@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,177 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import { useRef, useState, useLayoutEffect, useCallback, useMemo, useEffect } from 'react';
|
|
5
|
+
import { cn } from '../../../utils/cn.js';
|
|
6
|
+
import { setRefs } from '../../../utils/position.js';
|
|
7
|
+
import Portal from '../../utility/Portal.js';
|
|
8
|
+
import { useFloatingPosition } from '../../../hooks/useFloatingPosition.js';
|
|
9
|
+
import { useFocusTrap } from '../../../hooks/useFocusTrap.js';
|
|
10
|
+
import { useClickOutside } from '../../../hooks/useClickOutside.js';
|
|
11
|
+
import { useLatestRef } from '../../../hooks/useLatestRef.js';
|
|
12
|
+
import { getMenuItems, handleMenuKeyDown } from './menuKeyboard.js';
|
|
13
|
+
import { isDestructive } from './menuItems.js';
|
|
14
|
+
|
|
15
|
+
// Internal (not exported). Desktop presentation of the action menu: a
|
|
16
|
+
// portaled, floating `role="menu"` anchored to its trigger (flip + shift via
|
|
17
|
+
// useFloatingPosition), with roving focus and Escape/outside-press dismissal.
|
|
18
|
+
var MENU_CLASSES = "z-popover min-w-[10rem] max-h-80 overflow-y-auto rounded-control border border-line bg-surface p-1 text-foreground shadow-overlay focus:outline-none transition-opacity duration-fast motion-reduce:transition-none";
|
|
19
|
+
var ITEM_CLASSES = "flex w-full items-center gap-3 rounded-md px-3 py-2 text-left text-sm outline-none transition-colors focus:bg-line/50 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500";
|
|
20
|
+
function itemToneClass(item) {
|
|
21
|
+
if (item.disabled) return "cursor-not-allowed opacity-50 text-muted";
|
|
22
|
+
if (isDestructive(item)) return "text-error-600 dark:text-error-400 hover:bg-error-50 dark:hover:bg-error-900/30";
|
|
23
|
+
return "text-foreground hover:bg-line/50";
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* @param {object} props
|
|
27
|
+
* @param {HTMLElement|null} props.anchorEl - the trigger the menu floats next to.
|
|
28
|
+
* @param {Array} props.items - normalized items (see menuItems.js).
|
|
29
|
+
* @param {(item: object) => void} props.onSelectItem
|
|
30
|
+
* @param {(reason: string) => void} props.onRequestClose - 'escape' | 'outside' | 'tab' | 'scroll'.
|
|
31
|
+
* @param {string} [props.placement='bottom-start']
|
|
32
|
+
* @param {'first'|'last'} [props.initialFocus='first']
|
|
33
|
+
* @param {boolean} [props.closeOnScroll=false] - close when a scroll happens outside the menu.
|
|
34
|
+
*/
|
|
35
|
+
function MenuPopover(_ref) {
|
|
36
|
+
var anchorEl = _ref.anchorEl,
|
|
37
|
+
items = _ref.items,
|
|
38
|
+
onSelectItem = _ref.onSelectItem,
|
|
39
|
+
onRequestClose = _ref.onRequestClose,
|
|
40
|
+
_ref$placement = _ref.placement,
|
|
41
|
+
placement = _ref$placement === void 0 ? "bottom-start" : _ref$placement,
|
|
42
|
+
_ref$initialFocus = _ref.initialFocus,
|
|
43
|
+
initialFocus = _ref$initialFocus === void 0 ? "first" : _ref$initialFocus,
|
|
44
|
+
_ref$closeOnScroll = _ref.closeOnScroll,
|
|
45
|
+
closeOnScroll = _ref$closeOnScroll === void 0 ? false : _ref$closeOnScroll,
|
|
46
|
+
menuRef = _ref.menuRef,
|
|
47
|
+
id = _ref.id,
|
|
48
|
+
label = _ref.label,
|
|
49
|
+
className = _ref.className,
|
|
50
|
+
itemClassName = _ref.itemClassName,
|
|
51
|
+
_ref$emptyLabel = _ref.emptyLabel,
|
|
52
|
+
emptyLabel = _ref$emptyLabel === void 0 ? "No actions" : _ref$emptyLabel;
|
|
53
|
+
var _useFloatingPosition = useFloatingPosition({
|
|
54
|
+
placement: placement,
|
|
55
|
+
open: true
|
|
56
|
+
}),
|
|
57
|
+
refs = _useFloatingPosition.refs,
|
|
58
|
+
floatingStyles = _useFloatingPosition.floatingStyles,
|
|
59
|
+
isPositioned = _useFloatingPosition.isPositioned;
|
|
60
|
+
var elRef = useRef(null);
|
|
61
|
+
// The menu node once the Portal has rendered it; focus management waits.
|
|
62
|
+
var _useState = useState(null),
|
|
63
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
64
|
+
menuEl = _useState2[0],
|
|
65
|
+
setMenuEl = _useState2[1];
|
|
66
|
+
var closeRef = useLatestRef(onRequestClose);
|
|
67
|
+
useLayoutEffect(function () {
|
|
68
|
+
refs.setReference(anchorEl !== null && anchorEl !== void 0 ? anchorEl : null);
|
|
69
|
+
}, [refs, anchorEl]);
|
|
70
|
+
var setMenuNode = useCallback(function (node) {
|
|
71
|
+
return setRefs(node, elRef, refs.setFloating, menuRef, setMenuEl);
|
|
72
|
+
}, [refs, menuRef]);
|
|
73
|
+
var focusTarget = useMemo(function () {
|
|
74
|
+
return {
|
|
75
|
+
get current() {
|
|
76
|
+
var _ref2;
|
|
77
|
+
var list = getMenuItems(menuEl);
|
|
78
|
+
return (_ref2 = initialFocus === "last" ? list[list.length - 1] : list[0]) !== null && _ref2 !== void 0 ? _ref2 : menuEl;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}, [menuEl, initialFocus]);
|
|
82
|
+
useFocusTrap(elRef, {
|
|
83
|
+
active: menuEl != null,
|
|
84
|
+
trap: false,
|
|
85
|
+
initialFocusRef: focusTarget,
|
|
86
|
+
onEscape: function onEscape(e) {
|
|
87
|
+
var _e$preventDefault, _closeRef$current;
|
|
88
|
+
e === null || e === void 0 || (_e$preventDefault = e.preventDefault) === null || _e$preventDefault === void 0 || _e$preventDefault.call(e);
|
|
89
|
+
(_closeRef$current = closeRef.current) === null || _closeRef$current === void 0 || _closeRef$current.call(closeRef, "escape");
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
var anchorRef = useMemo(function () {
|
|
93
|
+
return {
|
|
94
|
+
current: anchorEl
|
|
95
|
+
};
|
|
96
|
+
}, [anchorEl]);
|
|
97
|
+
useClickOutside([elRef, anchorRef], function () {
|
|
98
|
+
var _closeRef$current2;
|
|
99
|
+
return (_closeRef$current2 = closeRef.current) === null || _closeRef$current2 === void 0 ? void 0 : _closeRef$current2.call(closeRef, "outside");
|
|
100
|
+
});
|
|
101
|
+
useEffect(function () {
|
|
102
|
+
if (!closeOnScroll) return undefined;
|
|
103
|
+
var onScroll = function onScroll(e) {
|
|
104
|
+
var _closeRef$current3;
|
|
105
|
+
var node = elRef.current;
|
|
106
|
+
if (node && e.target instanceof Node && node.contains(e.target)) return;
|
|
107
|
+
(_closeRef$current3 = closeRef.current) === null || _closeRef$current3 === void 0 || _closeRef$current3.call(closeRef, "scroll");
|
|
108
|
+
};
|
|
109
|
+
window.addEventListener("scroll", onScroll, true);
|
|
110
|
+
return function () {
|
|
111
|
+
return window.removeEventListener("scroll", onScroll, true);
|
|
112
|
+
};
|
|
113
|
+
}, [closeOnScroll, closeRef]);
|
|
114
|
+
var hasItems = items.length > 0;
|
|
115
|
+
return jsx(Portal, {
|
|
116
|
+
children: jsx("div", {
|
|
117
|
+
ref: setMenuNode,
|
|
118
|
+
id: id,
|
|
119
|
+
role: "menu",
|
|
120
|
+
"aria-orientation": "vertical",
|
|
121
|
+
"aria-label": label,
|
|
122
|
+
tabIndex: -1,
|
|
123
|
+
"data-presentation": "popover",
|
|
124
|
+
className: cn(MENU_CLASSES, className),
|
|
125
|
+
style: _objectSpread2(_objectSpread2({}, floatingStyles), {}, {
|
|
126
|
+
opacity: isPositioned ? 1 : 0
|
|
127
|
+
}),
|
|
128
|
+
onKeyDown: function onKeyDown(e) {
|
|
129
|
+
return handleMenuKeyDown(e, elRef.current, {
|
|
130
|
+
onTab: function onTab() {
|
|
131
|
+
var _closeRef$current4;
|
|
132
|
+
return (_closeRef$current4 = closeRef.current) === null || _closeRef$current4 === void 0 ? void 0 : _closeRef$current4.call(closeRef, "tab");
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
onClick: function onClick(e) {
|
|
137
|
+
return e.stopPropagation();
|
|
138
|
+
},
|
|
139
|
+
children: !hasItems ? jsx("div", {
|
|
140
|
+
className: "px-3 py-2 text-sm italic text-muted",
|
|
141
|
+
children: emptyLabel
|
|
142
|
+
}) : items.map(function (item, idx) {
|
|
143
|
+
var _item$content, _item$key;
|
|
144
|
+
return jsx("button", {
|
|
145
|
+
type: "button",
|
|
146
|
+
role: "menuitem",
|
|
147
|
+
tabIndex: -1,
|
|
148
|
+
disabled: item.disabled || undefined,
|
|
149
|
+
"aria-disabled": item.disabled || undefined,
|
|
150
|
+
"data-tone": isDestructive(item) ? "destructive" : undefined,
|
|
151
|
+
className: cn(ITEM_CLASSES, itemToneClass(item), itemClassName, !item.disabled && item.className),
|
|
152
|
+
onMouseEnter: function onMouseEnter(e) {
|
|
153
|
+
if (!item.disabled) e.currentTarget.focus({
|
|
154
|
+
preventScroll: true
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
onClick: function onClick(e) {
|
|
158
|
+
e.stopPropagation();
|
|
159
|
+
if (!item.disabled) onSelectItem(item);
|
|
160
|
+
},
|
|
161
|
+
children: (_item$content = item.content) !== null && _item$content !== void 0 ? _item$content : jsxs(Fragment, {
|
|
162
|
+
children: [item.icon != null && jsx("span", {
|
|
163
|
+
className: "inline-flex shrink-0",
|
|
164
|
+
"aria-hidden": "true",
|
|
165
|
+
children: item.icon
|
|
166
|
+
}), jsx("span", {
|
|
167
|
+
className: "min-w-0 flex-1 truncate",
|
|
168
|
+
children: item.label
|
|
169
|
+
})]
|
|
170
|
+
})
|
|
171
|
+
}, (_item$key = item.key) !== null && _item$key !== void 0 ? _item$key : "item-".concat(idx));
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export { MenuPopover as default, itemToneClass };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { typeof as _typeof } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
|
|
6
|
+
// Internal (not exported). Shared helpers for the action-menu primitive used
|
|
7
|
+
// by ThreeDotPopover and Table's row ActionMenu (DTUI-36).
|
|
8
|
+
//
|
|
9
|
+
// A normalized menu item looks like:
|
|
10
|
+
// {
|
|
11
|
+
// key: string | number, // React key
|
|
12
|
+
// label: ReactNode, // visible text (also used for typeahead)
|
|
13
|
+
// icon?: ReactNode, // rendered before the label
|
|
14
|
+
// content?: ReactNode, // replaces icon + label entirely
|
|
15
|
+
// disabled?: boolean,
|
|
16
|
+
// tone?: 'default' | 'destructive',
|
|
17
|
+
// destructive?: boolean, // legacy alias for tone: 'destructive'
|
|
18
|
+
// className?: string, // popover-mode-only extra item classes
|
|
19
|
+
// onSelect?: () => void,
|
|
20
|
+
// }
|
|
21
|
+
/** True when an item should render in the error (destructive) tone. */
|
|
22
|
+
var isDestructive = function isDestructive(item) {
|
|
23
|
+
return Boolean(item) && (item.tone === "destructive" || item.destructive === true);
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Renders an icon given either a component type (`Edit2`) or a ready node
|
|
27
|
+
* (`<Edit2 />`). Returns null for anything else.
|
|
28
|
+
*/
|
|
29
|
+
function renderIcon(icon, className) {
|
|
30
|
+
if (icon == null || icon === false) return null;
|
|
31
|
+
if (/*#__PURE__*/React.isValidElement(icon)) return icon;
|
|
32
|
+
var isComponent = typeof icon === "function" || _typeof(icon) === "object" && icon.$$typeof != null;
|
|
33
|
+
if (isComponent) {
|
|
34
|
+
var Icon = icon;
|
|
35
|
+
return jsx(Icon, {
|
|
36
|
+
className: className,
|
|
37
|
+
"aria-hidden": "true"
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return icon;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Normalizes a public ActionSheet action
|
|
44
|
+
* ({ key?, label, icon?, tone?, onSelect?, disabled? }) into a menu item.
|
|
45
|
+
* `icon` may be a node or a component type.
|
|
46
|
+
*/
|
|
47
|
+
function normalizeAction(action, idx) {
|
|
48
|
+
var _a$key;
|
|
49
|
+
var a = action || {};
|
|
50
|
+
return {
|
|
51
|
+
key: (_a$key = a.key) !== null && _a$key !== void 0 ? _a$key : "action-".concat(idx),
|
|
52
|
+
label: a.label,
|
|
53
|
+
icon: renderIcon(a.icon, "h-5 w-5"),
|
|
54
|
+
disabled: Boolean(a.disabled),
|
|
55
|
+
tone: a.tone,
|
|
56
|
+
destructive: a.destructive,
|
|
57
|
+
onSelect: a.onSelect
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { isDestructive, normalizeAction, renderIcon };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Internal (not exported). Roving focus for a `role="menu"` element: the
|
|
2
|
+
// menu's items all carry tabIndex=-1 and focus moves between them with the
|
|
3
|
+
// keyboard (WAI-ARIA menu pattern).
|
|
4
|
+
var ITEM_SELECTOR = '[role="menuitem"]:not([disabled]):not([aria-disabled="true"])';
|
|
5
|
+
/** The enabled menu items inside `menuEl`, in DOM order. */
|
|
6
|
+
var getMenuItems = function getMenuItems(menuEl) {
|
|
7
|
+
return menuEl ? Array.from(menuEl.querySelectorAll(ITEM_SELECTOR)) : [];
|
|
8
|
+
};
|
|
9
|
+
var focusItem = function focusItem(el) {
|
|
10
|
+
var _el$focus;
|
|
11
|
+
return el === null || el === void 0 || (_el$focus = el.focus) === null || _el$focus === void 0 ? void 0 : _el$focus.call(el, {
|
|
12
|
+
preventScroll: true
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
var isTypeaheadKey = function isTypeaheadKey(e) {
|
|
16
|
+
return e.key.length === 1 && /\S/.test(e.key) && !e.ctrlKey && !e.metaKey && !e.altKey;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Keydown handler for the menu element. ArrowDown/ArrowUp move (and wrap),
|
|
20
|
+
* Home/End jump, a printable character jumps to the next item starting with
|
|
21
|
+
* it, Tab calls `onTab`. Escape is handled by the caller's focus layer.
|
|
22
|
+
*
|
|
23
|
+
* @param {KeyboardEvent} e
|
|
24
|
+
* @param {HTMLElement} menuEl
|
|
25
|
+
* @param {{ onTab?: () => void }} [options]
|
|
26
|
+
*/
|
|
27
|
+
function handleMenuKeyDown(e, menuEl) {
|
|
28
|
+
var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
|
|
29
|
+
onTab = _ref.onTab;
|
|
30
|
+
if (e.key === "Tab") {
|
|
31
|
+
onTab === null || onTab === void 0 || onTab();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
var items = getMenuItems(menuEl);
|
|
35
|
+
if (items.length === 0) return;
|
|
36
|
+
var current = items.indexOf(document.activeElement);
|
|
37
|
+
var last = items.length - 1;
|
|
38
|
+
var next;
|
|
39
|
+
if (e.key === "ArrowDown") next = current < 0 || current === last ? 0 : current + 1;else if (e.key === "ArrowUp") next = current <= 0 ? last : current - 1;else if (e.key === "Home") next = 0;else if (e.key === "End") next = last;else if (isTypeaheadKey(e)) {
|
|
40
|
+
var key = e.key.toLowerCase();
|
|
41
|
+
for (var step = 1; step <= items.length; step += 1) {
|
|
42
|
+
var i = (current + step + items.length) % items.length;
|
|
43
|
+
if ((items[i].textContent || "").trim().toLowerCase().startsWith(key)) {
|
|
44
|
+
next = i;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (next === undefined) return;
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
focusItem(items[next]);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { getMenuItems, handleMenuKeyDown };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import ActionSheetMenu from '../core/menu/ActionSheetMenu.js';
|
|
7
|
+
import { normalizeAction } from '../core/menu/menuItems.js';
|
|
8
|
+
|
|
9
|
+
var _excluded = ["open", "isOpen", "onClose", "title", "message", "actions", "cancelLabel", "className", "aria-label"];
|
|
10
|
+
// iOS UIAlertController-style action sheet on the bottom Sheet: an optional
|
|
11
|
+
// title + message, a card of actions (destructive ones in the error tone) and
|
|
12
|
+
// a separate Cancel. The same implementation (ActionSheetMenu) renders the
|
|
13
|
+
// phone presentation of ThreeDotPopover and Table's row menu.
|
|
14
|
+
//
|
|
15
|
+
// Selecting an action calls its `onSelect`, then `onClose('select')`. Focus
|
|
16
|
+
// returns to the element that was focused before the sheet opened (the
|
|
17
|
+
// Sheet's focus trap restores it).
|
|
18
|
+
var ActionSheet = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
19
|
+
var open = _ref.open,
|
|
20
|
+
isOpen = _ref.isOpen,
|
|
21
|
+
_onClose = _ref.onClose,
|
|
22
|
+
title = _ref.title,
|
|
23
|
+
message = _ref.message,
|
|
24
|
+
_ref$actions = _ref.actions,
|
|
25
|
+
actions = _ref$actions === void 0 ? [] : _ref$actions,
|
|
26
|
+
_ref$cancelLabel = _ref.cancelLabel,
|
|
27
|
+
cancelLabel = _ref$cancelLabel === void 0 ? "Cancel" : _ref$cancelLabel,
|
|
28
|
+
className = _ref.className,
|
|
29
|
+
ariaLabel = _ref["aria-label"],
|
|
30
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
31
|
+
var items = (Array.isArray(actions) ? actions : []).filter(Boolean).map(normalizeAction);
|
|
32
|
+
var selectItem = function selectItem(item) {
|
|
33
|
+
var _item$onSelect;
|
|
34
|
+
if (item.disabled) return;
|
|
35
|
+
(_item$onSelect = item.onSelect) === null || _item$onSelect === void 0 || _item$onSelect.call(item);
|
|
36
|
+
_onClose === null || _onClose === void 0 || _onClose("select");
|
|
37
|
+
};
|
|
38
|
+
return jsx(ActionSheetMenu, _objectSpread2({
|
|
39
|
+
ref: ref,
|
|
40
|
+
open: Boolean(open !== null && open !== void 0 ? open : isOpen),
|
|
41
|
+
onClose: function onClose(reason) {
|
|
42
|
+
return _onClose === null || _onClose === void 0 ? void 0 : _onClose(reason);
|
|
43
|
+
},
|
|
44
|
+
groups: [items],
|
|
45
|
+
onSelectItem: selectItem,
|
|
46
|
+
title: title,
|
|
47
|
+
message: message,
|
|
48
|
+
label: ariaLabel,
|
|
49
|
+
cancelLabel: cancelLabel,
|
|
50
|
+
className: cn(className)
|
|
51
|
+
}, rest));
|
|
52
|
+
});
|
|
53
|
+
ActionSheet.displayName = "ActionSheet";
|
|
54
|
+
|
|
55
|
+
export { ActionSheet as default };
|
|
@@ -6,92 +6,102 @@ import { cn } from '../../utils/cn.js';
|
|
|
6
6
|
import { Info, AlertTriangle, AlertCircle, CheckCircle, X } from 'lucide-react';
|
|
7
7
|
import { TOUCH_TARGET } from '../../utils/touchTarget.js';
|
|
8
8
|
|
|
9
|
-
var _excluded = ["variant", "title", "children", "dismissible", "onDismiss", "className"];
|
|
9
|
+
var _excluded = ["variant", "title", "children", "actions", "dismissible", "onDismiss", "dismissLabel", "className"];
|
|
10
10
|
// error / warning need attention now (role="alert", assertive); info / success
|
|
11
|
-
//
|
|
11
|
+
// / neutral must not interrupt (role="status", polite).
|
|
12
12
|
var URGENT_VARIANTS = new Set(['error', 'warning']);
|
|
13
|
+
var VARIANTS = {
|
|
14
|
+
success: {
|
|
15
|
+
container: 'bg-success-50 border-success-200 dark:bg-success-950/40 dark:border-success-800',
|
|
16
|
+
Icon: CheckCircle,
|
|
17
|
+
icon: 'text-success-500 dark:text-success-400',
|
|
18
|
+
title: 'text-success-800 dark:text-success-200',
|
|
19
|
+
content: 'text-success-700 dark:text-success-300',
|
|
20
|
+
dismiss: 'text-success-500 hover:bg-success-100 focus-visible:ring-success-600 dark:text-success-400 dark:hover:bg-success-900/50'
|
|
21
|
+
},
|
|
22
|
+
error: {
|
|
23
|
+
container: 'bg-error-50 border-error-200 dark:bg-error-950/40 dark:border-error-800',
|
|
24
|
+
Icon: AlertCircle,
|
|
25
|
+
icon: 'text-error-500 dark:text-error-400',
|
|
26
|
+
title: 'text-error-800 dark:text-error-200',
|
|
27
|
+
content: 'text-error-700 dark:text-error-300',
|
|
28
|
+
dismiss: 'text-error-500 hover:bg-error-100 focus-visible:ring-error-600 dark:text-error-400 dark:hover:bg-error-900/50'
|
|
29
|
+
},
|
|
30
|
+
warning: {
|
|
31
|
+
container: 'bg-warning-50 border-warning-200 dark:bg-warning-950/40 dark:border-warning-800',
|
|
32
|
+
Icon: AlertTriangle,
|
|
33
|
+
icon: 'text-warning-500 dark:text-warning-400',
|
|
34
|
+
title: 'text-warning-800 dark:text-warning-200',
|
|
35
|
+
content: 'text-warning-700 dark:text-warning-300',
|
|
36
|
+
dismiss: 'text-warning-500 hover:bg-warning-100 focus-visible:ring-warning-600 dark:text-warning-400 dark:hover:bg-warning-900/50'
|
|
37
|
+
},
|
|
38
|
+
info: {
|
|
39
|
+
container: 'bg-primary-50 border-primary-200 dark:bg-primary-950/40 dark:border-primary-800',
|
|
40
|
+
Icon: Info,
|
|
41
|
+
icon: 'text-primary-500 dark:text-primary-400',
|
|
42
|
+
title: 'text-primary-800 dark:text-primary-200',
|
|
43
|
+
content: 'text-primary-700 dark:text-primary-300',
|
|
44
|
+
dismiss: 'text-primary-500 hover:bg-primary-100 focus-visible:ring-primary-600 dark:text-primary-400 dark:hover:bg-primary-900/50'
|
|
45
|
+
},
|
|
46
|
+
neutral: {
|
|
47
|
+
container: 'bg-surface border-line dark:bg-surface dark:border-line',
|
|
48
|
+
Icon: Info,
|
|
49
|
+
icon: 'text-muted dark:text-muted',
|
|
50
|
+
title: 'text-foreground dark:text-foreground',
|
|
51
|
+
content: 'text-muted dark:text-muted',
|
|
52
|
+
dismiss: 'text-muted hover:bg-line/50 focus-visible:ring-primary-500 dark:text-muted dark:hover:bg-line/50'
|
|
53
|
+
}
|
|
54
|
+
};
|
|
13
55
|
var Alert = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
14
56
|
var _ref$variant = _ref.variant,
|
|
15
57
|
variant = _ref$variant === void 0 ? 'info' : _ref$variant,
|
|
16
58
|
title = _ref.title,
|
|
17
59
|
children = _ref.children,
|
|
60
|
+
actions = _ref.actions,
|
|
18
61
|
_ref$dismissible = _ref.dismissible,
|
|
19
62
|
dismissible = _ref$dismissible === void 0 ? false : _ref$dismissible,
|
|
20
63
|
onDismiss = _ref.onDismiss,
|
|
64
|
+
_ref$dismissLabel = _ref.dismissLabel,
|
|
65
|
+
dismissLabel = _ref$dismissLabel === void 0 ? 'Dismiss' : _ref$dismissLabel,
|
|
21
66
|
className = _ref.className,
|
|
22
67
|
props = _objectWithoutProperties(_ref, _excluded);
|
|
23
|
-
var
|
|
24
|
-
|
|
25
|
-
container: 'bg-success-50 border-success-200',
|
|
26
|
-
icon: jsx(CheckCircle, {
|
|
27
|
-
className: "h-5 w-5 text-success-500",
|
|
28
|
-
"aria-hidden": "true"
|
|
29
|
-
}),
|
|
30
|
-
title: 'text-success-800',
|
|
31
|
-
content: 'text-success-700'
|
|
32
|
-
},
|
|
33
|
-
error: {
|
|
34
|
-
container: 'bg-error-50 border-error-200',
|
|
35
|
-
icon: jsx(AlertCircle, {
|
|
36
|
-
className: "h-5 w-5 text-error-500",
|
|
37
|
-
"aria-hidden": "true"
|
|
38
|
-
}),
|
|
39
|
-
title: 'text-error-800',
|
|
40
|
-
content: 'text-error-700'
|
|
41
|
-
},
|
|
42
|
-
warning: {
|
|
43
|
-
container: 'bg-warning-50 border-warning-200',
|
|
44
|
-
icon: jsx(AlertTriangle, {
|
|
45
|
-
className: "h-5 w-5 text-warning-500",
|
|
46
|
-
"aria-hidden": "true"
|
|
47
|
-
}),
|
|
48
|
-
title: 'text-warning-800',
|
|
49
|
-
content: 'text-warning-700'
|
|
50
|
-
},
|
|
51
|
-
info: {
|
|
52
|
-
container: 'bg-primary-50 border-primary-200',
|
|
53
|
-
icon: jsx(Info, {
|
|
54
|
-
className: "h-5 w-5 text-primary-500",
|
|
55
|
-
"aria-hidden": "true"
|
|
56
|
-
}),
|
|
57
|
-
title: 'text-primary-800',
|
|
58
|
-
content: 'text-primary-700'
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
var variantStyles = variants[variant];
|
|
68
|
+
var styles = VARIANTS[variant] || VARIANTS.info;
|
|
69
|
+
var Icon = styles.Icon;
|
|
62
70
|
return jsx("div", _objectSpread2(_objectSpread2({
|
|
63
71
|
ref: ref,
|
|
64
|
-
className: cn('rounded-md border p-4',
|
|
72
|
+
className: cn('rounded-md border p-4 animate-fade-in motion-reduce:animate-none', styles.container, className),
|
|
65
73
|
role: URGENT_VARIANTS.has(variant) ? 'alert' : 'status'
|
|
66
74
|
}, props), {}, {
|
|
67
75
|
children: jsxs("div", {
|
|
68
76
|
className: "flex",
|
|
69
77
|
children: [jsx("div", {
|
|
70
78
|
className: "flex-shrink-0",
|
|
71
|
-
children:
|
|
79
|
+
children: jsx(Icon, {
|
|
80
|
+
className: cn('h-5 w-5', styles.icon),
|
|
81
|
+
"aria-hidden": "true"
|
|
82
|
+
})
|
|
72
83
|
}), jsxs("div", {
|
|
73
|
-
className: "ml-3 flex-1",
|
|
84
|
+
className: "ml-3 flex-1 min-w-0",
|
|
74
85
|
children: [title && jsx("h3", {
|
|
75
|
-
className: cn('text-sm font-medium',
|
|
86
|
+
className: cn('text-sm font-medium', styles.title),
|
|
76
87
|
children: title
|
|
77
88
|
}), jsx("div", {
|
|
78
|
-
className: cn('text-sm',
|
|
89
|
+
className: cn('text-sm', styles.content, {
|
|
79
90
|
'mt-1': title
|
|
80
91
|
}),
|
|
81
92
|
children: children
|
|
93
|
+
}), actions != null && actions !== false && jsx("div", {
|
|
94
|
+
"data-slot": "actions",
|
|
95
|
+
className: "mt-3 flex flex-wrap items-center gap-2",
|
|
96
|
+
children: actions
|
|
82
97
|
})]
|
|
83
98
|
}), dismissible && jsx("div", {
|
|
84
99
|
className: "ml-auto pl-3",
|
|
85
100
|
children: jsx("button", {
|
|
86
101
|
type: "button",
|
|
87
|
-
className: cn('inline-flex items-center justify-center rounded-md p-1.5 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2', TOUCH_TARGET,
|
|
88
|
-
'text-success-500 hover:bg-success-100 focus-visible:ring-success-600': variant === 'success',
|
|
89
|
-
'text-error-500 hover:bg-error-100 focus-visible:ring-error-600': variant === 'error',
|
|
90
|
-
'text-warning-500 hover:bg-warning-100 focus-visible:ring-warning-600': variant === 'warning',
|
|
91
|
-
'text-primary-500 hover:bg-primary-100 focus-visible:ring-primary-600': variant === 'info'
|
|
92
|
-
}),
|
|
102
|
+
className: cn('inline-flex items-center justify-center rounded-md p-1.5 transition-colors motion-reduce:transition-none focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-background', TOUCH_TARGET, styles.dismiss),
|
|
93
103
|
onClick: onDismiss,
|
|
94
|
-
"aria-label":
|
|
104
|
+
"aria-label": dismissLabel,
|
|
95
105
|
children: jsx(X, {
|
|
96
106
|
className: "h-4 w-4",
|
|
97
107
|
"aria-hidden": "true"
|