From 0019c8e195f05e3e9c147a5759816be6d4d87e2a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Wed, 2 Sep 2026 17:37:57 -0500 Subject: [PATCH 1/2] feat(ts): close component markup grammar - Add segmented-control markup support with interpreter, compiled, contract, docs, preview, and conformance coverage. - Convert stepper and timeline-item ejects to TypeScript-compatible Native markup templates with identity parity tests. - Document and preserve explicit rulings for deferred data-grid, popover, image-lifecycle, and styling work. --- .../components/segmented-control-dark.webp | Bin 0 -> 1900 bytes .../segmented-control-hero-dark.webp | Bin 0 -> 1810 bytes .../segmented-control-hero-light.webp | Bin 0 -> 1828 bytes .../components/segmented-control-light.webp | Bin 0 -> 1870 bytes docs/src/app/docs/cli/page.mdx | 2 +- docs/src/app/docs/components/button/page.mdx | 2 +- .../components/segmented-control/layout.tsx | 7 + .../components/segmented-control/page.mdx | 47 +++++++ docs/src/app/docs/components/stepper/page.mdx | 2 +- docs/src/app/docs/components/tabs/page.mdx | 4 +- .../src/app/docs/components/timeline/page.mdx | 2 +- docs/src/app/docs/native-ui/page.mdx | 7 +- docs/src/lib/component-vocab.json | 20 ++- docs/src/lib/components-pages.ts | 1 + skill-data/native-ui/SKILL.md | 5 +- src/primitives/canvas/ui_markup.zig | 43 ++++-- src/primitives/canvas/ui_markup_compiled.zig | 25 +++- .../canvas/ui_markup_compiled_tests.zig | 17 +++ src/primitives/canvas/ui_markup_contract.zig | 3 + .../canvas/ui_markup_contract_tests.zig | 14 ++ src/primitives/canvas/ui_markup_tests.zig | 27 ++++ src/primitives/canvas/ui_markup_view.zig | 49 +++++-- .../canvas/ui_markup_view_tests.zig | 54 ++++++-- src/primitives/canvas/ui_schema.zig | 3 + src/primitives/canvas/ui_schema_tests.zig | 6 +- src/tooling/components/identity_tests.zig | 52 +++---- src/tooling/components/stepper.native | 22 +++ src/tooling/components/stepper.zig | 113 --------------- src/tooling/components/timeline-item.native | 20 +++ src/tooling/components/timeline_item.zig | 131 ------------------ src/tooling/eject_components.zig | 32 +++-- tools/docs_preview_scenes.zig | 25 +++- tools/native-sdk/main.zig | 7 + tools/native-sdk/markup_docs.zig | 3 +- tools/native-sdk/markup_lsp.zig | 2 +- 35 files changed, 407 insertions(+), 340 deletions(-) create mode 100644 docs/public/components/segmented-control-dark.webp create mode 100644 docs/public/components/segmented-control-hero-dark.webp create mode 100644 docs/public/components/segmented-control-hero-light.webp create mode 100644 docs/public/components/segmented-control-light.webp create mode 100644 docs/src/app/docs/components/segmented-control/layout.tsx create mode 100644 docs/src/app/docs/components/segmented-control/page.mdx create mode 100644 src/tooling/components/stepper.native delete mode 100644 src/tooling/components/stepper.zig create mode 100644 src/tooling/components/timeline-item.native delete mode 100644 src/tooling/components/timeline_item.zig diff --git a/docs/public/components/segmented-control-dark.webp b/docs/public/components/segmented-control-dark.webp new file mode 100644 index 0000000000000000000000000000000000000000..ab912edc40b0de0c9d7569471db4e4988c73bb89 GIT binary patch literal 1900 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 T(|zH4YIyYjIgl}t2zTN?Xr+^A literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..506de40f020fd897e5b13e5e4678ce6548ea069f GIT binary patch literal 1828 zcma)+`7;{`0EJ`Sb+fLO1`$G0f(EIgb+p7?*J|r3>Iy|s8kDqX-HD?l!nA^Q#ubV> zYLz%DN<-aLT#IU4%T}}YKiHW!^Szn(V;+yH=!*$q2qJ3T9*^RChT-W$Nk zww{5oy6-hcW~K7(X<4d4Jl`Gnvsm)2ELO3RJ9?IaI#2gEyzjfhGIPxqnMrd(FzQKb z=FZ`nC#Z?4TC7`sQ{=1!U~ysF8T*KZ;WGEXkN?4A@|wNbd5aixK0VE4F%nKZeir<1 zuofp>4VAG}(>)&9I(*$o=A z;cFqg8=;KHHFua3(7-zm+?lu#wve$Wo&5dH)Qdrvc3_=MTlt>=;O+LrVO9){*jL4S zAG{K1P};&M0e6S#NqE*fu$Nltzvvui89&)c?yM6%k;!=jpHj#HL1)sveO1ckYJyEg zP@yer5?M$3&OFOCqw*XPfoT~eeT0_#**Lrad}wyk*7!XG43_QoIcY!-uSGLYQg(rz zyx2{^R^nwO+mWh^^J!v$?>syQ3}}iXeIRoZ(=y2-ZC*{nGS}d>;@W_3%>5ztU&96* z0lr~Kk%M@Kn>^raoocUl4ETC@d1~hw32f^w_tu5D?YN?m>m)Rv&8>TDA@P9^!X|s0 z{dGRxUCxMOOd{5#?glQL;!9&xv;!Y!M4HmNkgU7CccU1NwSIT$F&!RIo{ z-8o-p`ex9H`D!rqTlQ5Wr4sqVSdyA^)Ns=&2=Q?s9((B8BTy+9!*=V#v0KXn2N}w=TPb?!#y7rjD^&Nddxl6BF7UI|6?LwdD{Vbhu2lj%@+B5a zGyS9(b*8O@Af_#|C>}cp`DFD8TH+WlZ?x9e%145@c#MxdTH3WHF^O{=}&1qwbk}zOPUsbCeudn1OlYhJ6W~2V8|QWAXR&2 zixi{sfnnIbG2A`DhvHojZTY)iP@2id8<>9MXY`sxw?-L%`}U_-;V@YW4c5kmRMSng z!ADLb4?#bqNsI3pu11tA&BW)>P4k0mN>?iv>tS8TcU2UqLKbY)S|+xP9nzV~G-R&$ zNLA?Z7|7}KZ&x`;dJDvWZdVz%T5&&eeiRG#I5;-&nn6^_IqNV*Boh%n3Oxo-Wekxvd**U6 zWfi5FRvclIep3E)|D{)om7g;PVtji@nv4do#&sMxD{i?236`ZHO0YQKV+t_rS)kh5 zrESHSU!Kn;w?JaJW1Nm!eAF*gZ;vU<*AOx<3clZYWkyU6{ZnbP{~~@RpV znooJ`kP}44qNI@O>gc0qvwKkJR|FMQ8hSa?6&thRTQ_AtNN57&lj_)}fUAZN3y=+& za6(p-+Yly1a=irX1o2SO4nT?FiBv_ zJq{v4u7~tDUteDW2LCnOmj{G#Z-Z1AY2ek9oMJwc=ygqL_;ikh&=oGKLd0` zzZkr^o4uN{nlV6~U5r~1XBJdT+;G1n`^H3vO|O)|MYczd4AdYoC=vE$4k|_1*>s}y zIJP0*lFwpceP#KQ#Qi*bcs-8EVNelo!zL9O-*wBXILA*afHn#$qpJFj>cXGY(zt6 zx=Mf2D?5<0fAxFhMW59Y!}e#j#kp3gQ58!UBEl?}V<&)Quf?1eoMwG&ZfwxJXpez) z(76?JN4O$7*n_W(xn0Juak)w2)g?ZRIVQ)cD$F-iiiTUX*Fewz;L9u5H_b1E`A+NH zoJ-Kn7hJqVR*dp{ee z^H9zSyfs=1r^w%I?+N7#9DUf*+7-lotO;EC;w`jY1Sf!S8Y3^2I=}dOkSmG?mPQSq p0D}iy`Xy(3Y$-Fd%Jkjf)&{gA3~e^VVs`(~U=9Cou*S3i{{q)smI?p> literal 0 HcmV?d00001 diff --git a/docs/public/components/segmented-control-light.webp b/docs/public/components/segmented-control-light.webp new file mode 100644 index 0000000000000000000000000000000000000000..4ad10b4b255e2040d71f7ddd4190886c5aa7b5d6 GIT binary patch literal 1870 zcmbW2_ct4g0>>k++WVT}A|h6llvi7?BBZUYNsIDSsnoniFIq7ht4gfeT%)wLLTI8? z8Y@Am(O9KMj9&BFs^ocp!h7d@&-s2ozkkp9I3N)S1SbH1wzzJGveUa|aIrPryKMo> zHU2X=Jc~8+Jzw!YF#K)8Adqk3y<9FBi7Gpl)4_XVLwDd@qnwj-)m`4^EM1XMH7f=bnfrC2gk6ULi>$I{695kgypZ}mh!G|t8e{rk;bS<g=ClE>1|lAP zqdHD??ViWOWcN$YPrtbgpvPa|teDL*t81C^c;7Pp7j^naQJOO<5!33zAp0S5T~K4) zYJ|o5n=g(@?mxMR1Sz;$$5Q@y++_Qhs~m!AkkXKI2LfbGakMYeIEY^#xsQ+?ebyY>wO*>VoR$_6ss17!3v zjUYu@Zj>xE7Wm}V4A|~Z?U(&EXd)D##O=bi@3xFEiJ?WIIe3>}L+DfB-7R#AQB*P$ z8_{+T+3v)U^q|DMK(;?>>xfoc9RlDp{+bye;0m954q$~{g*)(NmFr>V-Ht6zH`w-cD8&Ux|?w&Ht7qDkI7pKTd8phNqrI7)9Q?u znc`u|D(M*8Kz(B*H^s}H_F`wHb{|Vt)u-6tqnO{A{2dUoMJ2w{*5vI^1lC4-!xT=x zJvktnl<^fO1|k23=R?i`>$8edf~N)Lm6t=O;@NfRWfIl?6&^C>sKn1go4)pC^D4*} zxS$}v^IwnweK0hKyXsA3?-KFIM4ca^ncR&O_+WJ?xoGfI)%!ZB_i!(PZ*qmmw?w@FU2W3hj95~^3-=i zvtX7Avb#Zd2f{~u_U!8@{e)r%gIKI?k1&3qHPgM*Y23OM9HC1urFUYu#4F0y`70%5pMM_b@f+}nECX7*_(?;R@mlC#Khc$OOkc07n;MIaE^dYAv4c96 z&?LnjDDsM6qOs4rKiGyaX#_;DP>Gv{__{+%CiC&&nlA6Eho!ARy%&L_keHf>m_SDV z&g6txmf*em1B)FRGBt*28X-adqN=;*trJZHEg+ zoGpcLFEkVGOouHTx09u&*GohqKG3ucCz5{J=qrPJpctT#VRZ5BHdiB3em$eR73cO;%au4kX{(JzA}e;u(9{ui+a5BP{lpdGV8Fp=-dC%V~=U)*XrR9?k5i^ycHZq@S@D z#X`T5*@&*~F&~e1Y90A(_KJeHvJSW=zdR$Jf9lw>$ZU+HAneF`V}3pg}+r z0o5`Z%oA?b@Vd*Glg7(PL6L&R!%d666tSU)*tai@yrktVN*R~U>Wdj&$OAw2ab#xB SFQv*~@&B^Xe+?E*Wcv@HqPsHy literal 0 HcmV?d00001 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..9a62e6238 --- /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 `