@dreamtree-org/twreact-ui 1.3.10 → 1.3.11
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.
- package/README.md +30 -0
- package/ai-skills/dreamtree-ui.md +12 -7
- package/dist/ai-schema.json +137 -21
- package/dist/charts/index.js +195 -66
- package/dist/components/charts/CartesianChart.d.ts.map +1 -1
- package/dist/components/charts/ChartFrame.d.ts.map +1 -1
- package/dist/components/charts/useChartLayout.d.ts +25 -0
- package/dist/components/charts/useChartLayout.d.ts.map +1 -0
- package/dist/components/core/Button.d.ts.map +1 -1
- package/dist/components/core/Checkbox.d.ts.map +1 -1
- package/dist/components/core/ColorPicker.d.ts.map +1 -1
- package/dist/components/core/Input.d.ts.map +1 -1
- package/dist/components/core/Loader.d.ts.map +1 -1
- package/dist/components/core/LocationPicker.d.ts.map +1 -1
- package/dist/components/core/ProgressBar.d.ts.map +1 -1
- package/dist/components/core/Radio.d.ts.map +1 -1
- package/dist/components/core/Rate.d.ts.map +1 -1
- package/dist/components/core/RoundedTag.d.ts.map +1 -1
- package/dist/components/core/Skeleton.d.ts.map +1 -1
- package/dist/components/core/Slider.d.ts.map +1 -1
- package/dist/components/core/SpeechToText.d.ts.map +1 -1
- package/dist/components/core/Switch.d.ts.map +1 -1
- package/dist/components/core/Tabs.d.ts +2 -5
- package/dist/components/core/Tabs.d.ts.map +1 -1
- package/dist/components/core/Textarea.d.ts.map +1 -1
- package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/navigation/FootNav.d.ts.map +1 -1
- package/dist/components/utility/Avatar.d.ts +8 -0
- package/dist/components/utility/Avatar.d.ts.map +1 -1
- package/dist/components/utility/AvatarGroup.d.ts +4 -0
- package/dist/components/utility/AvatarGroup.d.ts.map +1 -0
- package/dist/components/utility/Badge.d.ts.map +1 -1
- package/dist/components/utility/Card.d.ts.map +1 -1
- package/dist/components/utility/Carousel.d.ts.map +1 -1
- package/dist/components/utility/FileUpload.d.ts.map +1 -1
- package/dist/components/utility/Pagination.d.ts.map +1 -1
- package/dist/components/utility/Sortable.d.ts.map +1 -1
- package/dist/components/utility/Stepper.d.ts.map +1 -1
- package/dist/esm/components/blocks/EmptyState.js +1 -1
- package/dist/esm/components/blocks/ErrorState.js +1 -1
- package/dist/esm/components/blocks/LoadingState.js +4 -4
- package/dist/esm/components/blocks/StatCard.js +6 -6
- package/dist/esm/components/blocks/StatusPill.js +5 -8
- package/dist/esm/components/charts/CartesianChart.js +85 -62
- package/dist/esm/components/charts/ChartFrame.js +12 -5
- package/dist/esm/components/charts/useChartLayout.js +105 -0
- package/dist/esm/components/core/Button.js +49 -25
- package/dist/esm/components/core/Checkbox.js +71 -45
- package/dist/esm/components/core/ColorPicker.js +31 -42
- package/dist/esm/components/core/Input.js +89 -22
- package/dist/esm/components/core/Loader.js +30 -44
- package/dist/esm/components/core/LocationPicker.js +82 -16
- package/dist/esm/components/core/ProgressBar.js +8 -12
- package/dist/esm/components/core/Radio.js +10 -12
- package/dist/esm/components/core/Rate.js +72 -4
- package/dist/esm/components/core/RoundedTag.js +5 -5
- package/dist/esm/components/core/Skeleton.js +13 -14
- package/dist/esm/components/core/Slider.js +24 -6
- package/dist/esm/components/core/SpeechToText.js +68 -16
- package/dist/esm/components/core/Switch.js +88 -16
- package/dist/esm/components/core/Tabs.js +180 -33
- package/dist/esm/components/core/Textarea.js +10 -2
- package/dist/esm/components/navigation/Breadcrumbs.js +97 -35
- package/dist/esm/components/navigation/FootNav.js +102 -13
- package/dist/esm/components/utility/Avatar.js +14 -12
- package/dist/esm/components/utility/AvatarGroup.js +56 -0
- package/dist/esm/components/utility/Badge.js +43 -23
- package/dist/esm/components/utility/Card.js +32 -8
- package/dist/esm/components/utility/Carousel.js +139 -29
- package/dist/esm/components/utility/FileUpload.js +106 -31
- package/dist/esm/components/utility/Pagination.js +31 -13
- package/dist/esm/components/utility/Sortable.js +6 -2
- package/dist/esm/components/utility/Stepper.js +110 -47
- package/dist/esm/hooks/useSliderValues.js +8 -2
- package/dist/esm/hooks/useSortable.js +107 -5
- package/dist/esm/index.js +1 -0
- package/dist/esm/utils/touchTarget.js +4 -1
- package/dist/hooks/useSliderValues.d.ts +6 -2
- package/dist/hooks/useSliderValues.d.ts.map +1 -1
- package/dist/hooks/useSortable.d.ts +11 -1
- package/dist/hooks/useSortable.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +2341 -1191
- package/dist/index.js +2341 -1190
- package/dist/types/charts.d.ts +3 -1
- package/dist/types/charts.d.ts.map +1 -1
- package/dist/types/index.d.ts +56 -7
- package/dist/types/index.d.ts.map +1 -1
- package/doc/README.md +1 -0
- package/mcp/catalog.snapshot.json +279 -80
- package/package.json +1 -1
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
-
import React, { forwardRef, useState, useRef, useId, useEffect, createContext, useContext } from 'react';
|
|
4
|
+
import React, { forwardRef, useState, useRef, useId, useEffect, createContext, useContext, useLayoutEffect } from 'react';
|
|
5
5
|
import { cn } from '../../utils/cn.js';
|
|
6
6
|
|
|
7
|
-
var _excluded = ["children", "defaultIndex", "index", "onChange", "orientation", "size", "variant", "animated", "className"]
|
|
7
|
+
var _excluded = ["children", "defaultIndex", "index", "onChange", "orientation", "size", "variant", "animated", "swipeable", "className"],
|
|
8
|
+
_excluded2 = ["children", "className"];
|
|
9
|
+
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
10
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
11
|
+
// Minimum horizontal travel (px) for a swipe to change tabs, and how much more
|
|
12
|
+
// horizontal than vertical it must be, so vertical page scrolls never switch tabs.
|
|
13
|
+
var SWIPE_THRESHOLD = 50;
|
|
14
|
+
var SWIPE_DOMINANCE = 1.5;
|
|
15
|
+
// Variants whose active state is drawn by the sliding indicator (horizontal only).
|
|
16
|
+
var INDICATOR_VARIANTS = ["line", "segmented"];
|
|
8
17
|
/*
|
|
9
18
|
Tabs.jsx
|
|
10
19
|
- Default export: Tabs (provider wrapper)
|
|
@@ -14,7 +23,10 @@ var _excluded = ["children", "defaultIndex", "index", "onChange", "orientation",
|
|
|
14
23
|
- Controlled / uncontrolled usage
|
|
15
24
|
- Keyboard navigation (Arrow keys, Home, End)
|
|
16
25
|
- ARIA attributes for accessibility
|
|
17
|
-
- Variants: "line" | "pills" | "unstyled"
|
|
26
|
+
- Variants: "line" | "pills" | "segmented" | "unstyled"
|
|
27
|
+
- Horizontal lists scroll with snap; the active tab is kept in view
|
|
28
|
+
- Animated active indicator for "line" / "segmented" (off under reduced motion)
|
|
29
|
+
- Optional `swipeable` panels (touch / pen pointer swipes)
|
|
18
30
|
- Sizes: "sm" | "md" | "lg"
|
|
19
31
|
- Simple fade animation
|
|
20
32
|
- Tailwind CSS only
|
|
@@ -60,6 +72,8 @@ var Tabs = /*#__PURE__*/forwardRef(function Tabs(_ref, ref) {
|
|
|
60
72
|
variant = _ref$variant === void 0 ? "line" : _ref$variant,
|
|
61
73
|
_ref$animated = _ref.animated,
|
|
62
74
|
animated = _ref$animated === void 0 ? true : _ref$animated,
|
|
75
|
+
_ref$swipeable = _ref.swipeable,
|
|
76
|
+
swipeable = _ref$swipeable === void 0 ? false : _ref$swipeable,
|
|
63
77
|
_ref$className = _ref.className,
|
|
64
78
|
className = _ref$className === void 0 ? "" : _ref$className,
|
|
65
79
|
rest = _objectWithoutProperties(_ref, _excluded);
|
|
@@ -71,6 +85,12 @@ var Tabs = /*#__PURE__*/forwardRef(function Tabs(_ref, ref) {
|
|
|
71
85
|
var activeIndex = isControlled ? controlledIndex : internalIndex;
|
|
72
86
|
var tabsRef = useRef([]); // DOM refs for keyboard navigation
|
|
73
87
|
var baseId = useId();
|
|
88
|
+
// Set by TabList once the sliding indicator has been measured; until then
|
|
89
|
+
// (SSR, first paint) tabs draw their own active styling.
|
|
90
|
+
var _useState3 = useState(false),
|
|
91
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
92
|
+
indicatorReady = _useState4[0],
|
|
93
|
+
setIndicatorReady = _useState4[1];
|
|
74
94
|
var changeTab = function changeTab(idx) {
|
|
75
95
|
if (!isControlled) setActiveIndex(idx);
|
|
76
96
|
onChange === null || onChange === void 0 || onChange(idx);
|
|
@@ -87,7 +107,10 @@ var Tabs = /*#__PURE__*/forwardRef(function Tabs(_ref, ref) {
|
|
|
87
107
|
orientation: orientation,
|
|
88
108
|
size: size,
|
|
89
109
|
variant: variant,
|
|
90
|
-
animated: animated
|
|
110
|
+
animated: animated,
|
|
111
|
+
swipeable: swipeable,
|
|
112
|
+
indicatorReady: indicatorReady,
|
|
113
|
+
setIndicatorReady: setIndicatorReady
|
|
91
114
|
};
|
|
92
115
|
return jsx(TabsContext.Provider, {
|
|
93
116
|
value: value,
|
|
@@ -101,25 +124,96 @@ var Tabs = /*#__PURE__*/forwardRef(function Tabs(_ref, ref) {
|
|
|
101
124
|
});
|
|
102
125
|
Tabs.displayName = "Tabs";
|
|
103
126
|
/* ------------------------- TabList ------------------------- */
|
|
104
|
-
function TabList(_ref2) {
|
|
127
|
+
var TabList = /*#__PURE__*/forwardRef(function TabList(_ref2, ref) {
|
|
105
128
|
var children = _ref2.children,
|
|
106
129
|
_ref2$className = _ref2.className,
|
|
107
|
-
className = _ref2$className === void 0 ? "" : _ref2$className
|
|
130
|
+
className = _ref2$className === void 0 ? "" : _ref2$className,
|
|
131
|
+
rest = _objectWithoutProperties(_ref2, _excluded2);
|
|
108
132
|
var _useTabsContext = useTabsContext("Tabs.List"),
|
|
109
|
-
orientation = _useTabsContext.orientation
|
|
110
|
-
|
|
133
|
+
orientation = _useTabsContext.orientation,
|
|
134
|
+
variant = _useTabsContext.variant,
|
|
135
|
+
activeIndex = _useTabsContext.activeIndex,
|
|
136
|
+
tabsRef = _useTabsContext.tabsRef,
|
|
137
|
+
indicatorReady = _useTabsContext.indicatorReady,
|
|
138
|
+
setIndicatorReady = _useTabsContext.setIndicatorReady;
|
|
139
|
+
var listRef = useRef(null);
|
|
140
|
+
var _useState5 = useState(null),
|
|
141
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
142
|
+
indicator = _useState6[0],
|
|
143
|
+
setIndicator = _useState6[1];
|
|
144
|
+
var horizontal = orientation !== "vertical";
|
|
145
|
+
var hasIndicator = horizontal && INDICATOR_VARIANTS.includes(variant);
|
|
146
|
+
var childCount = React.Children.count(children);
|
|
147
|
+
var setRefs = function setRefs(node) {
|
|
148
|
+
listRef.current = node;
|
|
149
|
+
if (typeof ref === "function") ref(node);else if (ref) ref.current = node;
|
|
150
|
+
};
|
|
151
|
+
// Measure the active tab: position the indicator and scroll the tab into view.
|
|
152
|
+
useIsomorphicLayoutEffect(function () {
|
|
153
|
+
var list = listRef.current;
|
|
154
|
+
var tab = tabsRef.current[activeIndex];
|
|
155
|
+
if (!list || !tab) return undefined;
|
|
156
|
+
var measure = function measure() {
|
|
157
|
+
if (horizontal) {
|
|
158
|
+
var left = tab.offsetLeft;
|
|
159
|
+
var right = left + tab.offsetWidth;
|
|
160
|
+
if (left < list.scrollLeft) list.scrollLeft = left;else if (right > list.scrollLeft + list.clientWidth) list.scrollLeft = right - list.clientWidth;
|
|
161
|
+
}
|
|
162
|
+
// jsdom / display:none report 0; keep the tabs' own active styling then.
|
|
163
|
+
if (!hasIndicator || !tab.offsetWidth) return;
|
|
164
|
+
setIndicator({
|
|
165
|
+
left: tab.offsetLeft,
|
|
166
|
+
top: tab.offsetTop,
|
|
167
|
+
width: tab.offsetWidth,
|
|
168
|
+
height: tab.offsetHeight
|
|
169
|
+
});
|
|
170
|
+
setIndicatorReady(true);
|
|
171
|
+
};
|
|
172
|
+
measure();
|
|
173
|
+
if (typeof ResizeObserver === "undefined") return undefined;
|
|
174
|
+
var ro = new ResizeObserver(measure);
|
|
175
|
+
ro.observe(list);
|
|
176
|
+
ro.observe(tab);
|
|
177
|
+
return function () {
|
|
178
|
+
return ro.disconnect();
|
|
179
|
+
};
|
|
180
|
+
}, [activeIndex, hasIndicator, horizontal, childCount]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
181
|
+
// Leaving an indicator variant hands the active styling back to the tabs.
|
|
182
|
+
useEffect(function () {
|
|
183
|
+
if (!hasIndicator && indicatorReady) setIndicatorReady(false);
|
|
184
|
+
}, [hasIndicator, indicatorReady, setIndicatorReady]);
|
|
185
|
+
var showIndicator = hasIndicator && indicatorReady && indicator;
|
|
186
|
+
return jsxs("div", _objectSpread2(_objectSpread2({
|
|
187
|
+
ref: setRefs,
|
|
111
188
|
role: "tablist",
|
|
112
189
|
"aria-orientation": orientation,
|
|
113
|
-
className:
|
|
114
|
-
|
|
190
|
+
className: cn("relative flex gap-1", horizontal ?
|
|
191
|
+
// Scroll with snap, scrollbar hidden; native smooth scrolling unless reduced motion.
|
|
192
|
+
"flex-row overflow-x-auto snap-x snap-mandatory scroll-smooth motion-reduce:scroll-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden" : "flex-col", variant === "segmented" && "rounded-lg bg-gray-100 p-1 dark:bg-gray-800", className)
|
|
193
|
+
}, rest), {}, {
|
|
194
|
+
children: [showIndicator && jsx("span", {
|
|
195
|
+
"aria-hidden": "true",
|
|
196
|
+
"data-tabs-indicator": "",
|
|
197
|
+
className: cn("pointer-events-none absolute left-0 top-0", "transition-[transform,width,height] duration-base ease-standard motion-reduce:transition-none", variant === "line" ? "bg-primary-500" : "rounded-md bg-surface shadow-sm"),
|
|
198
|
+
style: variant === "line" ? {
|
|
199
|
+
width: indicator.width,
|
|
200
|
+
height: 2,
|
|
201
|
+
transform: "translate(".concat(indicator.left, "px, ").concat(indicator.top + indicator.height - 2, "px)")
|
|
202
|
+
} : {
|
|
203
|
+
width: indicator.width,
|
|
204
|
+
height: indicator.height,
|
|
205
|
+
transform: "translate(".concat(indicator.left, "px, ").concat(indicator.top, "px)")
|
|
206
|
+
}
|
|
207
|
+
}), React.Children.map(children, function (child, i) {
|
|
115
208
|
var _child$props$index;
|
|
116
209
|
if (! /*#__PURE__*/React.isValidElement(child)) return child;
|
|
117
210
|
return /*#__PURE__*/React.cloneElement(child, {
|
|
118
211
|
index: (_child$props$index = child.props.index) !== null && _child$props$index !== void 0 ? _child$props$index : i
|
|
119
212
|
});
|
|
120
|
-
})
|
|
121
|
-
});
|
|
122
|
-
}
|
|
213
|
+
})]
|
|
214
|
+
}));
|
|
215
|
+
});
|
|
216
|
+
TabList.displayName = "Tabs.List";
|
|
123
217
|
/* ------------------------- Tab ------------------------- */
|
|
124
218
|
function Tab(_ref3) {
|
|
125
219
|
var children = _ref3.children,
|
|
@@ -139,32 +233,45 @@ function Tab(_ref3) {
|
|
|
139
233
|
tabsRef = _useTabsContext2.tabsRef,
|
|
140
234
|
baseId = _useTabsContext2.baseId,
|
|
141
235
|
size = _useTabsContext2.size,
|
|
142
|
-
variant = _useTabsContext2.variant
|
|
236
|
+
variant = _useTabsContext2.variant,
|
|
237
|
+
orientation = _useTabsContext2.orientation,
|
|
238
|
+
indicatorReady = _useTabsContext2.indicatorReady;
|
|
143
239
|
var internalRef = useRef(null);
|
|
144
240
|
// If the user didn't provide `index` we derive from DOM position by registering nulls until mount.
|
|
145
241
|
// However it's recommended to always keep Tabs.Tab order consistent with Panels.
|
|
146
|
-
|
|
242
|
+
// Registered from a ref callback (runs at commit, before any layout effect) so
|
|
243
|
+
// Tabs.List can measure the active tab on mount without a flash.
|
|
244
|
+
var setTabRef = function setTabRef(el) {
|
|
245
|
+
internalRef.current = el;
|
|
246
|
+
if (!el) return;
|
|
147
247
|
// find index in tabsRef if index not provided
|
|
148
|
-
var
|
|
149
|
-
return
|
|
248
|
+
var slot = typeof index === "number" ? index : tabsRef.current.findIndex(function (node) {
|
|
249
|
+
return node === el;
|
|
150
250
|
});
|
|
151
|
-
if (
|
|
152
|
-
registerTab(
|
|
153
|
-
|
|
154
|
-
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
251
|
+
if (slot === -1) slot = tabsRef.current.length; // fallback
|
|
252
|
+
registerTab(el, slot);
|
|
253
|
+
};
|
|
155
254
|
// TabList always injects `index`; a Tab rendered outside it is never selected.
|
|
156
255
|
var idx = typeof index === "number" ? index : -1;
|
|
157
256
|
var selected = idx === activeIndex;
|
|
158
257
|
var id = tabId(baseId, idx);
|
|
159
|
-
var
|
|
258
|
+
var horizontal = orientation !== "vertical";
|
|
259
|
+
// Once the sliding indicator is measured it draws the active state; until then
|
|
260
|
+
// (SSR / first paint) the tab draws it itself so nothing flashes.
|
|
261
|
+
var indicatorDraws = indicatorReady && horizontal && INDICATOR_VARIANTS.includes(variant);
|
|
262
|
+
var base = cn("relative inline-flex items-center gap-2 whitespace-nowrap outline-none select-none", "focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-1", "transition-colors duration-fast motion-reduce:transition-none", "disabled:cursor-not-allowed disabled:opacity-50",
|
|
263
|
+
// The scrolling list clips outside rings, so horizontal tabs draw theirs inset.
|
|
264
|
+
horizontal && "shrink-0 snap-start focus-visible:ring-inset focus-visible:ring-offset-0");
|
|
160
265
|
var sizeClasses = {
|
|
161
266
|
sm: "px-2 py-1 text-sm",
|
|
162
267
|
md: "px-3 py-2 text-sm",
|
|
163
268
|
lg: "px-4 py-3 text-base"
|
|
164
269
|
};
|
|
165
270
|
var variantClasses = {
|
|
166
|
-
line: selected ? "border-b-2 border-primary-500" : "border-b-2 border-transparent hover:border-gray-200",
|
|
167
|
-
pills: selected ? "bg-primary-600 text-white rounded-full shadow-sm" : "bg-transparent rounded-full hover:bg-gray-100",
|
|
271
|
+
line: selected ? cn("border-b-2", indicatorDraws ? "border-transparent" : "border-primary-500") : "border-b-2 border-transparent hover:border-gray-200 dark:hover:border-gray-700",
|
|
272
|
+
pills: selected ? "bg-primary-600 text-white rounded-full shadow-sm" : "bg-transparent rounded-full hover:bg-gray-100 dark:hover:bg-gray-800",
|
|
273
|
+
// iOS-style segmented control: equal-width segments on a tinted track.
|
|
274
|
+
segmented: cn("z-10 flex-1 justify-center rounded-md font-medium", selected ? cn("text-foreground", !indicatorDraws && "bg-surface shadow-sm") : "text-muted hover:text-foreground"),
|
|
168
275
|
unstyled: ""
|
|
169
276
|
};
|
|
170
277
|
var computedClass = cn(base, sizeClasses[size] || sizeClasses.md, variantClasses[variant], tabClassName, className);
|
|
@@ -208,7 +315,7 @@ function Tab(_ref3) {
|
|
|
208
315
|
}
|
|
209
316
|
};
|
|
210
317
|
return jsxs("button", {
|
|
211
|
-
ref:
|
|
318
|
+
ref: setTabRef,
|
|
212
319
|
id: id,
|
|
213
320
|
role: "tab",
|
|
214
321
|
"aria-selected": selected,
|
|
@@ -237,9 +344,49 @@ function Panels(_ref4) {
|
|
|
237
344
|
_ref4$className = _ref4.className,
|
|
238
345
|
className = _ref4$className === void 0 ? "" : _ref4$className;
|
|
239
346
|
var _useTabsContext3 = useTabsContext("Tabs.Panels"),
|
|
240
|
-
animated = _useTabsContext3.animated
|
|
241
|
-
|
|
242
|
-
|
|
347
|
+
animated = _useTabsContext3.animated,
|
|
348
|
+
swipeable = _useTabsContext3.swipeable,
|
|
349
|
+
activeIndex = _useTabsContext3.activeIndex,
|
|
350
|
+
changeTab = _useTabsContext3.changeTab,
|
|
351
|
+
tabsRef = _useTabsContext3.tabsRef;
|
|
352
|
+
var start = useRef(null);
|
|
353
|
+
// Next enabled tab in `dir`, or -1 at either end (no wrap-around on swipe).
|
|
354
|
+
var neighbour = function neighbour(dir) {
|
|
355
|
+
var tabs = tabsRef.current;
|
|
356
|
+
for (var i = activeIndex + dir; i >= 0 && i < tabs.length; i += dir) {
|
|
357
|
+
if (tabs[i] && !tabs[i].disabled) return i;
|
|
358
|
+
}
|
|
359
|
+
return -1;
|
|
360
|
+
};
|
|
361
|
+
var swipeHandlers = swipeable ? {
|
|
362
|
+
onPointerDown: function onPointerDown(e) {
|
|
363
|
+
// Touch and pen only: a mouse drag selects text instead.
|
|
364
|
+
if (e.pointerType === "mouse" || e.isPrimary === false) return;
|
|
365
|
+
start.current = {
|
|
366
|
+
x: e.clientX,
|
|
367
|
+
y: e.clientY
|
|
368
|
+
};
|
|
369
|
+
},
|
|
370
|
+
onPointerUp: function onPointerUp(e) {
|
|
371
|
+
var from = start.current;
|
|
372
|
+
start.current = null;
|
|
373
|
+
if (!from) return;
|
|
374
|
+
var dx = e.clientX - from.x;
|
|
375
|
+
var dy = e.clientY - from.y;
|
|
376
|
+
if (!Number.isFinite(dx) || !Number.isFinite(dy)) return;
|
|
377
|
+
if (Math.abs(dx) < SWIPE_THRESHOLD || Math.abs(dx) < Math.abs(dy) * SWIPE_DOMINANCE) return;
|
|
378
|
+
// Swipe left -> next tab, swipe right -> previous tab.
|
|
379
|
+
var next = neighbour(dx < 0 ? 1 : -1);
|
|
380
|
+
if (next !== -1) changeTab(next);
|
|
381
|
+
},
|
|
382
|
+
onPointerCancel: function onPointerCancel() {
|
|
383
|
+
start.current = null;
|
|
384
|
+
}
|
|
385
|
+
} : {};
|
|
386
|
+
return jsx("div", _objectSpread2(_objectSpread2({
|
|
387
|
+
// touch-pan-y: the browser keeps vertical scrolling; horizontal moves reach us.
|
|
388
|
+
className: cn("relative w-full", swipeable && "touch-pan-y", className)
|
|
389
|
+
}, swipeHandlers), {}, {
|
|
243
390
|
children: React.Children.map(children, function (child, i) {
|
|
244
391
|
var _child$props$index2;
|
|
245
392
|
// inject index if missing
|
|
@@ -249,7 +396,7 @@ function Panels(_ref4) {
|
|
|
249
396
|
animated: animated
|
|
250
397
|
});
|
|
251
398
|
})
|
|
252
|
-
});
|
|
399
|
+
}));
|
|
253
400
|
}
|
|
254
401
|
function Panel(_ref5) {
|
|
255
402
|
var children = _ref5.children,
|
|
@@ -262,10 +409,10 @@ function Panel(_ref5) {
|
|
|
262
409
|
activeIndex = _useTabsContext4.activeIndex,
|
|
263
410
|
baseId = _useTabsContext4.baseId;
|
|
264
411
|
var isActive = index === activeIndex;
|
|
265
|
-
var
|
|
266
|
-
|
|
267
|
-
wasActive =
|
|
268
|
-
setWasActive =
|
|
412
|
+
var _useState7 = useState(isActive),
|
|
413
|
+
_useState8 = _slicedToArray(_useState7, 2),
|
|
414
|
+
wasActive = _useState8[0],
|
|
415
|
+
setWasActive = _useState8[1];
|
|
269
416
|
// Remember that the panel has been shown once (adjust-during-render pattern).
|
|
270
417
|
if (isActive && !wasActive) setWasActive(true);
|
|
271
418
|
if (!wasActive && !isActive) return null;
|
|
@@ -6,7 +6,7 @@ import { AlertCircle } from 'lucide-react';
|
|
|
6
6
|
import { cn } from '../../utils/cn.js';
|
|
7
7
|
import { setRefs } from '../../utils/position.js';
|
|
8
8
|
|
|
9
|
-
var _excluded = ["id", "className", "label", "error", "helperText", "required", "disabled", "showCount", "maxLength", "autoResize", "rows", "maxRows", "value", "defaultValue", "onChange"];
|
|
9
|
+
var _excluded = ["id", "className", "label", "error", "helperText", "required", "disabled", "showCount", "maxLength", "autoResize", "rows", "maxRows", "value", "defaultValue", "onChange", "size"];
|
|
10
10
|
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
11
11
|
function fitToContent(el, maxRows) {
|
|
12
12
|
if (!el) return;
|
|
@@ -24,6 +24,12 @@ function fitToContent(el, maxRows) {
|
|
|
24
24
|
}
|
|
25
25
|
el.style.height = "".concat(height, "px");
|
|
26
26
|
}
|
|
27
|
+
// Padding / text per size; `md` is the original look. Rows set the height.
|
|
28
|
+
var SIZE_CLASSES = {
|
|
29
|
+
sm: "px-2.5 py-1.5 text-xs",
|
|
30
|
+
md: "px-3 py-2 text-sm",
|
|
31
|
+
lg: "px-4 py-2.5 text-base"
|
|
32
|
+
};
|
|
27
33
|
var Textarea = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
|
|
28
34
|
var id = _ref.id,
|
|
29
35
|
className = _ref.className,
|
|
@@ -45,6 +51,8 @@ var Textarea = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
|
|
|
45
51
|
value = _ref.value,
|
|
46
52
|
defaultValue = _ref.defaultValue,
|
|
47
53
|
onChange = _ref.onChange,
|
|
54
|
+
_ref$size = _ref.size,
|
|
55
|
+
size = _ref$size === void 0 ? "md" : _ref$size,
|
|
48
56
|
rest = _objectWithoutProperties(_ref, _excluded);
|
|
49
57
|
var reactId = useId();
|
|
50
58
|
var textareaId = id || "textarea-".concat(reactId);
|
|
@@ -93,7 +101,7 @@ var Textarea = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
|
|
|
93
101
|
onChange: handleChange,
|
|
94
102
|
"aria-invalid": error ? true : undefined,
|
|
95
103
|
"aria-describedby": describedBy,
|
|
96
|
-
className: cn("block w-full rounded-md border bg-
|
|
104
|
+
className: cn("block w-full rounded-md border bg-surface text-foreground placeholder-gray-400", SIZE_CLASSES[size] || SIZE_CLASSES.md, "transition-colors duration-fast ease-standard motion-reduce:transition-none", "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2", "disabled:cursor-not-allowed disabled:opacity-50", "dark:placeholder-gray-500 dark:focus-visible:ring-offset-gray-900", error ? "border-error-500 focus-visible:ring-error-500 dark:border-error-400" : "border-gray-300 focus-visible:ring-primary-500 dark:border-gray-600", autoResize ? "resize-none" : "resize-y", className)
|
|
97
105
|
})), (error || helperText || showCount && maxLength) && jsxs("div", {
|
|
98
106
|
className: "mt-1 flex items-start justify-between gap-3 text-sm",
|
|
99
107
|
children: [jsxs("div", {
|
|
@@ -1,32 +1,60 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { objectWithoutProperties as _objectWithoutProperties, toConsumableArray as _toConsumableArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
-
import React from 'react';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, toConsumableArray as _toConsumableArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
5
5
|
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import { TOUCH_TARGET } from '../../utils/touchTarget.js';
|
|
6
7
|
import { ChevronRight, Home } from 'lucide-react';
|
|
7
8
|
|
|
8
|
-
var _excluded = ["items", "separator", "showHome", "homeIcon", "onHomeClick", "className"];
|
|
9
|
+
var _excluded = ["items", "separator", "showHome", "homeIcon", "onHomeClick", "maxItems", "className"];
|
|
9
10
|
// Items without an `id` still need a stable, unique React key.
|
|
10
11
|
var itemKey = function itemKey(item, index) {
|
|
11
12
|
var _ref, _item$href;
|
|
12
13
|
return item.id != null ? "id:".concat(item.id) : "idx:".concat(index, ":").concat((_ref = (_item$href = item.href) !== null && _item$href !== void 0 ? _item$href : item.label) !== null && _ref !== void 0 ? _ref : '');
|
|
13
14
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
// Long labels truncate with an ellipsis; the full text stays available as a tooltip.
|
|
16
|
+
var LABEL_CLASSES = 'min-w-0 max-w-[10rem] truncate sm:max-w-[16rem]';
|
|
17
|
+
var FOCUS_RING = 'rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-1 dark:focus-visible:ring-offset-gray-900';
|
|
18
|
+
var labelTitle = function labelTitle(label) {
|
|
19
|
+
return typeof label === 'string' || typeof label === 'number' ? String(label) : undefined;
|
|
20
|
+
};
|
|
21
|
+
function ItemContent(_ref2) {
|
|
22
|
+
var item = _ref2.item;
|
|
23
|
+
return jsxs(Fragment, {
|
|
24
|
+
children: [item.icon && jsx("span", {
|
|
25
|
+
className: "mr-1 shrink-0",
|
|
26
|
+
children: item.icon
|
|
27
|
+
}), jsx("span", {
|
|
28
|
+
className: LABEL_CLASSES,
|
|
29
|
+
title: labelTitle(item.label),
|
|
30
|
+
children: item.label
|
|
31
|
+
})]
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
var Breadcrumbs = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
35
|
+
var _ref3$items = _ref3.items,
|
|
36
|
+
items = _ref3$items === void 0 ? [] : _ref3$items,
|
|
37
|
+
_ref3$separator = _ref3.separator,
|
|
38
|
+
separator = _ref3$separator === void 0 ? jsx(ChevronRight, {
|
|
19
39
|
className: "h-4 w-4"
|
|
20
|
-
}) :
|
|
21
|
-
|
|
22
|
-
showHome =
|
|
23
|
-
|
|
24
|
-
homeIcon =
|
|
40
|
+
}) : _ref3$separator,
|
|
41
|
+
_ref3$showHome = _ref3.showHome,
|
|
42
|
+
showHome = _ref3$showHome === void 0 ? true : _ref3$showHome,
|
|
43
|
+
_ref3$homeIcon = _ref3.homeIcon,
|
|
44
|
+
homeIcon = _ref3$homeIcon === void 0 ? jsx(Home, {
|
|
25
45
|
className: "h-4 w-4"
|
|
26
|
-
}) :
|
|
27
|
-
onHomeClick =
|
|
28
|
-
|
|
29
|
-
|
|
46
|
+
}) : _ref3$homeIcon,
|
|
47
|
+
onHomeClick = _ref3.onHomeClick,
|
|
48
|
+
maxItems = _ref3.maxItems,
|
|
49
|
+
className = _ref3.className,
|
|
50
|
+
props = _objectWithoutProperties(_ref3, _excluded);
|
|
51
|
+
var _useState = useState(false),
|
|
52
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
53
|
+
expanded = _useState2[0],
|
|
54
|
+
setExpanded = _useState2[1];
|
|
55
|
+
// After expanding, focus moves to the first revealed crumb instead of being lost.
|
|
56
|
+
var focusRevealed = useRef(false);
|
|
57
|
+
var firstHiddenRef = useRef(null);
|
|
30
58
|
var allItems = showHome ? [{
|
|
31
59
|
id: 'home',
|
|
32
60
|
label: 'Home',
|
|
@@ -34,37 +62,71 @@ var Breadcrumbs = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
|
|
|
34
62
|
icon: homeIcon,
|
|
35
63
|
onClick: onHomeClick
|
|
36
64
|
}].concat(_toConsumableArray(items)) : items;
|
|
65
|
+
// Collapse keeps the first crumb and the last (maxItems - 1); needs at least 2 to make sense.
|
|
66
|
+
var limit = Number.isFinite(maxItems) ? Math.max(2, Math.floor(maxItems)) : Infinity;
|
|
67
|
+
var collapsed = !expanded && allItems.length > limit;
|
|
68
|
+
var hiddenFrom = 1;
|
|
69
|
+
var hiddenTo = allItems.length - (limit - 1); // exclusive
|
|
70
|
+
var hiddenCount = collapsed ? hiddenTo - hiddenFrom : 0;
|
|
71
|
+
useEffect(function () {
|
|
72
|
+
if (expanded && focusRevealed.current) {
|
|
73
|
+
var _firstHiddenRef$curre;
|
|
74
|
+
focusRevealed.current = false;
|
|
75
|
+
(_firstHiddenRef$curre = firstHiddenRef.current) === null || _firstHiddenRef$curre === void 0 || _firstHiddenRef$curre.focus();
|
|
76
|
+
}
|
|
77
|
+
}, [expanded]);
|
|
78
|
+
var renderSeparator = function renderSeparator() {
|
|
79
|
+
return jsx("span", {
|
|
80
|
+
className: "shrink-0 text-primary-400 dark:text-primary-500",
|
|
81
|
+
"aria-hidden": "true",
|
|
82
|
+
children: separator
|
|
83
|
+
});
|
|
84
|
+
};
|
|
37
85
|
return jsx("nav", _objectSpread2(_objectSpread2({
|
|
38
86
|
ref: ref,
|
|
39
|
-
className: cn('flex items-center space-x-1 text-sm', className),
|
|
87
|
+
className: cn('flex min-w-0 items-center space-x-1 text-sm', className),
|
|
40
88
|
"aria-label": "Breadcrumb"
|
|
41
89
|
}, props), {}, {
|
|
42
90
|
children: allItems.map(function (item, index) {
|
|
91
|
+
if (collapsed && index >= hiddenFrom && index < hiddenTo) {
|
|
92
|
+
if (index !== hiddenFrom) return null;
|
|
93
|
+
return jsxs(React.Fragment, {
|
|
94
|
+
children: [renderSeparator(), jsx("button", {
|
|
95
|
+
type: "button",
|
|
96
|
+
className: cn('inline-flex items-center justify-center px-1 text-primary-500 transition-colors duration-fast motion-reduce:transition-none', 'hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300', FOCUS_RING, TOUCH_TARGET),
|
|
97
|
+
"aria-label": "Show ".concat(hiddenCount, " more breadcrumb").concat(hiddenCount === 1 ? '' : 's'),
|
|
98
|
+
onClick: function onClick() {
|
|
99
|
+
focusRevealed.current = true;
|
|
100
|
+
setExpanded(true);
|
|
101
|
+
},
|
|
102
|
+
children: jsx("span", {
|
|
103
|
+
"aria-hidden": "true",
|
|
104
|
+
children: "\u2026"
|
|
105
|
+
})
|
|
106
|
+
})]
|
|
107
|
+
}, "breadcrumbs-collapsed");
|
|
108
|
+
}
|
|
109
|
+
var isLast = index === allItems.length - 1;
|
|
43
110
|
return jsxs(React.Fragment, {
|
|
44
|
-
children: [index > 0 && jsx("span", {
|
|
45
|
-
className: "text-primary-
|
|
46
|
-
"aria-hidden": "true",
|
|
47
|
-
children: separator
|
|
48
|
-
}), index === allItems.length - 1 ? jsxs("span", {
|
|
49
|
-
className: "font-medium text-primary-900",
|
|
111
|
+
children: [index > 0 && renderSeparator(), isLast ? jsx("span", {
|
|
112
|
+
className: "flex min-w-0 items-center font-medium text-primary-900 dark:text-primary-100",
|
|
50
113
|
"aria-current": "page",
|
|
51
|
-
children:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
114
|
+
children: jsx(ItemContent, {
|
|
115
|
+
item: item
|
|
116
|
+
})
|
|
117
|
+
}) : jsx("a", {
|
|
118
|
+
ref: expanded && index === hiddenFrom ? firstHiddenRef : undefined,
|
|
56
119
|
href: item.href,
|
|
57
|
-
className:
|
|
120
|
+
className: cn('flex min-w-0 items-center text-primary-500 underline-offset-4 transition-colors duration-fast motion-reduce:transition-none', 'hover:text-primary-700 hover:underline dark:text-primary-400 dark:hover:text-primary-300', FOCUS_RING),
|
|
58
121
|
onClick: function onClick(e) {
|
|
59
122
|
if (item.onClick) {
|
|
60
123
|
e.preventDefault();
|
|
61
124
|
item.onClick(item);
|
|
62
125
|
}
|
|
63
126
|
},
|
|
64
|
-
children:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}), item.label]
|
|
127
|
+
children: jsx(ItemContent, {
|
|
128
|
+
item: item
|
|
129
|
+
})
|
|
68
130
|
})]
|
|
69
131
|
}, itemKey(item, index));
|
|
70
132
|
})
|