torch-glare 2.5.5 → 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 -338
- package/apps/lib/components/Breadcrumb.tsx +0 -280
- package/apps/lib/components/Button.tsx +0 -317
- 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 -383
- 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 -84
- 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 -63
- package/apps/lib/components/DataViews/states.tsx +0 -38
- 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 -420
- package/apps/lib/components/DropdownMenu.tsx +0 -540
- package/apps/lib/components/FieldHint.tsx +0 -69
- package/apps/lib/components/Form.tsx +0 -182
- package/apps/lib/components/FormBuilder/context.ts +0 -73
- 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 -163
- 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 -91
- 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 -47
- package/apps/lib/components/FormBuilder/types.ts +0 -311
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -128
- package/apps/lib/components/FormRenderer/detail.tsx +0 -207
- package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -297
- package/apps/lib/components/FormRenderer/header.tsx +0 -88
- package/apps/lib/components/FormRenderer/index.ts +0 -15
- package/apps/lib/components/FormRenderer/section.tsx +0 -39
- package/apps/lib/components/FormRenderer/stepper.tsx +0 -339
- package/apps/lib/components/FormRenderer/types.ts +0 -78
- 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 -147
- 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 -253
- 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 -610
- 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 -58
- package/apps/lib/hooks/useClickOutside.ts +0 -27
- package/apps/lib/hooks/useDragDrop.tsx +0 -365
- 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 -214
- 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 -1201
- 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/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 -712
- 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 -1495
- package/docs/components/data-views/migration.md +0 -79
- 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 -276
- package/docs/components/form-renderer.md +0 -326
- 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 -477
- 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 -54
- 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 -1500
- 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 -704
- 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,837 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: SlideDatePicker
|
|
3
|
-
description: Mobile-optimized date picker with slide/wheel interface for intuitive year, month, and day selection
|
|
4
|
-
group: Date & Time
|
|
5
|
-
keywords: [slide-picker, date, wheel, mobile, picker, scroll]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# SlideDatePicker
|
|
9
|
-
|
|
10
|
-
> A mobile-optimized date picker component featuring an intuitive slide/wheel interface for selecting year, month, and day. Perfect for touch devices and mobile-first applications with natural scrolling interactions.
|
|
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 SlideDatePicker
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
`add` also copies any components, hooks, and utilities that `SlideDatePicker` 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 { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Quick Examples
|
|
33
|
-
|
|
34
|
-
### Basic Usage
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
38
|
-
import { useState } from 'react'
|
|
39
|
-
|
|
40
|
-
function Example() {
|
|
41
|
-
const [date, setDate] = useState<Date>(new Date())
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<SlideDatePicker
|
|
45
|
-
value={date}
|
|
46
|
-
onChange={(e) => setDate(e.target.value)}
|
|
47
|
-
/>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Custom Date Format
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
56
|
-
import { useState } from 'react'
|
|
57
|
-
|
|
58
|
-
function CustomFormat() {
|
|
59
|
-
const [date, setDate] = useState<Date>(new Date())
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<SlideDatePicker
|
|
63
|
-
value={date}
|
|
64
|
-
onChange={(e) => setDate(e.target.value)}
|
|
65
|
-
dateFormat="MMM dd, yyyy" // "Jan 15, 2024"
|
|
66
|
-
/>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### With Custom Trigger
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
75
|
-
import { Button } from "@/components/Button";
|
|
76
|
-
import { useState } from 'react'
|
|
77
|
-
|
|
78
|
-
function CustomTrigger() {
|
|
79
|
-
const [date, setDate] = useState<Date>(new Date())
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<SlideDatePicker
|
|
83
|
-
value={date}
|
|
84
|
-
onChange={(e) => setDate(e.target.value)}
|
|
85
|
-
>
|
|
86
|
-
<Button variant="BluSecStyle">
|
|
87
|
-
<i className="ri-calendar-2-line" />
|
|
88
|
-
{date.toLocaleDateString()}
|
|
89
|
-
</Button>
|
|
90
|
-
</SlideDatePicker>
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Dark/Light Theme
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
99
|
-
|
|
100
|
-
function ThemedPicker() {
|
|
101
|
-
const [date, setDate] = useState<Date>(new Date())
|
|
102
|
-
|
|
103
|
-
return (
|
|
104
|
-
<div className="space-y-4">
|
|
105
|
-
<SlideDatePicker
|
|
106
|
-
theme="dark"
|
|
107
|
-
value={date}
|
|
108
|
-
onChange={(e) => setDate(e.target.value)}
|
|
109
|
-
/>
|
|
110
|
-
|
|
111
|
-
<SlideDatePicker
|
|
112
|
-
theme="light"
|
|
113
|
-
value={date}
|
|
114
|
-
onChange={(e) => setDate(e.target.value)}
|
|
115
|
-
/>
|
|
116
|
-
</div>
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Birthday Picker
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
125
|
-
import { InputField } from "@/components/InputField";
|
|
126
|
-
import { useState } from 'react'
|
|
127
|
-
|
|
128
|
-
function BirthdayPicker() {
|
|
129
|
-
const [birthday, setBirthday] = useState<Date>()
|
|
130
|
-
|
|
131
|
-
return (
|
|
132
|
-
<SlideDatePicker
|
|
133
|
-
value={birthday}
|
|
134
|
-
onChange={(e) => setBirthday(e.target.value)}
|
|
135
|
-
dateFormat="MMMM dd, yyyy"
|
|
136
|
-
>
|
|
137
|
-
<InputField
|
|
138
|
-
label="Date of Birth"
|
|
139
|
-
placeholder="Select your birthday"
|
|
140
|
-
/>
|
|
141
|
-
</SlideDatePicker>
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Appointment Scheduler
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
150
|
-
import { InputField } from "@/components/InputField";
|
|
151
|
-
import { useState } from 'react'
|
|
152
|
-
|
|
153
|
-
function AppointmentScheduler() {
|
|
154
|
-
const [appointmentDate, setAppointmentDate] = useState<Date>()
|
|
155
|
-
|
|
156
|
-
const today = new Date()
|
|
157
|
-
const formattedDate = appointmentDate
|
|
158
|
-
? appointmentDate.toLocaleDateString('en-US', {
|
|
159
|
-
weekday: 'long',
|
|
160
|
-
year: 'numeric',
|
|
161
|
-
month: 'long',
|
|
162
|
-
day: 'numeric',
|
|
163
|
-
})
|
|
164
|
-
: ''
|
|
165
|
-
|
|
166
|
-
return (
|
|
167
|
-
<div className="space-y-2">
|
|
168
|
-
<SlideDatePicker
|
|
169
|
-
value={appointmentDate}
|
|
170
|
-
onChange={(e) => setAppointmentDate(e.target.value)}
|
|
171
|
-
dateFormat="yyyy/MM/dd"
|
|
172
|
-
>
|
|
173
|
-
<InputField
|
|
174
|
-
label="Appointment Date"
|
|
175
|
-
placeholder="Select date"
|
|
176
|
-
/>
|
|
177
|
-
</SlideDatePicker>
|
|
178
|
-
{formattedDate && (
|
|
179
|
-
<p className="text-sm text-gray-600">{formattedDate}</p>
|
|
180
|
-
)}
|
|
181
|
-
</div>
|
|
182
|
-
)
|
|
183
|
-
}
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### With Initial Date
|
|
187
|
-
|
|
188
|
-
```typescript
|
|
189
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
190
|
-
import { useState } from 'react'
|
|
191
|
-
|
|
192
|
-
function WithInitialDate() {
|
|
193
|
-
// Start with date 6 months from now
|
|
194
|
-
const sixMonthsLater = new Date()
|
|
195
|
-
sixMonthsLater.setMonth(sixMonthsLater.getMonth() + 6)
|
|
196
|
-
|
|
197
|
-
const [date, setDate] = useState<Date>(sixMonthsLater)
|
|
198
|
-
|
|
199
|
-
return (
|
|
200
|
-
<SlideDatePicker
|
|
201
|
-
value={date}
|
|
202
|
-
onChange={(e) => setDate(e.target.value)}
|
|
203
|
-
/>
|
|
204
|
-
)
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### Multiple Date Pickers
|
|
209
|
-
|
|
210
|
-
```typescript
|
|
211
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
212
|
-
import { InputField } from "@/components/InputField";
|
|
213
|
-
import { useState } from 'react'
|
|
214
|
-
|
|
215
|
-
function DateRangePicker() {
|
|
216
|
-
const [startDate, setStartDate] = useState<Date>(new Date())
|
|
217
|
-
const [endDate, setEndDate] = useState<Date>()
|
|
218
|
-
|
|
219
|
-
return (
|
|
220
|
-
<div className="space-y-4">
|
|
221
|
-
<SlideDatePicker
|
|
222
|
-
value={startDate}
|
|
223
|
-
onChange={(e) => {
|
|
224
|
-
const newStart = e.target.value
|
|
225
|
-
setStartDate(newStart)
|
|
226
|
-
// Ensure end date is after start date
|
|
227
|
-
if (endDate && endDate < newStart) {
|
|
228
|
-
setEndDate(newStart)
|
|
229
|
-
}
|
|
230
|
-
}}
|
|
231
|
-
>
|
|
232
|
-
<InputField label="Start Date" />
|
|
233
|
-
</SlideDatePicker>
|
|
234
|
-
|
|
235
|
-
<SlideDatePicker
|
|
236
|
-
value={endDate}
|
|
237
|
-
onChange={(e) => setEndDate(e.target.value)}
|
|
238
|
-
>
|
|
239
|
-
<InputField
|
|
240
|
-
label="End Date"
|
|
241
|
-
placeholder="Select end date"
|
|
242
|
-
/>
|
|
243
|
-
</SlideDatePicker>
|
|
244
|
-
|
|
245
|
-
{startDate && endDate && (
|
|
246
|
-
<p className="text-sm">
|
|
247
|
-
Duration: {Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24))} days
|
|
248
|
-
</p>
|
|
249
|
-
)}
|
|
250
|
-
</div>
|
|
251
|
-
)
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### Form Integration
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
259
|
-
import { Button } from "@/components/Button";
|
|
260
|
-
import { InputField } from "@/components/InputField";
|
|
261
|
-
import { useState } from 'react'
|
|
262
|
-
|
|
263
|
-
function RegistrationForm() {
|
|
264
|
-
const [formData, setFormData] = useState({
|
|
265
|
-
name: '',
|
|
266
|
-
birthday: undefined as Date | undefined,
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
const handleSubmit = (e: React.FormEvent) => {
|
|
270
|
-
e.preventDefault()
|
|
271
|
-
console.log('Form data:', formData)
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return (
|
|
275
|
-
<form onSubmit={handleSubmit} className="space-y-4">
|
|
276
|
-
<InputField
|
|
277
|
-
label="Full Name"
|
|
278
|
-
value={formData.name}
|
|
279
|
-
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
|
280
|
-
/>
|
|
281
|
-
|
|
282
|
-
<SlideDatePicker
|
|
283
|
-
value={formData.birthday}
|
|
284
|
-
onChange={(e) => setFormData({ ...formData, birthday: e.target.value })}
|
|
285
|
-
dateFormat="MM/dd/yyyy"
|
|
286
|
-
>
|
|
287
|
-
<InputField
|
|
288
|
-
label="Date of Birth"
|
|
289
|
-
placeholder="MM/DD/YYYY"
|
|
290
|
-
required
|
|
291
|
-
/>
|
|
292
|
-
</SlideDatePicker>
|
|
293
|
-
|
|
294
|
-
<Button type="submit">Register</Button>
|
|
295
|
-
</form>
|
|
296
|
-
)
|
|
297
|
-
}
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Localized Date Format
|
|
301
|
-
|
|
302
|
-
```typescript
|
|
303
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
304
|
-
import { useState } from 'react'
|
|
305
|
-
|
|
306
|
-
function LocalizedPicker() {
|
|
307
|
-
const [date, setDate] = useState<Date>(new Date())
|
|
308
|
-
|
|
309
|
-
return (
|
|
310
|
-
<div className="space-y-4">
|
|
311
|
-
{/* US Format */}
|
|
312
|
-
<SlideDatePicker
|
|
313
|
-
value={date}
|
|
314
|
-
onChange={(e) => setDate(e.target.value)}
|
|
315
|
-
dateFormat="MM/dd/yyyy"
|
|
316
|
-
/>
|
|
317
|
-
|
|
318
|
-
{/* European Format */}
|
|
319
|
-
<SlideDatePicker
|
|
320
|
-
value={date}
|
|
321
|
-
onChange={(e) => setDate(e.target.value)}
|
|
322
|
-
dateFormat="dd/MM/yyyy"
|
|
323
|
-
/>
|
|
324
|
-
|
|
325
|
-
{/* ISO Format */}
|
|
326
|
-
<SlideDatePicker
|
|
327
|
-
value={date}
|
|
328
|
-
onChange={(e) => setDate(e.target.value)}
|
|
329
|
-
dateFormat="yyyy-MM-dd"
|
|
330
|
-
/>
|
|
331
|
-
</div>
|
|
332
|
-
)
|
|
333
|
-
}
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
## API Reference
|
|
337
|
-
|
|
338
|
-
### SlideDatePicker Props
|
|
339
|
-
|
|
340
|
-
Extends all `InputField` props except `onChange`.
|
|
341
|
-
|
|
342
|
-
| Prop | Type | Default | Description |
|
|
343
|
-
|------|------|---------|-------------|
|
|
344
|
-
| `value` | `Date` | `new Date()` | Selected date |
|
|
345
|
-
| `onChange` | `(e: Event) => void` | - | Change handler (event with target.value) |
|
|
346
|
-
| `dateFormat` | `string` | `'yyyy/MM/dd'` | Date display format (date-fns format) |
|
|
347
|
-
| `theme` | `'dark' \| 'light' \| 'default'` | `'dark'` | Theme variant |
|
|
348
|
-
| `children` | `ReactElement` | - | Custom trigger element |
|
|
349
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
350
|
-
| ...InputField Props | - | - | All InputField props |
|
|
351
|
-
|
|
352
|
-
### SlideValues Interface
|
|
353
|
-
|
|
354
|
-
Internal state structure for the picker wheels:
|
|
355
|
-
|
|
356
|
-
```typescript
|
|
357
|
-
type SlideValues = {
|
|
358
|
-
year: string // "2024"
|
|
359
|
-
month: string // "01" to "12"
|
|
360
|
-
day: string // "01" to "31"
|
|
361
|
-
}
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
## TypeScript
|
|
365
|
-
|
|
366
|
-
### Full Type Definitions
|
|
367
|
-
|
|
368
|
-
```typescript
|
|
369
|
-
import { ComponentProps, ReactElement } from 'react'
|
|
370
|
-
import { InputField } from "@/components/InputField";
|
|
371
|
-
|
|
372
|
-
interface SlideDatePickerProps extends Omit<ComponentProps<typeof InputField>, 'onChange'> {
|
|
373
|
-
onChange?: (e: { target: { value: Date } }) => void
|
|
374
|
-
theme?: "dark" | "light" | "default"
|
|
375
|
-
dateFormat?: string
|
|
376
|
-
value?: Date
|
|
377
|
-
children?: ReactElement
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
export const SlideDatePicker: React.ForwardRefExoticComponent<
|
|
381
|
-
SlideDatePickerProps & React.RefAttributes<HTMLInputElement>
|
|
382
|
-
>
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
### Usage with Types
|
|
386
|
-
|
|
387
|
-
```typescript
|
|
388
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
389
|
-
import { useRef, useState } from 'react'
|
|
390
|
-
|
|
391
|
-
function TypedExample() {
|
|
392
|
-
const [date, setDate] = useState<Date>(new Date())
|
|
393
|
-
const inputRef = useRef<HTMLInputElement>(null)
|
|
394
|
-
|
|
395
|
-
const handleChange = (e: { target: { value: Date } }): void => {
|
|
396
|
-
setDate(e.target.value)
|
|
397
|
-
console.log('Selected:', e.target.value)
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return (
|
|
401
|
-
<SlideDatePicker
|
|
402
|
-
ref={inputRef}
|
|
403
|
-
value={date}
|
|
404
|
-
onChange={handleChange}
|
|
405
|
-
dateFormat="yyyy/MM/dd"
|
|
406
|
-
/>
|
|
407
|
-
)
|
|
408
|
-
}
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
## Common Patterns
|
|
412
|
-
|
|
413
|
-
### Age Verification
|
|
414
|
-
|
|
415
|
-
```typescript
|
|
416
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
417
|
-
import { InputField } from "@/components/InputField";
|
|
418
|
-
import { useState } from 'react'
|
|
419
|
-
|
|
420
|
-
function AgeVerification() {
|
|
421
|
-
const [birthDate, setBirthDate] = useState<Date>()
|
|
422
|
-
const [age, setAge] = useState<number>()
|
|
423
|
-
|
|
424
|
-
const calculateAge = (date: Date): number => {
|
|
425
|
-
const today = new Date()
|
|
426
|
-
let age = today.getFullYear() - date.getFullYear()
|
|
427
|
-
const monthDiff = today.getMonth() - date.getMonth()
|
|
428
|
-
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < date.getDate())) {
|
|
429
|
-
age--
|
|
430
|
-
}
|
|
431
|
-
return age
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const handleDateChange = (e: { target: { value: Date } }) => {
|
|
435
|
-
const date = e.target.value
|
|
436
|
-
setBirthDate(date)
|
|
437
|
-
setAge(calculateAge(date))
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
const isOldEnough = age !== undefined && age >= 18
|
|
441
|
-
|
|
442
|
-
return (
|
|
443
|
-
<div className="space-y-2">
|
|
444
|
-
<SlideDatePicker
|
|
445
|
-
value={birthDate}
|
|
446
|
-
onChange={handleDateChange}
|
|
447
|
-
dateFormat="MM/dd/yyyy"
|
|
448
|
-
>
|
|
449
|
-
<InputField
|
|
450
|
-
label="Date of Birth"
|
|
451
|
-
placeholder="Select your birth date"
|
|
452
|
-
/>
|
|
453
|
-
</SlideDatePicker>
|
|
454
|
-
|
|
455
|
-
{age !== undefined && (
|
|
456
|
-
<p className={isOldEnough ? 'text-green-600' : 'text-red-600'}>
|
|
457
|
-
Age: {age} years old {!isOldEnough && '(Must be 18+)'}
|
|
458
|
-
</p>
|
|
459
|
-
)}
|
|
460
|
-
</div>
|
|
461
|
-
)
|
|
462
|
-
}
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
### Expiration Date Picker
|
|
466
|
-
|
|
467
|
-
```typescript
|
|
468
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
469
|
-
import { InputField } from "@/components/InputField";
|
|
470
|
-
import { useState } from 'react'
|
|
471
|
-
|
|
472
|
-
function ExpirationPicker() {
|
|
473
|
-
const [expiryDate, setExpiryDate] = useState<Date>()
|
|
474
|
-
|
|
475
|
-
const isExpired = expiryDate && expiryDate < new Date()
|
|
476
|
-
|
|
477
|
-
return (
|
|
478
|
-
<div className="space-y-2">
|
|
479
|
-
<SlideDatePicker
|
|
480
|
-
value={expiryDate}
|
|
481
|
-
onChange={(e) => setExpiryDate(e.target.value)}
|
|
482
|
-
dateFormat="MM/yyyy"
|
|
483
|
-
>
|
|
484
|
-
<InputField
|
|
485
|
-
label="Card Expiration"
|
|
486
|
-
placeholder="MM/YYYY"
|
|
487
|
-
/>
|
|
488
|
-
</SlideDatePicker>
|
|
489
|
-
|
|
490
|
-
{isExpired && (
|
|
491
|
-
<p className="text-red-600 text-sm">Card has expired</p>
|
|
492
|
-
)}
|
|
493
|
-
</div>
|
|
494
|
-
)
|
|
495
|
-
}
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
### Historical Date Picker
|
|
499
|
-
|
|
500
|
-
```typescript
|
|
501
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
502
|
-
import { useState } from 'react'
|
|
503
|
-
|
|
504
|
-
function HistoricalDatePicker() {
|
|
505
|
-
const [historicalDate, setHistoricalDate] = useState<Date>(
|
|
506
|
-
new Date(1969, 6, 20) // Moon landing
|
|
507
|
-
)
|
|
508
|
-
|
|
509
|
-
return (
|
|
510
|
-
<div className="space-y-2">
|
|
511
|
-
<SlideDatePicker
|
|
512
|
-
value={historicalDate}
|
|
513
|
-
onChange={(e) => setHistoricalDate(e.target.value)}
|
|
514
|
-
dateFormat="MMMM dd, yyyy"
|
|
515
|
-
>
|
|
516
|
-
<InputField label="Historical Event Date" />
|
|
517
|
-
</SlideDatePicker>
|
|
518
|
-
|
|
519
|
-
<p className="text-sm text-gray-600">
|
|
520
|
-
Year range: 1900 - {new Date().getFullYear() + 100}
|
|
521
|
-
</p>
|
|
522
|
-
</div>
|
|
523
|
-
)
|
|
524
|
-
}
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
## Testing
|
|
528
|
-
|
|
529
|
-
### Unit Test Examples
|
|
530
|
-
|
|
531
|
-
```typescript
|
|
532
|
-
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
|
533
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
534
|
-
import userEvent from '@testing-library/user-event'
|
|
535
|
-
|
|
536
|
-
describe('SlideDatePicker', () => {
|
|
537
|
-
it('renders with default input', () => {
|
|
538
|
-
render(<SlideDatePicker />)
|
|
539
|
-
|
|
540
|
-
const input = screen.getByRole('textbox')
|
|
541
|
-
expect(input).toBeInTheDocument()
|
|
542
|
-
expect(input).toHaveAttribute('readonly')
|
|
543
|
-
})
|
|
544
|
-
|
|
545
|
-
it('displays formatted date value', () => {
|
|
546
|
-
const date = new Date(2024, 0, 15)
|
|
547
|
-
|
|
548
|
-
render(
|
|
549
|
-
<SlideDatePicker
|
|
550
|
-
value={date}
|
|
551
|
-
dateFormat="MM/dd/yyyy"
|
|
552
|
-
/>
|
|
553
|
-
)
|
|
554
|
-
|
|
555
|
-
const input = screen.getByRole('textbox')
|
|
556
|
-
expect(input).toHaveValue('01/15/2024')
|
|
557
|
-
})
|
|
558
|
-
|
|
559
|
-
it('opens picker on input click', async () => {
|
|
560
|
-
render(<SlideDatePicker />)
|
|
561
|
-
|
|
562
|
-
const input = screen.getByRole('textbox')
|
|
563
|
-
await userEvent.click(input)
|
|
564
|
-
|
|
565
|
-
await waitFor(() => {
|
|
566
|
-
expect(screen.getByText('Year')).toBeInTheDocument()
|
|
567
|
-
expect(screen.getByText('Month')).toBeInTheDocument()
|
|
568
|
-
expect(screen.getByText('Day')).toBeInTheDocument()
|
|
569
|
-
})
|
|
570
|
-
})
|
|
571
|
-
|
|
572
|
-
it('calls onChange when date is selected', async () => {
|
|
573
|
-
const handleChange = jest.fn()
|
|
574
|
-
|
|
575
|
-
render(
|
|
576
|
-
<SlideDatePicker
|
|
577
|
-
onChange={handleChange}
|
|
578
|
-
/>
|
|
579
|
-
)
|
|
580
|
-
|
|
581
|
-
const input = screen.getByRole('textbox')
|
|
582
|
-
await userEvent.click(input)
|
|
583
|
-
|
|
584
|
-
// Simulate wheel interaction (implementation-specific)
|
|
585
|
-
// This would require mocking the Picker component
|
|
586
|
-
|
|
587
|
-
expect(handleChange).toHaveBeenCalled()
|
|
588
|
-
})
|
|
589
|
-
|
|
590
|
-
it('renders custom trigger element', () => {
|
|
591
|
-
const CustomButton = <button>Pick Date</button>
|
|
592
|
-
|
|
593
|
-
render(
|
|
594
|
-
<SlideDatePicker>
|
|
595
|
-
{CustomButton}
|
|
596
|
-
</SlideDatePicker>
|
|
597
|
-
)
|
|
598
|
-
|
|
599
|
-
expect(screen.getByText('Pick Date')).toBeInTheDocument()
|
|
600
|
-
})
|
|
601
|
-
|
|
602
|
-
it('applies theme correctly', async () => {
|
|
603
|
-
render(<SlideDatePicker theme="light" />)
|
|
604
|
-
|
|
605
|
-
const input = screen.getByRole('textbox')
|
|
606
|
-
await userEvent.click(input)
|
|
607
|
-
|
|
608
|
-
await waitFor(() => {
|
|
609
|
-
const popover = screen.getByText('Year').closest('[data-theme]')
|
|
610
|
-
expect(popover).toHaveAttribute('data-theme', 'light')
|
|
611
|
-
})
|
|
612
|
-
})
|
|
613
|
-
|
|
614
|
-
it('handles invalid dates gracefully', () => {
|
|
615
|
-
// Test with February 30th scenario
|
|
616
|
-
const handleChange = jest.fn()
|
|
617
|
-
|
|
618
|
-
render(
|
|
619
|
-
<SlideDatePicker
|
|
620
|
-
value={new Date(2024, 1, 29)} // Feb 29, 2024 (leap year)
|
|
621
|
-
onChange={handleChange}
|
|
622
|
-
/>
|
|
623
|
-
)
|
|
624
|
-
|
|
625
|
-
// After user changes to non-leap year, day should adjust
|
|
626
|
-
// Implementation would test the day adjustment logic
|
|
627
|
-
})
|
|
628
|
-
|
|
629
|
-
it('formats date according to locale', () => {
|
|
630
|
-
const date = new Date(2024, 0, 15)
|
|
631
|
-
|
|
632
|
-
const { rerender } = render(
|
|
633
|
-
<SlideDatePicker
|
|
634
|
-
value={date}
|
|
635
|
-
dateFormat="MM/dd/yyyy"
|
|
636
|
-
/>
|
|
637
|
-
)
|
|
638
|
-
|
|
639
|
-
expect(screen.getByRole('textbox')).toHaveValue('01/15/2024')
|
|
640
|
-
|
|
641
|
-
rerender(
|
|
642
|
-
<SlideDatePicker
|
|
643
|
-
value={date}
|
|
644
|
-
dateFormat="dd/MM/yyyy"
|
|
645
|
-
/>
|
|
646
|
-
)
|
|
647
|
-
|
|
648
|
-
expect(screen.getByRole('textbox')).toHaveValue('15/01/2024')
|
|
649
|
-
})
|
|
650
|
-
})
|
|
651
|
-
```
|
|
652
|
-
|
|
653
|
-
### Integration Test
|
|
654
|
-
|
|
655
|
-
```typescript
|
|
656
|
-
import { render, screen, waitFor } from '@testing-library/react'
|
|
657
|
-
import userEvent from '@testing-library/user-event'
|
|
658
|
-
import { SlideDatePicker } from "@/components/SlideDatePicker";
|
|
659
|
-
|
|
660
|
-
describe('SlideDatePicker Integration', () => {
|
|
661
|
-
it('updates form value on date selection', async () => {
|
|
662
|
-
const FormWrapper = () => {
|
|
663
|
-
const [date, setDate] = React.useState<Date>()
|
|
664
|
-
|
|
665
|
-
return (
|
|
666
|
-
<form>
|
|
667
|
-
<SlideDatePicker
|
|
668
|
-
value={date}
|
|
669
|
-
onChange={(e) => setDate(e.target.value)}
|
|
670
|
-
/>
|
|
671
|
-
<div data-testid="selected-date">
|
|
672
|
-
{date?.toISOString() || 'No date selected'}
|
|
673
|
-
</div>
|
|
674
|
-
</form>
|
|
675
|
-
)
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
render(<FormWrapper />)
|
|
679
|
-
|
|
680
|
-
const input = screen.getByRole('textbox')
|
|
681
|
-
await userEvent.click(input)
|
|
682
|
-
|
|
683
|
-
// Simulate date selection
|
|
684
|
-
// ...
|
|
685
|
-
|
|
686
|
-
await waitFor(() => {
|
|
687
|
-
expect(screen.getByTestId('selected-date')).not.toHaveTextContent('No date selected')
|
|
688
|
-
})
|
|
689
|
-
})
|
|
690
|
-
})
|
|
691
|
-
```
|
|
692
|
-
|
|
693
|
-
## Accessibility
|
|
694
|
-
|
|
695
|
-
- **Keyboard Navigation**:
|
|
696
|
-
- Tab: Focus input field
|
|
697
|
-
- Enter/Space: Open picker dropdown
|
|
698
|
-
- Arrow keys: Navigate through wheel values
|
|
699
|
-
- Escape: Close picker
|
|
700
|
-
- **Touch Gestures**: Swipe/scroll to change values
|
|
701
|
-
- **Screen Readers**: Date announced on selection
|
|
702
|
-
- **Focus Management**: Focus returns to trigger after selection
|
|
703
|
-
- **Body Scroll Lock**: Prevents background scroll when picker open
|
|
704
|
-
|
|
705
|
-
### Accessibility Best Practices
|
|
706
|
-
|
|
707
|
-
```typescript
|
|
708
|
-
// Provide clear labels
|
|
709
|
-
<SlideDatePicker>
|
|
710
|
-
<InputField
|
|
711
|
-
label="Select Date"
|
|
712
|
-
aria-label="Date picker"
|
|
713
|
-
/>
|
|
714
|
-
</SlideDatePicker>
|
|
715
|
-
|
|
716
|
-
// Add helper text
|
|
717
|
-
<div>
|
|
718
|
-
<SlideDatePicker>
|
|
719
|
-
<InputField
|
|
720
|
-
label="Birth Date"
|
|
721
|
-
aria-describedby="birth-date-hint"
|
|
722
|
-
/>
|
|
723
|
-
</SlideDatePicker>
|
|
724
|
-
<p id="birth-date-hint" className="text-sm">
|
|
725
|
-
Swipe to select year, month, and day
|
|
726
|
-
</p>
|
|
727
|
-
</div>
|
|
728
|
-
```
|
|
729
|
-
|
|
730
|
-
## Performance
|
|
731
|
-
|
|
732
|
-
| Metric | Value |
|
|
733
|
-
|--------|-------|
|
|
734
|
-
| Bundle size (minified) | ~25kb |
|
|
735
|
-
| Bundle size (gzipped) | ~8kb |
|
|
736
|
-
| Dependencies | torch-react-mobile-picker, date-fns |
|
|
737
|
-
| Initial render | <20ms |
|
|
738
|
-
| Picker open | <15ms |
|
|
739
|
-
| Wheel scroll | <5ms per scroll |
|
|
740
|
-
| Tree-shakeable | ✅ |
|
|
741
|
-
|
|
742
|
-
### Performance Tips
|
|
743
|
-
|
|
744
|
-
1. **Memoize onChange handlers**:
|
|
745
|
-
```typescript
|
|
746
|
-
const handleChange = useCallback((e) => {
|
|
747
|
-
setDate(e.target.value)
|
|
748
|
-
}, [])
|
|
749
|
-
```
|
|
750
|
-
|
|
751
|
-
2. **Avoid re-renders**: Use stable date format strings
|
|
752
|
-
|
|
753
|
-
3. **Lazy render picker**: Only renders when popover opens
|
|
754
|
-
|
|
755
|
-
4. **Optimized wheel rendering**: Virtual scrolling for large date ranges
|
|
756
|
-
|
|
757
|
-
## Styling
|
|
758
|
-
|
|
759
|
-
### Custom Styles
|
|
760
|
-
|
|
761
|
-
```typescript
|
|
762
|
-
<SlideDatePicker
|
|
763
|
-
className="custom-picker"
|
|
764
|
-
theme="dark"
|
|
765
|
-
>
|
|
766
|
-
<InputField className="custom-input" />
|
|
767
|
-
</SlideDatePicker>
|
|
768
|
-
```
|
|
769
|
-
|
|
770
|
-
### Default Styling
|
|
771
|
-
|
|
772
|
-
- Input: Read-only field with calendar icon
|
|
773
|
-
- Popover: Fixed width (285px) with overflow hidden
|
|
774
|
-
- Wheels: Three columns for year/month/day
|
|
775
|
-
- Headers: Labels above each wheel column
|
|
776
|
-
- Selection highlight: Center highlight on selected value
|
|
777
|
-
|
|
778
|
-
## Day Adjustment Logic
|
|
779
|
-
|
|
780
|
-
The component automatically handles invalid dates when switching months or years:
|
|
781
|
-
|
|
782
|
-
```typescript
|
|
783
|
-
// Example: User selects January 31, then changes month to February
|
|
784
|
-
// Component adjusts day from 31 to 28 (or 29 in leap year)
|
|
785
|
-
|
|
786
|
-
const getDayArray = (year: number, month: number): string[] => {
|
|
787
|
-
const daysInMonth = getDaysInMonth(new Date(year, month - 1))
|
|
788
|
-
return Array.from({ length: daysInMonth }, (_, i) =>
|
|
789
|
-
String(i + 1).padStart(2, '0')
|
|
790
|
-
)
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
// When month/year changes, validate day
|
|
794
|
-
if (key === 'year' || key === 'month') {
|
|
795
|
-
const newDayArray = getDayArray(year, month)
|
|
796
|
-
if (!newDayArray.includes(day)) {
|
|
797
|
-
day = newDayArray[newDayArray.length - 1] // Use last valid day
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
```
|
|
801
|
-
|
|
802
|
-
## Best Practices
|
|
803
|
-
|
|
804
|
-
1. **Use for mobile interfaces**: Optimized for touch interactions
|
|
805
|
-
|
|
806
|
-
2. **Provide visual feedback**: Show formatted date clearly
|
|
807
|
-
|
|
808
|
-
3. **Handle edge cases**: Leap years, month-end dates
|
|
809
|
-
|
|
810
|
-
4. **Use appropriate date formats**: Match user locale
|
|
811
|
-
|
|
812
|
-
5. **Validate dates**: Check for valid date ranges
|
|
813
|
-
|
|
814
|
-
6. **Memoize callbacks**: Prevent unnecessary re-renders
|
|
815
|
-
|
|
816
|
-
7. **Test on devices**: Ensure smooth wheel scrolling
|
|
817
|
-
|
|
818
|
-
8. **Consider fallbacks**: Provide alternative input for desktop
|
|
819
|
-
|
|
820
|
-
## Comparison with DatePicker
|
|
821
|
-
|
|
822
|
-
| Feature | SlideDatePicker | DatePicker |
|
|
823
|
-
|---------|----------------|------------|
|
|
824
|
-
| Interface | Wheel/slide | Calendar grid |
|
|
825
|
-
| Best for | Mobile/touch | Desktop/mouse |
|
|
826
|
-
| Time picker | ❌ | ✅ |
|
|
827
|
-
| Range selection | ❌ | ✅ |
|
|
828
|
-
| Multiple dates | ❌ | ✅ |
|
|
829
|
-
| Bundle size | Smaller (~25kb) | Larger (~45kb) |
|
|
830
|
-
| Date restrictions | Limited | Full support |
|
|
831
|
-
|
|
832
|
-
## Related Components
|
|
833
|
-
|
|
834
|
-
- [DatePicker](./date-picker.md) - Calendar-based date picker with time support
|
|
835
|
-
- [Calendar](./calendar.md) - Standalone calendar component
|
|
836
|
-
- [InputField](./input-field.md) - Input field used as default trigger
|
|
837
|
-
- [Popover](./popover.md) - Dropdown container
|