@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,141 @@
1
+ import type { JsxRenderable } from '@ecopages/jsx';
2
+ import type { RadiantSlotProps } from '../../../types';
3
+ import type { RuiSidebarProps } from './sidebar.script';
4
+ import type { RuiSidebarTriggerProps } from './sidebar-trigger.script';
5
+ import './sidebar.css';
6
+ export type RuiSidebarProviderProps = {
7
+ /** Layout context. `default` is the standard shell; `full` removes chrome. */
8
+ layout?: 'default' | 'full';
9
+ /** Slot for the sidebar element. */
10
+ sidebar?: JsxRenderable;
11
+ /** Slot for the inset (main content). */
12
+ children?: JsxRenderable;
13
+ /** Extra class names. */
14
+ class?: string;
15
+ };
16
+ /**
17
+ * `<div>` shell that wraps the sidebar and the main inset. Reflects
18
+ * `data-layout` so stylesheets can adapt. Plays the role of
19
+ * `SidebarProvider` from common sidebar kits, but without a runtime context —
20
+ * coordination between trigger, sidebar, and inset is achieved through
21
+ * `id`/`aria-controls` and shared `data-*` attributes.
22
+ */
23
+ export declare function RuiSidebarProvider({ layout, sidebar, children, class: className, }: RuiSidebarProviderProps): JsxRenderable;
24
+ export type RuiSidebarHeaderProps = {
25
+ children: JsxRenderable;
26
+ class?: string;
27
+ /** Accessible name for the header region. */
28
+ 'aria-label'?: string;
29
+ };
30
+ /** Top section of the sidebar pane (logo, search, primary trigger). */
31
+ export declare function RuiSidebarHeader({ children, class: className, 'aria-label': ariaLabel }: RuiSidebarHeaderProps): JsxRenderable;
32
+ export type RuiSidebarContentProps = {
33
+ children: JsxRenderable;
34
+ class?: string;
35
+ /** Optional label for the scrolling content region. */
36
+ 'aria-label'?: string;
37
+ };
38
+ /** Scrollable middle section. Multiple allowed; each becomes its own region. */
39
+ export declare function RuiSidebarContent({ children, class: className, 'aria-label': ariaLabel }: RuiSidebarContentProps): JsxRenderable;
40
+ export type RuiSidebarFooterProps = {
41
+ children: JsxRenderable;
42
+ class?: string;
43
+ };
44
+ /** Pinned bottom section (user, theme toggle, settings). */
45
+ export declare function RuiSidebarFooter({ children, class: className }: RuiSidebarFooterProps): JsxRenderable;
46
+ export type RuiSidebarSeparatorProps = {
47
+ class?: string;
48
+ /** Accessible label for the separator. */
49
+ 'aria-label'?: string;
50
+ };
51
+ /** Horizontal rule between sidebar sections. */
52
+ export declare function RuiSidebarSeparator({ class: className, 'aria-label': ariaLabel }: RuiSidebarSeparatorProps): JsxRenderable;
53
+ export type RuiSidebarGroupProps = {
54
+ children: JsxRenderable;
55
+ class?: string;
56
+ /** Accessible label for the group region. */
57
+ 'aria-label'?: string;
58
+ };
59
+ /** Landmark group of related sidebar items. */
60
+ export declare function RuiSidebarGroup({ children, class: className, 'aria-label': ariaLabel }: RuiSidebarGroupProps): JsxRenderable;
61
+ export type RuiSidebarGroupLabelProps = {
62
+ children: JsxRenderable;
63
+ class?: string;
64
+ /** Optional `id` so the group can be referenced by `aria-labelledby`. */
65
+ id?: string;
66
+ };
67
+ /** Heading for a sidebar group. */
68
+ export declare function RuiSidebarGroupLabel({ children, class: className, id }: RuiSidebarGroupLabelProps): JsxRenderable;
69
+ export type RuiSidebarGroupActionProps = {
70
+ children: JsxRenderable;
71
+ class?: string;
72
+ /** Accessible label for the action button. */
73
+ 'aria-label'?: string;
74
+ };
75
+ /** Top-right action button inside a group header. */
76
+ export declare function RuiSidebarGroupAction({ children, class: className, 'aria-label': ariaLabel, }: RuiSidebarGroupActionProps): JsxRenderable;
77
+ export type RuiSidebarGroupHeaderProps = {
78
+ label: JsxRenderable;
79
+ action?: JsxRenderable;
80
+ class?: string;
81
+ };
82
+ /** Convenience: a label + optional action in one row. */
83
+ export declare function RuiSidebarGroupHeader({ label, action, class: className }: RuiSidebarGroupHeaderProps): JsxRenderable;
84
+ export type RuiSidebarMenuProps = {
85
+ children: JsxRenderable;
86
+ class?: string;
87
+ /** Accessible label for the menu list. */
88
+ 'aria-label'?: string;
89
+ };
90
+ /** `<ul>` of sidebar items. */
91
+ export declare function RuiSidebarMenu({ children, class: className, 'aria-label': ariaLabel }: RuiSidebarMenuProps): JsxRenderable;
92
+ export type RuiSidebarMenuItemProps = {
93
+ children: JsxRenderable;
94
+ class?: string;
95
+ };
96
+ /** `<li>` of a sidebar menu. */
97
+ export declare function RuiSidebarMenuItem({ children, class: className }: RuiSidebarMenuItemProps): JsxRenderable;
98
+ export type RuiSidebarMenuButtonProps = {
99
+ children: JsxRenderable;
100
+ class?: string;
101
+ /** Mark this button as the current page. */
102
+ isActive?: boolean;
103
+ /** Render as a different element via the `as` prop. Default: `a` when `href` is set, else `button`. */
104
+ as?: 'a' | 'button';
105
+ /** Forwarded to anchor or button. */
106
+ href?: string;
107
+ type?: 'button' | 'submit' | 'reset';
108
+ /** Optional tooltip label for collapsed-icon mode. */
109
+ tooltip?: string;
110
+ disabled?: boolean;
111
+ /** Click handler for `button` mode. */
112
+ onClick?: (event: Event) => void;
113
+ };
114
+ /**
115
+ * The clickable surface inside a `RuiSidebarMenuItem`. When the sidebar
116
+ * collapses to icon mode, only this element remains visible; it must keep an
117
+ * accessible name via `tooltip` or visible children.
118
+ */
119
+ export declare function RuiSidebarMenuButton({ children, class: className, isActive, as, href, type, tooltip, disabled, onClick, }: RuiSidebarMenuButtonProps): JsxRenderable;
120
+ export type RuiSidebarMenuActionProps = RuiSidebarMenuButtonProps;
121
+ /** Smaller, secondary button (e.g. `+ New`) below a menu or group. */
122
+ export declare function RuiSidebarMenuAction(props: RuiSidebarMenuActionProps): JsxRenderable;
123
+ export type RuiSidebarInsetProps = {
124
+ children: JsxRenderable;
125
+ class?: string;
126
+ /** Optional `id` so the sidebar trigger can target the main landmark. */
127
+ id?: string;
128
+ };
129
+ /** The main content area that sits next to the sidebar. */
130
+ export declare function RuiSidebarInset({ children, class: className, id }: RuiSidebarInsetProps): JsxRenderable;
131
+ export type RuiSidebarViewProps = RuiSidebarProps & RadiantSlotProps & {
132
+ id: string;
133
+ children: JsxRenderable;
134
+ class?: string;
135
+ };
136
+ export declare const RuiSidebar: import("../../../lib/radiant-view").RadiantViewComponent<RuiSidebarViewProps>;
137
+ export type RuiSidebarTriggerViewProps = RuiSidebarTriggerProps & RadiantSlotProps & {
138
+ children?: JsxRenderable;
139
+ class?: string;
140
+ };
141
+ export declare const RuiSidebarTrigger: import("../../../lib/radiant-view").RadiantViewComponent<RuiSidebarTriggerViewProps>;
@@ -0,0 +1,140 @@
1
+ import { RadiantElement } from '@ecopages/radiant';
2
+ import type { EventEmitter } from '@ecopages/radiant/tools/event-emitter';
3
+ export type RuiSidebarVariant = 'sidebar' | 'inset';
4
+ export type RuiSidebarSide = 'left' | 'right';
5
+ export type RuiSidebarCollapsible = 'off' | 'icon' | 'full';
6
+ export type RuiSidebarState = 'expanded' | 'collapsed';
7
+ export type RuiSidebarProps = {
8
+ /** Visual treatment. `sidebar` is the default bordered pane; `inset` floats inside a card. Default: `sidebar`. */
9
+ variant?: RuiSidebarVariant;
10
+ /** Which edge the sidebar sits on. Default: `left`. */
11
+ side?: RuiSidebarSide;
12
+ /** Collapse behavior. `off` keeps the pane open; `icon` collapses to an icon rail; `full` collapses fully. Default: `off`. */
13
+ collapsible?: RuiSidebarCollapsible;
14
+ /** Initial open state when uncontrolled. Default: `true`. */
15
+ defaultOpen?: boolean;
16
+ /** Controlled open state. */
17
+ open?: boolean;
18
+ /** Initial width in pixels when uncontrolled. Default: `256`. */
19
+ defaultWidth?: number;
20
+ /** Controlled width in pixels. */
21
+ width?: number;
22
+ /** Minimum width in pixels when resizing. Default: `200`. */
23
+ minWidth?: number;
24
+ /** Maximum width in pixels when resizing. Default: `480`. */
25
+ maxWidth?: number;
26
+ /** Hide on viewports below this width. Default: `768`. */
27
+ mobileBreakpoint?: number;
28
+ /** Accessible name announced by the pane landmark and triggers. Default: `Sidebar`. */
29
+ label?: string;
30
+ };
31
+ export type RuiSidebarToggleDetail = {
32
+ open: boolean;
33
+ state: RuiSidebarState;
34
+ };
35
+ export type RuiSidebarResizeDetail = {
36
+ width: number;
37
+ };
38
+ type RuiSidebarBindings = {
39
+ label: string;
40
+ };
41
+ /**
42
+ * `<rui-sidebar>` — a resizable, collapsible side panel.
43
+ *
44
+ * The sidebar hosts the pane content in the default slot. When the parent
45
+ * supplies a `RuiSidebarRail` element (or the `collapsible` mode is not
46
+ * `off`), the sidebar manages open/closed state, a focusable resize handle,
47
+ * and keyboard navigation that follows the APG Window Splitter pattern.
48
+ *
49
+ * When `collapsible="off"` (the default), the pane stays open and exposes
50
+ * a draggable resize handle. When `collapsible="icon"`, the pane collapses
51
+ * to a narrow rail. When `collapsible="full"`, the pane is hidden until
52
+ * toggled, and shown as an overlay drawer below the mobile breakpoint.
53
+ *
54
+ * The host reflects `data-state`, `data-collapsible`, `data-variant`,
55
+ * `data-side`, and `data-mobile` so the stylesheet can drive every visual
56
+ * mode without imperative JS.
57
+ *
58
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/
59
+ *
60
+ * @element rui-sidebar
61
+ * @slot - Pane content. Stack header, content, and footer inside.
62
+ * @fires rui-sidebar-toggle - Emitted on every open/closed transition.
63
+ * `detail` is `{ open, state }`.
64
+ * @fires rui-sidebar-resize - Emitted on every width change. `detail` is `{ width }`.
65
+ * @fires rui-sidebar-mobile-change - Emitted when the host flips between
66
+ * mobile drawer mode and inline mode. `detail` is `{ mobile: boolean }`.
67
+ */
68
+ export declare class RuiSidebar extends RadiantElement<RuiSidebarBindings> {
69
+ variant: RuiSidebarVariant;
70
+ side: RuiSidebarSide;
71
+ collapsible: RuiSidebarCollapsible;
72
+ defaultWidth: number;
73
+ width: number | undefined;
74
+ minWidth: number;
75
+ maxWidth: number;
76
+ defaultOpen: boolean;
77
+ open: boolean | undefined;
78
+ mobileBreakpoint: number;
79
+ label: string;
80
+ rootTarget: HTMLElement;
81
+ paneTarget: HTMLElement;
82
+ handleTarget: HTMLElement;
83
+ scrimTarget: HTMLButtonElement;
84
+ toggleEvent: EventEmitter<RuiSidebarToggleDetail>;
85
+ resizeEvent: EventEmitter<RuiSidebarResizeDetail>;
86
+ mobileChangeEvent: EventEmitter<{
87
+ mobile: boolean;
88
+ }>;
89
+ isMobile: boolean;
90
+ private mediaQuery;
91
+ private readonly mediaListener;
92
+ private dragging;
93
+ private dragStartCoord;
94
+ private dragStartSize;
95
+ connectedCallback(): void;
96
+ disconnectedCallback(): void;
97
+ /**
98
+ * Keep host `data-*` in sync for `:has(> rui-sidebar[...])` and public API.
99
+ * Visual styles target the inner `.rui-sidebar` root (host is `display: contents`).
100
+ */
101
+ private syncHostAttributes;
102
+ private isOpen;
103
+ /**
104
+ * Optional `Number` props initialize to `0` when no attribute/default is set
105
+ * (`defaultValueForType(Number)`). Treat that unset `0` as “use defaultWidth”.
106
+ */
107
+ private ensureWidthInitialized;
108
+ onStateUpdated(): void;
109
+ onMobileBreakpointUpdated(): void;
110
+ private unbindMobileMediaQuery;
111
+ private bindMobileMediaQuery;
112
+ private setMobile;
113
+ private clampWidth;
114
+ private paneWidth;
115
+ /** Drive layout through the CSS variable only — never set inline pane width. */
116
+ private syncPaneWidthVar;
117
+ private applyWidth;
118
+ toggle(): void;
119
+ setOpen(next: boolean): void;
120
+ private beginDrag;
121
+ private endDrag;
122
+ private onPointerMove;
123
+ private onPointerUp;
124
+ private onHandlePointerDown;
125
+ private onHandleKeydown;
126
+ private onScrimClick;
127
+ onHostKeydown(event: Event): void;
128
+ /**
129
+ * Only the pane's `aria-label` is bound below. `data-state`/`data-collapsible`/
130
+ * `data-variant`/`data-side`/`data-mobile` and the handle's `aria-value*`/
131
+ * `aria-orientation` stay plain reads deliberately — this component's open/
132
+ * close, drag-resize, and mobile-detection paths are the same high-frequency
133
+ * interactive category where two sibling components in this migration
134
+ * (tooltip, menu-button) hit real regressions from binding conversion that
135
+ * weren't fully root-caused. Deferred as a follow-up rather than risking the
136
+ * same class of bug here under the same review budget.
137
+ */
138
+ render(): import("@ecopages/jsx").JsxRenderable;
139
+ }
140
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export { RuiSlider as RuiSliderElement, type RuiSliderProps, type RuiSliderChangeDetail } from './slider.script';
2
+ export { RuiSlider } from './slider';
@@ -0,0 +1,2 @@
1
+ import{RadiantElement as T,customElement as M,event as R,onEvent as s,onUpdated as h,prop as r,query as u}from"@ecopages/radiant";var m=@M("rui-slider")class extends T{@r({type:String,defaultValue:"single"})variant;@r({type:Number,reflect:!0,defaultValue:50})value;@r({type:Number,reflect:!0,attribute:"range-min",defaultValue:25})rangeMin;@r({type:Number,reflect:!0,attribute:"range-max",defaultValue:75})rangeMax;@r({type:Number,defaultValue:0})min;@r({type:Number,defaultValue:100})max;@r({type:Number,defaultValue:1})step;@r({type:Number,defaultValue:0})minDistance;@r({type:Boolean,reflect:!0,defaultValue:!1})disabled;@r({type:String,defaultValue:""})label;@r({type:String,defaultValue:""})name;@R({name:"rui-change",bubbles:!0,composed:!0})changeEvent;@u({ref:"input"})inputTarget;@u({ref:"value"})valueTarget;@u({ref:"rangeMinThumb"})rangeMinThumb;@u({ref:"rangeMaxThumb"})rangeMaxThumb;@u({ref:"rangeFill"})rangeFill;interacting=!1;activeThumb=null;pendingRange=null;resolvedDisabledTabindex=this.$.disabled.map(e=>e?-1:0);resolvedMinLabel=this.$.label.map(e=>e?`${e} minimum`:"Minimum value");resolvedMaxLabel=this.$.label.map(e=>e?`${e} maximum`:"Maximum value");resolvedName=this.$.name.map(e=>e||void 0);connectedCallback(){super.connectedCallback(),queueMicrotask(()=>{this.variant==="single"?this.syncInputFromValue():this.syncRangeUi()})}@h(["value","min","max","step","variant"])onSinglePropsUpdated(){this.variant!=="single"||this.interacting||this.syncInputFromValue()}@h(["rangeMin","rangeMax","min","max","step","minDistance","variant"])onRangePropsUpdated(){this.variant!=="range"||this.activeThumb||this.syncRangeUi()}clamp(e){let t=Math.round(e/this.step)*this.step;return Math.min(this.max,Math.max(this.min,t))}normalizeRange(e=this.rangeMin,t=this.rangeMax){let i=this.clamp(e),a=this.clamp(t);return i>a&&([i,a]=[a,i]),a-i<this.minDistance&&(this.activeThumb==="min"?i=this.clamp(a-this.minDistance):a=this.clamp(i+this.minDistance)),[i,a]}getActiveRange(){return this.normalizeRange(...this.pendingRange??[this.rangeMin,this.rangeMax])}percentFor(e){return this.max===this.min?0:(e-this.min)/(this.max-this.min)*100}valueFromPointer(e,t){let i=t.getBoundingClientRect(),a=Math.min(1,Math.max(0,(e-i.left)/i.width));return this.clamp(this.min+a*(this.max-this.min))}syncInputFromValue(){let e=this.inputTarget;if(!e)return;let t=String(this.value);e.value!==t&&(e.value=t),e.min=String(this.min),e.max=String(this.max),e.step=String(this.step),this.updateDisplayedValue(this.value)}updateDisplayedValue(e){this.valueTarget&&(this.valueTarget.textContent=String(e)),this.inputTarget&&this.inputTarget.setAttribute("aria-valuenow",String(e))}syncRangeUi(){let[e,t]=this.getActiveRange();this.activeThumb||(e!==this.rangeMin&&(this.rangeMin=e),t!==this.rangeMax&&(this.rangeMax=t)),this.paintRangeUi(e,t)}paintRangeUi(e,t){let i=this.percentFor(e),a=this.percentFor(t),n=this.querySelector(".rui-slider__range-track");n&&(n.style.setProperty("--rui-slider-min",`${i}%`),n.style.setProperty("--rui-slider-max",`${a}%`)),this.rangeMinThumb&&(this.rangeMinThumb.setAttribute("aria-valuemin",String(this.min)),this.rangeMinThumb.setAttribute("aria-valuemax",String(t)),this.rangeMinThumb.setAttribute("aria-valuenow",String(e))),this.rangeMaxThumb&&(this.rangeMaxThumb.setAttribute("aria-valuemin",String(e)),this.rangeMaxThumb.setAttribute("aria-valuemax",String(this.max)),this.rangeMaxThumb.setAttribute("aria-valuenow",String(t))),this.rangeFill&&(this.rangeFill.style.left=`${i}%`,this.rangeFill.style.width=`${a-i}%`),this.valueTarget&&(this.valueTarget.textContent=`${e} \u2013 ${t}`)}commitRange(e=!0){let[t,i]=this.getActiveRange(),a=t!==this.rangeMin||i!==this.rangeMax;this.pendingRange=null,this.rangeMin=t,this.rangeMax=i,this.paintRangeUi(t,i),e&&a&&this.changeEvent.emit({values:[t,i]})}setRangeValue(e,t){this.activeThumb=e;let[i,a]=this.pendingRange??[this.rangeMin,this.rangeMax],[n,o]=this.normalizeRange(e==="min"?t:i,e==="max"?t:a);this.pendingRange=[n,o],this.paintRangeUi(n,o)}commitSingleValue(e){let t=Number(e.value);this.updateDisplayedValue(t),t!==this.value&&(this.value=t,this.changeEvent.emit({value:t}))}@s({ref:"input",type:"pointerdown"})onPointerDown(e){e.button!==0||this.variant!=="single"||(this.interacting=!0)}@s({ref:"input",type:"pointerup"})onPointerUp(e){!this.interacting||this.variant!=="single"||(this.interacting=!1,this.commitSingleValue(e.target))}@s({ref:"input",type:"pointercancel"})onPointerCancel(e){!this.interacting||this.variant!=="single"||(this.interacting=!1,this.commitSingleValue(e.target))}@s({ref:"input",type:"input"})onInput(e){if(this.variant!=="single")return;let t=e.target,i=Number(t.value);if(this.updateDisplayedValue(i),this.interacting){this.changeEvent.emit({value:i});return}this.commitSingleValue(t)}@s({ref:"input",type:"change"})onChange(e){this.variant==="single"&&(this.interacting=!1,this.commitSingleValue(e.target))}@s({selector:"[data-thumb]",type:"pointerdown"})onThumbPointerDown(e){if(e.button!==0||this.variant!=="range"||this.disabled)return;let t=e.target.closest("[data-thumb]");if(!t)return;let i=t.getAttribute("data-thumb");this.activeThumb=i,this.pendingRange=[this.rangeMin,this.rangeMax],t.setPointerCapture(e.pointerId),e.preventDefault()}@s({selector:"[data-thumb]",type:"pointermove"})onThumbPointerMove(e){if(!this.activeThumb||this.variant!=="range")return;let t=this.querySelector(".rui-slider__range-track");t&&(this.setRangeValue(this.activeThumb,this.valueFromPointer(e.clientX,t)),this.pendingRange&&this.changeEvent.emit({values:this.pendingRange}))}@s({selector:"[data-thumb]",type:"pointerup"})onThumbPointerUp(){!this.activeThumb||this.variant!=="range"||(this.commitRange(),this.activeThumb=null)}@s({selector:"[data-thumb]",type:"pointercancel"})onThumbPointerCancel(){!this.activeThumb||this.variant!=="range"||(this.pendingRange=null,this.syncRangeUi(),this.activeThumb=null)}@s({selector:"[data-thumb]",type:"keydown"})onThumbKeydown(e){if(this.variant!=="range"||this.disabled)return;let t=e.target.closest("[data-thumb]");if(!t)return;let i=t.getAttribute("data-thumb"),a=i==="min"?this.rangeMin:this.rangeMax,n=a;switch(e.key){case"ArrowRight":case"ArrowUp":n=this.clamp(a+this.step);break;case"ArrowLeft":case"ArrowDown":n=this.clamp(a-this.step);break;case"Home":n=this.min;break;case"End":n=this.max;break;case"PageUp":n=this.clamp(a+this.step*10);break;case"PageDown":n=this.clamp(a-this.step*10);break;default:return}e.preventDefault(),this.setRangeValue(i,n),this.commitRange(!1),this.changeEvent.emit({values:[this.rangeMin,this.rangeMax]}),this.activeThumb=null}render(){return this.variant==="range"?React.createElement("div",{class:"rui-slider rui-slider--range"},this.label?React.createElement("span",{class:"rui-slider__label"},this.label):null,React.createElement("div",{class:"rui-slider__range"},React.createElement("div",{class:"rui-slider__range-track"},React.createElement("div",{class:"rui-slider__range-fill","data-ref":"rangeFill"}),React.createElement("button",{type:"button",class:"rui-slider__thumb","data-ref":"rangeMinThumb","data-thumb":"min",role:"slider",tabindex:this.resolvedDisabledTabindex,"aria-label":this.resolvedMinLabel,"aria-valuemin":this.min,"aria-valuemax":this.rangeMax,"aria-valuenow":this.rangeMin,disabled:this.$.disabled}),React.createElement("button",{type:"button",class:"rui-slider__thumb","data-ref":"rangeMaxThumb","data-thumb":"max",role:"slider",tabindex:this.resolvedDisabledTabindex,"aria-label":this.resolvedMaxLabel,"aria-valuemin":this.rangeMin,"aria-valuemax":this.max,"aria-valuenow":this.rangeMax,disabled:this.$.disabled}))),React.createElement("span",{class:"rui-slider__value","data-ref":"value","aria-hidden":"true"},this.rangeMin," \u2013 ",this.rangeMax)):React.createElement("label",{class:"rui-slider"},this.label?React.createElement("span",{class:"rui-slider__label"},this.label):null,React.createElement("input",{type:"range","data-ref":"input","data-rui-control":!0,"data-rui-control-type":"number",class:"rui-slider__input",disabled:this.$.disabled,name:this.resolvedName,"aria-valuemin":this.min,"aria-valuemax":this.max,"aria-valuenow":this.value}),React.createElement("span",{class:"rui-slider__value","data-ref":"value","aria-hidden":"true"},this.value))}};var x=Symbol.for("@ecopages/storybook-radiant.viewElement"),d=Symbol.for("@ecopages/storybook-radiant.scriptModule"),g=Symbol.for("@ecopages/storybook-radiant.scriptExport");function y(l,e){l[x]=e;let t=e[d];t&&(l[d]=t,l[g]=e[g]??e.name)}function p(l,e){let t=(i=>e(i));return y(t,l),t}import"./slider.css";var E=p(m,({slot:l,variant:e,value:t,values:i,min:a,max:n,step:o,minDistance:c,disabled:b,label:v,name:f})=>React.createElement("rui-slider",{slot:l,variant:e,value:t,rangeMin:i?.[0],rangeMax:i?.[1],min:a,max:n,step:o,minDistance:c,disabled:b,label:v,name:f}));export{E as RuiSlider,m as RuiSliderElement};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/components/ui/slider/slider.script.tsx", "../../../../src/lib/radiant-view.ts", "../../../../src/components/ui/slider/slider.tsx"],
4
+ "sourcesContent": ["import { RadiantElement, customElement, event, onEvent, onUpdated, prop, query } from '@ecopages/radiant';\nimport type { EventEmitter } from '@ecopages/radiant/tools/event-emitter';\n\nexport type RuiSliderVariant = 'single' | 'range';\n\nexport type RuiSliderProps = {\n\tvariant?: RuiSliderVariant;\n\tvalue?: number;\n\trangeMin?: number;\n\trangeMax?: number;\n\tmin?: number;\n\tmax?: number;\n\tstep?: number;\n\tminDistance?: number;\n\tdisabled?: boolean;\n\tlabel?: string;\n\tname?: string;\n};\n\nexport type RuiSliderChangeDetail = { value: number } | { values: [number, number] };\n\ntype RuiSliderBindings = {\n\tdisabled: boolean;\n\tname: string;\n\tlabel: string;\n};\n\n/**\n * `<rui-slider>` \u2014 select a value from a continuous or discrete range.\n *\n * Single mode uses native `<input type=\"range\">`. Range mode implements the APG\n * multi-thumb slider pattern with two `role=\"slider\"` thumbs on one track.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/slider/\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/slider-multithumb/\n *\n * @element rui-slider\n * @fires rui-change\n */\n@customElement('rui-slider')\nexport class RuiSlider extends RadiantElement<RuiSliderBindings> {\n\t@prop({ type: String, defaultValue: 'single' }) variant: RuiSliderVariant;\n\t@prop({ type: Number, reflect: true, defaultValue: 50 }) value: number;\n\t@prop({ type: Number, reflect: true, attribute: 'range-min', defaultValue: 25 }) rangeMin: number;\n\t@prop({ type: Number, reflect: true, attribute: 'range-max', defaultValue: 75 }) rangeMax: number;\n\t@prop({ type: Number, defaultValue: 0 }) min: number;\n\t@prop({ type: Number, defaultValue: 100 }) max: number;\n\t@prop({ type: Number, defaultValue: 1 }) step: number;\n\t@prop({ type: Number, defaultValue: 0 }) minDistance: number;\n\t@prop({ type: Boolean, reflect: true, defaultValue: false }) disabled: boolean;\n\t@prop({ type: String, defaultValue: '' }) label: string;\n\t@prop({ type: String, defaultValue: '' }) name: string;\n\n\t@event({ name: 'rui-change', bubbles: true, composed: true })\n\tchangeEvent: EventEmitter<RuiSliderChangeDetail>;\n\n\t@query({ ref: 'input' }) inputTarget: HTMLInputElement;\n\t@query({ ref: 'value' }) valueTarget: HTMLElement;\n\t@query({ ref: 'rangeMinThumb' }) rangeMinThumb: HTMLElement;\n\t@query({ ref: 'rangeMaxThumb' }) rangeMaxThumb: HTMLElement;\n\t@query({ ref: 'rangeFill' }) rangeFill: HTMLElement;\n\n\tprivate interacting = false;\n\tprivate activeThumb: 'min' | 'max' | null = null;\n\t/** Live range while dragging \u2014 avoids reactive prop updates that re-render mid-drag. */\n\tprivate pendingRange: [number, number] | null = null;\n\n\t/**\n\t * Only disabled/tabindex/aria-label/name are bound below \u2014 none of them\n\t * change during a drag. The value text and every aria-value* attribute\n\t * stay plain reads + imperative writes (paintRangeUi/updateDisplayedValue)\n\t * deliberately: they must show the LIVE pointer position while dragging,\n\t * before pendingRange commits to the reactive value/rangeMin/rangeMax\n\t * props. A binding only reacts to committed prop changes, so it cannot\n\t * replace that live-preview write without losing drag feedback \u2014 this\n\t * isn't a caution-driven exception, it's the correct tool for the job.\n\t */\n\tprivate readonly resolvedDisabledTabindex = this.$.disabled.map((disabled) => (disabled ? -1 : 0));\n\tprivate readonly resolvedMinLabel = this.$.label.map((label) => (label ? `${label} minimum` : 'Minimum value'));\n\tprivate readonly resolvedMaxLabel = this.$.label.map((label) => (label ? `${label} maximum` : 'Maximum value'));\n\tprivate readonly resolvedName = this.$.name.map((name) => name || undefined);\n\n\toverride connectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tqueueMicrotask(() => {\n\t\t\tif (this.variant === 'single') {\n\t\t\t\tthis.syncInputFromValue();\n\t\t\t} else {\n\t\t\t\tthis.syncRangeUi();\n\t\t\t}\n\t\t});\n\t}\n\n\t@onUpdated(['value', 'min', 'max', 'step', 'variant'])\n\tonSinglePropsUpdated(): void {\n\t\tif (this.variant !== 'single' || this.interacting) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.syncInputFromValue();\n\t}\n\n\t@onUpdated(['rangeMin', 'rangeMax', 'min', 'max', 'step', 'minDistance', 'variant'])\n\tonRangePropsUpdated(): void {\n\t\tif (this.variant !== 'range' || this.activeThumb) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.syncRangeUi();\n\t}\n\n\tprivate clamp(next: number): number {\n\t\tconst stepped = Math.round(next / this.step) * this.step;\n\t\treturn Math.min(this.max, Math.max(this.min, stepped));\n\t}\n\n\tprivate normalizeRange(low = this.rangeMin, high = this.rangeMax): [number, number] {\n\t\tlet nextLow = this.clamp(low);\n\t\tlet nextHigh = this.clamp(high);\n\n\t\tif (nextLow > nextHigh) {\n\t\t\t[nextLow, nextHigh] = [nextHigh, nextLow];\n\t\t}\n\n\t\tif (nextHigh - nextLow < this.minDistance) {\n\t\t\tif (this.activeThumb === 'min') {\n\t\t\t\tnextLow = this.clamp(nextHigh - this.minDistance);\n\t\t\t} else {\n\t\t\t\tnextHigh = this.clamp(nextLow + this.minDistance);\n\t\t\t}\n\t\t}\n\n\t\treturn [nextLow, nextHigh];\n\t}\n\n\tprivate getActiveRange(): [number, number] {\n\t\treturn this.normalizeRange(...(this.pendingRange ?? [this.rangeMin, this.rangeMax]));\n\t}\n\n\tprivate percentFor(value: number): number {\n\t\tif (this.max === this.min) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn ((value - this.min) / (this.max - this.min)) * 100;\n\t}\n\n\tprivate valueFromPointer(clientX: number, track: HTMLElement): number {\n\t\tconst rect = track.getBoundingClientRect();\n\t\tconst ratio = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));\n\t\treturn this.clamp(this.min + ratio * (this.max - this.min));\n\t}\n\n\tprivate syncInputFromValue(): void {\n\t\tconst input = this.inputTarget;\n\t\tif (!input) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst nextValue = String(this.value);\n\t\tif (input.value !== nextValue) {\n\t\t\tinput.value = nextValue;\n\t\t}\n\n\t\tinput.min = String(this.min);\n\t\tinput.max = String(this.max);\n\t\tinput.step = String(this.step);\n\t\tthis.updateDisplayedValue(this.value);\n\t}\n\n\tprivate updateDisplayedValue(next: number): void {\n\t\tif (this.valueTarget) {\n\t\t\tthis.valueTarget.textContent = String(next);\n\t\t}\n\n\t\tif (this.inputTarget) {\n\t\t\tthis.inputTarget.setAttribute('aria-valuenow', String(next));\n\t\t}\n\t}\n\n\tprivate syncRangeUi(): void {\n\t\tconst [low, high] = this.getActiveRange();\n\n\t\tif (!this.activeThumb) {\n\t\t\tif (low !== this.rangeMin) {\n\t\t\t\tthis.rangeMin = low;\n\t\t\t}\n\t\t\tif (high !== this.rangeMax) {\n\t\t\t\tthis.rangeMax = high;\n\t\t\t}\n\t\t}\n\n\t\tthis.paintRangeUi(low, high);\n\t}\n\n\tprivate paintRangeUi(low: number, high: number): void {\n\t\tconst lowPercent = this.percentFor(low);\n\t\tconst highPercent = this.percentFor(high);\n\t\tconst track = this.querySelector<HTMLElement>('.rui-slider__range-track');\n\n\t\tif (track) {\n\t\t\ttrack.style.setProperty('--rui-slider-min', `${lowPercent}%`);\n\t\t\ttrack.style.setProperty('--rui-slider-max', `${highPercent}%`);\n\t\t}\n\n\t\tif (this.rangeMinThumb) {\n\t\t\tthis.rangeMinThumb.setAttribute('aria-valuemin', String(this.min));\n\t\t\tthis.rangeMinThumb.setAttribute('aria-valuemax', String(high));\n\t\t\tthis.rangeMinThumb.setAttribute('aria-valuenow', String(low));\n\t\t}\n\n\t\tif (this.rangeMaxThumb) {\n\t\t\tthis.rangeMaxThumb.setAttribute('aria-valuemin', String(low));\n\t\t\tthis.rangeMaxThumb.setAttribute('aria-valuemax', String(this.max));\n\t\t\tthis.rangeMaxThumb.setAttribute('aria-valuenow', String(high));\n\t\t}\n\n\t\tif (this.rangeFill) {\n\t\t\tthis.rangeFill.style.left = `${lowPercent}%`;\n\t\t\tthis.rangeFill.style.width = `${highPercent - lowPercent}%`;\n\t\t}\n\n\t\tif (this.valueTarget) {\n\t\t\tthis.valueTarget.textContent = `${low} \u2013 ${high}`;\n\t\t}\n\t}\n\n\tprivate commitRange(emit = true): void {\n\t\tconst [low, high] = this.getActiveRange();\n\t\tconst changed = low !== this.rangeMin || high !== this.rangeMax;\n\t\tthis.pendingRange = null;\n\t\tthis.rangeMin = low;\n\t\tthis.rangeMax = high;\n\t\tthis.paintRangeUi(low, high);\n\n\t\tif (emit && changed) {\n\t\t\tthis.changeEvent.emit({ values: [low, high] });\n\t\t}\n\t}\n\n\tprivate setRangeValue(thumb: 'min' | 'max', next: number): void {\n\t\tthis.activeThumb = thumb;\n\t\tconst [currentLow, currentHigh] = this.pendingRange ?? [this.rangeMin, this.rangeMax];\n\t\tconst [low, high] = this.normalizeRange(\n\t\t\tthumb === 'min' ? next : currentLow,\n\t\t\tthumb === 'max' ? next : currentHigh,\n\t\t);\n\t\tthis.pendingRange = [low, high];\n\t\tthis.paintRangeUi(low, high);\n\t}\n\n\tprivate commitSingleValue(input: HTMLInputElement): void {\n\t\tconst next = Number(input.value);\n\t\tthis.updateDisplayedValue(next);\n\n\t\tif (next === this.value) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.value = next;\n\t\tthis.changeEvent.emit({ value: next });\n\t}\n\n\t@onEvent({ ref: 'input', type: 'pointerdown' })\n\tonPointerDown(event: PointerEvent): void {\n\t\tif (event.button !== 0 || this.variant !== 'single') {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.interacting = true;\n\t}\n\n\t@onEvent({ ref: 'input', type: 'pointerup' })\n\tonPointerUp(event: Event): void {\n\t\tif (!this.interacting || this.variant !== 'single') {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.interacting = false;\n\t\tthis.commitSingleValue(event.target as HTMLInputElement);\n\t}\n\n\t@onEvent({ ref: 'input', type: 'pointercancel' })\n\tonPointerCancel(event: Event): void {\n\t\tif (!this.interacting || this.variant !== 'single') {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.interacting = false;\n\t\tthis.commitSingleValue(event.target as HTMLInputElement);\n\t}\n\n\t@onEvent({ ref: 'input', type: 'input' })\n\tonInput(event: Event): void {\n\t\tif (this.variant !== 'single') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst input = event.target as HTMLInputElement;\n\t\tconst next = Number(input.value);\n\t\tthis.updateDisplayedValue(next);\n\n\t\tif (this.interacting) {\n\t\t\tthis.changeEvent.emit({ value: next });\n\t\t\treturn;\n\t\t}\n\n\t\tthis.commitSingleValue(input);\n\t}\n\n\t@onEvent({ ref: 'input', type: 'change' })\n\tonChange(event: Event): void {\n\t\tif (this.variant !== 'single') {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.interacting = false;\n\t\tthis.commitSingleValue(event.target as HTMLInputElement);\n\t}\n\n\t@onEvent({ selector: '[data-thumb]', type: 'pointerdown' })\n\tonThumbPointerDown(event: PointerEvent): void {\n\t\tif (event.button !== 0 || this.variant !== 'range' || this.disabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst thumbElement = (event.target as HTMLElement).closest<HTMLElement>('[data-thumb]');\n\t\tif (!thumbElement) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst thumb = thumbElement.getAttribute('data-thumb') as 'min' | 'max';\n\t\tthis.activeThumb = thumb;\n\t\tthis.pendingRange = [this.rangeMin, this.rangeMax];\n\t\tthumbElement.setPointerCapture(event.pointerId);\n\t\tevent.preventDefault();\n\t}\n\n\t@onEvent({ selector: '[data-thumb]', type: 'pointermove' })\n\tonThumbPointerMove(event: PointerEvent): void {\n\t\tif (!this.activeThumb || this.variant !== 'range') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst track = this.querySelector<HTMLElement>('.rui-slider__range-track');\n\t\tif (!track) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setRangeValue(this.activeThumb, this.valueFromPointer(event.clientX, track));\n\n\t\tif (this.pendingRange) {\n\t\t\tthis.changeEvent.emit({ values: this.pendingRange });\n\t\t}\n\t}\n\n\t@onEvent({ selector: '[data-thumb]', type: 'pointerup' })\n\tonThumbPointerUp(): void {\n\t\tif (!this.activeThumb || this.variant !== 'range') {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.commitRange();\n\t\tthis.activeThumb = null;\n\t}\n\n\t@onEvent({ selector: '[data-thumb]', type: 'pointercancel' })\n\tonThumbPointerCancel(): void {\n\t\tif (!this.activeThumb || this.variant !== 'range') {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pendingRange = null;\n\t\tthis.syncRangeUi();\n\t\tthis.activeThumb = null;\n\t}\n\n\t@onEvent({ selector: '[data-thumb]', type: 'keydown' })\n\tonThumbKeydown(event: KeyboardEvent): void {\n\t\tif (this.variant !== 'range' || this.disabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst thumbElement = (event.target as HTMLElement).closest<HTMLElement>('[data-thumb]');\n\t\tif (!thumbElement) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst thumb = thumbElement.getAttribute('data-thumb') as 'min' | 'max';\n\t\tconst current = thumb === 'min' ? this.rangeMin : this.rangeMax;\n\t\tlet next = current;\n\n\t\tswitch (event.key) {\n\t\t\tcase 'ArrowRight':\n\t\t\tcase 'ArrowUp':\n\t\t\t\tnext = this.clamp(current + this.step);\n\t\t\t\tbreak;\n\t\t\tcase 'ArrowLeft':\n\t\t\tcase 'ArrowDown':\n\t\t\t\tnext = this.clamp(current - this.step);\n\t\t\t\tbreak;\n\t\t\tcase 'Home':\n\t\t\t\tnext = this.min;\n\t\t\t\tbreak;\n\t\t\tcase 'End':\n\t\t\t\tnext = this.max;\n\t\t\t\tbreak;\n\t\t\tcase 'PageUp':\n\t\t\t\tnext = this.clamp(current + this.step * 10);\n\t\t\t\tbreak;\n\t\t\tcase 'PageDown':\n\t\t\t\tnext = this.clamp(current - this.step * 10);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn;\n\t\t}\n\n\t\tevent.preventDefault();\n\t\tthis.setRangeValue(thumb, next);\n\t\tthis.commitRange(false);\n\t\tthis.changeEvent.emit({ values: [this.rangeMin, this.rangeMax] });\n\t\tthis.activeThumb = null;\n\t}\n\n\toverride render() {\n\t\tif (this.variant === 'range') {\n\t\t\treturn (\n\t\t\t\t<div class=\"rui-slider rui-slider--range\">\n\t\t\t\t\t{this.label ? <span class=\"rui-slider__label\">{this.label}</span> : null}\n\t\t\t\t\t<div class=\"rui-slider__range\">\n\t\t\t\t\t\t<div class=\"rui-slider__range-track\">\n\t\t\t\t\t\t\t<div class=\"rui-slider__range-fill\" data-ref=\"rangeFill\" />\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"rui-slider__thumb\"\n\t\t\t\t\t\t\t\tdata-ref=\"rangeMinThumb\"\n\t\t\t\t\t\t\t\tdata-thumb=\"min\"\n\t\t\t\t\t\t\t\trole=\"slider\"\n\t\t\t\t\t\t\t\ttabindex={this.resolvedDisabledTabindex}\n\t\t\t\t\t\t\t\taria-label={this.resolvedMinLabel}\n\t\t\t\t\t\t\t\taria-valuemin={this.min}\n\t\t\t\t\t\t\t\taria-valuemax={this.rangeMax}\n\t\t\t\t\t\t\t\taria-valuenow={this.rangeMin}\n\t\t\t\t\t\t\t\tdisabled={this.$.disabled}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"rui-slider__thumb\"\n\t\t\t\t\t\t\t\tdata-ref=\"rangeMaxThumb\"\n\t\t\t\t\t\t\t\tdata-thumb=\"max\"\n\t\t\t\t\t\t\t\trole=\"slider\"\n\t\t\t\t\t\t\t\ttabindex={this.resolvedDisabledTabindex}\n\t\t\t\t\t\t\t\taria-label={this.resolvedMaxLabel}\n\t\t\t\t\t\t\t\taria-valuemin={this.rangeMin}\n\t\t\t\t\t\t\t\taria-valuemax={this.max}\n\t\t\t\t\t\t\t\taria-valuenow={this.rangeMax}\n\t\t\t\t\t\t\t\tdisabled={this.$.disabled}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span class=\"rui-slider__value\" data-ref=\"value\" aria-hidden=\"true\">\n\t\t\t\t\t\t{this.rangeMin} \u2013 {this.rangeMax}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\n\t\treturn (\n\t\t\t<label class=\"rui-slider\">\n\t\t\t\t{this.label ? <span class=\"rui-slider__label\">{this.label}</span> : null}\n\t\t\t\t<input\n\t\t\t\t\ttype=\"range\"\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=\"number\"\n\t\t\t\t\tclass=\"rui-slider__input\"\n\t\t\t\t\tdisabled={this.$.disabled}\n\t\t\t\t\tname={this.resolvedName}\n\t\t\t\t\taria-valuemin={this.min}\n\t\t\t\t\taria-valuemax={this.max}\n\t\t\t\t\taria-valuenow={this.value}\n\t\t\t\t/>\n\t\t\t\t<span class=\"rui-slider__value\" data-ref=\"value\" aria-hidden=\"true\">\n\t\t\t\t\t{this.value}\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 { RadiantSlotProps } from '../../../types';\nimport { defineRadiantView } from '../../../lib/radiant-view';\nimport type { RuiSliderProps } from './slider.script';\nimport { RuiSlider as RuiSliderElement } from './slider.script';\nimport './slider.css';\n\nexport type RuiSliderViewProps = RuiSliderProps &\n\tRadiantSlotProps & {\n\t\tvalues?: [number, number];\n\t};\n\nexport const RuiSlider = defineRadiantView(\n\tRuiSliderElement,\n\t({ slot, variant, value, values, min, max, step, minDistance, disabled, label, name }: RuiSliderViewProps) => (\n\t\t<rui-slider\n\t\t\tslot={slot}\n\t\t\tvariant={variant}\n\t\t\tvalue={value}\n\t\t\trangeMin={values?.[0]}\n\t\t\trangeMax={values?.[1]}\n\t\t\tmin={min}\n\t\t\tmax={max}\n\t\t\tstep={step}\n\t\t\tminDistance={minDistance}\n\t\t\tdisabled={disabled}\n\t\t\tlabel={label}\n\t\t\tname={name}\n\t\t/>\n\t),\n);\n"],
5
+ "mappings": "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",
6
+ "names": ["RadiantElement", "customElement", "event", "onEvent", "onUpdated", "prop", "query", "RuiSlider", "disabled", "label", "name", "next", "stepped", "low", "high", "nextLow", "nextHigh", "value", "clientX", "track", "rect", "ratio", "input", "nextValue", "lowPercent", "highPercent", "emit", "changed", "thumb", "currentLow", "currentHigh", "thumbElement", "current", "RADIANT_VIEW_ELEMENT", "RADIANT_SCRIPT_MODULE", "RADIANT_SCRIPT_EXPORT", "linkViewToElement", "view", "element", "ssrModule", "defineRadiantView", "render", "args", "RuiSlider", "defineRadiantView", "slot", "variant", "value", "values", "min", "max", "step", "minDistance", "disabled", "label", "name"]
7
+ }
@@ -0,0 +1,51 @@
1
+ @reference '../../../styles/radiant-ui.css';
2
+
3
+ rui-slider {
4
+ @apply block w-full max-w-full min-w-0;
5
+ }
6
+
7
+ @layer components {
8
+ .rui-slider {
9
+ @apply flex w-full min-w-0 max-w-full flex-col gap-inline text-sm text-on-background;
10
+ }
11
+
12
+ .rui-slider__input {
13
+ @apply block w-full min-w-0 max-w-full accent-primary;
14
+ }
15
+
16
+ .rui-slider__value {
17
+ @apply tabular-nums text-on-surface;
18
+ }
19
+
20
+ .rui-slider__range {
21
+ @apply w-full min-w-0 py-2;
22
+ }
23
+
24
+ .rui-slider__range-track {
25
+ @apply relative h-2 w-full min-w-0 rounded-full bg-surface;
26
+ }
27
+
28
+ .rui-slider__range-fill {
29
+ @apply absolute top-0 h-full rounded-full bg-primary;
30
+ }
31
+
32
+ .rui-slider__thumb {
33
+ @apply absolute top-1/2 h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-primary bg-background shadow-sm;
34
+ }
35
+
36
+ .rui-slider__thumb:focus-visible {
37
+ @apply rounded-full outline-hidden ring-2 ring-focus-ring;
38
+ }
39
+
40
+ .rui-slider__thumb:active:not(:disabled) {
41
+ @apply rounded-full;
42
+ }
43
+
44
+ .rui-slider__thumb[data-thumb='min'] {
45
+ left: var(--rui-slider-min, 0%);
46
+ }
47
+
48
+ .rui-slider__thumb[data-thumb='max'] {
49
+ left: var(--rui-slider-max, 100%);
50
+ }
51
+ }
@@ -0,0 +1,7 @@
1
+ import type { RadiantSlotProps } from '../../../types';
2
+ import type { RuiSliderProps } from './slider.script';
3
+ import './slider.css';
4
+ export type RuiSliderViewProps = RuiSliderProps & RadiantSlotProps & {
5
+ values?: [number, number];
6
+ };
7
+ export declare const RuiSlider: import("../../../lib/radiant-view").RadiantViewComponent<RuiSliderViewProps>;
@@ -0,0 +1,102 @@
1
+ import { RadiantElement } from '@ecopages/radiant';
2
+ import type { EventEmitter } from '@ecopages/radiant/tools/event-emitter';
3
+ export type RuiSliderVariant = 'single' | 'range';
4
+ export type RuiSliderProps = {
5
+ variant?: RuiSliderVariant;
6
+ value?: number;
7
+ rangeMin?: number;
8
+ rangeMax?: number;
9
+ min?: number;
10
+ max?: number;
11
+ step?: number;
12
+ minDistance?: number;
13
+ disabled?: boolean;
14
+ label?: string;
15
+ name?: string;
16
+ };
17
+ export type RuiSliderChangeDetail = {
18
+ value: number;
19
+ } | {
20
+ values: [number, number];
21
+ };
22
+ type RuiSliderBindings = {
23
+ disabled: boolean;
24
+ name: string;
25
+ label: string;
26
+ };
27
+ /**
28
+ * `<rui-slider>` — select a value from a continuous or discrete range.
29
+ *
30
+ * Single mode uses native `<input type="range">`. Range mode implements the APG
31
+ * multi-thumb slider pattern with two `role="slider"` thumbs on one track.
32
+ *
33
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/slider/
34
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/slider-multithumb/
35
+ *
36
+ * @element rui-slider
37
+ * @fires rui-change
38
+ */
39
+ export declare class RuiSlider extends RadiantElement<RuiSliderBindings> {
40
+ variant: RuiSliderVariant;
41
+ value: number;
42
+ rangeMin: number;
43
+ rangeMax: number;
44
+ min: number;
45
+ max: number;
46
+ step: number;
47
+ minDistance: number;
48
+ disabled: boolean;
49
+ label: string;
50
+ name: string;
51
+ changeEvent: EventEmitter<RuiSliderChangeDetail>;
52
+ inputTarget: HTMLInputElement;
53
+ valueTarget: HTMLElement;
54
+ rangeMinThumb: HTMLElement;
55
+ rangeMaxThumb: HTMLElement;
56
+ rangeFill: HTMLElement;
57
+ private interacting;
58
+ private activeThumb;
59
+ /** Live range while dragging — avoids reactive prop updates that re-render mid-drag. */
60
+ private pendingRange;
61
+ /**
62
+ * Only disabled/tabindex/aria-label/name are bound below — none of them
63
+ * change during a drag. The value text and every aria-value* attribute
64
+ * stay plain reads + imperative writes (paintRangeUi/updateDisplayedValue)
65
+ * deliberately: they must show the LIVE pointer position while dragging,
66
+ * before pendingRange commits to the reactive value/rangeMin/rangeMax
67
+ * props. A binding only reacts to committed prop changes, so it cannot
68
+ * replace that live-preview write without losing drag feedback — this
69
+ * isn't a caution-driven exception, it's the correct tool for the job.
70
+ */
71
+ private readonly resolvedDisabledTabindex;
72
+ private readonly resolvedMinLabel;
73
+ private readonly resolvedMaxLabel;
74
+ private readonly resolvedName;
75
+ connectedCallback(): void;
76
+ onSinglePropsUpdated(): void;
77
+ onRangePropsUpdated(): void;
78
+ private clamp;
79
+ private normalizeRange;
80
+ private getActiveRange;
81
+ private percentFor;
82
+ private valueFromPointer;
83
+ private syncInputFromValue;
84
+ private updateDisplayedValue;
85
+ private syncRangeUi;
86
+ private paintRangeUi;
87
+ private commitRange;
88
+ private setRangeValue;
89
+ private commitSingleValue;
90
+ onPointerDown(event: PointerEvent): void;
91
+ onPointerUp(event: Event): void;
92
+ onPointerCancel(event: Event): void;
93
+ onInput(event: Event): void;
94
+ onChange(event: Event): void;
95
+ onThumbPointerDown(event: PointerEvent): void;
96
+ onThumbPointerMove(event: PointerEvent): void;
97
+ onThumbPointerUp(): void;
98
+ onThumbPointerCancel(): void;
99
+ onThumbKeydown(event: KeyboardEvent): void;
100
+ render(): import("@ecopages/jsx").JsxRenderable;
101
+ }
102
+ export {};
@@ -0,0 +1,2 @@
1
+ export { RuiSpinbutton as RuiSpinbuttonElement, type RuiSpinbuttonProps, type RuiSpinbuttonChangeDetail, } from './spinbutton.script';
2
+ export { RuiSpinbutton } from './spinbutton';
@@ -0,0 +1,2 @@
1
+ import{RadiantElement as f,customElement as v,event as R,onEvent as r,onUpdated as y,prop as a,state as o}from"@ecopages/radiant";var s=@v("rui-spinbutton")class extends f{@a({type:Number,reflect:!0,defaultValue:0})value;@a({type:Number,defaultValue:0})min;@a({type:Number,defaultValue:100})max;@a({type:Number,defaultValue:1})step;@a({type:Boolean,reflect:!0,defaultValue:!1})disabled;@a({type:String,defaultValue:""})label;@a({type:String,defaultValue:""})name;@R({name:"rui-change",bubbles:!0,composed:!0})changeEvent;@o decreaseDisabled=!1;@o increaseDisabled=!1;nameAttr=this.$.name.map(e=>e||void 0);resolvedAriaLabel=this.$.label.map(e=>e||void 0);@y(["disabled","value","min","max"])onRangeUpdated(){this.decreaseDisabled=this.isDecreaseDisabled(),this.increaseDisabled=this.isIncreaseDisabled(),queueMicrotask(()=>this.syncSlottedStepperControls())}syncSlottedStepperControls(){let e=this.isDecreaseDisabled(),t=this.isIncreaseDisabled();for(let i of this.querySelectorAll('[slot][data-spinbutton-action="decrease"]'))i.disabled=e;for(let i of this.querySelectorAll('[slot][data-spinbutton-action="increase"]'))i.disabled=t}isDecreaseDisabled(){return this.disabled||this.value<=this.min}isIncreaseDisabled(){return this.disabled||this.value>=this.max}clamp(e){let t=Math.round(e/this.step)*this.step;return Math.min(this.max,Math.max(this.min,t))}setValue(e){let t=this.clamp(e);t!==this.value&&(this.value=t,this.changeEvent.emit({value:t}))}@r({selector:'[data-spinbutton-action="decrease"]',type:"click"})decrement(){this.isDecreaseDisabled()||this.setValue(this.value-this.step)}@r({selector:'[data-spinbutton-action="increase"]',type:"click"})increment(){this.isIncreaseDisabled()||this.setValue(this.value+this.step)}@r({ref:"input",type:"change"})onChange(e){let t=e.target,i=Number(t.value);this.setValue(Number.isFinite(i)?i:this.value),t.value=String(this.value)}@r({ref:"input",type:"keydown"})onKeydown(e){this.disabled||(e.key==="ArrowUp"?(e.preventDefault(),this.increment()):e.key==="ArrowDown"?(e.preventDefault(),this.decrement()):e.key==="Home"?(e.preventDefault(),this.setValue(this.min)):e.key==="End"&&(e.preventDefault(),this.setValue(this.max)))}render(){return React.createElement("div",{class:"rui-spinbutton"},this.label?React.createElement("span",{class:"rui-spinbutton__label",id:`${this.id||"spin"}-label`},this.$.label):null,React.createElement("div",{class:"rui-spinbutton__control"},React.createElement("slot",{name:"decrease"},React.createElement("button",{type:"button",class:"rui-button rui-button--outline rui-button--sm","data-spinbutton-action":"decrease","aria-label":"Decrease",disabled:this.$.decreaseDisabled},"\u2212")),React.createElement("input",{type:"text",inputmode:"numeric","data-ref":"input","data-rui-control":!0,"data-rui-control-type":"number",class:"rui-spinbutton__input",role:"spinbutton","prop:value":this.$.value.map(String),disabled:this.$.disabled,name:this.nameAttr,"aria-valuemin":this.$.min,"aria-valuemax":this.$.max,"aria-valuenow":this.$.value,"aria-label":this.resolvedAriaLabel}),React.createElement("slot",{name:"increase"},React.createElement("button",{type:"button",class:"rui-button rui-button--outline rui-button--sm","data-spinbutton-action":"increase","aria-label":"Increase",disabled:this.$.increaseDisabled},"+"))))}};var D=Symbol.for("@ecopages/storybook-radiant.viewElement"),l=Symbol.for("@ecopages/storybook-radiant.scriptModule"),u=Symbol.for("@ecopages/storybook-radiant.scriptExport");function g(n,e){n[D]=e;let t=e[l];t&&(n[l]=t,n[u]=e[u]??e.name)}function d(n,e){let t=(i=>e(i));return g(t,n),t}import"./spinbutton.css";var E=d(s,({slot:n,value:e,min:t,max:i,step:p,disabled:b,label:m,name:c,children:h})=>React.createElement("rui-spinbutton",{slot:n,value:e,min:t,max:i,step:p,disabled:b,label:m,name:c},h));export{E as RuiSpinbutton,s as RuiSpinbuttonElement};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/components/ui/spinbutton/spinbutton.script.tsx", "../../../../src/lib/radiant-view.ts", "../../../../src/components/ui/spinbutton/spinbutton.tsx"],
4
+ "sourcesContent": ["import { RadiantElement, customElement, event, onEvent, onUpdated, prop, state } from '@ecopages/radiant';\nimport type { EventEmitter } from '@ecopages/radiant/tools/event-emitter';\n\nexport type RuiSpinbuttonProps = {\n\tvalue?: number;\n\tmin?: number;\n\tmax?: number;\n\tstep?: number;\n\tdisabled?: boolean;\n\tlabel?: string;\n\tname?: string;\n};\n\nexport type RuiSpinbuttonChangeDetail = { value: number };\n\ntype RuiSpinbuttonBindings = {\n\tvalue: number;\n\tdisabled: boolean;\n\tlabel: string;\n\tname: string;\n\tmin: number;\n\tmax: number;\n\tdecreaseDisabled: boolean;\n\tincreaseDisabled: boolean;\n};\n\n/**\n * `<rui-spinbutton>` \u2014 an input restricted to a discrete numeric range.\n *\n * Implements the APG Spinbutton pattern with `role=\"spinbutton\"` on a native\n * number-like text field, plus decrement/increment buttons.\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/\n *\n * @element rui-spinbutton\n * @slot decrease - Optional custom decrease control. Use `data-spinbutton-action=\"decrease\"`.\n * @slot increase - Optional custom increase control. Use `data-spinbutton-action=\"increase\"`.\n * @fires rui-change\n */\n@customElement('rui-spinbutton')\nexport class RuiSpinbutton extends RadiantElement<RuiSpinbuttonBindings> {\n\t@prop({ type: Number, reflect: true, defaultValue: 0 }) value: number;\n\t@prop({ type: Number, defaultValue: 0 }) min: number;\n\t@prop({ type: Number, defaultValue: 100 }) max: number;\n\t@prop({ type: Number, defaultValue: 1 }) step: number;\n\t@prop({ type: Boolean, reflect: true, defaultValue: false }) disabled: boolean;\n\t@prop({ type: String, defaultValue: '' }) label: string;\n\t@prop({ type: String, defaultValue: '' }) name: string;\n\n\t@event({ name: 'rui-change', bubbles: true, composed: true })\n\tchangeEvent: EventEmitter<RuiSpinbuttonChangeDetail>;\n\n\t@state decreaseDisabled = false;\n\t@state increaseDisabled = false;\n\n\tprivate readonly nameAttr = this.$.name.map((name) => name || undefined);\n\tprivate readonly resolvedAriaLabel = this.$.label.map((label) => label || undefined);\n\n\t/** Derived from disabled/value/min/max \u2014 recomputed here instead of per-render. */\n\t@onUpdated(['disabled', 'value', 'min', 'max'])\n\tonRangeUpdated(): void {\n\t\tthis.decreaseDisabled = this.isDecreaseDisabled();\n\t\tthis.increaseDisabled = this.isIncreaseDisabled();\n\t\tqueueMicrotask(() => this.syncSlottedStepperControls());\n\t}\n\n\tprivate syncSlottedStepperControls(): void {\n\t\tconst decreaseDisabled = this.isDecreaseDisabled();\n\t\tconst increaseDisabled = this.isIncreaseDisabled();\n\n\t\tfor (const button of this.querySelectorAll<HTMLButtonElement>('[slot][data-spinbutton-action=\"decrease\"]')) {\n\t\t\tbutton.disabled = decreaseDisabled;\n\t\t}\n\n\t\tfor (const button of this.querySelectorAll<HTMLButtonElement>('[slot][data-spinbutton-action=\"increase\"]')) {\n\t\t\tbutton.disabled = increaseDisabled;\n\t\t}\n\t}\n\n\tprivate isDecreaseDisabled(): boolean {\n\t\treturn this.disabled || this.value <= this.min;\n\t}\n\n\tprivate isIncreaseDisabled(): boolean {\n\t\treturn this.disabled || this.value >= this.max;\n\t}\n\n\tprivate clamp(next: number): number {\n\t\tconst stepped = Math.round(next / this.step) * this.step;\n\t\treturn Math.min(this.max, Math.max(this.min, stepped));\n\t}\n\n\tprivate setValue(next: number): void {\n\t\tconst value = this.clamp(next);\n\t\tif (value === this.value) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.value = value;\n\t\tthis.changeEvent.emit({ value });\n\t}\n\n\t@onEvent({ selector: '[data-spinbutton-action=\"decrease\"]', type: 'click' })\n\tdecrement(): void {\n\t\tif (this.isDecreaseDisabled()) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setValue(this.value - this.step);\n\t}\n\n\t@onEvent({ selector: '[data-spinbutton-action=\"increase\"]', type: 'click' })\n\tincrement(): void {\n\t\tif (this.isIncreaseDisabled()) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setValue(this.value + this.step);\n\t}\n\n\t@onEvent({ ref: 'input', type: 'change' })\n\tonChange(event: Event): void {\n\t\tconst input = event.target as HTMLInputElement;\n\t\tconst parsed = Number(input.value);\n\t\tthis.setValue(Number.isFinite(parsed) ? parsed : this.value);\n\t\tinput.value = String(this.value);\n\t}\n\n\t@onEvent({ ref: 'input', type: 'keydown' })\n\tonKeydown(event: KeyboardEvent): void {\n\t\tif (this.disabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (event.key === 'ArrowUp') {\n\t\t\tevent.preventDefault();\n\t\t\tthis.increment();\n\t\t} else if (event.key === 'ArrowDown') {\n\t\t\tevent.preventDefault();\n\t\t\tthis.decrement();\n\t\t} else if (event.key === 'Home') {\n\t\t\tevent.preventDefault();\n\t\t\tthis.setValue(this.min);\n\t\t} else if (event.key === 'End') {\n\t\t\tevent.preventDefault();\n\t\t\tthis.setValue(this.max);\n\t\t}\n\t}\n\n\toverride render() {\n\t\treturn (\n\t\t\t<div class=\"rui-spinbutton\">\n\t\t\t\t{this.label ? (\n\t\t\t\t\t<span class=\"rui-spinbutton__label\" id={`${this.id || 'spin'}-label`}>\n\t\t\t\t\t\t{this.$.label}\n\t\t\t\t\t</span>\n\t\t\t\t) : null}\n\t\t\t\t<div class=\"rui-spinbutton__control\">\n\t\t\t\t\t<slot name=\"decrease\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"rui-button rui-button--outline rui-button--sm\"\n\t\t\t\t\t\t\tdata-spinbutton-action=\"decrease\"\n\t\t\t\t\t\t\taria-label=\"Decrease\"\n\t\t\t\t\t\t\tdisabled={this.$.decreaseDisabled}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\u2212\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</slot>\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\tinputmode=\"numeric\"\n\t\t\t\t\t\tdata-ref=\"input\"\n\t\t\t\t\t\tdata-rui-control\n\t\t\t\t\t\tdata-rui-control-type=\"number\"\n\t\t\t\t\t\tclass=\"rui-spinbutton__input\"\n\t\t\t\t\t\trole=\"spinbutton\"\n\t\t\t\t\t\tprop:value={this.$.value.map(String)}\n\t\t\t\t\t\tdisabled={this.$.disabled}\n\t\t\t\t\t\tname={this.nameAttr}\n\t\t\t\t\t\taria-valuemin={this.$.min}\n\t\t\t\t\t\taria-valuemax={this.$.max}\n\t\t\t\t\t\taria-valuenow={this.$.value}\n\t\t\t\t\t\taria-label={this.resolvedAriaLabel}\n\t\t\t\t\t/>\n\t\t\t\t\t<slot name=\"increase\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"rui-button rui-button--outline rui-button--sm\"\n\t\t\t\t\t\t\tdata-spinbutton-action=\"increase\"\n\t\t\t\t\t\t\taria-label=\"Increase\"\n\t\t\t\t\t\t\tdisabled={this.$.increaseDisabled}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t+\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</slot>\n\t\t\t\t</div>\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 { WithChildren, RadiantSlotProps } from '../../../types';\nimport { defineRadiantView } from '../../../lib/radiant-view';\nimport type { RuiSpinbuttonProps } from './spinbutton.script';\nimport { RuiSpinbutton as RuiSpinbuttonElement } from './spinbutton.script';\nimport './spinbutton.css';\n\nexport const RuiSpinbutton = defineRadiantView(\n\tRuiSpinbuttonElement,\n\t({\n\t\tslot,\n\t\tvalue,\n\t\tmin,\n\t\tmax,\n\t\tstep,\n\t\tdisabled,\n\t\tlabel,\n\t\tname,\n\t\tchildren,\n\t}: WithChildren<RuiSpinbuttonProps & RadiantSlotProps>) => (\n\t\t<rui-spinbutton\n\t\t\tslot={slot}\n\t\t\tvalue={value}\n\t\t\tmin={min}\n\t\t\tmax={max}\n\t\t\tstep={step}\n\t\t\tdisabled={disabled}\n\t\t\tlabel={label}\n\t\t\tname={name}\n\t\t>\n\t\t\t{children}\n\t\t</rui-spinbutton>\n\t),\n);\n"],
5
+ "mappings": "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",
6
+ "names": ["RadiantElement", "customElement", "event", "onEvent", "onUpdated", "prop", "state", "RuiSpinbutton", "name", "label", "decreaseDisabled", "increaseDisabled", "button", "next", "stepped", "value", "input", "parsed", "RADIANT_VIEW_ELEMENT", "RADIANT_SCRIPT_MODULE", "RADIANT_SCRIPT_EXPORT", "linkViewToElement", "view", "element", "ssrModule", "defineRadiantView", "render", "args", "RuiSpinbutton", "defineRadiantView", "slot", "value", "min", "max", "step", "disabled", "label", "name", "children"]
7
+ }
@@ -0,0 +1,19 @@
1
+ @reference '../../../styles/radiant-ui.css';
2
+
3
+ rui-spinbutton {
4
+ @apply inline-flex;
5
+ }
6
+
7
+ @layer components {
8
+ .rui-spinbutton {
9
+ @apply flex flex-col gap-1 text-sm;
10
+ }
11
+
12
+ .rui-spinbutton__control {
13
+ @apply inline-flex items-center gap-1;
14
+ }
15
+
16
+ .rui-spinbutton__input {
17
+ @apply w-16 rounded-button border border-border bg-background px-2 py-1 text-center tabular-nums;
18
+ }
19
+ }
@@ -0,0 +1,4 @@
1
+ import type { WithChildren, RadiantSlotProps } from '../../../types';
2
+ import type { RuiSpinbuttonProps } from './spinbutton.script';
3
+ import './spinbutton.css';
4
+ export declare const RuiSpinbutton: import("../../../lib/radiant-view").RadiantViewComponent<WithChildren<RuiSpinbuttonProps & RadiantSlotProps>>;