@proyecto-viviana/ui 0.2.5 → 0.3.1
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/index.js +210 -557
- package/dist/index.js.map +7 -1
- package/dist/index.ssr.js +42 -399
- package/dist/index.ssr.js.map +7 -1
- package/dist/radio/index.d.ts +27 -12
- package/dist/radio/index.d.ts.map +1 -1
- package/package.json +11 -12
- package/src/alert/index.tsx +0 -48
- package/src/assets/favicon.png +0 -0
- package/src/assets/fire.gif +0 -0
- package/src/autocomplete/index.tsx +0 -313
- package/src/avatar/index.tsx +0 -75
- package/src/badge/index.tsx +0 -43
- package/src/breadcrumbs/index.tsx +0 -207
- package/src/button/Button.tsx +0 -74
- package/src/button/index.ts +0 -2
- package/src/button/types.ts +0 -24
- package/src/calendar/DateField.tsx +0 -200
- package/src/calendar/DatePicker.tsx +0 -298
- package/src/calendar/RangeCalendar.tsx +0 -236
- package/src/calendar/TimeField.tsx +0 -196
- package/src/calendar/index.tsx +0 -223
- package/src/checkbox/index.tsx +0 -257
- package/src/color/index.tsx +0 -687
- package/src/combobox/index.tsx +0 -383
- package/src/components.css +0 -1077
- package/src/custom/calendar-card/index.tsx +0 -66
- package/src/custom/chip/index.tsx +0 -46
- package/src/custom/conversation/index.tsx +0 -105
- package/src/custom/event-card/index.tsx +0 -132
- package/src/custom/header/index.tsx +0 -33
- package/src/custom/lateral-nav/index.tsx +0 -88
- package/src/custom/logo/index.tsx +0 -58
- package/src/custom/nav-header/index.tsx +0 -42
- package/src/custom/page-layout/index.tsx +0 -29
- package/src/custom/profile-card/index.tsx +0 -64
- package/src/custom/project-card/index.tsx +0 -59
- package/src/custom/timeline-item/index.tsx +0 -105
- package/src/dialog/Dialog.tsx +0 -260
- package/src/dialog/index.tsx +0 -3
- package/src/disclosure/index.tsx +0 -307
- package/src/gridlist/index.tsx +0 -403
- package/src/icon/icons/GitHubIcon.tsx +0 -20
- package/src/icon/index.tsx +0 -48
- package/src/index.ts +0 -322
- package/src/landmark/index.tsx +0 -231
- package/src/link/index.tsx +0 -130
- package/src/listbox/index.tsx +0 -231
- package/src/menu/index.tsx +0 -297
- package/src/meter/index.tsx +0 -163
- package/src/numberfield/index.tsx +0 -482
- package/src/popover/index.tsx +0 -260
- package/src/progress-bar/index.tsx +0 -169
- package/src/radio/index.tsx +0 -173
- package/src/searchfield/index.tsx +0 -453
- package/src/select/index.tsx +0 -349
- package/src/separator/index.tsx +0 -141
- package/src/slider/index.tsx +0 -382
- package/src/styles.css +0 -450
- package/src/switch/ToggleSwitch.tsx +0 -112
- package/src/switch/index.tsx +0 -90
- package/src/table/index.tsx +0 -531
- package/src/tabs/index.tsx +0 -273
- package/src/tag-group/index.tsx +0 -240
- package/src/test-utils/index.ts +0 -32
- package/src/textfield/index.tsx +0 -211
- package/src/theme.css +0 -101
- package/src/toast/index.tsx +0 -324
- package/src/toolbar/index.tsx +0 -108
- package/src/tooltip/index.tsx +0 -197
- package/src/tree/index.tsx +0 -494
package/src/tree/index.tsx
DELETED
|
@@ -1,494 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tree component for proyecto-viviana-ui
|
|
3
|
-
*
|
|
4
|
-
* Styled tree component built on top of solidaria-components.
|
|
5
|
-
* Inspired by Spectrum 2's Tree component patterns.
|
|
6
|
-
*
|
|
7
|
-
* Tree displays hierarchical data with expandable/collapsible nodes,
|
|
8
|
-
* supporting keyboard navigation and selection.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { type JSX, splitProps, createContext, useContext, Show } from 'solid-js'
|
|
12
|
-
import {
|
|
13
|
-
Tree as HeadlessTree,
|
|
14
|
-
TreeItem as HeadlessTreeItem,
|
|
15
|
-
TreeExpandButton as HeadlessTreeExpandButton,
|
|
16
|
-
TreeSelectionCheckbox as HeadlessTreeSelectionCheckbox,
|
|
17
|
-
type TreeProps as HeadlessTreeProps,
|
|
18
|
-
type TreeItemProps as HeadlessTreeItemProps,
|
|
19
|
-
type TreeExpandButtonProps as HeadlessTreeExpandButtonProps,
|
|
20
|
-
type TreeRenderProps,
|
|
21
|
-
type TreeItemRenderProps,
|
|
22
|
-
type TreeRenderItemState,
|
|
23
|
-
} from '@proyecto-viviana/solidaria-components'
|
|
24
|
-
import type { Key, TreeItemData } from '@proyecto-viviana/solid-stately'
|
|
25
|
-
|
|
26
|
-
// ============================================
|
|
27
|
-
// SIZE CONTEXT
|
|
28
|
-
// ============================================
|
|
29
|
-
|
|
30
|
-
export type TreeSize = 'sm' | 'md' | 'lg'
|
|
31
|
-
export type TreeVariant = 'default' | 'bordered' | 'quiet'
|
|
32
|
-
|
|
33
|
-
interface TreeContextValue {
|
|
34
|
-
size: TreeSize
|
|
35
|
-
variant: TreeVariant
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const TreeSizeContext = createContext<TreeContextValue>({ size: 'md', variant: 'default' })
|
|
39
|
-
|
|
40
|
-
// ============================================
|
|
41
|
-
// TYPES
|
|
42
|
-
// ============================================
|
|
43
|
-
|
|
44
|
-
export interface TreeProps<T extends object>
|
|
45
|
-
extends Omit<HeadlessTreeProps<T>, 'class' | 'style'> {
|
|
46
|
-
/** The size of the tree. */
|
|
47
|
-
size?: TreeSize
|
|
48
|
-
/** The visual variant of the tree. */
|
|
49
|
-
variant?: TreeVariant
|
|
50
|
-
/** Additional CSS class name. */
|
|
51
|
-
class?: string
|
|
52
|
-
/** Label for the tree. */
|
|
53
|
-
label?: string
|
|
54
|
-
/** Description for the tree. */
|
|
55
|
-
description?: string
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface TreeItemProps<T extends object>
|
|
59
|
-
extends Omit<HeadlessTreeItemProps<T>, 'class' | 'style'> {
|
|
60
|
-
/** Additional CSS class name. */
|
|
61
|
-
class?: string
|
|
62
|
-
/** Optional description text. */
|
|
63
|
-
description?: string
|
|
64
|
-
/**
|
|
65
|
-
* Optional icon to display before the content.
|
|
66
|
-
* Use a function returning JSX for SSR compatibility: `icon={() => <FolderIcon />}`
|
|
67
|
-
*/
|
|
68
|
-
icon?: () => JSX.Element
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface TreeExpandButtonProps extends Omit<HeadlessTreeExpandButtonProps, 'class' | 'style'> {
|
|
72
|
-
/** Additional CSS class name. */
|
|
73
|
-
class?: string
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ============================================
|
|
77
|
-
// STYLES
|
|
78
|
-
// ============================================
|
|
79
|
-
|
|
80
|
-
const sizeStyles = {
|
|
81
|
-
sm: {
|
|
82
|
-
tree: 'text-sm',
|
|
83
|
-
item: 'py-1 px-2 gap-1',
|
|
84
|
-
indent: 16,
|
|
85
|
-
icon: 'h-4 w-4',
|
|
86
|
-
expandButton: 'h-4 w-4',
|
|
87
|
-
label: 'text-sm',
|
|
88
|
-
description: 'text-xs',
|
|
89
|
-
checkbox: 'w-4 h-4',
|
|
90
|
-
},
|
|
91
|
-
md: {
|
|
92
|
-
tree: 'text-base',
|
|
93
|
-
item: 'py-1.5 px-3 gap-2',
|
|
94
|
-
indent: 20,
|
|
95
|
-
icon: 'h-5 w-5',
|
|
96
|
-
expandButton: 'h-5 w-5',
|
|
97
|
-
label: 'text-base',
|
|
98
|
-
description: 'text-sm',
|
|
99
|
-
checkbox: 'w-5 h-5',
|
|
100
|
-
},
|
|
101
|
-
lg: {
|
|
102
|
-
tree: 'text-lg',
|
|
103
|
-
item: 'py-2 px-4 gap-2',
|
|
104
|
-
indent: 24,
|
|
105
|
-
icon: 'h-6 w-6',
|
|
106
|
-
expandButton: 'h-6 w-6',
|
|
107
|
-
label: 'text-lg',
|
|
108
|
-
description: 'text-base',
|
|
109
|
-
checkbox: 'w-6 h-6',
|
|
110
|
-
},
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const variantStyles = {
|
|
114
|
-
default: {
|
|
115
|
-
tree: 'bg-bg-400 rounded-lg border border-bg-300 p-2',
|
|
116
|
-
item: 'rounded-md',
|
|
117
|
-
itemHover: 'hover:bg-bg-200/50',
|
|
118
|
-
itemSelected: 'bg-accent/10 text-accent',
|
|
119
|
-
},
|
|
120
|
-
bordered: {
|
|
121
|
-
tree: 'bg-bg-400 rounded-lg border-2 border-bg-400 p-2',
|
|
122
|
-
item: 'border-b border-bg-300/30 last:border-b-0',
|
|
123
|
-
itemHover: 'hover:bg-bg-200/50',
|
|
124
|
-
itemSelected: 'bg-accent/10 text-accent',
|
|
125
|
-
},
|
|
126
|
-
quiet: {
|
|
127
|
-
tree: 'bg-transparent',
|
|
128
|
-
item: 'rounded-md',
|
|
129
|
-
itemHover: 'hover:bg-bg-300/50',
|
|
130
|
-
itemSelected: 'bg-accent/10 text-accent',
|
|
131
|
-
},
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// ============================================
|
|
135
|
-
// TREE COMPONENT
|
|
136
|
-
// ============================================
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* A tree displays hierarchical data with expandable/collapsible nodes,
|
|
140
|
-
* supporting keyboard navigation and selection.
|
|
141
|
-
*
|
|
142
|
-
* Built on solidaria-components Tree for full accessibility support.
|
|
143
|
-
*
|
|
144
|
-
* @example
|
|
145
|
-
* ```tsx
|
|
146
|
-
* const items = [
|
|
147
|
-
* {
|
|
148
|
-
* key: 'documents',
|
|
149
|
-
* value: { name: 'Documents' },
|
|
150
|
-
* children: [
|
|
151
|
-
* { key: 'doc1', value: { name: 'Report.pdf' } },
|
|
152
|
-
* { key: 'doc2', value: { name: 'Notes.txt' } },
|
|
153
|
-
* ],
|
|
154
|
-
* },
|
|
155
|
-
* {
|
|
156
|
-
* key: 'images',
|
|
157
|
-
* value: { name: 'Images' },
|
|
158
|
-
* children: [
|
|
159
|
-
* { key: 'img1', value: { name: 'Photo.jpg' } },
|
|
160
|
-
* ],
|
|
161
|
-
* },
|
|
162
|
-
* ]
|
|
163
|
-
*
|
|
164
|
-
* <Tree items={items} defaultExpandedKeys={['documents']}>
|
|
165
|
-
* {(item, state) => (
|
|
166
|
-
* <TreeItem id={item.key} icon={() => <FolderIcon />}>
|
|
167
|
-
* {item.value.name}
|
|
168
|
-
* </TreeItem>
|
|
169
|
-
* )}
|
|
170
|
-
* </Tree>
|
|
171
|
-
* ```
|
|
172
|
-
*/
|
|
173
|
-
export function Tree<T extends object>(props: TreeProps<T>): JSX.Element {
|
|
174
|
-
const [local, headlessProps] = splitProps(props, [
|
|
175
|
-
'size',
|
|
176
|
-
'variant',
|
|
177
|
-
'class',
|
|
178
|
-
'label',
|
|
179
|
-
'description',
|
|
180
|
-
])
|
|
181
|
-
|
|
182
|
-
const size = () => local.size ?? 'md'
|
|
183
|
-
const variant = () => local.variant ?? 'default'
|
|
184
|
-
const styles = () => sizeStyles[size()]
|
|
185
|
-
const variantStyle = () => variantStyles[variant()]
|
|
186
|
-
const customClass = local.class ?? ''
|
|
187
|
-
|
|
188
|
-
const getClassName = (renderProps: TreeRenderProps): string => {
|
|
189
|
-
const base = 'overflow-auto focus:outline-none'
|
|
190
|
-
const sizeClass = styles().tree
|
|
191
|
-
const variantClass = variantStyle().tree
|
|
192
|
-
|
|
193
|
-
let stateClass = ''
|
|
194
|
-
if (renderProps.isDisabled) {
|
|
195
|
-
stateClass = 'opacity-50'
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const focusClass = renderProps.isFocusVisible
|
|
199
|
-
? 'ring-2 ring-accent-300 ring-offset-2 ring-offset-bg-400'
|
|
200
|
-
: ''
|
|
201
|
-
|
|
202
|
-
return [base, sizeClass, variantClass, stateClass, focusClass, customClass]
|
|
203
|
-
.filter(Boolean)
|
|
204
|
-
.join(' ')
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const defaultEmptyState = () => (
|
|
208
|
-
<div class="py-8 text-center text-primary-400">
|
|
209
|
-
<div class="flex flex-col items-center gap-2">
|
|
210
|
-
<EmptyTreeIcon class="w-12 h-12 text-primary-500" />
|
|
211
|
-
<span>No items</span>
|
|
212
|
-
</div>
|
|
213
|
-
</div>
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
const contextValue = () => ({ size: size(), variant: variant() })
|
|
217
|
-
|
|
218
|
-
return (
|
|
219
|
-
<TreeSizeContext.Provider value={contextValue()}>
|
|
220
|
-
<div class="flex flex-col gap-2">
|
|
221
|
-
<Show when={local.label}>
|
|
222
|
-
<label class={`text-primary-200 font-medium ${styles().label}`}>
|
|
223
|
-
{local.label}
|
|
224
|
-
</label>
|
|
225
|
-
</Show>
|
|
226
|
-
<HeadlessTree
|
|
227
|
-
{...headlessProps}
|
|
228
|
-
class={getClassName}
|
|
229
|
-
renderEmptyState={headlessProps.renderEmptyState ?? defaultEmptyState}
|
|
230
|
-
/>
|
|
231
|
-
<Show when={local.description}>
|
|
232
|
-
<span class="text-primary-400 text-sm">{local.description}</span>
|
|
233
|
-
</Show>
|
|
234
|
-
</div>
|
|
235
|
-
</TreeSizeContext.Provider>
|
|
236
|
-
)
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// ============================================
|
|
240
|
-
// TREE ITEM COMPONENT
|
|
241
|
-
// ============================================
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* An item in a tree.
|
|
245
|
-
*/
|
|
246
|
-
export function TreeItem<T extends object>(props: TreeItemProps<T>): JSX.Element {
|
|
247
|
-
const [local, headlessProps] = splitProps(props, [
|
|
248
|
-
'class',
|
|
249
|
-
'description',
|
|
250
|
-
'icon',
|
|
251
|
-
])
|
|
252
|
-
|
|
253
|
-
const context = useContext(TreeSizeContext)
|
|
254
|
-
const sizeStyle = sizeStyles[context.size]
|
|
255
|
-
const variantStyle = variantStyles[context.variant]
|
|
256
|
-
const customClass = local.class ?? ''
|
|
257
|
-
|
|
258
|
-
const getClassName = (renderProps: TreeItemRenderProps): string => {
|
|
259
|
-
const base = 'flex items-center cursor-pointer transition-all duration-150 outline-none'
|
|
260
|
-
const sizeClass = sizeStyle.item
|
|
261
|
-
const variantClass = variantStyle.item
|
|
262
|
-
|
|
263
|
-
let stateClass = ''
|
|
264
|
-
if (renderProps.isDisabled) {
|
|
265
|
-
stateClass = 'opacity-50 cursor-not-allowed'
|
|
266
|
-
} else if (renderProps.isSelected) {
|
|
267
|
-
stateClass = variantStyle.itemSelected
|
|
268
|
-
} else if (renderProps.isHovered) {
|
|
269
|
-
stateClass = variantStyle.itemHover
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
let textClass = ''
|
|
273
|
-
if (!renderProps.isDisabled && !renderProps.isSelected) {
|
|
274
|
-
textClass = 'text-primary-200'
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const focusClass = renderProps.isFocusVisible
|
|
278
|
-
? 'ring-2 ring-inset ring-accent-300'
|
|
279
|
-
: ''
|
|
280
|
-
|
|
281
|
-
const pressedClass = renderProps.isPressed ? 'scale-[0.99]' : ''
|
|
282
|
-
|
|
283
|
-
return [base, sizeClass, variantClass, stateClass, textClass, focusClass, pressedClass, customClass]
|
|
284
|
-
.filter(Boolean)
|
|
285
|
-
.join(' ')
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const getStyle = (renderProps: TreeItemRenderProps): JSX.CSSProperties => ({
|
|
289
|
-
'padding-left': `${renderProps.level * sizeStyle.indent + 8}px`,
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
return (
|
|
293
|
-
<HeadlessTreeItem {...headlessProps} class={getClassName} style={getStyle}>
|
|
294
|
-
{(renderProps: TreeItemRenderProps) => (
|
|
295
|
-
<>
|
|
296
|
-
{/* Expand button */}
|
|
297
|
-
<TreeExpandButton class={`${sizeStyle.expandButton} shrink-0`} />
|
|
298
|
-
|
|
299
|
-
{/* Icon */}
|
|
300
|
-
<Show when={local.icon}>
|
|
301
|
-
<span class={`shrink-0 ${sizeStyle.icon}`}>
|
|
302
|
-
{local.icon!()}
|
|
303
|
-
</span>
|
|
304
|
-
</Show>
|
|
305
|
-
|
|
306
|
-
{/* Default folder/file icon if no custom icon */}
|
|
307
|
-
<Show when={!local.icon}>
|
|
308
|
-
{renderProps.isExpandable ? (
|
|
309
|
-
<FolderIcon class={`shrink-0 ${sizeStyle.icon} text-accent-300`} isOpen={renderProps.isExpanded} />
|
|
310
|
-
) : (
|
|
311
|
-
<FileIcon class={`shrink-0 ${sizeStyle.icon} text-primary-400`} />
|
|
312
|
-
)}
|
|
313
|
-
</Show>
|
|
314
|
-
|
|
315
|
-
{/* Content */}
|
|
316
|
-
<div class="flex flex-col flex-1 min-w-0">
|
|
317
|
-
<span class="truncate">
|
|
318
|
-
{typeof props.children === 'function'
|
|
319
|
-
? props.children(renderProps)
|
|
320
|
-
: props.children}
|
|
321
|
-
</span>
|
|
322
|
-
<Show when={local.description}>
|
|
323
|
-
<span class={`text-primary-400 truncate ${sizeStyle.description}`}>
|
|
324
|
-
{local.description}
|
|
325
|
-
</span>
|
|
326
|
-
</Show>
|
|
327
|
-
</div>
|
|
328
|
-
|
|
329
|
-
{/* Selection indicator */}
|
|
330
|
-
<Show when={renderProps.isSelected}>
|
|
331
|
-
<CheckIcon class={`shrink-0 ${sizeStyle.icon} text-accent`} />
|
|
332
|
-
</Show>
|
|
333
|
-
</>
|
|
334
|
-
)}
|
|
335
|
-
</HeadlessTreeItem>
|
|
336
|
-
)
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// ============================================
|
|
340
|
-
// TREE EXPAND BUTTON COMPONENT
|
|
341
|
-
// ============================================
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* A button to expand/collapse a tree item.
|
|
345
|
-
*/
|
|
346
|
-
export function TreeExpandButton(props: TreeExpandButtonProps): JSX.Element {
|
|
347
|
-
const [local, headlessProps] = splitProps(props, ['class'])
|
|
348
|
-
const context = useContext(TreeSizeContext)
|
|
349
|
-
const sizeStyle = sizeStyles[context.size]
|
|
350
|
-
const customClass = local.class ?? ''
|
|
351
|
-
|
|
352
|
-
const className = [
|
|
353
|
-
'flex items-center justify-center transition-transform duration-150 text-primary-400 hover:text-primary-200',
|
|
354
|
-
customClass,
|
|
355
|
-
]
|
|
356
|
-
.filter(Boolean)
|
|
357
|
-
.join(' ')
|
|
358
|
-
|
|
359
|
-
return (
|
|
360
|
-
<HeadlessTreeExpandButton
|
|
361
|
-
{...headlessProps}
|
|
362
|
-
class={className}
|
|
363
|
-
>
|
|
364
|
-
{props.children ?? (({ isExpanded }: { isExpanded: boolean }) => (
|
|
365
|
-
<ChevronIcon
|
|
366
|
-
class={`${sizeStyle.expandButton} transition-transform duration-150 ${
|
|
367
|
-
isExpanded ? 'rotate-90' : ''
|
|
368
|
-
}`}
|
|
369
|
-
/>
|
|
370
|
-
))}
|
|
371
|
-
</HeadlessTreeExpandButton>
|
|
372
|
-
)
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// ============================================
|
|
376
|
-
// TREE SELECTION CHECKBOX COMPONENT
|
|
377
|
-
// ============================================
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* A styled checkbox for item selection in a tree.
|
|
381
|
-
*/
|
|
382
|
-
export function TreeSelectionCheckbox(props: { itemKey: Key; class?: string }): JSX.Element {
|
|
383
|
-
const context = useContext(TreeSizeContext)
|
|
384
|
-
const sizeStyle = sizeStyles[context.size]
|
|
385
|
-
const className = `${sizeStyle.checkbox} rounded border-2 border-primary-500 bg-bg-400 text-accent cursor-pointer checked:bg-accent checked:border-accent focus:ring-2 focus:ring-accent-300 focus:ring-offset-1 focus:ring-offset-bg-400 ${props.class ?? ''}`
|
|
386
|
-
|
|
387
|
-
return (
|
|
388
|
-
<span class={className}>
|
|
389
|
-
<HeadlessTreeSelectionCheckbox itemKey={props.itemKey} />
|
|
390
|
-
</span>
|
|
391
|
-
)
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// ============================================
|
|
395
|
-
// ICONS
|
|
396
|
-
// ============================================
|
|
397
|
-
|
|
398
|
-
function ChevronIcon(props: { class?: string }): JSX.Element {
|
|
399
|
-
return (
|
|
400
|
-
<svg
|
|
401
|
-
class={props.class}
|
|
402
|
-
fill="none"
|
|
403
|
-
viewBox="0 0 24 24"
|
|
404
|
-
stroke="currentColor"
|
|
405
|
-
stroke-width="2"
|
|
406
|
-
>
|
|
407
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
|
|
408
|
-
</svg>
|
|
409
|
-
)
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
function FolderIcon(props: { class?: string; isOpen?: boolean }): JSX.Element {
|
|
413
|
-
return (
|
|
414
|
-
<svg
|
|
415
|
-
class={props.class}
|
|
416
|
-
fill="none"
|
|
417
|
-
viewBox="0 0 24 24"
|
|
418
|
-
stroke="currentColor"
|
|
419
|
-
stroke-width="1.5"
|
|
420
|
-
>
|
|
421
|
-
{props.isOpen ? (
|
|
422
|
-
<path
|
|
423
|
-
stroke-linecap="round"
|
|
424
|
-
stroke-linejoin="round"
|
|
425
|
-
d="M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 00-1.883 2.542l.857 6a2.25 2.25 0 002.227 1.932H19.05a2.25 2.25 0 002.227-1.932l.857-6a2.25 2.25 0 00-1.883-2.542m-16.5 0V6A2.25 2.25 0 016 3.75h3.879a1.5 1.5 0 011.06.44l2.122 2.12a1.5 1.5 0 001.06.44H18A2.25 2.25 0 0120.25 9v.776"
|
|
426
|
-
/>
|
|
427
|
-
) : (
|
|
428
|
-
<path
|
|
429
|
-
stroke-linecap="round"
|
|
430
|
-
stroke-linejoin="round"
|
|
431
|
-
d="M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z"
|
|
432
|
-
/>
|
|
433
|
-
)}
|
|
434
|
-
</svg>
|
|
435
|
-
)
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
function FileIcon(props: { class?: string }): JSX.Element {
|
|
439
|
-
return (
|
|
440
|
-
<svg
|
|
441
|
-
class={props.class}
|
|
442
|
-
fill="none"
|
|
443
|
-
viewBox="0 0 24 24"
|
|
444
|
-
stroke="currentColor"
|
|
445
|
-
stroke-width="1.5"
|
|
446
|
-
>
|
|
447
|
-
<path
|
|
448
|
-
stroke-linecap="round"
|
|
449
|
-
stroke-linejoin="round"
|
|
450
|
-
d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z"
|
|
451
|
-
/>
|
|
452
|
-
</svg>
|
|
453
|
-
)
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
function CheckIcon(props: { class?: string }): JSX.Element {
|
|
457
|
-
return (
|
|
458
|
-
<svg
|
|
459
|
-
class={props.class}
|
|
460
|
-
fill="none"
|
|
461
|
-
viewBox="0 0 24 24"
|
|
462
|
-
stroke="currentColor"
|
|
463
|
-
stroke-width="2"
|
|
464
|
-
>
|
|
465
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
|
466
|
-
</svg>
|
|
467
|
-
)
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
function EmptyTreeIcon(props: { class?: string }): JSX.Element {
|
|
471
|
-
return (
|
|
472
|
-
<svg
|
|
473
|
-
class={props.class}
|
|
474
|
-
fill="none"
|
|
475
|
-
viewBox="0 0 24 24"
|
|
476
|
-
stroke="currentColor"
|
|
477
|
-
stroke-width="1.5"
|
|
478
|
-
>
|
|
479
|
-
<path
|
|
480
|
-
stroke-linecap="round"
|
|
481
|
-
stroke-linejoin="round"
|
|
482
|
-
d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6z"
|
|
483
|
-
/>
|
|
484
|
-
</svg>
|
|
485
|
-
)
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// Attach sub-components for convenience
|
|
489
|
-
Tree.Item = TreeItem
|
|
490
|
-
Tree.ExpandButton = TreeExpandButton
|
|
491
|
-
Tree.SelectionCheckbox = TreeSelectionCheckbox
|
|
492
|
-
|
|
493
|
-
// Re-export types for convenience
|
|
494
|
-
export type { Key, TreeItemData, TreeRenderItemState }
|