@object-ui/components 3.3.0 → 3.3.1
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/CHANGELOG.md +20 -0
- package/README.md +21 -1
- package/dist/index.css +6339 -2
- package/dist/index.js +17600 -17481
- package/dist/index.umd.cjs +36 -36
- package/dist/packages/components/src/custom/empty.d.ts +12 -1
- package/dist/packages/components/src/renderers/action/action-bar.d.ts +12 -1
- package/dist/packages/components/src/ui/chart.d.ts +10 -29
- package/package.json +65 -44
- package/.turbo/turbo-build.log +0 -84
- package/README_SHADCN_SYNC.md +0 -281
- package/TESTING.md +0 -335
- package/docs/FilterBuilder.md +0 -268
- package/metadata/Chart.component.yml +0 -30
- package/metadata/FilterBuilder.component.yml +0 -39
- package/metadata/GridLayout.component.yml +0 -27
- package/metadata/Menu.component.yml +0 -31
- package/metadata/ObjectForm.component.yml +0 -34
- package/metadata/ObjectGrid.component.yml +0 -72
- package/metadata/Page.component.yml +0 -24
- package/postcss.config.js +0 -14
- package/shadcn-components.json +0 -440
- package/src/SchemaRenderer.tsx +0 -28
- package/src/__tests__/PageRendererRegions.test.tsx +0 -668
- package/src/__tests__/README.md +0 -124
- package/src/__tests__/__snapshots__/snapshot-critical.test.tsx.snap +0 -811
- package/src/__tests__/__snapshots__/snapshot.test.tsx.snap +0 -327
- package/src/__tests__/accessibility.test.tsx +0 -137
- package/src/__tests__/action-bar.test.tsx +0 -206
- package/src/__tests__/api-consistency.test.tsx +0 -596
- package/src/__tests__/basic-renderers.test.tsx +0 -255
- package/src/__tests__/color-contrast.test.tsx +0 -212
- package/src/__tests__/complex-disclosure-renderers.test.tsx +0 -302
- package/src/__tests__/compliance.test.tsx +0 -72
- package/src/__tests__/config-field-renderer.test.tsx +0 -307
- package/src/__tests__/config-panel-renderer.test.tsx +0 -580
- package/src/__tests__/config-primitives.test.tsx +0 -106
- package/src/__tests__/edge-cases.test.tsx +0 -285
- package/src/__tests__/feedback-overlay-renderers.test.tsx +0 -349
- package/src/__tests__/filter-builder.test.tsx +0 -409
- package/src/__tests__/form-renderers.test.tsx +0 -364
- package/src/__tests__/layout-data-renderers.test.tsx +0 -340
- package/src/__tests__/mobile-accessibility.test.tsx +0 -120
- package/src/__tests__/navigation-overlay.test.tsx +0 -370
- package/src/__tests__/snapshot-critical.test.tsx +0 -317
- package/src/__tests__/snapshot.test.tsx +0 -205
- package/src/__tests__/test-utils.tsx +0 -190
- package/src/__tests__/use-config-draft.test.tsx +0 -295
- package/src/__tests__/view-compliance.test.tsx +0 -153
- package/src/__tests__/wcag-audit.test.tsx +0 -493
- package/src/custom/action-param-dialog.tsx +0 -264
- package/src/custom/button-group.tsx +0 -91
- package/src/custom/combobox.tsx +0 -104
- package/src/custom/config-field-renderer.tsx +0 -276
- package/src/custom/config-panel-renderer.tsx +0 -306
- package/src/custom/config-row.tsx +0 -50
- package/src/custom/date-picker.tsx +0 -61
- package/src/custom/empty.tsx +0 -112
- package/src/custom/field.tsx +0 -81
- package/src/custom/filter-builder.tsx +0 -418
- package/src/custom/index.ts +0 -21
- package/src/custom/input-group.tsx +0 -53
- package/src/custom/item.tsx +0 -201
- package/src/custom/kbd.tsx +0 -36
- package/src/custom/mobile-dialog-content.tsx +0 -67
- package/src/custom/native-select.tsx +0 -33
- package/src/custom/navigation-overlay.tsx +0 -334
- package/src/custom/section-header.tsx +0 -68
- package/src/custom/sort-builder.tsx +0 -129
- package/src/custom/spinner.tsx +0 -26
- package/src/custom/view-skeleton.tsx +0 -243
- package/src/custom/view-states.tsx +0 -153
- package/src/debug/DebugPanel.tsx +0 -313
- package/src/debug/__tests__/DebugPanel.test.tsx +0 -134
- package/src/debug/index.ts +0 -10
- package/src/hooks/use-config-draft.ts +0 -127
- package/src/hooks/use-mobile.tsx +0 -27
- package/src/index.css +0 -245
- package/src/index.ts +0 -47
- package/src/lib/use-sync-external-store-shim.ts +0 -10
- package/src/lib/use-sync-external-store-with-selector-shim.ts +0 -90
- package/src/lib/utils.tsx +0 -35
- package/src/new-components.test.ts +0 -73
- package/src/renderers/action/action-bar.tsx +0 -221
- package/src/renderers/action/action-button.tsx +0 -158
- package/src/renderers/action/action-group.tsx +0 -270
- package/src/renderers/action/action-icon.tsx +0 -150
- package/src/renderers/action/action-menu.tsx +0 -203
- package/src/renderers/action/index.ts +0 -19
- package/src/renderers/action/resolve-icon.ts +0 -35
- package/src/renderers/basic/button-group.tsx +0 -79
- package/src/renderers/basic/div.tsx +0 -60
- package/src/renderers/basic/html.tsx +0 -43
- package/src/renderers/basic/icon.tsx +0 -89
- package/src/renderers/basic/image.tsx +0 -49
- package/src/renderers/basic/index.ts +0 -18
- package/src/renderers/basic/navigation-menu.tsx +0 -81
- package/src/renderers/basic/pagination.tsx +0 -109
- package/src/renderers/basic/separator.tsx +0 -57
- package/src/renderers/basic/span.tsx +0 -63
- package/src/renderers/basic/text.tsx +0 -52
- package/src/renderers/complex/README-KANBAN.md +0 -208
- package/src/renderers/complex/TIMELINE.md +0 -353
- package/src/renderers/complex/__tests__/data-table-airtable-ux.test.tsx +0 -239
- package/src/renderers/complex/__tests__/data-table-batch-editing.test.tsx +0 -275
- package/src/renderers/complex/__tests__/data-table-cell-renderer.test.tsx +0 -120
- package/src/renderers/complex/__tests__/data-table-editing.test.tsx +0 -221
- package/src/renderers/complex/__tests__/data-table.test.ts +0 -76
- package/src/renderers/complex/carousel.tsx +0 -69
- package/src/renderers/complex/data-table.tsx +0 -1243
- package/src/renderers/complex/filter-builder.tsx +0 -77
- package/src/renderers/complex/index.ts +0 -16
- package/src/renderers/complex/resizable.tsx +0 -66
- package/src/renderers/complex/scroll-area.tsx +0 -58
- package/src/renderers/complex/table.tsx +0 -95
- package/src/renderers/data-display/alert.tsx +0 -46
- package/src/renderers/data-display/avatar.tsx +0 -38
- package/src/renderers/data-display/badge.tsx +0 -55
- package/src/renderers/data-display/breadcrumb.tsx +0 -61
- package/src/renderers/data-display/index.ts +0 -18
- package/src/renderers/data-display/kbd.tsx +0 -50
- package/src/renderers/data-display/list.tsx +0 -75
- package/src/renderers/data-display/statistic.tsx +0 -95
- package/src/renderers/data-display/table.tsx +0 -78
- package/src/renderers/data-display/tree-view.tsx +0 -176
- package/src/renderers/disclosure/accordion.tsx +0 -69
- package/src/renderers/disclosure/collapsible.tsx +0 -53
- package/src/renderers/disclosure/index.ts +0 -11
- package/src/renderers/disclosure/toggle-group.tsx +0 -79
- package/src/renderers/feedback/empty.tsx +0 -49
- package/src/renderers/feedback/index.ts +0 -16
- package/src/renderers/feedback/loading.tsx +0 -78
- package/src/renderers/feedback/progress.tsx +0 -29
- package/src/renderers/feedback/skeleton.tsx +0 -31
- package/src/renderers/feedback/sonner.tsx +0 -56
- package/src/renderers/feedback/spinner.tsx +0 -55
- package/src/renderers/feedback/toast.tsx +0 -59
- package/src/renderers/feedback/toaster.tsx +0 -23
- package/src/renderers/form/button.tsx +0 -103
- package/src/renderers/form/calendar.tsx +0 -34
- package/src/renderers/form/checkbox.tsx +0 -71
- package/src/renderers/form/combobox.tsx +0 -48
- package/src/renderers/form/command.tsx +0 -58
- package/src/renderers/form/date-picker.tsx +0 -84
- package/src/renderers/form/file-upload.tsx +0 -184
- package/src/renderers/form/form.tsx +0 -540
- package/src/renderers/form/index.ts +0 -26
- package/src/renderers/form/input-otp.tsx +0 -51
- package/src/renderers/form/input.tsx +0 -121
- package/src/renderers/form/label.tsx +0 -45
- package/src/renderers/form/radio-group.tsx +0 -63
- package/src/renderers/form/select.tsx +0 -94
- package/src/renderers/form/slider.tsx +0 -61
- package/src/renderers/form/switch.tsx +0 -48
- package/src/renderers/form/textarea.tsx +0 -76
- package/src/renderers/form/toggle.tsx +0 -42
- package/src/renderers/index.ts +0 -18
- package/src/renderers/layout/aspect-ratio.tsx +0 -51
- package/src/renderers/layout/card.tsx +0 -85
- package/src/renderers/layout/container.tsx +0 -122
- package/src/renderers/layout/flex.tsx +0 -132
- package/src/renderers/layout/grid.tsx +0 -178
- package/src/renderers/layout/index.ts +0 -19
- package/src/renderers/layout/page.tsx +0 -466
- package/src/renderers/layout/semantic.tsx +0 -48
- package/src/renderers/layout/stack.tsx +0 -132
- package/src/renderers/layout/tabs.tsx +0 -97
- package/src/renderers/navigation/header-bar.tsx +0 -118
- package/src/renderers/navigation/index.ts +0 -10
- package/src/renderers/navigation/sidebar.tsx +0 -208
- package/src/renderers/overlay/alert-dialog.tsx +0 -72
- package/src/renderers/overlay/context-menu.tsx +0 -100
- package/src/renderers/overlay/dialog.tsx +0 -77
- package/src/renderers/overlay/drawer.tsx +0 -77
- package/src/renderers/overlay/dropdown-menu.tsx +0 -99
- package/src/renderers/overlay/hover-card.tsx +0 -55
- package/src/renderers/overlay/index.ts +0 -18
- package/src/renderers/overlay/menubar.tsx +0 -76
- package/src/renderers/overlay/popover.tsx +0 -56
- package/src/renderers/overlay/sheet.tsx +0 -77
- package/src/renderers/overlay/tooltip.tsx +0 -67
- package/src/renderers/placeholders.tsx +0 -107
- package/src/stories/CRMApp.stories.tsx +0 -706
- package/src/stories/ConfigPanel.stories.tsx +0 -232
- package/src/stories/Guide.mdx +0 -55
- package/src/stories/MockedData.stories.tsx +0 -121
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +0 -1
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +0 -1
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +0 -1
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +0 -1
- package/src/stories/assets/youtube.svg +0 -1
- package/src/stories/button.css +0 -30
- package/src/stories/header.css +0 -32
- package/src/stories/page.css +0 -68
- package/src/stories-json/Accessibility.mdx +0 -297
- package/src/stories-json/EdgeCases.stories.tsx +0 -160
- package/src/stories-json/GettingStarted.mdx +0 -89
- package/src/stories-json/Introduction.mdx +0 -127
- package/src/stories-json/accordion.stories.tsx +0 -43
- package/src/stories-json/aggrid.stories.tsx +0 -103
- package/src/stories-json/alert.stories.tsx +0 -39
- package/src/stories-json/aspect-ratio.stories.tsx +0 -34
- package/src/stories-json/avatar.stories.tsx +0 -38
- package/src/stories-json/badge.stories.tsx +0 -53
- package/src/stories-json/breadcrumb.stories.tsx +0 -30
- package/src/stories-json/button-group.stories.tsx +0 -43
- package/src/stories-json/button.stories.tsx +0 -73
- package/src/stories-json/calendar.stories.tsx +0 -85
- package/src/stories-json/card.stories.tsx +0 -48
- package/src/stories-json/carousel.stories.tsx +0 -33
- package/src/stories-json/charts.stories.tsx +0 -195
- package/src/stories-json/chatbot.stories.tsx +0 -349
- package/src/stories-json/code-editor.stories.tsx +0 -92
- package/src/stories-json/collapsible.stories.tsx +0 -40
- package/src/stories-json/controls.stories.tsx +0 -36
- package/src/stories-json/crm-live-data.stories.tsx +0 -154
- package/src/stories-json/dashboard.stories.tsx +0 -318
- package/src/stories-json/data-table.stories.tsx +0 -136
- package/src/stories-json/data_display_extras.stories.tsx +0 -102
- package/src/stories-json/date-picker.stories.tsx +0 -28
- package/src/stories-json/detail-view.stories.tsx +0 -258
- package/src/stories-json/dialog.stories.tsx +0 -43
- package/src/stories-json/feedback_extras.stories.tsx +0 -40
- package/src/stories-json/feedback_others.stories.tsx +0 -46
- package/src/stories-json/form-variants.stories.tsx +0 -210
- package/src/stories-json/form_advanced.stories.tsx +0 -117
- package/src/stories-json/form_extras.stories.tsx +0 -123
- package/src/stories-json/grid.stories.tsx +0 -56
- package/src/stories-json/icon.stories.tsx +0 -36
- package/src/stories-json/input.stories.tsx +0 -52
- package/src/stories-json/kanban.stories.tsx +0 -295
- package/src/stories-json/layout_extended.stories.tsx +0 -76
- package/src/stories-json/layout_flex.stories.tsx +0 -107
- package/src/stories-json/list-view.stories.tsx +0 -97
- package/src/stories-json/markdown.stories.tsx +0 -129
- package/src/stories-json/menus.stories.tsx +0 -63
- package/src/stories-json/metric-card.stories.tsx +0 -143
- package/src/stories-json/navigation-menu.stories.tsx +0 -37
- package/src/stories-json/object-aggrid-advanced.stories.tsx +0 -389
- package/src/stories-json/object-aggrid.stories.tsx +0 -252
- package/src/stories-json/object-form.stories.tsx +0 -130
- package/src/stories-json/object-gantt.stories.tsx +0 -114
- package/src/stories-json/object-grid.stories.tsx +0 -315
- package/src/stories-json/object-map.stories.tsx +0 -116
- package/src/stories-json/object-view.stories.tsx +0 -118
- package/src/stories-json/overlay_extras.stories.tsx +0 -113
- package/src/stories-json/overlay_others.stories.tsx +0 -76
- package/src/stories-json/page.stories.tsx +0 -55
- package/src/stories-json/reports.stories.tsx +0 -163
- package/src/stories-json/resizable.stories.tsx +0 -44
- package/src/stories-json/select.stories.tsx +0 -34
- package/src/stories-json/separator.stories.tsx +0 -41
- package/src/stories-json/sidebar.stories.tsx +0 -147
- package/src/stories-json/statistic.stories.tsx +0 -44
- package/src/stories-json/tabs.stories.tsx +0 -51
- package/src/stories-json/timeline.stories.tsx +0 -188
- package/src/stories-json/typography.stories.tsx +0 -45
- package/src/types/config-panel.ts +0 -101
- package/src/ui/accordion.tsx +0 -66
- package/src/ui/alert-dialog.tsx +0 -149
- package/src/ui/alert.tsx +0 -67
- package/src/ui/aspect-ratio.tsx +0 -15
- package/src/ui/avatar.tsx +0 -58
- package/src/ui/badge.tsx +0 -44
- package/src/ui/breadcrumb.tsx +0 -123
- package/src/ui/button.tsx +0 -64
- package/src/ui/calendar.tsx +0 -221
- package/src/ui/card.tsx +0 -87
- package/src/ui/carousel.tsx +0 -270
- package/src/ui/chart.tsx +0 -377
- package/src/ui/checkbox.tsx +0 -38
- package/src/ui/collapsible.tsx +0 -19
- package/src/ui/command.tsx +0 -161
- package/src/ui/context-menu.tsx +0 -208
- package/src/ui/dialog.tsx +0 -130
- package/src/ui/drawer.tsx +0 -126
- package/src/ui/dropdown-menu.tsx +0 -208
- package/src/ui/form.tsx +0 -186
- package/src/ui/hover-card.tsx +0 -37
- package/src/ui/index.ts +0 -56
- package/src/ui/input-otp.tsx +0 -79
- package/src/ui/input.tsx +0 -30
- package/src/ui/label.tsx +0 -34
- package/src/ui/menubar.tsx +0 -264
- package/src/ui/navigation-menu.tsx +0 -136
- package/src/ui/pagination.tsx +0 -125
- package/src/ui/popover.tsx +0 -39
- package/src/ui/progress.tsx +0 -36
- package/src/ui/radio-group.tsx +0 -52
- package/src/ui/resizable.tsx +0 -53
- package/src/ui/scroll-area.tsx +0 -56
- package/src/ui/select.tsx +0 -168
- package/src/ui/separator.tsx +0 -39
- package/src/ui/sheet.tsx +0 -150
- package/src/ui/sidebar.tsx +0 -781
- package/src/ui/skeleton.tsx +0 -23
- package/src/ui/slider.tsx +0 -39
- package/src/ui/sonner.tsx +0 -53
- package/src/ui/switch.tsx +0 -37
- package/src/ui/table.tsx +0 -125
- package/src/ui/tabs.tsx +0 -63
- package/src/ui/textarea.tsx +0 -30
- package/src/ui/toast.tsx +0 -137
- package/src/ui/toggle-group.tsx +0 -69
- package/src/ui/toggle.tsx +0 -53
- package/src/ui/tooltip.tsx +0 -38
- package/src/ui/typography.tsx +0 -85
- package/tsconfig.json +0 -19
- package/vite.config.ts +0 -71
- package/vitest.config.ts +0 -5
|
@@ -1,540 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { ComponentRegistry } from '@object-ui/core';
|
|
10
|
-
import type { FormSchema, FormField as FormFieldConfig, ValidationRule, FieldCondition, SelectOption } from '@object-ui/types';
|
|
11
|
-
import { useForm } from 'react-hook-form';
|
|
12
|
-
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage, FormDescription } from '../../ui/form';
|
|
13
|
-
import { Button } from '../../ui/button';
|
|
14
|
-
import { Input } from '../../ui/input';
|
|
15
|
-
import { Textarea } from '../../ui/textarea';
|
|
16
|
-
import { Checkbox } from '../../ui/checkbox';
|
|
17
|
-
import { Switch } from '../../ui/switch';
|
|
18
|
-
import {
|
|
19
|
-
Select,
|
|
20
|
-
SelectTrigger,
|
|
21
|
-
SelectValue,
|
|
22
|
-
SelectContent,
|
|
23
|
-
SelectItem
|
|
24
|
-
} from '../../ui/select';
|
|
25
|
-
import { renderChildren } from '../../lib/utils';
|
|
26
|
-
import { Alert, AlertDescription } from '../../ui/alert';
|
|
27
|
-
import { AlertCircle, Loader2 } from 'lucide-react';
|
|
28
|
-
import { cn } from '../../lib/utils';
|
|
29
|
-
import React from 'react';
|
|
30
|
-
import { SchemaRendererContext } from '@object-ui/react';
|
|
31
|
-
import { createSafeTranslation } from '@object-ui/i18n';
|
|
32
|
-
|
|
33
|
-
const useSafeFormTranslation = createSafeTranslation(
|
|
34
|
-
{ 'common.selectOption': 'Select an option' },
|
|
35
|
-
'common.selectOption',
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
// Form renderer component - Airtable-style feature-complete form
|
|
39
|
-
ComponentRegistry.register('form',
|
|
40
|
-
({ schema, className, onAction, ...props }: { schema: FormSchema; className?: string; onAction?: (action: any) => void; [key: string]: any }) => {
|
|
41
|
-
const { t } = useSafeFormTranslation();
|
|
42
|
-
const {
|
|
43
|
-
defaultValues = {},
|
|
44
|
-
fields = [],
|
|
45
|
-
submitLabel = 'Submit',
|
|
46
|
-
cancelLabel = 'Cancel',
|
|
47
|
-
showCancel = false,
|
|
48
|
-
showSubmit = true,
|
|
49
|
-
layout = 'vertical',
|
|
50
|
-
columns = 1,
|
|
51
|
-
onSubmit: onSubmitProp,
|
|
52
|
-
onChange: onChangeProp,
|
|
53
|
-
onCancel: onCancelProp,
|
|
54
|
-
resetOnSubmit = false,
|
|
55
|
-
validationMode = 'onSubmit',
|
|
56
|
-
disabled = false,
|
|
57
|
-
} = schema;
|
|
58
|
-
|
|
59
|
-
// Initialize react-hook-form
|
|
60
|
-
const form = useForm({
|
|
61
|
-
defaultValues,
|
|
62
|
-
mode: validationMode,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
66
|
-
const [submitError, setSubmitError] = React.useState<string | null>(null);
|
|
67
|
-
|
|
68
|
-
// Read DataSource from SchemaRendererContext and propagate it to field
|
|
69
|
-
// widgets as a prop so they can dynamically load related records.
|
|
70
|
-
const schemaCtx = React.useContext(SchemaRendererContext);
|
|
71
|
-
const contextDataSource = schemaCtx?.dataSource ?? null;
|
|
72
|
-
|
|
73
|
-
// React to defaultValues changes
|
|
74
|
-
React.useEffect(() => {
|
|
75
|
-
form.reset(defaultValues);
|
|
76
|
-
}, [defaultValues]);
|
|
77
|
-
|
|
78
|
-
// Watch for form changes - only track changes when onAction is available
|
|
79
|
-
React.useEffect(() => {
|
|
80
|
-
if (onAction) {
|
|
81
|
-
const subscription = form.watch((data) => {
|
|
82
|
-
onAction({
|
|
83
|
-
type: 'form_change',
|
|
84
|
-
data,
|
|
85
|
-
formData: data,
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
return () => subscription.unsubscribe();
|
|
89
|
-
}
|
|
90
|
-
}, [form, onAction]);
|
|
91
|
-
|
|
92
|
-
// Handle form submission
|
|
93
|
-
const handleSubmit = form.handleSubmit(async (data) => {
|
|
94
|
-
setIsSubmitting(true);
|
|
95
|
-
setSubmitError(null);
|
|
96
|
-
|
|
97
|
-
// Defensive check: If data is an Event, use getValues()
|
|
98
|
-
let formData = data;
|
|
99
|
-
// Check for Event-like properties
|
|
100
|
-
const isEvent = data && (
|
|
101
|
-
(data as any).nativeEvent ||
|
|
102
|
-
typeof (data as any).preventDefault === 'function' ||
|
|
103
|
-
typeof (data as any).stopPropagation === 'function' ||
|
|
104
|
-
(data as any).target ||
|
|
105
|
-
(data as any).bubbles
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
if (isEvent) {
|
|
109
|
-
// This should not happen with RHF handleSubmit, but just in case
|
|
110
|
-
formData = form.getValues();
|
|
111
|
-
} else if (!formData || Object.keys(formData).length === 0) {
|
|
112
|
-
// Fallback: if data is empty check getValues(), in case RHF failed to pass it for some reason
|
|
113
|
-
const values = form.getValues();
|
|
114
|
-
if (values && Object.keys(values).length > 0) {
|
|
115
|
-
formData = values;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
if (onAction) {
|
|
121
|
-
const result = await onAction({
|
|
122
|
-
type: 'form_submit',
|
|
123
|
-
data: formData,
|
|
124
|
-
formData: formData,
|
|
125
|
-
}) as any;
|
|
126
|
-
|
|
127
|
-
// Check if submission returned an error
|
|
128
|
-
if (result?.error) {
|
|
129
|
-
setSubmitError(result.error);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (onSubmitProp && typeof onSubmitProp === 'function') {
|
|
135
|
-
await onSubmitProp(formData);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (resetOnSubmit) {
|
|
139
|
-
form.reset();
|
|
140
|
-
}
|
|
141
|
-
} catch (error) {
|
|
142
|
-
// Handle different error types safely
|
|
143
|
-
const errorMessage = error instanceof Error
|
|
144
|
-
? error.message
|
|
145
|
-
: typeof error === 'string'
|
|
146
|
-
? error
|
|
147
|
-
: 'An error occurred during submission';
|
|
148
|
-
setSubmitError(errorMessage);
|
|
149
|
-
|
|
150
|
-
// Log errors for debugging (dev environment only)
|
|
151
|
-
// process may not be defined in all environments
|
|
152
|
-
if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') {
|
|
153
|
-
console.error('Form submission error:', error);
|
|
154
|
-
}
|
|
155
|
-
} finally {
|
|
156
|
-
setIsSubmitting(false);
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// Handle cancel
|
|
161
|
-
const handleCancel = () => {
|
|
162
|
-
form.reset();
|
|
163
|
-
|
|
164
|
-
if (onCancelProp && typeof onCancelProp === 'function') {
|
|
165
|
-
onCancelProp();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (onAction) {
|
|
169
|
-
onAction({
|
|
170
|
-
type: 'form_cancel',
|
|
171
|
-
data: form.getValues(),
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
// Determine grid classes based on columns (explicit classes for Tailwind JIT)
|
|
177
|
-
// Mobile-first: 1 column on mobile, responsive breakpoints for larger screens
|
|
178
|
-
const gridColsClass =
|
|
179
|
-
columns === 1 ? '' :
|
|
180
|
-
columns === 2 ? 'md:grid-cols-2' :
|
|
181
|
-
columns === 3 ? 'md:grid-cols-2 lg:grid-cols-3' :
|
|
182
|
-
'md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4';
|
|
183
|
-
|
|
184
|
-
const gridClass = columns > 1
|
|
185
|
-
? cn('grid gap-4', gridColsClass)
|
|
186
|
-
: 'space-y-4';
|
|
187
|
-
|
|
188
|
-
// Extract designer-related props and conflicting handlers
|
|
189
|
-
const {
|
|
190
|
-
'data-obj-id': dataObjId,
|
|
191
|
-
'data-obj-type': dataObjType,
|
|
192
|
-
style,
|
|
193
|
-
onSubmit: _ignoredOnSubmit, // Prevent overwriting our handleSubmit
|
|
194
|
-
onChange: _ignoredOnChange, // Prevent overwriting our onChange
|
|
195
|
-
// Extract schema props that should not be spread to DOM (handled separately by schema destructuring above)
|
|
196
|
-
submitLabel: _submitLabel,
|
|
197
|
-
cancelLabel: _cancelLabel,
|
|
198
|
-
showSubmit: _showSubmit,
|
|
199
|
-
showCancel: _showCancel,
|
|
200
|
-
resetOnSubmit: _resetOnSubmit,
|
|
201
|
-
defaultValues: _defaultValues,
|
|
202
|
-
inputType: _inputType,
|
|
203
|
-
...formProps
|
|
204
|
-
} = props;
|
|
205
|
-
|
|
206
|
-
return (
|
|
207
|
-
<Form {...form}>
|
|
208
|
-
<form
|
|
209
|
-
onSubmit={handleSubmit}
|
|
210
|
-
className={className}
|
|
211
|
-
{...formProps}
|
|
212
|
-
// Apply designer props
|
|
213
|
-
data-obj-id={dataObjId}
|
|
214
|
-
data-obj-type={dataObjType}
|
|
215
|
-
style={style}
|
|
216
|
-
>
|
|
217
|
-
{/* Form Error Alert */}
|
|
218
|
-
{submitError && (
|
|
219
|
-
<Alert variant="destructive" className="mb-4">
|
|
220
|
-
<AlertCircle className="h-4 w-4" />
|
|
221
|
-
<AlertDescription>{submitError}</AlertDescription>
|
|
222
|
-
</Alert>
|
|
223
|
-
)}
|
|
224
|
-
|
|
225
|
-
{/* Form Fields */}
|
|
226
|
-
{schema.children ? (
|
|
227
|
-
// If children are provided directly, render them
|
|
228
|
-
<div className={schema.fieldContainerClass || 'space-y-4'}>
|
|
229
|
-
{renderChildren(schema.children)}
|
|
230
|
-
</div>
|
|
231
|
-
) : (
|
|
232
|
-
// Otherwise render fields from schema
|
|
233
|
-
<div className={schema.fieldContainerClass || gridClass}>
|
|
234
|
-
{fields.map((field: FormFieldConfig) => {
|
|
235
|
-
const {
|
|
236
|
-
name,
|
|
237
|
-
label,
|
|
238
|
-
description,
|
|
239
|
-
type = 'input',
|
|
240
|
-
required = false,
|
|
241
|
-
disabled: fieldDisabled = false,
|
|
242
|
-
validation = {},
|
|
243
|
-
condition,
|
|
244
|
-
colSpan,
|
|
245
|
-
hidden,
|
|
246
|
-
widget,
|
|
247
|
-
visibleOn,
|
|
248
|
-
readonly,
|
|
249
|
-
...fieldProps
|
|
250
|
-
} = field;
|
|
251
|
-
|
|
252
|
-
// Skip hidden fields
|
|
253
|
-
if (hidden) return null;
|
|
254
|
-
|
|
255
|
-
// Handle conditional rendering with null/undefined safety
|
|
256
|
-
if (condition) {
|
|
257
|
-
const watchField = condition.field;
|
|
258
|
-
const watchValue = form.watch(watchField);
|
|
259
|
-
|
|
260
|
-
// Check for null/undefined before evaluating conditions
|
|
261
|
-
const hasValue = watchValue !== undefined && watchValue !== null;
|
|
262
|
-
|
|
263
|
-
if (condition.equals !== undefined && watchValue !== condition.equals) {
|
|
264
|
-
return null;
|
|
265
|
-
}
|
|
266
|
-
if (condition.notEquals !== undefined && watchValue === condition.notEquals) {
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
if (condition.in && (!hasValue || !condition.in.includes(watchValue))) {
|
|
270
|
-
return null;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Build validation rules
|
|
275
|
-
const rules: any = {
|
|
276
|
-
...validation,
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
if (required) {
|
|
280
|
-
rules.required = typeof validation.required === 'string'
|
|
281
|
-
? validation.required
|
|
282
|
-
: `${label || name} is required`;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Use field.id or field.name for stable keys (never use index alone)
|
|
286
|
-
const fieldKey = field.id ?? name;
|
|
287
|
-
|
|
288
|
-
// Resolve the component type: prefer widget override, fallback to field type
|
|
289
|
-
const resolvedType = widget || type;
|
|
290
|
-
|
|
291
|
-
// colSpan classes for grid layout
|
|
292
|
-
const colSpanClass = colSpan && colSpan > 1
|
|
293
|
-
? colSpan === 2 ? 'col-span-2'
|
|
294
|
-
: colSpan === 3 ? 'col-span-3'
|
|
295
|
-
: colSpan >= 4 ? 'col-span-4'
|
|
296
|
-
: ''
|
|
297
|
-
: '';
|
|
298
|
-
|
|
299
|
-
return (
|
|
300
|
-
<FormField
|
|
301
|
-
key={fieldKey}
|
|
302
|
-
control={form.control}
|
|
303
|
-
name={name}
|
|
304
|
-
rules={rules}
|
|
305
|
-
render={({ field: formField }) => (
|
|
306
|
-
<FormItem className={colSpanClass || undefined}>
|
|
307
|
-
{label && (
|
|
308
|
-
<FormLabel className="text-xs sm:text-sm">
|
|
309
|
-
{label}
|
|
310
|
-
{required && (
|
|
311
|
-
<span className="text-destructive ml-1" aria-label="required">
|
|
312
|
-
*
|
|
313
|
-
</span>
|
|
314
|
-
)}
|
|
315
|
-
</FormLabel>
|
|
316
|
-
)}
|
|
317
|
-
<FormControl>
|
|
318
|
-
{/* Render the actual field component based on resolved type */}
|
|
319
|
-
{renderFieldComponent(resolvedType, {
|
|
320
|
-
...fieldProps,
|
|
321
|
-
// specialized fields needs raw metadata, but we should traverse down if it exists
|
|
322
|
-
// field is the field configuration loop variable
|
|
323
|
-
field: (field as any).field || field,
|
|
324
|
-
...formField,
|
|
325
|
-
inputType: fieldProps.inputType,
|
|
326
|
-
options: fieldProps.options,
|
|
327
|
-
placeholder: fieldProps.placeholder ?? (resolvedType === 'select' ? t('common.selectOption') : undefined),
|
|
328
|
-
disabled: disabled || fieldDisabled || readonly || isSubmitting,
|
|
329
|
-
dataSource: contextDataSource,
|
|
330
|
-
})}
|
|
331
|
-
</FormControl>
|
|
332
|
-
{description && (
|
|
333
|
-
<FormDescription>{description}</FormDescription>
|
|
334
|
-
)}
|
|
335
|
-
<FormMessage />
|
|
336
|
-
</FormItem>
|
|
337
|
-
)}
|
|
338
|
-
/>
|
|
339
|
-
);
|
|
340
|
-
})}
|
|
341
|
-
</div>
|
|
342
|
-
)}
|
|
343
|
-
|
|
344
|
-
{/* Form Actions */}
|
|
345
|
-
{(schema.showActions !== false) && (
|
|
346
|
-
<div className={`flex flex-col sm:flex-row gap-2 ${layout === 'horizontal' ? 'sm:justify-end' : 'sm:justify-start'} mt-6`}>
|
|
347
|
-
{showCancel && (
|
|
348
|
-
<Button
|
|
349
|
-
type="button"
|
|
350
|
-
variant="outline"
|
|
351
|
-
onClick={handleCancel}
|
|
352
|
-
disabled={isSubmitting || disabled}
|
|
353
|
-
className="w-full sm:w-auto"
|
|
354
|
-
>
|
|
355
|
-
{cancelLabel}
|
|
356
|
-
</Button>
|
|
357
|
-
)}
|
|
358
|
-
{showSubmit && (
|
|
359
|
-
<Button
|
|
360
|
-
type="submit"
|
|
361
|
-
disabled={isSubmitting || disabled}
|
|
362
|
-
className="w-full sm:w-auto"
|
|
363
|
-
>
|
|
364
|
-
{isSubmitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
|
365
|
-
{submitLabel}
|
|
366
|
-
</Button>
|
|
367
|
-
)}
|
|
368
|
-
</div>
|
|
369
|
-
)}
|
|
370
|
-
</form>
|
|
371
|
-
</Form>
|
|
372
|
-
);
|
|
373
|
-
},
|
|
374
|
-
{
|
|
375
|
-
namespace: 'ui',
|
|
376
|
-
label: 'Form',
|
|
377
|
-
inputs: [
|
|
378
|
-
{
|
|
379
|
-
name: 'fields',
|
|
380
|
-
type: 'array',
|
|
381
|
-
label: 'Fields',
|
|
382
|
-
description: 'Array of field configurations with name, label, type, validation, etc.'
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
name: 'defaultValues',
|
|
386
|
-
type: 'object',
|
|
387
|
-
label: 'Default Values',
|
|
388
|
-
description: 'Object with default values for form fields'
|
|
389
|
-
},
|
|
390
|
-
{ name: 'submitLabel', type: 'string', label: 'Submit Button Label', defaultValue: 'Submit' },
|
|
391
|
-
{ name: 'cancelLabel', type: 'string', label: 'Cancel Button Label', defaultValue: 'Cancel' },
|
|
392
|
-
{ name: 'showCancel', type: 'boolean', label: 'Show Cancel Button', defaultValue: false },
|
|
393
|
-
{
|
|
394
|
-
name: 'layout',
|
|
395
|
-
type: 'enum',
|
|
396
|
-
enum: ['vertical', 'horizontal'],
|
|
397
|
-
label: 'Layout',
|
|
398
|
-
defaultValue: 'vertical'
|
|
399
|
-
},
|
|
400
|
-
{
|
|
401
|
-
name: 'columns',
|
|
402
|
-
type: 'number',
|
|
403
|
-
label: 'Number of Columns',
|
|
404
|
-
defaultValue: 1,
|
|
405
|
-
description: 'For multi-column layouts (1-4)'
|
|
406
|
-
},
|
|
407
|
-
{
|
|
408
|
-
name: 'validationMode',
|
|
409
|
-
type: 'enum',
|
|
410
|
-
enum: ['onSubmit', 'onBlur', 'onChange', 'onTouched', 'all'],
|
|
411
|
-
label: 'Validation Mode',
|
|
412
|
-
defaultValue: 'onSubmit'
|
|
413
|
-
},
|
|
414
|
-
{ name: 'resetOnSubmit', type: 'boolean', label: 'Reset After Submit', defaultValue: false },
|
|
415
|
-
{ name: 'disabled', type: 'boolean', label: 'Disabled', defaultValue: false },
|
|
416
|
-
{ name: 'className', type: 'string', label: 'CSS Class' },
|
|
417
|
-
{ name: 'fieldContainerClass', type: 'string', label: 'Field Container CSS Class' }
|
|
418
|
-
],
|
|
419
|
-
defaultProps: {
|
|
420
|
-
submitLabel: 'Submit',
|
|
421
|
-
cancelLabel: 'Cancel',
|
|
422
|
-
showCancel: false,
|
|
423
|
-
layout: 'vertical',
|
|
424
|
-
columns: 1,
|
|
425
|
-
validationMode: 'onSubmit',
|
|
426
|
-
resetOnSubmit: false,
|
|
427
|
-
disabled: false,
|
|
428
|
-
fields: [
|
|
429
|
-
{
|
|
430
|
-
name: 'name',
|
|
431
|
-
label: 'Name',
|
|
432
|
-
type: 'input',
|
|
433
|
-
required: true,
|
|
434
|
-
placeholder: 'Enter your name',
|
|
435
|
-
},
|
|
436
|
-
{
|
|
437
|
-
name: 'email',
|
|
438
|
-
label: 'Email',
|
|
439
|
-
type: 'input',
|
|
440
|
-
inputType: 'email',
|
|
441
|
-
required: true,
|
|
442
|
-
placeholder: 'Enter your email',
|
|
443
|
-
},
|
|
444
|
-
],
|
|
445
|
-
},
|
|
446
|
-
}
|
|
447
|
-
);
|
|
448
|
-
|
|
449
|
-
// Helper function to render field components with proper typing
|
|
450
|
-
interface RenderFieldProps {
|
|
451
|
-
inputType?: string;
|
|
452
|
-
options?: SelectOption[];
|
|
453
|
-
placeholder?: string;
|
|
454
|
-
value?: any;
|
|
455
|
-
onChange?: (value: any) => void;
|
|
456
|
-
disabled?: boolean;
|
|
457
|
-
[key: string]: any;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function renderFieldComponent(type: string, props: RenderFieldProps) {
|
|
461
|
-
// 1. Try to resolve specialized field widget from registry first
|
|
462
|
-
// We prioritize registry components (e.g., 'field.currency', 'field.date')
|
|
463
|
-
const RegisteredComponent = ComponentRegistry.get(type);
|
|
464
|
-
|
|
465
|
-
if (RegisteredComponent) {
|
|
466
|
-
// For specialized fields (e.g. fields package), they expect 'field' prop.
|
|
467
|
-
// Ensure we pass all props.
|
|
468
|
-
// Also pass 'schema' for standard renderers that expect it
|
|
469
|
-
return <RegisteredComponent schema={props} {...props} />;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
const { inputType, options = [], placeholder, ...fieldProps } = props;
|
|
473
|
-
|
|
474
|
-
switch (type) {
|
|
475
|
-
case 'input':
|
|
476
|
-
if (inputType === 'file') {
|
|
477
|
-
// File inputs cannot be controlled with value prop
|
|
478
|
-
const { value, ...fileProps } = fieldProps;
|
|
479
|
-
return <Input type="file" placeholder={placeholder} className="min-h-[44px] sm:min-h-0" {...fileProps} />;
|
|
480
|
-
}
|
|
481
|
-
return <Input type={inputType || 'text'} placeholder={placeholder} className="min-h-[44px] sm:min-h-0" {...fieldProps} value={fieldProps.value ?? ''} />;
|
|
482
|
-
|
|
483
|
-
case 'textarea':
|
|
484
|
-
return <Textarea placeholder={placeholder} className="min-h-[44px] sm:min-h-0" {...fieldProps} value={fieldProps.value ?? ''} />;
|
|
485
|
-
|
|
486
|
-
case 'checkbox': {
|
|
487
|
-
// For checkbox, we need to handle the value differently
|
|
488
|
-
const { value, onChange, ...checkboxProps } = fieldProps;
|
|
489
|
-
return (
|
|
490
|
-
<Checkbox
|
|
491
|
-
checked={value}
|
|
492
|
-
onCheckedChange={onChange}
|
|
493
|
-
className="min-h-[44px] min-w-[44px] sm:min-h-0 sm:min-w-0"
|
|
494
|
-
{...checkboxProps}
|
|
495
|
-
/>
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
case 'switch': {
|
|
500
|
-
// For switch, we need to handle the value differently (same as checkbox)
|
|
501
|
-
const { value, onChange, ...switchProps } = fieldProps;
|
|
502
|
-
return (
|
|
503
|
-
<Switch
|
|
504
|
-
checked={value}
|
|
505
|
-
onCheckedChange={onChange}
|
|
506
|
-
className="min-h-[44px] min-w-[44px] sm:min-h-0 sm:min-w-0"
|
|
507
|
-
{...switchProps}
|
|
508
|
-
/>
|
|
509
|
-
);
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
case 'select': {
|
|
513
|
-
// For select with react-hook-form, we need to handle the onChange
|
|
514
|
-
const { value: selectValue, onChange: selectOnChange, ...selectProps } = fieldProps;
|
|
515
|
-
|
|
516
|
-
// Safety check for options
|
|
517
|
-
if (!options || options.length === 0) {
|
|
518
|
-
return <div className="text-sm text-muted-foreground">No options available</div>;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
return (
|
|
522
|
-
<Select value={selectValue} onValueChange={selectOnChange} {...selectProps}>
|
|
523
|
-
<SelectTrigger className="min-h-[44px] sm:min-h-0">
|
|
524
|
-
<SelectValue placeholder={placeholder || 'Select an option'} />
|
|
525
|
-
</SelectTrigger>
|
|
526
|
-
<SelectContent>
|
|
527
|
-
{options.map((opt: SelectOption) => (
|
|
528
|
-
<SelectItem key={opt.value} value={opt.value}>
|
|
529
|
-
{opt.label}
|
|
530
|
-
</SelectItem>
|
|
531
|
-
))}
|
|
532
|
-
</SelectContent>
|
|
533
|
-
</Select>
|
|
534
|
-
);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
default:
|
|
538
|
-
return <Input type={inputType || 'text'} placeholder={placeholder} {...fieldProps} />;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import './form';
|
|
10
|
-
import './button';
|
|
11
|
-
import './label';
|
|
12
|
-
import './input';
|
|
13
|
-
import './textarea';
|
|
14
|
-
|
|
15
|
-
import './checkbox';
|
|
16
|
-
import './switch';
|
|
17
|
-
import './select';
|
|
18
|
-
import './radio-group';
|
|
19
|
-
import './slider';
|
|
20
|
-
import './toggle';
|
|
21
|
-
import './input-otp';
|
|
22
|
-
import './calendar';
|
|
23
|
-
import './date-picker';
|
|
24
|
-
import './file-upload';
|
|
25
|
-
import './combobox';
|
|
26
|
-
import './command';
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { ComponentRegistry } from '@object-ui/core';
|
|
10
|
-
import type { InputOTPSchema } from '@object-ui/types';
|
|
11
|
-
import { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from '../../ui';
|
|
12
|
-
|
|
13
|
-
ComponentRegistry.register('input-otp',
|
|
14
|
-
({ schema, className, onChange, value, ...props }: { schema: InputOTPSchema; className?: string; [key: string]: any }) => {
|
|
15
|
-
const length = schema.maxLength || 6;
|
|
16
|
-
const slots = Array.from({ length });
|
|
17
|
-
|
|
18
|
-
const handleChange = (val: string) => {
|
|
19
|
-
if (onChange) {
|
|
20
|
-
onChange(val);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<InputOTP
|
|
26
|
-
maxLength={length}
|
|
27
|
-
className={className}
|
|
28
|
-
value={value ?? schema.value}
|
|
29
|
-
onChange={handleChange}
|
|
30
|
-
{...props}
|
|
31
|
-
>
|
|
32
|
-
<InputOTPGroup>
|
|
33
|
-
{slots.map((_, i) => (
|
|
34
|
-
<InputOTPSlot key={i} index={i} />
|
|
35
|
-
))}
|
|
36
|
-
</InputOTPGroup>
|
|
37
|
-
</InputOTP>
|
|
38
|
-
);
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
namespace: 'ui',
|
|
42
|
-
label: 'Input OTP',
|
|
43
|
-
inputs: [
|
|
44
|
-
{ name: 'maxLength', type: 'number', label: 'Max Length', defaultValue: 6 },
|
|
45
|
-
{ name: 'className', type: 'string', label: 'CSS Class' }
|
|
46
|
-
],
|
|
47
|
-
defaultProps: {
|
|
48
|
-
maxLength: 6
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
);
|