diff --git a/docs/public/components/segmented-control-dark.webp b/docs/public/components/segmented-control-dark.webp new file mode 100644 index 000000000..ab912edc4 Binary files /dev/null and b/docs/public/components/segmented-control-dark.webp differ diff --git a/docs/public/components/segmented-control-hero-dark.webp b/docs/public/components/segmented-control-hero-dark.webp new file mode 100644 index 000000000..f830ff500 Binary files /dev/null and b/docs/public/components/segmented-control-hero-dark.webp differ diff --git a/docs/public/components/segmented-control-hero-light.webp b/docs/public/components/segmented-control-hero-light.webp new file mode 100644 index 000000000..506de40f0 Binary files /dev/null and b/docs/public/components/segmented-control-hero-light.webp differ diff --git a/docs/public/components/segmented-control-light.webp b/docs/public/components/segmented-control-light.webp new file mode 100644 index 000000000..4ad10b4b2 Binary files /dev/null and b/docs/public/components/segmented-control-light.webp differ diff --git a/docs/src/app/docs/cli/page.mdx b/docs/src/app/docs/cli/page.mdx index 20f57eb67..c4e612924 100644 --- a/docs/src/app/docs/cli/page.mdx +++ b/docs/src/app/docs/cli/page.mdx @@ -95,7 +95,7 @@ Write an owned `build.zig`/`build.zig.zon` into the app (once); the verbs then d native eject component [dir] ``` -Write an owned copy of a library composite into `src/components/` (once, never overwriting — ejecting again errors with the file to delete first). Ejectable today: `stepper`, `timeline`, `timeline-item` — the library views that are honest compositions of primitives; engine controls are not on the menu (theme them through [tokens](/docs/theming) instead). `timeline` lands as a markup template (use it via ``), the others as Zig view functions; each file opens with a header comment walking through the call-site migration, and each builds a widget tree identical to its library form at the moment of ejection. Unknown names get a did-you-mean plus the full ejectable list. See [Building Components](/docs/building-components#use-eject-or-build). +Write an owned copy of a library composite into `src/components/` (once, never overwriting — ejecting again errors with the file to delete first). Ejectable today: `stepper`, `timeline`, `timeline-item` — the library views that are compositions of primitives; engine controls are not on the menu (theme them through [tokens](/docs/theming) instead). All three eject as Native markup templates, so they work in TypeScript apps without an app-side Zig file; use them through `` and ``. Each file opens with a header comment walking through the call-site migration, and each builds a widget tree identical to its library form at the moment of ejection. Unknown names get a did-you-mean plus the full ejectable list. See [Building Components](/docs/building-components#use-eject-or-build). ### `native doctor` diff --git a/docs/src/app/docs/components/button/page.mdx b/docs/src/app/docs/components/button/page.mdx index 846ded1b2..fa2f94878 100644 --- a/docs/src/app/docs/components/button/page.mdx +++ b/docs/src/app/docs/components/button/page.mdx @@ -36,7 +36,7 @@ Four sizes: `sm`, `default`, `lg`, and `icon` — the icon size renders a square ## Icons -`icon` names a built-in vector icon (see the [icon registry](/docs/components/icon)) drawn inline before the label — one hit target, one enabled/disabled tint. +`icon` names a built-in vector icon (see the [icon registry](/docs/components/icon)) drawn inline before the label — one hit target, one enabled/disabled tint. For an image-free icon button, use `size="icon"` with empty content and provide `label` for its accessible name. Registered-image button content remains a separate asset-lifecycle proposal. diff --git a/docs/src/app/docs/components/segmented-control/layout.tsx b/docs/src/app/docs/components/segmented-control/layout.tsx new file mode 100644 index 000000000..4bc7db339 --- /dev/null +++ b/docs/src/app/docs/components/segmented-control/layout.tsx @@ -0,0 +1,7 @@ +import { pageMetadata } from "@/lib/page-metadata"; + +export const metadata = pageMetadata("components/segmented-control"); + +export default function SegmentedControlLayout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/docs/src/app/docs/components/segmented-control/page.mdx b/docs/src/app/docs/components/segmented-control/page.mdx new file mode 100644 index 000000000..e0343730a --- /dev/null +++ b/docs/src/app/docs/components/segmented-control/page.mdx @@ -0,0 +1,47 @@ +import { ComponentPreview } from "@/components/component-preview"; +import { AttrTable } from "@/components/attr-table"; + +# Segmented Control + +A standalone exclusive-choice segment. Each `segmented-control` is one named, pressable item: bind `selected` from the model, dispatch `on-press`, and add a vector `icon` when the label benefits from one. Put several in a row for a compact choice control; use [tabs](/docs/components/tabs) when you also need the tab-strip container and conditional panel. + + + +## Markup + +```html + + Day + Week + Month + +``` + +`selected` is model-owned. Pressing a segment sends its message; the next view rebuild reflects the new selection. The segment itself is a text-bearing control, so it needs visible content or a `label` accessible name. + +## Icons and sizes + +The `icon` attribute uses the same closed vector-icon vocabulary as [button](/docs/components/button). It is drawn as part of the segment's own hit target and follows the segment's state tint. `size` selects the shared control register; `label` supplies an accessible name when the visible content is absent. + +```html + + + + +``` + +## Programmatic construction (Zig) + +In a Zig view, use the same retained widget kind directly with `canvas.Ui`: + +```zig +ui.row(.{ .gap = 6 }, .{ + ui.el(.segmented_control, .{ .text = "Day", .selected = model.range == .day, .on_press = .choose_day }, .{}), + ui.el(.segmented_control, .{ .text = "Week", .icon = "settings", .selected = model.range == .week, .on_press = .choose_week }, .{}), + ui.el(.segmented_control, .{ .text = "Month", .selected = model.range == .month, .on_press = .choose_month }, .{}), +}) +``` + +## Attributes + + diff --git a/docs/src/app/docs/components/stepper/page.mdx b/docs/src/app/docs/components/stepper/page.mdx index c7edf50b5..663896c65 100644 --- a/docs/src/app/docs/components/stepper/page.mdx +++ b/docs/src/app/docs/components/stepper/page.mdx @@ -10,7 +10,7 @@ A stage stepper: `step` children joined by hairline connectors, with `active` na ## Markup -`active` is required — a number or one `{binding}`. +`active` is required — a number or one `{binding}`. The component is also ejectable as a markup template when you need to own its shape. ```html diff --git a/docs/src/app/docs/components/tabs/page.mdx b/docs/src/app/docs/components/tabs/page.mdx index a1de229ce..dce254584 100644 --- a/docs/src/app/docs/components/tabs/page.mdx +++ b/docs/src/app/docs/components/tabs/page.mdx @@ -3,7 +3,7 @@ import { AttrTable } from "@/components/attr-table"; # Tabs -A tab strip: ONE muted rounded container (the house tab-strip treatment) whose triggers sit inside it — the active trigger lifts to the surface with a hairline, inactive triggers stay muted on the container's wash. The children are [buttons](/docs/components/button) whose `selected` state marks the active tab — usually an equality against a model field — and whose `on-press` switches it. The segmented-control foundation is what the engine renders tab triggers with: both markup engines lower `