@zvk/ui 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/LICENSE.md +26 -0
- package/README.md +31 -0
- package/dist/components/accordion/accordion.d.ts +43 -0
- package/dist/components/accordion/accordion.js +207 -0
- package/dist/components/accordion/index.d.ts +2 -0
- package/dist/components/accordion/index.js +2 -0
- package/dist/components/alert/alert.d.ts +24 -0
- package/dist/components/alert/alert.js +17 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/alert/index.js +1 -0
- package/dist/components/alert-dialog/alert-dialog.d.ts +46 -0
- package/dist/components/alert-dialog/alert-dialog.js +112 -0
- package/dist/components/alert-dialog/index.d.ts +2 -0
- package/dist/components/alert-dialog/index.js +2 -0
- package/dist/components/avatar/avatar.d.ts +14 -0
- package/dist/components/avatar/avatar.js +22 -0
- package/dist/components/avatar/index.d.ts +2 -0
- package/dist/components/avatar/index.js +2 -0
- package/dist/components/badge/badge.d.ts +11 -0
- package/dist/components/badge/badge.js +6 -0
- package/dist/components/badge/index.d.ts +2 -0
- package/dist/components/badge/index.js +1 -0
- package/dist/components/breadcrumbs/breadcrumbs.d.ts +24 -0
- package/dist/components/breadcrumbs/breadcrumbs.js +18 -0
- package/dist/components/breadcrumbs/index.d.ts +2 -0
- package/dist/components/breadcrumbs/index.js +1 -0
- package/dist/components/button/button.d.ts +13 -0
- package/dist/components/button/button.js +8 -0
- package/dist/components/button/index.d.ts +2 -0
- package/dist/components/button/index.js +1 -0
- package/dist/components/card/card.d.ts +31 -0
- package/dist/components/card/card.js +28 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/card/index.js +1 -0
- package/dist/components/checkbox/checkbox.d.ts +11 -0
- package/dist/components/checkbox/checkbox.js +30 -0
- package/dist/components/checkbox/index.d.ts +2 -0
- package/dist/components/checkbox/index.js +2 -0
- package/dist/components/code-block/code-block.d.ts +10 -0
- package/dist/components/code-block/code-block.js +16 -0
- package/dist/components/code-block/index.d.ts +2 -0
- package/dist/components/code-block/index.js +1 -0
- package/dist/components/collapsible/collapsible.d.ts +23 -0
- package/dist/components/collapsible/collapsible.js +52 -0
- package/dist/components/collapsible/index.d.ts +2 -0
- package/dist/components/collapsible/index.js +2 -0
- package/dist/components/combobox/combobox.d.ts +20 -0
- package/dist/components/combobox/combobox.js +121 -0
- package/dist/components/combobox/index.d.ts +2 -0
- package/dist/components/combobox/index.js +2 -0
- package/dist/components/command/command-dialog.d.ts +2 -0
- package/dist/components/command/command-dialog.js +1 -0
- package/dist/components/command/command-filter.d.ts +7 -0
- package/dist/components/command/command-filter.js +14 -0
- package/dist/components/command/command.d.ts +55 -0
- package/dist/components/command/command.js +200 -0
- package/dist/components/command/index.d.ts +2 -0
- package/dist/components/command/index.js +2 -0
- package/dist/components/context-menu/context-menu.d.ts +34 -0
- package/dist/components/context-menu/context-menu.js +154 -0
- package/dist/components/context-menu/index.d.ts +2 -0
- package/dist/components/context-menu/index.js +2 -0
- package/dist/components/conversation/conversation.d.ts +60 -0
- package/dist/components/conversation/conversation.js +49 -0
- package/dist/components/conversation/index.d.ts +2 -0
- package/dist/components/conversation/index.js +1 -0
- package/dist/components/copy-button/copy-button.d.ts +23 -0
- package/dist/components/copy-button/copy-button.js +50 -0
- package/dist/components/copy-button/index.d.ts +2 -0
- package/dist/components/copy-button/index.js +2 -0
- package/dist/components/dialog/dialog.d.ts +62 -0
- package/dist/components/dialog/dialog.js +141 -0
- package/dist/components/dialog/index.d.ts +2 -0
- package/dist/components/dialog/index.js +2 -0
- package/dist/components/dropdown-menu/dropdown-menu.d.ts +43 -0
- package/dist/components/dropdown-menu/dropdown-menu.js +286 -0
- package/dist/components/dropdown-menu/index.d.ts +2 -0
- package/dist/components/dropdown-menu/index.js +2 -0
- package/dist/components/empty-state/empty-state.d.ts +13 -0
- package/dist/components/empty-state/empty-state.js +34 -0
- package/dist/components/empty-state/index.d.ts +2 -0
- package/dist/components/empty-state/index.js +1 -0
- package/dist/components/error-boundary/error-boundary.d.ts +29 -0
- package/dist/components/error-boundary/error-boundary.js +43 -0
- package/dist/components/error-boundary/index.d.ts +2 -0
- package/dist/components/error-boundary/index.js +2 -0
- package/dist/components/field/field.d.ts +23 -0
- package/dist/components/field/field.js +20 -0
- package/dist/components/field/index.d.ts +2 -0
- package/dist/components/field/index.js +1 -0
- package/dist/components/file-upload-input/file-upload-input.d.ts +13 -0
- package/dist/components/file-upload-input/file-upload-input.js +41 -0
- package/dist/components/file-upload-input/index.d.ts +2 -0
- package/dist/components/file-upload-input/index.js +2 -0
- package/dist/components/form/form.d.ts +30 -0
- package/dist/components/form/form.js +88 -0
- package/dist/components/form/index.d.ts +2 -0
- package/dist/components/form/index.js +2 -0
- package/dist/components/icon-button/icon-button.d.ts +10 -0
- package/dist/components/icon-button/icon-button.js +8 -0
- package/dist/components/icon-button/index.d.ts +2 -0
- package/dist/components/icon-button/index.js +1 -0
- package/dist/components/index.d.ts +102 -0
- package/dist/components/index.js +51 -0
- package/dist/components/input/index.d.ts +2 -0
- package/dist/components/input/index.js +1 -0
- package/dist/components/input/input.d.ts +11 -0
- package/dist/components/input/input.js +27 -0
- package/dist/components/label/index.d.ts +2 -0
- package/dist/components/label/index.js +1 -0
- package/dist/components/label/label.d.ts +9 -0
- package/dist/components/label/label.js +6 -0
- package/dist/components/menubar/index.d.ts +2 -0
- package/dist/components/menubar/index.js +2 -0
- package/dist/components/menubar/menubar.d.ts +39 -0
- package/dist/components/menubar/menubar.js +214 -0
- package/dist/components/pagination/index.d.ts +2 -0
- package/dist/components/pagination/index.js +1 -0
- package/dist/components/pagination/pagination.d.ts +21 -0
- package/dist/components/pagination/pagination.js +92 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/index.js +2 -0
- package/dist/components/popover/popover.d.ts +28 -0
- package/dist/components/popover/popover.js +164 -0
- package/dist/components/progress/index.d.ts +2 -0
- package/dist/components/progress/index.js +1 -0
- package/dist/components/progress/progress.d.ts +24 -0
- package/dist/components/progress/progress.js +29 -0
- package/dist/components/radio-group/index.d.ts +2 -0
- package/dist/components/radio-group/index.js +2 -0
- package/dist/components/radio-group/radio-group.d.ts +42 -0
- package/dist/components/radio-group/radio-group.js +69 -0
- package/dist/components/responsive-container/index.d.ts +2 -0
- package/dist/components/responsive-container/index.js +1 -0
- package/dist/components/responsive-container/responsive-container.d.ts +10 -0
- package/dist/components/responsive-container/responsive-container.js +6 -0
- package/dist/components/scroll-area/index.d.ts +2 -0
- package/dist/components/scroll-area/index.js +2 -0
- package/dist/components/scroll-area/scroll-area.d.ts +21 -0
- package/dist/components/scroll-area/scroll-area.js +23 -0
- package/dist/components/sectioned-sidebar-nav/index.d.ts +2 -0
- package/dist/components/sectioned-sidebar-nav/index.js +1 -0
- package/dist/components/sectioned-sidebar-nav/sectioned-sidebar-nav.d.ts +39 -0
- package/dist/components/sectioned-sidebar-nav/sectioned-sidebar-nav.js +37 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/index.js +2 -0
- package/dist/components/select/select.d.ts +46 -0
- package/dist/components/select/select.js +239 -0
- package/dist/components/separator/index.d.ts +2 -0
- package/dist/components/separator/index.js +1 -0
- package/dist/components/separator/separator.d.ts +8 -0
- package/dist/components/separator/separator.js +6 -0
- package/dist/components/sheet/index.d.ts +2 -0
- package/dist/components/sheet/index.js +2 -0
- package/dist/components/sheet/sheet.d.ts +49 -0
- package/dist/components/sheet/sheet.js +116 -0
- package/dist/components/sidebar-shell/index.d.ts +2 -0
- package/dist/components/sidebar-shell/index.js +1 -0
- package/dist/components/sidebar-shell/sidebar-shell.d.ts +35 -0
- package/dist/components/sidebar-shell/sidebar-shell.js +28 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/index.js +1 -0
- package/dist/components/skeleton/skeleton.d.ts +10 -0
- package/dist/components/skeleton/skeleton.js +16 -0
- package/dist/components/slider/index.d.ts +2 -0
- package/dist/components/slider/index.js +2 -0
- package/dist/components/slider/slider.d.ts +12 -0
- package/dist/components/slider/slider.js +30 -0
- package/dist/components/spinner/index.d.ts +2 -0
- package/dist/components/spinner/index.js +1 -0
- package/dist/components/spinner/spinner.d.ts +10 -0
- package/dist/components/spinner/spinner.js +7 -0
- package/dist/components/stat/index.d.ts +2 -0
- package/dist/components/stat/index.js +1 -0
- package/dist/components/stat/stat.d.ts +13 -0
- package/dist/components/stat/stat.js +8 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/index.js +2 -0
- package/dist/components/switch/switch.d.ts +11 -0
- package/dist/components/switch/switch.js +27 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/index.js +1 -0
- package/dist/components/table/table.d.ts +45 -0
- package/dist/components/table/table.js +36 -0
- package/dist/components/tabs/index.d.ts +2 -0
- package/dist/components/tabs/index.js +2 -0
- package/dist/components/tabs/tabs.d.ts +34 -0
- package/dist/components/tabs/tabs.js +233 -0
- package/dist/components/tabs-with-sidebar/index.d.ts +2 -0
- package/dist/components/tabs-with-sidebar/index.js +2 -0
- package/dist/components/tabs-with-sidebar/tabs-with-sidebar.d.ts +21 -0
- package/dist/components/tabs-with-sidebar/tabs-with-sidebar.js +18 -0
- package/dist/components/textarea/index.d.ts +2 -0
- package/dist/components/textarea/index.js +2 -0
- package/dist/components/textarea/textarea.d.ts +11 -0
- package/dist/components/textarea/textarea.js +28 -0
- package/dist/components/toast/index.d.ts +2 -0
- package/dist/components/toast/index.js +1 -0
- package/dist/components/toast/toast.d.ts +33 -0
- package/dist/components/toast/toast.js +27 -0
- package/dist/components/toggle/index.d.ts +2 -0
- package/dist/components/toggle/index.js +2 -0
- package/dist/components/toggle/toggle.d.ts +12 -0
- package/dist/components/toggle/toggle.js +18 -0
- package/dist/components/toggle-group/index.d.ts +2 -0
- package/dist/components/toggle-group/index.js +2 -0
- package/dist/components/toggle-group/toggle-group.d.ts +28 -0
- package/dist/components/toggle-group/toggle-group.js +67 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/components/tooltip/index.js +2 -0
- package/dist/components/tooltip/tooltip.d.ts +10 -0
- package/dist/components/tooltip/tooltip.js +100 -0
- package/dist/hooks/index.d.ts +7 -0
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/use-composed-refs.d.ts +3 -0
- package/dist/hooks/use-composed-refs.js +18 -0
- package/dist/hooks/use-controllable-state.d.ts +7 -0
- package/dist/hooks/use-controllable-state.js +30 -0
- package/dist/hooks/use-disclosure.d.ts +13 -0
- package/dist/hooks/use-disclosure.js +20 -0
- package/dist/hooks/use-event.d.ts +1 -0
- package/dist/hooks/use-event.js +11 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/internal/collection/collection.d.ts +18 -0
- package/dist/internal/collection/collection.js +54 -0
- package/dist/internal/collection/index.d.ts +2 -0
- package/dist/internal/collection/index.js +1 -0
- package/dist/internal/dismissable-layer/dismissable-layer.d.ts +13 -0
- package/dist/internal/dismissable-layer/dismissable-layer.js +73 -0
- package/dist/internal/dismissable-layer/index.d.ts +2 -0
- package/dist/internal/dismissable-layer/index.js +1 -0
- package/dist/internal/floating/auto-update.d.ts +9 -0
- package/dist/internal/floating/auto-update.js +48 -0
- package/dist/internal/floating/compute-position.d.ts +2 -0
- package/dist/internal/floating/compute-position.js +96 -0
- package/dist/internal/floating/detect-overflow.d.ts +13 -0
- package/dist/internal/floating/detect-overflow.js +13 -0
- package/dist/internal/floating/floating-types.d.ts +42 -0
- package/dist/internal/floating/floating-types.js +1 -0
- package/dist/internal/floating/index.d.ts +27 -0
- package/dist/internal/floating/index.js +5 -0
- package/dist/internal/floating/middleware.d.ts +11 -0
- package/dist/internal/floating/middleware.js +42 -0
- package/dist/internal/floating/use-floating-position.d.ts +2 -0
- package/dist/internal/floating/use-floating-position.js +113 -0
- package/dist/internal/focus/focus-scope.d.ts +10 -0
- package/dist/internal/focus/focus-scope.js +68 -0
- package/dist/internal/focus/focus-utils.d.ts +9 -0
- package/dist/internal/focus/focus-utils.js +94 -0
- package/dist/internal/focus/index.d.ts +3 -0
- package/dist/internal/focus/index.js +2 -0
- package/dist/internal/overlay-stack/index.d.ts +1 -0
- package/dist/internal/overlay-stack/index.js +1 -0
- package/dist/internal/overlay-stack/overlay-stack.d.ts +12 -0
- package/dist/internal/overlay-stack/overlay-stack.js +41 -0
- package/dist/internal/portal/index.d.ts +2 -0
- package/dist/internal/portal/index.js +1 -0
- package/dist/internal/portal/portal.d.ts +7 -0
- package/dist/internal/portal/portal.js +19 -0
- package/dist/internal/scroll-lock/index.d.ts +1 -0
- package/dist/internal/scroll-lock/index.js +1 -0
- package/dist/internal/scroll-lock/scroll-lock.d.ts +4 -0
- package/dist/internal/scroll-lock/scroll-lock.js +69 -0
- package/dist/styles.css +3852 -0
- package/dist/tokens/index.d.ts +2 -0
- package/dist/tokens/index.js +1 -0
- package/dist/tokens/token-types.d.ts +23 -0
- package/dist/tokens/token-types.js +1 -0
- package/dist/tokens/tokens.d.ts +139 -0
- package/dist/tokens/tokens.js +139 -0
- package/dist/utils/cn.d.ts +2 -0
- package/dist/utils/cn.js +3 -0
- package/dist/utils/compose-event-handlers.d.ts +6 -0
- package/dist/utils/compose-event-handlers.js +8 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +2 -0
- package/package.json +282 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
import type { FloatingPlacement } from "./floating-types.js";
|
|
3
|
+
export type { FloatingAlign, FloatingBoundary, FloatingPlacement, FloatingPositionResult, FloatingRect, FloatingSide, FloatingStrategy, ComputeFloatingPositionOptions } from "./floating-types.js";
|
|
4
|
+
export type UseFloatingPositionOptions = {
|
|
5
|
+
open: boolean;
|
|
6
|
+
placement?: import("./floating-types.js").FloatingPlacement;
|
|
7
|
+
strategy?: import("./floating-types.js").FloatingStrategy;
|
|
8
|
+
offset?: number;
|
|
9
|
+
collisionPadding?: number;
|
|
10
|
+
matchReferenceWidth?: boolean;
|
|
11
|
+
maxHeight?: number;
|
|
12
|
+
flip?: boolean;
|
|
13
|
+
shift?: boolean;
|
|
14
|
+
boundary?: import("./floating-types.js").FloatingBoundary;
|
|
15
|
+
};
|
|
16
|
+
export interface UseFloatingPositionResult {
|
|
17
|
+
referenceRef: (node: HTMLElement | null) => void;
|
|
18
|
+
floatingRef: (node: HTMLElement | null) => void;
|
|
19
|
+
floatingStyle: React.CSSProperties & Record<`--${string}`, string>;
|
|
20
|
+
placement: FloatingPlacement;
|
|
21
|
+
updatePosition: () => void;
|
|
22
|
+
}
|
|
23
|
+
export { autoUpdateFloating } from "./auto-update.js";
|
|
24
|
+
export { computeFloatingPosition } from "./compute-position.js";
|
|
25
|
+
export { detectOverflow } from "./detect-overflow.js";
|
|
26
|
+
export { getOppositeSide, parsePlacement, buildPlacement, clamp } from "./middleware.js";
|
|
27
|
+
export { useFloatingPosition } from "./use-floating-position.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { autoUpdateFloating } from "./auto-update.js";
|
|
2
|
+
export { computeFloatingPosition } from "./compute-position.js";
|
|
3
|
+
export { detectOverflow } from "./detect-overflow.js";
|
|
4
|
+
export { getOppositeSide, parsePlacement, buildPlacement, clamp } from "./middleware.js";
|
|
5
|
+
export { useFloatingPosition } from "./use-floating-position.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FloatingAlign, FloatingPlacement, FloatingSide } from "./floating-types.js";
|
|
2
|
+
export interface ParsedPlacement {
|
|
3
|
+
side: FloatingSide;
|
|
4
|
+
align: FloatingAlign;
|
|
5
|
+
}
|
|
6
|
+
export declare function isFloatingSide(value: string): value is FloatingSide;
|
|
7
|
+
export declare function parsePlacement(placement: FloatingPlacement): ParsedPlacement;
|
|
8
|
+
export declare function getOppositeSide(side: FloatingSide): FloatingSide;
|
|
9
|
+
export declare function buildPlacement(side: FloatingSide, align: FloatingAlign): FloatingPlacement;
|
|
10
|
+
export declare function clamp(value: number, min: number, max: number): number;
|
|
11
|
+
export declare function normalizePlacement(placement: FloatingPlacement): FloatingPlacement;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function isFloatingSide(value) {
|
|
2
|
+
return value === "top" || value === "right" || value === "bottom" || value === "left";
|
|
3
|
+
}
|
|
4
|
+
export function parsePlacement(placement) {
|
|
5
|
+
const [side, align] = placement.split("-");
|
|
6
|
+
if (!isFloatingSide(side)) {
|
|
7
|
+
return { side: "bottom", align: "center" };
|
|
8
|
+
}
|
|
9
|
+
if (align === "start" || align === "end") {
|
|
10
|
+
return { side, align };
|
|
11
|
+
}
|
|
12
|
+
return { side, align: "center" };
|
|
13
|
+
}
|
|
14
|
+
export function getOppositeSide(side) {
|
|
15
|
+
switch (side) {
|
|
16
|
+
case "top": {
|
|
17
|
+
return "bottom";
|
|
18
|
+
}
|
|
19
|
+
case "right": {
|
|
20
|
+
return "left";
|
|
21
|
+
}
|
|
22
|
+
case "bottom": {
|
|
23
|
+
return "top";
|
|
24
|
+
}
|
|
25
|
+
case "left": {
|
|
26
|
+
return "right";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function buildPlacement(side, align) {
|
|
31
|
+
if (align === "center") {
|
|
32
|
+
return side;
|
|
33
|
+
}
|
|
34
|
+
return `${side}-${align}`;
|
|
35
|
+
}
|
|
36
|
+
export function clamp(value, min, max) {
|
|
37
|
+
return Math.min(Math.max(value, min), max);
|
|
38
|
+
}
|
|
39
|
+
export function normalizePlacement(placement) {
|
|
40
|
+
const parsed = parsePlacement(placement);
|
|
41
|
+
return buildPlacement(parsed.side, parsed.align);
|
|
42
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { computeFloatingPosition } from "./compute-position.js";
|
|
4
|
+
import { autoUpdateFloating } from "./auto-update.js";
|
|
5
|
+
export function useFloatingPosition(options) {
|
|
6
|
+
const { open, placement = "bottom", strategy = "absolute", offset = 0, collisionPadding = 0, matchReferenceWidth = false, maxHeight, flip = true, shift = true, boundary } = options;
|
|
7
|
+
const [referenceEl, setReferenceEl] = React.useState(null);
|
|
8
|
+
const [floatingEl, setFloatingEl] = React.useState(null);
|
|
9
|
+
const [style, setStyle] = React.useState({
|
|
10
|
+
position: strategy
|
|
11
|
+
});
|
|
12
|
+
const [resolvedPlacement, setResolvedPlacement] = React.useState((placement ?? "bottom"));
|
|
13
|
+
const referenceRef = React.useCallback((node) => {
|
|
14
|
+
setReferenceEl(node);
|
|
15
|
+
}, []);
|
|
16
|
+
const floatingRef = React.useCallback((node) => {
|
|
17
|
+
setFloatingEl(node);
|
|
18
|
+
}, []);
|
|
19
|
+
const buildEnvironment = React.useCallback(() => {
|
|
20
|
+
if (referenceEl === null || floatingEl === null || typeof window === "undefined") {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const referenceRect = referenceEl.getBoundingClientRect();
|
|
24
|
+
const floatingRect = floatingEl.getBoundingClientRect();
|
|
25
|
+
const viewport = {
|
|
26
|
+
x: strategy === "fixed" ? 0 : window.scrollX,
|
|
27
|
+
y: strategy === "fixed" ? 0 : window.scrollY,
|
|
28
|
+
width: window.innerWidth,
|
|
29
|
+
height: window.innerHeight
|
|
30
|
+
};
|
|
31
|
+
const safeBoundary = boundary ?? viewport;
|
|
32
|
+
const shiftedReferenceRect = {
|
|
33
|
+
x: (strategy === "absolute" ? referenceRect.left + viewport.x : referenceRect.left),
|
|
34
|
+
y: (strategy === "absolute" ? referenceRect.top + viewport.y : referenceRect.top),
|
|
35
|
+
width: referenceRect.width,
|
|
36
|
+
height: referenceRect.height
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
boundary: {
|
|
40
|
+
...safeBoundary,
|
|
41
|
+
x: safeBoundary.x,
|
|
42
|
+
y: safeBoundary.y
|
|
43
|
+
},
|
|
44
|
+
referenceRect: shiftedReferenceRect,
|
|
45
|
+
floatingRect: {
|
|
46
|
+
x: 0,
|
|
47
|
+
y: 0,
|
|
48
|
+
width: floatingRect.width,
|
|
49
|
+
height: floatingRect.height
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}, [boundary, referenceEl, floatingEl, strategy]);
|
|
53
|
+
const updatePosition = React.useCallback(() => {
|
|
54
|
+
const env = buildEnvironment();
|
|
55
|
+
if (env === null) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const computed = computeFloatingPosition({
|
|
59
|
+
reference: env.referenceRect,
|
|
60
|
+
floating: env.floatingRect,
|
|
61
|
+
boundary: env.boundary,
|
|
62
|
+
placement: placement,
|
|
63
|
+
strategy: strategy,
|
|
64
|
+
offset,
|
|
65
|
+
collisionPadding,
|
|
66
|
+
matchReferenceWidth,
|
|
67
|
+
...(maxHeight === undefined ? {} : { maxHeight }),
|
|
68
|
+
flip,
|
|
69
|
+
shift
|
|
70
|
+
});
|
|
71
|
+
setStyle({
|
|
72
|
+
position: computed.strategy,
|
|
73
|
+
left: `${computed.x}px`,
|
|
74
|
+
top: `${computed.y}px`,
|
|
75
|
+
width: matchReferenceWidth ? `${referenceEl?.offsetWidth ?? computed.referenceWidth}px` : "auto",
|
|
76
|
+
"--liano-floating-available-width": `${computed.availableWidth}px`,
|
|
77
|
+
"--liano-floating-available-height": `${computed.availableHeight}px`
|
|
78
|
+
});
|
|
79
|
+
setResolvedPlacement(computed.placement);
|
|
80
|
+
}, [
|
|
81
|
+
buildEnvironment,
|
|
82
|
+
placement,
|
|
83
|
+
strategy,
|
|
84
|
+
offset,
|
|
85
|
+
collisionPadding,
|
|
86
|
+
matchReferenceWidth,
|
|
87
|
+
maxHeight,
|
|
88
|
+
flip,
|
|
89
|
+
shift,
|
|
90
|
+
referenceEl
|
|
91
|
+
]);
|
|
92
|
+
React.useEffect(() => {
|
|
93
|
+
if (!open) {
|
|
94
|
+
setResolvedPlacement((placement ?? "bottom"));
|
|
95
|
+
}
|
|
96
|
+
}, [open, placement]);
|
|
97
|
+
React.useEffect(() => {
|
|
98
|
+
const autoCleanup = autoUpdateFloating({
|
|
99
|
+
enabled: open,
|
|
100
|
+
reference: referenceEl,
|
|
101
|
+
floating: floatingEl,
|
|
102
|
+
update: updatePosition
|
|
103
|
+
});
|
|
104
|
+
return autoCleanup;
|
|
105
|
+
}, [open, referenceEl, floatingEl, updatePosition]);
|
|
106
|
+
return {
|
|
107
|
+
referenceRef,
|
|
108
|
+
floatingRef,
|
|
109
|
+
floatingStyle: style,
|
|
110
|
+
placement: resolvedPlacement,
|
|
111
|
+
updatePosition
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
interface FocusScopeProps {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
trapped?: boolean;
|
|
5
|
+
active?: boolean;
|
|
6
|
+
initialFocus?: HTMLElement | null;
|
|
7
|
+
restoreFocus?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function FocusScope({ children, trapped, active, initialFocus, restoreFocus }: FocusScopeProps): React.ReactElement;
|
|
10
|
+
export type { FocusScopeProps };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { getFocusableElements, focusFirst, focusNext } from "./focus-utils.js";
|
|
5
|
+
export function FocusScope({ children, trapped = false, active = true, initialFocus, restoreFocus = true }) {
|
|
6
|
+
const containerRef = React.useRef(null);
|
|
7
|
+
const previouslyFocused = React.useRef(null);
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
if (!active || containerRef.current === null) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
previouslyFocused.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
13
|
+
if (initialFocus) {
|
|
14
|
+
initialFocus.focus();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const focusables = getFocusableElements(containerRef.current);
|
|
18
|
+
focusables[0]?.focus();
|
|
19
|
+
}, [active, initialFocus]);
|
|
20
|
+
React.useEffect(() => {
|
|
21
|
+
if (!active || containerRef.current === null || !trapped) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const handleKeyDown = (event) => {
|
|
25
|
+
if (event.key !== "Tab") {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const focusables = getFocusableElements(containerRef.current);
|
|
29
|
+
if (focusables.length === 0) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const activeElement = document.activeElement;
|
|
33
|
+
if (activeElement === null) {
|
|
34
|
+
focusables[0]?.focus();
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (containerRef.current &&
|
|
39
|
+
!containerRef.current.contains(event.target) &&
|
|
40
|
+
!containerRef.current.contains(activeElement)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (event.shiftKey) {
|
|
44
|
+
focusNext(containerRef.current, "prev");
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
focusNext(containerRef.current, "next");
|
|
48
|
+
}
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
};
|
|
51
|
+
const listener = (event) => handleKeyDown(event);
|
|
52
|
+
document.addEventListener("keydown", listener);
|
|
53
|
+
return () => {
|
|
54
|
+
document.removeEventListener("keydown", listener);
|
|
55
|
+
};
|
|
56
|
+
}, [active, trapped]);
|
|
57
|
+
React.useEffect(() => {
|
|
58
|
+
return () => {
|
|
59
|
+
if (!restoreFocus) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (previouslyFocused.current && document.body.contains(previouslyFocused.current)) {
|
|
63
|
+
previouslyFocused.current.focus();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}, [restoreFocus]);
|
|
67
|
+
return _jsx("div", { ref: containerRef, children: children });
|
|
68
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function isElementTabbable(element: Element): element is HTMLElement;
|
|
2
|
+
export declare function getFocusableElements(root: ParentNode): HTMLElement[];
|
|
3
|
+
export declare function focusFirst(root: ParentNode, options?: {
|
|
4
|
+
preventScroll?: boolean;
|
|
5
|
+
}): HTMLElement | null;
|
|
6
|
+
export declare function focusLast(root: ParentNode, options?: {
|
|
7
|
+
preventScroll?: boolean;
|
|
8
|
+
}): HTMLElement | null;
|
|
9
|
+
export declare function focusNext(root: ParentNode, direction?: "next" | "prev"): HTMLElement | null;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const FOCUSABLE_SELECTOR = [
|
|
2
|
+
"a[href]",
|
|
3
|
+
"button:not([disabled])",
|
|
4
|
+
"input:not([disabled])",
|
|
5
|
+
"select:not([disabled])",
|
|
6
|
+
"textarea:not([disabled])",
|
|
7
|
+
"[tabindex]"
|
|
8
|
+
].join(",");
|
|
9
|
+
function hasNegativeTabIndex(element) {
|
|
10
|
+
const tabIndex = element.getAttribute("tabindex");
|
|
11
|
+
if (tabIndex === null) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const index = Number.parseInt(tabIndex, 10);
|
|
15
|
+
return Number.isNaN(index) || index < 0;
|
|
16
|
+
}
|
|
17
|
+
function isHiddenByStyle(element) {
|
|
18
|
+
if (element.hasAttribute("hidden")) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
if (element.style.display === "none" || element.style.visibility === "hidden") {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
const style = window.getComputedStyle(element);
|
|
25
|
+
if (style.display === "none" || style.visibility === "hidden") {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
export function isElementTabbable(element) {
|
|
31
|
+
if (!(element instanceof HTMLElement)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (element.inert) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (element.matches(":disabled")) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
if (hasNegativeTabIndex(element)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
if (isHiddenByStyle(element)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
let parent = element.parentElement;
|
|
47
|
+
while (parent !== null) {
|
|
48
|
+
if (isHiddenByStyle(parent)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
parent = parent.parentElement;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
export function getFocusableElements(root) {
|
|
56
|
+
const nodes = Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
57
|
+
return nodes.filter(isElementTabbable);
|
|
58
|
+
}
|
|
59
|
+
export function focusFirst(root, options) {
|
|
60
|
+
const [first] = getFocusableElements(root);
|
|
61
|
+
if (!first) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
first.focus({ preventScroll: options?.preventScroll ?? false });
|
|
65
|
+
return first;
|
|
66
|
+
}
|
|
67
|
+
export function focusLast(root, options) {
|
|
68
|
+
const focusables = getFocusableElements(root);
|
|
69
|
+
const last = focusables[focusables.length - 1] ?? null;
|
|
70
|
+
if (!last) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
last.focus({ preventScroll: options?.preventScroll ?? false });
|
|
74
|
+
return last;
|
|
75
|
+
}
|
|
76
|
+
export function focusNext(root, direction = "next") {
|
|
77
|
+
const focusables = getFocusableElements(root);
|
|
78
|
+
const active = document.activeElement;
|
|
79
|
+
if (focusables.length === 0) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (!active || !focusables.includes(active)) {
|
|
83
|
+
return focusables[0] ?? null;
|
|
84
|
+
}
|
|
85
|
+
const currentIndex = focusables.indexOf(active);
|
|
86
|
+
if (direction === "next") {
|
|
87
|
+
const next = focusables[(currentIndex + 1) % focusables.length];
|
|
88
|
+
next.focus();
|
|
89
|
+
return next;
|
|
90
|
+
}
|
|
91
|
+
const previous = focusables[(currentIndex - 1 + focusables.length) % focusables.length];
|
|
92
|
+
previous.focus();
|
|
93
|
+
return previous;
|
|
94
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getOverlayStackLength, getTopOverlay, isInOverlayStack, isTopOverlay, popOverlay, pushOverlay, resetOverlayStackForTests } from "./overlay-stack.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getOverlayStackLength, getTopOverlay, isInOverlayStack, isTopOverlay, popOverlay, pushOverlay, resetOverlayStackForTests } from "./overlay-stack.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface OverlayStackEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
node: HTMLElement;
|
|
4
|
+
}
|
|
5
|
+
export declare function pushOverlay(node: HTMLElement): string;
|
|
6
|
+
export declare function popOverlay(id: string): void;
|
|
7
|
+
export declare function getTopOverlay(): OverlayStackEntry | undefined;
|
|
8
|
+
export declare function isTopOverlay(id: string): boolean;
|
|
9
|
+
export declare function isInOverlayStack(node: Node): boolean;
|
|
10
|
+
export declare function resetOverlayStackForTests(): void;
|
|
11
|
+
export declare function getOverlayStackLength(): number;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const overlayStack = [];
|
|
2
|
+
export function pushOverlay(node) {
|
|
3
|
+
const id = `liano-overlay-${overlayStack.length + 1}-${Math.random().toString(36).slice(2)}`;
|
|
4
|
+
overlayStack.push({ id, node });
|
|
5
|
+
return id;
|
|
6
|
+
}
|
|
7
|
+
export function popOverlay(id) {
|
|
8
|
+
const index = overlayStack.findIndex((entry) => entry.id === id);
|
|
9
|
+
if (index === -1) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
overlayStack.splice(index, 1);
|
|
13
|
+
}
|
|
14
|
+
export function getTopOverlay() {
|
|
15
|
+
if (overlayStack.length === 0) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
for (let i = overlayStack.length - 1; i >= 0; i -= 1) {
|
|
19
|
+
const candidate = overlayStack[i];
|
|
20
|
+
if (candidate === undefined) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const containsAnotherOverlay = overlayStack.some((entry) => entry.node !== candidate.node && candidate.node.contains(entry.node));
|
|
24
|
+
if (!containsAnotherOverlay) {
|
|
25
|
+
return candidate;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return overlayStack.at(-1);
|
|
29
|
+
}
|
|
30
|
+
export function isTopOverlay(id) {
|
|
31
|
+
return getTopOverlay()?.id === id;
|
|
32
|
+
}
|
|
33
|
+
export function isInOverlayStack(node) {
|
|
34
|
+
return overlayStack.some((entry) => entry.node === node);
|
|
35
|
+
}
|
|
36
|
+
export function resetOverlayStackForTests() {
|
|
37
|
+
overlayStack.length = 0;
|
|
38
|
+
}
|
|
39
|
+
export function getOverlayStackLength() {
|
|
40
|
+
return overlayStack.length;
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Portal } from "./portal.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
export function Portal({ children, container }) {
|
|
6
|
+
const [mounted, setMounted] = React.useState(false);
|
|
7
|
+
React.useEffect(() => {
|
|
8
|
+
setMounted(true);
|
|
9
|
+
}, []);
|
|
10
|
+
if (!mounted) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
if (container === null) {
|
|
14
|
+
return _jsx(_Fragment, { children: children });
|
|
15
|
+
}
|
|
16
|
+
const target = container ?? document.body;
|
|
17
|
+
return createPortal(children, target);
|
|
18
|
+
}
|
|
19
|
+
export default Portal;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getLockDepth, lockScroll, resetScrollLockForTests, unlockScroll } from "./scroll-lock.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getLockDepth, lockScroll, resetScrollLockForTests, unlockScroll } from "./scroll-lock.js";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
let lockCount = 0;
|
|
2
|
+
let snapshot = null;
|
|
3
|
+
function hasBrowserEnvironment() {
|
|
4
|
+
return typeof document !== "undefined" && typeof window !== "undefined";
|
|
5
|
+
}
|
|
6
|
+
function getBody() {
|
|
7
|
+
return document.body ?? null;
|
|
8
|
+
}
|
|
9
|
+
function getScrollbarWidth() {
|
|
10
|
+
const body = getBody();
|
|
11
|
+
if (body === null) {
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
return window.innerWidth - document.documentElement.clientWidth;
|
|
15
|
+
}
|
|
16
|
+
export function lockScroll() {
|
|
17
|
+
if (!hasBrowserEnvironment()) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const body = getBody();
|
|
21
|
+
if (body === null) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (lockCount === 0) {
|
|
25
|
+
snapshot = {
|
|
26
|
+
overflow: body.style.overflow,
|
|
27
|
+
paddingRight: body.style.paddingRight
|
|
28
|
+
};
|
|
29
|
+
const scrollbar = getScrollbarWidth();
|
|
30
|
+
const parsedPadding = Number.parseFloat(body.style.paddingRight || "0");
|
|
31
|
+
body.style.overflow = "hidden";
|
|
32
|
+
if (!Number.isNaN(scrollbar) && scrollbar > 0) {
|
|
33
|
+
body.style.paddingRight = `${(Number.isNaN(parsedPadding) ? 0 : parsedPadding) + scrollbar}px`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
lockCount += 1;
|
|
37
|
+
}
|
|
38
|
+
export function unlockScroll() {
|
|
39
|
+
if (!hasBrowserEnvironment()) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (lockCount === 0) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
lockCount -= 1;
|
|
46
|
+
if (lockCount > 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const body = getBody();
|
|
50
|
+
if (body === null || snapshot === null) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
body.style.overflow = snapshot.overflow;
|
|
54
|
+
body.style.paddingRight = snapshot.paddingRight;
|
|
55
|
+
snapshot = null;
|
|
56
|
+
}
|
|
57
|
+
export function getLockDepth() {
|
|
58
|
+
return lockCount;
|
|
59
|
+
}
|
|
60
|
+
export function resetScrollLockForTests() {
|
|
61
|
+
if (typeof document === "undefined") {
|
|
62
|
+
lockCount = 0;
|
|
63
|
+
snapshot = null;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
while (lockCount > 0) {
|
|
67
|
+
unlockScroll();
|
|
68
|
+
}
|
|
69
|
+
}
|