@ecopages/radiant-ui 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/README.md +70 -0
  2. package/dist/components/ui/alert/alert.css +27 -0
  3. package/dist/components/ui/alert/alert.d.ts +4 -0
  4. package/dist/components/ui/alert/alert.script.d.ts +25 -0
  5. package/dist/components/ui/alert/index.d.ts +2 -0
  6. package/dist/components/ui/alert/index.js +2 -0
  7. package/dist/components/ui/alert/index.js.map +7 -0
  8. package/dist/components/ui/breadcrumb/breadcrumb.css +41 -0
  9. package/dist/components/ui/breadcrumb/breadcrumb.d.ts +59 -0
  10. package/dist/components/ui/breadcrumb/breadcrumb.script.d.ts +40 -0
  11. package/dist/components/ui/breadcrumb/index.d.ts +2 -0
  12. package/dist/components/ui/breadcrumb/index.js +2 -0
  13. package/dist/components/ui/breadcrumb/index.js.map +7 -0
  14. package/dist/components/ui/button/button.d.ts +37 -0
  15. package/dist/components/ui/button/index.d.ts +1 -0
  16. package/dist/components/ui/button/index.js +2 -0
  17. package/dist/components/ui/button/index.js.map +7 -0
  18. package/dist/components/ui/carousel/carousel.css +170 -0
  19. package/dist/components/ui/carousel/carousel.d.ts +39 -0
  20. package/dist/components/ui/carousel/carousel.script.d.ts +113 -0
  21. package/dist/components/ui/carousel/index.d.ts +2 -0
  22. package/dist/components/ui/carousel/index.js +2 -0
  23. package/dist/components/ui/carousel/index.js.map +7 -0
  24. package/dist/components/ui/checkbox/checkbox.css +55 -0
  25. package/dist/components/ui/checkbox/checkbox.d.ts +4 -0
  26. package/dist/components/ui/checkbox/checkbox.script.d.ts +58 -0
  27. package/dist/components/ui/checkbox/index.d.ts +2 -0
  28. package/dist/components/ui/checkbox/index.js +2 -0
  29. package/dist/components/ui/checkbox/index.js.map +7 -0
  30. package/dist/components/ui/combobox/combobox.css +65 -0
  31. package/dist/components/ui/combobox/combobox.d.ts +53 -0
  32. package/dist/components/ui/combobox/combobox.script.d.ts +89 -0
  33. package/dist/components/ui/combobox/index.d.ts +2 -0
  34. package/dist/components/ui/combobox/index.js +2 -0
  35. package/dist/components/ui/combobox/index.js.map +7 -0
  36. package/dist/components/ui/dialog/dialog-registry.d.ts +34 -0
  37. package/dist/components/ui/dialog/dialog-registry.test.d.ts +1 -0
  38. package/dist/components/ui/dialog/dialog-types.d.ts +55 -0
  39. package/dist/components/ui/dialog/dialog.css +53 -0
  40. package/dist/components/ui/dialog/dialog.d.ts +36 -0
  41. package/dist/components/ui/dialog/dialog.script.d.ts +61 -0
  42. package/dist/components/ui/dialog/index.d.ts +4 -0
  43. package/dist/components/ui/dialog/index.js +2 -0
  44. package/dist/components/ui/dialog/index.js.map +7 -0
  45. package/dist/components/ui/disclosure/disclosure-group.script.d.ts +31 -0
  46. package/dist/components/ui/disclosure/disclosure.css +105 -0
  47. package/dist/components/ui/disclosure/disclosure.d.ts +35 -0
  48. package/dist/components/ui/disclosure/disclosure.script.d.ts +38 -0
  49. package/dist/components/ui/disclosure/index.d.ts +3 -0
  50. package/dist/components/ui/disclosure/index.js +2 -0
  51. package/dist/components/ui/disclosure/index.js.map +7 -0
  52. package/dist/components/ui/feed/feed.css +14 -0
  53. package/dist/components/ui/feed/feed.d.ts +12 -0
  54. package/dist/components/ui/feed/feed.script.d.ts +22 -0
  55. package/dist/components/ui/feed/index.d.ts +2 -0
  56. package/dist/components/ui/feed/index.js +2 -0
  57. package/dist/components/ui/feed/index.js.map +7 -0
  58. package/dist/components/ui/field/field-context.d.ts +20 -0
  59. package/dist/components/ui/field/field-description.d.ts +8 -0
  60. package/dist/components/ui/field/field-error.d.ts +9 -0
  61. package/dist/components/ui/field/field-ssr-hydration.test.d.ts +1 -0
  62. package/dist/components/ui/field/field.css +26 -0
  63. package/dist/components/ui/field/field.d.ts +4 -0
  64. package/dist/components/ui/field/field.script.d.ts +68 -0
  65. package/dist/components/ui/field/index.d.ts +5 -0
  66. package/dist/components/ui/field/index.js +2 -0
  67. package/dist/components/ui/field/index.js.map +7 -0
  68. package/dist/components/ui/form/control-protocol.d.ts +19 -0
  69. package/dist/components/ui/form/form-context.d.ts +27 -0
  70. package/dist/components/ui/form/form-field.test.d.ts +3 -0
  71. package/dist/components/ui/form/form-store.d.ts +53 -0
  72. package/dist/components/ui/form/form-store.test.d.ts +1 -0
  73. package/dist/components/ui/form/form.css +12 -0
  74. package/dist/components/ui/form/form.d.ts +5 -0
  75. package/dist/components/ui/form/form.script.d.ts +67 -0
  76. package/dist/components/ui/form/index.d.ts +7 -0
  77. package/dist/components/ui/form/index.js +2 -0
  78. package/dist/components/ui/form/index.js.map +7 -0
  79. package/dist/components/ui/form/resolvers.d.ts +3 -0
  80. package/dist/components/ui/form/types.d.ts +72 -0
  81. package/dist/components/ui/grid/grid.css +47 -0
  82. package/dist/components/ui/grid/grid.d.ts +7 -0
  83. package/dist/components/ui/grid/grid.script.d.ts +26 -0
  84. package/dist/components/ui/grid/index.d.ts +2 -0
  85. package/dist/components/ui/grid/index.js +2 -0
  86. package/dist/components/ui/grid/index.js.map +7 -0
  87. package/dist/components/ui/input/index.d.ts +1 -0
  88. package/dist/components/ui/input/index.js +2 -0
  89. package/dist/components/ui/input/index.js.map +7 -0
  90. package/dist/components/ui/input/input.css +32 -0
  91. package/dist/components/ui/input/input.d.ts +23 -0
  92. package/dist/components/ui/label/index.d.ts +1 -0
  93. package/dist/components/ui/label/index.js +2 -0
  94. package/dist/components/ui/label/index.js.map +7 -0
  95. package/dist/components/ui/label/label.css +8 -0
  96. package/dist/components/ui/label/label.d.ts +9 -0
  97. package/dist/components/ui/listbox/index.d.ts +2 -0
  98. package/dist/components/ui/listbox/index.js +2 -0
  99. package/dist/components/ui/listbox/index.js.map +7 -0
  100. package/dist/components/ui/listbox/listbox.css +23 -0
  101. package/dist/components/ui/listbox/listbox.d.ts +12 -0
  102. package/dist/components/ui/listbox/listbox.script.d.ts +40 -0
  103. package/dist/components/ui/menu-button/index.d.ts +2 -0
  104. package/dist/components/ui/menu-button/index.js +2 -0
  105. package/dist/components/ui/menu-button/index.js.map +7 -0
  106. package/dist/components/ui/menu-button/menu-button.css +43 -0
  107. package/dist/components/ui/menu-button/menu-button.d.ts +13 -0
  108. package/dist/components/ui/menu-button/menu-button.script.d.ts +64 -0
  109. package/dist/components/ui/menubar/index.d.ts +2 -0
  110. package/dist/components/ui/menubar/index.js +2 -0
  111. package/dist/components/ui/menubar/index.js.map +7 -0
  112. package/dist/components/ui/menubar/menubar.css +45 -0
  113. package/dist/components/ui/menubar/menubar.d.ts +16 -0
  114. package/dist/components/ui/menubar/menubar.script.d.ts +52 -0
  115. package/dist/components/ui/meter/index.d.ts +2 -0
  116. package/dist/components/ui/meter/index.js +2 -0
  117. package/dist/components/ui/meter/index.js.map +7 -0
  118. package/dist/components/ui/meter/meter.css +17 -0
  119. package/dist/components/ui/meter/meter.d.ts +4 -0
  120. package/dist/components/ui/meter/meter.script.d.ts +33 -0
  121. package/dist/components/ui/navigation-menu/index.d.ts +2 -0
  122. package/dist/components/ui/navigation-menu/index.js +2 -0
  123. package/dist/components/ui/navigation-menu/index.js.map +7 -0
  124. package/dist/components/ui/navigation-menu/navigation-menu.css +90 -0
  125. package/dist/components/ui/navigation-menu/navigation-menu.d.ts +28 -0
  126. package/dist/components/ui/navigation-menu/navigation-menu.script.d.ts +49 -0
  127. package/dist/components/ui/radio-group/index.d.ts +2 -0
  128. package/dist/components/ui/radio-group/index.js +2 -0
  129. package/dist/components/ui/radio-group/index.js.map +7 -0
  130. package/dist/components/ui/radio-group/radio-group.css +44 -0
  131. package/dist/components/ui/radio-group/radio-group.d.ts +12 -0
  132. package/dist/components/ui/radio-group/radio-group.script.d.ts +52 -0
  133. package/dist/components/ui/sidebar/index.d.ts +3 -0
  134. package/dist/components/ui/sidebar/index.js +2 -0
  135. package/dist/components/ui/sidebar/index.js.map +7 -0
  136. package/dist/components/ui/sidebar/sidebar-trigger.script.d.ts +53 -0
  137. package/dist/components/ui/sidebar/sidebar.css +362 -0
  138. package/dist/components/ui/sidebar/sidebar.d.ts +141 -0
  139. package/dist/components/ui/sidebar/sidebar.script.d.ts +140 -0
  140. package/dist/components/ui/sidebar/sidebar.test.d.ts +1 -0
  141. package/dist/components/ui/slider/index.d.ts +2 -0
  142. package/dist/components/ui/slider/index.js +2 -0
  143. package/dist/components/ui/slider/index.js.map +7 -0
  144. package/dist/components/ui/slider/slider.css +51 -0
  145. package/dist/components/ui/slider/slider.d.ts +7 -0
  146. package/dist/components/ui/slider/slider.script.d.ts +102 -0
  147. package/dist/components/ui/spinbutton/index.d.ts +2 -0
  148. package/dist/components/ui/spinbutton/index.js +2 -0
  149. package/dist/components/ui/spinbutton/index.js.map +7 -0
  150. package/dist/components/ui/spinbutton/spinbutton.css +19 -0
  151. package/dist/components/ui/spinbutton/spinbutton.d.ts +4 -0
  152. package/dist/components/ui/spinbutton/spinbutton.script.d.ts +64 -0
  153. package/dist/components/ui/switch/index.d.ts +2 -0
  154. package/dist/components/ui/switch/index.js +2 -0
  155. package/dist/components/ui/switch/index.js.map +7 -0
  156. package/dist/components/ui/switch/switch.css +47 -0
  157. package/dist/components/ui/switch/switch.d.ts +4 -0
  158. package/dist/components/ui/switch/switch.script.d.ts +51 -0
  159. package/dist/components/ui/tabs/index.d.ts +2 -0
  160. package/dist/components/ui/tabs/index.js +2 -0
  161. package/dist/components/ui/tabs/index.js.map +7 -0
  162. package/dist/components/ui/tabs/tabs.css +28 -0
  163. package/dist/components/ui/tabs/tabs.d.ts +12 -0
  164. package/dist/components/ui/tabs/tabs.script.d.ts +54 -0
  165. package/dist/components/ui/textarea/index.d.ts +1 -0
  166. package/dist/components/ui/textarea/index.js +2 -0
  167. package/dist/components/ui/textarea/index.js.map +7 -0
  168. package/dist/components/ui/textarea/textarea.css +33 -0
  169. package/dist/components/ui/textarea/textarea.d.ts +23 -0
  170. package/dist/components/ui/toast/index.d.ts +5 -0
  171. package/dist/components/ui/toast/index.js +2 -0
  172. package/dist/components/ui/toast/index.js.map +7 -0
  173. package/dist/components/ui/toast/toast-api.d.ts +29 -0
  174. package/dist/components/ui/toast/toast-context.d.ts +59 -0
  175. package/dist/components/ui/toast/toast-state.d.ts +25 -0
  176. package/dist/components/ui/toast/toast.css +315 -0
  177. package/dist/components/ui/toast/toast.d.ts +8 -0
  178. package/dist/components/ui/toast/toast.script.d.ts +91 -0
  179. package/dist/components/ui/toast/toast.test.d.ts +2 -0
  180. package/dist/components/ui/toast/toaster.script.d.ts +79 -0
  181. package/dist/components/ui/toolbar/index.d.ts +2 -0
  182. package/dist/components/ui/toolbar/index.js +2 -0
  183. package/dist/components/ui/toolbar/index.js.map +7 -0
  184. package/dist/components/ui/toolbar/toolbar.css +16 -0
  185. package/dist/components/ui/toolbar/toolbar.d.ts +4 -0
  186. package/dist/components/ui/toolbar/toolbar.script.d.ts +30 -0
  187. package/dist/components/ui/tooltip/index.d.ts +2 -0
  188. package/dist/components/ui/tooltip/index.js +2 -0
  189. package/dist/components/ui/tooltip/index.js.map +7 -0
  190. package/dist/components/ui/tooltip/tooltip.css +25 -0
  191. package/dist/components/ui/tooltip/tooltip.d.ts +4 -0
  192. package/dist/components/ui/tooltip/tooltip.script.d.ts +70 -0
  193. package/dist/components/ui/tree/index.d.ts +2 -0
  194. package/dist/components/ui/tree/index.js +2 -0
  195. package/dist/components/ui/tree/index.js.map +7 -0
  196. package/dist/components/ui/tree/tree.css +54 -0
  197. package/dist/components/ui/tree/tree.d.ts +13 -0
  198. package/dist/components/ui/tree/tree.script.d.ts +45 -0
  199. package/dist/components/ui/treegrid/index.d.ts +2 -0
  200. package/dist/components/ui/treegrid/index.js +2 -0
  201. package/dist/components/ui/treegrid/index.js.map +7 -0
  202. package/dist/components/ui/treegrid/treegrid.css +77 -0
  203. package/dist/components/ui/treegrid/treegrid.d.ts +14 -0
  204. package/dist/components/ui/treegrid/treegrid.script.d.ts +49 -0
  205. package/dist/components/ui/window-splitter/index.d.ts +2 -0
  206. package/dist/components/ui/window-splitter/index.js +2 -0
  207. package/dist/components/ui/window-splitter/index.js.map +7 -0
  208. package/dist/components/ui/window-splitter/window-splitter.css +35 -0
  209. package/dist/components/ui/window-splitter/window-splitter.d.ts +8 -0
  210. package/dist/components/ui/window-splitter/window-splitter.script.d.ts +49 -0
  211. package/dist/index.d.ts +36 -0
  212. package/dist/index.js +2 -0
  213. package/dist/index.js.map +7 -0
  214. package/dist/lib/focusable-elements.d.ts +2 -0
  215. package/dist/lib/radiant-view.d.ts +17 -0
  216. package/dist/lib/roving-tabindex.d.ts +27 -0
  217. package/dist/styles/components/button.css +115 -0
  218. package/dist/styles/radiant-ui-core.css +7 -0
  219. package/dist/styles/radiant-ui.css +10 -0
  220. package/dist/styles/styles.css +36 -0
  221. package/dist/styles/tailwind.css +41 -0
  222. package/dist/styles/themes/aurora.css +19 -0
  223. package/dist/styles/themes/default-compact-soft.css +19 -0
  224. package/dist/styles/themes/default.css +2 -0
  225. package/dist/styles/themes/glacier.css +19 -0
  226. package/dist/styles/tokens/colors/aurora.css +73 -0
  227. package/dist/styles/tokens/colors/basalt.css +36 -0
  228. package/dist/styles/tokens/colors/glacier.css +45 -0
  229. package/dist/styles/tokens/colors/palettes.css +3 -0
  230. package/dist/styles/tokens/elevation/default.css +22 -0
  231. package/dist/styles/tokens/elevation/flat.css +22 -0
  232. package/dist/styles/tokens/motion/default.css +19 -0
  233. package/dist/styles/tokens/motion/snappy.css +19 -0
  234. package/dist/styles/tokens/presets/colors/aurora.css +126 -0
  235. package/dist/styles/tokens/presets/colors/basalt.css +126 -0
  236. package/dist/styles/tokens/presets/colors/ember.css +134 -0
  237. package/dist/styles/tokens/presets/colors/glacier.css +130 -0
  238. package/dist/styles/tokens/presets/colors/index.css +4 -0
  239. package/dist/styles/tokens/presets/radius.css +45 -0
  240. package/dist/styles/tokens/presets/spacing.css +57 -0
  241. package/dist/styles/tokens/radius/default.css +34 -0
  242. package/dist/styles/tokens/radius/edgy.css +35 -0
  243. package/dist/styles/tokens/radius/sharp.css +2 -0
  244. package/dist/styles/tokens/radius/soft.css +34 -0
  245. package/dist/styles/tokens/semantic.css +80 -0
  246. package/dist/styles/tokens/spacing/compact.css +23 -0
  247. package/dist/styles/tokens/spacing/default.css +23 -0
  248. package/dist/styles/tokens/spacing/scale-bridge.css +17 -0
  249. package/dist/styles/tokens/spacing/wide.css +23 -0
  250. package/dist/styles/tokens/system.css +36 -0
  251. package/dist/styles/tokens/typography/default.css +37 -0
  252. package/dist/styles/utilities/sheen.css +7 -0
  253. package/dist/types.d.ts +14 -0
  254. package/package.json +371 -0
