@funstack/ui 0.0.0-stage → 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +42 -2
- package/dist/accordion/accordion-context.d.mts +5 -0
- package/dist/accordion/accordion-context.d.mts.map +1 -0
- package/dist/accordion/accordion-context.mjs +9 -0
- package/dist/accordion/accordion-context.mjs.map +1 -0
- package/dist/accordion/accordion-item.d.mts +53 -0
- package/dist/accordion/accordion-item.d.mts.map +1 -0
- package/dist/accordion/accordion-item.mjs +85 -0
- package/dist/accordion/accordion-item.mjs.map +1 -0
- package/dist/accordion/accordion-panel.d.mts +40 -0
- package/dist/accordion/accordion-panel.d.mts.map +1 -0
- package/dist/accordion/accordion-panel.mjs +40 -0
- package/dist/accordion/accordion-panel.mjs.map +1 -0
- package/dist/accordion/accordion-root.d.mts +90 -0
- package/dist/accordion/accordion-root.d.mts.map +1 -0
- package/dist/accordion/accordion-root.mjs +229 -0
- package/dist/accordion/accordion-root.mjs.map +1 -0
- package/dist/accordion/accordion-trigger.d.mts +37 -0
- package/dist/accordion/accordion-trigger.d.mts.map +1 -0
- package/dist/accordion/accordion-trigger.mjs +81 -0
- package/dist/accordion/accordion-trigger.mjs.map +1 -0
- package/dist/accordion/index.d.mts +20 -0
- package/dist/accordion/index.d.mts.map +1 -0
- package/dist/accordion/index.mjs +20 -0
- package/dist/accordion/index.mjs.map +1 -0
- package/dist/checkbox/checkbox.d.mts +92 -0
- package/dist/checkbox/checkbox.d.mts.map +1 -0
- package/dist/checkbox/checkbox.mjs +82 -0
- package/dist/checkbox/checkbox.mjs.map +1 -0
- package/dist/checkbox/index.d.mts +3 -0
- package/dist/checkbox/index.mjs +1 -0
- package/dist/dialog/dialog-close.d.mts +44 -0
- package/dist/dialog/dialog-close.d.mts.map +1 -0
- package/dist/dialog/dialog-close.mjs +76 -0
- package/dist/dialog/dialog-close.mjs.map +1 -0
- package/dist/dialog/dialog-context.mjs +13 -0
- package/dist/dialog/dialog-context.mjs.map +1 -0
- package/dist/dialog/dialog-description.d.mts +22 -0
- package/dist/dialog/dialog-description.d.mts.map +1 -0
- package/dist/dialog/dialog-description.mjs +31 -0
- package/dist/dialog/dialog-description.mjs.map +1 -0
- package/dist/dialog/dialog-form.d.mts +58 -0
- package/dist/dialog/dialog-form.d.mts.map +1 -0
- package/dist/dialog/dialog-form.mjs +108 -0
- package/dist/dialog/dialog-form.mjs.map +1 -0
- package/dist/dialog/dialog-popup.d.mts +81 -0
- package/dist/dialog/dialog-popup.d.mts.map +1 -0
- package/dist/dialog/dialog-popup.mjs +366 -0
- package/dist/dialog/dialog-popup.mjs.map +1 -0
- package/dist/dialog/dialog-root.d.mts +70 -0
- package/dist/dialog/dialog-root.d.mts.map +1 -0
- package/dist/dialog/dialog-root.mjs +105 -0
- package/dist/dialog/dialog-root.mjs.map +1 -0
- package/dist/dialog/dialog-title.d.mts +23 -0
- package/dist/dialog/dialog-title.d.mts.map +1 -0
- package/dist/dialog/dialog-title.mjs +31 -0
- package/dist/dialog/dialog-title.mjs.map +1 -0
- package/dist/dialog/dialog-trigger.d.mts +39 -0
- package/dist/dialog/dialog-trigger.d.mts.map +1 -0
- package/dist/dialog/dialog-trigger.mjs +80 -0
- package/dist/dialog/dialog-trigger.mjs.map +1 -0
- package/dist/dialog/index.d.mts +28 -0
- package/dist/dialog/index.d.mts.map +1 -0
- package/dist/dialog/index.mjs +28 -0
- package/dist/dialog/index.mjs.map +1 -0
- package/dist/index.d.mts +38 -0
- package/dist/index.mjs +9 -0
- package/dist/internal/action-details.mjs +47 -0
- package/dist/internal/action-details.mjs.map +1 -0
- package/dist/internal/data-attr.mjs +13 -0
- package/dist/internal/data-attr.mjs.map +1 -0
- package/dist/internal/merge-props.mjs +119 -0
- package/dist/internal/merge-props.mjs.map +1 -0
- package/dist/internal/platform-attributes.d.mts +49 -0
- package/dist/internal/platform-attributes.d.mts.map +1 -0
- package/dist/internal/transition-boundary.mjs +52 -0
- package/dist/internal/transition-boundary.mjs.map +1 -0
- package/dist/internal/transition-types.mjs +15 -0
- package/dist/internal/transition-types.mjs.map +1 -0
- package/dist/internal/types.d.mts +38 -0
- package/dist/internal/types.d.mts.map +1 -0
- package/dist/internal/use-controllable-action.mjs +115 -0
- package/dist/internal/use-controllable-action.mjs.map +1 -0
- package/dist/internal/use-dev-warning.mjs +21 -0
- package/dist/internal/use-dev-warning.mjs.map +1 -0
- package/dist/internal/use-form-reset.mjs +50 -0
- package/dist/internal/use-form-reset.mjs.map +1 -0
- package/dist/internal/use-native-checked.mjs +113 -0
- package/dist/internal/use-native-checked.mjs.map +1 -0
- package/dist/internal/use-native-group-reconciliation.mjs +64 -0
- package/dist/internal/use-native-group-reconciliation.mjs.map +1 -0
- package/dist/internal/use-render.mjs +51 -0
- package/dist/internal/use-render.mjs.map +1 -0
- package/dist/internal/use-until-found.mjs +40 -0
- package/dist/internal/use-until-found.mjs.map +1 -0
- package/dist/radio-group/index.d.mts +20 -0
- package/dist/radio-group/index.d.mts.map +1 -0
- package/dist/radio-group/index.mjs +20 -0
- package/dist/radio-group/index.mjs.map +1 -0
- package/dist/radio-group/radio-group-context.mjs +13 -0
- package/dist/radio-group/radio-group-context.mjs.map +1 -0
- package/dist/radio-group/radio-group-item.d.mts +54 -0
- package/dist/radio-group/radio-group-item.d.mts.map +1 -0
- package/dist/radio-group/radio-group-item.mjs +88 -0
- package/dist/radio-group/radio-group-item.mjs.map +1 -0
- package/dist/radio-group/radio-group-label.d.mts +21 -0
- package/dist/radio-group/radio-group-label.d.mts.map +1 -0
- package/dist/radio-group/radio-group-label.mjs +30 -0
- package/dist/radio-group/radio-group-label.mjs.map +1 -0
- package/dist/radio-group/radio-group-root.d.mts +92 -0
- package/dist/radio-group/radio-group-root.d.mts.map +1 -0
- package/dist/radio-group/radio-group-root.mjs +137 -0
- package/dist/radio-group/radio-group-root.mjs.map +1 -0
- package/dist/switch/index.d.mts +3 -0
- package/dist/switch/index.mjs +1 -0
- package/dist/switch/switch.d.mts +78 -0
- package/dist/switch/switch.d.mts.map +1 -0
- package/dist/switch/switch.mjs +77 -0
- package/dist/switch/switch.mjs.map +1 -0
- package/dist/tabs/index.d.mts +24 -0
- package/dist/tabs/index.d.mts.map +1 -0
- package/dist/tabs/index.mjs +23 -0
- package/dist/tabs/index.mjs.map +1 -0
- package/dist/tabs/tabs-context.d.mts +7 -0
- package/dist/tabs/tabs-context.d.mts.map +1 -0
- package/dist/tabs/tabs-context.mjs +13 -0
- package/dist/tabs/tabs-context.mjs.map +1 -0
- package/dist/tabs/tabs-ids.mjs +39 -0
- package/dist/tabs/tabs-ids.mjs.map +1 -0
- package/dist/tabs/tabs-indicator.d.mts +32 -0
- package/dist/tabs/tabs-indicator.d.mts.map +1 -0
- package/dist/tabs/tabs-indicator.mjs +49 -0
- package/dist/tabs/tabs-indicator.mjs.map +1 -0
- package/dist/tabs/tabs-list.d.mts +34 -0
- package/dist/tabs/tabs-list.d.mts.map +1 -0
- package/dist/tabs/tabs-list.mjs +122 -0
- package/dist/tabs/tabs-list.mjs.map +1 -0
- package/dist/tabs/tabs-panel.d.mts +50 -0
- package/dist/tabs/tabs-panel.d.mts.map +1 -0
- package/dist/tabs/tabs-panel.mjs +81 -0
- package/dist/tabs/tabs-panel.mjs.map +1 -0
- package/dist/tabs/tabs-root.d.mts +64 -0
- package/dist/tabs/tabs-root.d.mts.map +1 -0
- package/dist/tabs/tabs-root.mjs +90 -0
- package/dist/tabs/tabs-root.mjs.map +1 -0
- package/dist/tabs/tabs-tab.d.mts +49 -0
- package/dist/tabs/tabs-tab.d.mts.map +1 -0
- package/dist/tabs/tabs-tab.mjs +86 -0
- package/dist/tabs/tabs-tab.mjs.map +1 -0
- package/dist/toggle/index.d.mts +3 -0
- package/dist/toggle/index.mjs +1 -0
- package/dist/toggle/toggle.d.mts +57 -0
- package/dist/toggle/toggle.d.mts.map +1 -0
- package/dist/toggle/toggle.mjs +59 -0
- package/dist/toggle/toggle.mjs.map +1 -0
- package/dist/tooltip/index.d.mts +20 -0
- package/dist/tooltip/index.d.mts.map +1 -0
- package/dist/tooltip/index.mjs +19 -0
- package/dist/tooltip/index.mjs.map +1 -0
- package/dist/tooltip/tooltip-context.d.mts +5 -0
- package/dist/tooltip/tooltip-context.d.mts.map +1 -0
- package/dist/tooltip/tooltip-context.mjs +13 -0
- package/dist/tooltip/tooltip-context.mjs.map +1 -0
- package/dist/tooltip/tooltip-popup.d.mts +49 -0
- package/dist/tooltip/tooltip-popup.d.mts.map +1 -0
- package/dist/tooltip/tooltip-popup.mjs +57 -0
- package/dist/tooltip/tooltip-popup.mjs.map +1 -0
- package/dist/tooltip/tooltip-root.d.mts +41 -0
- package/dist/tooltip/tooltip-root.d.mts.map +1 -0
- package/dist/tooltip/tooltip-root.mjs +86 -0
- package/dist/tooltip/tooltip-root.mjs.map +1 -0
- package/dist/tooltip/tooltip-trigger.d.mts +38 -0
- package/dist/tooltip/tooltip-trigger.d.mts.map +1 -0
- package/dist/tooltip/tooltip-trigger.mjs +55 -0
- package/dist/tooltip/tooltip-trigger.mjs.map +1 -0
- package/dist/tooltip/use-tooltip-interaction.mjs +131 -0
- package/dist/tooltip/use-tooltip-interaction.mjs.map +1 -0
- package/package.json +70 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog-title.d.mts","names":[],"sources":["../../src/dialog/dialog-title.tsx"],"mappings":";;;;YAOY,mBAAmB;iBAEd,yBAAyB,KACxC;EAGA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;EAC9C,WAAW,WAAW,WAAW;;EAEjC,SAAS,WAAW,6BAA6B;;;;;;;wBAQnC,cAAc,WAAW,OAAO,UAAU,WAAW,QAAQ,mBAAgB;yBAA7E"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
3
|
+
import { useDialogContext } from "./dialog-context.mjs";
|
|
4
|
+
//#region src/dialog/dialog-title.tsx
|
|
5
|
+
/**
|
|
6
|
+
* The dialog's name: an `<h2>` whose id the Popup references with `aria-labelledby`.
|
|
7
|
+
*
|
|
8
|
+
* Owned key (conventions 1.2): `id`.
|
|
9
|
+
*/
|
|
10
|
+
function DialogTitle({ className, style, children, render, ...rest }) {
|
|
11
|
+
const ctx = useDialogContext("Dialog.Title");
|
|
12
|
+
const state = {
|
|
13
|
+
open: ctx.committed,
|
|
14
|
+
modal: ctx.modal
|
|
15
|
+
};
|
|
16
|
+
return useRender({
|
|
17
|
+
defaultElement: "h2",
|
|
18
|
+
render,
|
|
19
|
+
state,
|
|
20
|
+
className,
|
|
21
|
+
style,
|
|
22
|
+
children,
|
|
23
|
+
props: rest,
|
|
24
|
+
libraryProps: { id: ctx.ids.title }
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
DialogTitle.displayName = "DialogTitle";
|
|
28
|
+
//#endregion
|
|
29
|
+
export { DialogTitle };
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=dialog-title.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog-title.mjs","names":[],"sources":["../../src/dialog/dialog-title.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport { useDialogContext } from \"./dialog-context.js\";\nimport type { DialogPopupState } from \"./dialog-popup.js\";\n\nexport type DialogTitleState = DialogPopupState;\n\nexport interface DialogTitleProps extends Omit<\n ComponentPropsWithRef<\"h2\">,\n \"id\" | \"className\" | \"style\" | \"children\"\n> {\n className?: StateValue<string | undefined, DialogTitleState>;\n style?: StateValue<CSSProperties | undefined, DialogTitleState>;\n children?: StateValue<ReactNode, DialogTitleState>;\n /** `render={<h3 />}` changes the heading level. */\n render?: RenderProp<ComponentPropsWithRef<\"h2\">, DialogTitleState>;\n}\n\n/**\n * The dialog's name: an `<h2>` whose id the Popup references with `aria-labelledby`.\n *\n * Owned key (conventions 1.2): `id`.\n */\nexport function DialogTitle({ className, style, children, render, ...rest }: DialogTitleProps) {\n const ctx = useDialogContext(\"Dialog.Title\");\n const state: DialogTitleState = { open: ctx.committed, modal: ctx.modal };\n return useRender<ComponentPropsWithRef<\"h2\">, DialogTitleState>({\n defaultElement: \"h2\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps: { id: ctx.ids.title },\n });\n}\n\nDialogTitle.displayName = \"DialogTitle\";\n"],"mappings":";;;;;;;;;AAyBA,SAAgB,YAAY,EAAE,WAAW,OAAO,UAAU,QAAQ,GAAG,QAA0B;CAC7F,MAAM,MAAM,iBAAiB,cAAc;CAC3C,MAAM,QAA0B;EAAE,MAAM,IAAI;EAAW,OAAO,IAAI;CAAM;CACxE,OAAO,UAAyD;EAC9D,gBAAgB;EAChB;EACA;EACA;EACA;EACA;EACA,OAAO;EACP,cAAc,EAAE,IAAI,IAAI,IAAI,MAAM;CACpC,CAAC;AACH;AAEA,YAAY,cAAc"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { RenderProp, StateValue } from "../internal/types.mjs";
|
|
2
|
+
import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
|
|
3
|
+
//#region src/dialog/dialog-trigger.d.ts
|
|
4
|
+
export interface DialogTriggerState {
|
|
5
|
+
/** Optimistic open state (library mode); `false` in JS-free mode. */
|
|
6
|
+
readonly open: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* The Root's transition is pending: an open in flight, a close notification in flight, or a
|
|
9
|
+
* re-open requested while a close notification is still settling.
|
|
10
|
+
*/
|
|
11
|
+
readonly pending: boolean;
|
|
12
|
+
readonly disabled: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface DialogTriggerProps extends Omit<ComponentPropsWithRef<"button">, "onClick" | "className" | "style" | "children"> {
|
|
15
|
+
/** Native `disabled`: a disabled button is not a valid invoker and never dispatches. */
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
className?: StateValue<string | undefined, DialogTriggerState>;
|
|
18
|
+
style?: StateValue<CSSProperties | undefined, DialogTriggerState>;
|
|
19
|
+
/** Rendered from optimistic state; must not suspend. */
|
|
20
|
+
children?: StateValue<ReactNode, DialogTriggerState>;
|
|
21
|
+
/** Should render a `<button>`; another element works only in library mode (click handler). */
|
|
22
|
+
render?: RenderProp<ComponentPropsWithRef<"button">, DialogTriggerState>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The opener: `<button type="button" commandfor command="show-modal">`. In JS-free mode the
|
|
26
|
+
* browser runs the command. In library mode the click is cancelled (so the command does not run)
|
|
27
|
+
* and dispatched through the Root's transition; the button shows optimistic `data-open` and
|
|
28
|
+
* `data-pending` until the dialog has opened. Non-modal dialogs have no command and always use a
|
|
29
|
+
* click handler (`show()`).
|
|
30
|
+
*
|
|
31
|
+
* Owned keys (conventions 1.2): `type` (on a `<button>` only), `disabled`, `commandfor`,
|
|
32
|
+
* `command`, `onClick`, `data-open`, `data-pending`, `data-disabled`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function DialogTrigger({ disabled, className, style, children, render, ...rest }: DialogTriggerProps): ReactNode;
|
|
35
|
+
export declare namespace DialogTrigger {
|
|
36
|
+
var displayName: string;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//# sourceMappingURL=dialog-trigger.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog-trigger.d.mts","names":[],"sources":["../../src/dialog/dialog-trigger.tsx"],"mappings":";;;iBASiB;;WAEN;;;;;WAKA;WACA;;iBAGM,2BAA2B,KAC1C;;EAIA;EACA,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;;EAE9C,WAAW,WAAW,WAAW;;EAEjC,SAAS,WAAW,iCAAiC;;;;;;;;;;;;wBAevC,gBACd,UACA,WACA,OACA,UACA,WACG,QACF,qBAAkB;yBAPL"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { dataAttr } from "../internal/data-attr.mjs";
|
|
3
|
+
import { rendersButton, useRender } from "../internal/use-render.mjs";
|
|
4
|
+
import { useDialogContext } from "./dialog-context.mjs";
|
|
5
|
+
import { useCallback, useEffect } from "react";
|
|
6
|
+
//#region src/dialog/dialog-trigger.tsx
|
|
7
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
8
|
+
/**
|
|
9
|
+
* The opener: `<button type="button" commandfor command="show-modal">`. In JS-free mode the
|
|
10
|
+
* browser runs the command. In library mode the click is cancelled (so the command does not run)
|
|
11
|
+
* and dispatched through the Root's transition; the button shows optimistic `data-open` and
|
|
12
|
+
* `data-pending` until the dialog has opened. Non-modal dialogs have no command and always use a
|
|
13
|
+
* click handler (`show()`).
|
|
14
|
+
*
|
|
15
|
+
* Owned keys (conventions 1.2): `type` (on a `<button>` only), `disabled`, `commandfor`,
|
|
16
|
+
* `command`, `onClick`, `data-open`, `data-pending`, `data-disabled`.
|
|
17
|
+
*/
|
|
18
|
+
function DialogTrigger({ disabled = false, className, style, children, render, ...rest }) {
|
|
19
|
+
const ctx = useDialogContext("Dialog.Trigger");
|
|
20
|
+
const isLibrary = ctx.mode === "library";
|
|
21
|
+
const { modal, ids, triggerRef, dialogRef } = ctx;
|
|
22
|
+
const state = {
|
|
23
|
+
open: ctx.optimistic,
|
|
24
|
+
pending: ctx.pending,
|
|
25
|
+
disabled
|
|
26
|
+
};
|
|
27
|
+
const libraryRef = useCallback((element) => {
|
|
28
|
+
if (isDev && !isLibrary && modal && element.tagName !== "BUTTON") console.error(`Dialog.Trigger: rendered a <${element.tagName.toLowerCase()}> in JS-free mode. Only a <button> runs \`command="show-modal"\`; this trigger will not open the dialog. Render a <button>, or put the Dialog in library mode (\`defaultOpen={false}\`).`);
|
|
29
|
+
triggerRef.current = element;
|
|
30
|
+
return () => {
|
|
31
|
+
if (triggerRef.current === element) triggerRef.current = null;
|
|
32
|
+
};
|
|
33
|
+
}, [
|
|
34
|
+
isLibrary,
|
|
35
|
+
modal,
|
|
36
|
+
triggerRef
|
|
37
|
+
]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!isDev) return;
|
|
40
|
+
if (document.getElementById(ids.dialog) === null) console.error("Dialog.Trigger: no Dialog.Popup is rendered for this Dialog.Root; the trigger opens nothing.");
|
|
41
|
+
}, [ids.dialog]);
|
|
42
|
+
const installClick = isLibrary || !modal;
|
|
43
|
+
const onClick = (event) => {
|
|
44
|
+
if (isLibrary) {
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
if (disabled) return;
|
|
47
|
+
ctx.requestOpen(event.nativeEvent, "activate");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (disabled) return;
|
|
51
|
+
const dialog = dialogRef.current;
|
|
52
|
+
if (dialog !== null && !dialog.open && dialog.isConnected) dialog.show();
|
|
53
|
+
};
|
|
54
|
+
const libraryProps = {
|
|
55
|
+
...rendersButton(render) && { type: "button" },
|
|
56
|
+
disabled,
|
|
57
|
+
commandfor: modal ? ids.dialog : void 0,
|
|
58
|
+
command: modal ? "show-modal" : void 0,
|
|
59
|
+
...installClick && { onClick },
|
|
60
|
+
"data-open": dataAttr(state.open),
|
|
61
|
+
"data-pending": dataAttr(state.pending),
|
|
62
|
+
"data-disabled": dataAttr(isLibrary && disabled)
|
|
63
|
+
};
|
|
64
|
+
return useRender({
|
|
65
|
+
defaultElement: "button",
|
|
66
|
+
render,
|
|
67
|
+
state,
|
|
68
|
+
className,
|
|
69
|
+
style,
|
|
70
|
+
children,
|
|
71
|
+
props: rest,
|
|
72
|
+
libraryProps,
|
|
73
|
+
ref: libraryRef
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
DialogTrigger.displayName = "DialogTrigger";
|
|
77
|
+
//#endregion
|
|
78
|
+
export { DialogTrigger };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=dialog-trigger.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog-trigger.mjs","names":[],"sources":["../../src/dialog/dialog-trigger.tsx"],"sourcesContent":["\"use client\";\nimport { useCallback, useEffect } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport { useDialogContext } from \"./dialog-context.js\";\n\nexport interface DialogTriggerState {\n /** Optimistic open state (library mode); `false` in JS-free mode. */\n readonly open: boolean;\n /**\n * The Root's transition is pending: an open in flight, a close notification in flight, or a\n * re-open requested while a close notification is still settling.\n */\n readonly pending: boolean;\n readonly disabled: boolean;\n}\n\nexport interface DialogTriggerProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"className\" | \"style\" | \"children\"\n> {\n /** Native `disabled`: a disabled button is not a valid invoker and never dispatches. */\n disabled?: boolean;\n className?: StateValue<string | undefined, DialogTriggerState>;\n style?: StateValue<CSSProperties | undefined, DialogTriggerState>;\n /** Rendered from optimistic state; must not suspend. */\n children?: StateValue<ReactNode, DialogTriggerState>;\n /** Should render a `<button>`; another element works only in library mode (click handler). */\n render?: RenderProp<ComponentPropsWithRef<\"button\">, DialogTriggerState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\n/**\n * The opener: `<button type=\"button\" commandfor command=\"show-modal\">`. In JS-free mode the\n * browser runs the command. In library mode the click is cancelled (so the command does not run)\n * and dispatched through the Root's transition; the button shows optimistic `data-open` and\n * `data-pending` until the dialog has opened. Non-modal dialogs have no command and always use a\n * click handler (`show()`).\n *\n * Owned keys (conventions 1.2): `type` (on a `<button>` only), `disabled`, `commandfor`,\n * `command`, `onClick`, `data-open`, `data-pending`, `data-disabled`.\n */\nexport function DialogTrigger({\n disabled = false,\n className,\n style,\n children,\n render,\n ...rest\n}: DialogTriggerProps) {\n const ctx = useDialogContext(\"Dialog.Trigger\");\n const isLibrary = ctx.mode === \"library\";\n const { modal, ids, triggerRef, dialogRef } = ctx;\n\n const state: DialogTriggerState = {\n open: ctx.optimistic,\n // Every Root dispatch is an open or a close notification and both belong to the Trigger\n // (design 4.2). Not `optimistic !== committed`: a re-open while a close notification is\n // still settling has both `true` (the close never committed) and is pending all the same.\n pending: ctx.pending,\n disabled,\n };\n\n const libraryRef = useCallback(\n (element: HTMLElement) => {\n if (isDev && !isLibrary && modal && element.tagName !== \"BUTTON\") {\n console.error(\n `Dialog.Trigger: rendered a <${element.tagName.toLowerCase()}> in JS-free mode. Only a ` +\n '<button> runs `command=\"show-modal\"`; this trigger will not open the dialog. Render ' +\n \"a <button>, or put the Dialog in library mode (`defaultOpen={false}`).\",\n );\n }\n triggerRef.current = element;\n return () => {\n if (triggerRef.current === element) triggerRef.current = null;\n };\n },\n [isLibrary, modal, triggerRef],\n );\n\n // A Trigger without a Popup opens nothing (design 14, dev warnings).\n useEffect(() => {\n if (!isDev) return;\n if (document.getElementById(ids.dialog) === null) {\n console.error(\n \"Dialog.Trigger: no Dialog.Popup is rendered for this Dialog.Root; the trigger opens nothing.\",\n );\n }\n }, [ids.dialog]);\n\n // Library mode (both modal and non-modal) and non-modal JS-free mode need a click handler;\n // modal JS-free mode is the browser's command.\n const installClick = isLibrary || !modal;\n const onClick = (event: MouseEvent<HTMLElement>) => {\n if (isLibrary) {\n // Cancelling the click cancels the command (it runs as the button's activation\n // behaviour, only if the click was not cancelled).\n event.preventDefault();\n if (disabled) return;\n ctx.requestOpen(event.nativeEvent, \"activate\");\n return;\n }\n if (disabled) return;\n const dialog = dialogRef.current;\n if (dialog !== null && !dialog.open && dialog.isConnected) dialog.show();\n };\n\n const libraryProps: ComponentPropsWithRef<\"button\"> & DataAttributes = {\n // `type` only applies to a <button>; on any other element the key is not owned.\n ...(rendersButton(render) && { type: \"button\" as const }),\n // Owned: a render element must not re-enable a disabled Trigger (in JS-free mode the\n // browser would run its command).\n disabled,\n commandfor: modal ? ids.dialog : undefined,\n command: modal ? \"show-modal\" : undefined,\n // Only owned when installed, so a render element keeps its own `onClick` in modal JS-free\n // mode (Accordion's rule).\n ...(installClick && { onClick }),\n \"data-open\": dataAttr(state.open),\n \"data-pending\": dataAttr(state.pending),\n \"data-disabled\": dataAttr(isLibrary && disabled),\n };\n\n return useRender<ComponentPropsWithRef<\"button\">, DialogTriggerState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps,\n ref: libraryRef,\n });\n}\n\nDialogTrigger.displayName = \"DialogTrigger\";\n"],"mappings":";;;;;;AAkCA,MAAM,QAAQ,QAAQ,IAAI,aAAa;;;;;;;;;;;AAYvC,SAAgB,cAAc,EAC5B,WAAW,OACX,WACA,OACA,UACA,QACA,GAAG,QACkB;CACrB,MAAM,MAAM,iBAAiB,gBAAgB;CAC7C,MAAM,YAAY,IAAI,SAAS;CAC/B,MAAM,EAAE,OAAO,KAAK,YAAY,cAAc;CAE9C,MAAM,QAA4B;EAChC,MAAM,IAAI;EAIV,SAAS,IAAI;EACb;CACF;CAEA,MAAM,aAAa,aAChB,YAAyB;EACxB,IAAI,SAAS,CAAC,aAAa,SAAS,QAAQ,YAAY,UACtD,QAAQ,MACN,+BAA+B,QAAQ,QAAQ,YAAY,EAAE,yLAG/D;EAEF,WAAW,UAAU;EACrB,aAAa;GACX,IAAI,WAAW,YAAY,SAAS,WAAW,UAAU;EAC3D;CACF,GACA;EAAC;EAAW;EAAO;CAAU,CAC/B;CAGA,gBAAgB;EACd,IAAI,CAAC,OAAO;EACZ,IAAI,SAAS,eAAe,IAAI,MAAM,MAAM,MAC1C,QAAQ,MACN,8FACF;CAEJ,GAAG,CAAC,IAAI,MAAM,CAAC;CAIf,MAAM,eAAe,aAAa,CAAC;CACnC,MAAM,WAAW,UAAmC;EAClD,IAAI,WAAW;GAGb,MAAM,eAAe;GACrB,IAAI,UAAU;GACd,IAAI,YAAY,MAAM,aAAa,UAAU;GAC7C;EACF;EACA,IAAI,UAAU;EACd,MAAM,SAAS,UAAU;EACzB,IAAI,WAAW,QAAQ,CAAC,OAAO,QAAQ,OAAO,aAAa,OAAO,KAAK;CACzE;CAEA,MAAM,eAAiE;EAErE,GAAI,cAAc,MAAM,KAAK,EAAE,MAAM,SAAkB;EAGvD;EACA,YAAY,QAAQ,IAAI,SAAS,KAAA;EACjC,SAAS,QAAQ,eAAe,KAAA;EAGhC,GAAI,gBAAgB,EAAE,QAAQ;EAC9B,aAAa,SAAS,MAAM,IAAI;EAChC,gBAAgB,SAAS,MAAM,OAAO;EACtC,iBAAiB,SAAS,aAAa,QAAQ;CACjD;CAEA,OAAO,UAA+D;EACpE,gBAAgB;EAChB;EACA;EACA;EACA;EACA;EACA,OAAO;EACP;EACA,KAAK;CACP,CAAC;AACH;AAEA,cAAc,cAAc"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "../internal/platform-attributes.mjs";
|
|
2
|
+
import { DialogClose, DialogCloseDetails, DialogCloseProps, DialogCloseState } from "./dialog-close.mjs";
|
|
3
|
+
import { DialogPopup, DialogPopupProps, DialogPopupState } from "./dialog-popup.mjs";
|
|
4
|
+
import { DialogDescription, DialogDescriptionProps, DialogDescriptionState } from "./dialog-description.mjs";
|
|
5
|
+
import { DialogForm, DialogFormProps, DialogFormState } from "./dialog-form.mjs";
|
|
6
|
+
import { DialogOpenChangeDetails, DialogRoot, DialogRootProps, DialogRootState } from "./dialog-root.mjs";
|
|
7
|
+
import { DialogTitle, DialogTitleProps, DialogTitleState } from "./dialog-title.mjs";
|
|
8
|
+
import { DialogTrigger, DialogTriggerProps, DialogTriggerState } from "./dialog-trigger.mjs";
|
|
9
|
+
//#region src/dialog/index.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* Dialog built on `<dialog>` and Invoker Commands: `Root` (no DOM) > `Trigger`
|
|
12
|
+
* (`button[command=show-modal]`) + `Popup` (`dialog`) > `Title`, `Description`, `Form`, `Close`.
|
|
13
|
+
* JS-free when the Root has none of `open` / `defaultOpen` / `openChangeAction`; otherwise
|
|
14
|
+
* opening is a transition (pending Trigger, content from committed state) and closing is the
|
|
15
|
+
* browser's, notified through `openChangeAction(false)`.
|
|
16
|
+
*/
|
|
17
|
+
export declare const Dialog: {
|
|
18
|
+
readonly Root: typeof DialogRoot;
|
|
19
|
+
readonly Trigger: typeof DialogTrigger;
|
|
20
|
+
readonly Popup: typeof DialogPopup;
|
|
21
|
+
readonly Close: typeof DialogClose;
|
|
22
|
+
readonly Form: typeof DialogForm;
|
|
23
|
+
readonly Title: typeof DialogTitle;
|
|
24
|
+
readonly Description: typeof DialogDescription;
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export type { DialogCloseDetails, DialogCloseProps, DialogCloseState, DialogDescriptionProps, DialogDescriptionState, DialogFormProps, DialogFormState, DialogOpenChangeDetails, DialogPopupProps, DialogPopupState, DialogRootProps, DialogRootState, DialogTitleProps, DialogTitleState, DialogTriggerProps, DialogTriggerState };
|
|
28
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/dialog/index.ts"],"mappings":";;;;;;;;;;;;;;;;qBAkBa;WACX,aAAI;WACJ,gBAAO;WACP,cAAK;WACL,cAAK;WACL,aAAI;WACJ,cAAK;WACL,oBAAW"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DialogClose } from "./dialog-close.mjs";
|
|
2
|
+
import { DialogDescription } from "./dialog-description.mjs";
|
|
3
|
+
import { DialogForm } from "./dialog-form.mjs";
|
|
4
|
+
import { DialogPopup } from "./dialog-popup.mjs";
|
|
5
|
+
import { DialogRoot } from "./dialog-root.mjs";
|
|
6
|
+
import { DialogTitle } from "./dialog-title.mjs";
|
|
7
|
+
import { DialogTrigger } from "./dialog-trigger.mjs";
|
|
8
|
+
//#region src/dialog/index.ts
|
|
9
|
+
/**
|
|
10
|
+
* Dialog built on `<dialog>` and Invoker Commands: `Root` (no DOM) > `Trigger`
|
|
11
|
+
* (`button[command=show-modal]`) + `Popup` (`dialog`) > `Title`, `Description`, `Form`, `Close`.
|
|
12
|
+
* JS-free when the Root has none of `open` / `defaultOpen` / `openChangeAction`; otherwise
|
|
13
|
+
* opening is a transition (pending Trigger, content from committed state) and closing is the
|
|
14
|
+
* browser's, notified through `openChangeAction(false)`.
|
|
15
|
+
*/
|
|
16
|
+
const Dialog = {
|
|
17
|
+
Root: DialogRoot,
|
|
18
|
+
Trigger: DialogTrigger,
|
|
19
|
+
Popup: DialogPopup,
|
|
20
|
+
Close: DialogClose,
|
|
21
|
+
Form: DialogForm,
|
|
22
|
+
Title: DialogTitle,
|
|
23
|
+
Description: DialogDescription
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { Dialog };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/dialog/index.ts"],"sourcesContent":["// Ships the platform attribute typings (`command`, `commandfor`) with this subpath\n// (conventions 7.4). Type-only: the built JS has no import of it.\nimport \"../internal/platform-attributes.js\";\nimport { DialogClose } from \"./dialog-close.js\";\nimport { DialogDescription } from \"./dialog-description.js\";\nimport { DialogForm } from \"./dialog-form.js\";\nimport { DialogPopup } from \"./dialog-popup.js\";\nimport { DialogRoot } from \"./dialog-root.js\";\nimport { DialogTitle } from \"./dialog-title.js\";\nimport { DialogTrigger } from \"./dialog-trigger.js\";\n\n/**\n * Dialog built on `<dialog>` and Invoker Commands: `Root` (no DOM) > `Trigger`\n * (`button[command=show-modal]`) + `Popup` (`dialog`) > `Title`, `Description`, `Form`, `Close`.\n * JS-free when the Root has none of `open` / `defaultOpen` / `openChangeAction`; otherwise\n * opening is a transition (pending Trigger, content from committed state) and closing is the\n * browser's, notified through `openChangeAction(false)`.\n */\nexport const Dialog = {\n Root: DialogRoot,\n Trigger: DialogTrigger,\n Popup: DialogPopup,\n Close: DialogClose,\n Form: DialogForm,\n Title: DialogTitle,\n Description: DialogDescription,\n} as const;\n\nexport type { DialogRootProps, DialogRootState, DialogOpenChangeDetails } from \"./dialog-root.js\";\nexport type { DialogTriggerProps, DialogTriggerState } from \"./dialog-trigger.js\";\nexport type { DialogPopupProps, DialogPopupState } from \"./dialog-popup.js\";\nexport type { DialogCloseProps, DialogCloseState, DialogCloseDetails } from \"./dialog-close.js\";\nexport type { DialogFormProps, DialogFormState } from \"./dialog-form.js\";\nexport type { DialogTitleProps, DialogTitleState } from \"./dialog-title.js\";\nexport type { DialogDescriptionProps, DialogDescriptionState } from \"./dialog-description.js\";\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,MAAa,SAAS;CACpB,MAAM;CACN,SAAS;CACT,OAAO;CACP,OAAO;CACP,MAAM;CACN,OAAO;CACP,aAAa;AACf"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import "./internal/platform-attributes.mjs";
|
|
2
|
+
import { Action, ActionDetails, ChangeAction, ChangeReason, RenderProp, StateValue } from "./internal/types.mjs";
|
|
3
|
+
import { AccordionItemProps, AccordionItemState } from "./accordion/accordion-item.mjs";
|
|
4
|
+
import { AccordionPanelProps, AccordionPanelState } from "./accordion/accordion-panel.mjs";
|
|
5
|
+
import { AccordionRootExclusiveProps, AccordionRootMultipleProps, AccordionRootProps, AccordionRootState, AccordionValueChangeDetails } from "./accordion/accordion-root.mjs";
|
|
6
|
+
import { AccordionTriggerProps, AccordionTriggerState } from "./accordion/accordion-trigger.mjs";
|
|
7
|
+
import { Accordion } from "./accordion/index.mjs";
|
|
8
|
+
import { Checkbox, CheckboxCheckedChangeDetails, CheckboxProps, CheckboxState } from "./checkbox/checkbox.mjs";
|
|
9
|
+
import "./checkbox/index.mjs";
|
|
10
|
+
import { DialogCloseDetails, DialogCloseProps, DialogCloseState } from "./dialog/dialog-close.mjs";
|
|
11
|
+
import { DialogPopupProps, DialogPopupState } from "./dialog/dialog-popup.mjs";
|
|
12
|
+
import { DialogDescriptionProps, DialogDescriptionState } from "./dialog/dialog-description.mjs";
|
|
13
|
+
import { DialogFormProps, DialogFormState } from "./dialog/dialog-form.mjs";
|
|
14
|
+
import { DialogOpenChangeDetails, DialogRootProps, DialogRootState } from "./dialog/dialog-root.mjs";
|
|
15
|
+
import { DialogTitleProps, DialogTitleState } from "./dialog/dialog-title.mjs";
|
|
16
|
+
import { DialogTriggerProps, DialogTriggerState } from "./dialog/dialog-trigger.mjs";
|
|
17
|
+
import { Dialog } from "./dialog/index.mjs";
|
|
18
|
+
import { Toggle, TogglePressedChangeDetails, ToggleProps, ToggleState } from "./toggle/toggle.mjs";
|
|
19
|
+
import "./toggle/index.mjs";
|
|
20
|
+
import { TabsActivationMode, TabsOrientation } from "./tabs/tabs-context.mjs";
|
|
21
|
+
import { TabsIndicatorProps, TabsIndicatorState } from "./tabs/tabs-indicator.mjs";
|
|
22
|
+
import { TabsListProps, TabsListState } from "./tabs/tabs-list.mjs";
|
|
23
|
+
import { TabsPanelProps, TabsPanelState } from "./tabs/tabs-panel.mjs";
|
|
24
|
+
import { TabsRootProps, TabsRootState, TabsValueChangeDetails } from "./tabs/tabs-root.mjs";
|
|
25
|
+
import { TabsTabProps, TabsTabState } from "./tabs/tabs-tab.mjs";
|
|
26
|
+
import { Tabs } from "./tabs/index.mjs";
|
|
27
|
+
import { TooltipAlign, TooltipPopupProps, TooltipPopupState, TooltipSide } from "./tooltip/tooltip-popup.mjs";
|
|
28
|
+
import { TooltipProvides } from "./tooltip/tooltip-context.mjs";
|
|
29
|
+
import { TooltipRootProps, TooltipRootState } from "./tooltip/tooltip-root.mjs";
|
|
30
|
+
import { TooltipTriggerProps, TooltipTriggerState } from "./tooltip/tooltip-trigger.mjs";
|
|
31
|
+
import { Tooltip } from "./tooltip/index.mjs";
|
|
32
|
+
import { Switch, SwitchCheckedChangeDetails, SwitchProps, SwitchState } from "./switch/switch.mjs";
|
|
33
|
+
import "./switch/index.mjs";
|
|
34
|
+
import { RadioGroupItemProps, RadioGroupItemState } from "./radio-group/radio-group-item.mjs";
|
|
35
|
+
import { RadioGroupRootProps, RadioGroupRootState, RadioGroupValueChangeDetails } from "./radio-group/radio-group-root.mjs";
|
|
36
|
+
import { RadioGroupLabelProps } from "./radio-group/radio-group-label.mjs";
|
|
37
|
+
import { RadioGroup } from "./radio-group/index.mjs";
|
|
38
|
+
export { Accordion, type AccordionItemProps, type AccordionItemState, type AccordionPanelProps, type AccordionPanelState, type AccordionRootExclusiveProps, type AccordionRootMultipleProps, type AccordionRootProps, type AccordionRootState, type AccordionTriggerProps, type AccordionTriggerState, type AccordionValueChangeDetails, type Action, type ActionDetails, type ChangeAction, type ChangeReason, Checkbox, type CheckboxCheckedChangeDetails, type CheckboxProps, type CheckboxState, Dialog, type DialogCloseDetails, type DialogCloseProps, type DialogCloseState, type DialogDescriptionProps, type DialogDescriptionState, type DialogFormProps, type DialogFormState, type DialogOpenChangeDetails, type DialogPopupProps, type DialogPopupState, type DialogRootProps, type DialogRootState, type DialogTitleProps, type DialogTitleState, type DialogTriggerProps, type DialogTriggerState, RadioGroup, type RadioGroupItemProps, type RadioGroupItemState, type RadioGroupLabelProps, type RadioGroupRootProps, type RadioGroupRootState, type RadioGroupValueChangeDetails, type RenderProp, type StateValue, Switch, type SwitchCheckedChangeDetails, type SwitchProps, type SwitchState, Tabs, type TabsActivationMode, type TabsIndicatorProps, type TabsIndicatorState, type TabsListProps, type TabsListState, type TabsOrientation, type TabsPanelProps, type TabsPanelState, type TabsRootProps, type TabsRootState, type TabsTabProps, type TabsTabState, type TabsValueChangeDetails, Toggle, type TogglePressedChangeDetails, type ToggleProps, type ToggleState, Tooltip, type TooltipAlign, type TooltipPopupProps, type TooltipPopupState, type TooltipProvides, type TooltipRootProps, type TooltipRootState, type TooltipSide, type TooltipTriggerProps, type TooltipTriggerState };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Toggle } from "./toggle/toggle.mjs";
|
|
2
|
+
import { Accordion } from "./accordion/index.mjs";
|
|
3
|
+
import { Tabs } from "./tabs/index.mjs";
|
|
4
|
+
import { Tooltip } from "./tooltip/index.mjs";
|
|
5
|
+
import { Switch } from "./switch/switch.mjs";
|
|
6
|
+
import { Checkbox } from "./checkbox/checkbox.mjs";
|
|
7
|
+
import { Dialog } from "./dialog/index.mjs";
|
|
8
|
+
import { RadioGroup } from "./radio-group/index.mjs";
|
|
9
|
+
export { Accordion, Checkbox, Dialog, RadioGroup, Switch, Tabs, Toggle, Tooltip };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/internal/action-details.ts
|
|
2
|
+
function isDev() {
|
|
3
|
+
return process.env.NODE_ENV !== "production";
|
|
4
|
+
}
|
|
5
|
+
function rejectEventWrite() {
|
|
6
|
+
throw new TypeError("`details.event` is a read-only virtual property; it cannot be assigned or defined. Keep the DOM event out of `details` so that it stays serialisable.");
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Builds the `details` argument of an action (conventions 2.2).
|
|
10
|
+
*
|
|
11
|
+
* `fields` is a plain, extensible object of serialisable component-specific fields. `event` is a
|
|
12
|
+
* virtual, non-own property served by a Proxy: `details.event` and `"event" in details` work,
|
|
13
|
+
* while `Object.keys`, spread, `JSON.stringify` and React's Server Function serialiser see only
|
|
14
|
+
* the real fields. That is what lets a Server Function be passed directly as an action.
|
|
15
|
+
*
|
|
16
|
+
* Writing `event` (`details.event = x`, `Object.defineProperty(details, "event", ...)`) is
|
|
17
|
+
* rejected so that an own, enumerable `event` can never appear: in development it throws a
|
|
18
|
+
* `TypeError`; in production an assignment is ignored and a `defineProperty` is declined (which
|
|
19
|
+
* makes `Object.defineProperty` throw and `Reflect.defineProperty` return `false`).
|
|
20
|
+
*
|
|
21
|
+
* No `"use client"` directive: this file uses no client-only API, so it is importable from
|
|
22
|
+
* anywhere (conventions 7.1).
|
|
23
|
+
*/
|
|
24
|
+
function createActionDetails(event, fields) {
|
|
25
|
+
return new Proxy(fields, {
|
|
26
|
+
get: (target, key, receiver) => key === "event" ? event : Reflect.get(target, key, receiver),
|
|
27
|
+
has: (target, key) => key === "event" || Reflect.has(target, key),
|
|
28
|
+
set: (target, key, value, receiver) => {
|
|
29
|
+
if (key === "event") {
|
|
30
|
+
if (isDev()) rejectEventWrite();
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return Reflect.set(target, key, value, receiver);
|
|
34
|
+
},
|
|
35
|
+
defineProperty: (target, key, descriptor) => {
|
|
36
|
+
if (key === "event") {
|
|
37
|
+
if (isDev()) rejectEventWrite();
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return Reflect.defineProperty(target, key, descriptor);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { createActionDetails };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=action-details.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-details.mjs","names":[],"sources":["../../src/internal/action-details.ts"],"sourcesContent":["import type { ActionDetails } from \"./types.js\";\n\nfunction isDev(): boolean {\n return process.env.NODE_ENV !== \"production\";\n}\n\nfunction rejectEventWrite(): never {\n throw new TypeError(\n \"`details.event` is a read-only virtual property; it cannot be assigned or defined. \" +\n \"Keep the DOM event out of `details` so that it stays serialisable.\",\n );\n}\n\n/**\n * Builds the `details` argument of an action (conventions 2.2).\n *\n * `fields` is a plain, extensible object of serialisable component-specific fields. `event` is a\n * virtual, non-own property served by a Proxy: `details.event` and `\"event\" in details` work,\n * while `Object.keys`, spread, `JSON.stringify` and React's Server Function serialiser see only\n * the real fields. That is what lets a Server Function be passed directly as an action.\n *\n * Writing `event` (`details.event = x`, `Object.defineProperty(details, \"event\", ...)`) is\n * rejected so that an own, enumerable `event` can never appear: in development it throws a\n * `TypeError`; in production an assignment is ignored and a `defineProperty` is declined (which\n * makes `Object.defineProperty` throw and `Reflect.defineProperty` return `false`).\n *\n * No `\"use client\"` directive: this file uses no client-only API, so it is importable from\n * anywhere (conventions 7.1).\n */\nexport function createActionDetails<T extends object>(\n event: Event | undefined,\n fields: T,\n): T & ActionDetails {\n return new Proxy(fields, {\n get: (target, key, receiver) => (key === \"event\" ? event : Reflect.get(target, key, receiver)),\n has: (target, key) => key === \"event\" || Reflect.has(target, key),\n set: (target, key, value, receiver) => {\n if (key === \"event\") {\n if (isDev()) rejectEventWrite();\n return true;\n }\n return Reflect.set(target, key, value, receiver);\n },\n defineProperty: (target, key, descriptor) => {\n if (key === \"event\") {\n if (isDev()) rejectEventWrite();\n return false;\n }\n return Reflect.defineProperty(target, key, descriptor);\n },\n }) as T & ActionDetails;\n}\n"],"mappings":";AAEA,SAAS,QAAiB;CACxB,OAAO,QAAQ,IAAI,aAAa;AAClC;AAEA,SAAS,mBAA0B;CACjC,MAAM,IAAI,UACR,uJAEF;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,oBACd,OACA,QACmB;CACnB,OAAO,IAAI,MAAM,QAAQ;EACvB,MAAM,QAAQ,KAAK,aAAc,QAAQ,UAAU,QAAQ,QAAQ,IAAI,QAAQ,KAAK,QAAQ;EAC5F,MAAM,QAAQ,QAAQ,QAAQ,WAAW,QAAQ,IAAI,QAAQ,GAAG;EAChE,MAAM,QAAQ,KAAK,OAAO,aAAa;GACrC,IAAI,QAAQ,SAAS;IACnB,IAAI,MAAM,GAAG,iBAAiB;IAC9B,OAAO;GACT;GACA,OAAO,QAAQ,IAAI,QAAQ,KAAK,OAAO,QAAQ;EACjD;EACA,iBAAiB,QAAQ,KAAK,eAAe;GAC3C,IAAI,QAAQ,SAAS;IACnB,IAAI,MAAM,GAAG,iBAAiB;IAC9B,OAAO;GACT;GACA,OAAO,QAAQ,eAAe,QAAQ,KAAK,UAAU;EACvD;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/internal/data-attr.ts
|
|
2
|
+
/**
|
|
3
|
+
* Boolean data attributes are emitted by presence: `data-x=""` when true, absent when false.
|
|
4
|
+
* react-dom would stringify `true` as `"true"`, so this helper is the only place the presence
|
|
5
|
+
* form is spelled out (conventions 4.1).
|
|
6
|
+
*/
|
|
7
|
+
function dataAttr(flag) {
|
|
8
|
+
return flag ? "" : void 0;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { dataAttr };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=data-attr.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-attr.mjs","names":[],"sources":["../../src/internal/data-attr.ts"],"sourcesContent":["/**\n * Boolean data attributes are emitted by presence: `data-x=\"\"` when true, absent when false.\n * react-dom would stringify `true` as `\"true\"`, so this helper is the only place the presence\n * form is spelled out (conventions 4.1).\n */\nexport function dataAttr(flag: boolean): \"\" | undefined {\n return flag ? \"\" : undefined;\n}\n"],"mappings":";;;;;;AAKA,SAAgB,SAAS,MAA+B;CACtD,OAAO,OAAO,KAAK,KAAA;AACrB"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
//#region src/internal/merge-props.ts
|
|
2
|
+
/**
|
|
3
|
+
* ARIA id-reference lists are merged as token lists rather than overridden (conventions 1.2), so
|
|
4
|
+
* a trigger can be described by more than the element the library wires it to.
|
|
5
|
+
*/
|
|
6
|
+
const ID_REFERENCE_LISTS = /* @__PURE__ */ new Set([
|
|
7
|
+
"aria-labelledby",
|
|
8
|
+
"aria-describedby",
|
|
9
|
+
"aria-controls",
|
|
10
|
+
"aria-owns"
|
|
11
|
+
]);
|
|
12
|
+
function isIdReferenceList(key) {
|
|
13
|
+
return ID_REFERENCE_LISTS.has(key);
|
|
14
|
+
}
|
|
15
|
+
function isEventHandler(key, value) {
|
|
16
|
+
return typeof value === "function" && /^on[A-Z]/.test(key);
|
|
17
|
+
}
|
|
18
|
+
function isObjectRef(ref) {
|
|
19
|
+
return typeof ref === "object" && ref !== null && "current" in ref;
|
|
20
|
+
}
|
|
21
|
+
function attachRef(ref, node) {
|
|
22
|
+
if (ref === null || ref === void 0) return void 0;
|
|
23
|
+
if (typeof ref === "function") {
|
|
24
|
+
const cleanup = ref(node);
|
|
25
|
+
return typeof cleanup === "function" ? cleanup : () => ref(null);
|
|
26
|
+
}
|
|
27
|
+
if (isObjectRef(ref)) {
|
|
28
|
+
ref.current = node;
|
|
29
|
+
return () => {
|
|
30
|
+
ref.current = null;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Merges several refs into one callback ref. The callback returns a cleanup function (React 19),
|
|
36
|
+
* so each inner ref is detached through its own cleanup (callback refs that returned one) or by
|
|
37
|
+
* being set to `null`.
|
|
38
|
+
*/
|
|
39
|
+
function mergeRefs(...refs) {
|
|
40
|
+
return (node) => {
|
|
41
|
+
const cleanups = refs.map((ref) => attachRef(ref, node));
|
|
42
|
+
return () => {
|
|
43
|
+
for (const cleanup of cleanups) cleanup?.();
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Joins two space-separated id lists, `first` tokens first, without duplicates. */
|
|
48
|
+
function mergeTokenLists(first, second) {
|
|
49
|
+
const tokens = [];
|
|
50
|
+
for (const list of [first, second]) {
|
|
51
|
+
if (typeof list !== "string") continue;
|
|
52
|
+
for (const token of list.split(/\s+/)) if (token !== "" && !tokens.includes(token)) tokens.push(token);
|
|
53
|
+
}
|
|
54
|
+
return tokens.join(" ");
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Layers `over` onto `under`, with the rules shared by every layer of the merge:
|
|
58
|
+
*
|
|
59
|
+
* - `className`: concatenated (`under` first).
|
|
60
|
+
* - `style`: merged, `over` wins per property.
|
|
61
|
+
* - `ref`: both attached.
|
|
62
|
+
* - Event handlers: both run; `overFirst` says whether `over`'s runs before `under`'s.
|
|
63
|
+
* - ARIA id-reference lists: token-merged; `overFirst` says whose tokens come first.
|
|
64
|
+
* - Everything else: `over` wins when it defines the prop. `undefined` is "not given" (JSX
|
|
65
|
+
* optional props are routinely `undefined`), except in an `owned` layer, where a key present
|
|
66
|
+
* with an `undefined` value removes the prop: the library-controlled layer owns its keys.
|
|
67
|
+
*/
|
|
68
|
+
function layer(under, over, overFirst, owned) {
|
|
69
|
+
const result = { ...under };
|
|
70
|
+
for (const key of Object.keys(over)) {
|
|
71
|
+
const overValue = over[key];
|
|
72
|
+
const underValue = under[key];
|
|
73
|
+
if (overValue === void 0) {
|
|
74
|
+
if (owned) result[key] = void 0;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (key === "className") result[key] = typeof underValue === "string" && underValue !== "" ? `${underValue} ${String(overValue)}` : overValue;
|
|
78
|
+
else if (key === "style") result[key] = {
|
|
79
|
+
...underValue,
|
|
80
|
+
...overValue
|
|
81
|
+
};
|
|
82
|
+
else if (key === "ref") result[key] = underValue === void 0 || underValue === null ? overValue : mergeRefs(underValue, overValue);
|
|
83
|
+
else if (isEventHandler(key, overValue) && isEventHandler(key, underValue)) {
|
|
84
|
+
const [first, second] = overFirst ? [overValue, underValue] : [underValue, overValue];
|
|
85
|
+
result[key] = (...args) => {
|
|
86
|
+
first(...args);
|
|
87
|
+
second(...args);
|
|
88
|
+
};
|
|
89
|
+
} else if (isIdReferenceList(key) && typeof underValue === "string") result[key] = overFirst ? mergeTokenLists(overValue, underValue) : mergeTokenLists(underValue, overValue);
|
|
90
|
+
else result[key] = overValue;
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Merges the props for a part's element in the order of conventions 1.2: the part's pass-through
|
|
96
|
+
* props, then the `render` element's props, then the library-controlled attributes on top.
|
|
97
|
+
*
|
|
98
|
+
* - The `render` element wins over pass-through props (`aria-label`, `data-*` from the part's own
|
|
99
|
+
* props, `type`, ...); the library-controlled attributes (`role`, computed `aria-*` state, id
|
|
100
|
+
* wiring, `data-*` state, the library's handlers) win over the element.
|
|
101
|
+
* - Library-controlled keys are **owned**: a key present in `libraryProps` with an `undefined`
|
|
102
|
+
* value removes the attribute, whatever the element or the pass-through props say, so a
|
|
103
|
+
* `render` element can never re-introduce `data-open`, `aria-disabled`, `name`, ... when the
|
|
104
|
+
* part computes none. A part that does not own a key in some mode omits the key instead. The
|
|
105
|
+
* function form of `render` is the way to override library attributes deliberately.
|
|
106
|
+
* - `className` is concatenated (part, element), `style` merged with the element winning.
|
|
107
|
+
* - Event handlers all run: the element's first, then the part's pass-through one, then the
|
|
108
|
+
* library's.
|
|
109
|
+
* - `aria-labelledby` / `aria-describedby` / `aria-controls` / `aria-owns` are merged as token
|
|
110
|
+
* lists, the element's tokens first.
|
|
111
|
+
* - `ref`s are all attached.
|
|
112
|
+
*/
|
|
113
|
+
function mergeProps(partProps, elementProps, libraryProps = {}) {
|
|
114
|
+
return layer(layer(partProps, elementProps, true, false), libraryProps, false, true);
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
export { mergeProps, mergeRefs, mergeTokenLists };
|
|
118
|
+
|
|
119
|
+
//# sourceMappingURL=merge-props.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-props.mjs","names":[],"sources":["../../src/internal/merge-props.ts"],"sourcesContent":["import type { CSSProperties, Ref, RefCallback } from \"react\";\n\ntype AnyProps = Record<string, unknown>;\n\n/**\n * ARIA id-reference lists are merged as token lists rather than overridden (conventions 1.2), so\n * a trigger can be described by more than the element the library wires it to.\n */\nconst ID_REFERENCE_LISTS = new Set([\n \"aria-labelledby\",\n \"aria-describedby\",\n \"aria-controls\",\n \"aria-owns\",\n]);\n\nfunction isIdReferenceList(key: string): boolean {\n return ID_REFERENCE_LISTS.has(key);\n}\n\nfunction isEventHandler(key: string, value: unknown): value is (...args: unknown[]) => void {\n return typeof value === \"function\" && /^on[A-Z]/.test(key);\n}\n\nfunction isObjectRef<T>(ref: unknown): ref is { current: T | null } {\n return typeof ref === \"object\" && ref !== null && \"current\" in ref;\n}\n\nfunction attachRef<T>(ref: Ref<T> | undefined, node: T): (() => void) | undefined {\n if (ref === null || ref === undefined) return undefined;\n if (typeof ref === \"function\") {\n const cleanup = ref(node);\n return typeof cleanup === \"function\" ? cleanup : () => ref(null);\n }\n if (isObjectRef<T>(ref)) {\n ref.current = node;\n return () => {\n ref.current = null;\n };\n }\n return undefined;\n}\n\n/**\n * Merges several refs into one callback ref. The callback returns a cleanup function (React 19),\n * so each inner ref is detached through its own cleanup (callback refs that returned one) or by\n * being set to `null`.\n */\nexport function mergeRefs<T>(...refs: readonly (Ref<T> | undefined)[]): RefCallback<T> {\n return (node: T) => {\n const cleanups = refs.map((ref) => attachRef(ref, node));\n return () => {\n for (const cleanup of cleanups) cleanup?.();\n };\n };\n}\n\n/** Joins two space-separated id lists, `first` tokens first, without duplicates. */\nexport function mergeTokenLists(first: unknown, second: unknown): string {\n const tokens: string[] = [];\n for (const list of [first, second]) {\n if (typeof list !== \"string\") continue;\n for (const token of list.split(/\\s+/)) {\n if (token !== \"\" && !tokens.includes(token)) tokens.push(token);\n }\n }\n return tokens.join(\" \");\n}\n\n/**\n * Layers `over` onto `under`, with the rules shared by every layer of the merge:\n *\n * - `className`: concatenated (`under` first).\n * - `style`: merged, `over` wins per property.\n * - `ref`: both attached.\n * - Event handlers: both run; `overFirst` says whether `over`'s runs before `under`'s.\n * - ARIA id-reference lists: token-merged; `overFirst` says whose tokens come first.\n * - Everything else: `over` wins when it defines the prop. `undefined` is \"not given\" (JSX\n * optional props are routinely `undefined`), except in an `owned` layer, where a key present\n * with an `undefined` value removes the prop: the library-controlled layer owns its keys.\n */\nfunction layer(under: AnyProps, over: AnyProps, overFirst: boolean, owned: boolean): AnyProps {\n const result: AnyProps = { ...under };\n\n for (const key of Object.keys(over)) {\n const overValue = over[key];\n const underValue = under[key];\n\n if (overValue === undefined) {\n // An explicit `undefined` (not a deletion): `cloneElement` layers the merged props over the\n // render element's original props, so only an own `undefined` removes the attribute there.\n if (owned) result[key] = undefined;\n continue;\n }\n\n if (key === \"className\") {\n result[key] =\n typeof underValue === \"string\" && underValue !== \"\"\n ? `${underValue} ${String(overValue)}`\n : overValue;\n } else if (key === \"style\") {\n result[key] = {\n ...(underValue as CSSProperties | undefined),\n ...(overValue as CSSProperties),\n };\n } else if (key === \"ref\") {\n result[key] =\n underValue === undefined || underValue === null\n ? overValue\n : mergeRefs(underValue as Ref<unknown>, overValue as Ref<unknown>);\n } else if (isEventHandler(key, overValue) && isEventHandler(key, underValue)) {\n const [first, second] = overFirst ? [overValue, underValue] : [underValue, overValue];\n result[key] = (...args: unknown[]) => {\n first(...args);\n second(...args);\n };\n } else if (isIdReferenceList(key) && typeof underValue === \"string\") {\n result[key] = overFirst\n ? mergeTokenLists(overValue, underValue)\n : mergeTokenLists(underValue, overValue);\n } else {\n result[key] = overValue;\n }\n }\n\n return result;\n}\n\n/**\n * Merges the props for a part's element in the order of conventions 1.2: the part's pass-through\n * props, then the `render` element's props, then the library-controlled attributes on top.\n *\n * - The `render` element wins over pass-through props (`aria-label`, `data-*` from the part's own\n * props, `type`, ...); the library-controlled attributes (`role`, computed `aria-*` state, id\n * wiring, `data-*` state, the library's handlers) win over the element.\n * - Library-controlled keys are **owned**: a key present in `libraryProps` with an `undefined`\n * value removes the attribute, whatever the element or the pass-through props say, so a\n * `render` element can never re-introduce `data-open`, `aria-disabled`, `name`, ... when the\n * part computes none. A part that does not own a key in some mode omits the key instead. The\n * function form of `render` is the way to override library attributes deliberately.\n * - `className` is concatenated (part, element), `style` merged with the element winning.\n * - Event handlers all run: the element's first, then the part's pass-through one, then the\n * library's.\n * - `aria-labelledby` / `aria-describedby` / `aria-controls` / `aria-owns` are merged as token\n * lists, the element's tokens first.\n * - `ref`s are all attached.\n */\nexport function mergeProps<P extends AnyProps>(\n partProps: P,\n elementProps: AnyProps,\n libraryProps: AnyProps = {},\n): P {\n // The render element's handlers and tokens come first in both layers.\n return layer(layer(partProps, elementProps, true, false), libraryProps, false, true) as P;\n}\n"],"mappings":";;;;;AAQA,MAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,kBAAkB,KAAsB;CAC/C,OAAO,mBAAmB,IAAI,GAAG;AACnC;AAEA,SAAS,eAAe,KAAa,OAAuD;CAC1F,OAAO,OAAO,UAAU,cAAc,WAAW,KAAK,GAAG;AAC3D;AAEA,SAAS,YAAe,KAA4C;CAClE,OAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,aAAa;AACjE;AAEA,SAAS,UAAa,KAAyB,MAAmC;CAChF,IAAI,QAAQ,QAAQ,QAAQ,KAAA,GAAW,OAAO,KAAA;CAC9C,IAAI,OAAO,QAAQ,YAAY;EAC7B,MAAM,UAAU,IAAI,IAAI;EACxB,OAAO,OAAO,YAAY,aAAa,gBAAgB,IAAI,IAAI;CACjE;CACA,IAAI,YAAe,GAAG,GAAG;EACvB,IAAI,UAAU;EACd,aAAa;GACX,IAAI,UAAU;EAChB;CACF;AAEF;;;;;;AAOA,SAAgB,UAAa,GAAG,MAAuD;CACrF,QAAQ,SAAY;EAClB,MAAM,WAAW,KAAK,KAAK,QAAQ,UAAU,KAAK,IAAI,CAAC;EACvD,aAAa;GACX,KAAK,MAAM,WAAW,UAAU,UAAU;EAC5C;CACF;AACF;;AAGA,SAAgB,gBAAgB,OAAgB,QAAyB;CACvE,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,QAAQ,CAAC,OAAO,MAAM,GAAG;EAClC,IAAI,OAAO,SAAS,UAAU;EAC9B,KAAK,MAAM,SAAS,KAAK,MAAM,KAAK,GAClC,IAAI,UAAU,MAAM,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO,KAAK,KAAK;CAElE;CACA,OAAO,OAAO,KAAK,GAAG;AACxB;;;;;;;;;;;;;AAcA,SAAS,MAAM,OAAiB,MAAgB,WAAoB,OAA0B;CAC5F,MAAM,SAAmB,EAAE,GAAG,MAAM;CAEpC,KAAK,MAAM,OAAO,OAAO,KAAK,IAAI,GAAG;EACnC,MAAM,YAAY,KAAK;EACvB,MAAM,aAAa,MAAM;EAEzB,IAAI,cAAc,KAAA,GAAW;GAG3B,IAAI,OAAO,OAAO,OAAO,KAAA;GACzB;EACF;EAEA,IAAI,QAAQ,aACV,OAAO,OACL,OAAO,eAAe,YAAY,eAAe,KAC7C,GAAG,WAAW,GAAG,OAAO,SAAS,MACjC;OACD,IAAI,QAAQ,SACjB,OAAO,OAAO;GACZ,GAAI;GACJ,GAAI;EACN;OACK,IAAI,QAAQ,OACjB,OAAO,OACL,eAAe,KAAA,KAAa,eAAe,OACvC,YACA,UAAU,YAA4B,SAAyB;OAChE,IAAI,eAAe,KAAK,SAAS,KAAK,eAAe,KAAK,UAAU,GAAG;GAC5E,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,WAAW,UAAU,IAAI,CAAC,YAAY,SAAS;GACpF,OAAO,QAAQ,GAAG,SAAoB;IACpC,MAAM,GAAG,IAAI;IACb,OAAO,GAAG,IAAI;GAChB;EACF,OAAO,IAAI,kBAAkB,GAAG,KAAK,OAAO,eAAe,UACzD,OAAO,OAAO,YACV,gBAAgB,WAAW,UAAU,IACrC,gBAAgB,YAAY,SAAS;OAEzC,OAAO,OAAO;CAElB;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,WACd,WACA,cACA,eAAyB,CAAC,GACvB;CAEH,OAAO,MAAM,MAAM,WAAW,cAAc,MAAM,KAAK,GAAG,cAAc,OAAO,IAAI;AACrF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/internal/platform-attributes.d.ts
|
|
2
|
+
declare module "react" {
|
|
3
|
+
interface HTMLAttributes<T> {
|
|
4
|
+
/**
|
|
5
|
+
* `focusgroup` (Chromium 150+): native roving focus. A behaviour token (`tablist`, `toolbar`,
|
|
6
|
+
* ...) plus modifiers (`inline`, `block`, `wrap`, `nowrap`, `nomemory`).
|
|
7
|
+
* Not in `@types/react` 19.3.0 (no DefinitelyTyped issue filed as of 2026-10-16).
|
|
8
|
+
*/
|
|
9
|
+
focusgroup?: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
interface ButtonHTMLAttributes<T> {
|
|
12
|
+
/**
|
|
13
|
+
* `interestfor` (Interest Invokers, Chromium 142+): id of the element, usually a popover,
|
|
14
|
+
* shown when the user shows interest in this button (hover, keyboard focus, long-press).
|
|
15
|
+
* Not in `@types/react` 19.3.0 (DefinitelyTyped #74664).
|
|
16
|
+
*/
|
|
17
|
+
interestfor?: string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* `commandfor` (Invoker Commands): id of the element the button's `command` acts on.
|
|
20
|
+
* Not in `@types/react` 19.3.0 (DefinitelyTyped #74664).
|
|
21
|
+
*/
|
|
22
|
+
commandfor?: string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* `command` (Invoker Commands): a built-in command (`show-popover`, `hide-popover`,
|
|
25
|
+
* `toggle-popover`, `show-modal`, `close`, `request-close`) or a custom `--command`.
|
|
26
|
+
* Not in `@types/react` 19.3.0 (DefinitelyTyped #74664).
|
|
27
|
+
*/
|
|
28
|
+
command?: "show-popover" | "hide-popover" | "toggle-popover" | "show-modal" | "close" | "request-close" | `--${string}` | undefined;
|
|
29
|
+
}
|
|
30
|
+
interface AnchorHTMLAttributes<T> {
|
|
31
|
+
/** `interestfor` on `<a href>` (Chromium 142+). Not in `@types/react` 19.3.0 (DefinitelyTyped #74664). */
|
|
32
|
+
interestfor?: string | undefined;
|
|
33
|
+
}
|
|
34
|
+
interface AreaHTMLAttributes<T> {
|
|
35
|
+
/** `interestfor` on `<area href>` (Chromium 142+). Not in `@types/react` 19.3.0 (DefinitelyTyped #74664). */
|
|
36
|
+
interestfor?: string | undefined;
|
|
37
|
+
}
|
|
38
|
+
interface CSSProperties {
|
|
39
|
+
/** `interest-delay` shorthand (Chromium 142+). Not in `csstype` 3.2.3. */
|
|
40
|
+
interestDelay?: string | undefined;
|
|
41
|
+
/** `interest-delay-start` (Chromium 142+; default `0.25s`). Not in `csstype` 3.2.3. */
|
|
42
|
+
interestDelayStart?: string | undefined;
|
|
43
|
+
/** `interest-delay-end` (Chromium 142+; default `0.15s`). Not in `csstype` 3.2.3. */
|
|
44
|
+
interestDelayEnd?: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=platform-attributes.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-attributes.d.mts","names":[],"sources":["../../src/internal/platform-attributes.ts"],"mappings":";;YAkBY,eAAe;;;;;;IAMvB;;YAGQ,qBAAqB;;;;;;IAM7B;;;;;IAKA;;;;;;IAMA;;YAWQ,qBAAqB;;IAE7B;;YAGQ,mBAAmB;;IAE3B;;YAGQ;;IAER;;IAEA;;IAEA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { ViewTransition, useEffect, useRef } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/internal/transition-boundary.tsx
|
|
5
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
6
|
+
/**
|
|
7
|
+
* Wraps a part's output in `<ViewTransition default={transition}>` **only when the consumer
|
|
8
|
+
* passed `transition`** (conventions 5.1). With `transition === undefined` the node is returned
|
|
9
|
+
* unwrapped and the part renders no boundary at all.
|
|
10
|
+
*
|
|
11
|
+
* Reason (docs/research/view-transition-mount-cost.md, issue #35): react-dom 19.3 starts a
|
|
12
|
+
* document view transition whenever a `<ViewTransition>` mounts or is revealed by `<Activity>` in
|
|
13
|
+
* a transition-lane commit, whatever its class resolves to (`"none"` included). The browser's
|
|
14
|
+
* 250 ms root cross-fade then runs and every later transition commit waits for it. Exits and
|
|
15
|
+
* updates of a `"none"` boundary are free, so an explicit `transition="none"` keeps the boundary
|
|
16
|
+
* and lets a consumer switch between `"none"` and a class without remounting.
|
|
17
|
+
*
|
|
18
|
+
* The boundary stays the outermost node of the part's output, so a part that is the top of an
|
|
19
|
+
* inserted subtree gets enter / exit. A plain function (not a component), so it adds no fiber
|
|
20
|
+
* between the boundary and the element.
|
|
21
|
+
*/
|
|
22
|
+
function transitionBoundary(transition, node) {
|
|
23
|
+
if (transition === void 0) return node;
|
|
24
|
+
return /* @__PURE__ */ jsx(ViewTransition, {
|
|
25
|
+
default: transition,
|
|
26
|
+
children: node
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* {@link transitionBoundary} plus the development warning for a non-static `transition`
|
|
31
|
+
* (conventions 5.1): changing it between `undefined` and a value changes the element type at the
|
|
32
|
+
* part's root, so React remounts the part's subtree (DOM and state lost). Warns once per
|
|
33
|
+
* instance, from an effect. `part` is the public name used in the message (`"Tabs.Panel"`).
|
|
34
|
+
*
|
|
35
|
+
* Pass the *effective* value: a part that ignores `transition` in some mode (Accordion, Dialog
|
|
36
|
+
* JS-free mode) passes `undefined` there.
|
|
37
|
+
*/
|
|
38
|
+
function useTransitionBoundary(part, transition, node) {
|
|
39
|
+
const hasBoundary = transition !== void 0;
|
|
40
|
+
const initial = useRef(hasBoundary);
|
|
41
|
+
const warned = useRef(false);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!isDev || warned.current || hasBoundary === initial.current) return;
|
|
44
|
+
warned.current = true;
|
|
45
|
+
console.error(`${part}: \`transition\` changed between undefined and a value after mount. The part renders a <ViewTransition> only when \`transition\` is given, so this remounts its subtree (DOM and state are lost). Keep \`transition\` static; use \`transition="none"\` to switch animation off without removing the boundary.`);
|
|
46
|
+
}, [hasBoundary, part]);
|
|
47
|
+
return transitionBoundary(transition, node);
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { transitionBoundary, useTransitionBoundary };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=transition-boundary.mjs.map
|