@torch-ui/solid 0.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/README.md +166 -0
- package/package.json +67 -0
- package/src/components/actions/Button.tsx +612 -0
- package/src/components/actions/ButtonGroup.tsx +728 -0
- package/src/components/actions/Copy.tsx +98 -0
- package/src/components/actions/DarkModeToggle.tsx +80 -0
- package/src/components/actions/Link.tsx +37 -0
- package/src/components/actions/index.ts +19 -0
- package/src/components/actions/useCopyToClipboard.ts +90 -0
- package/src/components/charts/Chart.tsx +331 -0
- package/src/components/charts/Sparkline.tsx +156 -0
- package/src/components/charts/index.ts +13 -0
- package/src/components/data-display/Avatar.tsx +208 -0
- package/src/components/data-display/AvatarGroup.tsx +228 -0
- package/src/components/data-display/Badge.tsx +70 -0
- package/src/components/data-display/Carousel.tsx +214 -0
- package/src/components/data-display/ColorSwatch.tsx +56 -0
- package/src/components/data-display/DataTable.tsx +886 -0
- package/src/components/data-display/EmptyState.tsx +61 -0
- package/src/components/data-display/Image.tsx +277 -0
- package/src/components/data-display/Kbd.tsx +114 -0
- package/src/components/data-display/Persona.tsx +78 -0
- package/src/components/data-display/StatCard.tsx +338 -0
- package/src/components/data-display/Table.tsx +147 -0
- package/src/components/data-display/Tag.tsx +91 -0
- package/src/components/data-display/Timeline.tsx +200 -0
- package/src/components/data-display/TreeView.tsx +172 -0
- package/src/components/data-display/Video.tsx +95 -0
- package/src/components/data-display/avatar-utils.ts +32 -0
- package/src/components/data-display/index.ts +81 -0
- package/src/components/feedback/Loading.tsx +159 -0
- package/src/components/feedback/Progress.tsx +321 -0
- package/src/components/feedback/Skeleton.tsx +62 -0
- package/src/components/feedback/SkeletonBlocks.tsx +222 -0
- package/src/components/feedback/Toast.tsx +648 -0
- package/src/components/feedback/index.ts +44 -0
- package/src/components/feedback/password/PasswordStrengthIndicator.tsx +232 -0
- package/src/components/feedback/password/password-strength.ts +115 -0
- package/src/components/feedback/password/password-validation-data.ts +66 -0
- package/src/components/feedback/password/password-validation.ts +93 -0
- package/src/components/forms/Autocomplete.tsx +268 -0
- package/src/components/forms/Checkbox.tsx +155 -0
- package/src/components/forms/CodeInput.tsx +237 -0
- package/src/components/forms/ColorPicker/ColorPicker.tsx +469 -0
- package/src/components/forms/ColorPicker/color-utils.ts +75 -0
- package/src/components/forms/ColorPicker/index.ts +2 -0
- package/src/components/forms/DatePicker.tsx +516 -0
- package/src/components/forms/DateRangePicker.tsx +464 -0
- package/src/components/forms/FieldPicker.tsx +64 -0
- package/src/components/forms/FileUpload.tsx +614 -0
- package/src/components/forms/FilterBuilder/FilterGroupBlock.ts +6 -0
- package/src/components/forms/FilterBuilder.tsx +16 -0
- package/src/components/forms/FilterRuleRow.tsx +68 -0
- package/src/components/forms/Input.tsx +200 -0
- package/src/components/forms/MultiSelect.tsx +361 -0
- package/src/components/forms/NumberField.tsx +145 -0
- package/src/components/forms/RadioGroup.tsx +135 -0
- package/src/components/forms/RelativeDateDefaultInput.tsx +62 -0
- package/src/components/forms/ReorderableList.tsx +163 -0
- package/src/components/forms/Select.tsx +268 -0
- package/src/components/forms/Slider.tsx +260 -0
- package/src/components/forms/Switch.tsx +135 -0
- package/src/components/forms/TextArea.tsx +202 -0
- package/src/components/forms/ViewCustomizer.tsx +44 -0
- package/src/components/forms/index.ts +43 -0
- package/src/components/layout/Accordion.tsx +110 -0
- package/src/components/layout/Alert.tsx +156 -0
- package/src/components/layout/BlockQuote.tsx +70 -0
- package/src/components/layout/Card.tsx +166 -0
- package/src/components/layout/CodeBlock/CodeBlock.tsx +477 -0
- package/src/components/layout/CodeBlock/code-block-tokens.css +104 -0
- package/src/components/layout/CodeBlock/prism.ts +81 -0
- package/src/components/layout/Collapsible.tsx +84 -0
- package/src/components/layout/Container.tsx +55 -0
- package/src/components/layout/Divider.tsx +64 -0
- package/src/components/layout/Form.tsx +39 -0
- package/src/components/layout/FormActions.tsx +50 -0
- package/src/components/layout/Grid.tsx +53 -0
- package/src/components/layout/PageHeading.tsx +46 -0
- package/src/components/layout/PromptWithAction.tsx +49 -0
- package/src/components/layout/Section.tsx +60 -0
- package/src/components/layout/TablePanel.tsx +24 -0
- package/src/components/layout/TableView/TableView.tsx +1018 -0
- package/src/components/layout/TableView/index.ts +3 -0
- package/src/components/layout/TableView/types.ts +51 -0
- package/src/components/layout/WizardStep.tsx +40 -0
- package/src/components/layout/WizardStepper.tsx +173 -0
- package/src/components/layout/index.ts +96 -0
- package/src/components/navigation/Breadcrumbs.tsx +66 -0
- package/src/components/navigation/DropdownMenu.tsx +86 -0
- package/src/components/navigation/MegaMenu.tsx +480 -0
- package/src/components/navigation/NavigationMenu.tsx +305 -0
- package/src/components/navigation/Pagination.tsx +298 -0
- package/src/components/navigation/Sidebar.tsx +280 -0
- package/src/components/navigation/Tabs.tsx +122 -0
- package/src/components/navigation/ViewSwitcher.tsx +314 -0
- package/src/components/navigation/index.ts +66 -0
- package/src/components/overlays/AlertDialog.tsx +174 -0
- package/src/components/overlays/ContextMenu.tsx +65 -0
- package/src/components/overlays/Dialog.tsx +279 -0
- package/src/components/overlays/Drawer.tsx +370 -0
- package/src/components/overlays/HoverCard.tsx +107 -0
- package/src/components/overlays/Popover.tsx +73 -0
- package/src/components/overlays/Tooltip.tsx +31 -0
- package/src/components/overlays/index.ts +71 -0
- package/src/components/typography/Code.tsx +72 -0
- package/src/components/typography/Icon.tsx +36 -0
- package/src/components/typography/index.ts +10 -0
- package/src/env.d.ts +9 -0
- package/src/index.ts +13 -0
- package/src/styles/theme.css +226 -0
- package/src/types/avatar-types.ts +11 -0
- package/src/types/filter-types.ts +35 -0
- package/src/utilities/classNames.ts +6 -0
- package/src/utilities/componentSize.ts +46 -0
- package/src/utilities/i18n.tsx +60 -0
- package/src/utilities/mergeRefs.ts +12 -0
- package/src/utilities/relativeDateDefault.ts +14 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable skeleton blocks for common layouts (Card, Table, Section, etc.).
|
|
3
|
+
* These do NOT set role="status" or aria-label — they are intended to be
|
|
4
|
+
* wrapped by a container that provides accessibility (e.g. <Loading>).
|
|
5
|
+
*/
|
|
6
|
+
import type { JSX } from 'solid-js'
|
|
7
|
+
import { For, Show, splitProps } from 'solid-js'
|
|
8
|
+
import { cn } from '../../utilities/classNames'
|
|
9
|
+
|
|
10
|
+
const range = (n: number) => Array.from({ length: n }, (_, i) => i)
|
|
11
|
+
|
|
12
|
+
const SKELETON_CLASS = 'animate-pulse'
|
|
13
|
+
const BAR = 'rounded bg-ink-200'
|
|
14
|
+
const BAR_LIGHT = 'rounded bg-surface-overlay'
|
|
15
|
+
const CARD_BASE =
|
|
16
|
+
'rounded-xl border border-surface-border bg-surface-raised'
|
|
17
|
+
const TABLE_HEAD = 'border-b border-surface-border'
|
|
18
|
+
const TABLE_DIVIDE = 'divide-y divide-surface-border'
|
|
19
|
+
|
|
20
|
+
/** Skeleton that matches Card layout: optional header, body with N lines. Compose to match your Card structure. */
|
|
21
|
+
export interface SkeletonCardProps {
|
|
22
|
+
/** Show a header bar (like Card.Header). Default true. */
|
|
23
|
+
header?: boolean
|
|
24
|
+
/** Number of body lines. Default 2. */
|
|
25
|
+
bodyLines?: number
|
|
26
|
+
/** Horizontal layout: image/avatar placeholder on left (like Card horizontal). */
|
|
27
|
+
horizontal?: boolean
|
|
28
|
+
class?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function SkeletonCard(props: SkeletonCardProps): JSX.Element {
|
|
32
|
+
const [local] = splitProps(props, ['header', 'bodyLines', 'horizontal', 'class'])
|
|
33
|
+
|
|
34
|
+
const header = () => local.header !== false
|
|
35
|
+
const bodyLines = () => local.bodyLines ?? 2
|
|
36
|
+
const horizontal = () => local.horizontal === true
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
class={cn(
|
|
40
|
+
SKELETON_CLASS,
|
|
41
|
+
CARD_BASE,
|
|
42
|
+
horizontal() ? 'flex flex-row overflow-hidden' : 'flex flex-col',
|
|
43
|
+
local.class
|
|
44
|
+
)}
|
|
45
|
+
aria-hidden="true"
|
|
46
|
+
>
|
|
47
|
+
<Show when={horizontal()}>
|
|
48
|
+
<div class="h-24 w-24 shrink-0 rounded-l-xl bg-surface-overlay sm:h-28 sm:w-28" />
|
|
49
|
+
</Show>
|
|
50
|
+
<div class="min-w-0 flex-1 flex flex-col">
|
|
51
|
+
<Show when={header()}>
|
|
52
|
+
<div class="flex shrink-0 items-center justify-between gap-3 border-b border-surface-border px-6 py-4">
|
|
53
|
+
<div class={cn('h-5 w-32', BAR)} />
|
|
54
|
+
</div>
|
|
55
|
+
</Show>
|
|
56
|
+
<div class="flex flex-1 flex-col gap-2 p-6">
|
|
57
|
+
<For each={range(bodyLines())}>
|
|
58
|
+
{(i) => (
|
|
59
|
+
<div
|
|
60
|
+
class={cn('h-4 rounded', BAR_LIGHT)}
|
|
61
|
+
style={{ width: `${Math.max(50, 90 - (i + 1) * 15)}%` }}
|
|
62
|
+
/>
|
|
63
|
+
)}
|
|
64
|
+
</For>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Skeleton that matches Table layout: header row + N body rows × M cells. Compose to match your Table structure. */
|
|
72
|
+
export interface SkeletonTableProps {
|
|
73
|
+
/** Number of body rows. Default 5. */
|
|
74
|
+
rows?: number
|
|
75
|
+
/** Number of columns (header + each row). Default 4. */
|
|
76
|
+
columns?: number
|
|
77
|
+
class?: string
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function SkeletonTable(props: SkeletonTableProps): JSX.Element {
|
|
81
|
+
const [local] = splitProps(props, ['rows', 'columns', 'class'])
|
|
82
|
+
|
|
83
|
+
const rows = () => local.rows ?? 5
|
|
84
|
+
const columns = () => local.columns ?? 4
|
|
85
|
+
return (
|
|
86
|
+
<div class={cn(SKELETON_CLASS, 'overflow-hidden rounded-xl border border-surface-border bg-surface-raised', local.class)} aria-hidden="true">
|
|
87
|
+
<div class={cn('flex gap-4 px-6 py-3', TABLE_HEAD)}>
|
|
88
|
+
<For each={range(columns())}>
|
|
89
|
+
{() => <div class={cn('h-4 flex-1 rounded', BAR_LIGHT)} />}
|
|
90
|
+
</For>
|
|
91
|
+
</div>
|
|
92
|
+
<div class={TABLE_DIVIDE}>
|
|
93
|
+
<For each={range(rows())}>
|
|
94
|
+
{() => (
|
|
95
|
+
<div class="flex gap-4 px-6 py-4">
|
|
96
|
+
<For each={range(columns())}>
|
|
97
|
+
{() => <div class={cn('h-4 flex-1 rounded', BAR_LIGHT)} />}
|
|
98
|
+
</For>
|
|
99
|
+
</div>
|
|
100
|
+
)}
|
|
101
|
+
</For>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Skeleton that matches Section / PageHeading: title bar + optional description + content block. Compose to match your Section structure. */
|
|
108
|
+
export interface SkeletonSectionProps {
|
|
109
|
+
/** Show a description line under the title. Default true. */
|
|
110
|
+
description?: boolean
|
|
111
|
+
/** Show a content block below (e.g. form or card placeholder). Default true. */
|
|
112
|
+
content?: boolean
|
|
113
|
+
/** Content block lines. Default 3. */
|
|
114
|
+
contentLines?: number
|
|
115
|
+
class?: string
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function SkeletonSection(props: SkeletonSectionProps): JSX.Element {
|
|
119
|
+
const [local] = splitProps(props, ['description', 'content', 'contentLines', 'class'])
|
|
120
|
+
|
|
121
|
+
const description = () => local.description !== false
|
|
122
|
+
const content = () => local.content !== false
|
|
123
|
+
const contentLines = () => local.contentLines ?? 3
|
|
124
|
+
return (
|
|
125
|
+
<div class={cn(SKELETON_CLASS, 'space-y-4', local.class)} aria-hidden="true">
|
|
126
|
+
<div>
|
|
127
|
+
<div class={cn('h-7 w-48 rounded', BAR)} />
|
|
128
|
+
<Show when={description()}>
|
|
129
|
+
<div class={cn('mt-2 h-4 max-w-md rounded', BAR_LIGHT)} />
|
|
130
|
+
</Show>
|
|
131
|
+
</div>
|
|
132
|
+
<Show when={content()}>
|
|
133
|
+
<div class="rounded-xl border border-surface-border bg-surface-raised p-6">
|
|
134
|
+
<div class="flex flex-col gap-3">
|
|
135
|
+
<For each={range(contentLines())}>
|
|
136
|
+
{(i) => (
|
|
137
|
+
<div
|
|
138
|
+
class={cn('h-4 rounded', BAR_LIGHT)}
|
|
139
|
+
style={{ width: `${90 - (i + 1) * 10}%` }}
|
|
140
|
+
/>
|
|
141
|
+
)}
|
|
142
|
+
</For>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</Show>
|
|
146
|
+
</div>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Skeleton block for a simple title + one line (e.g. PageHeading only, no section content). */
|
|
151
|
+
export interface SkeletonHeadingProps {
|
|
152
|
+
/** Show description line. Default true. */
|
|
153
|
+
description?: boolean
|
|
154
|
+
class?: string
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function SkeletonHeading(props: SkeletonHeadingProps): JSX.Element {
|
|
158
|
+
const [local] = splitProps(props, ['description', 'class'])
|
|
159
|
+
|
|
160
|
+
const description = () => local.description !== false
|
|
161
|
+
return (
|
|
162
|
+
<div class={cn(SKELETON_CLASS, local.class)} aria-hidden="true">
|
|
163
|
+
<div class={cn('h-8 w-48 rounded', BAR)} />
|
|
164
|
+
<Show when={description()}>
|
|
165
|
+
<div class={cn('mt-2 h-4 max-w-sm rounded', BAR_LIGHT)} />
|
|
166
|
+
</Show>
|
|
167
|
+
</div>
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Skeleton for a form-like block: label lines + inputs + buttons. */
|
|
172
|
+
export interface SkeletonFormProps {
|
|
173
|
+
fields?: number
|
|
174
|
+
buttons?: number
|
|
175
|
+
class?: string
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function SkeletonForm(props: SkeletonFormProps): JSX.Element {
|
|
179
|
+
const [local] = splitProps(props, ['fields', 'buttons', 'class'])
|
|
180
|
+
|
|
181
|
+
const fields = () => local.fields ?? 2
|
|
182
|
+
const buttons = () => local.buttons ?? 2
|
|
183
|
+
return (
|
|
184
|
+
<div class={cn(SKELETON_CLASS, 'space-y-4 rounded-xl border border-surface-border bg-surface-raised p-6', local.class)} aria-hidden="true">
|
|
185
|
+
<For each={range(fields())}>
|
|
186
|
+
{() => (
|
|
187
|
+
<div class="space-y-1">
|
|
188
|
+
<div class={cn('h-4 w-32 rounded', BAR_LIGHT)} />
|
|
189
|
+
<div class={cn('h-10 w-full rounded-lg', BAR_LIGHT)} />
|
|
190
|
+
</div>
|
|
191
|
+
)}
|
|
192
|
+
</For>
|
|
193
|
+
<div class="flex gap-2 pt-2">
|
|
194
|
+
<For each={range(buttons())}>
|
|
195
|
+
{() => <div class={cn('h-10 w-24 rounded-lg', BAR)} />}
|
|
196
|
+
</For>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Skeleton for a sidebar nav block: section label + list of items. */
|
|
203
|
+
export interface SkeletonNavBlockProps {
|
|
204
|
+
items?: number
|
|
205
|
+
class?: string
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function SkeletonNavBlock(props: SkeletonNavBlockProps): JSX.Element {
|
|
209
|
+
const [local] = splitProps(props, ['items', 'class'])
|
|
210
|
+
|
|
211
|
+
const items = () => local.items ?? 4
|
|
212
|
+
return (
|
|
213
|
+
<div class={cn(SKELETON_CLASS, 'space-y-2', local.class)} aria-hidden="true">
|
|
214
|
+
<div class={cn('h-3 w-20 rounded', BAR)} />
|
|
215
|
+
<div class="space-y-0.5">
|
|
216
|
+
<For each={range(items())}>
|
|
217
|
+
{() => <div class={cn('h-9 rounded-lg', BAR_LIGHT)} />}
|
|
218
|
+
</For>
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
)
|
|
222
|
+
}
|