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,307 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: DataViews example — Filters
|
|
3
|
-
description: Every filter control, presets, custom filters and the summary.
|
|
4
|
-
group: examples
|
|
5
|
-
component: DataViews
|
|
6
|
-
keywords: [data-views, example, examples, filters]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# DataViews example — Filters
|
|
10
|
-
|
|
11
|
-
Every filter control, presets, custom filters and the summary.
|
|
12
|
-
|
|
13
|
-
Complete and runnable — this is the page itself, not an excerpt. In the monorepo it lives at `apps/app/data-views/filters/page.tsx`.
|
|
14
|
-
|
|
15
|
-
See the [component reference](../index.md) for what each prop does, or the [guide](../guide.md) for the same ground as scenarios.
|
|
16
|
-
|
|
17
|
-
```tsx
|
|
18
|
-
"use client";
|
|
19
|
-
|
|
20
|
-
import { useMemo, useState } from "react";
|
|
21
|
-
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
22
|
-
import { Filter, Settings } from "lucide-react";
|
|
23
|
-
import { Button } from "@/components/Button";
|
|
24
|
-
import { DataViews, emptyQuery, queryToParams, type SavedView } from "@/components/DataViews";
|
|
25
|
-
import { FormBuilder } from "@/components/FormBuilder";
|
|
26
|
-
import type {
|
|
27
|
-
DataViewsQuery,
|
|
28
|
-
FieldConfig,
|
|
29
|
-
FilterState,
|
|
30
|
-
FilterValue,
|
|
31
|
-
Row,
|
|
32
|
-
} from "@/utils/dataViews/types";
|
|
33
|
-
|
|
34
|
-
// ─── Data ─────────────────────────────────────────────────────────────────────
|
|
35
|
-
|
|
36
|
-
interface Order extends Row {
|
|
37
|
-
id: number;
|
|
38
|
-
customer: { name: string };
|
|
39
|
-
status: "Pending" | "Shipped" | "Delivered";
|
|
40
|
-
priority: "High" | "Medium" | "Low";
|
|
41
|
-
total: number;
|
|
42
|
-
items: number;
|
|
43
|
-
createdAt: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const FIELDS: FieldConfig[] = [
|
|
47
|
-
{ path: "id", label: "Order #", type: "number" },
|
|
48
|
-
{ path: "customer.name", label: "Customer", type: "text" },
|
|
49
|
-
{ path: "brand.name", label: "Brand", type: "text" },
|
|
50
|
-
{ path: "status", label: "Status", type: "enum-badge", variants: { Pending: "yellow", Shipped: "blue", Delivered: "green" } },
|
|
51
|
-
{ path: "priority", label: "Priority", type: "enum-badge", variants: { High: "redOrange", Medium: "purple", Low: "gray" } },
|
|
52
|
-
{ path: "items", label: "Items", type: "number" },
|
|
53
|
-
{ path: "total", label: "Total", type: "currency", currency: "USD" },
|
|
54
|
-
{ path: "createdAt", label: "Created", type: "date-format", dateFormat: "YYYY-MM-DD" },
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* The options each control offers. Supplied — DataViews never scans the dataset to find them, and
|
|
59
|
-
* in a real app they come from the same endpoint that does the filtering.
|
|
60
|
-
*/
|
|
61
|
-
/** Dynamic sets — in a real app these come from the endpoint that also does the filtering. */
|
|
62
|
-
const CUSTOMER_OPTIONS = [
|
|
63
|
-
"Acme Inc.", "Globex Corp.", "Initech", "Umbrella",
|
|
64
|
-
"Hooli", "Stark Industries", "Wayne Enterprises", "Cyberdyne",
|
|
65
|
-
].map((v) => ({ label: v, value: v }));
|
|
66
|
-
|
|
67
|
-
const BRAND_OPTIONS = ["Bosch", "Makita", "DeWalt", "Hilti"].map((v) => ({ label: v, value: v }));
|
|
68
|
-
|
|
69
|
-
const STATUS_OPTIONS = [
|
|
70
|
-
{ label: "Pending", value: "Pending" },
|
|
71
|
-
{ label: "Shipped", value: "Shipped" },
|
|
72
|
-
{ label: "Delivered", value: "Delivered" },
|
|
73
|
-
];
|
|
74
|
-
|
|
75
|
-
const PRIORITY_OPTIONS = [
|
|
76
|
-
{ label: "High", value: "High" },
|
|
77
|
-
{ label: "Medium", value: "Medium" },
|
|
78
|
-
{ label: "Low", value: "Low" },
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
/** Buckets for the custom control below — DataViews has no built-in for this. */
|
|
82
|
-
/**
|
|
83
|
-
* The request this page makes. The querying itself happens in `app/api/orders/route.ts` —
|
|
84
|
-
* nothing on this page filters, sorts or pages anything, which is the split DataViews is built
|
|
85
|
-
* around.
|
|
86
|
-
*/
|
|
87
|
-
async function fetchOrders(q: DataViewsQuery): Promise<{ rows: Order[]; total: number }> {
|
|
88
|
-
const params = queryToParams(q);
|
|
89
|
-
const res = await fetch(`/api/orders?${params}`);
|
|
90
|
-
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
91
|
-
return res.json();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* The buckets this picker offers. What each one *means* — which item counts fall in it — is the
|
|
96
|
-
* endpoint's business, in `app/api/orders/route.ts`. The page sends the label; the server decides.
|
|
97
|
-
*/
|
|
98
|
-
const BUCKETS = ["1–3", "4–10", "10+"];
|
|
99
|
-
|
|
100
|
-
/** `Filters.Custom` renders whatever you like against this path's slot in `FilterState`. */
|
|
101
|
-
function ItemsPicker({
|
|
102
|
-
value,
|
|
103
|
-
setValue,
|
|
104
|
-
}: {
|
|
105
|
-
value: FilterValue | undefined;
|
|
106
|
-
setValue: (v: FilterValue | undefined) => void;
|
|
107
|
-
}) {
|
|
108
|
-
const selected = Array.isArray(value) ? value : [];
|
|
109
|
-
return (
|
|
110
|
-
<div className="flex gap-1">
|
|
111
|
-
{BUCKETS.map((bucket) => (
|
|
112
|
-
<button
|
|
113
|
-
key={bucket}
|
|
114
|
-
type="button"
|
|
115
|
-
onClick={() => {
|
|
116
|
-
const next = selected.includes(bucket)
|
|
117
|
-
? selected.filter((b) => b !== bucket)
|
|
118
|
-
: [...selected, bucket];
|
|
119
|
-
setValue(next.length ? next : undefined);
|
|
120
|
-
}}
|
|
121
|
-
className={[
|
|
122
|
-
"typography-body-small-regular rounded-[6px] border px-2 py-1 transition-colors",
|
|
123
|
-
selected.includes(bucket)
|
|
124
|
-
? "border-transparent bg-background-presentation-action-selected text-content-presentation-global-primary"
|
|
125
|
-
: "border-border-presentation-global-primary text-content-presentation-global-secondary",
|
|
126
|
-
].join(" ")}
|
|
127
|
-
>
|
|
128
|
-
{bucket}
|
|
129
|
-
</button>
|
|
130
|
-
))}
|
|
131
|
-
</div>
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// ─── Page ─────────────────────────────────────────────────────────────────────
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* The controls are real FormBuilder fields — `Select`, `MultiSelect`, `Slider`, `DateRange` — in
|
|
139
|
-
* `CellContext`'s `"bare"` mode: no label row, no table borders. One set of inputs across the
|
|
140
|
-
* design system.
|
|
141
|
-
*
|
|
142
|
-
* Three behaviours worth knowing:
|
|
143
|
-
*
|
|
144
|
-
* - **A slider at its bounds emits nothing.** Drag *Total* away from 0–15,000 and a `total` key
|
|
145
|
-
* appears; drag it back and the key vanishes, because "the whole range" and "no constraint" are
|
|
146
|
-
* the same query. The cost is that a filter genuinely meaning "0 to 15,000" is inexpressible —
|
|
147
|
-
* use `Filters.Custom` if you need that distinction.
|
|
148
|
-
* - **Dates are local, not UTC.** You get the day you clicked; `toISOString()` would hand back the
|
|
149
|
-
* previous day for anyone east of Greenwich.
|
|
150
|
-
* - **A parent may rewrite what it is handed.** Turn on *Normalising*: every emitted array comes
|
|
151
|
-
* back sorted. Because `Filters` debounces and compares before emitting, the rewritten value
|
|
152
|
-
* settles instead of ping-ponging — a control that echoed immediately would loop and eat every
|
|
153
|
-
* keystroke.
|
|
154
|
-
*
|
|
155
|
-
* The custom `items` key is owned by no declared control, and survives anyway: the built-in
|
|
156
|
-
* controls merge over the paths in `fields` and leave everything else alone.
|
|
157
|
-
*/
|
|
158
|
-
export default function FiltersExample() {
|
|
159
|
-
// Controlled, because this page starts with a filter no control owns and then rewrites what it
|
|
160
|
-
// is handed. Everywhere else `onQueryChange` alone is enough.
|
|
161
|
-
const [query, setQuery] = useState<DataViewsQuery>({
|
|
162
|
-
...emptyQuery(),
|
|
163
|
-
filters: { items: ["10+"] },
|
|
164
|
-
});
|
|
165
|
-
const [saved, setSaved] = useState<SavedView[]>([]);
|
|
166
|
-
const [normalise, setNormalise] = useState(false);
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* A parent may rewrite what it is handed. With normalising on, every emitted list comes back
|
|
170
|
-
* sorted — and it settles rather than ping-ponging, because `Filters` debounces and compares
|
|
171
|
-
* before emitting again. A control that echoed immediately would loop and eat every keystroke.
|
|
172
|
-
*/
|
|
173
|
-
const onQueryChange = (next: DataViewsQuery) => {
|
|
174
|
-
if (!normalise) return setQuery(next);
|
|
175
|
-
const filters: FilterState = {};
|
|
176
|
-
for (const [path, value] of Object.entries(next.filters)) {
|
|
177
|
-
filters[path] = Array.isArray(value) ? [...value].sort() : value;
|
|
178
|
-
}
|
|
179
|
-
setQuery({ ...next, filters });
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
const { data, isPending, fetchNextPage, isFetchingNextPage } = useInfiniteQuery({
|
|
183
|
-
// The key *is* the query: touch any part of it and TanStack refetches, and a response that
|
|
184
|
-
// has been superseded is discarded rather than landing on top of a newer one.
|
|
185
|
-
queryKey: ["filters-orders", { ...query, page: undefined }],
|
|
186
|
-
queryFn: ({ pageParam }) => fetchOrders({ ...query, page: pageParam }),
|
|
187
|
-
initialPageParam: 1,
|
|
188
|
-
// Undefined means "no more" — which is what the component's `hasMore` resolves to.
|
|
189
|
-
getNextPageParam: (last, pages) => {
|
|
190
|
-
const loaded = pages.reduce((n, page) => n + page.rows.length, 0);
|
|
191
|
-
return loaded < last.total ? pages.length + 1 : undefined;
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
const rows = useMemo(() => data?.pages.flatMap((page) => page.rows) ?? [], [data]);
|
|
196
|
-
const total = data?.pages[0]?.total ?? 0;
|
|
197
|
-
|
|
198
|
-
return (
|
|
199
|
-
<div className="flex h-full min-h-0 flex-col p-4">
|
|
200
|
-
<DataViews
|
|
201
|
-
rows={rows}
|
|
202
|
-
fields={FIELDS}
|
|
203
|
-
total={total}
|
|
204
|
-
loading={isPending}
|
|
205
|
-
onLoadMore={fetchNextPage}
|
|
206
|
-
loadingMore={isFetchingNextPage}
|
|
207
|
-
query={query}
|
|
208
|
-
onQueryChange={onQueryChange}
|
|
209
|
-
className="h-full"
|
|
210
|
-
>
|
|
211
|
-
<DataViews.Header title="Orders">
|
|
212
|
-
<DataViews.ViewSwitch />
|
|
213
|
-
<DataViews.Search />
|
|
214
|
-
<DataViews.Actions>
|
|
215
|
-
<Button variant="BluColStyle"
|
|
216
|
-
size="M"
|
|
217
|
-
onClick={() => setNormalise((v) => !v)}
|
|
218
|
-
>
|
|
219
|
-
{normalise ? "Normalising on" : "Normalising off"}
|
|
220
|
-
</Button>
|
|
221
|
-
<Button
|
|
222
|
-
variant="BluColStyle"
|
|
223
|
-
size="M"
|
|
224
|
-
onClick={() => setQuery({ ...emptyQuery(), filters: { items: ["10+"] } })}
|
|
225
|
-
>
|
|
226
|
-
Reset
|
|
227
|
-
</Button>
|
|
228
|
-
</DataViews.Actions>
|
|
229
|
-
<DataViews.PanelToggle />
|
|
230
|
-
</DataViews.Header>
|
|
231
|
-
|
|
232
|
-
{/* The active query, as removable chips — including the search term. */}
|
|
233
|
-
<div className="border-border-presentation-global-primary border-b px-4 py-2 empty:hidden">
|
|
234
|
-
</div>
|
|
235
|
-
|
|
236
|
-
<DataViews.Table />
|
|
237
|
-
<DataViews.Panel>
|
|
238
|
-
<DataViews.Panel.Tab value="config" label="Config." icon={<Settings />}>
|
|
239
|
-
{/* Saving is the app's job — a view outlives the component. Restoring is not:
|
|
240
|
-
hand the snapshot back and selecting it puts everything back internally. */}
|
|
241
|
-
<DataViews.Panel.SavedViews
|
|
242
|
-
views={saved}
|
|
243
|
-
onSave={(snapshot) =>
|
|
244
|
-
setSaved((prev) => [
|
|
245
|
-
...prev,
|
|
246
|
-
{ id: `view-${prev.length + 1}`, label: `View ${prev.length + 1}`, snapshot },
|
|
247
|
-
])
|
|
248
|
-
}
|
|
249
|
-
/>
|
|
250
|
-
<DataViews.Panel.Columns />
|
|
251
|
-
<DataViews.Panel.Sort />
|
|
252
|
-
</DataViews.Panel.Tab>
|
|
253
|
-
|
|
254
|
-
<DataViews.Panel.Tab value="filters" label="Filters" icon={<Filter />}>
|
|
255
|
-
{/* Every kind of control, written as the FormBuilder fields they are. The
|
|
256
|
-
<FormBuilder> itself lives inside Filters — you supply its fields and nothing
|
|
257
|
-
else, and Filters reads each one's name, label and bounds to learn what it is. */}
|
|
258
|
-
<DataViews.Filters
|
|
259
|
-
title={null}
|
|
260
|
-
className="border-b-0 p-0"
|
|
261
|
-
>
|
|
262
|
-
{/* ① FIXED set, multi-pick → a checkbox list. The four statuses are fixed by the
|
|
263
|
-
model; an org cannot add a fifth without a release. */}
|
|
264
|
-
<FormBuilder.CheckboxGroup name="status" label="Status" options={STATUS_OPTIONS} />
|
|
265
|
-
|
|
266
|
-
{/* ② FIXED set, single-pick → radios. High/Medium/Low are mutually exclusive, so
|
|
267
|
-
picking two would be meaningless. Writes a one-element array. */}
|
|
268
|
-
<FormBuilder.RadioList name="priority" label="Priority" options={PRIORITY_OPTIONS} />
|
|
269
|
-
|
|
270
|
-
{/* ③ DYNAMIC set, single-pick → a searchable combobox. Customers are data-fed, so
|
|
271
|
-
the list grows; one record has one customer, so one at a time is the natural pick. */}
|
|
272
|
-
<FormBuilder.SearchableSelect
|
|
273
|
-
name="customer.name"
|
|
274
|
-
label="Customer"
|
|
275
|
-
options={CUSTOMER_OPTIONS}
|
|
276
|
-
/>
|
|
277
|
-
|
|
278
|
-
{/* ④ DYNAMIC set, multi-pick → BadgeField: search *and* several values, as chips.
|
|
279
|
-
This is the control the enhancement request asked for; `MultiSelect` and `Tags`
|
|
280
|
-
are the same field and both render it. */}
|
|
281
|
-
<FormBuilder.MultiSelect name="brand.name" label="Brand" options={BRAND_OPTIONS} />
|
|
282
|
-
<FormBuilder.Slider name="total" label="Total" range min={0} max={15000} step={100} />
|
|
283
|
-
<DataViews.Filters.Presets
|
|
284
|
-
for="total"
|
|
285
|
-
items={[
|
|
286
|
-
{ label: "Under $500", max: 500 },
|
|
287
|
-
{ label: "$5k+", min: 5000 },
|
|
288
|
-
]}
|
|
289
|
-
/>
|
|
290
|
-
<FormBuilder.DateRange name="createdAt" label="Created" />
|
|
291
|
-
<DataViews.Filters.Presets
|
|
292
|
-
for="createdAt"
|
|
293
|
-
items={[{ label: "September", from: "2025-09-01", to: "2025-09-30" }]}
|
|
294
|
-
/>
|
|
295
|
-
<DataViews.Filters.Custom
|
|
296
|
-
path="items"
|
|
297
|
-
label="Item count"
|
|
298
|
-
render={({ value, setValue }) => <ItemsPicker value={value} setValue={setValue} />}
|
|
299
|
-
/>
|
|
300
|
-
</DataViews.Filters>
|
|
301
|
-
</DataViews.Panel.Tab>
|
|
302
|
-
</DataViews.Panel>
|
|
303
|
-
</DataViews>
|
|
304
|
-
</div>
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
```
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: DataViews example — Inbox → route
|
|
3
|
-
description: `itemHref` + `linkComponent` — the detail pane driven by the URL.
|
|
4
|
-
group: examples
|
|
5
|
-
component: DataViews
|
|
6
|
-
keywords: [data-views, example, examples, inbox, routing]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# DataViews example — Inbox → route
|
|
10
|
-
|
|
11
|
-
`itemHref` + `linkComponent` — the detail pane driven by the URL.
|
|
12
|
-
|
|
13
|
-
Complete and runnable — this is the page itself, not an excerpt. In the monorepo it lives at `apps/app/data-views/inbox-routing/page.tsx` and `apps/app/data-views/inbox-routing/[id]/page.tsx`.
|
|
14
|
-
|
|
15
|
-
See the [component reference](../index.md) for what each prop does, or the [guide](../guide.md) for the same ground as scenarios.
|
|
16
|
-
|
|
17
|
-
## `apps/app/data-views/inbox-routing/page.tsx`
|
|
18
|
-
|
|
19
|
-
```tsx
|
|
20
|
-
"use client";
|
|
21
|
-
|
|
22
|
-
import { useMemo, useState } from "react";
|
|
23
|
-
import Link from "next/link";
|
|
24
|
-
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
25
|
-
import { Filter, Settings } from "lucide-react";
|
|
26
|
-
import { DataViews, emptyQuery, queryToParams, type SavedView } from "@/components/DataViews";
|
|
27
|
-
import { FormBuilder } from "@/components/FormBuilder";
|
|
28
|
-
import type {
|
|
29
|
-
DataViewsQuery,
|
|
30
|
-
FieldConfig,
|
|
31
|
-
Row,
|
|
32
|
-
} from "@/utils/dataViews/types";
|
|
33
|
-
|
|
34
|
-
// ─── Data ─────────────────────────────────────────────────────────────────────
|
|
35
|
-
|
|
36
|
-
interface Message extends Row {
|
|
37
|
-
id: string;
|
|
38
|
-
subject: string;
|
|
39
|
-
from: string;
|
|
40
|
-
preview?: string;
|
|
41
|
-
receivedAt?: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const FIELDS: FieldConfig[] = [
|
|
45
|
-
{ path: "subject", label: "Subject", type: "text" },
|
|
46
|
-
{ path: "from", label: "From", type: "text" },
|
|
47
|
-
{ path: "preview", label: "Preview", type: "text" },
|
|
48
|
-
{ path: "receivedAt", label: "Received", type: "date-format", dateFormat: "DD MMM" },
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
const FROM_OPTIONS = [
|
|
52
|
-
{ label: "logistics@acme.test", value: "logistics@acme.test" },
|
|
53
|
-
{ label: "ap@initech.test", value: "ap@initech.test" },
|
|
54
|
-
{ label: "supply@umbrella.test", value: "supply@umbrella.test" },
|
|
55
|
-
{ label: "procurement@hooli.test", value: "procurement@hooli.test" },
|
|
56
|
-
{ label: "ops@cyberdyne.test", value: "ops@cyberdyne.test" },
|
|
57
|
-
];
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* The request this page makes. The querying happens in `app/api/messages/route.ts`.
|
|
61
|
-
*/
|
|
62
|
-
async function fetchMessages(q: DataViewsQuery): Promise<{ rows: Message[]; total: number }> {
|
|
63
|
-
const params = queryToParams(q);
|
|
64
|
-
const res = await fetch(`/api/messages?${params}`);
|
|
65
|
-
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
66
|
-
return res.json();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ─── Page ─────────────────────────────────────────────────────────────────────
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* `itemHref` turns each row into a link and `linkComponent` swaps the plain anchor for the
|
|
73
|
-
* router's, so navigation stays client-side.
|
|
74
|
-
*
|
|
75
|
-
* Following one unmounts this page — the App Router replaces pages while keeping layouts — so the
|
|
76
|
-
* detail route has to stand on its own. Keeping the list beside the detail would mean hoisting
|
|
77
|
-
* `<DataViews>` into `inbox-routing/layout.tsx` and letting each page supply only the pane.
|
|
78
|
-
*/
|
|
79
|
-
export default function InboxRoutingExample() {
|
|
80
|
-
const [query, setQuery] = useState(emptyQuery());
|
|
81
|
-
const [saved, setSaved] = useState<SavedView[]>([]);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const { data, isPending, fetchNextPage, isFetchingNextPage } = useInfiniteQuery({
|
|
85
|
-
queryKey: ["messages", { ...query, page: undefined }],
|
|
86
|
-
queryFn: ({ pageParam }) => fetchMessages({ ...query, page: pageParam }),
|
|
87
|
-
initialPageParam: 1,
|
|
88
|
-
// Undefined means "no more" — which is what the component's `hasMore` resolves to.
|
|
89
|
-
getNextPageParam: (last, pages) => {
|
|
90
|
-
const loaded = pages.reduce((n, page) => n + page.rows.length, 0);
|
|
91
|
-
return loaded < last.total ? pages.length + 1 : undefined;
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const rows = useMemo(() => data?.pages.flatMap((page) => page.rows) ?? [], [data]);
|
|
96
|
-
const total = data?.pages[0]?.total ?? 0;
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<div className="flex h-full min-h-0 flex-col p-4">
|
|
100
|
-
<DataViews
|
|
101
|
-
rows={rows}
|
|
102
|
-
fields={FIELDS}
|
|
103
|
-
total={total}
|
|
104
|
-
loading={isPending}
|
|
105
|
-
onLoadMore={fetchNextPage}
|
|
106
|
-
loadingMore={isFetchingNextPage}
|
|
107
|
-
onQueryChange={setQuery}
|
|
108
|
-
className="h-full"
|
|
109
|
-
>
|
|
110
|
-
<DataViews.Header title="Inbox">
|
|
111
|
-
<DataViews.ViewSwitch />
|
|
112
|
-
<DataViews.Search />
|
|
113
|
-
<DataViews.PanelToggle />
|
|
114
|
-
</DataViews.Header>
|
|
115
|
-
|
|
116
|
-
<DataViews.Inbox
|
|
117
|
-
titlePath="subject"
|
|
118
|
-
datePath="receivedAt"
|
|
119
|
-
itemHref={(_row, id) => `/data-views/inbox-routing/${id}`}
|
|
120
|
-
linkComponent={Link}
|
|
121
|
-
placeholder={
|
|
122
|
-
<div className="typography-body-medium-regular text-content-presentation-global-secondary flex h-full items-center justify-center p-8">
|
|
123
|
-
Click a message to navigate to its own page.
|
|
124
|
-
</div>
|
|
125
|
-
}
|
|
126
|
-
/>
|
|
127
|
-
|
|
128
|
-
<DataViews.Panel>
|
|
129
|
-
<DataViews.Panel.Tab value="config" label="Config." icon={<Settings />}>
|
|
130
|
-
{/* Saving is the app's job — a view outlives the component. Restoring is not:
|
|
131
|
-
hand the snapshot back and selecting it puts everything back internally. */}
|
|
132
|
-
<DataViews.Panel.SavedViews
|
|
133
|
-
views={saved}
|
|
134
|
-
onSave={(snapshot) =>
|
|
135
|
-
setSaved((prev) => [
|
|
136
|
-
...prev,
|
|
137
|
-
{ id: `view-${prev.length + 1}`, label: `View ${prev.length + 1}`, snapshot },
|
|
138
|
-
])
|
|
139
|
-
}
|
|
140
|
-
/>
|
|
141
|
-
<DataViews.Panel.Columns />
|
|
142
|
-
<DataViews.Panel.Sort />
|
|
143
|
-
</DataViews.Panel.Tab>
|
|
144
|
-
|
|
145
|
-
<DataViews.Panel.Tab value="filters" label="Filters" icon={<Filter />}>
|
|
146
|
-
{/* The controls are FormBuilder fields — the same Select and Slider any form in
|
|
147
|
-
this library uses. The <FormBuilder> itself lives inside Filters; you write only
|
|
148
|
-
its fields, and Filters reads each one's name, label and bounds to learn what
|
|
149
|
-
it is. */}
|
|
150
|
-
<DataViews.Filters
|
|
151
|
-
title={null}
|
|
152
|
-
className="border-b-0 p-0"
|
|
153
|
-
>
|
|
154
|
-
{/* A message carries no enum, no numeric field and one date, so only the
|
|
155
|
-
searchable single-select, the date range and the text match have data to bind
|
|
156
|
-
to. A checkbox list over a field that does not exist would filter to nothing. */}
|
|
157
|
-
<FormBuilder.Text name="subject" label="Subject contains" />
|
|
158
|
-
<FormBuilder.SearchableSelect name="from" label="From" options={FROM_OPTIONS} />
|
|
159
|
-
<FormBuilder.DateRange name="receivedAt" label="Received" />
|
|
160
|
-
</DataViews.Filters>
|
|
161
|
-
</DataViews.Panel.Tab>
|
|
162
|
-
</DataViews.Panel>
|
|
163
|
-
</DataViews>
|
|
164
|
-
</div>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
## `apps/app/data-views/inbox-routing/[id]/page.tsx`
|
|
170
|
-
|
|
171
|
-
```tsx
|
|
172
|
-
import Link from "next/link";
|
|
173
|
-
import { notFound } from "next/navigation";
|
|
174
|
-
import { MESSAGES } from "../../../api/_lib/messages";
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Where `itemHref` lands. A plain server-rendered page — no `DataViews` involved, because by this
|
|
178
|
-
* point the inbox has unmounted.
|
|
179
|
-
*
|
|
180
|
-
* This route is scoped to the one example that needs it. A `[id]` directly under `data-views/`
|
|
181
|
-
* would swallow every mistyped example slug and render a "detail" page instead of a 404.
|
|
182
|
-
*
|
|
183
|
-
* It reads the same store `/api/messages` serves rather than fetching from it: this already runs
|
|
184
|
-
* on the server, and a server component calling its own HTTP endpoint pays for a round trip to
|
|
185
|
-
* itself. The list page fetches because it runs in the browser.
|
|
186
|
-
*/
|
|
187
|
-
|
|
188
|
-
export default async function MessageDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
|
189
|
-
const { id } = await params;
|
|
190
|
-
const message = MESSAGES.find((m) => m.id === id);
|
|
191
|
-
if (!message) notFound();
|
|
192
|
-
|
|
193
|
-
return (
|
|
194
|
-
<div className="flex h-full flex-col gap-4 overflow-y-auto p-8">
|
|
195
|
-
<Link
|
|
196
|
-
href="/data-views/inbox-routing"
|
|
197
|
-
className="typography-body-small-regular text-content-presentation-action-link flex w-fit items-center gap-1"
|
|
198
|
-
>
|
|
199
|
-
<i className="ri-arrow-left-line" aria-hidden />
|
|
200
|
-
Back to the inbox
|
|
201
|
-
</Link>
|
|
202
|
-
|
|
203
|
-
<article className="flex flex-col gap-3">
|
|
204
|
-
<h1 className="typography-headers-medium-medium text-content-presentation-global-primary">
|
|
205
|
-
{message.subject}
|
|
206
|
-
</h1>
|
|
207
|
-
<p className="typography-body-small-regular text-content-presentation-global-secondary">
|
|
208
|
-
{message.from}
|
|
209
|
-
{message.receivedAt ? ` · ${message.receivedAt}` : " · no date"}
|
|
210
|
-
</p>
|
|
211
|
-
<p className="typography-body-medium-regular text-content-presentation-global-primary max-w-[65ch]">
|
|
212
|
-
{message.preview ?? "This message has no preview text."}
|
|
213
|
-
</p>
|
|
214
|
-
</article>
|
|
215
|
-
</div>
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
```
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: DataViews examples
|
|
3
|
-
description: Every runnable DataViews example page, as shipped documentation.
|
|
4
|
-
group: examples
|
|
5
|
-
component: DataViews
|
|
6
|
-
keywords: [data-views, example, examples, index]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# DataViews examples
|
|
10
|
-
|
|
11
|
-
Each page below is complete and runnable. They ship with the package, so the code an agent is pointed at is code it can actually read.
|
|
12
|
-
|
|
13
|
-
| Example | Shows |
|
|
14
|
-
| --- | --- |
|
|
15
|
-
| [Views](./views.md) | All four views over one dataset, with drag round-trips. |
|
|
16
|
-
| [Inbox → route](./inbox-routing.md) | `itemHref` + `linkComponent` — the detail pane driven by the URL. |
|
|
17
|
-
| [Tree → custom UI](./tree-custom.md) | Every custom-UI seam of the tree: `renderNode`, `paneRows`, a custom cell, card and tab, `paneActions`, and a whole-pane override. |
|
|
18
|
-
| [Fields](./fields.md) | The field types, painted. |
|
|
19
|
-
| [Filters](./filters.md) | Every filter control, presets, custom filters and the summary. |
|
|
20
|
-
| [Server-side](./server-side.md) | `queryToParams` on the way out, `parseQuery` on the way in. |
|
|
21
|
-
| [Panel](./panel.md) | The settings rail: saved views, columns, sort — and the pane-mode round trip. |
|
|
22
|
-
| [State](./state.md) | Controlled versus uncontrolled query. |
|
|
23
|
-
| [View registry](./view-registry.md) | A view of your own via `markView`, beside the built-in four. |
|
|
24
|
-
| [Scale](./scale.md) | Virtualization and scroll loading at size. |
|
|
25
|
-
| [Keyboard & RTL](./a11y-rtl.md) | Keyboard paths and the RTL mirror. |
|
|
26
|
-
| [Everything at once](./overview.md) | Every part at once — the fastest way to see the whole shape. |
|
|
27
|
-
| [The endpoint these examples call](./api-orders-route.md) | The route handler every DataViews example fetches from — and the only worked example of `parseQuery` on the server. |
|
|
28
|
-
|
|
29
|
-
See the [component reference](../index.md) and the [guide](../guide.md).
|