@@ -0,0 +1,35 @@
1
+ import type { JsxRenderable } from '@ecopages/jsx';
2
+ import type { RadiantSlotProps } from '../../../types';
3
+ import type { RuiDisclosureGroupProps } from './disclosure-group.script';
4
+ import type { RuiDisclosureProps } from './disclosure.script';
5
+ import './disclosure-group.css';
6
+ import './disclosure.css';
7
+ export type RuiDisclosureIconProps = {
8
+ variant?: 'chevron' | 'plus';
9
+ class?: string;
10
+ };
11
+ /** Default disclosure indicator. Override via `RuiDisclosureTrigger` `icon` prop. */
12
+ export declare function RuiDisclosureIcon({ variant, class: className }: RuiDisclosureIconProps): JsxRenderable;
13
+ export type RuiDisclosureTriggerProps = RadiantSlotProps & {
14
+ children: JsxRenderable;
15
+ class?: string;
16
+ disabled?: boolean;
17
+ /** Custom indicator. Pass `null` to hide. Defaults to chevron. */
18
+ icon?: JsxRenderable | null;
19
+ iconPosition?: 'start' | 'end';
20
+ };
21
+ /** Disclosure button slotted into `trigger` by default. */
22
+ export declare function RuiDisclosureTrigger({ slot, children, class: className, disabled, icon, iconPosition, }: RuiDisclosureTriggerProps): JsxRenderable;
23
+ export type RuiDisclosurePanelProps = {
24
+ children: JsxRenderable;
25
+ class?: string;
26
+ };
27
+ /** Disclosure panel in the default slot. */
28
+ export declare function RuiDisclosurePanel({ children, class: className }: RuiDisclosurePanelProps): JsxRenderable;
29
+ export declare const RuiDisclosure: import("../../../lib/radiant-view").RadiantViewComponent<RuiDisclosureProps & RadiantSlotProps & {
30
+ trigger?: JsxRenderable;
31
+ children?: JsxRenderable;
32
+ }>;
33
+ export declare const RuiDisclosureGroup: import("../../../lib/radiant-view").RadiantViewComponent<RuiDisclosureGroupProps & RadiantSlotProps & {
34
+ children: JsxRenderable;
35
+ }>;
@@ -0,0 +1,38 @@
1
+ import { RadiantElement } from '@ecopages/radiant';
2
+ export type RuiDisclosureProps = {
3
+ /** Whether the disclosure content starts expanded. Default: `false`. */
4
+ open?: boolean;
5
+ /** Optional value used when coordinating disclosures inside a group. */
6
+ value?: string;
7
+ /** Animate panel height. Also enabled when inside an animated disclosure group. */
8
+ animated?: boolean;
9
+ };
10
+ export type RuiDisclosureToggleDetail = {
11
+ value: string;
12
+ open: boolean;
13
+ };
14
+ /**
15
+ * `<rui-disclosure>` — a composition-first show/hide control.
16
+ *
17
+ * Implements the WAI-ARIA APG Disclosure (Show/Hide) pattern. Pair a trigger
18
+ * marked with `data-disclosure-trigger` and a panel marked with
19
+ * `data-disclosure-panel` (see the view helpers).
20
+ *
21
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/
22
+ *
23
+ * @element rui-disclosure
24
+ * @slot trigger - Disclosure button (use `RuiDisclosureTrigger`).
25
+ * @slot - Panel content (use `RuiDisclosurePanel`).
26
+ */
27
+ export declare class RuiDisclosure extends RadiantElement {
28
+ open: boolean;
29
+ value: string;
30
+ animated: boolean;
31
+ private panelId;
32
+ connectedCallback(): void;
33
+ private syncAnimated;
34
+ onTriggerClick(event: Event): void;
35
+ private toggle;
36
+ syncExpanded(): void;
37
+ render(): import("@ecopages/jsx").JsxRenderable;
38
+ }
@@ -0,0 +1,3 @@
1
+ export { RuiDisclosure as RuiDisclosureElement, type RuiDisclosureProps, type RuiDisclosureToggleDetail, } from './disclosure.script';
2
+ export { RuiDisclosureGroup as RuiDisclosureGroupElement, type RuiDisclosureGroupProps, } from './disclosure-group.script';
3
+ export { RuiDisclosure, RuiDisclosureGroup, RuiDisclosureIcon, RuiDisclosurePanel, RuiDisclosureTrigger, } from './disclosure';
@@ -0,0 +1,2 @@
1
+ import{RadiantElement as E,bound as A,customElement as I,onEvent as P,onUpdated as _,prop as d}from"@ecopages/radiant";var u=@I("rui-disclosure")class extends E{@d({type:Boolean,reflect:!0,defaultValue:!1})open;@d({type:String,reflect:!0,defaultValue:""})value;@d({type:Boolean,reflect:!0,defaultValue:!1})animated;panelId=`rui-disclosure-${Math.random().toString(36).slice(2,9)}`;connectedCallback(){super.connectedCallback(),queueMicrotask(()=>{this.syncAnimated(),this.syncExpanded()})}syncAnimated(){this.toggleAttribute("data-animated",this.animated)}@P({selector:"[data-disclosure-trigger]",type:"click"})onTriggerClick(e){e.preventDefault(),this.toggle()}toggle(){let e=!this.open;this.open=e,this.dispatchEvent(new CustomEvent("rui-disclosure-toggle",{bubbles:!0,composed:!0,detail:{value:this.value,open:e}}))}@A@_(["open","animated"])syncExpanded(){this.syncAnimated();let e=this.querySelector("[data-disclosure-trigger]"),t=this.querySelector("[data-disclosure-panel]");if(!(!e||!t)){if(e.setAttribute("aria-expanded",String(this.open)),e.setAttribute("aria-controls",this.panelId),t.id=this.panelId,t.dataset.state=this.open?"open":"closed",this.animated){t.hidden=!1,t.setAttribute("aria-hidden",String(!this.open));return}t.hidden=!this.open,t.removeAttribute("aria-hidden")}}render(){return React.createElement("div",{class:"rui-disclosure"},React.createElement("slot",{name:"trigger"}),React.createElement("slot",null))}};import{RadiantElement as w,customElement as S,onEvent as h,onUpdated as L,prop as T}from"@ecopages/radiant";function p(r,e){r.forEach((t,i)=>{t.tabIndex=i===e?0:-1})}function M(r,e){if(!r.length)return null;let t=Math.max(0,Math.min(r.length-1,e));return p(r,t),r[t]?.focus(),r[t]??null}function C(r,e){return r==="Home"?"first":r==="End"?"last":e==="horizontal"?r==="ArrowRight"?"next":r==="ArrowLeft"?"prev":null:r==="ArrowDown"?"next":r==="ArrowUp"?"prev":null}function R(r){let{items:e,current:t,key:i,orientation:s="horizontal",wrap:o=!0}=r;if(!e.length||!t)return{handled:!1};let n=e.indexOf(t);if(n<0)return{handled:!1};let l=C(i,s);if(!l)return{handled:!1};let a=n;l==="first"?a=0:l==="last"?a=e.length-1:l==="next"?a=o?(n+1)%e.length:Math.min(e.length-1,n+1):a=o?(n-1+e.length)%e.length:Math.max(0,n-1);let f=M(e,a);return f?{handled:!0,index:a,item:f}:{handled:!1}}var c=@S("rui-disclosure-group")class extends w{@T({type:Boolean,reflect:!0,defaultValue:!1})multiple;@T({type:Boolean,reflect:!0,attribute:"animated",defaultValue:!1})animated;connectedCallback(){super.connectedCallback(),queueMicrotask(()=>{this.syncChildrenAnimated(),this.syncTriggers()})}getTriggers(){return Array.from(this.querySelectorAll("[data-disclosure-trigger]"))}getDisclosureForTrigger(e){return e.closest("rui-disclosure")}syncTriggers(){let e=this.getTriggers();if(!e.length)return;let t=Math.max(0,e.findIndex(i=>i.tabIndex===0||i===document.activeElement));p(e,t)}syncChildrenAnimated(){for(let e of this.querySelectorAll("rui-disclosure"))e.animated=this.animated}@L("animated")onAnimatedUpdated(){this.syncChildrenAnimated()}@h({selector:"rui-disclosure",type:"rui-disclosure-toggle"})onDisclosureToggle(e){if(this.multiple||!e.detail?.open)return;let i=e.target;if(i instanceof u)for(let s of this.querySelectorAll("rui-disclosure"))s!==i&&(s.open=!1)}@h({selector:"[data-disclosure-trigger]",type:"keydown"})onTriggerKeydown(e){let t=this.getTriggers(),i=e.target.closest("[data-disclosure-trigger]");if(!i)return;if(e.key==="ArrowLeft"||e.key==="ArrowRight"){let o=this.getDisclosureForTrigger(i);if(!o)return;let n=e.key==="ArrowRight";if(o.open===n){e.preventDefault();return}if(e.preventDefault(),o.open=n,n&&!this.multiple)for(let l of this.querySelectorAll("rui-disclosure"))l!==o&&(l.open=!1);return}R({items:t,current:i,key:e.key,orientation:"vertical",wrap:!0}).handled&&e.preventDefault()}render(){return React.createElement("div",{class:"rui-disclosure-group","data-ref":"root"},React.createElement("slot",null))}};var k=Symbol.for("@ecopages/storybook-radiant.viewElement"),D=Symbol.for("@ecopages/storybook-radiant.scriptModule"),v=Symbol.for("@ecopages/storybook-radiant.scriptExport");function V(r,e){r[k]=e;let t=e[D];t&&(r[D]=t,r[v]=e[v]??e.name)}function g(r,e){let t=(i=>e(i));return V(t,r),t}import"./disclosure-group.css";import"./disclosure.css";function m(...r){return r.filter(Boolean).join(" ")}function x({variant:r="chevron",class:e}){return React.createElement("span",{class:m("rui-disclosure__icon",`rui-disclosure__icon--${r}`,e),"data-disclosure-icon":!0,"aria-hidden":"true"})}function y({slot:r="trigger",children:e,class:t,disabled:i,icon:s,iconPosition:o="start"}){let l=s!==null?s??React.createElement(x,null):null;return React.createElement("button",{slot:r,type:"button","data-disclosure-trigger":!0,class:m("rui-disclosure__trigger",o==="end"&&"rui-disclosure__trigger--icon-end",t),disabled:i},o==="start"?l:null,React.createElement("span",{class:"rui-disclosure__label"},e),o==="end"?l:null)}function b({children:r,class:e}){return React.createElement("div",{"data-disclosure-panel":!0,"data-ref":"panel",class:m("rui-disclosure__panel",e)},React.createElement("div",{class:"rui-disclosure__panel-inner"},r))}var N=g(u,({slot:r,open:e,value:t,animated:i,trigger:s,children:o})=>s!=null?React.createElement("rui-disclosure",{slot:r,open:e,value:t,animated:i},React.createElement(y,null,s),o!=null?React.createElement(b,null,o):null):React.createElement("rui-disclosure",{slot:r,open:e,value:t,animated:i},o)),H=g(c,({slot:r,multiple:e,animated:t,children:i})=>React.createElement("rui-disclosure-group",{slot:r,multiple:e,animated:t},i));export{N as RuiDisclosure,u as RuiDisclosureElement,H as RuiDisclosureGroup,c as RuiDisclosureGroupElement,x as RuiDisclosureIcon,b as RuiDisclosurePanel,y as RuiDisclosureTrigger};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/components/ui/disclosure/disclosure.script.tsx", "../../../../src/components/ui/disclosure/disclosure-group.script.tsx", "../../../../src/lib/roving-tabindex.ts", "../../../../src/lib/radiant-view.ts", "../../../../src/components/ui/disclosure/disclosure.tsx"],
4
+ "sourcesContent": ["import { RadiantElement, bound, customElement, onEvent, onUpdated, prop } from '@ecopages/radiant';\n\nexport type RuiDisclosureProps = {\n\t/** Whether the disclosure content starts expanded. Default: `false`. */\n\topen?: boolean;\n\t/** Optional value used when coordinating disclosures inside a group. */\n\tvalue?: string;\n\t/** Animate panel height. Also enabled when inside an animated disclosure group. */\n\tanimated?: boolean;\n};\n\nexport type RuiDisclosureToggleDetail = {\n\tvalue: string;\n\topen: boolean;\n};\n\n/**\n * `<rui-disclosure>` \u2014 a composition-first show/hide control.\n *\n * Implements the WAI-ARIA APG Disclosure (Show/Hide) pattern. Pair a trigger\n * marked with `data-disclosure-trigger` and a panel marked with\n * `data-disclosure-panel` (see the view helpers).\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/\n *\n * @element rui-disclosure\n * @slot trigger - Disclosure button (use `RuiDisclosureTrigger`).\n * @slot - Panel content (use `RuiDisclosurePanel`).\n */\n@customElement('rui-disclosure')\nexport class RuiDisclosure extends RadiantElement {\n\t@prop({ type: Boolean, reflect: true, defaultValue: false }) open: boolean;\n\t@prop({ type: String, reflect: true, defaultValue: '' }) value: string;\n\t@prop({ type: Boolean, reflect: true, defaultValue: false }) animated: boolean;\n\n\tprivate panelId = `rui-disclosure-${Math.random().toString(36).slice(2, 9)}`;\n\n\toverride connectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tqueueMicrotask(() => {\n\t\t\tthis.syncAnimated();\n\t\t\tthis.syncExpanded();\n\t\t});\n\t}\n\n\tprivate syncAnimated(): void {\n\t\tthis.toggleAttribute('data-animated', this.animated);\n\t}\n\n\t@onEvent({ selector: '[data-disclosure-trigger]', type: 'click' })\n\tonTriggerClick(event: Event): void {\n\t\tevent.preventDefault();\n\t\tthis.toggle();\n\t}\n\n\tprivate toggle(): void {\n\t\tconst next = !this.open;\n\t\tthis.open = next;\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent<RuiDisclosureToggleDetail>('rui-disclosure-toggle', {\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t\tdetail: { value: this.value, open: next },\n\t\t\t}),\n\t\t);\n\t}\n\n\t@bound\n\t@onUpdated(['open', 'animated'])\n\tsyncExpanded(): void {\n\t\tthis.syncAnimated();\n\n\t\tconst trigger = this.querySelector<HTMLElement>('[data-disclosure-trigger]');\n\t\tconst panel = this.querySelector<HTMLElement>('[data-disclosure-panel]');\n\t\tif (!trigger || !panel) {\n\t\t\treturn;\n\t\t}\n\n\t\ttrigger.setAttribute('aria-expanded', String(this.open));\n\t\ttrigger.setAttribute('aria-controls', this.panelId);\n\t\tpanel.id = this.panelId;\n\t\tpanel.dataset.state = this.open ? 'open' : 'closed';\n\n\t\tif (this.animated) {\n\t\t\tpanel.hidden = false;\n\t\t\tpanel.setAttribute('aria-hidden', String(!this.open));\n\t\t\treturn;\n\t\t}\n\n\t\tpanel.hidden = !this.open;\n\t\tpanel.removeAttribute('aria-hidden');\n\t}\n\n\toverride render() {\n\t\treturn (\n\t\t\t<div class=\"rui-disclosure\">\n\t\t\t\t<slot name=\"trigger\"></slot>\n\t\t\t\t<slot></slot>\n\t\t\t</div>\n\t\t);\n\t}\n}\n", "import { RadiantElement, customElement, onEvent, onUpdated, prop } from '@ecopages/radiant';\nimport { applyRovingTabindex, navigateRovingTabindex } from '../../../lib/roving-tabindex';\nimport type { RuiDisclosureToggleDetail } from './disclosure.script';\nimport { RuiDisclosure } from './disclosure.script';\n\nexport type RuiDisclosureGroupProps = {\n\t/** Allow more than one disclosure to stay open. Default: `false` (exclusive). */\n\tmultiple?: boolean;\n\t/** Animate panel height for child disclosures. Default: `false`. */\n\tanimated?: boolean;\n};\n\n/**\n * `<rui-disclosure-group>` \u2014 coordinates stacked disclosures (accordion-style).\n *\n * When `multiple` is `false` (default), opening one disclosure closes the others.\n * Supports APG accordion keyboard navigation between triggers (ArrowUp/Down, Home/End)\n * and optional ArrowLeft/Right to collapse/expand the focused section.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/accordion/\n * @element rui-disclosure-group\n * @slot - `rui-disclosure` children.\n */\n@customElement('rui-disclosure-group')\nexport class RuiDisclosureGroup extends RadiantElement {\n\t@prop({ type: Boolean, reflect: true, defaultValue: false }) multiple: boolean;\n\t@prop({ type: Boolean, reflect: true, attribute: 'animated', defaultValue: false }) animated: boolean;\n\n\toverride connectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tqueueMicrotask(() => {\n\t\t\tthis.syncChildrenAnimated();\n\t\t\tthis.syncTriggers();\n\t\t});\n\t}\n\n\tprivate getTriggers(): HTMLElement[] {\n\t\treturn Array.from(this.querySelectorAll<HTMLElement>('[data-disclosure-trigger]'));\n\t}\n\n\tprivate getDisclosureForTrigger(trigger: HTMLElement): RuiDisclosure | null {\n\t\treturn trigger.closest('rui-disclosure');\n\t}\n\n\tprivate syncTriggers(): void {\n\t\tconst triggers = this.getTriggers();\n\t\tif (!triggers.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst activeIndex = Math.max(\n\t\t\t0,\n\t\t\ttriggers.findIndex((trigger) => trigger.tabIndex === 0 || trigger === document.activeElement),\n\t\t);\n\t\tapplyRovingTabindex(triggers, activeIndex);\n\t}\n\n\tprivate syncChildrenAnimated(): void {\n\t\tfor (const disclosure of this.querySelectorAll<RuiDisclosure>('rui-disclosure')) {\n\t\t\tdisclosure.animated = this.animated;\n\t\t}\n\t}\n\n\t@onUpdated('animated')\n\tonAnimatedUpdated(): void {\n\t\tthis.syncChildrenAnimated();\n\t}\n\n\t@onEvent({ selector: 'rui-disclosure', type: 'rui-disclosure-toggle' })\n\tonDisclosureToggle(event: Event): void {\n\t\tif (this.multiple) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst detail = (event as CustomEvent<RuiDisclosureToggleDetail>).detail;\n\t\tif (!detail?.open) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst source = event.target;\n\t\tif (!(source instanceof RuiDisclosure)) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const disclosure of this.querySelectorAll<RuiDisclosure>('rui-disclosure')) {\n\t\t\tif (disclosure !== source) {\n\t\t\t\tdisclosure.open = false;\n\t\t\t}\n\t\t}\n\t}\n\n\t@onEvent({ selector: '[data-disclosure-trigger]', type: 'keydown' })\n\tonTriggerKeydown(event: KeyboardEvent): void {\n\t\tconst triggers = this.getTriggers();\n\t\tconst current = (event.target as HTMLElement).closest<HTMLElement>('[data-disclosure-trigger]');\n\t\tif (!current) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Optional APG accordion: Left collapses, Right expands the focused header.\n\t\tif (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {\n\t\t\tconst disclosure = this.getDisclosureForTrigger(current);\n\t\t\tif (!disclosure) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst nextOpen = event.key === 'ArrowRight';\n\t\t\tif (disclosure.open === nextOpen) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tevent.preventDefault();\n\t\t\tdisclosure.open = nextOpen;\n\n\t\t\tif (nextOpen && !this.multiple) {\n\t\t\t\tfor (const other of this.querySelectorAll<RuiDisclosure>('rui-disclosure')) {\n\t\t\t\t\tif (other !== disclosure) {\n\t\t\t\t\t\tother.open = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst result = navigateRovingTabindex({\n\t\t\titems: triggers,\n\t\t\tcurrent,\n\t\t\tkey: event.key,\n\t\t\torientation: 'vertical',\n\t\t\twrap: true,\n\t\t});\n\n\t\tif (!result.handled) {\n\t\t\treturn;\n\t\t}\n\n\t\tevent.preventDefault();\n\t}\n\n\toverride render() {\n\t\treturn (\n\t\t\t<div class=\"rui-disclosure-group\" data-ref=\"root\">\n\t\t\t\t<slot></slot>\n\t\t\t</div>\n\t\t);\n\t}\n}\n", "export type RovingOrientation = 'horizontal' | 'vertical';\n\nexport type RovingNavResult = { handled: false } | { handled: true; index: number; item: HTMLElement };\n\n/**\n * Apply the APG roving-tabindex pattern: one item is tabbable, the rest are `-1`.\n */\nexport function applyRovingTabindex(items: HTMLElement[], activeIndex: number): void {\n\titems.forEach((item, index) => {\n\t\titem.tabIndex = index === activeIndex ? 0 : -1;\n\t});\n}\n\n/**\n * Focus `items[index]` and update tabindexes. Returns the focused item, or null.\n */\nexport function focusRovingItem(items: HTMLElement[], index: number): HTMLElement | null {\n\tif (!items.length) return null;\n\tconst next = Math.max(0, Math.min(items.length - 1, index));\n\tapplyRovingTabindex(items, next);\n\titems[next]?.focus();\n\treturn items[next] ?? null;\n}\n\nfunction deltaForKey(key: string, orientation: RovingOrientation): 'prev' | 'next' | 'first' | 'last' | null {\n\tif (key === 'Home') return 'first';\n\tif (key === 'End') return 'last';\n\n\tif (orientation === 'horizontal') {\n\t\tif (key === 'ArrowRight') return 'next';\n\t\tif (key === 'ArrowLeft') return 'prev';\n\t\treturn null;\n\t}\n\n\tif (key === 'ArrowDown') return 'next';\n\tif (key === 'ArrowUp') return 'prev';\n\treturn null;\n}\n\n/**\n * Handle arrow / Home / End navigation for a flat roving-tabindex collection.\n * Does not activate the item \u2014 callers decide whether to select on move.\n */\nexport function navigateRovingTabindex(options: {\n\titems: HTMLElement[];\n\tcurrent: HTMLElement | null;\n\tkey: string;\n\torientation?: RovingOrientation;\n\twrap?: boolean;\n}): RovingNavResult {\n\tconst { items, current, key, orientation = 'horizontal', wrap = true } = options;\n\tif (!items.length || !current) return { handled: false };\n\n\tconst index = items.indexOf(current);\n\tif (index < 0) return { handled: false };\n\n\tconst delta = deltaForKey(key, orientation);\n\tif (!delta) return { handled: false };\n\n\tlet next = index;\n\tif (delta === 'first') next = 0;\n\telse if (delta === 'last') next = items.length - 1;\n\telse if (delta === 'next') next = wrap ? (index + 1) % items.length : Math.min(items.length - 1, index + 1);\n\telse next = wrap ? (index - 1 + items.length) % items.length : Math.max(0, index - 1);\n\n\tconst item = focusRovingItem(items, next);\n\tif (!item) return { handled: false };\n\treturn { handled: true, index: next, item };\n}\n", "import type { JsxRenderable } from '@ecopages/jsx';\n\nconst RADIANT_VIEW_ELEMENT = Symbol.for('@ecopages/storybook-radiant.viewElement');\nconst RADIANT_SCRIPT_MODULE = Symbol.for('@ecopages/storybook-radiant.scriptModule');\nconst RADIANT_SCRIPT_EXPORT = Symbol.for('@ecopages/storybook-radiant.scriptExport');\n\nexport type RadiantViewComponent<TArgs = unknown> = ((args: TArgs) => JsxRenderable) & {\n\t[RADIANT_VIEW_ELEMENT]?: CustomElementConstructor;\n\t[RADIANT_SCRIPT_MODULE]?: string;\n\t[RADIANT_SCRIPT_EXPORT]?: string;\n};\n\nfunction linkViewToElement<TArgs>(\n\tview: RadiantViewComponent<TArgs>,\n\telement: CustomElementConstructor & {\n\t\t[RADIANT_SCRIPT_MODULE]?: string;\n\t\t[RADIANT_SCRIPT_EXPORT]?: string;\n\t},\n): void {\n\tview[RADIANT_VIEW_ELEMENT] = element;\n\n\tconst ssrModule = element[RADIANT_SCRIPT_MODULE];\n\tif (ssrModule) {\n\t\tview[RADIANT_SCRIPT_MODULE] = ssrModule;\n\t\tview[RADIANT_SCRIPT_EXPORT] = element[RADIANT_SCRIPT_EXPORT] ?? element.name;\n\t}\n}\n\n/** Link a JSX view export to its RadiantElement class (same symbols as the Storybook framework). */\nexport function defineRadiantView<TArgs>(\n\telement: CustomElementConstructor & {\n\t\t[RADIANT_SCRIPT_MODULE]?: string;\n\t\t[RADIANT_SCRIPT_EXPORT]?: string;\n\t},\n\trender: (args: TArgs) => JsxRenderable,\n): RadiantViewComponent<TArgs> {\n\tconst view = ((args: TArgs) => render(args)) as RadiantViewComponent<TArgs>;\n\tlinkViewToElement(view, element);\n\treturn view;\n}\n\n/** Re-copy SSR metadata from the linked element (e.g. after HMR). */\nexport function syncRadiantViewMetadata(view: RadiantViewComponent): void {\n\tconst element = view[RADIANT_VIEW_ELEMENT];\n\tif (element) {\n\t\tlinkViewToElement(view, element);\n\t}\n}\n", "import type { JsxRenderable } from '@ecopages/jsx';\nimport type { RadiantSlotProps } from '../../../types';\nimport { defineRadiantView } from '../../../lib/radiant-view';\nimport type { RuiDisclosureGroupProps } from './disclosure-group.script';\nimport { RuiDisclosureGroup as RuiDisclosureGroupElement } from './disclosure-group.script';\nimport type { RuiDisclosureProps } from './disclosure.script';\nimport { RuiDisclosure as RuiDisclosureElement } from './disclosure.script';\nimport './disclosure-group.css';\nimport './disclosure.css';\n\nfunction cx(...parts: Array<string | false | null | undefined>): string {\n\treturn parts.filter(Boolean).join(' ');\n}\n\nexport type RuiDisclosureIconProps = {\n\tvariant?: 'chevron' | 'plus';\n\tclass?: string;\n};\n\n/** Default disclosure indicator. Override via `RuiDisclosureTrigger` `icon` prop. */\nexport function RuiDisclosureIcon({ variant = 'chevron', class: className }: RuiDisclosureIconProps) {\n\treturn (\n\t\t<span\n\t\t\tclass={cx('rui-disclosure__icon', `rui-disclosure__icon--${variant}`, className)}\n\t\t\tdata-disclosure-icon\n\t\t\taria-hidden=\"true\"\n\t\t></span>\n\t);\n}\n\nexport type RuiDisclosureTriggerProps = RadiantSlotProps & {\n\tchildren: JsxRenderable;\n\tclass?: string;\n\tdisabled?: boolean;\n\t/** Custom indicator. Pass `null` to hide. Defaults to chevron. */\n\ticon?: JsxRenderable | null;\n\ticonPosition?: 'start' | 'end';\n};\n\n/** Disclosure button slotted into `trigger` by default. */\nexport function RuiDisclosureTrigger({\n\tslot = 'trigger',\n\tchildren,\n\tclass: className,\n\tdisabled,\n\ticon,\n\ticonPosition = 'start',\n}: RuiDisclosureTriggerProps) {\n\tconst showIcon = icon !== null;\n\tconst iconNode = showIcon ? (icon ?? <RuiDisclosureIcon />) : null;\n\n\treturn (\n\t\t<button\n\t\t\tslot={slot}\n\t\t\ttype=\"button\"\n\t\t\tdata-disclosure-trigger\n\t\t\tclass={cx(\n\t\t\t\t'rui-disclosure__trigger',\n\t\t\t\ticonPosition === 'end' && 'rui-disclosure__trigger--icon-end',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tdisabled={disabled}\n\t\t>\n\t\t\t{iconPosition === 'start' ? iconNode : null}\n\t\t\t<span class=\"rui-disclosure__label\">{children}</span>\n\t\t\t{iconPosition === 'end' ? iconNode : null}\n\t\t</button>\n\t);\n}\n\nexport type RuiDisclosurePanelProps = {\n\tchildren: JsxRenderable;\n\tclass?: string;\n};\n\n/** Disclosure panel in the default slot. */\nexport function RuiDisclosurePanel({ children, class: className }: RuiDisclosurePanelProps) {\n\treturn (\n\t\t<div data-disclosure-panel data-ref=\"panel\" class={cx('rui-disclosure__panel', className)}>\n\t\t\t<div class=\"rui-disclosure__panel-inner\">{children}</div>\n\t\t</div>\n\t);\n}\n\nexport const RuiDisclosure = defineRadiantView(\n\tRuiDisclosureElement,\n\t({\n\t\tslot,\n\t\topen,\n\t\tvalue,\n\t\tanimated,\n\t\ttrigger,\n\t\tchildren,\n\t}: RuiDisclosureProps &\n\t\tRadiantSlotProps & {\n\t\t\ttrigger?: JsxRenderable;\n\t\t\tchildren?: JsxRenderable;\n\t\t}) => {\n\t\tif (trigger != null) {\n\t\t\treturn (\n\t\t\t\t<rui-disclosure slot={slot} open={open} value={value} animated={animated}>\n\t\t\t\t\t<RuiDisclosureTrigger>{trigger}</RuiDisclosureTrigger>\n\t\t\t\t\t{children != null ? <RuiDisclosurePanel>{children}</RuiDisclosurePanel> : null}\n\t\t\t\t</rui-disclosure>\n\t\t\t);\n\t\t}\n\n\t\treturn (\n\t\t\t<rui-disclosure slot={slot} open={open} value={value} animated={animated}>\n\t\t\t\t{children}\n\t\t\t</rui-disclosure>\n\t\t);\n\t},\n);\n\nexport const RuiDisclosureGroup = defineRadiantView(\n\tRuiDisclosureGroupElement,\n\t({\n\t\tslot,\n\t\tmultiple,\n\t\tanimated,\n\t\tchildren,\n\t}: RuiDisclosureGroupProps & RadiantSlotProps & { children: JsxRenderable }) => (\n\t\t<rui-disclosure-group slot={slot} multiple={multiple} animated={animated}>\n\t\t\t{children}\n\t\t</rui-disclosure-group>\n\t),\n);\n"],
5
+ "mappings": "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",
6
+ "names": ["RadiantElement", "bound", "customElement", "onEvent", "onUpdated", "prop", "RuiDisclosure", "event", "next", "trigger", "panel", "RadiantElement", "customElement", "onEvent", "onUpdated", "prop", "applyRovingTabindex", "items", "activeIndex", "item", "index", "focusRovingItem", "next", "deltaForKey", "key", "orientation", "navigateRovingTabindex", "options", "current", "wrap", "delta", "RuiDisclosureGroup", "customElement", "RadiantElement", "prop", "trigger", "triggers", "activeIndex", "applyRovingTabindex", "disclosure", "onUpdated", "onEvent", "event", "source", "RuiDisclosure", "current", "nextOpen", "other", "navigateRovingTabindex", "RADIANT_VIEW_ELEMENT", "RADIANT_SCRIPT_MODULE", "RADIANT_SCRIPT_EXPORT", "linkViewToElement", "view", "element", "ssrModule", "defineRadiantView", "render", "args", "cx", "parts", "RuiDisclosureIcon", "variant", "className", "RuiDisclosureTrigger", "slot", "children", "disabled", "icon", "iconPosition", "iconNode", "RuiDisclosurePanel", "RuiDisclosure", "defineRadiantView", "open", "value", "animated", "trigger", "RuiDisclosureGroup", "multiple"]
7
+ }
@@ -0,0 +1,14 @@
1
+ @reference '../../../styles/radiant-ui.css';
2
+
3
+ rui-feed {
4
+ @apply block;
5
+ }
6
+
7
+ @layer components {
8
+ .rui-feed {
9
+ @apply flex flex-col gap-stack;
10
+ }
11
+ .rui-feed__article {
12
+ @apply rounded-container border border-border bg-background p-inset text-sm;
13
+ }
14
+ }
@@ -0,0 +1,12 @@
1
+ import type { JsxRenderable } from '@ecopages/jsx';
2
+ import type { RadiantSlotProps } from '../../../types';
3
+ import type { RuiFeedProps } from './feed.script';
4
+ import './feed.css';
5
+ export type RuiFeedArticle = {
6
+ id: string;
7
+ title: string;
8
+ children: JsxRenderable;
9
+ };
10
+ export declare const RuiFeed: import("../../../lib/radiant-view").RadiantViewComponent<RuiFeedProps & RadiantSlotProps & {
11
+ articles: RuiFeedArticle[];
12
+ }>;
@@ -0,0 +1,22 @@
1
+ import { RadiantElement } from '@ecopages/radiant';
2
+ export type RuiFeedProps = {
3
+ label?: string;
4
+ };
5
+ type RuiFeedBindings = {
6
+ label: string;
7
+ };
8
+ /**
9
+ * `<rui-feed>` — a section that can load articles as the user scrolls.
10
+ *
11
+ * Implements the APG Feed pattern shell: `role="feed"` with article children.
12
+ * Consumers own infinite-scroll loading; this host provides the landmark + labeling.
13
+ *
14
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/feed/
15
+ * @element rui-feed
16
+ */
17
+ export declare class RuiFeed extends RadiantElement<RuiFeedBindings> {
18
+ label: string;
19
+ private readonly resolvedAriaLabel;
20
+ render(): import("@ecopages/jsx").JsxRenderable;
21
+ }
22
+ export {};
@@ -0,0 +1,2 @@
1
+ export { RuiFeed as RuiFeedElement, type RuiFeedProps } from './feed.script';
2
+ export { RuiFeed, type RuiFeedArticle } from './feed';
@@ -0,0 +1,2 @@
1
+ import{RadiantElement as l,customElement as p,prop as R}from"@ecopages/radiant";var o=@p("rui-feed")class extends l{@R({type:String,defaultValue:""})label;resolvedAriaLabel=this.$.label.map(e=>e||void 0);render(){return React.createElement("div",{class:"rui-feed",role:"feed","aria-label":this.resolvedAriaLabel},React.createElement("slot",null))}};var m=Symbol.for("@ecopages/storybook-radiant.viewElement"),n=Symbol.for("@ecopages/storybook-radiant.scriptModule"),s=Symbol.for("@ecopages/storybook-radiant.scriptExport");function u(t,e){t[m]=e;let r=e[n];r&&(t[n]=r,t[s]=e[s]??e.name)}function a(t,e){let r=(i=>e(i));return u(r,t),r}import"./feed.css";var A=a(o,({slot:t,label:e,articles:r})=>React.createElement("rui-feed",{slot:t,label:e},r.map((i,d)=>React.createElement("article",{class:"rui-feed__article","aria-labelledby":`feed-${i.id}`,"aria-posinset":d+1,"aria-setsize":r.length},React.createElement("h3",{id:`feed-${i.id}`},i.title),i.children))));export{A as RuiFeed,o as RuiFeedElement};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/components/ui/feed/feed.script.tsx", "../../../../src/lib/radiant-view.ts", "../../../../src/components/ui/feed/feed.tsx"],
4
+ "sourcesContent": ["import { RadiantElement, customElement, prop } from '@ecopages/radiant';\n\nexport type RuiFeedProps = {\n\tlabel?: string;\n};\n\ntype RuiFeedBindings = {\n\tlabel: string;\n};\n\n/**\n * `<rui-feed>` \u2014 a section that can load articles as the user scrolls.\n *\n * Implements the APG Feed pattern shell: `role=\"feed\"` with article children.\n * Consumers own infinite-scroll loading; this host provides the landmark + labeling.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/feed/\n * @element rui-feed\n */\n@customElement('rui-feed')\nexport class RuiFeed extends RadiantElement<RuiFeedBindings> {\n\t@prop({ type: String, defaultValue: '' }) label: string;\n\n\tprivate readonly resolvedAriaLabel = this.$.label.map((label) => label || undefined);\n\n\toverride render() {\n\t\treturn (\n\t\t\t<div class=\"rui-feed\" role=\"feed\" aria-label={this.resolvedAriaLabel}>\n\t\t\t\t<slot></slot>\n\t\t\t</div>\n\t\t);\n\t}\n}\n", "import type { JsxRenderable } from '@ecopages/jsx';\n\nconst RADIANT_VIEW_ELEMENT = Symbol.for('@ecopages/storybook-radiant.viewElement');\nconst RADIANT_SCRIPT_MODULE = Symbol.for('@ecopages/storybook-radiant.scriptModule');\nconst RADIANT_SCRIPT_EXPORT = Symbol.for('@ecopages/storybook-radiant.scriptExport');\n\nexport type RadiantViewComponent<TArgs = unknown> = ((args: TArgs) => JsxRenderable) & {\n\t[RADIANT_VIEW_ELEMENT]?: CustomElementConstructor;\n\t[RADIANT_SCRIPT_MODULE]?: string;\n\t[RADIANT_SCRIPT_EXPORT]?: string;\n};\n\nfunction linkViewToElement<TArgs>(\n\tview: RadiantViewComponent<TArgs>,\n\telement: CustomElementConstructor & {\n\t\t[RADIANT_SCRIPT_MODULE]?: string;\n\t\t[RADIANT_SCRIPT_EXPORT]?: string;\n\t},\n): void {\n\tview[RADIANT_VIEW_ELEMENT] = element;\n\n\tconst ssrModule = element[RADIANT_SCRIPT_MODULE];\n\tif (ssrModule) {\n\t\tview[RADIANT_SCRIPT_MODULE] = ssrModule;\n\t\tview[RADIANT_SCRIPT_EXPORT] = element[RADIANT_SCRIPT_EXPORT] ?? element.name;\n\t}\n}\n\n/** Link a JSX view export to its RadiantElement class (same symbols as the Storybook framework). */\nexport function defineRadiantView<TArgs>(\n\telement: CustomElementConstructor & {\n\t\t[RADIANT_SCRIPT_MODULE]?: string;\n\t\t[RADIANT_SCRIPT_EXPORT]?: string;\n\t},\n\trender: (args: TArgs) => JsxRenderable,\n): RadiantViewComponent<TArgs> {\n\tconst view = ((args: TArgs) => render(args)) as RadiantViewComponent<TArgs>;\n\tlinkViewToElement(view, element);\n\treturn view;\n}\n\n/** Re-copy SSR metadata from the linked element (e.g. after HMR). */\nexport function syncRadiantViewMetadata(view: RadiantViewComponent): void {\n\tconst element = view[RADIANT_VIEW_ELEMENT];\n\tif (element) {\n\t\tlinkViewToElement(view, element);\n\t}\n}\n", "import type { JsxRenderable } from '@ecopages/jsx';\nimport type { RadiantSlotProps } from '../../../types';\nimport { defineRadiantView } from '../../../lib/radiant-view';\nimport type { RuiFeedProps } from './feed.script';\nimport { RuiFeed as RuiFeedElement } from './feed.script';\nimport './feed.css';\n\nexport type RuiFeedArticle = { id: string; title: string; children: JsxRenderable };\n\nexport const RuiFeed = defineRadiantView(\n\tRuiFeedElement,\n\t({ slot, label, articles }: RuiFeedProps & RadiantSlotProps & { articles: RuiFeedArticle[] }) => (\n\t\t<rui-feed slot={slot} label={label}>\n\t\t\t{articles.map((article, index) => (\n\t\t\t\t<article\n\t\t\t\t\tclass=\"rui-feed__article\"\n\t\t\t\t\taria-labelledby={`feed-${article.id}`}\n\t\t\t\t\taria-posinset={index + 1}\n\t\t\t\t\taria-setsize={articles.length}\n\t\t\t\t>\n\t\t\t\t\t<h3 id={`feed-${article.id}`}>{article.title}</h3>\n\t\t\t\t\t{article.children}\n\t\t\t\t</article>\n\t\t\t))}\n\t\t</rui-feed>\n\t),\n);\n"],
5
+ "mappings": "AAAA,OAAS,kBAAAA,EAAgB,iBAAAC,EAAe,QAAAC,MAAY,oBAoB7C,IAAMC,EADb,CAACF,EAAc,UAAU,CAClB,cAAsBD,CAAgC,CAC5D,CAACE,EAAK,CAAE,KAAM,OAAQ,aAAc,EAAG,CAAC,CAAE,MAEzB,kBAAoB,KAAK,EAAE,MAAM,IAAKE,GAAUA,GAAS,MAAS,EAE1E,QAAS,CACjB,OACC,oBAAC,OAAI,MAAM,WAAW,KAAK,OAAO,aAAY,KAAK,mBAClD,oBAAC,WAAK,CACP,CAEF,CACD,EC9BA,IAAMC,EAAuB,OAAO,IAAI,yCAAyC,EAC3EC,EAAwB,OAAO,IAAI,0CAA0C,EAC7EC,EAAwB,OAAO,IAAI,0CAA0C,EAQnF,SAASC,EACRC,EACAC,EAIO,CACPD,EAAKJ,CAAoB,EAAIK,EAE7B,IAAMC,EAAYD,EAAQJ,CAAqB,EAC3CK,IACHF,EAAKH,CAAqB,EAAIK,EAC9BF,EAAKF,CAAqB,EAAIG,EAAQH,CAAqB,GAAKG,EAAQ,KAE1E,CAGO,SAASE,EACfF,EAIAG,EAC8B,CAC9B,IAAMJ,GAASK,GAAgBD,EAAOC,CAAI,GAC1C,OAAAN,EAAkBC,EAAMC,CAAO,EACxBD,CACR,CClCA,MAAO,aAIA,IAAMM,EAAUC,EACtBD,EACA,CAAC,CAAE,KAAAE,EAAM,MAAAC,EAAO,SAAAC,CAAS,IACxB,oBAAC,YAAS,KAAMF,EAAM,MAAOC,GAC3BC,EAAS,IAAI,CAACC,EAASC,IACvB,oBAAC,WACA,MAAM,oBACN,kBAAiB,QAAQD,EAAQ,EAAE,GACnC,gBAAeC,EAAQ,EACvB,eAAcF,EAAS,QAEvB,oBAAC,MAAG,GAAI,QAAQC,EAAQ,EAAE,IAAKA,EAAQ,KAAM,EAC5CA,EAAQ,QACV,CACA,CACF,CAEF",
6
+ "names": ["RadiantElement", "customElement", "prop", "RuiFeed", "label", "RADIANT_VIEW_ELEMENT", "RADIANT_SCRIPT_MODULE", "RADIANT_SCRIPT_EXPORT", "linkViewToElement", "view", "element", "ssrModule", "defineRadiantView", "render", "args", "RuiFeed", "defineRadiantView", "slot", "label", "articles", "article", "index"]
7
+ }
@@ -0,0 +1,20 @@
1
+ import type { FieldRules } from '../form/types';
2
+ export type FieldContextValue = {
3
+ name: string;
4
+ controlId: string;
5
+ descriptionId: string;
6
+ errorId: string;
7
+ error?: string;
8
+ invalid: boolean;
9
+ required: boolean;
10
+ /**
11
+ * The field's own rules, carried across a real SSR round-trip — `prop:rules` doesn't
12
+ * survive that boundary, so `RuiField` republishes them on its own context, hydrated
13
+ * client-side from the `<script>` this provider emits. Never carries `validate`; see
14
+ * `fieldProvider`'s `serialize` option.
15
+ */
16
+ rules?: FieldRules;
17
+ };
18
+ export declare const fieldContext: {
19
+ __context__: FieldContextValue;
20
+ };
@@ -0,0 +1,8 @@
1
+ import type { JsxRenderable } from '@ecopages/jsx';
2
+ import './field.css';
3
+ export type RuiFieldDescriptionProps = {
4
+ class?: string;
5
+ children: JsxRenderable;
6
+ };
7
+ /** Helper text associated with a field via `aria-describedby`. */
8
+ export declare function RuiFieldDescription({ class: className, children }: RuiFieldDescriptionProps): JsxRenderable;
@@ -0,0 +1,9 @@
1
+ import './field.css';
2
+ export type RuiFieldErrorProps = {
3
+ class?: string;
4
+ };
5
+ /**
6
+ * Error message region for a field. Text is populated by `<rui-field>` from form validation
7
+ * or the field's `error` prop.
8
+ */
9
+ export declare function RuiFieldError({ class: className }: RuiFieldErrorProps): import("@ecopages/jsx").JsxRenderable;
@@ -0,0 +1 @@
1
+ import './field.script';
@@ -0,0 +1,26 @@
1
+ @reference '../../../styles/radiant-ui.css';
2
+
3
+ rui-field {
4
+ @apply block;
5
+ }
6
+
7
+ @layer components {
8
+ .rui-field {
9
+ @apply flex flex-col;
10
+ gap: var(--space-inline);
11
+ }
12
+
13
+ .rui-field__description {
14
+ @apply text-on-surface;
15
+ font-size: var(--text-body-sm, 0.875rem);
16
+ }
17
+
18
+ .rui-field__error {
19
+ @apply text-error;
20
+ font-size: var(--text-body-sm, 0.875rem);
21
+ }
22
+
23
+ .rui-field__error[hidden] {
24
+ display: none;
25
+ }
26
+ }
@@ -0,0 +1,4 @@
1
+ import type { WithChildren } from '../../../types';
2
+ import type { RuiFieldProps } from './field.script';
3
+ import './field.css';
4
+ export declare const RuiField: import("../../../lib/radiant-view").RadiantViewComponent<WithChildren<RuiFieldProps>>;
@@ -0,0 +1,68 @@
1
+ import { RadiantElement } from '@ecopages/radiant';
2
+ import type { ContextProvider } from '@ecopages/radiant/context';
3
+ import { type FormContextValue } from '../form/form-context';
4
+ import { fieldContext } from './field-context';
5
+ import type { FieldRules } from '../form/types';
6
+ export type RuiFieldProps = {
7
+ name: string;
8
+ rules?: FieldRules;
9
+ defaultValue?: unknown;
10
+ defaultValueData?: string;
11
+ disabled?: boolean;
12
+ /** Standalone error message when not using a form provider. */
13
+ error?: string;
14
+ /** Standalone invalid flag when not using a form provider. */
15
+ invalid?: boolean;
16
+ };
17
+ /**
18
+ * `<rui-field>` — connector between slotted controls and an ancestor `<rui-form>`.
19
+ *
20
+ * Registers with the form via {@link formContext} actions, forwards control events,
21
+ * and applies presentation (errors, ARIA) from the form-published `fields` map.
22
+ *
23
+ * @element rui-field
24
+ */
25
+ export declare class RuiField extends RadiantElement {
26
+ name: string;
27
+ rules?: FieldRules;
28
+ defaultValue?: unknown;
29
+ defaultValueData?: string;
30
+ disabled: boolean;
31
+ error: string;
32
+ invalid: boolean;
33
+ fieldProvider: ContextProvider<typeof fieldContext>;
34
+ private formContextProvider?;
35
+ private uid;
36
+ /** Resolved field name from property or `name` attribute (Storybook can hydrate props after connect). */
37
+ private resolveFieldName;
38
+ private unregister?;
39
+ private unregisterPresentation?;
40
+ private registeredWithForm;
41
+ constructor();
42
+ connectedCallback(): void;
43
+ disconnectedCallback(): void;
44
+ private get currentFormContext();
45
+ private parseJsonAttr;
46
+ /**
47
+ * Prefers the live `rules` prop — it's the only channel that can carry a `validate`
48
+ * function. Falls back to `fieldProvider`'s own context, which only ever holds the
49
+ * JSON-safe subset (see its `serialize` option) — this is what recovers rules after a
50
+ * real SSR hydrate, since `prop:rules` itself doesn't survive that boundary.
51
+ */
52
+ private readFieldRules;
53
+ private readDefaultValue;
54
+ private isRequired;
55
+ private resolveErrorMessage;
56
+ private resolveInvalid;
57
+ private connectToForm;
58
+ onFormContextChanged(ctx: FormContextValue): void;
59
+ onNameUpdated(): void;
60
+ onRulesUpdated(): void;
61
+ onPresentationUpdated(): void;
62
+ onControlChange(): void;
63
+ onControlInput(): void;
64
+ onControlNativeChange(): void;
65
+ onControlFocusOut(): void;
66
+ private syncField;
67
+ render(): import("@ecopages/jsx").JsxRenderable;
68
+ }
@@ -0,0 +1,5 @@
1
+ export { RuiField } from './field';
2
+ export { RuiField as RuiFieldElement, type RuiFieldProps } from './field.script';
3
+ export { RuiFieldDescription } from './field-description';
4
+ export { RuiFieldError } from './field-error';
5
+ export { fieldContext, type FieldContextValue } from './field-context';
@@ -0,0 +1,2 @@
1
+ var J=Symbol.for("@ecopages/storybook-radiant.viewElement"),H=Symbol.for("@ecopages/storybook-radiant.scriptModule"),_=Symbol.for("@ecopages/storybook-radiant.scriptExport");function X(e,t){e[J]=t;let r=t[H];r&&(e[H]=r,e[_]=t[_]??t.name)}function N(e,t){let r=(i=>t(i));return X(r,e),r}import{RadiantElement as Z,customElement as ee,onEvent as E,onUpdated as C,prop as c,registerSsrPreparationCallback as te}from"@ecopages/radiant";import{consumeContext as re,onContextUpdate as ie,provideContext as ne}from"@ecopages/radiant/context";var m="data-rui-control",V="data-rui-field-managed",G="data-rui-field-label",g="data-rui-field-description",f="data-rui-field-error",F="data-default-value";var h=new Set(["rui-combobox","rui-checkbox","rui-switch","rui-radio-group","rui-slider","rui-spinbutton","rui-listbox"]),P=`[${m}], ${Array.from(h).join(", ")}, input, textarea`;function D(e,t){let r=e,i=new Set,n=o=>{i.has(o)||(i.add(o),t(o))};if(typeof r.getSlotElements=="function")for(let o of r.getSlotElements())n(o);let l=e.querySelector(".rui-field")??e;for(let o of Array.from(l.children))n(o);for(let o of l.querySelectorAll("*"))n(o);for(let o of Array.from(e.children))n(o);let s=e.shadowRoot;if(s)for(let o of Array.from(s.children))n(o)}function x(e,t){let r=null;return D(e,i=>{if(!(r||!(i instanceof HTMLElement))){if(i.matches(t)){r=i;return}r=i.querySelector(t)}}),r}function z(e){if(e.length===0)return null;if(e.length===1)return e[0];let t=document.activeElement;if(t instanceof HTMLElement){for(let n of e)if(n===t||n.contains(t))return n}let r=e.filter(n=>n.isConnected&&n.getClientRects().length>0&&!n.closest('[hidden],[aria-hidden="true"]')),i=r.length>0?r:e.filter(n=>n.isConnected);return i[i.length-1]??e[e.length-1]}function K(e){let t=e.querySelector(".rui-field");return t instanceof HTMLElement?Array.from(t.querySelectorAll(P)).filter(r=>e.contains(r)):[]}function T(e){let t=z(K(e));if(t)return t;let r=null;if(D(e,n=>{if(r)return;let l=S(n);l&&(r=l)}),r)return r;let i=e.querySelector(".rui-field")??e;return S(i)}function S(e){return e instanceof HTMLElement?e.matches(`[${m}]`)||h.has(e.localName)||e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement?e:e.querySelector(P):null}function k(e){if(e instanceof HTMLInputElement)return e.type==="checkbox"?e.checked:e.type==="number"||e.type==="range"?e.value===""?"":Number(e.value):e.value;if(e instanceof HTMLTextAreaElement)return e.value;let t=q(e);if(t.localName==="rui-checkbox"||t.localName==="rui-switch"){let r=t.querySelector('input[type="checkbox"]');return r?r.checked:t.hasAttribute("checked")}if(t.localName==="rui-combobox"||t.localName==="rui-radio-group"||t.localName==="rui-listbox")return t.value??t.getAttribute("value")??"";if(t.localName==="rui-slider"||t.localName==="rui-spinbutton"){let r=t.value;if(typeof r=="number")return r;let i=t.getAttribute("value");return i==null||i===""?"":Number(i)}return t.getAttribute("value")??""}function O(e,t){if(e instanceof HTMLInputElement){if(e.type==="checkbox"){e.checked=!!t;let i=e.closest("rui-checkbox, rui-switch");i&&(t?i.setAttribute("checked",""):i.removeAttribute("checked"));return}e.value=t==null?"":String(t);return}if(e instanceof HTMLTextAreaElement){e.value=t==null?"":String(t);return}let r=q(e);if(r.localName==="rui-checkbox"||r.localName==="rui-switch"){t?r.setAttribute("checked",""):r.removeAttribute("checked");return}r.setAttribute("value",t==null?"":String(t))}function q(e){return e.hasAttribute(m)?e.closest(Array.from(h).join(","))??e:e}function w(e){return x(e,`[${G}], label.rui-label`)}function U(e){return x(e,`[${g}]`)}function j(e){return R(e)[0]??null}function R(e){let t=e.querySelector(".rui-field");if(t instanceof HTMLElement){let n=Array.from(t.querySelectorAll(`[${f}]`)),l=n.filter(s=>s.getClientRects().length>0);if(l.length>0)return l;if(n.length>0)return n}let r=Array.from(e.querySelectorAll(`[${f}]`));if(r.length>0)return r;let i=x(e,`[${f}]`);return i?[i]:[]}function $(e,t,r){r&&((t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement)&&(t.name=r),e&&e!==t&&h.has(e.localName)&&e.setAttribute("name",r))}function B(e){if(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e.hasAttribute(m))return e;let t=e.querySelector(`[${m}]`);if(t)return t;if(e.localName==="rui-combobox")return e.querySelector("[data-combobox-input]")??e;if(e.localName==="rui-spinbutton")return e.querySelector("[data-spinbutton-input], input")??e;if(e.localName==="rui-slider")return e.querySelector('input[type="range"]')??e;if(e.localName==="rui-checkbox"||e.localName==="rui-switch")return e.querySelector("input")??e;if(e.localName==="rui-radio-group"){let r=e.querySelector('input[type="radio"]:checked'),i=e.querySelector('input[type="radio"]');return r??i??e}return e}import{createContext as Q}from"@ecopages/radiant/context";var b=Q(Symbol.for("rui-form-context"));import{createContext as Y}from"@ecopages/radiant/context";var v=Y(Symbol.for("rui-field-context"));function oe(e){if(!e)return;let{validate:t,...r}=e;return r}var p=@ee("rui-field")class extends Z{@c({type:String,reflect:!0,defaultValue:""})name;@c({type:Object})rules;@c({type:Object})defaultValue;@c({type:String,attribute:F})defaultValueData;@c({type:Boolean,reflect:!0,defaultValue:!1})disabled;@c({type:String,defaultValue:""})error;@c({type:Boolean,reflect:!0,defaultValue:!1})invalid;@ne({context:v,initialValue:{name:"",controlId:"",descriptionId:"",errorId:"",error:void 0,invalid:!1,required:!1},hydrate:Object,serialize:t=>({...t,rules:oe(t.rules)})})fieldProvider;@re(b)formContextProvider;uid=Math.random().toString(36).slice(2,9);resolveFieldName(){return(this.name||this.getAttribute("name")||"").trim()}unregister;unregisterPresentation;registeredWithForm=!1;constructor(){super(),te(this,()=>this.fieldProvider.setContext({rules:this.readFieldRules()}))}connectedCallback(){super.connectedCallback(),this.connectToForm(),queueMicrotask(()=>{this.connectToForm()})}disconnectedCallback(){this.unregister?.(),this.unregister=void 0,this.unregisterPresentation?.(),this.unregisterPresentation=void 0,this.registeredWithForm=!1,super.disconnectedCallback()}get currentFormContext(){return this.formContextProvider?.getContext()}parseJsonAttr(t){if(t)try{return JSON.parse(t)}catch{return}}readFieldRules(){let t=this.rules;return t&&typeof t=="object"&&!Array.isArray(t)&&Object.keys(t).length>0?t:this.fieldProvider.getContext()?.rules}readDefaultValue(){return this.defaultValue!==void 0?this.defaultValue:this.parseJsonAttr(this.defaultValueData??this.getAttribute(F))}isRequired(){return!!this.readFieldRules()?.required}resolveErrorMessage(t){if(this.error)return this.error;let r=this.resolveFieldName();return r?(t??this.currentFormContext)?.fields[r]?.error:void 0}resolveInvalid(t){if(this.invalid||this.error)return!0;let r=this.resolveFieldName();return r?(t??this.currentFormContext)?.fields[r]?.invalid??!1:!1}connectToForm(){let t=this.resolveFieldName(),r=this.currentFormContext,i=r?.actions;if(!r?.ready||!i||!t){this.syncField();return}if(!this.registeredWithForm){this.registeredWithForm=!0,this.unregisterPresentation?.(),this.unregisterPresentation=i.subscribePresentation(n=>this.syncField(n)),this.unregister=i.register({name:t,rules:this.readFieldRules(),getRules:()=>this.readFieldRules(),defaultValue:this.readDefaultValue(),getValue:()=>{let n=T(this);return n?k(n):void 0},setValue:n=>{let l=T(this);l&&O(l,n)}});return}i.updateFieldOptions(t,{rules:this.readFieldRules(),defaultValue:this.readDefaultValue()}),this.syncField()}@ie({context:b,requestUpdate:!1})onFormContextChanged(t){if(!this.registeredWithForm){t.ready?this.connectToForm():this.syncField(t);return}this.syncField(t)}@C(["name"])onNameUpdated(){this.unregister?.(),this.unregister=void 0,this.unregisterPresentation?.(),this.unregisterPresentation=void 0,this.registeredWithForm=!1,this.connectToForm()}@C(["rules","defaultValue","defaultValueData"])onRulesUpdated(){this.connectToForm()}@C(["disabled","error","invalid"])onPresentationUpdated(){this.syncField()}@E({selector:"[data-rui-control], rui-combobox, rui-checkbox, rui-switch, rui-radio-group, rui-slider, rui-spinbutton, rui-listbox",type:"rui-change"})onControlChange(){let t=this.resolveFieldName();t&&this.currentFormContext?.actions.handleFieldChange(t)}@E({selector:"[data-rui-control], input, textarea",type:"input",options:{capture:!0}})onControlInput(){let t=this.resolveFieldName();t&&this.currentFormContext?.actions.handleFieldChange(t)}@E({selector:"[data-rui-control], input, textarea",type:"change",options:{capture:!0}})onControlNativeChange(){let t=this.resolveFieldName();t&&this.currentFormContext?.actions.handleFieldChange(t)}@E({selector:"[data-rui-control], input, textarea",type:"focusout"})onControlFocusOut(){let t=this.resolveFieldName();t&&this.currentFormContext?.actions.handleFieldBlur(t)}syncField(t){let r=T(this),i=r?B(r):null,n=i?.id||`rui-field-control-${this.uid}`,l=`rui-field-desc-${this.uid}`,s=`rui-field-error-${this.uid}`,o=this.resolveErrorMessage(t),y=this.resolveInvalid(t),W=this.isRequired(),A=this.resolveFieldName();if($(r,i,A),i){i.id||(i.id=n),i.setAttribute(V,""),i.setAttribute("aria-invalid",y?"true":"false"),this.isRequired()?i.setAttribute("aria-required","true"):i.removeAttribute("aria-required");let u=[],M=U(this);M&&(M.id=l,u.push(l));let I=j(this);I&&(I.id=s,o&&u.push(s)),u.length>0?i.setAttribute("aria-describedby",u.join(" ")):i.removeAttribute("aria-describedby"),this.disabled&&(i.setAttribute("aria-disabled","true"),(i instanceof HTMLInputElement||i instanceof HTMLTextAreaElement)&&(i.disabled=!0))}let L=w(this);L&&i&&(L.htmlFor=i.id);for(let u of R(this))u.textContent=o??"",o?(u.hidden=!1,u.removeAttribute("hidden")):u.hidden=!0;let a={name:A,controlId:i?.id??n,descriptionId:l,errorId:s,error:o,invalid:y,required:W},d=this.fieldProvider.getContext();d.name===a.name&&d.controlId===a.controlId&&d.descriptionId===a.descriptionId&&d.errorId===a.errorId&&d.error===a.error&&d.invalid===a.invalid&&d.required===a.required||this.fieldProvider.setContext(a)}render(){return React.createElement("div",{class:"rui-field"},React.createElement("slot",null))}};import"./field.css";var le=N(p,({name:e,rules:t,defaultValue:r,defaultValueData:i,disabled:n,error:l,invalid:s,children:o})=>React.createElement("rui-field",{name:e,"prop:rules":t,"prop:defaultValue":r,disabled:n,error:l,invalid:s,"attr:data-default-value":i??(r!==void 0?JSON.stringify(r):void 0)},o));import"./field.css";function se({class:e,children:t}){return React.createElement("p",{[g]:"",class:["rui-field__description",e].filter(Boolean).join(" ")},t)}import"./field.css";function ue({class:e}){return React.createElement("p",{[f]:"",class:["rui-field__error",e].filter(Boolean).join(" "),role:"alert",hidden:!0})}export{le as RuiField,se as RuiFieldDescription,p as RuiFieldElement,ue as RuiFieldError,v as fieldContext};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/lib/radiant-view.ts", "../../../../src/components/ui/field/field.script.tsx", "../../../../src/components/ui/form/control-protocol.ts", "../../../../src/components/ui/form/form-context.ts", "../../../../src/components/ui/field/field-context.ts", "../../../../src/components/ui/field/field.tsx", "../../../../src/components/ui/field/field-description.tsx", "../../../../src/components/ui/field/field-error.tsx"],
4
+ "sourcesContent": ["import type { JsxRenderable } from '@ecopages/jsx';\n\nconst RADIANT_VIEW_ELEMENT = Symbol.for('@ecopages/storybook-radiant.viewElement');\nconst RADIANT_SCRIPT_MODULE = Symbol.for('@ecopages/storybook-radiant.scriptModule');\nconst RADIANT_SCRIPT_EXPORT = Symbol.for('@ecopages/storybook-radiant.scriptExport');\n\nexport type RadiantViewComponent<TArgs = unknown> = ((args: TArgs) => JsxRenderable) & {\n\t[RADIANT_VIEW_ELEMENT]?: CustomElementConstructor;\n\t[RADIANT_SCRIPT_MODULE]?: string;\n\t[RADIANT_SCRIPT_EXPORT]?: string;\n};\n\nfunction linkViewToElement<TArgs>(\n\tview: RadiantViewComponent<TArgs>,\n\telement: CustomElementConstructor & {\n\t\t[RADIANT_SCRIPT_MODULE]?: string;\n\t\t[RADIANT_SCRIPT_EXPORT]?: string;\n\t},\n): void {\n\tview[RADIANT_VIEW_ELEMENT] = element;\n\n\tconst ssrModule = element[RADIANT_SCRIPT_MODULE];\n\tif (ssrModule) {\n\t\tview[RADIANT_SCRIPT_MODULE] = ssrModule;\n\t\tview[RADIANT_SCRIPT_EXPORT] = element[RADIANT_SCRIPT_EXPORT] ?? element.name;\n\t}\n}\n\n/** Link a JSX view export to its RadiantElement class (same symbols as the Storybook framework). */\nexport function defineRadiantView<TArgs>(\n\telement: CustomElementConstructor & {\n\t\t[RADIANT_SCRIPT_MODULE]?: string;\n\t\t[RADIANT_SCRIPT_EXPORT]?: string;\n\t},\n\trender: (args: TArgs) => JsxRenderable,\n): RadiantViewComponent<TArgs> {\n\tconst view = ((args: TArgs) => render(args)) as RadiantViewComponent<TArgs>;\n\tlinkViewToElement(view, element);\n\treturn view;\n}\n\n/** Re-copy SSR metadata from the linked element (e.g. after HMR). */\nexport function syncRadiantViewMetadata(view: RadiantViewComponent): void {\n\tconst element = view[RADIANT_VIEW_ELEMENT];\n\tif (element) {\n\t\tlinkViewToElement(view, element);\n\t}\n}\n", "import {\n\tRadiantElement,\n\tcustomElement,\n\tonEvent,\n\tonUpdated,\n\tprop,\n\tregisterSsrPreparationCallback,\n} from '@ecopages/radiant';\nimport { consumeContext, onContextUpdate, provideContext } from '@ecopages/radiant/context';\nimport type { ContextProvider } from '@ecopages/radiant/context';\nimport {\n\tfindFieldControl,\n\tfindFieldDescription,\n\tfindFieldError,\n\tfindFieldErrorElements,\n\tfindFieldLabel,\n\tgetAriaControlTarget,\n\treadControlValue,\n\tRUI_FIELD_DEFAULT_VALUE_ATTR,\n\tRUI_FIELD_MANAGED_ATTR,\n\twriteControlValue,\n\twireFieldControlName,\n} from '../form/control-protocol';\nimport { formContext, type FormContextValue } from '../form/form-context';\nimport { fieldContext } from './field-context';\nimport type { FieldRules } from '../form/types';\n\n/**\n * The JSON-safe subset of `FieldRules` for SSR hydration \u2014 a `validate` function can't\n * survive serialization and is dropped, same as any function crossing that boundary.\n */\nfunction stripValidate(rules: FieldRules | undefined): Omit<FieldRules, 'validate'> | undefined {\n\tif (!rules) {\n\t\treturn undefined;\n\t}\n\tconst { validate: _validate, ...serializable } = rules;\n\treturn serializable;\n}\n\nexport type RuiFieldProps = {\n\tname: string;\n\trules?: FieldRules;\n\tdefaultValue?: unknown;\n\tdefaultValueData?: string;\n\tdisabled?: boolean;\n\t/** Standalone error message when not using a form provider. */\n\terror?: string;\n\t/** Standalone invalid flag when not using a form provider. */\n\tinvalid?: boolean;\n};\n\n/**\n * `<rui-field>` \u2014 connector between slotted controls and an ancestor `<rui-form>`.\n *\n * Registers with the form via {@link formContext} actions, forwards control events,\n * and applies presentation (errors, ARIA) from the form-published `fields` map.\n *\n * @element rui-field\n */\n@customElement('rui-field')\nexport class RuiField extends RadiantElement {\n\t@prop({ type: String, reflect: true, defaultValue: '' }) name: string;\n\t@prop({ type: Object }) rules?: FieldRules;\n\t@prop({ type: Object }) defaultValue?: unknown;\n\t@prop({ type: String, attribute: RUI_FIELD_DEFAULT_VALUE_ATTR }) defaultValueData?: string;\n\t@prop({ type: Boolean, reflect: true, defaultValue: false }) disabled: boolean;\n\t@prop({ type: String, defaultValue: '' }) error: string;\n\t@prop({ type: Boolean, reflect: true, defaultValue: false }) invalid: boolean;\n\n\t@provideContext({\n\t\tcontext: fieldContext,\n\t\tinitialValue: {\n\t\t\tname: '',\n\t\t\tcontrolId: '',\n\t\t\tdescriptionId: '',\n\t\t\terrorId: '',\n\t\t\terror: undefined,\n\t\t\tinvalid: false,\n\t\t\trequired: false,\n\t\t},\n\t\thydrate: Object,\n\t\tserialize: (value) => ({ ...value, rules: stripValidate(value.rules) }),\n\t})\n\tfieldProvider: ContextProvider<typeof fieldContext>;\n\n\t@consumeContext(formContext)\n\tprivate formContextProvider?: ContextProvider<typeof formContext>;\n\n\tprivate uid = Math.random().toString(36).slice(2, 9);\n\t/** Resolved field name from property or `name` attribute (Storybook can hydrate props after connect). */\n\tprivate resolveFieldName(): string {\n\t\treturn (this.name || this.getAttribute('name') || '').trim();\n\t}\n\n\tprivate unregister?: () => void;\n\tprivate unregisterPresentation?: () => void;\n\tprivate registeredWithForm = false;\n\n\tconstructor() {\n\t\tsuper();\n\t\t// connectedCallback never runs during real SSR rendering \u2014 only this SSR-prep\n\t\t// lifecycle does, and only after `prop:rules` has already been applied to the\n\t\t// instance. Publishing rules onto fieldProvider here is what lets a hydrated field\n\t\t// recover them after a real SSR round-trip, since `prop:rules` itself doesn't\n\t\t// survive that boundary.\n\t\tregisterSsrPreparationCallback(this, () => this.fieldProvider.setContext({ rules: this.readFieldRules() }));\n\t}\n\n\toverride connectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tthis.connectToForm();\n\t\tqueueMicrotask(() => {\n\t\t\tthis.connectToForm();\n\t\t});\n\t}\n\n\toverride disconnectedCallback(): void {\n\t\tthis.unregister?.();\n\t\tthis.unregister = undefined;\n\t\tthis.unregisterPresentation?.();\n\t\tthis.unregisterPresentation = undefined;\n\t\tthis.registeredWithForm = false;\n\t\tsuper.disconnectedCallback();\n\t}\n\n\tprivate get currentFormContext(): FormContextValue | undefined {\n\t\treturn this.formContextProvider?.getContext();\n\t}\n\n\tprivate parseJsonAttr(raw: string | null | undefined): unknown {\n\t\tif (!raw) {\n\t\t\treturn undefined;\n\t\t}\n\t\ttry {\n\t\t\treturn JSON.parse(raw);\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Prefers the live `rules` prop \u2014 it's the only channel that can carry a `validate`\n\t * function. Falls back to `fieldProvider`'s own context, which only ever holds the\n\t * JSON-safe subset (see its `serialize` option) \u2014 this is what recovers rules after a\n\t * real SSR hydrate, since `prop:rules` itself doesn't survive that boundary.\n\t */\n\tprivate readFieldRules(): FieldRules | undefined {\n\t\tconst rules = this.rules;\n\t\tif (rules && typeof rules === 'object' && !Array.isArray(rules) && Object.keys(rules).length > 0) {\n\t\t\treturn rules;\n\t\t}\n\t\treturn this.fieldProvider.getContext()?.rules;\n\t}\n\n\tprivate readDefaultValue(): unknown {\n\t\tif (this.defaultValue !== undefined) {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\treturn this.parseJsonAttr(this.defaultValueData ?? this.getAttribute(RUI_FIELD_DEFAULT_VALUE_ATTR));\n\t}\n\n\tprivate isRequired(): boolean {\n\t\treturn Boolean(this.readFieldRules()?.required);\n\t}\n\n\tprivate resolveErrorMessage(formCtx?: FormContextValue): string | undefined {\n\t\tif (this.error) {\n\t\t\treturn this.error;\n\t\t}\n\t\tconst fieldName = this.resolveFieldName();\n\t\tif (!fieldName) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst ctx = formCtx ?? this.currentFormContext;\n\t\treturn ctx?.fields[fieldName]?.error;\n\t}\n\n\tprivate resolveInvalid(formCtx?: FormContextValue): boolean {\n\t\tif (this.invalid) {\n\t\t\treturn true;\n\t\t}\n\t\tif (this.error) {\n\t\t\treturn true;\n\t\t}\n\t\tconst fieldName = this.resolveFieldName();\n\t\tif (!fieldName) {\n\t\t\treturn false;\n\t\t}\n\t\tconst ctx = formCtx ?? this.currentFormContext;\n\t\treturn ctx?.fields[fieldName]?.invalid ?? false;\n\t}\n\n\tprivate connectToForm(): void {\n\t\tconst fieldName = this.resolveFieldName();\n\t\tconst ctx = this.currentFormContext;\n\t\tconst actions = ctx?.actions;\n\t\tif (!ctx?.ready || !actions || !fieldName) {\n\t\t\tthis.syncField();\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.registeredWithForm) {\n\t\t\tthis.registeredWithForm = true;\n\t\t\tthis.unregisterPresentation?.();\n\t\t\tthis.unregisterPresentation = actions.subscribePresentation((ctx) => this.syncField(ctx));\n\t\t\tthis.unregister = actions.register({\n\t\t\t\tname: fieldName,\n\t\t\t\trules: this.readFieldRules(),\n\t\t\t\tgetRules: () => this.readFieldRules(),\n\t\t\t\tdefaultValue: this.readDefaultValue(),\n\t\t\t\tgetValue: () => {\n\t\t\t\t\tconst control = findFieldControl(this);\n\t\t\t\t\treturn control ? readControlValue(control) : undefined;\n\t\t\t\t},\n\t\t\t\tsetValue: (value) => {\n\t\t\t\t\tconst control = findFieldControl(this);\n\t\t\t\t\tif (control) {\n\t\t\t\t\t\twriteControlValue(control, value);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tactions.updateFieldOptions(fieldName, {\n\t\t\trules: this.readFieldRules(),\n\t\t\tdefaultValue: this.readDefaultValue(),\n\t\t});\n\t\tthis.syncField();\n\t}\n\n\t@onContextUpdate({ context: formContext, requestUpdate: false })\n\tonFormContextChanged(ctx: FormContextValue): void {\n\t\tif (!this.registeredWithForm) {\n\t\t\tif (ctx.ready) {\n\t\t\t\tthis.connectToForm();\n\t\t\t} else {\n\t\t\t\tthis.syncField(ctx);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.syncField(ctx);\n\t}\n\n\t@onUpdated(['name'])\n\tonNameUpdated(): void {\n\t\tthis.unregister?.();\n\t\tthis.unregister = undefined;\n\t\tthis.unregisterPresentation?.();\n\t\tthis.unregisterPresentation = undefined;\n\t\tthis.registeredWithForm = false;\n\t\tthis.connectToForm();\n\t}\n\n\t@onUpdated(['rules', 'defaultValue', 'defaultValueData'])\n\tonRulesUpdated(): void {\n\t\tthis.connectToForm();\n\t}\n\n\t@onUpdated(['disabled', 'error', 'invalid'])\n\tonPresentationUpdated(): void {\n\t\tthis.syncField();\n\t}\n\n\t@onEvent({\n\t\tselector:\n\t\t\t'[data-rui-control], rui-combobox, rui-checkbox, rui-switch, rui-radio-group, rui-slider, rui-spinbutton, rui-listbox',\n\t\ttype: 'rui-change',\n\t})\n\tonControlChange(): void {\n\t\tconst fieldName = this.resolveFieldName();\n\t\tif (fieldName) {\n\t\t\tthis.currentFormContext?.actions.handleFieldChange(fieldName);\n\t\t}\n\t}\n\n\t@onEvent({\n\t\tselector: '[data-rui-control], input, textarea',\n\t\ttype: 'input',\n\t\toptions: { capture: true },\n\t})\n\tonControlInput(): void {\n\t\tconst fieldName = this.resolveFieldName();\n\t\tif (fieldName) {\n\t\t\tthis.currentFormContext?.actions.handleFieldChange(fieldName);\n\t\t}\n\t}\n\n\t@onEvent({\n\t\tselector: '[data-rui-control], input, textarea',\n\t\ttype: 'change',\n\t\toptions: { capture: true },\n\t})\n\tonControlNativeChange(): void {\n\t\tconst fieldName = this.resolveFieldName();\n\t\tif (fieldName) {\n\t\t\tthis.currentFormContext?.actions.handleFieldChange(fieldName);\n\t\t}\n\t}\n\n\t@onEvent({ selector: '[data-rui-control], input, textarea', type: 'focusout' })\n\tonControlFocusOut(): void {\n\t\tconst fieldName = this.resolveFieldName();\n\t\tif (fieldName) {\n\t\t\tthis.currentFormContext?.actions.handleFieldBlur(fieldName);\n\t\t}\n\t}\n\n\tprivate syncField(formCtx?: FormContextValue): void {\n\t\tconst controlHost = findFieldControl(this);\n\t\tconst ariaTarget = controlHost ? getAriaControlTarget(controlHost) : null;\n\t\tconst controlId = ariaTarget?.id || `rui-field-control-${this.uid}`;\n\t\tconst descriptionId = `rui-field-desc-${this.uid}`;\n\t\tconst errorId = `rui-field-error-${this.uid}`;\n\t\tconst errorMessage = this.resolveErrorMessage(formCtx);\n\t\tconst invalid = this.resolveInvalid(formCtx);\n\t\tconst required = this.isRequired();\n\n\t\tconst fieldName = this.resolveFieldName();\n\t\twireFieldControlName(controlHost, ariaTarget, fieldName);\n\n\t\tif (ariaTarget) {\n\t\t\tif (!ariaTarget.id) {\n\t\t\t\tariaTarget.id = controlId;\n\t\t\t}\n\t\t\tariaTarget.setAttribute(RUI_FIELD_MANAGED_ATTR, '');\n\t\t\tariaTarget.setAttribute('aria-invalid', invalid ? 'true' : 'false');\n\t\t\tif (this.isRequired()) {\n\t\t\t\tariaTarget.setAttribute('aria-required', 'true');\n\t\t\t} else {\n\t\t\t\tariaTarget.removeAttribute('aria-required');\n\t\t\t}\n\n\t\t\tconst describedBy: string[] = [];\n\t\t\tconst description = findFieldDescription(this);\n\t\t\tif (description) {\n\t\t\t\tdescription.id = descriptionId;\n\t\t\t\tdescribedBy.push(descriptionId);\n\t\t\t}\n\t\t\tconst errorEl = findFieldError(this);\n\t\t\tif (errorEl) {\n\t\t\t\terrorEl.id = errorId;\n\t\t\t\tif (errorMessage) {\n\t\t\t\t\tdescribedBy.push(errorId);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (describedBy.length > 0) {\n\t\t\t\tariaTarget.setAttribute('aria-describedby', describedBy.join(' '));\n\t\t\t} else {\n\t\t\t\tariaTarget.removeAttribute('aria-describedby');\n\t\t\t}\n\n\t\t\tif (this.disabled) {\n\t\t\t\tariaTarget.setAttribute('aria-disabled', 'true');\n\t\t\t\tif (ariaTarget instanceof HTMLInputElement || ariaTarget instanceof HTMLTextAreaElement) {\n\t\t\t\t\tariaTarget.disabled = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst label = findFieldLabel(this);\n\t\tif (label && ariaTarget) {\n\t\t\tlabel.htmlFor = ariaTarget.id;\n\t\t}\n\n\t\tfor (const errorEl of findFieldErrorElements(this)) {\n\t\t\terrorEl.textContent = errorMessage ?? '';\n\t\t\tif (errorMessage) {\n\t\t\t\terrorEl.hidden = false;\n\t\t\t\terrorEl.removeAttribute('hidden');\n\t\t\t} else {\n\t\t\t\terrorEl.hidden = true;\n\t\t\t}\n\t\t}\n\n\t\tconst nextFieldContext = {\n\t\t\tname: fieldName,\n\t\t\tcontrolId: ariaTarget?.id ?? controlId,\n\t\t\tdescriptionId,\n\t\t\terrorId,\n\t\t\terror: errorMessage,\n\t\t\tinvalid,\n\t\t\trequired,\n\t\t};\n\t\tconst prev = this.fieldProvider.getContext();\n\t\tif (\n\t\t\tprev.name === nextFieldContext.name &&\n\t\t\tprev.controlId === nextFieldContext.controlId &&\n\t\t\tprev.descriptionId === nextFieldContext.descriptionId &&\n\t\t\tprev.errorId === nextFieldContext.errorId &&\n\t\t\tprev.error === nextFieldContext.error &&\n\t\t\tprev.invalid === nextFieldContext.invalid &&\n\t\t\tprev.required === nextFieldContext.required\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.fieldProvider.setContext(nextFieldContext);\n\t}\n\n\toverride render() {\n\t\treturn (\n\t\t\t<div class=\"rui-field\">\n\t\t\t\t<slot></slot>\n\t\t\t</div>\n\t\t);\n\t}\n}\n", "export const RUI_CONTROL_ATTR = 'data-rui-control';\nexport const RUI_FIELD_MANAGED_ATTR = 'data-rui-field-managed';\nexport const RUI_FIELD_LABEL_ATTR = 'data-rui-field-label';\nexport const RUI_FIELD_DESCRIPTION_ATTR = 'data-rui-field-description';\nexport const RUI_FIELD_ERROR_ATTR = 'data-rui-field-error';\nexport const RUI_FIELD_DEFAULT_VALUE_ATTR = 'data-default-value';\nexport const RUI_FORM_DEFAULT_VALUES_ATTR = 'data-default-values';\n\nconst HOST_CONTROL_TAGS = new Set([\n\t'rui-combobox',\n\t'rui-checkbox',\n\t'rui-switch',\n\t'rui-radio-group',\n\t'rui-slider',\n\t'rui-spinbutton',\n\t'rui-listbox',\n]);\n\nconst CONTROL_SELECTOR = `[${RUI_CONTROL_ATTR}], ${Array.from(HOST_CONTROL_TAGS).join(', ')}, input, textarea`;\n\ntype FieldSlotHost = HTMLElement & { getSlotElements?: (name?: string) => Element[] };\n\n/** Radiant slot projection moves authored children into the render tree; search projected nodes first. */\nfunction forEachFieldContentNode(root: HTMLElement, visit: (node: Element) => void): void {\n\tconst slotHost = root as FieldSlotHost;\n\tconst visited = new Set<Element>();\n\tconst safeVisit = (node: Element) => {\n\t\tif (visited.has(node)) {\n\t\t\treturn;\n\t\t}\n\t\tvisited.add(node);\n\t\tvisit(node);\n\t};\n\n\tif (typeof slotHost.getSlotElements === 'function') {\n\t\tfor (const node of slotHost.getSlotElements()) {\n\t\t\tsafeVisit(node);\n\t\t}\n\t}\n\n\tconst renderRoot = root.querySelector('.rui-field') ?? root;\n\tfor (const child of Array.from(renderRoot.children)) {\n\t\tsafeVisit(child);\n\t}\n\tfor (const node of renderRoot.querySelectorAll('*')) {\n\t\tsafeVisit(node);\n\t}\n\n\tfor (const child of Array.from(root.children)) {\n\t\tsafeVisit(child);\n\t}\n\n\tconst shadow = root.shadowRoot;\n\tif (shadow) {\n\t\tfor (const child of Array.from(shadow.children)) {\n\t\t\tsafeVisit(child);\n\t\t}\n\t}\n}\n\nfunction queryFieldContent(root: HTMLElement, selector: string): HTMLElement | null {\n\tlet found: HTMLElement | null = null;\n\tforEachFieldContentNode(root, (node) => {\n\t\tif (found || !(node instanceof HTMLElement)) {\n\t\t\treturn;\n\t\t}\n\t\tif (node.matches(selector)) {\n\t\t\tfound = node;\n\t\t\treturn;\n\t\t}\n\t\tfound = node.querySelector<HTMLElement>(selector);\n\t});\n\treturn found;\n}\n\nfunction pickPrimaryFieldControl(candidates: HTMLElement[]): HTMLElement | null {\n\tif (candidates.length === 0) {\n\t\treturn null;\n\t}\n\tif (candidates.length === 1) {\n\t\treturn candidates[0];\n\t}\n\n\tconst active = document.activeElement;\n\tif (active instanceof HTMLElement) {\n\t\tfor (const candidate of candidates) {\n\t\t\tif (candidate === active || candidate.contains(active)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst visible = candidates.filter(\n\t\t(el) => el.isConnected && el.getClientRects().length > 0 && !el.closest('[hidden],[aria-hidden=\"true\"]'),\n\t);\n\tconst pool = visible.length > 0 ? visible : candidates.filter((el) => el.isConnected);\n\treturn pool[pool.length - 1] ?? candidates[candidates.length - 1];\n}\n\nfunction listFieldControlsInRenderTree(root: HTMLElement): HTMLElement[] {\n\tconst renderRoot = root.querySelector('.rui-field');\n\tif (!(renderRoot instanceof HTMLElement)) {\n\t\treturn [];\n\t}\n\treturn Array.from(renderRoot.querySelectorAll<HTMLElement>(CONTROL_SELECTOR)).filter((el) => root.contains(el));\n}\n\nexport function findFieldControl(root: HTMLElement): HTMLElement | null {\n\tconst fromRenderTree = pickPrimaryFieldControl(listFieldControlsInRenderTree(root));\n\tif (fromRenderTree) {\n\t\treturn fromRenderTree;\n\t}\n\n\tlet found: HTMLElement | null = null;\n\tforEachFieldContentNode(root, (node) => {\n\t\tif (found) {\n\t\t\treturn;\n\t\t}\n\t\tconst match = findControlInSubtree(node);\n\t\tif (match) {\n\t\t\tfound = match;\n\t\t}\n\t});\n\tif (found) {\n\t\treturn found;\n\t}\n\tconst renderRoot = root.querySelector('.rui-field') ?? root;\n\treturn findControlInSubtree(renderRoot);\n}\n\nfunction findControlInSubtree(node: Element): HTMLElement | null {\n\tif (!(node instanceof HTMLElement)) {\n\t\treturn null;\n\t}\n\tif (node.matches(`[${RUI_CONTROL_ATTR}]`)) {\n\t\treturn node;\n\t}\n\tif (HOST_CONTROL_TAGS.has(node.localName)) {\n\t\treturn node;\n\t}\n\tif (node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement) {\n\t\treturn node;\n\t}\n\tconst nested = node.querySelector<HTMLElement>(CONTROL_SELECTOR);\n\treturn nested;\n}\n\nexport function readControlValue(control: HTMLElement): unknown {\n\tif (control instanceof HTMLInputElement) {\n\t\tif (control.type === 'checkbox') {\n\t\t\treturn control.checked;\n\t\t}\n\t\tif (control.type === 'number' || control.type === 'range') {\n\t\t\treturn control.value === '' ? '' : Number(control.value);\n\t\t}\n\t\treturn control.value;\n\t}\n\n\tif (control instanceof HTMLTextAreaElement) {\n\t\treturn control.value;\n\t}\n\n\tconst host = resolveControlHost(control);\n\n\tif (host.localName === 'rui-checkbox' || host.localName === 'rui-switch') {\n\t\tconst input = host.querySelector<HTMLInputElement>('input[type=\"checkbox\"]');\n\t\tif (input) {\n\t\t\treturn input.checked;\n\t\t}\n\t\treturn host.hasAttribute('checked');\n\t}\n\n\tif (host.localName === 'rui-combobox' || host.localName === 'rui-radio-group' || host.localName === 'rui-listbox') {\n\t\treturn (host as HTMLElement & { value?: string }).value ?? host.getAttribute('value') ?? '';\n\t}\n\n\tif (host.localName === 'rui-slider' || host.localName === 'rui-spinbutton') {\n\t\tconst propValue = (host as HTMLElement & { value?: number }).value;\n\t\tif (typeof propValue === 'number') {\n\t\t\treturn propValue;\n\t\t}\n\t\tconst raw = host.getAttribute('value');\n\t\treturn raw == null || raw === '' ? '' : Number(raw);\n\t}\n\n\treturn host.getAttribute('value') ?? '';\n}\n\nexport function writeControlValue(control: HTMLElement, value: unknown): void {\n\tif (control instanceof HTMLInputElement) {\n\t\tif (control.type === 'checkbox') {\n\t\t\tcontrol.checked = Boolean(value);\n\t\t\tconst ce = control.closest('rui-checkbox, rui-switch');\n\t\t\tif (ce) {\n\t\t\t\tif (value) {\n\t\t\t\t\tce.setAttribute('checked', '');\n\t\t\t\t} else {\n\t\t\t\t\tce.removeAttribute('checked');\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tcontrol.value = value == null ? '' : String(value);\n\t\treturn;\n\t}\n\n\tif (control instanceof HTMLTextAreaElement) {\n\t\tcontrol.value = value == null ? '' : String(value);\n\t\treturn;\n\t}\n\n\tconst host = resolveControlHost(control);\n\n\tif (host.localName === 'rui-checkbox' || host.localName === 'rui-switch') {\n\t\tif (value) {\n\t\t\thost.setAttribute('checked', '');\n\t\t} else {\n\t\t\thost.removeAttribute('checked');\n\t\t}\n\t\treturn;\n\t}\n\n\thost.setAttribute('value', value == null ? '' : String(value));\n}\n\nfunction resolveControlHost(control: HTMLElement): HTMLElement {\n\tif (control.hasAttribute(RUI_CONTROL_ATTR)) {\n\t\tconst host = control.closest(Array.from(HOST_CONTROL_TAGS).join(',')) as HTMLElement | null;\n\t\treturn host ?? control;\n\t}\n\treturn control;\n}\n\nexport function findFieldLabel(root: HTMLElement): HTMLLabelElement | null {\n\treturn queryFieldContent(root, `[${RUI_FIELD_LABEL_ATTR}], label.rui-label`) as HTMLLabelElement | null;\n}\n\nexport function findFieldDescription(root: HTMLElement): HTMLElement | null {\n\treturn queryFieldContent(root, `[${RUI_FIELD_DESCRIPTION_ATTR}]`);\n}\n\nexport function findFieldError(root: HTMLElement): HTMLElement | null {\n\tconst all = findFieldErrorElements(root);\n\treturn all[0] ?? null;\n}\n\n/** Every error region in the field (handles duplicate slot-projection copies). */\nexport function findFieldErrorElements(root: HTMLElement): HTMLElement[] {\n\tconst renderRoot = root.querySelector('.rui-field');\n\tif (renderRoot instanceof HTMLElement) {\n\t\tconst inRender = Array.from(renderRoot.querySelectorAll<HTMLElement>(`[${RUI_FIELD_ERROR_ATTR}]`));\n\t\tconst visible = inRender.filter((el) => el.getClientRects().length > 0);\n\t\tif (visible.length > 0) {\n\t\t\treturn visible;\n\t\t}\n\t\tif (inRender.length > 0) {\n\t\t\treturn inRender;\n\t\t}\n\t}\n\tconst fromDom = Array.from(root.querySelectorAll<HTMLElement>(`[${RUI_FIELD_ERROR_ATTR}]`));\n\tif (fromDom.length > 0) {\n\t\treturn fromDom;\n\t}\n\tconst single = queryFieldContent(root, `[${RUI_FIELD_ERROR_ATTR}]`);\n\treturn single ? [single] : [];\n}\n\n/** Syncs the field name onto the native control and custom-element hosts. */\nexport function wireFieldControlName(\n\tcontrolHost: HTMLElement | null,\n\tariaTarget: HTMLElement | null,\n\tname: string,\n): void {\n\tif (!name) {\n\t\treturn;\n\t}\n\n\tif (ariaTarget instanceof HTMLInputElement || ariaTarget instanceof HTMLTextAreaElement) {\n\t\tariaTarget.name = name;\n\t}\n\n\tif (!controlHost) {\n\t\treturn;\n\t}\n\n\tif (controlHost === ariaTarget) {\n\t\treturn;\n\t}\n\n\tif (HOST_CONTROL_TAGS.has(controlHost.localName)) {\n\t\tcontrolHost.setAttribute('name', name);\n\t}\n}\n\n/** Element that receives `id`, `aria-invalid`, and `aria-describedby` from Field. */\nexport function getAriaControlTarget(control: HTMLElement): HTMLElement {\n\tif (control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) {\n\t\treturn control;\n\t}\n\n\tif (control.hasAttribute(RUI_CONTROL_ATTR)) {\n\t\treturn control;\n\t}\n\n\tconst marked = control.querySelector<HTMLElement>(`[${RUI_CONTROL_ATTR}]`);\n\tif (marked) {\n\t\treturn marked;\n\t}\n\n\tif (control.localName === 'rui-combobox') {\n\t\treturn control.querySelector<HTMLElement>('[data-combobox-input]') ?? control;\n\t}\n\n\tif (control.localName === 'rui-spinbutton') {\n\t\treturn control.querySelector<HTMLElement>('[data-spinbutton-input], input') ?? control;\n\t}\n\n\tif (control.localName === 'rui-slider') {\n\t\treturn control.querySelector<HTMLElement>('input[type=\"range\"]') ?? control;\n\t}\n\n\tif (control.localName === 'rui-checkbox' || control.localName === 'rui-switch') {\n\t\treturn control.querySelector<HTMLElement>('input') ?? control;\n\t}\n\n\tif (control.localName === 'rui-radio-group') {\n\t\tconst checked = control.querySelector<HTMLInputElement>('input[type=\"radio\"]:checked');\n\t\tconst first = control.querySelector<HTMLInputElement>('input[type=\"radio\"]');\n\t\treturn checked ?? first ?? control;\n\t}\n\n\treturn control;\n}\n", "import { createContext } from '@ecopages/radiant/context';\nimport type { FieldRegistration, RegisterOptions } from './types';\n\n/** UI slice for one field, computed by `<rui-form>` from the store. */\nexport type FormFieldPresentation = {\n\terror?: string;\n\tinvalid: boolean;\n};\n\nexport type FormContextActions = {\n\tregister: (registration: FieldRegistration) => () => void;\n\tupdateFieldOptions: (name: string, options: RegisterOptions) => void;\n\thandleFieldChange: (name: string) => void;\n\thandleFieldBlur: (name: string) => void;\n\t/** Notified whenever the form publishes a new presentation snapshot. */\n\tsubscribePresentation: (listener: (value: FormContextValue) => void) => () => void;\n};\n\nexport type FormContextValue = {\n\t/** False until `<rui-form>` has created its store and bound real actions. */\n\tready: boolean;\n\t/** Bumps when form store state changes. */\n\trevision: number;\n\t/** Per-field messages and invalid flags; only the form writes this map. */\n\tfields: Record<string, FormFieldPresentation>;\n\t/** Registration and validation triggers; fields call these instead of touching the store. */\n\tactions: FormContextActions;\n};\n\nexport const formContext = createContext<FormContextValue>(Symbol.for('rui-form-context'));\n", "import { createContext } from '@ecopages/radiant/context';\nimport type { FieldRules } from '../form/types';\n\nexport type FieldContextValue = {\n\tname: string;\n\tcontrolId: string;\n\tdescriptionId: string;\n\terrorId: string;\n\terror?: string;\n\tinvalid: boolean;\n\trequired: boolean;\n\t/**\n\t * The field's own rules, carried across a real SSR round-trip \u2014 `prop:rules` doesn't\n\t * survive that boundary, so `RuiField` republishes them on its own context, hydrated\n\t * client-side from the `<script>` this provider emits. Never carries `validate`; see\n\t * `fieldProvider`'s `serialize` option.\n\t */\n\trules?: FieldRules;\n};\n\nexport const fieldContext = createContext<FieldContextValue>(Symbol.for('rui-field-context'));\n", "import type { WithChildren } from '../../../types';\nimport { defineRadiantView } from '../../../lib/radiant-view';\nimport type { RuiFieldProps } from './field.script';\nimport { RuiField as RuiFieldElement } from './field.script';\nimport './field.css';\n\nexport const RuiField = defineRadiantView(\n\tRuiFieldElement,\n\t({\n\t\tname,\n\t\trules,\n\t\tdefaultValue,\n\t\tdefaultValueData,\n\t\tdisabled,\n\t\terror,\n\t\tinvalid,\n\t\tchildren,\n\t}: WithChildren<RuiFieldProps>) => (\n\t\t<rui-field\n\t\t\tname={name}\n\t\t\tprop:rules={rules}\n\t\t\tprop:defaultValue={defaultValue}\n\t\t\tdisabled={disabled}\n\t\t\terror={error}\n\t\t\tinvalid={invalid}\n\t\t\tattr:data-default-value={\n\t\t\t\tdefaultValueData ?? (defaultValue !== undefined ? JSON.stringify(defaultValue) : undefined)\n\t\t\t}\n\t\t>\n\t\t\t{children}\n\t\t</rui-field>\n\t),\n);\n", "import type { JsxRenderable } from '@ecopages/jsx';\nimport { RUI_FIELD_DESCRIPTION_ATTR } from '../form/control-protocol';\nimport './field.css';\n\nexport type RuiFieldDescriptionProps = {\n\tclass?: string;\n\tchildren: JsxRenderable;\n};\n\n/** Helper text associated with a field via `aria-describedby`. */\nexport function RuiFieldDescription({ class: className, children }: RuiFieldDescriptionProps) {\n\treturn (\n\t\t<p\n\t\t\t{...{ [RUI_FIELD_DESCRIPTION_ATTR]: '' }}\n\t\t\tclass={['rui-field__description', className].filter(Boolean).join(' ')}\n\t\t>\n\t\t\t{children}\n\t\t</p>\n\t);\n}\n", "import { RUI_FIELD_ERROR_ATTR } from '../form/control-protocol';\nimport './field.css';\n\nexport type RuiFieldErrorProps = {\n\tclass?: string;\n};\n\n/**\n * Error message region for a field. Text is populated by `<rui-field>` from form validation\n * or the field's `error` prop.\n */\nexport function RuiFieldError({ class: className }: RuiFieldErrorProps) {\n\treturn (\n\t\t<p\n\t\t\t{...{ [RUI_FIELD_ERROR_ATTR]: '' }}\n\t\t\tclass={['rui-field__error', className].filter(Boolean).join(' ')}\n\t\t\trole=\"alert\"\n\t\t\thidden\n\t\t></p>\n\t);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["RADIANT_VIEW_ELEMENT", "RADIANT_SCRIPT_MODULE", "RADIANT_SCRIPT_EXPORT", "linkViewToElement", "view", "element", "ssrModule", "defineRadiantView", "render", "args", "RadiantElement", "customElement", "onEvent", "onUpdated", "prop", "registerSsrPreparationCallback", "consumeContext", "onContextUpdate", "provideContext", "RUI_CONTROL_ATTR", "RUI_FIELD_MANAGED_ATTR", "RUI_FIELD_LABEL_ATTR", "RUI_FIELD_DESCRIPTION_ATTR", "RUI_FIELD_ERROR_ATTR", "RUI_FIELD_DEFAULT_VALUE_ATTR", "HOST_CONTROL_TAGS", "CONTROL_SELECTOR", "RUI_CONTROL_ATTR", "forEachFieldContentNode", "root", "visit", "slotHost", "visited", "safeVisit", "node", "renderRoot", "child", "shadow", "queryFieldContent", "selector", "found", "pickPrimaryFieldControl", "candidates", "active", "candidate", "visible", "el", "pool", "listFieldControlsInRenderTree", "findFieldControl", "fromRenderTree", "match", "findControlInSubtree", "readControlValue", "control", "host", "resolveControlHost", "input", "propValue", "raw", "writeControlValue", "value", "ce", "findFieldLabel", "RUI_FIELD_LABEL_ATTR", "findFieldDescription", "RUI_FIELD_DESCRIPTION_ATTR", "findFieldError", "findFieldErrorElements", "inRender", "RUI_FIELD_ERROR_ATTR", "fromDom", "single", "wireFieldControlName", "controlHost", "ariaTarget", "name", "getAriaControlTarget", "marked", "checked", "first", "createContext", "formContext", "createContext", "fieldContext", "stripValidate", "rules", "_validate", "serializable", "RuiField", "customElement", "RadiantElement", "prop", "RUI_FIELD_DEFAULT_VALUE_ATTR", "provideContext", "fieldContext", "value", "consumeContext", "formContext", "registerSsrPreparationCallback", "raw", "formCtx", "fieldName", "ctx", "actions", "control", "findFieldControl", "readControlValue", "writeControlValue", "onContextUpdate", "onUpdated", "onEvent", "controlHost", "ariaTarget", "getAriaControlTarget", "controlId", "descriptionId", "errorId", "errorMessage", "invalid", "required", "wireFieldControlName", "RUI_FIELD_MANAGED_ATTR", "describedBy", "description", "findFieldDescription", "errorEl", "findFieldError", "label", "findFieldLabel", "findFieldErrorElements", "nextFieldContext", "prev", "RuiField", "defineRadiantView", "name", "rules", "defaultValue", "defaultValueData", "disabled", "error", "invalid", "children", "RuiFieldDescription", "className", "children", "RUI_FIELD_DESCRIPTION_ATTR", "RuiFieldError", "className", "RUI_FIELD_ERROR_ATTR"]
7
+ }
@@ -0,0 +1,19 @@
1
+ export declare const RUI_CONTROL_ATTR = "data-rui-control";
2
+ export declare const RUI_FIELD_MANAGED_ATTR = "data-rui-field-managed";
3
+ export declare const RUI_FIELD_LABEL_ATTR = "data-rui-field-label";
4
+ export declare const RUI_FIELD_DESCRIPTION_ATTR = "data-rui-field-description";
5
+ export declare const RUI_FIELD_ERROR_ATTR = "data-rui-field-error";
6
+ export declare const RUI_FIELD_DEFAULT_VALUE_ATTR = "data-default-value";
7
+ export declare const RUI_FORM_DEFAULT_VALUES_ATTR = "data-default-values";
8
+ export declare function findFieldControl(root: HTMLElement): HTMLElement | null;
9
+ export declare function readControlValue(control: HTMLElement): unknown;
10
+ export declare function writeControlValue(control: HTMLElement, value: unknown): void;
11
+ export declare function findFieldLabel(root: HTMLElement): HTMLLabelElement | null;
12
+ export declare function findFieldDescription(root: HTMLElement): HTMLElement | null;
13
+ export declare function findFieldError(root: HTMLElement): HTMLElement | null;
14
+ /** Every error region in the field (handles duplicate slot-projection copies). */
15
+ export declare function findFieldErrorElements(root: HTMLElement): HTMLElement[];
16
+ /** Syncs the field name onto the native control and custom-element hosts. */
17
+ export declare function wireFieldControlName(controlHost: HTMLElement | null, ariaTarget: HTMLElement | null, name: string): void;
18
+ /** Element that receives `id`, `aria-invalid`, and `aria-describedby` from Field. */
19
+ export declare function getAriaControlTarget(control: HTMLElement): HTMLElement;
@@ -0,0 +1,27 @@
1
+ import type { FieldRegistration, RegisterOptions } from './types';
2
+ /** UI slice for one field, computed by `<rui-form>` from the store. */
3
+ export type FormFieldPresentation = {
4
+ error?: string;
5
+ invalid: boolean;
6
+ };
7
+ export type FormContextActions = {
8
+ register: (registration: FieldRegistration) => () => void;
9
+ updateFieldOptions: (name: string, options: RegisterOptions) => void;
10
+ handleFieldChange: (name: string) => void;
11
+ handleFieldBlur: (name: string) => void;
12
+ /** Notified whenever the form publishes a new presentation snapshot. */
13
+ subscribePresentation: (listener: (value: FormContextValue) => void) => () => void;
14
+ };
15
+ export type FormContextValue = {
16
+ /** False until `<rui-form>` has created its store and bound real actions. */
17
+ ready: boolean;
18
+ /** Bumps when form store state changes. */
19
+ revision: number;
20
+ /** Per-field messages and invalid flags; only the form writes this map. */
21
+ fields: Record<string, FormFieldPresentation>;
22
+ /** Registration and validation triggers; fields call these instead of touching the store. */
23
+ actions: FormContextActions;
24
+ };
25
+ export declare const formContext: {
26
+ __context__: FormContextValue;
27
+ };
@@ -0,0 +1,3 @@
1
+ import '../field/field.script';
2
+ import './form.script';
3
+ import '../switch/switch.script';