torch-glare 2.5.6 → 2.6.0
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 +4 -3
- package/dist/bin/index.js +9 -24
- package/dist/bin/index.js.map +1 -1
- package/dist/src/commands/add.d.ts +2 -2
- package/dist/src/commands/add.d.ts.map +1 -1
- package/dist/src/commands/add.js +4 -70
- package/dist/src/commands/add.js.map +1 -1
- package/dist/src/commands/hook.d.ts +5 -4
- package/dist/src/commands/hook.d.ts.map +1 -1
- package/dist/src/commands/hook.js +7 -75
- package/dist/src/commands/hook.js.map +1 -1
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/layout.d.ts +5 -4
- package/dist/src/commands/layout.d.ts.map +1 -1
- package/dist/src/commands/layout.js +7 -75
- package/dist/src/commands/layout.js.map +1 -1
- package/dist/src/commands/provider.d.ts +5 -4
- package/dist/src/commands/provider.d.ts.map +1 -1
- package/dist/src/commands/provider.js +7 -75
- package/dist/src/commands/provider.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +78 -43
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/commands/utils.d.ts +5 -4
- package/dist/src/commands/utils.d.ts.map +1 -1
- package/dist/src/commands/utils.js +7 -80
- package/dist/src/commands/utils.js.map +1 -1
- package/dist/src/shared/addFromRegistry.d.ts +16 -0
- package/dist/src/shared/addFromRegistry.d.ts.map +1 -0
- package/dist/src/shared/addFromRegistry.js +88 -0
- package/dist/src/shared/addFromRegistry.js.map +1 -0
- package/dist/src/shared/getInstallCommand.d.ts.map +1 -1
- package/dist/src/shared/getInstallCommand.js +5 -0
- package/dist/src/shared/getInstallCommand.js.map +1 -1
- package/dist/src/shared/installDependencies.d.ts +0 -10
- package/dist/src/shared/installDependencies.d.ts.map +1 -1
- package/dist/src/shared/installDependencies.js +0 -17
- package/dist/src/shared/installDependencies.js.map +1 -1
- package/dist/src/shared/installFromPlan.d.ts +7 -5
- package/dist/src/shared/installFromPlan.d.ts.map +1 -1
- package/dist/src/shared/installFromPlan.js +103 -36
- package/dist/src/shared/installFromPlan.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +12 -3
- package/dist/src/shared/loadRegistry.d.ts.map +1 -1
- package/dist/src/shared/loadRegistry.js +19 -20
- package/dist/src/shared/loadRegistry.js.map +1 -1
- package/dist/src/shared/registryClient.d.ts +19 -0
- package/dist/src/shared/registryClient.d.ts.map +1 -0
- package/dist/src/shared/registryClient.js +128 -0
- package/dist/src/shared/registryClient.js.map +1 -0
- package/dist/src/shared/resolveEntry.d.ts +10 -7
- package/dist/src/shared/resolveEntry.d.ts.map +1 -1
- package/dist/src/shared/resolveEntry.js +18 -13
- package/dist/src/shared/resolveEntry.js.map +1 -1
- package/dist/src/shared/suggestOtherCommand.d.ts +7 -1
- package/dist/src/shared/suggestOtherCommand.d.ts.map +1 -1
- package/dist/src/shared/suggestOtherCommand.js +29 -23
- package/dist/src/shared/suggestOtherCommand.js.map +1 -1
- package/dist/src/types/main.d.ts +31 -2
- package/dist/src/types/main.d.ts.map +1 -1
- package/package.json +6 -11
- package/apps/lib/components/ActionButton.tsx +0 -93
- package/apps/lib/components/ActionsGroup.tsx +0 -27
- package/apps/lib/components/AlertDialog.tsx +0 -204
- package/apps/lib/components/Avatar.tsx +0 -46
- package/apps/lib/components/Badge.tsx +0 -250
- package/apps/lib/components/BadgeField.tsx +0 -403
- package/apps/lib/components/Breadcrumb.tsx +0 -280
- package/apps/lib/components/Button.tsx +0 -325
- package/apps/lib/components/ButtonGroup.tsx +0 -190
- package/apps/lib/components/Calendar.tsx +0 -115
- package/apps/lib/components/Card.tsx +0 -95
- package/apps/lib/components/Checkbox.tsx +0 -42
- package/apps/lib/components/ColorPicker.tsx +0 -441
- package/apps/lib/components/ConclusionHeader.tsx +0 -148
- package/apps/lib/components/ContextMenu.tsx +0 -571
- package/apps/lib/components/CountBadge.tsx +0 -52
- package/apps/lib/components/DataTable.tsx +0 -213
- package/apps/lib/components/DataViews/badge.ts +0 -49
- package/apps/lib/components/DataViews/cell.tsx +0 -324
- package/apps/lib/components/DataViews/context.ts +0 -144
- package/apps/lib/components/DataViews/data-views.tsx +0 -395
- package/apps/lib/components/DataViews/filters/children.tsx +0 -98
- package/apps/lib/components/DataViews/filters/custom.tsx +0 -34
- package/apps/lib/components/DataViews/filters/filters.tsx +0 -157
- package/apps/lib/components/DataViews/filters/index.ts +0 -4
- package/apps/lib/components/DataViews/filters/labelled.tsx +0 -20
- package/apps/lib/components/DataViews/filters/presets.tsx +0 -65
- package/apps/lib/components/DataViews/filters/sync.tsx +0 -35
- package/apps/lib/components/DataViews/filters/values.ts +0 -173
- package/apps/lib/components/DataViews/header.tsx +0 -220
- package/apps/lib/components/DataViews/hooks/index.ts +0 -5
- package/apps/lib/components/DataViews/hooks/useActiveRow.ts +0 -22
- package/apps/lib/components/DataViews/hooks/useControllable.ts +0 -52
- package/apps/lib/components/DataViews/index.ts +0 -88
- package/apps/lib/components/DataViews/panel/columns.tsx +0 -153
- package/apps/lib/components/DataViews/panel/controls.tsx +0 -106
- package/apps/lib/components/DataViews/panel/index.ts +0 -3
- package/apps/lib/components/DataViews/panel/panel.tsx +0 -164
- package/apps/lib/components/DataViews/panel/saved-views.tsx +0 -67
- package/apps/lib/components/DataViews/panel/section.tsx +0 -81
- package/apps/lib/components/DataViews/panel/sort.tsx +0 -42
- package/apps/lib/components/DataViews/panel/tab.tsx +0 -31
- package/apps/lib/components/DataViews/slots.ts +0 -72
- package/apps/lib/components/DataViews/states.tsx +0 -73
- package/apps/lib/components/DataViews/types.ts +0 -510
- package/apps/lib/components/DataViews/views/board-view.tsx +0 -381
- package/apps/lib/components/DataViews/views/card-rows.tsx +0 -36
- package/apps/lib/components/DataViews/views/inbox-view.tsx +0 -260
- package/apps/lib/components/DataViews/views/pane-views.tsx +0 -196
- package/apps/lib/components/DataViews/views/table-view.tsx +0 -493
- package/apps/lib/components/DataViews/views/tree-view.tsx +0 -367
- package/apps/lib/components/DatePicker.tsx +0 -232
- package/apps/lib/components/Dialog.tsx +0 -116
- package/apps/lib/components/Divider.tsx +0 -28
- package/apps/lib/components/Drawer.tsx +0 -451
- package/apps/lib/components/DropdownMenu.tsx +0 -554
- package/apps/lib/components/FieldHint.tsx +0 -69
- package/apps/lib/components/Form.tsx +0 -182
- package/apps/lib/components/FormBuilder/context.ts +0 -85
- package/apps/lib/components/FormBuilder/field-kind.ts +0 -28
- package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +0 -60
- package/apps/lib/components/FormBuilder/fields/ColorField.tsx +0 -59
- package/apps/lib/components/FormBuilder/fields/CustomField.tsx +0 -11
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +0 -32
- package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +0 -74
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +0 -168
- package/apps/lib/components/FormBuilder/fields/FileField.tsx +0 -39
- package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +0 -132
- package/apps/lib/components/FormBuilder/fields/OtpField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +0 -109
- package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +0 -114
- package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +0 -157
- package/apps/lib/components/FormBuilder/fields/SliderField.tsx +0 -67
- package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +0 -41
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +0 -336
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +0 -213
- package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +0 -43
- package/apps/lib/components/FormBuilder/fields/countries.ts +0 -303
- package/apps/lib/components/FormBuilder/fields/index.ts +0 -25
- package/apps/lib/components/FormBuilder/form-builder.tsx +0 -198
- package/apps/lib/components/FormBuilder/index.ts +0 -31
- package/apps/lib/components/FormBuilder/numberFormat.ts +0 -16
- package/apps/lib/components/FormBuilder/submit.tsx +0 -67
- package/apps/lib/components/FormBuilder/types.ts +0 -316
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -250
- package/apps/lib/components/FormRenderer/detail.tsx +0 -256
- package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -358
- package/apps/lib/components/FormRenderer/header.tsx +0 -88
- package/apps/lib/components/FormRenderer/index.ts +0 -17
- package/apps/lib/components/FormRenderer/notch-action.tsx +0 -64
- package/apps/lib/components/FormRenderer/section.tsx +0 -39
- package/apps/lib/components/FormRenderer/stepper.tsx +0 -393
- package/apps/lib/components/FormRenderer/types.ts +0 -115
- package/apps/lib/components/FormSummary.tsx +0 -282
- package/apps/lib/components/HeaderBar.tsx +0 -117
- package/apps/lib/components/ImageAttachment.tsx +0 -209
- package/apps/lib/components/InnerLabelField.tsx +0 -154
- package/apps/lib/components/Input.tsx +0 -224
- package/apps/lib/components/InputField.tsx +0 -147
- package/apps/lib/components/InputOTP.tsx +0 -84
- package/apps/lib/components/Label.tsx +0 -129
- package/apps/lib/components/LabelField.tsx +0 -76
- package/apps/lib/components/LabeledCheckBox.tsx +0 -51
- package/apps/lib/components/LabeledRadio.tsx +0 -51
- package/apps/lib/components/LinkButton.tsx +0 -94
- package/apps/lib/components/LoginButton.tsx +0 -51
- package/apps/lib/components/PasswordLevel.tsx +0 -58
- package/apps/lib/components/Popover.tsx +0 -312
- package/apps/lib/components/ProfileMenu.tsx +0 -85
- package/apps/lib/components/Radio.tsx +0 -59
- package/apps/lib/components/RadioCard.tsx +0 -50
- package/apps/lib/components/ScrollArea.tsx +0 -54
- package/apps/lib/components/SearchField.tsx +0 -62
- package/apps/lib/components/SearchableSelect.tsx +0 -318
- package/apps/lib/components/SearchableTable.tsx +0 -344
- package/apps/lib/components/SearchableTree.tsx +0 -485
- package/apps/lib/components/SearchableTreeDialog.tsx +0 -502
- package/apps/lib/components/SectionBlock.tsx +0 -168
- package/apps/lib/components/Select.tsx +0 -347
- package/apps/lib/components/SimpleSelect.tsx +0 -225
- package/apps/lib/components/Skeleton.tsx +0 -12
- package/apps/lib/components/SlideDatePicker.tsx +0 -255
- package/apps/lib/components/SpinLoading.tsx +0 -174
- package/apps/lib/components/Stepper.tsx +0 -480
- package/apps/lib/components/Switch.tsx +0 -82
- package/apps/lib/components/TabFormItem.tsx +0 -153
- package/apps/lib/components/TabSwitch.tsx +0 -172
- package/apps/lib/components/Table.tsx +0 -597
- package/apps/lib/components/TextEditor/ChartBlockTool.ts +0 -676
- package/apps/lib/components/TextEditor/RichTextField.tsx +0 -46
- package/apps/lib/components/TextEditor/TableDnDWrapper.ts +0 -462
- package/apps/lib/components/TextEditor/TextEditor.tsx +0 -1164
- package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +0 -429
- package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +0 -70
- package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +0 -50
- package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +0 -48
- package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +0 -98
- package/apps/lib/components/TextEditor/editorjs.d.ts +0 -60
- package/apps/lib/components/TextEditor/index.ts +0 -7
- package/apps/lib/components/TextEditor/markdownParser.ts +0 -346
- package/apps/lib/components/Textarea.tsx +0 -117
- package/apps/lib/components/Timeline.tsx +0 -263
- package/apps/lib/components/Toast.tsx +0 -87
- package/apps/lib/components/Toggle.tsx +0 -125
- package/apps/lib/components/ToggleButton.tsx +0 -140
- package/apps/lib/components/Tooltip.tsx +0 -116
- package/apps/lib/components/TransparentLabel.tsx +0 -71
- package/apps/lib/components/TreeDropDown.tsx +0 -115
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +0 -380
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +0 -75
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +0 -354
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +0 -60
- package/apps/lib/components/TreeFolder/icons.tsx +0 -60
- package/apps/lib/components/TreeFolder/index.ts +0 -24
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +0 -109
- package/apps/lib/components/TreeFolder/types.ts +0 -77
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +0 -118
- package/apps/lib/hooks/useActiveTreeItem.ts +0 -61
- package/apps/lib/hooks/useClickOutside.ts +0 -27
- package/apps/lib/hooks/useDragDrop.tsx +0 -365
- package/apps/lib/hooks/useHtmlDir.ts +0 -31
- package/apps/lib/hooks/useInfiniteScroll.ts +0 -108
- package/apps/lib/hooks/useIsMobile.ts +0 -21
- package/apps/lib/hooks/useResize.ts +0 -67
- package/apps/lib/hooks/useTagSelection.ts +0 -300
- package/apps/lib/layouts/CNLayout.tsx +0 -372
- package/apps/lib/layouts/DataViewCard.tsx +0 -62
- package/apps/lib/layouts/FieldSection.tsx +0 -91
- package/apps/lib/layouts/TreeSubLayout.tsx +0 -173
- package/apps/lib/providers/ThemeProvider.tsx +0 -84
- package/apps/lib/registry.json +0 -1217
- package/apps/lib/tsconfig.json +0 -9
- package/apps/lib/tsconfig.tsbuildinfo +0 -1
- package/apps/lib/utils/cn.ts +0 -6
- package/apps/lib/utils/color.ts +0 -175
- package/apps/lib/utils/dataViews/path.ts +0 -67
- package/apps/lib/utils/dataViews/query.ts +0 -73
- package/apps/lib/utils/dataViews/types.ts +0 -187
- package/apps/lib/utils/dateFormat.ts +0 -108
- package/apps/lib/utils/resize.ts +0 -31
- package/apps/lib/utils/scroller.ts +0 -26
- package/apps/lib/utils/types.ts +0 -16
- package/docs/BLOCKS.md +0 -129
- package/docs/CHANGELOG-1.1.16.md +0 -108
- package/docs/Cover.png +0 -0
- package/docs/README.md +0 -215
- package/docs/components/action-button.md +0 -638
- package/docs/components/actions-group.md +0 -708
- package/docs/components/alert-dialog.md +0 -920
- package/docs/components/avatar.md +0 -709
- package/docs/components/badge-field.md +0 -738
- package/docs/components/badge.md +0 -301
- package/docs/components/breadcrumb.md +0 -930
- package/docs/components/button-group.md +0 -650
- package/docs/components/button.md +0 -639
- package/docs/components/calendar.md +0 -555
- package/docs/components/card.md +0 -622
- package/docs/components/chart-block-tool.md +0 -129
- package/docs/components/checkbox.md +0 -699
- package/docs/components/cn-layout.md +0 -854
- package/docs/components/color-picker.md +0 -101
- package/docs/components/conclusion-header.md +0 -80
- package/docs/components/context-menu.md +0 -483
- package/docs/components/count-badge.md +0 -560
- package/docs/components/data-table.md +0 -854
- package/docs/components/data-views/backend-response.md +0 -324
- package/docs/components/data-views/examples/a11y-rtl.md +0 -250
- package/docs/components/data-views/examples/api-orders-route.md +0 -130
- package/docs/components/data-views/examples/fields.md +0 -362
- package/docs/components/data-views/examples/filters.md +0 -307
- package/docs/components/data-views/examples/inbox-routing.md +0 -218
- package/docs/components/data-views/examples/index.md +0 -29
- package/docs/components/data-views/examples/overview.md +0 -244
- package/docs/components/data-views/examples/panel.md +0 -212
- package/docs/components/data-views/examples/scale.md +0 -231
- package/docs/components/data-views/examples/server-side.md +0 -210
- package/docs/components/data-views/examples/state.md +0 -250
- package/docs/components/data-views/examples/tree-custom.md +0 -388
- package/docs/components/data-views/examples/view-registry.md +0 -313
- package/docs/components/data-views/examples/views.md +0 -534
- package/docs/components/data-views/guide.md +0 -405
- package/docs/components/data-views/index.md +0 -1521
- package/docs/components/data-views/migration.md +0 -81
- package/docs/components/date-picker.md +0 -857
- package/docs/components/dialog.md +0 -929
- package/docs/components/divider.md +0 -766
- package/docs/components/drawer.md +0 -654
- package/docs/components/dropdown-menu.md +0 -668
- package/docs/components/field-hint.md +0 -898
- package/docs/components/field-section.md +0 -781
- package/docs/components/form-builder.md +0 -284
- package/docs/components/form-renderer.md +0 -396
- package/docs/components/form-summary.md +0 -138
- package/docs/components/form.md +0 -785
- package/docs/components/header-bar.md +0 -188
- package/docs/components/image-attachment.md +0 -906
- package/docs/components/inner-label-field.md +0 -819
- package/docs/components/input-field.md +0 -623
- package/docs/components/input-otp.md +0 -756
- package/docs/components/input.md +0 -634
- package/docs/components/label-field.md +0 -770
- package/docs/components/label.md +0 -761
- package/docs/components/labeled-check-box.md +0 -642
- package/docs/components/labeled-radio.md +0 -796
- package/docs/components/link-button.md +0 -685
- package/docs/components/login-button.md +0 -872
- package/docs/components/password-level.md +0 -803
- package/docs/components/popover.md +0 -649
- package/docs/components/profile-menu.md +0 -656
- package/docs/components/radio-card.md +0 -801
- package/docs/components/radio.md +0 -735
- package/docs/components/scroll-area.md +0 -691
- package/docs/components/search-field.md +0 -702
- package/docs/components/searchable-select.md +0 -368
- package/docs/components/searchable-table.md +0 -438
- package/docs/components/searchable-tree-dialog.md +0 -190
- package/docs/components/searchable-tree.md +0 -200
- package/docs/components/section-block.md +0 -483
- package/docs/components/select.md +0 -709
- package/docs/components/simple-select.md +0 -741
- package/docs/components/skeleton.md +0 -706
- package/docs/components/slide-date-picker.md +0 -837
- package/docs/components/spin-loading.md +0 -696
- package/docs/components/stepper.md +0 -316
- package/docs/components/switch.md +0 -770
- package/docs/components/tab-form-item.md +0 -773
- package/docs/components/tab-switch.md +0 -170
- package/docs/components/table-dnd-wrapper.md +0 -107
- package/docs/components/table.md +0 -1088
- package/docs/components/text-editor.md +0 -735
- package/docs/components/textarea.md +0 -681
- package/docs/components/timeline.md +0 -254
- package/docs/components/toast.md +0 -773
- package/docs/components/toggle-button.md +0 -643
- package/docs/components/toggle.md +0 -882
- package/docs/components/tooltip.md +0 -513
- package/docs/components/transparent-label.md +0 -721
- package/docs/components/tree-drop-down.md +0 -740
- package/docs/components/tree-folder.md +0 -110
- package/docs/components/tree-sub-layout.md +0 -707
- package/docs/explanation/architecture.md +0 -54
- package/docs/explanation/design-system.md +0 -52
- package/docs/how-to/form-and-list-recipes.md +0 -386
- package/docs/how-to/forms-with-form-builder.md +0 -472
- package/docs/how-to/guides.md +0 -1027
- package/docs/migration/changelog.md +0 -60
- package/docs/migration/form-builder-2.5.2.md +0 -113
- package/docs/reference/cli.md +0 -112
- package/docs/reference/components.md +0 -572
- package/docs/reference/hooks.md +0 -1523
- package/docs/reference/providers.md +0 -866
- package/docs/reference/tailwind-plugins.md +0 -942
- package/docs/reference/theme.md +0 -85
- package/docs/reference/types.md +0 -1016
- package/docs/reference/utilities.md +0 -726
- package/docs/tutorials/building-first-form.md +0 -846
- package/docs/tutorials/component-composition.md +0 -882
- package/docs/tutorials/getting-started.md +0 -302
- package/docs/tutorials/theming-basics.md +0 -785
|
@@ -1,706 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Skeleton
|
|
3
|
-
description: Loading placeholder component with pulse animation for content states
|
|
4
|
-
group: Data Display
|
|
5
|
-
keywords: [skeleton, loading, placeholder, shimmer, pulse, loader, content-loader]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Skeleton
|
|
9
|
-
|
|
10
|
-
> A simple, flexible loading placeholder component with pulse animation. Use to show a loading state while content is being fetched or processed.
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
13
|
-
|
|
14
|
-
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
15
|
-
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npx torch-glare@latest init
|
|
19
|
-
npx torch-glare@latest add Skeleton
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
`add` also copies any components, hooks, and utilities that `Skeleton` depends on.
|
|
23
|
-
|
|
24
|
-
## Import
|
|
25
|
-
|
|
26
|
-
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
27
|
-
|
|
28
|
-
```tsx
|
|
29
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Quick Examples
|
|
33
|
-
|
|
34
|
-
### Basic Usage
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
38
|
-
|
|
39
|
-
function Example() {
|
|
40
|
-
return <Skeleton className="h-4 w-[250px]" />
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Text Lines
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
48
|
-
|
|
49
|
-
function TextSkeleton() {
|
|
50
|
-
return (
|
|
51
|
-
<div className="space-y-2">
|
|
52
|
-
<Skeleton className="h-4 w-full" />
|
|
53
|
-
<Skeleton className="h-4 w-full" />
|
|
54
|
-
<Skeleton className="h-4 w-3/4" />
|
|
55
|
-
</div>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Card Skeleton
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
64
|
-
|
|
65
|
-
function CardSkeleton() {
|
|
66
|
-
return (
|
|
67
|
-
<div className="border rounded-lg p-4">
|
|
68
|
-
<Skeleton className="h-12 w-12 rounded-full mb-4" />
|
|
69
|
-
<Skeleton className="h-4 w-2/3 mb-2" />
|
|
70
|
-
<Skeleton className="h-4 w-full mb-2" />
|
|
71
|
-
<Skeleton className="h-4 w-5/6" />
|
|
72
|
-
</div>
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### Profile Skeleton
|
|
78
|
-
|
|
79
|
-
```typescript
|
|
80
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
81
|
-
|
|
82
|
-
function ProfileSkeleton() {
|
|
83
|
-
return (
|
|
84
|
-
<div className="flex items-center space-x-4">
|
|
85
|
-
{/* Avatar */}
|
|
86
|
-
<Skeleton className="h-16 w-16 rounded-full" />
|
|
87
|
-
|
|
88
|
-
{/* Profile info */}
|
|
89
|
-
<div className="space-y-2 flex-1">
|
|
90
|
-
<Skeleton className="h-4 w-[200px]" />
|
|
91
|
-
<Skeleton className="h-3 w-[150px]" />
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Table Skeleton
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
102
|
-
|
|
103
|
-
function TableSkeleton() {
|
|
104
|
-
return (
|
|
105
|
-
<div className="w-full">
|
|
106
|
-
{/* Table header */}
|
|
107
|
-
<div className="flex gap-4 mb-4">
|
|
108
|
-
<Skeleton className="h-8 w-1/4" />
|
|
109
|
-
<Skeleton className="h-8 w-1/4" />
|
|
110
|
-
<Skeleton className="h-8 w-1/4" />
|
|
111
|
-
<Skeleton className="h-8 w-1/4" />
|
|
112
|
-
</div>
|
|
113
|
-
|
|
114
|
-
{/* Table rows */}
|
|
115
|
-
{[...Array(5)].map((_, i) => (
|
|
116
|
-
<div key={i} className="flex gap-4 mb-2">
|
|
117
|
-
<Skeleton className="h-6 w-1/4" />
|
|
118
|
-
<Skeleton className="h-6 w-1/4" />
|
|
119
|
-
<Skeleton className="h-6 w-1/4" />
|
|
120
|
-
<Skeleton className="h-6 w-1/4" />
|
|
121
|
-
</div>
|
|
122
|
-
))}
|
|
123
|
-
</div>
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Button Skeleton
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
132
|
-
|
|
133
|
-
function ButtonSkeleton() {
|
|
134
|
-
return <Skeleton className="h-10 w-32 rounded-md" />
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Image Skeleton
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
142
|
-
|
|
143
|
-
function ImageSkeleton() {
|
|
144
|
-
return (
|
|
145
|
-
<div className="space-y-2">
|
|
146
|
-
{/* Image */}
|
|
147
|
-
<Skeleton className="h-64 w-full rounded-lg" />
|
|
148
|
-
|
|
149
|
-
{/* Caption */}
|
|
150
|
-
<Skeleton className="h-3 w-2/3 mx-auto" />
|
|
151
|
-
</div>
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### List Skeleton
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
160
|
-
|
|
161
|
-
function ListSkeleton() {
|
|
162
|
-
return (
|
|
163
|
-
<div className="space-y-4">
|
|
164
|
-
{[1, 2, 3, 4].map((i) => (
|
|
165
|
-
<div key={i} className="flex items-start space-x-3">
|
|
166
|
-
<Skeleton className="h-10 w-10 rounded-md flex-shrink-0" />
|
|
167
|
-
<div className="flex-1 space-y-2">
|
|
168
|
-
<Skeleton className="h-4 w-3/4" />
|
|
169
|
-
<Skeleton className="h-3 w-1/2" />
|
|
170
|
-
</div>
|
|
171
|
-
</div>
|
|
172
|
-
))}
|
|
173
|
-
</div>
|
|
174
|
-
)
|
|
175
|
-
}
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Dashboard Skeleton
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
182
|
-
|
|
183
|
-
function DashboardSkeleton() {
|
|
184
|
-
return (
|
|
185
|
-
<div className="grid grid-cols-3 gap-4">
|
|
186
|
-
{/* Stat cards */}
|
|
187
|
-
{[1, 2, 3].map((i) => (
|
|
188
|
-
<div key={i} className="border rounded-lg p-4">
|
|
189
|
-
<Skeleton className="h-4 w-20 mb-2" />
|
|
190
|
-
<Skeleton className="h-8 w-32" />
|
|
191
|
-
</div>
|
|
192
|
-
))}
|
|
193
|
-
|
|
194
|
-
{/* Chart */}
|
|
195
|
-
<div className="col-span-3 border rounded-lg p-4">
|
|
196
|
-
<Skeleton className="h-6 w-40 mb-4" />
|
|
197
|
-
<Skeleton className="h-64 w-full" />
|
|
198
|
-
</div>
|
|
199
|
-
</div>
|
|
200
|
-
)
|
|
201
|
-
}
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
### Conditional Loading
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
208
|
-
import { useState, useEffect } from 'react'
|
|
209
|
-
|
|
210
|
-
interface User {
|
|
211
|
-
name: string
|
|
212
|
-
email: string
|
|
213
|
-
avatar: string
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function UserProfile() {
|
|
217
|
-
const [user, setUser] = useState<User | null>(null)
|
|
218
|
-
const [loading, setLoading] = useState(true)
|
|
219
|
-
|
|
220
|
-
useEffect(() => {
|
|
221
|
-
fetchUser().then((data) => {
|
|
222
|
-
setUser(data)
|
|
223
|
-
setLoading(false)
|
|
224
|
-
})
|
|
225
|
-
}, [])
|
|
226
|
-
|
|
227
|
-
if (loading) {
|
|
228
|
-
return (
|
|
229
|
-
<div className="flex items-center space-x-4">
|
|
230
|
-
<Skeleton className="h-12 w-12 rounded-full" />
|
|
231
|
-
<div className="space-y-2">
|
|
232
|
-
<Skeleton className="h-4 w-[200px]" />
|
|
233
|
-
<Skeleton className="h-3 w-[150px]" />
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
)
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return (
|
|
240
|
-
<div className="flex items-center space-x-4">
|
|
241
|
-
<img src={user.avatar} alt={user.name} className="h-12 w-12 rounded-full" />
|
|
242
|
-
<div>
|
|
243
|
-
<h3>{user.name}</h3>
|
|
244
|
-
<p>{user.email}</p>
|
|
245
|
-
</div>
|
|
246
|
-
</div>
|
|
247
|
-
)
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### Grid Skeleton
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
255
|
-
|
|
256
|
-
function GridSkeleton() {
|
|
257
|
-
return (
|
|
258
|
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
259
|
-
{[...Array(6)].map((_, i) => (
|
|
260
|
-
<div key={i} className="border rounded-lg p-4">
|
|
261
|
-
<Skeleton className="h-48 w-full rounded mb-4" />
|
|
262
|
-
<Skeleton className="h-4 w-3/4 mb-2" />
|
|
263
|
-
<Skeleton className="h-3 w-full mb-2" />
|
|
264
|
-
<Skeleton className="h-3 w-5/6" />
|
|
265
|
-
</div>
|
|
266
|
-
))}
|
|
267
|
-
</div>
|
|
268
|
-
)
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## API Reference
|
|
273
|
-
|
|
274
|
-
### Skeleton Props
|
|
275
|
-
|
|
276
|
-
| Prop | Type | Default | Description |
|
|
277
|
-
|------|------|---------|-------------|
|
|
278
|
-
| `className` | `string` | - | Additional CSS classes for sizing and styling |
|
|
279
|
-
|
|
280
|
-
### Inherited Props
|
|
281
|
-
|
|
282
|
-
Extends `HTMLAttributes<HTMLDivElement>`, so all standard div props are supported:
|
|
283
|
-
- `style`, `id`, `data-*` attributes
|
|
284
|
-
- `onClick`, `onMouseEnter`, etc.
|
|
285
|
-
- `role`, `aria-*` attributes
|
|
286
|
-
|
|
287
|
-
## TypeScript
|
|
288
|
-
|
|
289
|
-
### Full Type Definitions
|
|
290
|
-
|
|
291
|
-
```typescript
|
|
292
|
-
interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
293
|
-
className?: string
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export const Skeleton: React.FC<SkeletonProps>
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### Usage with TypeScript
|
|
300
|
-
|
|
301
|
-
```typescript
|
|
302
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
303
|
-
|
|
304
|
-
function TypedSkeleton() {
|
|
305
|
-
const skeletonProps: React.ComponentProps<typeof Skeleton> = {
|
|
306
|
-
className: 'h-4 w-full',
|
|
307
|
-
'aria-label': 'Loading content',
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return <Skeleton {...skeletonProps} />
|
|
311
|
-
}
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
## Common Patterns
|
|
315
|
-
|
|
316
|
-
### Reusable Skeleton Components
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
320
|
-
|
|
321
|
-
// Avatar skeleton
|
|
322
|
-
export function AvatarSkeleton({ size = 'M' }: { size?: 'S' | 'M' | 'L' }) {
|
|
323
|
-
const sizeClasses = {
|
|
324
|
-
S: 'h-8 w-8',
|
|
325
|
-
M: 'h-12 w-12',
|
|
326
|
-
L: 'h-16 w-16',
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return <Skeleton className={`${sizeClasses[size]} rounded-full`} />
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Text skeleton
|
|
333
|
-
export function TextSkeleton({ lines = 3 }: { lines?: number }) {
|
|
334
|
-
return (
|
|
335
|
-
<div className="space-y-2">
|
|
336
|
-
{[...Array(lines)].map((_, i) => (
|
|
337
|
-
<Skeleton
|
|
338
|
-
key={i}
|
|
339
|
-
className={`h-4 ${i === lines - 1 ? 'w-3/4' : 'w-full'}`}
|
|
340
|
-
/>
|
|
341
|
-
))}
|
|
342
|
-
</div>
|
|
343
|
-
)
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Usage
|
|
347
|
-
<AvatarSkeleton size="L" />
|
|
348
|
-
<TextSkeleton lines={4} />
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
### With Suspense
|
|
352
|
-
|
|
353
|
-
```typescript
|
|
354
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
355
|
-
import { Suspense } from 'react'
|
|
356
|
-
|
|
357
|
-
function ProfileSkeleton() {
|
|
358
|
-
return (
|
|
359
|
-
<div className="flex items-center space-x-4">
|
|
360
|
-
<Skeleton className="h-16 w-16 rounded-full" />
|
|
361
|
-
<div className="space-y-2">
|
|
362
|
-
<Skeleton className="h-4 w-[200px]" />
|
|
363
|
-
<Skeleton className="h-3 w-[150px]" />
|
|
364
|
-
</div>
|
|
365
|
-
</div>
|
|
366
|
-
)
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function App() {
|
|
370
|
-
return (
|
|
371
|
-
<Suspense fallback={<ProfileSkeleton />}>
|
|
372
|
-
<UserProfile />
|
|
373
|
-
</Suspense>
|
|
374
|
-
)
|
|
375
|
-
}
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
### Loading States Hook
|
|
379
|
-
|
|
380
|
-
```typescript
|
|
381
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
382
|
-
import { useState, useEffect } from 'react'
|
|
383
|
-
|
|
384
|
-
function useLoading<T>(fetchFn: () => Promise<T>) {
|
|
385
|
-
const [data, setData] = useState<T | null>(null)
|
|
386
|
-
const [loading, setLoading] = useState(true)
|
|
387
|
-
|
|
388
|
-
useEffect(() => {
|
|
389
|
-
fetchFn().then((result) => {
|
|
390
|
-
setData(result)
|
|
391
|
-
setLoading(false)
|
|
392
|
-
})
|
|
393
|
-
}, [])
|
|
394
|
-
|
|
395
|
-
return { data, loading }
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function DataDisplay() {
|
|
399
|
-
const { data, loading } = useLoading(fetchData)
|
|
400
|
-
|
|
401
|
-
if (loading) {
|
|
402
|
-
return <Skeleton className="h-32 w-full" />
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return <div>{data}</div>
|
|
406
|
-
}
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
### Delayed Skeleton
|
|
410
|
-
|
|
411
|
-
```typescript
|
|
412
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
413
|
-
import { useState, useEffect } from 'react'
|
|
414
|
-
|
|
415
|
-
function DelayedSkeleton({ delay = 300, children }) {
|
|
416
|
-
const [show, setShow] = useState(false)
|
|
417
|
-
|
|
418
|
-
useEffect(() => {
|
|
419
|
-
const timer = setTimeout(() => setShow(true), delay)
|
|
420
|
-
return () => clearTimeout(timer)
|
|
421
|
-
}, [delay])
|
|
422
|
-
|
|
423
|
-
if (!show) return null
|
|
424
|
-
|
|
425
|
-
return children || <Skeleton className="h-4 w-full" />
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Usage: Only show skeleton if loading takes > 300ms
|
|
429
|
-
function FastLoading() {
|
|
430
|
-
const [loading, setLoading] = useState(true)
|
|
431
|
-
|
|
432
|
-
if (loading) {
|
|
433
|
-
return (
|
|
434
|
-
<DelayedSkeleton>
|
|
435
|
-
<Skeleton className="h-32 w-full" />
|
|
436
|
-
</DelayedSkeleton>
|
|
437
|
-
)
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
return <Content />
|
|
441
|
-
}
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
## Styling Tips
|
|
445
|
-
|
|
446
|
-
### Common Size Classes
|
|
447
|
-
|
|
448
|
-
```typescript
|
|
449
|
-
// Heights
|
|
450
|
-
<Skeleton className="h-3" /> // Small text
|
|
451
|
-
<Skeleton className="h-4" /> // Regular text
|
|
452
|
-
<Skeleton className="h-6" /> // Large text
|
|
453
|
-
<Skeleton className="h-8" /> // Heading
|
|
454
|
-
<Skeleton className="h-10" /> // Button
|
|
455
|
-
<Skeleton className="h-32" /> // Image/card
|
|
456
|
-
|
|
457
|
-
// Widths
|
|
458
|
-
<Skeleton className="w-1/4" /> // 25%
|
|
459
|
-
<Skeleton className="w-1/2" /> // 50%
|
|
460
|
-
<Skeleton className="w-3/4" /> // 75%
|
|
461
|
-
<Skeleton className="w-full" /> // 100%
|
|
462
|
-
<Skeleton className="w-[200px]" /> // Fixed width
|
|
463
|
-
|
|
464
|
-
// Shapes
|
|
465
|
-
<Skeleton className="rounded-full" /> // Circle/avatar
|
|
466
|
-
<Skeleton className="rounded-md" /> // Rounded corners
|
|
467
|
-
<Skeleton className="rounded-lg" /> // More rounded
|
|
468
|
-
<Skeleton className="rounded-none" /> // Square
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
### Custom Colors
|
|
472
|
-
|
|
473
|
-
```typescript
|
|
474
|
-
// Light gray (default)
|
|
475
|
-
<Skeleton className="h-4 w-full" />
|
|
476
|
-
|
|
477
|
-
// Custom color
|
|
478
|
-
<Skeleton className="h-4 w-full bg-blue-200" />
|
|
479
|
-
|
|
480
|
-
// Darker skeleton
|
|
481
|
-
<Skeleton className="h-4 w-full bg-gray-300" />
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
## Testing
|
|
485
|
-
|
|
486
|
-
### Unit Test Example
|
|
487
|
-
|
|
488
|
-
```typescript
|
|
489
|
-
import { render, screen } from '@testing-library/react'
|
|
490
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
491
|
-
|
|
492
|
-
describe('Skeleton', () => {
|
|
493
|
-
it('renders skeleton with correct classes', () => {
|
|
494
|
-
render(<Skeleton className="h-4 w-full" data-testid="skeleton" />)
|
|
495
|
-
|
|
496
|
-
const skeleton = screen.getByTestId('skeleton')
|
|
497
|
-
expect(skeleton).toHaveClass('h-4', 'w-full', 'animate-pulse')
|
|
498
|
-
})
|
|
499
|
-
|
|
500
|
-
it('accepts custom props', () => {
|
|
501
|
-
render(<Skeleton aria-label="Loading" id="custom-skeleton" />)
|
|
502
|
-
|
|
503
|
-
const skeleton = screen.getByLabelText('Loading')
|
|
504
|
-
expect(skeleton).toHaveAttribute('id', 'custom-skeleton')
|
|
505
|
-
})
|
|
506
|
-
})
|
|
507
|
-
```
|
|
508
|
-
|
|
509
|
-
### Testing Loading States
|
|
510
|
-
|
|
511
|
-
```typescript
|
|
512
|
-
import { render, screen, waitFor } from '@testing-library/react'
|
|
513
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
514
|
-
|
|
515
|
-
function ComponentWithLoading() {
|
|
516
|
-
const [loading, setLoading] = useState(true)
|
|
517
|
-
|
|
518
|
-
useEffect(() => {
|
|
519
|
-
setTimeout(() => setLoading(false), 1000)
|
|
520
|
-
}, [])
|
|
521
|
-
|
|
522
|
-
if (loading) return <Skeleton className="h-32" data-testid="skeleton" />
|
|
523
|
-
return <div data-testid="content">Content</div>
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
test('shows skeleton then content', async () => {
|
|
527
|
-
render(<ComponentWithLoading />)
|
|
528
|
-
|
|
529
|
-
// Skeleton visible initially
|
|
530
|
-
expect(screen.getByTestId('skeleton')).toBeInTheDocument()
|
|
531
|
-
|
|
532
|
-
// Content visible after loading
|
|
533
|
-
await waitFor(() => {
|
|
534
|
-
expect(screen.getByTestId('content')).toBeInTheDocument()
|
|
535
|
-
expect(screen.queryByTestId('skeleton')).not.toBeInTheDocument()
|
|
536
|
-
})
|
|
537
|
-
})
|
|
538
|
-
```
|
|
539
|
-
|
|
540
|
-
## Accessibility
|
|
541
|
-
|
|
542
|
-
- **ARIA Attributes**: Add `aria-label` for screen readers
|
|
543
|
-
```typescript
|
|
544
|
-
<Skeleton aria-label="Loading user profile" />
|
|
545
|
-
```
|
|
546
|
-
|
|
547
|
-
- **ARIA Live Region**: Announce when loading completes
|
|
548
|
-
```typescript
|
|
549
|
-
<div aria-live="polite" aria-busy={loading}>
|
|
550
|
-
{loading ? <Skeleton /> : <Content />}
|
|
551
|
-
</div>
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
- **Reduced Motion**: Pulse animation respects `prefers-reduced-motion`
|
|
555
|
-
```css
|
|
556
|
-
@media (prefers-reduced-motion: reduce) {
|
|
557
|
-
.animate-pulse {
|
|
558
|
-
animation: none;
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
### Enhanced Accessibility
|
|
564
|
-
|
|
565
|
-
```typescript
|
|
566
|
-
import { Skeleton } from "@/components/Skeleton";
|
|
567
|
-
|
|
568
|
-
function AccessibleSkeleton() {
|
|
569
|
-
return (
|
|
570
|
-
<div
|
|
571
|
-
role="status"
|
|
572
|
-
aria-live="polite"
|
|
573
|
-
aria-label="Loading content"
|
|
574
|
-
>
|
|
575
|
-
<Skeleton className="h-32 w-full" />
|
|
576
|
-
<span className="sr-only">Loading...</span>
|
|
577
|
-
</div>
|
|
578
|
-
)
|
|
579
|
-
}
|
|
580
|
-
```
|
|
581
|
-
|
|
582
|
-
## Performance
|
|
583
|
-
|
|
584
|
-
| Metric | Value |
|
|
585
|
-
|--------|-------|
|
|
586
|
-
| Bundle size (gzip) | <0.5kb |
|
|
587
|
-
| Dependencies | None |
|
|
588
|
-
| First render | <1ms |
|
|
589
|
-
| Animation | CSS-only (GPU accelerated) |
|
|
590
|
-
| Tree-shakeable | ✅ |
|
|
591
|
-
|
|
592
|
-
### Performance Tips
|
|
593
|
-
|
|
594
|
-
1. **Use CSS animations**: Built-in `animate-pulse` is GPU-accelerated
|
|
595
|
-
2. **Avoid complex skeletons**: Simpler shapes render faster
|
|
596
|
-
3. **Reuse skeleton components**: Create reusable patterns
|
|
597
|
-
4. **Consider delayed showing**: Don't show skeleton for fast loads (<300ms)
|
|
598
|
-
|
|
599
|
-
```typescript
|
|
600
|
-
// Good: Simple skeleton
|
|
601
|
-
<Skeleton className="h-4 w-full" />
|
|
602
|
-
|
|
603
|
-
// Avoid: Overly complex nested skeletons
|
|
604
|
-
// (unless necessary for UX)
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
## Migration from Other Loaders
|
|
608
|
-
|
|
609
|
-
### From React Loading Skeleton
|
|
610
|
-
|
|
611
|
-
```diff
|
|
612
|
-
- import Skeleton from 'react-loading-skeleton'
|
|
613
|
-
+ import { Skeleton } from "@/components/Skeleton";
|
|
614
|
-
|
|
615
|
-
- <Skeleton count={3} />
|
|
616
|
-
+ {[...Array(3)].map((_, i) => (
|
|
617
|
-
+ <Skeleton key={i} className="h-4 w-full mb-2" />
|
|
618
|
-
+ ))}
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
### From Material-UI Skeleton
|
|
622
|
-
|
|
623
|
-
```diff
|
|
624
|
-
- import { Skeleton } from '@mui/material'
|
|
625
|
-
+ import { Skeleton } from "@/components/Skeleton";
|
|
626
|
-
|
|
627
|
-
- <Skeleton width={210} height={60} /> {/* MUI text variant */}
|
|
628
|
-
+ <Skeleton className="h-[60px] w-[210px]" />
|
|
629
|
-
|
|
630
|
-
- <Skeleton width={40} height={40} /> {/* MUI circular variant */}
|
|
631
|
-
+ <Skeleton className="h-10 w-10 rounded-full" />
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
### From Ant Design Skeleton
|
|
635
|
-
|
|
636
|
-
```diff
|
|
637
|
-
- import { Skeleton } from 'antd'
|
|
638
|
-
+ import { Skeleton } from "@/components/Skeleton";
|
|
639
|
-
|
|
640
|
-
- <Skeleton active />
|
|
641
|
-
+ <Skeleton className="h-4 w-full" />
|
|
642
|
-
|
|
643
|
-
- <Skeleton.Avatar active /> {/* Ant large avatar */}
|
|
644
|
-
+ <Skeleton className="h-16 w-16 rounded-full" />
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
## Best Practices
|
|
648
|
-
|
|
649
|
-
1. **Match content dimensions**: Skeleton should approximate final content size
|
|
650
|
-
```typescript
|
|
651
|
-
// Content is h-32, skeleton should be too
|
|
652
|
-
{loading ? <Skeleton className="h-32 w-full" /> : <Content />}
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
2. **Use appropriate shapes**: Circles for avatars, rectangles for text
|
|
656
|
-
```typescript
|
|
657
|
-
<Skeleton className="rounded-full" /> // Avatar
|
|
658
|
-
<Skeleton className="rounded-md" /> // Card
|
|
659
|
-
```
|
|
660
|
-
|
|
661
|
-
3. **Show hierarchy**: Vary skeleton sizes to indicate content importance
|
|
662
|
-
```typescript
|
|
663
|
-
<Skeleton className="h-8 w-3/4 mb-2" /> // Title
|
|
664
|
-
<Skeleton className="h-4 w-full mb-1" /> // Text
|
|
665
|
-
<Skeleton className="h-4 w-5/6" /> // Text
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
4. **Don't overuse**: Too many skeletons can be distracting
|
|
669
|
-
```typescript
|
|
670
|
-
// Good: Show skeleton for main content only
|
|
671
|
-
{loading ? <Skeleton /> : <MainContent />}
|
|
672
|
-
|
|
673
|
-
// Avoid: Skeletons for every tiny element
|
|
674
|
-
```
|
|
675
|
-
|
|
676
|
-
5. **Add aria-labels**: Help screen reader users understand loading state
|
|
677
|
-
```typescript
|
|
678
|
-
<Skeleton aria-label="Loading article" />
|
|
679
|
-
```
|
|
680
|
-
|
|
681
|
-
6. **Consider delay**: Don't show skeleton for very fast loads
|
|
682
|
-
```typescript
|
|
683
|
-
// Show skeleton only if loading > 300ms
|
|
684
|
-
<DelayedSkeleton delay={300}>
|
|
685
|
-
<Skeleton />
|
|
686
|
-
</DelayedSkeleton>
|
|
687
|
-
```
|
|
688
|
-
|
|
689
|
-
7. **Create reusable patterns**: Build common skeleton layouts
|
|
690
|
-
```typescript
|
|
691
|
-
export function CardSkeleton() {
|
|
692
|
-
return (
|
|
693
|
-
<div className="border rounded-lg p-4">
|
|
694
|
-
<Skeleton className="h-48 w-full rounded mb-4" />
|
|
695
|
-
<Skeleton className="h-4 w-3/4 mb-2" />
|
|
696
|
-
<Skeleton className="h-3 w-full" />
|
|
697
|
-
</div>
|
|
698
|
-
)
|
|
699
|
-
}
|
|
700
|
-
```
|
|
701
|
-
|
|
702
|
-
## Related Components
|
|
703
|
-
|
|
704
|
-
- [SpinLoading](./spin-loading.md) - Spinner loader for inline loading states
|
|
705
|
-
- [Card](./card.md) - Often used with skeleton for card layouts
|
|
706
|
-
- [Avatar](./avatar.md) - Avatar component that skeleton often mimics
|