@dreamtree-org/twreact-ui 1.2.1 → 1.3.1

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 (215) hide show
  1. package/DESIGN.md +118 -0
  2. package/README.md +231 -44
  3. package/ai-skills/dreamtree-ui.md +98 -12
  4. package/dist/ai-schema.json +452 -17
  5. package/dist/components/blocks/AppShell.d.ts +4 -0
  6. package/dist/components/blocks/AppShell.d.ts.map +1 -0
  7. package/dist/components/blocks/ConfirmDialog.d.ts +4 -0
  8. package/dist/components/blocks/ConfirmDialog.d.ts.map +1 -0
  9. package/dist/components/blocks/EmptyState.d.ts +4 -0
  10. package/dist/components/blocks/EmptyState.d.ts.map +1 -0
  11. package/dist/components/blocks/ErrorState.d.ts +4 -0
  12. package/dist/components/blocks/ErrorState.d.ts.map +1 -0
  13. package/dist/components/blocks/LoadingState.d.ts +9 -0
  14. package/dist/components/blocks/LoadingState.d.ts.map +1 -0
  15. package/dist/components/blocks/PageHeader.d.ts +4 -0
  16. package/dist/components/blocks/PageHeader.d.ts.map +1 -0
  17. package/dist/components/blocks/StatCard.d.ts +4 -0
  18. package/dist/components/blocks/StatCard.d.ts.map +1 -0
  19. package/dist/components/blocks/StatusPill.d.ts +5 -0
  20. package/dist/components/blocks/StatusPill.d.ts.map +1 -0
  21. package/dist/components/core/Accordion.d.ts.map +1 -1
  22. package/dist/components/core/Button.d.ts.map +1 -1
  23. package/dist/components/core/Checkbox.d.ts.map +1 -1
  24. package/dist/components/core/ColorPicker.d.ts.map +1 -1
  25. package/dist/components/core/DatePicker.d.ts.map +1 -1
  26. package/dist/components/core/DateRangePicker.d.ts.map +1 -1
  27. package/dist/components/core/Form.d.ts.map +1 -1
  28. package/dist/components/core/Input.d.ts.map +1 -1
  29. package/dist/components/core/LocationPicker.d.ts.map +1 -1
  30. package/dist/components/core/Popover.d.ts +4 -0
  31. package/dist/components/core/Popover.d.ts.map +1 -0
  32. package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
  33. package/dist/components/core/ProgressBar.d.ts.map +1 -1
  34. package/dist/components/core/Radio.d.ts.map +1 -1
  35. package/dist/components/core/Rate.d.ts.map +1 -1
  36. package/dist/components/core/Select.d.ts.map +1 -1
  37. package/dist/components/core/Skeleton.d.ts.map +1 -1
  38. package/dist/components/core/Slider.d.ts +4 -0
  39. package/dist/components/core/Slider.d.ts.map +1 -0
  40. package/dist/components/core/SpeechToText.d.ts.map +1 -1
  41. package/dist/components/core/Switch.d.ts.map +1 -1
  42. package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
  43. package/dist/components/core/Table/ColumnMenu.d.ts +2 -1
  44. package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
  45. package/dist/components/core/Table/MobileCard.d.ts +2 -2
  46. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  47. package/dist/components/core/Table/Table.d.ts.map +1 -1
  48. package/dist/components/core/Table/TableRow.d.ts +4 -2
  49. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  50. package/dist/components/core/Tabs.d.ts.map +1 -1
  51. package/dist/components/core/Textarea.d.ts +4 -0
  52. package/dist/components/core/Textarea.d.ts.map +1 -0
  53. package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
  54. package/dist/components/core/Tooltip.d.ts.map +1 -1
  55. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  56. package/dist/components/feedback/Drawer.d.ts +4 -0
  57. package/dist/components/feedback/Drawer.d.ts.map +1 -0
  58. package/dist/components/feedback/Toast.d.ts +14 -5
  59. package/dist/components/feedback/Toast.d.ts.map +1 -1
  60. package/dist/components/feedback/Tour.d.ts +4 -0
  61. package/dist/components/feedback/Tour.d.ts.map +1 -0
  62. package/dist/components/feedback/TourSpotlight.d.ts +9 -0
  63. package/dist/components/feedback/TourSpotlight.d.ts.map +1 -0
  64. package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
  65. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  66. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  67. package/dist/components/navigation/Sidebar.d.ts +8 -2
  68. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  69. package/dist/components/utility/Badge.d.ts.map +1 -1
  70. package/dist/components/utility/FileUpload.d.ts.map +1 -1
  71. package/dist/components/utility/Sortable.d.ts +4 -0
  72. package/dist/components/utility/Sortable.d.ts.map +1 -0
  73. package/dist/esm/_vendor/object-assign/index.js +99 -0
  74. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.development.js +190 -0
  75. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.production.min.js +26 -0
  76. package/dist/esm/_vendor/prop-types/_vendor/react-is/index.js +19 -0
  77. package/dist/esm/_vendor/prop-types/checkPropTypes.js +115 -0
  78. package/dist/esm/_vendor/prop-types/factoryWithThrowingShims.js +74 -0
  79. package/dist/esm/_vendor/prop-types/factoryWithTypeCheckers.js +625 -0
  80. package/dist/esm/_vendor/prop-types/index.js +30 -0
  81. package/dist/esm/_vendor/prop-types/lib/ReactPropTypesSecret.js +21 -0
  82. package/dist/esm/_vendor/prop-types/lib/has.js +11 -0
  83. package/dist/esm/_virtual/_commonjsHelpers.js +5 -0
  84. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
  85. package/dist/esm/_virtual/index.js +3 -0
  86. package/dist/esm/_virtual/index2.js +3 -0
  87. package/dist/esm/_virtual/react-is.development.js +3 -0
  88. package/dist/esm/_virtual/react-is.production.min.js +3 -0
  89. package/dist/esm/components/blocks/AppShell.js +205 -0
  90. package/dist/esm/components/blocks/ConfirmDialog.js +57 -0
  91. package/dist/esm/components/blocks/EmptyState.js +44 -0
  92. package/dist/esm/components/blocks/ErrorState.js +53 -0
  93. package/dist/esm/components/blocks/LoadingState.js +134 -0
  94. package/dist/esm/components/blocks/PageHeader.js +51 -0
  95. package/dist/esm/components/blocks/StatCard.js +79 -0
  96. package/dist/esm/components/blocks/StatusPill.js +55 -0
  97. package/dist/esm/components/core/Accordion.js +260 -0
  98. package/dist/esm/components/core/Button.js +59 -0
  99. package/dist/esm/components/core/Checkbox.js +188 -0
  100. package/dist/esm/components/core/ColorPicker.js +348 -0
  101. package/dist/esm/components/core/DatePicker.js +436 -0
  102. package/dist/esm/components/core/DateRangePicker.js +494 -0
  103. package/dist/esm/components/core/Form.js +522 -0
  104. package/dist/esm/components/core/Input.js +179 -0
  105. package/dist/esm/components/core/Loader.js +141 -0
  106. package/dist/esm/components/core/LocationPicker.js +161 -0
  107. package/dist/esm/components/core/Popover.js +171 -0
  108. package/dist/esm/components/core/PriceRangePicker.js +376 -0
  109. package/dist/esm/components/core/ProgressBar.js +152 -0
  110. package/dist/esm/components/core/Radio.js +156 -0
  111. package/dist/esm/components/core/Rate.js +197 -0
  112. package/dist/esm/components/core/RoundedTag.js +118 -0
  113. package/dist/esm/components/core/Select.js +857 -0
  114. package/dist/esm/components/core/Skeleton.js +100 -0
  115. package/dist/esm/components/core/Slider.js +134 -0
  116. package/dist/esm/components/core/SpeechToText.js +226 -0
  117. package/dist/esm/components/core/Switch.js +207 -0
  118. package/dist/esm/components/core/Table/ActionMenu.js +251 -0
  119. package/dist/esm/components/core/Table/ColumnMenu.js +55 -0
  120. package/dist/esm/components/core/Table/FieldInput.js +157 -0
  121. package/dist/esm/components/core/Table/MobileCard.js +187 -0
  122. package/dist/esm/components/core/Table/MobileFilters.js +72 -0
  123. package/dist/esm/components/core/Table/Pagination.js +157 -0
  124. package/dist/esm/components/core/Table/Table.js +1533 -0
  125. package/dist/esm/components/core/Table/TableRow.js +254 -0
  126. package/dist/esm/components/core/Table/constants.js +35 -0
  127. package/dist/esm/components/core/Table/helpers.js +124 -0
  128. package/dist/esm/components/core/Table/useClickOutside.js +26 -0
  129. package/dist/esm/components/core/Tabs.js +289 -0
  130. package/dist/esm/components/core/TextToSpeech.js +52 -0
  131. package/dist/esm/components/core/Textarea.js +125 -0
  132. package/dist/esm/components/core/ThreeDotPopover.js +160 -0
  133. package/dist/esm/components/core/Tooltip.js +372 -0
  134. package/dist/esm/components/feedback/Alert.js +96 -0
  135. package/dist/esm/components/feedback/Dialog.js +200 -0
  136. package/dist/esm/components/feedback/Drawer.js +171 -0
  137. package/dist/esm/components/feedback/Toast.js +362 -0
  138. package/dist/esm/components/feedback/Tour.js +214 -0
  139. package/dist/esm/components/feedback/TourSpotlight.js +71 -0
  140. package/dist/esm/components/navigation/Breadcrumbs.js +75 -0
  141. package/dist/esm/components/navigation/Dropdown.js +53 -0
  142. package/dist/esm/components/navigation/FootNav.js +51 -0
  143. package/dist/esm/components/navigation/Navbar.js +437 -0
  144. package/dist/esm/components/navigation/Sidebar.js +567 -0
  145. package/dist/esm/components/utility/Avatar.js +89 -0
  146. package/dist/esm/components/utility/Badge.js +47 -0
  147. package/dist/esm/components/utility/Card.js +85 -0
  148. package/dist/esm/components/utility/Carousel.js +97 -0
  149. package/dist/esm/components/utility/Condition.js +9 -0
  150. package/dist/esm/components/utility/FileUpload.js +177 -0
  151. package/dist/esm/components/utility/Pagination.js +111 -0
  152. package/dist/esm/components/utility/Sortable.js +190 -0
  153. package/dist/esm/components/utility/Stepper.js +101 -0
  154. package/dist/esm/hooks/useApi.js +169 -0
  155. package/dist/esm/hooks/useControllableState.js +32 -0
  156. package/dist/esm/hooks/useFocusTrap.js +85 -0
  157. package/dist/esm/hooks/useLatestRef.js +20 -0
  158. package/dist/esm/hooks/useMixins.js +100 -0
  159. package/dist/esm/hooks/useScrollLock.js +26 -0
  160. package/dist/esm/hooks/useSliderValues.js +135 -0
  161. package/dist/esm/hooks/useSortable.js +188 -0
  162. package/dist/esm/hooks/useTheme.js +53 -0
  163. package/dist/esm/hooks/useTourTarget.js +92 -0
  164. package/dist/esm/index.js +65 -0
  165. package/dist/esm/store/index.js +26 -0
  166. package/dist/esm/store/store.js +107 -0
  167. package/dist/esm/store/storeSlice.js +45 -0
  168. package/dist/esm/utils/cn.js +11 -0
  169. package/dist/esm/utils/emitter.js +169 -0
  170. package/dist/esm/utils/helpers.js +161 -0
  171. package/dist/esm/utils/position.js +134 -0
  172. package/dist/hooks/useApi.d.ts +2 -1
  173. package/dist/hooks/useApi.d.ts.map +1 -1
  174. package/dist/hooks/useControllableState.d.ts +11 -0
  175. package/dist/hooks/useControllableState.d.ts.map +1 -0
  176. package/dist/hooks/useFocusTrap.d.ts +15 -0
  177. package/dist/hooks/useFocusTrap.d.ts.map +1 -0
  178. package/dist/hooks/useLatestRef.d.ts +8 -0
  179. package/dist/hooks/useLatestRef.d.ts.map +1 -0
  180. package/dist/hooks/useMixins.d.ts.map +1 -1
  181. package/dist/hooks/useScrollLock.d.ts +2 -0
  182. package/dist/hooks/useScrollLock.d.ts.map +1 -0
  183. package/dist/hooks/useSliderValues.d.ts +43 -0
  184. package/dist/hooks/useSliderValues.d.ts.map +1 -0
  185. package/dist/hooks/useSortable.d.ts +32 -0
  186. package/dist/hooks/useSortable.d.ts.map +1 -0
  187. package/dist/hooks/useTheme.d.ts.map +1 -1
  188. package/dist/hooks/useTourTarget.d.ts +15 -0
  189. package/dist/hooks/useTourTarget.d.ts.map +1 -0
  190. package/dist/index.css +1 -1
  191. package/dist/index.d.ts +55 -39
  192. package/dist/index.esm.css +1 -1
  193. package/dist/index.esm.js +7937 -4659
  194. package/dist/index.js +7950 -4657
  195. package/dist/tokens/brands/default.css +1 -0
  196. package/dist/tokens/brands/default.json +5 -0
  197. package/dist/tokens/brands/practicepro.css +17 -0
  198. package/dist/tokens/brands/practicepro.json +27 -0
  199. package/dist/tokens/tailwind3-preset.cjs +214 -0
  200. package/dist/tokens/theme.css +193 -0
  201. package/dist/tokens/tokens.json +373 -0
  202. package/dist/tokens/vars.css +98 -0
  203. package/dist/types/blocks.d.ts +109 -0
  204. package/dist/types/blocks.d.ts.map +1 -0
  205. package/dist/types/index.d.ts +194 -5
  206. package/dist/types/index.d.ts.map +1 -1
  207. package/dist/utils/position.d.ts +30 -0
  208. package/dist/utils/position.d.ts.map +1 -0
  209. package/doc/README.md +26 -1
  210. package/mcp/catalog.snapshot.json +1643 -549
  211. package/package.json +24 -6
  212. package/tokens/brands/default.json +5 -0
  213. package/tokens/brands/practicepro.json +27 -0
  214. package/tokens/lib.cjs +128 -0
  215. package/tokens/tokens.json +133 -0
