@godxjp/ui 22.0.0 → 23.1.0
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 +4 -4
- package/dist/app/date-format-labels.d.ts +14 -2
- package/dist/app/date-format-labels.js +1 -1
- package/dist/app/date-formats.d.ts +14 -2
- package/dist/app/date-formats.js +9 -2
- package/dist/components/data-display/data-table.d.ts +8 -1
- package/dist/components/data-display/data-table.js +9 -2
- package/dist/components/data-display/scroll-area.d.ts +24 -4
- package/dist/components/data-display/scroll-area.js +34 -72
- package/dist/components/data-entry/cascader.js +8 -6
- package/dist/components/data-entry/checkbox.js +3 -1
- package/dist/components/data-entry/choice-hit-target.d.ts +24 -0
- package/dist/components/data-entry/choice-hit-target.js +12 -0
- package/dist/components/data-entry/control-surface.d.ts +8 -0
- package/dist/components/data-entry/control-surface.js +10 -1
- package/dist/components/data-entry/form-field.js +5 -4
- package/dist/components/data-entry/input.js +1 -1
- package/dist/components/data-entry/number-input.js +27 -6
- package/dist/components/data-entry/radio.js +4 -3
- package/dist/components/data-entry/search-select.js +225 -95
- package/dist/components/data-entry/select.d.ts +76 -14
- package/dist/components/data-entry/select.js +495 -163
- package/dist/components/data-entry/slider.d.ts +3 -11
- package/dist/components/data-entry/slider.js +582 -93
- package/dist/components/data-entry/switch.js +3 -1
- package/dist/components/feedback/dialog.js +2 -2
- package/dist/components/feedback/sheet.js +2 -22
- package/dist/components/navigation/dropdown-menu.d.ts +11 -3
- package/dist/components/navigation/dropdown-menu.js +190 -15
- package/dist/components/navigation/filter-bar.js +2 -1
- package/dist/components/navigation/index.d.ts +0 -3
- package/dist/components/navigation/index.js +0 -78
- package/dist/components/navigation/tabs.js +16 -4
- package/dist/components/ui/index.d.ts +0 -3
- package/dist/components/ui/index.js +0 -3
- package/dist/components/ui/input-otp.d.ts +1 -1
- package/dist/components/ui/segmented.js +3 -1
- package/dist/components/ui/tag-input.js +3 -5
- package/dist/i18n/messages/en.json +5 -1
- package/dist/i18n/messages/ja.json +5 -1
- package/dist/i18n/messages/vi.json +5 -1
- package/dist/lib/breakpoint-token.d.ts +8 -0
- package/dist/lib/breakpoint-token.js +29 -0
- package/dist/lib/select-options.d.ts +21 -0
- package/dist/lib/select-options.js +46 -0
- package/dist/props/components/data-display.prop.d.ts +17 -7
- package/dist/props/components/data-entry.prop.d.ts +323 -30
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/navigation.prop.d.ts +25 -1
- package/dist/props/registry.d.ts +69 -1
- package/dist/props/registry.js +75 -0
- package/dist/props/vocabulary/data.prop.d.ts +5 -0
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/styles/control.css +246 -28
- package/dist/styles/data-display-layout.css +18 -10
- package/dist/styles/focus-ring.css +28 -0
- package/dist/styles/fonts.css +88 -4
- package/dist/styles/form-layout.css +4 -0
- package/dist/styles/layout.css +2 -1
- package/dist/styles/navigation-layout.css +24 -238
- package/dist/styles/shell-layout.css +148 -139
- package/dist/styles/table-layout.css +12 -5
- package/dist/tokens/components/control.css +12 -3
- package/dist/tokens/components/data-display.css +0 -5
- package/dist/tokens/components/navigation.css +5 -5
- package/dist/tokens/components/scroll-area.css +7 -0
- package/docs/CONSUMER-RULES.md +7 -2
- package/docs/CUSTOMER-THEMING.md +25 -9
- package/docs/DATETIME.md +11 -2
- package/docs/FRAME-COVERAGE-REPORT.md +4 -7
- package/docs/SPACING.md +35 -5
- package/docs/TOKENS.md +1 -1
- package/docs/data-display/data-table/index.tsx +44 -3
- package/docs/data-display/popover.tsx +4 -6
- package/docs/data-display/scroll-area.tsx +51 -45
- package/docs/data-display/table.tsx +1 -1
- package/docs/data-entry/date-picker.tsx +2 -3
- package/docs/data-entry/input-otp.tsx +5 -2
- package/docs/data-entry/segmented-in-filter-row.tsx +77 -0
- package/docs/data-entry/segmented.tsx +40 -1
- package/docs/data-entry/select-matrix.tsx +1 -2
- package/docs/data-entry/select.tsx +108 -3
- package/docs/data-entry/slider.tsx +125 -47
- package/docs/feedback/dialog.tsx +1 -2
- package/docs/feedback/sheet.tsx +1 -2
- package/docs/layout/app-shell-states.tsx +143 -0
- package/docs/navigation/dropdown-menu.tsx +77 -6
- package/docs/navigation/tabs.tsx +72 -0
- package/docs/roadmap/ai-chat-components.md +1 -2
- package/docs/roadmap/parity-audit-data-entry.md +44 -33
- package/docs/roadmap/parity-audit-layout-navigation-general.md +304 -310
- package/docs/roadmap/parity-backlog.md +2 -3
- package/docs/roadmap/tree-components.md +0 -1
- package/package.json +25 -55
- package/scripts/_agent-setup.mjs +18 -0
- package/scripts/guinea-pig-skill.md +12 -6
- package/scripts/ui-audit.mjs +185 -7
- package/scripts/visual-audit-rules.mjs +0 -7
- package/scripts/visual-audit.mjs +6 -27
- package/dist/components/navigation/context-menu.d.ts +0 -21
- package/dist/components/navigation/context-menu.js +0 -149
- package/dist/components/navigation/menubar.d.ts +0 -28
- package/dist/components/navigation/menubar.js +0 -136
- package/dist/components/navigation/navigation-menu.d.ts +0 -10
- package/dist/components/navigation/navigation-menu.js +0 -91
- package/dist/components/ui/context-menu.d.ts +0 -1
- package/dist/components/ui/context-menu.js +0 -2
- package/dist/components/ui/menubar.d.ts +0 -1
- package/dist/components/ui/menubar.js +0 -2
- package/dist/components/ui/navigation-menu.d.ts +0 -1
- package/dist/components/ui/navigation-menu.js +0 -2
- package/docs/FRAME-A11Y-CI.md +0 -349
- package/docs/navigation/context-menu.tsx +0 -128
- package/docs/navigation/menubar.tsx +0 -141
- package/docs/navigation/navigation-menu.tsx +0 -158
|
@@ -5,6 +5,7 @@ import { Switch as AriaSwitch } from "react-aria-components";
|
|
|
5
5
|
import { Loader2 } from "lucide-react";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
7
|
import { useFieldIdentity, useMirroredInputAttributes } from "../../lib/field-a11y.js";
|
|
8
|
+
import { withOwnHitTarget } from "./choice-hit-target.js";
|
|
8
9
|
const Switch = React.forwardRef(
|
|
9
10
|
({
|
|
10
11
|
className,
|
|
@@ -72,13 +73,14 @@ const Switch = React.forwardRef(
|
|
|
72
73
|
event.preventDefault();
|
|
73
74
|
handleCheckedChange(!isChecked);
|
|
74
75
|
},
|
|
76
|
+
render: (domProps) => /* @__PURE__ */ jsx("label", { ...domProps, children: withOwnHitTarget(domProps.children) }),
|
|
75
77
|
className: cn(
|
|
76
78
|
// `.ui-switch:disabled, .ui-switch[data-disabled]` in styles/control.css already
|
|
77
79
|
// declares both and reads --disabled-opacity. The utility was layered after
|
|
78
80
|
// components, so it silently outranked that token. Byte-identical: the token
|
|
79
81
|
// defaults to 0.5. (`shadow-xs` STAYS — .ui-switch declares --shadow-sm, so this
|
|
80
82
|
// utility is the switch's real resting elevation, not a duplicate.)
|
|
81
|
-
"peer ui-switch shadow-xs transition-all
|
|
83
|
+
"peer ui-switch shadow-xs transition-all",
|
|
82
84
|
className
|
|
83
85
|
),
|
|
84
86
|
children: [
|
|
@@ -149,7 +149,7 @@ function DialogContent({
|
|
|
149
149
|
showCloseButton ? /* @__PURE__ */ jsxs(
|
|
150
150
|
DialogClose,
|
|
151
151
|
{
|
|
152
|
-
className: "ui-focus-ring transition-opacity
|
|
152
|
+
className: "ui-focus-ring transition-opacity disabled:pointer-events-none",
|
|
153
153
|
children: [
|
|
154
154
|
/* @__PURE__ */ jsx(X, { className: "ui-dialog-close-icon", "aria-hidden": "true" }),
|
|
155
155
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: t("feedback.alert.dismiss") })
|
|
@@ -265,7 +265,7 @@ function AlertDialogContent({
|
|
|
265
265
|
{
|
|
266
266
|
type: "button",
|
|
267
267
|
"data-slot": "dialog-close",
|
|
268
|
-
className: "ui-focus-ring transition-opacity
|
|
268
|
+
className: "ui-focus-ring transition-opacity disabled:pointer-events-none",
|
|
269
269
|
"aria-label": t("feedback.alert.dismiss"),
|
|
270
270
|
onClick: () => {
|
|
271
271
|
state.setOpen(false);
|
|
@@ -6,7 +6,7 @@ import { chain, mergeRefs } from "@react-aria/utils";
|
|
|
6
6
|
import { Dialog as RacDialog, Modal, ModalOverlay } from "react-aria-components";
|
|
7
7
|
import { cva } from "class-variance-authority";
|
|
8
8
|
import { X } from "lucide-react";
|
|
9
|
-
import {
|
|
9
|
+
import { useMaxWidthBreakpoint } from "../../lib/breakpoint-token.js";
|
|
10
10
|
import { cn } from "../../lib/utils.js";
|
|
11
11
|
import { Slot } from "../../lib/slot.js";
|
|
12
12
|
import { overlayHeaderToneClass } from "./overlay-header-tone.js";
|
|
@@ -15,28 +15,8 @@ import { useTranslation } from "../../i18n/use-translation.js";
|
|
|
15
15
|
const toCssLength = (v) => typeof v === "number" ? `${v}px` : v;
|
|
16
16
|
const SHEET_BREAKPOINT_TOKEN = "--sheet-responsive-breakpoint-width";
|
|
17
17
|
const SHEET_BREAKPOINT_FALLBACK_QUERY = "(max-width: 768px)";
|
|
18
|
-
function cssLengthToPx(value, rootFontSize) {
|
|
19
|
-
const match = /^(-?\d*\.?\d+)(px|rem|em)?$/.exec(value.trim());
|
|
20
|
-
if (match == null) return void 0;
|
|
21
|
-
const amount = Number(match[1]);
|
|
22
|
-
if (!Number.isFinite(amount)) return void 0;
|
|
23
|
-
return match[2] === "rem" || match[2] === "em" ? amount * rootFontSize : amount;
|
|
24
|
-
}
|
|
25
|
-
function readSheetBreakpointQuery() {
|
|
26
|
-
if (typeof document === "undefined" || typeof window.getComputedStyle !== "function") {
|
|
27
|
-
return SHEET_BREAKPOINT_FALLBACK_QUERY;
|
|
28
|
-
}
|
|
29
|
-
const rootStyle = window.getComputedStyle(document.documentElement);
|
|
30
|
-
const rootFontSize = cssLengthToPx(rootStyle.fontSize || "16px", 16) ?? 16;
|
|
31
|
-
const px = cssLengthToPx(rootStyle.getPropertyValue(SHEET_BREAKPOINT_TOKEN), rootFontSize);
|
|
32
|
-
return px == null ? SHEET_BREAKPOINT_FALLBACK_QUERY : `(max-width: ${String(px)}px)`;
|
|
33
|
-
}
|
|
34
18
|
function useSheetResponsiveMode(responsive = "side") {
|
|
35
|
-
const
|
|
36
|
-
React.useEffect(() => {
|
|
37
|
-
setQuery(readSheetBreakpointQuery());
|
|
38
|
-
}, []);
|
|
39
|
-
const compact = useMediaQuery(query);
|
|
19
|
+
const compact = useMaxWidthBreakpoint(SHEET_BREAKPOINT_TOKEN, SHEET_BREAKPOINT_FALLBACK_QUERY);
|
|
40
20
|
if (responsive === "side" || responsive === "bottom") return responsive;
|
|
41
21
|
return compact ? "bottom" : "side";
|
|
42
22
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type MenuItemRenderProps, type PopoverProps, type PopoverRenderProps } from "react-aria-components";
|
|
3
|
-
import type { DropdownMenuPlacementProp } from "../../props/components/navigation.prop.js";
|
|
4
|
-
export type { DropdownMenuPlacementProp } from "../../props/components/navigation.prop.js";
|
|
3
|
+
import type { DropdownMenuPlacementProp, DropdownMenuTriggerActionProp } from "../../props/components/navigation.prop.js";
|
|
4
|
+
export type { DropdownMenuPlacementProp, DropdownMenuTriggerActionProp, } from "../../props/components/navigation.prop.js";
|
|
5
5
|
/**
|
|
6
6
|
* Dịch trạng thái item của RAC sang bộ `data-*` mà Radix phát ra và CSS của kho đang bám.
|
|
7
7
|
*
|
|
@@ -47,9 +47,17 @@ interface DropdownMenuPropsOwn {
|
|
|
47
47
|
* `useLocale`), nên prop này còn trong API vì hợp đồng, nhưng không tự đảo hướng.
|
|
48
48
|
*/
|
|
49
49
|
dir?: "ltr" | "rtl";
|
|
50
|
+
/** Ant Design `trigger`. @see DropdownMenuTriggerActionProp. Default `['click']`. */
|
|
51
|
+
trigger?: readonly DropdownMenuTriggerActionProp[];
|
|
52
|
+
/** Ant Design `disabled` — no gesture opens the menu (antd empties the trigger list). */
|
|
53
|
+
disabled?: boolean;
|
|
54
|
+
/** Ant Design `mouseEnterDelay`, in SECONDS, for `trigger={['hover']}`. Default 0.15. */
|
|
55
|
+
mouseEnterDelay?: number;
|
|
56
|
+
/** Ant Design `mouseLeaveDelay`, in SECONDS. Default 0.1 — long enough to cross the gap. */
|
|
57
|
+
mouseLeaveDelay?: number;
|
|
50
58
|
}
|
|
51
59
|
type DropdownMenuProps = React.PropsWithChildren<DropdownMenuPropsOwn>;
|
|
52
|
-
export declare function DropdownMenu({ children, open, defaultOpen, onOpenChange, modal, dir, }: DropdownMenuProps): React.JSX.Element;
|
|
60
|
+
export declare function DropdownMenu({ children, open, defaultOpen, onOpenChange, modal, dir, trigger, disabled, mouseEnterDelay, mouseLeaveDelay, }: DropdownMenuProps): React.JSX.Element;
|
|
53
61
|
interface DropdownMenuTriggerProps extends React.ComponentPropsWithoutRef<"button"> {
|
|
54
62
|
/** Giao hành vi mở cho phần tử con thay vì `<button>` mặc định — như Radix. */
|
|
55
63
|
asChild?: boolean;
|
|
@@ -12,9 +12,11 @@ import {
|
|
|
12
12
|
OverlayTriggerStateContext,
|
|
13
13
|
Popover,
|
|
14
14
|
Pressable,
|
|
15
|
+
RootMenuTriggerStateContext,
|
|
15
16
|
Separator,
|
|
16
17
|
OverlayArrow,
|
|
17
|
-
SubmenuTrigger
|
|
18
|
+
SubmenuTrigger,
|
|
19
|
+
useLocale
|
|
18
20
|
} from "react-aria-components";
|
|
19
21
|
import { Check, ChevronRight } from "lucide-react";
|
|
20
22
|
import { cn } from "../../lib/utils.js";
|
|
@@ -58,39 +60,201 @@ function selectEvent(name) {
|
|
|
58
60
|
return typeof CustomEvent === "function" ? new CustomEvent(name, { bubbles: false, cancelable: true }) : { defaultPrevented: false, preventDefault() {
|
|
59
61
|
} };
|
|
60
62
|
}
|
|
61
|
-
const
|
|
63
|
+
const DROPDOWN_MENU_DEFAULT_TRIGGER = ["click"];
|
|
64
|
+
const DROPDOWN_MENU_MOUSE_ENTER_DELAY = 0.15;
|
|
65
|
+
const DROPDOWN_MENU_MOUSE_LEAVE_DELAY = 0.1;
|
|
66
|
+
const SECOND_IN_MS = 1e3;
|
|
67
|
+
const DropdownMenuModalContext = React.createContext({
|
|
68
|
+
modal: true,
|
|
69
|
+
contextMenuGesture: false,
|
|
70
|
+
disabled: false,
|
|
71
|
+
hover: null,
|
|
72
|
+
racOwnsContextMenu: false,
|
|
73
|
+
openedByHover: { current: false }
|
|
74
|
+
});
|
|
75
|
+
function clearContextMenuPoint(state) {
|
|
76
|
+
state?.setPoint(null);
|
|
77
|
+
}
|
|
78
|
+
function chainGestureProps(own, incoming) {
|
|
79
|
+
const merged = { ...own };
|
|
80
|
+
for (const [key, handler] of Object.entries(incoming)) {
|
|
81
|
+
const existing = own[key];
|
|
82
|
+
merged[key] = typeof existing === "function" && typeof handler === "function" ? (event) => {
|
|
83
|
+
existing(event);
|
|
84
|
+
if (!event.defaultPrevented) handler(event);
|
|
85
|
+
} : handler;
|
|
86
|
+
}
|
|
87
|
+
return merged;
|
|
88
|
+
}
|
|
89
|
+
function isContextMenuKey(event) {
|
|
90
|
+
return event.key === "ContextMenu" || event.key === "F10" && event.shiftKey;
|
|
91
|
+
}
|
|
62
92
|
function DropdownMenu({
|
|
63
93
|
children,
|
|
64
94
|
open,
|
|
65
95
|
defaultOpen,
|
|
66
96
|
onOpenChange,
|
|
67
97
|
modal = true,
|
|
68
|
-
dir
|
|
98
|
+
dir,
|
|
99
|
+
trigger = DROPDOWN_MENU_DEFAULT_TRIGGER,
|
|
100
|
+
disabled = false,
|
|
101
|
+
mouseEnterDelay = DROPDOWN_MENU_MOUSE_ENTER_DELAY,
|
|
102
|
+
mouseLeaveDelay = DROPDOWN_MENU_MOUSE_LEAVE_DELAY
|
|
69
103
|
}) {
|
|
70
104
|
void dir;
|
|
71
|
-
const
|
|
72
|
-
|
|
105
|
+
const wantsHover = !disabled && trigger.includes("hover");
|
|
106
|
+
const wantsClick = !disabled && trigger.includes("click");
|
|
107
|
+
const wantsContextMenu = !disabled && trigger.includes("contextMenu");
|
|
108
|
+
const racOwnsContextMenu = wantsContextMenu && !wantsClick && !wantsHover;
|
|
109
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultOpen ?? false);
|
|
110
|
+
const isOpen = open ?? uncontrolled;
|
|
111
|
+
const isOpenRef = React.useRef(isOpen);
|
|
112
|
+
isOpenRef.current = isOpen;
|
|
113
|
+
const openedByHover = React.useRef(false);
|
|
114
|
+
const setOpen = React.useCallback(
|
|
115
|
+
(next) => {
|
|
116
|
+
if (next === isOpenRef.current) return;
|
|
117
|
+
if (next && disabled) return;
|
|
118
|
+
if (!next) openedByHover.current = false;
|
|
119
|
+
if (open === void 0) setUncontrolled(next);
|
|
120
|
+
onOpenChange?.(next);
|
|
121
|
+
},
|
|
122
|
+
[disabled, open, onOpenChange]
|
|
123
|
+
);
|
|
124
|
+
const enterTimer = React.useRef(null);
|
|
125
|
+
const leaveTimer = React.useRef(null);
|
|
126
|
+
React.useEffect(
|
|
127
|
+
() => () => {
|
|
128
|
+
if (enterTimer.current) clearTimeout(enterTimer.current);
|
|
129
|
+
if (leaveTimer.current) clearTimeout(leaveTimer.current);
|
|
130
|
+
},
|
|
131
|
+
[]
|
|
132
|
+
);
|
|
133
|
+
const hover = React.useMemo(() => {
|
|
134
|
+
if (!wantsHover) return null;
|
|
135
|
+
return {
|
|
136
|
+
enter: () => {
|
|
137
|
+
if (leaveTimer.current) clearTimeout(leaveTimer.current);
|
|
138
|
+
if (isOpenRef.current) return;
|
|
139
|
+
enterTimer.current = setTimeout(() => {
|
|
140
|
+
openedByHover.current = true;
|
|
141
|
+
setOpen(true);
|
|
142
|
+
}, mouseEnterDelay * SECOND_IN_MS);
|
|
143
|
+
},
|
|
144
|
+
leave: () => {
|
|
145
|
+
if (enterTimer.current) clearTimeout(enterTimer.current);
|
|
146
|
+
leaveTimer.current = setTimeout(() => setOpen(false), mouseLeaveDelay * SECOND_IN_MS);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}, [wantsHover, mouseEnterDelay, mouseLeaveDelay, setOpen]);
|
|
150
|
+
const options = React.useMemo(
|
|
151
|
+
() => ({
|
|
152
|
+
// A HOVER MENU CANNOT BE MODAL. A modal RAC popover paints a full-bleed underlay the instant
|
|
153
|
+
// it opens; that underlay lands under the pointer, the trigger gets `pointerleave`, and the
|
|
154
|
+
// menu closes before the reader can move onto it. antd's hover dropdown is non-modal for the
|
|
155
|
+
// same reason. Every other mode keeps the caller's `modal`.
|
|
156
|
+
modal: wantsHover ? false : modal,
|
|
157
|
+
contextMenuGesture: wantsContextMenu,
|
|
158
|
+
disabled,
|
|
159
|
+
hover,
|
|
160
|
+
racOwnsContextMenu,
|
|
161
|
+
openedByHover
|
|
162
|
+
}),
|
|
163
|
+
[modal, wantsContextMenu, disabled, hover, racOwnsContextMenu, wantsHover]
|
|
164
|
+
);
|
|
165
|
+
return /* @__PURE__ */ jsx(DropdownMenuModalContext.Provider, { value: options, children: /* @__PURE__ */ jsx(
|
|
166
|
+
MenuTrigger,
|
|
167
|
+
{
|
|
168
|
+
isOpen,
|
|
169
|
+
onOpenChange: setOpen,
|
|
170
|
+
trigger: racOwnsContextMenu ? "contextMenu" : "press",
|
|
171
|
+
children
|
|
172
|
+
}
|
|
173
|
+
) });
|
|
73
174
|
}
|
|
74
175
|
function DropdownMenuTrigger({ asChild, children, ...props }) {
|
|
75
176
|
const state = React.useContext(OverlayTriggerStateContext);
|
|
177
|
+
const menuState = React.useContext(
|
|
178
|
+
RootMenuTriggerStateContext
|
|
179
|
+
);
|
|
180
|
+
const { contextMenuGesture, disabled, hover, racOwnsContextMenu } = React.useContext(DropdownMenuModalContext);
|
|
76
181
|
const dataState = state?.isOpen ? "open" : "closed";
|
|
182
|
+
const wantsContextMenu = contextMenuGesture;
|
|
183
|
+
const isDisabled = disabled || props.disabled;
|
|
184
|
+
const { direction } = useLocale();
|
|
185
|
+
const openAtTriggerBox = (element) => {
|
|
186
|
+
const rect = element.getBoundingClientRect();
|
|
187
|
+
menuState?.setPoint({ x: direction === "rtl" ? rect.right : rect.left, y: rect.bottom });
|
|
188
|
+
menuState?.open("first");
|
|
189
|
+
};
|
|
190
|
+
const gestureProps = {};
|
|
191
|
+
if (wantsContextMenu && !isDisabled) {
|
|
192
|
+
gestureProps.onKeyDown = (event) => {
|
|
193
|
+
if (!isContextMenuKey(event)) return;
|
|
194
|
+
event.preventDefault();
|
|
195
|
+
openAtTriggerBox(event.currentTarget);
|
|
196
|
+
};
|
|
197
|
+
if (!racOwnsContextMenu) {
|
|
198
|
+
gestureProps.onContextMenu = (event) => {
|
|
199
|
+
event.preventDefault();
|
|
200
|
+
menuState?.setPoint({ x: event.clientX, y: event.clientY });
|
|
201
|
+
menuState?.open(null);
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (!racOwnsContextMenu) {
|
|
206
|
+
gestureProps.onPointerDownCapture = () => clearContextMenuPoint(menuState);
|
|
207
|
+
gestureProps.onKeyDownCapture = (event) => {
|
|
208
|
+
if (!isContextMenuKey(event)) clearContextMenuPoint(menuState);
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (hover && !isDisabled) {
|
|
212
|
+
gestureProps.onPointerEnter = (event) => {
|
|
213
|
+
if (event.pointerType === "mouse") hover.enter();
|
|
214
|
+
};
|
|
215
|
+
gestureProps.onPointerLeave = (event) => {
|
|
216
|
+
if (event.pointerType === "mouse") hover.leave();
|
|
217
|
+
};
|
|
218
|
+
}
|
|
77
219
|
if (asChild && React.isValidElement(children)) {
|
|
78
|
-
return /* @__PURE__ */ jsx(Pressable, { children: React.cloneElement(children, {
|
|
220
|
+
return /* @__PURE__ */ jsx(Pressable, { isDisabled, children: React.cloneElement(children, {
|
|
79
221
|
"data-slot": "dropdown-menu-trigger",
|
|
80
|
-
"data-state": dataState
|
|
222
|
+
"data-state": dataState,
|
|
223
|
+
// A right click target is usually a region rather than a button, and Shift+F10 needs it
|
|
224
|
+
// focusable — so it is given a tab stop unless the consumer already placed one.
|
|
225
|
+
...wantsContextMenu && children.props.tabIndex === void 0 ? { tabIndex: 0 } : {},
|
|
226
|
+
...chainGestureProps(
|
|
227
|
+
children.props,
|
|
228
|
+
gestureProps
|
|
229
|
+
)
|
|
81
230
|
}) });
|
|
82
231
|
}
|
|
83
232
|
return /* @__PURE__ */ jsx(
|
|
84
233
|
AriaButton,
|
|
85
234
|
{
|
|
86
|
-
...
|
|
87
|
-
|
|
235
|
+
...chainGestureProps(
|
|
236
|
+
props,
|
|
237
|
+
gestureProps
|
|
238
|
+
),
|
|
239
|
+
isDisabled,
|
|
88
240
|
"data-slot": "dropdown-menu-trigger",
|
|
89
241
|
"data-state": dataState,
|
|
90
242
|
children
|
|
91
243
|
}
|
|
92
244
|
);
|
|
93
245
|
}
|
|
246
|
+
function useHoverSurfaceProps() {
|
|
247
|
+
const { hover } = React.useContext(DropdownMenuModalContext);
|
|
248
|
+
if (!hover) return {};
|
|
249
|
+
return {
|
|
250
|
+
onPointerEnter: (event) => {
|
|
251
|
+
if (event.pointerType === "mouse") hover.enter();
|
|
252
|
+
},
|
|
253
|
+
onPointerLeave: (event) => {
|
|
254
|
+
if (event.pointerType === "mouse") hover.leave();
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
}
|
|
94
258
|
function DropdownMenuPortal({ children }) {
|
|
95
259
|
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
96
260
|
}
|
|
@@ -129,7 +293,7 @@ function DropdownMenuContent({
|
|
|
129
293
|
className,
|
|
130
294
|
side,
|
|
131
295
|
align,
|
|
132
|
-
sideOffset
|
|
296
|
+
sideOffset,
|
|
133
297
|
placement,
|
|
134
298
|
arrow,
|
|
135
299
|
width,
|
|
@@ -144,17 +308,25 @@ function DropdownMenuContent({
|
|
|
144
308
|
void hideWhenDetached;
|
|
145
309
|
void sticky;
|
|
146
310
|
void forceMount;
|
|
147
|
-
const { modal } = React.useContext(DropdownMenuModalContext);
|
|
311
|
+
const { modal, openedByHover } = React.useContext(DropdownMenuModalContext);
|
|
312
|
+
const hoverSurfaceProps = useHoverSurfaceProps();
|
|
313
|
+
const menuState = React.useContext(
|
|
314
|
+
RootMenuTriggerStateContext
|
|
315
|
+
);
|
|
148
316
|
const anchor = placement ? DROPDOWN_MENU_PLACEMENT[placement] : void 0;
|
|
149
317
|
const overlayPortalContainer = useOverlayPortalContainer();
|
|
318
|
+
const pointAnchored = menuState?.point != null;
|
|
319
|
+
const hasExplicitAnchor = placement !== void 0 || side !== void 0 || align !== void 0;
|
|
320
|
+
const resolvedPlacement = hasExplicitAnchor || !pointAnchored ? toPlacement(side ?? anchor?.side, align ?? anchor?.align) : "bottom start";
|
|
321
|
+
const resolvedOffset = sideOffset ?? (pointAnchored && !hasExplicitAnchor ? 0 : 4);
|
|
150
322
|
return /* @__PURE__ */ jsx(DropdownMenuPortal, { children: /* @__PURE__ */ jsxs(
|
|
151
323
|
Popover,
|
|
152
324
|
{
|
|
153
325
|
UNSTABLE_portalContainer: overlayPortalContainer,
|
|
154
326
|
"data-slot": "dropdown-menu-content",
|
|
155
327
|
isNonModal: !modal,
|
|
156
|
-
placement:
|
|
157
|
-
offset:
|
|
328
|
+
placement: resolvedPlacement,
|
|
329
|
+
offset: resolvedOffset,
|
|
158
330
|
crossOffset: alignOffset,
|
|
159
331
|
shouldFlip: avoidCollisions,
|
|
160
332
|
containerPadding: collisionPadding,
|
|
@@ -168,15 +340,16 @@ function DropdownMenuContent({
|
|
|
168
340
|
"div",
|
|
169
341
|
{
|
|
170
342
|
...props,
|
|
343
|
+
...hoverSurfaceProps,
|
|
171
344
|
role: void 0,
|
|
172
345
|
...radixSurfaceState(state),
|
|
173
|
-
"data-align": align ?? anchor?.align ?? "center",
|
|
346
|
+
"data-align": align ?? anchor?.align ?? (pointAnchored && !hasExplicitAnchor ? "start" : "center"),
|
|
174
347
|
"data-width": width
|
|
175
348
|
}
|
|
176
349
|
)
|
|
177
350
|
),
|
|
178
351
|
children: [
|
|
179
|
-
/* @__PURE__ */ jsx(Menu, { shouldFocusWrap: loop, children }),
|
|
352
|
+
/* @__PURE__ */ jsx(Menu, { shouldFocusWrap: loop, autoFocus: openedByHover.current ? false : void 0, children }),
|
|
180
353
|
arrow ? /* @__PURE__ */ jsx(OverlayArrow, { children: /* @__PURE__ */ jsx(
|
|
181
354
|
"svg",
|
|
182
355
|
{
|
|
@@ -388,6 +561,7 @@ function DropdownMenuSubContent({
|
|
|
388
561
|
void hideWhenDetached;
|
|
389
562
|
void sticky;
|
|
390
563
|
const overlayPortalContainer = useOverlayPortalContainer();
|
|
564
|
+
const hoverSurfaceProps = useHoverSurfaceProps();
|
|
391
565
|
return /* @__PURE__ */ jsx(
|
|
392
566
|
Popover,
|
|
393
567
|
{
|
|
@@ -408,6 +582,7 @@ function DropdownMenuSubContent({
|
|
|
408
582
|
"div",
|
|
409
583
|
{
|
|
410
584
|
...props,
|
|
585
|
+
...hoverSurfaceProps,
|
|
411
586
|
role: void 0,
|
|
412
587
|
...radixSurfaceState(state),
|
|
413
588
|
"data-align": align ?? "center"
|
|
@@ -96,7 +96,8 @@ function Toolbar({
|
|
|
96
96
|
defaultValue: filter.defaultSelected,
|
|
97
97
|
onValueChange: (selected) => filter.onSelectedChange?.(selected),
|
|
98
98
|
placeholder: filter.placeholder,
|
|
99
|
-
disabled: disabled || filter.disabled
|
|
99
|
+
disabled: disabled || filter.disabled,
|
|
100
|
+
clearLabel: typeof filter.label === "string" ? t("navigation.filterBar.clearFilter", { label: filter.label }) : void 0
|
|
100
101
|
}
|
|
101
102
|
)
|
|
102
103
|
},
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
export { Tabs, TabsContent, TabsList, TabsTrigger } from "./tabs.js";
|
|
2
|
-
export { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, } from "./context-menu.js";
|
|
3
2
|
export { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationEllipsis, PaginationPrevious, PaginationNext, } from "./pagination.js";
|
|
4
|
-
export { Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, } from "./menubar.js";
|
|
5
|
-
export { NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, } from "./navigation-menu.js";
|
|
6
3
|
export { Steps } from "./steps.js";
|
|
7
4
|
export { FilterBar, FilterBarGroup, Toolbar, ToolbarGroup } from "./filter-bar.js";
|
|
8
5
|
export type { FilterBarChipProp, FilterBarChipProps, FilterBarFilterProp, FilterBarFilterProps, FilterBarGroupProp, FilterBarGroupProps, FilterBarOverflowProp, FilterBarProp, FilterBarProps, FilterBarSearchProp, FilterBarSearchProps, ToolbarGroupProps, ToolbarProps, } from "./filter-bar.js";
|
|
@@ -1,20 +1,4 @@
|
|
|
1
1
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./tabs.js";
|
|
2
|
-
import {
|
|
3
|
-
ContextMenu,
|
|
4
|
-
ContextMenuCheckboxItem,
|
|
5
|
-
ContextMenuContent,
|
|
6
|
-
ContextMenuItem,
|
|
7
|
-
ContextMenuLabel,
|
|
8
|
-
ContextMenuPortal,
|
|
9
|
-
ContextMenuRadioGroup,
|
|
10
|
-
ContextMenuRadioItem,
|
|
11
|
-
ContextMenuSeparator,
|
|
12
|
-
ContextMenuShortcut,
|
|
13
|
-
ContextMenuSub,
|
|
14
|
-
ContextMenuSubContent,
|
|
15
|
-
ContextMenuSubTrigger,
|
|
16
|
-
ContextMenuTrigger
|
|
17
|
-
} from "./context-menu.js";
|
|
18
2
|
import {
|
|
19
3
|
Pagination,
|
|
20
4
|
PaginationContent,
|
|
@@ -24,32 +8,6 @@ import {
|
|
|
24
8
|
PaginationPrevious,
|
|
25
9
|
PaginationNext
|
|
26
10
|
} from "./pagination.js";
|
|
27
|
-
import {
|
|
28
|
-
Menubar,
|
|
29
|
-
MenubarCheckboxItem,
|
|
30
|
-
MenubarContent,
|
|
31
|
-
MenubarItem,
|
|
32
|
-
MenubarLabel,
|
|
33
|
-
MenubarMenu,
|
|
34
|
-
MenubarRadioGroup,
|
|
35
|
-
MenubarRadioItem,
|
|
36
|
-
MenubarSeparator,
|
|
37
|
-
MenubarShortcut,
|
|
38
|
-
MenubarSub,
|
|
39
|
-
MenubarSubContent,
|
|
40
|
-
MenubarSubTrigger,
|
|
41
|
-
MenubarTrigger
|
|
42
|
-
} from "./menubar.js";
|
|
43
|
-
import {
|
|
44
|
-
NavigationMenu,
|
|
45
|
-
NavigationMenuContent,
|
|
46
|
-
NavigationMenuIndicator,
|
|
47
|
-
NavigationMenuItem,
|
|
48
|
-
NavigationMenuLink,
|
|
49
|
-
NavigationMenuList,
|
|
50
|
-
NavigationMenuTrigger,
|
|
51
|
-
NavigationMenuViewport
|
|
52
|
-
} from "./navigation-menu.js";
|
|
53
11
|
import { Steps } from "./steps.js";
|
|
54
12
|
import { FilterBar, FilterBarGroup, Toolbar, ToolbarGroup } from "./filter-bar.js";
|
|
55
13
|
import { AppSettingPicker } from "./app-setting-picker.js";
|
|
@@ -74,20 +32,6 @@ import {
|
|
|
74
32
|
export {
|
|
75
33
|
AppSettingPicker,
|
|
76
34
|
AppSettingToggle,
|
|
77
|
-
ContextMenu,
|
|
78
|
-
ContextMenuCheckboxItem,
|
|
79
|
-
ContextMenuContent,
|
|
80
|
-
ContextMenuItem,
|
|
81
|
-
ContextMenuLabel,
|
|
82
|
-
ContextMenuPortal,
|
|
83
|
-
ContextMenuRadioGroup,
|
|
84
|
-
ContextMenuRadioItem,
|
|
85
|
-
ContextMenuSeparator,
|
|
86
|
-
ContextMenuShortcut,
|
|
87
|
-
ContextMenuSub,
|
|
88
|
-
ContextMenuSubContent,
|
|
89
|
-
ContextMenuSubTrigger,
|
|
90
|
-
ContextMenuTrigger,
|
|
91
35
|
DropdownMenu,
|
|
92
36
|
DropdownMenuCheckboxItem,
|
|
93
37
|
DropdownMenuContent,
|
|
@@ -105,28 +49,6 @@ export {
|
|
|
105
49
|
DropdownMenuTrigger,
|
|
106
50
|
FilterBar,
|
|
107
51
|
FilterBarGroup,
|
|
108
|
-
Menubar,
|
|
109
|
-
MenubarCheckboxItem,
|
|
110
|
-
MenubarContent,
|
|
111
|
-
MenubarItem,
|
|
112
|
-
MenubarLabel,
|
|
113
|
-
MenubarMenu,
|
|
114
|
-
MenubarRadioGroup,
|
|
115
|
-
MenubarRadioItem,
|
|
116
|
-
MenubarSeparator,
|
|
117
|
-
MenubarShortcut,
|
|
118
|
-
MenubarSub,
|
|
119
|
-
MenubarSubContent,
|
|
120
|
-
MenubarSubTrigger,
|
|
121
|
-
MenubarTrigger,
|
|
122
|
-
NavigationMenu,
|
|
123
|
-
NavigationMenuContent,
|
|
124
|
-
NavigationMenuIndicator,
|
|
125
|
-
NavigationMenuItem,
|
|
126
|
-
NavigationMenuLink,
|
|
127
|
-
NavigationMenuList,
|
|
128
|
-
NavigationMenuTrigger,
|
|
129
|
-
NavigationMenuViewport,
|
|
130
52
|
Pagination,
|
|
131
53
|
PaginationContent,
|
|
132
54
|
PaginationEllipsis,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "react-aria-components";
|
|
10
10
|
import { MoreHorizontal, Plus, X } from "lucide-react";
|
|
11
11
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
12
|
+
import { useMaxWidthBreakpoint } from "../../lib/breakpoint-token.js";
|
|
12
13
|
import { cn } from "../../lib/utils.js";
|
|
13
14
|
import {
|
|
14
15
|
DropdownMenu,
|
|
@@ -57,6 +58,13 @@ function resolveTabsAxis(tabPlacement, orientation) {
|
|
|
57
58
|
orientation: orientation ?? "horizontal"
|
|
58
59
|
};
|
|
59
60
|
}
|
|
61
|
+
const TABS_PLACEMENT_BREAKPOINT_TOKEN = "--tabs-placement-responsive-breakpoint-width";
|
|
62
|
+
const TABS_PLACEMENT_BREAKPOINT_FALLBACK_QUERY = "(max-width: 768px)";
|
|
63
|
+
function foldVerticalPlacement(axis, narrow) {
|
|
64
|
+
if (!narrow || axis.orientation !== "vertical") return axis;
|
|
65
|
+
const trailing = axis.placement === "end" || axis.placement === "bottom";
|
|
66
|
+
return { placement: trailing ? "bottom" : "top", orientation: "horizontal" };
|
|
67
|
+
}
|
|
60
68
|
function Tabs({
|
|
61
69
|
className,
|
|
62
70
|
orientation,
|
|
@@ -85,9 +93,13 @@ function Tabs({
|
|
|
85
93
|
}) {
|
|
86
94
|
const { t } = useTranslation();
|
|
87
95
|
const resolvedDefault = resolveFallbackTabValue(items, defaultValue);
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
const narrow = useMaxWidthBreakpoint(
|
|
97
|
+
TABS_PLACEMENT_BREAKPOINT_TOKEN,
|
|
98
|
+
TABS_PLACEMENT_BREAKPOINT_FALLBACK_QUERY
|
|
99
|
+
);
|
|
100
|
+
const { placement, orientation: resolvedOrientation } = foldVerticalPlacement(
|
|
101
|
+
resolveTabsAxis(tabPlacement, orientation),
|
|
102
|
+
narrow
|
|
91
103
|
);
|
|
92
104
|
const selectionSuppressed = value === void 0 && items != null && items.length > 0 && resolvedDefault === void 0;
|
|
93
105
|
const frame = React.useMemo(
|
|
@@ -470,7 +482,7 @@ const TabsContent = React.forwardRef(
|
|
|
470
482
|
ref,
|
|
471
483
|
id: value,
|
|
472
484
|
shouldForceMount: forceMount,
|
|
473
|
-
className: cn("ui-focus-ring flex-1
|
|
485
|
+
className: cn("ui-focus-ring flex-1", className),
|
|
474
486
|
render: (domProps, renderProps) => withDomProps("div", "tabs-content", props, domProps, {
|
|
475
487
|
// A force-mounted panel whose tab is not selected: Radix marked it `data-state="inactive"`
|
|
476
488
|
// and `hidden`; RAC marks it inert. The state hook is re-emitted so CSS keys the same way.
|
|
@@ -10,9 +10,6 @@ export * from "./card.js";
|
|
|
10
10
|
export * from "./checkbox.js";
|
|
11
11
|
export * from "./color-picker.js";
|
|
12
12
|
export * from "./command.js";
|
|
13
|
-
export * from "./context-menu.js";
|
|
14
|
-
export * from "./menubar.js";
|
|
15
|
-
export * from "./navigation-menu.js";
|
|
16
13
|
export * from "./resizable.js";
|
|
17
14
|
export * from "./date-picker.js";
|
|
18
15
|
export * from "./dialog.js";
|
|
@@ -11,9 +11,6 @@ export * from "./card.js";
|
|
|
11
11
|
export * from "./checkbox.js";
|
|
12
12
|
export * from "./color-picker.js";
|
|
13
13
|
export * from "./command.js";
|
|
14
|
-
export * from "./context-menu.js";
|
|
15
|
-
export * from "./menubar.js";
|
|
16
|
-
export * from "./navigation-menu.js";
|
|
17
14
|
export * from "./resizable.js";
|
|
18
15
|
export * from "./date-picker.js";
|
|
19
16
|
export * from "./dialog.js";
|
|
@@ -16,7 +16,7 @@ import * as React from "react";
|
|
|
16
16
|
* too, and `input-otp` writes its own internal state inside its paste handler, which a wrapper
|
|
17
17
|
* that only intercepted `onChange` could not undo.
|
|
18
18
|
*/
|
|
19
|
-
export declare const InputOTP: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "children" | "defaultValue" | "onChange" | "size" | "value"> & {
|
|
19
|
+
export declare const InputOTP: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "children" | "defaultValue" | "onChange" | "size" | "style" | "value"> & {
|
|
20
20
|
maxLength: number;
|
|
21
21
|
value?: string;
|
|
22
22
|
defaultValue?: string;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Radio as AriaRadio, RadioGroup as AriaRadioGroup } from "react-aria-components";
|
|
5
|
+
import { withOwnHitTarget } from "../data-entry/choice-hit-target.js";
|
|
5
6
|
import { cn } from "../../lib/utils.js";
|
|
6
7
|
const Segmented = React.forwardRef(function Segmented2({
|
|
7
8
|
options,
|
|
@@ -44,7 +45,8 @@ const Segmented = React.forwardRef(function Segmented2({
|
|
|
44
45
|
"label",
|
|
45
46
|
{
|
|
46
47
|
...domProps,
|
|
47
|
-
"data-state": state.isSelected ? "checked" : "unchecked"
|
|
48
|
+
"data-state": state.isSelected ? "checked" : "unchecked",
|
|
49
|
+
children: withOwnHitTarget(domProps.children)
|
|
48
50
|
}
|
|
49
51
|
),
|
|
50
52
|
children: [
|
|
@@ -7,11 +7,9 @@ import { cn } from "../../lib/utils.js";
|
|
|
7
7
|
import {
|
|
8
8
|
applyMaxTagCount,
|
|
9
9
|
controlSurfaceAttrs,
|
|
10
|
-
resolveAllowClear
|
|
10
|
+
resolveAllowClear,
|
|
11
|
+
splitByTokenSeparators
|
|
11
12
|
} from "../data-entry/control-surface.js";
|
|
12
|
-
function escapeForCharClass(character) {
|
|
13
|
-
return character.replace(/[\\\]^-]/g, "\\$&");
|
|
14
|
-
}
|
|
15
13
|
const TagInput = React.forwardRef(
|
|
16
14
|
({
|
|
17
15
|
value,
|
|
@@ -51,7 +49,7 @@ const TagInput = React.forwardRef(
|
|
|
51
49
|
};
|
|
52
50
|
const addAll = (raw) => {
|
|
53
51
|
let next = [...tags];
|
|
54
|
-
const pieces =
|
|
52
|
+
const pieces = splitByTokenSeparators(raw, tokenSeparators);
|
|
55
53
|
for (const piece of pieces) {
|
|
56
54
|
const tag = piece.trim();
|
|
57
55
|
if (!tag || next.includes(tag)) continue;
|