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,157 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useEffect, useRef } from "react";
|
|
4
|
-
|
|
5
|
-
import { Button } from "../../Button";
|
|
6
|
-
import { GroupStyles } from "../../Input";
|
|
7
|
-
import { cn } from "../../../utils/cn";
|
|
8
|
-
import { useLoading } from "../context";
|
|
9
|
-
import type { SignatureFieldProps } from "../types";
|
|
10
|
-
import { FieldShell } from "./FieldShell";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* `FormBuilder.Signature` — a freehand signature pad (native `<canvas>` + pointer
|
|
14
|
-
* events, no dependency). Value is a PNG data-URL string (`""` when empty), so it
|
|
15
|
-
* registers/validates/submits/views like any other field via `FieldShell`.
|
|
16
|
-
*
|
|
17
|
-
* Forced to a **vertical, full-width** layout (label on top, pad below spanning the whole
|
|
18
|
-
* section) — like `FormBuilder.RichText`: the canvas needs the full width, not the right column.
|
|
19
|
-
*/
|
|
20
|
-
export function SignatureField(props: SignatureFieldProps) {
|
|
21
|
-
const loading = useLoading();
|
|
22
|
-
const penColor = props.penColor ?? "#111827";
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<FieldShell {...props} direction="vertical" fullWidth>
|
|
26
|
-
{(field) => (
|
|
27
|
-
<SignaturePad
|
|
28
|
-
value={typeof field.value === "string" ? field.value : ""}
|
|
29
|
-
onChange={field.onChange}
|
|
30
|
-
disabled={props.disabled || loading}
|
|
31
|
-
penColor={penColor}
|
|
32
|
-
/>
|
|
33
|
-
)}
|
|
34
|
-
</FieldShell>
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
interface SignaturePadProps {
|
|
39
|
-
value: string;
|
|
40
|
-
onChange: (value: string) => void;
|
|
41
|
-
disabled?: boolean;
|
|
42
|
-
penColor: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function SignaturePad({ value, onChange, disabled, penColor }: SignaturePadProps) {
|
|
46
|
-
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
47
|
-
const drawing = useRef(false);
|
|
48
|
-
const last = useRef<{ x: number; y: number } | null>(null);
|
|
49
|
-
// Track whether the canvas currently holds strokes, so Clear can no-op cleanly.
|
|
50
|
-
const dirty = useRef(false);
|
|
51
|
-
|
|
52
|
-
// Size the backing store to the element box (accounting for DPR) and seed it
|
|
53
|
-
// from the current value. Runs once on mount; a remount `key` re-seeds on edit.
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
const canvas = canvasRef.current;
|
|
56
|
-
if (!canvas) return;
|
|
57
|
-
const ctx = canvas.getContext("2d");
|
|
58
|
-
if (!ctx) return;
|
|
59
|
-
|
|
60
|
-
const rect = canvas.getBoundingClientRect();
|
|
61
|
-
const dpr = window.devicePixelRatio || 1;
|
|
62
|
-
canvas.width = Math.max(1, Math.round(rect.width * dpr));
|
|
63
|
-
canvas.height = Math.max(1, Math.round(rect.height * dpr));
|
|
64
|
-
ctx.scale(dpr, dpr);
|
|
65
|
-
ctx.lineWidth = 2;
|
|
66
|
-
ctx.lineCap = "round";
|
|
67
|
-
ctx.lineJoin = "round";
|
|
68
|
-
ctx.strokeStyle = penColor;
|
|
69
|
-
|
|
70
|
-
if (value) {
|
|
71
|
-
const img = new Image();
|
|
72
|
-
img.onload = () => ctx.drawImage(img, 0, 0, rect.width, rect.height);
|
|
73
|
-
img.src = value;
|
|
74
|
-
dirty.current = true;
|
|
75
|
-
}
|
|
76
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- initial-only seed (like date/richtext)
|
|
77
|
-
}, []);
|
|
78
|
-
|
|
79
|
-
const pointToCanvas = (e: React.PointerEvent<HTMLCanvasElement>) => {
|
|
80
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
81
|
-
return { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const handleDown = (e: React.PointerEvent<HTMLCanvasElement>) => {
|
|
85
|
-
if (disabled) return;
|
|
86
|
-
e.currentTarget.setPointerCapture(e.pointerId);
|
|
87
|
-
drawing.current = true;
|
|
88
|
-
last.current = pointToCanvas(e);
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const handleMove = (e: React.PointerEvent<HTMLCanvasElement>) => {
|
|
92
|
-
if (!drawing.current || disabled) return;
|
|
93
|
-
const ctx = canvasRef.current?.getContext("2d");
|
|
94
|
-
if (!ctx || !last.current) return;
|
|
95
|
-
const p = pointToCanvas(e);
|
|
96
|
-
ctx.beginPath();
|
|
97
|
-
ctx.moveTo(last.current.x, last.current.y);
|
|
98
|
-
ctx.lineTo(p.x, p.y);
|
|
99
|
-
ctx.stroke();
|
|
100
|
-
last.current = p;
|
|
101
|
-
dirty.current = true;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const handleUp = () => {
|
|
105
|
-
if (!drawing.current) return;
|
|
106
|
-
drawing.current = false;
|
|
107
|
-
last.current = null;
|
|
108
|
-
if (disabled) return;
|
|
109
|
-
const canvas = canvasRef.current;
|
|
110
|
-
if (canvas && dirty.current) onChange(canvas.toDataURL("image/png"));
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const clear = () => {
|
|
114
|
-
const canvas = canvasRef.current;
|
|
115
|
-
const ctx = canvas?.getContext("2d");
|
|
116
|
-
if (canvas && ctx) {
|
|
117
|
-
const rect = canvas.getBoundingClientRect();
|
|
118
|
-
ctx.clearRect(0, 0, rect.width, rect.height);
|
|
119
|
-
}
|
|
120
|
-
dirty.current = false;
|
|
121
|
-
onChange("");
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
return (
|
|
125
|
-
<div
|
|
126
|
-
className={cn(
|
|
127
|
-
GroupStyles({ size: "M", variant: "PresentationStyle" }),
|
|
128
|
-
"relative h-[440px] w-full overflow-hidden p-0",
|
|
129
|
-
disabled && "opacity-60",
|
|
130
|
-
)}
|
|
131
|
-
>
|
|
132
|
-
<canvas
|
|
133
|
-
ref={canvasRef}
|
|
134
|
-
onPointerDown={handleDown}
|
|
135
|
-
onPointerMove={handleMove}
|
|
136
|
-
onPointerUp={handleUp}
|
|
137
|
-
onPointerLeave={handleUp}
|
|
138
|
-
className={cn(
|
|
139
|
-
"h-full w-full touch-none bg-white",
|
|
140
|
-
disabled ? "cursor-not-allowed" : "cursor-crosshair",
|
|
141
|
-
)}
|
|
142
|
-
/>
|
|
143
|
-
{!disabled && (
|
|
144
|
-
<Button
|
|
145
|
-
type="button"
|
|
146
|
-
size="S"
|
|
147
|
-
variant="BorderStyle"
|
|
148
|
-
onClick={clear}
|
|
149
|
-
className="absolute right-2 top-2"
|
|
150
|
-
>
|
|
151
|
-
<i className="ri-eraser-line" />
|
|
152
|
-
Clear
|
|
153
|
-
</Button>
|
|
154
|
-
)}
|
|
155
|
-
</div>
|
|
156
|
-
);
|
|
157
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as Slider from "@radix-ui/react-slider";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../../utils/cn";
|
|
6
|
-
import { useLoading } from "../context";
|
|
7
|
-
import type { SliderFieldProps } from "../types";
|
|
8
|
-
import { FieldShell } from "./FieldShell";
|
|
9
|
-
|
|
10
|
-
// The white knob + soft shadow, matching the design (same knob token + shadow as `Switch`).
|
|
11
|
-
const THUMB = cn(
|
|
12
|
-
"block size-[12px] rounded-full bg-background-presentation-switcher-knob",
|
|
13
|
-
"shadow-[0px_0px_0px_1px_rgba(0,0,0,0.04),0px_3px_8px_0px_rgba(0,0,0,0.15),0px_3px_1px_0px_rgba(0,0,0,0.06)]",
|
|
14
|
-
"outline-none transition-transform hover:scale-110",
|
|
15
|
-
"focus-visible:ring-2 focus-visible:ring-background-presentation-body-scroller-hover",
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* `FormBuilder.Slider` — numeric slider (single value or a `[min,max]` range).
|
|
20
|
-
* A `@radix-ui/react-slider` styled to the Figma range field: a `#f9f9f9` box holding a
|
|
21
|
-
* 6px track, a blue fill, a white knob, and the live value readout on the right.
|
|
22
|
-
*/
|
|
23
|
-
export function SliderField(props: SliderFieldProps) {
|
|
24
|
-
const loading = useLoading();
|
|
25
|
-
const min = props.min ?? 0;
|
|
26
|
-
const max = props.max ?? 100;
|
|
27
|
-
const step = props.step ?? 1;
|
|
28
|
-
const suffix = props.suffix ?? "";
|
|
29
|
-
const fmt = (n: number) => `${n}${suffix}`;
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<FieldShell {...props}>
|
|
33
|
-
{(field) => {
|
|
34
|
-
const raw = field.value;
|
|
35
|
-
const values: number[] = props.range
|
|
36
|
-
? Array.isArray(raw)
|
|
37
|
-
? (raw as number[])
|
|
38
|
-
: [min, max]
|
|
39
|
-
: [typeof raw === "number" ? raw : min];
|
|
40
|
-
const disabled = props.disabled || loading;
|
|
41
|
-
return (
|
|
42
|
-
<div className="flex w-full items-center gap-[10px] rounded-[8px] bg-background-presentation-form-field-primary px-[10px] py-[6px]">
|
|
43
|
-
<Slider.Root
|
|
44
|
-
className="relative flex h-[12px] w-full grow touch-none select-none items-center"
|
|
45
|
-
min={min}
|
|
46
|
-
max={max}
|
|
47
|
-
step={step}
|
|
48
|
-
value={values}
|
|
49
|
-
onValueChange={(v) => field.onChange(props.range ? v : v[0])}
|
|
50
|
-
disabled={disabled}
|
|
51
|
-
>
|
|
52
|
-
<Slider.Track className="relative h-[6px] grow rounded-[10px] bg-background-presentation-body-scroller-default">
|
|
53
|
-
<Slider.Range className="absolute h-full rounded-[10px] bg-background-presentation-body-scroller-hover" />
|
|
54
|
-
</Slider.Track>
|
|
55
|
-
{values.map((_, i) => (
|
|
56
|
-
<Slider.Thumb key={i} className={THUMB} />
|
|
57
|
-
))}
|
|
58
|
-
</Slider.Root>
|
|
59
|
-
<span className="min-w-[40px] shrink-0 whitespace-nowrap text-right tabular-nums typography-body-medium-regular text-content-presentation-global-primary">
|
|
60
|
-
{props.range ? `${values[0]}–${fmt(values[1])}` : fmt(values[0])}
|
|
61
|
-
</span>
|
|
62
|
-
</div>
|
|
63
|
-
);
|
|
64
|
-
}}
|
|
65
|
-
</FieldShell>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
@@ -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
|
-
}
|