// Package webui is a Go/WebAssembly UI component kit for the gowasm engine — a
// direct port of kjol's Solid.js TSX kit (web/kit). Components are neutral
// *vdom.VNode builders: they render to HTML on the server (SSR) and hydrate on
// the client, styled with Tailwind utility classes.
//
// Port conventions (how the TSX maps to Go):
//
//   - A TSX component `function Foo(props)` becomes `func Foo(p FooProps, children ...*vdom.VNode) *vdom.VNode`
//     (children variadic when the component wraps content).
//   - Solid's reactive accessors (`value | () => value`) collapse away: the whole
//     component re-renders on a signal write (React-style), so callers pass plain
//     current values — read a signal with `.Get()` at the call site.
//   - `onclick={fn}` → `vdom.On(vdom.EVENT_CLICK, fn)`; handlers needing the event use
//     `OnEvent`. `class` overrides are the trailing `Class` field, joined via cx.
//   - Tailwind classes are copied verbatim so kjol/cmd/twcss (scanning these .go
//     files) emits the matching CSS. Custom tokens (rounded-default, bg-primary,
//     text-text-heading, …) come from the app's @theme block.
//
// # Browser-backed components
//
// Anything that has to measure the page — a popover that must not fall off the
// screen, a column you can drag wider, a tour that spotlights an element — reaches
// the browser through the host API in kjol/wasmruntime (Measure, Viewport, SetStyle,
// RAF, AfterRender, OnDocument/OnWindow, storage, …). That API is dual-build: real
// in the browser, no-op stubs natively. So these components stay neutral and still
// server-render: on the server every measurement is the zero Rect, no listener is
// installed, and the component renders its unmeasured state (a panel that is closed,
// a table in its declared column order). See kjol/wasmruntime/host.go.
//
// Such components are CONTROLLERS, not plain functions: they own refs, timers and
// open state, so they must be created ONCE — alongside your signals, never inside a
// render closure, which would rebuild them every frame:
//
//	menu  := webui.NewMenu(webui.MenuOptions{})
//	table := webui.NewAutoTableState(cols, webui.AutoTableStateOptions{})
//
//	return func() *vdom.VNode {
//	    return Div(menu.Trigger(…), menu.Content(…), table.Render(…))
//	}
//
// Floating panels (Tooltip, Popover, Menu, Submenu, DatePicker, Modal, Tutorial) are
// all built on the Floating controller in floating.go, which portals them to
// document.body and positions them with the engine in position.go.
package webui

import (
	"strings"

	"kjol/vdom"
)

// cx joins non-empty class fragments with single spaces (a tiny clsx). Trailing
// user `Class` overrides go last so they win under equal specificity.
func cx(parts ...string) string {
	var b strings.Builder
	for _, p := range parts {
		p = strings.TrimSpace(p)
		if p == "" {
			continue
		}
		if b.Len() > 0 {
			b.WriteByte(' ')
		}
		b.WriteString(p)
	}
	return b.String()
}

// pick returns v if non-empty, else def (for defaulted string props like type).
func pick(v, def string) string {
	if v == "" {
		return def
	}
	return v
}

// kids appends children VNodes onto a mod slice (helper for the props+children shape).
func kids(mods []vdom.Mod, children []*vdom.VNode) []vdom.Mod {
	for _, c := range children {
		if c != nil {
			mods = append(mods, c)
		}
	}
	return mods
}
