@nizivo/react 0.1.0 → 0.2.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/THIRD_PARTY_NOTICES +12 -5
- package/dist/_engines/react-aria/dialog.client.js +16 -24
- package/dist/_engines/react-aria/drawer.client.js +8 -0
- package/dist/_engines/react-aria/file-upload.client.js +50 -0
- package/dist/_engines/react-aria/menu.client.js +17 -13
- package/dist/_engines/react-aria/open-state.client.js +53 -0
- package/dist/_engines/react-aria/outside-press.client.js +61 -0
- package/dist/_engines/react-aria/overlay.client.js +6 -1
- package/dist/_engines/react-aria/popover.client.js +148 -0
- package/dist/_engines/react-aria/popup.client.js +31 -5
- package/dist/_engines/react-aria/select.client.js +22 -12
- package/dist/_engines/react-aria/toast.client.js +38 -0
- package/dist/_engines/react-aria/tooltip.client.js +11 -11
- package/dist/_internal/data-status.d.ts +3 -0
- package/dist/_internal/data-status.js +13 -0
- package/dist/_internal/glyphs.js +54 -1
- package/dist/_internal/modal.client.js +54 -0
- package/dist/_internal/nested-focus.js +33 -0
- package/dist/alert/alert-dismiss.client.d.ts +1 -1
- package/dist/alert/alert-dismiss.client.js +3 -1
- package/dist/app-shell/app-shell.d.ts +24 -0
- package/dist/app-shell/app-shell.js +56 -0
- package/dist/app-shell/index.d.ts +2 -0
- package/dist/app-shell/index.js +1 -0
- package/dist/avatar/avatar.d.ts +96 -0
- package/dist/avatar/avatar.js +94 -0
- package/dist/avatar/index.d.ts +2 -0
- package/dist/avatar/index.js +1 -0
- package/dist/banner/banner-dismiss.client.d.ts +32 -0
- package/dist/banner/banner-dismiss.client.js +38 -0
- package/dist/banner/banner.d.ts +34 -0
- package/dist/banner/banner.js +47 -0
- package/dist/banner/index.d.ts +3 -0
- package/dist/banner/index.js +3 -0
- package/dist/breadcrumb/breadcrumb.d.ts +46 -0
- package/dist/breadcrumb/breadcrumb.js +46 -0
- package/dist/breadcrumb/breadcrumb.parts.d.ts +6 -0
- package/dist/breadcrumb/breadcrumb.parts.js +9 -0
- package/dist/breadcrumb/index.d.ts +3 -0
- package/dist/breadcrumb/index.js +3 -0
- package/dist/button/button.d.ts +3 -2
- package/dist/card/card.d.ts +9 -2
- package/dist/chip-group/chip-group.client.d.ts +88 -0
- package/dist/chip-group/chip-group.client.js +157 -0
- package/dist/chip-group/index.d.ts +2 -0
- package/dist/chip-group/index.js +1 -0
- package/dist/choice-card/choice-card.client.d.ts +66 -0
- package/dist/choice-card/choice-card.client.js +138 -0
- package/dist/choice-card/index.d.ts +2 -0
- package/dist/choice-card/index.js +1 -0
- package/dist/config/config.client.d.ts +16 -1
- package/dist/config/config.client.js +18 -3
- package/dist/config/index.d.ts +2 -2
- package/dist/contracts/index.d.ts +1 -1
- package/dist/css/app-shell.css +2 -0
- package/dist/css/avatar.css +2 -0
- package/dist/css/banner.css +2 -0
- package/dist/css/base.css +1 -1
- package/dist/css/breadcrumb.css +2 -0
- package/dist/css/card.css +1 -1
- package/dist/css/chip-group.css +2 -0
- package/dist/css/choice-card.css +2 -0
- package/dist/css/delta.css +1 -1
- package/dist/css/drawer.css +2 -0
- package/dist/css/file-upload.css +2 -0
- package/dist/css/form.css +2 -0
- package/dist/css/heading.css +1 -1
- package/dist/css/kpi-tile.css +2 -0
- package/dist/css/metric.css +2 -0
- package/dist/css/mobile-tab-bar.css +2 -0
- package/dist/css/mobile-top-bar.css +2 -0
- package/dist/css/motion.css +2 -0
- package/dist/css/nav-item.css +2 -0
- package/dist/css/number-value.css +2 -0
- package/dist/css/page-header.css +2 -0
- package/dist/css/pagination.css +2 -0
- package/dist/css/password-input.css +2 -0
- package/dist/css/popover.css +2 -0
- package/dist/css/ranked-list.css +2 -0
- package/dist/css/search-field.css +2 -0
- package/dist/css/sidebar.css +2 -0
- package/dist/css/split.css +2 -0
- package/dist/css/sticky-bar.css +2 -0
- package/dist/css/table-selection.css +2 -0
- package/dist/css/table.css +2 -0
- package/dist/css/text.css +1 -1
- package/dist/css/toast.css +2 -0
- package/dist/css/top-bar.css +2 -0
- package/dist/css/trend-card.css +2 -0
- package/dist/dialog/dialog.client.d.ts +1 -1
- package/dist/dialog/dialog.client.js +15 -37
- package/dist/drawer/drawer.client.d.ts +25 -0
- package/dist/drawer/drawer.client.js +154 -0
- package/dist/drawer/drawer.contract.d.ts +98 -0
- package/dist/drawer/drawer.parts.d.ts +6 -0
- package/dist/drawer/drawer.parts.js +16 -0
- package/dist/drawer/index.d.ts +5 -0
- package/dist/drawer/index.js +3 -0
- package/dist/field/field-scope.client.js +9 -2
- package/dist/file-upload/file-upload.client.d.ts +9 -0
- package/dist/file-upload/file-upload.client.js +406 -0
- package/dist/file-upload/file-upload.contract.d.ts +112 -0
- package/dist/file-upload/index.d.ts +3 -0
- package/dist/file-upload/index.js +1 -0
- package/dist/file-upload/seam.d.ts +1 -0
- package/dist/form/form.client.d.ts +38 -0
- package/dist/form/form.client.js +127 -0
- package/dist/form/form.d.ts +36 -0
- package/dist/form/form.js +29 -0
- package/dist/form/index.d.ts +4 -0
- package/dist/form/index.js +4 -0
- package/dist/form/submit-button.client.d.ts +20 -0
- package/dist/form/submit-button.client.js +19 -0
- package/dist/heading/heading.d.ts +4 -1
- package/dist/i18n/format-label.d.ts +24 -0
- package/dist/i18n/format-label.js +19 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +1 -0
- package/dist/icon-button/icon-button.client.js +1 -1
- package/dist/icon-button/icon-button.js +1 -1
- package/dist/index.d.ts +84 -5
- package/dist/index.js +49 -4
- package/dist/kpi-tile/index.d.ts +2 -0
- package/dist/kpi-tile/index.js +1 -0
- package/dist/kpi-tile/kpi-tile.d.ts +30 -0
- package/dist/kpi-tile/kpi-tile.js +48 -0
- package/dist/locales/en-US.d.ts +77 -0
- package/dist/locales/en-US.js +83 -0
- package/dist/menu/menu.contract.d.ts +1 -1
- package/dist/metric/index.d.ts +2 -0
- package/dist/metric/index.js +1 -0
- package/dist/metric/metric.d.ts +72 -0
- package/dist/metric/metric.js +116 -0
- package/dist/mobile-tab-bar/index.d.ts +4 -0
- package/dist/mobile-tab-bar/index.js +4 -0
- package/dist/mobile-tab-bar/mobile-tab-bar-inset.client.js +38 -0
- package/dist/mobile-tab-bar/mobile-tab-bar-more.client.d.ts +26 -0
- package/dist/mobile-tab-bar/mobile-tab-bar-more.client.js +60 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.d.ts +39 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.js +54 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.parts.d.ts +6 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.parts.js +9 -0
- package/dist/mobile-top-bar/index.d.ts +2 -0
- package/dist/mobile-top-bar/index.js +1 -0
- package/dist/mobile-top-bar/mobile-top-bar.d.ts +17 -0
- package/dist/mobile-top-bar/mobile-top-bar.js +31 -0
- package/dist/motion/count-up.client.d.ts +39 -0
- package/dist/motion/count-up.client.js +109 -0
- package/dist/motion/index.d.ts +2 -0
- package/dist/motion/index.js +1 -0
- package/dist/nav-item/index.d.ts +2 -0
- package/dist/nav-item/index.js +1 -0
- package/dist/nav-item/nav-item.d.ts +35 -0
- package/dist/nav-item/nav-item.js +50 -0
- package/dist/number-value/index.d.ts +2 -0
- package/dist/number-value/index.js +1 -0
- package/dist/number-value/number-value.d.ts +25 -0
- package/dist/number-value/number-value.js +26 -0
- package/dist/page-header/index.d.ts +2 -0
- package/dist/page-header/index.js +1 -0
- package/dist/page-header/page-header.d.ts +19 -0
- package/dist/page-header/page-header.js +39 -0
- package/dist/pagination/index.d.ts +2 -0
- package/dist/pagination/index.js +1 -0
- package/dist/pagination/pagination.d.ts +74 -0
- package/dist/pagination/pagination.js +136 -0
- package/dist/password-input/index.d.ts +2 -0
- package/dist/password-input/index.js +1 -0
- package/dist/password-input/password-input.client.d.ts +52 -0
- package/dist/password-input/password-input.client.js +106 -0
- package/dist/popover/index.d.ts +5 -0
- package/dist/popover/index.js +3 -0
- package/dist/popover/popover.client.d.ts +20 -0
- package/dist/popover/popover.client.js +113 -0
- package/dist/popover/popover.contract.d.ts +88 -0
- package/dist/popover/popover.parts.d.ts +6 -0
- package/dist/popover/popover.parts.js +13 -0
- package/dist/ranked-list/index.d.ts +3 -0
- package/dist/ranked-list/index.js +3 -0
- package/dist/ranked-list/ranked-list.d.ts +85 -0
- package/dist/ranked-list/ranked-list.js +153 -0
- package/dist/ranked-list/ranked-list.parts.d.ts +6 -0
- package/dist/ranked-list/ranked-list.parts.js +10 -0
- package/dist/search-field/index.d.ts +2 -0
- package/dist/search-field/index.js +1 -0
- package/dist/search-field/search-field.client.d.ts +55 -0
- package/dist/search-field/search-field.client.js +136 -0
- package/dist/select/select.contract.d.ts +1 -1
- package/dist/sidebar/index.d.ts +4 -0
- package/dist/sidebar/index.js +4 -0
- package/dist/sidebar/sidebar-item.client.d.ts +10 -0
- package/dist/sidebar/sidebar-item.client.js +55 -0
- package/dist/sidebar/sidebar.d.ts +45 -0
- package/dist/sidebar/sidebar.js +62 -0
- package/dist/sidebar/sidebar.parts.d.ts +6 -0
- package/dist/sidebar/sidebar.parts.js +11 -0
- package/dist/split/index.d.ts +3 -0
- package/dist/split/index.js +3 -0
- package/dist/split/split.d.ts +28 -0
- package/dist/split/split.js +33 -0
- package/dist/split/split.parts.d.ts +6 -0
- package/dist/split/split.parts.js +10 -0
- package/dist/sticky-bar/index.d.ts +2 -0
- package/dist/sticky-bar/index.js +1 -0
- package/dist/sticky-bar/sticky-bar.d.ts +16 -0
- package/dist/sticky-bar/sticky-bar.js +26 -0
- package/dist/styles.css +66 -7
- package/dist/table/index.d.ts +3 -0
- package/dist/table/index.js +3 -0
- package/dist/table/table.d.ts +101 -0
- package/dist/table/table.js +121 -0
- package/dist/table/table.parts.d.ts +6 -0
- package/dist/table/table.parts.js +18 -0
- package/dist/table-selection/index.d.ts +3 -0
- package/dist/table-selection/index.js +3 -0
- package/dist/table-selection/table-selection.client.d.ts +14 -0
- package/dist/table-selection/table-selection.client.js +84 -0
- package/dist/table-selection/table-selection.d.ts +34 -0
- package/dist/table-selection/table-selection.js +50 -0
- package/dist/text/text.d.ts +13 -2
- package/dist/toast/index.d.ts +4 -0
- package/dist/toast/index.js +3 -0
- package/dist/toast/seam.d.ts +2 -0
- package/dist/toast/store.d.ts +19 -0
- package/dist/toast/store.js +136 -0
- package/dist/toast/toast.contract.d.ts +56 -0
- package/dist/toast/toaster.client.d.ts +10 -0
- package/dist/toast/toaster.client.js +305 -0
- package/dist/tooltip/tooltip.contract.d.ts +1 -1
- package/dist/top-bar/index.d.ts +2 -0
- package/dist/top-bar/index.js +1 -0
- package/dist/top-bar/top-bar.d.ts +17 -0
- package/dist/top-bar/top-bar.js +35 -0
- package/dist/trend-card/index.d.ts +2 -0
- package/dist/trend-card/index.js +1 -0
- package/dist/trend-card/trend-card.d.ts +34 -0
- package/dist/trend-card/trend-card.js +74 -0
- package/package.json +167 -4
package/THIRD_PARTY_NOTICES
CHANGED
|
@@ -7,13 +7,20 @@ The internal glyphs in dist/_internal/glyphs.js reuse the SVG path data of these
|
|
|
7
7
|
Lucide icons:
|
|
8
8
|
|
|
9
9
|
loader-circle (the Button and IconButton pending spinner)
|
|
10
|
+
chevron-right (the Breadcrumb separator and the Pagination previous/next marks)
|
|
10
11
|
chevrons-up-down (the Select trigger indicator)
|
|
11
|
-
circle-x (the Field, Fieldset and InlineError error mark)
|
|
12
|
+
circle-x (the Field, Fieldset and InlineError error mark, the critical Toast mark)
|
|
13
|
+
circle-check (the success Toast mark)
|
|
14
|
+
info (the neutral Toast mark)
|
|
12
15
|
x (the AlertDismiss close mark)
|
|
13
16
|
check (the Checkbox checked mark)
|
|
14
17
|
minus (the Checkbox indeterminate dash)
|
|
18
|
+
eye (the PasswordInput toggle while the password is hidden)
|
|
19
|
+
eye-off (the PasswordInput toggle while the password is shown)
|
|
20
|
+
search (the SearchField magnifier)
|
|
21
|
+
ellipsis (the MobileTabBar More mark)
|
|
15
22
|
|
|
16
|
-
Lucide's licence covers all
|
|
23
|
+
Lucide's licence covers all thirteen:
|
|
17
24
|
|
|
18
25
|
ISC License
|
|
19
26
|
|
|
@@ -34,9 +41,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
34
41
|
--------------------------------------------------------------------------------
|
|
35
42
|
Feather (https://feathericons.com)
|
|
36
43
|
|
|
37
|
-
circle-x (Feather's x-circle), x, check
|
|
38
|
-
|
|
39
|
-
licence:
|
|
44
|
+
chevron-right, circle-x (Feather's x-circle), info, x, check, minus, search and
|
|
45
|
+
ellipsis (Feather's more-horizontal) are on Lucide's list of icons derived from the
|
|
46
|
+
Feather project, so their path data is also under Feather's licence:
|
|
40
47
|
|
|
41
48
|
The MIT License (MIT)
|
|
42
49
|
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { mergeProps } from "../../contracts/merge-props.js";
|
|
3
|
-
import { details } from "../../contracts/details.js";
|
|
4
3
|
import { stateAttrs } from "../../contracts/state.js";
|
|
5
4
|
import { defined, engineDom } from "./dom.js";
|
|
6
5
|
import { EngineLocale } from "./locale.client.js";
|
|
7
6
|
import { OverlayScope, TOP_LAYER } from "./overlay.client.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { useOpenState } from "./open-state.client.js";
|
|
8
|
+
import { InitialFocus, ReturnFocus, useTriggerRef } from "./popup.client.js";
|
|
9
|
+
import { OutsidePress } from "./outside-press.client.js";
|
|
10
|
+
import { createElement, use, useRef } from "react";
|
|
10
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
12
|
import { Button, Dialog, DialogTrigger, Heading, Modal, ModalOverlay, OverlayTriggerStateContext, Text } from "react-aria-components";
|
|
12
13
|
//#region src/_engines/react-aria/dialog.client.tsx
|
|
13
14
|
/** A box-less wrapper: popups portaled into it position against the positioner. */
|
|
14
15
|
const NESTED_STYLE = { display: "contents" };
|
|
15
|
-
const Root = ({ open, defaultOpen, onOpenChange, children }) =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
16
|
+
const Root = ({ open, defaultOpen, onOpenChange, children }) => {
|
|
17
|
+
const [isOpen, setOpen, key] = useOpenState(open, defaultOpen, onOpenChange);
|
|
18
|
+
return /* @__PURE__ */ jsx(EngineLocale, { children: /* @__PURE__ */ jsx(DialogTrigger, {
|
|
19
|
+
isOpen,
|
|
20
|
+
onOpenChange: setOpen,
|
|
21
|
+
children
|
|
22
|
+
}, key) });
|
|
23
|
+
};
|
|
23
24
|
const Trigger = ({ render, children, ...dom }) => {
|
|
24
25
|
const open = use(OverlayTriggerStateContext)?.isOpen ?? false;
|
|
25
26
|
return /* @__PURE__ */ jsx(Button, {
|
|
@@ -35,19 +36,6 @@ const Trigger = ({ render, children, ...dom }) => {
|
|
|
35
36
|
children
|
|
36
37
|
});
|
|
37
38
|
};
|
|
38
|
-
/**
|
|
39
|
-
* Moves focus to the leaf's initial-focus element. A child of the content element, so its effect runs
|
|
40
|
-
* before React Aria's own focus-the-dialog effect (a parent's), which then sees focus inside and
|
|
41
|
-
* leaves it; and after FocusScope recorded the trigger to return focus to.
|
|
42
|
-
*/
|
|
43
|
-
function InitialFocus({ content, resolve }) {
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
const element = content.current;
|
|
46
|
-
if (element === null || element.contains(element.ownerDocument.activeElement)) return;
|
|
47
|
-
resolve(element)?.focus();
|
|
48
|
-
}, [content, resolve]);
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
39
|
const Popup = ({ role, backdrop, container, positioner, backdropProps, contentProps, initialFocus, returnFocus, "aria-label": label, "aria-labelledby": labelledBy, "aria-describedby": describedBy, render, children, ...dom }) => {
|
|
52
40
|
const nestedRef = useRef(null);
|
|
53
41
|
const contentRef = useRef(null);
|
|
@@ -99,6 +87,10 @@ const Popup = ({ role, backdrop, container, positioner, backdropProps, contentPr
|
|
|
99
87
|
popup: contentRef,
|
|
100
88
|
target: returnFocus
|
|
101
89
|
}),
|
|
90
|
+
/* @__PURE__ */ jsx(OutsidePress, {
|
|
91
|
+
popup: contentRef,
|
|
92
|
+
dismissable: role !== "alertdialog"
|
|
93
|
+
}),
|
|
102
94
|
children
|
|
103
95
|
]
|
|
104
96
|
})
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import "./dialog.client.js";
|
|
3
|
+
import { useLocale } from "react-aria-components";
|
|
4
|
+
//#region src/_engines/react-aria/drawer.client.tsx
|
|
5
|
+
/** The engine's writing direction, from the locale every engine root provides (§9.3 rule 5). */
|
|
6
|
+
const useDirection = () => useLocale().direction;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { useDirection };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRef, useState } from "react";
|
|
3
|
+
//#region src/_engines/react-aria/file-upload.client.tsx
|
|
4
|
+
const carriesFiles = (event) => event.dataTransfer?.types.includes("Files") ?? false;
|
|
5
|
+
function useDropTarget(options, _ref) {
|
|
6
|
+
const [over, setOver] = useState(false);
|
|
7
|
+
const depth = useRef(0);
|
|
8
|
+
if (options.disabled) return {
|
|
9
|
+
dropProps: {
|
|
10
|
+
onDragOver: refuse,
|
|
11
|
+
onDrop: refuse
|
|
12
|
+
},
|
|
13
|
+
isDropTarget: false
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
dropProps: {
|
|
17
|
+
onDragEnter(event) {
|
|
18
|
+
if (!carriesFiles(event)) return;
|
|
19
|
+
event.preventDefault();
|
|
20
|
+
depth.current += 1;
|
|
21
|
+
setOver(true);
|
|
22
|
+
},
|
|
23
|
+
onDragOver(event) {
|
|
24
|
+
if (!carriesFiles(event)) return;
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
if (event.dataTransfer !== null) event.dataTransfer.dropEffect = "copy";
|
|
27
|
+
},
|
|
28
|
+
onDragLeave(event) {
|
|
29
|
+
if (!carriesFiles(event)) return;
|
|
30
|
+
depth.current = Math.max(0, depth.current - 1);
|
|
31
|
+
if (depth.current === 0) setOver(false);
|
|
32
|
+
},
|
|
33
|
+
onDrop(event) {
|
|
34
|
+
if (!carriesFiles(event)) return;
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
depth.current = 0;
|
|
37
|
+
setOver(false);
|
|
38
|
+
const files = [...event.dataTransfer?.files ?? []];
|
|
39
|
+
if (files.length > 0) options.onDrop(files, event.currentTarget);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
isDropTarget: over
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function refuse(event) {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
if (event.dataTransfer !== null) event.dataTransfer.dropEffect = "none";
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { useDropTarget };
|
|
@@ -5,7 +5,9 @@ import { stateAttrs } from "../../contracts/state.js";
|
|
|
5
5
|
import { defined, engineDom } from "./dom.js";
|
|
6
6
|
import { EngineLocale } from "./locale.client.js";
|
|
7
7
|
import { popupStyle, resolveSide, toPlacement } from "./overlay.client.js";
|
|
8
|
+
import { useOpenState } from "./open-state.client.js";
|
|
8
9
|
import { ReturnFocus, useTabOut, useTriggerRef } from "./popup.client.js";
|
|
10
|
+
import { OutsidePress } from "./outside-press.client.js";
|
|
9
11
|
import { Children, createContext, createElement, isValidElement, use, useRef, useState } from "react";
|
|
10
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
13
|
import { Button, Header, Menu, MenuItem, MenuSection, MenuTrigger, Popover, RootMenuTriggerStateContext, Separator, useLocale } from "react-aria-components";
|
|
@@ -40,16 +42,14 @@ function itemValues(children, out = []) {
|
|
|
40
42
|
}
|
|
41
43
|
const Root = ({ open, defaultOpen, onOpenChange, children }) => {
|
|
42
44
|
const [store] = useState(() => /* @__PURE__ */ new Map());
|
|
45
|
+
const [isOpen, setOpen, key] = useOpenState(open, defaultOpen, onOpenChange);
|
|
43
46
|
return /* @__PURE__ */ jsx(EngineLocale, { children: /* @__PURE__ */ jsx(Kept, {
|
|
44
47
|
value: store,
|
|
45
48
|
children: /* @__PURE__ */ jsx(MenuTrigger, {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
defaultOpen
|
|
49
|
-
}),
|
|
50
|
-
onOpenChange: (isOpen) => onOpenChange?.(isOpen, details("unknown")),
|
|
49
|
+
isOpen,
|
|
50
|
+
onOpenChange: setOpen,
|
|
51
51
|
children
|
|
52
|
-
})
|
|
52
|
+
}, key)
|
|
53
53
|
}) });
|
|
54
54
|
};
|
|
55
55
|
const Trigger = ({ render, children, ...dom }) => {
|
|
@@ -102,13 +102,17 @@ const Popup = ({ side, align, sideOffset, container, list, render, children, ...
|
|
|
102
102
|
});
|
|
103
103
|
return render(mergeProps(engine, dom, attrs, { ref: popup }), s);
|
|
104
104
|
},
|
|
105
|
-
children: [
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
children: [
|
|
106
|
+
/* @__PURE__ */ jsx(ReturnFocus, {
|
|
107
|
+
trigger,
|
|
108
|
+
popup
|
|
109
|
+
}),
|
|
110
|
+
/* @__PURE__ */ jsx(OutsidePress, { popup }),
|
|
111
|
+
/* @__PURE__ */ jsx(Menu, {
|
|
112
|
+
render: (p) => createElement("div", mergeProps(listDom(p, list), list, { onKeyDown: tabOut })),
|
|
113
|
+
children
|
|
114
|
+
})
|
|
115
|
+
]
|
|
112
116
|
});
|
|
113
117
|
};
|
|
114
118
|
const Item = ({ textValue, disabled, onAction, closeOnSelect, href, target, rel, download, hrefLang, ping, referrerPolicy, render, children, ...dom }) => /* @__PURE__ */ jsx(MenuItem, {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { details } from "../../contracts/details.js";
|
|
3
|
+
import { createContext, useLayoutEffect, useRef, useState } from "react";
|
|
4
|
+
//#region src/_engines/react-aria/open-state.client.tsx
|
|
5
|
+
/**
|
|
6
|
+
* The key, for a popup part whose Root keeps other state in the engine (Select's value): that part
|
|
7
|
+
* remounts its popup instead.
|
|
8
|
+
*/
|
|
9
|
+
const PopupKey = createContext(0);
|
|
10
|
+
/**
|
|
11
|
+
* `[isOpen, setOpen, key]` for the engine: the consumer's `open`, else the Root's own state, and the
|
|
12
|
+
* key to render the engine's root with.
|
|
13
|
+
*/
|
|
14
|
+
function useOpenState(open, defaultOpen, onOpenChange) {
|
|
15
|
+
const [own, setOwn] = useState(defaultOpen ?? false);
|
|
16
|
+
const [key, setKey] = useState(0);
|
|
17
|
+
const controlled = open !== void 0;
|
|
18
|
+
const isOpen = controlled ? open : own;
|
|
19
|
+
const latest = useRef({
|
|
20
|
+
controlled,
|
|
21
|
+
onOpenChange
|
|
22
|
+
});
|
|
23
|
+
useLayoutEffect(() => {
|
|
24
|
+
latest.current = {
|
|
25
|
+
controlled,
|
|
26
|
+
onOpenChange
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
const seenClosed = useRef(false);
|
|
30
|
+
const armed = useRef(false);
|
|
31
|
+
useLayoutEffect(() => {
|
|
32
|
+
if (!isOpen) seenClosed.current = true;
|
|
33
|
+
armed.current = isOpen && seenClosed.current;
|
|
34
|
+
}, [isOpen]);
|
|
35
|
+
useLayoutEffect(() => () => {
|
|
36
|
+
if (!armed.current) return;
|
|
37
|
+
armed.current = false;
|
|
38
|
+
if (!latest.current.controlled) setOwn(false);
|
|
39
|
+
setKey((k) => k + 1);
|
|
40
|
+
latest.current.onOpenChange?.(false, details("hidden"));
|
|
41
|
+
}, []);
|
|
42
|
+
const setOpen = (next) => {
|
|
43
|
+
if (!controlled) setOwn(next);
|
|
44
|
+
onOpenChange?.(next, details("unknown"));
|
|
45
|
+
};
|
|
46
|
+
return [
|
|
47
|
+
isOpen,
|
|
48
|
+
setOpen,
|
|
49
|
+
key
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { PopupKey, useOpenState };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { returnAfterClose } from "./popup.client.js";
|
|
3
|
+
import { use, useEffect, useLayoutEffect, useRef } from "react";
|
|
4
|
+
import { OverlayTriggerStateContext } from "react-aria-components";
|
|
5
|
+
//#region src/_engines/react-aria/outside-press.client.tsx
|
|
6
|
+
/**
|
|
7
|
+
* The family's open popups, in open order. Its own list, not popup.client's registry: a Select's
|
|
8
|
+
* hidden collection pass registers and unregisters there under the same ref. Only entries on the
|
|
9
|
+
* page count.
|
|
10
|
+
*/
|
|
11
|
+
const STACK = [];
|
|
12
|
+
const onPage = (popup) => popup.current?.isConnected === true;
|
|
13
|
+
/**
|
|
14
|
+
* Outside press for a popup opened inside another overlay (§12.2 Dismiss stack). React Aria's
|
|
15
|
+
* useInteractOutside ignores every press inside an element marked top-layer, and the family's
|
|
16
|
+
* nested-portal containers carry that mark (§12.1 L2), so a press on a nested popup's underlay, or
|
|
17
|
+
* anywhere else in its parent's container, never reached the engine's dismiss logic: a Select or
|
|
18
|
+
* Menu inside a Dialog stayed open (weeks 4 to 12; found in week 13). The family completes it: a
|
|
19
|
+
* press that starts and ends outside `popup`, inside a top-layer element that is not Nizivo's own
|
|
20
|
+
* top layer (the toast region and announcer, `data-nz-top-layer`, dismiss nothing) and not on a
|
|
21
|
+
* tooltip, closes `popup` when it is the topmost. Every other press stays with the engine. The
|
|
22
|
+
* element is read at the press: a Select's popup is attached after this component's first effect.
|
|
23
|
+
*/
|
|
24
|
+
function OutsidePress({ popup, dismissable = true }) {
|
|
25
|
+
const context = use(OverlayTriggerStateContext);
|
|
26
|
+
const state = useRef(context);
|
|
27
|
+
useLayoutEffect(() => {
|
|
28
|
+
state.current = context;
|
|
29
|
+
});
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
STACK.push(popup);
|
|
32
|
+
const ours = (event) => {
|
|
33
|
+
const element = popup.current;
|
|
34
|
+
const { target } = event;
|
|
35
|
+
if (!dismissable || event.button > 0 || element === null || !(target instanceof Element) || element.contains(target)) return false;
|
|
36
|
+
const host = target.closest("[data-react-aria-top-layer]");
|
|
37
|
+
return host !== null && host.closest("[data-nz-top-layer]") === null && target.closest("[role=\"tooltip\"]") === null && STACK.findLast(onPage) === popup;
|
|
38
|
+
};
|
|
39
|
+
let started = false;
|
|
40
|
+
const down = (event) => {
|
|
41
|
+
started = ours(event);
|
|
42
|
+
};
|
|
43
|
+
const up = (event) => {
|
|
44
|
+
if (started && ours(event)) {
|
|
45
|
+
returnAfterClose(popup);
|
|
46
|
+
state.current?.close();
|
|
47
|
+
}
|
|
48
|
+
started = false;
|
|
49
|
+
};
|
|
50
|
+
document.addEventListener("pointerdown", down, true);
|
|
51
|
+
document.addEventListener("pointerup", up, true);
|
|
52
|
+
return () => {
|
|
53
|
+
STACK.splice(STACK.lastIndexOf(popup), 1);
|
|
54
|
+
document.removeEventListener("pointerdown", down, true);
|
|
55
|
+
document.removeEventListener("pointerup", up, true);
|
|
56
|
+
};
|
|
57
|
+
}, [popup, dismissable]);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { OutsidePress };
|
|
@@ -11,6 +11,11 @@ function OverlayScope({ container, children }) {
|
|
|
11
11
|
}
|
|
12
12
|
/** React Aria's inert exemption, as props for an element the adapter renders itself. */
|
|
13
13
|
const TOP_LAYER = { "data-react-aria-top-layer": "" };
|
|
14
|
+
/** Maps Nizivo's `data-nz-top-layer` to React Aria's inert exemption. */
|
|
15
|
+
function markTopLayer(element) {
|
|
16
|
+
element.setAttribute("data-react-aria-top-layer", "");
|
|
17
|
+
return () => element.removeAttribute("data-react-aria-top-layer");
|
|
18
|
+
}
|
|
14
19
|
/** Logical side + alignment → a React Aria placement. */
|
|
15
20
|
function toPlacement(side, align) {
|
|
16
21
|
if (align === "center") return side;
|
|
@@ -38,4 +43,4 @@ function popupStyle(style) {
|
|
|
38
43
|
return out;
|
|
39
44
|
}
|
|
40
45
|
//#endregion
|
|
41
|
-
export { OverlayScope, TOP_LAYER, popupStyle, resolveSide, toPlacement };
|
|
46
|
+
export { OverlayScope, TOP_LAYER, markTopLayer, popupStyle, resolveSide, toPlacement };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { mergeProps } from "../../contracts/merge-props.js";
|
|
3
|
+
import { stateAttrs } from "../../contracts/state.js";
|
|
4
|
+
import { defined, engineDom } from "./dom.js";
|
|
5
|
+
import { EngineLocale } from "./locale.client.js";
|
|
6
|
+
import { OverlayScope, markTopLayer, popupStyle, resolveSide, toPlacement } from "./overlay.client.js";
|
|
7
|
+
import { useOpenState } from "./open-state.client.js";
|
|
8
|
+
import { InitialFocus, ReturnFocus, useTriggerRef } from "./popup.client.js";
|
|
9
|
+
import { OutsidePress } from "./outside-press.client.js";
|
|
10
|
+
import { createElement, use, useCallback, useRef } from "react";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
import { Button, Dialog, DialogTrigger, Heading, OverlayTriggerStateContext, Popover, Text, useLocale } from "react-aria-components";
|
|
13
|
+
//#region src/_engines/react-aria/popover.client.tsx
|
|
14
|
+
const Root = ({ open, defaultOpen, onOpenChange, children }) => {
|
|
15
|
+
const [isOpen, setOpen, key] = useOpenState(open, defaultOpen, onOpenChange);
|
|
16
|
+
return /* @__PURE__ */ jsx(EngineLocale, { children: /* @__PURE__ */ jsx(DialogTrigger, {
|
|
17
|
+
isOpen,
|
|
18
|
+
onOpenChange: setOpen,
|
|
19
|
+
children
|
|
20
|
+
}, key) });
|
|
21
|
+
};
|
|
22
|
+
const Trigger = ({ render, children, ...dom }) => {
|
|
23
|
+
const open = use(OverlayTriggerStateContext)?.isOpen ?? false;
|
|
24
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
25
|
+
render: (p, rp) => {
|
|
26
|
+
const s = {
|
|
27
|
+
open,
|
|
28
|
+
pressed: rp.isPressed && !open,
|
|
29
|
+
focusVisible: rp.isFocusVisible,
|
|
30
|
+
disabled: rp.isDisabled
|
|
31
|
+
};
|
|
32
|
+
return render(mergeProps(engineDom(p), dom, stateAttrs(s)), s);
|
|
33
|
+
},
|
|
34
|
+
children
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The nested-portal container (§12.1 L2): a box-less element right after the popup, in the
|
|
39
|
+
* container the popup portaled into, so overlays opened inside the popover paint above it. It is not
|
|
40
|
+
* inside the popup, which scrolls (a clip) and scales while it enters. The engine hides everything
|
|
41
|
+
* outside a modal popover, so it carries the family's top-layer exemption, as the Dialog's does: a
|
|
42
|
+
* tooltip portaled there stays hoverable (WCAG 1.4.13). Created here, not by React, because the
|
|
43
|
+
* engine owns the popup's portal and nothing can render a sibling into it. A hidden anchor inside
|
|
44
|
+
* the popup makes it with a stable callback ref: in the commit that inserts the popup, so a tooltip
|
|
45
|
+
* shown by the initial focus (a passive effect) already finds it; a ref merged into the popup's own
|
|
46
|
+
* props would be a new function, detached and attached again, on every render.
|
|
47
|
+
*/
|
|
48
|
+
function useNestedContainer() {
|
|
49
|
+
const container = useRef(null);
|
|
50
|
+
return {
|
|
51
|
+
container,
|
|
52
|
+
anchor: useCallback((element) => {
|
|
53
|
+
const popup = element?.parentElement;
|
|
54
|
+
if (popup == null) return void 0;
|
|
55
|
+
const nested = popup.ownerDocument.createElement("div");
|
|
56
|
+
nested.style.display = "contents";
|
|
57
|
+
const undo = markTopLayer(nested);
|
|
58
|
+
popup.after(nested);
|
|
59
|
+
container.current = nested;
|
|
60
|
+
return () => {
|
|
61
|
+
undo();
|
|
62
|
+
nested.remove();
|
|
63
|
+
if (container.current === nested) container.current = null;
|
|
64
|
+
};
|
|
65
|
+
}, [])
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const Popup = ({ side, align, sideOffset, container, contentProps, initialFocus, "aria-label": label, "aria-labelledby": labelledBy, "aria-describedby": describedBy, render, children, ...dom }) => {
|
|
69
|
+
const { direction } = useLocale();
|
|
70
|
+
const popup = useRef(null);
|
|
71
|
+
const content = useRef(null);
|
|
72
|
+
const { container: nested, anchor } = useNestedContainer();
|
|
73
|
+
const trigger = useTriggerRef();
|
|
74
|
+
return /* @__PURE__ */ jsxs(Popover, {
|
|
75
|
+
placement: toPlacement(side, align),
|
|
76
|
+
offset: sideOffset,
|
|
77
|
+
...defined({ UNSTABLE_portalContainer: container ?? void 0 }),
|
|
78
|
+
render: (p, rp) => {
|
|
79
|
+
const s = {
|
|
80
|
+
entering: rp.isEntering,
|
|
81
|
+
exiting: rp.isExiting,
|
|
82
|
+
side: resolveSide(rp.placement, side, direction)
|
|
83
|
+
};
|
|
84
|
+
const engine = {
|
|
85
|
+
...engineDom(p),
|
|
86
|
+
style: popupStyle(p.style)
|
|
87
|
+
};
|
|
88
|
+
const attrs = stateAttrs({
|
|
89
|
+
open: !rp.isExiting,
|
|
90
|
+
...s,
|
|
91
|
+
align
|
|
92
|
+
});
|
|
93
|
+
return render(mergeProps(engine, dom, attrs, { ref: popup }), s);
|
|
94
|
+
},
|
|
95
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
96
|
+
hidden: true,
|
|
97
|
+
ref: anchor
|
|
98
|
+
}), /* @__PURE__ */ jsxs(Dialog, {
|
|
99
|
+
...defined({
|
|
100
|
+
"aria-label": label,
|
|
101
|
+
"aria-labelledby": labelledBy,
|
|
102
|
+
"aria-describedby": describedBy
|
|
103
|
+
}),
|
|
104
|
+
render: (p) => createElement("section", mergeProps(engineDom(p), contentProps, { ref: content })),
|
|
105
|
+
children: [
|
|
106
|
+
/* @__PURE__ */ jsx(InitialFocus, {
|
|
107
|
+
content,
|
|
108
|
+
resolve: initialFocus
|
|
109
|
+
}),
|
|
110
|
+
/* @__PURE__ */ jsx(ReturnFocus, {
|
|
111
|
+
trigger,
|
|
112
|
+
popup
|
|
113
|
+
}),
|
|
114
|
+
/* @__PURE__ */ jsx(OutsidePress, { popup }),
|
|
115
|
+
/* @__PURE__ */ jsx(OverlayScope, {
|
|
116
|
+
container: nested,
|
|
117
|
+
children
|
|
118
|
+
})
|
|
119
|
+
]
|
|
120
|
+
})]
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
const Title = ({ level, render, children, ...dom }) => /* @__PURE__ */ jsx(Heading, {
|
|
124
|
+
slot: "title",
|
|
125
|
+
level,
|
|
126
|
+
render: (p) => render(mergeProps(engineDom(p), dom), {}),
|
|
127
|
+
children
|
|
128
|
+
});
|
|
129
|
+
const Description = ({ render, children, ...dom }) => /* @__PURE__ */ jsx(Text, {
|
|
130
|
+
slot: "description",
|
|
131
|
+
elementType: "p",
|
|
132
|
+
render: (p) => render(mergeProps(engineDom(p), dom), {}),
|
|
133
|
+
children
|
|
134
|
+
});
|
|
135
|
+
const Close = ({ render, children, ...dom }) => /* @__PURE__ */ jsx(Button, {
|
|
136
|
+
slot: "close",
|
|
137
|
+
render: (p, rp) => {
|
|
138
|
+
const s = {
|
|
139
|
+
pressed: rp.isPressed,
|
|
140
|
+
focusVisible: rp.isFocusVisible,
|
|
141
|
+
disabled: rp.isDisabled
|
|
142
|
+
};
|
|
143
|
+
return render(mergeProps(engineDom(p), dom, stateAttrs(s)), s);
|
|
144
|
+
},
|
|
145
|
+
children
|
|
146
|
+
});
|
|
147
|
+
//#endregion
|
|
148
|
+
export { Close, Description, Popup, Root, Title, Trigger };
|
|
@@ -43,6 +43,17 @@ function useTriggerRef() {
|
|
|
43
43
|
const ref = typeof context === "object" && context !== null && "triggerRef" in context ? context.triggerRef : void 0;
|
|
44
44
|
return isElementRef(ref) ? ref : void 0;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Popups the family closed itself on an outside press (outside-press.client.tsx). The press lands on
|
|
48
|
+
* the popup's underlay, so no control took focus, but a modal parent's FocusScope moves focus to its
|
|
49
|
+
* first control as the popup's content leaves (React Aria's containment fallback), before any
|
|
50
|
+
* restore: the chain runs for these even though focus is no longer on <body> (O-12).
|
|
51
|
+
*/
|
|
52
|
+
const CLOSED_OUTSIDE = /* @__PURE__ */ new WeakSet();
|
|
53
|
+
/** Marks `popup` as closed by the family's outside press, for ReturnFocus. */
|
|
54
|
+
function returnAfterClose(popup) {
|
|
55
|
+
CLOSED_OUTSIDE.add(popup);
|
|
56
|
+
}
|
|
46
57
|
/** The family's open popups and their triggers: the parent-overlay step below. */
|
|
47
58
|
const OPEN = /* @__PURE__ */ new Map();
|
|
48
59
|
/**
|
|
@@ -96,17 +107,18 @@ function ReturnFocus({ trigger, popup, target = true }) {
|
|
|
96
107
|
let handled = false;
|
|
97
108
|
const onRestore = (event) => {
|
|
98
109
|
const own = latest.current;
|
|
99
|
-
const to = named(own);
|
|
100
|
-
if (event.defaultPrevented || mounted(popup) || own !== false &&
|
|
110
|
+
const to = own === false ? void 0 : [named(own), element].find(usable);
|
|
111
|
+
if (event.defaultPrevented || mounted(popup) || own !== false && to === void 0) return;
|
|
101
112
|
event.preventDefault();
|
|
102
113
|
handled = true;
|
|
103
|
-
|
|
114
|
+
to?.focus();
|
|
104
115
|
};
|
|
105
116
|
doc.addEventListener(ENGINE_RESTORE, onRestore, true);
|
|
106
117
|
requestAnimationFrame(() => {
|
|
107
118
|
doc.removeEventListener(ENGINE_RESTORE, onRestore, true);
|
|
108
119
|
const own = latest.current;
|
|
109
|
-
|
|
120
|
+
const outside = CLOSED_OUTSIDE.delete(popup);
|
|
121
|
+
if (handled || !shown.current || own === false || mounted(popup) || (doc.activeElement ?? doc.body) !== doc.body && !outside) return;
|
|
110
122
|
const next = [
|
|
111
123
|
named(own),
|
|
112
124
|
element,
|
|
@@ -123,5 +135,19 @@ function ReturnFocus({ trigger, popup, target = true }) {
|
|
|
123
135
|
]);
|
|
124
136
|
return null;
|
|
125
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Moves focus to the leaf's initial-focus element (§12.2 Focus on open; Dialog, Drawer, Popover). A
|
|
140
|
+
* child of the content element, so its effect runs before React Aria's own focus-the-dialog effect (a
|
|
141
|
+
* parent's), which then sees focus inside and leaves it; and after FocusScope recorded the trigger to
|
|
142
|
+
* return focus to.
|
|
143
|
+
*/
|
|
144
|
+
function InitialFocus({ content, resolve }) {
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
const element = content.current;
|
|
147
|
+
if (element === null || element.contains(element.ownerDocument.activeElement)) return;
|
|
148
|
+
resolve(element)?.focus();
|
|
149
|
+
}, [content, resolve]);
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
126
152
|
//#endregion
|
|
127
|
-
export { ReturnFocus, useTabOut, useTriggerRef };
|
|
153
|
+
export { InitialFocus, ReturnFocus, returnAfterClose, useTabOut, useTriggerRef };
|
|
@@ -5,7 +5,9 @@ import { stateAttrs } from "../../contracts/state.js";
|
|
|
5
5
|
import { defined, engineDom } from "./dom.js";
|
|
6
6
|
import { EngineLocale } from "./locale.client.js";
|
|
7
7
|
import { popupStyle, resolveSide, toPlacement } from "./overlay.client.js";
|
|
8
|
+
import { PopupKey, useOpenState } from "./open-state.client.js";
|
|
8
9
|
import { ReturnFocus, useTabOut, useTriggerRef } from "./popup.client.js";
|
|
10
|
+
import { OutsidePress } from "./outside-press.client.js";
|
|
9
11
|
import { createElement, use, useEffect, useLayoutEffect, useRef } from "react";
|
|
10
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
13
|
import { Button, Header, ListBox, ListBoxItem, ListBoxSection, Popover, Select, SelectStateContext, SelectValue, Separator, useLocale } from "react-aria-components";
|
|
@@ -37,12 +39,11 @@ function FormReset({ root }) {
|
|
|
37
39
|
}
|
|
38
40
|
const Root = ({ value, defaultValue, onValueChange, open, defaultOpen, onOpenChange, name, required, disabled, invalid, placeholder, "aria-label": label, "aria-labelledby": labelledBy, render, children, ...dom }) => {
|
|
39
41
|
const root = useRef(null);
|
|
42
|
+
const [isOpen, setOpen, popupKey] = useOpenState(open, defaultOpen, onOpenChange);
|
|
40
43
|
return /* @__PURE__ */ jsx(EngineLocale, { children: /* @__PURE__ */ jsxs(Select, {
|
|
41
44
|
...defined({
|
|
42
45
|
value,
|
|
43
46
|
defaultValue,
|
|
44
|
-
isOpen: open,
|
|
45
|
-
defaultOpen,
|
|
46
47
|
name,
|
|
47
48
|
isRequired: required,
|
|
48
49
|
isDisabled: disabled,
|
|
@@ -51,8 +52,9 @@ const Root = ({ value, defaultValue, onValueChange, open, defaultOpen, onOpenCha
|
|
|
51
52
|
"aria-label": label,
|
|
52
53
|
"aria-labelledby": labelledBy
|
|
53
54
|
}),
|
|
55
|
+
isOpen,
|
|
56
|
+
onOpenChange: setOpen,
|
|
54
57
|
onChange: (key) => onValueChange?.(key == null ? null : String(key), details("unknown")),
|
|
55
|
-
onOpenChange: (isOpen) => onOpenChange?.(isOpen, details("unknown")),
|
|
56
58
|
validationBehavior: "native",
|
|
57
59
|
render: (p, rp) => {
|
|
58
60
|
const s = {
|
|
@@ -66,7 +68,10 @@ const Root = ({ value, defaultValue, onValueChange, open, defaultOpen, onOpenCha
|
|
|
66
68
|
});
|
|
67
69
|
return render(mergeProps(engineDom(p), dom, attrs, { ref: root }), s);
|
|
68
70
|
},
|
|
69
|
-
children: [
|
|
71
|
+
children: [/* @__PURE__ */ jsx(PopupKey, {
|
|
72
|
+
value: popupKey,
|
|
73
|
+
children
|
|
74
|
+
}), /* @__PURE__ */ jsx(FormReset, { root })]
|
|
70
75
|
}) });
|
|
71
76
|
};
|
|
72
77
|
const Trigger = ({ id, "aria-label": label, "aria-describedby": describedBy, render, children, ...dom }) => {
|
|
@@ -101,6 +106,7 @@ const Popup = ({ side, align, sideOffset, container, list, render, children, ...
|
|
|
101
106
|
const popup = useRef(null);
|
|
102
107
|
const tabOut = useTabOut(popup);
|
|
103
108
|
const trigger = useTriggerRef();
|
|
109
|
+
const key = use(PopupKey);
|
|
104
110
|
return /* @__PURE__ */ jsxs(Popover, {
|
|
105
111
|
placement: toPlacement(side, align),
|
|
106
112
|
offset: sideOffset,
|
|
@@ -122,14 +128,18 @@ const Popup = ({ side, align, sideOffset, container, list, render, children, ...
|
|
|
122
128
|
});
|
|
123
129
|
return render(mergeProps(engine, dom, attrs, { ref: popup }), s);
|
|
124
130
|
},
|
|
125
|
-
children: [
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
children: [
|
|
132
|
+
/* @__PURE__ */ jsx(ReturnFocus, {
|
|
133
|
+
trigger,
|
|
134
|
+
popup
|
|
135
|
+
}),
|
|
136
|
+
/* @__PURE__ */ jsx(OutsidePress, { popup }),
|
|
137
|
+
/* @__PURE__ */ jsx(ListBox, {
|
|
138
|
+
render: (p) => createElement("div", mergeProps(engineDom(p), list, { onKeyDown: tabOut })),
|
|
139
|
+
children
|
|
140
|
+
})
|
|
141
|
+
]
|
|
142
|
+
}, key);
|
|
133
143
|
};
|
|
134
144
|
const Item = ({ value, textValue, disabled, render, children, ...dom }) => /* @__PURE__ */ jsx(ListBoxItem, {
|
|
135
145
|
id: value,
|