torch-glare 2.1.2 → 2.1.3
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/apps/lib/components/Avatar.tsx +1 -1
- package/apps/lib/components/Card.tsx +68 -54
- package/apps/lib/components/DataViews/DataViewRadio.tsx +47 -0
- package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +56 -45
- package/apps/lib/components/DataViews/DataViewsHeader.tsx +130 -28
- package/apps/lib/components/DataViews/DataViewsLayout.tsx +32 -2
- package/apps/lib/components/DataViews/FilterPanel.tsx +148 -3
- package/apps/lib/components/DataViews/HeaderSearch.tsx +97 -0
- package/apps/lib/components/DataViews/InboxView.tsx +263 -282
- package/apps/lib/components/DataViews/InboxViewCard.tsx +136 -0
- package/apps/lib/components/DataViews/KanbanView.tsx +264 -153
- package/apps/lib/components/DataViews/PanelControls.tsx +10 -41
- package/apps/lib/components/DataViews/TreeView.tsx +220 -191
- package/apps/lib/components/DataViews/index.ts +6 -0
- package/apps/lib/components/DataViews/types.ts +30 -1
- package/apps/lib/components/Radio.tsx +18 -21
- package/apps/lib/components/Switch.tsx +3 -1
- package/apps/lib/components/Table.tsx +1 -1
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +160 -137
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +221 -93
- package/apps/lib/components/TreeFolder/types.ts +9 -0
- package/apps/lib/layouts/DataViewCard.tsx +76 -0
- package/dist/src/shared/copyComponentsRecursively.js +9 -1
- package/dist/src/shared/copyComponentsRecursively.js.map +1 -1
- package/docs/components/data-views-config-panel.md +204 -0
- package/docs/components/data-views-layout.md +270 -0
- package/package.json +1 -1
|
@@ -1,47 +1,44 @@
|
|
|
1
|
-
"use client"
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import { ChevronRight, ChevronDown, GripVertical } from "lucide-react"
|
|
4
|
-
import type { DragEvent } from "react"
|
|
5
|
-
import { cn } from "../../utils/cn"
|
|
6
|
-
import { resolveIcon } from "./icons"
|
|
7
|
-
import type {
|
|
8
|
-
TreeFolderIconResolver,
|
|
9
|
-
TreeFolderVisibleRow,
|
|
10
|
-
} from "./types"
|
|
3
|
+
import { ChevronRight, ChevronDown, GripVertical } from "lucide-react";
|
|
4
|
+
import type { DragEvent } from "react";
|
|
5
|
+
import { cn } from "../../utils/cn";
|
|
6
|
+
import { resolveIcon } from "./icons";
|
|
7
|
+
import type { TreeFolderIconResolver, TreeFolderVisibleRow } from "./types";
|
|
11
8
|
|
|
12
9
|
export type TreeFolderRowDragHandlers = {
|
|
13
|
-
draggable: boolean
|
|
14
|
-
onDragStart: (e: DragEvent<HTMLElement>) => void
|
|
15
|
-
onDragEnd: (e: DragEvent<HTMLElement>) => void
|
|
16
|
-
onDragOver: (e: DragEvent<HTMLElement>) => void
|
|
17
|
-
onDragLeave: (e: DragEvent<HTMLElement>) => void
|
|
18
|
-
onDrop: (e: DragEvent<HTMLElement>) => void
|
|
19
|
-
}
|
|
10
|
+
draggable: boolean;
|
|
11
|
+
onDragStart: (e: DragEvent<HTMLElement>) => void;
|
|
12
|
+
onDragEnd: (e: DragEvent<HTMLElement>) => void;
|
|
13
|
+
onDragOver: (e: DragEvent<HTMLElement>) => void;
|
|
14
|
+
onDragLeave: (e: DragEvent<HTMLElement>) => void;
|
|
15
|
+
onDrop: (e: DragEvent<HTMLElement>) => void;
|
|
16
|
+
};
|
|
20
17
|
|
|
21
18
|
export type TreeFolderRowProps = {
|
|
22
|
-
row: TreeFolderVisibleRow
|
|
23
|
-
rowHeight: number
|
|
24
|
-
indent: number
|
|
25
|
-
iconFor?: TreeFolderIconResolver
|
|
26
|
-
|
|
27
|
-
isSelected: boolean
|
|
28
|
-
isAncestor: boolean
|
|
29
|
-
isDescendantOfSelected: boolean
|
|
19
|
+
row: TreeFolderVisibleRow;
|
|
20
|
+
rowHeight: number;
|
|
21
|
+
indent: number;
|
|
22
|
+
iconFor?: TreeFolderIconResolver;
|
|
23
|
+
|
|
24
|
+
isSelected: boolean;
|
|
25
|
+
isAncestor: boolean;
|
|
26
|
+
isDescendantOfSelected: boolean;
|
|
30
27
|
/** True when the previous visible row is part of the same selected-subtree band. */
|
|
31
|
-
isPrevInBand: boolean
|
|
28
|
+
isPrevInBand: boolean;
|
|
32
29
|
/** True when the next visible row is part of the same selected-subtree band. */
|
|
33
|
-
isNextInBand: boolean
|
|
30
|
+
isNextInBand: boolean;
|
|
34
31
|
|
|
35
|
-
isDragging: boolean
|
|
36
|
-
isDropTargetInside: boolean
|
|
37
|
-
isDropBefore: boolean
|
|
38
|
-
isDropAfter: boolean
|
|
32
|
+
isDragging: boolean;
|
|
33
|
+
isDropTargetInside: boolean;
|
|
34
|
+
isDropBefore: boolean;
|
|
35
|
+
isDropAfter: boolean;
|
|
39
36
|
|
|
40
|
-
dndEnabled: boolean
|
|
41
|
-
onSelect: (id: string | null) => void
|
|
42
|
-
onToggle: (id: string) => void
|
|
43
|
-
dragHandlers: TreeFolderRowDragHandlers
|
|
44
|
-
}
|
|
37
|
+
dndEnabled: boolean;
|
|
38
|
+
onSelect: (id: string | null) => void;
|
|
39
|
+
onToggle: (id: string) => void;
|
|
40
|
+
dragHandlers: TreeFolderRowDragHandlers;
|
|
41
|
+
};
|
|
45
42
|
|
|
46
43
|
export function TreeFolderRow({
|
|
47
44
|
row,
|
|
@@ -62,83 +59,134 @@ export function TreeFolderRow({
|
|
|
62
59
|
onToggle,
|
|
63
60
|
dragHandlers,
|
|
64
61
|
}: TreeFolderRowProps) {
|
|
65
|
-
const { node, level, isOpen, isInternal } = row
|
|
66
|
-
const data = node
|
|
67
|
-
const hasChildren = isInternal
|
|
68
|
-
|
|
69
|
-
const willReceiveDrop = isDropTargetInside && dndEnabled
|
|
70
|
-
const inSubtreeOfSelected = isDescendantOfSelected
|
|
71
|
-
const inAncestorChain = isAncestor
|
|
72
|
-
const inBand = (isSelected || inSubtreeOfSelected) && !willReceiveDrop
|
|
62
|
+
const { node, level, isOpen, isInternal, ancestorHasMoreSiblings } = row;
|
|
63
|
+
const data = node;
|
|
64
|
+
const hasChildren = isInternal;
|
|
73
65
|
|
|
74
|
-
const
|
|
75
|
-
const
|
|
66
|
+
const willReceiveDrop = isDropTargetInside && dndEnabled;
|
|
67
|
+
const inSubtreeOfSelected = isDescendantOfSelected;
|
|
68
|
+
const inAncestorChain = isAncestor;
|
|
69
|
+
// Selected row gets the strong fill; direct children get a softer overlay so
|
|
70
|
+
// they read as "members of the selected group" without competing with the
|
|
71
|
+
// selection itself. Rows stand alone — no neighbor-aware joining anymore.
|
|
72
|
+
const showSelected = isSelected && !willReceiveDrop;
|
|
73
|
+
const showChildOfSelected =
|
|
74
|
+
inSubtreeOfSelected && !isSelected && !willReceiveDrop;
|
|
75
|
+
// A row is "in the selection group" if it's the selected node itself or a
|
|
76
|
+
// descendant tinted by it. Neighbor-aware rounding then merges adjacent rows
|
|
77
|
+
// into one continuous pill instead of stacked individual chips.
|
|
78
|
+
const inGroup = showSelected || showChildOfSelected;
|
|
79
|
+
const isGroupStart = inGroup && !isPrevInBand;
|
|
80
|
+
const isGroupEnd = inGroup && !isNextInBand;
|
|
76
81
|
|
|
77
82
|
const icon = resolveIcon(iconFor, data, {
|
|
78
83
|
isOpen,
|
|
79
84
|
isInternal,
|
|
80
85
|
isSelected,
|
|
81
|
-
})
|
|
86
|
+
});
|
|
82
87
|
|
|
83
88
|
const outerClassName = cn(
|
|
84
89
|
"relative w-full min-w-max",
|
|
85
90
|
isDragging && "opacity-40",
|
|
86
91
|
data.disabled && "opacity-50 pointer-events-none",
|
|
87
|
-
)
|
|
92
|
+
);
|
|
88
93
|
|
|
89
94
|
const bandClassName = cn(
|
|
90
|
-
"pointer-events-none absolute inset-y-0 inset-x-[2px] transition-colors duration-100",
|
|
91
|
-
"rounded-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
"pointer-events-none absolute inset-y-0 inset-x-[2px] z-0 rounded-md transition-colors duration-100",
|
|
96
|
+
inGroup && !isGroupStart && "rounded-t-none",
|
|
97
|
+
inGroup && !isGroupEnd && "rounded-b-none",
|
|
98
|
+
!willReceiveDrop &&
|
|
99
|
+
!inGroup &&
|
|
95
100
|
"group-hover/row:bg-background-presentation-form-field-hover group-active/row:bg-background-presentation-action-hover/20",
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
showSelected && "bg-background-presentation-state-information-primary",
|
|
102
|
+
// Token isn't exposed as channels, so Tailwind's /alpha modifier doesn't
|
|
103
|
+
// work on it — paint the descendant tint with the same hex at 30% alpha.
|
|
104
|
+
showChildOfSelected && "bg-[#005ECC]/30",
|
|
105
|
+
inAncestorChain &&
|
|
106
|
+
!inGroup &&
|
|
98
107
|
"bg-background-presentation-state-information-secondary",
|
|
99
108
|
willReceiveDrop && "bg-background-presentation-state-information-primary",
|
|
100
|
-
)
|
|
109
|
+
);
|
|
101
110
|
|
|
102
111
|
const rowClassName = cn(
|
|
103
112
|
"relative z-10 flex items-center gap-1 py-1 pr-2 cursor-pointer text-sm min-w-max",
|
|
104
|
-
|
|
113
|
+
showSelected && "text-white",
|
|
105
114
|
willReceiveDrop && "text-white",
|
|
106
|
-
)
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Grip occupies a fixed slot at the outer-left edge. `contentStart` is where
|
|
118
|
+
// the indent-padding origin (depth 0) begins, leaving breathing room between
|
|
119
|
+
// the grip column and the first connector / chevron.
|
|
120
|
+
const gripSlotWidth = 16;
|
|
121
|
+
const gripGutterPad = 6;
|
|
122
|
+
const contentStart = gripSlotWidth + gripGutterPad; // 22px
|
|
107
123
|
|
|
108
124
|
const rowStyle = {
|
|
109
|
-
|
|
125
|
+
paddingInlineStart: contentStart + level * indent,
|
|
110
126
|
height: rowHeight,
|
|
111
|
-
}
|
|
127
|
+
};
|
|
112
128
|
|
|
113
129
|
const handleRowClick = () => {
|
|
114
|
-
if (data.disabled) return
|
|
115
|
-
onSelect(node.id)
|
|
116
|
-
}
|
|
130
|
+
if (data.disabled) return;
|
|
131
|
+
onSelect(node.id);
|
|
132
|
+
};
|
|
117
133
|
|
|
118
134
|
// Insert lines for "between" drops (above/below sibling). Inset to the row's
|
|
119
135
|
// indent so they line up with the new sibling's level.
|
|
120
|
-
const insertLineInset =
|
|
136
|
+
const insertLineInset = contentStart + level * indent;
|
|
121
137
|
|
|
122
138
|
return (
|
|
123
139
|
<div
|
|
124
140
|
data-row-id={node.id}
|
|
125
141
|
className={cn("select-none group/row", outerClassName)}
|
|
142
|
+
style={{ height: rowHeight }}
|
|
126
143
|
{...dragHandlers}
|
|
127
144
|
>
|
|
128
145
|
<span aria-hidden className={bandClassName} />
|
|
129
146
|
|
|
147
|
+
{/* Drag handle sits in a fixed slot at the outer-left of the row so it
|
|
148
|
+
never collides with the connector verticals — those start to the
|
|
149
|
+
right of this 16px reserved column. Hidden until row hover. */}
|
|
150
|
+
{dndEnabled && (
|
|
151
|
+
<span
|
|
152
|
+
className="absolute start-1.5 top-0 z-[6] flex h-full w-4 items-center justify-center opacity-0 group-hover/row:opacity-100 transition-opacity duration-150 cursor-grab active:cursor-grabbing"
|
|
153
|
+
aria-hidden
|
|
154
|
+
>
|
|
155
|
+
<GripVertical
|
|
156
|
+
className={cn(
|
|
157
|
+
"w-3.5 h-3.5",
|
|
158
|
+
showSelected
|
|
159
|
+
? "text-white/80"
|
|
160
|
+
: "text-content-presentation-global-tertiary",
|
|
161
|
+
)}
|
|
162
|
+
/>
|
|
163
|
+
</span>
|
|
164
|
+
)}
|
|
165
|
+
|
|
166
|
+
{level > 0 && (
|
|
167
|
+
<div className="pointer-events-none absolute inset-0 z-[5]">
|
|
168
|
+
<TreeConnectors
|
|
169
|
+
level={level}
|
|
170
|
+
indent={indent}
|
|
171
|
+
rowHeight={rowHeight}
|
|
172
|
+
contentStart={contentStart}
|
|
173
|
+
ancestorHasMoreSiblings={ancestorHasMoreSiblings}
|
|
174
|
+
/>
|
|
175
|
+
</div>
|
|
176
|
+
)}
|
|
177
|
+
|
|
130
178
|
{isDropBefore && (
|
|
131
179
|
<span
|
|
132
180
|
aria-hidden
|
|
133
181
|
className="pointer-events-none absolute -top-px left-0 right-0 z-20 h-0.5 bg-background-presentation-state-information-primary"
|
|
134
|
-
style={{
|
|
182
|
+
style={{ marginInlineStart: insertLineInset }}
|
|
135
183
|
/>
|
|
136
184
|
)}
|
|
137
185
|
{isDropAfter && (
|
|
138
186
|
<span
|
|
139
187
|
aria-hidden
|
|
140
188
|
className="pointer-events-none absolute -bottom-px left-0 right-0 z-20 h-0.5 bg-background-presentation-state-information-primary"
|
|
141
|
-
style={{
|
|
189
|
+
style={{ marginInlineStart: insertLineInset }}
|
|
142
190
|
/>
|
|
143
191
|
)}
|
|
144
192
|
|
|
@@ -152,30 +200,16 @@ export function TreeFolderRow({
|
|
|
152
200
|
className={rowClassName}
|
|
153
201
|
style={rowStyle}
|
|
154
202
|
>
|
|
155
|
-
{dndEnabled && (
|
|
156
|
-
<span
|
|
157
|
-
className="shrink-0 w-4 h-4 flex items-center justify-center opacity-0 group-hover/row:opacity-100 transition-opacity duration-150 cursor-grab active:cursor-grabbing"
|
|
158
|
-
aria-hidden
|
|
159
|
-
>
|
|
160
|
-
<GripVertical
|
|
161
|
-
className={cn(
|
|
162
|
-
"w-3.5 h-3.5",
|
|
163
|
-
inBand ? "text-white/80" : "text-content-presentation-global-tertiary",
|
|
164
|
-
)}
|
|
165
|
-
/>
|
|
166
|
-
</span>
|
|
167
|
-
)}
|
|
168
|
-
|
|
169
203
|
{hasChildren ? (
|
|
170
204
|
<button
|
|
171
205
|
type="button"
|
|
172
206
|
onClick={(e) => {
|
|
173
|
-
e.stopPropagation()
|
|
174
|
-
onToggle(node.id)
|
|
207
|
+
e.stopPropagation();
|
|
208
|
+
onToggle(node.id);
|
|
175
209
|
}}
|
|
176
210
|
className={cn(
|
|
177
211
|
"shrink-0 w-4 h-4 flex items-center justify-center rounded",
|
|
178
|
-
|
|
212
|
+
showSelected
|
|
179
213
|
? "text-white/80 hover:text-white"
|
|
180
214
|
: "text-content-presentation-global-tertiary hover:text-content-presentation-global-primary",
|
|
181
215
|
)}
|
|
@@ -194,7 +228,9 @@ export function TreeFolderRow({
|
|
|
194
228
|
<span
|
|
195
229
|
className={cn(
|
|
196
230
|
"shrink-0 w-4 h-4 flex items-center justify-center",
|
|
197
|
-
|
|
231
|
+
showSelected
|
|
232
|
+
? "text-white/90"
|
|
233
|
+
: "text-content-presentation-global-tertiary",
|
|
198
234
|
)}
|
|
199
235
|
aria-hidden
|
|
200
236
|
>
|
|
@@ -209,7 +245,9 @@ export function TreeFolderRow({
|
|
|
209
245
|
<span
|
|
210
246
|
className={cn(
|
|
211
247
|
"shrink-0 text-xs tabular-nums",
|
|
212
|
-
|
|
248
|
+
showSelected
|
|
249
|
+
? "text-white/80"
|
|
250
|
+
: "text-content-presentation-global-tertiary",
|
|
213
251
|
)}
|
|
214
252
|
>
|
|
215
253
|
({countDescendants(node)})
|
|
@@ -217,19 +255,109 @@ export function TreeFolderRow({
|
|
|
217
255
|
)}
|
|
218
256
|
</div>
|
|
219
257
|
</div>
|
|
220
|
-
)
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Connector lines (T/L bends) aligned to where each ancestor's chevron sits in
|
|
263
|
+
* the row layout, so verticals drop directly from the parent's twisty rather
|
|
264
|
+
* than floating in the indent column. Geometry:
|
|
265
|
+
*
|
|
266
|
+
* row paddingLeft = 4 + level * indent
|
|
267
|
+
* row content order = [grip?(16)] [chevron(16)] [icon(16)] [text]
|
|
268
|
+
*
|
|
269
|
+
* So the chevron of a row at depth D is centered at:
|
|
270
|
+
* chevronX(D) = 4 + D * indent + (dndEnabled ? 16 : 0) + 8
|
|
271
|
+
*
|
|
272
|
+
* A child at depth D+1 hangs its vertical at chevronX(D) and runs a horizontal
|
|
273
|
+
* stub from there out to (paddingLeft - 2) — landing just before the child's
|
|
274
|
+
* own grip/chevron. Last child renders an "L" (vertical stops at midline);
|
|
275
|
+
* other siblings render a "T" (vertical runs full height). Ancestor gutters
|
|
276
|
+
* keep their verticals only when that ancestor still has siblings below.
|
|
277
|
+
*/
|
|
278
|
+
function TreeConnectors({
|
|
279
|
+
level,
|
|
280
|
+
indent,
|
|
281
|
+
rowHeight,
|
|
282
|
+
contentStart,
|
|
283
|
+
ancestorHasMoreSiblings,
|
|
284
|
+
}: {
|
|
285
|
+
level: number;
|
|
286
|
+
indent: number;
|
|
287
|
+
rowHeight: number;
|
|
288
|
+
contentStart: number;
|
|
289
|
+
ancestorHasMoreSiblings: boolean[];
|
|
290
|
+
}) {
|
|
291
|
+
// Grip handle sits in a fixed outer-left slot, so the chevron column for a
|
|
292
|
+
// row at depth D is: contentStart + D*indent + chevron-half(8).
|
|
293
|
+
const chevronX = (depth: number) => contentStart + depth * indent + 8;
|
|
294
|
+
// Connector color is theme-aware: black/20 on default+light, white/20 on dark.
|
|
295
|
+
// The dark swap relies on a `data-theme="dark"` ancestor (set by TreeFolder).
|
|
296
|
+
const lineClass = "bg-black-alpha-20 [[data-theme=dark]_&]:bg-white-alpha-20";
|
|
297
|
+
const segments: React.ReactNode[] = [];
|
|
298
|
+
|
|
299
|
+
// Ancestor verticals: full-height line at each ancestor's chevron column,
|
|
300
|
+
// skipped when the ancestor at that depth has no more siblings below.
|
|
301
|
+
// ancestorHasMoreSiblings[d] === "ancestor at depth d still has siblings
|
|
302
|
+
// below this row," so it controls whether to draw the vertical in that
|
|
303
|
+
// ancestor's chevron gutter (chevronX(d)).
|
|
304
|
+
for (let d = 0; d < level - 1; d++) {
|
|
305
|
+
if (!ancestorHasMoreSiblings[d]) continue;
|
|
306
|
+
segments.push(
|
|
307
|
+
<span
|
|
308
|
+
key={`v-${d}`}
|
|
309
|
+
aria-hidden
|
|
310
|
+
className={cn("pointer-events-none absolute top-0 bottom-0 w-px", lineClass)}
|
|
311
|
+
style={{ insetInlineStart: chevronX(d) }}
|
|
312
|
+
/>,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Parent's gutter (depth = level - 1). T or L vertical, plus horizontal stub
|
|
317
|
+
// landing just before this row's own grip/chevron starts.
|
|
318
|
+
const parentDepth = level - 1;
|
|
319
|
+
const parentX = chevronX(parentDepth);
|
|
320
|
+
const midY = rowHeight / 2;
|
|
321
|
+
const ownContentX = contentStart + level * indent + 2; // extend 4px further toward the row content
|
|
322
|
+
|
|
323
|
+
segments.push(
|
|
324
|
+
<span
|
|
325
|
+
key="v-own"
|
|
326
|
+
aria-hidden
|
|
327
|
+
className={cn("pointer-events-none absolute w-px", lineClass)}
|
|
328
|
+
style={{
|
|
329
|
+
insetInlineStart: parentX,
|
|
330
|
+
top: 0,
|
|
331
|
+
height: "100%",
|
|
332
|
+
}}
|
|
333
|
+
/>,
|
|
334
|
+
);
|
|
335
|
+
segments.push(
|
|
336
|
+
<span
|
|
337
|
+
key="h-own"
|
|
338
|
+
aria-hidden
|
|
339
|
+
className={cn("pointer-events-none absolute h-px", lineClass)}
|
|
340
|
+
style={{
|
|
341
|
+
insetInlineStart: parentX,
|
|
342
|
+
top: midY,
|
|
343
|
+
width: Math.max(4, ownContentX - parentX),
|
|
344
|
+
}}
|
|
345
|
+
/>,
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
return <>{segments}</>;
|
|
221
349
|
}
|
|
222
350
|
|
|
223
351
|
function countDescendants(node: {
|
|
224
|
-
children?: { children?: any[] }[] | null
|
|
352
|
+
children?: { children?: any[] }[] | null;
|
|
225
353
|
}): number {
|
|
226
|
-
if (!node.children) return 0
|
|
227
|
-
let n = 0
|
|
228
|
-
const stack: any[] = [...node.children]
|
|
354
|
+
if (!node.children) return 0;
|
|
355
|
+
let n = 0;
|
|
356
|
+
const stack: any[] = [...node.children];
|
|
229
357
|
while (stack.length) {
|
|
230
|
-
n
|
|
231
|
-
const top = stack.pop()
|
|
232
|
-
if (top.children) for (const c of top.children) stack.push(c)
|
|
358
|
+
n++;
|
|
359
|
+
const top = stack.pop();
|
|
360
|
+
if (top.children) for (const c of top.children) stack.push(c);
|
|
233
361
|
}
|
|
234
|
-
return n
|
|
362
|
+
return n;
|
|
235
363
|
}
|
|
@@ -56,6 +56,15 @@ export type TreeFolderVisibleRow = {
|
|
|
56
56
|
isOpen: boolean
|
|
57
57
|
/** True for internal nodes (any node with non-empty children). */
|
|
58
58
|
isInternal: boolean
|
|
59
|
+
/**
|
|
60
|
+
* Connector-line geometry. `isLastChild` toggles the row's own bend between L
|
|
61
|
+
* (last) and T (non-last). `ancestorHasMoreSiblings[d]` is true when the
|
|
62
|
+
* ancestor at depth `d` still has visible siblings after this row — that
|
|
63
|
+
* controls whether the vertical guide renders in that ancestor's gutter.
|
|
64
|
+
* Length === `level`.
|
|
65
|
+
*/
|
|
66
|
+
isLastChild: boolean
|
|
67
|
+
ancestorHasMoreSiblings: boolean[]
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
/** Where the pointer is dropping relative to the hovered row. */
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Fragment, type HTMLAttributes, type ReactNode } from "react";
|
|
4
|
+
import { cn } from "../utils/cn";
|
|
5
|
+
import { Card, CardContent, CardHeader } from "../components/Card";
|
|
6
|
+
import type { Themes } from "../utils/types";
|
|
7
|
+
|
|
8
|
+
export type DataViewCardCell = {
|
|
9
|
+
key: string;
|
|
10
|
+
label: ReactNode;
|
|
11
|
+
value: ReactNode;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type DataViewCardRow = DataViewCardCell[];
|
|
15
|
+
|
|
16
|
+
export interface DataViewCardProps extends Omit<
|
|
17
|
+
HTMLAttributes<HTMLElement>,
|
|
18
|
+
"title"
|
|
19
|
+
> {
|
|
20
|
+
title?: ReactNode;
|
|
21
|
+
rows?: DataViewCardRow[];
|
|
22
|
+
theme?: Themes;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function DataViewCard({
|
|
26
|
+
title,
|
|
27
|
+
rows = [],
|
|
28
|
+
className,
|
|
29
|
+
theme,
|
|
30
|
+
...props
|
|
31
|
+
}: DataViewCardProps) {
|
|
32
|
+
return (
|
|
33
|
+
<Card
|
|
34
|
+
data-theme={theme}
|
|
35
|
+
{...props}
|
|
36
|
+
className={cn("p-[8px] rounded-[10px] gap-0", className)}
|
|
37
|
+
>
|
|
38
|
+
{title != null && (
|
|
39
|
+
<CardHeader className=" border-b border-border-presentation-global-primary">
|
|
40
|
+
<div className="min-w-0 typography-headers-large-semibold text-content-presentation-global-primary">
|
|
41
|
+
{title}
|
|
42
|
+
</div>
|
|
43
|
+
</CardHeader>
|
|
44
|
+
)}
|
|
45
|
+
{rows.length > 0 && (
|
|
46
|
+
<CardContent className="grid grid-cols-2 gap-0 pt-0 w-full">
|
|
47
|
+
{rows.map((cells, rowIdx) => (
|
|
48
|
+
<Fragment key={rowIdx}>
|
|
49
|
+
{cells.map((cell, cellIdx) => (
|
|
50
|
+
<div
|
|
51
|
+
key={cell.key}
|
|
52
|
+
className={cn(
|
|
53
|
+
"relative flex flex-col gap-[2px] min-w-0 p-[6px]",
|
|
54
|
+
rowIdx > 0 &&
|
|
55
|
+
"border-t border-border-presentation-global-primary",
|
|
56
|
+
cells.length === 2 &&
|
|
57
|
+
cellIdx === 0 &&
|
|
58
|
+
"after:absolute after:end-0 after:top-[7%] after:h-[80%] after:w-px after:bg-border-presentation-global-primary",
|
|
59
|
+
cells.length === 1 && "col-span-2",
|
|
60
|
+
)}
|
|
61
|
+
>
|
|
62
|
+
<span className="typography-body-small-medium text-content-presentation-global-tertiary">
|
|
63
|
+
{cell.label}
|
|
64
|
+
</span>
|
|
65
|
+
<div className="typography-body-medium-semibold text-content-presentation-global-primary truncate">
|
|
66
|
+
{cell.value}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
))}
|
|
70
|
+
</Fragment>
|
|
71
|
+
))}
|
|
72
|
+
</CardContent>
|
|
73
|
+
)}
|
|
74
|
+
</Card>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -42,10 +42,18 @@ export function copyDirectorySync(source, target) {
|
|
|
42
42
|
if (item.isDirectory()) {
|
|
43
43
|
copyDirectorySync(sourcePath, targetPath);
|
|
44
44
|
}
|
|
45
|
-
else {
|
|
45
|
+
else if (isCopyableFile(item.name)) {
|
|
46
46
|
fs.copyFileSync(sourcePath, targetPath);
|
|
47
47
|
installDependencies(sourcePath);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Decide whether a file should be copied into the user's project. Skips
|
|
53
|
+
* documentation/meta files that live alongside source for maintainers but add
|
|
54
|
+
* noise to a consumer's drop-in (e.g. ARCHITECTURE.md inside a component folder).
|
|
55
|
+
*/
|
|
56
|
+
function isCopyableFile(fileName) {
|
|
57
|
+
return !/\.(md|mdx)$/i.test(fileName);
|
|
58
|
+
}
|
|
51
59
|
//# sourceMappingURL=copyComponentsRecursively.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copyComponentsRecursively.js","sourceRoot":"","sources":["../../../cli/src/shared/copyComponentsRecursively.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAc,EAAE,MAAc;IACpE,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACrC,kEAAkE;QAClE,oEAAoE;QACpE,iEAAiE;QACjE,2CAA2C;QAC3C,MAAM,WAAW,GACb,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;YACvD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC,CAAC,MAAM,CAAC;QACjB,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACJ,IAAI,WAAW,GAAG,MAAM,CAAC;QAEzB,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YAC9D,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3D,CAAC;QAED,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACrC,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;AACL,CAAC;AACD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC7B,MAAc,EACd,MAAc;IAEd,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhD,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACrB,iBAAiB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"copyComponentsRecursively.js","sourceRoot":"","sources":["../../../cli/src/shared/copyComponentsRecursively.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAc,EAAE,MAAc;IACpE,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACrC,kEAAkE;QAClE,oEAAoE;QACpE,iEAAiE;QACjE,2CAA2C;QAC3C,MAAM,WAAW,GACb,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;YACvD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC,CAAC,MAAM,CAAC;QACjB,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACJ,IAAI,WAAW,GAAG,MAAM,CAAC;QAEzB,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YAC9D,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3D,CAAC;QAED,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACrC,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;AACL,CAAC;AACD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC7B,MAAc,EACd,MAAc;IAEd,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhD,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACrB,iBAAiB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC9C,CAAC;aAAM,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACxC,mBAAmB,CAAC,UAAU,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,QAAgB;IACpC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC"}
|