@djangocfg/ui-tools 2.1.416 → 2.1.418
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audio-player/index.cjs +2098 -0
- package/dist/audio-player/index.cjs.map +1 -0
- package/dist/audio-player/index.css +65 -0
- package/dist/audio-player/index.css.map +1 -0
- package/dist/audio-player/index.d.cts +166 -0
- package/dist/audio-player/index.d.ts +166 -0
- package/dist/audio-player/index.mjs +2075 -0
- package/dist/audio-player/index.mjs.map +1 -0
- package/dist/composer-registry/index.cjs +45 -0
- package/dist/composer-registry/index.cjs.map +1 -0
- package/dist/composer-registry/index.d.cts +73 -0
- package/dist/composer-registry/index.d.ts +73 -0
- package/dist/composer-registry/index.mjs +39 -0
- package/dist/composer-registry/index.mjs.map +1 -0
- package/dist/tree/index.cjs +82 -63
- package/dist/tree/index.cjs.map +1 -1
- package/dist/tree/index.d.cts +15 -1
- package/dist/tree/index.d.ts +15 -1
- package/dist/tree/index.mjs +83 -64
- package/dist/tree/index.mjs.map +1 -1
- package/package.json +38 -17
- package/src/tools/chat/composer/Composer.tsx +8 -8
- package/src/tools/chat/context/ChatProvider.tsx +13 -78
- package/src/tools/chat/hooks/useAutoFocusOnStreamEnd.ts +12 -15
- package/src/tools/chat/hooks/useFocusOnEmptyClick.ts +4 -5
- package/src/tools/chat/launcher/header/ChatHeader.tsx +14 -19
- package/src/tools/chat/launcher/header/ChatHeaderActionButton.tsx +8 -12
- package/src/tools/data/Tree/TreeRoot.tsx +33 -109
- package/src/tools/data/Tree/context/TreeContext.tsx +22 -3
- package/src/tools/data/Tree/context/menu/index.ts +1 -0
- package/src/tools/data/Tree/context/menu/render.tsx +75 -0
- package/src/tools/data/Tree/context/menu/use-resolved-menu.ts +16 -2
- package/src/tools/data/Tree/index.tsx +1 -0
- package/src/tools/data/Tree/types/index.ts +1 -1
- package/src/tools/data/Tree/types/root-props.ts +16 -0
- package/src/tools/dev/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +6 -9
- package/src/tools/dev/OpenapiViewer/components/DocsLayout/index.tsx +2 -4
- package/src/tools/forms/CodeEditor/components/Editor.tsx +19 -0
- package/src/tools/forms/CodeEditor/types/index.ts +7 -0
- package/src/tools/forms/MarkdownEditor/MarkdownEditor.tsx +40 -0
- package/src/tools/forms/MarkdownEditor/styles.css +174 -21
- package/src/tools/forms/NotionEditor/CustomKeymap.ts +48 -0
- package/src/tools/forms/NotionEditor/LinkDialog.tsx +133 -0
- package/src/tools/forms/NotionEditor/NotionEditor.tsx +304 -0
- package/src/tools/forms/NotionEditor/SlashExtension.ts +32 -0
- package/src/tools/forms/NotionEditor/SlashList.tsx +136 -0
- package/src/tools/forms/NotionEditor/TaskItemView.tsx +41 -0
- package/src/tools/forms/NotionEditor/createSlashSuggestion.ts +121 -0
- package/src/tools/forms/NotionEditor/extensions.ts +105 -0
- package/src/tools/forms/NotionEditor/index.ts +1 -0
- package/src/tools/forms/NotionEditor/lazy.tsx +44 -0
- package/src/tools/forms/NotionEditor/slashItems.ts +159 -0
- package/src/tools/forms/NotionEditor/styles.css +478 -0
- package/src/tools/forms/NotionEditor/types.ts +28 -0
- package/src/tools/input/SpeechRecognition/widgets/VoiceComposerSlot.tsx +11 -12
- package/src/tools/integration/ComposerRegistry/index.ts +105 -0
- package/src/tools/media/AudioPlayer/Player.tsx +2 -0
- package/src/tools/media/AudioPlayer/PlayerShell.tsx +29 -22
- package/src/tools/media/AudioPlayer/lazy.tsx +30 -42
- package/src/tools/media/AudioPlayer/parts/Controls/IconButton.tsx +10 -11
- package/src/tools/media/AudioPlayer/parts/Controls/VolumeControl.tsx +52 -115
- package/src/tools/media/AudioPlayer/types.ts +8 -0
- package/src/tools/media/ImageViewer/components/ImageViewer.tsx +8 -0
- package/src/tools/media/ImageViewer/types.ts +4 -0
- package/src/tools/media/VideoPlayer/VideoPlayer.tsx +20 -1
- package/src/tools/media/VideoPlayer/types.ts +4 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal imperative handle every text-editor surface implements so
|
|
3
|
+
* an external tool (voice dictation, command palette, AI suggestion)
|
|
4
|
+
* can read/write its text content without traversing React.
|
|
5
|
+
*
|
|
6
|
+
* Methods are optional so a host can register a partial handle
|
|
7
|
+
* (e.g. only `getValue` + `setValue`), and the caller checks before use.
|
|
8
|
+
*/
|
|
9
|
+
interface ComposerHandle {
|
|
10
|
+
/** Move keyboard focus into the composer's editable surface. */
|
|
11
|
+
focus: () => void;
|
|
12
|
+
/** Move the caret to the very end of the input. */
|
|
13
|
+
moveCursorToEnd?: () => void;
|
|
14
|
+
/** Read the current draft text. Voice dictation anchors partial
|
|
15
|
+
* transcripts onto the user's already-typed prefix via this. */
|
|
16
|
+
getValue?: () => string;
|
|
17
|
+
/** Replace the current draft text. Voice dictation pushes interim
|
|
18
|
+
* and final transcripts through this without owning a controlled
|
|
19
|
+
* binding. */
|
|
20
|
+
setValue?: (value: string) => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* `@djangocfg/ui-tools/composer-registry`
|
|
24
|
+
*
|
|
25
|
+
* Cross-tool bridge: the currently-active text composer's handle.
|
|
26
|
+
*
|
|
27
|
+
* Producer side (`@djangocfg/ui-tools/chat` and TipTap hosts):
|
|
28
|
+
* register their composer's imperative handle via `attachComposer`.
|
|
29
|
+
*
|
|
30
|
+
* Consumer side (`@djangocfg/ui-tools/speech-recognition`):
|
|
31
|
+
* reads the active handle via `useActiveComposer`/`getActiveComposer`
|
|
32
|
+
* and pipes voice transcripts into it.
|
|
33
|
+
*
|
|
34
|
+
* Why this lives in its own subpath (not inside `chat`)
|
|
35
|
+
* ----------------------------------------------------
|
|
36
|
+
* `chat` and `speech-recognition` are sibling subpath exports. If the
|
|
37
|
+
* registry lived inside `chat`, then `speech-recognition` would have
|
|
38
|
+
* to reach into it via a cross-tool relative import — and under Vite
|
|
39
|
+
* dev's dependency optimizer that file ends up loaded TWICE (once via
|
|
40
|
+
* the `./chat` URL, once via the `./speech-recognition` relative-up
|
|
41
|
+
* URL), giving the producer and the consumer two separate `let active`
|
|
42
|
+
* slots. The active handle registered by chat would be invisible to
|
|
43
|
+
* speech-recognition (and vice versa).
|
|
44
|
+
*
|
|
45
|
+
* Putting the registry in its own dedicated subpath (a single tool
|
|
46
|
+
* that NEITHER chat nor speech-recognition cross-import — they both
|
|
47
|
+
* import this one as their dependency) means Vite resolves it from a
|
|
48
|
+
* single URL across the whole graph. One module instance, one shared
|
|
49
|
+
* `active` slot.
|
|
50
|
+
*
|
|
51
|
+
* Semantics: one active composer per realm. The most recent
|
|
52
|
+
* `registerComposer(handle)` wins; `registerComposer(null)` clears it.
|
|
53
|
+
*/
|
|
54
|
+
type Listener = (handle: ComposerHandle | null) => void;
|
|
55
|
+
/** Set or replace the active composer handle. Pass `null` to clear. */
|
|
56
|
+
declare function registerComposer(handle: ComposerHandle | null): void;
|
|
57
|
+
/**
|
|
58
|
+
* Convenience for components: register on mount, unregister on
|
|
59
|
+
* unmount. Returns a cleanup function suitable for `useEffect`.
|
|
60
|
+
*/
|
|
61
|
+
declare function attachComposer(handle: ComposerHandle): () => void;
|
|
62
|
+
/** Read the current active handle (no subscription). */
|
|
63
|
+
declare function getActiveComposer(): ComposerHandle | null;
|
|
64
|
+
/** Subscribe to handle changes; returns an unsubscribe fn. */
|
|
65
|
+
declare function subscribeComposer(listener: Listener): () => void;
|
|
66
|
+
/**
|
|
67
|
+
* React hook: re-renders the caller whenever the active composer
|
|
68
|
+
* changes. Built on `useSyncExternalStore` so concurrent rendering,
|
|
69
|
+
* SSR, and dev-mode strict-effects all behave correctly.
|
|
70
|
+
*/
|
|
71
|
+
declare function useActiveComposer(): ComposerHandle | null;
|
|
72
|
+
|
|
73
|
+
export { type ComposerHandle, attachComposer, getActiveComposer, registerComposer, subscribeComposer, useActiveComposer };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { __name } from '../chunk-PAWJFY3S.mjs';
|
|
2
|
+
import { useCallback, useSyncExternalStore } from 'react';
|
|
3
|
+
|
|
4
|
+
var active = null;
|
|
5
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
function registerComposer(handle) {
|
|
7
|
+
active = handle;
|
|
8
|
+
for (const fn of listeners) fn(active);
|
|
9
|
+
}
|
|
10
|
+
__name(registerComposer, "registerComposer");
|
|
11
|
+
function attachComposer(handle) {
|
|
12
|
+
registerComposer(handle);
|
|
13
|
+
return () => {
|
|
14
|
+
if (active === handle) registerComposer(null);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
__name(attachComposer, "attachComposer");
|
|
18
|
+
function getActiveComposer() {
|
|
19
|
+
return active;
|
|
20
|
+
}
|
|
21
|
+
__name(getActiveComposer, "getActiveComposer");
|
|
22
|
+
function subscribeComposer(listener) {
|
|
23
|
+
listeners.add(listener);
|
|
24
|
+
return () => {
|
|
25
|
+
listeners.delete(listener);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
__name(subscribeComposer, "subscribeComposer");
|
|
29
|
+
function useActiveComposer() {
|
|
30
|
+
const subscribe = useCallback((onChange) => {
|
|
31
|
+
return subscribeComposer(onChange);
|
|
32
|
+
}, []);
|
|
33
|
+
return useSyncExternalStore(subscribe, getActiveComposer, () => null);
|
|
34
|
+
}
|
|
35
|
+
__name(useActiveComposer, "useActiveComposer");
|
|
36
|
+
|
|
37
|
+
export { attachComposer, getActiveComposer, registerComposer, subscribeComposer, useActiveComposer };
|
|
38
|
+
//# sourceMappingURL=index.mjs.map
|
|
39
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/tools/integration/ComposerRegistry/index.ts"],"names":[],"mappings":";;;AA6DA,IAAI,MAAA,GAAgC,IAAA;AACpC,IAAM,SAAA,uBAAgB,GAAA,EAAc;AAG7B,SAAS,iBAAiB,MAAA,EAAqC;AACpE,EAAA,MAAA,GAAS,MAAA;AACT,EAAA,KAAA,MAAW,EAAA,IAAM,SAAA,EAAW,EAAA,CAAG,MAAM,CAAA;AACvC;AAHgB,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAST,SAAS,eAAe,MAAA,EAAoC;AACjE,EAAA,gBAAA,CAAiB,MAAM,CAAA;AACvB,EAAA,OAAO,MAAM;AACX,IAAA,IAAI,MAAA,KAAW,MAAA,EAAQ,gBAAA,CAAiB,IAAI,CAAA;AAAA,EAC9C,CAAA;AACF;AALgB,MAAA,CAAA,cAAA,EAAA,gBAAA,CAAA;AAQT,SAAS,iBAAA,GAA2C;AACzD,EAAA,OAAO,MAAA;AACT;AAFgB,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAKT,SAAS,kBAAkB,QAAA,EAAgC;AAChE,EAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,EAAA,OAAO,MAAM;AACX,IAAA,SAAA,CAAU,OAAO,QAAQ,CAAA;AAAA,EAC3B,CAAA;AACF;AALgB,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAYT,SAAS,iBAAA,GAA2C;AACzD,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,CAAC,QAAA,KAAyB;AACtD,IAAA,OAAO,kBAAkB,QAAQ,CAAA;AAAA,EACnC,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,OAAO,oBAAA,CAAqB,SAAA,EAAW,iBAAA,EAAmB,MAAM,IAAI,CAAA;AACtE;AALgB,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA","file":"index.mjs","sourcesContent":["'use client';\n\nimport { useCallback, useSyncExternalStore } from 'react';\n\n/**\n * Minimal imperative handle every text-editor surface implements so\n * an external tool (voice dictation, command palette, AI suggestion)\n * can read/write its text content without traversing React.\n *\n * Methods are optional so a host can register a partial handle\n * (e.g. only `getValue` + `setValue`), and the caller checks before use.\n */\nexport interface ComposerHandle {\n /** Move keyboard focus into the composer's editable surface. */\n focus: () => void;\n /** Move the caret to the very end of the input. */\n moveCursorToEnd?: () => void;\n /** Read the current draft text. Voice dictation anchors partial\n * transcripts onto the user's already-typed prefix via this. */\n getValue?: () => string;\n /** Replace the current draft text. Voice dictation pushes interim\n * and final transcripts through this without owning a controlled\n * binding. */\n setValue?: (value: string) => void;\n}\n\n/**\n * `@djangocfg/ui-tools/composer-registry`\n *\n * Cross-tool bridge: the currently-active text composer's handle.\n *\n * Producer side (`@djangocfg/ui-tools/chat` and TipTap hosts):\n * register their composer's imperative handle via `attachComposer`.\n *\n * Consumer side (`@djangocfg/ui-tools/speech-recognition`):\n * reads the active handle via `useActiveComposer`/`getActiveComposer`\n * and pipes voice transcripts into it.\n *\n * Why this lives in its own subpath (not inside `chat`)\n * ----------------------------------------------------\n * `chat` and `speech-recognition` are sibling subpath exports. If the\n * registry lived inside `chat`, then `speech-recognition` would have\n * to reach into it via a cross-tool relative import — and under Vite\n * dev's dependency optimizer that file ends up loaded TWICE (once via\n * the `./chat` URL, once via the `./speech-recognition` relative-up\n * URL), giving the producer and the consumer two separate `let active`\n * slots. The active handle registered by chat would be invisible to\n * speech-recognition (and vice versa).\n *\n * Putting the registry in its own dedicated subpath (a single tool\n * that NEITHER chat nor speech-recognition cross-import — they both\n * import this one as their dependency) means Vite resolves it from a\n * single URL across the whole graph. One module instance, one shared\n * `active` slot.\n *\n * Semantics: one active composer per realm. The most recent\n * `registerComposer(handle)` wins; `registerComposer(null)` clears it.\n */\n\ntype Listener = (handle: ComposerHandle | null) => void;\n\nlet active: ComposerHandle | null = null;\nconst listeners = new Set<Listener>();\n\n/** Set or replace the active composer handle. Pass `null` to clear. */\nexport function registerComposer(handle: ComposerHandle | null): void {\n active = handle;\n for (const fn of listeners) fn(active);\n}\n\n/**\n * Convenience for components: register on mount, unregister on\n * unmount. Returns a cleanup function suitable for `useEffect`.\n */\nexport function attachComposer(handle: ComposerHandle): () => void {\n registerComposer(handle);\n return () => {\n if (active === handle) registerComposer(null);\n };\n}\n\n/** Read the current active handle (no subscription). */\nexport function getActiveComposer(): ComposerHandle | null {\n return active;\n}\n\n/** Subscribe to handle changes; returns an unsubscribe fn. */\nexport function subscribeComposer(listener: Listener): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\n/**\n * React hook: re-renders the caller whenever the active composer\n * changes. Built on `useSyncExternalStore` so concurrent rendering,\n * SSR, and dev-mode strict-effects all behave correctly.\n */\nexport function useActiveComposer(): ComposerHandle | null {\n const subscribe = useCallback((onChange: () => void) => {\n return subscribeComposer(onChange);\n }, []);\n return useSyncExternalStore(subscribe, getActiveComposer, () => null);\n}\n"]}
|
package/dist/tree/index.cjs
CHANGED
|
@@ -5,9 +5,9 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var chunkPK6SKIKE_cjs = require('../chunk-PK6SKIKE.cjs');
|
|
6
6
|
var React = require('react');
|
|
7
7
|
var lib = require('@djangocfg/ui-core/lib');
|
|
8
|
-
var components = require('@djangocfg/ui-core/components');
|
|
9
8
|
var dialogService = require('@djangocfg/ui-core/lib/dialog-service');
|
|
10
9
|
var lucideReact = require('lucide-react');
|
|
10
|
+
var components = require('@djangocfg/ui-core/components');
|
|
11
11
|
var jsxRuntime = require('react/jsx-runtime');
|
|
12
12
|
var core = require('@dnd-kit/core');
|
|
13
13
|
var hooks = require('@djangocfg/ui-core/hooks');
|
|
@@ -1071,6 +1071,47 @@ function useResolvedMenu(opts) {
|
|
|
1071
1071
|
]);
|
|
1072
1072
|
}
|
|
1073
1073
|
chunkPK6SKIKE_cjs.__name(useResolvedMenu, "useResolvedMenu");
|
|
1074
|
+
function renderItemsAsContextMenu(rowProps, items, trigger) {
|
|
1075
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(components.ContextMenu, { children: [
|
|
1076
|
+
/* @__PURE__ */ jsxRuntime.jsx(components.ContextMenuTrigger, { asChild: true, children: trigger }),
|
|
1077
|
+
/* @__PURE__ */ jsxRuntime.jsx(components.ContextMenuContent, { children: items.map((item, idx) => {
|
|
1078
|
+
if (item === "separator") {
|
|
1079
|
+
return /* @__PURE__ */ jsxRuntime.jsx(components.ContextMenuSeparator, {}, `sep-${idx}`);
|
|
1080
|
+
}
|
|
1081
|
+
const Icon = item.icon;
|
|
1082
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1083
|
+
components.ContextMenuItem,
|
|
1084
|
+
{
|
|
1085
|
+
disabled: item.disabled,
|
|
1086
|
+
variant: item.destructive ? "destructive" : void 0,
|
|
1087
|
+
onSelect: () => item.onSelect(rowProps),
|
|
1088
|
+
children: [
|
|
1089
|
+
Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, {}) : null,
|
|
1090
|
+
item.label,
|
|
1091
|
+
item.shortcut ? /* @__PURE__ */ jsxRuntime.jsx(components.ContextMenuShortcut, { children: item.shortcut }) : null
|
|
1092
|
+
]
|
|
1093
|
+
},
|
|
1094
|
+
item.id
|
|
1095
|
+
);
|
|
1096
|
+
}) })
|
|
1097
|
+
] });
|
|
1098
|
+
}
|
|
1099
|
+
chunkPK6SKIKE_cjs.__name(renderItemsAsContextMenu, "renderItemsAsContextMenu");
|
|
1100
|
+
function tidyMenuItems(items) {
|
|
1101
|
+
const out = [];
|
|
1102
|
+
for (const it of items) {
|
|
1103
|
+
if (it === "separator") {
|
|
1104
|
+
if (out.length === 0) continue;
|
|
1105
|
+
if (out[out.length - 1] === "separator") continue;
|
|
1106
|
+
out.push(it);
|
|
1107
|
+
} else {
|
|
1108
|
+
out.push(it);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
while (out.length > 0 && out[out.length - 1] === "separator") out.pop();
|
|
1112
|
+
return out;
|
|
1113
|
+
}
|
|
1114
|
+
chunkPK6SKIKE_cjs.__name(tidyMenuItems, "tidyMenuItems");
|
|
1074
1115
|
|
|
1075
1116
|
// src/tools/data/Tree/data/dnd.ts
|
|
1076
1117
|
function resolveDropZone(input) {
|
|
@@ -1435,6 +1476,20 @@ function TreeProvider(props) {
|
|
|
1435
1476
|
copyToClipboard: clipboard.copyToClipboard,
|
|
1436
1477
|
pasteFromClipboard: clipboard.pasteFromClipboard
|
|
1437
1478
|
});
|
|
1479
|
+
const finalRenderContextMenu = React.useMemo(
|
|
1480
|
+
() => {
|
|
1481
|
+
if (renderContextMenu) return renderContextMenu;
|
|
1482
|
+
const resolve = resolvedContextMenuActions;
|
|
1483
|
+
if (!resolve) return void 0;
|
|
1484
|
+
return (rowProps, trigger) => {
|
|
1485
|
+
const items = resolve(rowProps);
|
|
1486
|
+
const cleaned = items ? tidyMenuItems(items) : null;
|
|
1487
|
+
if (!cleaned || cleaned.length === 0) return trigger;
|
|
1488
|
+
return renderItemsAsContextMenu(rowProps, cleaned, trigger);
|
|
1489
|
+
};
|
|
1490
|
+
},
|
|
1491
|
+
[renderContextMenu, resolvedContextMenuActions]
|
|
1492
|
+
);
|
|
1438
1493
|
const value = React.useMemo(
|
|
1439
1494
|
() => ({
|
|
1440
1495
|
// state
|
|
@@ -1476,7 +1531,7 @@ function TreeProvider(props) {
|
|
|
1476
1531
|
renderIcon,
|
|
1477
1532
|
renderLabel,
|
|
1478
1533
|
renderActions,
|
|
1479
|
-
renderContextMenu,
|
|
1534
|
+
renderContextMenu: finalRenderContextMenu,
|
|
1480
1535
|
adapter,
|
|
1481
1536
|
resolvedContextMenuActions,
|
|
1482
1537
|
getNodeById: /* @__PURE__ */ chunkPK6SKIKE_cjs.__name((id) => nodeById.get(id), "getNodeById"),
|
|
@@ -1513,7 +1568,7 @@ function TreeProvider(props) {
|
|
|
1513
1568
|
renderIcon,
|
|
1514
1569
|
renderLabel,
|
|
1515
1570
|
renderActions,
|
|
1516
|
-
|
|
1571
|
+
finalRenderContextMenu,
|
|
1517
1572
|
adapter,
|
|
1518
1573
|
resolvedContextMenuActions,
|
|
1519
1574
|
nodeById,
|
|
@@ -2789,47 +2844,6 @@ function useTreeFinderHotkeys(opts) {
|
|
|
2789
2844
|
return { ref };
|
|
2790
2845
|
}
|
|
2791
2846
|
chunkPK6SKIKE_cjs.__name(useTreeFinderHotkeys, "useTreeFinderHotkeys");
|
|
2792
|
-
function renderItemsAsContextMenu(rowProps, items, trigger) {
|
|
2793
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(components.ContextMenu, { children: [
|
|
2794
|
-
/* @__PURE__ */ jsxRuntime.jsx(components.ContextMenuTrigger, { asChild: true, children: trigger }),
|
|
2795
|
-
/* @__PURE__ */ jsxRuntime.jsx(components.ContextMenuContent, { children: items.map((item, idx) => {
|
|
2796
|
-
if (item === "separator") {
|
|
2797
|
-
return /* @__PURE__ */ jsxRuntime.jsx(components.ContextMenuSeparator, {}, `sep-${idx}`);
|
|
2798
|
-
}
|
|
2799
|
-
const Icon = item.icon;
|
|
2800
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2801
|
-
components.ContextMenuItem,
|
|
2802
|
-
{
|
|
2803
|
-
disabled: item.disabled,
|
|
2804
|
-
variant: item.destructive ? "destructive" : void 0,
|
|
2805
|
-
onSelect: () => item.onSelect(rowProps),
|
|
2806
|
-
children: [
|
|
2807
|
-
Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, {}) : null,
|
|
2808
|
-
item.label,
|
|
2809
|
-
item.shortcut ? /* @__PURE__ */ jsxRuntime.jsx(components.ContextMenuShortcut, { children: item.shortcut }) : null
|
|
2810
|
-
]
|
|
2811
|
-
},
|
|
2812
|
-
item.id
|
|
2813
|
-
);
|
|
2814
|
-
}) })
|
|
2815
|
-
] });
|
|
2816
|
-
}
|
|
2817
|
-
chunkPK6SKIKE_cjs.__name(renderItemsAsContextMenu, "renderItemsAsContextMenu");
|
|
2818
|
-
function tidyMenuItems(items) {
|
|
2819
|
-
const out = [];
|
|
2820
|
-
for (const it of items) {
|
|
2821
|
-
if (it === "separator") {
|
|
2822
|
-
if (out.length === 0) continue;
|
|
2823
|
-
if (out[out.length - 1] === "separator") continue;
|
|
2824
|
-
out.push(it);
|
|
2825
|
-
} else {
|
|
2826
|
-
out.push(it);
|
|
2827
|
-
}
|
|
2828
|
-
}
|
|
2829
|
-
while (out.length > 0 && out[out.length - 1] === "separator") out.pop();
|
|
2830
|
-
return out;
|
|
2831
|
-
}
|
|
2832
|
-
chunkPK6SKIKE_cjs.__name(tidyMenuItems, "tidyMenuItems");
|
|
2833
2847
|
function TreeRoot(props) {
|
|
2834
2848
|
const {
|
|
2835
2849
|
data,
|
|
@@ -2863,6 +2877,7 @@ function TreeRoot(props) {
|
|
|
2863
2877
|
persistSelection = false,
|
|
2864
2878
|
adapter,
|
|
2865
2879
|
defaultMenuItems,
|
|
2880
|
+
actionsRef,
|
|
2866
2881
|
className,
|
|
2867
2882
|
style
|
|
2868
2883
|
} = props;
|
|
@@ -2905,7 +2920,8 @@ function TreeRoot(props) {
|
|
|
2905
2920
|
enableSearch,
|
|
2906
2921
|
enableTypeAhead,
|
|
2907
2922
|
enableFinderHotkeys,
|
|
2908
|
-
renderRow
|
|
2923
|
+
renderRow,
|
|
2924
|
+
actionsRef
|
|
2909
2925
|
}
|
|
2910
2926
|
)
|
|
2911
2927
|
}
|
|
@@ -2918,10 +2934,29 @@ function TreeRootShell({
|
|
|
2918
2934
|
enableSearch,
|
|
2919
2935
|
enableTypeAhead,
|
|
2920
2936
|
enableFinderHotkeys,
|
|
2921
|
-
renderRow
|
|
2937
|
+
renderRow,
|
|
2938
|
+
actionsRef
|
|
2922
2939
|
}) {
|
|
2923
2940
|
const containerRef = React.useRef(null);
|
|
2924
2941
|
const ctx = useTreeContext();
|
|
2942
|
+
React.useEffect(() => {
|
|
2943
|
+
if (!actionsRef) return;
|
|
2944
|
+
actionsRef.current = {
|
|
2945
|
+
refresh: ctx.refresh,
|
|
2946
|
+
refreshAll: ctx.refreshAll,
|
|
2947
|
+
expandAll: ctx.expandAll,
|
|
2948
|
+
collapseAll: ctx.collapseAll
|
|
2949
|
+
};
|
|
2950
|
+
return () => {
|
|
2951
|
+
if (actionsRef.current) actionsRef.current = null;
|
|
2952
|
+
};
|
|
2953
|
+
}, [
|
|
2954
|
+
actionsRef,
|
|
2955
|
+
ctx.refresh,
|
|
2956
|
+
ctx.refreshAll,
|
|
2957
|
+
ctx.expandAll,
|
|
2958
|
+
ctx.collapseAll
|
|
2959
|
+
]);
|
|
2925
2960
|
const isMulti = ctx.selectionMode === "multiple";
|
|
2926
2961
|
const { ref: keyboardRef } = useTreeKeyboard({
|
|
2927
2962
|
rows: ctx.flatRows,
|
|
@@ -2998,21 +3033,6 @@ function TreeRootShell({
|
|
|
2998
3033
|
onMatch: onTypeAheadMatch,
|
|
2999
3034
|
enabled: enableTypeAhead
|
|
3000
3035
|
});
|
|
3001
|
-
const finalRenderContextMenu = React.useMemo(() => {
|
|
3002
|
-
if (ctx.renderContextMenu) return ctx.renderContextMenu;
|
|
3003
|
-
const resolve = ctx.resolvedContextMenuActions;
|
|
3004
|
-
if (!resolve) return void 0;
|
|
3005
|
-
return (rowProps, trigger) => {
|
|
3006
|
-
const items = resolve(rowProps);
|
|
3007
|
-
const cleaned = items ? tidyMenuItems(items) : null;
|
|
3008
|
-
if (!cleaned || cleaned.length === 0) return trigger;
|
|
3009
|
-
return renderItemsAsContextMenu(rowProps, cleaned, trigger);
|
|
3010
|
-
};
|
|
3011
|
-
}, [ctx.renderContextMenu, ctx.resolvedContextMenuActions]);
|
|
3012
|
-
const childCtx = React.useMemo(
|
|
3013
|
-
() => ({ ...ctx, renderContextMenu: finalRenderContextMenu }),
|
|
3014
|
-
[ctx, finalRenderContextMenu]
|
|
3015
|
-
);
|
|
3016
3036
|
const treeBody = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3017
3037
|
"div",
|
|
3018
3038
|
{
|
|
@@ -3038,8 +3058,7 @@ function TreeRootShell({
|
|
|
3038
3058
|
]
|
|
3039
3059
|
}
|
|
3040
3060
|
);
|
|
3041
|
-
|
|
3042
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TreeDndProvider, { children: body });
|
|
3061
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TreeDndProvider, { children: treeBody });
|
|
3043
3062
|
}
|
|
3044
3063
|
chunkPK6SKIKE_cjs.__name(TreeRootShell, "TreeRootShell");
|
|
3045
3064
|
var TreeRoot_default = TreeRoot;
|