@keboola/design 10.1.0 → 11.0.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/AGENTS.md +2 -0
- package/dist/AIKit-Dre37SJr.js +1320 -0
- package/dist/AIKit-Dre37SJr.js.map +1 -0
- package/dist/Alert-DfZq9kGe.js +133 -0
- package/dist/Alert-DfZq9kGe.js.map +1 -0
- package/dist/AlertModal-BUC4Es8o.js +222 -0
- package/dist/AlertModal-BUC4Es8o.js.map +1 -0
- package/dist/AppShell-B5GQN6Zs.js +143 -0
- package/dist/AppShell-B5GQN6Zs.js.map +1 -0
- package/dist/AutoSaveTextarea-BeuWuszr.js +58 -0
- package/dist/AutoSaveTextarea-BeuWuszr.js.map +1 -0
- package/dist/Badge-Ch26CXoP.js +195 -0
- package/dist/Badge-Ch26CXoP.js.map +1 -0
- package/dist/BrandEditor-B8o9zdZO.js +903 -0
- package/dist/BrandEditor-B8o9zdZO.js.map +1 -0
- package/dist/BrandLogo-CJkRd0F8.js +46 -0
- package/dist/BrandLogo-CJkRd0F8.js.map +1 -0
- package/dist/Breadcrumb-DJp7WwSv.js +330 -0
- package/dist/Breadcrumb-DJp7WwSv.js.map +1 -0
- package/dist/Button-nzmDNS2q.js +391 -0
- package/dist/Button-nzmDNS2q.js.map +1 -0
- package/dist/Calendar-cG5NIJ4O.js +6768 -0
- package/dist/Calendar-cG5NIJ4O.js.map +1 -0
- package/dist/Card-BAoZ35CV.js +105 -0
- package/dist/Card-BAoZ35CV.js.map +1 -0
- package/dist/Checkbox-GJ8-srt4.js +97 -0
- package/dist/Checkbox-GJ8-srt4.js.map +1 -0
- package/dist/Clipboard-CBJZiviP.js +58 -0
- package/dist/Clipboard-CBJZiviP.js.map +1 -0
- package/dist/ClipboardButton-ez5V3fkk.js +43 -0
- package/dist/ClipboardButton-ez5V3fkk.js.map +1 -0
- package/dist/CodeEditor-BfQJfbhL.js +952 -0
- package/dist/CodeEditor-BfQJfbhL.js.map +1 -0
- package/dist/Collapsible-BQXWEOBC.js +34 -0
- package/dist/Collapsible-BQXWEOBC.js.map +1 -0
- package/dist/ColorInput-Dx8Dsv7Y.js +180 -0
- package/dist/ColorInput-Dx8Dsv7Y.js.map +1 -0
- package/dist/ColorModeSwitch-CCqj7tjE.js +77 -0
- package/dist/ColorModeSwitch-CCqj7tjE.js.map +1 -0
- package/dist/Combobox-c_xBjf0P.js +439 -0
- package/dist/Combobox-c_xBjf0P.js.map +1 -0
- package/dist/Command-CQ_bQsJp.js +102 -0
- package/dist/Command-CQ_bQsJp.js.map +1 -0
- package/dist/CopyField-BJ96zvXs.js +322 -0
- package/dist/CopyField-BJ96zvXs.js.map +1 -0
- package/dist/DateInput-CMD3dY-T.js +141 -0
- package/dist/DateInput-CMD3dY-T.js.map +1 -0
- package/dist/DatePicker-BbFbmsGl.js +24 -0
- package/dist/DatePicker-BbFbmsGl.js.map +1 -0
- package/dist/DateRangeInput-D3BhiKyk.js +139 -0
- package/dist/DateRangeInput-D3BhiKyk.js.map +1 -0
- package/dist/DateRangePicker-BiUgtt_M.js +159 -0
- package/dist/DateRangePicker-BiUgtt_M.js.map +1 -0
- package/dist/DiagramSkeleton-lwBS2YBa.js +11 -0
- package/dist/DiagramSkeleton-lwBS2YBa.js.map +1 -0
- package/dist/DiffView-ppTIzh2h.js +429 -0
- package/dist/DiffView-ppTIzh2h.js.map +1 -0
- package/dist/DropdownMenu-B6ZbYvaM.js +327 -0
- package/dist/DropdownMenu-B6ZbYvaM.js.map +1 -0
- package/dist/FieldBox-D7DYtX_m.js +70 -0
- package/dist/FieldBox-D7DYtX_m.js.map +1 -0
- package/dist/FileUpload-sXRv7JiY.js +2527 -0
- package/dist/FileUpload-sXRv7JiY.js.map +1 -0
- package/dist/Form-BDCef6O9.js +371 -0
- package/dist/Form-BDCef6O9.js.map +1 -0
- package/dist/FormGroup-S9mPNHKH.js +124 -0
- package/dist/FormGroup-S9mPNHKH.js.map +1 -0
- package/dist/FullScreenModal-CJa2VkJ2.js +96 -0
- package/dist/FullScreenModal-CJa2VkJ2.js.map +1 -0
- package/dist/HoverCard-WfDkLK1s.js +31 -0
- package/dist/HoverCard-WfDkLK1s.js.map +1 -0
- package/dist/InputGroup-BJWsI35s.js +292 -0
- package/dist/InputGroup-BJWsI35s.js.map +1 -0
- package/dist/Kbd-CxHAo1oo.js +111 -0
- package/dist/Kbd-CxHAo1oo.js.map +1 -0
- package/dist/MarkedText-Ckbft5mw.js +44 -0
- package/dist/MarkedText-Ckbft5mw.js.map +1 -0
- package/dist/MermaidDiagram-BB06gymm.js +399 -0
- package/dist/MermaidDiagram-BB06gymm.js.map +1 -0
- package/dist/Modal-BA5Wc3sx.js +185 -0
- package/dist/Modal-BA5Wc3sx.js.map +1 -0
- package/dist/ModalTitle-C76ke2eo.js +28 -0
- package/dist/ModalTitle-C76ke2eo.js.map +1 -0
- package/dist/MultiActionButtonGroup-CiBHxsSk.js +33 -0
- package/dist/MultiActionButtonGroup-CiBHxsSk.js.map +1 -0
- package/dist/Navbar-t16usFZQ.js +322 -0
- package/dist/Navbar-t16usFZQ.js.map +1 -0
- package/dist/OtpInput-CbbymqYs.js +93 -0
- package/dist/OtpInput-CbbymqYs.js.map +1 -0
- package/dist/PageHeader-Q3IpCnQd.js +177 -0
- package/dist/PageHeader-Q3IpCnQd.js.map +1 -0
- package/dist/PageLayout-DSVM-ASz.js +176 -0
- package/dist/PageLayout-DSVM-ASz.js.map +1 -0
- package/dist/PageToolbar-0_1OBzaZ.js +153 -0
- package/dist/PageToolbar-0_1OBzaZ.js.map +1 -0
- package/dist/Pagination-CM_Rszz-.js +70 -0
- package/dist/Pagination-CM_Rszz-.js.map +1 -0
- package/dist/Popconfirm-BGe1jLov.js +170 -0
- package/dist/Popconfirm-BGe1jLov.js.map +1 -0
- package/dist/Popover-Ca0V6AD1.js +92 -0
- package/dist/Popover-Ca0V6AD1.js.map +1 -0
- package/dist/RadioGroup-sIveSsNa.js +233 -0
- package/dist/RadioGroup-sIveSsNa.js.map +1 -0
- package/dist/Resizable-D3vYToZH.js +52 -0
- package/dist/Resizable-D3vYToZH.js.map +1 -0
- package/dist/Search-3UiqNZRj.js +184 -0
- package/dist/Search-3UiqNZRj.js.map +1 -0
- package/dist/SearchInput-D2fcOv7E.js +102 -0
- package/dist/SearchInput-D2fcOv7E.js.map +1 -0
- package/dist/SectionNav--7bw2b6u.js +276 -0
- package/dist/SectionNav--7bw2b6u.js.map +1 -0
- package/dist/Select-4YX38G5h.js +181 -0
- package/dist/Select-4YX38G5h.js.map +1 -0
- package/dist/Sheet-BQrX8-h5.js +169 -0
- package/dist/Sheet-BQrX8-h5.js.map +1 -0
- package/dist/Sidebar-ROaR_AqC.js +799 -0
- package/dist/Sidebar-ROaR_AqC.js.map +1 -0
- package/dist/Slider-Da_3mS5v.js +127 -0
- package/dist/Slider-Da_3mS5v.js.map +1 -0
- package/dist/Stepper-C8sm9ZFM.js +325 -0
- package/dist/Stepper-C8sm9ZFM.js.map +1 -0
- package/dist/Switch-CX2A0v50.js +201 -0
- package/dist/Switch-CX2A0v50.js.map +1 -0
- package/dist/Table-CvYuTuNU.js +104 -0
- package/dist/Table-CvYuTuNU.js.map +1 -0
- package/dist/Tabs-EAihyqCt.js +74 -0
- package/dist/Tabs-EAihyqCt.js.map +1 -0
- package/dist/TextInput-BGed-V13.js +110 -0
- package/dist/TextInput-BGed-V13.js.map +1 -0
- package/dist/ThemeProvider-QncUrfJn.js +203 -0
- package/dist/ThemeProvider-QncUrfJn.js.map +1 -0
- package/dist/TimePicker-B_NegL-7.js +98 -0
- package/dist/TimePicker-B_NegL-7.js.map +1 -0
- package/dist/Timeline-6btyJl4D.js +154 -0
- package/dist/Timeline-6btyJl4D.js.map +1 -0
- package/dist/Toast-DQSbs3oA.js +49 -0
- package/dist/Toast-DQSbs3oA.js.map +1 -0
- package/dist/ToggleGroup-Cy_10Mvu.js +47 -0
- package/dist/ToggleGroup-Cy_10Mvu.js.map +1 -0
- package/dist/Workbench-BzE-Vvd9.js +293 -0
- package/dist/Workbench-BzE-Vvd9.js.map +1 -0
- package/dist/ZoomableSvg-DG9PnAm8.js +248 -0
- package/dist/ZoomableSvg-DG9PnAm8.js.map +1 -0
- package/dist/charts.d.ts +124 -111
- package/dist/charts.js +303 -249
- package/dist/charts.js.map +1 -1
- package/dist/classNames-BzrkDnOD.js +9 -0
- package/dist/classNames-BzrkDnOD.js.map +1 -0
- package/dist/constants-D6JcsD4_.d.ts +41 -0
- package/dist/context-KxxeMHbR.js +62 -0
- package/dist/context-KxxeMHbR.js.map +1 -0
- package/dist/editors.d.ts +180 -173
- package/dist/editors.js +747 -420
- package/dist/editors.js.map +1 -1
- package/dist/escapeStringRegexp-8MxP2knR.js +6 -0
- package/dist/escapeStringRegexp-8MxP2knR.js.map +1 -0
- package/dist/icons-Cek151jC.js +640 -0
- package/dist/icons-Cek151jC.js.map +1 -0
- package/dist/icons.d.ts +2 -41
- package/dist/icons.js +2 -4
- package/dist/index-m-kQEWiY.d.ts +54 -0
- package/dist/index.d.ts +6192 -9904
- package/dist/index.js +112 -15803
- package/dist/internal/blocks/AIKit.js +2 -0
- package/dist/internal/blocks/AppShell.js +2 -0
- package/dist/internal/blocks/AutoSaveTextarea.js +2 -0
- package/dist/internal/blocks/BrandEditor.js +2 -0
- package/dist/internal/blocks/ChartPanel.js +46 -0
- package/dist/internal/blocks/ChartPanel.js.map +1 -0
- package/dist/internal/blocks/ClipboardButton.js +2 -0
- package/dist/internal/blocks/ColorInput.js +2 -0
- package/dist/internal/blocks/ColorModeSwitch.js +2 -0
- package/dist/internal/blocks/Command.js +2 -0
- package/dist/internal/blocks/CopyField.js +2 -0
- package/dist/internal/blocks/DashboardHero.js +59 -0
- package/dist/internal/blocks/DashboardHero.js.map +1 -0
- package/dist/internal/blocks/DateInput.js +2 -0
- package/dist/internal/blocks/DateRangeInput.js +2 -0
- package/dist/internal/blocks/EmptyConfigurationActionCard.js +16 -0
- package/dist/internal/blocks/EmptyConfigurationActionCard.js.map +1 -0
- package/dist/internal/blocks/EmptyState.js +142 -0
- package/dist/internal/blocks/EmptyState.js.map +1 -0
- package/dist/internal/blocks/ErrorState.js +179 -0
- package/dist/internal/blocks/ErrorState.js.map +1 -0
- package/dist/internal/blocks/ExportMenu.js +41 -0
- package/dist/internal/blocks/ExportMenu.js.map +1 -0
- package/dist/internal/blocks/Form.js +2 -0
- package/dist/internal/blocks/FormGroup.js +2 -0
- package/dist/internal/blocks/GoogleButton.js +95 -0
- package/dist/internal/blocks/GoogleButton.js.map +1 -0
- package/dist/internal/blocks/MicrosoftButton.js +64 -0
- package/dist/internal/blocks/MicrosoftButton.js.map +1 -0
- package/dist/internal/blocks/MultiActionButtonGroup.js +2 -0
- package/dist/internal/blocks/MultiCombobox.js +188 -0
- package/dist/internal/blocks/MultiCombobox.js.map +1 -0
- package/dist/internal/blocks/NumberInput.js +44 -0
- package/dist/internal/blocks/NumberInput.js.map +1 -0
- package/dist/internal/blocks/OtpInput.js +2 -0
- package/dist/internal/blocks/PageHeader.js +2 -0
- package/dist/internal/blocks/PageLayout.js +2 -0
- package/dist/internal/blocks/PageToolbar.js +2 -0
- package/dist/internal/blocks/PasswordInput.js +97 -0
- package/dist/internal/blocks/PasswordInput.js.map +1 -0
- package/dist/internal/blocks/SearchInput.js +2 -0
- package/dist/internal/blocks/SearchInputWithNavigation.js +65 -0
- package/dist/internal/blocks/SearchInputWithNavigation.js.map +1 -0
- package/dist/internal/blocks/SectionNav.js +2 -0
- package/dist/internal/blocks/SplitButton.js +46 -0
- package/dist/internal/blocks/SplitButton.js.map +1 -0
- package/dist/internal/blocks/StatCard.js +97 -0
- package/dist/internal/blocks/StatCard.js.map +1 -0
- package/dist/internal/blocks/TextInput.js +2 -0
- package/dist/internal/blocks/Textarea.js +32 -0
- package/dist/internal/blocks/Textarea.js.map +1 -0
- package/dist/internal/blocks/TimeInput.js +77 -0
- package/dist/internal/blocks/TimeInput.js.map +1 -0
- package/dist/internal/components/Alert.js +2 -0
- package/dist/internal/components/AlertModal.js +2 -0
- package/dist/internal/components/Avatar.js +53 -0
- package/dist/internal/components/Avatar.js.map +1 -0
- package/dist/internal/components/Badge.js +2 -0
- package/dist/internal/components/BrandLogo.js +2 -0
- package/dist/internal/components/Breadcrumb.js +2 -0
- package/dist/internal/components/Button.js +2 -0
- package/dist/internal/components/ButtonGroup.js +66 -0
- package/dist/internal/components/ButtonGroup.js.map +1 -0
- package/dist/internal/components/Calendar.js +2 -0
- package/dist/internal/components/Card.js +2 -0
- package/dist/internal/components/Checkbox.js +2 -0
- package/dist/internal/components/Clipboard.js +2 -0
- package/dist/internal/components/Collapsible.js +2 -0
- package/dist/internal/components/CollapsiblePanel.js +87 -0
- package/dist/internal/components/CollapsiblePanel.js.map +1 -0
- package/dist/internal/components/Combobox.js +2 -0
- package/dist/internal/components/DatePicker.js +2 -0
- package/dist/internal/components/DateRangePicker.js +2 -0
- package/dist/internal/components/DiffView.js +2 -0
- package/dist/internal/components/DotsLoader.js +18 -0
- package/dist/internal/components/DotsLoader.js.map +1 -0
- package/dist/internal/components/DropdownMenu.js +2 -0
- package/dist/internal/components/EmptySearchContent.js +12 -0
- package/dist/internal/components/EmptySearchContent.js.map +1 -0
- package/dist/internal/components/FileUpload.js +2 -0
- package/dist/internal/components/FullScreenModal.js +2 -0
- package/dist/internal/components/HelpBlock.js +25 -0
- package/dist/internal/components/HelpBlock.js.map +1 -0
- package/dist/internal/components/HoverCard.js +2 -0
- package/dist/internal/components/InputGroup.js +2 -0
- package/dist/internal/components/Kbd.js +2 -0
- package/dist/internal/components/Label.js +39 -0
- package/dist/internal/components/Label.js.map +1 -0
- package/dist/internal/components/Link.js +22 -0
- package/dist/internal/components/Link.js.map +1 -0
- package/dist/internal/components/MarkedText.js +2 -0
- package/dist/internal/components/MergeEditor/ConflictStatus/ConflictStatusIndicator.js +20 -0
- package/dist/internal/components/MergeEditor/ConflictStatus/ConflictStatusIndicator.js.map +1 -0
- package/dist/internal/components/MergeEditor/PaneHeader.js +13 -0
- package/dist/internal/components/MergeEditor/PaneHeader.js.map +1 -0
- package/dist/internal/components/MergeEditor/constants.js +18 -0
- package/dist/internal/components/MergeEditor/constants.js.map +1 -0
- package/dist/internal/components/MergeEditor/useMergeDiff.js +2 -0
- package/dist/internal/components/Modal.js +2 -0
- package/dist/internal/components/Navbar.js +2 -0
- package/dist/internal/components/Pagination.js +2 -0
- package/dist/internal/components/PanelWithDetails.js +31 -0
- package/dist/internal/components/PanelWithDetails.js.map +1 -0
- package/dist/internal/components/Popconfirm.js +2 -0
- package/dist/internal/components/Popover.js +2 -0
- package/dist/internal/components/Progress.js +47 -0
- package/dist/internal/components/Progress.js.map +1 -0
- package/dist/internal/components/RadioGroup.js +2 -0
- package/dist/internal/components/Resizable.js +2 -0
- package/dist/internal/components/ScrollArea.js +42 -0
- package/dist/internal/components/ScrollArea.js.map +1 -0
- package/dist/internal/components/Search.js +2 -0
- package/dist/internal/components/Select.js +2 -0
- package/dist/internal/components/Separator.js +84 -0
- package/dist/internal/components/Separator.js.map +1 -0
- package/dist/internal/components/Sheet.js +2 -0
- package/dist/internal/components/Sidebar.js +2 -0
- package/dist/internal/components/Skeleton/Skeleton.js +39 -0
- package/dist/internal/components/Skeleton/Skeleton.js.map +1 -0
- package/dist/internal/components/Skeleton/SkeletonList.js +41 -0
- package/dist/internal/components/Skeleton/SkeletonList.js.map +1 -0
- package/dist/internal/components/Slider.js +2 -0
- package/dist/internal/components/SpotlightBackdrop.js +132 -0
- package/dist/internal/components/SpotlightBackdrop.js.map +1 -0
- package/dist/internal/components/Stepper.js +2 -0
- package/dist/internal/components/Switch.js +2 -0
- package/dist/internal/components/Table.js +2 -0
- package/dist/internal/components/Tabs.js +2 -0
- package/dist/internal/components/ThemeProvider.js +3 -0
- package/dist/internal/components/TimePicker.js +2 -0
- package/dist/internal/components/Timeline.js +2 -0
- package/dist/internal/components/Toast.js +3 -0
- package/dist/internal/components/Toggle.js +169 -0
- package/dist/internal/components/Toggle.js.map +1 -0
- package/dist/internal/components/ToggleGroup.js +2 -0
- package/dist/internal/components/Tooltip.js +2 -0
- package/dist/internal/components/Truncated.js +45 -0
- package/dist/internal/components/Truncated.js.map +1 -0
- package/dist/internal/components/Workbench.js +2 -0
- package/dist/internal/components/ZoomableSvg.js +2 -0
- package/dist/internal/hooks/useAutosizeInput.js +77 -0
- package/dist/internal/hooks/useAutosizeInput.js.map +1 -0
- package/dist/internal/hooks/useScrollbarPosition.js +45 -0
- package/dist/internal/hooks/useScrollbarPosition.js.map +1 -0
- package/dist/internal/hooks/useStableCallback.js +29 -0
- package/dist/internal/hooks/useStableCallback.js.map +1 -0
- package/dist/internal/utils/mergeRefs.js +20 -0
- package/dist/internal/utils/mergeRefs.js.map +1 -0
- package/dist/internal/utils.js +5 -0
- package/dist/markdown-editor.d.ts +72 -72
- package/dist/markdown-editor.js +1122 -1193
- package/dist/markdown-editor.js.map +1 -1
- package/dist/mermaid.d.ts +12 -12
- package/dist/mermaid.js +2 -10
- package/dist/rjsf.d.ts +33 -34
- package/dist/rjsf.js +1543 -1600
- package/dist/rjsf.js.map +1 -1
- package/dist/rolldown-runtime-Bdc48AWt.js +33 -0
- package/dist/styles-DSUP_-9Z.js +158 -0
- package/dist/styles-DSUP_-9Z.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/testing.d.ts +8 -7
- package/dist/testing.js +36 -16
- package/dist/testing.js.map +1 -1
- package/dist/themeTokens-BNg98Mu9.js +85 -0
- package/dist/themeTokens-BNg98Mu9.js.map +1 -0
- package/dist/toast-CjkURw0M.js +184 -0
- package/dist/toast-CjkURw0M.js.map +1 -0
- package/dist/useColorSchemeState-CYqcUfSH.js +61 -0
- package/dist/useColorSchemeState-CYqcUfSH.js.map +1 -0
- package/dist/useControllableState-M6494mCT.js +31 -0
- package/dist/useControllableState-M6494mCT.js.map +1 -0
- package/dist/useElement-DkF6esWL.js +15 -0
- package/dist/useElement-DkF6esWL.js.map +1 -0
- package/dist/useMergeDiff-CvowEXJ1.js +465 -0
- package/dist/useMergeDiff-CvowEXJ1.js.map +1 -0
- package/dist/utils-D0c5VAyF.js +308 -0
- package/dist/utils-D0c5VAyF.js.map +1 -0
- package/package.json +10 -9
- package/src/styles.css +35 -7
- package/src/theme.css +64 -0
- package/dist/MermaidDiagram-EOKJHQQV.js +0 -10
- package/dist/MermaidDiagram-EOKJHQQV.js.map +0 -1
- package/dist/chunk-63NSN2VL.js +0 -274
- package/dist/chunk-63NSN2VL.js.map +0 -1
- package/dist/chunk-6FPEI4EM.js +0 -6683
- package/dist/chunk-6FPEI4EM.js.map +0 -1
- package/dist/chunk-7PUUHEJQ.js +0 -1313
- package/dist/chunk-7PUUHEJQ.js.map +0 -1
- package/dist/chunk-BOHNXTMM.js +0 -606
- package/dist/chunk-BOHNXTMM.js.map +0 -1
- package/dist/chunk-C3L3TBBT.js +0 -242
- package/dist/chunk-C3L3TBBT.js.map +0 -1
- package/dist/chunk-CTCFYWJC.js +0 -407
- package/dist/chunk-CTCFYWJC.js.map +0 -1
- package/dist/chunk-ESBL3IPF.js +0 -23
- package/dist/chunk-ESBL3IPF.js.map +0 -1
- package/dist/chunk-IJTHFNNJ.js +0 -261
- package/dist/chunk-IJTHFNNJ.js.map +0 -1
- package/dist/chunk-JP7PNHLH.js +0 -40
- package/dist/chunk-JP7PNHLH.js.map +0 -1
- package/dist/chunk-KPNAW5MU.js +0 -229
- package/dist/chunk-KPNAW5MU.js.map +0 -1
- package/dist/chunk-L37JJ6MR.js +0 -152
- package/dist/chunk-L37JJ6MR.js.map +0 -1
- package/dist/chunk-Q7NWXLCT.js +0 -90
- package/dist/chunk-Q7NWXLCT.js.map +0 -1
- package/dist/chunk-SYIEF644.js +0 -1016
- package/dist/chunk-SYIEF644.js.map +0 -1
- package/dist/chunk-VMFSRV5H.js +0 -16
- package/dist/chunk-VMFSRV5H.js.map +0 -1
- package/dist/chunk-VPPM7UUQ.js +0 -47
- package/dist/chunk-VPPM7UUQ.js.map +0 -1
- package/dist/chunk-XV3UUOYF.js +0 -845
- package/dist/chunk-XV3UUOYF.js.map +0 -1
- package/dist/constants-D3gaMY-W.d.ts +0 -39
- package/dist/icons.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mermaid.js.map +0 -1
package/dist/rjsf.js
CHANGED
|
@@ -1,1655 +1,1598 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
import { Tooltip, debounce } from "./utils-D0c5VAyF.js";
|
|
2
|
+
import { BookOpen, Info, Trash2 } from "./icons-Cek151jC.js";
|
|
3
|
+
import { Button } from "./Button-nzmDNS2q.js";
|
|
4
|
+
import { Label } from "./internal/components/Label.js";
|
|
5
|
+
import { Link } from "./internal/components/Link.js";
|
|
6
|
+
import { TextInput } from "./TextInput-BGed-V13.js";
|
|
7
|
+
import { RadioGroup } from "./RadioGroup-sIveSsNa.js";
|
|
8
|
+
import { Checkbox } from "./Checkbox-GJ8-srt4.js";
|
|
9
|
+
import { Combobox } from "./Combobox-c_xBjf0P.js";
|
|
10
|
+
import { Textarea } from "./internal/blocks/Textarea.js";
|
|
11
|
+
import { DateInput } from "./DateInput-CMD3dY-T.js";
|
|
12
|
+
import { NumberInput } from "./internal/blocks/NumberInput.js";
|
|
13
|
+
import { PasswordInput } from "./internal/blocks/PasswordInput.js";
|
|
14
|
+
import { FormGroup } from "./FormGroup-S9mPNHKH.js";
|
|
15
|
+
import { Alert } from "./Alert-DfZq9kGe.js";
|
|
16
|
+
import { CollapsiblePanel } from "./internal/components/CollapsiblePanel.js";
|
|
17
|
+
import { Tabs, TabsContent } from "./Tabs-EAihyqCt.js";
|
|
18
|
+
import { CodeEditor, isLanguageMode } from "./CodeEditor-BfQJfbhL.js";
|
|
19
|
+
import { createContext, isValidElement, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
20
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
21
|
+
import DOMPurify from "dompurify";
|
|
22
|
+
import Form from "@rjsf/core";
|
|
23
|
+
import validator from "@rjsf/validator-ajv8";
|
|
24
|
+
//#region src/blocks/RjsfSchemaEditor/markdownContext.ts
|
|
25
|
+
/** Falls back to plain text when the host app doesn't provide a markdown renderer. */
|
|
26
|
+
const RenderMarkdownContext = createContext((source) => source);
|
|
27
|
+
const RenderMarkdownProvider = RenderMarkdownContext;
|
|
28
|
+
const useRenderMarkdown = () => use(RenderMarkdownContext);
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/CodeEditorWidget.tsx
|
|
31
|
+
const isValidJson = (raw) => {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(raw);
|
|
34
|
+
return Boolean(parsed && typeof parsed === "object");
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
27
38
|
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
const sanitize = (val) => {
|
|
40
|
+
if (typeof val === "object" && val !== null) return JSON.stringify(val, null, " ");
|
|
41
|
+
return String(val ?? "");
|
|
31
42
|
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
value: text,
|
|
79
|
-
mode,
|
|
80
|
-
readOnly: true,
|
|
81
|
-
withCopyButton: true,
|
|
82
|
-
withLineNumbers: editorOptions.lineNumbers !== false
|
|
83
|
-
}
|
|
84
|
-
) : /* @__PURE__ */ jsx(
|
|
85
|
-
CodeEditor,
|
|
86
|
-
{
|
|
87
|
-
variant: "field",
|
|
88
|
-
value: text,
|
|
89
|
-
mode,
|
|
90
|
-
onChange: handleChange,
|
|
91
|
-
withCopyButton: true,
|
|
92
|
-
withLineNumbers: editorOptions.lineNumbers !== false,
|
|
93
|
-
help
|
|
94
|
-
}
|
|
95
|
-
) });
|
|
43
|
+
const CodeEditorWidget = ({ id, value, onChange, disabled, readonly, options }) => {
|
|
44
|
+
const editorOptions = options.editor ?? {};
|
|
45
|
+
const rawMode = editorOptions.mode ?? "application/json";
|
|
46
|
+
const mode = isLanguageMode(rawMode) ? rawMode : "application/json";
|
|
47
|
+
const isJsonMode = mode === "application/json";
|
|
48
|
+
const isReadOnly = disabled || readonly || !!editorOptions.readOnly;
|
|
49
|
+
const [text, setText] = useState(() => sanitize(value));
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
setText((currentText) => {
|
|
52
|
+
const sanitized = sanitize(value);
|
|
53
|
+
if (currentText === sanitized) return currentText;
|
|
54
|
+
if (isJsonMode && isValidJson(currentText)) try {
|
|
55
|
+
if (JSON.stringify(JSON.parse(currentText)) === JSON.stringify(typeof value === "object" ? value : JSON.parse(sanitized))) return currentText;
|
|
56
|
+
} catch {}
|
|
57
|
+
return sanitized;
|
|
58
|
+
});
|
|
59
|
+
}, [value, isJsonMode]);
|
|
60
|
+
const handleChange = (raw) => {
|
|
61
|
+
setText(raw);
|
|
62
|
+
if (isJsonMode && isValidJson(raw)) onChange(JSON.parse(raw));
|
|
63
|
+
else onChange(raw);
|
|
64
|
+
};
|
|
65
|
+
const help = isJsonMode && !isReadOnly && options.encryptionHint !== false ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
66
|
+
"Properties prefixed with ",
|
|
67
|
+
/* @__PURE__ */ jsx("code", { children: "#" }),
|
|
68
|
+
" sign will be encrypted on save. Already encrypted strings will persist."
|
|
69
|
+
] }) : null;
|
|
70
|
+
return /* @__PURE__ */ jsx("div", {
|
|
71
|
+
id,
|
|
72
|
+
children: isReadOnly ? /* @__PURE__ */ jsx(CodeEditor, {
|
|
73
|
+
variant: "field",
|
|
74
|
+
value: text,
|
|
75
|
+
mode,
|
|
76
|
+
readOnly: true,
|
|
77
|
+
withCopyButton: true,
|
|
78
|
+
withLineNumbers: editorOptions.lineNumbers !== false
|
|
79
|
+
}) : /* @__PURE__ */ jsx(CodeEditor, {
|
|
80
|
+
variant: "field",
|
|
81
|
+
value: text,
|
|
82
|
+
mode,
|
|
83
|
+
onChange: handleChange,
|
|
84
|
+
withCopyButton: true,
|
|
85
|
+
withLineNumbers: editorOptions.lineNumbers !== false,
|
|
86
|
+
help
|
|
87
|
+
})
|
|
88
|
+
});
|
|
96
89
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
options: uiOptions ?? {}
|
|
115
|
-
}
|
|
116
|
-
);
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/blocks/RjsfSchemaEditor/fields/CodeEditorField.tsx
|
|
92
|
+
/**
|
|
93
|
+
* Field wrapper for CodeEditorWidget when used with type: "object".
|
|
94
|
+
* RJSF only applies ui:widget to primitive types, so object-typed
|
|
95
|
+
* code editors need a custom field that delegates to the widget.
|
|
96
|
+
*/
|
|
97
|
+
const CodeEditorField = ({ fieldPathId, formData, onChange, disabled, readonly, uiSchema }) => {
|
|
98
|
+
const uiOptions = uiSchema?.["ui:options"];
|
|
99
|
+
return /* @__PURE__ */ jsx(CodeEditorWidget, {
|
|
100
|
+
id: fieldPathId.$id,
|
|
101
|
+
value: formData,
|
|
102
|
+
onChange: (val) => onChange(val, fieldPathId.path),
|
|
103
|
+
disabled: !!disabled,
|
|
104
|
+
readonly: !!readonly,
|
|
105
|
+
options: uiOptions ?? {}
|
|
106
|
+
});
|
|
117
107
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/blocks/RjsfSchemaEditor/fieldHelpers.ts
|
|
110
|
+
/** No-op function reused as onBlur/onFocus stub in custom fields. */
|
|
111
|
+
const noop = () => {};
|
|
112
|
+
const NullField = () => null;
|
|
113
|
+
/** RJSF always registers SchemaField; the fallback only satisfies the indexed-access type. */
|
|
114
|
+
const getSchemaField = (registry) => registry.fields.SchemaField ?? NullField;
|
|
115
|
+
/** Stub props shared by all custom SchemaField call-sites (onBlur, onFocus, errorSchema). */
|
|
116
|
+
const SCHEMA_FIELD_STUBS = {
|
|
117
|
+
onBlur: noop,
|
|
118
|
+
onFocus: noop,
|
|
119
|
+
errorSchema: {}
|
|
121
120
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Resolves a dot-path against an object (e.g. "_metadata_.table.columns").
|
|
123
|
+
*
|
|
124
|
+
* json-editor watch paths may be prefixed with the schema `id` (e.g.
|
|
125
|
+
* "rootschema.endpoints.contact"). The prefix is not a real data key — it
|
|
126
|
+
* identifies the schema root. When the first segment doesn't exist in `data`
|
|
127
|
+
* we retry without it so components using this convention still resolve.
|
|
128
|
+
*/
|
|
129
|
+
const resolveByPath = (path, data) => {
|
|
130
|
+
const parts = path.split(".");
|
|
131
|
+
const walk = (segments) => {
|
|
132
|
+
let current = data;
|
|
133
|
+
for (const part of segments) {
|
|
134
|
+
if (current == null || typeof current !== "object") return void 0;
|
|
135
|
+
current = current[part];
|
|
136
|
+
}
|
|
137
|
+
return current;
|
|
138
|
+
};
|
|
139
|
+
const result = walk(parts);
|
|
140
|
+
const [first] = parts;
|
|
141
|
+
if (result !== void 0 || first === void 0 || parts.length <= 1) return result;
|
|
142
|
+
if (!(first in data)) return walk(parts.slice(1));
|
|
143
|
+
return result;
|
|
128
144
|
};
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const result = walk(parts);
|
|
140
|
-
const [first] = parts;
|
|
141
|
-
if (result !== void 0 || first === void 0 || parts.length <= 1) return result;
|
|
142
|
-
if (!(first in data)) return walk(parts.slice(1));
|
|
143
|
-
return result;
|
|
145
|
+
/**
|
|
146
|
+
* Whether a `template-watch` field is the invisible computed-helper variant.
|
|
147
|
+
*
|
|
148
|
+
* - `template-watch` replaces `ui:widget: 'hidden'`, so `ui:options.hidden` carries the schema's
|
|
149
|
+
* `options.hidden` instead.
|
|
150
|
+
* - The field stays mounted either way; only its wrapper is hidden.
|
|
151
|
+
*/
|
|
152
|
+
const isHiddenTemplateWatch = (uiSchema) => {
|
|
153
|
+
if (uiSchema?.["ui:widget"] !== "template-watch") return false;
|
|
154
|
+
return !!uiSchema["ui:options"]?.hidden;
|
|
144
155
|
};
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Extracts a property name from a simple Mustache-like template.
|
|
158
|
+
* e.g. "{{item.field_name}}" → "field_name"
|
|
159
|
+
*/
|
|
160
|
+
const extractProperty = (template) => {
|
|
161
|
+
return /\{\{item\.(\w+)\}\}/.exec(template)?.[1] ?? "";
|
|
148
162
|
};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Builds select options from watched form data and enumSource config.
|
|
165
|
+
*
|
|
166
|
+
* Supports two json-editor enumSource formats:
|
|
167
|
+
* 1. String: `enumSource: "varName"` — use the watched array directly as string values
|
|
168
|
+
* 2. Array: `enumSource: [{ source, value, title }]` — map items through templates
|
|
169
|
+
*/
|
|
170
|
+
const buildDynamicOptions = (watch, enumSource, rootFormData) => {
|
|
171
|
+
if (typeof enumSource === "string") {
|
|
172
|
+
const watchPath = watch[enumSource];
|
|
173
|
+
if (!watchPath) return [];
|
|
174
|
+
const sourceData = resolveByPath(watchPath, rootFormData);
|
|
175
|
+
if (!Array.isArray(sourceData)) return [];
|
|
176
|
+
return sourceData.map((item) => {
|
|
177
|
+
const val = String(item ?? "");
|
|
178
|
+
return {
|
|
179
|
+
value: val,
|
|
180
|
+
label: val
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (Array.isArray(enumSource) && enumSource.length > 0) {
|
|
185
|
+
if (enumSource.length > 1) console.warn("[RJSF] Multiple enumSource entries are not supported, only the first is used.");
|
|
186
|
+
const source = enumSource[0];
|
|
187
|
+
const watchPath = watch[source.source];
|
|
188
|
+
if (!watchPath) return [];
|
|
189
|
+
const sourceData = resolveByPath(watchPath, rootFormData);
|
|
190
|
+
if (!Array.isArray(sourceData)) return [];
|
|
191
|
+
const valueProp = extractProperty(source.value);
|
|
192
|
+
const titleProp = extractProperty(source.title);
|
|
193
|
+
return sourceData.filter((item) => item != null && typeof item === "object").map((item) => ({
|
|
194
|
+
value: String(item[valueProp] ?? ""),
|
|
195
|
+
label: String(item[titleProp] ?? item[valueProp] ?? "")
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
return [];
|
|
177
199
|
};
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
200
|
+
/**
|
|
201
|
+
* Builds a child `fieldPathId` for a nested SchemaField.
|
|
202
|
+
* Joins segments with "_" for the $id and appends them to the path array.
|
|
203
|
+
*/
|
|
204
|
+
const childFieldPathId = (parentFieldPathId, ...segments) => ({
|
|
205
|
+
$id: [parentFieldPathId?.$id ?? "root", ...segments].join("_"),
|
|
206
|
+
path: [...parentFieldPathId?.path ?? [], ...segments]
|
|
181
207
|
});
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
208
|
+
/**
|
|
209
|
+
* Sorts object entries by `propertyOrder`, falling back to MAX_SAFE_INTEGER
|
|
210
|
+
* for properties without an explicit order.
|
|
211
|
+
*/
|
|
212
|
+
const sortByPropertyOrder = (properties) => Object.entries(properties).sort(([, a], [, b]) => (a.propertyOrder ?? Number.MAX_SAFE_INTEGER) - (b.propertyOrder ?? Number.MAX_SAFE_INTEGER)).map(([key]) => key);
|
|
213
|
+
//#endregion
|
|
214
|
+
//#region src/blocks/RjsfSchemaEditor/SchemaDescription.tsx
|
|
215
|
+
/** Renders a schema description with sanitized HTML support (links, formatting, etc.). */
|
|
216
|
+
const SchemaDescription = ({ description }) => {
|
|
217
|
+
if (!description) return null;
|
|
218
|
+
return /* @__PURE__ */ jsx("p", {
|
|
219
|
+
className: "tw:text-xs tw:text-neutral-400",
|
|
220
|
+
dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(description) }
|
|
221
|
+
});
|
|
194
222
|
};
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
);
|
|
271
|
-
}
|
|
272
|
-
if (schema.title) {
|
|
273
|
-
return /* @__PURE__ */ jsxs("div", { className: "tw:rounded-lg tw:border tw:border-solid tw:border-neutral-200 tw:p-4", children: [
|
|
274
|
-
/* @__PURE__ */ jsx("h3", { className: "tw:mb-3 tw:text-base tw:font-medium tw:text-neutral-800", children: schema.title }),
|
|
275
|
-
/* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }),
|
|
276
|
-
gridContent
|
|
277
|
-
] });
|
|
278
|
-
}
|
|
279
|
-
return /* @__PURE__ */ jsxs("div", { className: "tw:flex tw:flex-col tw:gap-4", children: [
|
|
280
|
-
/* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }),
|
|
281
|
-
gridContent
|
|
282
|
-
] });
|
|
223
|
+
//#endregion
|
|
224
|
+
//#region src/blocks/RjsfSchemaEditor/fields/GridObjectField.tsx
|
|
225
|
+
/**
|
|
226
|
+
* Custom field that renders an object's properties in a responsive grid layout.
|
|
227
|
+
* Used for schema objects with `format: "grid"` or `"grid-strict"`.
|
|
228
|
+
* json-editor uses a 12-column grid; each property can specify `options.grid_columns`.
|
|
229
|
+
* Supports `options.collapsed` for collapsible sections.
|
|
230
|
+
*/
|
|
231
|
+
const GridObjectField = ({ schema, uiSchema = {}, formData, onChange, disabled, readonly, registry, fieldPathId }) => {
|
|
232
|
+
const properties = schema.properties ?? {};
|
|
233
|
+
const data = formData ?? {};
|
|
234
|
+
const SchemaField = getSchemaField(registry);
|
|
235
|
+
const dataRef = useRef(data);
|
|
236
|
+
dataRef.current = data;
|
|
237
|
+
const fieldPath = fieldPathId?.path;
|
|
238
|
+
const onPropertyChange = useCallback((key) => (value, _childPath, errorSchema, id) => {
|
|
239
|
+
onChange({
|
|
240
|
+
...dataRef.current,
|
|
241
|
+
[key]: value
|
|
242
|
+
}, fieldPath, errorSchema, id);
|
|
243
|
+
}, [onChange, fieldPath]);
|
|
244
|
+
const uiOptions = uiSchema["ui:options"];
|
|
245
|
+
const hasCollapsed = uiOptions?.collapsed !== void 0;
|
|
246
|
+
const collapsed = !!uiOptions?.collapsed;
|
|
247
|
+
const disableCollapse = !!uiOptions?.disableCollapse;
|
|
248
|
+
const sortedKeys = sortByPropertyOrder(properties);
|
|
249
|
+
if (sortedKeys.length === 0) return null;
|
|
250
|
+
const gridContent = /* @__PURE__ */ jsx("div", {
|
|
251
|
+
className: "tw:grid tw:grid-cols-12 tw:gap-4 tw:[&>div:empty]:hidden",
|
|
252
|
+
children: sortedKeys.map((key) => {
|
|
253
|
+
const gridCols = properties[key]?.options?.grid_columns ?? 12;
|
|
254
|
+
const gridBreak = !!properties[key]?.options?.grid_break;
|
|
255
|
+
return /* @__PURE__ */ jsx("div", {
|
|
256
|
+
style: { gridColumn: gridBreak ? "1 / -1" : `span ${Math.min(gridCols, 12)}` },
|
|
257
|
+
children: /* @__PURE__ */ jsx(SchemaField, {
|
|
258
|
+
name: key,
|
|
259
|
+
schema: schema.properties[key],
|
|
260
|
+
uiSchema: uiSchema[key] ?? {},
|
|
261
|
+
formData: data[key],
|
|
262
|
+
...SCHEMA_FIELD_STUBS,
|
|
263
|
+
fieldPathId: childFieldPathId(fieldPathId, key),
|
|
264
|
+
registry,
|
|
265
|
+
onChange: onPropertyChange(key),
|
|
266
|
+
disabled: !!disabled,
|
|
267
|
+
readonly: !!readonly
|
|
268
|
+
})
|
|
269
|
+
}, key);
|
|
270
|
+
})
|
|
271
|
+
});
|
|
272
|
+
if (hasCollapsed && !disableCollapse) {
|
|
273
|
+
const defaultExpanded = Object.values(data).some((v) => v !== void 0 && v !== null && v !== "" && v !== false) ? !collapsed : true;
|
|
274
|
+
return /* @__PURE__ */ jsxs(CollapsiblePanel, {
|
|
275
|
+
className: "tw:rounded-lg",
|
|
276
|
+
header: schema.title || "Settings",
|
|
277
|
+
defaultExpanded,
|
|
278
|
+
headerClassName: "tw:rounded-lg",
|
|
279
|
+
bodyClassName: "tw:flex tw:flex-col tw:gap-4",
|
|
280
|
+
children: [/* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }), gridContent]
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
if (schema.title) return /* @__PURE__ */ jsxs("div", {
|
|
284
|
+
className: "tw:rounded-lg tw:border tw:border-solid tw:border-neutral-200 tw:p-4",
|
|
285
|
+
children: [
|
|
286
|
+
/* @__PURE__ */ jsx("h3", {
|
|
287
|
+
className: "tw:mb-3 tw:text-base tw:font-medium tw:text-neutral-800",
|
|
288
|
+
children: schema.title
|
|
289
|
+
}),
|
|
290
|
+
/* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }),
|
|
291
|
+
gridContent
|
|
292
|
+
]
|
|
293
|
+
});
|
|
294
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
295
|
+
className: "tw:flex tw:flex-col tw:gap-4",
|
|
296
|
+
children: [/* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }), gridContent]
|
|
297
|
+
});
|
|
283
298
|
};
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/blocks/RjsfSchemaEditor/fields/InfoField.tsx
|
|
301
|
+
const VALID_ALERT_TYPES = /* @__PURE__ */ new Set([
|
|
302
|
+
"info",
|
|
303
|
+
"warning",
|
|
304
|
+
"error",
|
|
305
|
+
"success"
|
|
306
|
+
]);
|
|
307
|
+
/**
|
|
308
|
+
* Custom field that renders static informational text.
|
|
309
|
+
* Used for schema properties with `format: "info"`.
|
|
310
|
+
* Displays title and description as a read-only alert.
|
|
311
|
+
* Supports `options.alert_type` to control the alert variant
|
|
312
|
+
* (`"info"` (default), `"warning"`, `"error"`, `"success"`).
|
|
313
|
+
*/
|
|
314
|
+
const InfoField = ({ schema, uiSchema }) => {
|
|
315
|
+
if (!schema.title && !schema.description) return null;
|
|
316
|
+
const uiOptions = uiSchema?.["ui:options"];
|
|
317
|
+
const alertType = String(uiOptions?.alertType ?? "info");
|
|
318
|
+
const variant = VALID_ALERT_TYPES.has(alertType) ? alertType : "info";
|
|
319
|
+
return /* @__PURE__ */ jsx("div", {
|
|
320
|
+
className: "tw:my-3",
|
|
321
|
+
children: /* @__PURE__ */ jsx(Alert, {
|
|
322
|
+
variant,
|
|
323
|
+
title: schema.title,
|
|
324
|
+
children: schema.description
|
|
325
|
+
})
|
|
326
|
+
});
|
|
291
327
|
};
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region src/blocks/RjsfSchemaEditor/TooltipIcon.tsx
|
|
330
|
+
const TooltipIcon = ({ rawHelp }) => {
|
|
331
|
+
const renderMarkdown = useRenderMarkdown();
|
|
332
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
333
|
+
placement: "top",
|
|
334
|
+
variant: "explanatory",
|
|
335
|
+
tooltip: renderMarkdown(rawHelp),
|
|
336
|
+
triggerAsChild: true,
|
|
337
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
338
|
+
className: "tw:cursor-help tw:text-neutral-400",
|
|
339
|
+
children: /* @__PURE__ */ jsx(Info, { className: "tw:size-4" })
|
|
340
|
+
})
|
|
341
|
+
});
|
|
295
342
|
};
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
343
|
+
//#endregion
|
|
344
|
+
//#region src/blocks/RjsfSchemaEditor/fields/TableArrayField.tsx
|
|
345
|
+
/** Default value for a freshly added cell/item, honouring the schema default. */
|
|
346
|
+
const defaultValueFor = (prop) => {
|
|
347
|
+
if (prop.default !== void 0) return prop.default;
|
|
348
|
+
if (prop.type === "boolean") return false;
|
|
349
|
+
if (prop.type === "string") return "";
|
|
301
350
|
};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
addButton
|
|
442
|
-
]
|
|
443
|
-
}
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
return /* @__PURE__ */ jsxs("div", { className: "tw:flex tw:flex-col tw:gap-4", children: [
|
|
447
|
-
/* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }),
|
|
448
|
-
table,
|
|
449
|
-
addButton
|
|
450
|
-
] });
|
|
351
|
+
/**
|
|
352
|
+
* Custom field that renders an array as a table.
|
|
353
|
+
* Used for schema arrays with `format: "table"`.
|
|
354
|
+
*
|
|
355
|
+
* - Array of objects: each item is a row, each property a column.
|
|
356
|
+
* - Array of primitives (e.g. `items: { type: 'string' }`): each item is a
|
|
357
|
+
* single-column row holding the value itself.
|
|
358
|
+
*
|
|
359
|
+
* Cells are rendered via RJSF's SchemaField so all registered widgets are used.
|
|
360
|
+
*/
|
|
361
|
+
const TableArrayField = ({ schema, uiSchema = {}, formData, onChange, disabled, readonly, registry, fieldPathId }) => {
|
|
362
|
+
const items = formData ?? [];
|
|
363
|
+
const itemSchema = schema.items;
|
|
364
|
+
const properties = itemSchema?.properties ?? {};
|
|
365
|
+
const itemUiSchema = uiSchema.items ?? {};
|
|
366
|
+
const SchemaField = getSchemaField(registry);
|
|
367
|
+
const sortedKeys = sortByPropertyOrder(properties);
|
|
368
|
+
const isPrimitiveItems = sortedKeys.length === 0 && itemSchema != null;
|
|
369
|
+
const isReadOnly = disabled || readonly;
|
|
370
|
+
const fieldPath = fieldPathId?.path ?? [];
|
|
371
|
+
const itemsRef = useRef(items);
|
|
372
|
+
itemsRef.current = items;
|
|
373
|
+
const handleCellChange = (rowIndex, key, value) => {
|
|
374
|
+
const newItems = [...itemsRef.current];
|
|
375
|
+
newItems[rowIndex] = {
|
|
376
|
+
...newItems[rowIndex],
|
|
377
|
+
[key]: value
|
|
378
|
+
};
|
|
379
|
+
onChange(newItems, fieldPath);
|
|
380
|
+
};
|
|
381
|
+
const handleItemChange = (rowIndex, value) => {
|
|
382
|
+
const newItems = [...itemsRef.current];
|
|
383
|
+
newItems[rowIndex] = value;
|
|
384
|
+
onChange(newItems, fieldPath);
|
|
385
|
+
};
|
|
386
|
+
const handleRemoveRow = (rowIndex) => {
|
|
387
|
+
onChange(itemsRef.current.filter((_, i) => i !== rowIndex), fieldPath);
|
|
388
|
+
};
|
|
389
|
+
const handleAddRow = () => {
|
|
390
|
+
if (isPrimitiveItems) {
|
|
391
|
+
onChange([...itemsRef.current, defaultValueFor({
|
|
392
|
+
type: itemSchema?.type,
|
|
393
|
+
default: itemSchema?.default
|
|
394
|
+
})], fieldPath);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const newItem = {};
|
|
398
|
+
for (const key of sortedKeys) newItem[key] = defaultValueFor(properties[key] ?? {});
|
|
399
|
+
onChange([...itemsRef.current, newItem], fieldPath);
|
|
400
|
+
};
|
|
401
|
+
const withHiddenLabel = (base) => ({
|
|
402
|
+
...base,
|
|
403
|
+
"ui:options": {
|
|
404
|
+
...base["ui:options"],
|
|
405
|
+
label: false
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
const getCellUiSchema = (key) => withHiddenLabel(itemUiSchema[key] ?? {});
|
|
409
|
+
const table = items.length > 0 && /* @__PURE__ */ jsxs("table", {
|
|
410
|
+
className: "tw:w-full tw:table-fixed tw:border-collapse tw:text-sm",
|
|
411
|
+
children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [isPrimitiveItems ? /* @__PURE__ */ jsx("th", {
|
|
412
|
+
className: "tw:border-b tw:border-neutral-200 tw:p-2 tw:text-left tw:text-xs tw:font-medium tw:text-neutral-600",
|
|
413
|
+
children: itemSchema?.title ?? ""
|
|
414
|
+
}) : sortedKeys.map((key) => /* @__PURE__ */ jsx("th", {
|
|
415
|
+
className: "tw:border-b tw:border-neutral-200 tw:p-2 tw:text-left tw:text-xs tw:font-medium tw:text-neutral-600",
|
|
416
|
+
children: properties[key]?.title ?? key
|
|
417
|
+
}, key)), !isReadOnly && /* @__PURE__ */ jsx("th", { className: "tw:w-20" })] }) }), /* @__PURE__ */ jsx("tbody", { children: items.map((item, rowIndex) => /* @__PURE__ */ jsxs("tr", {
|
|
418
|
+
className: "tw:border-b tw:border-neutral-100",
|
|
419
|
+
children: [isPrimitiveItems ? /* @__PURE__ */ jsx("td", {
|
|
420
|
+
className: "tw:px-2 tw:py-1.5 tw:[&>div]:mb-0",
|
|
421
|
+
children: /* @__PURE__ */ jsx(SchemaField, {
|
|
422
|
+
name: String(rowIndex),
|
|
423
|
+
schema: itemSchema,
|
|
424
|
+
uiSchema: withHiddenLabel(itemUiSchema),
|
|
425
|
+
formData: item,
|
|
426
|
+
...SCHEMA_FIELD_STUBS,
|
|
427
|
+
fieldPathId: childFieldPathId(fieldPathId, rowIndex),
|
|
428
|
+
registry,
|
|
429
|
+
onChange: (val) => handleItemChange(rowIndex, val),
|
|
430
|
+
disabled: !!disabled,
|
|
431
|
+
readonly: !!readonly
|
|
432
|
+
})
|
|
433
|
+
}) : sortedKeys.map((key) => /* @__PURE__ */ jsx("td", {
|
|
434
|
+
className: "tw:px-2 tw:py-1.5 tw:[&>div]:mb-0",
|
|
435
|
+
children: /* @__PURE__ */ jsx(SchemaField, {
|
|
436
|
+
name: key,
|
|
437
|
+
schema: properties[key],
|
|
438
|
+
uiSchema: getCellUiSchema(key),
|
|
439
|
+
formData: item[key],
|
|
440
|
+
...SCHEMA_FIELD_STUBS,
|
|
441
|
+
fieldPathId: childFieldPathId(fieldPathId, rowIndex, key),
|
|
442
|
+
registry,
|
|
443
|
+
onChange: (val) => handleCellChange(rowIndex, key, val),
|
|
444
|
+
disabled: !!disabled,
|
|
445
|
+
readonly: !!readonly
|
|
446
|
+
})
|
|
447
|
+
}, key)), !isReadOnly && /* @__PURE__ */ jsx("td", {
|
|
448
|
+
className: "tw:px-2 tw:py-1.5 tw:text-right",
|
|
449
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
450
|
+
variant: "invisible",
|
|
451
|
+
size: "icon",
|
|
452
|
+
onClick: () => handleRemoveRow(rowIndex),
|
|
453
|
+
"aria-label": "Remove row",
|
|
454
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "tw:size-4" })
|
|
455
|
+
})
|
|
456
|
+
})]
|
|
457
|
+
}, rowIndex)) })]
|
|
458
|
+
});
|
|
459
|
+
const addButton = !isReadOnly && /* @__PURE__ */ jsxs(Button, {
|
|
460
|
+
variant: "outline",
|
|
461
|
+
onClick: handleAddRow,
|
|
462
|
+
children: ["Add ", itemSchema?.title || "Item"]
|
|
463
|
+
});
|
|
464
|
+
if (schema.title) {
|
|
465
|
+
const tooltip = uiSchema["ui:help"];
|
|
466
|
+
return /* @__PURE__ */ jsxs(CollapsiblePanel, {
|
|
467
|
+
className: "tw:rounded-lg",
|
|
468
|
+
headerClassName: "tw:rounded-lg",
|
|
469
|
+
header: /* @__PURE__ */ jsxs("span", {
|
|
470
|
+
className: "tw:inline-flex tw:items-center tw:gap-1",
|
|
471
|
+
children: [schema.title, tooltip && /* @__PURE__ */ jsx(TooltipIcon, { rawHelp: tooltip })]
|
|
472
|
+
}),
|
|
473
|
+
defaultExpanded: true,
|
|
474
|
+
bodyClassName: "tw:flex tw:flex-col tw:gap-4",
|
|
475
|
+
children: [
|
|
476
|
+
/* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }),
|
|
477
|
+
table,
|
|
478
|
+
addButton
|
|
479
|
+
]
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
483
|
+
className: "tw:flex tw:flex-col tw:gap-4",
|
|
484
|
+
children: [
|
|
485
|
+
/* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }),
|
|
486
|
+
table,
|
|
487
|
+
addButton
|
|
488
|
+
]
|
|
489
|
+
});
|
|
451
490
|
};
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
491
|
+
//#endregion
|
|
492
|
+
//#region src/blocks/RjsfSchemaEditor/fields/TabsObjectField.tsx
|
|
493
|
+
/**
|
|
494
|
+
* Custom field that renders an object's properties as tabs.
|
|
495
|
+
* Used for schema objects with `format: "tabs"`, `"tabs-top"`, or `"categories"`.
|
|
496
|
+
* Each property becomes a tab panel.
|
|
497
|
+
*/
|
|
498
|
+
const TabsObjectField = ({ schema, uiSchema = {}, formData, onChange, disabled, readonly, registry, fieldPathId }) => {
|
|
499
|
+
const properties = schema.properties ?? {};
|
|
500
|
+
const data = formData ?? {};
|
|
501
|
+
const SchemaField = getSchemaField(registry);
|
|
502
|
+
const dataRef = useRef(data);
|
|
503
|
+
dataRef.current = data;
|
|
504
|
+
const onPropertyChange = useCallback((key) => (value, path, errorSchema, id) => {
|
|
505
|
+
onChange({
|
|
506
|
+
...dataRef.current,
|
|
507
|
+
[key]: value
|
|
508
|
+
}, path, errorSchema, id);
|
|
509
|
+
}, [onChange]);
|
|
510
|
+
const sortedKeys = sortByPropertyOrder(properties);
|
|
511
|
+
const [activeTab, setActiveTab] = useState(sortedKeys[0] ?? "");
|
|
512
|
+
if (sortedKeys.length === 0) return null;
|
|
513
|
+
const triggers = sortedKeys.map((key) => ({
|
|
514
|
+
value: key,
|
|
515
|
+
title: properties[key]?.title ?? key
|
|
516
|
+
}));
|
|
517
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
518
|
+
className: "tw:flex tw:flex-col tw:gap-4",
|
|
519
|
+
children: [
|
|
520
|
+
schema.title && /* @__PURE__ */ jsx("h3", {
|
|
521
|
+
className: "tw:text-base tw:font-medium tw:text-neutral-800",
|
|
522
|
+
children: schema.title
|
|
523
|
+
}),
|
|
524
|
+
/* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }),
|
|
525
|
+
/* @__PURE__ */ jsx(Tabs, {
|
|
526
|
+
triggers,
|
|
527
|
+
value: activeTab,
|
|
528
|
+
onValueChange: setActiveTab,
|
|
529
|
+
compact: true,
|
|
530
|
+
children: sortedKeys.map((key) => /* @__PURE__ */ jsx(TabsContent, {
|
|
531
|
+
value: key,
|
|
532
|
+
children: /* @__PURE__ */ jsx(SchemaField, {
|
|
533
|
+
name: key,
|
|
534
|
+
schema: schema.properties[key],
|
|
535
|
+
uiSchema: uiSchema[key] ?? {},
|
|
536
|
+
formData: data[key],
|
|
537
|
+
...SCHEMA_FIELD_STUBS,
|
|
538
|
+
fieldPathId: childFieldPathId(fieldPathId, key),
|
|
539
|
+
registry,
|
|
540
|
+
onChange: onPropertyChange(key),
|
|
541
|
+
disabled: !!disabled,
|
|
542
|
+
readonly: !!readonly
|
|
543
|
+
})
|
|
544
|
+
}, key))
|
|
545
|
+
})
|
|
546
|
+
]
|
|
547
|
+
});
|
|
500
548
|
};
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
Button,
|
|
551
|
-
{
|
|
552
|
-
variant: "outline",
|
|
553
|
-
size: "small",
|
|
554
|
-
className: "tw:mt-5 tw:shrink-0",
|
|
555
|
-
onClick: buttonsProps.onRemoveItem,
|
|
556
|
-
children: "Delete"
|
|
557
|
-
}
|
|
558
|
-
)
|
|
559
|
-
] }) });
|
|
549
|
+
//#endregion
|
|
550
|
+
//#region src/blocks/RjsfSchemaEditor/templates/ArrayFieldItemTemplate.tsx
|
|
551
|
+
const ArrayFieldItemTemplate = ({ children, index, totalItems, schema, hasToolbar, disabled, readonly, buttonsProps }) => {
|
|
552
|
+
const isObject = schema.type === "object";
|
|
553
|
+
const canRemove = hasToolbar && buttonsProps.hasRemove && !disabled && !readonly;
|
|
554
|
+
if (isObject) {
|
|
555
|
+
const itemTitle = `${schema.title || "Item"} ${index + 1}`;
|
|
556
|
+
const defaultExpanded = totalItems <= 1;
|
|
557
|
+
return /* @__PURE__ */ jsx(CollapsiblePanel, {
|
|
558
|
+
className: "tw:rounded-lg",
|
|
559
|
+
headerClassName: "tw:rounded-lg",
|
|
560
|
+
header: /* @__PURE__ */ jsxs("div", {
|
|
561
|
+
className: "tw:flex tw:w-full tw:items-center tw:justify-between",
|
|
562
|
+
children: [/* @__PURE__ */ jsx("span", { children: itemTitle }), canRemove && /* @__PURE__ */ jsx("div", {
|
|
563
|
+
role: "presentation",
|
|
564
|
+
onClick: (e) => e.stopPropagation(),
|
|
565
|
+
onKeyUp: (e) => e.stopPropagation(),
|
|
566
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
567
|
+
variant: "invisible",
|
|
568
|
+
size: "icon",
|
|
569
|
+
"aria-label": `Remove ${itemTitle}`,
|
|
570
|
+
onClick: buttonsProps.onRemoveItem,
|
|
571
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "tw:size-4" })
|
|
572
|
+
})
|
|
573
|
+
})]
|
|
574
|
+
}),
|
|
575
|
+
defaultExpanded,
|
|
576
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
577
|
+
className: "tw:flex tw:flex-col tw:gap-4",
|
|
578
|
+
children
|
|
579
|
+
})
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
return /* @__PURE__ */ jsx("div", {
|
|
583
|
+
className: "tw:rounded-lg tw:border tw:border-solid tw:border-neutral-200 tw:bg-white tw:p-4",
|
|
584
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
585
|
+
className: "tw:flex tw:items-start tw:gap-3",
|
|
586
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
587
|
+
className: "tw:flex tw:flex-1 tw:flex-col tw:gap-4",
|
|
588
|
+
children
|
|
589
|
+
}), canRemove && /* @__PURE__ */ jsx(Button, {
|
|
590
|
+
variant: "outline",
|
|
591
|
+
size: "small",
|
|
592
|
+
className: "tw:mt-5 tw:shrink-0",
|
|
593
|
+
onClick: buttonsProps.onRemoveItem,
|
|
594
|
+
children: "Delete"
|
|
595
|
+
})]
|
|
596
|
+
})
|
|
597
|
+
});
|
|
560
598
|
};
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
599
|
+
//#endregion
|
|
600
|
+
//#region src/blocks/RjsfSchemaEditor/templates/ArrayFieldTemplate.tsx
|
|
601
|
+
const ArrayFieldTemplate = ({ items, canAdd, onAddClick, title, schema, disabled, readonly }) => {
|
|
602
|
+
const isReadOnly = disabled || readonly;
|
|
603
|
+
const itemLabel = typeof schema.items === "object" && schema.items !== null && !Array.isArray(schema.items) ? schema.items.title || "Item" : "Item";
|
|
604
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
605
|
+
className: "tw:flex tw:flex-col tw:gap-4",
|
|
606
|
+
children: [
|
|
607
|
+
(title || schema.description) && /* @__PURE__ */ jsxs("div", { children: [title && /* @__PURE__ */ jsx("h3", {
|
|
608
|
+
className: "tw:text-base tw:font-medium tw:text-neutral-800",
|
|
609
|
+
children: title
|
|
610
|
+
}), schema.description && /* @__PURE__ */ jsx("p", {
|
|
611
|
+
className: "tw:mt-1 tw:text-xs tw:text-neutral-400",
|
|
612
|
+
children: schema.description
|
|
613
|
+
})] }),
|
|
614
|
+
items,
|
|
615
|
+
canAdd && !isReadOnly && /* @__PURE__ */ jsxs(Button, {
|
|
616
|
+
variant: "outline",
|
|
617
|
+
onClick: onAddClick,
|
|
618
|
+
children: ["Add ", itemLabel]
|
|
619
|
+
})
|
|
620
|
+
]
|
|
621
|
+
});
|
|
583
622
|
};
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
623
|
+
//#endregion
|
|
624
|
+
//#region src/blocks/RjsfSchemaEditor/templates/DescriptionFieldTemplate.tsx
|
|
625
|
+
/**
|
|
626
|
+
* Custom description template that renders HTML in schema descriptions.
|
|
627
|
+
* Uses DOMPurify to sanitize the HTML before rendering.
|
|
628
|
+
* Schema descriptions are authored by component developers and may contain
|
|
629
|
+
* links (<a>), formatting (<strong>, <code>, <br>), etc.
|
|
630
|
+
*/
|
|
631
|
+
const DescriptionFieldTemplate = ({ description, id }) => {
|
|
632
|
+
if (!description) return null;
|
|
633
|
+
if (isValidElement(description)) return /* @__PURE__ */ jsx("div", {
|
|
634
|
+
id,
|
|
635
|
+
children: description
|
|
636
|
+
});
|
|
637
|
+
return /* @__PURE__ */ jsx("p", {
|
|
638
|
+
id,
|
|
639
|
+
className: "tw:text-xs tw:text-neutral-400",
|
|
640
|
+
dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(String(description)) }
|
|
641
|
+
});
|
|
597
642
|
};
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
643
|
+
//#endregion
|
|
644
|
+
//#region src/blocks/RjsfSchemaEditor/templates/ErrorListTemplate.tsx
|
|
645
|
+
const ErrorListTemplate = ({ errors }) => {
|
|
646
|
+
if (!errors.length) return null;
|
|
647
|
+
return /* @__PURE__ */ jsx("div", {
|
|
648
|
+
className: "tw:mb-4",
|
|
649
|
+
children: errors.map((error) => /* @__PURE__ */ jsx("p", {
|
|
650
|
+
className: "tw:text-xs tw:text-error-500",
|
|
651
|
+
children: error.message
|
|
652
|
+
}, `${error.property}:${error.message}`))
|
|
653
|
+
});
|
|
601
654
|
};
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/blocks/RjsfSchemaEditor/RootFormDataContext.ts
|
|
657
|
+
const RootFormDataContext = createContext({});
|
|
658
|
+
const RootFormDataProvider = RootFormDataContext;
|
|
659
|
+
const useRootFormData = () => use(RootFormDataContext);
|
|
660
|
+
//#endregion
|
|
661
|
+
//#region src/blocks/RjsfSchemaEditor/templates/FieldTemplate.tsx
|
|
662
|
+
/**
|
|
663
|
+
* Resolves a dot-path against an object.
|
|
664
|
+
*/
|
|
665
|
+
const resolveByPath$1 = (parts, data) => {
|
|
666
|
+
let current = data;
|
|
667
|
+
for (const part of parts) {
|
|
668
|
+
if (current == null || typeof current !== "object") return void 0;
|
|
669
|
+
current = current[part];
|
|
670
|
+
}
|
|
671
|
+
return current;
|
|
612
672
|
};
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
673
|
+
/**
|
|
674
|
+
* Resolves a dependency path against form data.
|
|
675
|
+
*
|
|
676
|
+
* - Paths starting with "root." are resolved from the root form data
|
|
677
|
+
* - Other paths are resolved as siblings (relative to the parent object)
|
|
678
|
+
*/
|
|
679
|
+
const resolveDependencyValue = (path, formData, parentPath) => {
|
|
680
|
+
if (path.startsWith("root.")) return resolveByPath$1(path.replace(/^root\./, "").split("."), formData);
|
|
681
|
+
const parent = resolveByPath$1(parentPath.map(String), formData);
|
|
682
|
+
if (parent && typeof parent === "object") {
|
|
683
|
+
const sibling = resolveByPath$1(path.split("."), parent);
|
|
684
|
+
if (sibling !== void 0) return sibling;
|
|
685
|
+
}
|
|
686
|
+
return resolveByPath$1(path.split("."), formData);
|
|
623
687
|
};
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
688
|
+
/**
|
|
689
|
+
* Evaluates json-editor `options.dependencies` against current form data.
|
|
690
|
+
* Returns true if the field should be visible.
|
|
691
|
+
*
|
|
692
|
+
* Rules (matching old json-editor behavior):
|
|
693
|
+
* - `{ "field": "value" }` — show when field equals value
|
|
694
|
+
* - `{ "field": ["a", "b"] }` — show when field is one of the values
|
|
695
|
+
* - `{ "field": "" }` — show when field is empty/falsy
|
|
696
|
+
* - Multiple entries are AND-ed: all conditions must match
|
|
697
|
+
*/
|
|
698
|
+
const evaluateDependencies = (dependencies, formData, parentPath) => {
|
|
699
|
+
for (const [path, expected] of Object.entries(dependencies)) {
|
|
700
|
+
const actual = resolveDependencyValue(path, formData, parentPath);
|
|
701
|
+
if (Array.isArray(expected)) {
|
|
702
|
+
if (!expected.includes(actual)) return false;
|
|
703
|
+
} else if (expected === "") {
|
|
704
|
+
if (actual !== "" && actual !== void 0 && actual !== null) return false;
|
|
705
|
+
} else if (actual !== expected) return false;
|
|
706
|
+
}
|
|
707
|
+
return true;
|
|
636
708
|
};
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
)
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
] }) : children,
|
|
690
|
-
rawDescription && /* @__PURE__ */ jsx(FormGroup.Help, { children: /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(rawDescription) } }) }),
|
|
691
|
-
hasErrors && /* @__PURE__ */ jsx(FormGroup.Help, { children: rawErrors.join(". ") })
|
|
692
|
-
] });
|
|
709
|
+
const DocumentationLinkIcon = ({ documentation }) => /* @__PURE__ */ jsx(Tooltip, {
|
|
710
|
+
placement: "top",
|
|
711
|
+
variant: "explanatory",
|
|
712
|
+
tooltip: documentation.tooltip ?? "Open documentation",
|
|
713
|
+
triggerAsChild: true,
|
|
714
|
+
children: /* @__PURE__ */ jsx(Link, {
|
|
715
|
+
href: documentation.link,
|
|
716
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
717
|
+
className: "tw:cursor-pointer tw:text-neutral-400 tw:hover:text-neutral-600",
|
|
718
|
+
children: /* @__PURE__ */ jsx(BookOpen, { className: "tw:size-4" })
|
|
719
|
+
})
|
|
720
|
+
})
|
|
721
|
+
});
|
|
722
|
+
/**
|
|
723
|
+
* Renders the field's FormGroup wrapper, label, help, and errors.
|
|
724
|
+
* Does NOT subscribe to RootFormDataContext — that subscription only happens
|
|
725
|
+
* inside FieldTemplateWithDependencies, so fields without dependencies don't
|
|
726
|
+
* re-render on every form-state change.
|
|
727
|
+
*/
|
|
728
|
+
const FieldTemplateBody = ({ id, label, rawHelp, rawDescription, rawErrors, children, schema, uiSchema, displayLabel }) => {
|
|
729
|
+
const widget = uiSchema?.["ui:widget"];
|
|
730
|
+
if (widget === "test-connection" || widget === "sync-action") return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
731
|
+
if (schema.type === "object") return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
732
|
+
if (schema.type === "array" && !uiSchema?.["ui:widget"]) return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
733
|
+
const documentation = (uiSchema?.["ui:options"])?.documentation;
|
|
734
|
+
const hasErrors = rawErrors && rawErrors.length > 0;
|
|
735
|
+
const isCheckbox = schema.type === "boolean" && uiSchema?.["ui:widget"] !== "select";
|
|
736
|
+
const showLabel = displayLabel && label && !isCheckbox;
|
|
737
|
+
const hasHelpIcons = Boolean(rawHelp || documentation);
|
|
738
|
+
const helpIcons = /* @__PURE__ */ jsxs(Fragment$1, { children: [rawHelp && /* @__PURE__ */ jsx(TooltipIcon, { rawHelp }), documentation && /* @__PURE__ */ jsx(DocumentationLinkIcon, { documentation })] });
|
|
739
|
+
return /* @__PURE__ */ jsxs(FormGroup, {
|
|
740
|
+
state: hasErrors ? "error" : "default",
|
|
741
|
+
children: [
|
|
742
|
+
showLabel && /* @__PURE__ */ jsx(Label, {
|
|
743
|
+
htmlFor: id,
|
|
744
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
745
|
+
className: "tw:inline-flex tw:items-center tw:gap-1",
|
|
746
|
+
children: [label, helpIcons]
|
|
747
|
+
})
|
|
748
|
+
}),
|
|
749
|
+
!showLabel && !isCheckbox && hasHelpIcons && /* @__PURE__ */ jsx("div", {
|
|
750
|
+
className: "tw:flex tw:items-center tw:gap-1",
|
|
751
|
+
children: helpIcons
|
|
752
|
+
}),
|
|
753
|
+
isCheckbox && hasHelpIcons ? /* @__PURE__ */ jsxs("div", {
|
|
754
|
+
className: "tw:flex tw:items-center tw:gap-1",
|
|
755
|
+
children: [children, helpIcons]
|
|
756
|
+
}) : children,
|
|
757
|
+
rawDescription && /* @__PURE__ */ jsx(FormGroup.Help, { children: /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(rawDescription) } }) }),
|
|
758
|
+
hasErrors && /* @__PURE__ */ jsx(FormGroup.Help, { children: rawErrors.join(". ") })
|
|
759
|
+
]
|
|
760
|
+
});
|
|
693
761
|
};
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
762
|
+
/**
|
|
763
|
+
* Wraps FieldTemplateBody with a root-form-data subscription used to evaluate
|
|
764
|
+
* conditional visibility (options.dependencies). Subscribing here — instead of
|
|
765
|
+
* unconditionally in FieldTemplate — keeps fields without dependencies out of
|
|
766
|
+
* the RootFormDataContext consumer set, so they don't re-render on every
|
|
767
|
+
* keystroke. Critical for forms with many fields (e.g. column_mapping tables).
|
|
768
|
+
*/
|
|
769
|
+
const FieldTemplateWithDependencies = ({ dependencies, keepMounted, ...props }) => {
|
|
770
|
+
const rootFormData = useRootFormData();
|
|
771
|
+
const parentPath = props.fieldPathId.path.slice(0, -1);
|
|
772
|
+
if (!evaluateDependencies(dependencies, rootFormData, parentPath)) return keepMounted ? /* @__PURE__ */ jsx("div", {
|
|
773
|
+
className: "tw:hidden",
|
|
774
|
+
children: props.children
|
|
775
|
+
}) : null;
|
|
776
|
+
return /* @__PURE__ */ jsx(FieldTemplateBody, { ...props });
|
|
704
777
|
};
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
778
|
+
const FieldTemplate = (props) => {
|
|
779
|
+
if (props.hidden) return /* @__PURE__ */ jsx("div", {
|
|
780
|
+
className: "tw:hidden",
|
|
781
|
+
children: props.children
|
|
782
|
+
});
|
|
783
|
+
const uiOptions = props.uiSchema?.["ui:options"];
|
|
784
|
+
if (isHiddenTemplateWatch(props.uiSchema)) return /* @__PURE__ */ jsx("div", {
|
|
785
|
+
className: "tw:hidden",
|
|
786
|
+
children: props.children
|
|
787
|
+
});
|
|
788
|
+
const dependencies = uiOptions?.dependencies;
|
|
789
|
+
if (dependencies) return /* @__PURE__ */ jsx(FieldTemplateWithDependencies, {
|
|
790
|
+
dependencies,
|
|
791
|
+
keepMounted: props.uiSchema?.["ui:widget"] === "template-watch",
|
|
792
|
+
...props
|
|
793
|
+
});
|
|
794
|
+
return /* @__PURE__ */ jsx(FieldTemplateBody, { ...props });
|
|
716
795
|
};
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
] });
|
|
796
|
+
//#endregion
|
|
797
|
+
//#region src/blocks/RjsfSchemaEditor/templates/ObjectFieldTemplate.tsx
|
|
798
|
+
const ObjectFieldTemplate = ({ title, description, properties, formData, uiSchema, schema, fieldPathId }) => {
|
|
799
|
+
const isRoot = !fieldPathId?.path?.length;
|
|
800
|
+
const uiOptions = uiSchema?.["ui:options"];
|
|
801
|
+
const hasCollapsed = uiOptions?.collapsed !== void 0;
|
|
802
|
+
const collapsed = !!uiOptions?.collapsed;
|
|
803
|
+
const disableCollapse = !!uiOptions?.disableCollapse;
|
|
804
|
+
const isArrayItem = typeof fieldPathId?.path?.at(-1) === "number";
|
|
805
|
+
const childSchemas = schema.properties;
|
|
806
|
+
const isContainerSchema = (s) => {
|
|
807
|
+
if (!s) return false;
|
|
808
|
+
if (s.properties || s.items) return true;
|
|
809
|
+
if (Array.isArray(s.type)) return s.type.includes("object") || s.type.includes("array");
|
|
810
|
+
return s.type === "object" || s.type === "array";
|
|
811
|
+
};
|
|
812
|
+
const visibleProperties = properties.filter((prop) => {
|
|
813
|
+
if (uiSchema?.[prop.name]?.["ui:widget"] !== "hidden") return true;
|
|
814
|
+
return !isContainerSchema(childSchemas?.[prop.name]);
|
|
815
|
+
});
|
|
816
|
+
const isHiddenMount = (name) => {
|
|
817
|
+
const childUi = uiSchema?.[name];
|
|
818
|
+
return childUi?.["ui:widget"] === "hidden" || isHiddenTemplateWatch(childUi);
|
|
819
|
+
};
|
|
820
|
+
const renderChildren = (props) => props.map((prop) => /* @__PURE__ */ jsx("div", {
|
|
821
|
+
className: isHiddenMount(prop.name) ? "tw:hidden" : void 0,
|
|
822
|
+
children: prop.content
|
|
823
|
+
}, prop.name));
|
|
824
|
+
if (isRoot) return /* @__PURE__ */ jsx("div", {
|
|
825
|
+
className: "tw:flex tw:flex-col tw:gap-4 tw:[&>div:empty]:hidden",
|
|
826
|
+
children: renderChildren(visibleProperties)
|
|
827
|
+
});
|
|
828
|
+
const childrenContent = renderChildren(visibleProperties);
|
|
829
|
+
if (hasCollapsed && !disableCollapse) {
|
|
830
|
+
const defaultExpanded = Object.values(formData ?? {}).some((v) => v !== void 0 && v !== null && v !== "" && v !== false) ? !collapsed : true;
|
|
831
|
+
return /* @__PURE__ */ jsxs(CollapsiblePanel, {
|
|
832
|
+
className: "tw:rounded-lg",
|
|
833
|
+
headerClassName: "tw:rounded-lg",
|
|
834
|
+
header: title || "Settings",
|
|
835
|
+
defaultExpanded,
|
|
836
|
+
bodyClassName: "tw:flex tw:flex-col tw:gap-4 tw:[&>div:empty]:hidden",
|
|
837
|
+
children: [description, childrenContent]
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
if (isArrayItem) return /* @__PURE__ */ jsx("div", {
|
|
841
|
+
className: "tw:flex tw:flex-col tw:gap-4 tw:[&>div:empty]:hidden",
|
|
842
|
+
children: childrenContent
|
|
843
|
+
});
|
|
844
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
845
|
+
className: "tw:rounded-lg tw:border tw:border-solid tw:border-neutral-200 tw:bg-white tw:p-4",
|
|
846
|
+
children: [
|
|
847
|
+
title && /* @__PURE__ */ jsx("h3", {
|
|
848
|
+
className: "tw:mb-2 tw:text-base tw:font-medium tw:text-neutral-800",
|
|
849
|
+
children: title
|
|
850
|
+
}),
|
|
851
|
+
description && /* @__PURE__ */ jsx("p", {
|
|
852
|
+
className: "tw:mb-3 tw:text-xs tw:text-neutral-400",
|
|
853
|
+
children: description
|
|
854
|
+
}),
|
|
855
|
+
/* @__PURE__ */ jsx("div", {
|
|
856
|
+
className: "tw:flex tw:flex-col tw:gap-4 tw:[&>div:empty]:hidden",
|
|
857
|
+
children: childrenContent
|
|
858
|
+
})
|
|
859
|
+
]
|
|
860
|
+
});
|
|
783
861
|
};
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
return /* @__PURE__ */ jsx(Checkbox, { id, checked, onCheckedChange: onChange, disabled: disabled || readonly, children: hideLabel ? void 0 : label });
|
|
862
|
+
//#endregion
|
|
863
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/CheckboxWidget.tsx
|
|
864
|
+
const CheckboxWidget = ({ id, value, onChange, disabled, readonly, label, hideLabel }) => {
|
|
865
|
+
return /* @__PURE__ */ jsx(Checkbox, {
|
|
866
|
+
id,
|
|
867
|
+
checked: !!value,
|
|
868
|
+
onCheckedChange: onChange,
|
|
869
|
+
disabled: disabled || readonly,
|
|
870
|
+
children: hideLabel ? void 0 : label
|
|
871
|
+
});
|
|
795
872
|
};
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
})
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
}
|
|
826
|
-
const year = date.getFullYear();
|
|
827
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
828
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
829
|
-
onChange(`${year}-${month}-${day}`);
|
|
830
|
-
},
|
|
831
|
-
onBlur: () => onBlur(id, value),
|
|
832
|
-
onFocus: () => onFocus(id, value),
|
|
833
|
-
disabled: disabled || readonly,
|
|
834
|
-
placeholder: placeholder || "Select a date",
|
|
835
|
-
state: rawErrors?.length ? "error" : "default",
|
|
836
|
-
variant: "secondary"
|
|
837
|
-
}
|
|
838
|
-
);
|
|
873
|
+
//#endregion
|
|
874
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/DateWidget.tsx
|
|
875
|
+
const DateWidget = ({ id, value, onChange, onBlur, onFocus, disabled, readonly, placeholder, rawErrors }) => {
|
|
876
|
+
const dateValue = (() => {
|
|
877
|
+
if (!value) return null;
|
|
878
|
+
const parts = value.split("-").map(Number);
|
|
879
|
+
const [year, month, day] = parts;
|
|
880
|
+
if (parts.length !== 3 || parts.some(Number.isNaN)) return null;
|
|
881
|
+
if (year === void 0 || month === void 0 || day === void 0) return null;
|
|
882
|
+
return new Date(year, month - 1, day);
|
|
883
|
+
})();
|
|
884
|
+
const isValid = dateValue && !Number.isNaN(dateValue.getTime());
|
|
885
|
+
return /* @__PURE__ */ jsx(DateInput, {
|
|
886
|
+
id,
|
|
887
|
+
value: isValid ? dateValue : null,
|
|
888
|
+
onValueChange: (date) => {
|
|
889
|
+
if (!date) {
|
|
890
|
+
onChange(void 0);
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
onChange(`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`);
|
|
894
|
+
},
|
|
895
|
+
onBlur: () => onBlur(id, value),
|
|
896
|
+
onFocus: () => onFocus(id, value),
|
|
897
|
+
disabled: disabled || readonly,
|
|
898
|
+
placeholder: placeholder || "Select a date",
|
|
899
|
+
state: rawErrors?.length ? "error" : "default",
|
|
900
|
+
variant: "secondary"
|
|
901
|
+
});
|
|
839
902
|
};
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
}) => {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
903
|
+
//#endregion
|
|
904
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/DynamicSelectWidget.tsx
|
|
905
|
+
/**
|
|
906
|
+
* Widget for fields using json-editor's enumSource/watch pattern.
|
|
907
|
+
* Reads options dynamically from the root form data based on watched paths.
|
|
908
|
+
*/
|
|
909
|
+
const DynamicSelectWidget = ({ value, onChange, disabled, readonly, options: widgetOptions }) => {
|
|
910
|
+
const data = useRootFormData();
|
|
911
|
+
const watch = widgetOptions.watch;
|
|
912
|
+
const enumSource = widgetOptions.enumSource;
|
|
913
|
+
const dynamicItems = watch ? buildDynamicOptions(watch, enumSource, data) : [];
|
|
914
|
+
const stringValue = value == null ? "" : String(value);
|
|
915
|
+
const matched = dynamicItems.find((item) => item.value === stringValue);
|
|
916
|
+
const fallbackItem = !matched && stringValue !== "" ? {
|
|
917
|
+
value: stringValue,
|
|
918
|
+
label: stringValue
|
|
919
|
+
} : null;
|
|
920
|
+
const selectedItem = matched ?? fallbackItem;
|
|
921
|
+
const items = fallbackItem ? [fallbackItem, ...dynamicItems] : dynamicItems;
|
|
922
|
+
return /* @__PURE__ */ jsx(Combobox, {
|
|
923
|
+
variant: "secondary",
|
|
924
|
+
items,
|
|
925
|
+
value: selectedItem,
|
|
926
|
+
disabled: disabled || readonly,
|
|
927
|
+
onValueChange: (selected) => onChange(selected?.value ?? "")
|
|
928
|
+
});
|
|
866
929
|
};
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
onValueChange: (num) => onChange(num ?? void 0),
|
|
885
|
-
onBlur: () => onBlur(id, value),
|
|
886
|
-
onFocus: () => onFocus(id, value),
|
|
887
|
-
disabled: disabled || readonly,
|
|
888
|
-
placeholder,
|
|
889
|
-
min: schema.minimum,
|
|
890
|
-
max: schema.maximum,
|
|
891
|
-
step: schema.multipleOf,
|
|
892
|
-
state: rawErrors?.length ? "error" : "default",
|
|
893
|
-
variant: "secondary"
|
|
894
|
-
}
|
|
895
|
-
);
|
|
930
|
+
//#endregion
|
|
931
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/NumberWidget.tsx
|
|
932
|
+
const NumberWidget = ({ id, value, onChange, onBlur, onFocus, disabled, readonly, placeholder, schema, rawErrors }) => {
|
|
933
|
+
return /* @__PURE__ */ jsx(NumberInput, {
|
|
934
|
+
id,
|
|
935
|
+
value: value ?? null,
|
|
936
|
+
onValueChange: (num) => onChange(num ?? void 0),
|
|
937
|
+
onBlur: () => onBlur(id, value),
|
|
938
|
+
onFocus: () => onFocus(id, value),
|
|
939
|
+
disabled: disabled || readonly,
|
|
940
|
+
placeholder,
|
|
941
|
+
min: schema.minimum,
|
|
942
|
+
max: schema.maximum,
|
|
943
|
+
step: schema.multipleOf,
|
|
944
|
+
state: rawErrors?.length ? "error" : "default",
|
|
945
|
+
variant: "secondary"
|
|
946
|
+
});
|
|
896
947
|
};
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
id,
|
|
913
|
-
value: stringValue,
|
|
914
|
-
onValueChange: onChange,
|
|
915
|
-
onBlur: () => onBlur(id, value),
|
|
916
|
-
onFocus: () => onFocus(id, value),
|
|
917
|
-
disabled: disabled || readonly,
|
|
918
|
-
placeholder,
|
|
919
|
-
allowPasswordToggle: true,
|
|
920
|
-
state: rawErrors?.length ? "error" : "default",
|
|
921
|
-
variant: "secondary"
|
|
922
|
-
}
|
|
923
|
-
);
|
|
948
|
+
//#endregion
|
|
949
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/PasswordWidget.tsx
|
|
950
|
+
const PasswordWidget = ({ id, value, onChange, onBlur, onFocus, disabled, readonly, placeholder, rawErrors }) => {
|
|
951
|
+
return /* @__PURE__ */ jsx(PasswordInput, {
|
|
952
|
+
id,
|
|
953
|
+
value: value == null ? "" : String(value),
|
|
954
|
+
onValueChange: onChange,
|
|
955
|
+
onBlur: () => onBlur(id, value),
|
|
956
|
+
onFocus: () => onFocus(id, value),
|
|
957
|
+
disabled: disabled || readonly,
|
|
958
|
+
placeholder,
|
|
959
|
+
allowPasswordToggle: true,
|
|
960
|
+
state: rawErrors?.length ? "error" : "default",
|
|
961
|
+
variant: "secondary"
|
|
962
|
+
});
|
|
924
963
|
};
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
964
|
+
//#endregion
|
|
965
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/RadioWidget.tsx
|
|
966
|
+
const RadioWidget = ({ id, value, onChange, disabled, readonly, options }) => {
|
|
967
|
+
const enumOptions = options.enumOptions ?? [];
|
|
968
|
+
return /* @__PURE__ */ jsx(RadioGroup, {
|
|
969
|
+
id,
|
|
970
|
+
value: value ?? "",
|
|
971
|
+
onValueChange: onChange,
|
|
972
|
+
disabled: disabled || readonly,
|
|
973
|
+
orientation: "vertical",
|
|
974
|
+
children: enumOptions.map((opt) => /* @__PURE__ */ jsx(RadioGroup.Item, {
|
|
975
|
+
value: opt.value,
|
|
976
|
+
children: opt.label
|
|
977
|
+
}, opt.value))
|
|
978
|
+
});
|
|
938
979
|
};
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
onValueChange: (selected) => {
|
|
966
|
-
const selectedValue = selected?.value ?? "";
|
|
967
|
-
if (isBoolean) {
|
|
968
|
-
onChange(selectedValue === "true");
|
|
969
|
-
return;
|
|
970
|
-
}
|
|
971
|
-
onChange(selectedValue);
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
);
|
|
980
|
+
//#endregion
|
|
981
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/SelectWidget.tsx
|
|
982
|
+
const SelectWidget = ({ value, schema, onChange, disabled, readonly, options, placeholder, required }) => {
|
|
983
|
+
const enumOptions = options.enumOptions ?? [];
|
|
984
|
+
const isBoolean = schema.type === "boolean";
|
|
985
|
+
const items = enumOptions.map((o) => ({
|
|
986
|
+
value: String(o.value ?? ""),
|
|
987
|
+
label: o.label
|
|
988
|
+
}));
|
|
989
|
+
const selectedItem = items.find((item) => item.value === (value == null ? "" : String(value)));
|
|
990
|
+
return /* @__PURE__ */ jsx(Combobox, {
|
|
991
|
+
variant: "secondary",
|
|
992
|
+
items,
|
|
993
|
+
value: selectedItem ?? null,
|
|
994
|
+
allowClear: !required,
|
|
995
|
+
disabled: disabled || readonly,
|
|
996
|
+
placeholder,
|
|
997
|
+
onValueChange: (selected) => {
|
|
998
|
+
const selectedValue = selected?.value ?? "";
|
|
999
|
+
if (isBoolean) {
|
|
1000
|
+
onChange(selectedValue === "true");
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
onChange(selectedValue);
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
975
1006
|
};
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1007
|
+
//#endregion
|
|
1008
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/TemplateWatchWidget.tsx
|
|
1009
|
+
/**
|
|
1010
|
+
* Renders a watched value as text.
|
|
1011
|
+
*
|
|
1012
|
+
* - Objects and arrays are serialized as JSON; anything else goes through `String`.
|
|
1013
|
+
* - `null` and `undefined` render as an empty string.
|
|
1014
|
+
*/
|
|
1015
|
+
const stringify = (value) => {
|
|
1016
|
+
if (value == null) return "";
|
|
1017
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
1018
|
+
return String(value);
|
|
983
1019
|
};
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
onChange(computedStr);
|
|
995
|
-
}
|
|
996
|
-
}, [computed, onChange]);
|
|
997
|
-
return null;
|
|
1020
|
+
/**
|
|
1021
|
+
* Resolves a json-editor `template` string by substituting watched variables.
|
|
1022
|
+
* e.g. template="{{val}}" with watch={ val: "some.path" } → resolves "some.path" from form data.
|
|
1023
|
+
*/
|
|
1024
|
+
const resolveTemplate = (template, watch, rootFormData) => {
|
|
1025
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, varName) => {
|
|
1026
|
+
const watchPath = watch[varName];
|
|
1027
|
+
if (!watchPath) return "";
|
|
1028
|
+
return stringify(resolveByPath(watchPath, rootFormData));
|
|
1029
|
+
});
|
|
998
1030
|
};
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
);
|
|
1031
|
+
/**
|
|
1032
|
+
* Widget for json-editor's `template`/`watch` pattern (without `enumSource`).
|
|
1033
|
+
* Computes a value from watched form data paths and keeps the field in sync.
|
|
1034
|
+
*
|
|
1035
|
+
* - With `options.hidden` it renders nothing — a helper for cross-object dependencies.
|
|
1036
|
+
* - Without it, the value is shown in a read-only input; `FieldTemplate` supplies the label.
|
|
1037
|
+
*/
|
|
1038
|
+
const TemplateWatchWidget = ({ id, value, onChange, disabled, readonly, rawErrors, options: widgetOptions }) => {
|
|
1039
|
+
const data = useRootFormData();
|
|
1040
|
+
const watch = widgetOptions.watch;
|
|
1041
|
+
const template = widgetOptions.template;
|
|
1042
|
+
const computed = watch && template ? resolveTemplate(template, watch, data) : stringify(value);
|
|
1043
|
+
const lastSetRef = useRef(stringify(value));
|
|
1044
|
+
useEffect(() => {
|
|
1045
|
+
if (computed !== lastSetRef.current) {
|
|
1046
|
+
lastSetRef.current = computed;
|
|
1047
|
+
onChange(computed);
|
|
1048
|
+
}
|
|
1049
|
+
}, [computed, onChange]);
|
|
1050
|
+
if (widgetOptions.hidden) return null;
|
|
1051
|
+
return /* @__PURE__ */ jsx(TextInput, {
|
|
1052
|
+
id,
|
|
1053
|
+
value: computed,
|
|
1054
|
+
readOnly: true,
|
|
1055
|
+
disabled: disabled || readonly,
|
|
1056
|
+
state: rawErrors?.length ? "error" : "default",
|
|
1057
|
+
variant: "secondary"
|
|
1058
|
+
});
|
|
1028
1059
|
};
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
TextInput,
|
|
1046
|
-
{
|
|
1047
|
-
id,
|
|
1048
|
-
value: stringValue,
|
|
1049
|
-
onChange: (e) => {
|
|
1050
|
-
const v = e.target.value;
|
|
1051
|
-
onChange(shouldTrim ? v.trim() : v);
|
|
1052
|
-
},
|
|
1053
|
-
onBlur: () => onBlur(id, value),
|
|
1054
|
-
onFocus: () => onFocus(id, value),
|
|
1055
|
-
disabled: disabled || readonly,
|
|
1056
|
-
placeholder,
|
|
1057
|
-
type: schema.format === "email" ? "email" : "text",
|
|
1058
|
-
state: rawErrors?.length ? "error" : "default",
|
|
1059
|
-
variant: "secondary"
|
|
1060
|
-
}
|
|
1061
|
-
);
|
|
1060
|
+
//#endregion
|
|
1061
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/TextareaWidget.tsx
|
|
1062
|
+
const TextareaWidget = ({ id, value, onChange, onBlur, onFocus, disabled, readonly, placeholder, options, rawErrors }) => {
|
|
1063
|
+
const rows = options.rows ?? 5;
|
|
1064
|
+
return /* @__PURE__ */ jsx(Textarea, {
|
|
1065
|
+
id,
|
|
1066
|
+
value: value == null ? "" : String(value),
|
|
1067
|
+
onValueChange: onChange,
|
|
1068
|
+
onBlur: () => onBlur(id, value),
|
|
1069
|
+
onFocus: () => onFocus(id, value),
|
|
1070
|
+
disabled: disabled || readonly,
|
|
1071
|
+
placeholder,
|
|
1072
|
+
minRows: rows,
|
|
1073
|
+
state: rawErrors?.length ? "error" : "default",
|
|
1074
|
+
variant: "secondary"
|
|
1075
|
+
});
|
|
1062
1076
|
};
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1077
|
+
//#endregion
|
|
1078
|
+
//#region src/blocks/RjsfSchemaEditor/widgets/TextWidget.tsx
|
|
1079
|
+
const TextWidget = ({ id, value, onChange, onBlur, onFocus, disabled, readonly, placeholder, schema, options, rawErrors }) => {
|
|
1080
|
+
const stringValue = value == null ? "" : typeof value === "object" ? "" : String(value);
|
|
1081
|
+
const shouldTrim = !!options.trim;
|
|
1082
|
+
return /* @__PURE__ */ jsx(TextInput, {
|
|
1083
|
+
id,
|
|
1084
|
+
value: stringValue,
|
|
1085
|
+
onChange: (e) => {
|
|
1086
|
+
const v = e.target.value;
|
|
1087
|
+
onChange(shouldTrim ? v.trim() : v);
|
|
1088
|
+
},
|
|
1089
|
+
onBlur: () => onBlur(id, value),
|
|
1090
|
+
onFocus: () => onFocus(id, value),
|
|
1091
|
+
disabled: disabled || readonly,
|
|
1092
|
+
placeholder,
|
|
1093
|
+
type: schema.format === "email" ? "email" : "text",
|
|
1094
|
+
state: rawErrors?.length ? "error" : "default",
|
|
1095
|
+
variant: "secondary"
|
|
1096
|
+
});
|
|
1074
1097
|
};
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
URLWidget: TextWidget,
|
|
1087
|
-
DateWidget,
|
|
1088
|
-
DateTimeWidget: TextWidget,
|
|
1089
|
-
// Custom widgets mapped via uiSchema
|
|
1090
|
-
"code-editor": CodeEditorWidget,
|
|
1091
|
-
"dynamic-select": DynamicSelectWidget,
|
|
1092
|
-
"template-watch": TemplateWatchWidget,
|
|
1093
|
-
// Host-coupled widgets — injected by the host app
|
|
1094
|
-
"test-connection": StubWidget,
|
|
1095
|
-
"sync-action": StubWidget,
|
|
1096
|
-
"async-select": StubWidget,
|
|
1097
|
-
"async-multi-select": StubWidget
|
|
1098
|
+
//#endregion
|
|
1099
|
+
//#region src/blocks/RjsfSchemaEditor/registry.ts
|
|
1100
|
+
const StubWidget = () => null;
|
|
1101
|
+
const StubField = () => null;
|
|
1102
|
+
const defaultFields = {
|
|
1103
|
+
tableArray: TableArrayField,
|
|
1104
|
+
tabsObject: TabsObjectField,
|
|
1105
|
+
gridObject: GridObjectField,
|
|
1106
|
+
codeEditor: CodeEditorField,
|
|
1107
|
+
info: InfoField,
|
|
1108
|
+
sshForm: StubField
|
|
1098
1109
|
};
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1110
|
+
const defaultWidgets = {
|
|
1111
|
+
TextWidget,
|
|
1112
|
+
UpDownWidget: NumberWidget,
|
|
1113
|
+
TextareaWidget,
|
|
1114
|
+
PasswordWidget,
|
|
1115
|
+
SelectWidget,
|
|
1116
|
+
CheckboxWidget,
|
|
1117
|
+
RadioWidget,
|
|
1118
|
+
EmailWidget: TextWidget,
|
|
1119
|
+
URLWidget: TextWidget,
|
|
1120
|
+
DateWidget,
|
|
1121
|
+
DateTimeWidget: TextWidget,
|
|
1122
|
+
"code-editor": CodeEditorWidget,
|
|
1123
|
+
"dynamic-select": DynamicSelectWidget,
|
|
1124
|
+
"template-watch": TemplateWatchWidget,
|
|
1125
|
+
"test-connection": StubWidget,
|
|
1126
|
+
"sync-action": StubWidget,
|
|
1127
|
+
"async-select": StubWidget,
|
|
1128
|
+
"async-multi-select": StubWidget
|
|
1106
1129
|
};
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
const { $ref, ...overrides } = propSchema;
|
|
1115
|
-
return { ...resolved, ...overrides };
|
|
1130
|
+
const defaultTemplates = {
|
|
1131
|
+
FieldTemplate,
|
|
1132
|
+
ObjectFieldTemplate,
|
|
1133
|
+
DescriptionFieldTemplate,
|
|
1134
|
+
ArrayFieldTemplate,
|
|
1135
|
+
ArrayFieldItemTemplate,
|
|
1136
|
+
ErrorListTemplate
|
|
1116
1137
|
};
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
fieldUi["ui:widget"] = "hidden";
|
|
1133
|
-
}
|
|
1134
|
-
if (type === "array" && format === "table") {
|
|
1135
|
-
fieldUi["ui:field"] = "tableArray";
|
|
1136
|
-
}
|
|
1137
|
-
if (type === "array" && format === "checkbox") {
|
|
1138
|
-
fieldUi["ui:widget"] = "checkboxes";
|
|
1139
|
-
}
|
|
1140
|
-
if (format === "radio" && propSchema.enum) {
|
|
1141
|
-
fieldUi["ui:widget"] = "radio";
|
|
1142
|
-
}
|
|
1143
|
-
if (type === "object" && (format === "tabs" || format === "tabs-top" || format === "categories")) {
|
|
1144
|
-
fieldUi["ui:field"] = "tabsObject";
|
|
1145
|
-
}
|
|
1146
|
-
if (type === "object" && (format === "grid" || format === "grid-strict")) {
|
|
1147
|
-
fieldUi["ui:field"] = "gridObject";
|
|
1148
|
-
}
|
|
1149
|
-
if (format === "info") {
|
|
1150
|
-
fieldUi["ui:field"] = "info";
|
|
1151
|
-
if (options?.alert_type) {
|
|
1152
|
-
fieldUi["ui:options"] = {
|
|
1153
|
-
...fieldUi["ui:options"],
|
|
1154
|
-
alertType: options.alert_type
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
if (type === "button" && format === "test-connection") {
|
|
1159
|
-
fieldUi["ui:widget"] = "test-connection";
|
|
1160
|
-
fieldUi["ui:options"] = options ?? {};
|
|
1161
|
-
} else if (type === "button" && format === "sync-action") {
|
|
1162
|
-
fieldUi["ui:widget"] = "sync-action";
|
|
1163
|
-
fieldUi["ui:options"] = options ?? {};
|
|
1164
|
-
} else if ((type === "string" || type === "object") && format === "editor") {
|
|
1165
|
-
if (type === "object") {
|
|
1166
|
-
fieldUi["ui:field"] = "codeEditor";
|
|
1167
|
-
} else {
|
|
1168
|
-
fieldUi["ui:widget"] = "code-editor";
|
|
1169
|
-
}
|
|
1170
|
-
fieldUi["ui:options"] = {
|
|
1171
|
-
editor: options?.editor ?? {},
|
|
1172
|
-
// A JSON editor stores parsed keys, so `#` prefixes really are encrypted here.
|
|
1173
|
-
// Fields whose JSON is not Keboola configuration (a query filter tree, a payload
|
|
1174
|
-
// template) opt out with `encryption_hint: false` — encrypting a key there would
|
|
1175
|
-
// hand the component ciphertext it cannot use.
|
|
1176
|
-
encryptionHint: options?.encryption_hint !== false
|
|
1177
|
-
};
|
|
1178
|
-
} else if (type === "object" && format === "ssh-editor") {
|
|
1179
|
-
fieldUi["ui:field"] = "sshForm";
|
|
1180
|
-
fieldUi["ui:options"] = { only_keys: !!options?.only_keys };
|
|
1181
|
-
} else if (type === "string" && format === "password") {
|
|
1182
|
-
if (!hasProtectedDefaultBranch) {
|
|
1183
|
-
fieldUi["ui:widget"] = "password";
|
|
1184
|
-
}
|
|
1185
|
-
} else if (type === "string" && format === "textarea") {
|
|
1186
|
-
fieldUi["ui:widget"] = "textarea";
|
|
1187
|
-
if (options?.input_height) {
|
|
1188
|
-
fieldUi["ui:options"] = {
|
|
1189
|
-
...fieldUi["ui:options"],
|
|
1190
|
-
rows: parseInputHeightToRows(String(options.input_height))
|
|
1191
|
-
};
|
|
1192
|
-
}
|
|
1193
|
-
} else if (type === "string" && format === "trim") {
|
|
1194
|
-
fieldUi["ui:options"] = {
|
|
1195
|
-
...fieldUi["ui:options"],
|
|
1196
|
-
trim: true
|
|
1197
|
-
};
|
|
1198
|
-
} else if (isDynamicSelectSchema(propSchema)) {
|
|
1199
|
-
fieldUi["ui:widget"] = "dynamic-select";
|
|
1200
|
-
fieldUi["ui:options"] = {
|
|
1201
|
-
...fieldUi["ui:options"],
|
|
1202
|
-
watch: propSchema.watch,
|
|
1203
|
-
enumSource: propSchema.enumSource,
|
|
1204
|
-
tags: !!options?.tags
|
|
1205
|
-
};
|
|
1206
|
-
} else if (isMultiSelectSchema(propSchema)) {
|
|
1207
|
-
const items = propSchema.items;
|
|
1208
|
-
const itemsOptions = items?.options;
|
|
1209
|
-
fieldUi["ui:widget"] = "async-multi-select";
|
|
1210
|
-
fieldUi["ui:options"] = {
|
|
1211
|
-
async: options?.async ?? itemsOptions?.async ?? null,
|
|
1212
|
-
creatable: !!options?.creatable || !!options?.tags,
|
|
1213
|
-
placeholder: String(
|
|
1214
|
-
options?.inputAttributes?.placeholder ?? ""
|
|
1215
|
-
),
|
|
1216
|
-
// Pass dynamic source from items for enumSource/watch multi-selects
|
|
1217
|
-
...items?.watch && { watch: items.watch },
|
|
1218
|
-
...items?.enumSource && { enumSource: items.enumSource }
|
|
1219
|
-
};
|
|
1220
|
-
} else if (isAsyncSelectSchema(propSchema)) {
|
|
1221
|
-
fieldUi["ui:widget"] = "async-select";
|
|
1222
|
-
fieldUi["ui:options"] = {
|
|
1223
|
-
async: options?.async ?? null,
|
|
1224
|
-
creatable: !!options?.creatable,
|
|
1225
|
-
placeholder: String(
|
|
1226
|
-
options?.inputAttributes?.placeholder ?? ""
|
|
1227
|
-
)
|
|
1228
|
-
};
|
|
1229
|
-
}
|
|
1230
|
-
if (isTemplateWatchSchema(propSchema)) {
|
|
1231
|
-
fieldUi["ui:widget"] = "template-watch";
|
|
1232
|
-
fieldUi["ui:options"] = {
|
|
1233
|
-
...fieldUi["ui:options"],
|
|
1234
|
-
watch: propSchema.watch,
|
|
1235
|
-
template: propSchema.template
|
|
1236
|
-
};
|
|
1237
|
-
}
|
|
1238
|
-
if (type === "boolean" && options?.enum_titles) {
|
|
1239
|
-
fieldUi["ui:widget"] = "select";
|
|
1240
|
-
}
|
|
1241
|
-
if (options?.collapsed !== void 0) {
|
|
1242
|
-
fieldUi["ui:options"] = {
|
|
1243
|
-
...fieldUi["ui:options"],
|
|
1244
|
-
collapsed: !!options.collapsed
|
|
1245
|
-
};
|
|
1246
|
-
}
|
|
1247
|
-
if (options?.disable_collapse) {
|
|
1248
|
-
fieldUi["ui:options"] = {
|
|
1249
|
-
...fieldUi["ui:options"],
|
|
1250
|
-
disableCollapse: true
|
|
1251
|
-
};
|
|
1252
|
-
}
|
|
1253
|
-
if (options?.dependencies) {
|
|
1254
|
-
fieldUi["ui:options"] = {
|
|
1255
|
-
...fieldUi["ui:options"],
|
|
1256
|
-
dependencies: options.dependencies
|
|
1257
|
-
};
|
|
1258
|
-
}
|
|
1259
|
-
if (options?.grid_break) {
|
|
1260
|
-
fieldUi["ui:options"] = {
|
|
1261
|
-
...fieldUi["ui:options"],
|
|
1262
|
-
gridBreak: true
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
if (options?.enabled === false) {
|
|
1266
|
-
fieldUi["ui:disabled"] = true;
|
|
1267
|
-
}
|
|
1268
|
-
const globalValue = globalConfig?.[key];
|
|
1269
|
-
if (globalValue !== void 0) {
|
|
1270
|
-
if (typeof globalValue !== "object" || globalValue === null || Array.isArray(globalValue)) {
|
|
1271
|
-
fieldUi["ui:disabled"] = true;
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
if (options?.tooltip) {
|
|
1275
|
-
fieldUi["ui:help"] = String(options.tooltip);
|
|
1276
|
-
}
|
|
1277
|
-
if (options?.documentation?.link) {
|
|
1278
|
-
fieldUi["ui:options"] = {
|
|
1279
|
-
...fieldUi["ui:options"],
|
|
1280
|
-
documentation: options?.documentation
|
|
1281
|
-
};
|
|
1282
|
-
}
|
|
1283
|
-
if (options?.inputAttributes?.placeholder && !fieldUi["ui:widget"]) {
|
|
1284
|
-
fieldUi["ui:placeholder"] = String(
|
|
1285
|
-
options?.inputAttributes?.placeholder
|
|
1286
|
-
);
|
|
1287
|
-
}
|
|
1288
|
-
if (options?.enum_titles && propSchema.enum) {
|
|
1289
|
-
fieldUi["ui:options"] = {
|
|
1290
|
-
...fieldUi["ui:options"],
|
|
1291
|
-
enumNames: options.enum_titles
|
|
1292
|
-
};
|
|
1293
|
-
}
|
|
1294
|
-
if (type === "array") {
|
|
1295
|
-
const arrayOpts = {};
|
|
1296
|
-
if (options?.disable_array_add) arrayOpts.addable = false;
|
|
1297
|
-
if (options?.disable_array_delete) arrayOpts.removable = false;
|
|
1298
|
-
if (options?.disable_array_reorder) arrayOpts.orderable = false;
|
|
1299
|
-
if (Object.keys(arrayOpts).length > 0) {
|
|
1300
|
-
fieldUi["ui:options"] = {
|
|
1301
|
-
...fieldUi["ui:options"],
|
|
1302
|
-
...arrayOpts
|
|
1303
|
-
};
|
|
1304
|
-
}
|
|
1305
|
-
const itemsEnumTitles = propSchema.items?.options?.enum_titles;
|
|
1306
|
-
if (Array.isArray(itemsEnumTitles)) {
|
|
1307
|
-
fieldUi.items = { "ui:options": { enumNames: itemsEnumTitles } };
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
if (type === "object" && propSchema.properties) {
|
|
1311
|
-
const nestedGlobal = globalValue && typeof globalValue === "object" && !Array.isArray(globalValue) ? globalValue : void 0;
|
|
1312
|
-
const nested = generateUiSchema(
|
|
1313
|
-
propSchema,
|
|
1314
|
-
readOnly,
|
|
1315
|
-
defs,
|
|
1316
|
-
nestedGlobal,
|
|
1317
|
-
hasProtectedDefaultBranch
|
|
1318
|
-
);
|
|
1319
|
-
Object.assign(fieldUi, nested);
|
|
1320
|
-
}
|
|
1321
|
-
if (type === "array" && propSchema.items?.properties) {
|
|
1322
|
-
const itemsUi = generateUiSchema(
|
|
1323
|
-
propSchema.items,
|
|
1324
|
-
readOnly,
|
|
1325
|
-
defs,
|
|
1326
|
-
void 0,
|
|
1327
|
-
hasProtectedDefaultBranch
|
|
1328
|
-
);
|
|
1329
|
-
if (Object.keys(itemsUi).length > 0) {
|
|
1330
|
-
fieldUi.items = itemsUi;
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
if ((propSchema.enumSource || propSchema.watch) && !fieldUi["ui:widget"]) {
|
|
1334
|
-
console.warn(
|
|
1335
|
-
`[RJSF] Property "${key}" uses enumSource/watch which is not yet supported. It will render as a plain input.`
|
|
1336
|
-
);
|
|
1337
|
-
}
|
|
1338
|
-
if (Object.keys(fieldUi).length > 0) {
|
|
1339
|
-
uiSchema[key] = fieldUi;
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
const orderedEntries = Object.entries(properties).filter(([, prop]) => prop.propertyOrder !== void 0).sort(
|
|
1343
|
-
([, a], [, b]) => (a.propertyOrder ?? Number.MAX_SAFE_INTEGER) - (b.propertyOrder ?? Number.MAX_SAFE_INTEGER)
|
|
1344
|
-
);
|
|
1345
|
-
if (orderedEntries.length > 0) {
|
|
1346
|
-
uiSchema["ui:order"] = [...orderedEntries.map(([key]) => key), "*"];
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
for (const combiner of ["allOf", "anyOf", "oneOf"]) {
|
|
1350
|
-
const schemas = schema[combiner];
|
|
1351
|
-
if (schemas) {
|
|
1352
|
-
for (const subSchema of schemas) {
|
|
1353
|
-
const subUi = generateUiSchema(
|
|
1354
|
-
subSchema,
|
|
1355
|
-
readOnly,
|
|
1356
|
-
void 0,
|
|
1357
|
-
void 0,
|
|
1358
|
-
hasProtectedDefaultBranch
|
|
1359
|
-
);
|
|
1360
|
-
Object.assign(uiSchema, subUi);
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
for (const branch of ["if", "then", "else"]) {
|
|
1365
|
-
const branchSchema = schema[branch];
|
|
1366
|
-
if (branchSchema?.properties) {
|
|
1367
|
-
const branchUi = generateUiSchema(
|
|
1368
|
-
branchSchema,
|
|
1369
|
-
readOnly,
|
|
1370
|
-
void 0,
|
|
1371
|
-
void 0,
|
|
1372
|
-
hasProtectedDefaultBranch
|
|
1373
|
-
);
|
|
1374
|
-
Object.assign(uiSchema, branchUi);
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
return uiSchema;
|
|
1138
|
+
//#endregion
|
|
1139
|
+
//#region src/blocks/RjsfSchemaEditor/schemaUtils.ts
|
|
1140
|
+
/**
|
|
1141
|
+
* Resolves a $ref reference against the schema definitions, merging any
|
|
1142
|
+
* sibling overrides (title, options, etc.) on top of the resolved schema.
|
|
1143
|
+
*/
|
|
1144
|
+
const resolveRef = (propSchema, definitions) => {
|
|
1145
|
+
if (!propSchema.$ref || !definitions) return propSchema;
|
|
1146
|
+
const resolved = definitions[String(propSchema.$ref).replace("#/definitions/", "")];
|
|
1147
|
+
if (!resolved) return propSchema;
|
|
1148
|
+
const { $ref, ...overrides } = propSchema;
|
|
1149
|
+
return {
|
|
1150
|
+
...resolved,
|
|
1151
|
+
...overrides
|
|
1152
|
+
};
|
|
1378
1153
|
};
|
|
1379
|
-
|
|
1380
|
-
|
|
1154
|
+
/**
|
|
1155
|
+
* Walks a JSON Schema and generates a RJSF uiSchema based on custom `format` and `options` properties.
|
|
1156
|
+
* This maps the legacy @json-editor/json-editor conventions to RJSF widget references.
|
|
1157
|
+
*/
|
|
1158
|
+
const generateUiSchema = (schema, readOnly = false, definitions, globalConfig, hasProtectedDefaultBranch = false) => {
|
|
1159
|
+
const uiSchema = {};
|
|
1160
|
+
const defs = definitions ?? schema.definitions;
|
|
1161
|
+
if (readOnly) uiSchema["ui:disabled"] = true;
|
|
1162
|
+
const properties = schema.properties;
|
|
1163
|
+
if (!properties) {} else {
|
|
1164
|
+
for (const [key, rawPropSchema] of Object.entries(properties)) {
|
|
1165
|
+
const propSchema = resolveRef(rawPropSchema, defs);
|
|
1166
|
+
const format = propSchema.format;
|
|
1167
|
+
const type = propSchema.type ?? (propSchema.properties ? "object" : void 0);
|
|
1168
|
+
const options = propSchema.options;
|
|
1169
|
+
const fieldUi = {};
|
|
1170
|
+
if (options?.hidden) fieldUi["ui:widget"] = "hidden";
|
|
1171
|
+
if (type === "array" && format === "table") fieldUi["ui:field"] = "tableArray";
|
|
1172
|
+
if (type === "array" && format === "checkbox") fieldUi["ui:widget"] = "checkboxes";
|
|
1173
|
+
if (format === "radio" && propSchema.enum) fieldUi["ui:widget"] = "radio";
|
|
1174
|
+
if (type === "object" && (format === "tabs" || format === "tabs-top" || format === "categories")) fieldUi["ui:field"] = "tabsObject";
|
|
1175
|
+
if (type === "object" && (format === "grid" || format === "grid-strict")) fieldUi["ui:field"] = "gridObject";
|
|
1176
|
+
if (format === "info") {
|
|
1177
|
+
fieldUi["ui:field"] = "info";
|
|
1178
|
+
if (options?.alert_type) fieldUi["ui:options"] = {
|
|
1179
|
+
...fieldUi["ui:options"],
|
|
1180
|
+
alertType: options.alert_type
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
if (type === "button" && format === "test-connection") {
|
|
1184
|
+
fieldUi["ui:widget"] = "test-connection";
|
|
1185
|
+
fieldUi["ui:options"] = options ?? {};
|
|
1186
|
+
} else if (type === "button" && format === "sync-action") {
|
|
1187
|
+
fieldUi["ui:widget"] = "sync-action";
|
|
1188
|
+
fieldUi["ui:options"] = options ?? {};
|
|
1189
|
+
} else if ((type === "string" || type === "object") && format === "editor") {
|
|
1190
|
+
if (type === "object") fieldUi["ui:field"] = "codeEditor";
|
|
1191
|
+
else fieldUi["ui:widget"] = "code-editor";
|
|
1192
|
+
fieldUi["ui:options"] = {
|
|
1193
|
+
editor: options?.editor ?? {},
|
|
1194
|
+
encryptionHint: options?.encryption_hint !== false
|
|
1195
|
+
};
|
|
1196
|
+
} else if (type === "object" && format === "ssh-editor") {
|
|
1197
|
+
fieldUi["ui:field"] = "sshForm";
|
|
1198
|
+
fieldUi["ui:options"] = { only_keys: !!options?.only_keys };
|
|
1199
|
+
} else if (type === "string" && format === "password") {
|
|
1200
|
+
if (!hasProtectedDefaultBranch) fieldUi["ui:widget"] = "password";
|
|
1201
|
+
} else if (type === "string" && format === "textarea") {
|
|
1202
|
+
fieldUi["ui:widget"] = "textarea";
|
|
1203
|
+
if (options?.input_height) fieldUi["ui:options"] = {
|
|
1204
|
+
...fieldUi["ui:options"],
|
|
1205
|
+
rows: parseInputHeightToRows(String(options.input_height))
|
|
1206
|
+
};
|
|
1207
|
+
} else if (type === "string" && format === "trim") fieldUi["ui:options"] = {
|
|
1208
|
+
...fieldUi["ui:options"],
|
|
1209
|
+
trim: true
|
|
1210
|
+
};
|
|
1211
|
+
else if (isDynamicSelectSchema(propSchema)) {
|
|
1212
|
+
fieldUi["ui:widget"] = "dynamic-select";
|
|
1213
|
+
fieldUi["ui:options"] = {
|
|
1214
|
+
...fieldUi["ui:options"],
|
|
1215
|
+
watch: propSchema.watch,
|
|
1216
|
+
enumSource: propSchema.enumSource,
|
|
1217
|
+
tags: !!options?.tags
|
|
1218
|
+
};
|
|
1219
|
+
} else if (isMultiSelectSchema(propSchema)) {
|
|
1220
|
+
const items = propSchema.items;
|
|
1221
|
+
const itemsOptions = items?.options;
|
|
1222
|
+
fieldUi["ui:widget"] = "async-multi-select";
|
|
1223
|
+
fieldUi["ui:options"] = {
|
|
1224
|
+
async: options?.async ?? itemsOptions?.async ?? null,
|
|
1225
|
+
creatable: !!options?.creatable || !!options?.tags,
|
|
1226
|
+
placeholder: String((options?.inputAttributes)?.placeholder ?? ""),
|
|
1227
|
+
...items?.watch && { watch: items.watch },
|
|
1228
|
+
...items?.enumSource && { enumSource: items.enumSource }
|
|
1229
|
+
};
|
|
1230
|
+
} else if (isAsyncSelectSchema(propSchema)) {
|
|
1231
|
+
fieldUi["ui:widget"] = "async-select";
|
|
1232
|
+
fieldUi["ui:options"] = {
|
|
1233
|
+
async: options?.async ?? null,
|
|
1234
|
+
creatable: !!options?.creatable,
|
|
1235
|
+
placeholder: String((options?.inputAttributes)?.placeholder ?? "")
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
if (isTemplateWatchSchema(propSchema)) {
|
|
1239
|
+
fieldUi["ui:widget"] = "template-watch";
|
|
1240
|
+
fieldUi["ui:options"] = {
|
|
1241
|
+
...fieldUi["ui:options"],
|
|
1242
|
+
watch: propSchema.watch,
|
|
1243
|
+
template: propSchema.template,
|
|
1244
|
+
hidden: !!options?.hidden || isContainerType(propSchema)
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
if (type === "boolean" && options?.enum_titles) fieldUi["ui:widget"] = "select";
|
|
1248
|
+
if (options?.collapsed !== void 0) fieldUi["ui:options"] = {
|
|
1249
|
+
...fieldUi["ui:options"],
|
|
1250
|
+
collapsed: !!options.collapsed
|
|
1251
|
+
};
|
|
1252
|
+
if (options?.disable_collapse) fieldUi["ui:options"] = {
|
|
1253
|
+
...fieldUi["ui:options"],
|
|
1254
|
+
disableCollapse: true
|
|
1255
|
+
};
|
|
1256
|
+
if (options?.dependencies) fieldUi["ui:options"] = {
|
|
1257
|
+
...fieldUi["ui:options"],
|
|
1258
|
+
dependencies: options.dependencies
|
|
1259
|
+
};
|
|
1260
|
+
if (options?.grid_break) fieldUi["ui:options"] = {
|
|
1261
|
+
...fieldUi["ui:options"],
|
|
1262
|
+
gridBreak: true
|
|
1263
|
+
};
|
|
1264
|
+
if (options?.enabled === false) fieldUi["ui:disabled"] = true;
|
|
1265
|
+
const globalValue = globalConfig?.[key];
|
|
1266
|
+
if (globalValue !== void 0) {
|
|
1267
|
+
if (typeof globalValue !== "object" || globalValue === null || Array.isArray(globalValue)) fieldUi["ui:disabled"] = true;
|
|
1268
|
+
}
|
|
1269
|
+
if (options?.tooltip) fieldUi["ui:help"] = String(options.tooltip);
|
|
1270
|
+
if ((options?.documentation)?.link) fieldUi["ui:options"] = {
|
|
1271
|
+
...fieldUi["ui:options"],
|
|
1272
|
+
documentation: options?.documentation
|
|
1273
|
+
};
|
|
1274
|
+
if ((options?.inputAttributes)?.placeholder && !fieldUi["ui:widget"]) fieldUi["ui:placeholder"] = String((options?.inputAttributes)?.placeholder);
|
|
1275
|
+
if (options?.enum_titles && propSchema.enum) fieldUi["ui:options"] = {
|
|
1276
|
+
...fieldUi["ui:options"],
|
|
1277
|
+
enumNames: options.enum_titles
|
|
1278
|
+
};
|
|
1279
|
+
if (type === "array") {
|
|
1280
|
+
const arrayOpts = {};
|
|
1281
|
+
if (options?.disable_array_add) arrayOpts.addable = false;
|
|
1282
|
+
if (options?.disable_array_delete) arrayOpts.removable = false;
|
|
1283
|
+
if (options?.disable_array_reorder) arrayOpts.orderable = false;
|
|
1284
|
+
if (Object.keys(arrayOpts).length > 0) fieldUi["ui:options"] = {
|
|
1285
|
+
...fieldUi["ui:options"],
|
|
1286
|
+
...arrayOpts
|
|
1287
|
+
};
|
|
1288
|
+
const itemsEnumTitles = (propSchema.items?.options)?.enum_titles;
|
|
1289
|
+
if (Array.isArray(itemsEnumTitles)) fieldUi.items = { "ui:options": { enumNames: itemsEnumTitles } };
|
|
1290
|
+
}
|
|
1291
|
+
if (type === "object" && propSchema.properties) {
|
|
1292
|
+
const nested = generateUiSchema(propSchema, readOnly, defs, globalValue && typeof globalValue === "object" && !Array.isArray(globalValue) ? globalValue : void 0, hasProtectedDefaultBranch);
|
|
1293
|
+
Object.assign(fieldUi, nested);
|
|
1294
|
+
}
|
|
1295
|
+
if (type === "array" && propSchema.items?.properties) {
|
|
1296
|
+
const itemsUi = generateUiSchema(propSchema.items, readOnly, defs, void 0, hasProtectedDefaultBranch);
|
|
1297
|
+
if (Object.keys(itemsUi).length > 0) fieldUi.items = itemsUi;
|
|
1298
|
+
}
|
|
1299
|
+
if ((propSchema.enumSource || propSchema.watch) && !fieldUi["ui:widget"]) console.warn(`[RJSF] Property "${key}" uses enumSource/watch which is not yet supported. It will render as a plain input.`);
|
|
1300
|
+
if (Object.keys(fieldUi).length > 0) uiSchema[key] = fieldUi;
|
|
1301
|
+
}
|
|
1302
|
+
const orderedEntries = Object.entries(properties).filter(([, prop]) => prop.propertyOrder !== void 0).sort(([, a], [, b]) => (a.propertyOrder ?? Number.MAX_SAFE_INTEGER) - (b.propertyOrder ?? Number.MAX_SAFE_INTEGER));
|
|
1303
|
+
if (orderedEntries.length > 0) uiSchema["ui:order"] = [...orderedEntries.map(([key]) => key), "*"];
|
|
1304
|
+
}
|
|
1305
|
+
for (const combiner of [
|
|
1306
|
+
"allOf",
|
|
1307
|
+
"anyOf",
|
|
1308
|
+
"oneOf"
|
|
1309
|
+
]) {
|
|
1310
|
+
const schemas = schema[combiner];
|
|
1311
|
+
if (schemas) for (const subSchema of schemas) {
|
|
1312
|
+
const subUi = generateUiSchema(subSchema, readOnly, void 0, void 0, hasProtectedDefaultBranch);
|
|
1313
|
+
Object.assign(uiSchema, subUi);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
for (const branch of [
|
|
1317
|
+
"if",
|
|
1318
|
+
"then",
|
|
1319
|
+
"else"
|
|
1320
|
+
]) {
|
|
1321
|
+
const branchSchema = schema[branch];
|
|
1322
|
+
if (branchSchema?.properties) {
|
|
1323
|
+
const branchUi = generateUiSchema(branchSchema, readOnly, void 0, void 0, hasProtectedDefaultBranch);
|
|
1324
|
+
Object.assign(uiSchema, branchUi);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
return uiSchema;
|
|
1381
1328
|
};
|
|
1382
|
-
|
|
1383
|
-
|
|
1329
|
+
const isDynamicSelectSchema = (schema) => {
|
|
1330
|
+
return !!(schema.enumSource && schema.watch && schema.type === "string");
|
|
1384
1331
|
};
|
|
1385
|
-
|
|
1386
|
-
|
|
1332
|
+
const isTemplateWatchSchema = (schema) => {
|
|
1333
|
+
return !!(schema.template && schema.watch && !schema.enumSource);
|
|
1387
1334
|
};
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1335
|
+
/**
|
|
1336
|
+
* Whether a schema describes an object or an array.
|
|
1337
|
+
*
|
|
1338
|
+
* - `properties` or `items` imply the type even when json-editor omits it.
|
|
1339
|
+
* - `type` may be a union, e.g. `['object', 'null']`.
|
|
1340
|
+
*/
|
|
1341
|
+
const isContainerType = (schema) => {
|
|
1342
|
+
if (schema.properties || schema.items) return true;
|
|
1343
|
+
const { type } = schema;
|
|
1344
|
+
if (Array.isArray(type)) return type.includes("object") || type.includes("array");
|
|
1345
|
+
return type === "object" || type === "array";
|
|
1391
1346
|
};
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
if (Number.isNaN(px) || px <= 0) return 5;
|
|
1395
|
-
return Math.max(2, Math.round(px / 20));
|
|
1347
|
+
const isAsyncSelectSchema = (schema) => {
|
|
1348
|
+
return !!(schema.options?.async || schema.options?.creatable);
|
|
1396
1349
|
};
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1350
|
+
const isMultiSelectSchema = (schema) => {
|
|
1351
|
+
const items = schema.items;
|
|
1352
|
+
return !!(items && schema.uniqueItems && schema.type === "array" && schema.format !== "checkbox" && !Array.isArray(items) && [
|
|
1353
|
+
"string",
|
|
1354
|
+
"number",
|
|
1355
|
+
"integer"
|
|
1356
|
+
].includes(items.type) && (items.enum || items.enumSource || schema.options?.tags));
|
|
1357
|
+
};
|
|
1358
|
+
/**
|
|
1359
|
+
* Cleans up non-standard properties from a schema before passing to RJSF/AJV.
|
|
1360
|
+
* RJSF is strict about unknown keywords, and our schemas contain json-editor-specific
|
|
1361
|
+
* extensions (format: 'button', options, etc.).
|
|
1362
|
+
*/
|
|
1363
|
+
/** Convert CSS height like "100px" to approximate textarea rows */
|
|
1364
|
+
const parseInputHeightToRows = (height) => {
|
|
1365
|
+
const px = parseInt(height, 10);
|
|
1366
|
+
if (Number.isNaN(px) || px <= 0) return 5;
|
|
1367
|
+
return Math.max(2, Math.round(px / 20));
|
|
1368
|
+
};
|
|
1369
|
+
const CUSTOM_FORMATS = [
|
|
1370
|
+
"table",
|
|
1371
|
+
"editor",
|
|
1372
|
+
"ssh-editor",
|
|
1373
|
+
"trim",
|
|
1374
|
+
"textarea",
|
|
1375
|
+
"grid",
|
|
1376
|
+
"grid-strict",
|
|
1377
|
+
"tabs",
|
|
1378
|
+
"tabs-top",
|
|
1379
|
+
"categories",
|
|
1380
|
+
"info",
|
|
1381
|
+
"select",
|
|
1382
|
+
"checkbox",
|
|
1383
|
+
"json",
|
|
1384
|
+
"button",
|
|
1385
|
+
"radio"
|
|
1414
1386
|
];
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
for (const combiner of ["allOf", "anyOf", "oneOf"]) {
|
|
1483
|
-
const schemas = cleaned[combiner];
|
|
1484
|
-
if (schemas) {
|
|
1485
|
-
cleaned[combiner] = schemas.map((s) => sanitizeSchema(s, defs));
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
for (const branch of ["if", "then", "else"]) {
|
|
1489
|
-
const branchSchema = cleaned[branch];
|
|
1490
|
-
if (branchSchema) {
|
|
1491
|
-
cleaned[branch] = sanitizeSchema(branchSchema, defs, true);
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
if (cleaned.items && typeof cleaned.items === "object" && !Array.isArray(cleaned.items)) {
|
|
1495
|
-
cleaned.items = sanitizeSchema(cleaned.items, defs);
|
|
1496
|
-
}
|
|
1497
|
-
return cleaned;
|
|
1387
|
+
const sanitizeSchema = (schema, definitions, isConditionalBranch = false) => {
|
|
1388
|
+
const cleaned = { ...schema };
|
|
1389
|
+
const defs = definitions ?? cleaned.definitions;
|
|
1390
|
+
if (Array.isArray(cleaned.enum) && cleaned.enum.length === 0) delete cleaned.enum;
|
|
1391
|
+
if (Array.isArray(cleaned.enum) && cleaned.enum.length > 0 && (cleaned.type === "string" || cleaned.type === "integer" || cleaned.type === "number")) {
|
|
1392
|
+
if (cleaned.default === void 0) cleaned.default = cleaned.enum[0];
|
|
1393
|
+
else if (!cleaned.enum.includes(cleaned.default)) delete cleaned.default;
|
|
1394
|
+
}
|
|
1395
|
+
if (cleaned.properties && !cleaned.type) cleaned.type = "object";
|
|
1396
|
+
if (cleaned.required === true) delete cleaned.required;
|
|
1397
|
+
if (CUSTOM_FORMATS.includes(cleaned.format)) delete cleaned.format;
|
|
1398
|
+
const properties = cleaned.properties;
|
|
1399
|
+
if (properties) {
|
|
1400
|
+
const sanitizedProps = {};
|
|
1401
|
+
const required = cleaned.required ?? [];
|
|
1402
|
+
const sanitizedRequired = [];
|
|
1403
|
+
for (const [key, rawPropSchema] of Object.entries(properties)) {
|
|
1404
|
+
const propSchema = resolveRef(rawPropSchema, defs);
|
|
1405
|
+
if (propSchema.type === "button") {
|
|
1406
|
+
sanitizedProps[key] = {
|
|
1407
|
+
type: "string",
|
|
1408
|
+
title: propSchema.title,
|
|
1409
|
+
...propSchema.propertyOrder !== void 0 && { propertyOrder: propSchema.propertyOrder },
|
|
1410
|
+
...propSchema.description !== void 0 && { description: propSchema.description }
|
|
1411
|
+
};
|
|
1412
|
+
continue;
|
|
1413
|
+
}
|
|
1414
|
+
if (propSchema.type === "boolean" && propSchema.options?.enum_titles) {
|
|
1415
|
+
const titles = propSchema.options.enum_titles;
|
|
1416
|
+
const sanitized = sanitizeSchema(propSchema, defs);
|
|
1417
|
+
sanitized.oneOf = (propSchema.enum ?? [true, false]).map((value, index) => ({
|
|
1418
|
+
const: value,
|
|
1419
|
+
title: titles[index] ?? (value ? "Yes" : "No")
|
|
1420
|
+
}));
|
|
1421
|
+
sanitizedProps[key] = sanitized;
|
|
1422
|
+
if (required.includes(key) || propSchema.required === true) {
|
|
1423
|
+
if (!sanitizedRequired.includes(key)) sanitizedRequired.push(key);
|
|
1424
|
+
}
|
|
1425
|
+
continue;
|
|
1426
|
+
}
|
|
1427
|
+
sanitizedProps[key] = sanitizeSchema(propSchema, defs);
|
|
1428
|
+
if (required.includes(key) || propSchema.required === true) {
|
|
1429
|
+
if (!sanitizedRequired.includes(key)) sanitizedRequired.push(key);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
cleaned.properties = sanitizedProps;
|
|
1433
|
+
if (sanitizedRequired.length > 0) cleaned.required = sanitizedRequired;
|
|
1434
|
+
if (!isConditionalBranch && cleaned.additionalProperties === void 0 && !cleaned.if) cleaned.additionalProperties = false;
|
|
1435
|
+
}
|
|
1436
|
+
for (const combiner of [
|
|
1437
|
+
"allOf",
|
|
1438
|
+
"anyOf",
|
|
1439
|
+
"oneOf"
|
|
1440
|
+
]) {
|
|
1441
|
+
const schemas = cleaned[combiner];
|
|
1442
|
+
if (schemas) cleaned[combiner] = schemas.map((s) => sanitizeSchema(s, defs));
|
|
1443
|
+
}
|
|
1444
|
+
for (const branch of [
|
|
1445
|
+
"if",
|
|
1446
|
+
"then",
|
|
1447
|
+
"else"
|
|
1448
|
+
]) {
|
|
1449
|
+
const branchSchema = cleaned[branch];
|
|
1450
|
+
if (branchSchema) cleaned[branch] = sanitizeSchema(branchSchema, defs, true);
|
|
1451
|
+
}
|
|
1452
|
+
if (cleaned.items && typeof cleaned.items === "object" && !Array.isArray(cleaned.items)) cleaned.items = sanitizeSchema(cleaned.items, defs);
|
|
1453
|
+
return cleaned;
|
|
1498
1454
|
};
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1455
|
+
//#endregion
|
|
1456
|
+
//#region src/blocks/RjsfSchemaEditor/RjsfSchemaEditor.tsx
|
|
1457
|
+
const defaultRenderMarkdown = (source) => source;
|
|
1458
|
+
/**
|
|
1459
|
+
* Produces a canonical JSON string with sorted keys at every level.
|
|
1460
|
+
* This ensures two objects with the same data but different key ordering
|
|
1461
|
+
* produce the same string. Also normalizes undefined → omitted (via JSON.stringify).
|
|
1462
|
+
*/
|
|
1463
|
+
const stableStringify = (obj) => JSON.stringify(obj, (_key, val) => {
|
|
1464
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
1465
|
+
const sorted = {};
|
|
1466
|
+
for (const key of Object.keys(val).sort()) sorted[key] = val[key];
|
|
1467
|
+
return sorted;
|
|
1468
|
+
}
|
|
1469
|
+
return val;
|
|
1509
1470
|
});
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
schema: schemaJs,
|
|
1634
|
-
initialFormData: initialDataRef.current,
|
|
1635
|
-
uiSchema,
|
|
1636
|
-
validator,
|
|
1637
|
-
onChange: handleChange,
|
|
1638
|
-
widgets: mergedWidgets,
|
|
1639
|
-
fields: mergedFields,
|
|
1640
|
-
templates: defaultTemplates,
|
|
1641
|
-
formContext,
|
|
1642
|
-
disabled: readOnly,
|
|
1643
|
-
liveValidate: hasValidated ? "onBlur" : void 0,
|
|
1644
|
-
showErrorList: false,
|
|
1645
|
-
noHtml5Validate: true,
|
|
1646
|
-
tagName: inForm ? "div" : "form",
|
|
1647
|
-
children: /* @__PURE__ */ jsx(Fragment, {})
|
|
1648
|
-
},
|
|
1649
|
-
formKey
|
|
1650
|
-
) }) }) });
|
|
1471
|
+
const RjsfSchemaEditor = ({ schema, value, onChange, readOnly, inForm, globalConfig, onRegisterValidate, widgets, fields, renderMarkdown, hasProtectedDefaultBranch = false }) => {
|
|
1472
|
+
const schemaJs = useMemo(() => sanitizeSchema(schema), [schema]);
|
|
1473
|
+
const uiSchema = useMemo(() => generateUiSchema(schema, readOnly, void 0, globalConfig ?? void 0, hasProtectedDefaultBranch), [
|
|
1474
|
+
schema,
|
|
1475
|
+
readOnly,
|
|
1476
|
+
globalConfig,
|
|
1477
|
+
hasProtectedDefaultBranch
|
|
1478
|
+
]);
|
|
1479
|
+
const mergedWidgets = useMemo(() => ({
|
|
1480
|
+
...defaultWidgets,
|
|
1481
|
+
...widgets
|
|
1482
|
+
}), [widgets]);
|
|
1483
|
+
const mergedFields = useMemo(() => ({
|
|
1484
|
+
...defaultFields,
|
|
1485
|
+
...fields
|
|
1486
|
+
}), [fields]);
|
|
1487
|
+
const initialDataRef = useRef(value);
|
|
1488
|
+
const formDataRef = useRef(initialDataRef.current);
|
|
1489
|
+
const [formKey, setFormKey] = useState(0);
|
|
1490
|
+
const [hasValidated, setHasValidated] = useState(false);
|
|
1491
|
+
const [rootFormData, setRootFormData] = useState(initialDataRef.current);
|
|
1492
|
+
const mountedFormDataJsonRef = useRef(null);
|
|
1493
|
+
const isInitialMountRef = useRef(true);
|
|
1494
|
+
useEffect(() => {
|
|
1495
|
+
isInitialMountRef.current = false;
|
|
1496
|
+
}, [formKey]);
|
|
1497
|
+
const onChangeRef = useRef(onChange);
|
|
1498
|
+
onChangeRef.current = onChange;
|
|
1499
|
+
const valueRef = useRef(value);
|
|
1500
|
+
valueRef.current = value;
|
|
1501
|
+
const lastSentJsonRef = useRef(null);
|
|
1502
|
+
const debouncedOnChange = useMemo(() => debounce((data) => {
|
|
1503
|
+
const dataJson = stableStringify(data);
|
|
1504
|
+
if (dataJson !== stableStringify(valueRef.current)) {
|
|
1505
|
+
if (lastSentJsonRef.current === null && mountedFormDataJsonRef.current && dataJson === mountedFormDataJsonRef.current) return;
|
|
1506
|
+
lastSentJsonRef.current = dataJson;
|
|
1507
|
+
onChangeRef.current(data);
|
|
1508
|
+
}
|
|
1509
|
+
}, 100), []);
|
|
1510
|
+
useEffect(() => () => debouncedOnChange.cancel(), [debouncedOnChange]);
|
|
1511
|
+
const [prevValue, setPrevValue] = useState(value);
|
|
1512
|
+
if (value !== prevValue) {
|
|
1513
|
+
setPrevValue(value);
|
|
1514
|
+
const incomingJson = stableStringify(value);
|
|
1515
|
+
if (incomingJson !== stableStringify(prevValue)) {
|
|
1516
|
+
if (lastSentJsonRef.current && lastSentJsonRef.current === incomingJson) lastSentJsonRef.current = null;
|
|
1517
|
+
else {
|
|
1518
|
+
debouncedOnChange.cancel();
|
|
1519
|
+
lastSentJsonRef.current = null;
|
|
1520
|
+
initialDataRef.current = value;
|
|
1521
|
+
formDataRef.current = value;
|
|
1522
|
+
isInitialMountRef.current = true;
|
|
1523
|
+
mountedFormDataJsonRef.current = null;
|
|
1524
|
+
setFormKey((k) => k + 1);
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
const handleChange = useCallback((e) => {
|
|
1529
|
+
if (!e.formData) return;
|
|
1530
|
+
formDataRef.current = e.formData;
|
|
1531
|
+
setRootFormData(e.formData);
|
|
1532
|
+
if (isInitialMountRef.current) {
|
|
1533
|
+
mountedFormDataJsonRef.current = stableStringify(e.formData);
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
debouncedOnChange(e.formData);
|
|
1537
|
+
}, [debouncedOnChange]);
|
|
1538
|
+
const debouncedOnChangeRef = useRef(debouncedOnChange);
|
|
1539
|
+
debouncedOnChangeRef.current = debouncedOnChange;
|
|
1540
|
+
const setRootFormDataRef = useRef(setRootFormData);
|
|
1541
|
+
setRootFormDataRef.current = setRootFormData;
|
|
1542
|
+
const formContext = useMemo(() => ({
|
|
1543
|
+
setFormData: (data) => {
|
|
1544
|
+
const merged = {
|
|
1545
|
+
...formDataRef.current,
|
|
1546
|
+
...data
|
|
1547
|
+
};
|
|
1548
|
+
initialDataRef.current = merged;
|
|
1549
|
+
formDataRef.current = merged;
|
|
1550
|
+
setRootFormDataRef.current(merged);
|
|
1551
|
+
debouncedOnChangeRef.current.cancel();
|
|
1552
|
+
lastSentJsonRef.current = stableStringify(merged);
|
|
1553
|
+
onChangeRef.current(merged);
|
|
1554
|
+
isInitialMountRef.current = true;
|
|
1555
|
+
mountedFormDataJsonRef.current = null;
|
|
1556
|
+
setFormKey((k) => k + 1);
|
|
1557
|
+
},
|
|
1558
|
+
getFormData: () => formDataRef.current
|
|
1559
|
+
}), []);
|
|
1560
|
+
const formRef = useRef(null);
|
|
1561
|
+
useEffect(() => {
|
|
1562
|
+
if (onRegisterValidate) onRegisterValidate(() => {
|
|
1563
|
+
setHasValidated(true);
|
|
1564
|
+
return formRef.current?.validateForm() ?? true;
|
|
1565
|
+
});
|
|
1566
|
+
}, [onRegisterValidate, formKey]);
|
|
1567
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1568
|
+
className: "json-editor",
|
|
1569
|
+
children: /* @__PURE__ */ jsx(RenderMarkdownProvider, {
|
|
1570
|
+
value: renderMarkdown ?? defaultRenderMarkdown,
|
|
1571
|
+
children: /* @__PURE__ */ jsx(RootFormDataProvider, {
|
|
1572
|
+
value: rootFormData,
|
|
1573
|
+
children: /* @__PURE__ */ jsx(Form, {
|
|
1574
|
+
ref: formRef,
|
|
1575
|
+
schema: schemaJs,
|
|
1576
|
+
initialFormData: initialDataRef.current,
|
|
1577
|
+
uiSchema,
|
|
1578
|
+
validator,
|
|
1579
|
+
onChange: handleChange,
|
|
1580
|
+
widgets: mergedWidgets,
|
|
1581
|
+
fields: mergedFields,
|
|
1582
|
+
templates: defaultTemplates,
|
|
1583
|
+
formContext,
|
|
1584
|
+
disabled: readOnly,
|
|
1585
|
+
liveValidate: hasValidated ? "onBlur" : void 0,
|
|
1586
|
+
showErrorList: false,
|
|
1587
|
+
noHtml5Validate: true,
|
|
1588
|
+
tagName: inForm ? "div" : "form",
|
|
1589
|
+
children: /* @__PURE__ */ jsx(Fragment$1, {})
|
|
1590
|
+
}, formKey)
|
|
1591
|
+
})
|
|
1592
|
+
})
|
|
1593
|
+
});
|
|
1651
1594
|
};
|
|
1652
|
-
|
|
1595
|
+
//#endregion
|
|
1653
1596
|
export { RjsfSchemaEditor, buildDynamicOptions, resolveByPath, useRootFormData };
|
|
1654
|
-
|
|
1597
|
+
|
|
1655
1598
|
//# sourceMappingURL=rjsf.js.map
|