@aaas-pro/library 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -2
- package/dist/components/address-picker.d.ts +18 -0
- package/dist/components/address-picker.js +46 -0
- package/dist/components/card-date-filter.d.ts +12 -0
- package/dist/components/card-date-filter.js +95 -0
- package/dist/components/date-time-picker.d.ts +12 -0
- package/dist/components/date-time-picker.js +96 -0
- package/dist/components/detail-dialog.d.ts +48 -0
- package/dist/components/detail-dialog.js +97 -0
- package/dist/components/document-links.d.ts +13 -0
- package/dist/components/document-links.js +19 -0
- package/dist/components/draft-row-actions.d.ts +14 -0
- package/dist/components/draft-row-actions.js +70 -0
- package/dist/components/error-boundary.d.ts +14 -0
- package/dist/components/error-boundary.js +35 -0
- package/dist/components/glow-card.d.ts +13 -0
- package/dist/components/glow-card.js +48 -0
- package/dist/components/org-picker.d.ts +17 -0
- package/dist/components/org-picker.js +56 -0
- package/dist/components/overflow-row-actions.d.ts +29 -0
- package/dist/components/overflow-row-actions.js +135 -0
- package/dist/components/page-header.d.ts +21 -0
- package/dist/components/page-header.js +21 -0
- package/dist/components/permission-button.d.ts +4 -0
- package/dist/components/permission-button.js +17 -0
- package/dist/components/permission-context.d.ts +12 -0
- package/dist/components/permission-context.js +17 -0
- package/dist/components/person-picker.d.ts +20 -0
- package/dist/components/person-picker.js +38 -0
- package/dist/components/process-flow-bar.d.ts +15 -0
- package/dist/components/process-flow-bar.js +19 -0
- package/dist/components/product-picker.d.ts +19 -0
- package/dist/components/product-picker.js +155 -0
- package/dist/components/ref-doc-picker.d.ts +24 -0
- package/dist/components/ref-doc-picker.js +139 -0
- package/dist/components/scroll-to-top.d.ts +1 -0
- package/dist/components/scroll-to-top.js +20 -0
- package/dist/components/state-view.d.ts +26 -0
- package/dist/components/state-view.js +75 -0
- package/dist/components/theme-switcher.d.ts +27 -0
- package/dist/components/theme-switcher.js +77 -0
- package/dist/components/time-filter.d.ts +7 -0
- package/dist/components/time-filter.js +65 -0
- package/dist/components/ui/accordion.d.ts +7 -0
- package/dist/components/ui/accordion.js +64 -0
- package/dist/components/ui/alert-dialog.d.ts +15 -0
- package/dist/components/ui/alert-dialog.js +160 -0
- package/dist/components/ui/alert.d.ts +12 -0
- package/dist/components/ui/alert.js +66 -0
- package/dist/components/ui/aspect-ratio.d.ts +3 -0
- package/dist/components/ui/aspect-ratio.js +10 -0
- package/dist/components/ui/avatar.d.ts +6 -0
- package/dist/components/ui/avatar.js +53 -0
- package/dist/components/ui/badge.d.ts +12 -0
- package/dist/components/ui/badge.js +44 -0
- package/dist/components/ui/breadcrumb.d.ts +11 -0
- package/dist/components/ui/breadcrumb.js +103 -0
- package/dist/components/ui/button-group.d.ts +14 -0
- package/dist/components/ui/button-group.js +76 -0
- package/dist/components/ui/button.d.ts +20 -0
- package/dist/components/ui/button.js +93 -0
- package/dist/components/ui/calendar.d.ts +73 -0
- package/dist/components/ui/calendar.js +103 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/card.js +90 -0
- package/dist/components/ui/carousel.d.ts +14 -0
- package/dist/components/ui/carousel.js +200 -0
- package/dist/components/ui/chart.d.ts +43 -0
- package/dist/components/ui/chart.js +252 -0
- package/dist/components/ui/checkbox.d.ts +4 -0
- package/dist/components/ui/checkbox.js +31 -0
- package/dist/components/ui/collapsible.d.ts +5 -0
- package/dist/components/ui/collapsible.js +34 -0
- package/dist/components/ui/command.d.ts +18 -0
- package/dist/components/ui/command.js +170 -0
- package/dist/components/ui/context-menu.d.ts +26 -0
- package/dist/components/ui/context-menu.js +237 -0
- package/dist/components/ui/dialog.d.ts +17 -0
- package/dist/components/ui/dialog.js +139 -0
- package/dist/components/ui/drawer.d.ts +13 -0
- package/dist/components/ui/drawer.js +129 -0
- package/dist/components/ui/dropdown-menu.d.ts +26 -0
- package/dist/components/ui/dropdown-menu.js +245 -0
- package/dist/components/ui/empty.d.ts +14 -0
- package/dist/components/ui/empty.js +102 -0
- package/dist/components/ui/field.d.ts +27 -0
- package/dist/components/ui/field.js +229 -0
- package/dist/components/ui/form.d.ts +26 -0
- package/dist/components/ui/form.js +118 -0
- package/dist/components/ui/hover-card.d.ts +6 -0
- package/dist/components/ui/hover-card.js +39 -0
- package/dist/components/ui/input-group.d.ts +22 -0
- package/dist/components/ui/input-group.js +156 -0
- package/dist/components/ui/input-otp.d.ts +11 -0
- package/dist/components/ui/input-otp.js +66 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/input.js +21 -0
- package/dist/components/ui/item.d.ts +29 -0
- package/dist/components/ui/item.js +187 -0
- package/dist/components/ui/kbd.d.ts +3 -0
- package/dist/components/ui/kbd.js +31 -0
- package/dist/components/ui/label.d.ts +4 -0
- package/dist/components/ui/label.js +22 -0
- package/dist/components/ui/menubar.d.ts +26 -0
- package/dist/components/ui/menubar.js +252 -0
- package/dist/components/ui/navigation-menu.d.ts +17 -0
- package/dist/components/ui/navigation-menu.js +170 -0
- package/dist/components/ui/pagination.d.ts +13 -0
- package/dist/components/ui/pagination.js +118 -0
- package/dist/components/ui/popover.d.ts +8 -0
- package/dist/components/ui/popover.js +47 -0
- package/dist/components/ui/progress.d.ts +4 -0
- package/dist/components/ui/progress.js +34 -0
- package/dist/components/ui/radio-group.d.ts +5 -0
- package/dist/components/ui/radio-group.js +45 -0
- package/dist/components/ui/resizable.d.ts +7 -0
- package/dist/components/ui/resizable.js +49 -0
- package/dist/components/ui/scroll-area.d.ts +5 -0
- package/dist/components/ui/scroll-area.js +60 -0
- package/dist/components/ui/select.d.ts +17 -0
- package/dist/components/ui/select.js +215 -0
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/separator.js +26 -0
- package/dist/components/ui/sheet.d.ts +13 -0
- package/dist/components/ui/sheet.js +127 -0
- package/dist/components/ui/sidebar.d.ts +72 -0
- package/dist/components/ui/sidebar.js +656 -0
- package/dist/components/ui/skeleton.d.ts +2 -0
- package/dist/components/ui/skeleton.js +15 -0
- package/dist/components/ui/slider.d.ts +4 -0
- package/dist/components/ui/slider.js +63 -0
- package/dist/components/ui/sonner.d.ts +4 -0
- package/dist/components/ui/sonner.js +34 -0
- package/dist/components/ui/spinner.d.ts +2 -0
- package/dist/components/ui/spinner.js +17 -0
- package/dist/components/ui/switch.d.ts +4 -0
- package/dist/components/ui/switch.js +31 -0
- package/dist/components/ui/table.d.ts +10 -0
- package/dist/components/ui/table.js +114 -0
- package/dist/components/ui/tabs.d.ts +7 -0
- package/dist/components/ui/tabs.js +67 -0
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/components/ui/textarea.js +18 -0
- package/dist/components/ui/toggle-group.d.ts +9 -0
- package/dist/components/ui/toggle-group.js +68 -0
- package/dist/components/ui/toggle.d.ts +12 -0
- package/dist/components/ui/toggle.js +43 -0
- package/dist/components/ui/tooltip.d.ts +7 -0
- package/dist/components/ui/tooltip.js +56 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-mobile.js +18 -0
- package/dist/icons/index.d.ts +57 -0
- package/dist/icons/index.js +115 -0
- package/dist/icons/paths.d.ts +556 -0
- package/dist/icons/paths.js +231 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +399 -0
- package/dist/internal/selection-base.d.ts +37 -0
- package/dist/internal/selection-base.js +40 -0
- package/dist/lib/class-names.d.ts +6 -0
- package/dist/lib/class-names.js +159 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.js +7 -0
- package/dist/lib/variants.d.ts +21 -0
- package/dist/lib/variants.js +21 -0
- package/dist/primitives/accordion.d.ts +29 -0
- package/dist/primitives/accordion.js +49 -0
- package/dist/primitives/alert-dialog.d.ts +10 -0
- package/dist/primitives/alert-dialog.js +22 -0
- package/dist/primitives/aspect-ratio.d.ts +4 -0
- package/dist/primitives/aspect-ratio.js +7 -0
- package/dist/primitives/avatar.d.ts +8 -0
- package/dist/primitives/avatar.js +45 -0
- package/dist/primitives/carousel.d.ts +22 -0
- package/dist/primitives/carousel.js +78 -0
- package/dist/primitives/chart.d.ts +71 -0
- package/dist/primitives/chart.js +125 -0
- package/dist/primitives/checkbox.d.ts +13 -0
- package/dist/primitives/checkbox.js +24 -0
- package/dist/primitives/collapsible.d.ts +14 -0
- package/dist/primitives/collapsible.js +29 -0
- package/dist/primitives/command.d.ts +43 -0
- package/dist/primitives/command.js +98 -0
- package/dist/primitives/context-menu.d.ts +24 -0
- package/dist/primitives/context-menu.js +19 -0
- package/dist/primitives/core.d.ts +25 -0
- package/dist/primitives/core.js +89 -0
- package/dist/primitives/dialog.d.ts +7 -0
- package/dist/primitives/dialog.js +15 -0
- package/dist/primitives/drawer.d.ts +30 -0
- package/dist/primitives/drawer.js +39 -0
- package/dist/primitives/dropdown-menu.d.ts +24 -0
- package/dist/primitives/dropdown-menu.js +19 -0
- package/dist/primitives/form.d.ts +154 -0
- package/dist/primitives/form.js +139 -0
- package/dist/primitives/hover-card.d.ts +4 -0
- package/dist/primitives/hover-card.js +8 -0
- package/dist/primitives/input-otp.d.ts +21 -0
- package/dist/primitives/input-otp.js +78 -0
- package/dist/primitives/label.d.ts +2 -0
- package/dist/primitives/label.js +7 -0
- package/dist/primitives/layer.d.ts +84 -0
- package/dist/primitives/layer.js +300 -0
- package/dist/primitives/menu.d.ts +56 -0
- package/dist/primitives/menu.js +126 -0
- package/dist/primitives/menubar.d.ts +91 -0
- package/dist/primitives/menubar.js +44 -0
- package/dist/primitives/navigation-menu.d.ts +32 -0
- package/dist/primitives/navigation-menu.js +121 -0
- package/dist/primitives/popover.d.ts +4 -0
- package/dist/primitives/popover.js +12 -0
- package/dist/primitives/progress.d.ts +7 -0
- package/dist/primitives/progress.js +13 -0
- package/dist/primitives/radio-group.d.ts +18 -0
- package/dist/primitives/radio-group.js +36 -0
- package/dist/primitives/resizable.d.ts +19 -0
- package/dist/primitives/resizable.js +91 -0
- package/dist/primitives/scroll-area.d.ts +12 -0
- package/dist/primitives/scroll-area.js +26 -0
- package/dist/primitives/select.d.ts +42 -0
- package/dist/primitives/select.js +167 -0
- package/dist/primitives/separator.d.ts +5 -0
- package/dist/primitives/separator.js +7 -0
- package/dist/primitives/slider.d.ts +25 -0
- package/dist/primitives/slider.js +98 -0
- package/dist/primitives/slot.d.ts +1 -0
- package/dist/primitives/slot.js +4 -0
- package/dist/primitives/switch.d.ts +11 -0
- package/dist/primitives/switch.js +22 -0
- package/dist/primitives/tabs.d.ts +23 -0
- package/dist/primitives/tabs.js +38 -0
- package/dist/primitives/toast.d.ts +55 -0
- package/dist/primitives/toast.js +86 -0
- package/dist/primitives/toggle-group.d.ts +24 -0
- package/dist/primitives/toggle-group.js +33 -0
- package/dist/primitives/toggle.d.ts +7 -0
- package/dist/primitives/toggle.js +13 -0
- package/dist/primitives/tooltip.d.ts +7 -0
- package/dist/primitives/tooltip.js +10 -0
- package/dist/style-entry.d.ts +1 -0
- package/dist/style-entry.js +1 -0
- package/dist/styles.css +7016 -0
- package/dist/styles.js +1 -0
- package/dist/theme/index.d.ts +110 -0
- package/dist/theme/index.js +199 -0
- package/licenses/Lucide.txt +15 -0
- package/package.json +67 -4
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
function useForm({ defaultValues = {}, mode = "onSubmit" } = {}) {
|
|
4
|
+
const initial = React.useRef(defaultValues);
|
|
5
|
+
const modeRef = React.useRef(mode);
|
|
6
|
+
modeRef.current = mode;
|
|
7
|
+
const controlRef = React.useRef(null);
|
|
8
|
+
if (!controlRef.current) {
|
|
9
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
10
|
+
const publish2 = (patch) => {
|
|
11
|
+
control2.snapshot = { ...control2.snapshot, ...patch };
|
|
12
|
+
listeners.forEach((callback) => callback());
|
|
13
|
+
};
|
|
14
|
+
const control2 = {
|
|
15
|
+
snapshot: { values: { ...defaultValues }, errors: {}, touchedFields: {}, dirtyFields: {}, isSubmitting: false, isSubmitted: false },
|
|
16
|
+
rules: /* @__PURE__ */ new Map(),
|
|
17
|
+
refs: /* @__PURE__ */ new Map(),
|
|
18
|
+
subscribe(callback) {
|
|
19
|
+
listeners.add(callback);
|
|
20
|
+
return () => {
|
|
21
|
+
listeners.delete(callback);
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
setValue(name, value, options = {}) {
|
|
25
|
+
publish2({ values: { ...control2.snapshot.values, [name]: value }, dirtyFields: options.shouldDirty === false ? control2.snapshot.dirtyFields : { ...control2.snapshot.dirtyFields, [name]: value !== initial.current[name] }, touchedFields: options.shouldTouch ? { ...control2.snapshot.touchedFields, [name]: true } : control2.snapshot.touchedFields });
|
|
26
|
+
if (options.shouldValidate || modeRef.current === "onChange" || control2.snapshot.isSubmitted) void control2.validate([name]);
|
|
27
|
+
},
|
|
28
|
+
touch(name) {
|
|
29
|
+
publish2({ touchedFields: { ...control2.snapshot.touchedFields, [name]: true } });
|
|
30
|
+
if (modeRef.current === "onBlur") void control2.validate([name]);
|
|
31
|
+
},
|
|
32
|
+
async validate(names = [...control2.rules.keys()]) {
|
|
33
|
+
const values = control2.snapshot.values;
|
|
34
|
+
const results = await Promise.all(names.map(async (name) => [name, await validateValue(values[name], control2.rules.get(name) ?? {})]));
|
|
35
|
+
const errors = { ...control2.snapshot.errors };
|
|
36
|
+
results.forEach(([name, error]) => {
|
|
37
|
+
if (control2.snapshot.values[name] !== values[name]) return;
|
|
38
|
+
if (error) errors[name] = error;
|
|
39
|
+
else delete errors[name];
|
|
40
|
+
});
|
|
41
|
+
publish2({ errors });
|
|
42
|
+
return names.every((name) => !errors[name]);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
Object.assign(control2, { publish: publish2 });
|
|
46
|
+
controlRef.current = control2;
|
|
47
|
+
}
|
|
48
|
+
const control = controlRef.current;
|
|
49
|
+
const snapshot = React.useSyncExternalStore(control.subscribe, () => control.snapshot, () => control.snapshot);
|
|
50
|
+
const publish = (patch) => control.publish(patch);
|
|
51
|
+
const getFieldState = (name, state = control.snapshot) => ({ error: state.errors[name], invalid: !!state.errors[name], isTouched: !!state.touchedFields[name], isDirty: !!state.dirtyFields[name] });
|
|
52
|
+
return {
|
|
53
|
+
control,
|
|
54
|
+
formState: { ...snapshot, isDirty: Object.values(snapshot.dirtyFields).some(Boolean), isValid: !Object.keys(snapshot.errors).length },
|
|
55
|
+
getFieldState,
|
|
56
|
+
getValues: () => ({ ...control.snapshot.values }),
|
|
57
|
+
setValue: control.setValue,
|
|
58
|
+
trigger: (name) => control.validate(name ? [name] : void 0),
|
|
59
|
+
reset(values = initial.current) {
|
|
60
|
+
initial.current = values;
|
|
61
|
+
publish({ values: { ...values }, errors: {}, touchedFields: {}, dirtyFields: {}, isSubmitted: false });
|
|
62
|
+
},
|
|
63
|
+
setFocus(name) {
|
|
64
|
+
control.refs.get(name)?.focus();
|
|
65
|
+
},
|
|
66
|
+
handleSubmit(onValid, onInvalid) {
|
|
67
|
+
return async (event) => {
|
|
68
|
+
event?.preventDefault();
|
|
69
|
+
if (control.snapshot.isSubmitting) return;
|
|
70
|
+
publish({ isSubmitting: true, isSubmitted: true });
|
|
71
|
+
try {
|
|
72
|
+
if (await control.validate()) await onValid({ ...control.snapshot.values });
|
|
73
|
+
else {
|
|
74
|
+
onInvalid?.(control.snapshot.errors);
|
|
75
|
+
control.refs.get(Object.keys(control.snapshot.errors)[0])?.focus();
|
|
76
|
+
}
|
|
77
|
+
} finally {
|
|
78
|
+
publish({ isSubmitting: false });
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
async function validateValue(value, rules) {
|
|
85
|
+
const fail = (type, message) => ({ type, message });
|
|
86
|
+
if (rules.required && (value == null || value === "" || value === false || Array.isArray(value) && !value.length)) return fail("required", typeof rules.required === "string" ? rules.required : "此字段必填");
|
|
87
|
+
if (value != null && value !== "") {
|
|
88
|
+
for (const name of ["min", "max", "minLength", "maxLength"]) {
|
|
89
|
+
const rule = rules[name];
|
|
90
|
+
if (rule === void 0) continue;
|
|
91
|
+
const bound = typeof rule === "number" ? rule : rule.value;
|
|
92
|
+
const actual = name.endsWith("Length") ? value.length : Number(value);
|
|
93
|
+
if (name.startsWith("min") ? actual < bound : actual > bound) return fail(name, typeof rule === "number" ? `${name.startsWith("min") ? "最小" : "最大"}${name.endsWith("Length") ? "长度" : "值"}为 ${bound}` : rule.message);
|
|
94
|
+
}
|
|
95
|
+
if (rules.pattern) {
|
|
96
|
+
const pattern = rules.pattern instanceof RegExp ? rules.pattern : rules.pattern.value;
|
|
97
|
+
pattern.lastIndex = 0;
|
|
98
|
+
if (!pattern.test(String(value))) return fail("pattern", rules.pattern instanceof RegExp ? "格式不正确" : rules.pattern.message);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (rules.validate) {
|
|
102
|
+
const result = await rules.validate(value);
|
|
103
|
+
if (result !== true) return fail("validate", typeof result === "string" ? result : "校验未通过");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const FormContext = React.createContext(null);
|
|
107
|
+
function FormProvider({ children, ...form }) {
|
|
108
|
+
return /* @__PURE__ */ jsx(FormContext.Provider, { value: form, children });
|
|
109
|
+
}
|
|
110
|
+
function useFormContext() {
|
|
111
|
+
const form = React.useContext(FormContext);
|
|
112
|
+
if (!form) throw new Error("字段必须在 Form 内使用");
|
|
113
|
+
return form;
|
|
114
|
+
}
|
|
115
|
+
function useFormState(_options) {
|
|
116
|
+
return useFormContext().formState;
|
|
117
|
+
}
|
|
118
|
+
function Controller({ name, control, rules, defaultValue, disabled, render }) {
|
|
119
|
+
const state = React.useSyncExternalStore(control.subscribe, () => control.snapshot, () => control.snapshot);
|
|
120
|
+
control.rules.set(name, disabled ? {} : rules ?? {});
|
|
121
|
+
React.useEffect(() => {
|
|
122
|
+
if (control.snapshot.values[name] === void 0 && defaultValue !== void 0) control.setValue(name, defaultValue, { shouldDirty: false });
|
|
123
|
+
return () => {
|
|
124
|
+
control.rules.delete(name);
|
|
125
|
+
control.refs.delete(name);
|
|
126
|
+
};
|
|
127
|
+
}, [control, name]);
|
|
128
|
+
return render({ field: { name, value: state.values[name] ?? defaultValue ?? "", disabled, onChange: (event) => control.setValue(name, event?.target ? event.target.type === "checkbox" ? event.target.checked : event.target.value : event), onBlur: () => control.touch(name), ref: (element) => {
|
|
129
|
+
if (element) control.refs.set(name, element);
|
|
130
|
+
else control.refs.delete(name);
|
|
131
|
+
} }, fieldState: { error: state.errors[name], invalid: !!state.errors[name] }, formState: state });
|
|
132
|
+
}
|
|
133
|
+
export {
|
|
134
|
+
Controller,
|
|
135
|
+
FormProvider,
|
|
136
|
+
useForm,
|
|
137
|
+
useFormContext,
|
|
138
|
+
useFormState
|
|
139
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const Root: ({ children, open: controlled, defaultOpen, onOpenChange, modal: isModal, delayDuration, openDelay, closeDelay, ...rest }: import("./layer").LayerRootProps & {
|
|
2
|
+
sub?: boolean;
|
|
3
|
+
direction?: import("./layer").LayerState["direction"];
|
|
4
|
+
}) => import("react").JSX.Element, Trigger: ({ onClick, onKeyDown, onPointerEnter, onPointerLeave, onFocus, onBlur, onContextMenu, ref, disabled, ...props }: import("./core").ButtonProps) => import("react").JSX.Element, Portal: ({ children, container, forceMount }: import("./layer").PortalProps) => import("react").ReactPortal | null, Content: ({ forceMount, side, align, sideOffset, alignOffset, avoidCollisions, collisionPadding, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside, ref, style, onKeyDown, onPointerEnter, onPointerLeave, ...props }: import("./layer").LayerContentProps) => import("react").JSX.Element | null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
type SlotState = {
|
|
3
|
+
char: string | null;
|
|
4
|
+
isActive: boolean;
|
|
5
|
+
hasFakeCaret: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare const OTPInputContext: React.Context<{
|
|
8
|
+
slots: SlotState[];
|
|
9
|
+
}>;
|
|
10
|
+
export interface OTPInputProps extends Omit<React.ComponentProps<'input'>, 'value' | 'defaultValue' | 'onChange' | 'children' | 'maxLength'> {
|
|
11
|
+
maxLength: number;
|
|
12
|
+
value?: string;
|
|
13
|
+
defaultValue?: string;
|
|
14
|
+
onChange?: (value: string) => void;
|
|
15
|
+
onComplete?: (value: string) => void;
|
|
16
|
+
pasteTransformer?: (text: string) => string;
|
|
17
|
+
containerClassName?: string;
|
|
18
|
+
children?: React.ReactNode;
|
|
19
|
+
}
|
|
20
|
+
export declare function OTPInput({ maxLength, value, defaultValue, onChange, onComplete, pasteTransformer, containerClassName, children, pattern, disabled, readOnly, ref, style, onFocus, onBlur, onSelect, onPaste, autoComplete, inputMode, ...props }: OTPInputProps): React.JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { useControllable, useMergedRef } from "./core.js";
|
|
4
|
+
const OTPInputContext = React.createContext({ slots: [] });
|
|
5
|
+
function OTPInput({ maxLength, value, defaultValue = "", onChange, onComplete, pasteTransformer, containerClassName, children, pattern, disabled, readOnly, ref, style, onFocus, onBlur, onSelect, onPaste, autoComplete = "one-time-code", inputMode = "numeric", ...props }) {
|
|
6
|
+
const [current, set] = useControllable(value, defaultValue, onChange);
|
|
7
|
+
const [focused, setFocused] = React.useState(false), [caret, setCaret] = React.useState(0);
|
|
8
|
+
const input = React.useRef(null), merged = useMergedRef(ref, input);
|
|
9
|
+
const length = Math.max(1, Math.floor(maxLength));
|
|
10
|
+
const accept = (candidate) => {
|
|
11
|
+
const next = candidate.slice(0, length);
|
|
12
|
+
if (next && pattern && !new RegExp(`^(?:${pattern})$`).test(next)) return;
|
|
13
|
+
set(next);
|
|
14
|
+
setCaret(Math.min(next.length, length - 1));
|
|
15
|
+
if (next.length === length && next !== current) onComplete?.(next);
|
|
16
|
+
};
|
|
17
|
+
const slots = Array.from({ length }, (_, index) => ({ char: current[index] ?? null, isActive: focused && caret === index, hasFakeCaret: focused && caret === index && !current[index] }));
|
|
18
|
+
return /* @__PURE__ */ jsx(OTPInputContext.Provider, { value: { slots }, children: /* @__PURE__ */ jsxs("div", { className: containerClassName, style: { position: "relative", cursor: disabled ? "not-allowed" : "text" }, "data-disabled": disabled ? "" : void 0, children: [
|
|
19
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { display: "contents" }, children }),
|
|
20
|
+
/* @__PURE__ */ jsx(
|
|
21
|
+
"input",
|
|
22
|
+
{
|
|
23
|
+
...props,
|
|
24
|
+
ref: merged,
|
|
25
|
+
value: current,
|
|
26
|
+
disabled,
|
|
27
|
+
readOnly,
|
|
28
|
+
maxLength: length,
|
|
29
|
+
pattern,
|
|
30
|
+
autoComplete,
|
|
31
|
+
inputMode,
|
|
32
|
+
style: { position: "absolute", inset: 0, width: "100%", height: "100%", opacity: 0, caretColor: "transparent", ...style },
|
|
33
|
+
onPointerDown: (event) => {
|
|
34
|
+
props.onPointerDown?.(event);
|
|
35
|
+
if (event.defaultPrevented || disabled) return;
|
|
36
|
+
const slots2 = [...event.currentTarget.parentElement.querySelectorAll('[data-slot="input-otp-slot"]')];
|
|
37
|
+
const index = slots2.findIndex((slot) => {
|
|
38
|
+
const bounds = slot.getBoundingClientRect();
|
|
39
|
+
return event.clientX >= bounds.left && event.clientX <= bounds.right;
|
|
40
|
+
});
|
|
41
|
+
if (index >= 0) {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
event.currentTarget.focus();
|
|
44
|
+
event.currentTarget.setSelectionRange(Math.min(index, current.length), Math.min(index + 1, current.length));
|
|
45
|
+
setCaret(index);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
onChange: (event) => accept(event.target.value),
|
|
49
|
+
onFocus: (event) => {
|
|
50
|
+
setFocused(true);
|
|
51
|
+
setCaret(Math.min(event.target.selectionStart ?? current.length, length - 1));
|
|
52
|
+
onFocus?.(event);
|
|
53
|
+
},
|
|
54
|
+
onBlur: (event) => {
|
|
55
|
+
setFocused(false);
|
|
56
|
+
onBlur?.(event);
|
|
57
|
+
},
|
|
58
|
+
onSelect: (event) => {
|
|
59
|
+
setCaret(Math.min(event.currentTarget.selectionStart ?? 0, length - 1));
|
|
60
|
+
onSelect?.(event);
|
|
61
|
+
},
|
|
62
|
+
onPaste: (event) => {
|
|
63
|
+
onPaste?.(event);
|
|
64
|
+
if (event.defaultPrevented || disabled || readOnly) return;
|
|
65
|
+
event.preventDefault();
|
|
66
|
+
const raw = event.clipboardData.getData("text");
|
|
67
|
+
const text = pasteTransformer ? pasteTransformer(raw) : raw;
|
|
68
|
+
const start = event.currentTarget.selectionStart ?? current.length, end = event.currentTarget.selectionEnd ?? start;
|
|
69
|
+
accept(current.slice(0, start) + text + current.slice(end));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
] }) });
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
OTPInput,
|
|
77
|
+
OTPInputContext
|
|
78
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type ButtonProps, type DivProps } from './core';
|
|
3
|
+
export interface LayerRootProps {
|
|
4
|
+
children?: React.ReactNode;
|
|
5
|
+
open?: boolean;
|
|
6
|
+
defaultOpen?: boolean;
|
|
7
|
+
onOpenChange?: (open: boolean) => void;
|
|
8
|
+
/** Modal layers trap focus and lock background scrolling. */
|
|
9
|
+
modal?: boolean;
|
|
10
|
+
delayDuration?: number;
|
|
11
|
+
openDelay?: number;
|
|
12
|
+
closeDelay?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface PortalProps {
|
|
15
|
+
children?: React.ReactNode;
|
|
16
|
+
container?: HTMLElement | null;
|
|
17
|
+
forceMount?: true;
|
|
18
|
+
}
|
|
19
|
+
export type OutsideEvent = CustomEvent<{
|
|
20
|
+
originalEvent: PointerEvent | FocusEvent;
|
|
21
|
+
}>;
|
|
22
|
+
export interface LayerContentProps extends DivProps {
|
|
23
|
+
forceMount?: true;
|
|
24
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
25
|
+
align?: 'start' | 'center' | 'end';
|
|
26
|
+
sideOffset?: number;
|
|
27
|
+
alignOffset?: number;
|
|
28
|
+
avoidCollisions?: boolean;
|
|
29
|
+
collisionPadding?: number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>;
|
|
30
|
+
onOpenAutoFocus?: (event: Event) => void;
|
|
31
|
+
onCloseAutoFocus?: (event: Event) => void;
|
|
32
|
+
onEscapeKeyDown?: (event: KeyboardEvent) => void;
|
|
33
|
+
onPointerDownOutside?: (event: OutsideEvent) => void;
|
|
34
|
+
onFocusOutside?: (event: OutsideEvent) => void;
|
|
35
|
+
onInteractOutside?: (event: OutsideEvent) => void;
|
|
36
|
+
}
|
|
37
|
+
export interface LayerState {
|
|
38
|
+
open: boolean;
|
|
39
|
+
setOpen: (v: boolean) => void;
|
|
40
|
+
modal: boolean;
|
|
41
|
+
id: string;
|
|
42
|
+
trigger: React.RefObject<HTMLElement | null>;
|
|
43
|
+
anchor: React.RefObject<HTMLElement | null>;
|
|
44
|
+
point: React.RefObject<{
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
} | null>;
|
|
48
|
+
parent?: LayerState;
|
|
49
|
+
sub?: boolean;
|
|
50
|
+
direction?: 'top' | 'right' | 'bottom' | 'left';
|
|
51
|
+
schedule: (open: boolean, immediate?: boolean) => void;
|
|
52
|
+
}
|
|
53
|
+
export declare function createLayer({ modal, role, floating, hover, contextMenu, alert }?: {
|
|
54
|
+
modal?: boolean;
|
|
55
|
+
role?: 'dialog' | 'alertdialog' | 'tooltip' | 'menu' | 'listbox';
|
|
56
|
+
floating?: boolean;
|
|
57
|
+
hover?: boolean;
|
|
58
|
+
contextMenu?: boolean;
|
|
59
|
+
alert?: boolean;
|
|
60
|
+
}): {
|
|
61
|
+
Root: ({ children, open: controlled, defaultOpen, onOpenChange, modal: isModal, delayDuration, openDelay, closeDelay, ...rest }: LayerRootProps & {
|
|
62
|
+
sub?: boolean;
|
|
63
|
+
direction?: LayerState["direction"];
|
|
64
|
+
}) => React.JSX.Element;
|
|
65
|
+
Provider: ({ children, delayDuration }: {
|
|
66
|
+
children?: React.ReactNode;
|
|
67
|
+
delayDuration?: number;
|
|
68
|
+
}) => React.JSX.Element;
|
|
69
|
+
Trigger: ({ onClick, onKeyDown, onPointerEnter, onPointerLeave, onFocus, onBlur, onContextMenu, ref, disabled, ...props }: ButtonProps) => React.JSX.Element;
|
|
70
|
+
Anchor: ({ ref, ...props }: DivProps) => React.JSX.Element;
|
|
71
|
+
Close: ({ onClick, ...props }: ButtonProps) => React.JSX.Element;
|
|
72
|
+
Portal: ({ children, container, forceMount }: PortalProps) => React.ReactPortal | null;
|
|
73
|
+
Overlay: ({ forceMount, ...props }: DivProps & {
|
|
74
|
+
forceMount?: true;
|
|
75
|
+
}) => React.JSX.Element | null;
|
|
76
|
+
Content: ({ forceMount, side, align, sideOffset, alignOffset, avoidCollisions, collisionPadding, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside, ref, style, onKeyDown, onPointerEnter, onPointerLeave, ...props }: LayerContentProps) => React.JSX.Element | null;
|
|
77
|
+
Title: (props: React.ComponentProps<"h2">) => React.JSX.Element;
|
|
78
|
+
Description: (props: React.ComponentProps<"p">) => React.JSX.Element;
|
|
79
|
+
Arrow: (props: React.ComponentProps<"span">) => React.JSX.Element;
|
|
80
|
+
Sub: (props: LayerRootProps) => React.JSX.Element;
|
|
81
|
+
useLayer: () => LayerState;
|
|
82
|
+
};
|
|
83
|
+
export type ModalRootProps = Omit<LayerRootProps, "delayDuration" | "openDelay" | "closeDelay">;
|
|
84
|
+
export type ModalContentProps = Omit<LayerContentProps, "side" | "align" | "sideOffset" | "alignOffset" | "avoidCollisions" | "collisionPadding">;
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
import { useMergedRef, focusable, DivPart, ButtonPart, useControllable } from "./core.js";
|
|
5
|
+
const stack = [];
|
|
6
|
+
let locks = 0, originalOverflow = "";
|
|
7
|
+
let hidden = [];
|
|
8
|
+
function updateBackground() {
|
|
9
|
+
hidden.forEach(({ node, inert, aria }) => {
|
|
10
|
+
node.inert = inert;
|
|
11
|
+
if (aria === null)
|
|
12
|
+
node.removeAttribute("aria-hidden");
|
|
13
|
+
else
|
|
14
|
+
node.setAttribute("aria-hidden", aria);
|
|
15
|
+
});
|
|
16
|
+
hidden = [];
|
|
17
|
+
if (!stack.some((layer) => layer.modal))
|
|
18
|
+
return;
|
|
19
|
+
const allowed = stack.map((layer) => layer.node);
|
|
20
|
+
const visit = (parent) => [...parent.children].forEach((element) => {
|
|
21
|
+
if (!(element instanceof HTMLElement) || ["SCRIPT", "STYLE", "LINK"].includes(element.tagName))
|
|
22
|
+
return;
|
|
23
|
+
if (allowed.includes(element))
|
|
24
|
+
return;
|
|
25
|
+
if (allowed.some((node) => element.contains(node)))
|
|
26
|
+
visit(element);
|
|
27
|
+
else {
|
|
28
|
+
hidden.push({ node: element, inert: element.inert, aria: element.getAttribute("aria-hidden") });
|
|
29
|
+
element.inert = true;
|
|
30
|
+
element.setAttribute("aria-hidden", "true");
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
visit(document.body);
|
|
34
|
+
}
|
|
35
|
+
const Nesting = React.createContext(null);
|
|
36
|
+
const depth = (state) => state.parent ? 1 + depth(state.parent) : 0;
|
|
37
|
+
function createLayer({ modal = false, role = "dialog", floating = true, hover = false, contextMenu = false, alert = false } = {}) {
|
|
38
|
+
const Context = React.createContext(null);
|
|
39
|
+
const DelayContext = React.createContext(0);
|
|
40
|
+
const PortalMountContext = React.createContext(false);
|
|
41
|
+
function useLayer() {
|
|
42
|
+
const value = React.useContext(Context);
|
|
43
|
+
if (!value)
|
|
44
|
+
throw new Error("Layer part must be inside its root");
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
function Root({ children, open: controlled, defaultOpen = false, onOpenChange, modal: isModal = modal, delayDuration, openDelay, closeDelay = 100, ...rest }) {
|
|
48
|
+
const parent = React.useContext(Nesting), delay = React.useContext(DelayContext);
|
|
49
|
+
const [open, setOpen] = useControllable(controlled, defaultOpen, onOpenChange);
|
|
50
|
+
const trigger = React.useRef(null), anchor = React.useRef(null), point = React.useRef(null);
|
|
51
|
+
const timer = React.useRef(void 0), id = React.useId();
|
|
52
|
+
React.useEffect(() => () => clearTimeout(timer.current), []);
|
|
53
|
+
const schedule = (next, immediate = false) => {
|
|
54
|
+
clearTimeout(timer.current);
|
|
55
|
+
const ms = immediate ? 0 : next ? openDelay ?? delayDuration ?? delay : closeDelay;
|
|
56
|
+
if (!ms)
|
|
57
|
+
setOpen(next);
|
|
58
|
+
else
|
|
59
|
+
timer.current = setTimeout(() => setOpen(next), ms);
|
|
60
|
+
};
|
|
61
|
+
const state = { open, setOpen, modal: isModal, trigger, anchor, point, id, parent: parent ?? void 0, sub: rest.sub, direction: rest.direction, schedule };
|
|
62
|
+
return /* @__PURE__ */ jsx(Context.Provider, { value: state, children: /* @__PURE__ */ jsx(Nesting.Provider, { value: state, children }) });
|
|
63
|
+
}
|
|
64
|
+
function Provider({ children, delayDuration = 0 }) {
|
|
65
|
+
return /* @__PURE__ */ jsx(DelayContext.Provider, { value: delayDuration, children });
|
|
66
|
+
}
|
|
67
|
+
function Trigger({ onClick, onKeyDown, onPointerEnter, onPointerLeave, onFocus, onBlur, onContextMenu, ref, disabled, ...props }) {
|
|
68
|
+
const state = useLayer();
|
|
69
|
+
const merged = useMergedRef(ref, state.trigger);
|
|
70
|
+
return /* @__PURE__ */ jsx(ButtonPart, { ...props, ref: merged, disabled, "aria-haspopup": role === "tooltip" ? void 0 : role === "alertdialog" ? "dialog" : role, "aria-expanded": role === "tooltip" ? void 0 : state.open, "aria-controls": state.open ? state.id : void 0, "aria-describedby": role === "tooltip" && state.open ? state.id : props["aria-describedby"], "data-state": state.open ? "open" : "closed", onClick: (event) => {
|
|
71
|
+
onClick?.(event);
|
|
72
|
+
if (!event.defaultPrevented && !disabled && !hover && !contextMenu)
|
|
73
|
+
state.setOpen(!state.open);
|
|
74
|
+
}, onKeyDown: (event) => {
|
|
75
|
+
onKeyDown?.(event);
|
|
76
|
+
if (event.defaultPrevented || disabled)
|
|
77
|
+
return;
|
|
78
|
+
if (["ArrowDown", "ArrowUp"].includes(event.key) || contextMenu && event.key === "ContextMenu") {
|
|
79
|
+
event.preventDefault();
|
|
80
|
+
state.setOpen(true);
|
|
81
|
+
}
|
|
82
|
+
}, onContextMenu: (event) => {
|
|
83
|
+
onContextMenu?.(event);
|
|
84
|
+
if (contextMenu && !disabled && !event.defaultPrevented) {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
state.point.current = { x: event.clientX, y: event.clientY };
|
|
87
|
+
state.setOpen(true);
|
|
88
|
+
}
|
|
89
|
+
}, onPointerEnter: (event) => {
|
|
90
|
+
onPointerEnter?.(event);
|
|
91
|
+
if (hover && !disabled)
|
|
92
|
+
state.schedule(true);
|
|
93
|
+
}, onPointerLeave: (event) => {
|
|
94
|
+
onPointerLeave?.(event);
|
|
95
|
+
if (hover)
|
|
96
|
+
state.schedule(false);
|
|
97
|
+
}, onFocus: (event) => {
|
|
98
|
+
onFocus?.(event);
|
|
99
|
+
if (hover && !disabled)
|
|
100
|
+
state.schedule(true, true);
|
|
101
|
+
}, onBlur: (event) => {
|
|
102
|
+
onBlur?.(event);
|
|
103
|
+
if (hover)
|
|
104
|
+
state.schedule(false);
|
|
105
|
+
} });
|
|
106
|
+
}
|
|
107
|
+
function Anchor({ ref, ...props }) {
|
|
108
|
+
const state = useLayer();
|
|
109
|
+
const merged = useMergedRef(ref, state.anchor);
|
|
110
|
+
return /* @__PURE__ */ jsx(DivPart, { ref: merged, ...props });
|
|
111
|
+
}
|
|
112
|
+
function Close({ onClick, ...props }) {
|
|
113
|
+
const state = useLayer();
|
|
114
|
+
return /* @__PURE__ */ jsx(ButtonPart, { ...props, onClick: (event) => {
|
|
115
|
+
onClick?.(event);
|
|
116
|
+
if (!event.defaultPrevented)
|
|
117
|
+
state.setOpen(false);
|
|
118
|
+
} });
|
|
119
|
+
}
|
|
120
|
+
function Portal({ children, container, forceMount }) {
|
|
121
|
+
useLayer();
|
|
122
|
+
return typeof document !== "undefined" ? createPortal(/* @__PURE__ */ jsx(PortalMountContext.Provider, { value: !!forceMount, children }), container ?? document.body) : null;
|
|
123
|
+
}
|
|
124
|
+
function Overlay({ forceMount, ...props }) {
|
|
125
|
+
const state = useLayer(), portalMount = React.useContext(PortalMountContext);
|
|
126
|
+
return state.open || forceMount || portalMount ? /* @__PURE__ */ jsx(DivPart, { ...props, hidden: !state.open, "data-state": state.open ? "open" : "closed", "aria-hidden": "true" }) : null;
|
|
127
|
+
}
|
|
128
|
+
function Content({ forceMount, side = "bottom", align = "center", sideOffset = 0, alignOffset = 0, avoidCollisions = true, collisionPadding = 8, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside, ref, style, onKeyDown, onPointerEnter, onPointerLeave, ...props }) {
|
|
129
|
+
const portalMount = React.useContext(PortalMountContext);
|
|
130
|
+
const state = useLayer();
|
|
131
|
+
const local = React.useRef(null);
|
|
132
|
+
const merged = useMergedRef(ref, local);
|
|
133
|
+
const latest = React.useRef({ state, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside });
|
|
134
|
+
latest.current = { state, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside };
|
|
135
|
+
const [position, setPosition] = React.useState({ position: "fixed", visibility: "hidden" });
|
|
136
|
+
const [actualSide, setActualSide] = React.useState(side);
|
|
137
|
+
React.useLayoutEffect(() => {
|
|
138
|
+
if (!state.open || !floating)
|
|
139
|
+
return;
|
|
140
|
+
const update = () => {
|
|
141
|
+
const node = local.current, anchor = state.anchor.current ?? state.trigger.current;
|
|
142
|
+
if (!node)
|
|
143
|
+
return;
|
|
144
|
+
const rect = state.point.current ? { left: state.point.current.x, right: state.point.current.x, top: state.point.current.y, bottom: state.point.current.y, width: 0, height: 0 } : anchor?.getBoundingClientRect();
|
|
145
|
+
if (!rect)
|
|
146
|
+
return;
|
|
147
|
+
const size = node.getBoundingClientRect();
|
|
148
|
+
const padding = typeof collisionPadding === "number" ? collisionPadding : Math.max(8, ...Object.values(collisionPadding));
|
|
149
|
+
let resolved = state.sub ? "right" : side;
|
|
150
|
+
if (avoidCollisions) {
|
|
151
|
+
if (resolved === "bottom" && rect.bottom + sideOffset + size.height > innerHeight - padding && rect.top > innerHeight - rect.bottom)
|
|
152
|
+
resolved = "top";
|
|
153
|
+
else if (resolved === "top" && rect.top - sideOffset - size.height < padding && innerHeight - rect.bottom > rect.top)
|
|
154
|
+
resolved = "bottom";
|
|
155
|
+
else if (resolved === "right" && rect.right + sideOffset + size.width > innerWidth - padding)
|
|
156
|
+
resolved = "left";
|
|
157
|
+
else if (resolved === "left" && rect.left - sideOffset - size.width < padding)
|
|
158
|
+
resolved = "right";
|
|
159
|
+
}
|
|
160
|
+
const vertical = resolved === "top" || resolved === "bottom";
|
|
161
|
+
let x = vertical ? align === "start" ? rect.left : align === "end" ? rect.right - size.width : rect.left + (rect.width - size.width) / 2 : resolved === "right" ? rect.right + sideOffset : rect.left - size.width - sideOffset;
|
|
162
|
+
let y = vertical ? resolved === "bottom" ? rect.bottom + sideOffset : rect.top - size.height - sideOffset : align === "end" ? rect.bottom - size.height : align === "center" ? rect.top + (rect.height - size.height) / 2 : rect.top;
|
|
163
|
+
if (vertical)
|
|
164
|
+
x += alignOffset;
|
|
165
|
+
else
|
|
166
|
+
y += alignOffset;
|
|
167
|
+
if (avoidCollisions) {
|
|
168
|
+
x = Math.max(padding, Math.min(innerWidth - size.width - padding, x));
|
|
169
|
+
y = Math.max(padding, Math.min(innerHeight - size.height - padding, y));
|
|
170
|
+
}
|
|
171
|
+
const available = Math.max(0, resolved === "top" ? rect.top - sideOffset - padding : resolved === "bottom" ? innerHeight - rect.bottom - sideOffset - padding : innerHeight - padding * 2);
|
|
172
|
+
setActualSide(resolved);
|
|
173
|
+
setPosition({ position: "fixed", left: x, top: y, visibility: "visible", maxHeight: available, "--aaas-trigger-width": `${rect.width}px`, "--aaas-content-available-height": `${available}px`, "--aaas-content-transform-origin": `${align} ${resolved === "bottom" ? "top" : resolved === "top" ? "bottom" : "center"}` });
|
|
174
|
+
};
|
|
175
|
+
update();
|
|
176
|
+
window.addEventListener("resize", update);
|
|
177
|
+
window.addEventListener("scroll", update, true);
|
|
178
|
+
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(update) : null;
|
|
179
|
+
if (local.current)
|
|
180
|
+
observer?.observe(local.current);
|
|
181
|
+
return () => {
|
|
182
|
+
window.removeEventListener("resize", update);
|
|
183
|
+
window.removeEventListener("scroll", update, true);
|
|
184
|
+
observer?.disconnect();
|
|
185
|
+
};
|
|
186
|
+
}, [state.open, floating, side, align, sideOffset, alignOffset, avoidCollisions, collisionPadding, state.sub]);
|
|
187
|
+
React.useLayoutEffect(() => {
|
|
188
|
+
const node = local.current;
|
|
189
|
+
if (!state.open || !node)
|
|
190
|
+
return;
|
|
191
|
+
const entry = { node, modal: state.modal, state };
|
|
192
|
+
stack.push(entry);
|
|
193
|
+
stack.sort((a, b) => depth(a.state) - depth(b.state));
|
|
194
|
+
const previous = document.activeElement;
|
|
195
|
+
if (state.modal) {
|
|
196
|
+
if (!locks++) {
|
|
197
|
+
originalOverflow = document.body.style.overflow;
|
|
198
|
+
document.body.style.overflow = "hidden";
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const opening = new Event("openAutoFocus", { cancelable: true });
|
|
202
|
+
latest.current.onOpenAutoFocus?.(opening);
|
|
203
|
+
if (!opening.defaultPrevented && role !== "tooltip" && !hover && stack.at(-1) === entry)
|
|
204
|
+
((alert ? node.querySelector('[data-slot="alert-dialog-cancel"]') : null) ?? node.querySelector('[role="option"]:not(:disabled),[role^="menuitem"]:not(:disabled)') ?? focusable(node)[0] ?? node).focus();
|
|
205
|
+
if (!Object.prototype.hasOwnProperty.call(props, "aria-describedby") && document.getElementById(`${state.id}-description`))
|
|
206
|
+
node.setAttribute("aria-describedby", `${state.id}-description`);
|
|
207
|
+
updateBackground();
|
|
208
|
+
const top = () => stack.at(-1) === entry;
|
|
209
|
+
const escape = (event) => {
|
|
210
|
+
if (!top())
|
|
211
|
+
return;
|
|
212
|
+
if (event.key === "Escape") {
|
|
213
|
+
latest.current.onEscapeKeyDown?.(event);
|
|
214
|
+
if (!event.defaultPrevented) {
|
|
215
|
+
event.preventDefault();
|
|
216
|
+
event.stopPropagation();
|
|
217
|
+
latest.current.state.setOpen(false);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (event.key === "Tab" && state.modal) {
|
|
221
|
+
const nodes = focusable(node), first = nodes[0] ?? node, last = nodes.at(-1) ?? node;
|
|
222
|
+
if (!nodes.length || (event.shiftKey ? document.activeElement === first || document.activeElement === node : document.activeElement === last)) {
|
|
223
|
+
event.preventDefault();
|
|
224
|
+
(event.shiftKey ? last : first).focus();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const outside = (event) => {
|
|
229
|
+
if (!top() || node.contains(event.target) || state.trigger.current?.contains(event.target))
|
|
230
|
+
return;
|
|
231
|
+
const cancel = new CustomEvent("pointerDownOutside", { cancelable: true, detail: { originalEvent: event } });
|
|
232
|
+
latest.current.onPointerDownOutside?.(cancel);
|
|
233
|
+
latest.current.onInteractOutside?.(cancel);
|
|
234
|
+
if (!cancel.defaultPrevented && !alert)
|
|
235
|
+
latest.current.state.setOpen(false);
|
|
236
|
+
};
|
|
237
|
+
const focus = (event) => {
|
|
238
|
+
if (!top() || node.contains(event.target) || state.trigger.current?.contains(event.target))
|
|
239
|
+
return;
|
|
240
|
+
const cancel = new CustomEvent("focusOutside", { cancelable: true, detail: { originalEvent: event } });
|
|
241
|
+
latest.current.onFocusOutside?.(cancel);
|
|
242
|
+
latest.current.onInteractOutside?.(cancel);
|
|
243
|
+
if (state.modal) {
|
|
244
|
+
if (!cancel.defaultPrevented)
|
|
245
|
+
(focusable(node)[0] ?? node).focus();
|
|
246
|
+
} else if (!cancel.defaultPrevented && role !== "tooltip")
|
|
247
|
+
latest.current.state.setOpen(false);
|
|
248
|
+
};
|
|
249
|
+
document.addEventListener("keydown", escape, true);
|
|
250
|
+
document.addEventListener("pointerdown", outside, true);
|
|
251
|
+
document.addEventListener("focusin", focus);
|
|
252
|
+
return () => {
|
|
253
|
+
document.removeEventListener("keydown", escape, true);
|
|
254
|
+
document.removeEventListener("pointerdown", outside, true);
|
|
255
|
+
document.removeEventListener("focusin", focus);
|
|
256
|
+
stack.splice(stack.indexOf(entry), 1);
|
|
257
|
+
if (state.modal && !--locks)
|
|
258
|
+
document.body.style.overflow = originalOverflow;
|
|
259
|
+
updateBackground();
|
|
260
|
+
const closing = new Event("closeAutoFocus", { cancelable: true });
|
|
261
|
+
latest.current.onCloseAutoFocus?.(closing);
|
|
262
|
+
if (!closing.defaultPrevented && role !== "tooltip" && !hover) {
|
|
263
|
+
const target = state.trigger.current ?? previous;
|
|
264
|
+
if (target?.isConnected)
|
|
265
|
+
target.focus();
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
}, [state.open, state.modal]);
|
|
269
|
+
if (!state.open && !forceMount && !portalMount)
|
|
270
|
+
return null;
|
|
271
|
+
const floatingRole = role === "dialog" && !state.modal ? "dialog" : role;
|
|
272
|
+
return /* @__PURE__ */ jsx(DivPart, { ...props, id: props.id ?? state.id, ref: merged, role: props.role ?? floatingRole, "aria-modal": state.modal && role !== "tooltip" ? true : void 0, "aria-labelledby": props["aria-labelledby"] ?? (!floating ? `${state.id}-title` : void 0), tabIndex: -1, hidden: !state.open, "data-aaas-layer": "", "data-state": state.open ? "open" : "closed", "data-side": actualSide, "data-align": align, "data-drawer-direction": state.direction, style: { ...floating ? position : {}, ...style }, onKeyDown, onPointerEnter: (event) => {
|
|
273
|
+
onPointerEnter?.(event);
|
|
274
|
+
if (hover)
|
|
275
|
+
state.schedule(true, true);
|
|
276
|
+
}, onPointerLeave: (event) => {
|
|
277
|
+
onPointerLeave?.(event);
|
|
278
|
+
if (hover)
|
|
279
|
+
state.schedule(false);
|
|
280
|
+
} });
|
|
281
|
+
}
|
|
282
|
+
function Title(props) {
|
|
283
|
+
const state = useLayer();
|
|
284
|
+
return /* @__PURE__ */ jsx("h2", { id: `${state.id}-title`, ...props });
|
|
285
|
+
}
|
|
286
|
+
function Description(props) {
|
|
287
|
+
const state = useLayer();
|
|
288
|
+
return /* @__PURE__ */ jsx("p", { id: `${state.id}-description`, ...props });
|
|
289
|
+
}
|
|
290
|
+
function Arrow(props) {
|
|
291
|
+
return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", ...props });
|
|
292
|
+
}
|
|
293
|
+
function Sub(props) {
|
|
294
|
+
return /* @__PURE__ */ jsx(Root, { ...props, sub: true });
|
|
295
|
+
}
|
|
296
|
+
return { Root, Provider, Trigger, Anchor, Close, Portal, Overlay, Content, Title, Description, Arrow, Sub, useLayer };
|
|
297
|
+
}
|
|
298
|
+
export {
|
|
299
|
+
createLayer
|
|
300
|
+
};
|