@dreamtree-org/twreact-ui 1.3.11 → 2.0.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.
- package/README.md +40 -6
- package/ai-skills/dreamtree-ui.md +47 -9
- package/codemods/v2.cjs +198 -0
- package/dist/ai-schema.json +609 -33
- package/dist/components/blocks/AppShell.d.ts.map +1 -1
- package/dist/components/blocks/BottomActionBar.d.ts +6 -0
- package/dist/components/blocks/BottomActionBar.d.ts.map +1 -0
- package/dist/components/blocks/ConfirmDialog.d.ts.map +1 -1
- package/dist/components/blocks/PageHeader.d.ts.map +1 -1
- package/dist/components/core/Checkbox.d.ts.map +1 -1
- package/dist/components/core/DatePicker.d.ts.map +1 -1
- package/dist/components/core/DateRangePicker.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/Popover.d.ts.map +1 -1
- package/dist/components/core/ProgressBar.d.ts.map +1 -1
- package/dist/components/core/Rate.d.ts.map +1 -1
- package/dist/components/core/SearchField.d.ts +9 -0
- package/dist/components/core/SearchField.d.ts.map +1 -0
- package/dist/components/core/SegmentedControl.d.ts +8 -0
- package/dist/components/core/SegmentedControl.d.ts.map +1 -0
- package/dist/components/core/Select.d.ts.map +1 -1
- package/dist/components/core/SwipeableListItem.d.ts +4 -0
- package/dist/components/core/SwipeableListItem.d.ts.map +1 -0
- package/dist/components/core/SwipeableListItemGesture.d.ts +58 -0
- package/dist/components/core/SwipeableListItemGesture.d.ts.map +1 -0
- package/dist/components/core/Switch.d.ts.map +1 -1
- package/dist/components/core/Table/ActionMenu.d.ts +10 -3
- package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
- package/dist/components/core/Table/MobileCard.d.ts +10 -1
- package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
- package/dist/components/core/Table/MobileFilters.d.ts +8 -2
- package/dist/components/core/Table/MobileFilters.d.ts.map +1 -1
- package/dist/components/core/Table/Table.d.ts.map +1 -1
- package/dist/components/core/Table/TableRow.d.ts +2 -1
- package/dist/components/core/Table/TableRow.d.ts.map +1 -1
- package/dist/components/core/Tabs.d.ts +3 -3
- package/dist/components/core/Tabs.d.ts.map +1 -1
- package/dist/components/core/ThreeDotPopover.d.ts +10 -22
- package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
- package/dist/components/core/Tooltip.d.ts +2 -1
- package/dist/components/core/Tooltip.d.ts.map +1 -1
- package/dist/components/core/internal/Calendar.d.ts +77 -0
- package/dist/components/core/internal/Calendar.d.ts.map +1 -0
- package/dist/components/core/menu/ActionMenuSurface.d.ts +42 -0
- package/dist/components/core/menu/ActionMenuSurface.d.ts.map +1 -0
- package/dist/components/core/menu/ActionSheetMenu.d.ts +17 -0
- package/dist/components/core/menu/ActionSheetMenu.d.ts.map +1 -0
- package/dist/components/core/menu/MenuPopover.d.ts +21 -0
- package/dist/components/core/menu/MenuPopover.d.ts.map +1 -0
- package/dist/components/core/menu/menuItems.d.ts +21 -0
- package/dist/components/core/menu/menuItems.d.ts.map +1 -0
- package/dist/components/core/menu/menuKeyboard.d.ts +16 -0
- package/dist/components/core/menu/menuKeyboard.d.ts.map +1 -0
- package/dist/components/feedback/ActionSheet.d.ts +4 -0
- package/dist/components/feedback/ActionSheet.d.ts.map +1 -0
- package/dist/components/feedback/Alert.d.ts.map +1 -1
- package/dist/components/feedback/Dialog.d.ts.map +1 -1
- package/dist/components/feedback/Drawer.d.ts.map +1 -1
- package/dist/components/feedback/Sheet.d.ts +4 -0
- package/dist/components/feedback/Sheet.d.ts.map +1 -0
- package/dist/components/feedback/Toast.d.ts +4 -3
- package/dist/components/feedback/Toast.d.ts.map +1 -1
- package/dist/components/feedback/ToastItem.d.ts +47 -0
- package/dist/components/feedback/ToastItem.d.ts.map +1 -0
- package/dist/components/feedback/ToastStack.d.ts +20 -0
- package/dist/components/feedback/ToastStack.d.ts.map +1 -0
- package/dist/components/feedback/ToastSwipe.d.ts +22 -0
- package/dist/components/feedback/ToastSwipe.d.ts.map +1 -0
- package/dist/components/feedback/Tour.d.ts.map +1 -1
- package/dist/components/feedback/sheetCore.d.ts +30 -0
- package/dist/components/feedback/sheetCore.d.ts.map +1 -0
- package/dist/components/navigation/Navbar.d.ts.map +1 -1
- package/dist/components/navigation/Sidebar.d.ts +6 -0
- package/dist/components/navigation/Sidebar.d.ts.map +1 -1
- package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -1
- package/dist/components/rich-text/RichTextToolbar.d.ts +6 -2
- package/dist/components/rich-text/RichTextToolbar.d.ts.map +1 -1
- package/dist/components/utility/PullToRefresh.d.ts +5 -0
- package/dist/components/utility/PullToRefresh.d.ts.map +1 -0
- package/dist/esm/components/blocks/AppShell.js +97 -90
- package/dist/esm/components/blocks/BottomActionBar.js +132 -0
- package/dist/esm/components/blocks/ConfirmDialog.js +40 -4
- package/dist/esm/components/blocks/PageHeader.js +16 -3
- package/dist/esm/components/core/Checkbox.js +13 -24
- package/dist/esm/components/core/DatePicker.js +117 -304
- package/dist/esm/components/core/DateRangePicker.js +260 -308
- package/dist/esm/components/core/Form.js +11 -2
- package/dist/esm/components/core/Input.js +13 -18
- package/dist/esm/components/core/Popover.js +59 -48
- package/dist/esm/components/core/ProgressBar.js +36 -64
- package/dist/esm/components/core/Rate.js +5 -10
- package/dist/esm/components/core/SearchField.js +311 -0
- package/dist/esm/components/core/SegmentedControl.js +189 -0
- package/dist/esm/components/core/Select.js +185 -190
- package/dist/esm/components/core/SwipeableListItem.js +286 -0
- package/dist/esm/components/core/SwipeableListItemGesture.js +219 -0
- package/dist/esm/components/core/Switch.js +11 -13
- package/dist/esm/components/core/Table/ActionMenu.js +45 -231
- package/dist/esm/components/core/Table/ColumnMenu.js +1 -1
- package/dist/esm/components/core/Table/MobileCard.js +66 -16
- package/dist/esm/components/core/Table/MobileFilters.js +181 -10
- package/dist/esm/components/core/Table/Table.js +149 -102
- package/dist/esm/components/core/Table/TableRow.js +10 -2
- package/dist/esm/components/core/Tabs.js +7 -7
- package/dist/esm/components/core/ThreeDotPopover.js +93 -99
- package/dist/esm/components/core/Tooltip.js +138 -145
- package/dist/esm/components/core/internal/Calendar.js +381 -0
- package/dist/esm/components/core/menu/ActionMenuSurface.js +110 -0
- package/dist/esm/components/core/menu/ActionSheetMenu.js +140 -0
- package/dist/esm/components/core/menu/MenuPopover.js +177 -0
- package/dist/esm/components/core/menu/menuItems.js +61 -0
- package/dist/esm/components/core/menu/menuKeyboard.js +54 -0
- package/dist/esm/components/feedback/ActionSheet.js +55 -0
- package/dist/esm/components/feedback/Alert.js +63 -53
- package/dist/esm/components/feedback/Dialog.js +141 -53
- package/dist/esm/components/feedback/Drawer.js +130 -132
- package/dist/esm/components/feedback/Sheet.js +125 -0
- package/dist/esm/components/feedback/Toast.js +21 -291
- package/dist/esm/components/feedback/ToastItem.js +348 -0
- package/dist/esm/components/feedback/ToastStack.js +130 -0
- package/dist/esm/components/feedback/ToastSwipe.js +52 -0
- package/dist/esm/components/feedback/Tour.js +107 -30
- package/dist/esm/components/feedback/sheetCore.js +494 -0
- package/dist/esm/components/navigation/Dropdown.js +1 -1
- package/dist/esm/components/navigation/Navbar.js +172 -37
- package/dist/esm/components/navigation/Sidebar.js +263 -111
- package/dist/esm/components/rich-text/RichTextEditor.js +9 -3
- package/dist/esm/components/rich-text/RichTextToolbar.js +29 -9
- package/dist/esm/components/utility/Portal.js +31 -0
- package/dist/esm/components/utility/PullToRefresh.js +229 -0
- package/dist/esm/hooks/useFloatingPosition.js +82 -0
- package/dist/esm/hooks/useHaptics.js +65 -0
- package/dist/esm/hooks/usePresence.js +58 -0
- package/dist/esm/hooks/usePresentation.js +21 -0
- package/dist/esm/hooks/useSheetDrag.js +220 -0
- package/dist/esm/index.js +13 -2
- package/dist/esm/utils/position.js +10 -63
- package/dist/hooks/useFloatingPosition.d.ts +8 -4
- package/dist/hooks/useFloatingPosition.d.ts.map +1 -1
- package/dist/hooks/useHaptics.d.ts +19 -0
- package/dist/hooks/useHaptics.d.ts.map +1 -0
- package/dist/hooks/useSheetDrag.d.ts +31 -0
- package/dist/hooks/useSheetDrag.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +8851 -3198
- package/dist/index.js +8856 -3195
- package/dist/rich-text/index.js +41 -11
- package/dist/types/blocks.d.ts +32 -2
- package/dist/types/blocks.d.ts.map +1 -1
- package/dist/types/index.d.ts +353 -19
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/rich-text.d.ts +5 -0
- package/dist/types/rich-text.d.ts.map +1 -1
- package/dist/utils/position.d.ts +0 -15
- package/dist/utils/position.d.ts.map +1 -1
- package/doc/README.md +15 -0
- package/mcp/catalog.snapshot.json +1398 -464
- package/package.json +7 -2
- package/dist/esm/hooks/useSwipeToClose.js +0 -66
- package/dist/hooks/useSwipeToClose.d.ts +0 -24
- package/dist/hooks/useSwipeToClose.d.ts.map +0 -1
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import React, { useState, useRef, useId, useCallback } from 'react';
|
|
5
|
+
import { Search, X } from 'lucide-react';
|
|
6
|
+
import { cn } from '../../utils/cn.js';
|
|
7
|
+
import { setRefs } from '../../utils/position.js';
|
|
8
|
+
import { TOUCH_TARGET } from '../../utils/touchTarget.js';
|
|
9
|
+
import { useControllableState } from '../../hooks/useControllableState.js';
|
|
10
|
+
import { usePresentation } from '../../hooks/usePresentation.js';
|
|
11
|
+
import { useClickOutside } from '../../hooks/useClickOutside.js';
|
|
12
|
+
import Sheet from '../feedback/Sheet.js';
|
|
13
|
+
|
|
14
|
+
var _excluded = ["value", "defaultValue", "onChange", "onValueChange", "onSearch", "onCancel", "onClear", "placeholder", "cancelLabel", "clearLabel", "showCancel", "presentation", "results", "renderResults", "resultsOpen", "onResultsOpenChange", "resultsLabel", "disabled", "readOnly", "className", "inputClassName", "style", "onFocus", "onBlur", "onKeyDown", "onClick", "aria-label"];
|
|
15
|
+
// iOS-style search field (DTUI-58): leading icon, clear button, a "Cancel"
|
|
16
|
+
// text button on phones while focused, and an optional results surface that
|
|
17
|
+
// is a full-height Sheet on phones and a popover beneath the field elsewhere.
|
|
18
|
+
var INPUT_CLASSES = cn("h-10 w-full min-w-0 appearance-none rounded-control border border-line bg-background pl-9 pr-9 text-sm text-foreground", "placeholder:text-muted [@media(pointer:coarse)]:h-11 [@media(pointer:coarse)]:pr-12", "transition-colors duration-fast ease-standard motion-reduce:transition-none", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", "disabled:cursor-not-allowed disabled:opacity-50",
|
|
19
|
+
// The native WebKit clear (x) would duplicate ours.
|
|
20
|
+
"[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none");
|
|
21
|
+
var CLEAR_BUTTON_CLASSES = cn("absolute right-1 top-1/2 inline-flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-pill text-muted", "hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", TOUCH_TARGET);
|
|
22
|
+
var CANCEL_BUTTON_CLASSES = cn("inline-flex shrink-0 items-center rounded-control px-2 text-sm font-medium text-primary-600 dark:text-primary-400", "hover:text-primary-700 dark:hover:text-primary-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", "min-h-10 [@media(pointer:coarse)]:min-h-11");
|
|
23
|
+
var RESULTS_POPOVER_CLASSES = cn("absolute inset-x-0 top-full z-popover mt-1 max-h-80 overflow-y-auto overscroll-contain", "rounded-control border border-line bg-surface text-foreground shadow-overlay");
|
|
24
|
+
// Keeps focus in the input when a button inside the field is pressed, so a
|
|
25
|
+
// blur does not hide the Cancel button before its click lands.
|
|
26
|
+
var keepFocus = function keepFocus(e) {
|
|
27
|
+
return e.preventDefault();
|
|
28
|
+
};
|
|
29
|
+
var isEmptyNode = function isEmptyNode(node) {
|
|
30
|
+
return node === undefined || node === null || node === false;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* SearchField — `type="search"` input with iOS conventions.
|
|
34
|
+
*
|
|
35
|
+
* `ref` and unknown props go to the `<input>`; `className` styles the root.
|
|
36
|
+
*/
|
|
37
|
+
var SearchField = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
38
|
+
var valueProp = _ref.value,
|
|
39
|
+
_ref$defaultValue = _ref.defaultValue,
|
|
40
|
+
defaultValue = _ref$defaultValue === void 0 ? "" : _ref$defaultValue,
|
|
41
|
+
onChange = _ref.onChange,
|
|
42
|
+
onValueChange = _ref.onValueChange,
|
|
43
|
+
onSearch = _ref.onSearch,
|
|
44
|
+
onCancel = _ref.onCancel,
|
|
45
|
+
onClear = _ref.onClear,
|
|
46
|
+
_ref$placeholder = _ref.placeholder,
|
|
47
|
+
placeholder = _ref$placeholder === void 0 ? "Search" : _ref$placeholder,
|
|
48
|
+
_ref$cancelLabel = _ref.cancelLabel,
|
|
49
|
+
cancelLabel = _ref$cancelLabel === void 0 ? "Cancel" : _ref$cancelLabel,
|
|
50
|
+
_ref$clearLabel = _ref.clearLabel,
|
|
51
|
+
clearLabel = _ref$clearLabel === void 0 ? "Clear search" : _ref$clearLabel,
|
|
52
|
+
_ref$showCancel = _ref.showCancel,
|
|
53
|
+
showCancel = _ref$showCancel === void 0 ? "auto" : _ref$showCancel,
|
|
54
|
+
_ref$presentation = _ref.presentation,
|
|
55
|
+
presentation = _ref$presentation === void 0 ? "auto" : _ref$presentation,
|
|
56
|
+
results = _ref.results,
|
|
57
|
+
renderResults = _ref.renderResults,
|
|
58
|
+
resultsOpen = _ref.resultsOpen,
|
|
59
|
+
onResultsOpenChange = _ref.onResultsOpenChange,
|
|
60
|
+
_ref$resultsLabel = _ref.resultsLabel,
|
|
61
|
+
resultsLabel = _ref$resultsLabel === void 0 ? "Search results" : _ref$resultsLabel,
|
|
62
|
+
_ref$disabled = _ref.disabled,
|
|
63
|
+
disabled = _ref$disabled === void 0 ? false : _ref$disabled,
|
|
64
|
+
_ref$readOnly = _ref.readOnly,
|
|
65
|
+
readOnly = _ref$readOnly === void 0 ? false : _ref$readOnly,
|
|
66
|
+
className = _ref.className,
|
|
67
|
+
inputClassName = _ref.inputClassName,
|
|
68
|
+
style = _ref.style,
|
|
69
|
+
onFocus = _ref.onFocus,
|
|
70
|
+
onBlur = _ref.onBlur,
|
|
71
|
+
onKeyDown = _ref.onKeyDown,
|
|
72
|
+
onClick = _ref.onClick,
|
|
73
|
+
ariaLabel = _ref["aria-label"],
|
|
74
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
75
|
+
var _useControllableState = useControllableState({
|
|
76
|
+
value: valueProp,
|
|
77
|
+
defaultValue: defaultValue,
|
|
78
|
+
onChange: onValueChange
|
|
79
|
+
}),
|
|
80
|
+
_useControllableState2 = _slicedToArray(_useControllableState, 2),
|
|
81
|
+
value = _useControllableState2[0],
|
|
82
|
+
setValue = _useControllableState2[1];
|
|
83
|
+
var text = value == null ? "" : String(value);
|
|
84
|
+
var _useControllableState3 = useControllableState({
|
|
85
|
+
value: resultsOpen,
|
|
86
|
+
defaultValue: false,
|
|
87
|
+
onChange: onResultsOpenChange
|
|
88
|
+
}),
|
|
89
|
+
_useControllableState4 = _slicedToArray(_useControllableState3, 2),
|
|
90
|
+
open = _useControllableState4[0],
|
|
91
|
+
setOpen = _useControllableState4[1];
|
|
92
|
+
var _useState = useState(false),
|
|
93
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
94
|
+
focused = _useState2[0],
|
|
95
|
+
setFocused = _useState2[1];
|
|
96
|
+
var mode = usePresentation(presentation);
|
|
97
|
+
var isPhone = mode === "sheet";
|
|
98
|
+
var hasResultsSlot = results !== undefined || typeof renderResults === "function";
|
|
99
|
+
var sheetMode = isPhone && hasResultsSlot;
|
|
100
|
+
var rootRef = useRef(null);
|
|
101
|
+
var inputRef = useRef(null);
|
|
102
|
+
var sheetInputRef = useRef(null);
|
|
103
|
+
// Set by Cancel inside the sheet: the focus the Sheet restores to the
|
|
104
|
+
// inline field is dropped, like iOS dismissing search.
|
|
105
|
+
var blurOnRestoreRef = useRef(false);
|
|
106
|
+
var resultsId = "search-results-".concat(useId());
|
|
107
|
+
var inputCallbackRef = useCallback(function (node) {
|
|
108
|
+
return setRefs(node, inputRef, ref);
|
|
109
|
+
}, [ref]);
|
|
110
|
+
var close = useCallback(function () {
|
|
111
|
+
if (open) setOpen(false);
|
|
112
|
+
}, [open, setOpen]);
|
|
113
|
+
var content = !hasResultsSlot ? null : typeof renderResults === "function" ? renderResults({
|
|
114
|
+
value: text,
|
|
115
|
+
close: close
|
|
116
|
+
}) : results;
|
|
117
|
+
var popoverOpen = !sheetMode && hasResultsSlot && Boolean(open) && !isEmptyNode(content);
|
|
118
|
+
var sheetOpen = sheetMode && Boolean(open);
|
|
119
|
+
useClickOutside(rootRef, function () {
|
|
120
|
+
return setOpen(false);
|
|
121
|
+
}, {
|
|
122
|
+
enabled: popoverOpen
|
|
123
|
+
});
|
|
124
|
+
var emitChange = function emitChange(next, event) {
|
|
125
|
+
setValue(next);
|
|
126
|
+
if (event) onChange === null || onChange === void 0 || onChange(event);else onChange === null || onChange === void 0 || onChange({
|
|
127
|
+
target: {
|
|
128
|
+
value: next
|
|
129
|
+
},
|
|
130
|
+
currentTarget: {
|
|
131
|
+
value: next
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
var handleChange = function handleChange(e) {
|
|
136
|
+
emitChange(e.target.value, e);
|
|
137
|
+
if (hasResultsSlot && !open) setOpen(true);
|
|
138
|
+
};
|
|
139
|
+
var handleClear = function handleClear(target) {
|
|
140
|
+
var _target$current, _target$current$focus;
|
|
141
|
+
emitChange("");
|
|
142
|
+
onClear === null || onClear === void 0 || onClear();
|
|
143
|
+
target === null || target === void 0 || (_target$current = target.current) === null || _target$current === void 0 || (_target$current$focus = _target$current.focus) === null || _target$current$focus === void 0 || _target$current$focus.call(_target$current);
|
|
144
|
+
};
|
|
145
|
+
var handleCancel = function handleCancel(fromSheet) {
|
|
146
|
+
if (text !== "") emitChange("");
|
|
147
|
+
if (open) setOpen(false);
|
|
148
|
+
if (fromSheet) {
|
|
149
|
+
// Only the restore that follows this close; never a later, real focus.
|
|
150
|
+
blurOnRestoreRef.current = true;
|
|
151
|
+
setTimeout(function () {
|
|
152
|
+
blurOnRestoreRef.current = false;
|
|
153
|
+
}, 300);
|
|
154
|
+
} else {
|
|
155
|
+
var _inputRef$current, _inputRef$current$blu;
|
|
156
|
+
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || (_inputRef$current$blu = _inputRef$current.blur) === null || _inputRef$current$blu === void 0 || _inputRef$current$blu.call(_inputRef$current);
|
|
157
|
+
}
|
|
158
|
+
setFocused(false);
|
|
159
|
+
onCancel === null || onCancel === void 0 || onCancel();
|
|
160
|
+
};
|
|
161
|
+
var handleKeyDown = function handleKeyDown(e, inSheet) {
|
|
162
|
+
var _e$nativeEvent;
|
|
163
|
+
onKeyDown === null || onKeyDown === void 0 || onKeyDown(e);
|
|
164
|
+
if (e.defaultPrevented) return;
|
|
165
|
+
if (e.key === "Enter" && !((_e$nativeEvent = e.nativeEvent) !== null && _e$nativeEvent !== void 0 && _e$nativeEvent.isComposing)) {
|
|
166
|
+
onSearch === null || onSearch === void 0 || onSearch(text);
|
|
167
|
+
} else if (e.key === "Escape" && !inSheet) {
|
|
168
|
+
if (popoverOpen) {
|
|
169
|
+
e.stopPropagation();
|
|
170
|
+
setOpen(false);
|
|
171
|
+
} else if (text !== "") {
|
|
172
|
+
e.stopPropagation();
|
|
173
|
+
emitChange("");
|
|
174
|
+
onClear === null || onClear === void 0 || onClear();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
var handleFocus = function handleFocus(e) {
|
|
179
|
+
if (blurOnRestoreRef.current) {
|
|
180
|
+
var _e$target$blur, _e$target;
|
|
181
|
+
blurOnRestoreRef.current = false;
|
|
182
|
+
(_e$target$blur = (_e$target = e.target).blur) === null || _e$target$blur === void 0 || _e$target$blur.call(_e$target);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
setFocused(true);
|
|
186
|
+
onFocus === null || onFocus === void 0 || onFocus(e);
|
|
187
|
+
if (hasResultsSlot && !sheetMode && !open) setOpen(true);
|
|
188
|
+
};
|
|
189
|
+
var handleBlur = function handleBlur(e) {
|
|
190
|
+
setFocused(false);
|
|
191
|
+
onBlur === null || onBlur === void 0 || onBlur(e);
|
|
192
|
+
// Tabbing out closes the popover; a press on non-focusable results
|
|
193
|
+
// content (relatedTarget null) is handled by the outside-press check.
|
|
194
|
+
var next = e.relatedTarget;
|
|
195
|
+
if (popoverOpen && next && rootRef.current && !rootRef.current.contains(next)) setOpen(false);
|
|
196
|
+
};
|
|
197
|
+
var handleClick = function handleClick(e) {
|
|
198
|
+
onClick === null || onClick === void 0 || onClick(e);
|
|
199
|
+
if (sheetMode && !disabled && !readOnly && !open) setOpen(true);
|
|
200
|
+
};
|
|
201
|
+
var cancelVisible = !disabled && (showCancel === true || showCancel === "auto" && isPhone && focused);
|
|
202
|
+
var renderRow = function renderRow(_ref2) {
|
|
203
|
+
var inputProps = _ref2.inputProps,
|
|
204
|
+
inSheet = _ref2.inSheet;
|
|
205
|
+
return jsxs(Fragment, {
|
|
206
|
+
children: [jsxs("div", {
|
|
207
|
+
className: "relative min-w-0 flex-1",
|
|
208
|
+
children: [jsx(Search, {
|
|
209
|
+
className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted",
|
|
210
|
+
"aria-hidden": "true"
|
|
211
|
+
}), inputProps, text !== "" && !disabled && !readOnly && jsx("button", {
|
|
212
|
+
type: "button",
|
|
213
|
+
className: CLEAR_BUTTON_CLASSES,
|
|
214
|
+
"aria-label": clearLabel,
|
|
215
|
+
onMouseDown: keepFocus,
|
|
216
|
+
onClick: function onClick() {
|
|
217
|
+
return handleClear(inSheet ? sheetInputRef : inputRef);
|
|
218
|
+
},
|
|
219
|
+
"data-search-clear": "",
|
|
220
|
+
children: jsx(X, {
|
|
221
|
+
className: "h-4 w-4",
|
|
222
|
+
"aria-hidden": "true"
|
|
223
|
+
})
|
|
224
|
+
})]
|
|
225
|
+
}), (inSheet || cancelVisible) && jsx("button", {
|
|
226
|
+
type: "button",
|
|
227
|
+
className: CANCEL_BUTTON_CLASSES,
|
|
228
|
+
onMouseDown: keepFocus,
|
|
229
|
+
onClick: function onClick() {
|
|
230
|
+
return handleCancel(inSheet);
|
|
231
|
+
},
|
|
232
|
+
"data-search-cancel": "",
|
|
233
|
+
children: cancelLabel
|
|
234
|
+
})]
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
var sharedInputProps = {
|
|
238
|
+
type: "search",
|
|
239
|
+
enterKeyHint: "search",
|
|
240
|
+
inputMode: "search",
|
|
241
|
+
autoComplete: "off",
|
|
242
|
+
placeholder: placeholder,
|
|
243
|
+
disabled: disabled,
|
|
244
|
+
readOnly: readOnly,
|
|
245
|
+
value: text,
|
|
246
|
+
onChange: handleChange,
|
|
247
|
+
"aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : rest["aria-labelledby"] ? undefined : placeholder || "Search"
|
|
248
|
+
};
|
|
249
|
+
var inlineInput = jsx("input", _objectSpread2(_objectSpread2(_objectSpread2({
|
|
250
|
+
ref: inputCallbackRef
|
|
251
|
+
}, sharedInputProps), {}, {
|
|
252
|
+
"aria-controls": popoverOpen ? resultsId : undefined,
|
|
253
|
+
onKeyDown: function onKeyDown(e) {
|
|
254
|
+
return handleKeyDown(e, false);
|
|
255
|
+
},
|
|
256
|
+
onFocus: handleFocus,
|
|
257
|
+
onBlur: handleBlur,
|
|
258
|
+
onClick: handleClick
|
|
259
|
+
}, rest), {}, {
|
|
260
|
+
className: cn(INPUT_CLASSES, inputClassName)
|
|
261
|
+
}));
|
|
262
|
+
return jsxs("div", {
|
|
263
|
+
ref: rootRef,
|
|
264
|
+
className: cn("relative flex w-full items-center gap-2", className),
|
|
265
|
+
style: style,
|
|
266
|
+
"data-search-field": "",
|
|
267
|
+
children: [renderRow({
|
|
268
|
+
inputProps: inlineInput,
|
|
269
|
+
inSheet: false
|
|
270
|
+
}), popoverOpen && jsx("div", {
|
|
271
|
+
id: resultsId,
|
|
272
|
+
role: "region",
|
|
273
|
+
"aria-label": resultsLabel,
|
|
274
|
+
className: RESULTS_POPOVER_CLASSES,
|
|
275
|
+
children: content
|
|
276
|
+
}), sheetMode && jsxs(Sheet, {
|
|
277
|
+
open: sheetOpen,
|
|
278
|
+
onClose: function onClose() {
|
|
279
|
+
return setOpen(false);
|
|
280
|
+
},
|
|
281
|
+
handle: false,
|
|
282
|
+
initialFocus: sheetInputRef,
|
|
283
|
+
"aria-label": resultsLabel,
|
|
284
|
+
className: "h-[calc(100dvh-env(safe-area-inset-top)-1rem)]",
|
|
285
|
+
"data-search-sheet": "",
|
|
286
|
+
children: [jsx("div", {
|
|
287
|
+
className: "flex shrink-0 items-center gap-2 border-b border-line px-4 py-3",
|
|
288
|
+
children: renderRow({
|
|
289
|
+
inSheet: true,
|
|
290
|
+
inputProps: jsx("input", _objectSpread2(_objectSpread2({
|
|
291
|
+
ref: sheetInputRef
|
|
292
|
+
}, sharedInputProps), {}, {
|
|
293
|
+
"aria-controls": resultsId,
|
|
294
|
+
onKeyDown: function onKeyDown(e) {
|
|
295
|
+
return handleKeyDown(e, true);
|
|
296
|
+
},
|
|
297
|
+
className: cn(INPUT_CLASSES, inputClassName)
|
|
298
|
+
}))
|
|
299
|
+
})
|
|
300
|
+
}), jsx(Sheet.Body, {
|
|
301
|
+
id: resultsId,
|
|
302
|
+
role: "region",
|
|
303
|
+
"aria-label": resultsLabel,
|
|
304
|
+
children: content
|
|
305
|
+
})]
|
|
306
|
+
})]
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
SearchField.displayName = "SearchField";
|
|
310
|
+
|
|
311
|
+
export { SearchField as default };
|
|
@@ -0,0 +1,189 @@
|
|
|
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, useRef, useState, useLayoutEffect, useEffect } from 'react';
|
|
5
|
+
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import { setRefs } from '../../utils/position.js';
|
|
7
|
+
import { useControllableState } from '../../hooks/useControllableState.js';
|
|
8
|
+
import { PRESS_FEEDBACK, TOUCH_TARGET } from '../../utils/touchTarget.js';
|
|
9
|
+
|
|
10
|
+
var _excluded = ["options", "value", "defaultValue", "onChange", "size", "fullWidth", "name", "disabled", "className"];
|
|
11
|
+
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
12
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
13
|
+
// Same padding / type scale as `Tabs` segments, so the two read as one control.
|
|
14
|
+
var SIZE_CLASSES = {
|
|
15
|
+
sm: "px-2 py-1 text-sm",
|
|
16
|
+
md: "px-3 py-2 text-sm",
|
|
17
|
+
lg: "px-4 py-3 text-base"
|
|
18
|
+
};
|
|
19
|
+
// PRESS_FEEDBACK sets transition-transform; this keeps the colour transition as well.
|
|
20
|
+
var TRANSITION_WITH_PRESS = "transition-[color,background-color,transform]";
|
|
21
|
+
var NEXT_KEYS = {
|
|
22
|
+
ArrowRight: 1,
|
|
23
|
+
ArrowDown: 1,
|
|
24
|
+
ArrowLeft: -1,
|
|
25
|
+
ArrowUp: -1
|
|
26
|
+
};
|
|
27
|
+
function isRtl(el) {
|
|
28
|
+
var dirEl = el.closest("[dir]");
|
|
29
|
+
if (dirEl) return dirEl.getAttribute("dir") === "rtl";
|
|
30
|
+
return typeof window !== "undefined" && window.getComputedStyle(el).direction === "rtl";
|
|
31
|
+
}
|
|
32
|
+
// Next enabled index from `from` in `step` direction, wrapping; -1 when none.
|
|
33
|
+
function findEnabled(options, from, step) {
|
|
34
|
+
var len = options.length;
|
|
35
|
+
for (var i = 1; i <= len; i += 1) {
|
|
36
|
+
var idx = ((from + step * i) % len + len) % len;
|
|
37
|
+
if (!options[idx].disabled) return idx;
|
|
38
|
+
}
|
|
39
|
+
return -1;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* SegmentedControl: a radiogroup view toggle (iOS segmented control).
|
|
43
|
+
* Use `Tabs variant="segmented"` instead when the choice switches panels.
|
|
44
|
+
*/
|
|
45
|
+
var SegmentedControl = /*#__PURE__*/forwardRef(function SegmentedControl(_ref, _ref2) {
|
|
46
|
+
var _ref$options = _ref.options,
|
|
47
|
+
options = _ref$options === void 0 ? [] : _ref$options,
|
|
48
|
+
valueProp = _ref.value,
|
|
49
|
+
defaultValue = _ref.defaultValue,
|
|
50
|
+
onChange = _ref.onChange,
|
|
51
|
+
_ref$size = _ref.size,
|
|
52
|
+
size = _ref$size === void 0 ? "md" : _ref$size,
|
|
53
|
+
_ref$fullWidth = _ref.fullWidth,
|
|
54
|
+
fullWidth = _ref$fullWidth === void 0 ? false : _ref$fullWidth,
|
|
55
|
+
name = _ref.name,
|
|
56
|
+
_ref$disabled = _ref.disabled,
|
|
57
|
+
disabled = _ref$disabled === void 0 ? false : _ref$disabled,
|
|
58
|
+
className = _ref.className,
|
|
59
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
60
|
+
var _useControllableState = useControllableState({
|
|
61
|
+
value: valueProp,
|
|
62
|
+
defaultValue: defaultValue,
|
|
63
|
+
onChange: onChange
|
|
64
|
+
}),
|
|
65
|
+
_useControllableState2 = _slicedToArray(_useControllableState, 2),
|
|
66
|
+
value = _useControllableState2[0],
|
|
67
|
+
setValue = _useControllableState2[1];
|
|
68
|
+
var rootRef = useRef(null);
|
|
69
|
+
var optionRefs = useRef([]);
|
|
70
|
+
var _useState = useState(null),
|
|
71
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
72
|
+
thumb = _useState2[0],
|
|
73
|
+
setThumb = _useState2[1];
|
|
74
|
+
var selectedIndex = options.findIndex(function (o) {
|
|
75
|
+
return o.value === value;
|
|
76
|
+
});
|
|
77
|
+
var firstEnabled = disabled ? -1 : findEnabled(options, -1, 1);
|
|
78
|
+
var selectedEnabled = selectedIndex >= 0 && !options[selectedIndex].disabled && !disabled;
|
|
79
|
+
var tabbableIndex = selectedEnabled ? selectedIndex : firstEnabled;
|
|
80
|
+
// Measure the selected option and move the thumb under it. Runs before paint,
|
|
81
|
+
// so the thumb never flashes; the CSS transition animates the slide.
|
|
82
|
+
useIsomorphicLayoutEffect(function () {
|
|
83
|
+
var root = rootRef.current;
|
|
84
|
+
var option = optionRefs.current[selectedIndex];
|
|
85
|
+
if (!root || !option) return undefined;
|
|
86
|
+
var measure = function measure() {
|
|
87
|
+
// jsdom / display:none report 0; the option keeps its own selected styling then.
|
|
88
|
+
if (!option.offsetWidth) return;
|
|
89
|
+
var next = {
|
|
90
|
+
left: option.offsetLeft,
|
|
91
|
+
top: option.offsetTop,
|
|
92
|
+
width: option.offsetWidth,
|
|
93
|
+
height: option.offsetHeight
|
|
94
|
+
};
|
|
95
|
+
setThumb(function (prev) {
|
|
96
|
+
return prev && prev.left === next.left && prev.top === next.top && prev.width === next.width && prev.height === next.height ? prev : next;
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
measure();
|
|
100
|
+
if (typeof ResizeObserver === "undefined") return undefined;
|
|
101
|
+
var ro = new ResizeObserver(measure);
|
|
102
|
+
ro.observe(root);
|
|
103
|
+
ro.observe(option);
|
|
104
|
+
return function () {
|
|
105
|
+
return ro.disconnect();
|
|
106
|
+
};
|
|
107
|
+
}, [selectedIndex, options.length, size, fullWidth]);
|
|
108
|
+
var showThumb = selectedIndex >= 0 && thumb !== null;
|
|
109
|
+
var select = function select(index) {
|
|
110
|
+
var option = options[index];
|
|
111
|
+
if (!option || option.disabled || disabled) return;
|
|
112
|
+
if (option.value !== value) setValue(option.value);
|
|
113
|
+
};
|
|
114
|
+
var _onKeyDown = function onKeyDown(event, index) {
|
|
115
|
+
var _optionRefs$current$t;
|
|
116
|
+
var key = event.key;
|
|
117
|
+
var target = -1;
|
|
118
|
+
if (key in NEXT_KEYS) {
|
|
119
|
+
var step = NEXT_KEYS[key];
|
|
120
|
+
// Horizontal arrows follow the reading direction.
|
|
121
|
+
if ((key === "ArrowLeft" || key === "ArrowRight") && isRtl(event.currentTarget)) step = -step;
|
|
122
|
+
target = findEnabled(options, index, step);
|
|
123
|
+
} else if (key === "Home") {
|
|
124
|
+
target = findEnabled(options, -1, 1);
|
|
125
|
+
} else if (key === "End") {
|
|
126
|
+
target = findEnabled(options, options.length, -1);
|
|
127
|
+
} else {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
if (target < 0) return;
|
|
132
|
+
(_optionRefs$current$t = optionRefs.current[target]) === null || _optionRefs$current$t === void 0 || _optionRefs$current$t.focus();
|
|
133
|
+
select(target);
|
|
134
|
+
};
|
|
135
|
+
return jsxs("div", _objectSpread2(_objectSpread2({
|
|
136
|
+
ref: function ref(node) {
|
|
137
|
+
return setRefs(node, rootRef, _ref2);
|
|
138
|
+
},
|
|
139
|
+
role: "radiogroup",
|
|
140
|
+
"aria-disabled": disabled || undefined,
|
|
141
|
+
className: cn("relative gap-1 rounded-lg bg-line p-1", fullWidth ? "flex w-full" : "inline-flex", disabled && "cursor-not-allowed opacity-50", className)
|
|
142
|
+
}, rest), {}, {
|
|
143
|
+
children: [showThumb && jsx("span", {
|
|
144
|
+
"aria-hidden": "true",
|
|
145
|
+
"data-segmented-thumb": "",
|
|
146
|
+
className: cn("pointer-events-none absolute left-0 top-0 rounded-md bg-surface shadow-sm", "transition-[transform,width,height] duration-base ease-standard motion-reduce:transition-none"),
|
|
147
|
+
style: {
|
|
148
|
+
width: thumb.width,
|
|
149
|
+
height: thumb.height,
|
|
150
|
+
transform: "translate(".concat(thumb.left, "px, ").concat(thumb.top, "px)")
|
|
151
|
+
}
|
|
152
|
+
}), options.map(function (option, index) {
|
|
153
|
+
var checked = index === selectedIndex;
|
|
154
|
+
var optionDisabled = disabled || Boolean(option.disabled);
|
|
155
|
+
return jsxs("button", {
|
|
156
|
+
ref: function ref(node) {
|
|
157
|
+
optionRefs.current[index] = node;
|
|
158
|
+
},
|
|
159
|
+
type: "button",
|
|
160
|
+
role: "radio",
|
|
161
|
+
"aria-checked": checked,
|
|
162
|
+
tabIndex: index === tabbableIndex ? 0 : -1,
|
|
163
|
+
disabled: optionDisabled,
|
|
164
|
+
"data-state": checked ? "checked" : "unchecked",
|
|
165
|
+
onClick: function onClick() {
|
|
166
|
+
return select(index);
|
|
167
|
+
},
|
|
168
|
+
onKeyDown: function onKeyDown(event) {
|
|
169
|
+
return _onKeyDown(event, index);
|
|
170
|
+
},
|
|
171
|
+
className: cn("relative z-10 inline-flex flex-1 items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium outline-none select-none", "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500", TOUCH_TARGET, PRESS_FEEDBACK, TRANSITION_WITH_PRESS, "motion-reduce:transition-none",
|
|
172
|
+
// A disabled group dims once at the root; a lone disabled option dims itself.
|
|
173
|
+
"disabled:cursor-not-allowed", option.disabled && !disabled && "opacity-50", SIZE_CLASSES[size] || SIZE_CLASSES.md, checked ? cn("text-foreground", !showThumb && "bg-surface shadow-sm") : "text-muted enabled:hover:text-foreground"),
|
|
174
|
+
children: [option.icon && jsx("span", {
|
|
175
|
+
"aria-hidden": "true",
|
|
176
|
+
className: "inline-flex shrink-0",
|
|
177
|
+
children: option.icon
|
|
178
|
+
}), option.label]
|
|
179
|
+
}, String(option.value));
|
|
180
|
+
}), name && jsx("input", {
|
|
181
|
+
type: "hidden",
|
|
182
|
+
name: name,
|
|
183
|
+
value: value !== null && value !== void 0 ? value : ""
|
|
184
|
+
})]
|
|
185
|
+
}));
|
|
186
|
+
});
|
|
187
|
+
SegmentedControl.displayName = "SegmentedControl";
|
|
188
|
+
|
|
189
|
+
export { SegmentedControl as default };
|