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,41 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Switch } from "../../Switch";
|
|
4
|
-
import { useLoading } from "../context";
|
|
5
|
-
import type { SwitchBoxFieldProps } from "../types";
|
|
6
|
-
import { FieldShell } from "./FieldShell";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* `FormBuilder.SwitchBox` — a switch inside a `#f9f9f9` field box (design node
|
|
10
|
-
* 8999:170563). Value is a `boolean`.
|
|
11
|
-
*
|
|
12
|
-
* Renders like any other field: the field `label` sits in the normal `FieldShell` label
|
|
13
|
-
* column. The control is the box, which holds an optional inline `subLabel` (the design's
|
|
14
|
-
* "Sub-Field-Header"), a vertical divider, and the switch on the right.
|
|
15
|
-
*/
|
|
16
|
-
export function SwitchBoxField({ subLabel, ...props }: SwitchBoxFieldProps) {
|
|
17
|
-
const loading = useLoading();
|
|
18
|
-
const hasSubLabel = subLabel != null && subLabel !== "";
|
|
19
|
-
return (
|
|
20
|
-
<FieldShell {...props}>
|
|
21
|
-
{(field) => (
|
|
22
|
-
<div className="flex w-full items-center justify-end gap-[10px] rounded-[8px] bg-background-presentation-form-field-primary px-[10px] py-[6px]">
|
|
23
|
-
{hasSubLabel && (
|
|
24
|
-
<>
|
|
25
|
-
<span className="min-w-0 flex-1 typography-headers-small-regular text-content-presentation-global-primary">
|
|
26
|
-
{subLabel}
|
|
27
|
-
</span>
|
|
28
|
-
<div className="h-[20px] w-px shrink-0 bg-border-presentation-global-primary" />
|
|
29
|
-
</>
|
|
30
|
-
)}
|
|
31
|
-
<Switch
|
|
32
|
-
id={props.name}
|
|
33
|
-
checked={!!field.value}
|
|
34
|
-
onCheckedChange={field.onChange}
|
|
35
|
-
disabled={props.disabled || loading}
|
|
36
|
-
/>
|
|
37
|
-
</div>
|
|
38
|
-
)}
|
|
39
|
-
</FieldShell>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { type ReactNode, useState } from "react";
|
|
4
|
-
import { useFormContext, useFieldArray, type FieldValues, type ArrayPath } from "react-hook-form";
|
|
5
|
-
import { CSS } from "@dnd-kit/utilities";
|
|
6
|
-
import {
|
|
7
|
-
DndContext,
|
|
8
|
-
closestCenter,
|
|
9
|
-
KeyboardSensor,
|
|
10
|
-
PointerSensor,
|
|
11
|
-
useSensor,
|
|
12
|
-
useSensors,
|
|
13
|
-
type DragEndEvent,
|
|
14
|
-
} from "@dnd-kit/core";
|
|
15
|
-
import {
|
|
16
|
-
SortableContext,
|
|
17
|
-
sortableKeyboardCoordinates,
|
|
18
|
-
useSortable,
|
|
19
|
-
verticalListSortingStrategy,
|
|
20
|
-
} from "@dnd-kit/sortable";
|
|
21
|
-
|
|
22
|
-
import { cn } from "../../../utils/cn";
|
|
23
|
-
import { SectionBlock } from "../../SectionBlock";
|
|
24
|
-
import {
|
|
25
|
-
Table,
|
|
26
|
-
TableBody,
|
|
27
|
-
TableCell,
|
|
28
|
-
TableEndAction,
|
|
29
|
-
TableHead,
|
|
30
|
-
TableHeader,
|
|
31
|
-
TableRow,
|
|
32
|
-
TableScroller,
|
|
33
|
-
} from "../../Table";
|
|
34
|
-
import { Checkbox } from "../../Checkbox";
|
|
35
|
-
import { Button } from "../../Button";
|
|
36
|
-
import { CellContext, useLoading } from "../context";
|
|
37
|
-
import type { TableColumn, TableFieldProps } from "../types";
|
|
38
|
-
|
|
39
|
-
const ALIGN: Record<NonNullable<TableColumn["align"]>, string> = {
|
|
40
|
-
start: "justify-start text-start",
|
|
41
|
-
center: "justify-center text-center",
|
|
42
|
-
end: "justify-end text-end",
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* `FormBuilder.Table` — an editable data-grid field built on the FieldArray pattern.
|
|
47
|
-
* Rows are records; each column cell is any `FormBuilder.*` field, rendered "bare" via
|
|
48
|
-
* `CellContext`. Rows can be checkbox-selected, drag-reordered, added and removed.
|
|
49
|
-
*/
|
|
50
|
-
export function TableField(props: TableFieldProps) {
|
|
51
|
-
const { name, columns, selectable = true, reorderable = true } = props;
|
|
52
|
-
const form = useFormContext<FieldValues>();
|
|
53
|
-
const loading = useLoading();
|
|
54
|
-
|
|
55
|
-
const { fields, append, remove, move, replace } = useFieldArray({
|
|
56
|
-
control: form.control,
|
|
57
|
-
name: name as ArrayPath<FieldValues>,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const [selected, setSelected] = useState<Set<string>>(new Set());
|
|
61
|
-
const [sort, setSort] = useState<{ key: string; dir: "asc" | "desc" } | null>(null);
|
|
62
|
-
// Drag-resized column widths, keyed by column index; falls back to `column.width`.
|
|
63
|
-
const [resized, setResized] = useState<Record<number, number>>({});
|
|
64
|
-
|
|
65
|
-
const sensors = useSensors(
|
|
66
|
-
useSensor(PointerSensor),
|
|
67
|
-
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
if (props.hidden) return null;
|
|
71
|
-
|
|
72
|
-
const showHandle = reorderable;
|
|
73
|
-
const showSelect = selectable;
|
|
74
|
-
|
|
75
|
-
const toggleRow = (id: string) =>
|
|
76
|
-
setSelected((prev) => {
|
|
77
|
-
const next = new Set(prev);
|
|
78
|
-
if (next.has(id)) next.delete(id);
|
|
79
|
-
else next.add(id);
|
|
80
|
-
return next;
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const allSelected = fields.length > 0 && fields.every((f) => selected.has(f.id));
|
|
84
|
-
const someSelected = fields.some((f) => selected.has(f.id));
|
|
85
|
-
const toggleAll = () => setSelected(allSelected ? new Set() : new Set(fields.map((f) => f.id)));
|
|
86
|
-
|
|
87
|
-
const deleteSelected = () => {
|
|
88
|
-
if (loading) return;
|
|
89
|
-
const indices = fields.map((f, i) => (selected.has(f.id) ? i : -1)).filter((i) => i >= 0);
|
|
90
|
-
remove(indices);
|
|
91
|
-
setSelected(new Set());
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const onDragEnd = (event: DragEndEvent) => {
|
|
95
|
-
const { active, over } = event;
|
|
96
|
-
if (!over || active.id === over.id) return;
|
|
97
|
-
const oldIndex = fields.findIndex((f) => f.id === active.id);
|
|
98
|
-
const newIndex = fields.findIndex((f) => f.id === over.id);
|
|
99
|
-
if (oldIndex >= 0 && newIndex >= 0) move(oldIndex, newIndex);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// Sort the rows by a column's key (asc/desc toggle). `replace` re-keys the field ids,
|
|
103
|
-
// so selection (keyed by id) is cleared afterwards.
|
|
104
|
-
const applySort = (key: string) => {
|
|
105
|
-
if (loading) return;
|
|
106
|
-
const dir: "asc" | "desc" = sort?.key === key && sort.dir === "asc" ? "desc" : "asc";
|
|
107
|
-
const rows = (form.getValues(name) as Record<string, unknown>[] | undefined) ?? [];
|
|
108
|
-
const sorted = [...rows].sort((a, b) => {
|
|
109
|
-
const av = a?.[key];
|
|
110
|
-
const bv = b?.[key];
|
|
111
|
-
if (av == null) return bv == null ? 0 : 1;
|
|
112
|
-
if (bv == null) return -1;
|
|
113
|
-
const cmp =
|
|
114
|
-
typeof av === "number" && typeof bv === "number"
|
|
115
|
-
? av - bv
|
|
116
|
-
: String(av).localeCompare(String(bv));
|
|
117
|
-
return dir === "asc" ? cmp : -cmp;
|
|
118
|
-
});
|
|
119
|
-
replace(sorted);
|
|
120
|
-
setSort({ key, dir });
|
|
121
|
-
setSelected(new Set());
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const totalCols = columns.length + (showHandle ? 1 : 0) + (showSelect ? 1 : 0);
|
|
125
|
-
|
|
126
|
-
// Under the browser's default `table-layout: auto`, a column's `width` is only a hint —
|
|
127
|
-
// content (an input's intrinsic size, a currency prefix) silently widens it, which is why
|
|
128
|
-
// a `width: 110` column used to render at 200-odd px. When every column declares a width
|
|
129
|
-
// we can switch to fixed layout and have them honoured exactly. Mixed/absent widths keep
|
|
130
|
-
// auto layout, since under fixed layout an unsized column would collapse to nothing.
|
|
131
|
-
//
|
|
132
|
-
// Fixed layout also needs a *definite* table width — with `width: auto` the browser sizes
|
|
133
|
-
// the table from content and then redistributes, throwing the declared widths (and any
|
|
134
|
-
// drag-resize) away. So the widths are owned here and totalled onto the table, which is
|
|
135
|
-
// what lets a drag grow the table instead of stealing space from the next column.
|
|
136
|
-
const DUMMY_COL_WIDTH = 40; // the design's onset / selector columns
|
|
137
|
-
const colWidth = (col: TableColumn, ci: number) => resized[ci] ?? col.width;
|
|
138
|
-
const fixedLayout = columns.length > 0 && columns.every((col, ci) => !!colWidth(col, ci));
|
|
139
|
-
const tableWidth = fixedLayout
|
|
140
|
-
? columns.reduce((sum, col, ci) => sum + (colWidth(col, ci) ?? 0), 0) +
|
|
141
|
-
(showHandle ? DUMMY_COL_WIDTH : 0) +
|
|
142
|
-
(showSelect ? DUMMY_COL_WIDTH : 0)
|
|
143
|
-
: undefined;
|
|
144
|
-
|
|
145
|
-
const rowCells = (rowName: string, index: number) => (
|
|
146
|
-
<>
|
|
147
|
-
{showSelect && (
|
|
148
|
-
<TableCell isDummy>
|
|
149
|
-
<Checkbox
|
|
150
|
-
size="S"
|
|
151
|
-
checked={selected.has(fields[index].id)}
|
|
152
|
-
onCheckedChange={() => toggleRow(fields[index].id)}
|
|
153
|
-
/>
|
|
154
|
-
</TableCell>
|
|
155
|
-
)}
|
|
156
|
-
{columns.map((col, ci) => (
|
|
157
|
-
<TableCell
|
|
158
|
-
key={ci}
|
|
159
|
-
style={colWidth(col, ci) ? { width: colWidth(col, ci) } : undefined}
|
|
160
|
-
// Column widths come from `col.width`, so opt out of TableCell's 200px floor —
|
|
161
|
-
// otherwise a narrow column (e.g. `width: 110`) silently renders at 200px.
|
|
162
|
-
minWidth={0}
|
|
163
|
-
// Every cell here holds a form control, and the right-edge fade washes out whatever
|
|
164
|
-
// sits at its end — a Select's chevron, a date picker's button.
|
|
165
|
-
fade={false}
|
|
166
|
-
childrenClassName={cn("min-w-0 w-full", col.align && ALIGN[col.align])}
|
|
167
|
-
>
|
|
168
|
-
<CellContext.Provider value="table">{col.cell(rowName, index)}</CellContext.Provider>
|
|
169
|
-
</TableCell>
|
|
170
|
-
))}
|
|
171
|
-
</>
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
const table = (
|
|
175
|
-
// `min-w-full` so the grid still spans the card when the columns are narrower than it,
|
|
176
|
-
// while staying free to overflow (and scroll) when they aren't.
|
|
177
|
-
<Table
|
|
178
|
-
className={cn("min-w-full", fixedLayout && "[table-layout:fixed]")}
|
|
179
|
-
style={tableWidth ? { width: tableWidth } : undefined}
|
|
180
|
-
>
|
|
181
|
-
<TableHeader>
|
|
182
|
-
<TableRow>
|
|
183
|
-
{/* Fixed 40px, per the design — and so these unsized columns can't absorb the
|
|
184
|
-
table's slack width and push the data columns off-screen. */}
|
|
185
|
-
{showHandle && <TableHead isDummy style={{ width: DUMMY_COL_WIDTH }} />}
|
|
186
|
-
{showSelect && (
|
|
187
|
-
<TableHead isDummy style={{ width: DUMMY_COL_WIDTH }}>
|
|
188
|
-
<Checkbox
|
|
189
|
-
size="S"
|
|
190
|
-
checked={allSelected ? true : someSelected ? "indeterminate" : false}
|
|
191
|
-
onCheckedChange={toggleAll}
|
|
192
|
-
/>
|
|
193
|
-
</TableHead>
|
|
194
|
-
)}
|
|
195
|
-
{columns.map((col, ci) => (
|
|
196
|
-
<TableHead
|
|
197
|
-
key={ci}
|
|
198
|
-
// Width goes on the <th> too, so header and body columns agree.
|
|
199
|
-
style={colWidth(col, ci) ? { width: colWidth(col, ci) } : undefined}
|
|
200
|
-
onResize={(w) => setResized((prev) => ({ ...prev, [ci]: w }))}
|
|
201
|
-
sortType={col.sortKey && sort?.key === col.sortKey ? sort.dir : undefined}
|
|
202
|
-
sortLabel={typeof col.header === "string" ? col.header : undefined}
|
|
203
|
-
onSort={col.sortKey ? () => applySort(col.sortKey as string) : undefined}
|
|
204
|
-
>
|
|
205
|
-
{col.header}
|
|
206
|
-
</TableHead>
|
|
207
|
-
))}
|
|
208
|
-
</TableRow>
|
|
209
|
-
</TableHeader>
|
|
210
|
-
|
|
211
|
-
<TableBody>
|
|
212
|
-
{showHandle ? (
|
|
213
|
-
<SortableContext items={fields.map((f) => f.id)} strategy={verticalListSortingStrategy}>
|
|
214
|
-
{fields.map((f, index) => (
|
|
215
|
-
<SortableRow key={f.id} id={f.id} state={selected.has(f.id) ? "selected" : undefined}>
|
|
216
|
-
{rowCells(`${name}.${index}`, index)}
|
|
217
|
-
</SortableRow>
|
|
218
|
-
))}
|
|
219
|
-
</SortableContext>
|
|
220
|
-
) : (
|
|
221
|
-
fields.map((f, index) => (
|
|
222
|
-
<TableRow key={f.id} state={selected.has(f.id) ? "selected" : undefined}>
|
|
223
|
-
{rowCells(`${name}.${index}`, index)}
|
|
224
|
-
</TableRow>
|
|
225
|
-
))
|
|
226
|
-
)}
|
|
227
|
-
|
|
228
|
-
{fields.length === 0 && (
|
|
229
|
-
<TableRow>
|
|
230
|
-
<TableCell colSpan={totalCols} minWidth={0}>
|
|
231
|
-
<span className="typography-body-small-regular text-content-presentation-global-secondary">
|
|
232
|
-
No rows yet.
|
|
233
|
-
</span>
|
|
234
|
-
</TableCell>
|
|
235
|
-
</TableRow>
|
|
236
|
-
)}
|
|
237
|
-
</TableBody>
|
|
238
|
-
</Table>
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
// Header actions on the right of the SectionBlock title row: a "Delete Row" that's disabled
|
|
242
|
-
// until rows are selected, and a primary "Add New". They live outside the scroll container,
|
|
243
|
-
// so they stay put while the grid scrolls sideways.
|
|
244
|
-
const headerActions = (
|
|
245
|
-
<>
|
|
246
|
-
{selectable && (
|
|
247
|
-
<Button
|
|
248
|
-
type="button"
|
|
249
|
-
size="M"
|
|
250
|
-
variant="BorderStyle"
|
|
251
|
-
disabled={loading || selected.size === 0}
|
|
252
|
-
onClick={deleteSelected}
|
|
253
|
-
>
|
|
254
|
-
Delete Row
|
|
255
|
-
</Button>
|
|
256
|
-
)}
|
|
257
|
-
<Button
|
|
258
|
-
type="button"
|
|
259
|
-
size="M"
|
|
260
|
-
variant="BluColStyle"
|
|
261
|
-
disabled={loading}
|
|
262
|
-
onClick={() => append((props.defaultItem ?? {}) as never)}
|
|
263
|
-
>
|
|
264
|
-
{props.addLabel ?? "Add New"}
|
|
265
|
-
</Button>
|
|
266
|
-
</>
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
return (
|
|
270
|
-
<SectionBlock
|
|
271
|
-
variant="Table"
|
|
272
|
-
title={props.title}
|
|
273
|
-
color={props.color}
|
|
274
|
-
icon={props.icon}
|
|
275
|
-
action={headerActions}
|
|
276
|
-
>
|
|
277
|
-
{props.description && (
|
|
278
|
-
<p className="px-[16px] pt-[12px] typography-body-small-regular text-content-presentation-global-secondary">
|
|
279
|
-
{props.description}
|
|
280
|
-
</p>
|
|
281
|
-
)}
|
|
282
|
-
|
|
283
|
-
{/* The table is the only horizontally scrolling element … */}
|
|
284
|
-
<TableScroller>
|
|
285
|
-
{showHandle ? (
|
|
286
|
-
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={onDragEnd}>
|
|
287
|
-
{table}
|
|
288
|
-
</DndContext>
|
|
289
|
-
) : (
|
|
290
|
-
table
|
|
291
|
-
)}
|
|
292
|
-
</TableScroller>
|
|
293
|
-
|
|
294
|
-
{/* … so this stays visible no matter how far right the columns are scrolled. */}
|
|
295
|
-
<TableEndAction disabled={loading} onClick={() => append((props.defaultItem ?? {}) as never)}>
|
|
296
|
-
<i className="ri-add-line" />
|
|
297
|
-
{props.addLabel ?? "Add New"}
|
|
298
|
-
</TableEndAction>
|
|
299
|
-
</SectionBlock>
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/** A draggable table row — the drag handle lives in the leading `isDummy` cell. */
|
|
304
|
-
function SortableRow({
|
|
305
|
-
id,
|
|
306
|
-
state,
|
|
307
|
-
children,
|
|
308
|
-
}: {
|
|
309
|
-
id: string;
|
|
310
|
-
state?: "selected";
|
|
311
|
-
children: ReactNode;
|
|
312
|
-
}) {
|
|
313
|
-
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
|
314
|
-
id,
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
const style = {
|
|
318
|
-
transform: CSS.Transform.toString(transform),
|
|
319
|
-
transition,
|
|
320
|
-
opacity: isDragging ? 0.5 : 1,
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
return (
|
|
324
|
-
<TableRow ref={setNodeRef} style={style} state={state}>
|
|
325
|
-
<TableCell
|
|
326
|
-
{...attributes}
|
|
327
|
-
{...listeners}
|
|
328
|
-
className="cursor-grab active:cursor-grabbing"
|
|
329
|
-
isDummy
|
|
330
|
-
>
|
|
331
|
-
<i className="ri-draggable text-[18px] text-content-presentation-global-secondary" />
|
|
332
|
-
</TableCell>
|
|
333
|
-
{children}
|
|
334
|
-
</TableRow>
|
|
335
|
-
);
|
|
336
|
-
}
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { ReactNode, useEffect, useLayoutEffect, useRef, useState, type ChangeEvent } from "react";
|
|
4
|
-
import type { ControllerRenderProps, FieldValues } from "react-hook-form";
|
|
5
|
-
|
|
6
|
-
import { InputField } from "../../InputField";
|
|
7
|
-
import { Textarea } from "../../Textarea";
|
|
8
|
-
import { PasswordLevel } from "../../PasswordLevel";
|
|
9
|
-
import { useLoading, useOnTable } from "../context";
|
|
10
|
-
import { formatNumber } from "../numberFormat";
|
|
11
|
-
import type { BaseFieldProps, CurrencyFieldProps, PasswordFieldProps } from "../types";
|
|
12
|
-
import { FieldShell } from "./FieldShell";
|
|
13
|
-
|
|
14
|
-
// Run before paint on the client; fall back to useEffect on the server (no SSR warning).
|
|
15
|
-
const useIsoLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* A number input that shows a **live** thousands-separated value (e.g. "1,299")
|
|
19
|
-
* while storing the raw `number` in the form. Commas are inserted as you type and
|
|
20
|
-
* the caret is preserved; decimals (and a trailing ".") are kept intact.
|
|
21
|
-
*/
|
|
22
|
-
function NumberInput({
|
|
23
|
-
field,
|
|
24
|
-
icon,
|
|
25
|
-
placeholder,
|
|
26
|
-
disabled,
|
|
27
|
-
onTable,
|
|
28
|
-
}: {
|
|
29
|
-
field: ControllerRenderProps<FieldValues, string>;
|
|
30
|
-
icon?: ReactNode;
|
|
31
|
-
placeholder?: string;
|
|
32
|
-
disabled?: boolean;
|
|
33
|
-
onTable?: boolean;
|
|
34
|
-
}) {
|
|
35
|
-
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
36
|
-
const caretRef = useRef<number | null>(null);
|
|
37
|
-
const [text, setText] = useState<string>(() => formatNumber(field.value));
|
|
38
|
-
|
|
39
|
-
// Reflect external value changes (e.g. edit data loading) while not editing.
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
if (document.activeElement === inputRef.current) return;
|
|
42
|
-
setText(formatNumber(field.value));
|
|
43
|
-
}, [field.value]);
|
|
44
|
-
|
|
45
|
-
// Restore the caret after a live reformat (commas shift positions).
|
|
46
|
-
useIsoLayoutEffect(() => {
|
|
47
|
-
if (caretRef.current != null && inputRef.current) {
|
|
48
|
-
inputRef.current.setSelectionRange(caretRef.current, caretRef.current);
|
|
49
|
-
caretRef.current = null;
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const setRefs = (el: HTMLInputElement | null) => {
|
|
54
|
-
inputRef.current = el;
|
|
55
|
-
if (typeof field.ref === "function") field.ref(el);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
59
|
-
const raw = e.target.value;
|
|
60
|
-
const caret = e.target.selectionStart ?? raw.length;
|
|
61
|
-
const digitsBeforeCaret = raw.slice(0, caret).replace(/\D/g, "").length;
|
|
62
|
-
|
|
63
|
-
// Keep digits and a single decimal point.
|
|
64
|
-
let cleaned = raw.replace(/[^\d.]/g, "");
|
|
65
|
-
const dot = cleaned.indexOf(".");
|
|
66
|
-
if (dot !== -1) {
|
|
67
|
-
cleaned = cleaned.slice(0, dot + 1) + cleaned.slice(dot + 1).replace(/\./g, "");
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
let formatted = "";
|
|
71
|
-
if (cleaned !== "") {
|
|
72
|
-
const [intPart, decPart] = cleaned.split(".");
|
|
73
|
-
const intFmt = intPart === "" ? "" : Number(intPart).toLocaleString("en-US");
|
|
74
|
-
formatted = decPart !== undefined ? `${intFmt}.${decPart}` : intFmt;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Caret goes after the same count of digits, skipping the inserted commas.
|
|
78
|
-
let pos = 0;
|
|
79
|
-
let seen = 0;
|
|
80
|
-
while (pos < formatted.length && seen < digitsBeforeCaret) {
|
|
81
|
-
if (/\d/.test(formatted[pos])) seen++;
|
|
82
|
-
pos++;
|
|
83
|
-
}
|
|
84
|
-
caretRef.current = pos;
|
|
85
|
-
|
|
86
|
-
setText(formatted);
|
|
87
|
-
field.onChange(cleaned === "" || cleaned === "." ? undefined : Number(cleaned));
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
return (
|
|
91
|
-
<InputField
|
|
92
|
-
name={field.name}
|
|
93
|
-
ref={setRefs}
|
|
94
|
-
type="text"
|
|
95
|
-
inputMode="decimal"
|
|
96
|
-
icon={icon}
|
|
97
|
-
value={text}
|
|
98
|
-
placeholder={placeholder}
|
|
99
|
-
disabled={disabled}
|
|
100
|
-
onTable={onTable}
|
|
101
|
-
className="w-full"
|
|
102
|
-
onChange={handleChange}
|
|
103
|
-
onBlur={() => field.onBlur()}
|
|
104
|
-
/>
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function TextLike({ props, type }: { props: BaseFieldProps; type: "text" | "email" | "password" }) {
|
|
109
|
-
const loading = useLoading();
|
|
110
|
-
const onTable = useOnTable();
|
|
111
|
-
return (
|
|
112
|
-
<FieldShell {...props}>
|
|
113
|
-
{(field) => (
|
|
114
|
-
<InputField
|
|
115
|
-
{...field}
|
|
116
|
-
type={type}
|
|
117
|
-
value={field.value ?? ""}
|
|
118
|
-
placeholder={props.placeholder}
|
|
119
|
-
disabled={props.disabled || loading}
|
|
120
|
-
onTable={onTable}
|
|
121
|
-
className="w-full"
|
|
122
|
-
/>
|
|
123
|
-
)}
|
|
124
|
-
</FieldShell>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export function TextField(props: BaseFieldProps) {
|
|
129
|
-
return <TextLike props={props} type="text" />;
|
|
130
|
-
}
|
|
131
|
-
export function EmailField(props: BaseFieldProps) {
|
|
132
|
-
return <TextLike props={props} type="email" />;
|
|
133
|
-
}
|
|
134
|
-
export function PasswordField(props: PasswordFieldProps) {
|
|
135
|
-
const loading = useLoading();
|
|
136
|
-
const onTable = useOnTable();
|
|
137
|
-
return (
|
|
138
|
-
<FieldShell {...props}>
|
|
139
|
-
{(field) => (
|
|
140
|
-
<div className="flex w-full flex-col gap-2">
|
|
141
|
-
<InputField
|
|
142
|
-
{...field}
|
|
143
|
-
type="password"
|
|
144
|
-
value={field.value ?? ""}
|
|
145
|
-
placeholder={props.placeholder}
|
|
146
|
-
disabled={props.disabled || loading}
|
|
147
|
-
onTable={onTable}
|
|
148
|
-
className="w-full"
|
|
149
|
-
/>
|
|
150
|
-
{props.strengthMeter && <PasswordLevel value={field.value ?? ""} />}
|
|
151
|
-
</div>
|
|
152
|
-
)}
|
|
153
|
-
</FieldShell>
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export function NumberField(props: BaseFieldProps) {
|
|
158
|
-
const loading = useLoading();
|
|
159
|
-
const onTable = useOnTable();
|
|
160
|
-
return (
|
|
161
|
-
<FieldShell {...props}>
|
|
162
|
-
{(field) => (
|
|
163
|
-
<NumberInput
|
|
164
|
-
field={field}
|
|
165
|
-
placeholder={props.placeholder}
|
|
166
|
-
disabled={props.disabled || loading}
|
|
167
|
-
onTable={onTable}
|
|
168
|
-
/>
|
|
169
|
-
)}
|
|
170
|
-
</FieldShell>
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export function CurrencyField(props: CurrencyFieldProps) {
|
|
175
|
-
const loading = useLoading();
|
|
176
|
-
const onTable = useOnTable();
|
|
177
|
-
return (
|
|
178
|
-
<FieldShell {...props}>
|
|
179
|
-
{(field) => (
|
|
180
|
-
<NumberInput
|
|
181
|
-
field={field}
|
|
182
|
-
icon={
|
|
183
|
-
props.currencySymbol ? (
|
|
184
|
-
<span className="typography-body-small-medium">{props.currencySymbol}</span>
|
|
185
|
-
) : undefined
|
|
186
|
-
}
|
|
187
|
-
placeholder={props.placeholder}
|
|
188
|
-
disabled={props.disabled || loading}
|
|
189
|
-
onTable={onTable}
|
|
190
|
-
/>
|
|
191
|
-
)}
|
|
192
|
-
</FieldShell>
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function TextareaField(props: BaseFieldProps & { rows?: number }) {
|
|
197
|
-
const loading = useLoading();
|
|
198
|
-
return (
|
|
199
|
-
<FieldShell {...props}>
|
|
200
|
-
{(field, fieldState) => (
|
|
201
|
-
<Textarea
|
|
202
|
-
{...field}
|
|
203
|
-
value={field.value ?? ""}
|
|
204
|
-
rows={props.rows}
|
|
205
|
-
placeholder={props.placeholder}
|
|
206
|
-
disabled={props.disabled || loading}
|
|
207
|
-
state={fieldState.error ? "negative" : undefined}
|
|
208
|
-
className="w-full"
|
|
209
|
-
/>
|
|
210
|
-
)}
|
|
211
|
-
</FieldShell>
|
|
212
|
-
);
|
|
213
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { SearchableTree } from "../../SearchableTree";
|
|
4
|
-
import type { TreeSelectFieldProps } from "../types";
|
|
5
|
-
import { FieldShell } from "./FieldShell";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* `FormBuilder.TreeSelect` — hierarchical single-select (Glare `SearchableTree`).
|
|
9
|
-
* Stores the selected node's id; seeds the picker + view label by finding the
|
|
10
|
-
* node back from that id.
|
|
11
|
-
*/
|
|
12
|
-
export function TreeSelectField<T>(props: TreeSelectFieldProps<T>) {
|
|
13
|
-
const findById = (id: unknown): T | null => {
|
|
14
|
-
const target = String(id ?? "");
|
|
15
|
-
if (!target) return null;
|
|
16
|
-
// Works for both nested (getNodeChildren) and flat node lists.
|
|
17
|
-
const stack: T[] = [...props.nodes];
|
|
18
|
-
while (stack.length) {
|
|
19
|
-
const node = stack.pop() as T;
|
|
20
|
-
if (props.getNodeId(node) === target) return node;
|
|
21
|
-
const kids = props.getNodeChildren?.(node);
|
|
22
|
-
if (kids && kids.length) stack.push(...kids);
|
|
23
|
-
}
|
|
24
|
-
return null;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<FieldShell {...props}>
|
|
29
|
-
{(field) => (
|
|
30
|
-
<SearchableTree
|
|
31
|
-
nodes={props.nodes}
|
|
32
|
-
getNodeId={props.getNodeId}
|
|
33
|
-
getNodeLabel={props.getNodeLabel}
|
|
34
|
-
getNodeChildren={props.getNodeChildren}
|
|
35
|
-
parentIdKey={props.parentIdKey as (keyof T & string) | undefined}
|
|
36
|
-
selectableFolders={props.selectableFolders}
|
|
37
|
-
value={findById(field.value)}
|
|
38
|
-
onSelect={(node) => field.onChange(props.getNodeId(node))}
|
|
39
|
-
/>
|
|
40
|
-
)}
|
|
41
|
-
</FieldShell>
|
|
42
|
-
);
|
|
43
|
-
}
|