@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,64 @@
1
+ import { RadiantElement } from '@ecopages/radiant';
2
+ import type { EventEmitter } from '@ecopages/radiant/tools/event-emitter';
3
+ export type RuiSpinbuttonProps = {
4
+ value?: number;
5
+ min?: number;
6
+ max?: number;
7
+ step?: number;
8
+ disabled?: boolean;
9
+ label?: string;
10
+ name?: string;
11
+ };
12
+ export type RuiSpinbuttonChangeDetail = {
13
+ value: number;
14
+ };
15
+ type RuiSpinbuttonBindings = {
16
+ value: number;
17
+ disabled: boolean;
18
+ label: string;
19
+ name: string;
20
+ min: number;
21
+ max: number;
22
+ decreaseDisabled: boolean;
23
+ increaseDisabled: boolean;
24
+ };
25
+ /**
26
+ * `<rui-spinbutton>` — an input restricted to a discrete numeric range.
27
+ *
28
+ * Implements the APG Spinbutton pattern with `role="spinbutton"` on a native
29
+ * number-like text field, plus decrement/increment buttons.
30
+ *
31
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/
32
+ *
33
+ * @element rui-spinbutton
34
+ * @slot decrease - Optional custom decrease control. Use `data-spinbutton-action="decrease"`.
35
+ * @slot increase - Optional custom increase control. Use `data-spinbutton-action="increase"`.
36
+ * @fires rui-change
37
+ */
38
+ export declare class RuiSpinbutton extends RadiantElement<RuiSpinbuttonBindings> {
39
+ value: number;
40
+ min: number;
41
+ max: number;
42
+ step: number;
43
+ disabled: boolean;
44
+ label: string;
45
+ name: string;
46
+ changeEvent: EventEmitter<RuiSpinbuttonChangeDetail>;
47
+ decreaseDisabled: boolean;
48
+ increaseDisabled: boolean;
49
+ private readonly nameAttr;
50
+ private readonly resolvedAriaLabel;
51
+ /** Derived from disabled/value/min/max — recomputed here instead of per-render. */
52
+ onRangeUpdated(): void;
53
+ private syncSlottedStepperControls;
54
+ private isDecreaseDisabled;
55
+ private isIncreaseDisabled;
56
+ private clamp;
57
+ private setValue;
58
+ decrement(): void;
59
+ increment(): void;
60
+ onChange(event: Event): void;
61
+ onKeydown(event: KeyboardEvent): void;
62
+ render(): import("@ecopages/jsx").JsxRenderable;
63
+ }
64
+ export {};
@@ -0,0 +1,2 @@
1
+ export { RuiSwitch as RuiSwitchElement, type RuiSwitchProps, type RuiSwitchChangeDetail } from './switch.script';
2
+ export { RuiSwitch } from './switch';
@@ -0,0 +1,2 @@
1
+ import{RadiantElement as l,customElement as d,event as u,onEvent as h,prop as r}from"@ecopages/radiant";var n=@d("rui-switch")class extends l{@r({type:Boolean,reflect:!0,defaultValue:!1})checked;@r({type:Boolean,reflect:!0,defaultValue:!1})disabled;@r({type:String,defaultValue:""})name;@u({name:"rui-change",bubbles:!0,composed:!0})changeEvent;nameAttr=this.$.name.map(e=>e||void 0);@h({ref:"input",type:"change"})onInputChange(e){let t=e.target;this.checked=t.checked,this.changeEvent.emit({checked:this.checked})}render(){return React.createElement("label",{class:"rui-switch"},React.createElement("input",{type:"checkbox",role:"switch","data-ref":"input","data-rui-control":!0,"data-rui-control-type":"boolean",class:"rui-switch__input","prop:checked":this.$.checked,disabled:this.$.disabled,name:this.nameAttr}),React.createElement("span",{class:"rui-switch__track","aria-hidden":"true"},React.createElement("span",{class:"rui-switch__thumb"})),React.createElement("span",{class:"rui-switch__label"},React.createElement("slot",null)))}};var m=Symbol.for("@ecopages/storybook-radiant.viewElement"),a=Symbol.for("@ecopages/storybook-radiant.scriptModule"),s=Symbol.for("@ecopages/storybook-radiant.scriptExport");function R(i,e){i[m]=e;let t=e[a];t&&(i[a]=t,i[s]=e[s]??e.name)}function c(i,e){let t=(o=>e(o));return R(t,i),t}import"./switch.css";var g=c(n,({slot:i,checked:e,disabled:t,name:o,children:p})=>React.createElement("rui-switch",{slot:i,checked:e,disabled:t,name:o},p));export{g as RuiSwitch,n as RuiSwitchElement};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/components/ui/switch/switch.script.tsx", "../../../../src/lib/radiant-view.ts", "../../../../src/components/ui/switch/switch.tsx"],
4
+ "sourcesContent": ["import { RadiantElement, customElement, event, onEvent, prop } from '@ecopages/radiant';\nimport type { EventEmitter } from '@ecopages/radiant/tools/event-emitter';\n\nexport type RuiSwitchProps = {\n\t/** Whether the switch is on. Reflects to markup. Default: `false`. */\n\tchecked?: boolean;\n\t/** Disable the switch. Default: `false`. */\n\tdisabled?: boolean;\n\t/** Associates the control with a form field name. */\n\tname?: string;\n};\n\nexport type RuiSwitchChangeDetail = {\n\tchecked: boolean;\n};\n\ntype RuiSwitchBindings = {\n\tchecked: boolean;\n\tdisabled: boolean;\n\tname: string;\n};\n\n/**\n * `<rui-switch>` \u2014 a binary on/off control.\n *\n * Implements the WAI-ARIA APG Switch pattern using a native\n * `<input type=\"checkbox\" role=\"switch\">` wrapped in a `<label>`. The browser\n * owns activation (click on label or control, Space when focused); no click\n * delegation is required. The HTML `checked` attribute conveys state.\n *\n * Prefer Switch over Checkbox when the UI communicates on/off (for example\n * enabling notifications) rather than checked/unchecked membership in a set.\n *\n * Important: the accessible label must not change when the switch state changes.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/switch/\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/switch/examples/switch-checkbox/\n *\n * Keyboard interaction (native to the checkbox):\n * - `Space`: toggle the switch\n *\n * @element rui-switch\n * @slot - Visible label for the switch. Must not change with state.\n * @fires rui-change - Emitted after the checked state changes; `detail.checked` holds the new state.\n */\n@customElement('rui-switch')\nexport class RuiSwitch extends RadiantElement<RuiSwitchBindings> {\n\t@prop({ type: Boolean, reflect: true, defaultValue: false }) checked: boolean;\n\t@prop({ type: Boolean, reflect: true, defaultValue: false }) disabled: boolean;\n\t@prop({ type: String, defaultValue: '' }) name: string;\n\n\t@event({ name: 'rui-change', bubbles: true, composed: true })\n\tchangeEvent: EventEmitter<RuiSwitchChangeDetail>;\n\n\tprivate readonly nameAttr = this.$.name.map((name) => name || undefined);\n\n\t@onEvent({ ref: 'input', type: 'change' })\n\tonInputChange(event: Event): void {\n\t\tconst input = event.target as HTMLInputElement;\n\t\tthis.checked = input.checked;\n\t\tthis.changeEvent.emit({ checked: this.checked });\n\t}\n\n\toverride render() {\n\t\treturn (\n\t\t\t<label class=\"rui-switch\">\n\t\t\t\t<input\n\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\trole=\"switch\"\n\t\t\t\t\tdata-ref=\"input\"\n\t\t\t\t\tdata-rui-control\n\t\t\t\t\tdata-rui-control-type=\"boolean\"\n\t\t\t\t\tclass=\"rui-switch__input\"\n\t\t\t\t\tprop:checked={this.$.checked}\n\t\t\t\t\tdisabled={this.$.disabled}\n\t\t\t\t\tname={this.nameAttr}\n\t\t\t\t/>\n\t\t\t\t<span class=\"rui-switch__track\" aria-hidden=\"true\">\n\t\t\t\t\t<span class=\"rui-switch__thumb\"></span>\n\t\t\t\t</span>\n\t\t\t\t<span class=\"rui-switch__label\">\n\t\t\t\t\t<slot></slot>\n\t\t\t\t</span>\n\t\t\t</label>\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 { WithChildren, RadiantSlotProps } from '../../../types';\nimport { defineRadiantView } from '../../../lib/radiant-view';\nimport type { RuiSwitchProps } from './switch.script';\nimport { RuiSwitch as RuiSwitchElement } from './switch.script';\nimport './switch.css';\n\nexport const RuiSwitch = defineRadiantView(\n\tRuiSwitchElement,\n\t({ slot, checked, disabled, name, children }: WithChildren<RuiSwitchProps & RadiantSlotProps>) => (\n\t\t<rui-switch slot={slot} checked={checked} disabled={disabled} name={name}>\n\t\t\t{children}\n\t\t</rui-switch>\n\t),\n);\n"],
5
+ "mappings": "AAAA,OAAS,kBAAAA,EAAgB,iBAAAC,EAAe,SAAAC,EAAO,WAAAC,EAAS,QAAAC,MAAY,oBA8C7D,IAAMC,EADb,CAACJ,EAAc,YAAY,CACpB,cAAwBD,CAAkC,CAChE,CAACI,EAAK,CAAE,KAAM,QAAS,QAAS,GAAM,aAAc,EAAM,CAAC,CAAE,QAC7D,CAACA,EAAK,CAAE,KAAM,QAAS,QAAS,GAAM,aAAc,EAAM,CAAC,CAAE,SAC7D,CAACA,EAAK,CAAE,KAAM,OAAQ,aAAc,EAAG,CAAC,CAAE,KAE1C,CAACF,EAAM,CAAE,KAAM,aAAc,QAAS,GAAM,SAAU,EAAK,CAAC,CAC5D,YAEiB,SAAW,KAAK,EAAE,KAAK,IAAKI,GAASA,GAAQ,MAAS,EAEvE,CAACH,EAAQ,CAAE,IAAK,QAAS,KAAM,QAAS,CAAC,CACzC,cAAcD,EAAoB,CACjC,IAAMK,EAAQL,EAAM,OACpB,KAAK,QAAUK,EAAM,QACrB,KAAK,YAAY,KAAK,CAAE,QAAS,KAAK,OAAQ,CAAC,CAChD,CAES,QAAS,CACjB,OACC,oBAAC,SAAM,MAAM,cACZ,oBAAC,SACA,KAAK,WACL,KAAK,SACL,WAAS,QACT,mBAAgB,GAChB,wBAAsB,UACtB,MAAM,oBACN,eAAc,KAAK,EAAE,QACrB,SAAU,KAAK,EAAE,SACjB,KAAM,KAAK,SACZ,EACA,oBAAC,QAAK,MAAM,oBAAoB,cAAY,QAC3C,oBAAC,QAAK,MAAM,oBAAoB,CACjC,EACA,oBAAC,QAAK,MAAM,qBACX,oBAAC,WAAK,CACP,CACD,CAEF,CACD,ECpFA,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,CCnCA,MAAO,eAEA,IAAMM,EAAYC,EACxBD,EACA,CAAC,CAAE,KAAAE,EAAM,QAAAC,EAAS,SAAAC,EAAU,KAAAC,EAAM,SAAAC,CAAS,IAC1C,oBAAC,cAAW,KAAMJ,EAAM,QAASC,EAAS,SAAUC,EAAU,KAAMC,GAClEC,CACF,CAEF",
6
+ "names": ["RadiantElement", "customElement", "event", "onEvent", "prop", "RuiSwitch", "name", "input", "RADIANT_VIEW_ELEMENT", "RADIANT_SCRIPT_MODULE", "RADIANT_SCRIPT_EXPORT", "linkViewToElement", "view", "element", "ssrModule", "defineRadiantView", "render", "args", "RuiSwitch", "defineRadiantView", "slot", "checked", "disabled", "name", "children"]
7
+ }
@@ -0,0 +1,47 @@
1
+ @reference '../../../styles/radiant-ui.css';
2
+
3
+ rui-switch {
4
+ @apply inline-flex;
5
+ }
6
+
7
+ @layer components {
8
+ .rui-switch {
9
+ @apply inline-flex items-center gap-3;
10
+ @apply cursor-pointer text-sm text-on-background;
11
+ }
12
+
13
+ .rui-switch:has(input:disabled) {
14
+ @apply cursor-not-allowed opacity-disabled;
15
+ }
16
+
17
+ .rui-switch__input {
18
+ @apply sr-only;
19
+ }
20
+
21
+ .rui-switch__input:focus-visible + .rui-switch__track {
22
+ @apply ring-2 ring-focus-ring ring-offset-2;
23
+ }
24
+
25
+ .rui-switch__track {
26
+ @apply relative inline-flex h-6 w-11 shrink-0 items-center rounded-full;
27
+ @apply bg-surface-container transition-colors duration-normal;
28
+ }
29
+
30
+ .rui-switch__input:checked + .rui-switch__track {
31
+ @apply bg-primary;
32
+ }
33
+
34
+ .rui-switch__thumb {
35
+ @apply absolute left-0.5 top-0.5 size-5 rounded-full bg-white;
36
+ @apply transition-transform duration-normal;
37
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.2);
38
+ }
39
+
40
+ .rui-switch__input:checked + .rui-switch__track .rui-switch__thumb {
41
+ transform: translateX(1.25rem);
42
+ }
43
+
44
+ .rui-switch__label {
45
+ @apply select-text;
46
+ }
47
+ }
@@ -0,0 +1,4 @@
1
+ import type { WithChildren, RadiantSlotProps } from '../../../types';
2
+ import type { RuiSwitchProps } from './switch.script';
3
+ import './switch.css';
4
+ export declare const RuiSwitch: import("../../../lib/radiant-view").RadiantViewComponent<WithChildren<RuiSwitchProps & RadiantSlotProps>>;
@@ -0,0 +1,51 @@
1
+ import { RadiantElement } from '@ecopages/radiant';
2
+ import type { EventEmitter } from '@ecopages/radiant/tools/event-emitter';
3
+ export type RuiSwitchProps = {
4
+ /** Whether the switch is on. Reflects to markup. Default: `false`. */
5
+ checked?: boolean;
6
+ /** Disable the switch. Default: `false`. */
7
+ disabled?: boolean;
8
+ /** Associates the control with a form field name. */
9
+ name?: string;
10
+ };
11
+ export type RuiSwitchChangeDetail = {
12
+ checked: boolean;
13
+ };
14
+ type RuiSwitchBindings = {
15
+ checked: boolean;
16
+ disabled: boolean;
17
+ name: string;
18
+ };
19
+ /**
20
+ * `<rui-switch>` — a binary on/off control.
21
+ *
22
+ * Implements the WAI-ARIA APG Switch pattern using a native
23
+ * `<input type="checkbox" role="switch">` wrapped in a `<label>`. The browser
24
+ * owns activation (click on label or control, Space when focused); no click
25
+ * delegation is required. The HTML `checked` attribute conveys state.
26
+ *
27
+ * Prefer Switch over Checkbox when the UI communicates on/off (for example
28
+ * enabling notifications) rather than checked/unchecked membership in a set.
29
+ *
30
+ * Important: the accessible label must not change when the switch state changes.
31
+ *
32
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/switch/
33
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/switch/examples/switch-checkbox/
34
+ *
35
+ * Keyboard interaction (native to the checkbox):
36
+ * - `Space`: toggle the switch
37
+ *
38
+ * @element rui-switch
39
+ * @slot - Visible label for the switch. Must not change with state.
40
+ * @fires rui-change - Emitted after the checked state changes; `detail.checked` holds the new state.
41
+ */
42
+ export declare class RuiSwitch extends RadiantElement<RuiSwitchBindings> {
43
+ checked: boolean;
44
+ disabled: boolean;
45
+ name: string;
46
+ changeEvent: EventEmitter<RuiSwitchChangeDetail>;
47
+ private readonly nameAttr;
48
+ onInputChange(event: Event): void;
49
+ render(): import("@ecopages/jsx").JsxRenderable;
50
+ }
51
+ export {};
@@ -0,0 +1,2 @@
1
+ export { RuiTabs as RuiTabsElement, type RuiTabsProps, type RuiTabsChangeDetail } from './tabs.script';
2
+ export { RuiTabs, type RuiTabItem } from './tabs';
@@ -0,0 +1,2 @@
1
+ import{RadiantElement as v,customElement as E,event as y,onEvent as p,onUpdated as x,prop as d}from"@ecopages/radiant";function g(n,t){n.forEach((e,r)=>{e.tabIndex=r===t?0:-1})}function R(n,t){if(!n.length)return null;let e=Math.max(0,Math.min(n.length-1,t));return g(n,e),n[e]?.focus(),n[e]??null}function h(n,t){return n==="Home"?"first":n==="End"?"last":t==="horizontal"?n==="ArrowRight"?"next":n==="ArrowLeft"?"prev":null:n==="ArrowDown"?"next":n==="ArrowUp"?"prev":null}function b(n){let{items:t,current:e,key:r,orientation:i="horizontal",wrap:a=!0}=n;if(!t.length||!e)return{handled:!1};let o=t.indexOf(e);if(o<0)return{handled:!1};let l=h(r,i);if(!l)return{handled:!1};let s=o;l==="first"?s=0:l==="last"?s=t.length-1:l==="next"?s=a?(o+1)%t.length:Math.min(t.length-1,o+1):s=a?(o-1+t.length)%t.length:Math.max(0,o-1);let c=R(t,s);return c?{handled:!0,index:s,item:c}:{handled:!1}}var u=@E("rui-tabs")class extends v{@d({type:String,reflect:!0,defaultValue:""})value;@d({type:String,defaultValue:""})label;@d({type:Boolean,defaultValue:!0})automatic;@y({name:"rui-change",bubbles:!0,composed:!0})changeEvent;connectedCallback(){super.connectedCallback(),queueMicrotask(()=>{this.syncTablistLabel(),this.syncSelection(this.value||this.getTabs()[0]?.id||"")})}@x(["value","label"])onPropsUpdated(){this.syncTablistLabel(),this.value&&this.syncSelection(this.value)}getTabs(){return Array.from(this.querySelectorAll('[role="tab"]'))}getPanels(){return Array.from(this.querySelectorAll('[role="tabpanel"]'))}syncTablistLabel(){let t=this.querySelector('[role="tablist"]');!t||!this.label||t.setAttribute("aria-label",this.label)}syncSelection(t){let e=this.getTabs(),r=this.getPanels();if(!e.length)return;let i=e.find(a=>a.id===t)??e[0];this.value=i.id;for(let a of e){let o=a===i;a.setAttribute("aria-selected",String(o)),a.tabIndex=o?0:-1}for(let a of r){let l=e.find(s=>s.getAttribute("aria-controls")===a.id)===i;a.hidden=!l,a.hasAttribute("tabindex")||(a.tabIndex=0)}}activateTab(t){!t||t.getAttribute("aria-disabled")==="true"||(this.syncSelection(t.id),this.changeEvent.emit({value:t.id}))}@p({selector:'[role="tab"]',type:"click"})onTabClick(t){let e=t.target.closest('[role="tab"]');!e||!this.contains(e)||this.activateTab(e)}@p({selector:'[role="tab"]',type:"keydown"})onTabKeydown(t){let e=this.getTabs(),r=t.target.closest('[role="tab"]');if(!r||!e.includes(r))return;if(t.key==="Enter"||t.key===" "){t.preventDefault(),this.activateTab(r);return}let i=b({items:e,current:r,key:t.key,orientation:"horizontal"});i.handled&&(t.preventDefault(),this.automatic&&this.activateTab(i.item))}};var A=Symbol.for("@ecopages/storybook-radiant.viewElement"),m=Symbol.for("@ecopages/storybook-radiant.scriptModule"),T=Symbol.for("@ecopages/storybook-radiant.scriptExport");function M(n,t){n[A]=t;let e=t[m];e&&(n[m]=e,n[T]=t[T]??t.name)}function f(n,t){let e=(r=>t(r));return M(e,n),e}import"./tabs.css";var I=f(u,({slot:n,value:t,label:e,automatic:r,items:i})=>React.createElement("rui-tabs",{slot:n,value:t,label:e,automatic:r},React.createElement("div",{class:"rui-tabs__list",role:"tablist"},i.map(a=>React.createElement("button",{type:"button",class:"rui-tabs__tab",role:"tab",id:`tab-${a.id}`,"aria-controls":`panel-${a.id}`,"aria-selected":"false",tabindex:-1},a.label))),i.map(a=>React.createElement("div",{class:"rui-tabs__panel",role:"tabpanel",id:`panel-${a.id}`,"aria-labelledby":`tab-${a.id}`,tabindex:0,hidden:!0},a.children))));export{I as RuiTabs,u as RuiTabsElement};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/components/ui/tabs/tabs.script.tsx", "../../../../src/lib/roving-tabindex.ts", "../../../../src/lib/radiant-view.ts", "../../../../src/components/ui/tabs/tabs.tsx"],
4
+ "sourcesContent": ["import { RadiantElement, customElement, event, onEvent, onUpdated, prop } from '@ecopages/radiant';\nimport type { EventEmitter } from '@ecopages/radiant/tools/event-emitter';\nimport { navigateRovingTabindex } from '../../../lib/roving-tabindex';\n\nexport type RuiTabsProps = {\n\t/** ID of the initially selected tab. Defaults to the first tab. */\n\tvalue?: string;\n\t/** Accessible name for the tab list. */\n\tlabel?: string;\n\t/**\n\t * When `true` (default), focusing a tab activates it (automatic activation).\n\t * When `false`, Space/Enter activate the focused tab (manual activation).\n\t */\n\tautomatic?: boolean;\n};\n\nexport type RuiTabsChangeDetail = {\n\tvalue: string;\n};\n\n/**\n * `<rui-tabs>` \u2014 layered sections of content with one visible panel at a time.\n *\n * Implements the WAI-ARIA APG Tabs pattern with a `tablist`, `tab` controls, and\n * associated `tabpanel` regions. Automatic activation is the default.\n *\n * Author a `[role=\"tablist\"]` of `[role=\"tab\"]` buttons and matching\n * `[role=\"tabpanel\"]` regions as children. Each tab must have an `id` and\n * `aria-controls` pointing at its panel; each panel must have `aria-labelledby`\n * pointing at its tab.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/tabs/\n *\n * Keyboard interaction:\n * - `Tab`: move focus into the active tab, then to the panel / next page control\n * - `ArrowLeft` / `ArrowRight`: move focus (and activate when automatic)\n * - `Home` / `End`: jump to first / last tab\n * - `Space` / `Enter`: activate the focused tab (manual mode)\n *\n * @element rui-tabs\n * @slot - A tablist and one or more tabpanels.\n * @fires rui-change - Emitted when the selected tab changes.\n */\n@customElement('rui-tabs')\nexport class RuiTabs extends RadiantElement {\n\t@prop({ type: String, reflect: true, defaultValue: '' }) value: string;\n\t@prop({ type: String, defaultValue: '' }) label: string;\n\t@prop({ type: Boolean, defaultValue: true }) automatic: boolean;\n\n\t@event({ name: 'rui-change', bubbles: true, composed: true })\n\tchangeEvent: EventEmitter<RuiTabsChangeDetail>;\n\n\toverride connectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tqueueMicrotask(() => {\n\t\t\tthis.syncTablistLabel();\n\t\t\tthis.syncSelection(this.value || this.getTabs()[0]?.id || '');\n\t\t});\n\t}\n\n\t@onUpdated(['value', 'label'])\n\tonPropsUpdated(): void {\n\t\tthis.syncTablistLabel();\n\t\tif (this.value) this.syncSelection(this.value);\n\t}\n\n\tprivate getTabs(): HTMLElement[] {\n\t\treturn Array.from(this.querySelectorAll<HTMLElement>('[role=\"tab\"]'));\n\t}\n\n\tprivate getPanels(): HTMLElement[] {\n\t\treturn Array.from(this.querySelectorAll<HTMLElement>('[role=\"tabpanel\"]'));\n\t}\n\n\tprivate syncTablistLabel(): void {\n\t\tconst tablist = this.querySelector<HTMLElement>('[role=\"tablist\"]');\n\t\tif (!tablist || !this.label) return;\n\t\ttablist.setAttribute('aria-label', this.label);\n\t}\n\n\tprivate syncSelection(nextValue: string): void {\n\t\tconst tabs = this.getTabs();\n\t\tconst panels = this.getPanels();\n\t\tif (!tabs.length) return;\n\n\t\tconst selected = tabs.find((tab) => tab.id === nextValue) ?? tabs[0];\n\t\tthis.value = selected.id;\n\n\t\tfor (const tab of tabs) {\n\t\t\tconst isSelected = tab === selected;\n\t\t\ttab.setAttribute('aria-selected', String(isSelected));\n\t\t\ttab.tabIndex = isSelected ? 0 : -1;\n\t\t}\n\n\t\tfor (const panel of panels) {\n\t\t\tconst controls = tabs.find((tab) => tab.getAttribute('aria-controls') === panel.id);\n\t\t\tconst isSelected = controls === selected;\n\t\t\tpanel.hidden = !isSelected;\n\t\t\tif (!panel.hasAttribute('tabindex')) {\n\t\t\t\tpanel.tabIndex = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate activateTab(tab: HTMLElement): void {\n\t\tif (!tab || tab.getAttribute('aria-disabled') === 'true') return;\n\t\tthis.syncSelection(tab.id);\n\t\tthis.changeEvent.emit({ value: tab.id });\n\t}\n\n\t@onEvent({ selector: '[role=\"tab\"]', type: 'click' })\n\tonTabClick(event: Event): void {\n\t\tconst tab = (event.target as HTMLElement).closest('[role=\"tab\"]') as HTMLElement | null;\n\t\tif (!tab || !this.contains(tab)) return;\n\t\tthis.activateTab(tab);\n\t}\n\n\t@onEvent({ selector: '[role=\"tab\"]', type: 'keydown' })\n\tonTabKeydown(event: KeyboardEvent): void {\n\t\tconst tabs = this.getTabs();\n\t\tconst current = (event.target as HTMLElement).closest('[role=\"tab\"]') as HTMLElement | null;\n\t\tif (!current || !tabs.includes(current)) return;\n\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tthis.activateTab(current);\n\t\t\treturn;\n\t\t}\n\n\t\tconst result = navigateRovingTabindex({\n\t\t\titems: tabs,\n\t\t\tcurrent,\n\t\t\tkey: event.key,\n\t\t\torientation: 'horizontal',\n\t\t});\n\t\tif (!result.handled) return;\n\n\t\tevent.preventDefault();\n\t\tif (this.automatic) this.activateTab(result.item);\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 { RuiTabsProps } from './tabs.script';\nimport { RuiTabs as RuiTabsElement } from './tabs.script';\nimport './tabs.css';\n\nexport type RuiTabItem = {\n\tid: string;\n\tlabel: JsxRenderable;\n\tchildren: JsxRenderable;\n};\n\nexport const RuiTabs = defineRadiantView(\n\tRuiTabsElement,\n\t({\n\t\tslot,\n\t\tvalue,\n\t\tlabel,\n\t\tautomatic,\n\t\titems,\n\t}: RuiTabsProps &\n\t\tRadiantSlotProps & {\n\t\t\titems: RuiTabItem[];\n\t\t}) => (\n\t\t<rui-tabs slot={slot} value={value} label={label} automatic={automatic}>\n\t\t\t<div class=\"rui-tabs__list\" role=\"tablist\">\n\t\t\t\t{items.map((item) => (\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"rui-tabs__tab\"\n\t\t\t\t\t\trole=\"tab\"\n\t\t\t\t\t\tid={`tab-${item.id}`}\n\t\t\t\t\t\taria-controls={`panel-${item.id}`}\n\t\t\t\t\t\taria-selected=\"false\"\n\t\t\t\t\t\ttabindex={-1}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.label}\n\t\t\t\t\t</button>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t\t{items.map((item) => (\n\t\t\t\t<div\n\t\t\t\t\tclass=\"rui-tabs__panel\"\n\t\t\t\t\trole=\"tabpanel\"\n\t\t\t\t\tid={`panel-${item.id}`}\n\t\t\t\t\taria-labelledby={`tab-${item.id}`}\n\t\t\t\t\ttabindex={0}\n\t\t\t\t\thidden\n\t\t\t\t>\n\t\t\t\t\t{item.children}\n\t\t\t\t</div>\n\t\t\t))}\n\t\t</rui-tabs>\n\t),\n);\n"],
5
+ "mappings": "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",
6
+ "names": ["RadiantElement", "customElement", "event", "onEvent", "onUpdated", "prop", "applyRovingTabindex", "items", "activeIndex", "item", "index", "focusRovingItem", "next", "deltaForKey", "key", "orientation", "navigateRovingTabindex", "options", "current", "wrap", "delta", "RuiTabs", "customElement", "RadiantElement", "prop", "event", "onUpdated", "tablist", "nextValue", "tabs", "panels", "selected", "tab", "isSelected", "panel", "onEvent", "current", "result", "navigateRovingTabindex", "RADIANT_VIEW_ELEMENT", "RADIANT_SCRIPT_MODULE", "RADIANT_SCRIPT_EXPORT", "linkViewToElement", "view", "element", "ssrModule", "defineRadiantView", "render", "args", "RuiTabs", "defineRadiantView", "slot", "value", "label", "automatic", "items", "item"]
7
+ }
@@ -0,0 +1,28 @@
1
+ @reference '../../../styles/radiant-ui.css';
2
+
3
+ rui-tabs {
4
+ @apply block;
5
+ }
6
+
7
+ @layer components {
8
+ .rui-tabs__list {
9
+ @apply flex gap-1 border-b border-border;
10
+ }
11
+
12
+ .rui-tabs__tab {
13
+ @apply cursor-pointer rounded-t-md border-0 bg-transparent px-control-x py-2 text-sm;
14
+ @apply text-on-surface;
15
+ }
16
+
17
+ .rui-tabs__tab[aria-selected='true'] {
18
+ @apply border-b-2 border-primary font-medium text-on-background;
19
+ }
20
+
21
+ .rui-tabs__tab:focus-visible {
22
+ @apply ring-2 ring-focus-ring outline-hidden;
23
+ }
24
+
25
+ .rui-tabs__panel {
26
+ @apply px-1 py-4 text-sm text-on-background;
27
+ }
28
+ }
@@ -0,0 +1,12 @@
1
+ import type { JsxRenderable } from '@ecopages/jsx';
2
+ import type { RadiantSlotProps } from '../../../types';
3
+ import type { RuiTabsProps } from './tabs.script';
4
+ import './tabs.css';
5
+ export type RuiTabItem = {
6
+ id: string;
7
+ label: JsxRenderable;
8
+ children: JsxRenderable;
9
+ };
10
+ export declare const RuiTabs: import("../../../lib/radiant-view").RadiantViewComponent<RuiTabsProps & RadiantSlotProps & {
11
+ items: RuiTabItem[];
12
+ }>;
@@ -0,0 +1,54 @@
1
+ import { RadiantElement } from '@ecopages/radiant';
2
+ import type { EventEmitter } from '@ecopages/radiant/tools/event-emitter';
3
+ export type RuiTabsProps = {
4
+ /** ID of the initially selected tab. Defaults to the first tab. */
5
+ value?: string;
6
+ /** Accessible name for the tab list. */
7
+ label?: string;
8
+ /**
9
+ * When `true` (default), focusing a tab activates it (automatic activation).
10
+ * When `false`, Space/Enter activate the focused tab (manual activation).
11
+ */
12
+ automatic?: boolean;
13
+ };
14
+ export type RuiTabsChangeDetail = {
15
+ value: string;
16
+ };
17
+ /**
18
+ * `<rui-tabs>` — layered sections of content with one visible panel at a time.
19
+ *
20
+ * Implements the WAI-ARIA APG Tabs pattern with a `tablist`, `tab` controls, and
21
+ * associated `tabpanel` regions. Automatic activation is the default.
22
+ *
23
+ * Author a `[role="tablist"]` of `[role="tab"]` buttons and matching
24
+ * `[role="tabpanel"]` regions as children. Each tab must have an `id` and
25
+ * `aria-controls` pointing at its panel; each panel must have `aria-labelledby`
26
+ * pointing at its tab.
27
+ *
28
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/tabs/
29
+ *
30
+ * Keyboard interaction:
31
+ * - `Tab`: move focus into the active tab, then to the panel / next page control
32
+ * - `ArrowLeft` / `ArrowRight`: move focus (and activate when automatic)
33
+ * - `Home` / `End`: jump to first / last tab
34
+ * - `Space` / `Enter`: activate the focused tab (manual mode)
35
+ *
36
+ * @element rui-tabs
37
+ * @slot - A tablist and one or more tabpanels.
38
+ * @fires rui-change - Emitted when the selected tab changes.
39
+ */
40
+ export declare class RuiTabs extends RadiantElement {
41
+ value: string;
42
+ label: string;
43
+ automatic: boolean;
44
+ changeEvent: EventEmitter<RuiTabsChangeDetail>;
45
+ connectedCallback(): void;
46
+ onPropsUpdated(): void;
47
+ private getTabs;
48
+ private getPanels;
49
+ private syncTablistLabel;
50
+ private syncSelection;
51
+ private activateTab;
52
+ onTabClick(event: Event): void;
53
+ onTabKeydown(event: KeyboardEvent): void;
54
+ }
@@ -0,0 +1 @@
1
+ export { RuiTextarea, type RuiTextareaProps } from './textarea';
@@ -0,0 +1,2 @@
1
+ var t="data-rui-control";var E=new Set(["rui-combobox","rui-checkbox","rui-switch","rui-radio-group","rui-slider","rui-spinbutton","rui-listbox"]),p=`[${t}], ${Array.from(E).join(", ")}, input, textarea`;import"./textarea.css";function d(...e){return e.filter(Boolean).join(" ")}function L({value:e,placeholder:n,disabled:r,name:i,rows:l=3,size:u="md",class:o,id:a,"aria-label":s,"on:input":c,"on:change":f,"on:blur":m,...T}){return React.createElement("textarea",{id:a,[t]:"","data-rui-control-type":"text",class:d("rui-textarea",`rui-textarea--${u}`,o),value:e,placeholder:n,disabled:r,rows:l,name:i,"aria-label":s,"on:input":c,"on:change":f,"on:blur":m,...T})}export{L as RuiTextarea};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/components/ui/form/control-protocol.ts", "../../../../src/components/ui/textarea/textarea.tsx"],
4
+ "sourcesContent": ["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 { RUI_CONTROL_ATTR } from '../form/control-protocol';\nimport type { RuiInputSize } from '../input';\nimport './textarea.css';\n\nexport type RuiTextareaProps = {\n\tvalue?: string;\n\tplaceholder?: string;\n\tdisabled?: boolean;\n\tname?: string;\n\trows?: number;\n\tsize?: RuiInputSize;\n\tclass?: string;\n\tid?: string;\n\t'aria-label'?: string;\n\t'on:input'?: (event: Event) => void;\n\t'on:change'?: (event: Event) => void;\n\t'on:blur'?: (event: Event) => void;\n};\n\nfunction cx(...parts: Array<string | false | null | undefined>): string {\n\treturn parts.filter(Boolean).join(' ');\n}\n\n/**\n * Presentational wrapper around a native `<textarea>`.\n *\n * No custom element \u2014 Field owns labeling, `aria-*`, and validation wiring.\n * Marked with `data-rui-control` so `<rui-field>` can discover it.\n */\nexport function RuiTextarea({\n\tvalue,\n\tplaceholder,\n\tdisabled,\n\tname,\n\trows = 3,\n\tsize = 'md',\n\tclass: className,\n\tid,\n\t'aria-label': ariaLabel,\n\t'on:input': onInput,\n\t'on:change': onChange,\n\t'on:blur': onBlur,\n\t...rest\n}: RuiTextareaProps) {\n\treturn (\n\t\t<textarea\n\t\t\tid={id}\n\t\t\t{...{ [RUI_CONTROL_ATTR]: '' }}\n\t\t\tdata-rui-control-type=\"text\"\n\t\t\tclass={cx('rui-textarea', `rui-textarea--${size}`, className)}\n\t\t\tvalue={value}\n\t\t\tplaceholder={placeholder}\n\t\t\tdisabled={disabled}\n\t\t\trows={rows}\n\t\t\tname={name}\n\t\t\taria-label={ariaLabel}\n\t\t\ton:input={onInput}\n\t\t\ton:change={onChange}\n\t\t\ton:blur={onBlur}\n\t\t\t{...rest}\n\t\t/>\n\t);\n}\n"],
5
+ "mappings": "AAAO,IAAMA,EAAmB,mBAQhC,IAAMC,EAAoB,IAAI,IAAI,CACjC,eACA,eACA,aACA,kBACA,aACA,iBACA,aACD,CAAC,EAEKC,EAAmB,IAAIC,CAAgB,MAAM,MAAM,KAAKF,CAAiB,EAAE,KAAK,IAAI,CAAC,oBChB3F,MAAO,iBAiBP,SAASG,KAAMC,EAAyD,CACvE,OAAOA,EAAM,OAAO,OAAO,EAAE,KAAK,GAAG,CACtC,CAQO,SAASC,EAAY,CAC3B,MAAAC,EACA,YAAAC,EACA,SAAAC,EACA,KAAAC,EACA,KAAAC,EAAO,EACP,KAAAC,EAAO,KACP,MAAOC,EACP,GAAAC,EACA,aAAcC,EACd,WAAYC,EACZ,YAAaC,EACb,UAAWC,EACX,GAAGC,CACJ,EAAqB,CACpB,OACC,oBAAC,YACA,GAAIL,EACE,CAACM,CAAgB,EAAG,GAC1B,wBAAsB,OACtB,MAAOhB,EAAG,eAAgB,iBAAiBQ,CAAI,GAAIC,CAAS,EAC5D,MAAON,EACP,YAAaC,EACb,SAAUC,EACV,KAAME,EACN,KAAMD,EACN,aAAYK,EACZ,WAAUC,EACV,YAAWC,EACX,UAASC,EACR,GAAGC,EACL,CAEF",
6
+ "names": ["RUI_CONTROL_ATTR", "HOST_CONTROL_TAGS", "CONTROL_SELECTOR", "RUI_CONTROL_ATTR", "cx", "parts", "RuiTextarea", "value", "placeholder", "disabled", "name", "rows", "size", "className", "id", "ariaLabel", "onInput", "onChange", "onBlur", "rest", "RUI_CONTROL_ATTR"]
7
+ }
@@ -0,0 +1,33 @@
1
+ @reference '../../../styles/radiant-ui.css';
2
+
3
+ @layer components {
4
+ .rui-textarea {
5
+ @apply w-full resize-y border border-border bg-background text-on-background outline-none;
6
+ border-radius: var(--radius-control);
7
+ padding-inline: var(--space-control-x);
8
+ padding-block: var(--space-control-y);
9
+ font-size: var(--text-control, 0.875rem);
10
+ min-height: calc(var(--space-control-y) * 2 + 1.25rem * 3);
11
+ transition-duration: var(--duration-normal);
12
+ }
13
+
14
+ .rui-textarea:focus-visible {
15
+ @apply ring-2 ring-focus-ring;
16
+ }
17
+
18
+ .rui-textarea:disabled {
19
+ @apply cursor-not-allowed opacity-disabled;
20
+ }
21
+
22
+ .rui-textarea[aria-invalid='true'] {
23
+ @apply border-error;
24
+ }
25
+
26
+ .rui-textarea--sm {
27
+ min-height: calc(var(--space-control-y) * 2 + 1rem * 2);
28
+ }
29
+
30
+ .rui-textarea--lg {
31
+ min-height: calc(var(--space-control-y) * 2 + 1.25rem * 4);
32
+ }
33
+ }
@@ -0,0 +1,23 @@
1
+ import type { RuiInputSize } from '../input';
2
+ import './textarea.css';
3
+ export type RuiTextareaProps = {
4
+ value?: string;
5
+ placeholder?: string;
6
+ disabled?: boolean;
7
+ name?: string;
8
+ rows?: number;
9
+ size?: RuiInputSize;
10
+ class?: string;
11
+ id?: string;
12
+ 'aria-label'?: string;
13
+ 'on:input'?: (event: Event) => void;
14
+ 'on:change'?: (event: Event) => void;
15
+ 'on:blur'?: (event: Event) => void;
16
+ };
17
+ /**
18
+ * Presentational wrapper around a native `<textarea>`.
19
+ *
20
+ * No custom element — Field owns labeling, `aria-*`, and validation wiring.
21
+ * Marked with `data-rui-control` so `<rui-field>` can discover it.
22
+ */
23
+ export declare function RuiTextarea({ value, placeholder, disabled, name, rows, size, class: className, id, 'aria-label': ariaLabel, 'on:input': onInput, 'on:change': onChange, 'on:blur': onBlur, ...rest }: RuiTextareaProps): import("@ecopages/jsx").JsxRenderable;
@@ -0,0 +1,5 @@
1
+ export { RuiToast as RuiToastElement, type RuiToastProps } from './toast.script';
2
+ export { RuiToaster as RuiToasterElement, type RuiToasterProps } from './toaster.script';
3
+ export { RuiToast, RuiToaster, type RuiToastViewProps, type RuiToasterViewProps } from './toast';
4
+ export { toast, showToast, dismissToast, type ToastCallable } from './toast-api';
5
+ export { RUI_TOAST_SHOW_EVENT, RUI_TOAST_DISMISS_EVENT, TOAST_LIFETIME, TOAST_WIDTH, TOAST_GAP, TOAST_VIEWPORT_OFFSET, TOAST_VISIBLE_AMOUNT, TOAST_SWIPE_THRESHOLD, TOAST_EXIT_MS, DEFAULT_TOAST_POSITION, type ToastVariant, type ToastPosition, type ToastAction, type ToastId, type ToastOptions, type ToastRecord, type ToastDismissDetail, type ToastShowDetail, type PromiseToastMessages, } from './toast-context';
@@ -0,0 +1,2 @@
1
+ import{RadiantElement as q,bound as V,customElement as X,onEvent as B,onUpdated as I,prop as c,query as Y}from"@ecopages/radiant";var v="rui-toast-show",f="rui-toast-dismiss",y=4e3,w=356,O=14,R=24,A=3,b=45,_=200,g="bottom-end";function h(i){let[t,e]=i.split("-");return{y:t,x:e}}var W=1;function $(){return W++}function C(i,t){return typeof i=="function"?i(t):i}var D=class{subscribers=[];toasts=[];subscribe=t=>(this.subscribers.push(t),t(this.toasts),()=>{let e=this.subscribers.indexOf(t);e>=0&&this.subscribers.splice(e,1)});getSnapshot=()=>this.toasts;publish(){let t=this.toasts;for(let e of this.subscribers)e(t)}create=(t,e={})=>{let s=e.id??$(),n=e.dismissible??!0,o=this.toasts.findIndex(r=>r.id===s),a={id:s,title:t,description:e.description,variant:e.variant??"default",duration:e.duration,action:e.action,dismissible:n,closeButton:e.closeButton,position:e.position,delete:!1};return o>=0?this.toasts=this.toasts.map(r=>r.id===s?{...r,...a,delete:!1}:r):this.toasts=[a,...this.toasts],this.publish(),s};dismiss=t=>{if(t==null){if(this.toasts.length===0)return;this.toasts=this.toasts.map(e=>({...e,delete:!0}))}else{let e=this.toasts.find(s=>s.id===t);if(!e||e.delete)return;this.toasts=this.toasts.map(s=>s.id===t?{...s,delete:!0}:s)}this.publish()};remove=t=>{this.toasts=this.toasts.filter(e=>e.id!==t),this.publish()};clear=()=>{this.toasts.length!==0&&(this.toasts=[],this.publish())};message=(t,e)=>this.create(t,e);success=(t,e)=>this.create(t,{...e,variant:"success"});error=(t,e)=>this.create(t,{...e,variant:"error"});info=(t,e)=>this.create(t,{...e,variant:"info"});warning=(t,e)=>this.create(t,{...e,variant:"warning"});loading=(t,e)=>this.create(t,{...e,variant:"loading",duration:e?.duration??Number.POSITIVE_INFINITY});promise=(t,e)=>{let s=this.loading(e.loading,{duration:Number.POSITIVE_INFINITY,action:e.action,closeButton:e.closeButton,position:e.position,description:typeof e.description=="string"?e.description:void 0});return(typeof t=="function"?t():t).then(o=>{let a=typeof e.description=="function"?e.description(o):e.description;this.create(C(e.success,o),{id:s,variant:"success",description:a,duration:e.duration,action:e.action,closeButton:e.closeButton,position:e.position})}).catch(o=>{let a=typeof e.description=="function"?e.description(o):e.description;this.create(C(e.error,o),{id:s,variant:"error",description:a,duration:e.duration,action:e.action,closeButton:e.closeButton,position:e.position})}),s}},p=new D;var S=@X("rui-toast")class extends q{@c({type:String,reflect:!0,defaultValue:""})toastId;@c({type:String,defaultValue:""})title;@c({type:String,defaultValue:""})description;@c({type:String,reflect:!0,defaultValue:"default"})variant;@c({type:Number,defaultValue:4e3})duration;@c({type:Boolean,defaultValue:!0})dismissible;@c({type:Boolean,defaultValue:!1})closeButton;@c({type:String,defaultValue:""})actionLabel;@c({type:String,defaultValue:g})position;@c({type:Boolean,defaultValue:!1})markedDelete;@Y({ref:"toast"})toastTarget;mounted=!1;removed=!1;swiping=!1;swipeOut=!1;swipeAxis=null;swipeOutDirection=null;held=!1;timerReady=!1;timeoutId=null;pointerStart=null;dragStartTime=null;exitTimer=null;connectedCallback(){super.connectedCallback();let t=this.mounted;if(this.addEventListener("pointerdown",this.onPointerDown),this.addEventListener("pointermove",this.onPointerMove),this.addEventListener("pointerup",this.onPointerUp),this.addEventListener("pointercancel",this.onPointerUp),t){this.syncDomState(),this.dispatchEvent(new CustomEvent("rui-toast-mounted",{bubbles:!0}));return}this.timerReady=!1,requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.isConnected&&(this.mounted=!0,this.timerReady=!0,this.syncDomState(),this.dispatchEvent(new CustomEvent("rui-toast-mounted",{bubbles:!0})))})}),this.syncDomState()}disconnectedCallback(){this.clearTimer(),this.exitTimer&&(clearTimeout(this.exitTimer),this.exitTimer=null);let t=this.resolvedId;t!==""&&this.removed&&p.remove(t),this.held=!1,this.timerReady=!1,this.removeEventListener("pointerdown",this.onPointerDown),this.removeEventListener("pointermove",this.onPointerMove),this.removeEventListener("pointerup",this.onPointerUp),this.removeEventListener("pointercancel",this.onPointerUp),super.disconnectedCallback()}@I(["title","description","variant","actionLabel","closeButton"])onContentUpdated(){this.requestUpdate()}@I("position")onPositionUpdated(){this.syncDomState()}setPaused(t){if(this.held===t){!t&&this.timerReady&&this.mounted&&!this.removed&&!this.timeoutId&&this.startTimer();return}this.held=t,!(!this.timerReady||!this.mounted||this.removed)&&(t||document.hidden?this.clearTimer():this.startTimer())}@I("duration")onDurationUpdated(){!this.timerReady||!this.mounted||this.removed||this.held||this.startTimer()}@I("markedDelete")onMarkedDeleteUpdated(){this.markedDelete&&!this.removed&&this.beginRemove()}get resolvedId(){let t=this.toastId;if(t==null||t==="")return"";let e=Number(t);return Number.isFinite(e)&&String(e)===t?e:t}clearTimer(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}startTimer(){if(!(this.held||this.removed||document.hidden)&&!(this.duration===Number.POSITIVE_INFINITY||this.variant==="loading")){if(this.duration<=0){this.beginRemove();return}this.clearTimer(),this.timeoutId=setTimeout(()=>this.beginRemove(),this.duration)}}beginRemove(){this.removed||(this.removed=!0,this.clearTimer(),this.syncDomState(),this.markedDelete||p.dismiss(this.resolvedId),this.exitTimer=setTimeout(()=>{this.exitTimer=null,p.remove(this.resolvedId)},200))}@V onPointerDown(t){!this.dismissible||this.variant==="loading"||t.button!==0||t.target?.closest("[data-toast-close], [data-toast-action], button, a")||(this.dragStartTime=Date.now(),this.pointerStart={x:t.clientX,y:t.clientY},this.swipeAxis=null,this.setPointerCapture(t.pointerId))}@V onPointerMove(t){if(!this.pointerStart)return;let{y:e,x:s}=h(this.position),n=t.clientX-this.pointerStart.x,o=t.clientY-this.pointerStart.y;if(!this.swiping){if(Math.abs(n)<8&&Math.abs(o)<8)return;this.swiping=!0,this.syncDomState()}this.swipeAxis||(this.swipeAxis=Math.abs(n)>Math.abs(o)?"x":"y");let a=this.swipeAxis==="x"?n:0,r=this.swipeAxis==="y"?o:0;if(this.swipeAxis==="y"&&!(e==="bottom"?r>0:r<0)&&Math.abs(r)<45){this.style.setProperty("--swipe-amount-x","0px"),this.style.setProperty("--swipe-amount-y","0px");return}if(this.swipeAxis==="x"){let u=s==="start"?a<0:a>0;if(s!=="center"&&!u&&Math.abs(a)<45){this.style.setProperty("--swipe-amount-x","0px"),this.style.setProperty("--swipe-amount-y","0px");return}}this.style.setProperty("--swipe-amount-x",`${a}px`),this.style.setProperty("--swipe-amount-y",`${r}px`)}@V onPointerUp(t){if(!this.pointerStart)return;try{this.releasePointerCapture(t.pointerId)}catch{}let e=this.swiping;if(this.swiping=!1,!e){this.pointerStart=null,this.dragStartTime=null,this.swipeAxis=null;return}let s=Number.parseFloat(this.style.getPropertyValue("--swipe-amount-x")||"0"),n=Number.parseFloat(this.style.getPropertyValue("--swipe-amount-y")||"0"),o=this.swipeAxis==="x"?s:n,a=this.dragStartTime?Date.now()-this.dragStartTime:0,r=Math.abs(o)/Math.max(a,1);if((Math.abs(o)>=45||r>.11)&&this.dismissible){let{y:m,x:l}=h(this.position);this.swipeAxis==="x"?(this.swipeOutDirection=s<0?"left":"right",l==="start"&&(this.swipeOutDirection="left"),l==="end"&&(this.swipeOutDirection="right")):this.swipeOutDirection=m==="bottom"?"down":"up",this.swipeOut=!0,this.syncDomState(),this.beginRemove()}else this.style.setProperty("--swipe-amount-x","0px"),this.style.setProperty("--swipe-amount-y","0px"),this.swipeAxis=null,this.syncDomState();this.pointerStart=null,this.dragStartTime=null}@B({selector:"[data-toast-close]",type:"click"})onCloseClick(t){t.stopPropagation(),this.dismissible&&this.beginRemove()}@B({selector:"[data-toast-action]",type:"click"})onActionClick(t){t.stopPropagation(),p.getSnapshot().find(s=>s.id===this.resolvedId)?.action?.onClick(t),this.dismissible&&this.beginRemove()}syncDomState(){let{y:t,x:e}=h(this.position);this.setAttribute("role","listitem"),this.dataset.mounted=String(this.mounted),this.dataset.removed=String(this.removed),this.dataset.swiping=String(this.swiping),this.dataset.swipeOut=String(this.swipeOut),this.dataset.dismissible=String(this.dismissible),this.dataset.yPosition=t,this.dataset.xPosition=e,this.dataset.variant=this.variant??"default",this.swipeOutDirection?this.dataset.swipeDirection=this.swipeOutDirection:delete this.dataset.swipeDirection}iconForVariant(){switch(this.variant){case"success":return"\u2713";case"error":return"\u2715";case"warning":return"!";case"info":return"i";default:return""}}render(){let t=this.variant??"default",e=this.iconForVariant(),s=t!=="default";return React.createElement("div",{ref:"toast",class:`rui-toast rui-toast--${t}`,role:"status","aria-live":"off","data-ref":"toast"},this.closeButton&&t!=="loading"?React.createElement("button",{type:"button",class:"rui-toast__close","data-toast-close":!0,"aria-label":"Close toast"},"\xD7"):null,s?React.createElement("span",{class:"rui-toast__icon","data-icon":!0,"aria-hidden":"true"},t==="loading"?React.createElement("span",{class:"rui-toast__loader"}):e):null,React.createElement("div",{class:"rui-toast__content"},React.createElement("div",{class:"rui-toast__title","data-title":!0},this.$.title),this.description?React.createElement("div",{class:"rui-toast__description","data-description":!0},this.$.description):null),this.actionLabel?React.createElement("button",{type:"button",class:"rui-toast__action rui-button rui-button--outline rui-button--sm","data-toast-action":!0},this.$.actionLabel):null)}};import{RadiantElement as z,bound as P,customElement as G,onEvent as L,onUpdated as J,prop as T,state as j}from"@ecopages/radiant";function k(i,t){return i instanceof Node&&t.contains(i)}var x=@G("rui-toaster")class extends z{@T({type:String,reflect:!0,defaultValue:g})position;@T({type:Number,defaultValue:4e3})duration;@T({type:Number,defaultValue:3})visibleToasts;@T({type:Boolean,defaultValue:!1})closeButton;@T({type:Boolean,defaultValue:!1})expand;@T({type:Number,defaultValue:14})gap;@T({type:Number,defaultValue:24})offset;@j toasts=[];expanded=!1;interacting=!1;unsubscribe=null;visibilityHandler=null;heights=new Map;observers=new Map;layoutFrame=null;connectedCallback(){super.connectedCallback(),this.syncHostPosition(),this.unsubscribe=p.subscribe(t=>{this.toasts=t,t.length===0&&this.resetLayoutState(),this.scheduleLayoutSync()}),this.visibilityHandler=()=>this.syncPauseState(),document.addEventListener("visibilitychange",this.visibilityHandler)}disconnectedCallback(){this.unsubscribe?.(),this.unsubscribe=null,this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),document.removeEventListener("pointerup",this.onPointerUp),document.removeEventListener("pointercancel",this.onPointerUp),this.layoutFrame!=null&&cancelAnimationFrame(this.layoutFrame),this.resetLayoutState(),super.disconnectedCallback()}@J(["position","duration","visibleToasts","closeButton","expand","gap","offset"])onConfigUpdated(){this.syncHostPosition(),this.scheduleLayoutSync()}@L({document:!0,type:v})onDocumentShow(t){let e=t.detail;e?.title&&p.create(e.title,{id:e.id,description:e.description,variant:e.variant,duration:e.duration,action:e.action,dismissible:e.dismissible,closeButton:e.closeButton,position:e.position})}@L({document:!0,type:f})onDocumentDismiss(t){let e=t.detail;p.dismiss(e?.id)}@L({selector:"rui-toast",type:"rui-toast-mounted"})onToastMounted(){this.observeToasts(),this.syncPauseState()}filteredToasts(){let t=this.toasts.filter(n=>(n.position??this.position)===this.position),e=[],s=[];for(let n of t)n.delete?s.push(n):e.push(n);return[...e.slice(0,this.visibleToasts),...s]}syncHostPosition(){let{y:t,x:e}=h(this.position);this.dataset.yPosition=t,this.dataset.xPosition=e,this.style.setProperty("--width",`${356}px`),this.style.setProperty("--gap",`${this.gap}px`),this.style.setProperty("--viewport-offset",`${this.offset}px`)}isStackExpanded(){return this.expanded||this.expand}isPaused(){return this.isStackExpanded()||this.interacting||document.hidden}resetLayoutState(){for(let e of this.observers.values())e.disconnect();this.observers.clear(),this.heights.clear(),this.expanded=!1,this.interacting=!1;let t=this.querySelector(".rui-toaster");t&&(t.style.height="0px",t.dataset.expanded="false"),this.dataset.expanded="false"}syncPauseState(){let t=this.isPaused();for(let e of this.querySelectorAll("rui-toast"))e.setPaused(t);this.patchStackLayout()}scheduleLayoutSync(){this.layoutFrame!=null&&cancelAnimationFrame(this.layoutFrame),this.layoutFrame=requestAnimationFrame(()=>{if(this.layoutFrame=null,this.toasts.length>0&&!this.interacting){let e=!!(this.querySelector(".rui-toaster")?.matches(":hover")||this.matches(":hover"));this.expanded=e}this.observeToasts(),this.syncPauseState()})}measureToast(t){let e=t.style.height,s=t.style.overflow;t.style.height="auto",t.style.overflow="visible";let n=t.querySelector(".rui-toast"),o=Math.round(n instanceof HTMLElement?n.offsetHeight:t.offsetHeight)||64;return t.style.height=e,t.style.overflow=s,o}observeToasts(){let t=this.querySelector(".rui-toaster");if(!t)return;let e=[...t.querySelectorAll("rui-toast")],s=new Set;for(let n of e){let o=n.toastId;if(!o)continue;s.add(o);let a=n.querySelector(".rui-toast")??n;if(!this.observers.has(o)){let r=new ResizeObserver(()=>{let u=this.measureToast(n);this.heights.get(o)!==u&&(this.heights.set(o,u),this.patchStackLayout())});r.observe(a),this.observers.set(o,r)}this.heights.set(o,this.measureToast(n))}for(let[n,o]of[...this.observers])s.has(n)||(o.disconnect(),this.observers.delete(n),this.heights.delete(n))}patchStackLayout(){let t=this.querySelector(".rui-toaster");if(!t)return;let e=this.isStackExpanded(),{y:s}=h(this.position),n=s==="bottom"?-1:1;this.dataset.expanded=String(e),t.dataset.expanded=String(e);let o=[...t.querySelectorAll("rui-toast")].filter(l=>l.dataset.mounted==="true"&&l.dataset.removed!=="true");if(o.length===0){t.style.height="0px";return}let a=o.map(l=>{let d=this.heights.get(l.toastId)??this.measureToast(l);return this.heights.set(l.toastId,d),d}),r=a[0]??64,u=0;for(let l=0;l<o.length;l+=1){let d=o[l];if(!d)continue;let E=a[l]??64,N=l===0;if(d.dataset.index=String(l),d.dataset.front=String(N),d.dataset.expanded=String(e),d.style.setProperty("--z-index",String(o.length-l)),e)d.style.setProperty("--y",`translateY(${n*u}px)`),d.style.height=`${E}px`,d.style.overflow="visible",u+=E+this.gap;else if(N)d.style.setProperty("--y","translateY(0px)"),d.style.height=`${E}px`,d.style.overflow="visible";else{let H=Math.max(.7,1-l*.05);d.style.setProperty("--y",`translateY(${n*l*this.gap}px) scale(${H})`),d.style.height=`${r}px`,d.style.overflow="hidden"}}let m=e?Math.max(0,u>0?u-this.gap:r):r+Math.max(0,o.length-1)*this.gap;t.style.height=`${m}px`}@P onPointerOver(t){k(t.relatedTarget,this)||(this.expanded=!0,this.syncPauseState())}@P onPointerOut(t){k(t.relatedTarget,this)||this.interacting||(this.expanded=!1,this.syncPauseState())}@P onPointerDown(){this.interacting=!0,this.expanded=!0,this.syncPauseState(),document.addEventListener("pointerup",this.onPointerUp,{once:!0}),document.addEventListener("pointercancel",this.onPointerUp,{once:!0})}@P onPointerUp(){if(!this.interacting)return;this.interacting=!1,this.matches(":hover")||this.querySelector("rui-toast:hover")||(this.expanded=!1),this.syncPauseState()}render(){let t=this.filteredToasts();return React.createElement("section",{class:"rui-toaster-region","aria-label":"Notifications","aria-live":"polite","aria-relevant":"additions text","aria-atomic":"false",tabIndex:-1},React.createElement("ol",{class:"rui-toaster","data-rui-toaster":!0,"on:pointerover":this.onPointerOver,"on:pointerout":this.onPointerOut,"on:pointerdown":this.onPointerDown},t.map(e=>{let s=e.duration??(e.variant==="loading"?Number.POSITIVE_INFINITY:this.duration);return React.createElement("rui-toast",{key:String(e.id),"prop:toastId":String(e.id),"prop:title":e.title,"prop:description":e.description??"","prop:variant":e.variant,"prop:duration":s,"prop:dismissible":e.dismissible,"prop:closeButton":e.closeButton??this.closeButton,"prop:actionLabel":e.action?.label??"","prop:position":e.position??this.position,"prop:markedDelete":!!e.delete})})))}};var K=Symbol.for("@ecopages/storybook-radiant.viewElement"),U=Symbol.for("@ecopages/storybook-radiant.scriptModule"),F=Symbol.for("@ecopages/storybook-radiant.scriptExport");function Q(i,t){i[K]=t;let e=t[U];e&&(i[U]=e,i[F]=t[F]??t.name)}function M(i,t){let e=(s=>t(s));return Q(e,i),e}import"./toast.css";var Z=M(S,({slot:i,toastId:t,title:e,description:s,variant:n,duration:o,dismissible:a,closeButton:r,actionLabel:u,position:m,markedDelete:l})=>React.createElement("rui-toast",{slot:i,"prop:toastId":t!=null?String(t):void 0,"prop:title":e,"prop:description":s,"prop:variant":n,"prop:duration":o,"prop:dismissible":a,"prop:closeButton":r,"prop:actionLabel":u,"prop:position":m,"prop:markedDelete":l})),tt=M(x,({slot:i,position:t,duration:e,visibleToasts:s,closeButton:n,expand:o,gap:a,offset:r,children:u})=>React.createElement("rui-toaster",{slot:i,"prop:position":t,"prop:duration":e,"prop:visibleToasts":s,"prop:closeButton":n,"prop:expand":o,"prop:gap":a,"prop:offset":r},u));var et=Object.assign((i,t)=>p.create(i,t),{message:(i,t)=>p.message(i,t),success:(i,t)=>p.success(i,t),error:(i,t)=>p.error(i,t),info:(i,t)=>p.info(i,t),warning:(i,t)=>p.warning(i,t),loading:(i,t)=>p.loading(i,t),promise:(i,t)=>p.promise(i,t),dismiss:i=>p.dismiss(i),clear:()=>p.clear()});function it(i){document.dispatchEvent(new CustomEvent(v,{detail:i,bubbles:!0,composed:!0}))}function st(i){let t=i==null?{}:{id:i};document.dispatchEvent(new CustomEvent(f,{detail:t,bubbles:!0,composed:!0}))}export{g as DEFAULT_TOAST_POSITION,f as RUI_TOAST_DISMISS_EVENT,v as RUI_TOAST_SHOW_EVENT,Z as RuiToast,S as RuiToastElement,tt as RuiToaster,x as RuiToasterElement,_ as TOAST_EXIT_MS,O as TOAST_GAP,y as TOAST_LIFETIME,b as TOAST_SWIPE_THRESHOLD,R as TOAST_VIEWPORT_OFFSET,A as TOAST_VISIBLE_AMOUNT,w as TOAST_WIDTH,st as dismissToast,it as showToast,et as toast};
2
+ //# sourceMappingURL=index.js.map