@lobehub/ui 5.46.2 → 5.47.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/es/base-ui/Accordion/style.mjs +0 -1
- package/es/base-ui/Accordion/style.mjs.map +1 -1
- package/es/base-ui/Collapsible/Collapsible.d.mts +6 -0
- package/es/base-ui/Collapsible/Collapsible.mjs +25 -0
- package/es/base-ui/Collapsible/Collapsible.mjs.map +1 -0
- package/es/base-ui/Collapsible/index.d.mts +3 -0
- package/es/base-ui/Collapsible/type.d.mts +14 -0
- package/es/base-ui/FocusScope/FocusScope.d.mts +15 -0
- package/es/base-ui/FocusScope/FocusScope.mjs +36 -0
- package/es/base-ui/FocusScope/FocusScope.mjs.map +1 -0
- package/es/base-ui/FocusScope/domUtils.mjs +31 -0
- package/es/base-ui/FocusScope/domUtils.mjs.map +1 -0
- package/es/base-ui/FocusScope/index.d.mts +6 -0
- package/es/base-ui/FocusScope/store.d.mts +11 -0
- package/es/base-ui/FocusScope/store.mjs +76 -0
- package/es/base-ui/FocusScope/store.mjs.map +1 -0
- package/es/base-ui/FocusScope/style.d.mts +8 -0
- package/es/base-ui/FocusScope/style.mjs +18 -0
- package/es/base-ui/FocusScope/style.mjs.map +1 -0
- package/es/base-ui/FocusScope/useScopeArrowNav.d.mts +15 -0
- package/es/base-ui/FocusScope/useScopeArrowNav.mjs +111 -0
- package/es/base-ui/FocusScope/useScopeArrowNav.mjs.map +1 -0
- package/es/base-ui/FocusScope/useScopeSwitcher.d.mts +9 -0
- package/es/base-ui/FocusScope/useScopeSwitcher.mjs +47 -0
- package/es/base-ui/FocusScope/useScopeSwitcher.mjs.map +1 -0
- package/es/base-ui/Input/style.d.mts +1 -1
- package/es/base-ui/Text/style.d.mts +1 -1
- package/es/base-ui/Tree/Tree.d.mts +6 -0
- package/es/base-ui/Tree/Tree.mjs +175 -0
- package/es/base-ui/Tree/Tree.mjs.map +1 -0
- package/es/base-ui/Tree/TreeNode.mjs +124 -0
- package/es/base-ui/Tree/TreeNode.mjs.map +1 -0
- package/es/base-ui/Tree/context.mjs +12 -0
- package/es/base-ui/Tree/context.mjs.map +1 -0
- package/es/base-ui/Tree/index.d.mts +5 -0
- package/es/base-ui/Tree/style.d.mts +19 -0
- package/es/base-ui/Tree/style.mjs +149 -0
- package/es/base-ui/Tree/style.mjs.map +1 -0
- package/es/base-ui/Tree/type.d.mts +85 -0
- package/es/base-ui/Tree/utils.d.mts +11 -0
- package/es/base-ui/Tree/utils.mjs +73 -0
- package/es/base-ui/Tree/utils.mjs.map +1 -0
- package/es/base-ui/index.d.mts +22 -8
- package/es/base-ui/index.mjs +17 -8
- package/es/mdx/FileTree/File.mjs +3 -3
- package/es/mdx/FileTree/File.mjs.map +1 -1
- package/es/mdx/FileTree/Folder.mjs +3 -3
- package/es/mdx/FileTree/Folder.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.mjs","names":[],"sources":["../../../src/base-ui/Accordion/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\nimport { cva } from 'class-variance-authority';\n\nimport { focusRing } from '@/base-ui/focusRing';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n action: css`\n display: flex;\n flex-shrink: 0;\n gap: 4px;\n align-items: center;\n\n opacity: 0;\n\n transition: opacity 150ms ${cssVar.motionEaseOut};\n `,\n actionAlwaysVisible: css`\n opacity: 1;\n `,\n actionBorderless: css`\n padding-inline-end: var(--accordion-hover-inset, 8px);\n `,\n actionOutlined: css`\n padding-inline-end: 16px;\n `,\n content: css`\n font-size: 14px;\n line-height: 1.6;\n transition:\n opacity 200ms ${cssVar.motionEaseOut},\n translate 200ms ${cssVar.motionEaseOut};\n\n [data-starting-style] & {\n translate: 0 6px;\n opacity: 0;\n }\n\n [data-ending-style] & {\n translate: 0 -6px;\n opacity: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition-duration: 0s;\n }\n `,\n contentBorderless: css`\n padding-block: 0 12px;\n `,\n contentIndent: css`\n padding-inline-start: 24px;\n `,\n contentIndentOutlined: css`\n padding-inline-start: 40px;\n `,\n contentOutlined: css`\n padding-block: 4px 14px;\n padding-inline: 16px;\n `,\n header: css`\n position: relative;\n\n display: flex;\n align-items: center;\n\n margin: 0;\n\n font-size: inherit;\n font-weight: inherit;\n\n transition: background 150ms ${cssVar.motionEaseOut};\n\n &:hover:not(:has([data-disabled])) {\n background: ${cssVar.colorFillTertiary};\n }\n\n &:hover .accordion-action,\n &:focus-within .accordion-action {\n opacity: 1;\n }\n `,\n headerBorderless: css`\n margin-inline: calc(var(--accordion-hover-inset, 8px) * -1);\n border-radius: ${cssVar.borderRadius};\n `,\n headerInline: css`\n margin-inline: 0;\n\n > .accordion-action {\n padding-block: 4px;\n }\n `,\n contentInline: css`\n padding-block: 0;\n `,\n indicator: css`\n display: flex;\n flex-shrink: 0;\n align-items: center;\n\n color: ${cssVar.colorTextDescription};\n\n transition: transform 200ms ${cssVar.motionEaseOut};\n\n @media (prefers-reduced-motion: reduce) {\n transition-duration: 0s;\n }\n `,\n indicatorInline: css`\n justify-content: center;\n width: 18px;\n height: 18px;\n margin-inline-start: -6px;\n\n [data-panel-open] & {\n transform: rotate(90deg);\n }\n `,\n indicatorEnd: css`\n margin-inline-start: auto;\n\n [data-panel-open] & {\n transform: rotate(180deg);\n }\n `,\n indicatorStart: css`\n [data-panel-open] & {\n transform: rotate(90deg);\n }\n `,\n item: css`\n display: flex;\n flex-direction: column;\n `,\n itemOutlined: css`\n & + & {\n border-block-start: 1px solid ${cssVar.colorBorderSecondary};\n }\n `,\n panel: css`\n overflow: hidden;\n height: auto;\n transition: height 200ms ${cssVar.motionEaseOut};\n\n interpolate-size: allow-keywords;\n\n &[data-starting-style],\n &[data-ending-style] {\n height: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition-duration: 0s;\n }\n `,\n root: css`\n display: flex;\n flex-direction: column;\n width: 100%;\n `,\n rootOutlined: css`\n overflow: hidden;\n border: 1px solid ${cssVar.colorBorderSecondary};\n border-radius: ${cssVar.borderRadiusLG};\n `,\n trigger: css`\n cursor: pointer;\n user-select: none;\n\n display: flex;\n flex: 1;\n gap: 8px;\n align-items: center;\n\n min-width: 0;\n border: 0;\n border-radius: inherit;\n\n font: inherit;\n font-size: 14px;\n
|
|
1
|
+
{"version":3,"file":"style.mjs","names":[],"sources":["../../../src/base-ui/Accordion/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\nimport { cva } from 'class-variance-authority';\n\nimport { focusRing } from '@/base-ui/focusRing';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n action: css`\n display: flex;\n flex-shrink: 0;\n gap: 4px;\n align-items: center;\n\n opacity: 0;\n\n transition: opacity 150ms ${cssVar.motionEaseOut};\n `,\n actionAlwaysVisible: css`\n opacity: 1;\n `,\n actionBorderless: css`\n padding-inline-end: var(--accordion-hover-inset, 8px);\n `,\n actionOutlined: css`\n padding-inline-end: 16px;\n `,\n content: css`\n font-size: 14px;\n line-height: 1.6;\n transition:\n opacity 200ms ${cssVar.motionEaseOut},\n translate 200ms ${cssVar.motionEaseOut};\n\n [data-starting-style] & {\n translate: 0 6px;\n opacity: 0;\n }\n\n [data-ending-style] & {\n translate: 0 -6px;\n opacity: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition-duration: 0s;\n }\n `,\n contentBorderless: css`\n padding-block: 0 12px;\n `,\n contentIndent: css`\n padding-inline-start: 24px;\n `,\n contentIndentOutlined: css`\n padding-inline-start: 40px;\n `,\n contentOutlined: css`\n padding-block: 4px 14px;\n padding-inline: 16px;\n `,\n header: css`\n position: relative;\n\n display: flex;\n align-items: center;\n\n margin: 0;\n\n font-size: inherit;\n font-weight: inherit;\n\n transition: background 150ms ${cssVar.motionEaseOut};\n\n &:hover:not(:has([data-disabled])) {\n background: ${cssVar.colorFillTertiary};\n }\n\n &:hover .accordion-action,\n &:focus-within .accordion-action {\n opacity: 1;\n }\n `,\n headerBorderless: css`\n margin-inline: calc(var(--accordion-hover-inset, 8px) * -1);\n border-radius: ${cssVar.borderRadius};\n `,\n headerInline: css`\n margin-inline: 0;\n\n > .accordion-action {\n padding-block: 4px;\n }\n `,\n contentInline: css`\n padding-block: 0;\n `,\n indicator: css`\n display: flex;\n flex-shrink: 0;\n align-items: center;\n\n color: ${cssVar.colorTextDescription};\n\n transition: transform 200ms ${cssVar.motionEaseOut};\n\n @media (prefers-reduced-motion: reduce) {\n transition-duration: 0s;\n }\n `,\n indicatorInline: css`\n justify-content: center;\n width: 18px;\n height: 18px;\n margin-inline-start: -6px;\n\n [data-panel-open] & {\n transform: rotate(90deg);\n }\n `,\n indicatorEnd: css`\n margin-inline-start: auto;\n\n [data-panel-open] & {\n transform: rotate(180deg);\n }\n `,\n indicatorStart: css`\n [data-panel-open] & {\n transform: rotate(90deg);\n }\n `,\n item: css`\n display: flex;\n flex-direction: column;\n `,\n itemOutlined: css`\n & + & {\n border-block-start: 1px solid ${cssVar.colorBorderSecondary};\n }\n `,\n panel: css`\n overflow: hidden;\n height: auto;\n transition: height 200ms ${cssVar.motionEaseOut};\n\n interpolate-size: allow-keywords;\n\n &[data-starting-style],\n &[data-ending-style] {\n height: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition-duration: 0s;\n }\n `,\n root: css`\n display: flex;\n flex-direction: column;\n width: 100%;\n `,\n rootOutlined: css`\n overflow: hidden;\n border: 1px solid ${cssVar.colorBorderSecondary};\n border-radius: ${cssVar.borderRadiusLG};\n `,\n trigger: css`\n cursor: pointer;\n user-select: none;\n\n display: flex;\n flex: 1;\n gap: 8px;\n align-items: center;\n\n min-width: 0;\n border: 0;\n border-radius: inherit;\n\n font: inherit;\n font-size: 14px;\n color: ${cssVar.colorText};\n text-align: start;\n\n background: none;\n outline: none;\n\n ${focusRing};\n\n &[data-disabled] {\n cursor: not-allowed;\n color: ${cssVar.colorTextDisabled};\n }\n `,\n triggerBorderless: css`\n padding-block: 8px;\n padding-inline: var(--accordion-hover-inset, 8px);\n `,\n triggerOutlined: css`\n padding-block: 12px;\n padding-inline: 16px;\n\n &[data-panel-open] {\n padding-block-end: 8px;\n }\n `,\n}));\n\nexport const rootVariants = cva(styles.root, {\n defaultVariants: { variant: 'borderless' },\n variants: {\n variant: {\n borderless: null,\n outlined: styles.rootOutlined,\n },\n },\n});\n\nexport const itemVariants = cva(styles.item, {\n defaultVariants: { variant: 'borderless' },\n variants: {\n variant: {\n borderless: null,\n outlined: styles.itemOutlined,\n },\n },\n});\n\nexport const headerVariants = cva(styles.header, {\n compoundVariants: [{ class: styles.headerInline, inline: true, variant: 'borderless' }],\n defaultVariants: { inline: false, variant: 'borderless' },\n variants: {\n inline: {\n false: null,\n true: null,\n },\n variant: {\n borderless: styles.headerBorderless,\n outlined: null,\n },\n },\n});\n\nexport const triggerVariants = cva(styles.trigger, {\n defaultVariants: { variant: 'borderless' },\n variants: {\n variant: {\n borderless: styles.triggerBorderless,\n outlined: styles.triggerOutlined,\n },\n },\n});\n\nexport const indicatorVariants = cva(styles.indicator, {\n defaultVariants: { placement: 'start' },\n variants: {\n placement: {\n end: styles.indicatorEnd,\n inline: styles.indicatorInline,\n start: styles.indicatorStart,\n },\n },\n});\n\nexport const contentVariants = cva(styles.content, {\n compoundVariants: [\n {\n class: styles.contentInline,\n inline: true,\n variant: 'borderless',\n },\n {\n class: styles.contentIndent,\n indent: true,\n variant: 'borderless',\n },\n {\n class: styles.contentIndentOutlined,\n indent: true,\n variant: 'outlined',\n },\n ],\n defaultVariants: { indent: true, inline: false, variant: 'borderless' },\n variants: {\n indent: {\n false: null,\n true: null,\n },\n inline: {\n false: null,\n true: null,\n },\n variant: {\n borderless: styles.contentBorderless,\n outlined: styles.contentOutlined,\n },\n },\n});\n\nexport const actionVariants = cva(styles.action, {\n defaultVariants: { alwaysVisible: false, variant: 'borderless' },\n variants: {\n alwaysVisible: {\n false: null,\n true: styles.actionAlwaysVisible,\n },\n variant: {\n borderless: styles.actionBorderless,\n outlined: styles.actionOutlined,\n },\n },\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CollapsibleProps } from "./type.mjs";
|
|
2
|
+
//#region src/base-ui/Collapsible/Collapsible.d.ts
|
|
3
|
+
declare const Collapsible: import("react").NamedExoticComponent<CollapsibleProps>;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { Collapsible as default };
|
|
6
|
+
//# sourceMappingURL=Collapsible.d.mts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { styles } from "../Accordion/style.mjs";
|
|
3
|
+
import { memo } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { cx } from "antd-style";
|
|
6
|
+
import { Collapsible } from "@base-ui/react/collapsible";
|
|
7
|
+
//#region src/base-ui/Collapsible/Collapsible.tsx
|
|
8
|
+
const Collapsible$1 = memo(({ open, keepMounted, children, className, contentClassName, contentStyle, style }) => /* @__PURE__ */ jsx(Collapsible.Root, {
|
|
9
|
+
open,
|
|
10
|
+
children: /* @__PURE__ */ jsx(Collapsible.Panel, {
|
|
11
|
+
className: cx(styles.panel, className),
|
|
12
|
+
keepMounted,
|
|
13
|
+
style,
|
|
14
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
15
|
+
className: cx(styles.content, contentClassName),
|
|
16
|
+
style: contentStyle,
|
|
17
|
+
children
|
|
18
|
+
})
|
|
19
|
+
})
|
|
20
|
+
}));
|
|
21
|
+
Collapsible$1.displayName = "Collapsible";
|
|
22
|
+
//#endregion
|
|
23
|
+
export { Collapsible$1 as default };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=Collapsible.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Collapsible.mjs","names":["Collapsible","BaseUICollapsible","accordionStyles"],"sources":["../../../src/base-ui/Collapsible/Collapsible.tsx"],"sourcesContent":["'use client';\n\nimport { Collapsible as BaseUICollapsible } from '@base-ui/react/collapsible';\nimport { cx } from 'antd-style';\nimport { memo } from 'react';\n\nimport { accordionStyles } from '../Accordion/atoms';\nimport type { CollapsibleProps } from './type';\n\nconst Collapsible = memo<CollapsibleProps>(\n ({ open, keepMounted, children, className, contentClassName, contentStyle, style }) => (\n <BaseUICollapsible.Root open={open}>\n <BaseUICollapsible.Panel\n className={cx(accordionStyles.panel, className)}\n keepMounted={keepMounted}\n style={style}\n >\n <div className={cx(accordionStyles.content, contentClassName)} style={contentStyle}>\n {children}\n </div>\n </BaseUICollapsible.Panel>\n </BaseUICollapsible.Root>\n ),\n);\n\nCollapsible.displayName = 'Collapsible';\n\nexport default Collapsible;\n"],"mappings":";;;;;;;AASA,MAAMA,gBAAc,MACjB,EAAE,MAAM,aAAa,UAAU,WAAW,kBAAkB,cAAc,YACzE,oBAACC,YAAkB,MAAnB;CAA8B;CAC5B,UAAA,oBAACA,YAAkB,OAAnB;EACE,WAAW,GAAGC,OAAgB,OAAO,SAAS;EACjC;EACN;EAEP,UAAA,oBAAC,OAAD;GAAK,WAAW,GAAGA,OAAgB,SAAS,gBAAgB;GAAG,OAAO;GACnE;EACE,CAAA;CACkB,CAAA;AACH,CAAA,CAE5B;AAEA,cAAY,cAAc"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from "react";
|
|
2
|
+
//#region src/base-ui/Collapsible/type.d.ts
|
|
3
|
+
interface CollapsibleProps {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
contentClassName?: string;
|
|
7
|
+
contentStyle?: CSSProperties;
|
|
8
|
+
keepMounted?: boolean;
|
|
9
|
+
open: boolean;
|
|
10
|
+
style?: CSSProperties;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { CollapsibleProps };
|
|
14
|
+
//# sourceMappingURL=type.d.mts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { HTMLAttributes, Ref } from "react";
|
|
2
|
+
//#region src/base-ui/FocusScope/FocusScope.d.ts
|
|
3
|
+
interface FocusScopeProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
debugOutline?: boolean;
|
|
5
|
+
id?: string;
|
|
6
|
+
ref?: Ref<HTMLDivElement>;
|
|
7
|
+
}
|
|
8
|
+
declare const useFocusScopeId: () => string | null;
|
|
9
|
+
declare const FocusScope: {
|
|
10
|
+
({ id, debugOutline, className, children, onKeyDown, ...rest }: FocusScopeProps): import("react").JSX.Element;
|
|
11
|
+
displayName: string;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { FocusScope, FocusScopeProps, useFocusScopeId };
|
|
15
|
+
//# sourceMappingURL=FocusScope.d.mts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { registerScope, setActiveScope, useFocusScopeActive } from "./store.mjs";
|
|
3
|
+
import { styles } from "./style.mjs";
|
|
4
|
+
import { createContext, use, useEffect, useId } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { cx } from "antd-style";
|
|
7
|
+
//#region src/base-ui/FocusScope/FocusScope.tsx
|
|
8
|
+
const FocusScopeIdContext = createContext(null);
|
|
9
|
+
const useFocusScopeId = () => use(FocusScopeIdContext);
|
|
10
|
+
const FocusScope = ({ id, debugOutline = false, className, children, onKeyDown, ...rest }) => {
|
|
11
|
+
const generatedId = useId();
|
|
12
|
+
const scopeId = id ?? generatedId;
|
|
13
|
+
const isActive = useFocusScopeActive(scopeId);
|
|
14
|
+
useEffect(() => registerScope(scopeId), [scopeId]);
|
|
15
|
+
return /* @__PURE__ */ jsx(FocusScopeIdContext, {
|
|
16
|
+
value: scopeId,
|
|
17
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
18
|
+
"data-focus-scope": scopeId,
|
|
19
|
+
"data-scope-active": isActive ? "" : void 0,
|
|
20
|
+
tabIndex: -1,
|
|
21
|
+
...rest,
|
|
22
|
+
className: cx(styles.root, debugOutline && styles.debugOutline, className),
|
|
23
|
+
onKeyDown: (event) => {
|
|
24
|
+
onKeyDown?.(event);
|
|
25
|
+
if (event.defaultPrevented) return;
|
|
26
|
+
if (event.key === "Escape") setActiveScope(null);
|
|
27
|
+
},
|
|
28
|
+
children
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
FocusScope.displayName = "FocusScope";
|
|
33
|
+
//#endregion
|
|
34
|
+
export { FocusScope, useFocusScopeId };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=FocusScope.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FocusScope.mjs","names":[],"sources":["../../../src/base-ui/FocusScope/FocusScope.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { createContext, type HTMLAttributes, type Ref, use, useEffect, useId } from 'react';\n\nimport { registerScope, setActiveScope, useFocusScopeActive } from './store';\nimport { styles } from './style';\n\nexport interface FocusScopeProps extends HTMLAttributes<HTMLDivElement> {\n debugOutline?: boolean;\n id?: string;\n ref?: Ref<HTMLDivElement>;\n}\n\nconst FocusScopeIdContext = createContext<string | null>(null);\n\nexport const useFocusScopeId = () => use(FocusScopeIdContext);\n\nexport const FocusScope = ({\n id,\n debugOutline = false,\n className,\n children,\n onKeyDown,\n ...rest\n}: FocusScopeProps) => {\n const generatedId = useId();\n const scopeId = id ?? generatedId;\n const isActive = useFocusScopeActive(scopeId);\n\n useEffect(() => registerScope(scopeId), [scopeId]);\n\n return (\n <FocusScopeIdContext value={scopeId}>\n <div\n data-focus-scope={scopeId}\n data-scope-active={isActive ? '' : undefined}\n tabIndex={-1}\n {...rest}\n className={cx(styles.root, debugOutline && styles.debugOutline, className)}\n onKeyDown={(event) => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key === 'Escape') setActiveScope(null);\n }}\n >\n {children}\n </div>\n </FocusScopeIdContext>\n );\n};\n\nFocusScope.displayName = 'FocusScope';\n"],"mappings":";;;;;;;AAcA,MAAM,sBAAsB,cAA6B,IAAI;AAE7D,MAAa,wBAAwB,IAAI,mBAAmB;AAE5D,MAAa,cAAc,EACzB,IACA,eAAe,OACf,WACA,UACA,WACA,GAAG,WACkB;CACrB,MAAM,cAAc,MAAM;CAC1B,MAAM,UAAU,MAAM;CACtB,MAAM,WAAW,oBAAoB,OAAO;CAE5C,gBAAgB,cAAc,OAAO,GAAG,CAAC,OAAO,CAAC;CAEjD,OACE,oBAAC,qBAAD;EAAqB,OAAO;EAC1B,UAAA,oBAAC,OAAD;GACE,oBAAkB;GAClB,qBAAmB,WAAW,KAAK,KAAA;GACnC,UAAU;GACV,GAAI;GACJ,WAAW,GAAG,OAAO,MAAM,gBAAgB,OAAO,cAAc,SAAS;GACzE,YAAY,UAAU;IACpB,YAAY,KAAK;IACjB,IAAI,MAAM,kBAAkB;IAC5B,IAAI,MAAM,QAAQ,UAAU,eAAe,IAAI;GACjD;GAEC;EACE,CAAA;CACc,CAAA;AAEzB;AAEA,WAAW,cAAc"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/base-ui/FocusScope/domUtils.ts
|
|
2
|
+
const isItemVisible = (el) => {
|
|
3
|
+
if (typeof el.checkVisibility === "function") return el.checkVisibility({
|
|
4
|
+
checkOpacity: true,
|
|
5
|
+
checkVisibilityCSS: true
|
|
6
|
+
});
|
|
7
|
+
for (let node = el; node; node = node.parentElement) {
|
|
8
|
+
const style = getComputedStyle(node);
|
|
9
|
+
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
10
|
+
}
|
|
11
|
+
return true;
|
|
12
|
+
};
|
|
13
|
+
const hasSize = (el) => {
|
|
14
|
+
const rect = el.getBoundingClientRect();
|
|
15
|
+
return rect.width > 0 && rect.height > 0;
|
|
16
|
+
};
|
|
17
|
+
const isTextInputTarget = (target) => {
|
|
18
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
19
|
+
if (target.isContentEditable) return true;
|
|
20
|
+
return [
|
|
21
|
+
"INPUT",
|
|
22
|
+
"SELECT",
|
|
23
|
+
"TEXTAREA"
|
|
24
|
+
].includes(target.tagName);
|
|
25
|
+
};
|
|
26
|
+
const hasModifier = (event) => event.metaKey || event.ctrlKey || event.altKey;
|
|
27
|
+
const scopeSelector = (id) => `[data-focus-scope="${id.replaceAll("\"", "\\\"")}"]`;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { hasModifier, hasSize, isItemVisible, isTextInputTarget, scopeSelector };
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=domUtils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domUtils.mjs","names":[],"sources":["../../../src/base-ui/FocusScope/domUtils.ts"],"sourcesContent":["export const isItemVisible = (el: HTMLElement): boolean => {\n if (typeof el.checkVisibility === 'function') {\n return el.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true });\n }\n for (let node: HTMLElement | null = el; node; node = node.parentElement) {\n const style = getComputedStyle(node);\n if (style.display === 'none' || style.visibility === 'hidden') return false;\n }\n return true;\n};\n\nexport const hasSize = (el: HTMLElement) => {\n const rect = el.getBoundingClientRect();\n return rect.width > 0 && rect.height > 0;\n};\n\nexport const isTextInputTarget = (target: EventTarget | null) => {\n if (!(target instanceof HTMLElement)) return false;\n if (target.isContentEditable) return true;\n return ['INPUT', 'SELECT', 'TEXTAREA'].includes(target.tagName);\n};\n\nexport const hasModifier = (event: KeyboardEvent) => event.metaKey || event.ctrlKey || event.altKey;\n\nexport const scopeSelector = (id: string) => `[data-focus-scope=\"${id.replaceAll('\"', '\\\\\"')}\"]`;\n"],"mappings":";AAAA,MAAa,iBAAiB,OAA6B;CACzD,IAAI,OAAO,GAAG,oBAAoB,YAChC,OAAO,GAAG,gBAAgB;EAAE,cAAc;EAAM,oBAAoB;CAAK,CAAC;CAE5E,KAAK,IAAI,OAA2B,IAAI,MAAM,OAAO,KAAK,eAAe;EACvE,MAAM,QAAQ,iBAAiB,IAAI;EACnC,IAAI,MAAM,YAAY,UAAU,MAAM,eAAe,UAAU,OAAO;CACxE;CACA,OAAO;AACT;AAEA,MAAa,WAAW,OAAoB;CAC1C,MAAM,OAAO,GAAG,sBAAsB;CACtC,OAAO,KAAK,QAAQ,KAAK,KAAK,SAAS;AACzC;AAEA,MAAa,qBAAqB,WAA+B;CAC/D,IAAI,EAAE,kBAAkB,cAAc,OAAO;CAC7C,IAAI,OAAO,mBAAmB,OAAO;CACrC,OAAO;EAAC;EAAS;EAAU;CAAU,CAAC,CAAC,SAAS,OAAO,OAAO;AAChE;AAEA,MAAa,eAAe,UAAyB,MAAM,WAAW,MAAM,WAAW,MAAM;AAE7F,MAAa,iBAAiB,OAAe,sBAAsB,GAAG,WAAW,MAAK,MAAK,EAAE"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { FocusScope, FocusScopeProps, useFocusScopeId } from "./FocusScope.mjs";
|
|
2
|
+
import { getActiveScopeId, getLastFocusedItem, registerScope, setActiveScope, setLastFocusedItem, useActiveScopeId, useFocusScopeActive } from "./store.mjs";
|
|
3
|
+
import { styles } from "./style.mjs";
|
|
4
|
+
import { UseScopeArrowNavOptions, focusScopeItem, notifyScopeItemFocus, useScopeArrowNav } from "./useScopeArrowNav.mjs";
|
|
5
|
+
import { UseScopeSwitcherOptions, useScopeSwitcher } from "./useScopeSwitcher.mjs";
|
|
6
|
+
export { FocusScope, type FocusScopeProps, type UseScopeArrowNavOptions, type UseScopeSwitcherOptions, focusScopeItem, styles as focusScopeStyles, getActiveScopeId, getLastFocusedItem, notifyScopeItemFocus, registerScope, setActiveScope, setLastFocusedItem, useActiveScopeId, useFocusScopeActive, useFocusScopeId, useScopeArrowNav, useScopeSwitcher };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/base-ui/FocusScope/store.d.ts
|
|
2
|
+
declare const getActiveScopeId: () => string | null;
|
|
3
|
+
declare const setActiveScope: (id: string | null) => void;
|
|
4
|
+
declare const getLastFocusedItem: (scopeId: string) => string | null;
|
|
5
|
+
declare const setLastFocusedItem: (scopeId: string, itemId: string | null) => void;
|
|
6
|
+
declare const registerScope: (id: string) => () => void;
|
|
7
|
+
declare const useActiveScopeId: () => string | null;
|
|
8
|
+
declare const useFocusScopeActive: (id: string) => boolean;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { getActiveScopeId, getLastFocusedItem, registerScope, setActiveScope, setLastFocusedItem, useActiveScopeId, useFocusScopeActive };
|
|
11
|
+
//# sourceMappingURL=store.d.mts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
//#region src/base-ui/FocusScope/store.ts
|
|
3
|
+
let state = {
|
|
4
|
+
activeScopeId: null,
|
|
5
|
+
knownScopes: /* @__PURE__ */ new Map(),
|
|
6
|
+
lastFocusedItem: /* @__PURE__ */ new Map()
|
|
7
|
+
};
|
|
8
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
9
|
+
const setState = (patch) => {
|
|
10
|
+
state = {
|
|
11
|
+
...state,
|
|
12
|
+
...patch
|
|
13
|
+
};
|
|
14
|
+
listeners.forEach((listener) => listener());
|
|
15
|
+
};
|
|
16
|
+
const subscribe = (listener) => {
|
|
17
|
+
listeners.add(listener);
|
|
18
|
+
return () => listeners.delete(listener);
|
|
19
|
+
};
|
|
20
|
+
const getActiveScopeId = () => state.activeScopeId;
|
|
21
|
+
const setActiveScope = (id) => {
|
|
22
|
+
if (id !== null && !state.knownScopes.has(id)) return;
|
|
23
|
+
if (state.activeScopeId === id) return;
|
|
24
|
+
setState({ activeScopeId: id });
|
|
25
|
+
};
|
|
26
|
+
const getLastFocusedItem = (scopeId) => state.lastFocusedItem.get(scopeId) ?? null;
|
|
27
|
+
const setLastFocusedItem = (scopeId, itemId) => {
|
|
28
|
+
if ((state.lastFocusedItem.get(scopeId) ?? null) === itemId) return;
|
|
29
|
+
const next = new Map(state.lastFocusedItem);
|
|
30
|
+
if (itemId === null) next.delete(scopeId);
|
|
31
|
+
else next.set(scopeId, itemId);
|
|
32
|
+
setState({ lastFocusedItem: next });
|
|
33
|
+
};
|
|
34
|
+
const findScopeId = (event) => {
|
|
35
|
+
return (event.target instanceof Element ? event.target : null)?.closest("[data-focus-scope]")?.dataset.focusScope ?? null;
|
|
36
|
+
};
|
|
37
|
+
const onGlobalInteract = (event) => {
|
|
38
|
+
const id = findScopeId(event);
|
|
39
|
+
if (id !== null) setActiveScope(id);
|
|
40
|
+
};
|
|
41
|
+
let listening = false;
|
|
42
|
+
const ensureDocumentListeners = () => {
|
|
43
|
+
if (listening || typeof document === "undefined") return;
|
|
44
|
+
listening = true;
|
|
45
|
+
document.addEventListener("pointerdown", onGlobalInteract, true);
|
|
46
|
+
document.addEventListener("focusin", onGlobalInteract, true);
|
|
47
|
+
};
|
|
48
|
+
const registerScope = (id) => {
|
|
49
|
+
ensureDocumentListeners();
|
|
50
|
+
const next = new Map(state.knownScopes);
|
|
51
|
+
next.set(id, (next.get(id) ?? 0) + 1);
|
|
52
|
+
setState({ knownScopes: next });
|
|
53
|
+
return () => {
|
|
54
|
+
const count = state.knownScopes.get(id) ?? 0;
|
|
55
|
+
const scopes = new Map(state.knownScopes);
|
|
56
|
+
if (count > 1) {
|
|
57
|
+
scopes.set(id, count - 1);
|
|
58
|
+
setState({ knownScopes: scopes });
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
scopes.delete(id);
|
|
62
|
+
const lastFocused = new Map(state.lastFocusedItem);
|
|
63
|
+
lastFocused.delete(id);
|
|
64
|
+
setState({
|
|
65
|
+
activeScopeId: state.activeScopeId === id ? null : state.activeScopeId,
|
|
66
|
+
knownScopes: scopes,
|
|
67
|
+
lastFocusedItem: lastFocused
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
const useActiveScopeId = () => useSyncExternalStore(subscribe, getActiveScopeId, () => null);
|
|
72
|
+
const useFocusScopeActive = (id) => useSyncExternalStore(subscribe, () => state.activeScopeId === id, () => false);
|
|
73
|
+
//#endregion
|
|
74
|
+
export { getActiveScopeId, getLastFocusedItem, registerScope, setActiveScope, setLastFocusedItem, subscribe, useActiveScopeId, useFocusScopeActive };
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=store.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.mjs","names":[],"sources":["../../../src/base-ui/FocusScope/store.ts"],"sourcesContent":["import { useSyncExternalStore } from 'react';\n\ninterface FocusScopeState {\n activeScopeId: string | null;\n knownScopes: Map<string, number>;\n lastFocusedItem: Map<string, string>;\n}\n\nlet state: FocusScopeState = {\n activeScopeId: null,\n knownScopes: new Map(),\n lastFocusedItem: new Map(),\n};\n\nconst listeners = new Set<() => void>();\n\nconst setState = (patch: Partial<FocusScopeState>) => {\n state = { ...state, ...patch };\n listeners.forEach((listener) => listener());\n};\n\nexport const subscribe = (listener: () => void) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n};\n\nexport const getActiveScopeId = () => state.activeScopeId;\n\nexport const setActiveScope = (id: string | null) => {\n if (id !== null && !state.knownScopes.has(id)) return;\n if (state.activeScopeId === id) return;\n setState({ activeScopeId: id });\n};\n\nexport const getLastFocusedItem = (scopeId: string) => state.lastFocusedItem.get(scopeId) ?? null;\n\nexport const setLastFocusedItem = (scopeId: string, itemId: string | null) => {\n if ((state.lastFocusedItem.get(scopeId) ?? null) === itemId) return;\n const next = new Map(state.lastFocusedItem);\n if (itemId === null) next.delete(scopeId);\n else next.set(scopeId, itemId);\n setState({ lastFocusedItem: next });\n};\n\nconst findScopeId = (event: Event) => {\n const target = event.target instanceof Element ? event.target : null;\n return target?.closest<HTMLElement>('[data-focus-scope]')?.dataset.focusScope ?? null;\n};\n\nconst onGlobalInteract = (event: Event) => {\n const id = findScopeId(event);\n if (id !== null) setActiveScope(id);\n};\n\nlet listening = false;\n\nconst ensureDocumentListeners = () => {\n if (listening || typeof document === 'undefined') return;\n listening = true;\n document.addEventListener('pointerdown', onGlobalInteract, true);\n document.addEventListener('focusin', onGlobalInteract, true);\n};\n\nexport const registerScope = (id: string) => {\n ensureDocumentListeners();\n const next = new Map(state.knownScopes);\n next.set(id, (next.get(id) ?? 0) + 1);\n setState({ knownScopes: next });\n\n return () => {\n const count = state.knownScopes.get(id) ?? 0;\n const scopes = new Map(state.knownScopes);\n if (count > 1) {\n scopes.set(id, count - 1);\n setState({ knownScopes: scopes });\n return;\n }\n scopes.delete(id);\n const lastFocused = new Map(state.lastFocusedItem);\n lastFocused.delete(id);\n setState({\n activeScopeId: state.activeScopeId === id ? null : state.activeScopeId,\n knownScopes: scopes,\n lastFocusedItem: lastFocused,\n });\n };\n};\n\nexport const useActiveScopeId = () => useSyncExternalStore(subscribe, getActiveScopeId, () => null);\n\nexport const useFocusScopeActive = (id: string) =>\n useSyncExternalStore(\n subscribe,\n () => state.activeScopeId === id,\n () => false,\n );\n"],"mappings":";;AAQA,IAAI,QAAyB;CAC3B,eAAe;CACf,6BAAa,IAAI,IAAI;CACrB,iCAAiB,IAAI,IAAI;AAC3B;AAEA,MAAM,4BAAY,IAAI,IAAgB;AAEtC,MAAM,YAAY,UAAoC;CACpD,QAAQ;EAAE,GAAG;EAAO,GAAG;CAAM;CAC7B,UAAU,SAAS,aAAa,SAAS,CAAC;AAC5C;AAEA,MAAa,aAAa,aAAyB;CACjD,UAAU,IAAI,QAAQ;CACtB,aAAa,UAAU,OAAO,QAAQ;AACxC;AAEA,MAAa,yBAAyB,MAAM;AAE5C,MAAa,kBAAkB,OAAsB;CACnD,IAAI,OAAO,QAAQ,CAAC,MAAM,YAAY,IAAI,EAAE,GAAG;CAC/C,IAAI,MAAM,kBAAkB,IAAI;CAChC,SAAS,EAAE,eAAe,GAAG,CAAC;AAChC;AAEA,MAAa,sBAAsB,YAAoB,MAAM,gBAAgB,IAAI,OAAO,KAAK;AAE7F,MAAa,sBAAsB,SAAiB,WAA0B;CAC5E,KAAK,MAAM,gBAAgB,IAAI,OAAO,KAAK,UAAU,QAAQ;CAC7D,MAAM,OAAO,IAAI,IAAI,MAAM,eAAe;CAC1C,IAAI,WAAW,MAAM,KAAK,OAAO,OAAO;MACnC,KAAK,IAAI,SAAS,MAAM;CAC7B,SAAS,EAAE,iBAAiB,KAAK,CAAC;AACpC;AAEA,MAAM,eAAe,UAAiB;CAEpC,QADe,MAAM,kBAAkB,UAAU,MAAM,SAAS,KAAA,EACjD,QAAqB,oBAAoB,CAAC,EAAE,QAAQ,cAAc;AACnF;AAEA,MAAM,oBAAoB,UAAiB;CACzC,MAAM,KAAK,YAAY,KAAK;CAC5B,IAAI,OAAO,MAAM,eAAe,EAAE;AACpC;AAEA,IAAI,YAAY;AAEhB,MAAM,gCAAgC;CACpC,IAAI,aAAa,OAAO,aAAa,aAAa;CAClD,YAAY;CACZ,SAAS,iBAAiB,eAAe,kBAAkB,IAAI;CAC/D,SAAS,iBAAiB,WAAW,kBAAkB,IAAI;AAC7D;AAEA,MAAa,iBAAiB,OAAe;CAC3C,wBAAwB;CACxB,MAAM,OAAO,IAAI,IAAI,MAAM,WAAW;CACtC,KAAK,IAAI,KAAK,KAAK,IAAI,EAAE,KAAK,KAAK,CAAC;CACpC,SAAS,EAAE,aAAa,KAAK,CAAC;CAE9B,aAAa;EACX,MAAM,QAAQ,MAAM,YAAY,IAAI,EAAE,KAAK;EAC3C,MAAM,SAAS,IAAI,IAAI,MAAM,WAAW;EACxC,IAAI,QAAQ,GAAG;GACb,OAAO,IAAI,IAAI,QAAQ,CAAC;GACxB,SAAS,EAAE,aAAa,OAAO,CAAC;GAChC;EACF;EACA,OAAO,OAAO,EAAE;EAChB,MAAM,cAAc,IAAI,IAAI,MAAM,eAAe;EACjD,YAAY,OAAO,EAAE;EACrB,SAAS;GACP,eAAe,MAAM,kBAAkB,KAAK,OAAO,MAAM;GACzD,aAAa;GACb,iBAAiB;EACnB,CAAC;CACH;AACF;AAEA,MAAa,yBAAyB,qBAAqB,WAAW,wBAAwB,IAAI;AAElG,MAAa,uBAAuB,OAClC,qBACE,iBACM,MAAM,kBAAkB,UACxB,KACR"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createStaticStyles } from "antd-style";
|
|
2
|
+
//#region src/base-ui/FocusScope/style.ts
|
|
3
|
+
const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
4
|
+
debugOutline: css`
|
|
5
|
+
&[data-scope-active] {
|
|
6
|
+
outline: 2px dashed color-mix(in srgb, ${cssVar.colorInfo} 60%, transparent);
|
|
7
|
+
outline-offset: -2px;
|
|
8
|
+
}
|
|
9
|
+
`,
|
|
10
|
+
root: css`
|
|
11
|
+
position: relative;
|
|
12
|
+
outline: none;
|
|
13
|
+
`
|
|
14
|
+
}));
|
|
15
|
+
//#endregion
|
|
16
|
+
export { styles };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=style.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.mjs","names":[],"sources":["../../../src/base-ui/FocusScope/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n debugOutline: css`\n &[data-scope-active] {\n outline: 2px dashed color-mix(in srgb, ${cssVar.colorInfo} 60%, transparent);\n outline-offset: -2px;\n }\n `,\n root: css`\n position: relative;\n outline: none;\n `,\n}));\n"],"mappings":";;AAEA,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,cAAc,GAAG;;+CAE4B,OAAO,UAAU;;;;CAI9D,MAAM,GAAG;;;;AAIX,EAAE"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/base-ui/FocusScope/useScopeArrowNav.d.ts
|
|
2
|
+
interface UseScopeArrowNavOptions {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
extra?: Record<string, (event: KeyboardEvent) => void>;
|
|
5
|
+
itemSelector?: string;
|
|
6
|
+
onItemFocus?: (el: HTMLElement) => void;
|
|
7
|
+
scopeId: string;
|
|
8
|
+
vimKeys?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const notifyScopeItemFocus: (scopeId: string, el: HTMLElement) => void;
|
|
11
|
+
declare const focusScopeItem: (scopeId: string, el: HTMLElement) => void;
|
|
12
|
+
declare const useScopeArrowNav: ({ scopeId, itemSelector, enabled, vimKeys, onItemFocus, extra }: UseScopeArrowNavOptions) => void;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { UseScopeArrowNavOptions, focusScopeItem, notifyScopeItemFocus, useScopeArrowNav };
|
|
15
|
+
//# sourceMappingURL=useScopeArrowNav.d.mts.map
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { getActiveScopeId, setLastFocusedItem } from "./store.mjs";
|
|
2
|
+
import { hasModifier, isItemVisible, isTextInputTarget, scopeSelector } from "./domUtils.mjs";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
//#region src/base-ui/FocusScope/useScopeArrowNav.ts
|
|
5
|
+
let lastHandledEvent = null;
|
|
6
|
+
const focusListeners = /* @__PURE__ */ new Map();
|
|
7
|
+
const registerItemFocus = (scopeId, listener) => {
|
|
8
|
+
const set = focusListeners.get(scopeId) ?? /* @__PURE__ */ new Set();
|
|
9
|
+
set.add(listener);
|
|
10
|
+
focusListeners.set(scopeId, set);
|
|
11
|
+
return () => {
|
|
12
|
+
set.delete(listener);
|
|
13
|
+
if (set.size === 0) focusListeners.delete(scopeId);
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
const notifyScopeItemFocus = (scopeId, el) => {
|
|
17
|
+
const id = el.dataset.id;
|
|
18
|
+
if (id) setLastFocusedItem(scopeId, id);
|
|
19
|
+
focusListeners.get(scopeId)?.forEach((listener) => listener(el));
|
|
20
|
+
};
|
|
21
|
+
const getScopeRoot = (scopeId) => {
|
|
22
|
+
const selector = scopeSelector(scopeId);
|
|
23
|
+
const active = document.activeElement;
|
|
24
|
+
if (active instanceof HTMLElement) {
|
|
25
|
+
const owned = active.closest(selector);
|
|
26
|
+
if (owned) return owned;
|
|
27
|
+
}
|
|
28
|
+
const candidates = [...document.querySelectorAll(selector)];
|
|
29
|
+
return candidates.find(isItemVisible) ?? candidates[0] ?? null;
|
|
30
|
+
};
|
|
31
|
+
const focusScopeItem = (scopeId, el) => {
|
|
32
|
+
el.focus({ preventScroll: true });
|
|
33
|
+
el.scrollIntoView?.({ block: "nearest" });
|
|
34
|
+
notifyScopeItemFocus(scopeId, el);
|
|
35
|
+
};
|
|
36
|
+
const useScopeArrowNav = ({ scopeId, itemSelector = "[data-scope-item]", enabled = true, vimKeys = false, onItemFocus, extra }) => {
|
|
37
|
+
const optionsRef = useRef({
|
|
38
|
+
extra,
|
|
39
|
+
itemSelector,
|
|
40
|
+
onItemFocus,
|
|
41
|
+
scopeId
|
|
42
|
+
});
|
|
43
|
+
optionsRef.current = {
|
|
44
|
+
extra,
|
|
45
|
+
itemSelector,
|
|
46
|
+
onItemFocus,
|
|
47
|
+
scopeId
|
|
48
|
+
};
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (!onItemFocus) return;
|
|
51
|
+
return registerItemFocus(scopeId, (el) => optionsRef.current.onItemFocus?.(el));
|
|
52
|
+
}, [scopeId, !!onItemFocus]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!enabled || typeof window === "undefined") return;
|
|
55
|
+
const getItems = () => {
|
|
56
|
+
const root = getScopeRoot(optionsRef.current.scopeId);
|
|
57
|
+
if (!root) return [];
|
|
58
|
+
return [...root.querySelectorAll(optionsRef.current.itemSelector)].filter(isItemVisible);
|
|
59
|
+
};
|
|
60
|
+
const currentIndex = (items) => {
|
|
61
|
+
const active = document.activeElement;
|
|
62
|
+
if (!(active instanceof HTMLElement)) return -1;
|
|
63
|
+
const item = active.closest(optionsRef.current.itemSelector);
|
|
64
|
+
return item ? items.indexOf(item) : -1;
|
|
65
|
+
};
|
|
66
|
+
const move = (direction) => {
|
|
67
|
+
const items = getItems();
|
|
68
|
+
if (items.length === 0) return;
|
|
69
|
+
const index = currentIndex(items);
|
|
70
|
+
const next = index === -1 ? direction === 1 ? 0 : items.length - 1 : (index + direction + items.length) % items.length;
|
|
71
|
+
focusScopeItem(optionsRef.current.scopeId, items[next]);
|
|
72
|
+
};
|
|
73
|
+
const edge = (which) => {
|
|
74
|
+
const items = getItems();
|
|
75
|
+
if (items.length === 0) return;
|
|
76
|
+
focusScopeItem(optionsRef.current.scopeId, items[which === "first" ? 0 : items.length - 1]);
|
|
77
|
+
};
|
|
78
|
+
const isReachable = () => {
|
|
79
|
+
const id = optionsRef.current.scopeId;
|
|
80
|
+
if (getActiveScopeId() === id) return true;
|
|
81
|
+
const active = document.activeElement;
|
|
82
|
+
return active instanceof HTMLElement && !!active.closest(scopeSelector(id));
|
|
83
|
+
};
|
|
84
|
+
const onKeyDown = (event) => {
|
|
85
|
+
if (event.defaultPrevented || lastHandledEvent === event) return;
|
|
86
|
+
if (hasModifier(event) || isTextInputTarget(event.target) || !isReachable()) return;
|
|
87
|
+
const builtin = {
|
|
88
|
+
ArrowDown: () => move(1),
|
|
89
|
+
ArrowUp: () => move(-1),
|
|
90
|
+
End: () => edge("last"),
|
|
91
|
+
Home: () => edge("first"),
|
|
92
|
+
...vimKeys && {
|
|
93
|
+
j: () => move(1),
|
|
94
|
+
k: () => move(-1)
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const extraHandler = optionsRef.current.extra?.[event.key];
|
|
98
|
+
const handler = builtin[event.key] ?? (extraHandler && (() => extraHandler(event)));
|
|
99
|
+
if (!handler) return;
|
|
100
|
+
lastHandledEvent = event;
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
handler();
|
|
103
|
+
};
|
|
104
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
105
|
+
return () => window.removeEventListener("keydown", onKeyDown, true);
|
|
106
|
+
}, [enabled, vimKeys]);
|
|
107
|
+
};
|
|
108
|
+
//#endregion
|
|
109
|
+
export { focusScopeItem, getScopeRoot, notifyScopeItemFocus, useScopeArrowNav };
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=useScopeArrowNav.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScopeArrowNav.mjs","names":[],"sources":["../../../src/base-ui/FocusScope/useScopeArrowNav.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport { hasModifier, isItemVisible, isTextInputTarget, scopeSelector } from './domUtils';\nimport { getActiveScopeId, setLastFocusedItem } from './store';\n\nexport interface UseScopeArrowNavOptions {\n enabled?: boolean;\n extra?: Record<string, (event: KeyboardEvent) => void>;\n itemSelector?: string;\n onItemFocus?: (el: HTMLElement) => void;\n scopeId: string;\n vimKeys?: boolean;\n}\n\n// Sibling instances for one scope id (mobile + desktop mounts) all see the same\n// KeyboardEvent; the first one claims it so focus only moves once.\nlet lastHandledEvent: KeyboardEvent | null = null;\n\nconst focusListeners = new Map<string, Set<(el: HTMLElement) => void>>();\n\nconst registerItemFocus = (scopeId: string, listener: (el: HTMLElement) => void) => {\n const set = focusListeners.get(scopeId) ?? new Set();\n set.add(listener);\n focusListeners.set(scopeId, set);\n return () => {\n set.delete(listener);\n if (set.size === 0) focusListeners.delete(scopeId);\n };\n};\n\nexport const notifyScopeItemFocus = (scopeId: string, el: HTMLElement) => {\n const id = el.dataset.id;\n if (id) setLastFocusedItem(scopeId, id);\n focusListeners.get(scopeId)?.forEach((listener) => listener(el));\n};\n\nexport const getScopeRoot = (scopeId: string): HTMLElement | null => {\n const selector = scopeSelector(scopeId);\n const active = document.activeElement;\n if (active instanceof HTMLElement) {\n const owned = active.closest<HTMLElement>(selector);\n if (owned) return owned;\n }\n const candidates = [...document.querySelectorAll<HTMLElement>(selector)];\n return candidates.find(isItemVisible) ?? candidates[0] ?? null;\n};\n\nexport const focusScopeItem = (scopeId: string, el: HTMLElement) => {\n el.focus({ preventScroll: true });\n el.scrollIntoView?.({ block: 'nearest' });\n notifyScopeItemFocus(scopeId, el);\n};\n\nexport const useScopeArrowNav = ({\n scopeId,\n itemSelector = '[data-scope-item]',\n enabled = true,\n vimKeys = false,\n onItemFocus,\n extra,\n}: UseScopeArrowNavOptions) => {\n const optionsRef = useRef({ extra, itemSelector, onItemFocus, scopeId });\n optionsRef.current = { extra, itemSelector, onItemFocus, scopeId };\n\n useEffect(() => {\n if (!onItemFocus) return;\n return registerItemFocus(scopeId, (el) => optionsRef.current.onItemFocus?.(el));\n }, [scopeId, !!onItemFocus]);\n\n useEffect(() => {\n if (!enabled || typeof window === 'undefined') return;\n\n const getItems = () => {\n const root = getScopeRoot(optionsRef.current.scopeId);\n if (!root) return [];\n return [...root.querySelectorAll<HTMLElement>(optionsRef.current.itemSelector)].filter(\n isItemVisible,\n );\n };\n\n const currentIndex = (items: HTMLElement[]) => {\n const active = document.activeElement;\n if (!(active instanceof HTMLElement)) return -1;\n const item = active.closest<HTMLElement>(optionsRef.current.itemSelector);\n return item ? items.indexOf(item) : -1;\n };\n\n const move = (direction: 1 | -1) => {\n const items = getItems();\n if (items.length === 0) return;\n const index = currentIndex(items);\n const next =\n index === -1\n ? direction === 1\n ? 0\n : items.length - 1\n : (index + direction + items.length) % items.length;\n focusScopeItem(optionsRef.current.scopeId, items[next]);\n };\n\n const edge = (which: 'first' | 'last') => {\n const items = getItems();\n if (items.length === 0) return;\n focusScopeItem(optionsRef.current.scopeId, items[which === 'first' ? 0 : items.length - 1]);\n };\n\n const isReachable = () => {\n const id = optionsRef.current.scopeId;\n if (getActiveScopeId() === id) return true;\n const active = document.activeElement;\n return active instanceof HTMLElement && !!active.closest(scopeSelector(id));\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || lastHandledEvent === event) return;\n if (hasModifier(event) || isTextInputTarget(event.target) || !isReachable()) return;\n\n const builtin: Record<string, () => void> = {\n ArrowDown: () => move(1),\n ArrowUp: () => move(-1),\n End: () => edge('last'),\n Home: () => edge('first'),\n ...(vimKeys && { j: () => move(1), k: () => move(-1) }),\n };\n const extraHandler = optionsRef.current.extra?.[event.key];\n const handler = builtin[event.key] ?? (extraHandler && (() => extraHandler(event)));\n if (!handler) return;\n\n lastHandledEvent = event;\n event.preventDefault();\n handler();\n };\n\n window.addEventListener('keydown', onKeyDown, true);\n return () => window.removeEventListener('keydown', onKeyDown, true);\n }, [enabled, vimKeys]);\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/base-ui/FocusScope/useScopeSwitcher.d.ts
|
|
2
|
+
interface UseScopeSwitcherOptions {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
vimKeys?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare const useScopeSwitcher: ({ enabled, vimKeys }?: UseScopeSwitcherOptions) => void;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { UseScopeSwitcherOptions, useScopeSwitcher };
|
|
9
|
+
//# sourceMappingURL=useScopeSwitcher.d.mts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getActiveScopeId, getLastFocusedItem, setActiveScope } from "./store.mjs";
|
|
2
|
+
import { hasModifier, hasSize, isItemVisible, isTextInputTarget } from "./domUtils.mjs";
|
|
3
|
+
import { focusScopeItem } from "./useScopeArrowNav.mjs";
|
|
4
|
+
import { useEffect } from "react";
|
|
5
|
+
//#region src/base-ui/FocusScope/useScopeSwitcher.ts
|
|
6
|
+
const getOrderedScopes = () => {
|
|
7
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8
|
+
const out = [];
|
|
9
|
+
for (const el of document.querySelectorAll("[data-focus-scope]")) {
|
|
10
|
+
const id = el.dataset.focusScope;
|
|
11
|
+
if (!id || seen.has(id) || !isItemVisible(el) || !hasSize(el)) continue;
|
|
12
|
+
seen.add(id);
|
|
13
|
+
out.push(el);
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
};
|
|
17
|
+
const focusInto = (scope) => {
|
|
18
|
+
const id = scope.dataset.focusScope;
|
|
19
|
+
setActiveScope(id);
|
|
20
|
+
const lastId = getLastFocusedItem(id);
|
|
21
|
+
const target = lastId && [...scope.querySelectorAll("[data-scope-item]")].find((el) => el.dataset.id === lastId && isItemVisible(el)) || [...scope.querySelectorAll("[data-scope-item]")].find(isItemVisible) || scope;
|
|
22
|
+
focusScopeItem(id, target);
|
|
23
|
+
};
|
|
24
|
+
const useScopeSwitcher = ({ enabled = true, vimKeys = false } = {}) => {
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!enabled || typeof window === "undefined") return;
|
|
27
|
+
const onKeyDown = (event) => {
|
|
28
|
+
if (event.defaultPrevented || hasModifier(event) || isTextInputTarget(event.target)) return;
|
|
29
|
+
const direction = event.key === "ArrowRight" || vimKeys && event.key === "l" ? 1 : event.key === "ArrowLeft" || vimKeys && event.key === "h" ? -1 : 0;
|
|
30
|
+
if (!direction) return;
|
|
31
|
+
const scopes = getOrderedScopes();
|
|
32
|
+
if (scopes.length === 0) return;
|
|
33
|
+
const activeId = getActiveScopeId();
|
|
34
|
+
const index = scopes.findIndex((el) => el.dataset.focusScope === activeId);
|
|
35
|
+
const next = index === -1 ? direction === 1 ? scopes[0] : scopes.at(-1) : scopes[index + direction];
|
|
36
|
+
if (!next) return;
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
focusInto(next);
|
|
39
|
+
};
|
|
40
|
+
window.addEventListener("keydown", onKeyDown);
|
|
41
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
42
|
+
}, [enabled, vimKeys]);
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { useScopeSwitcher };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=useScopeSwitcher.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScopeSwitcher.mjs","names":[],"sources":["../../../src/base-ui/FocusScope/useScopeSwitcher.ts"],"sourcesContent":["import { useEffect } from 'react';\n\nimport { hasModifier, hasSize, isItemVisible, isTextInputTarget } from './domUtils';\nimport { getActiveScopeId, getLastFocusedItem, setActiveScope } from './store';\nimport { focusScopeItem } from './useScopeArrowNav';\n\nexport interface UseScopeSwitcherOptions {\n enabled?: boolean;\n vimKeys?: boolean;\n}\n\nconst getOrderedScopes = () => {\n const seen = new Set<string>();\n const out: HTMLElement[] = [];\n for (const el of document.querySelectorAll<HTMLElement>('[data-focus-scope]')) {\n const id = el.dataset.focusScope;\n if (!id || seen.has(id) || !isItemVisible(el) || !hasSize(el)) continue;\n seen.add(id);\n out.push(el);\n }\n return out;\n};\n\nconst focusInto = (scope: HTMLElement) => {\n const id = scope.dataset.focusScope!;\n setActiveScope(id);\n const lastId = getLastFocusedItem(id);\n const last =\n lastId &&\n [...scope.querySelectorAll<HTMLElement>('[data-scope-item]')].find(\n (el) => el.dataset.id === lastId && isItemVisible(el),\n );\n const target =\n last ||\n [...scope.querySelectorAll<HTMLElement>('[data-scope-item]')].find(isItemVisible) ||\n scope;\n focusScopeItem(id, target);\n};\n\nexport const useScopeSwitcher = ({ enabled = true, vimKeys = false }: UseScopeSwitcherOptions = {}) => {\n useEffect(() => {\n if (!enabled || typeof window === 'undefined') return;\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || hasModifier(event) || isTextInputTarget(event.target)) return;\n const direction =\n event.key === 'ArrowRight' || (vimKeys && event.key === 'l')\n ? 1\n : event.key === 'ArrowLeft' || (vimKeys && event.key === 'h')\n ? -1\n : 0;\n if (!direction) return;\n\n const scopes = getOrderedScopes();\n if (scopes.length === 0) return;\n const activeId = getActiveScopeId();\n const index = scopes.findIndex((el) => el.dataset.focusScope === activeId);\n const next = index === -1 ? (direction === 1 ? scopes[0] : scopes.at(-1)!) : scopes[index + direction];\n if (!next) return;\n event.preventDefault();\n focusInto(next);\n };\n\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [enabled, vimKeys]);\n};\n"],"mappings":";;;;;AAWA,MAAM,yBAAyB;CAC7B,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,MAAqB,CAAC;CAC5B,KAAK,MAAM,MAAM,SAAS,iBAA8B,oBAAoB,GAAG;EAC7E,MAAM,KAAK,GAAG,QAAQ;EACtB,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG;EAC/D,KAAK,IAAI,EAAE;EACX,IAAI,KAAK,EAAE;CACb;CACA,OAAO;AACT;AAEA,MAAM,aAAa,UAAuB;CACxC,MAAM,KAAK,MAAM,QAAQ;CACzB,eAAe,EAAE;CACjB,MAAM,SAAS,mBAAmB,EAAE;CAMpC,MAAM,SAJJ,UACA,CAAC,GAAG,MAAM,iBAA8B,mBAAmB,CAAC,CAAC,CAAC,MAC3D,OAAO,GAAG,QAAQ,OAAO,UAAU,cAAc,EAAE,CACtD,KAGA,CAAC,GAAG,MAAM,iBAA8B,mBAAmB,CAAC,CAAC,CAAC,KAAK,aAAa,KAChF;CACF,eAAe,IAAI,MAAM;AAC3B;AAEA,MAAa,oBAAoB,EAAE,UAAU,MAAM,UAAU,UAAmC,CAAC,MAAM;CACrG,gBAAgB;EACd,IAAI,CAAC,WAAW,OAAO,WAAW,aAAa;EAE/C,MAAM,aAAa,UAAyB;GAC1C,IAAI,MAAM,oBAAoB,YAAY,KAAK,KAAK,kBAAkB,MAAM,MAAM,GAAG;GACrF,MAAM,YACJ,MAAM,QAAQ,gBAAiB,WAAW,MAAM,QAAQ,MACpD,IACA,MAAM,QAAQ,eAAgB,WAAW,MAAM,QAAQ,MACrD,KACA;GACR,IAAI,CAAC,WAAW;GAEhB,MAAM,SAAS,iBAAiB;GAChC,IAAI,OAAO,WAAW,GAAG;GACzB,MAAM,WAAW,iBAAiB;GAClC,MAAM,QAAQ,OAAO,WAAW,OAAO,GAAG,QAAQ,eAAe,QAAQ;GACzE,MAAM,OAAO,UAAU,KAAM,cAAc,IAAI,OAAO,KAAK,OAAO,GAAG,EAAE,IAAM,OAAO,QAAQ;GAC5F,IAAI,CAAC,MAAM;GACX,MAAM,eAAe;GACrB,UAAU,IAAI;EAChB;EAEA,OAAO,iBAAiB,WAAW,SAAS;EAC5C,aAAa,OAAO,oBAAoB,WAAW,SAAS;CAC9D,GAAG,CAAC,SAAS,OAAO,CAAC;AACvB"}
|
|
@@ -24,7 +24,7 @@ declare const styles: {
|
|
|
24
24
|
declare const rootVariants: (props?: ({
|
|
25
25
|
shadow?: boolean | null | undefined;
|
|
26
26
|
size?: "large" | "middle" | "small" | null | undefined;
|
|
27
|
-
variant?: "
|
|
27
|
+
variant?: "filled" | "borderless" | "outlined" | null | undefined;
|
|
28
28
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
29
29
|
//#endregion
|
|
30
30
|
export { rootVariants, styles };
|
|
@@ -42,7 +42,7 @@ declare const variants: (props?: ({
|
|
|
42
42
|
mark?: boolean | null | undefined;
|
|
43
43
|
shiny?: boolean | null | undefined;
|
|
44
44
|
strong?: boolean | null | undefined;
|
|
45
|
-
type?: "danger" | "
|
|
45
|
+
type?: "danger" | "success" | "info" | "warning" | "secondary" | null | undefined;
|
|
46
46
|
underline?: boolean | null | undefined;
|
|
47
47
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
48
48
|
//#endregion
|