@djangocfg/ui-tools 2.1.429 → 2.1.431
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/tree/index.cjs +43 -8
- package/dist/tree/index.cjs.map +1 -1
- package/dist/tree/index.d.cts +31 -1
- package/dist/tree/index.d.ts +31 -1
- package/dist/tree/index.mjs +43 -8
- package/dist/tree/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/tools/chat/README.md +21 -0
- package/src/tools/chat/composer/PastedTextDialog.tsx +88 -0
- package/src/tools/chat/composer/index.ts +9 -0
- package/src/tools/chat/composer/textToAttachment.ts +69 -0
- package/src/tools/chat/composer/types.ts +13 -0
- package/src/tools/chat/composer/useComposerAttach.tsx +47 -0
- package/src/tools/chat/messages/Attachments.tsx +72 -8
- package/src/tools/chat/types/attachment.ts +12 -1
- package/src/tools/data/Tree/README.md +30 -0
- package/src/tools/data/Tree/components/TreeRow.tsx +11 -2
- package/src/tools/data/Tree/context/menu/render.tsx +56 -27
- package/src/tools/data/Tree/data/appearance.ts +65 -3
- package/src/tools/data/Tree/data/index.ts +2 -0
- package/src/tools/data/Tree/index.tsx +2 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { useState } from 'react';
|
|
3
4
|
import {
|
|
4
5
|
ContextMenu,
|
|
5
6
|
ContextMenuContent,
|
|
@@ -14,6 +15,60 @@ import type {
|
|
|
14
15
|
TreeRowRenderProps,
|
|
15
16
|
} from '../../types';
|
|
16
17
|
|
|
18
|
+
interface RowContextMenuProps<T> {
|
|
19
|
+
rowProps: TreeRowRenderProps<T>;
|
|
20
|
+
items: TreeContextMenuItem<T>[];
|
|
21
|
+
trigger: React.ReactNode;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Per-row context menu.
|
|
26
|
+
*
|
|
27
|
+
* PERF: every visible row wraps its trigger in a `<ContextMenu>`, so a
|
|
28
|
+
* large tree mounts hundreds of these. Building the full
|
|
29
|
+
* `<ContextMenuContent>` item subtree for each of them on every render is
|
|
30
|
+
* what made right-click feel laggy (the selection change on right-click
|
|
31
|
+
* re-renders all rows, each rebuilding its menu body). We now render the
|
|
32
|
+
* content body ONLY while this row's menu is actually open — closed rows
|
|
33
|
+
* cost just the lightweight `ContextMenu` + `Trigger` shell.
|
|
34
|
+
*/
|
|
35
|
+
function RowContextMenu<T>({
|
|
36
|
+
rowProps,
|
|
37
|
+
items,
|
|
38
|
+
trigger,
|
|
39
|
+
}: RowContextMenuProps<T>) {
|
|
40
|
+
const [open, setOpen] = useState(false);
|
|
41
|
+
return (
|
|
42
|
+
<ContextMenu onOpenChange={setOpen}>
|
|
43
|
+
<ContextMenuTrigger asChild>{trigger}</ContextMenuTrigger>
|
|
44
|
+
{open ? (
|
|
45
|
+
<ContextMenuContent>
|
|
46
|
+
{items.map((item, idx) => {
|
|
47
|
+
if (item === 'separator') {
|
|
48
|
+
return <ContextMenuSeparator key={`sep-${idx}`} />;
|
|
49
|
+
}
|
|
50
|
+
const Icon = item.icon;
|
|
51
|
+
return (
|
|
52
|
+
<ContextMenuItem
|
|
53
|
+
key={item.id}
|
|
54
|
+
disabled={item.disabled}
|
|
55
|
+
variant={item.destructive ? 'destructive' : undefined}
|
|
56
|
+
onSelect={() => item.onSelect(rowProps)}
|
|
57
|
+
>
|
|
58
|
+
{Icon ? <Icon /> : null}
|
|
59
|
+
{item.label}
|
|
60
|
+
{item.shortcut ? (
|
|
61
|
+
<ContextMenuShortcut>{item.shortcut}</ContextMenuShortcut>
|
|
62
|
+
) : null}
|
|
63
|
+
</ContextMenuItem>
|
|
64
|
+
);
|
|
65
|
+
})}
|
|
66
|
+
</ContextMenuContent>
|
|
67
|
+
) : null}
|
|
68
|
+
</ContextMenu>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
17
72
|
/**
|
|
18
73
|
* Render an array of declarative menu items as a themed `<ContextMenu>`
|
|
19
74
|
* wrapped around the supplied trigger element. Pure presentational layer
|
|
@@ -24,33 +79,7 @@ export function renderItemsAsContextMenu<T>(
|
|
|
24
79
|
items: TreeContextMenuItem<T>[],
|
|
25
80
|
trigger: React.ReactNode,
|
|
26
81
|
): React.ReactNode {
|
|
27
|
-
return
|
|
28
|
-
<ContextMenu>
|
|
29
|
-
<ContextMenuTrigger asChild>{trigger}</ContextMenuTrigger>
|
|
30
|
-
<ContextMenuContent>
|
|
31
|
-
{items.map((item, idx) => {
|
|
32
|
-
if (item === 'separator') {
|
|
33
|
-
return <ContextMenuSeparator key={`sep-${idx}`} />;
|
|
34
|
-
}
|
|
35
|
-
const Icon = item.icon;
|
|
36
|
-
return (
|
|
37
|
-
<ContextMenuItem
|
|
38
|
-
key={item.id}
|
|
39
|
-
disabled={item.disabled}
|
|
40
|
-
variant={item.destructive ? 'destructive' : undefined}
|
|
41
|
-
onSelect={() => item.onSelect(rowProps)}
|
|
42
|
-
>
|
|
43
|
-
{Icon ? <Icon /> : null}
|
|
44
|
-
{item.label}
|
|
45
|
-
{item.shortcut ? (
|
|
46
|
-
<ContextMenuShortcut>{item.shortcut}</ContextMenuShortcut>
|
|
47
|
-
) : null}
|
|
48
|
-
</ContextMenuItem>
|
|
49
|
-
);
|
|
50
|
-
})}
|
|
51
|
-
</ContextMenuContent>
|
|
52
|
-
</ContextMenu>
|
|
53
|
-
);
|
|
82
|
+
return <RowContextMenu rowProps={rowProps} items={items} trigger={trigger} />;
|
|
54
83
|
}
|
|
55
84
|
|
|
56
85
|
/**
|
|
@@ -6,6 +6,20 @@ export type TreeDensity = 'compact' | 'cozy' | 'comfortable';
|
|
|
6
6
|
export type TreeAccentIntensity = 'subtle' | 'default' | 'strong';
|
|
7
7
|
export type TreeRadius = 'none' | 'sm' | 'md';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* High-level look. Sets sensible defaults for icons / row sizing / the
|
|
11
|
+
* active indicator; any individual `TreeAppearance` field still overrides.
|
|
12
|
+
*
|
|
13
|
+
* - `'explorer'` (default) — classic file/folder tree: leaf + folder
|
|
14
|
+
* icons, fixed single-line rows, VSCode active-bar.
|
|
15
|
+
* - `'list'` — macOS-sidebar / chat-history look: no icons (chevron
|
|
16
|
+
* only on groups), auto-height rows (multi-line label friendly), quiet
|
|
17
|
+
* selection (no active-bar).
|
|
18
|
+
*/
|
|
19
|
+
export type TreeVariant = 'explorer' | 'list';
|
|
20
|
+
|
|
21
|
+
export type TreeRowSizing = 'fixed' | 'auto';
|
|
22
|
+
|
|
9
23
|
/**
|
|
10
24
|
* Cosmetic configuration. Every field is optional; missing values fall
|
|
11
25
|
* back to the `cozy` preset (a comfortable VSCode-Explorer-like density).
|
|
@@ -38,6 +52,21 @@ export interface TreeAppearance {
|
|
|
38
52
|
* Mimics the VSCode active-tab indicator. Default: `true`.
|
|
39
53
|
*/
|
|
40
54
|
showActiveIndicator?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* High-level look. Default: `'explorer'`. Sets defaults for the three
|
|
57
|
+
* fields below; pass any of them explicitly to override the variant.
|
|
58
|
+
*/
|
|
59
|
+
variant?: TreeVariant;
|
|
60
|
+
/** Hide per-leaf icons (chevron + label only). Variant default. */
|
|
61
|
+
hideLeafIcons?: boolean;
|
|
62
|
+
/** Hide folder icons too (chevron stays). Variant default. */
|
|
63
|
+
hideFolderIcons?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* `'fixed'` — every row is exactly `rowHeight` (single-line explorer).
|
|
66
|
+
* `'auto'` — `rowHeight` is a *minimum*; rows grow to fit a multi-line
|
|
67
|
+
* label (title + meta). Variant default.
|
|
68
|
+
*/
|
|
69
|
+
rowSizing?: TreeRowSizing;
|
|
41
70
|
}
|
|
42
71
|
|
|
43
72
|
export interface ResolvedAppearance {
|
|
@@ -52,6 +81,9 @@ export interface ResolvedAppearance {
|
|
|
52
81
|
radius: TreeRadius;
|
|
53
82
|
indentGuideOpacity: number;
|
|
54
83
|
showActiveIndicator: boolean;
|
|
84
|
+
hideLeafIcons: boolean;
|
|
85
|
+
hideFolderIcons: boolean;
|
|
86
|
+
rowSizing: TreeRowSizing;
|
|
55
87
|
}
|
|
56
88
|
|
|
57
89
|
const DENSITY_PRESETS: Record<
|
|
@@ -63,6 +95,31 @@ const DENSITY_PRESETS: Record<
|
|
|
63
95
|
comfortable: { rowHeight: 32, iconSize: 16, fontSize: 14, gap: 8 },
|
|
64
96
|
};
|
|
65
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Per-variant defaults for the icon / sizing / indicator fields. The
|
|
100
|
+
* `'list'` variant is the macOS-sidebar / chat-history look.
|
|
101
|
+
*/
|
|
102
|
+
const VARIANT_DEFAULTS: Record<
|
|
103
|
+
TreeVariant,
|
|
104
|
+
Pick<
|
|
105
|
+
ResolvedAppearance,
|
|
106
|
+
'hideLeafIcons' | 'hideFolderIcons' | 'rowSizing' | 'showActiveIndicator'
|
|
107
|
+
>
|
|
108
|
+
> = {
|
|
109
|
+
explorer: {
|
|
110
|
+
hideLeafIcons: false,
|
|
111
|
+
hideFolderIcons: false,
|
|
112
|
+
rowSizing: 'fixed',
|
|
113
|
+
showActiveIndicator: true,
|
|
114
|
+
},
|
|
115
|
+
list: {
|
|
116
|
+
hideLeafIcons: true,
|
|
117
|
+
hideFolderIcons: true,
|
|
118
|
+
rowSizing: 'auto',
|
|
119
|
+
showActiveIndicator: false,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
66
123
|
export const DEFAULT_TREE_APPEARANCE: ResolvedAppearance = {
|
|
67
124
|
density: 'cozy',
|
|
68
125
|
...DENSITY_PRESETS.cozy,
|
|
@@ -71,7 +128,7 @@ export const DEFAULT_TREE_APPEARANCE: ResolvedAppearance = {
|
|
|
71
128
|
accent: 'default',
|
|
72
129
|
radius: 'sm',
|
|
73
130
|
indentGuideOpacity: 0.4,
|
|
74
|
-
|
|
131
|
+
...VARIANT_DEFAULTS.explorer,
|
|
75
132
|
};
|
|
76
133
|
|
|
77
134
|
/**
|
|
@@ -88,6 +145,9 @@ export function resolveAppearance(
|
|
|
88
145
|
|
|
89
146
|
const density: TreeDensity = input?.density ?? 'cozy';
|
|
90
147
|
const preset = DENSITY_PRESETS[density];
|
|
148
|
+
// Variant sets the icon/sizing/indicator defaults; explicit fields win.
|
|
149
|
+
const variant: TreeVariant = input?.variant ?? 'explorer';
|
|
150
|
+
const v = VARIANT_DEFAULTS[variant];
|
|
91
151
|
|
|
92
152
|
return {
|
|
93
153
|
density,
|
|
@@ -101,8 +161,10 @@ export function resolveAppearance(
|
|
|
101
161
|
radius: input?.radius ?? DEFAULT_TREE_APPEARANCE.radius,
|
|
102
162
|
indentGuideOpacity:
|
|
103
163
|
input?.indentGuideOpacity ?? DEFAULT_TREE_APPEARANCE.indentGuideOpacity,
|
|
104
|
-
showActiveIndicator:
|
|
105
|
-
|
|
164
|
+
showActiveIndicator: input?.showActiveIndicator ?? v.showActiveIndicator,
|
|
165
|
+
hideLeafIcons: input?.hideLeafIcons ?? v.hideLeafIcons,
|
|
166
|
+
hideFolderIcons: input?.hideFolderIcons ?? v.hideFolderIcons,
|
|
167
|
+
rowSizing: input?.rowSizing ?? v.rowSizing,
|
|
106
168
|
};
|
|
107
169
|
}
|
|
108
170
|
|