@multiplatform.one/frappe-ui 7.7.6 → 7.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/ChartCard.native.js.map +1 -1
- package/dist/cjs/FileBrowser/AttachLibrary.native.js.map +1 -1
- package/dist/cjs/FileBrowser/folderTree.native.js.map +1 -1
- package/dist/cjs/FileBrowser/index.native.js.map +1 -1
- package/dist/cjs/FileBrowser/types.native.js.map +1 -1
- package/dist/cjs/FileBrowser/viewPersistence.native.js.map +1 -1
- package/dist/cjs/FormSidebar.cjs +7 -7
- package/dist/cjs/FormSidebar.native.js +7 -7
- package/dist/cjs/FormSidebar.native.js.map +1 -1
- package/dist/cjs/FrappeAssignment.native.js.map +1 -1
- package/dist/cjs/FrappeCalendar.cjs +20 -17
- package/dist/cjs/FrappeCalendar.native.js +22 -21
- package/dist/cjs/FrappeCalendar.native.js.map +1 -1
- package/dist/cjs/FrappeChartCard.cjs +29 -3
- package/dist/cjs/FrappeChartCard.native.js +29 -3
- package/dist/cjs/FrappeChartCard.native.js.map +1 -1
- package/dist/cjs/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/cjs/FrappeDashboard.native.js.map +1 -1
- package/dist/cjs/FrappeForm.cjs +1 -1
- package/dist/cjs/FrappeForm.native.js +2 -2
- package/dist/cjs/FrappeForm.native.js.map +1 -1
- package/dist/cjs/FrappeGantt.cjs +25 -34
- package/dist/cjs/FrappeGantt.native.js +27 -38
- package/dist/cjs/FrappeGantt.native.js.map +1 -1
- package/dist/cjs/FrappeImageView.cjs +4 -2
- package/dist/cjs/FrappeImageView.native.js +8 -4
- package/dist/cjs/FrappeImageView.native.js.map +1 -1
- package/dist/cjs/FrappeKPICard.cjs +29 -3
- package/dist/cjs/FrappeKPICard.native.js +29 -3
- package/dist/cjs/FrappeKPICard.native.js.map +1 -1
- package/dist/cjs/FrappeKanban.cjs +16 -17
- package/dist/cjs/FrappeKanban.native.js +18 -21
- package/dist/cjs/FrappeKanban.native.js.map +1 -1
- package/dist/cjs/FrappeLikedBy.cjs +1 -1
- package/dist/cjs/FrappeLikedBy.native.js +1 -1
- package/dist/cjs/FrappeLikedBy.native.js.map +1 -1
- package/dist/cjs/FrappeList.cjs +2 -2
- package/dist/cjs/FrappeList.native.js +2 -2
- package/dist/cjs/FrappeList.native.js.map +1 -1
- package/dist/cjs/FrappeListView.cjs +6 -6
- package/dist/cjs/FrappeListView.native.js +6 -6
- package/dist/cjs/FrappeListView.native.js.map +1 -1
- package/dist/cjs/FrappeProvider.native.js.map +1 -1
- package/dist/cjs/FrappeReconnectIndicator.native.js.map +1 -1
- package/dist/cjs/FrappeReportBuilder.cjs +2 -2
- package/dist/cjs/FrappeReportBuilder.native.js +2 -2
- package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
- package/dist/cjs/FrappeReportView.native.js +3 -3
- package/dist/cjs/FrappeReportView.native.js.map +1 -1
- package/dist/cjs/FrappeTable.cjs +35 -38
- package/dist/cjs/FrappeTable.native.js +38 -39
- package/dist/cjs/FrappeTable.native.js.map +1 -1
- package/dist/cjs/FrappeTreeView.cjs +85 -50
- package/dist/cjs/FrappeTreeView.native.js +129 -50
- package/dist/cjs/FrappeTreeView.native.js.map +1 -1
- package/dist/cjs/SyncErrorNotice.native.js.map +1 -1
- package/dist/cjs/commentActions.cjs +1 -1
- package/dist/cjs/commentActions.native.js +1 -1
- package/dist/cjs/commentActions.native.js.map +1 -1
- package/dist/cjs/components/attachments.native.js.map +1 -1
- package/dist/cjs/components/tags.native.js.map +1 -1
- package/dist/cjs/components/timeline.cjs +1 -1
- package/dist/cjs/components/timeline.native.js +1 -1
- package/dist/cjs/components/timeline.native.js.map +1 -1
- package/dist/cjs/dependsOn.native.js.map +1 -1
- package/dist/cjs/desk/DeskFormPage.native.js.map +1 -1
- package/dist/cjs/desk/DeskFormSidebar.native.js.map +1 -1
- package/dist/cjs/desk/DeskListPage.native.js.map +1 -1
- package/dist/cjs/desk/DeskShell.cjs +2 -0
- package/dist/cjs/desk/DeskShell.native.js +2 -0
- package/dist/cjs/desk/DeskShell.native.js.map +1 -1
- package/dist/cjs/desk/DeskSidebar.native.js.map +1 -1
- package/dist/cjs/desk/awesomebar.cjs +1 -1
- package/dist/cjs/desk/awesomebar.native.js +1 -1
- package/dist/cjs/desk/awesomebar.native.js.map +1 -1
- package/dist/cjs/fieldOverrides.native.js.map +1 -1
- package/dist/cjs/fieldRegistry.native.js +31 -31
- package/dist/cjs/fieldRegistry.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/index.native.js.map +1 -1
- package/dist/cjs/fields/Check/index.native.js.map +1 -1
- package/dist/cjs/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/cjs/fields/Color/index.native.js.map +1 -1
- package/dist/cjs/fields/Data/index.native.js.map +1 -1
- package/dist/cjs/fields/Date/sheetKeyboard.native.js.map +1 -1
- package/dist/cjs/fields/Date/types.native.js.map +1 -1
- package/dist/cjs/fields/Date/wire.native.js.map +1 -1
- package/dist/cjs/fields/DateRange/index.cjs +30 -2
- package/dist/cjs/fields/DateRange/index.native.js +34 -2
- package/dist/cjs/fields/DateRange/index.native.js.map +1 -1
- package/dist/cjs/fields/Duration/index.native.js.map +1 -1
- package/dist/cjs/fields/DynamicLink.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload.native.js.map +1 -1
- package/dist/cjs/fields/FileUploadField/index.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
- package/dist/cjs/fields/HTML/index.native.js.map +1 -1
- package/dist/cjs/fields/Heading/index.native.js.map +1 -1
- package/dist/cjs/fields/Icon/index.native.js.map +1 -1
- package/dist/cjs/fields/Link.native.js.map +1 -1
- package/dist/cjs/fields/LinkTree.native.js.map +1 -1
- package/dist/cjs/fields/LongText/index.native.js.map +1 -1
- package/dist/cjs/fields/MentionInput/index.cjs +4 -1
- package/dist/cjs/fields/MentionInput/index.native.js +4 -1
- package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
- package/dist/cjs/fields/Numeric/index.native.js.map +1 -1
- package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
- package/dist/cjs/fields/Password/index.native.js.map +1 -1
- package/dist/cjs/fields/Phone/index.native.js.map +1 -1
- package/dist/cjs/fields/Progress/index.native.js.map +1 -1
- package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
- package/dist/cjs/fields/Rating/index.native.js.map +1 -1
- package/dist/cjs/fields/ReadOnly/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/index.native.js.map +1 -1
- package/dist/cjs/fields/Signature/index.native.js.map +1 -1
- package/dist/cjs/fields/Slider/index.native.js.map +1 -1
- package/dist/cjs/fields/SmallText/index.native.js.map +1 -1
- package/dist/cjs/fields/Switch/index.native.js.map +1 -1
- package/dist/cjs/fields/TableMultiSelect.native.js.map +1 -1
- package/dist/cjs/fields/TextEditor/types.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/index.native.js.map +1 -1
- package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
- package/dist/cjs/fields/shared/EditorPreviewPanes.native.js.map +1 -1
- package/dist/cjs/filterFields.native.js.map +1 -1
- package/dist/cjs/formEngine/createPrefill.native.js.map +1 -1
- package/dist/cjs/formEngine/dirtyTracking.native.js.map +1 -1
- package/dist/cjs/formEngine/doctypeMeta.native.js.map +1 -1
- package/dist/cjs/formEngine/fetchFrom.native.js.map +1 -1
- package/dist/cjs/formEngine/fieldPermissions.native.js.map +1 -1
- package/dist/cjs/formEngine/formActions.native.js.map +1 -1
- package/dist/cjs/formEngine/formLayout.native.js.map +1 -1
- package/dist/cjs/formEngine/index.native.js.map +1 -1
- package/dist/cjs/formEngine/useFormEngine.native.js.map +1 -1
- package/dist/cjs/frappeEventColor.native.js.map +1 -1
- package/dist/cjs/frappeStoryTarget.native.js.map +1 -1
- package/dist/cjs/frappeUsers.native.js.map +1 -1
- package/dist/cjs/index.cjs +4 -0
- package/dist/cjs/index.native.js +38 -34
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/liveErrors.native.js.map +1 -1
- package/dist/cjs/resolveControl.native.js.map +1 -1
- package/dist/cjs/schemaForm/SchemaWizard.native.js.map +1 -1
- package/dist/cjs/schemaForm/applyFieldOrder.native.js.map +1 -1
- package/dist/cjs/schemaForm/index.cjs +10 -9
- package/dist/cjs/schemaForm/index.native.js +11 -10
- package/dist/cjs/schemaForm/index.native.js.map +1 -1
- package/dist/cjs/shared/devWarn.cjs +40 -0
- package/dist/cjs/shared/devWarn.native.js +45 -0
- package/dist/cjs/shared/devWarn.native.js.map +1 -0
- package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
- package/dist/cjs/syncError.native.js.map +1 -1
- package/dist/cjs/useFrappeAggregate.cjs +15 -8
- package/dist/cjs/useFrappeAggregate.native.js +15 -9
- package/dist/cjs/useFrappeAggregate.native.js.map +1 -1
- package/dist/cjs/useFrappeFacets.cjs +10 -9
- package/dist/cjs/useFrappeFacets.native.js +10 -10
- package/dist/cjs/useFrappeFacets.native.js.map +1 -1
- package/dist/cjs/useFrappePagination.native.js.map +1 -1
- package/dist/cjs/useFrappeRows.cjs +113 -0
- package/dist/cjs/useFrappeRows.native.js +129 -0
- package/dist/cjs/useFrappeRows.native.js.map +1 -0
- package/dist/esm/ChartCard.native.js.map +1 -1
- package/dist/esm/FileBrowser/AttachLibrary.native.js.map +1 -1
- package/dist/esm/FileBrowser/folderTree.native.js.map +1 -1
- package/dist/esm/FileBrowser/index.native.js.map +1 -1
- package/dist/esm/FileBrowser/types.native.js.map +1 -1
- package/dist/esm/FileBrowser/viewPersistence.native.js.map +1 -1
- package/dist/esm/FormSidebar.mjs +7 -7
- package/dist/esm/FormSidebar.mjs.map +1 -1
- package/dist/esm/FormSidebar.native.js +7 -7
- package/dist/esm/FormSidebar.native.js.map +1 -1
- package/dist/esm/FrappeAssignment.native.js.map +1 -1
- package/dist/esm/FrappeCalendar.mjs +20 -17
- package/dist/esm/FrappeCalendar.mjs.map +1 -1
- package/dist/esm/FrappeCalendar.native.js +22 -21
- package/dist/esm/FrappeCalendar.native.js.map +1 -1
- package/dist/esm/FrappeChartCard.mjs +30 -4
- package/dist/esm/FrappeChartCard.mjs.map +1 -1
- package/dist/esm/FrappeChartCard.native.js +30 -4
- package/dist/esm/FrappeChartCard.native.js.map +1 -1
- package/dist/esm/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/esm/FrappeDashboard.native.js.map +1 -1
- package/dist/esm/FrappeForm.mjs +1 -1
- package/dist/esm/FrappeForm.mjs.map +1 -1
- package/dist/esm/FrappeForm.native.js +1 -1
- package/dist/esm/FrappeForm.native.js.map +1 -1
- package/dist/esm/FrappeGantt.mjs +27 -36
- package/dist/esm/FrappeGantt.mjs.map +1 -1
- package/dist/esm/FrappeGantt.native.js +29 -40
- package/dist/esm/FrappeGantt.native.js.map +1 -1
- package/dist/esm/FrappeImageView.mjs +5 -3
- package/dist/esm/FrappeImageView.mjs.map +1 -1
- package/dist/esm/FrappeImageView.native.js +9 -5
- package/dist/esm/FrappeImageView.native.js.map +1 -1
- package/dist/esm/FrappeKPICard.mjs +30 -4
- package/dist/esm/FrappeKPICard.mjs.map +1 -1
- package/dist/esm/FrappeKPICard.native.js +30 -4
- package/dist/esm/FrappeKPICard.native.js.map +1 -1
- package/dist/esm/FrappeKanban.mjs +16 -17
- package/dist/esm/FrappeKanban.mjs.map +1 -1
- package/dist/esm/FrappeKanban.native.js +18 -21
- package/dist/esm/FrappeKanban.native.js.map +1 -1
- package/dist/esm/FrappeLikedBy.mjs +1 -1
- package/dist/esm/FrappeLikedBy.mjs.map +1 -1
- package/dist/esm/FrappeLikedBy.native.js +1 -1
- package/dist/esm/FrappeLikedBy.native.js.map +1 -1
- package/dist/esm/FrappeList.mjs +2 -2
- package/dist/esm/FrappeList.mjs.map +1 -1
- package/dist/esm/FrappeList.native.js +2 -2
- package/dist/esm/FrappeList.native.js.map +1 -1
- package/dist/esm/FrappeListView.mjs +6 -6
- package/dist/esm/FrappeListView.mjs.map +1 -1
- package/dist/esm/FrappeListView.native.js +6 -6
- package/dist/esm/FrappeListView.native.js.map +1 -1
- package/dist/esm/FrappeProvider.mjs.map +1 -1
- package/dist/esm/FrappeProvider.native.js.map +1 -1
- package/dist/esm/FrappeReconnectIndicator.native.js.map +1 -1
- package/dist/esm/FrappeReportBuilder.mjs +2 -2
- package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
- package/dist/esm/FrappeReportBuilder.native.js +2 -2
- package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
- package/dist/esm/FrappeReportView.native.js.map +1 -1
- package/dist/esm/FrappeTable.mjs +36 -39
- package/dist/esm/FrappeTable.mjs.map +1 -1
- package/dist/esm/FrappeTable.native.js +39 -40
- package/dist/esm/FrappeTable.native.js.map +1 -1
- package/dist/esm/FrappeTreeView.mjs +89 -55
- package/dist/esm/FrappeTreeView.mjs.map +1 -1
- package/dist/esm/FrappeTreeView.native.js +133 -55
- package/dist/esm/FrappeTreeView.native.js.map +1 -1
- package/dist/esm/SyncErrorNotice.native.js.map +1 -1
- package/dist/esm/commentActions.mjs +1 -1
- package/dist/esm/commentActions.mjs.map +1 -1
- package/dist/esm/commentActions.native.js +1 -1
- package/dist/esm/commentActions.native.js.map +1 -1
- package/dist/esm/components/attachments.native.js.map +1 -1
- package/dist/esm/components/tags.native.js.map +1 -1
- package/dist/esm/components/timeline.mjs +1 -1
- package/dist/esm/components/timeline.mjs.map +1 -1
- package/dist/esm/components/timeline.native.js +1 -1
- package/dist/esm/components/timeline.native.js.map +1 -1
- package/dist/esm/dependsOn.native.js.map +1 -1
- package/dist/esm/desk/DeskFormPage.native.js.map +1 -1
- package/dist/esm/desk/DeskFormSidebar.native.js.map +1 -1
- package/dist/esm/desk/DeskListPage.native.js.map +1 -1
- package/dist/esm/desk/DeskShell.mjs +2 -0
- package/dist/esm/desk/DeskShell.mjs.map +1 -1
- package/dist/esm/desk/DeskShell.native.js +2 -0
- package/dist/esm/desk/DeskShell.native.js.map +1 -1
- package/dist/esm/desk/DeskSidebar.native.js.map +1 -1
- package/dist/esm/desk/awesomebar.mjs +1 -1
- package/dist/esm/desk/awesomebar.mjs.map +1 -1
- package/dist/esm/desk/awesomebar.native.js +1 -1
- package/dist/esm/desk/awesomebar.native.js.map +1 -1
- package/dist/esm/fieldOverrides.native.js.map +1 -1
- package/dist/esm/fieldRegistry.native.js.map +1 -1
- package/dist/esm/fields/Barcode/index.native.js.map +1 -1
- package/dist/esm/fields/Check/index.native.js.map +1 -1
- package/dist/esm/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/esm/fields/Color/index.native.js.map +1 -1
- package/dist/esm/fields/Data/index.native.js.map +1 -1
- package/dist/esm/fields/Date/sheetKeyboard.native.js.map +1 -1
- package/dist/esm/fields/Date/types.native.js.map +1 -1
- package/dist/esm/fields/Date/wire.native.js.map +1 -1
- package/dist/esm/fields/DateRange/index.mjs +30 -2
- package/dist/esm/fields/DateRange/index.mjs.map +1 -1
- package/dist/esm/fields/DateRange/index.native.js +34 -2
- package/dist/esm/fields/DateRange/index.native.js.map +1 -1
- package/dist/esm/fields/Duration/index.native.js.map +1 -1
- package/dist/esm/fields/DynamicLink.native.js.map +1 -1
- package/dist/esm/fields/FileUpload.native.js.map +1 -1
- package/dist/esm/fields/FileUploadField/index.native.js.map +1 -1
- package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
- package/dist/esm/fields/HTML/index.native.js.map +1 -1
- package/dist/esm/fields/Heading/index.native.js.map +1 -1
- package/dist/esm/fields/Icon/index.native.js.map +1 -1
- package/dist/esm/fields/Link.native.js.map +1 -1
- package/dist/esm/fields/LinkTree.native.js.map +1 -1
- package/dist/esm/fields/LongText/index.native.js.map +1 -1
- package/dist/esm/fields/MentionInput/index.mjs +4 -1
- package/dist/esm/fields/MentionInput/index.mjs.map +1 -1
- package/dist/esm/fields/MentionInput/index.native.js +4 -1
- package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
- package/dist/esm/fields/Numeric/index.native.js.map +1 -1
- package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
- package/dist/esm/fields/Password/index.native.js.map +1 -1
- package/dist/esm/fields/Phone/index.native.js.map +1 -1
- package/dist/esm/fields/Progress/index.native.js.map +1 -1
- package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
- package/dist/esm/fields/Rating/index.native.js.map +1 -1
- package/dist/esm/fields/ReadOnly/index.native.js.map +1 -1
- package/dist/esm/fields/Select/index.native.js.map +1 -1
- package/dist/esm/fields/Signature/index.native.js.map +1 -1
- package/dist/esm/fields/Slider/index.native.js.map +1 -1
- package/dist/esm/fields/SmallText/index.native.js.map +1 -1
- package/dist/esm/fields/Switch/index.native.js.map +1 -1
- package/dist/esm/fields/TableMultiSelect.native.js.map +1 -1
- package/dist/esm/fields/TextEditor/types.native.js.map +1 -1
- package/dist/esm/fields/TimePicker/index.native.js.map +1 -1
- package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
- package/dist/esm/fields/shared/EditorPreviewPanes.native.js.map +1 -1
- package/dist/esm/filterFields.native.js.map +1 -1
- package/dist/esm/formEngine/createPrefill.native.js.map +1 -1
- package/dist/esm/formEngine/dirtyTracking.native.js.map +1 -1
- package/dist/esm/formEngine/doctypeMeta.native.js.map +1 -1
- package/dist/esm/formEngine/fetchFrom.native.js.map +1 -1
- package/dist/esm/formEngine/fieldPermissions.native.js.map +1 -1
- package/dist/esm/formEngine/formActions.native.js.map +1 -1
- package/dist/esm/formEngine/formLayout.native.js.map +1 -1
- package/dist/esm/formEngine/index.native.js.map +1 -1
- package/dist/esm/formEngine/useFormEngine.native.js.map +1 -1
- package/dist/esm/frappeEventColor.native.js.map +1 -1
- package/dist/esm/frappeStoryTarget.native.js.map +1 -1
- package/dist/esm/frappeUsers.native.js.map +1 -1
- package/dist/esm/index.mjs +2 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +2 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/liveErrors.native.js.map +1 -1
- package/dist/esm/resolveControl.native.js.map +1 -1
- package/dist/esm/schemaForm/SchemaWizard.native.js.map +1 -1
- package/dist/esm/schemaForm/applyFieldOrder.native.js.map +1 -1
- package/dist/esm/schemaForm/index.mjs +8 -7
- package/dist/esm/schemaForm/index.mjs.map +1 -1
- package/dist/esm/schemaForm/index.native.js +8 -7
- package/dist/esm/schemaForm/index.native.js.map +1 -1
- package/dist/esm/shared/devWarn.mjs +14 -0
- package/dist/esm/shared/devWarn.mjs.map +1 -0
- package/dist/esm/shared/devWarn.native.js +16 -0
- package/dist/esm/shared/devWarn.native.js.map +1 -0
- package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
- package/dist/esm/syncError.native.js.map +1 -1
- package/dist/esm/useFrappeAggregate.mjs +15 -8
- package/dist/esm/useFrappeAggregate.mjs.map +1 -1
- package/dist/esm/useFrappeAggregate.native.js +15 -9
- package/dist/esm/useFrappeAggregate.native.js.map +1 -1
- package/dist/esm/useFrappeFacets.mjs +10 -9
- package/dist/esm/useFrappeFacets.mjs.map +1 -1
- package/dist/esm/useFrappeFacets.native.js +10 -10
- package/dist/esm/useFrappeFacets.native.js.map +1 -1
- package/dist/esm/useFrappePagination.native.js.map +1 -1
- package/dist/esm/useFrappeRows.mjs +86 -0
- package/dist/esm/useFrappeRows.mjs.map +1 -0
- package/dist/esm/useFrappeRows.native.js +99 -0
- package/dist/esm/useFrappeRows.native.js.map +1 -0
- package/dist/jsx/FormSidebar.mjs +7 -7
- package/dist/jsx/FormSidebar.mjs.map +1 -1
- package/dist/jsx/FormSidebar.native.js +7 -7
- package/dist/jsx/FormSidebar.native.js.map +1 -1
- package/dist/jsx/FrappeCalendar.mjs +20 -17
- package/dist/jsx/FrappeCalendar.mjs.map +1 -1
- package/dist/jsx/FrappeCalendar.native.js +22 -21
- package/dist/jsx/FrappeCalendar.native.js.map +1 -1
- package/dist/jsx/FrappeChartCard.mjs +30 -4
- package/dist/jsx/FrappeChartCard.mjs.map +1 -1
- package/dist/jsx/FrappeChartCard.native.js +29 -3
- package/dist/jsx/FrappeChartCard.native.js.map +1 -1
- package/dist/jsx/FrappeForm.mjs +1 -1
- package/dist/jsx/FrappeForm.mjs.map +1 -1
- package/dist/jsx/FrappeForm.native.js +1 -1
- package/dist/jsx/FrappeForm.native.js.map +1 -1
- package/dist/jsx/FrappeGantt.mjs +27 -36
- package/dist/jsx/FrappeGantt.mjs.map +1 -1
- package/dist/jsx/FrappeGantt.native.js +27 -38
- package/dist/jsx/FrappeGantt.native.js.map +1 -1
- package/dist/jsx/FrappeImageView.mjs +5 -3
- package/dist/jsx/FrappeImageView.mjs.map +1 -1
- package/dist/jsx/FrappeImageView.native.js +8 -4
- package/dist/jsx/FrappeImageView.native.js.map +1 -1
- package/dist/jsx/FrappeKPICard.mjs +30 -4
- package/dist/jsx/FrappeKPICard.mjs.map +1 -1
- package/dist/jsx/FrappeKPICard.native.js +29 -3
- package/dist/jsx/FrappeKPICard.native.js.map +1 -1
- package/dist/jsx/FrappeKanban.mjs +16 -17
- package/dist/jsx/FrappeKanban.mjs.map +1 -1
- package/dist/jsx/FrappeKanban.native.js +18 -21
- package/dist/jsx/FrappeKanban.native.js.map +1 -1
- package/dist/jsx/FrappeLikedBy.mjs +1 -1
- package/dist/jsx/FrappeLikedBy.mjs.map +1 -1
- package/dist/jsx/FrappeLikedBy.native.js +1 -1
- package/dist/jsx/FrappeLikedBy.native.js.map +1 -1
- package/dist/jsx/FrappeList.mjs +2 -2
- package/dist/jsx/FrappeList.mjs.map +1 -1
- package/dist/jsx/FrappeList.native.js +2 -2
- package/dist/jsx/FrappeList.native.js.map +1 -1
- package/dist/jsx/FrappeListView.mjs +6 -6
- package/dist/jsx/FrappeListView.mjs.map +1 -1
- package/dist/jsx/FrappeListView.native.js +6 -6
- package/dist/jsx/FrappeListView.native.js.map +1 -1
- package/dist/jsx/FrappeProvider.mjs.map +1 -1
- package/dist/jsx/FrappeProvider.native.js.map +1 -1
- package/dist/jsx/FrappeReportBuilder.mjs +2 -2
- package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
- package/dist/jsx/FrappeReportBuilder.native.js +2 -2
- package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
- package/dist/jsx/FrappeTable.mjs +36 -39
- package/dist/jsx/FrappeTable.mjs.map +1 -1
- package/dist/jsx/FrappeTable.native.js +38 -39
- package/dist/jsx/FrappeTable.native.js.map +1 -1
- package/dist/jsx/FrappeTreeView.mjs +89 -55
- package/dist/jsx/FrappeTreeView.mjs.map +1 -1
- package/dist/jsx/FrappeTreeView.native.js +129 -50
- package/dist/jsx/FrappeTreeView.native.js.map +1 -1
- package/dist/jsx/commentActions.mjs +1 -1
- package/dist/jsx/commentActions.mjs.map +1 -1
- package/dist/jsx/commentActions.native.js +1 -1
- package/dist/jsx/commentActions.native.js.map +1 -1
- package/dist/jsx/components/timeline.mjs +1 -1
- package/dist/jsx/components/timeline.mjs.map +1 -1
- package/dist/jsx/components/timeline.native.js +1 -1
- package/dist/jsx/desk/DeskShell.mjs +2 -0
- package/dist/jsx/desk/DeskShell.mjs.map +1 -1
- package/dist/jsx/desk/DeskShell.native.js +2 -0
- package/dist/jsx/desk/DeskShell.native.js.map +1 -1
- package/dist/jsx/desk/awesomebar.mjs +1 -1
- package/dist/jsx/desk/awesomebar.mjs.map +1 -1
- package/dist/jsx/desk/awesomebar.native.js +1 -1
- package/dist/jsx/desk/awesomebar.native.js.map +1 -1
- package/dist/jsx/fields/DateRange/index.mjs +30 -2
- package/dist/jsx/fields/DateRange/index.mjs.map +1 -1
- package/dist/jsx/fields/DateRange/index.native.js +34 -2
- package/dist/jsx/fields/DateRange/index.native.js.map +1 -1
- package/dist/jsx/fields/MentionInput/index.mjs +4 -1
- package/dist/jsx/fields/MentionInput/index.mjs.map +1 -1
- package/dist/jsx/fields/MentionInput/index.native.js +4 -1
- package/dist/jsx/fields/MentionInput/index.native.js.map +1 -1
- package/dist/jsx/index.js +2 -1
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +2 -1
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +4 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/schemaForm/index.mjs +8 -7
- package/dist/jsx/schemaForm/index.mjs.map +1 -1
- package/dist/jsx/schemaForm/index.native.js +10 -9
- package/dist/jsx/schemaForm/index.native.js.map +1 -1
- package/dist/jsx/shared/devWarn.mjs +14 -0
- package/dist/jsx/shared/devWarn.mjs.map +1 -0
- package/dist/jsx/shared/devWarn.native.js +45 -0
- package/dist/jsx/shared/devWarn.native.js.map +1 -0
- package/dist/jsx/useFrappeAggregate.mjs +15 -8
- package/dist/jsx/useFrappeAggregate.mjs.map +1 -1
- package/dist/jsx/useFrappeAggregate.native.js +15 -9
- package/dist/jsx/useFrappeAggregate.native.js.map +1 -1
- package/dist/jsx/useFrappeFacets.mjs +10 -9
- package/dist/jsx/useFrappeFacets.mjs.map +1 -1
- package/dist/jsx/useFrappeFacets.native.js +10 -10
- package/dist/jsx/useFrappeFacets.native.js.map +1 -1
- package/dist/jsx/useFrappeRows.mjs +86 -0
- package/dist/jsx/useFrappeRows.mjs.map +1 -0
- package/dist/jsx/useFrappeRows.native.js +129 -0
- package/dist/jsx/useFrappeRows.native.js.map +1 -0
- package/package.json +17 -16
- package/src/FileBrowser/FileBrowser.spec.tsx +11 -1
- package/src/FormSidebar.tsx +7 -7
- package/src/FrappeCalendar.tsx +25 -22
- package/src/FrappeChartCard.spec.tsx +179 -0
- package/src/FrappeChartCard.tsx +55 -6
- package/src/FrappeForm.tsx +7 -3
- package/src/FrappeGantt.tsx +29 -39
- package/src/FrappeImageView.tsx +5 -3
- package/src/FrappeKPICard.spec.tsx +153 -0
- package/src/FrappeKPICard.tsx +52 -6
- package/src/FrappeKanban.tsx +24 -17
- package/src/FrappeLikedBy.tsx +1 -1
- package/src/FrappeList.tsx +3 -2
- package/src/FrappeListView.tsx +6 -6
- package/src/FrappeProvider.fixturesOnly.spec.tsx +129 -0
- package/src/FrappeProvider.tsx +16 -6
- package/src/FrappeReportBuilder.tsx +4 -2
- package/src/FrappeTable.autoHeight.spec.tsx +142 -0
- package/src/FrappeTable.rowAccumulator.spec.tsx +110 -0
- package/src/FrappeTable.tsx +75 -48
- package/src/FrappeTreeView.stories.tsx +59 -0
- package/src/FrappeTreeView.tsx +166 -56
- package/src/commentActions.ts +1 -1
- package/src/components/timeline.tsx +1 -1
- package/src/desk/DeskShell.tsx +2 -0
- package/src/desk/awesomebar.tsx +5 -2
- package/src/fields/CodeEditor/CodeEditor.spec.tsx +10 -9
- package/src/fields/Date/Date.spec.tsx +8 -1
- package/src/fields/Date/nativePresentation.spec.tsx +8 -1
- package/src/fields/Date/typeParity.spec.tsx +27 -10
- package/src/fields/DateRange/DateRange.spec.tsx +87 -15
- package/src/fields/DateRange/index.tsx +47 -3
- package/src/fields/Duration/Duration.spec.tsx +73 -0
- package/src/fields/MentionInput/MentionInput.spec.tsx +110 -0
- package/src/fields/MentionInput/index.tsx +4 -1
- package/src/fields/Password/index.tsx +1 -1
- package/src/fields/Progress/Progress.spec.tsx +9 -0
- package/src/fields/RadioGroup/RadioGroup.spec.tsx +93 -0
- package/src/fields/Signature/Signature.spec.tsx +105 -0
- package/src/fields/Slider/Slider.spec.tsx +73 -0
- package/src/fields/Switch/Switch.spec.tsx +65 -0
- package/src/fields/TextEditor/TextEditor.spec.tsx +2 -3
- package/src/fields/TextEditor/TextEditor.stories.tsx +31 -1
- package/src/fields/ToggleGroup/ToggleGroup.spec.tsx +110 -0
- package/src/frappeViews.designLaw.spec.ts +11 -7
- package/src/index.ts +13 -0
- package/src/schemaForm/index.tsx +6 -7
- package/src/shared/devWarn.ts +44 -0
- package/src/useFrappeAggregate.ts +17 -11
- package/src/useFrappeFacets.ts +17 -10
- package/src/useFrappeRows.spec.tsx +176 -0
- package/src/useFrappeRows.ts +293 -0
- package/types/FrappeCalendar.d.ts.map +1 -1
- package/types/FrappeChartCard.d.ts +17 -1
- package/types/FrappeChartCard.d.ts.map +1 -1
- package/types/FrappeForm.d.ts +6 -2
- package/types/FrappeForm.d.ts.map +1 -1
- package/types/FrappeGantt.d.ts.map +1 -1
- package/types/FrappeImageView.d.ts.map +1 -1
- package/types/FrappeKPICard.d.ts +14 -1
- package/types/FrappeKPICard.d.ts.map +1 -1
- package/types/FrappeKanban.d.ts.map +1 -1
- package/types/FrappeList.d.ts.map +1 -1
- package/types/FrappeProvider.d.ts +16 -6
- package/types/FrappeProvider.d.ts.map +1 -1
- package/types/FrappeReportBuilder.d.ts.map +1 -1
- package/types/FrappeTable.d.ts +20 -1
- package/types/FrappeTable.d.ts.map +1 -1
- package/types/FrappeTreeView.d.ts +38 -1
- package/types/FrappeTreeView.d.ts.map +1 -1
- package/types/desk/DeskShell.d.ts.map +1 -1
- package/types/desk/awesomebar.d.ts.map +1 -1
- package/types/fields/DateRange/index.d.ts.map +1 -1
- package/types/fields/MentionInput/index.d.ts.map +1 -1
- package/types/fields/Password/index.d.ts +1 -1
- package/types/fields/Password/index.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/schemaForm/index.d.ts.map +1 -1
- package/types/shared/devWarn.d.ts +23 -0
- package/types/shared/devWarn.d.ts.map +1 -0
- package/types/useFrappeAggregate.d.ts +2 -1
- package/types/useFrappeAggregate.d.ts.map +1 -1
- package/types/useFrappeFacets.d.ts +2 -1
- package/types/useFrappeFacets.d.ts.map +1 -1
- package/types/useFrappeRows.d.ts +186 -0
- package/types/useFrappeRows.d.ts.map +1 -0
|
@@ -2,19 +2,16 @@
|
|
|
2
2
|
* DateRangeField contract specs. The `Date Range` fieldtype composes the forms
|
|
3
3
|
* DateRangePicker, so the adapter's contract is which props survive the hop.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* tests describe today's behaviour and will go red the moment someone wires it
|
|
11
|
-
* up — which is the point: that is the signal to update them alongside the fix.
|
|
12
|
-
* Reported on MPO-123.
|
|
5
|
+
* `value` and `onChange` used to be DECLARED on DateRangeFieldProps and then
|
|
6
|
+
* destructured away instead of being handed to the picker, so a saved range
|
|
7
|
+
* never painted and a picked one never emitted (MPO-137, found by the MPO-123
|
|
8
|
+
* spec pass). Both are now wired, and the range is carried as the two calendar
|
|
9
|
+
* dates comma-separated — the shape the registry feeds in and reads back.
|
|
13
10
|
*/
|
|
14
11
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
15
|
-
import { cleanup } from "@testing-library/react";
|
|
12
|
+
import { act, cleanup, fireEvent, waitFor } from "@testing-library/react";
|
|
16
13
|
import type React from "react";
|
|
17
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
14
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
18
15
|
import { getFieldComponent, type FieldRenderProps } from "../../fieldRegistry";
|
|
19
16
|
import { DateRangeField } from ".";
|
|
20
17
|
|
|
@@ -27,6 +24,24 @@ const trigger = (container: HTMLElement) =>
|
|
|
27
24
|
const combobox = (container: HTMLElement) =>
|
|
28
25
|
container.querySelector('[data-testid="date-picker-trigger"]');
|
|
29
26
|
|
|
27
|
+
/**
|
|
28
|
+
* An enabled day cell in the month the picker opened on. The panel is
|
|
29
|
+
* portaled, and the wide layout renders the previous month first, so the
|
|
30
|
+
* range's own month is the LAST calendar panel in the document.
|
|
31
|
+
*/
|
|
32
|
+
function getDayButton(day: number): HTMLButtonElement | undefined {
|
|
33
|
+
const panels = document.body.querySelectorAll('[data-testid="date-picker-calendar"]');
|
|
34
|
+
const panel = panels[panels.length - 1];
|
|
35
|
+
if (!panel) return undefined;
|
|
36
|
+
return Array.from(panel.querySelectorAll('button, [role="button"]')).find((btn) => {
|
|
37
|
+
const disabled =
|
|
38
|
+
btn.hasAttribute("disabled") ||
|
|
39
|
+
btn.getAttribute("aria-disabled") === "true" ||
|
|
40
|
+
btn.hasAttribute("data-disabled");
|
|
41
|
+
return btn.textContent?.trim() === String(day) && !disabled;
|
|
42
|
+
}) as HTMLButtonElement | undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
describe("DateRangeField composes the forms DateRangePicker", () => {
|
|
31
46
|
it("renders a single range trigger, not two date inputs", () => {
|
|
32
47
|
const result = renderWithProviders(<DateRangeField label="Period" />);
|
|
@@ -84,21 +99,77 @@ describe("DateRangeField composes the forms DateRangePicker", () => {
|
|
|
84
99
|
});
|
|
85
100
|
});
|
|
86
101
|
|
|
87
|
-
describe("DateRangeField value
|
|
102
|
+
describe("DateRangeField controlled value (MPO-137)", () => {
|
|
88
103
|
it("declares value on its props type", () => {
|
|
89
104
|
// Type-level promise: the adapter advertises a controlled value.
|
|
90
105
|
const props: React.ComponentProps<typeof DateRangeField> = { value: "2026-01-01" };
|
|
91
106
|
expect(props.value).toBe("2026-01-01");
|
|
92
107
|
});
|
|
93
108
|
|
|
94
|
-
it("
|
|
109
|
+
it("paints a saved range on the trigger rather than the placeholder", () => {
|
|
110
|
+
const result = renderWithProviders(
|
|
111
|
+
<DateRangeField label="Period" placeholder="From – To" value="2026-01-01,2026-01-31" />,
|
|
112
|
+
);
|
|
113
|
+
expect(trigger(result.container)?.value).toBe("Jan 1, 2026 – Jan 31, 2026");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("paints a range that arrives after mount, without emitting (LC-14)", async () => {
|
|
117
|
+
const onChange = vi.fn();
|
|
118
|
+
const result = renderWithProviders(
|
|
119
|
+
<DateRangeField label="Period" value="" onChange={onChange} />,
|
|
120
|
+
);
|
|
121
|
+
expect(trigger(result.container)?.value ?? "").toBe("");
|
|
122
|
+
|
|
123
|
+
// Late seed: the engine applies create defaults once meta loads.
|
|
124
|
+
result.rerender(
|
|
125
|
+
<DateRangeField label="Period" value="2026-01-01,2026-01-31" onChange={onChange} />,
|
|
126
|
+
);
|
|
127
|
+
await waitFor(() => {
|
|
128
|
+
expect(trigger(result.container)?.value).toBe("Jan 1, 2026 – Jan 31, 2026");
|
|
129
|
+
});
|
|
130
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("emits the comma-separated wire string once a range is picked", async () => {
|
|
134
|
+
const onChange = vi.fn();
|
|
135
|
+
const result = renderWithProviders(
|
|
136
|
+
<DateRangeField label="Period" value="2026-03-05,2026-03-31" onChange={onChange} />,
|
|
137
|
+
);
|
|
138
|
+
await act(async () => {
|
|
139
|
+
fireEvent.click(trigger(result.container)!);
|
|
140
|
+
});
|
|
141
|
+
// The panel opens on the range's own month; in the wide (dual-calendar)
|
|
142
|
+
// layout that is the LAST panel, the previous month being the first.
|
|
143
|
+
await waitFor(() => {
|
|
144
|
+
expect(getDayButton(15)).toBeTruthy();
|
|
145
|
+
});
|
|
146
|
+
// A complete range restarts on the next click, so this one only re-anchors.
|
|
147
|
+
await act(async () => {
|
|
148
|
+
fireEvent.click(getDayButton(15)!);
|
|
149
|
+
});
|
|
150
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
151
|
+
|
|
152
|
+
await act(async () => {
|
|
153
|
+
fireEvent.click(getDayButton(20)!);
|
|
154
|
+
});
|
|
155
|
+
expect(onChange).toHaveBeenCalledTimes(1);
|
|
156
|
+
expect(onChange).toHaveBeenCalledWith("2026-03-15,2026-03-20");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("clearing the range emits the empty wire value", async () => {
|
|
160
|
+
const onChange = vi.fn();
|
|
95
161
|
const result = renderWithProviders(
|
|
96
|
-
<DateRangeField label="Period" value="2026-
|
|
162
|
+
<DateRangeField label="Period" value="2026-03-05,2026-03-31" onChange={onChange} />,
|
|
97
163
|
);
|
|
98
|
-
|
|
164
|
+
await act(async () => {
|
|
165
|
+
fireEvent.click(
|
|
166
|
+
result.container.querySelector('[data-testid="date-picker-clear"]') as HTMLElement,
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
expect(onChange).toHaveBeenCalledWith("");
|
|
99
170
|
});
|
|
100
171
|
|
|
101
|
-
it("
|
|
172
|
+
it("the registry hands value and onChange straight to the adapter", () => {
|
|
102
173
|
const Component = getFieldComponent("Date Range")!;
|
|
103
174
|
const element = (Component as Function)({
|
|
104
175
|
value: "2026-01-01,2026-01-31",
|
|
@@ -106,6 +177,7 @@ describe("DateRangeField value gap (MPO-123)", () => {
|
|
|
106
177
|
} as FieldRenderProps) as React.ReactElement<Record<string, any>>;
|
|
107
178
|
expect(element.type).toBe(DateRangeField);
|
|
108
179
|
expect(element.props.value).toBe("2026-01-01,2026-01-31");
|
|
180
|
+
expect(typeof element.props.onChange).toBe("function");
|
|
109
181
|
});
|
|
110
182
|
});
|
|
111
183
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type { FormFieldProps, FieldComponentProps } from "@multiplatform.one/forms";
|
|
1
|
+
import type { DateRange, FormFieldProps, FieldComponentProps } from "@multiplatform.one/forms";
|
|
2
2
|
import { DateRangePicker as FormsDateRangePicker } from "@multiplatform.one/forms";
|
|
3
3
|
import type { DeepKeys } from "@tanstack/form-core";
|
|
4
|
+
import { useMemo } from "react";
|
|
4
5
|
import { useProps } from "tamagui";
|
|
6
|
+
import { fromFrappeDateValue, toFrappeDateValue } from "../Date/wire";
|
|
5
7
|
|
|
6
8
|
export type DateRangeFieldProps<
|
|
7
9
|
TData extends Record<string, unknown> = Record<string, unknown>,
|
|
@@ -37,6 +39,39 @@ export type DateRangeFieldProps<
|
|
|
37
39
|
placeholder?: string;
|
|
38
40
|
};
|
|
39
41
|
|
|
42
|
+
/**
|
|
43
|
+
* A `Date Range` is stored as its two ends, comma-separated, and each end is
|
|
44
|
+
* the same bare `YYYY-MM-DD` a `Date` field writes — so both ends serialize
|
|
45
|
+
* through the Date field's shared wire body rather than a second local-midnight
|
|
46
|
+
* parse that could drift from it.
|
|
47
|
+
*/
|
|
48
|
+
const rangeSeparator = ",";
|
|
49
|
+
|
|
50
|
+
function toPickerDate(value: string | undefined): Date | null {
|
|
51
|
+
if (!value) return null;
|
|
52
|
+
const date = fromFrappeDateValue(value, "date");
|
|
53
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* `undefined` stays undefined so uncontrolled (`defaultValue`-only) and
|
|
58
|
+
* form-bound use keep their semantics: the picker adopts an external value
|
|
59
|
+
* only when `value` is not undefined.
|
|
60
|
+
*/
|
|
61
|
+
function toPickerRange(value: string | undefined): DateRange | null | undefined {
|
|
62
|
+
if (value === undefined) return undefined;
|
|
63
|
+
if (!value) return null;
|
|
64
|
+
const [start, end] = value.split(rangeSeparator);
|
|
65
|
+
return { start: toPickerDate(start?.trim()), end: toPickerDate(end?.trim()) };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function toWireValue(range: DateRange | null): string {
|
|
69
|
+
if (!range?.start) return "";
|
|
70
|
+
const start = toFrappeDateValue(range.start, "date");
|
|
71
|
+
if (!range.end) return start;
|
|
72
|
+
return `${start}${rangeSeparator}${toFrappeDateValue(range.end, "date")}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
40
75
|
export function DateRangeField<
|
|
41
76
|
TData extends Record<string, unknown> = Record<string, unknown>,
|
|
42
77
|
TName extends string = string,
|
|
@@ -47,20 +82,29 @@ export function DateRangeField<
|
|
|
47
82
|
mode: _mode,
|
|
48
83
|
name,
|
|
49
84
|
onBlur: _onBlur,
|
|
50
|
-
onChange
|
|
85
|
+
onChange,
|
|
51
86
|
preserveValue: _preserveValue,
|
|
52
87
|
validators,
|
|
53
88
|
disabled,
|
|
54
|
-
value
|
|
89
|
+
value,
|
|
55
90
|
placeholder,
|
|
56
91
|
...fieldProps
|
|
57
92
|
} = useProps(props);
|
|
58
93
|
|
|
94
|
+
const wireValue = value as string | undefined;
|
|
95
|
+
const emit = onChange as ((value: string) => void) | undefined;
|
|
96
|
+
// Memoized so the Date identities are stable across renders: the picker
|
|
97
|
+
// re-seeds its display state from every new `value` identity, which would
|
|
98
|
+
// otherwise discard a half-picked range on an unrelated re-render.
|
|
99
|
+
const rangeValue = useMemo(() => toPickerRange(wireValue), [wireValue]);
|
|
100
|
+
|
|
59
101
|
return (
|
|
60
102
|
<FormsDateRangePicker
|
|
61
103
|
name={name}
|
|
62
104
|
form={form}
|
|
63
105
|
validators={validators}
|
|
106
|
+
value={rangeValue}
|
|
107
|
+
onChange={(range) => emit?.(toWireValue(range))}
|
|
64
108
|
defaultValue={defaultValue}
|
|
65
109
|
label={fieldProps.label}
|
|
66
110
|
labelProps={fieldProps.labelProps}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duration adapter contract specs. The Frappe Duration field is seconds in,
|
|
3
|
+
* seconds out; this file only pins that the hop to forms Duration keeps
|
|
4
|
+
* value / onChange / disabled / label / error. The segment math lives in
|
|
5
|
+
* the forms spec.
|
|
6
|
+
*/
|
|
7
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
8
|
+
import { cleanup, fireEvent } from "@testing-library/react";
|
|
9
|
+
import type React from "react";
|
|
10
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
11
|
+
import { getFieldComponent, type FieldRenderProps } from "../../fieldRegistry";
|
|
12
|
+
import { Duration } from ".";
|
|
13
|
+
|
|
14
|
+
afterEach(cleanup);
|
|
15
|
+
|
|
16
|
+
const hours = (container: HTMLElement) =>
|
|
17
|
+
container.querySelector('input[aria-label="Hours"]') as HTMLInputElement | null;
|
|
18
|
+
|
|
19
|
+
describe("Duration composes the forms Duration", () => {
|
|
20
|
+
it("paints a controlled seconds value into the hours segment", () => {
|
|
21
|
+
const result = renderWithProviders(<Duration label="Time" value={7200} onChange={() => {}} />);
|
|
22
|
+
expect(hours(result.container)?.value ?? hours(result.container)?.getAttribute("value")).toBe(
|
|
23
|
+
"2",
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("emits seconds through canonical onChange", () => {
|
|
28
|
+
const onChange = vi.fn();
|
|
29
|
+
const result = renderWithProviders(<Duration label="Time" value={3600} onChange={onChange} />);
|
|
30
|
+
fireEvent.keyDown(hours(result.container) as HTMLInputElement, { key: "ArrowUp" });
|
|
31
|
+
expect(onChange).toHaveBeenCalledWith(7200);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("forwards disabled onto the hours segment", () => {
|
|
35
|
+
const result = renderWithProviders(
|
|
36
|
+
<Duration label="Time" value={3600} disabled onChange={() => {}} />,
|
|
37
|
+
);
|
|
38
|
+
const el = hours(result.container);
|
|
39
|
+
expect(el?.getAttribute("aria-disabled") === "true" || el?.disabled).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("forwards readOnly onto the hours segment", () => {
|
|
43
|
+
const result = renderWithProviders(
|
|
44
|
+
<Duration label="Time" value={3600} readOnly onChange={() => {}} />,
|
|
45
|
+
);
|
|
46
|
+
const el = result.container.querySelector("input");
|
|
47
|
+
expect(el?.getAttribute("aria-readonly") === "true" || el?.readOnly).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("shows the label and error", () => {
|
|
51
|
+
const result = renderWithProviders(
|
|
52
|
+
<Duration label="Time" value={3600} error="not a duration" onChange={() => {}} />,
|
|
53
|
+
);
|
|
54
|
+
expect(result.container.textContent).toContain("Time");
|
|
55
|
+
expect(result.container.textContent).toContain("not a duration");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("registry resolution (Duration fieldtype)", () => {
|
|
60
|
+
function propsFor(overrides: Partial<FieldRenderProps> = {}): FieldRenderProps {
|
|
61
|
+
return { value: "", onChange: () => {}, ...overrides };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
it("resolves 'Duration' to the Duration adapter and coerces a non-number to 0", () => {
|
|
65
|
+
const Component = getFieldComponent("Duration")!;
|
|
66
|
+
const element = (Component as Function)(
|
|
67
|
+
propsFor({ value: "nope", label: "Time" }),
|
|
68
|
+
) as React.ReactElement<Record<string, unknown>>;
|
|
69
|
+
expect(element.type).toBe(Duration);
|
|
70
|
+
expect(element.props.value).toBe(0);
|
|
71
|
+
expect(element.props.label).toBe("Time");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MentionInputField contract specs. The registry hands `value` and `onChange`
|
|
3
|
+
* straight to this adapter (MentionAdapter in fieldRegistry). The failure
|
|
4
|
+
* mode of a thin adapter is dropping those two, so a saved comment never
|
|
5
|
+
* paints and a typed comment never emits (LC-14). Pin the hop.
|
|
6
|
+
*/
|
|
7
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
8
|
+
import { act, cleanup, fireEvent } from "@testing-library/react";
|
|
9
|
+
import type React from "react";
|
|
10
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
11
|
+
import { getFieldComponent, type FieldRenderProps } from "../../fieldRegistry";
|
|
12
|
+
import { MentionInputField, type MentionValue } from ".";
|
|
13
|
+
|
|
14
|
+
afterEach(cleanup);
|
|
15
|
+
|
|
16
|
+
const mentions = [{ trigger: "@", data: [{ id: "u1", display: "Ada" }] }];
|
|
17
|
+
|
|
18
|
+
const seeded: MentionValue = { text: "hello ada", mentions: [] };
|
|
19
|
+
|
|
20
|
+
const textarea = (container: HTMLElement) =>
|
|
21
|
+
container.querySelector("textarea") as HTMLTextAreaElement | null;
|
|
22
|
+
|
|
23
|
+
describe("MentionInputField composes the forms MentionInput", () => {
|
|
24
|
+
it("paints a controlled value onto the textarea", () => {
|
|
25
|
+
const result = renderWithProviders(
|
|
26
|
+
<MentionInputField label="Comment" mentions={mentions} value={seeded} onChange={() => {}} />,
|
|
27
|
+
);
|
|
28
|
+
expect(textarea(result.container)?.value).toBe("hello ada");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("emits a MentionValue through canonical onChange", async () => {
|
|
32
|
+
const onChange = vi.fn();
|
|
33
|
+
const result = renderWithProviders(
|
|
34
|
+
<MentionInputField
|
|
35
|
+
label="Comment"
|
|
36
|
+
mentions={mentions}
|
|
37
|
+
value={{ text: "", mentions: [] }}
|
|
38
|
+
onChange={onChange}
|
|
39
|
+
/>,
|
|
40
|
+
);
|
|
41
|
+
await act(async () => {
|
|
42
|
+
fireEvent.change(textarea(result.container) as HTMLTextAreaElement, {
|
|
43
|
+
target: { value: "typed" },
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
expect(onChange).toHaveBeenCalled();
|
|
47
|
+
const emitted = onChange.mock.calls.at(-1)?.[0] as MentionValue;
|
|
48
|
+
expect(emitted.text).toBe("typed");
|
|
49
|
+
expect(Array.isArray(emitted.mentions)).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("forwards disabled onto the textarea", () => {
|
|
53
|
+
const result = renderWithProviders(
|
|
54
|
+
<MentionInputField
|
|
55
|
+
label="Comment"
|
|
56
|
+
mentions={mentions}
|
|
57
|
+
value={seeded}
|
|
58
|
+
disabled
|
|
59
|
+
onChange={() => {}}
|
|
60
|
+
/>,
|
|
61
|
+
);
|
|
62
|
+
const el = textarea(result.container);
|
|
63
|
+
expect(el?.disabled || el?.getAttribute("aria-disabled") === "true").toBe(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("forwards readOnly onto the textarea", () => {
|
|
67
|
+
const result = renderWithProviders(
|
|
68
|
+
<MentionInputField
|
|
69
|
+
label="Comment"
|
|
70
|
+
mentions={mentions}
|
|
71
|
+
value={seeded}
|
|
72
|
+
readOnly
|
|
73
|
+
onChange={() => {}}
|
|
74
|
+
/>,
|
|
75
|
+
);
|
|
76
|
+
const el = textarea(result.container);
|
|
77
|
+
expect(el?.readOnly || el?.getAttribute("aria-readonly") === "true").toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("shows the label and error", () => {
|
|
81
|
+
const result = renderWithProviders(
|
|
82
|
+
<MentionInputField
|
|
83
|
+
label="Comment"
|
|
84
|
+
mentions={mentions}
|
|
85
|
+
value={seeded}
|
|
86
|
+
error="too short"
|
|
87
|
+
onChange={() => {}}
|
|
88
|
+
/>,
|
|
89
|
+
);
|
|
90
|
+
expect(result.container.textContent).toContain("Comment");
|
|
91
|
+
expect(result.container.textContent).toContain("too short");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("registry resolution (Mention fieldtype)", () => {
|
|
96
|
+
function propsFor(overrides: Partial<FieldRenderProps> = {}): FieldRenderProps {
|
|
97
|
+
return { value: "", onChange: () => {}, ...overrides };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
it("resolves 'Mention' to MentionInputField and hands value through", () => {
|
|
101
|
+
const Component = getFieldComponent("Mention")!;
|
|
102
|
+
expect(Component).toBeTruthy();
|
|
103
|
+
const element = (Component as Function)(
|
|
104
|
+
propsFor({ value: "hello ada", label: "Comment" }),
|
|
105
|
+
) as React.ReactElement<Record<string, unknown>>;
|
|
106
|
+
expect(element.type).toBe(MentionInputField);
|
|
107
|
+
expect(element.props.value).toBe("hello ada");
|
|
108
|
+
expect(element.props.label).toBe("Comment");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -79,7 +79,8 @@ export function MentionInputField<
|
|
|
79
79
|
_preserveValue,
|
|
80
80
|
validators,
|
|
81
81
|
disabled,
|
|
82
|
-
|
|
82
|
+
value,
|
|
83
|
+
onChange,
|
|
83
84
|
mentions,
|
|
84
85
|
placeholder,
|
|
85
86
|
onMentionSelect,
|
|
@@ -103,6 +104,8 @@ export function MentionInputField<
|
|
|
103
104
|
id={fieldProps.id}
|
|
104
105
|
size={fieldProps.size}
|
|
105
106
|
disabled={disabled}
|
|
107
|
+
value={value}
|
|
108
|
+
onChange={onChange}
|
|
106
109
|
mentions={mentions ?? []}
|
|
107
110
|
placeholder={placeholder}
|
|
108
111
|
onMentionSelect={onMentionSelect}
|
|
@@ -57,6 +57,15 @@ describe("ProgressField chrome", () => {
|
|
|
57
57
|
expect(container.firstElementChild).toBeTruthy();
|
|
58
58
|
expect(container.textContent).toContain("Completion");
|
|
59
59
|
});
|
|
60
|
+
|
|
61
|
+
it("forwards the controlled value onto the progressbar", () => {
|
|
62
|
+
const { container } = renderWithProviders(
|
|
63
|
+
<ProgressField label="Completion" value={65} max={100} />,
|
|
64
|
+
);
|
|
65
|
+
expect(container.querySelector("[role='progressbar']")?.getAttribute("aria-valuenow")).toBe(
|
|
66
|
+
"65",
|
|
67
|
+
);
|
|
68
|
+
});
|
|
60
69
|
});
|
|
61
70
|
|
|
62
71
|
/**
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RadioGroupField contract specs. The adapter maps `onChange` onto the forms
|
|
3
|
+
* RadioGroup's `onValueChange`. Pin that value, onChange, disabled, label
|
|
4
|
+
* and error survive the hop.
|
|
5
|
+
*/
|
|
6
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
7
|
+
import { act, cleanup, fireEvent } from "@testing-library/react";
|
|
8
|
+
import type React from "react";
|
|
9
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
10
|
+
import { getFieldComponent, type FieldRenderProps } from "../../fieldRegistry";
|
|
11
|
+
import { RadioGroupField } from ".";
|
|
12
|
+
|
|
13
|
+
afterEach(cleanup);
|
|
14
|
+
|
|
15
|
+
const options = [
|
|
16
|
+
{ label: "Red", value: "red" },
|
|
17
|
+
{ label: "Blue", value: "blue" },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const radios = (container: HTMLElement) =>
|
|
21
|
+
Array.from(container.querySelectorAll('[role="radio"]')) as HTMLElement[];
|
|
22
|
+
|
|
23
|
+
describe("RadioGroupField composes the forms RadioGroup", () => {
|
|
24
|
+
it("paints a controlled value onto the matching radio", () => {
|
|
25
|
+
const result = renderWithProviders(
|
|
26
|
+
<RadioGroupField label="Color" value="blue" options={options} onChange={() => {}} />,
|
|
27
|
+
);
|
|
28
|
+
const all = radios(result.container);
|
|
29
|
+
const checked = all.find((el) => el.getAttribute("aria-checked") === "true");
|
|
30
|
+
expect(checked).toBeTruthy();
|
|
31
|
+
// option order is Red, Blue — the disc itself has no text
|
|
32
|
+
expect(checked).toBe(all[1]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("emits the option value through canonical onChange", async () => {
|
|
36
|
+
const onChange = vi.fn();
|
|
37
|
+
const result = renderWithProviders(
|
|
38
|
+
<RadioGroupField label="Color" value="red" options={options} onChange={onChange} />,
|
|
39
|
+
);
|
|
40
|
+
const blue = radios(result.container).find((el) => (el.textContent || "").includes("Blue"));
|
|
41
|
+
expect(blue || radios(result.container)[1]).toBeTruthy();
|
|
42
|
+
await act(async () => {
|
|
43
|
+
fireEvent.click(blue ?? radios(result.container)[1]);
|
|
44
|
+
});
|
|
45
|
+
expect(onChange).toHaveBeenCalledWith("blue");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("forwards disabled onto the radios", () => {
|
|
49
|
+
const result = renderWithProviders(
|
|
50
|
+
<RadioGroupField label="Color" value="red" options={options} disabled onChange={() => {}} />,
|
|
51
|
+
);
|
|
52
|
+
const el = radios(result.container)[0];
|
|
53
|
+
expect(el?.getAttribute("aria-disabled") === "true" || el?.hasAttribute("disabled")).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("shows the label and error", () => {
|
|
57
|
+
const result = renderWithProviders(
|
|
58
|
+
<RadioGroupField
|
|
59
|
+
label="Color"
|
|
60
|
+
value="red"
|
|
61
|
+
options={options}
|
|
62
|
+
error="pick one"
|
|
63
|
+
onChange={() => {}}
|
|
64
|
+
/>,
|
|
65
|
+
);
|
|
66
|
+
expect(result.container.textContent).toContain("Color");
|
|
67
|
+
expect(result.container.textContent).toContain("pick one");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe("registry resolution (Radio fieldtype)", () => {
|
|
72
|
+
function propsFor(overrides: Partial<FieldRenderProps> = {}): FieldRenderProps {
|
|
73
|
+
return { value: "", onChange: () => {}, ...overrides };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
it("resolves 'Radio' to RadioGroupField and splits df.options on newlines", () => {
|
|
77
|
+
const Component = getFieldComponent("Radio")!;
|
|
78
|
+
const element = (Component as Function)(
|
|
79
|
+
propsFor({
|
|
80
|
+
value: "Red",
|
|
81
|
+
label: "Color",
|
|
82
|
+
fieldMeta: { options: "Red\nBlue" },
|
|
83
|
+
} as Partial<FieldRenderProps>),
|
|
84
|
+
) as React.ReactElement<Record<string, unknown>>;
|
|
85
|
+
expect(element.type).toBe(RadioGroupField);
|
|
86
|
+
expect(element.props.value).toBe("Red");
|
|
87
|
+
expect(element.props.label).toBe("Color");
|
|
88
|
+
expect(element.props.options).toEqual([
|
|
89
|
+
{ label: "Red", value: "Red" },
|
|
90
|
+
{ label: "Blue", value: "Blue" },
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signature adapter contract specs. The Frappe Signature field stores a
|
|
3
|
+
* data URL; this adapter must hand value / onChange / disabled / label /
|
|
4
|
+
* error to the forms Signature pad. Drawing lives in the forms spec.
|
|
5
|
+
*/
|
|
6
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
7
|
+
import { cleanup, fireEvent } from "@testing-library/react";
|
|
8
|
+
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
|
9
|
+
import { getFieldComponent, type FieldRenderProps } from "../../fieldRegistry";
|
|
10
|
+
import type React from "react";
|
|
11
|
+
import { Signature } from ".";
|
|
12
|
+
|
|
13
|
+
function encodeSignature(strokes: number[][][]): string {
|
|
14
|
+
const json = JSON.stringify({ v: 2, s: strokes });
|
|
15
|
+
return `data:application/json;base64,${btoa(json)}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const inkedValue = encodeSignature([
|
|
19
|
+
[
|
|
20
|
+
[0.1, 0.2, 0.5],
|
|
21
|
+
[0.4, 0.3, 0.5],
|
|
22
|
+
[0.7, 0.25, 0.5],
|
|
23
|
+
],
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
function getPad(container: HTMLElement): HTMLElement {
|
|
27
|
+
const label = container.querySelector("label[for]") as HTMLLabelElement | null;
|
|
28
|
+
const id = label?.htmlFor;
|
|
29
|
+
const pad = id ? (container.querySelector(`#${CSS.escape(id)}`) as HTMLElement | null) : null;
|
|
30
|
+
if (!pad) throw new Error("signature pad not found");
|
|
31
|
+
return pad;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
beforeAll(() => {
|
|
35
|
+
HTMLCanvasElement.prototype.getContext = vi.fn(() => ({
|
|
36
|
+
clearRect: vi.fn(),
|
|
37
|
+
beginPath: vi.fn(),
|
|
38
|
+
moveTo: vi.fn(),
|
|
39
|
+
lineTo: vi.fn(),
|
|
40
|
+
stroke: vi.fn(),
|
|
41
|
+
fillRect: vi.fn(),
|
|
42
|
+
drawImage: vi.fn(),
|
|
43
|
+
})) as unknown as typeof HTMLCanvasElement.prototype.getContext;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(cleanup);
|
|
47
|
+
|
|
48
|
+
describe("Signature composes the forms Signature", () => {
|
|
49
|
+
it("paints a controlled value as a signed pad", () => {
|
|
50
|
+
const result = renderWithProviders(
|
|
51
|
+
<Signature label="Sign here" value={inkedValue} onChange={() => {}} />,
|
|
52
|
+
);
|
|
53
|
+
expect(getPad(result.container).getAttribute("data-signed")).toBe("true");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("emits an empty string through canonical onChange on Delete", () => {
|
|
57
|
+
const onChange = vi.fn();
|
|
58
|
+
const result = renderWithProviders(
|
|
59
|
+
<Signature label="Sign here" value={inkedValue} onChange={onChange} />,
|
|
60
|
+
);
|
|
61
|
+
const pad = getPad(result.container);
|
|
62
|
+
fireEvent.focus(pad);
|
|
63
|
+
fireEvent.keyDown(pad, { key: "Delete" });
|
|
64
|
+
expect(onChange).toHaveBeenCalledWith("");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("forwards readOnly onto the pad", () => {
|
|
68
|
+
const result = renderWithProviders(
|
|
69
|
+
<Signature label="Sign here" value={inkedValue} readOnly onChange={() => {}} />,
|
|
70
|
+
);
|
|
71
|
+
expect(getPad(result.container).getAttribute("aria-readonly")).toBe("true");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("forwards disabled onto the pad", () => {
|
|
75
|
+
const result = renderWithProviders(
|
|
76
|
+
<Signature label="Sign here" value={inkedValue} disabled onChange={() => {}} />,
|
|
77
|
+
);
|
|
78
|
+
const pad = getPad(result.container);
|
|
79
|
+
expect(pad.getAttribute("aria-disabled") === "true" || pad.hasAttribute("disabled")).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("shows the label and error", () => {
|
|
83
|
+
const result = renderWithProviders(
|
|
84
|
+
<Signature label="Sign here" value="" error="signature required" onChange={() => {}} />,
|
|
85
|
+
);
|
|
86
|
+
expect(result.container.textContent).toContain("Sign here");
|
|
87
|
+
expect(result.container.textContent).toContain("signature required");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("registry resolution (Signature fieldtype)", () => {
|
|
92
|
+
function propsFor(overrides: Partial<FieldRenderProps> = {}): FieldRenderProps {
|
|
93
|
+
return { value: "", onChange: () => {}, ...overrides };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
it("resolves 'Signature' to the Signature adapter and hands value through", () => {
|
|
97
|
+
const Component = getFieldComponent("Signature")!;
|
|
98
|
+
const element = (Component as Function)(
|
|
99
|
+
propsFor({ value: inkedValue, label: "Sign here" }),
|
|
100
|
+
) as React.ReactElement<Record<string, unknown>>;
|
|
101
|
+
expect(element.type).toBe(Signature);
|
|
102
|
+
expect(element.props.value).toBe(inkedValue);
|
|
103
|
+
expect(element.props.label).toBe("Sign here");
|
|
104
|
+
});
|
|
105
|
+
});
|