@lobehub/ui 5.42.7 → 5.43.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 +10 -7
- package/es/ConfigProvider/index.d.mts +1 -0
- package/es/ConfigProvider/index.mjs +5 -0
- package/es/ConfigProvider/index.mjs.map +1 -1
- package/es/GlobalFocusRing/index.d.mts +6 -0
- package/es/GlobalFocusRing/index.d.ts +1 -0
- package/es/GlobalFocusRing/index.js +1 -0
- package/es/GlobalFocusRing/index.mjs +136 -0
- package/es/GlobalFocusRing/index.mjs.map +1 -0
- package/es/GlobalFocusRing/style.mjs +35 -0
- package/es/GlobalFocusRing/style.mjs.map +1 -0
- package/es/Image/viewer/ImageViewer.mjs +73 -79
- package/es/Image/viewer/ImageViewer.mjs.map +1 -1
- package/es/base-ui/DraggablePanel/atoms.mjs +5 -3
- package/es/base-ui/DraggablePanel/atoms.mjs.map +1 -1
- package/es/base-ui/focusRing.mjs +11 -9
- package/es/base-ui/focusRing.mjs.map +1 -1
- package/es/index.d.mts +2 -1
- package/es/index.mjs +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -119,31 +119,34 @@ import hotkeyMessages from '@lobehub/ui/i18n/resources/hotkey';
|
|
|
119
119
|
|
|
120
120
|
### ConfigProvider (Motion)
|
|
121
121
|
|
|
122
|
-
You must pass a motion component via `ConfigProvider
|
|
123
|
-
If your app uses `LazyMotion`, pass `m`:
|
|
122
|
+
You must pass a motion component via `ConfigProvider`, and `ConfigProvider` must wrap `ThemeProvider` — never the other way round. `ThemeProvider` renders the antd `App` that hosts the static `notification` / `modal` holders and reads the CDN config for its webfonts, so both need the contexts from `ConfigProvider` above them.
|
|
124
123
|
|
|
125
124
|
```tsx
|
|
126
|
-
import { ConfigProvider } from '@lobehub/ui';
|
|
125
|
+
import { ConfigProvider, ThemeProvider } from '@lobehub/ui';
|
|
127
126
|
import { motion } from 'motion/react';
|
|
128
127
|
|
|
129
128
|
export default () => (
|
|
130
129
|
<ConfigProvider motion={motion}>
|
|
131
|
-
<
|
|
130
|
+
<ThemeProvider>
|
|
131
|
+
<App />
|
|
132
|
+
</ThemeProvider>
|
|
132
133
|
</ConfigProvider>
|
|
133
134
|
);
|
|
134
135
|
```
|
|
135
136
|
|
|
136
|
-
If your app uses `LazyMotion`:
|
|
137
|
+
If your app uses `LazyMotion`, pass `m`:
|
|
137
138
|
|
|
138
139
|
```tsx
|
|
139
|
-
import { ConfigProvider } from '@lobehub/ui';
|
|
140
|
+
import { ConfigProvider, ThemeProvider } from '@lobehub/ui';
|
|
140
141
|
import { LazyMotion, domAnimation } from 'motion/react';
|
|
141
142
|
import * as m from 'motion/react-m';
|
|
142
143
|
|
|
143
144
|
export default () => (
|
|
144
145
|
<LazyMotion features={domAnimation}>
|
|
145
146
|
<ConfigProvider motion={m}>
|
|
146
|
-
<
|
|
147
|
+
<ThemeProvider>
|
|
148
|
+
<App />
|
|
149
|
+
</ThemeProvider>
|
|
147
150
|
</ConfigProvider>
|
|
148
151
|
</LazyMotion>
|
|
149
152
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { installGlobalFocusRing } from "../GlobalFocusRing/index.mjs";
|
|
2
3
|
import { MotionComponent } from "../MotionProvider/index.mjs";
|
|
3
4
|
import { genCdnUrl } from "../utils/genCdnUrl.mjs";
|
|
4
5
|
import { createContext, memo, use, useEffect, useMemo, useRef, useState } from "react";
|
|
@@ -11,6 +12,10 @@ const I18nContextInternal = createContext({
|
|
|
11
12
|
});
|
|
12
13
|
const isThenable = (value) => typeof value?.then === "function";
|
|
13
14
|
const ConfigProvider = memo(({ children, config, locale, resources, motion }) => {
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (config?.globalFocusRing === false) return;
|
|
17
|
+
return installGlobalFocusRing();
|
|
18
|
+
}, [config?.globalFocusRing]);
|
|
14
19
|
const fallbackLocale = locale ?? "en";
|
|
15
20
|
const [resolvedResources, setResolvedResources] = useState(() => resources && !isThenable(resources) ? resources : void 0);
|
|
16
21
|
const [resolvedLocale, setResolvedLocale] = useState(fallbackLocale);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/ConfigProvider/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n type ElementType,\n memo,\n type ReactNode,\n use,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport {\n type I18nContextValue,\n type TranslationKey,\n type TranslationResourcesInput,\n type TranslationResourcesMap,\n} from '@/i18n/types';\nimport { MotionComponent, type MotionComponentType } from '@/MotionProvider';\nimport { type CDN, type CdnApi, genCdnUrl } from '@/utils/genCdnUrl';\n\nexport interface Config {\n aAs?: ElementType;\n customCdnFn?: CdnFn;\n imgAs?: ElementType;\n imgUnoptimized?: boolean;\n proxy?: CDN | 'custom';\n}\n\nexport const ConfigContext = createContext<Config | null>(null);\n\n// Internal i18n context\nconst I18nContextInternal = createContext<I18nContextValue>({\n locale: 'en',\n t: (key: TranslationKey) => key,\n});\n\nexport interface ConfigProviderProps {\n children: ReactNode;\n config?: Config;\n // i18n props - flattened at top level\n locale?: string;\n motion: MotionComponentType;\n resources?: TranslationResourcesInput;\n}\n\nconst isThenable = (value: unknown): value is Promise<TranslationResourcesMap> =>\n typeof (value as { then?: unknown })?.then === 'function';\n\nconst ConfigProvider = memo<ConfigProviderProps>(\n ({ children, config, locale, resources, motion }) => {\n const fallbackLocale = locale ?? 'en';\n const [resolvedResources, setResolvedResources] = useState<TranslationResourcesMap | undefined>(\n () => (resources && !isThenable(resources) ? resources : undefined),\n );\n const [resolvedLocale, setResolvedLocale] = useState(fallbackLocale);\n const latestRequestId = useRef(0);\n\n useEffect(() => {\n const requestId = ++latestRequestId.current;\n\n if (!resources) {\n setResolvedResources(undefined);\n setResolvedLocale(fallbackLocale);\n return;\n }\n\n if (isThenable(resources)) {\n const targetLocale = fallbackLocale;\n resources\n .then((nextResources) => {\n if (latestRequestId.current !== requestId) return;\n setResolvedResources(nextResources);\n setResolvedLocale(targetLocale);\n })\n .catch(() => {\n if (latestRequestId.current !== requestId) return;\n });\n return;\n }\n\n setResolvedResources(resources);\n setResolvedLocale(fallbackLocale);\n }, [fallbackLocale, resources]);\n\n const currentResources = isThenable(resources) ? resolvedResources : resources;\n const currentLocale = isThenable(resources) ? resolvedLocale : fallbackLocale;\n\n const i18nValue = useMemo((): I18nContextValue => {\n const resourceList = Array.isArray(currentResources)\n ? currentResources\n : currentResources\n ? Object.values(currentResources)\n : [];\n const mergedResources = Object.assign({}, ...resourceList);\n const t = (key: TranslationKey): string => mergedResources[key] || key;\n return { locale: currentLocale, t };\n }, [currentLocale, currentResources]);\n\n return (\n <I18nContextInternal value={i18nValue}>\n <ConfigContext value={config ?? null}>\n <MotionComponent value={motion}>{children}</MotionComponent>\n </ConfigContext>\n </I18nContextInternal>\n );\n },\n);\n\n// useCdnFn\nexport type CdnFn = ({ pkg, version, path }: CdnApi) => string;\n\nconst cdnFallback: CdnFn = ({ pkg, version, path }) =>\n genCdnUrl({ path, pkg, proxy: 'aliyun', version });\n\nexport const useCdnFn = (): CdnFn => {\n const config = use(ConfigContext);\n if (!config) return cdnFallback;\n if (config?.proxy !== 'custom')\n return ({ pkg, version, path }) =>\n genCdnUrl({ path, pkg, proxy: config.proxy as any, version });\n return config?.customCdnFn || cdnFallback;\n};\n\n// useI18n hook\nexport const useI18n = () => use(I18nContextInternal);\n\n// Export I18nContext for external reference\nexport { I18nContextInternal as I18nContext };\n\nexport default ConfigProvider;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/ConfigProvider/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n type ElementType,\n memo,\n type ReactNode,\n use,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { installGlobalFocusRing } from '@/GlobalFocusRing';\nimport {\n type I18nContextValue,\n type TranslationKey,\n type TranslationResourcesInput,\n type TranslationResourcesMap,\n} from '@/i18n/types';\nimport { MotionComponent, type MotionComponentType } from '@/MotionProvider';\nimport { type CDN, type CdnApi, genCdnUrl } from '@/utils/genCdnUrl';\n\nexport interface Config {\n aAs?: ElementType;\n customCdnFn?: CdnFn;\n globalFocusRing?: boolean;\n imgAs?: ElementType;\n imgUnoptimized?: boolean;\n proxy?: CDN | 'custom';\n}\n\nexport const ConfigContext = createContext<Config | null>(null);\n\n// Internal i18n context\nconst I18nContextInternal = createContext<I18nContextValue>({\n locale: 'en',\n t: (key: TranslationKey) => key,\n});\n\nexport interface ConfigProviderProps {\n children: ReactNode;\n config?: Config;\n // i18n props - flattened at top level\n locale?: string;\n motion: MotionComponentType;\n resources?: TranslationResourcesInput;\n}\n\nconst isThenable = (value: unknown): value is Promise<TranslationResourcesMap> =>\n typeof (value as { then?: unknown })?.then === 'function';\n\nconst ConfigProvider = memo<ConfigProviderProps>(\n ({ children, config, locale, resources, motion }) => {\n useEffect(() => {\n if (config?.globalFocusRing === false) return;\n return installGlobalFocusRing();\n }, [config?.globalFocusRing]);\n\n const fallbackLocale = locale ?? 'en';\n const [resolvedResources, setResolvedResources] = useState<TranslationResourcesMap | undefined>(\n () => (resources && !isThenable(resources) ? resources : undefined),\n );\n const [resolvedLocale, setResolvedLocale] = useState(fallbackLocale);\n const latestRequestId = useRef(0);\n\n useEffect(() => {\n const requestId = ++latestRequestId.current;\n\n if (!resources) {\n setResolvedResources(undefined);\n setResolvedLocale(fallbackLocale);\n return;\n }\n\n if (isThenable(resources)) {\n const targetLocale = fallbackLocale;\n resources\n .then((nextResources) => {\n if (latestRequestId.current !== requestId) return;\n setResolvedResources(nextResources);\n setResolvedLocale(targetLocale);\n })\n .catch(() => {\n if (latestRequestId.current !== requestId) return;\n });\n return;\n }\n\n setResolvedResources(resources);\n setResolvedLocale(fallbackLocale);\n }, [fallbackLocale, resources]);\n\n const currentResources = isThenable(resources) ? resolvedResources : resources;\n const currentLocale = isThenable(resources) ? resolvedLocale : fallbackLocale;\n\n const i18nValue = useMemo((): I18nContextValue => {\n const resourceList = Array.isArray(currentResources)\n ? currentResources\n : currentResources\n ? Object.values(currentResources)\n : [];\n const mergedResources = Object.assign({}, ...resourceList);\n const t = (key: TranslationKey): string => mergedResources[key] || key;\n return { locale: currentLocale, t };\n }, [currentLocale, currentResources]);\n\n return (\n <I18nContextInternal value={i18nValue}>\n <ConfigContext value={config ?? null}>\n <MotionComponent value={motion}>{children}</MotionComponent>\n </ConfigContext>\n </I18nContextInternal>\n );\n },\n);\n\n// useCdnFn\nexport type CdnFn = ({ pkg, version, path }: CdnApi) => string;\n\nconst cdnFallback: CdnFn = ({ pkg, version, path }) =>\n genCdnUrl({ path, pkg, proxy: 'aliyun', version });\n\nexport const useCdnFn = (): CdnFn => {\n const config = use(ConfigContext);\n if (!config) return cdnFallback;\n if (config?.proxy !== 'custom')\n return ({ pkg, version, path }) =>\n genCdnUrl({ path, pkg, proxy: config.proxy as any, version });\n return config?.customCdnFn || cdnFallback;\n};\n\n// useI18n hook\nexport const useI18n = () => use(I18nContextInternal);\n\n// Export I18nContext for external reference\nexport { I18nContextInternal as I18nContext };\n\nexport default ConfigProvider;\n"],"mappings":";;;;;;;AAiCA,MAAa,gBAAgB,cAA6B,IAAI;AAG9D,MAAM,sBAAsB,cAAgC;CAC1D,QAAQ;CACR,IAAI,QAAwB;AAC9B,CAAC;AAWD,MAAM,cAAc,UAClB,OAAQ,OAA8B,SAAS;AAEjD,MAAM,iBAAiB,MACpB,EAAE,UAAU,QAAQ,QAAQ,WAAW,aAAa;CACnD,gBAAgB;EACd,IAAI,QAAQ,oBAAoB,OAAO;EACvC,OAAO,uBAAuB;CAChC,GAAG,CAAC,QAAQ,eAAe,CAAC;CAE5B,MAAM,iBAAiB,UAAU;CACjC,MAAM,CAAC,mBAAmB,wBAAwB,eACzC,aAAa,CAAC,WAAW,SAAS,IAAI,YAAY,KAAA,CAC3D;CACA,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,cAAc;CACnE,MAAM,kBAAkB,OAAO,CAAC;CAEhC,gBAAgB;EACd,MAAM,YAAY,EAAE,gBAAgB;EAEpC,IAAI,CAAC,WAAW;GACd,qBAAqB,KAAA,CAAS;GAC9B,kBAAkB,cAAc;GAChC;EACF;EAEA,IAAI,WAAW,SAAS,GAAG;GACzB,MAAM,eAAe;GACrB,UACG,MAAM,kBAAkB;IACvB,IAAI,gBAAgB,YAAY,WAAW;IAC3C,qBAAqB,aAAa;IAClC,kBAAkB,YAAY;GAChC,CAAC,CAAC,CACD,YAAY;IACX,IAAI,gBAAgB,YAAY,WAAW;GAC7C,CAAC;GACH;EACF;EAEA,qBAAqB,SAAS;EAC9B,kBAAkB,cAAc;CAClC,GAAG,CAAC,gBAAgB,SAAS,CAAC;CAE9B,MAAM,mBAAmB,WAAW,SAAS,IAAI,oBAAoB;CACrE,MAAM,gBAAgB,WAAW,SAAS,IAAI,iBAAiB;CAE/D,MAAM,YAAY,cAAgC;EAChD,MAAM,eAAe,MAAM,QAAQ,gBAAgB,IAC/C,mBACA,mBACE,OAAO,OAAO,gBAAgB,IAC9B,CAAC;EACP,MAAM,kBAAkB,OAAO,OAAO,CAAC,GAAG,GAAG,YAAY;EACzD,MAAM,KAAK,QAAgC,gBAAgB,QAAQ;EACnE,OAAO;GAAE,QAAQ;GAAe;EAAE;CACpC,GAAG,CAAC,eAAe,gBAAgB,CAAC;CAEpC,OACE,oBAAC,qBAAD;EAAqB,OAAO;EAC1B,UAAA,oBAAC,eAAD;GAAe,OAAO,UAAU;GAC9B,UAAA,oBAAC,iBAAD;IAAiB,OAAO;IAAS;GAA0B,CAAA;EAC9C,CAAA;CACI,CAAA;AAEzB,CACF;AAKA,MAAM,eAAsB,EAAE,KAAK,SAAS,WAC1C,UAAU;CAAE;CAAM;CAAK,OAAO;CAAU;AAAQ,CAAC;AAEnD,MAAa,iBAAwB;CACnC,MAAM,SAAS,IAAI,aAAa;CAChC,IAAI,CAAC,QAAQ,OAAO;CACpB,IAAI,QAAQ,UAAU,UACpB,QAAQ,EAAE,KAAK,SAAS,WACtB,UAAU;EAAE;EAAM;EAAK,OAAO,OAAO;EAAc;CAAQ,CAAC;CAChE,OAAO,QAAQ,eAAe;AAChC;AAGA,MAAa,gBAAgB,IAAI,mBAAmB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/GlobalFocusRing/index.d.ts
|
|
2
|
+
/** Install once per document. The returned cleanup is safe for nested providers and Strict Mode. */
|
|
3
|
+
declare const installGlobalFocusRing: (doc?: Document) => (() => void);
|
|
4
|
+
//#endregion
|
|
5
|
+
export { installGlobalFocusRing };
|
|
6
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.d.mts';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.mjs';
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { globalFocusRingCSS } from "./style.mjs";
|
|
2
|
+
//#region src/GlobalFocusRing/index.ts
|
|
3
|
+
const installations = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
/** Install once per document. The returned cleanup is safe for nested providers and Strict Mode. */
|
|
5
|
+
const installGlobalFocusRing = (doc = document) => {
|
|
6
|
+
const existing = installations.get(doc);
|
|
7
|
+
if (existing) {
|
|
8
|
+
existing.users += 1;
|
|
9
|
+
let released = false;
|
|
10
|
+
return () => {
|
|
11
|
+
if (released) return;
|
|
12
|
+
released = true;
|
|
13
|
+
if (--existing.users === 0) existing.dispose();
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const win = doc.defaultView;
|
|
17
|
+
if (!win || !doc.body || !win.CSS?.supports("top", "anchor(top)") || !win.CSS.supports("position-visibility", "anchors-visible") || !("showPopover" in doc.createElement("div"))) return () => {};
|
|
18
|
+
const sheet = doc.createElement("style");
|
|
19
|
+
sheet.textContent = globalFocusRingCSS;
|
|
20
|
+
const ring = doc.createElement("div");
|
|
21
|
+
ring.setAttribute("data-lobe-global-focus-ring", "");
|
|
22
|
+
ring.setAttribute("aria-hidden", "true");
|
|
23
|
+
ring.setAttribute("popover", "manual");
|
|
24
|
+
doc.head.append(sheet);
|
|
25
|
+
doc.body.append(ring);
|
|
26
|
+
let target;
|
|
27
|
+
let restoreTarget;
|
|
28
|
+
let frame = 0;
|
|
29
|
+
let disposed = false;
|
|
30
|
+
const clear = () => {
|
|
31
|
+
if (ring.matches(":popover-open")) ring.hidePopover();
|
|
32
|
+
restoreTarget?.();
|
|
33
|
+
restoreTarget = void 0;
|
|
34
|
+
target = void 0;
|
|
35
|
+
};
|
|
36
|
+
const sync = () => {
|
|
37
|
+
if (disposed) return;
|
|
38
|
+
const next = doc.activeElement;
|
|
39
|
+
if (next === target && next?.matches(":focus-visible") && next.isConnected) return;
|
|
40
|
+
clear();
|
|
41
|
+
if (!next || next === doc.body || next.namespaceURI !== "http://www.w3.org/1999/xhtml" || next.shadowRoot || !next.matches(":focus-visible") || next.getClientRects().length !== 1) return;
|
|
42
|
+
const element = next;
|
|
43
|
+
const computed = win.getComputedStyle(element);
|
|
44
|
+
const rect = element.getBoundingClientRect();
|
|
45
|
+
if (!rect.width || !rect.height || computed.visibility !== "visible") return;
|
|
46
|
+
const saved = ["anchor-name", "outline"].map((property) => ({
|
|
47
|
+
priority: element.style.getPropertyPriority(property),
|
|
48
|
+
property,
|
|
49
|
+
value: element.style.getPropertyValue(property)
|
|
50
|
+
}));
|
|
51
|
+
const oldMarker = element.getAttribute("data-lobe-focus-ring");
|
|
52
|
+
const anchor = computed.getPropertyValue("anchor-name").trim();
|
|
53
|
+
const assignedAnchor = anchor && anchor !== "none" ? `${anchor}, --lobe-global-focus` : "--lobe-global-focus";
|
|
54
|
+
element.style.setProperty("anchor-name", assignedAnchor, "important");
|
|
55
|
+
ring.style.borderRadius = computed.borderRadius;
|
|
56
|
+
ring.style.setProperty("--lobe-focus-ring-color", computed.getPropertyValue("--lobe-focus-ring-color").trim() || computed.getPropertyValue("--ant-color-info").trim() || "#1677ff");
|
|
57
|
+
restoreTarget = () => {
|
|
58
|
+
for (const { property, value, priority } of saved) {
|
|
59
|
+
const assigned = property === "anchor-name" ? assignedAnchor : "none";
|
|
60
|
+
if (element.style.getPropertyValue(property) !== assigned) continue;
|
|
61
|
+
if (value) element.style.setProperty(property, value, priority);
|
|
62
|
+
else element.style.removeProperty(property);
|
|
63
|
+
}
|
|
64
|
+
if (element.getAttribute("data-lobe-focus-ring") === "managed") {
|
|
65
|
+
if (oldMarker === null) element.removeAttribute("data-lobe-focus-ring");
|
|
66
|
+
else element.setAttribute("data-lobe-focus-ring", oldMarker);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
try {
|
|
70
|
+
ring.showPopover();
|
|
71
|
+
const bounds = ring.getBoundingClientRect();
|
|
72
|
+
if (Math.max(...[
|
|
73
|
+
"top",
|
|
74
|
+
"right",
|
|
75
|
+
"bottom",
|
|
76
|
+
"left"
|
|
77
|
+
].map((edge) => Math.abs(bounds[edge] - rect[edge]))) > 1) {
|
|
78
|
+
clear();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
element.style.setProperty("outline", "none", "important");
|
|
82
|
+
element.setAttribute("data-lobe-focus-ring", "managed");
|
|
83
|
+
target = element;
|
|
84
|
+
} catch {
|
|
85
|
+
clear();
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const schedule = () => {
|
|
89
|
+
if (!frame) frame = win.requestAnimationFrame(() => {
|
|
90
|
+
frame = 0;
|
|
91
|
+
sync();
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
const blur = () => {
|
|
95
|
+
win.cancelAnimationFrame(frame);
|
|
96
|
+
frame = 0;
|
|
97
|
+
clear();
|
|
98
|
+
};
|
|
99
|
+
const observer = new MutationObserver(() => {
|
|
100
|
+
if (target && !target.isConnected) clear();
|
|
101
|
+
});
|
|
102
|
+
observer.observe(doc.body, {
|
|
103
|
+
childList: true,
|
|
104
|
+
subtree: true
|
|
105
|
+
});
|
|
106
|
+
doc.addEventListener("focusin", sync, true);
|
|
107
|
+
doc.addEventListener("focusout", schedule, true);
|
|
108
|
+
doc.addEventListener("keydown", schedule, true);
|
|
109
|
+
doc.addEventListener("pointerdown", schedule, true);
|
|
110
|
+
win.addEventListener("blur", blur);
|
|
111
|
+
win.addEventListener("focus", schedule);
|
|
112
|
+
installations.set(doc, {
|
|
113
|
+
dispose: () => {
|
|
114
|
+
disposed = true;
|
|
115
|
+
win.cancelAnimationFrame(frame);
|
|
116
|
+
observer.disconnect();
|
|
117
|
+
doc.removeEventListener("focusin", sync, true);
|
|
118
|
+
doc.removeEventListener("focusout", schedule, true);
|
|
119
|
+
doc.removeEventListener("keydown", schedule, true);
|
|
120
|
+
doc.removeEventListener("pointerdown", schedule, true);
|
|
121
|
+
win.removeEventListener("blur", blur);
|
|
122
|
+
win.removeEventListener("focus", schedule);
|
|
123
|
+
clear();
|
|
124
|
+
ring.remove();
|
|
125
|
+
sheet.remove();
|
|
126
|
+
installations.delete(doc);
|
|
127
|
+
},
|
|
128
|
+
users: 0
|
|
129
|
+
});
|
|
130
|
+
sync();
|
|
131
|
+
return installGlobalFocusRing(doc);
|
|
132
|
+
};
|
|
133
|
+
//#endregion
|
|
134
|
+
export { installGlobalFocusRing };
|
|
135
|
+
|
|
136
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/GlobalFocusRing/index.ts"],"sourcesContent":["import { globalFocusRingCSS } from './style';\n\nconst installations = new WeakMap<Document, { dispose: () => void; users: number }>();\n\n/** Install once per document. The returned cleanup is safe for nested providers and Strict Mode. */\nexport const installGlobalFocusRing = (doc: Document = document): (() => void) => {\n const existing = installations.get(doc);\n if (existing) {\n existing.users += 1;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n if (--existing.users === 0) existing.dispose();\n };\n }\n\n const win = doc.defaultView;\n if (\n !win ||\n !doc.body ||\n !win.CSS?.supports('top', 'anchor(top)') ||\n !win.CSS.supports('position-visibility', 'anchors-visible') ||\n !('showPopover' in doc.createElement('div'))\n )\n return () => {};\n\n const sheet = doc.createElement('style');\n sheet.textContent = globalFocusRingCSS;\n const ring = doc.createElement('div');\n ring.setAttribute('data-lobe-global-focus-ring', '');\n ring.setAttribute('aria-hidden', 'true');\n ring.setAttribute('popover', 'manual');\n doc.head.append(sheet);\n doc.body.append(ring);\n\n let target: HTMLElement | undefined;\n let restoreTarget: (() => void) | undefined;\n let frame = 0;\n let disposed = false;\n\n const clear = () => {\n if (ring.matches(':popover-open')) ring.hidePopover();\n restoreTarget?.();\n restoreTarget = undefined;\n target = undefined;\n };\n\n const sync = () => {\n if (disposed) return;\n const next = doc.activeElement;\n if (next === target && next?.matches(':focus-visible') && next.isConnected) return;\n clear();\n // Shadow roots and fragmented inline text retain their own focus treatment.\n if (\n !next ||\n next === doc.body ||\n next.namespaceURI !== 'http://www.w3.org/1999/xhtml' ||\n next.shadowRoot ||\n !next.matches(':focus-visible') ||\n next.getClientRects().length !== 1\n )\n return;\n\n const element = next as HTMLElement;\n const computed = win.getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n if (!rect.width || !rect.height || computed.visibility !== 'visible') return;\n\n const saved = ['anchor-name', 'outline'].map((property) => ({\n priority: element.style.getPropertyPriority(property),\n property,\n value: element.style.getPropertyValue(property),\n }));\n const oldMarker = element.getAttribute('data-lobe-focus-ring');\n const anchor = computed.getPropertyValue('anchor-name').trim();\n const assignedAnchor =\n anchor && anchor !== 'none' ? `${anchor}, --lobe-global-focus` : '--lobe-global-focus';\n element.style.setProperty('anchor-name', assignedAnchor, 'important');\n ring.style.borderRadius = computed.borderRadius;\n ring.style.setProperty(\n '--lobe-focus-ring-color',\n computed.getPropertyValue('--lobe-focus-ring-color').trim() ||\n computed.getPropertyValue('--ant-color-info').trim() ||\n '#1677ff',\n );\n\n restoreTarget = () => {\n for (const { property, value, priority } of saved) {\n const assigned = property === 'anchor-name' ? assignedAnchor : 'none';\n if (element.style.getPropertyValue(property) !== assigned) continue;\n if (value) element.style.setProperty(property, value, priority);\n else element.style.removeProperty(property);\n }\n if (element.getAttribute('data-lobe-focus-ring') === 'managed') {\n if (oldMarker === null) element.removeAttribute('data-lobe-focus-ring');\n else element.setAttribute('data-lobe-focus-ring', oldMarker);\n }\n };\n try {\n ring.showPopover();\n // Do not suppress a working native outline when an anchor cannot resolve.\n const bounds = ring.getBoundingClientRect();\n if (\n Math.max(\n ...(['top', 'right', 'bottom', 'left'] as const).map((edge) =>\n Math.abs(bounds[edge] - rect[edge]),\n ),\n ) > 1\n ) {\n clear();\n return;\n }\n element.style.setProperty('outline', 'none', 'important');\n element.setAttribute('data-lobe-focus-ring', 'managed');\n target = element;\n } catch {\n clear();\n }\n };\n\n const schedule = () => {\n if (!frame)\n frame = win.requestAnimationFrame(() => {\n frame = 0;\n sync();\n });\n };\n const blur = () => {\n win.cancelAnimationFrame(frame);\n frame = 0;\n clear();\n };\n const observer = new MutationObserver(() => {\n if (target && !target.isConnected) clear();\n });\n observer.observe(doc.body, { childList: true, subtree: true });\n doc.addEventListener('focusin', sync, true);\n doc.addEventListener('focusout', schedule, true);\n doc.addEventListener('keydown', schedule, true);\n doc.addEventListener('pointerdown', schedule, true);\n win.addEventListener('blur', blur);\n win.addEventListener('focus', schedule);\n\n const installation = {\n dispose: () => {\n disposed = true;\n win.cancelAnimationFrame(frame);\n observer.disconnect();\n doc.removeEventListener('focusin', sync, true);\n doc.removeEventListener('focusout', schedule, true);\n doc.removeEventListener('keydown', schedule, true);\n doc.removeEventListener('pointerdown', schedule, true);\n win.removeEventListener('blur', blur);\n win.removeEventListener('focus', schedule);\n clear();\n ring.remove();\n sheet.remove();\n installations.delete(doc);\n },\n users: 0,\n };\n installations.set(doc, installation);\n sync();\n return installGlobalFocusRing(doc);\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/GlobalFocusRing/style.ts
|
|
2
|
+
const focusRingColor = (color) => `color-mix(in srgb, ${color} 90%, transparent)`;
|
|
3
|
+
const globalFocusRingCSS = `
|
|
4
|
+
[data-lobe-global-focus-ring] {
|
|
5
|
+
all: initial;
|
|
6
|
+
position: fixed;
|
|
7
|
+
position-anchor: --lobe-global-focus;
|
|
8
|
+
top: anchor(top);
|
|
9
|
+
right: anchor(right);
|
|
10
|
+
bottom: anchor(bottom);
|
|
11
|
+
left: anchor(left);
|
|
12
|
+
position-visibility: anchors-visible;
|
|
13
|
+
pointer-events: none;
|
|
14
|
+
border-radius: inherit;
|
|
15
|
+
outline: 2px solid ${focusRingColor("var(--lobe-focus-ring-color)")};
|
|
16
|
+
outline-offset: 2px;
|
|
17
|
+
animation: lobe-global-focus-in 200ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
18
|
+
}
|
|
19
|
+
[data-lobe-global-focus-ring]:not(:popover-open) { display: none; }
|
|
20
|
+
[data-lobe-global-focus-ring]::backdrop { background: transparent; pointer-events: none; }
|
|
21
|
+
@keyframes lobe-global-focus-in {
|
|
22
|
+
from { opacity: 0.25; outline-offset: 5px; }
|
|
23
|
+
to { opacity: 1; outline-offset: 2px; }
|
|
24
|
+
}
|
|
25
|
+
@media (prefers-reduced-motion: reduce) {
|
|
26
|
+
[data-lobe-global-focus-ring] { animation: none; }
|
|
27
|
+
}
|
|
28
|
+
@media (forced-colors: active) {
|
|
29
|
+
[data-lobe-global-focus-ring] { outline-color: CanvasText; animation: none; }
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { focusRingColor, globalFocusRingCSS };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=style.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.mjs","names":[],"sources":["../../src/GlobalFocusRing/style.ts"],"sourcesContent":["export const focusRingColor = (color: string) => `color-mix(in srgb, ${color} 90%, transparent)`;\n\nexport const globalFocusRingCSS = `\n[data-lobe-global-focus-ring] {\n all: initial;\n position: fixed;\n position-anchor: --lobe-global-focus;\n top: anchor(top);\n right: anchor(right);\n bottom: anchor(bottom);\n left: anchor(left);\n position-visibility: anchors-visible;\n pointer-events: none;\n border-radius: inherit;\n outline: 2px solid ${focusRingColor('var(--lobe-focus-ring-color)')};\n outline-offset: 2px;\n animation: lobe-global-focus-in 200ms cubic-bezier(0.22, 1, 0.36, 1);\n}\n[data-lobe-global-focus-ring]:not(:popover-open) { display: none; }\n[data-lobe-global-focus-ring]::backdrop { background: transparent; pointer-events: none; }\n@keyframes lobe-global-focus-in {\n from { opacity: 0.25; outline-offset: 5px; }\n to { opacity: 1; outline-offset: 2px; }\n}\n@media (prefers-reduced-motion: reduce) {\n [data-lobe-global-focus-ring] { animation: none; }\n}\n@media (forced-colors: active) {\n [data-lobe-global-focus-ring] { outline-color: CanvasText; animation: none; }\n}\n`;\n"],"mappings":";AAAA,MAAa,kBAAkB,UAAkB,sBAAsB,MAAM;AAE7E,MAAa,qBAAqB;;;;;;;;;;;;uBAYX,eAAe,8BAA8B,EAAE"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { MotionComponent } from "../../MotionProvider/index.mjs";
|
|
3
2
|
import { useAppElement } from "../../ThemeProvider/AppElementContext.mjs";
|
|
4
3
|
import { useLayerZIndex } from "../../base-ui/zIndex/useLayerZIndex.mjs";
|
|
5
4
|
import { styles } from "../style.mjs";
|
|
@@ -13,9 +12,8 @@ import { readNatural, useGalleryNav } from "./useGalleryNav.mjs";
|
|
|
13
12
|
import { useRefitTransition } from "./useRefitTransition.mjs";
|
|
14
13
|
import { useZoomPan } from "./useZoomPan.mjs";
|
|
15
14
|
import ViewerChrome from "./ViewerChrome.mjs";
|
|
16
|
-
import { memo,
|
|
15
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
17
16
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
-
import { motion } from "motion/react";
|
|
19
17
|
import { useMergeRefs } from "react-merge-refs";
|
|
20
18
|
import { Dialog } from "@base-ui/react/dialog";
|
|
21
19
|
//#region src/Image/viewer/ImageViewer.tsx
|
|
@@ -27,8 +25,7 @@ const prefersReducedMotion = () => window.matchMedia?.("(prefers-reduced-motion:
|
|
|
27
25
|
const ImageViewer = memo(({ entries, index, openerFocusElement, token }) => {
|
|
28
26
|
const openerEntry = entries[index];
|
|
29
27
|
const appElement = useAppElement();
|
|
30
|
-
const
|
|
31
|
-
const [animated] = useState(() => !!motionComponent && !prefersReducedMotion());
|
|
28
|
+
const [animated] = useState(() => !prefersReducedMotion());
|
|
32
29
|
const { ref: layerRef, zIndex } = useLayerZIndex("modal");
|
|
33
30
|
const [currentIndex, setCurrentIndex] = useState(index);
|
|
34
31
|
const currentEntry = entries[currentIndex];
|
|
@@ -205,80 +202,77 @@ const ImageViewer = memo(({ entries, index, openerFocusElement, token }) => {
|
|
|
205
202
|
useEffect(() => () => {
|
|
206
203
|
if (!openerEntry.element.isConnected) endClosePreview(token);
|
|
207
204
|
}, [openerEntry, token]);
|
|
208
|
-
return /* @__PURE__ */ jsx(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
children:
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
/* @__PURE__ */ jsx(ToastHost, { root: appElement ?? void 0 })
|
|
280
|
-
]
|
|
281
|
-
})
|
|
205
|
+
return /* @__PURE__ */ jsx(Dialog.Root, {
|
|
206
|
+
modal: true,
|
|
207
|
+
open: true,
|
|
208
|
+
onOpenChange: handleDialogOpenChange,
|
|
209
|
+
children: /* @__PURE__ */ jsxs(Dialog.Portal, {
|
|
210
|
+
container: appElement ?? void 0,
|
|
211
|
+
children: [
|
|
212
|
+
/* @__PURE__ */ jsx(Dialog.Backdrop, {
|
|
213
|
+
forceRender: true,
|
|
214
|
+
className: styles.viewerBackdrop,
|
|
215
|
+
ref: backdropRef,
|
|
216
|
+
style: zIndex === void 0 ? void 0 : { zIndex },
|
|
217
|
+
onClick: gestures.onSurfaceClick
|
|
218
|
+
}),
|
|
219
|
+
/* @__PURE__ */ jsxs(Dialog.Popup, {
|
|
220
|
+
"aria-label": currentEntry.element.alt || void 0,
|
|
221
|
+
className: styles.viewerPopup,
|
|
222
|
+
finalFocus,
|
|
223
|
+
initialFocus: popupNodeRef,
|
|
224
|
+
ref: popupRef,
|
|
225
|
+
style: zIndex === void 0 ? void 0 : { zIndex: zIndex + 1 },
|
|
226
|
+
tabIndex: -1,
|
|
227
|
+
onClick: gestures.onSurfaceClick,
|
|
228
|
+
onPointerCancel: gestures.onPointerFinish,
|
|
229
|
+
onPointerDown: gestures.onPointerDown,
|
|
230
|
+
onPointerMove: gestures.onPointerMove,
|
|
231
|
+
onPointerUp: gestures.onPointerFinish,
|
|
232
|
+
children: [/* @__PURE__ */ jsx("img", {
|
|
233
|
+
alt: currentEntry.element.alt,
|
|
234
|
+
className: styles.viewerImage,
|
|
235
|
+
ref: imageRef,
|
|
236
|
+
src: source,
|
|
237
|
+
style: {
|
|
238
|
+
cursor: gestures.cursor,
|
|
239
|
+
height: imageRect.height,
|
|
240
|
+
left: imageRect.x,
|
|
241
|
+
top: imageRect.y,
|
|
242
|
+
width: imageRect.width
|
|
243
|
+
},
|
|
244
|
+
onClick: gestures.onImageClick,
|
|
245
|
+
onDoubleClick: gestures.onImageDoubleClick,
|
|
246
|
+
onLoad: handleLoad
|
|
247
|
+
}), /* @__PURE__ */ jsx(ViewerChrome, {
|
|
248
|
+
canZoomIn,
|
|
249
|
+
canZoomOut,
|
|
250
|
+
chromeRef,
|
|
251
|
+
current: currentIndex,
|
|
252
|
+
fitRect,
|
|
253
|
+
flipHorizontal,
|
|
254
|
+
flipVertical,
|
|
255
|
+
hasNext,
|
|
256
|
+
hasPrev,
|
|
257
|
+
natural,
|
|
258
|
+
next,
|
|
259
|
+
prev,
|
|
260
|
+
rotateLeft,
|
|
261
|
+
rotateRight,
|
|
262
|
+
rotation,
|
|
263
|
+
scale,
|
|
264
|
+
source,
|
|
265
|
+
toggleActualSize,
|
|
266
|
+
toolbarAddon: currentEntry.options.toolbarAddon,
|
|
267
|
+
total: entries.length,
|
|
268
|
+
zoomIn,
|
|
269
|
+
zoomOut,
|
|
270
|
+
onClose: handleClose,
|
|
271
|
+
onDownload: currentEntry.options.onDownload
|
|
272
|
+
})]
|
|
273
|
+
}),
|
|
274
|
+
/* @__PURE__ */ jsx(ToastHost, { root: appElement ?? void 0 })
|
|
275
|
+
]
|
|
282
276
|
})
|
|
283
277
|
});
|
|
284
278
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageViewer.mjs","names":[],"sources":["../../../src/Image/viewer/ImageViewer.tsx"],"sourcesContent":["'use client';\n\nimport { Dialog, type DialogRootProps } from '@base-ui/react/dialog';\nimport { motion } from 'motion/react';\nimport {\n memo,\n type SyntheticEvent,\n use,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useMergeRefs } from 'react-merge-refs';\n\nimport { ToastHost } from '@/base-ui/Toast';\nimport { useLayerZIndex } from '@/base-ui/zIndex';\nimport { MotionComponent } from '@/MotionProvider';\nimport { useAppElement } from '@/ThemeProvider';\n\nimport { styles } from '../style';\nimport { computeFit, type Size, unrotatedRect } from './geometry';\nimport { beginClosePreview, endClosePreview, type PreviewEntry } from './registry';\nimport { useFinalFocus } from './useFinalFocus';\nimport { useFlipTransition } from './useFlipTransition';\nimport { readNatural, useGalleryNav } from './useGalleryNav';\nimport { useRefitTransition } from './useRefitTransition';\nimport { useViewerGestures } from './useViewerGestures';\nimport { useZoomPan } from './useZoomPan';\nimport ViewerChrome from './ViewerChrome';\n\nexport interface ImageViewerProps {\n entries: PreviewEntry[];\n index: number;\n openerFocusElement: HTMLElement | null;\n token: number;\n}\n\nconst readViewport = (): Size => ({ height: window.innerHeight, width: window.innerWidth });\n\nconst prefersReducedMotion = () =>\n window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;\n\nconst ImageViewer = memo<ImageViewerProps>(({ entries, index, openerFocusElement, token }) => {\n const openerEntry = entries[index];\n const appElement = useAppElement();\n const motionComponent = use(MotionComponent);\n const [animated] = useState(() => !!motionComponent && !prefersReducedMotion());\n\n const { ref: layerRef, zIndex } = useLayerZIndex<HTMLDivElement>('modal');\n\n const [currentIndex, setCurrentIndex] = useState(index);\n const currentEntry = entries[currentIndex];\n const currentEntryRef = useRef(currentEntry);\n currentEntryRef.current = currentEntry;\n\n const [source, setSource] = useState(openerEntry.src);\n const [natural, setNatural] = useState<Size>(() => readNatural(openerEntry.element));\n const [viewport, setViewport] = useState<Size>(readViewport);\n\n const closeRef = useRef<(() => void) | null>(null);\n const requestClose = useCallback(() => closeRef.current?.(), []);\n\n // useZoomPan needs to gate its wheel/toolbar entry points on close-in-flight,\n // but that state only exists once useFlipTransition (below) has run — and it\n // needs useZoomPan's own transform values first. Break the cycle with a\n // stable indirection: the ref is repointed at the real isClosing once it's\n // available, written directly during render like the other *Ref fields here.\n const isClosingIndirectRef = useRef<() => boolean>(() => false);\n const isClosingIndirect = useCallback(() => isClosingIndirectRef.current(), []);\n\n const isTransitioningIndirectRef = useRef<() => boolean>(() => true);\n const isTransitioningIndirect = useCallback(() => isTransitioningIndirectRef.current(), []);\n\n const fillViewport = Boolean(\n currentEntry.previewSrc && currentEntry.previewSrc !== currentEntry.src,\n );\n\n const {\n canZoomIn,\n canZoomOut,\n dragBy,\n dragEnd,\n escIntent,\n flipHorizontal,\n flipVertical,\n flipX,\n flipY,\n getInitialScale,\n handleDoubleClick,\n handleWheel,\n isClean,\n isZoomed,\n reset,\n resetCloseTracking,\n rotate,\n rotateLeft,\n rotateRight,\n rotation,\n scale,\n setNatural: syncZoomNatural,\n setViewport: syncZoomViewport,\n toggleActualSize,\n x,\n y,\n zoomIn,\n zoomOut,\n } = useZoomPan({\n autoZoomThreshold: currentEntry.options.autoZoomThreshold,\n defaultZoom: currentEntry.options.defaultZoom,\n fillViewport,\n isClosing: isClosingIndirect,\n isTransitioning: isTransitioningIndirect,\n maxScale: currentEntry.options.maxScale,\n natural,\n onCloseRequest: requestClose,\n viewport,\n });\n\n const fitRect = useMemo(\n () => computeFit(natural, viewport, rotation, fillViewport),\n [natural, viewport, rotation, fillViewport],\n );\n const fitRectRef = useRef(fitRect);\n fitRectRef.current = fitRect;\n const getFitRect = useCallback(() => fitRectRef.current, []);\n\n const imageRect = useMemo(() => unrotatedRect(fitRect, rotation), [fitRect, rotation]);\n\n const viewportRef = useRef(viewport);\n viewportRef.current = viewport;\n const getViewportWidth = useCallback(() => viewportRef.current.width, []);\n\n const getCloseSource = useCallback(() => currentEntryRef.current.element, []);\n\n const transform = useMemo(\n () => ({ flipX, flipY, rotate, scale, x, y }),\n [flipX, flipY, rotate, scale, x, y],\n );\n const handleClosed = useCallback(() => endClosePreview(token), [token]);\n\n const {\n backdropRef,\n chromeRef,\n close,\n imageRef: flipImageRef,\n isClosing,\n isTransitioning,\n switchTo,\n } = useFlipTransition({\n animated,\n getCloseSource,\n getFitRect,\n getInitialScale,\n getViewportWidth,\n onClosed: handleClosed,\n source: openerEntry.element,\n transform,\n });\n isClosingIndirectRef.current = isClosing;\n isTransitioningIndirectRef.current = isTransitioning;\n\n useRefitTransition({\n animated,\n fillViewport,\n isTransitioning,\n natural,\n rotation,\n scale,\n viewport,\n x,\n y,\n });\n const finalFocus = useFinalFocus(openerFocusElement);\n\n const isCleanRef = useRef(isClean);\n isCleanRef.current = isClean;\n\n const handleClose = useCallback(() => {\n beginClosePreview(token);\n close({ fade: !isCleanRef.current });\n }, [close, token]);\n closeRef.current = handleClose;\n\n const handleDialogOpenChange = useCallback<NonNullable<DialogRootProps['onOpenChange']>>(\n (open, eventDetails) => {\n if (open) return;\n // Base UI fires this on every Esc regardless of whether we're already\n // mid-close (our Dialog.Root's open prop never actually flips to\n // false), so without this guard a second Esc during the close window\n // reads escIntent() off the close spring's mid-flight scale, decides\n // 'reset', and cancels the close animation out from under itself.\n if (isClosing()) return;\n if (eventDetails.reason === 'escape-key' && escIntent() === 'reset') {\n eventDetails.cancel();\n reset();\n return;\n }\n handleClose();\n },\n [escIntent, handleClose, isClosing, reset],\n );\n\n const gestures = useViewerGestures({\n dragBy,\n dragEnd,\n handleDoubleClick,\n handleWheel,\n isClean,\n isZoomed,\n onClose: handleClose,\n reset,\n zoomIn,\n zoomOut,\n });\n\n const { hasNext, hasPrev, next, prev } = useGalleryNav({\n cancelPendingClose: gestures.cancelPendingClose,\n currentIndex,\n entries,\n flipX,\n flipY,\n getInitialScale,\n resetCloseTracking,\n rotate,\n scale,\n setCurrentIndex,\n setNatural,\n setSource,\n switchTo,\n syncZoomNatural,\n x,\n y,\n });\n\n const popupNodeRef = useRef<HTMLDivElement | null>(null);\n const popupRef = useMergeRefs<HTMLDivElement>([layerRef, gestures.popupRef, popupNodeRef]);\n const imageRef = useMergeRefs<HTMLImageElement>([flipImageRef, gestures.imageRef]);\n\n const handleLoad = useCallback(\n (event: SyntheticEvent<HTMLImageElement>) => {\n const loaded = event.currentTarget;\n if (!loaded.naturalWidth || !loaded.naturalHeight) return;\n const next = { height: loaded.naturalHeight, width: loaded.naturalWidth };\n setNatural((prev) =>\n prev.width === next.width && prev.height === next.height ? prev : next,\n );\n syncZoomNatural(next);\n },\n [syncZoomNatural],\n );\n\n useEffect(() => {\n const handleResize = () => {\n const next = readViewport();\n setViewport(next);\n syncZoomViewport(next);\n };\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [syncZoomViewport]);\n\n useEffect(() => {\n const { previewSrc, src } = currentEntry;\n if (!previewSrc || previewSrc === src) return;\n let cancelled = false;\n const loader = new window.Image();\n const handleLoaded = () => {\n if (!cancelled) setSource(previewSrc);\n };\n loader.addEventListener('load', handleLoaded);\n loader.src = previewSrc;\n return () => {\n cancelled = true;\n loader.removeEventListener('load', handleLoaded);\n };\n }, [currentEntry]);\n\n useEffect(\n () => () => {\n const thumbnailWasRemoved = !openerEntry.element.isConnected;\n if (thumbnailWasRemoved) endClosePreview(token);\n },\n [openerEntry, token],\n );\n\n return (\n // The chrome is built from Base UI controls, which need a motion component to\n // render at all. The viewer itself still degrades to a plain fade without one —\n // `animated` stays false — but the toolbar has no such fallback, so an app that\n // skipped ConfigProvider gets motion here rather than a crash.\n <MotionComponent value={motionComponent ?? motion}>\n <Dialog.Root modal open onOpenChange={handleDialogOpenChange}>\n <Dialog.Portal container={appElement ?? undefined}>\n {/* Base UI drops a nested dialog's backdrop so overlays don't stack. The viewer is\n not an overlay on the surface it opened from — it replaces the screen — so it\n keeps its own scrim, or a viewer opened from a maskless drawer would show the\n page straight through the letterbox around the image. */}\n <Dialog.Backdrop\n forceRender\n className={styles.viewerBackdrop}\n ref={backdropRef}\n style={zIndex === undefined ? undefined : { zIndex }}\n onClick={gestures.onSurfaceClick}\n />\n <Dialog.Popup\n aria-label={currentEntry.element.alt || undefined}\n className={styles.viewerPopup}\n finalFocus={finalFocus}\n // Focus the popup itself instead of Base UI's default (the first\n // tabbable — the close button): a focus-visible close button pins\n // the idle auto-hide open forever and pops its tooltip on open.\n initialFocus={popupNodeRef}\n ref={popupRef}\n style={zIndex === undefined ? undefined : { zIndex: zIndex + 1 }}\n tabIndex={-1}\n onClick={gestures.onSurfaceClick}\n onPointerCancel={gestures.onPointerFinish}\n onPointerDown={gestures.onPointerDown}\n onPointerMove={gestures.onPointerMove}\n onPointerUp={gestures.onPointerFinish}\n >\n <img\n alt={currentEntry.element.alt}\n className={styles.viewerImage}\n ref={imageRef}\n src={source}\n style={{\n cursor: gestures.cursor,\n height: imageRect.height,\n left: imageRect.x,\n top: imageRect.y,\n width: imageRect.width,\n }}\n onClick={gestures.onImageClick}\n onDoubleClick={gestures.onImageDoubleClick}\n onLoad={handleLoad}\n />\n <ViewerChrome\n canZoomIn={canZoomIn}\n canZoomOut={canZoomOut}\n chromeRef={chromeRef}\n current={currentIndex}\n fitRect={fitRect}\n flipHorizontal={flipHorizontal}\n flipVertical={flipVertical}\n hasNext={hasNext}\n hasPrev={hasPrev}\n natural={natural}\n next={next}\n prev={prev}\n rotateLeft={rotateLeft}\n rotateRight={rotateRight}\n rotation={rotation}\n scale={scale}\n source={source}\n toggleActualSize={toggleActualSize}\n toolbarAddon={currentEntry.options.toolbarAddon}\n total={entries.length}\n zoomIn={zoomIn}\n zoomOut={zoomOut}\n onClose={handleClose}\n onDownload={currentEntry.options.onDownload}\n />\n </Dialog.Popup>\n <ToastHost root={appElement ?? undefined} />\n </Dialog.Portal>\n </Dialog.Root>\n </MotionComponent>\n );\n});\n\nImageViewer.displayName = 'ImageViewer';\n\nexport default ImageViewer;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ImageViewer.mjs","names":[],"sources":["../../../src/Image/viewer/ImageViewer.tsx"],"sourcesContent":["'use client';\n\nimport { Dialog, type DialogRootProps } from '@base-ui/react/dialog';\nimport {\n memo,\n type SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useMergeRefs } from 'react-merge-refs';\n\nimport { ToastHost } from '@/base-ui/Toast';\nimport { useLayerZIndex } from '@/base-ui/zIndex';\nimport { useAppElement } from '@/ThemeProvider';\n\nimport { styles } from '../style';\nimport { computeFit, type Size, unrotatedRect } from './geometry';\nimport { beginClosePreview, endClosePreview, type PreviewEntry } from './registry';\nimport { useFinalFocus } from './useFinalFocus';\nimport { useFlipTransition } from './useFlipTransition';\nimport { readNatural, useGalleryNav } from './useGalleryNav';\nimport { useRefitTransition } from './useRefitTransition';\nimport { useViewerGestures } from './useViewerGestures';\nimport { useZoomPan } from './useZoomPan';\nimport ViewerChrome from './ViewerChrome';\n\nexport interface ImageViewerProps {\n entries: PreviewEntry[];\n index: number;\n openerFocusElement: HTMLElement | null;\n token: number;\n}\n\nconst readViewport = (): Size => ({ height: window.innerHeight, width: window.innerWidth });\n\nconst prefersReducedMotion = () =>\n window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;\n\nconst ImageViewer = memo<ImageViewerProps>(({ entries, index, openerFocusElement, token }) => {\n const openerEntry = entries[index];\n const appElement = useAppElement();\n const [animated] = useState(() => !prefersReducedMotion());\n\n const { ref: layerRef, zIndex } = useLayerZIndex<HTMLDivElement>('modal');\n\n const [currentIndex, setCurrentIndex] = useState(index);\n const currentEntry = entries[currentIndex];\n const currentEntryRef = useRef(currentEntry);\n currentEntryRef.current = currentEntry;\n\n const [source, setSource] = useState(openerEntry.src);\n const [natural, setNatural] = useState<Size>(() => readNatural(openerEntry.element));\n const [viewport, setViewport] = useState<Size>(readViewport);\n\n const closeRef = useRef<(() => void) | null>(null);\n const requestClose = useCallback(() => closeRef.current?.(), []);\n\n // useZoomPan needs to gate its wheel/toolbar entry points on close-in-flight,\n // but that state only exists once useFlipTransition (below) has run — and it\n // needs useZoomPan's own transform values first. Break the cycle with a\n // stable indirection: the ref is repointed at the real isClosing once it's\n // available, written directly during render like the other *Ref fields here.\n const isClosingIndirectRef = useRef<() => boolean>(() => false);\n const isClosingIndirect = useCallback(() => isClosingIndirectRef.current(), []);\n\n const isTransitioningIndirectRef = useRef<() => boolean>(() => true);\n const isTransitioningIndirect = useCallback(() => isTransitioningIndirectRef.current(), []);\n\n const fillViewport = Boolean(\n currentEntry.previewSrc && currentEntry.previewSrc !== currentEntry.src,\n );\n\n const {\n canZoomIn,\n canZoomOut,\n dragBy,\n dragEnd,\n escIntent,\n flipHorizontal,\n flipVertical,\n flipX,\n flipY,\n getInitialScale,\n handleDoubleClick,\n handleWheel,\n isClean,\n isZoomed,\n reset,\n resetCloseTracking,\n rotate,\n rotateLeft,\n rotateRight,\n rotation,\n scale,\n setNatural: syncZoomNatural,\n setViewport: syncZoomViewport,\n toggleActualSize,\n x,\n y,\n zoomIn,\n zoomOut,\n } = useZoomPan({\n autoZoomThreshold: currentEntry.options.autoZoomThreshold,\n defaultZoom: currentEntry.options.defaultZoom,\n fillViewport,\n isClosing: isClosingIndirect,\n isTransitioning: isTransitioningIndirect,\n maxScale: currentEntry.options.maxScale,\n natural,\n onCloseRequest: requestClose,\n viewport,\n });\n\n const fitRect = useMemo(\n () => computeFit(natural, viewport, rotation, fillViewport),\n [natural, viewport, rotation, fillViewport],\n );\n const fitRectRef = useRef(fitRect);\n fitRectRef.current = fitRect;\n const getFitRect = useCallback(() => fitRectRef.current, []);\n\n const imageRect = useMemo(() => unrotatedRect(fitRect, rotation), [fitRect, rotation]);\n\n const viewportRef = useRef(viewport);\n viewportRef.current = viewport;\n const getViewportWidth = useCallback(() => viewportRef.current.width, []);\n\n const getCloseSource = useCallback(() => currentEntryRef.current.element, []);\n\n const transform = useMemo(\n () => ({ flipX, flipY, rotate, scale, x, y }),\n [flipX, flipY, rotate, scale, x, y],\n );\n const handleClosed = useCallback(() => endClosePreview(token), [token]);\n\n const {\n backdropRef,\n chromeRef,\n close,\n imageRef: flipImageRef,\n isClosing,\n isTransitioning,\n switchTo,\n } = useFlipTransition({\n animated,\n getCloseSource,\n getFitRect,\n getInitialScale,\n getViewportWidth,\n onClosed: handleClosed,\n source: openerEntry.element,\n transform,\n });\n isClosingIndirectRef.current = isClosing;\n isTransitioningIndirectRef.current = isTransitioning;\n\n useRefitTransition({\n animated,\n fillViewport,\n isTransitioning,\n natural,\n rotation,\n scale,\n viewport,\n x,\n y,\n });\n const finalFocus = useFinalFocus(openerFocusElement);\n\n const isCleanRef = useRef(isClean);\n isCleanRef.current = isClean;\n\n const handleClose = useCallback(() => {\n beginClosePreview(token);\n close({ fade: !isCleanRef.current });\n }, [close, token]);\n closeRef.current = handleClose;\n\n const handleDialogOpenChange = useCallback<NonNullable<DialogRootProps['onOpenChange']>>(\n (open, eventDetails) => {\n if (open) return;\n // Base UI fires this on every Esc regardless of whether we're already\n // mid-close (our Dialog.Root's open prop never actually flips to\n // false), so without this guard a second Esc during the close window\n // reads escIntent() off the close spring's mid-flight scale, decides\n // 'reset', and cancels the close animation out from under itself.\n if (isClosing()) return;\n if (eventDetails.reason === 'escape-key' && escIntent() === 'reset') {\n eventDetails.cancel();\n reset();\n return;\n }\n handleClose();\n },\n [escIntent, handleClose, isClosing, reset],\n );\n\n const gestures = useViewerGestures({\n dragBy,\n dragEnd,\n handleDoubleClick,\n handleWheel,\n isClean,\n isZoomed,\n onClose: handleClose,\n reset,\n zoomIn,\n zoomOut,\n });\n\n const { hasNext, hasPrev, next, prev } = useGalleryNav({\n cancelPendingClose: gestures.cancelPendingClose,\n currentIndex,\n entries,\n flipX,\n flipY,\n getInitialScale,\n resetCloseTracking,\n rotate,\n scale,\n setCurrentIndex,\n setNatural,\n setSource,\n switchTo,\n syncZoomNatural,\n x,\n y,\n });\n\n const popupNodeRef = useRef<HTMLDivElement | null>(null);\n const popupRef = useMergeRefs<HTMLDivElement>([layerRef, gestures.popupRef, popupNodeRef]);\n const imageRef = useMergeRefs<HTMLImageElement>([flipImageRef, gestures.imageRef]);\n\n const handleLoad = useCallback(\n (event: SyntheticEvent<HTMLImageElement>) => {\n const loaded = event.currentTarget;\n if (!loaded.naturalWidth || !loaded.naturalHeight) return;\n const next = { height: loaded.naturalHeight, width: loaded.naturalWidth };\n setNatural((prev) =>\n prev.width === next.width && prev.height === next.height ? prev : next,\n );\n syncZoomNatural(next);\n },\n [syncZoomNatural],\n );\n\n useEffect(() => {\n const handleResize = () => {\n const next = readViewport();\n setViewport(next);\n syncZoomViewport(next);\n };\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [syncZoomViewport]);\n\n useEffect(() => {\n const { previewSrc, src } = currentEntry;\n if (!previewSrc || previewSrc === src) return;\n let cancelled = false;\n const loader = new window.Image();\n const handleLoaded = () => {\n if (!cancelled) setSource(previewSrc);\n };\n loader.addEventListener('load', handleLoaded);\n loader.src = previewSrc;\n return () => {\n cancelled = true;\n loader.removeEventListener('load', handleLoaded);\n };\n }, [currentEntry]);\n\n useEffect(\n () => () => {\n const thumbnailWasRemoved = !openerEntry.element.isConnected;\n if (thumbnailWasRemoved) endClosePreview(token);\n },\n [openerEntry, token],\n );\n\n return (\n <Dialog.Root modal open onOpenChange={handleDialogOpenChange}>\n <Dialog.Portal container={appElement ?? undefined}>\n {/* Base UI drops a nested dialog's backdrop so overlays don't stack. The viewer is\n not an overlay on the surface it opened from — it replaces the screen — so it\n keeps its own scrim, or a viewer opened from a maskless drawer would show the\n page straight through the letterbox around the image. */}\n <Dialog.Backdrop\n forceRender\n className={styles.viewerBackdrop}\n ref={backdropRef}\n style={zIndex === undefined ? undefined : { zIndex }}\n onClick={gestures.onSurfaceClick}\n />\n <Dialog.Popup\n aria-label={currentEntry.element.alt || undefined}\n className={styles.viewerPopup}\n finalFocus={finalFocus}\n // Focus the popup itself instead of Base UI's default (the first\n // tabbable — the close button): a focus-visible close button pins\n // the idle auto-hide open forever and pops its tooltip on open.\n initialFocus={popupNodeRef}\n ref={popupRef}\n style={zIndex === undefined ? undefined : { zIndex: zIndex + 1 }}\n tabIndex={-1}\n onClick={gestures.onSurfaceClick}\n onPointerCancel={gestures.onPointerFinish}\n onPointerDown={gestures.onPointerDown}\n onPointerMove={gestures.onPointerMove}\n onPointerUp={gestures.onPointerFinish}\n >\n <img\n alt={currentEntry.element.alt}\n className={styles.viewerImage}\n ref={imageRef}\n src={source}\n style={{\n cursor: gestures.cursor,\n height: imageRect.height,\n left: imageRect.x,\n top: imageRect.y,\n width: imageRect.width,\n }}\n onClick={gestures.onImageClick}\n onDoubleClick={gestures.onImageDoubleClick}\n onLoad={handleLoad}\n />\n <ViewerChrome\n canZoomIn={canZoomIn}\n canZoomOut={canZoomOut}\n chromeRef={chromeRef}\n current={currentIndex}\n fitRect={fitRect}\n flipHorizontal={flipHorizontal}\n flipVertical={flipVertical}\n hasNext={hasNext}\n hasPrev={hasPrev}\n natural={natural}\n next={next}\n prev={prev}\n rotateLeft={rotateLeft}\n rotateRight={rotateRight}\n rotation={rotation}\n scale={scale}\n source={source}\n toggleActualSize={toggleActualSize}\n toolbarAddon={currentEntry.options.toolbarAddon}\n total={entries.length}\n zoomIn={zoomIn}\n zoomOut={zoomOut}\n onClose={handleClose}\n onDownload={currentEntry.options.onDownload}\n />\n </Dialog.Popup>\n <ToastHost root={appElement ?? undefined} />\n </Dialog.Portal>\n </Dialog.Root>\n );\n});\n\nImageViewer.displayName = 'ImageViewer';\n\nexport default ImageViewer;\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { useMotionComponent } from "../../MotionProvider/index.mjs";
|
|
2
3
|
import ActionIcon from "../ActionIcon/ActionIcon.mjs";
|
|
3
4
|
import { DraggablePanelContext, useDraggablePanelContext } from "./context.mjs";
|
|
4
5
|
import { AXES } from "./core/axes.mjs";
|
|
@@ -10,7 +11,7 @@ import { BOW, handleVariants, rootVariants, styles, toggleVariants } from "./sty
|
|
|
10
11
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
11
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
13
|
import { cx } from "antd-style";
|
|
13
|
-
import {
|
|
14
|
+
import { useTransform } from "motion/react";
|
|
14
15
|
import useMergeState from "use-merge-value";
|
|
15
16
|
import { ChevronLeft } from "lucide-react";
|
|
16
17
|
//#region src/base-ui/DraggablePanel/atoms.tsx
|
|
@@ -140,12 +141,13 @@ const DraggablePanelRoot = memo(({ backgroundColor, children, className, collaps
|
|
|
140
141
|
});
|
|
141
142
|
DraggablePanelRoot.displayName = "DraggablePanelRoot";
|
|
142
143
|
const DraggablePanelContent = memo(({ children, className, style, ...rest }) => {
|
|
144
|
+
const Motion = useMotionComponent();
|
|
143
145
|
const { axis, controller, expand, placement, state } = useDraggablePanelContext();
|
|
144
146
|
const extent = useTransform(controller.motion.size, (value) => Math.max(0, value));
|
|
145
147
|
const target = useStore(controller.subscribe, () => controller.target);
|
|
146
148
|
const clipping = state.dragging || state.folding || target === 0;
|
|
147
149
|
const shrunk = state.collapsing || !expand;
|
|
148
|
-
return /* @__PURE__ */ jsx(
|
|
150
|
+
return /* @__PURE__ */ jsx(Motion.div, {
|
|
149
151
|
inert: !expand,
|
|
150
152
|
style: {
|
|
151
153
|
display: "flex",
|
|
@@ -156,7 +158,7 @@ const DraggablePanelContent = memo(({ children, className, style, ...rest }) =>
|
|
|
156
158
|
[axis.cross]: "100%",
|
|
157
159
|
[axis.extent]: extent
|
|
158
160
|
},
|
|
159
|
-
children: /* @__PURE__ */ jsx(
|
|
161
|
+
children: /* @__PURE__ */ jsx(Motion.div, {
|
|
160
162
|
animate: { scale: shrunk ? COLLAPSED_SCALE : 1 },
|
|
161
163
|
className: cx(styles.content, className),
|
|
162
164
|
transition: timing(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atoms.mjs","names":["useControlledState","getHandleSize"],"sources":["../../../src/base-ui/DraggablePanel/atoms.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { ChevronLeft } from 'lucide-react';\nimport type { HTMLMotionProps, MotionStyle } from 'motion/react';\nimport { motion, useTransform } from 'motion/react';\nimport {\n type CSSProperties,\n memo,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport ActionIcon from '@/base-ui/ActionIcon';\nimport type { DivProps } from '@/types';\n\nimport { DraggablePanelContext, useDraggablePanelContext } from './context';\nimport type { Placement } from './core/axes';\nimport { AXES } from './core/axes';\nimport type { PanelControllerOptions } from './core/controller';\nimport { createPanelController } from './core/controller';\nimport { coarsePointer, handleSize as getHandleSize } from './core/env';\nimport { useIsomorphicLayoutEffect, useStore } from './core/internal';\nimport { timing } from './core/transition';\nimport { BOW, handleVariants, rootVariants, styles, toggleVariants } from './style';\n\nconst PAN_THRESHOLD = 3;\n\nconst BOW_CX = 15;\nconst BOW_CY = BOW.half + 8;\nconst BOW_W = BOW_CX * 2;\nconst BOW_H = BOW_CY * 2;\n\nconst bowPath = (direction: 1 | -1, verticalSeam: boolean) => {\n const k = BOW.half * BOW.curve;\n const b = BOW_CX + BOW.bulge * direction;\n const a0 = BOW_CY - BOW.half;\n const a1 = BOW_CY + BOW.half;\n // `a` runs along the seam, `b` across it; a horizontal seam swaps the two.\n const pt = (along: number, across: number) =>\n verticalSeam ? `${along} ${across}` : `${across} ${along}`;\n return [\n `M${pt(BOW_CX, a0)}`,\n `C${pt(BOW_CX, a0 + k)} ${pt(b, BOW_CY - k)} ${pt(b, BOW_CY)}`,\n `C${pt(b, BOW_CY + k)} ${pt(BOW_CX, a1 - k)} ${pt(BOW_CX, a1)}`,\n ].join(' ');\n};\n\nconst BOW_PATHS = {\n horizontalSeam: [bowPath(-1, false), bowPath(1, false)],\n verticalSeam: [bowPath(-1, true), bowPath(1, true)],\n};\n\n/** The chevron points the way a click moves the panel. */\nconst CHEVRON_TURN = { bottom: 270, left: 0, right: 180, top: 90 } as const;\n\nconst chevronPath = (cx: number, cy: number) =>\n `M${cx + 2.4} ${cy - 4.8} L${cx - 2.4} ${cy} L${cx + 2.4} ${cy + 4.8}`;\n\nconst ORIGIN_MAP = {\n bottom: 'center bottom',\n left: 'left center',\n right: 'right center',\n top: 'center top',\n} as const;\n\nconst COLLAPSED_SCALE = 0.97;\n\nconst EDGE_INSET = {\n bottom: 'insetBlockEnd',\n left: 'insetInlineStart',\n right: 'insetInlineEnd',\n top: 'insetBlockStart',\n} as const;\n\nexport interface DraggablePanelRootProps extends Omit<DivProps, 'onDrag'> {\n backgroundColor?: string;\n collapseThreshold?: number;\n defaultExpand?: boolean;\n defaultSize?: number;\n expand?: boolean;\n expandable?: boolean;\n max?: number;\n min?: number;\n mode?: 'fixed' | 'float';\n onExpandChange?: (expand: boolean) => void;\n onSizeChange?: (size: number, delta: number) => void;\n onSizeDragging?: (size: number, delta: number) => void;\n placement?: Placement;\n showBorder?: boolean;\n size?: number;\n}\n\nexport const DraggablePanelRoot = memo<DraggablePanelRootProps>(\n ({\n backgroundColor,\n children,\n className,\n collapseThreshold,\n defaultExpand = true,\n defaultSize,\n expand,\n expandable = true,\n max,\n min = 0,\n mode = 'fixed',\n onExpandChange,\n onSizeChange,\n onSizeDragging,\n placement = 'right',\n showBorder = true,\n size,\n style,\n ...rest\n }) => {\n const axis = AXES[placement];\n const fallbackSize = axis.vertical ? 180 : 280;\n const resolvedDefaultSize = defaultSize ?? fallbackSize;\n\n const [isExpand, setIsExpand] = useControlledState(defaultExpand, {\n onChange: onExpandChange,\n value: expand,\n });\n const [innerSize, setInnerSize] = useState(resolvedDefaultSize);\n const currentSize = size ?? innerSize;\n\n const commitSize = useCallback(\n (next: number, delta: number) => {\n if (size === undefined) setInnerSize(next);\n onSizeChange?.(next, delta);\n },\n [onSizeChange, size],\n );\n\n const options: PanelControllerOptions = {\n collapseThreshold,\n defaultSize: resolvedDefaultSize,\n expand: isExpand,\n max,\n min,\n onExpandChange: setIsExpand,\n onSizeChange: commitSize,\n onSizeDragging,\n placement,\n size: currentSize,\n };\n\n const [controller] = useState(() => createPanelController(options));\n const state = useStore(controller.subscribe, () => controller.state);\n const elementRef = useRef<HTMLElement>(null);\n\n useIsomorphicLayoutEffect(() => {\n controller.sync(options);\n });\n\n useIsomorphicLayoutEffect(() => {\n const node = elementRef.current;\n return node ? controller.attach(node) : undefined;\n }, [controller]);\n\n const toggleExpand = useCallback(() => {\n if (expandable) setIsExpand(!isExpand);\n }, [expandable, isExpand, setIsExpand]);\n\n const context = useMemo(\n () => ({\n axis,\n controller,\n expand: isExpand,\n expandable,\n placement,\n showBorder,\n state,\n toggleExpand,\n }),\n [axis, controller, isExpand, expandable, placement, showBorder, state, toggleExpand],\n );\n\n return (\n <DraggablePanelContext value={context}>\n <aside\n className={cx(rootVariants({ mode, placement }), className)}\n data-expand={isExpand}\n data-expandable={expandable}\n data-resizing={state.dragging}\n ref={elementRef}\n style={\n {\n '--draggable-panel-bg': backgroundColor || '',\n 'flexDirection': axis.vertical ? 'column' : 'row',\n ...style,\n } as CSSProperties\n }\n {...rest}\n >\n {children}\n </aside>\n </DraggablePanelContext>\n );\n },\n);\n\nDraggablePanelRoot.displayName = 'DraggablePanelRoot';\n\nexport interface DraggablePanelContentProps extends Omit<DivProps, 'onDrag'> {}\n\nexport const DraggablePanelContent = memo<DraggablePanelContentProps>(\n ({ children, className, style, ...rest }) => {\n const { axis, controller, expand, placement, state } = useDraggablePanelContext();\n const extent = useTransform(controller.motion.size, (value) => Math.max(0, value));\n // Subscribed, not read: a collapse that changes only the target would otherwise\n // leave the content unclipped and painted outside the zero-width box.\n const target = useStore(controller.subscribe, () => controller.target);\n const clipping = state.dragging || state.folding || target === 0;\n const shrunk = state.collapsing || !expand;\n\n return (\n <motion.div\n inert={!expand}\n style={\n {\n display: 'flex',\n flexDirection: axis.vertical ? 'column' : 'row',\n flexShrink: 0,\n justifyContent: axis.anchorEnd ? 'flex-end' : 'flex-start',\n overflow: clipping ? 'clip' : 'visible',\n [axis.cross]: '100%',\n [axis.extent]: extent,\n } as MotionStyle\n }\n >\n <motion.div\n animate={{ scale: shrunk ? COLLAPSED_SCALE : 1 }}\n className={cx(styles.content, className)}\n transition={timing()}\n style={\n {\n transformOrigin: ORIGIN_MAP[placement],\n [axis.cross]: '100%',\n [axis.extent]: controller.motion.content,\n ...style,\n } as MotionStyle\n }\n {...(rest as HTMLMotionProps<'div'>)}\n >\n {children}\n </motion.div>\n </motion.div>\n );\n },\n);\n\nDraggablePanelContent.displayName = 'DraggablePanelContent';\n\nexport interface DraggablePanelHandleProps extends Omit<DivProps, 'onDrag'> {\n wideArea?: boolean;\n}\n\nexport const DraggablePanelHandle = memo<DraggablePanelHandleProps>(\n ({ className, style, wideArea = true, ...rest }) => {\n const { axis, controller, expand, showBorder, state } = useDraggablePanelContext();\n const size = useStore(coarsePointer.subscribe, () => getHandleSize(wideArea));\n const target = useStore(controller.subscribe, () => controller.target);\n useEffect(() => () => controller.drag.cancel(), [controller]);\n\n const pressedRef = useRef<{ x: number; y: number } | null>(null);\n const draggingRef = useRef(false);\n const draggedRef = useRef(false);\n const { max, min } = controller.bounds();\n\n if (!expand) return null;\n\n return (\n <div\n aria-orientation={axis.ariaOrientation}\n aria-valuemax={Number.isFinite(max) ? max : undefined}\n aria-valuemin={min}\n aria-valuenow={target}\n aria-valuetext={`${target} pixels`}\n className={cx(handleVariants({ edge: axis.edge }), className)}\n data-border={showBorder}\n data-resizing={state.dragging || undefined}\n role=\"separator\"\n tabIndex={0}\n style={\n {\n '--draggable-panel-handle-size': `${size}px`,\n [EDGE_INSET[axis.edge]]: -size / 2,\n ...style,\n } as CSSProperties\n }\n onKeyDown={(event) => controller.resizeByKey(event)}\n onDoubleClick={() => {\n if (!draggedRef.current) controller.reset();\n }}\n onLostPointerCapture={() => {\n if (draggingRef.current) controller.drag.cancel();\n pressedRef.current = null;\n draggingRef.current = false;\n }}\n onPointerCancel={() => {\n controller.drag.cancel();\n pressedRef.current = null;\n draggingRef.current = false;\n }}\n onPointerDown={(event) => {\n draggedRef.current = false;\n pressedRef.current = { x: event.clientX, y: event.clientY };\n // A synthetic pointerdown carries no active pointer, and capturing throws.\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n /* empty */\n }\n }}\n onPointerMove={(event) => {\n if (!pressedRef.current) return;\n const offset = {\n x: event.clientX - pressedRef.current.x,\n y: event.clientY - pressedRef.current.y,\n };\n if (!draggingRef.current) {\n if (Math.hypot(offset.x, offset.y) < PAN_THRESHOLD) return;\n draggingRef.current = true;\n draggedRef.current = true;\n controller.drag.start();\n }\n controller.drag.move(offset);\n }}\n onPointerUp={() => {\n if (draggingRef.current) controller.drag.end();\n pressedRef.current = null;\n draggingRef.current = false;\n }}\n {...rest}\n />\n );\n },\n);\n\nDraggablePanelHandle.displayName = 'DraggablePanelHandle';\n\nexport interface DraggablePanelToggleProps extends Omit<DivProps, 'onDrag'> {\n showHandleWhenCollapsed?: boolean;\n}\n\nexport const DraggablePanelToggle = memo<DraggablePanelToggleProps>(\n ({ className, showHandleWhenCollapsed, style, ...rest }) => {\n const { axis, expand, expandable, placement, toggleExpand } = useDraggablePanelContext();\n\n if (!expandable) return null;\n\n const turn = CHEVRON_TURN[placement] + (expand ? 0 : 180);\n const chevX = axis.vertical ? BOW_CY : BOW_CX;\n const chevY = axis.vertical ? BOW_CX : BOW_CY;\n\n return (\n <div\n className={cx(toggleVariants({ placement }), className)}\n style={{ opacity: expand ? undefined : showHandleWhenCollapsed ? 1 : 0, ...style }}\n {...rest}\n >\n <button\n aria-label={expand ? 'Collapse panel' : 'Expand panel'}\n type=\"button\"\n onClick={toggleExpand}\n >\n <svg\n fill=\"none\"\n height={axis.vertical ? BOW_W : BOW_H}\n viewBox={`0 0 ${axis.vertical ? BOW_H : BOW_W} ${axis.vertical ? BOW_W : BOW_H}`}\n width={axis.vertical ? BOW_H : BOW_W}\n >\n {BOW_PATHS[axis.vertical ? 'horizontalSeam' : 'verticalSeam'].map((d) => (\n <path d={d} data-bow=\"\" key={d} strokeLinecap=\"round\" strokeWidth={BOW.stroke} />\n ))}\n <g\n style={{\n rotate: `${turn}deg`,\n transformOrigin: `${chevX}px ${chevY}px`,\n transition: 'rotate 0.25s var(--ant-motion-ease-out, ease)',\n }}\n >\n <path\n d={chevronPath(chevX, chevY)}\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.6}\n />\n </g>\n </svg>\n </button>\n </div>\n );\n },\n);\n\nDraggablePanelToggle.displayName = 'DraggablePanelToggle';\n\nexport type DraggablePanelContainerProps = DivProps;\n\nexport const DraggablePanelContainer = memo<DraggablePanelContainerProps>(\n ({ className, ...rest }) => <div className={cx(styles.container, className)} {...rest} />,\n);\n\nDraggablePanelContainer.displayName = 'DraggablePanelContainer';\n\nexport type DraggablePanelBodyProps = DivProps;\n\nexport const DraggablePanelBody = memo<DraggablePanelBodyProps>(({ className, style, ...rest }) => (\n <div className={cx(styles.body, className)} style={{ flex: 1, ...style }} {...rest} />\n));\n\nDraggablePanelBody.displayName = 'DraggablePanelBody';\n\nexport type DraggablePanelFooterProps = DivProps;\n\nexport const DraggablePanelFooter = memo<DraggablePanelFooterProps>(({ className, ...rest }) => (\n <div className={cx(styles.footer, className)} {...rest} />\n));\n\nDraggablePanelFooter.displayName = 'DraggablePanelFooter';\n\nexport interface DraggablePanelHeaderProps extends Omit<DivProps, 'children' | 'title'> {\n extra?: ReactNode;\n onCollapse?: () => void;\n title?: ReactNode;\n}\n\nexport const DraggablePanelHeader = memo<DraggablePanelHeaderProps>(\n ({ className, extra, onCollapse, title, ...rest }) => {\n const { toggleExpand } = useDraggablePanelContext();\n\n return (\n <div className={cx(styles.header, className)} {...rest}>\n <ActionIcon icon={ChevronLeft} size={'small'} onClick={onCollapse ?? toggleExpand} />\n {title}\n {extra}\n </div>\n );\n },\n);\n\nDraggablePanelHeader.displayName = 'DraggablePanelHeader';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"atoms.mjs","names":["useControlledState","getHandleSize"],"sources":["../../../src/base-ui/DraggablePanel/atoms.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { ChevronLeft } from 'lucide-react';\nimport type { HTMLMotionProps, MotionStyle } from 'motion/react';\nimport { useTransform } from 'motion/react';\nimport {\n type CSSProperties,\n memo,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport ActionIcon from '@/base-ui/ActionIcon';\nimport { useMotionComponent } from '@/MotionProvider';\nimport type { DivProps } from '@/types';\n\nimport { DraggablePanelContext, useDraggablePanelContext } from './context';\nimport type { Placement } from './core/axes';\nimport { AXES } from './core/axes';\nimport type { PanelControllerOptions } from './core/controller';\nimport { createPanelController } from './core/controller';\nimport { coarsePointer, handleSize as getHandleSize } from './core/env';\nimport { useIsomorphicLayoutEffect, useStore } from './core/internal';\nimport { timing } from './core/transition';\nimport { BOW, handleVariants, rootVariants, styles, toggleVariants } from './style';\n\nconst PAN_THRESHOLD = 3;\n\nconst BOW_CX = 15;\nconst BOW_CY = BOW.half + 8;\nconst BOW_W = BOW_CX * 2;\nconst BOW_H = BOW_CY * 2;\n\nconst bowPath = (direction: 1 | -1, verticalSeam: boolean) => {\n const k = BOW.half * BOW.curve;\n const b = BOW_CX + BOW.bulge * direction;\n const a0 = BOW_CY - BOW.half;\n const a1 = BOW_CY + BOW.half;\n // `a` runs along the seam, `b` across it; a horizontal seam swaps the two.\n const pt = (along: number, across: number) =>\n verticalSeam ? `${along} ${across}` : `${across} ${along}`;\n return [\n `M${pt(BOW_CX, a0)}`,\n `C${pt(BOW_CX, a0 + k)} ${pt(b, BOW_CY - k)} ${pt(b, BOW_CY)}`,\n `C${pt(b, BOW_CY + k)} ${pt(BOW_CX, a1 - k)} ${pt(BOW_CX, a1)}`,\n ].join(' ');\n};\n\nconst BOW_PATHS = {\n horizontalSeam: [bowPath(-1, false), bowPath(1, false)],\n verticalSeam: [bowPath(-1, true), bowPath(1, true)],\n};\n\n/** The chevron points the way a click moves the panel. */\nconst CHEVRON_TURN = { bottom: 270, left: 0, right: 180, top: 90 } as const;\n\nconst chevronPath = (cx: number, cy: number) =>\n `M${cx + 2.4} ${cy - 4.8} L${cx - 2.4} ${cy} L${cx + 2.4} ${cy + 4.8}`;\n\nconst ORIGIN_MAP = {\n bottom: 'center bottom',\n left: 'left center',\n right: 'right center',\n top: 'center top',\n} as const;\n\nconst COLLAPSED_SCALE = 0.97;\n\nconst EDGE_INSET = {\n bottom: 'insetBlockEnd',\n left: 'insetInlineStart',\n right: 'insetInlineEnd',\n top: 'insetBlockStart',\n} as const;\n\nexport interface DraggablePanelRootProps extends Omit<DivProps, 'onDrag'> {\n backgroundColor?: string;\n collapseThreshold?: number;\n defaultExpand?: boolean;\n defaultSize?: number;\n expand?: boolean;\n expandable?: boolean;\n max?: number;\n min?: number;\n mode?: 'fixed' | 'float';\n onExpandChange?: (expand: boolean) => void;\n onSizeChange?: (size: number, delta: number) => void;\n onSizeDragging?: (size: number, delta: number) => void;\n placement?: Placement;\n showBorder?: boolean;\n size?: number;\n}\n\nexport const DraggablePanelRoot = memo<DraggablePanelRootProps>(\n ({\n backgroundColor,\n children,\n className,\n collapseThreshold,\n defaultExpand = true,\n defaultSize,\n expand,\n expandable = true,\n max,\n min = 0,\n mode = 'fixed',\n onExpandChange,\n onSizeChange,\n onSizeDragging,\n placement = 'right',\n showBorder = true,\n size,\n style,\n ...rest\n }) => {\n const axis = AXES[placement];\n const fallbackSize = axis.vertical ? 180 : 280;\n const resolvedDefaultSize = defaultSize ?? fallbackSize;\n\n const [isExpand, setIsExpand] = useControlledState(defaultExpand, {\n onChange: onExpandChange,\n value: expand,\n });\n const [innerSize, setInnerSize] = useState(resolvedDefaultSize);\n const currentSize = size ?? innerSize;\n\n const commitSize = useCallback(\n (next: number, delta: number) => {\n if (size === undefined) setInnerSize(next);\n onSizeChange?.(next, delta);\n },\n [onSizeChange, size],\n );\n\n const options: PanelControllerOptions = {\n collapseThreshold,\n defaultSize: resolvedDefaultSize,\n expand: isExpand,\n max,\n min,\n onExpandChange: setIsExpand,\n onSizeChange: commitSize,\n onSizeDragging,\n placement,\n size: currentSize,\n };\n\n const [controller] = useState(() => createPanelController(options));\n const state = useStore(controller.subscribe, () => controller.state);\n const elementRef = useRef<HTMLElement>(null);\n\n useIsomorphicLayoutEffect(() => {\n controller.sync(options);\n });\n\n useIsomorphicLayoutEffect(() => {\n const node = elementRef.current;\n return node ? controller.attach(node) : undefined;\n }, [controller]);\n\n const toggleExpand = useCallback(() => {\n if (expandable) setIsExpand(!isExpand);\n }, [expandable, isExpand, setIsExpand]);\n\n const context = useMemo(\n () => ({\n axis,\n controller,\n expand: isExpand,\n expandable,\n placement,\n showBorder,\n state,\n toggleExpand,\n }),\n [axis, controller, isExpand, expandable, placement, showBorder, state, toggleExpand],\n );\n\n return (\n <DraggablePanelContext value={context}>\n <aside\n className={cx(rootVariants({ mode, placement }), className)}\n data-expand={isExpand}\n data-expandable={expandable}\n data-resizing={state.dragging}\n ref={elementRef}\n style={\n {\n '--draggable-panel-bg': backgroundColor || '',\n 'flexDirection': axis.vertical ? 'column' : 'row',\n ...style,\n } as CSSProperties\n }\n {...rest}\n >\n {children}\n </aside>\n </DraggablePanelContext>\n );\n },\n);\n\nDraggablePanelRoot.displayName = 'DraggablePanelRoot';\n\nexport interface DraggablePanelContentProps extends Omit<DivProps, 'onDrag'> {}\n\nexport const DraggablePanelContent = memo<DraggablePanelContentProps>(\n ({ children, className, style, ...rest }) => {\n const Motion = useMotionComponent();\n const { axis, controller, expand, placement, state } = useDraggablePanelContext();\n const extent = useTransform(controller.motion.size, (value) => Math.max(0, value));\n // Subscribed, not read: a collapse that changes only the target would otherwise\n // leave the content unclipped and painted outside the zero-width box.\n const target = useStore(controller.subscribe, () => controller.target);\n const clipping = state.dragging || state.folding || target === 0;\n const shrunk = state.collapsing || !expand;\n\n return (\n <Motion.div\n inert={!expand}\n style={\n {\n display: 'flex',\n flexDirection: axis.vertical ? 'column' : 'row',\n flexShrink: 0,\n justifyContent: axis.anchorEnd ? 'flex-end' : 'flex-start',\n overflow: clipping ? 'clip' : 'visible',\n [axis.cross]: '100%',\n [axis.extent]: extent,\n } as MotionStyle\n }\n >\n <Motion.div\n animate={{ scale: shrunk ? COLLAPSED_SCALE : 1 }}\n className={cx(styles.content, className)}\n transition={timing()}\n style={\n {\n transformOrigin: ORIGIN_MAP[placement],\n [axis.cross]: '100%',\n [axis.extent]: controller.motion.content,\n ...style,\n } as MotionStyle\n }\n {...(rest as HTMLMotionProps<'div'>)}\n >\n {children}\n </Motion.div>\n </Motion.div>\n );\n },\n);\n\nDraggablePanelContent.displayName = 'DraggablePanelContent';\n\nexport interface DraggablePanelHandleProps extends Omit<DivProps, 'onDrag'> {\n wideArea?: boolean;\n}\n\nexport const DraggablePanelHandle = memo<DraggablePanelHandleProps>(\n ({ className, style, wideArea = true, ...rest }) => {\n const { axis, controller, expand, showBorder, state } = useDraggablePanelContext();\n const size = useStore(coarsePointer.subscribe, () => getHandleSize(wideArea));\n const target = useStore(controller.subscribe, () => controller.target);\n useEffect(() => () => controller.drag.cancel(), [controller]);\n\n const pressedRef = useRef<{ x: number; y: number } | null>(null);\n const draggingRef = useRef(false);\n const draggedRef = useRef(false);\n const { max, min } = controller.bounds();\n\n if (!expand) return null;\n\n return (\n <div\n aria-orientation={axis.ariaOrientation}\n aria-valuemax={Number.isFinite(max) ? max : undefined}\n aria-valuemin={min}\n aria-valuenow={target}\n aria-valuetext={`${target} pixels`}\n className={cx(handleVariants({ edge: axis.edge }), className)}\n data-border={showBorder}\n data-resizing={state.dragging || undefined}\n role=\"separator\"\n tabIndex={0}\n style={\n {\n '--draggable-panel-handle-size': `${size}px`,\n [EDGE_INSET[axis.edge]]: -size / 2,\n ...style,\n } as CSSProperties\n }\n onKeyDown={(event) => controller.resizeByKey(event)}\n onDoubleClick={() => {\n if (!draggedRef.current) controller.reset();\n }}\n onLostPointerCapture={() => {\n if (draggingRef.current) controller.drag.cancel();\n pressedRef.current = null;\n draggingRef.current = false;\n }}\n onPointerCancel={() => {\n controller.drag.cancel();\n pressedRef.current = null;\n draggingRef.current = false;\n }}\n onPointerDown={(event) => {\n draggedRef.current = false;\n pressedRef.current = { x: event.clientX, y: event.clientY };\n // A synthetic pointerdown carries no active pointer, and capturing throws.\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n /* empty */\n }\n }}\n onPointerMove={(event) => {\n if (!pressedRef.current) return;\n const offset = {\n x: event.clientX - pressedRef.current.x,\n y: event.clientY - pressedRef.current.y,\n };\n if (!draggingRef.current) {\n if (Math.hypot(offset.x, offset.y) < PAN_THRESHOLD) return;\n draggingRef.current = true;\n draggedRef.current = true;\n controller.drag.start();\n }\n controller.drag.move(offset);\n }}\n onPointerUp={() => {\n if (draggingRef.current) controller.drag.end();\n pressedRef.current = null;\n draggingRef.current = false;\n }}\n {...rest}\n />\n );\n },\n);\n\nDraggablePanelHandle.displayName = 'DraggablePanelHandle';\n\nexport interface DraggablePanelToggleProps extends Omit<DivProps, 'onDrag'> {\n showHandleWhenCollapsed?: boolean;\n}\n\nexport const DraggablePanelToggle = memo<DraggablePanelToggleProps>(\n ({ className, showHandleWhenCollapsed, style, ...rest }) => {\n const { axis, expand, expandable, placement, toggleExpand } = useDraggablePanelContext();\n\n if (!expandable) return null;\n\n const turn = CHEVRON_TURN[placement] + (expand ? 0 : 180);\n const chevX = axis.vertical ? BOW_CY : BOW_CX;\n const chevY = axis.vertical ? BOW_CX : BOW_CY;\n\n return (\n <div\n className={cx(toggleVariants({ placement }), className)}\n style={{ opacity: expand ? undefined : showHandleWhenCollapsed ? 1 : 0, ...style }}\n {...rest}\n >\n <button\n aria-label={expand ? 'Collapse panel' : 'Expand panel'}\n type=\"button\"\n onClick={toggleExpand}\n >\n <svg\n fill=\"none\"\n height={axis.vertical ? BOW_W : BOW_H}\n viewBox={`0 0 ${axis.vertical ? BOW_H : BOW_W} ${axis.vertical ? BOW_W : BOW_H}`}\n width={axis.vertical ? BOW_H : BOW_W}\n >\n {BOW_PATHS[axis.vertical ? 'horizontalSeam' : 'verticalSeam'].map((d) => (\n <path d={d} data-bow=\"\" key={d} strokeLinecap=\"round\" strokeWidth={BOW.stroke} />\n ))}\n <g\n style={{\n rotate: `${turn}deg`,\n transformOrigin: `${chevX}px ${chevY}px`,\n transition: 'rotate 0.25s var(--ant-motion-ease-out, ease)',\n }}\n >\n <path\n d={chevronPath(chevX, chevY)}\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.6}\n />\n </g>\n </svg>\n </button>\n </div>\n );\n },\n);\n\nDraggablePanelToggle.displayName = 'DraggablePanelToggle';\n\nexport type DraggablePanelContainerProps = DivProps;\n\nexport const DraggablePanelContainer = memo<DraggablePanelContainerProps>(\n ({ className, ...rest }) => <div className={cx(styles.container, className)} {...rest} />,\n);\n\nDraggablePanelContainer.displayName = 'DraggablePanelContainer';\n\nexport type DraggablePanelBodyProps = DivProps;\n\nexport const DraggablePanelBody = memo<DraggablePanelBodyProps>(({ className, style, ...rest }) => (\n <div className={cx(styles.body, className)} style={{ flex: 1, ...style }} {...rest} />\n));\n\nDraggablePanelBody.displayName = 'DraggablePanelBody';\n\nexport type DraggablePanelFooterProps = DivProps;\n\nexport const DraggablePanelFooter = memo<DraggablePanelFooterProps>(({ className, ...rest }) => (\n <div className={cx(styles.footer, className)} {...rest} />\n));\n\nDraggablePanelFooter.displayName = 'DraggablePanelFooter';\n\nexport interface DraggablePanelHeaderProps extends Omit<DivProps, 'children' | 'title'> {\n extra?: ReactNode;\n onCollapse?: () => void;\n title?: ReactNode;\n}\n\nexport const DraggablePanelHeader = memo<DraggablePanelHeaderProps>(\n ({ className, extra, onCollapse, title, ...rest }) => {\n const { toggleExpand } = useDraggablePanelContext();\n\n return (\n <div className={cx(styles.header, className)} {...rest}>\n <ActionIcon icon={ChevronLeft} size={'small'} onClick={onCollapse ?? toggleExpand} />\n {title}\n {extra}\n </div>\n );\n },\n);\n\nDraggablePanelHeader.displayName = 'DraggablePanelHeader';\n"],"mappings":"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"}
|
package/es/base-ui/focusRing.mjs
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
+
import { focusRingColor as focusRingColor$1 } from "../GlobalFocusRing/style.mjs";
|
|
1
2
|
import { css, cssVar, keyframes } from "antd-style";
|
|
2
3
|
//#region src/base-ui/focusRing.ts
|
|
3
|
-
const
|
|
4
|
-
const glow = (color, scale = 1) => `0 0 0 ${3 * scale}px ${tint(color, 70)}, 0 0 ${5 * scale}px ${4 * scale}px ${tint(color, 35)}`;
|
|
5
|
-
const ringIn = (color) => keyframes`
|
|
4
|
+
const ringIn = keyframes`
|
|
6
5
|
from {
|
|
7
|
-
|
|
6
|
+
outline-color: transparent;
|
|
7
|
+
outline-offset: 5px;
|
|
8
8
|
}
|
|
9
9
|
`;
|
|
10
10
|
const ring = (color) => css`
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
--lobe-focus-ring-color: ${color};
|
|
12
|
+
|
|
13
|
+
&:focus-visible:not([data-lobe-focus-ring='managed']) {
|
|
14
|
+
outline: 2px solid ${focusRingColor$1(color)};
|
|
15
|
+
outline-offset: 2px;
|
|
16
|
+
animation: ${ringIn} 200ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
15
17
|
|
|
16
18
|
@media (prefers-reduced-motion: reduce) {
|
|
17
19
|
animation: none;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
@media (forced-colors: active) {
|
|
21
|
-
outline:
|
|
23
|
+
outline-color: CanvasText;
|
|
22
24
|
animation: none;
|
|
23
25
|
}
|
|
24
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focusRing.mjs","names":[],"sources":["../../src/base-ui/focusRing.ts"],"sourcesContent":["import { css, cssVar, keyframes } from 'antd-style';\n\
|
|
1
|
+
{"version":3,"file":"focusRing.mjs","names":["ringColor"],"sources":["../../src/base-ui/focusRing.ts"],"sourcesContent":["import { css, cssVar, keyframes } from 'antd-style';\n\nimport { focusRingColor as ringColor } from '@/GlobalFocusRing/style';\n\nconst ringIn = keyframes`\n from {\n outline-color: transparent;\n outline-offset: 5px;\n }\n`;\n\nconst ring = (color: string) => css`\n --lobe-focus-ring-color: ${color};\n\n &:focus-visible:not([data-lobe-focus-ring='managed']) {\n outline: 2px solid ${ringColor(color)};\n outline-offset: 2px;\n animation: ${ringIn} 200ms cubic-bezier(0.22, 1, 0.36, 1);\n\n @media (prefers-reduced-motion: reduce) {\n animation: none;\n }\n\n @media (forced-colors: active) {\n outline-color: CanvasText;\n animation: none;\n }\n }\n`;\n\nexport const focusRing = ring(cssVar.colorInfo);\n\nexport const focusRingColor = ring;\n"],"mappings":";;;AAIA,MAAM,SAAS,SAAS;;;;;;AAOxB,MAAM,QAAQ,UAAkB,GAAG;6BACN,MAAM;;;yBAGVA,iBAAU,KAAK,EAAE;;iBAEzB,OAAO;;;;;;;;;;;;AAaxB,MAAa,YAAY,KAAK,OAAO,SAAS;AAE9C,MAAa,iBAAiB"}
|
package/es/index.d.mts
CHANGED
|
@@ -164,6 +164,7 @@ import "./FormModal/index.mjs";
|
|
|
164
164
|
import { FreezeProps } from "./Freeze/type.mjs";
|
|
165
165
|
import Freeze from "./Freeze/Freeze.mjs";
|
|
166
166
|
import "./Freeze/index.mjs";
|
|
167
|
+
import { installGlobalFocusRing } from "./GlobalFocusRing/index.mjs";
|
|
167
168
|
import { GridProps } from "./Grid/type.mjs";
|
|
168
169
|
import Grid from "./Grid/Grid.mjs";
|
|
169
170
|
import "./Grid/index.mjs";
|
|
@@ -310,4 +311,4 @@ import { LayoutToc } from "./Layout/components/LayoutToc.mjs";
|
|
|
310
311
|
import Layout from "./Layout/index.mjs";
|
|
311
312
|
import { rehypeStreamAnimated } from "@lobehub/streamdown";
|
|
312
313
|
import { ErrorBoundary, ErrorBoundaryProps } from "react-error-boundary";
|
|
313
|
-
export { A, type AProps, Accordion, AccordionItem, type AccordionItemProps, type AccordionProps, ActionIcon, ActionIconGroup, type ActionIconGroupEvent, type MenuItemType as ActionIconGroupItemType, type ActionIconGroupProps, type ActionIconProps, type ActionIconSize, Alert, type AlertProps, AutoComplete, type AutoCompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type BaseMenuItemType, Block, type BlockProps, Burger, type BurgerProps, Button, type ButtonProps, type CDN, CLASSNAMES, Center, type CenterProps, Checkbox, CheckboxGroup, type CheckboxGroupOption, type CheckboxGroupProps, type CheckboxProps, CodeDiff, type CodeDiffProps, CodeEditor, type CodeEditorProps, Collapse, type CollapseItemType, type CollapseProps, type ColorPalettes, type ColorPalettesAlpha, ColorSwatches, type ColorSwatchesProps, type ColorToken, type Config, ConfigProvider, type ContextMenuCheckboxItem, ContextMenuHost, type ContextMenuInterceptor, type ContextMenuItem, ContextMenuTrigger, CopyButton, type CopyButtonProps, DatePicker, type DatePickerProps, type DiffViewMode, type DivProps, DownloadButton, type DownloadButtonProps, DraggablePanel, DraggablePanelBody, type DraggablePanelBodyProps, DraggablePanelContainer, type DraggablePanelContainerProps, DraggablePanelFooter, type DraggablePanelFooterProps, DraggablePanelHeader, type DraggablePanelHeaderProps, type DraggablePanelProps, DraggableSideNav, type DraggableSideNavProps, Drawer, type DrawerProps, Dropdown, type DropdownItem, DropdownMenu, type DropdownMenuCheckboxItem, DropdownMenuCheckboxItemIndicator, DropdownMenuCheckboxItemPrimitive, DropdownMenuFooter, type DropdownMenuFooterProps, DropdownMenuGroup, DropdownMenuGroupLabel, type DropdownMenuGroupLabelProps, DropdownMenuHeader, type DropdownMenuHeaderProps, DropdownMenuItem, DropdownMenuItemContent, type DropdownMenuItemContentProps, DropdownMenuItemExtra, type DropdownMenuItemExtraProps, DropdownMenuItemIcon, type DropdownMenuItemIconProps, DropdownMenuItemLabel, type DropdownMenuItemLabelProps, type DropdownMenuItemProps, type MenuItemType as DropdownMenuItemType, type DropdownMenuPlacement, DropdownMenuPopup, type DropdownMenuPopupProps, DropdownMenuPortal, type DropdownMenuPortalProps, DropdownMenuPositioner, type DropdownMenuPositionerProps, type DropdownMenuProps, DropdownMenuRoot, DropdownMenuScrollViewport, type DropdownMenuScrollViewportProps, DropdownMenuSeparator, type DropdownMenuSeparatorProps, DropdownMenuSubmenuArrow, type DropdownMenuSubmenuArrowProps, DropdownMenuSubmenuRoot, DropdownMenuSubmenuTrigger, type DropdownMenuSubmenuTriggerProps, DropdownMenuTrigger, type DropdownMenuTriggerProps, type DropdownProps, EditableText, type EditableTextProps, EditorSlashMenu, type EditorSlashMenuGroup, type EditorSlashMenuItems, type EditorSlashMenuOption, EmojiPicker, type EmojiPickerProps, Empty, type EmptyProps, ErrorBoundary, type ErrorBoundaryProps, FileTypeIcon, type FileTypeIconProps, _default as FlexBasic, type FlexBasicProps, _default as Flexbox, type FlexboxProps, FluentEmoji, type FluentEmojiProps, FontLoader, type FontLoaderProps, Footer, type FooterProps, Form, FormGroup, type FormGroupItemType, type FormGroupProps, type FormInstance, FormItem, type FormItemProps, FormModal, type FormModalProps, type FormProps, FormSubmitFooter, type FormSubmitFooterProps, FormTitle, type FormTitleProps, Freeze, type FreezeProps, type GenericItemType, Grid, type GridProps, GroupAvatar, type GroupAvatarProps, GuideCard, type GuideCardProps, DEFAULT_HEIGHT as HTML_PREVIEW_DEFAULT_HEIGHT, DEFAULT_SANDBOX as HTML_PREVIEW_DEFAULT_SANDBOX, AUTO_HEIGHT_MESSAGE_TYPE as HTML_PREVIEW_RESIZE_MESSAGE, Header, type HeaderProps, Highlighter, type HighlighterProps, Hotkey, HotkeyInput, type HotkeyInputProps, type HotkeyProps, HtmlPreview, HtmlPreviewIframe, type HtmlPreviewIframeProps, type HtmlPreviewMode, type HtmlPreviewProps, type HtmlPreviewStreamingMode, I18nProvider, type I18nProviderProps, Icon, type IconProps, IconProvider, type IconSize, Image, type ImagePreviewOptions, type ImageProps, ImageSelect, type ImageSelectItem, type ImageSelectProps, type ImgProps, type ImperativeModalProps, Input, InputNumber, type InputNumberProps, InputOPT, type InputOPTProps, InputPassword, type InputPasswordProps, type InputProps, type ItemType, KeyMapEnum, LOBE_THEME_APP_ID, Layout, LayoutFooter, type LayoutFooterProps, LayoutHeader, type LayoutHeaderProps, LayoutMain, type LayoutMainProps, type LayoutProps, LayoutSidebar, LayoutSidebarInner, type LayoutSidebarInnerProps, type LayoutSidebarProps, LayoutToc, type LayoutTocProps, List, ListItem, type ListItemProps, type ListProps, type LobeCustomStylish, type LobeCustomToken, I18nProvider as LobeUIProvider, Markdown, type MarkdownProps, MaskShadow, type MaskShadowProps, MaterialFileTypeIcon, type MaterialFileTypeIconProps, Menu, type MenuCheckboxItemType, type MenuInfo, type MenuItemType, type MenuProps, Mermaid, type MermaidProps, Meta, type MetaProps, Modal, ModalHost, type ModalHostProps, type ModalInstance, type ModalProps, ModalProvider, MotionComponent, type MotionComponentType, MotionProvider, NeuralNetworkLoading, type NeuralNetworkLoadingProps, NeutralColors, NeutralColorsObj, PatchDiff, type PatchDiffProps, type Placement, type PlacementConfig, Popover, PopoverArrow, type PopoverArrowAtomProps, PopoverArrowIcon, PopoverBackdrop, type PopoverContextValue, PopoverGroup, type PopoverGroupHandle, type PopoverGroupItem, type PopoverPlacement, PopoverPopup, type PopoverPopupAtomProps, PopoverPortal, type PopoverPortalAtomProps, PopoverPositioner, type PopoverPositionerAtomProps, type PopoverProps, PopoverProvider, PopoverRoot, type PopoverTrigger, PopoverTriggerElement, type PopoverTriggerElementProps, PopoverViewport, type PopoverViewportAtomProps, type PresetColorKey, type PresetColorType, type PresetSystemColorKey, type PresetSystemColorType, PreviewGroup, type PreviewGroupProps, PrimaryColors, PrimaryColorsObj, type RawModalComponent, type RawModalComponentProps, type RawModalInstance, type RawModalKeyOptions, type RawModalOptions, ScrollArea, ScrollAreaContent, type ScrollAreaContentProps, ScrollAreaCorner, type ScrollAreaCornerProps, type ScrollAreaProps, ScrollAreaRoot, type ScrollAreaRootProps, ScrollAreaScrollbar, type ScrollAreaScrollbarProps, ScrollAreaThumb, type ScrollAreaThumbProps, ScrollAreaViewport, type ScrollAreaViewportProps, ScrollShadow, type ScrollShadowProps, SearchBar, type SearchBarProps, SearchResultCards, type SearchResultCardsProps, Segmented, type SegmentedProps, Select, type SelectProps, _default$1 as ShikiLobeTheme, SideNav, type SideNavProps, Skeleton, SkeletonAvatar, type SkeletonAvatarProps, SkeletonBlock, type SkeletonBlockProps, SkeletonButton, type SkeletonButtonProps, SkeletonParagraph, type SkeletonParagraphProps, type SkeletonProps, SkeletonTags, type SkeletonTagsProps, SkeletonTitle, type SkeletonTitleProps, SliderWithInput, type SliderWithInputProps, Snippet, type SnippetProps, SortableList, type SortableListProps, type SpanProps, type SvgProps, SyntaxHighlighter, type SyntaxHighlighterProps, SyntaxMermaid, type SyntaxMermaidProps, type SystemColorToken, Tabs, type TabsProps, Tag, type TagProps, Text, TextArea, type TextAreaProps, type TextProps, ThemeProvider, type ThemeProviderProps, ThemeSwitch, type ThemeSwitchProps, type ToastAPI, ToastHost, type ToastHostProps, type ToastInstance, type ToastOptions, type ToastPosition, type ToastPromiseOptions, type ToastProps, type ToastType, Toc, type TocProps, Tooltip, TooltipGroup, type TooltipProps, type Trigger, Typography, type TypographyProps, Video, type VideoProps, closeContextMenu, combineKeys, copyToClipboard, createModal, createRawModal, findCustomThemeName, genCdnUrl, generateColorNeutralPalette, generateColorPalette, highlighterThemes, containsScript as htmlPreviewContainsScript, isFullHtmlDocument, isHtmlContentClosed, generateCustomStylish as lobeCustomStylish, generateCustomToken as lobeCustomToken, staticStylish as lobeStaticStylish, styles as menuSharedStyles, mermaidThemes, neutralColors, neutralColorsSwatches, placementMap, preprocessMarkdownContent, preventDefault, preventDefaultAndStopPropagation, primaryColors, primaryColorsSwatches, rehypeCustomFootnotes, rehypeKatexDir, rehypeStreamAnimated, remarkBr, remarkColor, remarkCustomFootnotes, remarkGfmPlus, remarkVideo, renderDropdownMenuItems, setContextMenuInterceptor, showContextMenu, stopPropagation, toFloatingUIPlacement, toast, updateContextMenuItems, useAppElement, useCdnFn, useModalContext, useMotionComponent, usePopoverContext, usePopoverGroupHandle, usePopoverPortalContainer, useToast, useTranslation };
|
|
314
|
+
export { A, type AProps, Accordion, AccordionItem, type AccordionItemProps, type AccordionProps, ActionIcon, ActionIconGroup, type ActionIconGroupEvent, type MenuItemType as ActionIconGroupItemType, type ActionIconGroupProps, type ActionIconProps, type ActionIconSize, Alert, type AlertProps, AutoComplete, type AutoCompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type BaseMenuItemType, Block, type BlockProps, Burger, type BurgerProps, Button, type ButtonProps, type CDN, CLASSNAMES, Center, type CenterProps, Checkbox, CheckboxGroup, type CheckboxGroupOption, type CheckboxGroupProps, type CheckboxProps, CodeDiff, type CodeDiffProps, CodeEditor, type CodeEditorProps, Collapse, type CollapseItemType, type CollapseProps, type ColorPalettes, type ColorPalettesAlpha, ColorSwatches, type ColorSwatchesProps, type ColorToken, type Config, ConfigProvider, type ContextMenuCheckboxItem, ContextMenuHost, type ContextMenuInterceptor, type ContextMenuItem, ContextMenuTrigger, CopyButton, type CopyButtonProps, DatePicker, type DatePickerProps, type DiffViewMode, type DivProps, DownloadButton, type DownloadButtonProps, DraggablePanel, DraggablePanelBody, type DraggablePanelBodyProps, DraggablePanelContainer, type DraggablePanelContainerProps, DraggablePanelFooter, type DraggablePanelFooterProps, DraggablePanelHeader, type DraggablePanelHeaderProps, type DraggablePanelProps, DraggableSideNav, type DraggableSideNavProps, Drawer, type DrawerProps, Dropdown, type DropdownItem, DropdownMenu, type DropdownMenuCheckboxItem, DropdownMenuCheckboxItemIndicator, DropdownMenuCheckboxItemPrimitive, DropdownMenuFooter, type DropdownMenuFooterProps, DropdownMenuGroup, DropdownMenuGroupLabel, type DropdownMenuGroupLabelProps, DropdownMenuHeader, type DropdownMenuHeaderProps, DropdownMenuItem, DropdownMenuItemContent, type DropdownMenuItemContentProps, DropdownMenuItemExtra, type DropdownMenuItemExtraProps, DropdownMenuItemIcon, type DropdownMenuItemIconProps, DropdownMenuItemLabel, type DropdownMenuItemLabelProps, type DropdownMenuItemProps, type MenuItemType as DropdownMenuItemType, type DropdownMenuPlacement, DropdownMenuPopup, type DropdownMenuPopupProps, DropdownMenuPortal, type DropdownMenuPortalProps, DropdownMenuPositioner, type DropdownMenuPositionerProps, type DropdownMenuProps, DropdownMenuRoot, DropdownMenuScrollViewport, type DropdownMenuScrollViewportProps, DropdownMenuSeparator, type DropdownMenuSeparatorProps, DropdownMenuSubmenuArrow, type DropdownMenuSubmenuArrowProps, DropdownMenuSubmenuRoot, DropdownMenuSubmenuTrigger, type DropdownMenuSubmenuTriggerProps, DropdownMenuTrigger, type DropdownMenuTriggerProps, type DropdownProps, EditableText, type EditableTextProps, EditorSlashMenu, type EditorSlashMenuGroup, type EditorSlashMenuItems, type EditorSlashMenuOption, EmojiPicker, type EmojiPickerProps, Empty, type EmptyProps, ErrorBoundary, type ErrorBoundaryProps, FileTypeIcon, type FileTypeIconProps, _default as FlexBasic, type FlexBasicProps, _default as Flexbox, type FlexboxProps, FluentEmoji, type FluentEmojiProps, FontLoader, type FontLoaderProps, Footer, type FooterProps, Form, FormGroup, type FormGroupItemType, type FormGroupProps, type FormInstance, FormItem, type FormItemProps, FormModal, type FormModalProps, type FormProps, FormSubmitFooter, type FormSubmitFooterProps, FormTitle, type FormTitleProps, Freeze, type FreezeProps, type GenericItemType, Grid, type GridProps, GroupAvatar, type GroupAvatarProps, GuideCard, type GuideCardProps, DEFAULT_HEIGHT as HTML_PREVIEW_DEFAULT_HEIGHT, DEFAULT_SANDBOX as HTML_PREVIEW_DEFAULT_SANDBOX, AUTO_HEIGHT_MESSAGE_TYPE as HTML_PREVIEW_RESIZE_MESSAGE, Header, type HeaderProps, Highlighter, type HighlighterProps, Hotkey, HotkeyInput, type HotkeyInputProps, type HotkeyProps, HtmlPreview, HtmlPreviewIframe, type HtmlPreviewIframeProps, type HtmlPreviewMode, type HtmlPreviewProps, type HtmlPreviewStreamingMode, I18nProvider, type I18nProviderProps, Icon, type IconProps, IconProvider, type IconSize, Image, type ImagePreviewOptions, type ImageProps, ImageSelect, type ImageSelectItem, type ImageSelectProps, type ImgProps, type ImperativeModalProps, Input, InputNumber, type InputNumberProps, InputOPT, type InputOPTProps, InputPassword, type InputPasswordProps, type InputProps, type ItemType, KeyMapEnum, LOBE_THEME_APP_ID, Layout, LayoutFooter, type LayoutFooterProps, LayoutHeader, type LayoutHeaderProps, LayoutMain, type LayoutMainProps, type LayoutProps, LayoutSidebar, LayoutSidebarInner, type LayoutSidebarInnerProps, type LayoutSidebarProps, LayoutToc, type LayoutTocProps, List, ListItem, type ListItemProps, type ListProps, type LobeCustomStylish, type LobeCustomToken, I18nProvider as LobeUIProvider, Markdown, type MarkdownProps, MaskShadow, type MaskShadowProps, MaterialFileTypeIcon, type MaterialFileTypeIconProps, Menu, type MenuCheckboxItemType, type MenuInfo, type MenuItemType, type MenuProps, Mermaid, type MermaidProps, Meta, type MetaProps, Modal, ModalHost, type ModalHostProps, type ModalInstance, type ModalProps, ModalProvider, MotionComponent, type MotionComponentType, MotionProvider, NeuralNetworkLoading, type NeuralNetworkLoadingProps, NeutralColors, NeutralColorsObj, PatchDiff, type PatchDiffProps, type Placement, type PlacementConfig, Popover, PopoverArrow, type PopoverArrowAtomProps, PopoverArrowIcon, PopoverBackdrop, type PopoverContextValue, PopoverGroup, type PopoverGroupHandle, type PopoverGroupItem, type PopoverPlacement, PopoverPopup, type PopoverPopupAtomProps, PopoverPortal, type PopoverPortalAtomProps, PopoverPositioner, type PopoverPositionerAtomProps, type PopoverProps, PopoverProvider, PopoverRoot, type PopoverTrigger, PopoverTriggerElement, type PopoverTriggerElementProps, PopoverViewport, type PopoverViewportAtomProps, type PresetColorKey, type PresetColorType, type PresetSystemColorKey, type PresetSystemColorType, PreviewGroup, type PreviewGroupProps, PrimaryColors, PrimaryColorsObj, type RawModalComponent, type RawModalComponentProps, type RawModalInstance, type RawModalKeyOptions, type RawModalOptions, ScrollArea, ScrollAreaContent, type ScrollAreaContentProps, ScrollAreaCorner, type ScrollAreaCornerProps, type ScrollAreaProps, ScrollAreaRoot, type ScrollAreaRootProps, ScrollAreaScrollbar, type ScrollAreaScrollbarProps, ScrollAreaThumb, type ScrollAreaThumbProps, ScrollAreaViewport, type ScrollAreaViewportProps, ScrollShadow, type ScrollShadowProps, SearchBar, type SearchBarProps, SearchResultCards, type SearchResultCardsProps, Segmented, type SegmentedProps, Select, type SelectProps, _default$1 as ShikiLobeTheme, SideNav, type SideNavProps, Skeleton, SkeletonAvatar, type SkeletonAvatarProps, SkeletonBlock, type SkeletonBlockProps, SkeletonButton, type SkeletonButtonProps, SkeletonParagraph, type SkeletonParagraphProps, type SkeletonProps, SkeletonTags, type SkeletonTagsProps, SkeletonTitle, type SkeletonTitleProps, SliderWithInput, type SliderWithInputProps, Snippet, type SnippetProps, SortableList, type SortableListProps, type SpanProps, type SvgProps, SyntaxHighlighter, type SyntaxHighlighterProps, SyntaxMermaid, type SyntaxMermaidProps, type SystemColorToken, Tabs, type TabsProps, Tag, type TagProps, Text, TextArea, type TextAreaProps, type TextProps, ThemeProvider, type ThemeProviderProps, ThemeSwitch, type ThemeSwitchProps, type ToastAPI, ToastHost, type ToastHostProps, type ToastInstance, type ToastOptions, type ToastPosition, type ToastPromiseOptions, type ToastProps, type ToastType, Toc, type TocProps, Tooltip, TooltipGroup, type TooltipProps, type Trigger, Typography, type TypographyProps, Video, type VideoProps, closeContextMenu, combineKeys, copyToClipboard, createModal, createRawModal, findCustomThemeName, genCdnUrl, generateColorNeutralPalette, generateColorPalette, highlighterThemes, containsScript as htmlPreviewContainsScript, installGlobalFocusRing, isFullHtmlDocument, isHtmlContentClosed, generateCustomStylish as lobeCustomStylish, generateCustomToken as lobeCustomToken, staticStylish as lobeStaticStylish, styles as menuSharedStyles, mermaidThemes, neutralColors, neutralColorsSwatches, placementMap, preprocessMarkdownContent, preventDefault, preventDefaultAndStopPropagation, primaryColors, primaryColorsSwatches, rehypeCustomFootnotes, rehypeKatexDir, rehypeStreamAnimated, remarkBr, remarkColor, remarkCustomFootnotes, remarkGfmPlus, remarkVideo, renderDropdownMenuItems, setContextMenuInterceptor, showContextMenu, stopPropagation, toFloatingUIPlacement, toast, updateContextMenuItems, useAppElement, useCdnFn, useModalContext, useMotionComponent, usePopoverContext, usePopoverGroupHandle, usePopoverPortalContainer, useToast, useTranslation };
|
package/es/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { installGlobalFocusRing } from "./GlobalFocusRing/index.mjs";
|
|
1
2
|
import { MotionComponent, MotionProvider, useMotionComponent } from "./MotionProvider/index.mjs";
|
|
2
3
|
import { genCdnUrl } from "./utils/genCdnUrl.mjs";
|
|
3
4
|
import ConfigProvider, { useCdnFn } from "./ConfigProvider/index.mjs";
|
|
@@ -161,4 +162,4 @@ import ThemeSwitch from "./ThemeSwitch/ThemeSwitch.mjs";
|
|
|
161
162
|
import Toc from "./Toc/Toc.mjs";
|
|
162
163
|
import { rehypeStreamAnimated } from "@lobehub/streamdown";
|
|
163
164
|
import { ErrorBoundary } from "react-error-boundary";
|
|
164
|
-
export { A, Accordion, AccordionItem, ActionIcon, ActionIconGroup, Alert, AutoComplete, Avatar, AvatarGroup, Block, Burger, Button, CLASSNAMES, Center, Checkbox, CheckboxGroup, CodeDiff, CodeEditor, Collapse, ColorSwatches, ConfigProvider, ContextMenuHost, ContextMenuTrigger, CopyButton, DatePicker, DownloadButton, DraggablePanel, DraggablePanelBody, DraggablePanelContainer, DraggablePanelFooter, DraggablePanelHeader, DraggableSideNav, Drawer, Dropdown, DropdownMenu, DropdownMenuCheckboxItemIndicator, DropdownMenuCheckboxItemPrimitive, DropdownMenuFooter, DropdownMenuGroup, DropdownMenuGroupLabel, DropdownMenuHeader, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemExtra, DropdownMenuItemIcon, DropdownMenuItemLabel, DropdownMenuPopup, DropdownMenuPortal, DropdownMenuPositioner, DropdownMenuRoot, DropdownMenuScrollViewport, DropdownMenuSeparator, DropdownMenuSubmenuArrow, DropdownMenuSubmenuRoot, DropdownMenuSubmenuTrigger, DropdownMenuTrigger, EditableText, EditorSlashMenu, EmojiPicker, Empty, ErrorBoundary, FileTypeIcon, FlexBasic_default as FlexBasic, FlexBasic_default as Flexbox, FluentEmoji, FontLoader, Footer, Form, FormGroup, FormItem, FormModal, FormSubmitFooter, FormTitle, Freeze, Grid, GroupAvatar, GuideCard, DEFAULT_HEIGHT as HTML_PREVIEW_DEFAULT_HEIGHT, DEFAULT_SANDBOX as HTML_PREVIEW_DEFAULT_SANDBOX, AUTO_HEIGHT_MESSAGE_TYPE as HTML_PREVIEW_RESIZE_MESSAGE, Header, Highlighter, Hotkey, HotkeyInput, HtmlPreview, HtmlPreviewIframe, I18nProvider, Icon, IconProvider, Image, ImageSelect, Input, InputNumber, InputOPT, InputPassword, KeyMapEnum, LOBE_THEME_APP_ID, Layout, LayoutFooter, LayoutHeader, LayoutMain, LayoutSidebar, LayoutSidebarInner, LayoutToc, List, ListItem, I18nProvider as LobeUIProvider, Markdown, MaskShadow, MaterialFileTypeIcon, Menu, Mermaid, Meta, Modal, ModalHost, ModalProvider, MotionComponent, MotionProvider, NeuralNetworkLoading, PatchDiff, Popover, PopoverArrow, PopoverArrowIcon, PopoverBackdrop, PopoverGroup, PopoverPopup, PopoverPortal, PopoverPositioner, PopoverProvider, PopoverRoot, PopoverTriggerElement, PopoverViewport, PreviewGroup, ScrollArea, ScrollAreaContent, ScrollAreaCorner, ScrollAreaRoot, ScrollAreaScrollbar, ScrollAreaThumb, ScrollAreaViewport, ScrollShadow, SearchBar, SearchResultCards, Segmented, Select, lobe_theme_default as ShikiLobeTheme, SideNav, Skeleton, SkeletonAvatar, SkeletonBlock, SkeletonButton, SkeletonParagraph, SkeletonTags, SkeletonTitle, SliderWithInput, Snippet, SortableList, SyntaxHighlighter, SyntaxMermaid, Tabs, Tag, Text, TextArea, ThemeProvider, ThemeSwitch, ToastHost, Toc, Tooltip, TooltipGroup, Typography, Video, closeContextMenu, combineKeys, copyToClipboard, createModal, createRawModal, findCustomThemeName, genCdnUrl, generateColorNeutralPalette, generateColorPalette, highlighterThemes, containsScript as htmlPreviewContainsScript, isFullHtmlDocument, isHtmlContentClosed, generateCustomStylish as lobeCustomStylish, generateCustomToken as lobeCustomToken, staticStylish as lobeStaticStylish, styles as menuSharedStyles, mermaidThemes, neutralColors, neutralColorsSwatches, placementMap, preprocessMarkdownContent, preventDefault, preventDefaultAndStopPropagation, primaryColors, primaryColorsSwatches, rehypeCustomFootnotes, rehypeKatexDir, rehypeStreamAnimated, remarkBr, remarkColor, remarkCustomFootnotes, remarkGfmPlus, remarkVideo, renderDropdownMenuItems, setContextMenuInterceptor, showContextMenu, stopPropagation, toFloatingUIPlacement, toast, updateContextMenuItems, useAppElement, useCdnFn, useModalContext, useMotionComponent, usePopoverContext, usePopoverGroupHandle, usePopoverPortalContainer, useToast, useTranslation };
|
|
165
|
+
export { A, Accordion, AccordionItem, ActionIcon, ActionIconGroup, Alert, AutoComplete, Avatar, AvatarGroup, Block, Burger, Button, CLASSNAMES, Center, Checkbox, CheckboxGroup, CodeDiff, CodeEditor, Collapse, ColorSwatches, ConfigProvider, ContextMenuHost, ContextMenuTrigger, CopyButton, DatePicker, DownloadButton, DraggablePanel, DraggablePanelBody, DraggablePanelContainer, DraggablePanelFooter, DraggablePanelHeader, DraggableSideNav, Drawer, Dropdown, DropdownMenu, DropdownMenuCheckboxItemIndicator, DropdownMenuCheckboxItemPrimitive, DropdownMenuFooter, DropdownMenuGroup, DropdownMenuGroupLabel, DropdownMenuHeader, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemExtra, DropdownMenuItemIcon, DropdownMenuItemLabel, DropdownMenuPopup, DropdownMenuPortal, DropdownMenuPositioner, DropdownMenuRoot, DropdownMenuScrollViewport, DropdownMenuSeparator, DropdownMenuSubmenuArrow, DropdownMenuSubmenuRoot, DropdownMenuSubmenuTrigger, DropdownMenuTrigger, EditableText, EditorSlashMenu, EmojiPicker, Empty, ErrorBoundary, FileTypeIcon, FlexBasic_default as FlexBasic, FlexBasic_default as Flexbox, FluentEmoji, FontLoader, Footer, Form, FormGroup, FormItem, FormModal, FormSubmitFooter, FormTitle, Freeze, Grid, GroupAvatar, GuideCard, DEFAULT_HEIGHT as HTML_PREVIEW_DEFAULT_HEIGHT, DEFAULT_SANDBOX as HTML_PREVIEW_DEFAULT_SANDBOX, AUTO_HEIGHT_MESSAGE_TYPE as HTML_PREVIEW_RESIZE_MESSAGE, Header, Highlighter, Hotkey, HotkeyInput, HtmlPreview, HtmlPreviewIframe, I18nProvider, Icon, IconProvider, Image, ImageSelect, Input, InputNumber, InputOPT, InputPassword, KeyMapEnum, LOBE_THEME_APP_ID, Layout, LayoutFooter, LayoutHeader, LayoutMain, LayoutSidebar, LayoutSidebarInner, LayoutToc, List, ListItem, I18nProvider as LobeUIProvider, Markdown, MaskShadow, MaterialFileTypeIcon, Menu, Mermaid, Meta, Modal, ModalHost, ModalProvider, MotionComponent, MotionProvider, NeuralNetworkLoading, PatchDiff, Popover, PopoverArrow, PopoverArrowIcon, PopoverBackdrop, PopoverGroup, PopoverPopup, PopoverPortal, PopoverPositioner, PopoverProvider, PopoverRoot, PopoverTriggerElement, PopoverViewport, PreviewGroup, ScrollArea, ScrollAreaContent, ScrollAreaCorner, ScrollAreaRoot, ScrollAreaScrollbar, ScrollAreaThumb, ScrollAreaViewport, ScrollShadow, SearchBar, SearchResultCards, Segmented, Select, lobe_theme_default as ShikiLobeTheme, SideNav, Skeleton, SkeletonAvatar, SkeletonBlock, SkeletonButton, SkeletonParagraph, SkeletonTags, SkeletonTitle, SliderWithInput, Snippet, SortableList, SyntaxHighlighter, SyntaxMermaid, Tabs, Tag, Text, TextArea, ThemeProvider, ThemeSwitch, ToastHost, Toc, Tooltip, TooltipGroup, Typography, Video, closeContextMenu, combineKeys, copyToClipboard, createModal, createRawModal, findCustomThemeName, genCdnUrl, generateColorNeutralPalette, generateColorPalette, highlighterThemes, containsScript as htmlPreviewContainsScript, installGlobalFocusRing, isFullHtmlDocument, isHtmlContentClosed, generateCustomStylish as lobeCustomStylish, generateCustomToken as lobeCustomToken, staticStylish as lobeStaticStylish, styles as menuSharedStyles, mermaidThemes, neutralColors, neutralColorsSwatches, placementMap, preprocessMarkdownContent, preventDefault, preventDefaultAndStopPropagation, primaryColors, primaryColorsSwatches, rehypeCustomFootnotes, rehypeKatexDir, rehypeStreamAnimated, remarkBr, remarkColor, remarkCustomFootnotes, remarkGfmPlus, remarkVideo, renderDropdownMenuItems, setContextMenuInterceptor, showContextMenu, stopPropagation, toFloatingUIPlacement, toast, updateContextMenuItems, useAppElement, useCdnFn, useModalContext, useMotionComponent, usePopoverContext, usePopoverGroupHandle, usePopoverPortalContainer, useToast, useTranslation };
|