@@ -0,0 +1,376 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, typeof as _typeof, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+ import { forwardRef, useState, useEffect, useMemo } from 'react';
5
+ import { cn } from '../../utils/cn.js';
6
+
7
+ var _excluded = ["min", "max", "step", "minGap", "value", "defaultValue", "onChange", "onFinalChange", "showInputs", "showTooltips", "disabled", "presets", "formatValue", "className", "size", "colorClass", "ariaLabel"];
8
+ /**
9
+ * PriceRangeSlider - UI library component (Tailwind)
10
+ *
11
+ * Props
12
+ * - min: number (default 0)
13
+ * - max: number (default 1000)
14
+ * - step: number (default 1)
15
+ * - minGap: number (minimum distance between thumbs, default 5)
16
+ * - value: { min: number, max: number } | null (controlled)
17
+ * - defaultValue: { min: number, max: number } (uncontrolled initial)
18
+ * - onChange: (value) => void
19
+ * - onFinalChange: (value) => void // called on mouseup/touchend or Enter in inputs
20
+ * - showInputs: boolean (default true)
21
+ * - showTooltips: boolean (default true)
22
+ * - disabled: boolean
23
+ * - presets: Array<{ id: string|number, label: string, value: {min:number,max:number} }>
24
+ * - formatValue: (n) => string (formatting callback, default: n => n)
25
+ * - className: string (container custom classes)
26
+ * - size: 'sm' | 'md' | 'lg' (affects thumb size & spacing)
27
+ * - colorClass: Tailwind class for active track/thumb, default 'bg-pink-500'
28
+ * - ariaLabel: string
29
+ *
30
+ * Usage notes
31
+ * - Controlled mode: pass `value` and handle updates via onChange.
32
+ * - Uncontrolled mode: omit `value` and use `defaultValue`.
33
+ *
34
+ * Accessibility
35
+ * - Inputs are labelled and thumbs are keyboard-focusable
36
+ */
37
+ var PriceRangePicker = /*#__PURE__*/forwardRef(function PriceRangePicker(_ref, ref) {
38
+ var _ref$min = _ref.min,
39
+ min = _ref$min === void 0 ? 0 : _ref$min,
40
+ _ref$max = _ref.max,
41
+ max = _ref$max === void 0 ? 1000 : _ref$max,
42
+ _ref$step = _ref.step,
43
+ step = _ref$step === void 0 ? 1 : _ref$step,
44
+ _ref$minGap = _ref.minGap,
45
+ minGap = _ref$minGap === void 0 ? 5 : _ref$minGap,
46
+ _ref$value = _ref.value,
47
+ value = _ref$value === void 0 ? null : _ref$value,
48
+ _ref$defaultValue = _ref.defaultValue,
49
+ defaultValue = _ref$defaultValue === void 0 ? {
50
+ min: 0,
51
+ max: 1000
52
+ } : _ref$defaultValue,
53
+ _ref$onChange = _ref.onChange,
54
+ onChange = _ref$onChange === void 0 ? function () {} : _ref$onChange,
55
+ _ref$onFinalChange = _ref.onFinalChange,
56
+ onFinalChange = _ref$onFinalChange === void 0 ? function () {} : _ref$onFinalChange,
57
+ _ref$showInputs = _ref.showInputs,
58
+ showInputs = _ref$showInputs === void 0 ? true : _ref$showInputs,
59
+ _ref$showTooltips = _ref.showTooltips,
60
+ showTooltips = _ref$showTooltips === void 0 ? true : _ref$showTooltips,
61
+ _ref$disabled = _ref.disabled,
62
+ disabled = _ref$disabled === void 0 ? false : _ref$disabled,
63
+ _ref$presets = _ref.presets,
64
+ presets = _ref$presets === void 0 ? [] : _ref$presets,
65
+ _ref$formatValue = _ref.formatValue,
66
+ formatValue = _ref$formatValue === void 0 ? function (n) {
67
+ return String(n);
68
+ } : _ref$formatValue,
69
+ _ref$className = _ref.className,
70
+ className = _ref$className === void 0 ? "" : _ref$className,
71
+ _ref$size = _ref.size,
72
+ size = _ref$size === void 0 ? "md" : _ref$size,
73
+ _ref$colorClass = _ref.colorClass,
74
+ colorClass = _ref$colorClass === void 0 ? "bg-pink-500" : _ref$colorClass,
75
+ _ref$ariaLabel = _ref.ariaLabel,
76
+ ariaLabel = _ref$ariaLabel === void 0 ? "Price range" : _ref$ariaLabel,
77
+ rest = _objectWithoutProperties(_ref, _excluded);
78
+ var isControlled = value && _typeof(value) === "object";
79
+ var _useState = useState(isControlled ? value.min : defaultValue.min),
80
+ _useState2 = _slicedToArray(_useState, 2),
81
+ internalMin = _useState2[0],
82
+ setInternalMin = _useState2[1];
83
+ var _useState3 = useState(isControlled ? value.max : defaultValue.max),
84
+ _useState4 = _slicedToArray(_useState3, 2),
85
+ internalMax = _useState4[0],
86
+ setInternalMax = _useState4[1];
87
+ // Inputs mirror state so editing doesn't immediately break constraints
88
+ var _useState5 = useState(internalMin),
89
+ _useState6 = _slicedToArray(_useState5, 2),
90
+ minInput = _useState6[0],
91
+ setMinInput = _useState6[1];
92
+ var _useState7 = useState(internalMax),
93
+ _useState8 = _slicedToArray(_useState7, 2),
94
+ maxInput = _useState8[0],
95
+ setMaxInput = _useState8[1];
96
+ // dragging state
97
+ var _useState9 = useState(false),
98
+ _useState0 = _slicedToArray(_useState9, 2),
99
+ isDragging = _useState0[0],
100
+ setIsDragging = _useState0[1];
101
+ useEffect(function () {
102
+ if (isControlled) {
103
+ setInternalMin(value.min);
104
+ setInternalMax(value.max);
105
+ setMinInput(value.min);
106
+ setMaxInput(value.max);
107
+ }
108
+ }, [value, isControlled]);
109
+ // Update inputs when internal changes (uncontrolled)
110
+ useEffect(function () {
111
+ if (!isControlled) {
112
+ setMinInput(internalMin);
113
+ setMaxInput(internalMax);
114
+ }
115
+ }, [internalMin, internalMax, isControlled]);
116
+ var clamp = function clamp(v) {
117
+ return Math.min(max, Math.max(min, v));
118
+ };
119
+ var setValues = function setValues(next) {
120
+ // next: {min, max}
121
+ // enforce gap and clamp
122
+ var a = clamp(Math.round(next.min / step) * step);
123
+ var b = clamp(Math.round(next.max / step) * step);
124
+ if (b - a < minGap) {
125
+ // push them apart (prefer keeping changed thumb)
126
+ if (next._active === "min") {
127
+ a = clamp(b - minGap);
128
+ } else if (next._active === "max") {
129
+ b = clamp(a + minGap);
130
+ } else {
131
+ // equal distribution
132
+ if (a + minGap <= max) b = a + minGap;else a = b - minGap;
133
+ }
134
+ }
135
+ if (isControlled) {
136
+ onChange({
137
+ min: a,
138
+ max: b
139
+ });
140
+ } else {
141
+ setInternalMin(a);
142
+ setInternalMax(b);
143
+ onChange({
144
+ min: a,
145
+ max: b
146
+ });
147
+ }
148
+ };
149
+ var handleFinal = function handleFinal(next) {
150
+ onFinalChange({
151
+ min: next.min,
152
+ max: next.max
153
+ });
154
+ };
155
+ // Handlers for range inputs
156
+ var handleMinRange = function handleMinRange(e) {
157
+ if (disabled) return;
158
+ var v = parseInt(e.target.value, 10);
159
+ setValues({
160
+ min: v,
161
+ max: isControlled ? value.max : internalMax,
162
+ _active: "min"
163
+ });
164
+ };
165
+ var handleMaxRange = function handleMaxRange(e) {
166
+ if (disabled) return;
167
+ var v = parseInt(e.target.value, 10);
168
+ setValues({
169
+ min: isControlled ? value.min : internalMin,
170
+ max: v,
171
+ _active: "max"
172
+ });
173
+ };
174
+ // Inputs change handlers (number boxes)
175
+ var handleMinInputChange = function handleMinInputChange(e) {
176
+ var raw = e.target.value;
177
+ var parsed = raw === "" ? "" : parseInt(raw, 10);
178
+ setMinInput(parsed);
179
+ };
180
+ var handleMaxInputChange = function handleMaxInputChange(e) {
181
+ var raw = e.target.value;
182
+ var parsed = raw === "" ? "" : parseInt(raw, 10);
183
+ setMaxInput(parsed);
184
+ };
185
+ var commitMinInput = function commitMinInput() {
186
+ var v = minInput === "" ? min : parseInt(minInput, 10);
187
+ v = clamp(v);
188
+ setValues({
189
+ min: v,
190
+ max: isControlled ? value.max : internalMax,
191
+ _active: "min"
192
+ });
193
+ handleFinal({
194
+ min: v,
195
+ max: isControlled ? value.max : internalMax
196
+ });
197
+ };
198
+ var commitMaxInput = function commitMaxInput() {
199
+ var v = maxInput === "" ? max : parseInt(maxInput, 10);
200
+ v = clamp(v);
201
+ setValues({
202
+ min: isControlled ? value.min : internalMin,
203
+ max: v,
204
+ _active: "max"
205
+ });
206
+ handleFinal({
207
+ min: isControlled ? value.min : internalMin,
208
+ max: v
209
+ });
210
+ };
211
+ // Keyboard handling for inputs
212
+ var handleMinInputKey = function handleMinInputKey(e) {
213
+ if (e.key === "Enter") commitMinInput();
214
+ };
215
+ var handleMaxInputKey = function handleMaxInputKey(e) {
216
+ if (e.key === "Enter") commitMaxInput();
217
+ };
218
+ // Dragging helpers
219
+ var startDrag = function startDrag() {
220
+ return setIsDragging(true);
221
+ };
222
+ var stopDrag = function stopDrag() {
223
+ setIsDragging(false);
224
+ handleFinal({
225
+ min: isControlled ? value.min : internalMin,
226
+ max: isControlled ? value.max : internalMax
227
+ });
228
+ };
229
+ var minPercent = useMemo(function () {
230
+ return ((isControlled ? value.min : internalMin) - min) / (max - min) * 100;
231
+ }, [value, internalMin, min, max, isControlled]);
232
+ var maxPercent = useMemo(function () {
233
+ return ((isControlled ? value.max : internalMax) - min) / (max - min) * 100;
234
+ }, [value, internalMax, min, max, isControlled]);
235
+ var thumbSize = size === "sm" ? 16 : size === "lg" ? 28 : 22;
236
+ var inputWidth = size === "sm" ? "w-12" : size === "lg" ? "w-20" : "w-14";
237
+ var trackHeight = size === "sm" ? "h-1" : size === "lg" ? "h-2" : "h-1.5";
238
+ // Preset helper
239
+ var applyPreset = function applyPreset(p) {
240
+ if (!p || !p.value) return;
241
+ var _p$value = p.value,
242
+ pmin = _p$value.min,
243
+ pmax = _p$value.max;
244
+ setValues({
245
+ min: pmin,
246
+ max: pmax
247
+ });
248
+ handleFinal({
249
+ min: pmin,
250
+ max: pmax
251
+ });
252
+ };
253
+ return jsxs("div", _objectSpread2(_objectSpread2({
254
+ ref: ref,
255
+ className: cn("bg-white rounded-lg p-4 w-full max-w-lg", className)
256
+ }, rest), {}, {
257
+ children: [jsxs("div", {
258
+ className: "flex items-center justify-between",
259
+ children: [showInputs ? jsxs("div", {
260
+ className: "flex items-center gap-2 w-full",
261
+ children: [jsx("div", {
262
+ className: "flex-1",
263
+ children: jsx("input", {
264
+ type: "number",
265
+ "aria-label": "Minimum",
266
+ value: minInput,
267
+ onChange: handleMinInputChange,
268
+ onBlur: commitMinInput,
269
+ onKeyDown: handleMinInputKey,
270
+ className: "".concat(inputWidth, " py-2 border border-gray-300 rounded-md text-center text-sm disabled:opacity-50"),
271
+ min: min,
272
+ max: max,
273
+ disabled: disabled
274
+ })
275
+ }), jsx("div", {
276
+ className: "text-xs text-primary-500",
277
+ children: "\u2014"
278
+ }), jsx("div", {
279
+ className: "flex-1 flex justify-end",
280
+ children: jsx("input", {
281
+ type: "number",
282
+ "aria-label": "Maximum",
283
+ value: maxInput,
284
+ onChange: handleMaxInputChange,
285
+ onBlur: commitMaxInput,
286
+ onKeyDown: handleMaxInputKey,
287
+ className: "".concat(inputWidth, " py-2 border border-gray-300 rounded-md text-center text-sm disabled:opacity-50"),
288
+ min: min,
289
+ max: max,
290
+ disabled: disabled
291
+ })
292
+ })]
293
+ }) : jsxs("div", {
294
+ className: "text-sm",
295
+ children: [formatValue(isControlled ? value.min : internalMin), " - ", formatValue(isControlled ? value.max : internalMax)]
296
+ }), presets && presets.length > 0 && jsx("div", {
297
+ className: "ml-4 flex gap-2",
298
+ children: presets.map(function (p) {
299
+ return jsx("button", {
300
+ type: "button",
301
+ onClick: function onClick() {
302
+ return applyPreset(p);
303
+ },
304
+ className: "text-xs px-2 py-1 border rounded-md hover:bg-gray-50 disabled:opacity-50",
305
+ disabled: disabled,
306
+ children: p.label
307
+ }, p.id);
308
+ })
309
+ })]
310
+ }), jsxs("div", {
311
+ className: "relative w-full mt-4 ".concat(trackHeight, " bg-gray-300 rounded-full"),
312
+ children: [jsx("div", {
313
+ className: "absolute ".concat(trackHeight, " rounded-full ").concat(colorClass),
314
+ style: {
315
+ left: "".concat(minPercent, "%"),
316
+ right: "".concat(100 - maxPercent, "%")
317
+ }
318
+ }), jsx("input", {
319
+ type: "range",
320
+ min: min,
321
+ max: max,
322
+ step: step,
323
+ value: isControlled ? value.min : internalMin,
324
+ onChange: handleMinRange,
325
+ onMouseDown: startDrag,
326
+ onMouseUp: stopDrag,
327
+ onTouchStart: startDrag,
328
+ onTouchEnd: stopDrag,
329
+ disabled: disabled,
330
+ "aria-label": "".concat(ariaLabel, " - min"),
331
+ className: "absolute inset-0 w-full appearance-none bg-transparent pointer-events-auto",
332
+ style: {
333
+ zIndex: 20
334
+ }
335
+ }), jsx("input", {
336
+ type: "range",
337
+ min: min,
338
+ max: max,
339
+ step: step,
340
+ value: isControlled ? value.max : internalMax,
341
+ onChange: handleMaxRange,
342
+ onMouseDown: startDrag,
343
+ onMouseUp: stopDrag,
344
+ onTouchStart: startDrag,
345
+ onTouchEnd: stopDrag,
346
+ disabled: disabled,
347
+ "aria-label": "".concat(ariaLabel, " - max"),
348
+ className: "absolute inset-0 w-full appearance-none bg-transparent pointer-events-auto",
349
+ style: {
350
+ zIndex: 10
351
+ }
352
+ }), showTooltips && isDragging && jsxs(Fragment, {
353
+ children: [jsx("div", {
354
+ className: "absolute -top-9 text-xs bg-white px-2 py-1 rounded-md shadow-sm border",
355
+ style: {
356
+ left: "".concat(minPercent, "%"),
357
+ transform: "translateX(-50%)"
358
+ },
359
+ children: formatValue(isControlled ? value.min : internalMin)
360
+ }), jsx("div", {
361
+ className: "absolute -top-9 text-xs bg-white px-2 py-1 rounded-md shadow-sm border",
362
+ style: {
363
+ left: "".concat(maxPercent, "%"),
364
+ transform: "translateX(-50%)"
365
+ },
366
+ children: formatValue(isControlled ? value.max : internalMax)
367
+ })]
368
+ })]
369
+ }), jsx("style", {
370
+ children: "\n input[type=range] { -webkit-appearance: none; appearance: none; background: transparent; }\n input[type=range]::-webkit-slider-runnable-track { height: 6px; background: transparent; }\n input[type=range]::-moz-range-track { height: 6px; background: transparent; }\n\n input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n height: ".concat(thumbSize, "px;\n width: ").concat(thumbSize, "px;\n border-radius: 9999px;\n border: 3px solid #ffffff;\n background: #ff6b6b;\n box-shadow: 0 2px 8px rgba(0,0,0,0.12);\n cursor: pointer;\n margin-top: -").concat(Math.round(thumbSize / 2 - 6), "px; /* vertical centering tweak */\n position: relative;\n }\n\n input[type=range]::-moz-range-thumb {\n height: ").concat(thumbSize, "px;\n width: ").concat(thumbSize, "px;\n border-radius: 9999px;\n border: 3px solid #ffffff;\n background: #ff6b6b;\n box-shadow: 0 2px 8px rgba(0,0,0,0.12);\n cursor: pointer;\n position: relative;\n }\n\n /* Make the track invisible so our styled track shows through */\n input[type=range]::-webkit-slider-runnable-track { background: transparent; }\n input[type=range]::-moz-range-track { background: transparent; }\n\n ")
371
+ })]
372
+ }));
373
+ });
374
+ PriceRangePicker.displayName = "PriceRangePicker";
375
+
376
+ export { PriceRangePicker as default };
@@ -0,0 +1,152 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import { forwardRef } from 'react';
5
+ import { cn } from '../../utils/cn.js';
6
+
7
+ var _excluded = ["value", "max", "size", "showValue", "rounded", "color", "bgColor", "valueColor", "striped", "animated", "label", "ariaLabel", "className", "style"];
8
+ // ProgressBar. Without colour props it uses the primary token classes, so it follows the brand (STUDIO-59).
9
+ // color, bgColor and valueColor still accept HEX for backwards compatibility (deprecated).
10
+ var SIZE_MAP = {
11
+ xs: "h-1",
12
+ sm: "h-2",
13
+ md: "h-3",
14
+ lg: "h-5"
15
+ };
16
+ function isHexColor(str) {
17
+ return typeof str === "string" && /^#([0-9A-F]{3}){1,2}$/i.test(str);
18
+ }
19
+ function hexToRgb(hex) {
20
+ if (!isHexColor(hex)) return null;
21
+ var h = hex.replace('#', '');
22
+ if (h.length === 3) h = h.split('').map(function (ch) {
23
+ return ch + ch;
24
+ }).join('');
25
+ var bigint = parseInt(h, 16);
26
+ return {
27
+ r: bigint >> 16 & 255,
28
+ g: bigint >> 8 & 255,
29
+ b: bigint & 255
30
+ };
31
+ }
32
+ function luminance(hex) {
33
+ var rgb = hexToRgb(hex);
34
+ if (!rgb) return 0;
35
+ // relative luminance
36
+ var srgb = [rgb.r, rgb.g, rgb.b].map(function (v) {
37
+ var s = v / 255;
38
+ return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
39
+ });
40
+ return 0.2126 * srgb[0] + 0.7152 * srgb[1] + 0.0722 * srgb[2];
41
+ }
42
+ function readableTextColor(bgHex, preferred) {
43
+ // If preferred is provided and valid, use it; otherwise pick black/white based on contrast
44
+ if (isHexColor(preferred)) return preferred;
45
+ var L = luminance(bgHex);
46
+ // WCAG suggests threshold around 0.179 for black/white contrast — we'll use 0.179
47
+ return L > 0.179 ? '#000000' : '#ffffff';
48
+ }
49
+ var ProgressBar = /*#__PURE__*/forwardRef(function ProgressBar(_ref, ref) {
50
+ var _SIZE_MAP$size;
51
+ var _ref$value = _ref.value,
52
+ value = _ref$value === void 0 ? 0 : _ref$value,
53
+ _ref$max = _ref.max,
54
+ max = _ref$max === void 0 ? 100 : _ref$max,
55
+ _ref$size = _ref.size,
56
+ size = _ref$size === void 0 ? 'md' : _ref$size,
57
+ _ref$showValue = _ref.showValue,
58
+ showValue = _ref$showValue === void 0 ? false : _ref$showValue,
59
+ _ref$rounded = _ref.rounded,
60
+ rounded = _ref$rounded === void 0 ? true : _ref$rounded,
61
+ _ref$color = _ref.color,
62
+ color = _ref$color === void 0 ? undefined : _ref$color,
63
+ _ref$bgColor = _ref.bgColor,
64
+ bgColor = _ref$bgColor === void 0 ? undefined : _ref$bgColor,
65
+ _ref$valueColor = _ref.valueColor,
66
+ valueColor = _ref$valueColor === void 0 ? undefined : _ref$valueColor,
67
+ _ref$striped = _ref.striped,
68
+ striped = _ref$striped === void 0 ? false : _ref$striped,
69
+ _ref$animated = _ref.animated,
70
+ animated = _ref$animated === void 0 ? false : _ref$animated,
71
+ _ref$label = _ref.label,
72
+ label = _ref$label === void 0 ? '' : _ref$label,
73
+ _ref$ariaLabel = _ref.ariaLabel,
74
+ ariaLabel = _ref$ariaLabel === void 0 ? 'Progress' : _ref$ariaLabel,
75
+ _ref$className = _ref.className,
76
+ className = _ref$className === void 0 ? '' : _ref$className,
77
+ _ref$style = _ref.style,
78
+ style = _ref$style === void 0 ? {} : _ref$style,
79
+ rest = _objectWithoutProperties(_ref, _excluded);
80
+ var safeMax = typeof max === 'number' && max > 0 ? max : 100;
81
+ var safeValue = typeof value === 'number' ? value : 0;
82
+ var clamped = Math.max(0, Math.min(safeValue, safeMax));
83
+ var percent = safeMax === 0 ? 0 : clamped / safeMax * 100;
84
+ // A valid HEX override is applied inline; anything else falls back to the token classes.
85
+ var fillHex = isHexColor(color) ? color : null;
86
+ var trackHex = isHexColor(bgColor) ? bgColor : null;
87
+ var textHex = isHexColor(valueColor) ? valueColor : fillHex ? readableTextColor(fillHex, undefined) : null;
88
+ var fillClass = fillHex ? '' : 'bg-primary-600';
89
+ var trackClass = trackHex ? '' : 'bg-primary-100';
90
+ var textClass = textHex ? '' : 'text-white';
91
+ // height class or inline style
92
+ var heightClass = typeof size === 'number' ? '' : (_SIZE_MAP$size = SIZE_MAP[size]) !== null && _SIZE_MAP$size !== void 0 ? _SIZE_MAP$size : SIZE_MAP['md'];
93
+ var heightStyle = typeof size === 'number' ? {
94
+ height: "".concat(size, "px")
95
+ } : {};
96
+ var radiusClass = rounded ? 'rounded-full' : 'rounded-sm';
97
+ var trackRadiusClass = rounded ? 'rounded-full' : 'rounded-sm';
98
+ // stripe background
99
+ var stripeStyle = striped ? {
100
+ backgroundImage: "repeating-linear-gradient(45deg, rgba(255,255,255,0.12) 0, rgba(255,255,255,0.12) 10px, transparent 10px, transparent 20px)",
101
+ backgroundSize: '20px 20px',
102
+ overflow: 'hidden'
103
+ } : {};
104
+ var animatedStyle = animated ? {
105
+ animation: 'stripeShift 1s linear infinite'
106
+ } : {};
107
+ var finalFillStyle = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({
108
+ width: "".concat(percent, "%")
109
+ }, fillHex ? {
110
+ backgroundColor: fillHex
111
+ } : {}), textHex ? {
112
+ color: textHex
113
+ } : {}), stripeStyle), animatedStyle), {}, {
114
+ transition: 'width 300ms ease-out'
115
+ });
116
+ return jsxs("div", _objectSpread2(_objectSpread2({
117
+ ref: ref,
118
+ className: cn("w-full", className),
119
+ style: style
120
+ }, rest), {}, {
121
+ children: [jsx("style", {
122
+ children: "@keyframes stripeShift { 0% { background-position: 0 0; } 100% { background-position: 40px 0; } }"
123
+ }), label ? jsx("div", {
124
+ className: "mb-2 text-sm font-medium",
125
+ children: label
126
+ }) : null, jsx("div", {
127
+ className: cn('w-full relative overflow-hidden', trackRadiusClass, trackClass),
128
+ style: _objectSpread2(_objectSpread2({}, trackHex ? {
129
+ backgroundColor: trackHex
130
+ } : {}), heightStyle),
131
+ role: "progressbar",
132
+ "aria-label": ariaLabel,
133
+ "aria-valuemin": 0,
134
+ "aria-valuemax": safeMax,
135
+ "aria-valuenow": clamped,
136
+ children: jsx("div", {
137
+ className: cn(radiusClass, heightClass, fillClass, textClass, 'flex items-center justify-center text-sm font-medium'),
138
+ style: finalFillStyle,
139
+ children: showValue ? jsxs("div", {
140
+ className: "px-2 whitespace-nowrap truncate",
141
+ style: textHex ? {
142
+ color: textHex
143
+ } : undefined,
144
+ children: [Math.round(percent), "%"]
145
+ }) : null
146
+ })
147
+ })]
148
+ }));
149
+ });
150
+ ProgressBar.displayName = "ProgressBar";
151
+
152
+ export { ProgressBar as default };
@@ -0,0 +1,156 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import { forwardRef, useId, useState } from 'react';
5
+ import PropTypes from '../../_vendor/prop-types/index.js';
6
+
7
+ var _excluded = ["id", "name", "value", "checked", "defaultChecked", "onChange", "disabled", "required", "label", "size", "labelPosition", "radioColor", "className", "ariaLabel"];
8
+ var cn = function cn() {
9
+ for (var _len = arguments.length, vals = new Array(_len), _key = 0; _key < _len; _key++) {
10
+ vals[_key] = arguments[_key];
11
+ }
12
+ return vals.filter(Boolean).join(" ");
13
+ };
14
+ var SIZE_MAP = {
15
+ sm: {
16
+ outer: "h-4 w-4",
17
+ dot: "w-2.5 h-2.5",
18
+ label: "text-sm"
19
+ },
20
+ md: {
21
+ outer: "h-5 w-5",
22
+ dot: "w-3 h-3",
23
+ label: "text-base"
24
+ },
25
+ lg: {
26
+ outer: "h-6 w-6",
27
+ dot: "w-3.5 h-3.5",
28
+ label: "text-base"
29
+ }
30
+ };
31
+ var Radio = /*#__PURE__*/forwardRef(function Radio(_ref, ref) {
32
+ var id = _ref.id,
33
+ name = _ref.name,
34
+ value = _ref.value,
35
+ checked = _ref.checked,
36
+ defaultChecked = _ref.defaultChecked,
37
+ onChange = _ref.onChange,
38
+ _ref$disabled = _ref.disabled,
39
+ disabled = _ref$disabled === void 0 ? false : _ref$disabled,
40
+ _ref$required = _ref.required,
41
+ required = _ref$required === void 0 ? false : _ref$required,
42
+ label = _ref.label,
43
+ _ref$size = _ref.size,
44
+ size = _ref$size === void 0 ? "md" : _ref$size,
45
+ _ref$labelPosition = _ref.labelPosition,
46
+ labelPosition = _ref$labelPosition === void 0 ? "right" : _ref$labelPosition,
47
+ radioColor = _ref.radioColor,
48
+ _ref$className = _ref.className,
49
+ className = _ref$className === void 0 ? "" : _ref$className,
50
+ ariaLabel = _ref.ariaLabel,
51
+ props = _objectWithoutProperties(_ref, _excluded);
52
+ var autoId = useId();
53
+ var inputId = id || "".concat(autoId, "-radio");
54
+ var accentColor = radioColor || "blue";
55
+ var _useState = useState(!!defaultChecked),
56
+ _useState2 = _slicedToArray(_useState, 2),
57
+ internalChecked = _useState2[0],
58
+ setInternalChecked = _useState2[1];
59
+ // Reset to `defaultChecked` when it (or controlled-ness) changes
60
+ // (adjust-during-render pattern).
61
+ var _useState3 = useState({
62
+ defaultChecked: defaultChecked,
63
+ checked: checked
64
+ }),
65
+ _useState4 = _slicedToArray(_useState3, 2),
66
+ prevProps = _useState4[0],
67
+ setPrevProps = _useState4[1];
68
+ if (prevProps.defaultChecked !== defaultChecked || prevProps.checked !== checked) {
69
+ setPrevProps({
70
+ defaultChecked: defaultChecked,
71
+ checked: checked
72
+ });
73
+ if (checked === undefined) setInternalChecked(!!defaultChecked);
74
+ }
75
+ var isChecked = checked !== undefined ? checked : internalChecked;
76
+ function handleChange(e) {
77
+ if (checked === undefined) setInternalChecked(e.target.checked);
78
+ if (typeof onChange === "function") onChange(e);
79
+ }
80
+ var sizeClasses = SIZE_MAP[size] || SIZE_MAP.md;
81
+ var showLabelLeft = label && labelPosition === "left";
82
+ return jsxs("label", {
83
+ htmlFor: inputId,
84
+ className: cn("relative inline-flex items-center select-none gap-2", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer", className),
85
+ "aria-disabled": disabled ? "true" : undefined,
86
+ children: [showLabelLeft && jsxs("span", {
87
+ className: cn(sizeClasses.label, "leading-none", disabled && "text-primary-400"),
88
+ children: [label, required ? jsx("span", {
89
+ "aria-hidden": "true",
90
+ children: " *"
91
+ }) : null]
92
+ }), jsx("input", _objectSpread2({
93
+ ref: ref,
94
+ id: inputId,
95
+ type: "radio",
96
+ name: name,
97
+ value: value,
98
+ checked: checked,
99
+ defaultChecked: defaultChecked,
100
+ onChange: handleChange,
101
+ disabled: disabled,
102
+ required: required,
103
+ "aria-label": ariaLabel,
104
+ className: "absolute inset-0 w-full h-full opacity-0 appearance-none m-0 z-10 cursor-pointer"
105
+ }, props)), jsx("span", {
106
+ "aria-hidden": true,
107
+ className: cn("inline-flex items-center justify-center rounded-full transition-all"),
108
+ style: {
109
+ "--radio-accent": accentColor
110
+ },
111
+ children: jsx("span", {
112
+ className: cn("flex items-center justify-center rounded-full border transition-colors duration-150 ease-in-out border-slate-300", sizeClasses.outer, disabled ? "bg-slate-100" : "bg-white", isChecked ? "shadow-inner" : ""),
113
+ children: jsx("span", {
114
+ "aria-hidden": true,
115
+ className: cn("rounded-full transform transition-all duration-200 ease-out", sizeClasses.dot),
116
+ style: {
117
+ backgroundColor: isChecked ? accentColor : "transparent",
118
+ opacity: isChecked ? 1 : 0,
119
+ transform: isChecked ? "scale(1)" : "scale(0.7)"
120
+ }
121
+ })
122
+ })
123
+ }), !showLabelLeft && label && jsxs("span", {
124
+ className: cn(sizeClasses.label, "leading-none", disabled && "text-primary-400"),
125
+ children: [label, required ? jsx("span", {
126
+ "aria-hidden": "true",
127
+ children: " *"
128
+ }) : null]
129
+ })]
130
+ });
131
+ });
132
+ Radio.propTypes = {
133
+ id: PropTypes.string,
134
+ name: PropTypes.string,
135
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
136
+ checked: PropTypes.bool,
137
+ defaultChecked: PropTypes.bool,
138
+ onChange: PropTypes.func,
139
+ disabled: PropTypes.bool,
140
+ required: PropTypes.bool,
141
+ label: PropTypes.node,
142
+ size: PropTypes.oneOf(["sm", "md", "lg"]),
143
+ labelPosition: PropTypes.oneOf(["left", "right"]),
144
+ radioColor: PropTypes.string,
145
+ backgroundColor: PropTypes.string,
146
+ className: PropTypes.string,
147
+ ariaLabel: PropTypes.string
148
+ };
149
+ Radio.defaultProps = {
150
+ size: "md",
151
+ labelPosition: "right",
152
+ disabled: false,
153
+ required: false
154
+ };
155
+
156
+ export { Radio as default };