@hjmds/react 1.1.1 → 1.3.4
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/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +12 -6
- package/dist/actions.js.map +1 -1
- package/dist/advanced-display.d.ts +21 -0
- package/dist/advanced-display.d.ts.map +1 -1
- package/dist/advanced-display.js +11 -0
- package/dist/advanced-display.js.map +1 -1
- package/dist/advanced-navigation.d.ts +2 -23
- package/dist/advanced-navigation.d.ts.map +1 -1
- package/dist/advanced-navigation.js +3 -24
- package/dist/advanced-navigation.js.map +1 -1
- package/dist/agreement.d.ts +20 -0
- package/dist/agreement.d.ts.map +1 -0
- package/dist/agreement.js +29 -0
- package/dist/agreement.js.map +1 -0
- package/dist/anchor.d.ts +24 -0
- package/dist/anchor.d.ts.map +1 -0
- package/dist/anchor.js +110 -0
- package/dist/anchor.js.map +1 -0
- package/dist/asset.d.ts +40 -0
- package/dist/asset.d.ts.map +1 -0
- package/dist/asset.js +26 -0
- package/dist/asset.js.map +1 -0
- package/dist/auth-screen.d.ts +29 -0
- package/dist/auth-screen.d.ts.map +1 -0
- package/dist/auth-screen.js +26 -0
- package/dist/auth-screen.js.map +1 -0
- package/dist/bottom-cta.d.ts +32 -0
- package/dist/bottom-cta.d.ts.map +1 -0
- package/dist/bottom-cta.js +30 -0
- package/dist/bottom-cta.js.map +1 -0
- package/dist/bottom-info.d.ts +16 -0
- package/dist/bottom-info.d.ts.map +1 -0
- package/dist/bottom-info.js +12 -0
- package/dist/bottom-info.js.map +1 -0
- package/dist/breadcrumb.d.ts +9 -0
- package/dist/breadcrumb.d.ts.map +1 -0
- package/dist/breadcrumb.js +12 -0
- package/dist/breadcrumb.js.map +1 -0
- package/dist/calendar.d.ts +30 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +69 -0
- package/dist/calendar.js.map +1 -0
- package/dist/carousel.d.ts +20 -0
- package/dist/carousel.d.ts.map +1 -0
- package/dist/carousel.js +70 -0
- package/dist/carousel.js.map +1 -0
- package/dist/clipboard.d.ts +33 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +40 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/collapsible.d.ts +11 -0
- package/dist/collapsible.d.ts.map +1 -0
- package/dist/collapsible.js +18 -0
- package/dist/collapsible.js.map +1 -0
- package/dist/command-palette.d.ts +25 -0
- package/dist/command-palette.d.ts.map +1 -0
- package/dist/command-palette.js +82 -0
- package/dist/command-palette.js.map +1 -0
- package/dist/context-menu.d.ts +12 -0
- package/dist/context-menu.d.ts.map +1 -0
- package/dist/context-menu.js +111 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/data-table.d.ts +30 -0
- package/dist/data-table.d.ts.map +1 -0
- package/dist/data-table.js +57 -0
- package/dist/data-table.js.map +1 -0
- package/dist/date-picker.d.ts +3 -1
- package/dist/date-picker.d.ts.map +1 -1
- package/dist/date-picker.js +16 -31
- package/dist/date-picker.js.map +1 -1
- package/dist/date-range.d.ts +24 -0
- package/dist/date-range.d.ts.map +1 -0
- package/dist/date-range.js +29 -0
- package/dist/date-range.js.map +1 -0
- package/dist/display.d.ts +16 -0
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +13 -1
- package/dist/display.js.map +1 -1
- package/dist/evidence.d.ts +496 -1
- package/dist/evidence.d.ts.map +1 -1
- package/dist/evidence.js +48 -2
- package/dist/evidence.js.map +1 -1
- package/dist/feedback.d.ts +18 -2
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +10 -2
- package/dist/feedback.js.map +1 -1
- package/dist/floating-action-button.d.ts +32 -0
- package/dist/floating-action-button.d.ts.map +1 -0
- package/dist/floating-action-button.js +58 -0
- package/dist/floating-action-button.js.map +1 -0
- package/dist/forms.d.ts +3 -3
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +18 -7
- package/dist/forms.js.map +1 -1
- package/dist/heading.d.ts +12 -0
- package/dist/heading.d.ts.map +1 -0
- package/dist/heading.js +25 -0
- package/dist/heading.js.map +1 -0
- package/dist/index.d.ts +36 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -2
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +1 -1
- package/dist/mentions.d.ts +28 -0
- package/dist/mentions.d.ts.map +1 -0
- package/dist/mentions.js +84 -0
- package/dist/mentions.js.map +1 -0
- package/dist/menubar.d.ts +11 -0
- package/dist/menubar.d.ts.map +1 -0
- package/dist/menubar.js +137 -0
- package/dist/menubar.js.map +1 -0
- package/dist/modal.d.ts +67 -0
- package/dist/modal.d.ts.map +1 -0
- package/dist/modal.js +307 -0
- package/dist/modal.js.map +1 -0
- package/dist/overlay-stack.d.ts +28 -0
- package/dist/overlay-stack.d.ts.map +1 -0
- package/dist/overlay-stack.js +47 -0
- package/dist/overlay-stack.js.map +1 -0
- package/dist/overlays.d.ts +26 -43
- package/dist/overlays.d.ts.map +1 -1
- package/dist/overlays.js +62 -302
- package/dist/overlays.js.map +1 -1
- package/dist/pagination.d.ts +17 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +21 -0
- package/dist/pagination.js.map +1 -0
- package/dist/popover.d.ts +25 -0
- package/dist/popover.d.ts.map +1 -0
- package/dist/popover.js +226 -0
- package/dist/popover.js.map +1 -0
- package/dist/portal.d.ts +5 -1
- package/dist/portal.d.ts.map +1 -1
- package/dist/portal.js +24 -1
- package/dist/portal.js.map +1 -1
- package/dist/provider-button.d.ts +21 -0
- package/dist/provider-button.d.ts.map +1 -0
- package/dist/provider-button.js +26 -0
- package/dist/provider-button.js.map +1 -0
- package/dist/provider.d.ts +13 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +12 -2
- package/dist/provider.js.map +1 -1
- package/dist/selection.d.ts +5 -1
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +2 -2
- package/dist/selection.js.map +1 -1
- package/dist/side-panel.d.ts +34 -0
- package/dist/side-panel.d.ts.map +1 -0
- package/dist/side-panel.js +95 -0
- package/dist/side-panel.js.map +1 -0
- package/dist/sidebar.d.ts +22 -0
- package/dist/sidebar.d.ts.map +1 -0
- package/dist/sidebar.js +29 -0
- package/dist/sidebar.js.map +1 -0
- package/dist/skip-nav.d.ts +12 -0
- package/dist/skip-nav.d.ts.map +1 -0
- package/dist/skip-nav.js +29 -0
- package/dist/skip-nav.js.map +1 -0
- package/dist/splitter.d.ts +45 -0
- package/dist/splitter.d.ts.map +1 -0
- package/dist/splitter.js +116 -0
- package/dist/splitter.js.map +1 -0
- package/dist/styles.css +1105 -26
- package/dist/supplemental-display.d.ts +12 -0
- package/dist/supplemental-display.d.ts.map +1 -1
- package/dist/supplemental-display.js +6 -2
- package/dist/supplemental-display.js.map +1 -1
- package/dist/tags-input.d.ts +60 -0
- package/dist/tags-input.d.ts.map +1 -0
- package/dist/tags-input.js +90 -0
- package/dist/tags-input.js.map +1 -0
- package/dist/text-formats.d.ts +16 -0
- package/dist/text-formats.d.ts.map +1 -0
- package/dist/text-formats.js +24 -0
- package/dist/text-formats.js.map +1 -0
- package/dist/toast.d.ts +1 -1
- package/dist/toggle-group.d.ts +13 -0
- package/dist/toggle-group.d.ts.map +1 -0
- package/dist/toggle-group.js +21 -0
- package/dist/toggle-group.js.map +1 -0
- package/dist/top-bar.d.ts +27 -0
- package/dist/top-bar.d.ts.map +1 -0
- package/dist/top-bar.js +30 -0
- package/dist/top-bar.js.map +1 -0
- package/dist/top.d.ts +15 -0
- package/dist/top.d.ts.map +1 -0
- package/dist/top.js +18 -0
- package/dist/top.js.map +1 -0
- package/dist/tour.d.ts +21 -0
- package/dist/tour.d.ts.map +1 -0
- package/dist/tour.js +122 -0
- package/dist/tour.js.map +1 -0
- package/dist/transfer-list.d.ts +24 -0
- package/dist/transfer-list.d.ts.map +1 -0
- package/dist/transfer-list.js +109 -0
- package/dist/transfer-list.js.map +1 -0
- package/dist/tree.d.ts +29 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +120 -0
- package/dist/tree.js.map +1 -0
- package/package.json +178 -3
package/dist/mentions.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { findActiveMentionTrigger, resolveMentionInsertion, } from "@hjmds/design-contracts/components/mentions";
|
|
3
|
+
import { forwardRef, useEffect, useId, useRef, useState, } from "react";
|
|
4
|
+
import { TextArea } from "./forms.js";
|
|
5
|
+
import { classNames, composeRefs } from "./internal.js";
|
|
6
|
+
import { AnchoredPortal, useAnchoredPopup } from "./portal.js";
|
|
7
|
+
export const Mentions = forwardRef(function Mentions({ value, onValueChange, triggers, candidates, onMentionQueryChange, emptyMessage, listLabel, renderCandidate, className, ...textAreaProps }, forwardedRef) {
|
|
8
|
+
const inputRef = useRef(null);
|
|
9
|
+
const [match, setMatch] = useState(null);
|
|
10
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
11
|
+
const [list, setList] = useState(null);
|
|
12
|
+
const id = `${useId().replaceAll(":", "")}-mentions`;
|
|
13
|
+
const open = match !== null;
|
|
14
|
+
const activeCandidate = candidates[Math.min(activeIndex, Math.max(candidates.length - 1, 0))];
|
|
15
|
+
const notifyRef = useRef(onMentionQueryChange);
|
|
16
|
+
notifyRef.current = onMentionQueryChange;
|
|
17
|
+
useEffect(() => { notifyRef.current?.(match); }, [match]);
|
|
18
|
+
const syncMatch = (text, cursor) => {
|
|
19
|
+
// The contract owns trigger detection, including "a space closes it" and
|
|
20
|
+
// "the nearer trigger wins"; this component only reports the cursor.
|
|
21
|
+
const next = findActiveMentionTrigger(text, cursor, triggers);
|
|
22
|
+
setMatch((previous) => (previous?.triggerStart === next?.triggerStart && previous?.query === next?.query ? previous : next));
|
|
23
|
+
if (next === null || next.query !== match?.query)
|
|
24
|
+
setActiveIndex(0);
|
|
25
|
+
};
|
|
26
|
+
const commit = (candidate) => {
|
|
27
|
+
const input = inputRef.current;
|
|
28
|
+
if (!match || !input)
|
|
29
|
+
return;
|
|
30
|
+
const result = resolveMentionInsertion(value, match, input.selectionStart ?? value.length, candidate.insertText ?? candidate.label);
|
|
31
|
+
onValueChange(result.text);
|
|
32
|
+
setMatch(null);
|
|
33
|
+
queueMicrotask(() => {
|
|
34
|
+
input.focus();
|
|
35
|
+
input.setSelectionRange(result.cursorPosition, result.cursorPosition);
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
const onKeyDown = (event) => {
|
|
39
|
+
if (!open)
|
|
40
|
+
return;
|
|
41
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
42
|
+
if (candidates.length === 0)
|
|
43
|
+
return;
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
setActiveIndex((previous) => {
|
|
46
|
+
const next = event.key === "ArrowDown" ? previous + 1 : previous - 1;
|
|
47
|
+
return (next + candidates.length) % candidates.length;
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (event.key === "Escape") {
|
|
52
|
+
// Dismissing the popup must not touch the text the user already typed.
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
event.stopPropagation();
|
|
55
|
+
setMatch(null);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (event.key === "Enter" && activeCandidate && candidates.length > 0) {
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
commit(activeCandidate);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const position = useAnchoredPopup(inputRef, open ? list : null, {
|
|
64
|
+
placement: "bottom", align: "start", matchAnchorWidth: true, zIndex: 900,
|
|
65
|
+
});
|
|
66
|
+
return (_jsxs("div", { className: classNames("hjm-mentions", className), children: [_jsx(TextArea, { ...textAreaProps, ref: composeRefs(inputRef, forwardedRef), value: value, role: "combobox", "aria-expanded": open, "aria-controls": open ? id : undefined, "aria-autocomplete": "list", "aria-activedescendant": open && activeCandidate ? `${id}-${activeCandidate.id}` : undefined, onChange: (event) => {
|
|
67
|
+
onValueChange(event.target.value);
|
|
68
|
+
syncMatch(event.target.value, event.target.selectionStart ?? event.target.value.length);
|
|
69
|
+
}, onKeyUp: (event) => {
|
|
70
|
+
// Caret moves without an edit (arrows, clicks) change which trigger is
|
|
71
|
+
// active, so the match is re-read from the caret, not only from input.
|
|
72
|
+
if (open && (event.key === "ArrowDown" || event.key === "ArrowUp"))
|
|
73
|
+
return;
|
|
74
|
+
const input = event.currentTarget;
|
|
75
|
+
syncMatch(input.value, input.selectionStart ?? input.value.length);
|
|
76
|
+
}, onClick: (event) => {
|
|
77
|
+
const input = event.currentTarget;
|
|
78
|
+
syncMatch(input.value, input.selectionStart ?? input.value.length);
|
|
79
|
+
}, onBlur: (event) => { textAreaProps.onBlur?.(event); setMatch(null); }, onKeyDown: (event) => { textAreaProps.onKeyDown?.(event); onKeyDown(event); } }), open ? (_jsx(AnchoredPortal, { anchorRef: inputRef, children: _jsx("div", { ref: setList, id: id, role: "listbox", "aria-label": listLabel, className: "hjm-mentions__list", style: position.style, children: candidates.length === 0 ? (_jsx("p", { className: "hjm-mentions__empty", role: "status", children: emptyMessage })) : candidates.map((candidate, index) => (_jsx("div", { id: `${id}-${candidate.id}`, role: "option", "aria-selected": candidate.id === activeCandidate?.id, className: "hjm-mentions__option",
|
|
80
|
+
// Pointer commit must not blur the textarea first, or the caret
|
|
81
|
+
// position the insertion depends on would already be gone.
|
|
82
|
+
onMouseDown: (event) => { event.preventDefault(); commit(candidate); }, onMouseEnter: () => setActiveIndex(index), children: renderCandidate?.(candidate) ?? (_jsxs(_Fragment, { children: [_jsx("span", { children: candidate.label }), candidate.description ? _jsx("span", { className: "hjm-mentions__description", children: candidate.description }) : null] })) }, candidate.id))) }) })) : null] }));
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=mentions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mentions.js","sourceRoot":"","sources":["../src/mentions.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n findActiveMentionTrigger,\n resolveMentionInsertion,\n type MentionMatch,\n type MentionTriggerConfig,\n} from \"@hjmds/design-contracts/components/mentions\";\nimport {\n forwardRef,\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { TextArea, type TextAreaProps } from \"./forms.js\";\nimport { classNames, composeRefs } from \"./internal.js\";\nimport { AnchoredPortal, useAnchoredPopup } from \"./portal.js\";\n\nexport type MentionCandidate = Readonly<{\n id: string;\n label: string;\n /** Text inserted after the trigger character; defaults to `label`. */\n insertText?: string;\n description?: string;\n}>;\n\nexport type MentionsProps<TriggerId extends string = string> =\n Omit<TextAreaProps, \"value\" | \"defaultValue\" | \"onChange\" | \"children\"> &\n Readonly<{\n value: string;\n onValueChange: (value: string) => void;\n triggers: readonly MentionTriggerConfig<TriggerId>[];\n /** Candidates for the active query; the product owns filtering and loading. */\n candidates: readonly MentionCandidate[];\n /** Fires whenever the active trigger match changes, including to null. */\n onMentionQueryChange?: (match: MentionMatch<TriggerId> | null) => void;\n /** Localized message shown when the popup is open with no candidates. */\n emptyMessage: string;\n /** Localized accessible name for the candidate list. */\n listLabel: string;\n renderCandidate?: (candidate: MentionCandidate) => ReactNode;\n }>;\n\nexport const Mentions = forwardRef(function Mentions<TriggerId extends string = string>(\n {\n value,\n onValueChange,\n triggers,\n candidates,\n onMentionQueryChange,\n emptyMessage,\n listLabel,\n renderCandidate,\n className,\n ...textAreaProps\n }: MentionsProps<TriggerId>,\n forwardedRef: React.Ref<HTMLTextAreaElement>,\n) {\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const [match, setMatch] = useState<MentionMatch<TriggerId> | null>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n const [list, setList] = useState<HTMLDivElement | null>(null);\n const id = `${useId().replaceAll(\":\", \"\")}-mentions`;\n const open = match !== null;\n const activeCandidate = candidates[Math.min(activeIndex, Math.max(candidates.length - 1, 0))];\n\n const notifyRef = useRef(onMentionQueryChange);\n notifyRef.current = onMentionQueryChange;\n useEffect(() => { notifyRef.current?.(match); }, [match]);\n\n const syncMatch = (text: string, cursor: number) => {\n // The contract owns trigger detection, including \"a space closes it\" and\n // \"the nearer trigger wins\"; this component only reports the cursor.\n const next = findActiveMentionTrigger(text, cursor, triggers);\n setMatch((previous) => (previous?.triggerStart === next?.triggerStart && previous?.query === next?.query ? previous : next));\n if (next === null || next.query !== match?.query) setActiveIndex(0);\n };\n const commit = (candidate: MentionCandidate) => {\n const input = inputRef.current;\n if (!match || !input) return;\n const result = resolveMentionInsertion(value, match, input.selectionStart ?? value.length, candidate.insertText ?? candidate.label);\n onValueChange(result.text);\n setMatch(null);\n queueMicrotask(() => {\n input.focus();\n input.setSelectionRange(result.cursorPosition, result.cursorPosition);\n });\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n if (!open) return;\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n if (candidates.length === 0) return;\n event.preventDefault();\n setActiveIndex((previous) => {\n const next = event.key === \"ArrowDown\" ? previous + 1 : previous - 1;\n return (next + candidates.length) % candidates.length;\n });\n return;\n }\n if (event.key === \"Escape\") {\n // Dismissing the popup must not touch the text the user already typed.\n event.preventDefault();\n event.stopPropagation();\n setMatch(null);\n return;\n }\n if (event.key === \"Enter\" && activeCandidate && candidates.length > 0) {\n event.preventDefault();\n commit(activeCandidate);\n }\n };\n\n const position = useAnchoredPopup(inputRef, open ? list : null, {\n placement: \"bottom\", align: \"start\", matchAnchorWidth: true, zIndex: 900,\n });\n\n return (\n <div className={classNames(\"hjm-mentions\", className)}>\n <TextArea\n {...textAreaProps}\n ref={composeRefs(inputRef, forwardedRef)}\n value={value}\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={open ? id : undefined}\n aria-autocomplete=\"list\"\n aria-activedescendant={open && activeCandidate ? `${id}-${activeCandidate.id}` : undefined}\n onChange={(event) => {\n onValueChange(event.target.value);\n syncMatch(event.target.value, event.target.selectionStart ?? event.target.value.length);\n }}\n onKeyUp={(event) => {\n // Caret moves without an edit (arrows, clicks) change which trigger is\n // active, so the match is re-read from the caret, not only from input.\n if (open && (event.key === \"ArrowDown\" || event.key === \"ArrowUp\")) return;\n const input = event.currentTarget;\n syncMatch(input.value, input.selectionStart ?? input.value.length);\n }}\n onClick={(event) => {\n const input = event.currentTarget;\n syncMatch(input.value, input.selectionStart ?? input.value.length);\n }}\n onBlur={(event) => { textAreaProps.onBlur?.(event); setMatch(null); }}\n onKeyDown={(event) => { textAreaProps.onKeyDown?.(event); onKeyDown(event); }}\n />\n {open ? (\n <AnchoredPortal anchorRef={inputRef}>\n <div\n ref={setList}\n id={id}\n role=\"listbox\"\n aria-label={listLabel}\n className=\"hjm-mentions__list\"\n style={position.style as CSSProperties}\n >\n {candidates.length === 0 ? (\n <p className=\"hjm-mentions__empty\" role=\"status\">{emptyMessage}</p>\n ) : candidates.map((candidate, index) => (\n <div\n key={candidate.id}\n id={`${id}-${candidate.id}`}\n role=\"option\"\n aria-selected={candidate.id === activeCandidate?.id}\n className=\"hjm-mentions__option\"\n // Pointer commit must not blur the textarea first, or the caret\n // position the insertion depends on would already be gone.\n onMouseDown={(event) => { event.preventDefault(); commit(candidate); }}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {renderCandidate?.(candidate) ?? (\n <>\n <span>{candidate.label}</span>\n {candidate.description ? <span className=\"hjm-mentions__description\">{candidate.description}</span> : null}\n </>\n )}\n </div>\n ))}\n </div>\n </AnchoredPortal>\n ) : null}\n </div>\n );\n}) as <TriggerId extends string = string>(\n props: MentionsProps<TriggerId> & { ref?: React.Ref<HTMLTextAreaElement> },\n) => React.ReactElement | null;\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type MenubarDescriptor } from "@hjmds/design-contracts/components/menubar";
|
|
2
|
+
export type MenubarProps<Key extends string = string, MenuKey extends string = string> = Readonly<{
|
|
3
|
+
descriptor: MenubarDescriptor<Key, MenuKey>;
|
|
4
|
+
openMenuId?: MenuKey | null;
|
|
5
|
+
defaultOpenMenuId?: MenuKey | null;
|
|
6
|
+
onOpenMenuIdChange?: (id: MenuKey | null) => void;
|
|
7
|
+
onAction: (id: Key, menuId: MenuKey) => void;
|
|
8
|
+
className?: string;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function Menubar<Key extends string = string, MenuKey extends string = string>({ descriptor, openMenuId: controlledOpen, defaultOpenMenuId, onOpenMenuIdChange, onAction, className, }: MenubarProps<Key, MenuKey>): import("react").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=menubar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menubar.d.ts","sourceRoot":"","sources":["../src/menubar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,4CAA4C,CAAC;AAIpD,MAAM,MAAM,YAAY,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAChG,UAAU,EAAE,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5C,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,iBAAiB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD,QAAQ,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,wBAAgB,OAAO,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,EACpF,UAAU,EACV,UAAU,EAAE,cAAc,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,SAAS,GACV,EAAE,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,+BA0J5B"}
|
package/dist/menubar.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { menubarRecipe, resolveMenubarNavigation, validateMenubarDescriptor, } from "@hjmds/design-contracts/components/menubar";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { classNames, useControllableState } from "./internal.js";
|
|
5
|
+
export function Menubar({ descriptor, openMenuId: controlledOpen, defaultOpenMenuId, onOpenMenuIdChange, onAction, className, }) {
|
|
6
|
+
validateMenubarDescriptor(descriptor);
|
|
7
|
+
const [openId, setOpenId] = useControllableState({
|
|
8
|
+
...(controlledOpen === undefined ? {} : { value: controlledOpen }),
|
|
9
|
+
defaultValue: defaultOpenMenuId ?? null,
|
|
10
|
+
...(onOpenMenuIdChange === undefined ? {} : { onChange: onOpenMenuIdChange }),
|
|
11
|
+
});
|
|
12
|
+
const enabledMenus = descriptor.menus.filter((menu) => menu.disabled !== true);
|
|
13
|
+
// Roving focus: the bar is one tab stop, so the bar — not each label — owns
|
|
14
|
+
// which menu is reachable by Tab.
|
|
15
|
+
const [focusedId, setFocusedId] = useState(enabledMenus[0]?.id ?? descriptor.menus[0].id);
|
|
16
|
+
const [activeItemIndex, setActiveItemIndex] = useState(0);
|
|
17
|
+
const rootRef = useRef(null);
|
|
18
|
+
const labelRefs = useRef(new Map());
|
|
19
|
+
const openMenu = descriptor.menus.find((menu) => menu.id === openId) ?? null;
|
|
20
|
+
const openItems = openMenu?.items.filter((item) => item.disabled !== true) ?? [];
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (openId === null)
|
|
23
|
+
return;
|
|
24
|
+
const onPointerDown = (event) => {
|
|
25
|
+
if (event.target instanceof Node && rootRef.current?.contains(event.target))
|
|
26
|
+
return;
|
|
27
|
+
setOpenId(null);
|
|
28
|
+
};
|
|
29
|
+
document.addEventListener("pointerdown", onPointerDown);
|
|
30
|
+
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
31
|
+
}, [openId, setOpenId]);
|
|
32
|
+
const focusLabel = (id) => {
|
|
33
|
+
setFocusedId(id);
|
|
34
|
+
labelRefs.current.get(id)?.focus();
|
|
35
|
+
};
|
|
36
|
+
const move = (direction) => {
|
|
37
|
+
const next = resolveMenubarNavigation(descriptor, focusedId, direction);
|
|
38
|
+
focusLabel(next);
|
|
39
|
+
// Left/right while a menu is open moves to the neighbour already open, which
|
|
40
|
+
// is the whole reason this is a bar and not three independent Menus.
|
|
41
|
+
if (openId !== null) {
|
|
42
|
+
setOpenId(next);
|
|
43
|
+
setActiveItemIndex(0);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return (_jsx("div", { ref: rootRef, role: "menubar", "aria-label": descriptor.accessibilityLabel, className: classNames("hjm-menubar", className), style: {
|
|
47
|
+
"--hjm-menubar-min-height": `${menubarRecipe.minHeight}px`,
|
|
48
|
+
"--hjm-menubar-gap": `${menubarRecipe.gap}px`,
|
|
49
|
+
"--hjm-menubar-padding": `${menubarRecipe.paddingHorizontal}px`,
|
|
50
|
+
"--hjm-menubar-label-padding": `${menubarRecipe.label.paddingHorizontal}px`,
|
|
51
|
+
"--hjm-menubar-label-radius": `${menubarRecipe.label.radius}px`,
|
|
52
|
+
}, onKeyDown: (event) => {
|
|
53
|
+
if (event.key === "ArrowRight") {
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
move("next");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (event.key === "ArrowLeft") {
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
move("previous");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (event.key === "Home" || event.key === "End") {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
const target = (event.key === "Home" ? enabledMenus[0] : enabledMenus.at(-1))?.id;
|
|
66
|
+
if (target !== undefined) {
|
|
67
|
+
focusLabel(target);
|
|
68
|
+
if (openId !== null) {
|
|
69
|
+
setOpenId(target);
|
|
70
|
+
setActiveItemIndex(0);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (event.key === "Escape" && openId !== null) {
|
|
76
|
+
event.preventDefault();
|
|
77
|
+
setOpenId(null);
|
|
78
|
+
focusLabel(focusedId);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (openId === null) {
|
|
82
|
+
if (event.key === "ArrowDown" || event.key === "Enter" || event.key === " ") {
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
setOpenId(focusedId);
|
|
85
|
+
setActiveItemIndex(0);
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
90
|
+
event.preventDefault();
|
|
91
|
+
setActiveItemIndex((previous) => {
|
|
92
|
+
const next = event.key === "ArrowDown" ? previous + 1 : previous - 1;
|
|
93
|
+
return (next + openItems.length) % Math.max(openItems.length, 1);
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
98
|
+
event.preventDefault();
|
|
99
|
+
const item = openItems[activeItemIndex];
|
|
100
|
+
if (item) {
|
|
101
|
+
onAction(item.id, openId);
|
|
102
|
+
// Activation runs an action and leaves nothing selected — unlike Tabs.
|
|
103
|
+
setOpenId(null);
|
|
104
|
+
focusLabel(openId);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}, children: descriptor.menus.map((menu) => {
|
|
108
|
+
const open = menu.id === openId;
|
|
109
|
+
return (_jsxs("div", { className: "hjm-menubar__menu", children: [_jsx("button", { type: "button", ref: (node) => { if (node)
|
|
110
|
+
labelRefs.current.set(menu.id, node);
|
|
111
|
+
else
|
|
112
|
+
labelRefs.current.delete(menu.id); }, role: "menuitem", "aria-haspopup": "menu", "aria-expanded": open, disabled: menu.disabled, tabIndex: menu.id === focusedId ? 0 : -1, "data-open": open || undefined, className: "hjm-menubar__label", onClick: () => {
|
|
113
|
+
setFocusedId(menu.id);
|
|
114
|
+
setOpenId(open ? null : menu.id);
|
|
115
|
+
setActiveItemIndex(0);
|
|
116
|
+
}, onMouseEnter: () => {
|
|
117
|
+
// Once one menu is open, hovering the bar switches menus — the
|
|
118
|
+
// desktop convention; with nothing open, hover opens nothing.
|
|
119
|
+
if (openId !== null && menu.disabled !== true) {
|
|
120
|
+
setOpenId(menu.id);
|
|
121
|
+
setFocusedId(menu.id);
|
|
122
|
+
setActiveItemIndex(0);
|
|
123
|
+
}
|
|
124
|
+
}, children: menu.label }), open ? (_jsx("div", { role: "menu", "aria-label": menu.label, className: "hjm-menubar__panel", children: menu.items.map((item) => {
|
|
125
|
+
const index = openItems.findIndex((candidate) => candidate.id === item.id);
|
|
126
|
+
return (_jsxs("div", { role: "menuitem", "aria-disabled": item.disabled || undefined, "data-active": index === activeItemIndex && item.disabled !== true ? "" : undefined, "data-tone": item.tone, className: "hjm-menubar__item", onMouseEnter: () => { if (index >= 0)
|
|
127
|
+
setActiveItemIndex(index); }, onClick: () => {
|
|
128
|
+
if (item.disabled)
|
|
129
|
+
return;
|
|
130
|
+
onAction(item.id, menu.id);
|
|
131
|
+
setOpenId(null);
|
|
132
|
+
focusLabel(menu.id);
|
|
133
|
+
}, children: [_jsx("span", { children: item.label }), item.shortcut ? _jsx("kbd", { className: "hjm-menubar__shortcut", children: item.shortcut }) : null] }, item.id));
|
|
134
|
+
}) })) : null] }, menu.id));
|
|
135
|
+
}) }));
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=menubar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menubar.js","sourceRoot":"","sources":["../src/menubar.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n menubarRecipe,\n resolveMenubarNavigation,\n validateMenubarDescriptor,\n type MenubarDescriptor,\n} from \"@hjmds/design-contracts/components/menubar\";\nimport { useEffect, useRef, useState, type CSSProperties } from \"react\";\nimport { classNames, useControllableState } from \"./internal.js\";\n\nexport type MenubarProps<Key extends string = string, MenuKey extends string = string> = Readonly<{\n descriptor: MenubarDescriptor<Key, MenuKey>;\n openMenuId?: MenuKey | null;\n defaultOpenMenuId?: MenuKey | null;\n onOpenMenuIdChange?: (id: MenuKey | null) => void;\n onAction: (id: Key, menuId: MenuKey) => void;\n className?: string;\n}>;\n\nexport function Menubar<Key extends string = string, MenuKey extends string = string>({\n descriptor,\n openMenuId: controlledOpen,\n defaultOpenMenuId,\n onOpenMenuIdChange,\n onAction,\n className,\n}: MenubarProps<Key, MenuKey>) {\n validateMenubarDescriptor(descriptor);\n const [openId, setOpenId] = useControllableState<MenuKey | null>({\n ...(controlledOpen === undefined ? {} : { value: controlledOpen }),\n defaultValue: defaultOpenMenuId ?? null,\n ...(onOpenMenuIdChange === undefined ? {} : { onChange: onOpenMenuIdChange }),\n });\n const enabledMenus = descriptor.menus.filter((menu) => menu.disabled !== true);\n // Roving focus: the bar is one tab stop, so the bar — not each label — owns\n // which menu is reachable by Tab.\n const [focusedId, setFocusedId] = useState<MenuKey>(enabledMenus[0]?.id ?? descriptor.menus[0]!.id);\n const [activeItemIndex, setActiveItemIndex] = useState(0);\n const rootRef = useRef<HTMLDivElement>(null);\n const labelRefs = useRef(new Map<MenuKey, HTMLButtonElement>());\n const openMenu = descriptor.menus.find((menu) => menu.id === openId) ?? null;\n const openItems = openMenu?.items.filter((item) => item.disabled !== true) ?? [];\n\n useEffect(() => {\n if (openId === null) return;\n const onPointerDown = (event: PointerEvent) => {\n if (event.target instanceof Node && rootRef.current?.contains(event.target)) return;\n setOpenId(null);\n };\n document.addEventListener(\"pointerdown\", onPointerDown);\n return () => document.removeEventListener(\"pointerdown\", onPointerDown);\n }, [openId, setOpenId]);\n\n const focusLabel = (id: MenuKey) => {\n setFocusedId(id);\n labelRefs.current.get(id)?.focus();\n };\n const move = (direction: \"next\" | \"previous\") => {\n const next = resolveMenubarNavigation(descriptor, focusedId, direction);\n focusLabel(next);\n // Left/right while a menu is open moves to the neighbour already open, which\n // is the whole reason this is a bar and not three independent Menus.\n if (openId !== null) { setOpenId(next); setActiveItemIndex(0); }\n };\n\n return (\n <div\n ref={rootRef}\n role=\"menubar\"\n aria-label={descriptor.accessibilityLabel}\n className={classNames(\"hjm-menubar\", className)}\n style={{\n \"--hjm-menubar-min-height\": `${menubarRecipe.minHeight}px`,\n \"--hjm-menubar-gap\": `${menubarRecipe.gap}px`,\n \"--hjm-menubar-padding\": `${menubarRecipe.paddingHorizontal}px`,\n \"--hjm-menubar-label-padding\": `${menubarRecipe.label.paddingHorizontal}px`,\n \"--hjm-menubar-label-radius\": `${menubarRecipe.label.radius}px`,\n } as CSSProperties}\n onKeyDown={(event) => {\n if (event.key === \"ArrowRight\") { event.preventDefault(); move(\"next\"); return; }\n if (event.key === \"ArrowLeft\") { event.preventDefault(); move(\"previous\"); return; }\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n const target = (event.key === \"Home\" ? enabledMenus[0] : enabledMenus.at(-1))?.id;\n if (target !== undefined) { focusLabel(target); if (openId !== null) { setOpenId(target); setActiveItemIndex(0); } }\n return;\n }\n if (event.key === \"Escape\" && openId !== null) {\n event.preventDefault();\n setOpenId(null);\n focusLabel(focusedId);\n return;\n }\n if (openId === null) {\n if (event.key === \"ArrowDown\" || event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpenId(focusedId);\n setActiveItemIndex(0);\n }\n return;\n }\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveItemIndex((previous) => {\n const next = event.key === \"ArrowDown\" ? previous + 1 : previous - 1;\n return (next + openItems.length) % Math.max(openItems.length, 1);\n });\n return;\n }\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n const item = openItems[activeItemIndex];\n if (item) {\n onAction(item.id as Key, openId);\n // Activation runs an action and leaves nothing selected — unlike Tabs.\n setOpenId(null);\n focusLabel(openId);\n }\n }\n }}\n >\n {descriptor.menus.map((menu) => {\n const open = menu.id === openId;\n return (\n <div key={menu.id} className=\"hjm-menubar__menu\">\n <button\n type=\"button\"\n ref={(node) => { if (node) labelRefs.current.set(menu.id, node); else labelRefs.current.delete(menu.id); }}\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n disabled={menu.disabled}\n tabIndex={menu.id === focusedId ? 0 : -1}\n data-open={open || undefined}\n className=\"hjm-menubar__label\"\n onClick={() => {\n setFocusedId(menu.id);\n setOpenId(open ? null : menu.id);\n setActiveItemIndex(0);\n }}\n onMouseEnter={() => {\n // Once one menu is open, hovering the bar switches menus — the\n // desktop convention; with nothing open, hover opens nothing.\n if (openId !== null && menu.disabled !== true) { setOpenId(menu.id); setFocusedId(menu.id); setActiveItemIndex(0); }\n }}\n >\n {menu.label}\n </button>\n {open ? (\n <div role=\"menu\" aria-label={menu.label} className=\"hjm-menubar__panel\">\n {menu.items.map((item) => {\n const index = openItems.findIndex((candidate) => candidate.id === item.id);\n return (\n <div\n key={item.id}\n role=\"menuitem\"\n aria-disabled={item.disabled || undefined}\n data-active={index === activeItemIndex && item.disabled !== true ? \"\" : undefined}\n data-tone={item.tone}\n className=\"hjm-menubar__item\"\n onMouseEnter={() => { if (index >= 0) setActiveItemIndex(index); }}\n onClick={() => {\n if (item.disabled) return;\n onAction(item.id as Key, menu.id);\n setOpenId(null);\n focusLabel(menu.id);\n }}\n >\n <span>{item.label}</span>\n {item.shortcut ? <kbd className=\"hjm-menubar__shortcut\">{item.shortcut}</kbd> : null}\n </div>\n );\n })}\n </div>\n ) : null}\n </div>\n );\n })}\n </div>\n );\n}\n"]}
|
package/dist/modal.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type AriaAttributes, type MouseEventHandler, type ReactElement, type ReactNode, type Ref } from "react";
|
|
2
|
+
export type TriggerElementProps = Readonly<{
|
|
3
|
+
ref?: Ref<HTMLElement>;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
6
|
+
onMouseEnter?: MouseEventHandler<HTMLElement>;
|
|
7
|
+
onMouseLeave?: MouseEventHandler<HTMLElement>;
|
|
8
|
+
onPointerEnter?: React.PointerEventHandler<HTMLElement>;
|
|
9
|
+
onPointerLeave?: React.PointerEventHandler<HTMLElement>;
|
|
10
|
+
onFocus?: React.FocusEventHandler<HTMLElement>;
|
|
11
|
+
onBlur?: React.FocusEventHandler<HTMLElement>;
|
|
12
|
+
onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
|
|
13
|
+
"aria-controls"?: string;
|
|
14
|
+
"aria-describedby"?: string;
|
|
15
|
+
"aria-disabled"?: AriaAttributes["aria-disabled"];
|
|
16
|
+
"aria-expanded"?: AriaAttributes["aria-expanded"];
|
|
17
|
+
"aria-haspopup"?: AriaAttributes["aria-haspopup"];
|
|
18
|
+
}>;
|
|
19
|
+
export type OverlayTrigger = ReactElement<TriggerElementProps>;
|
|
20
|
+
export declare function containsEventTarget(container: Node | null, target: EventTarget | null): boolean;
|
|
21
|
+
type ModalPortalProps = Readonly<{
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
container?: HTMLElement;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function HjmPortal({ children, container }: ModalPortalProps): import("react").ReactPortal | null;
|
|
26
|
+
export type OpenState<Detail> = Readonly<{
|
|
27
|
+
open: boolean;
|
|
28
|
+
defaultOpen?: never;
|
|
29
|
+
onOpenChange: (open: boolean, detail: Detail) => void;
|
|
30
|
+
}> | Readonly<{
|
|
31
|
+
open?: never;
|
|
32
|
+
defaultOpen?: boolean;
|
|
33
|
+
onOpenChange?: (open: boolean, detail: Detail) => void;
|
|
34
|
+
}>;
|
|
35
|
+
export type ModalOpenState<Detail> = Readonly<{
|
|
36
|
+
open: boolean;
|
|
37
|
+
defaultOpen?: never;
|
|
38
|
+
onOpenChange: (open: boolean, detail: Detail) => void;
|
|
39
|
+
/** Optional for product-owned, programmatically controlled overlays. */
|
|
40
|
+
trigger?: OverlayTrigger;
|
|
41
|
+
}> | Readonly<{
|
|
42
|
+
open?: never;
|
|
43
|
+
defaultOpen?: boolean;
|
|
44
|
+
onOpenChange?: (open: boolean, detail: Detail) => void;
|
|
45
|
+
/** Uncontrolled overlays need a first-party activation target. */
|
|
46
|
+
trigger: OverlayTrigger;
|
|
47
|
+
}>;
|
|
48
|
+
export declare function useOpenState<Detail>({ open, defaultOpen, onOpenChange, }: Readonly<{
|
|
49
|
+
open?: boolean;
|
|
50
|
+
defaultOpen?: boolean;
|
|
51
|
+
onOpenChange?: (open: boolean, detail: Detail) => void;
|
|
52
|
+
}>): readonly [boolean, (nextOpen: boolean, detail: Detail) => void];
|
|
53
|
+
export declare function getFocusable(container: HTMLElement): HTMLElement[];
|
|
54
|
+
export declare function getModalLayer(priority: number): number;
|
|
55
|
+
type ModalFocusOptions = Readonly<{
|
|
56
|
+
active: boolean;
|
|
57
|
+
priority?: number;
|
|
58
|
+
contentRef: React.RefObject<HTMLElement | null>;
|
|
59
|
+
initialFocusRef?: React.RefObject<HTMLElement | null>;
|
|
60
|
+
returnFocusRef?: React.RefObject<HTMLElement | null>;
|
|
61
|
+
fallbackReturnRef?: React.RefObject<HTMLElement | null>;
|
|
62
|
+
onEscape(): void;
|
|
63
|
+
}>;
|
|
64
|
+
export declare function useModalFocus({ active, priority, contentRef, initialFocusRef, returnFocusRef, fallbackReturnRef, onEscape, }: ModalFocusOptions): void;
|
|
65
|
+
export declare function renderTrigger(trigger: OverlayTrigger, triggerRef: React.RefObject<HTMLElement | null>, open: boolean, contentId: string, popup: "dialog" | "menu", onOpen: () => void): ReactElement;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=modal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,GAAG,EACT,MAAM,OAAO,CAAC;AAef,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACzC,YAAY,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC9C,YAAY,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC9C,cAAc,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACxD,cAAc,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;IACxD,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC9C,SAAS,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC;IACpD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;IAClD,eAAe,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;IAClD,eAAe,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;CACnD,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;AAE/D,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,IAAI,GAAG,IAAI,EACtB,MAAM,EAAE,WAAW,GAAG,IAAI,GACzB,OAAO,CAIT;AAED,KAAK,gBAAgB,GAAG,QAAQ,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB,CAAC,CAAC;AAEH,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,gBAAgB,sCAsBlE;AAED,MAAM,MAAM,SAAS,CAAC,MAAM,IACxB,QAAQ,CAAC;IACP,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxD,CAAC,CAAC;AAEP,MAAM,MAAM,cAAc,CAAC,MAAM,IAC7B,QAAQ,CAAC;IACP,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,wEAAwE;IACxE,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,kEAAkE;IAClE,OAAO,EAAE,cAAc,CAAC;CACzB,CAAC,CAAC;AAEP,wBAAgB,YAAY,CAAC,MAAM,EAAE,EACnC,IAAI,EACJ,WAAmB,EACnB,YAAY,GACb,EAAE,QAAQ,CAAC;IACV,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxD,CAAC,iCAWa,OAAO,UAAU,MAAM,WAmBrC;AAWD,wBAAgB,YAAY,CAAC,SAAS,EAAE,WAAW,GAAG,WAAW,EAAE,CAMlE;AAoCD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKtD;AAkGD,KAAK,iBAAiB,GAAG,QAAQ,CAAC;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAChD,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACtD,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACrD,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACxD,QAAQ,IAAI,IAAI,CAAC;CAClB,CAAC,CAAC;AAEH,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,QAAY,EACZ,UAAU,EACV,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,QAAQ,GACT,EAAE,iBAAiB,GAAG,IAAI,CAoG1B;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAC/C,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,QAAQ,GAAG,MAAM,EACxB,MAAM,EAAE,MAAM,IAAI,GACjB,YAAY,CAYd"}
|