@dreamtree-org/twreact-ui 1.3.9 → 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 +32 -0
- package/ai-skills/dreamtree-ui.md +12 -7
- package/dist/ai-schema.json +156 -29
- package/dist/charts/index.js +195 -66
- package/dist/components/blocks/AppShell.d.ts.map +1 -1
- 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/Accordion.d.ts.map +1 -1
- 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/DatePicker.d.ts.map +1 -1
- package/dist/components/core/Form.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/PriceRangePicker.d.ts +0 -29
- package/dist/components/core/PriceRangePicker.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/Table/ColumnMenu.d.ts.map +1 -1
- package/dist/components/core/Table/Pagination.d.ts.map +1 -1
- package/dist/components/core/Table/TableRow.d.ts.map +1 -1
- package/dist/components/core/Table/helpers.d.ts +2 -0
- package/dist/components/core/Table/helpers.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/TextToSpeech.d.ts +2 -7
- package/dist/components/core/TextToSpeech.d.ts.map +1 -1
- package/dist/components/core/Textarea.d.ts.map +1 -1
- package/dist/components/core/Tooltip.d.ts.map +1 -1
- package/dist/components/feedback/Alert.d.ts.map +1 -1
- package/dist/components/feedback/Dialog.d.ts.map +1 -1
- package/dist/components/feedback/Toast.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/navigation/Sidebar.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/AppShell.js +24 -18
- 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/Accordion.js +40 -9
- 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 +49 -48
- package/dist/esm/components/core/DatePicker.js +97 -58
- package/dist/esm/components/core/Form.js +35 -8
- package/dist/esm/components/core/Input.js +89 -20
- package/dist/esm/components/core/Loader.js +30 -44
- package/dist/esm/components/core/LocationPicker.js +82 -16
- package/dist/esm/components/core/PriceRangePicker.js +205 -218
- package/dist/esm/components/core/ProgressBar.js +8 -12
- package/dist/esm/components/core/Radio.js +43 -15
- package/dist/esm/components/core/Rate.js +109 -50
- package/dist/esm/components/core/RoundedTag.js +27 -10
- 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/Table/ColumnMenu.js +2 -4
- package/dist/esm/components/core/Table/Pagination.js +15 -18
- package/dist/esm/components/core/Table/TableRow.js +2 -2
- package/dist/esm/components/core/Table/helpers.js +33 -1
- package/dist/esm/components/core/Tabs.js +185 -37
- package/dist/esm/components/core/TextToSpeech.js +121 -28
- package/dist/esm/components/core/Textarea.js +10 -2
- package/dist/esm/components/core/Tooltip.js +100 -28
- package/dist/esm/components/feedback/Alert.js +21 -11
- package/dist/esm/components/feedback/Dialog.js +44 -100
- package/dist/esm/components/feedback/Toast.js +24 -5
- package/dist/esm/components/navigation/Breadcrumbs.js +97 -35
- package/dist/esm/components/navigation/FootNav.js +102 -13
- package/dist/esm/components/navigation/Sidebar.js +13 -61
- package/dist/esm/components/utility/Avatar.js +37 -22
- 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 +165 -38
- package/dist/esm/components/utility/FileUpload.js +106 -31
- package/dist/esm/components/utility/Pagination.js +33 -15
- package/dist/esm/components/utility/Sortable.js +6 -2
- package/dist/esm/components/utility/Stepper.js +110 -47
- package/dist/esm/hooks/useFocusTrap.js +10 -2
- 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/useFocusTrap.d.ts.map +1 -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 +3734 -2174
- package/dist/index.js +3732 -2171
- package/dist/types/charts.d.ts +3 -1
- package/dist/types/charts.d.ts.map +1 -1
- package/dist/types/index.d.ts +64 -9
- package/dist/types/index.d.ts.map +1 -1
- package/doc/README.md +1 -0
- package/mcp/catalog.snapshot.json +350 -121
- package/package.json +1 -1
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
-
import { forwardRef, useId, useState } from 'react';
|
|
4
|
+
import { forwardRef, useId, useState, useRef, useCallback, useEffect } from 'react';
|
|
5
5
|
import PropTypes from '../../_vendor/prop-types/index.js';
|
|
6
|
+
import { cn } from '../../utils/cn.js';
|
|
6
7
|
|
|
7
8
|
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
9
|
var SIZE_MAP = {
|
|
15
10
|
sm: {
|
|
16
11
|
outer: "h-4 w-4",
|
|
@@ -74,6 +69,32 @@ var Radio = /*#__PURE__*/forwardRef(function Radio(_ref, ref) {
|
|
|
74
69
|
if (checked === undefined) setInternalChecked(!!defaultChecked);
|
|
75
70
|
}
|
|
76
71
|
var isChecked = checked !== undefined ? checked : internalChecked;
|
|
72
|
+
// Merge the forwarded ref with our own so we can read the native state.
|
|
73
|
+
var inputRef = useRef(null);
|
|
74
|
+
var setRefs = useCallback(function (node) {
|
|
75
|
+
inputRef.current = node;
|
|
76
|
+
if (typeof ref === "function") ref(node);else if (ref) ref.current = node;
|
|
77
|
+
}, [ref]);
|
|
78
|
+
// DTUI-17: browsers never fire `change` on the radio being *unchecked*
|
|
79
|
+
// when a sibling in the same group is selected. In uncontrolled mode,
|
|
80
|
+
// listen for changes on any same-name radio and re-sync our visual state
|
|
81
|
+
// from the native input, so only one dot shows at a time.
|
|
82
|
+
useEffect(function () {
|
|
83
|
+
if (checked !== undefined || !name) return undefined;
|
|
84
|
+
var doc = inputRef.current && inputRef.current.ownerDocument;
|
|
85
|
+
if (!doc) return undefined;
|
|
86
|
+
var sync = function sync(e) {
|
|
87
|
+
var t = e.target;
|
|
88
|
+
var el = inputRef.current;
|
|
89
|
+
if (!el || t === el || !t || t.type !== "radio" || t.name !== name) return;
|
|
90
|
+
if (t.form !== el.form) return;
|
|
91
|
+
setInternalChecked(el.checked);
|
|
92
|
+
};
|
|
93
|
+
doc.addEventListener("change", sync, true);
|
|
94
|
+
return function () {
|
|
95
|
+
return doc.removeEventListener("change", sync, true);
|
|
96
|
+
};
|
|
97
|
+
}, [checked, name]);
|
|
77
98
|
function handleChange(e) {
|
|
78
99
|
if (checked === undefined) setInternalChecked(e.target.checked);
|
|
79
100
|
if (typeof onChange === "function") onChange(e);
|
|
@@ -82,16 +103,19 @@ var Radio = /*#__PURE__*/forwardRef(function Radio(_ref, ref) {
|
|
|
82
103
|
var showLabelLeft = label && labelPosition === "left";
|
|
83
104
|
return jsxs("label", {
|
|
84
105
|
htmlFor: inputId,
|
|
85
|
-
className: cn(
|
|
106
|
+
className: cn(
|
|
107
|
+
// The invisible input covers the whole label, so the row is the hit
|
|
108
|
+
// area; on coarse pointers it is at least 44px tall.
|
|
109
|
+
"relative inline-flex items-center select-none gap-2 [@media(pointer:coarse)]:min-h-11", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer", className),
|
|
86
110
|
"aria-disabled": disabled ? "true" : undefined,
|
|
87
111
|
children: [showLabelLeft && jsxs("span", {
|
|
88
|
-
className: cn(sizeClasses.label, "leading-none", disabled && "text-primary-400"),
|
|
112
|
+
className: cn(sizeClasses.label, "leading-none text-foreground", disabled && "text-primary-400"),
|
|
89
113
|
children: [label, required ? jsx("span", {
|
|
90
114
|
"aria-hidden": "true",
|
|
91
115
|
children: " *"
|
|
92
116
|
}) : null]
|
|
93
117
|
}), jsx("input", _objectSpread2({
|
|
94
|
-
ref:
|
|
118
|
+
ref: setRefs,
|
|
95
119
|
id: inputId,
|
|
96
120
|
type: "radio",
|
|
97
121
|
name: name,
|
|
@@ -102,18 +126,22 @@ var Radio = /*#__PURE__*/forwardRef(function Radio(_ref, ref) {
|
|
|
102
126
|
disabled: disabled,
|
|
103
127
|
required: required,
|
|
104
128
|
"aria-label": ariaLabel,
|
|
105
|
-
className: "absolute inset-0 w-full h-full opacity-0 appearance-none m-0 z-10 cursor-pointer"
|
|
129
|
+
className: "peer absolute inset-0 w-full h-full opacity-0 appearance-none m-0 z-10 cursor-pointer disabled:cursor-not-allowed"
|
|
106
130
|
}, props)), jsx("span", {
|
|
107
131
|
"aria-hidden": true,
|
|
108
|
-
|
|
132
|
+
"data-state": isChecked ? "checked" : "unchecked",
|
|
133
|
+
className: cn("inline-flex shrink-0 items-center justify-center rounded-full transition-shadow duration-fast motion-reduce:transition-none",
|
|
134
|
+
// Visible focus indicator: the native input is opacity-0, so the
|
|
135
|
+
// ring is drawn on the visual circle when the input has focus.
|
|
136
|
+
"peer-focus-visible:ring-2 peer-focus-visible:ring-primary-500 peer-focus-visible:ring-offset-2 dark:peer-focus-visible:ring-offset-gray-900"),
|
|
109
137
|
style: {
|
|
110
138
|
"--radio-accent": accentColor
|
|
111
139
|
},
|
|
112
140
|
children: jsx("span", {
|
|
113
|
-
className: cn("flex items-center justify-center rounded-full border transition-colors duration-
|
|
141
|
+
className: cn("flex items-center justify-center rounded-full border transition-colors duration-fast ease-standard motion-reduce:transition-none", isChecked ? "border-[color:var(--radio-accent)]" : "border-gray-300 dark:border-gray-600", sizeClasses.outer, disabled ? "bg-gray-100 dark:bg-gray-800" : "bg-surface", isChecked ? "shadow-inner" : ""),
|
|
114
142
|
children: jsx("span", {
|
|
115
143
|
"aria-hidden": true,
|
|
116
|
-
className: cn("rounded-full transform transition-
|
|
144
|
+
className: cn("rounded-full transform transition-[opacity,transform] duration-base ease-spring-out motion-reduce:transition-none", sizeClasses.dot),
|
|
117
145
|
style: {
|
|
118
146
|
backgroundColor: isChecked ? accentColor : "transparent",
|
|
119
147
|
opacity: isChecked ? 1 : 0,
|
|
@@ -122,7 +150,7 @@ var Radio = /*#__PURE__*/forwardRef(function Radio(_ref, ref) {
|
|
|
122
150
|
})
|
|
123
151
|
})
|
|
124
152
|
}), !showLabelLeft && label && jsxs("span", {
|
|
125
|
-
className: cn(sizeClasses.label, "leading-none", disabled && "text-primary-400"),
|
|
153
|
+
className: cn(sizeClasses.label, "leading-none text-foreground", disabled && "text-primary-400"),
|
|
126
154
|
children: [label, required ? jsx("span", {
|
|
127
155
|
"aria-hidden": "true",
|
|
128
156
|
children: " *"
|
|
@@ -1,8 +1,9 @@
|
|
|
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 { forwardRef, useState } from 'react';
|
|
4
|
+
import { forwardRef, useState, useRef } from 'react';
|
|
5
5
|
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import { TOUCH_TARGET } from '../../utils/touchTarget.js';
|
|
6
7
|
|
|
7
8
|
var _excluded = ["count", "value", "defaultValue", "readOnly", "icon", "toggledIcon", "activeColor", "inactiveColor", "size", "onChange", "onClick", "text", "className", "id", "name"];
|
|
8
9
|
function StarFilled(_ref) {
|
|
@@ -69,44 +70,98 @@ var Rate = /*#__PURE__*/forwardRef(function Rate(_ref3, ref) {
|
|
|
69
70
|
_useState4 = _slicedToArray(_useState3, 2),
|
|
70
71
|
hoverValue = _useState4[0],
|
|
71
72
|
setHoverValue = _useState4[1];
|
|
72
|
-
var
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
var starRefs = useRef([]);
|
|
74
|
+
// Touch drag (DTUI-42): { pointerId, moved, value } while a finger is down.
|
|
75
|
+
var drag = useRef(null);
|
|
76
|
+
var suppressClick = useRef(false);
|
|
76
77
|
var isControlled = value != null;
|
|
77
78
|
var selectedValue = isControlled ? value : internalValue;
|
|
78
|
-
|
|
79
|
+
// Hover preview (pointer devices only) wins over the committed value.
|
|
80
|
+
var displayValue = hoverValue != null ? hoverValue : selectedValue;
|
|
81
|
+
// Roving tabindex (DTUI-23): the group is a single tab stop — the star
|
|
82
|
+
// equal to the value, or the first star when nothing is selected.
|
|
83
|
+
var tabStop = selectedValue >= 1 ? Math.min(count, selectedValue) : 1;
|
|
79
84
|
var InactiveIcon = icon !== null && icon !== void 0 ? icon : jsx(StarOutline, {
|
|
80
85
|
size: size
|
|
81
86
|
});
|
|
82
87
|
var ActiveIcon = toggledIcon !== null && toggledIcon !== void 0 ? toggledIcon : jsx(StarFilled, {
|
|
83
88
|
size: size
|
|
84
89
|
});
|
|
85
|
-
var
|
|
86
|
-
if (readOnly) return;
|
|
90
|
+
var setValue = function setValue(n) {
|
|
87
91
|
if (!isControlled) setInternalValue(n);
|
|
88
92
|
if (typeof onChange === "function") onChange(n);
|
|
89
|
-
if (typeof onClick === "function") onClick(n);
|
|
90
93
|
};
|
|
91
|
-
var
|
|
94
|
+
var commit = function commit(n) {
|
|
92
95
|
if (readOnly) return;
|
|
93
|
-
|
|
96
|
+
setValue(n);
|
|
97
|
+
if (typeof onClick === "function") onClick(n);
|
|
94
98
|
};
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
// Touch taps emit pointer/compat-mouse events with no matching "leave",
|
|
100
|
+
// which used to leave the preview stuck. Only real hover devices preview.
|
|
101
|
+
var handlePointerHover = function handlePointerHover(e, n) {
|
|
102
|
+
if (readOnly || e.pointerType === "touch") return;
|
|
97
103
|
setHoverValue(n);
|
|
98
104
|
};
|
|
99
|
-
var
|
|
105
|
+
var clearHover = function clearHover() {
|
|
100
106
|
if (readOnly) return;
|
|
101
107
|
setHoverValue(null);
|
|
102
108
|
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
// Star under clientX: the last star whose left edge is at or before the finger,
|
|
110
|
+
// clamped to 1..count so sliding off either end keeps a valid rating.
|
|
111
|
+
var starAt = function starAt(clientX) {
|
|
112
|
+
var n = 1;
|
|
113
|
+
starRefs.current.slice(0, count).forEach(function (el, i) {
|
|
114
|
+
if (el && el.getBoundingClientRect().left <= clientX) n = i + 1;
|
|
115
|
+
});
|
|
116
|
+
return n;
|
|
106
117
|
};
|
|
107
|
-
var
|
|
108
|
-
|
|
109
|
-
|
|
118
|
+
var handleDragStart = function handleDragStart(e) {
|
|
119
|
+
var _e$currentTarget$setP, _e$currentTarget;
|
|
120
|
+
if (readOnly || e.pointerType !== "touch") return;
|
|
121
|
+
var start = starAt(e.clientX);
|
|
122
|
+
drag.current = {
|
|
123
|
+
pointerId: e.pointerId,
|
|
124
|
+
moved: false,
|
|
125
|
+
value: start,
|
|
126
|
+
startX: e.clientX
|
|
127
|
+
};
|
|
128
|
+
(_e$currentTarget$setP = (_e$currentTarget = e.currentTarget).setPointerCapture) === null || _e$currentTarget$setP === void 0 || _e$currentTarget$setP.call(_e$currentTarget, e.pointerId);
|
|
129
|
+
};
|
|
130
|
+
var handleDragMove = function handleDragMove(e) {
|
|
131
|
+
var d = drag.current;
|
|
132
|
+
if (!d || d.pointerId !== e.pointerId) return;
|
|
133
|
+
if (!d.moved && Math.abs(e.clientX - d.startX) < 4) return;
|
|
134
|
+
d.moved = true;
|
|
135
|
+
d.value = starAt(e.clientX);
|
|
136
|
+
setHoverValue(d.value);
|
|
137
|
+
};
|
|
138
|
+
var handleDragEnd = function handleDragEnd(e) {
|
|
139
|
+
var _e$currentTarget$rele, _e$currentTarget2, _starRefs$current;
|
|
140
|
+
var d = drag.current;
|
|
141
|
+
if (!d || d.pointerId !== e.pointerId) return;
|
|
142
|
+
drag.current = null;
|
|
143
|
+
(_e$currentTarget$rele = (_e$currentTarget2 = e.currentTarget).releasePointerCapture) === null || _e$currentTarget$rele === void 0 || _e$currentTarget$rele.call(_e$currentTarget2, e.pointerId);
|
|
144
|
+
setHoverValue(null);
|
|
145
|
+
if (!d.moved) return; // a plain tap: the star's click commits it
|
|
146
|
+
// The compat click that follows a drag must not re-commit the start star.
|
|
147
|
+
suppressClick.current = true;
|
|
148
|
+
setTimeout(function () {
|
|
149
|
+
suppressClick.current = false;
|
|
150
|
+
}, 400);
|
|
151
|
+
commit(d.value);
|
|
152
|
+
(_starRefs$current = starRefs.current[d.value - 1]) === null || _starRefs$current === void 0 || _starRefs$current.focus();
|
|
153
|
+
};
|
|
154
|
+
var handleDragCancel = function handleDragCancel(e) {
|
|
155
|
+
if (!drag.current || drag.current.pointerId !== e.pointerId) return;
|
|
156
|
+
drag.current = null;
|
|
157
|
+
setHoverValue(null);
|
|
158
|
+
};
|
|
159
|
+
var handleStarClick = function handleStarClick(n) {
|
|
160
|
+
if (suppressClick.current) {
|
|
161
|
+
suppressClick.current = false;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
commit(n);
|
|
110
165
|
};
|
|
111
166
|
var handleKeyDown = function handleKeyDown(e, n) {
|
|
112
167
|
if (readOnly) return;
|
|
@@ -115,22 +170,16 @@ var Rate = /*#__PURE__*/forwardRef(function Rate(_ref3, ref) {
|
|
|
115
170
|
commit(n);
|
|
116
171
|
return;
|
|
117
172
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
setFocusValue(function (prev) {
|
|
129
|
-
var base = prev != null ? prev : selectedValue || 0;
|
|
130
|
-
return Math.min(count, base + 1);
|
|
131
|
-
});
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
173
|
+
var next = null;
|
|
174
|
+
if (e.key === "ArrowRight" || e.key === "ArrowUp") next = n + 1;else if (e.key === "ArrowLeft" || e.key === "ArrowDown") next = n - 1;else if (e.key === "Home") next = 1;else if (e.key === "End") next = count;
|
|
175
|
+
if (next == null) return;
|
|
176
|
+
e.preventDefault();
|
|
177
|
+
next = Math.max(1, Math.min(count, next));
|
|
178
|
+
// Radio-group semantics: arrows move real focus AND the selection.
|
|
179
|
+
setHoverValue(null);
|
|
180
|
+
var target = starRefs.current[next - 1];
|
|
181
|
+
if (target) target.focus();
|
|
182
|
+
if (next !== selectedValue) setValue(next);
|
|
134
183
|
};
|
|
135
184
|
return jsxs("div", _objectSpread2(_objectSpread2({
|
|
136
185
|
ref: ref,
|
|
@@ -141,41 +190,51 @@ var Rate = /*#__PURE__*/forwardRef(function Rate(_ref3, ref) {
|
|
|
141
190
|
children: [jsx("div", {
|
|
142
191
|
role: "radiogroup",
|
|
143
192
|
"aria-label": name || "Rating",
|
|
144
|
-
|
|
145
|
-
|
|
193
|
+
"aria-readonly": readOnly ? "true" : undefined,
|
|
194
|
+
className: cn("inline-flex gap-1", !readOnly && "touch-pan-y select-none"),
|
|
195
|
+
onPointerLeave: function onPointerLeave(e) {
|
|
196
|
+
if (!drag.current) clearHover();
|
|
197
|
+
},
|
|
198
|
+
onPointerCancel: function onPointerCancel(e) {
|
|
199
|
+
handleDragCancel(e);
|
|
200
|
+
clearHover();
|
|
201
|
+
},
|
|
202
|
+
onPointerDown: handleDragStart,
|
|
203
|
+
onPointerMove: handleDragMove,
|
|
204
|
+
onPointerUp: handleDragEnd,
|
|
146
205
|
children: Array.from({
|
|
147
206
|
length: count
|
|
148
207
|
}, function (_, i) {
|
|
149
208
|
var starNumber = i + 1;
|
|
150
209
|
var filled = starNumber <= (displayValue || 0);
|
|
210
|
+
var checked = starNumber === selectedValue;
|
|
151
211
|
var color = filled ? activeColor : inactiveColor;
|
|
152
212
|
// Token classes unless a colour override is passed, so brands and dark mode apply (STUDIO-59).
|
|
153
213
|
var colorClass = color ? "" : filled ? " text-warning-400" : " text-gray-200";
|
|
154
214
|
return jsx("button", {
|
|
215
|
+
ref: function ref(el) {
|
|
216
|
+
starRefs.current[i] = el;
|
|
217
|
+
},
|
|
155
218
|
type: "button",
|
|
156
219
|
role: "radio",
|
|
157
|
-
"aria-checked":
|
|
220
|
+
"aria-checked": checked,
|
|
158
221
|
"aria-label": "".concat(starNumber, " star").concat(starNumber > 1 ? "s" : ""),
|
|
159
|
-
tabIndex: readOnly ?
|
|
222
|
+
tabIndex: !readOnly && starNumber === tabStop ? 0 : -1,
|
|
160
223
|
onClick: function onClick() {
|
|
161
|
-
return
|
|
224
|
+
return handleStarClick(starNumber);
|
|
162
225
|
},
|
|
163
226
|
onKeyDown: function onKeyDown(e) {
|
|
164
227
|
return handleKeyDown(e, starNumber);
|
|
165
228
|
},
|
|
166
|
-
|
|
167
|
-
return
|
|
168
|
-
},
|
|
169
|
-
onMouseMove: function onMouseMove() {
|
|
170
|
-
return handleMouseMove(starNumber);
|
|
229
|
+
onPointerEnter: function onPointerEnter(e) {
|
|
230
|
+
return handlePointerHover(e, starNumber);
|
|
171
231
|
},
|
|
172
|
-
|
|
173
|
-
return
|
|
232
|
+
onPointerMove: function onPointerMove(e) {
|
|
233
|
+
return handlePointerHover(e, starNumber);
|
|
174
234
|
},
|
|
175
|
-
onBlur: handleBlur,
|
|
176
235
|
disabled: readOnly,
|
|
177
236
|
title: "".concat(starNumber, " of ").concat(count),
|
|
178
|
-
className: "p-0 m-0 bg-transparent border-0 inline-flex items-center justify-center leading-0 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-
|
|
237
|
+
className: cn("p-0 m-0 bg-transparent border-0 inline-flex items-center justify-center leading-0 rounded", "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-primary-500", "transition-colors motion-reduce:transition-none", TOUCH_TARGET, colorClass.trim()),
|
|
179
238
|
style: color ? {
|
|
180
239
|
color: color
|
|
181
240
|
} : undefined,
|
|
@@ -3,8 +3,9 @@ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _
|
|
|
3
3
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
4
4
|
import { forwardRef } from 'react';
|
|
5
5
|
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import { TOUCH_TARGET, PRESS_FEEDBACK } from '../../utils/touchTarget.js';
|
|
6
7
|
|
|
7
|
-
var _excluded = ["label", "avatarSrc", "avatarAlt", "initials", "size", "onRemove", "onClick", "className", "closeClass", "ariaLabel", "avatarPosition", "avatarClassname", "initialClassname"];
|
|
8
|
+
var _excluded = ["label", "avatarSrc", "avatarAlt", "initials", "size", "onRemove", "onClick", "className", "closeClass", "ariaLabel", "onKeyDown", "avatarPosition", "avatarClassname", "initialClassname"];
|
|
8
9
|
var RoundedTag = /*#__PURE__*/forwardRef(function RoundedTag(_ref, ref) {
|
|
9
10
|
var label = _ref.label,
|
|
10
11
|
_ref$avatarSrc = _ref.avatarSrc,
|
|
@@ -23,8 +24,8 @@ var RoundedTag = /*#__PURE__*/forwardRef(function RoundedTag(_ref, ref) {
|
|
|
23
24
|
className = _ref$className === void 0 ? "" : _ref$className,
|
|
24
25
|
_ref$closeClass = _ref.closeClass,
|
|
25
26
|
closeClass = _ref$closeClass === void 0 ? "" : _ref$closeClass,
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
ariaLabel = _ref.ariaLabel,
|
|
28
|
+
onKeyDown = _ref.onKeyDown,
|
|
28
29
|
_ref$avatarPosition = _ref.avatarPosition,
|
|
29
30
|
avatarPosition = _ref$avatarPosition === void 0 ? "left" : _ref$avatarPosition,
|
|
30
31
|
_ref$avatarClassname = _ref.avatarClassname,
|
|
@@ -63,12 +64,25 @@ var RoundedTag = /*#__PURE__*/forwardRef(function RoundedTag(_ref, ref) {
|
|
|
63
64
|
e && e.stopPropagation();
|
|
64
65
|
onRemove && onRemove({});
|
|
65
66
|
}
|
|
67
|
+
var clickable = typeof _onClick === "function";
|
|
68
|
+
// Enter / Space activate a clickable tag like a native button. Keys from
|
|
69
|
+
// nested controls (the remove button) are left alone.
|
|
70
|
+
function handleKeyDown(e) {
|
|
71
|
+
onKeyDown && onKeyDown(e);
|
|
72
|
+
if (!clickable || e.defaultPrevented || e.target !== e.currentTarget) return;
|
|
73
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
_onClick(e);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
var labelText = typeof label === "string" || typeof label === "number" ? String(label) : "";
|
|
79
|
+
var removeLabel = labelText ? "Remove ".concat(labelText) : "Remove";
|
|
66
80
|
var s = sizes[size] || sizes.md;
|
|
67
81
|
var paddingClass = showAvatar ? s.paddingWithAvatar : s.paddingNoAvatar;
|
|
68
82
|
var gapClass = showAvatar ? s.gapWithAvatar : s.gapNoAvatar;
|
|
69
83
|
var AvatarNode = showAvatar && jsx(Fragment, {
|
|
70
84
|
children: avatarSrc ? jsx("div", {
|
|
71
|
-
className: "flex-shrink-0 rounded-full overflow-hidden bg-gray-300 flex items-center justify-center ".concat(s.avatar, " ").concat(avatarClassname),
|
|
85
|
+
className: "flex-shrink-0 rounded-full overflow-hidden bg-gray-300 dark:bg-gray-600 dark:text-gray-100 flex items-center justify-center ".concat(s.avatar, " ").concat(avatarClassname),
|
|
72
86
|
"aria-hidden": avatarSrc ? undefined : "true",
|
|
73
87
|
children: jsx("img", {
|
|
74
88
|
src: avatarSrc,
|
|
@@ -76,29 +90,32 @@ var RoundedTag = /*#__PURE__*/forwardRef(function RoundedTag(_ref, ref) {
|
|
|
76
90
|
className: "w-full h-full object-cover"
|
|
77
91
|
})
|
|
78
92
|
}) : jsx("div", {
|
|
79
|
-
className: "flex-shrink-0 rounded-full overflow-hidden bg-gray-300 flex items-center justify-center ".concat(s.avatar, " ").concat(initialClassname),
|
|
93
|
+
className: "flex-shrink-0 rounded-full overflow-hidden bg-gray-300 dark:bg-gray-600 dark:text-gray-100 flex items-center justify-center ".concat(s.avatar, " ").concat(initialClassname),
|
|
80
94
|
"aria-hidden": avatarSrc ? undefined : "true",
|
|
81
95
|
children: initials
|
|
82
96
|
})
|
|
83
97
|
});
|
|
84
98
|
return jsxs("div", _objectSpread2(_objectSpread2({
|
|
85
99
|
ref: ref,
|
|
86
|
-
className: cn("inline-flex items-center rounded-full bg-gray-100 text-primary-800", paddingClass, gapClass, s.text, className),
|
|
87
|
-
role: "group",
|
|
100
|
+
className: cn("inline-flex items-center rounded-full bg-gray-100 text-primary-800 dark:bg-gray-800 dark:text-gray-100", paddingClass, gapClass, s.text, clickable && ["cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-1 dark:focus-visible:ring-offset-gray-900", PRESS_FEEDBACK], className),
|
|
101
|
+
role: clickable ? "button" : "group",
|
|
102
|
+
tabIndex: clickable ? 0 : undefined,
|
|
88
103
|
"aria-label": ariaLabel,
|
|
89
104
|
onClick: function onClick(e) {
|
|
90
105
|
return _onClick && _onClick(e);
|
|
91
|
-
}
|
|
106
|
+
},
|
|
107
|
+
onKeyDown: handleKeyDown
|
|
92
108
|
}, rest), {}, {
|
|
93
109
|
children: [avatarPosition === "left" && AvatarNode, jsx("div", {
|
|
94
110
|
className: "truncate max-w-[10rem]",
|
|
95
111
|
children: label
|
|
96
112
|
}), avatarPosition === "right" && AvatarNode, onRemove && jsx("button", {
|
|
97
113
|
type: "button",
|
|
98
|
-
"aria-label":
|
|
114
|
+
"aria-label": removeLabel,
|
|
99
115
|
onClick: handleRemove,
|
|
100
|
-
className: "inline-flex items-center justify-center rounded-full p-1 hover:bg-gray-200 focus:outline-none "
|
|
116
|
+
className: cn("inline-flex items-center justify-center rounded-full p-1 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors duration-fast motion-reduce:transition-none focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", TOUCH_TARGET, closeClass),
|
|
101
117
|
children: jsx("svg", {
|
|
118
|
+
"aria-hidden": "true",
|
|
102
119
|
className: "w-3 h-3",
|
|
103
120
|
viewBox: "0 0 24 24",
|
|
104
121
|
fill: "none",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
-
import { jsx, Fragment
|
|
3
|
+
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { forwardRef } from 'react';
|
|
5
5
|
import { cn } from '../../utils/cn.js';
|
|
6
6
|
|
|
@@ -21,6 +21,11 @@ var _excluded = ["count", "circle", "height", "width", "rounded", "animated", "a
|
|
|
21
21
|
* - className (string) - extra wrapper classes
|
|
22
22
|
* - children - optional children to render when active === false
|
|
23
23
|
*/
|
|
24
|
+
var BONE_CLASSES = "relative inline-block overflow-hidden bg-gray-200 dark:bg-gray-700";
|
|
25
|
+
// Shimmer (DTUI-48): a Tailwind animation, no per-instance <style> tag. The
|
|
26
|
+
// highlight is a soft white in light mode and a faint one in dark mode (no white
|
|
27
|
+
// streak); under prefers-reduced-motion the bone is static and plain.
|
|
28
|
+
var SHIMMER_CLASSES = ["bg-gradient-to-r from-transparent via-white/50 to-transparent dark:via-white/10", "bg-[length:200%_100%] bg-no-repeat animate-shimmer", "motion-reduce:animate-none motion-reduce:bg-none"].join(" ");
|
|
24
29
|
function toPxOrUnit(value) {
|
|
25
30
|
if (typeof value === "number") return "".concat(value, "px");
|
|
26
31
|
if (typeof value === "string") return value;
|
|
@@ -61,8 +66,7 @@ var Skeleton = /*#__PURE__*/forwardRef(function Skeleton(_ref, ref) {
|
|
|
61
66
|
var items = Array.from({
|
|
62
67
|
length: Math.max(1, Math.floor(count))
|
|
63
68
|
});
|
|
64
|
-
|
|
65
|
-
return jsxs("div", _objectSpread2(_objectSpread2({
|
|
69
|
+
return jsx("div", _objectSpread2(_objectSpread2({
|
|
66
70
|
ref: ref,
|
|
67
71
|
className: cn("skeleton-wrapper", className),
|
|
68
72
|
role: "status",
|
|
@@ -75,24 +79,19 @@ var Skeleton = /*#__PURE__*/forwardRef(function Skeleton(_ref, ref) {
|
|
|
75
79
|
alignItems: "center"
|
|
76
80
|
}, style)
|
|
77
81
|
}, rest), {}, {
|
|
78
|
-
children:
|
|
79
|
-
children: "\n @keyframes skeleton-shimmer {\n 0% { background-position: -150% 0; }\n 100% { background-position: 150% 0; }\n }\n .skeleton-wrapper .skeleton-item {\n display: inline-block;\n position: relative;\n overflow: hidden;\n }\n "
|
|
80
|
-
}), items.map(function (_, i) {
|
|
82
|
+
children: items.map(function (_, i) {
|
|
81
83
|
return jsx("div", {
|
|
82
84
|
// Token classes rather than an inline hex, so brands and dark mode apply (STUDIO-59).
|
|
83
|
-
|
|
85
|
+
// Plain join, not cn(): tailwind-merge would treat the gradient / bg-size
|
|
86
|
+
// utilities as conflicts of the bg-gray-200 colour and drop it.
|
|
87
|
+
className: ["skeleton-item", BONE_CLASSES, animated && SHIMMER_CLASSES].filter(Boolean).join(" "),
|
|
84
88
|
style: {
|
|
85
89
|
height: resolvedHeight,
|
|
86
90
|
width: resolvedWidth,
|
|
87
|
-
borderRadius: borderRadius
|
|
88
|
-
backgroundImage: shimmerOverlay,
|
|
89
|
-
backgroundSize: animated ? "200% 100%" : undefined,
|
|
90
|
-
backgroundRepeat: "no-repeat",
|
|
91
|
-
animation: animated ? "skeleton-shimmer 1.2s linear infinite" : undefined,
|
|
92
|
-
willChange: animated ? "background-position" : undefined
|
|
91
|
+
borderRadius: borderRadius
|
|
93
92
|
}
|
|
94
93
|
}, i);
|
|
95
|
-
})
|
|
94
|
+
})
|
|
96
95
|
}));
|
|
97
96
|
});
|
|
98
97
|
Skeleton.displayName = "Skeleton";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
-
import { forwardRef, useId, useRef, useMemo } from 'react';
|
|
4
|
+
import { forwardRef, useId, useRef, useMemo, useState } from 'react';
|
|
5
5
|
import { cn } from '../../utils/cn.js';
|
|
6
6
|
import { useSliderValues, useSliderPointer, toPercent, keyToValue } from '../../hooks/useSliderValues.js';
|
|
7
7
|
|
|
8
|
-
var _excluded = ["value", "defaultValue", "onChange", "onChangeEnd", "min", "max", "step", "largeStep", "disabled", "label", "showValue", "formatValue", "thumbLabels", "name", "className", "aria-label"];
|
|
8
|
+
var _excluded = ["value", "defaultValue", "onChange", "onChangeEnd", "min", "max", "step", "largeStep", "disabled", "label", "showValue", "showBubble", "formatValue", "thumbLabels", "name", "className", "aria-label"];
|
|
9
9
|
var DEFAULT_THUMB_LABELS = ["Minimum", "Maximum"];
|
|
10
10
|
var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
11
11
|
var value = _ref.value,
|
|
@@ -24,6 +24,8 @@ var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
24
24
|
label = _ref.label,
|
|
25
25
|
_ref$showValue = _ref.showValue,
|
|
26
26
|
showValue = _ref$showValue === void 0 ? false : _ref$showValue,
|
|
27
|
+
_ref$showBubble = _ref.showBubble,
|
|
28
|
+
showBubble = _ref$showBubble === void 0 ? true : _ref$showBubble,
|
|
27
29
|
_ref$formatValue = _ref.formatValue,
|
|
28
30
|
formatValue = _ref$formatValue === void 0 ? String : _ref$formatValue,
|
|
29
31
|
_ref$thumbLabels = _ref.thumbLabels,
|
|
@@ -52,12 +54,18 @@ var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
52
54
|
values = _useSliderValues.values,
|
|
53
55
|
isRange = _useSliderValues.isRange,
|
|
54
56
|
setThumb = _useSliderValues.setThumb;
|
|
57
|
+
// Index of the thumb being dragged (drives the value bubble), else null.
|
|
58
|
+
var _useState = useState(null),
|
|
59
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
60
|
+
dragging = _useState2[0],
|
|
61
|
+
setDragging = _useState2[1];
|
|
55
62
|
var pointer = useSliderPointer({
|
|
56
63
|
trackRef: trackRef,
|
|
57
64
|
values: values,
|
|
58
65
|
setThumb: setThumb,
|
|
59
66
|
bounds: bounds,
|
|
60
|
-
disabled: disabled
|
|
67
|
+
disabled: disabled,
|
|
68
|
+
onActiveChange: setDragging
|
|
61
69
|
});
|
|
62
70
|
var handleKeyDown = function handleKeyDown(index) {
|
|
63
71
|
return function (e) {
|
|
@@ -90,7 +98,9 @@ var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
90
98
|
})]
|
|
91
99
|
}), jsxs("div", _objectSpread2(_objectSpread2({
|
|
92
100
|
ref: trackRef,
|
|
93
|
-
className: cn(
|
|
101
|
+
className: cn(
|
|
102
|
+
// 44px tall row on coarse pointers so the whole strip is easy to grab.
|
|
103
|
+
"relative flex h-5 touch-none select-none items-center [@media(pointer:coarse)]:h-11", disabled ? "cursor-not-allowed" : "cursor-pointer")
|
|
94
104
|
}, pointer), {}, {
|
|
95
105
|
children: [jsx("div", {
|
|
96
106
|
className: "h-1.5 w-full rounded-full bg-gray-200 dark:bg-gray-700"
|
|
@@ -117,7 +127,15 @@ var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
117
127
|
style: {
|
|
118
128
|
left: "".concat(toPercent(v, min, max), "%")
|
|
119
129
|
},
|
|
120
|
-
className: cn("absolute h-4 w-4 -translate-x-1/2 rounded-full border-2 border-primary-600 bg-
|
|
130
|
+
className: cn("absolute h-4 w-4 -translate-x-1/2 rounded-full border-2 border-primary-600 bg-surface shadow", "transition-shadow duration-fast motion-reduce:transition-none", "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-primary-500", "dark:border-primary-500 dark:focus-visible:ring-offset-gray-900",
|
|
131
|
+
// Grow the hit area to 44px on touch without changing the visual size.
|
|
132
|
+
"before:absolute before:left-1/2 before:top-1/2 before:-translate-x-1/2 before:-translate-y-1/2", "[@media(pointer:coarse)]:before:h-11 [@media(pointer:coarse)]:before:w-11 before:content-['']"),
|
|
133
|
+
children: showBubble && dragging === i && jsx("span", {
|
|
134
|
+
"aria-hidden": "true",
|
|
135
|
+
"data-slider-bubble": "",
|
|
136
|
+
className: cn("pointer-events-none absolute -top-9 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md border border-line", "bg-surface px-2 py-1 text-xs tabular-nums text-foreground shadow-sm", "animate-scale-in motion-reduce:animate-none"),
|
|
137
|
+
children: formatValue(v)
|
|
138
|
+
})
|
|
121
139
|
}, i);
|
|
122
140
|
})]
|
|
123
141
|
})), name && values.map(function (v, i) {
|