@multiplatform.one/frappe-ui 7.46.0 → 7.47.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/FileBrowser/index.cjs +1 -1
- package/dist/cjs/FileBrowser/index.native.js +1 -1
- package/dist/cjs/FileBrowser/index.native.js.map +1 -1
- package/dist/cjs/FrappeCalendar.cjs +2 -2
- package/dist/cjs/FrappeCalendar.native.js +2 -2
- package/dist/cjs/FrappeCalendar.native.js.map +1 -1
- package/dist/cjs/FrappeConnectionIndicator.cjs +2 -1
- package/dist/cjs/FrappeConnectionIndicator.native.js +2 -1
- package/dist/cjs/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/cjs/FrappeDashboard.cjs +1 -1
- package/dist/cjs/FrappeDashboard.native.js +1 -1
- package/dist/cjs/FrappeDashboard.native.js.map +1 -1
- package/dist/cjs/FrappeForm.cjs +54 -29
- package/dist/cjs/FrappeForm.native.js +56 -28
- package/dist/cjs/FrappeForm.native.js.map +1 -1
- package/dist/cjs/FrappeFormActions.cjs +121 -0
- package/dist/cjs/FrappeFormActions.native.js +123 -0
- package/dist/cjs/FrappeFormActions.native.js.map +1 -1
- package/dist/cjs/FrappeInsights.cjs +4 -1
- package/dist/cjs/FrappeInsights.native.js +4 -6
- package/dist/cjs/FrappeInsights.native.js.map +1 -1
- package/dist/cjs/FrappeKanban.cjs +1 -1
- package/dist/cjs/FrappeKanban.native.js +1 -1
- package/dist/cjs/FrappeKanban.native.js.map +1 -1
- package/dist/cjs/FrappeListView.cjs +1 -1
- package/dist/cjs/FrappeListView.native.js +4 -7
- package/dist/cjs/FrappeListView.native.js.map +1 -1
- package/dist/cjs/FrappeReconnectIndicator.cjs +2 -1
- package/dist/cjs/FrappeReconnectIndicator.native.js +2 -1
- package/dist/cjs/FrappeReconnectIndicator.native.js.map +1 -1
- package/dist/cjs/SyncErrorNotice.cjs +1 -1
- package/dist/cjs/SyncErrorNotice.native.js +1 -1
- package/dist/cjs/SyncErrorNotice.native.js.map +1 -1
- package/dist/cjs/desk/DeskFormPage.cjs +28 -42
- package/dist/cjs/desk/DeskFormPage.native.js +42 -58
- package/dist/cjs/desk/DeskFormPage.native.js.map +1 -1
- package/dist/cjs/desk/DeskShell.cjs +1 -1
- package/dist/cjs/desk/DeskShell.native.js +1 -1
- package/dist/cjs/desk/DeskShell.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/fields/CodeEditor/index.cjs +1 -1
- package/dist/cjs/fields/CodeEditor/index.native.js +1 -1
- package/dist/cjs/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/cjs/fields/Date/index.native.js +5 -4
- package/dist/cjs/fields/Date/index.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload.cjs +10 -8
- package/dist/cjs/fields/FileUpload.native.js +10 -8
- package/dist/cjs/fields/FileUpload.native.js.map +1 -1
- package/dist/cjs/fields/FileUploadField/index.cjs +50 -4
- package/dist/cjs/fields/FileUploadField/index.native.js +54 -5
- package/dist/cjs/fields/FileUploadField/index.native.js.map +1 -1
- package/dist/cjs/fields/Heading/index.cjs +1 -1
- package/dist/cjs/fields/Heading/index.native.js +1 -1
- package/dist/cjs/fields/Heading/index.native.js.map +1 -1
- package/dist/cjs/fields/MarkdownEditor/index.native.js +3 -2
- package/dist/cjs/fields/MarkdownEditor/index.native.js.map +1 -1
- package/dist/cjs/fields/Numeric/index.cjs +3 -2
- package/dist/cjs/fields/Numeric/index.native.js +3 -2
- package/dist/cjs/fields/Numeric/index.native.js.map +1 -1
- package/dist/cjs/fields/Password/index.cjs +18 -62
- package/dist/cjs/fields/Password/index.native.js +18 -65
- package/dist/cjs/fields/Password/index.native.js.map +1 -1
- package/dist/cjs/fields/ReadOnly/index.cjs +2 -1
- package/dist/cjs/fields/ReadOnly/index.native.js +2 -1
- package/dist/cjs/fields/ReadOnly/index.native.js.map +1 -1
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.native.js +2 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/insights/InsightsLeaders.cjs +2 -2
- package/dist/cjs/insights/InsightsLeaders.native.js +2 -2
- package/dist/cjs/insights/InsightsLeaders.native.js.map +1 -1
- package/dist/cjs/insights/InsightsRecords.cjs +2 -2
- package/dist/cjs/insights/InsightsRecords.native.js +2 -2
- package/dist/cjs/insights/InsightsRecords.native.js.map +1 -1
- package/dist/cjs/list/FacetBadge.cjs +4 -3
- package/dist/cjs/list/FacetBadge.native.js +4 -3
- package/dist/cjs/list/FacetBadge.native.js.map +1 -1
- package/dist/cjs/list/ImageWell.cjs +6 -18
- package/dist/cjs/list/ImageWell.native.js +7 -19
- package/dist/cjs/list/ImageWell.native.js.map +1 -1
- package/dist/cjs/list/RecordCard.cjs +2 -2
- package/dist/cjs/list/RecordCard.native.js +2 -2
- package/dist/cjs/list/RecordCard.native.js.map +1 -1
- package/dist/cjs/list/facetBadgeSteps.cjs +32 -0
- package/dist/cjs/list/facetBadgeSteps.native.js +35 -0
- package/dist/cjs/list/facetBadgeSteps.native.js.map +1 -0
- package/dist/cjs/record/RecordHero.cjs +4 -15
- package/dist/cjs/record/RecordHero.native.js +4 -15
- package/dist/cjs/record/RecordHero.native.js.map +1 -1
- package/dist/cjs/record/RecordPage.cjs +4 -4
- package/dist/cjs/record/RecordPage.native.js +7 -10
- package/dist/cjs/record/RecordPage.native.js.map +1 -1
- package/dist/cjs/report/ReportGrid.cjs +6 -6
- package/dist/cjs/report/ReportGrid.native.js +11 -7
- package/dist/cjs/report/ReportGrid.native.js.map +1 -1
- package/dist/cjs/schemaForm/index.cjs +3 -3
- package/dist/cjs/schemaForm/index.native.js +3 -3
- package/dist/cjs/schemaForm/index.native.js.map +1 -1
- package/dist/esm/FileBrowser/index.mjs +8 -8
- package/dist/esm/FileBrowser/index.mjs.map +1 -1
- package/dist/esm/FileBrowser/index.native.js +8 -8
- package/dist/esm/FileBrowser/index.native.js.map +1 -1
- package/dist/esm/FrappeCalendar.mjs +6 -6
- package/dist/esm/FrappeCalendar.mjs.map +1 -1
- package/dist/esm/FrappeCalendar.native.js +6 -6
- package/dist/esm/FrappeCalendar.native.js.map +1 -1
- package/dist/esm/FrappeConnectionIndicator.mjs +2 -1
- package/dist/esm/FrappeConnectionIndicator.mjs.map +1 -1
- package/dist/esm/FrappeConnectionIndicator.native.js +2 -1
- package/dist/esm/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/esm/FrappeDashboard.mjs +6 -6
- package/dist/esm/FrappeDashboard.mjs.map +1 -1
- package/dist/esm/FrappeDashboard.native.js +6 -6
- package/dist/esm/FrappeDashboard.native.js.map +1 -1
- package/dist/esm/FrappeForm.mjs +52 -27
- package/dist/esm/FrappeForm.mjs.map +1 -1
- package/dist/esm/FrappeForm.native.js +56 -28
- package/dist/esm/FrappeForm.native.js.map +1 -1
- package/dist/esm/FrappeFormActions.mjs +122 -2
- package/dist/esm/FrappeFormActions.mjs.map +1 -1
- package/dist/esm/FrappeFormActions.native.js +124 -2
- package/dist/esm/FrappeFormActions.native.js.map +1 -1
- package/dist/esm/FrappeInsights.mjs +4 -1
- package/dist/esm/FrappeInsights.mjs.map +1 -1
- package/dist/esm/FrappeInsights.native.js +4 -6
- package/dist/esm/FrappeInsights.native.js.map +1 -1
- package/dist/esm/FrappeKanban.mjs +5 -5
- package/dist/esm/FrappeKanban.mjs.map +1 -1
- package/dist/esm/FrappeKanban.native.js +5 -5
- package/dist/esm/FrappeKanban.native.js.map +1 -1
- package/dist/esm/FrappeListView.mjs +1 -1
- package/dist/esm/FrappeListView.mjs.map +1 -1
- package/dist/esm/FrappeListView.native.js +4 -7
- package/dist/esm/FrappeListView.native.js.map +1 -1
- package/dist/esm/FrappeReconnectIndicator.mjs +2 -1
- package/dist/esm/FrappeReconnectIndicator.mjs.map +1 -1
- package/dist/esm/FrappeReconnectIndicator.native.js +2 -1
- package/dist/esm/FrappeReconnectIndicator.native.js.map +1 -1
- package/dist/esm/SyncErrorNotice.mjs +2 -2
- package/dist/esm/SyncErrorNotice.mjs.map +1 -1
- package/dist/esm/SyncErrorNotice.native.js +2 -2
- package/dist/esm/SyncErrorNotice.native.js.map +1 -1
- package/dist/esm/desk/DeskFormPage.mjs +29 -43
- package/dist/esm/desk/DeskFormPage.mjs.map +1 -1
- package/dist/esm/desk/DeskFormPage.native.js +43 -59
- package/dist/esm/desk/DeskFormPage.native.js.map +1 -1
- package/dist/esm/desk/DeskShell.mjs +1 -1
- package/dist/esm/desk/DeskShell.mjs.map +1 -1
- package/dist/esm/desk/DeskShell.native.js +1 -1
- package/dist/esm/desk/DeskShell.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/fields/CodeEditor/index.mjs +3 -3
- package/dist/esm/fields/CodeEditor/index.mjs.map +1 -1
- package/dist/esm/fields/CodeEditor/index.native.js +3 -3
- package/dist/esm/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/esm/fields/Date/index.native.js +2 -1
- package/dist/esm/fields/Date/index.native.js.map +1 -1
- package/dist/esm/fields/FileUpload.mjs +5 -3
- package/dist/esm/fields/FileUpload.mjs.map +1 -1
- package/dist/esm/fields/FileUpload.native.js +5 -3
- package/dist/esm/fields/FileUpload.native.js.map +1 -1
- package/dist/esm/fields/FileUploadField/index.mjs +52 -6
- package/dist/esm/fields/FileUploadField/index.mjs.map +1 -1
- package/dist/esm/fields/FileUploadField/index.native.js +56 -7
- package/dist/esm/fields/FileUploadField/index.native.js.map +1 -1
- package/dist/esm/fields/Heading/index.mjs +3 -3
- package/dist/esm/fields/Heading/index.mjs.map +1 -1
- package/dist/esm/fields/Heading/index.native.js +3 -3
- package/dist/esm/fields/Heading/index.native.js.map +1 -1
- package/dist/esm/fields/MarkdownEditor/index.native.js +2 -1
- package/dist/esm/fields/MarkdownEditor/index.native.js.map +1 -1
- package/dist/esm/fields/Numeric/index.mjs +2 -1
- package/dist/esm/fields/Numeric/index.mjs.map +1 -1
- package/dist/esm/fields/Numeric/index.native.js +2 -1
- package/dist/esm/fields/Numeric/index.native.js.map +1 -1
- package/dist/esm/fields/Password/index.mjs +16 -60
- package/dist/esm/fields/Password/index.mjs.map +1 -1
- package/dist/esm/fields/Password/index.native.js +16 -63
- package/dist/esm/fields/Password/index.native.js.map +1 -1
- package/dist/esm/fields/ReadOnly/index.mjs +7 -6
- package/dist/esm/fields/ReadOnly/index.mjs.map +1 -1
- package/dist/esm/fields/ReadOnly/index.native.js +7 -6
- package/dist/esm/fields/ReadOnly/index.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/insights/InsightsLeaders.mjs +2 -2
- package/dist/esm/insights/InsightsLeaders.mjs.map +1 -1
- package/dist/esm/insights/InsightsLeaders.native.js +2 -2
- package/dist/esm/insights/InsightsLeaders.native.js.map +1 -1
- package/dist/esm/insights/InsightsRecords.mjs +2 -2
- package/dist/esm/insights/InsightsRecords.mjs.map +1 -1
- package/dist/esm/insights/InsightsRecords.native.js +2 -2
- package/dist/esm/insights/InsightsRecords.native.js.map +1 -1
- package/dist/esm/list/FacetBadge.mjs +4 -3
- package/dist/esm/list/FacetBadge.mjs.map +1 -1
- package/dist/esm/list/FacetBadge.native.js +4 -3
- package/dist/esm/list/FacetBadge.native.js.map +1 -1
- package/dist/esm/list/ImageWell.mjs +8 -20
- package/dist/esm/list/ImageWell.mjs.map +1 -1
- package/dist/esm/list/ImageWell.native.js +9 -21
- package/dist/esm/list/ImageWell.native.js.map +1 -1
- package/dist/esm/list/RecordCard.mjs +2 -2
- package/dist/esm/list/RecordCard.mjs.map +1 -1
- package/dist/esm/list/RecordCard.native.js +2 -2
- package/dist/esm/list/RecordCard.native.js.map +1 -1
- package/dist/esm/list/facetBadgeSteps.mjs +7 -0
- package/dist/esm/list/facetBadgeSteps.mjs.map +1 -0
- package/dist/esm/list/facetBadgeSteps.native.js +7 -0
- package/dist/esm/list/facetBadgeSteps.native.js.map +1 -0
- package/dist/esm/record/RecordHero.mjs +4 -15
- package/dist/esm/record/RecordHero.mjs.map +1 -1
- package/dist/esm/record/RecordHero.native.js +4 -15
- package/dist/esm/record/RecordHero.native.js.map +1 -1
- package/dist/esm/record/RecordPage.mjs +4 -4
- package/dist/esm/record/RecordPage.mjs.map +1 -1
- package/dist/esm/record/RecordPage.native.js +7 -10
- package/dist/esm/record/RecordPage.native.js.map +1 -1
- package/dist/esm/report/ReportGrid.mjs +7 -7
- package/dist/esm/report/ReportGrid.mjs.map +1 -1
- package/dist/esm/report/ReportGrid.native.js +12 -8
- package/dist/esm/report/ReportGrid.native.js.map +1 -1
- package/dist/esm/schemaForm/index.mjs +4 -4
- package/dist/esm/schemaForm/index.mjs.map +1 -1
- package/dist/esm/schemaForm/index.native.js +4 -4
- package/dist/esm/schemaForm/index.native.js.map +1 -1
- package/dist/jsx/FileBrowser/index.mjs +8 -8
- package/dist/jsx/FileBrowser/index.mjs.map +1 -1
- package/dist/jsx/FileBrowser/index.native.js +1 -1
- package/dist/jsx/FileBrowser/index.native.js.map +1 -1
- package/dist/jsx/FrappeCalendar.mjs +6 -6
- package/dist/jsx/FrappeCalendar.mjs.map +1 -1
- package/dist/jsx/FrappeCalendar.native.js +2 -2
- package/dist/jsx/FrappeCalendar.native.js.map +1 -1
- package/dist/jsx/FrappeConnectionIndicator.mjs +2 -1
- package/dist/jsx/FrappeConnectionIndicator.mjs.map +1 -1
- package/dist/jsx/FrappeConnectionIndicator.native.js +2 -1
- package/dist/jsx/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/jsx/FrappeDashboard.mjs +6 -6
- package/dist/jsx/FrappeDashboard.mjs.map +1 -1
- package/dist/jsx/FrappeDashboard.native.js +1 -1
- package/dist/jsx/FrappeDashboard.native.js.map +1 -1
- package/dist/jsx/FrappeForm.mjs +52 -27
- package/dist/jsx/FrappeForm.mjs.map +1 -1
- package/dist/jsx/FrappeForm.native.js +56 -28
- package/dist/jsx/FrappeForm.native.js.map +1 -1
- package/dist/jsx/FrappeFormActions.mjs +122 -2
- package/dist/jsx/FrappeFormActions.mjs.map +1 -1
- package/dist/jsx/FrappeFormActions.native.js +123 -0
- package/dist/jsx/FrappeFormActions.native.js.map +1 -1
- package/dist/jsx/FrappeInsights.mjs +4 -1
- package/dist/jsx/FrappeInsights.mjs.map +1 -1
- package/dist/jsx/FrappeInsights.native.js +4 -6
- package/dist/jsx/FrappeInsights.native.js.map +1 -1
- package/dist/jsx/FrappeKanban.mjs +5 -5
- package/dist/jsx/FrappeKanban.mjs.map +1 -1
- package/dist/jsx/FrappeKanban.native.js +1 -1
- package/dist/jsx/FrappeKanban.native.js.map +1 -1
- package/dist/jsx/FrappeListView.mjs +1 -1
- package/dist/jsx/FrappeListView.mjs.map +1 -1
- package/dist/jsx/FrappeListView.native.js +4 -7
- package/dist/jsx/FrappeListView.native.js.map +1 -1
- package/dist/jsx/FrappeReconnectIndicator.mjs +2 -1
- package/dist/jsx/FrappeReconnectIndicator.mjs.map +1 -1
- package/dist/jsx/FrappeReconnectIndicator.native.js +2 -1
- package/dist/jsx/FrappeReconnectIndicator.native.js.map +1 -1
- package/dist/jsx/SyncErrorNotice.mjs +2 -2
- package/dist/jsx/SyncErrorNotice.mjs.map +1 -1
- package/dist/jsx/SyncErrorNotice.native.js +1 -1
- package/dist/jsx/SyncErrorNotice.native.js.map +1 -1
- package/dist/jsx/desk/DeskFormPage.mjs +29 -43
- package/dist/jsx/desk/DeskFormPage.mjs.map +1 -1
- package/dist/jsx/desk/DeskFormPage.native.js +42 -58
- package/dist/jsx/desk/DeskFormPage.native.js.map +1 -1
- package/dist/jsx/desk/DeskShell.mjs +1 -1
- package/dist/jsx/desk/DeskShell.mjs.map +1 -1
- package/dist/jsx/desk/DeskShell.native.js +1 -1
- 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/CodeEditor/index.mjs +3 -3
- package/dist/jsx/fields/CodeEditor/index.mjs.map +1 -1
- package/dist/jsx/fields/CodeEditor/index.native.js +1 -1
- package/dist/jsx/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/jsx/fields/Date/index.native.js +5 -4
- package/dist/jsx/fields/Date/index.native.js.map +1 -1
- package/dist/jsx/fields/FileUpload.mjs +5 -3
- package/dist/jsx/fields/FileUpload.mjs.map +1 -1
- package/dist/jsx/fields/FileUpload.native.js +10 -8
- package/dist/jsx/fields/FileUpload.native.js.map +1 -1
- package/dist/jsx/fields/FileUploadField/index.mjs +52 -6
- package/dist/jsx/fields/FileUploadField/index.mjs.map +1 -1
- package/dist/jsx/fields/FileUploadField/index.native.js +54 -5
- package/dist/jsx/fields/FileUploadField/index.native.js.map +1 -1
- package/dist/jsx/fields/Heading/index.mjs +3 -3
- package/dist/jsx/fields/Heading/index.mjs.map +1 -1
- package/dist/jsx/fields/Heading/index.native.js +1 -1
- package/dist/jsx/fields/Heading/index.native.js.map +1 -1
- package/dist/jsx/fields/MarkdownEditor/index.native.js +3 -2
- package/dist/jsx/fields/MarkdownEditor/index.native.js.map +1 -1
- package/dist/jsx/fields/Numeric/index.mjs +2 -1
- package/dist/jsx/fields/Numeric/index.mjs.map +1 -1
- package/dist/jsx/fields/Numeric/index.native.js +3 -2
- package/dist/jsx/fields/Numeric/index.native.js.map +1 -1
- package/dist/jsx/fields/Password/index.mjs +16 -60
- package/dist/jsx/fields/Password/index.mjs.map +1 -1
- package/dist/jsx/fields/Password/index.native.js +18 -65
- package/dist/jsx/fields/Password/index.native.js.map +1 -1
- package/dist/jsx/fields/ReadOnly/index.mjs +7 -6
- package/dist/jsx/fields/ReadOnly/index.mjs.map +1 -1
- package/dist/jsx/fields/ReadOnly/index.native.js +2 -1
- package/dist/jsx/fields/ReadOnly/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 +2 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/insights/InsightsLeaders.mjs +2 -2
- package/dist/jsx/insights/InsightsLeaders.mjs.map +1 -1
- package/dist/jsx/insights/InsightsLeaders.native.js +2 -2
- package/dist/jsx/insights/InsightsLeaders.native.js.map +1 -1
- package/dist/jsx/insights/InsightsRecords.mjs +2 -2
- package/dist/jsx/insights/InsightsRecords.mjs.map +1 -1
- package/dist/jsx/insights/InsightsRecords.native.js +2 -2
- package/dist/jsx/insights/InsightsRecords.native.js.map +1 -1
- package/dist/jsx/list/FacetBadge.mjs +4 -3
- package/dist/jsx/list/FacetBadge.mjs.map +1 -1
- package/dist/jsx/list/FacetBadge.native.js +4 -3
- package/dist/jsx/list/FacetBadge.native.js.map +1 -1
- package/dist/jsx/list/ImageWell.mjs +8 -20
- package/dist/jsx/list/ImageWell.mjs.map +1 -1
- package/dist/jsx/list/ImageWell.native.js +7 -19
- package/dist/jsx/list/ImageWell.native.js.map +1 -1
- package/dist/jsx/list/RecordCard.mjs +2 -2
- package/dist/jsx/list/RecordCard.mjs.map +1 -1
- package/dist/jsx/list/RecordCard.native.js +2 -2
- package/dist/jsx/list/RecordCard.native.js.map +1 -1
- package/dist/jsx/list/facetBadgeSteps.mjs +7 -0
- package/dist/jsx/list/facetBadgeSteps.mjs.map +1 -0
- package/dist/jsx/list/facetBadgeSteps.native.js +35 -0
- package/dist/jsx/list/facetBadgeSteps.native.js.map +1 -0
- package/dist/jsx/record/RecordHero.mjs +4 -15
- package/dist/jsx/record/RecordHero.mjs.map +1 -1
- package/dist/jsx/record/RecordHero.native.js +4 -15
- package/dist/jsx/record/RecordHero.native.js.map +1 -1
- package/dist/jsx/record/RecordPage.mjs +4 -4
- package/dist/jsx/record/RecordPage.mjs.map +1 -1
- package/dist/jsx/record/RecordPage.native.js +7 -10
- package/dist/jsx/record/RecordPage.native.js.map +1 -1
- package/dist/jsx/report/ReportGrid.mjs +7 -7
- package/dist/jsx/report/ReportGrid.mjs.map +1 -1
- package/dist/jsx/report/ReportGrid.native.js +11 -7
- package/dist/jsx/report/ReportGrid.native.js.map +1 -1
- package/dist/jsx/schemaForm/index.mjs +4 -4
- package/dist/jsx/schemaForm/index.mjs.map +1 -1
- package/dist/jsx/schemaForm/index.native.js +3 -3
- package/dist/jsx/schemaForm/index.native.js.map +1 -1
- package/package.json +16 -16
- package/src/FileBrowser/index.tsx +14 -13
- package/src/FormSidebar.stories.tsx +2 -1
- package/src/FrappeCalendar.stories.tsx +1 -1
- package/src/FrappeCalendar.tsx +10 -9
- package/src/FrappeConnectionIndicator.stories.tsx +2 -1
- package/src/FrappeConnectionIndicator.tsx +2 -1
- package/src/FrappeDashboard.stories.tsx +2 -2
- package/src/FrappeDashboard.tsx +10 -10
- package/src/FrappeForm.lifecycle.spec.tsx +3 -1
- package/src/FrappeForm.tsx +106 -38
- package/src/FrappeFormActions.tsx +160 -1
- package/src/FrappeInsights.spec.tsx +1 -1
- package/src/FrappeInsights.tsx +4 -1
- package/src/FrappeKanban.stories.tsx +2 -1
- package/src/FrappeKanban.tsx +8 -7
- package/src/FrappeList.stories.tsx +11 -10
- package/src/FrappeListView.card.spec.tsx +1 -1
- package/src/FrappeListView.sidebar.spec.tsx +1 -1
- package/src/FrappeListView.tsx +1 -1
- package/src/FrappeProvider.stories.tsx +2 -1
- package/src/FrappeReconnectIndicator.stories.tsx +2 -1
- package/src/FrappeReconnectIndicator.tsx +2 -1
- package/src/SyncErrorNotice.tsx +2 -2
- package/src/desk/DeskFormPage.tsx +42 -62
- package/src/desk/DeskFormSidebar.stories.tsx +4 -2
- package/src/desk/DeskShell.tsx +1 -1
- package/src/desk/awesomebar.tsx +1 -1
- package/src/fields/CodeEditor/index.tsx +4 -4
- package/src/fields/Date/index.native.tsx +2 -1
- package/src/fields/FileUpload.tsx +8 -4
- package/src/fields/FileUploadField/FileUploadField.spec.tsx +86 -1
- package/src/fields/FileUploadField/FileUploadField.stories.tsx +9 -0
- package/src/fields/FileUploadField/index.tsx +67 -6
- package/src/fields/Heading/index.tsx +4 -4
- package/src/fields/MarkdownEditor/index.native.tsx +2 -1
- package/src/fields/Numeric/index.tsx +2 -1
- package/src/fields/Password/index.tsx +14 -70
- package/src/fields/ReadOnly/index.tsx +12 -11
- package/src/fields/TextEditor/TextEditor.stories.tsx +2 -1
- package/src/frappeRemainder.designLaw.spec.ts +3 -2
- package/src/frappeRoutes.spec.tsx +20 -6
- package/src/index.ts +7 -1
- package/src/insights/InsightsLeaders.tsx +2 -2
- package/src/insights/InsightsRecords.tsx +2 -2
- package/src/insights/insightsRecord.ts +2 -2
- package/src/list/FacetBadge.tsx +5 -4
- package/src/list/ImageWell.spec.tsx +47 -0
- package/src/list/ImageWell.tsx +8 -21
- package/src/list/RecordCard.native.tsx +2 -2
- package/src/list/RecordCard.spec.tsx +1 -1
- package/src/list/RecordCard.tsx +4 -4
- package/src/list/facetBadgeSteps.ts +2 -0
- package/src/record/RecordHero.tsx +4 -11
- package/src/record/RecordPage.tsx +4 -4
- package/src/report/ReportGrid.native.spec.tsx +152 -0
- package/src/report/ReportGrid.tsx +20 -9
- package/src/schemaForm/SchemaForm.stories.tsx +2 -1
- package/src/schemaForm/index.tsx +6 -6
- package/types/FileBrowser/index.d.ts.map +1 -1
- package/types/FrappeCalendar.d.ts.map +1 -1
- package/types/FrappeConnectionIndicator.d.ts.map +1 -1
- package/types/FrappeDashboard.d.ts.map +1 -1
- package/types/FrappeForm.d.ts +19 -0
- package/types/FrappeForm.d.ts.map +1 -1
- package/types/FrappeFormActions.d.ts +7 -0
- package/types/FrappeFormActions.d.ts.map +1 -1
- package/types/FrappeInsights.d.ts.map +1 -1
- package/types/FrappeKanban.d.ts.map +1 -1
- package/types/FrappeReconnectIndicator.d.ts.map +1 -1
- package/types/desk/DeskFormPage.d.ts +6 -6
- package/types/desk/DeskFormPage.d.ts.map +1 -1
- package/types/fields/Date/index.native.d.ts.map +1 -1
- package/types/fields/FileUpload.d.ts.map +1 -1
- package/types/fields/FileUploadField/index.d.ts.map +1 -1
- package/types/fields/MarkdownEditor/index.native.d.ts.map +1 -1
- package/types/fields/Numeric/index.d.ts.map +1 -1
- package/types/fields/Password/index.d.ts +13 -0
- package/types/fields/Password/index.d.ts.map +1 -1
- package/types/fields/ReadOnly/index.d.ts.map +1 -1
- package/types/index.d.ts +2 -1
- package/types/index.d.ts.map +1 -1
- package/types/insights/insightsRecord.d.ts +2 -2
- package/types/insights/insightsRecord.d.ts.map +1 -1
- package/types/list/FacetBadge.d.ts +1 -1
- package/types/list/FacetBadge.d.ts.map +1 -1
- package/types/list/ImageWell.d.ts +5 -4
- package/types/list/ImageWell.d.ts.map +1 -1
- package/types/list/RecordCard.d.ts +3 -3
- package/types/list/RecordCard.d.ts.map +1 -1
- package/types/list/RecordCard.native.d.ts +1 -1
- package/types/list/RecordCard.native.d.ts.map +1 -1
- package/types/list/facetBadgeSteps.d.ts +7 -0
- package/types/list/facetBadgeSteps.d.ts.map +1 -0
- package/types/record/RecordHero.d.ts +3 -3
- package/types/record/RecordHero.d.ts.map +1 -1
- package/types/report/ReportGrid.d.ts.map +1 -1
|
@@ -5,8 +5,9 @@ import { sizeRecipeForToken, useResolvedKnobs, sizeTokenStep } from "@multiplatf
|
|
|
5
5
|
import type React from "react";
|
|
6
6
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
7
7
|
import { useTranslation } from "react-i18next";
|
|
8
|
-
import { Button, Image, Label, Text, XStack, YStack } from "tamagui";
|
|
8
|
+
import { Button, Image, Label, Text as TamaguiText, XStack, YStack } from "tamagui";
|
|
9
9
|
import { useFrappeConfig } from "../FrappeProvider";
|
|
10
|
+
import { Text } from "@multiplatform.one/components";
|
|
10
11
|
|
|
11
12
|
export type FrappeFileUploadHandler = (
|
|
12
13
|
file: File,
|
|
@@ -189,7 +190,10 @@ export function FileUpload({
|
|
|
189
190
|
} catch (err) {
|
|
190
191
|
if (
|
|
191
192
|
controller.signal.aborted ||
|
|
192
|
-
(err instanceof
|
|
193
|
+
(err instanceof Error && err.name === "AbortError") ||
|
|
194
|
+
(typeof DOMException !== "undefined" &&
|
|
195
|
+
err instanceof DOMException &&
|
|
196
|
+
err.name === "AbortError")
|
|
193
197
|
) {
|
|
194
198
|
return;
|
|
195
199
|
}
|
|
@@ -290,9 +294,9 @@ export function FileUpload({
|
|
|
290
294
|
return (
|
|
291
295
|
<YStack {...knobProps.gap}>
|
|
292
296
|
{label && (
|
|
293
|
-
<Label>
|
|
297
|
+
<Label {...knobProps.label}>
|
|
294
298
|
{label}
|
|
295
|
-
{required && <
|
|
299
|
+
{required && <TamaguiText color="$red10"> *</TamaguiText>}
|
|
296
300
|
</Label>
|
|
297
301
|
)}
|
|
298
302
|
|
|
@@ -11,9 +11,11 @@
|
|
|
11
11
|
* 3. a controlled `value` winning over `defaultValue`, so a saved attachment
|
|
12
12
|
* paints on a re-render instead of the mount-time default.
|
|
13
13
|
*/
|
|
14
|
+
import { Form, useForm } from "@multiplatform.one/forms";
|
|
14
15
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
15
|
-
import { cleanup } from "@testing-library/react";
|
|
16
|
+
import { act, cleanup, fireEvent } from "@testing-library/react";
|
|
16
17
|
import type React from "react";
|
|
18
|
+
import { useState } from "react";
|
|
17
19
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
18
20
|
import { getFieldComponent, type FieldRenderProps } from "../../fieldRegistry";
|
|
19
21
|
import { FileUploadField } from ".";
|
|
@@ -202,3 +204,86 @@ describe("FileUploadField stored value", () => {
|
|
|
202
204
|
expect(result.container.querySelector('[data-file-upload="existing"]')).toBeNull();
|
|
203
205
|
});
|
|
204
206
|
});
|
|
207
|
+
|
|
208
|
+
describe("FileUploadField attachment states", () => {
|
|
209
|
+
it("hides source choices until Replace and keeps the library reachable", async () => {
|
|
210
|
+
const result = renderWithProviders(<FileUploadField value="/files/a.png" isImage />);
|
|
211
|
+
expect(result.getButton("From Library")).toBeUndefined();
|
|
212
|
+
expect(result.getButton("Choose File")).toBeUndefined();
|
|
213
|
+
await act(async () => {
|
|
214
|
+
fireEvent.click(result.container.querySelector('[aria-label="Replace"]')!);
|
|
215
|
+
});
|
|
216
|
+
expect(result.getButton("From Library")).toBeTruthy();
|
|
217
|
+
expect(result.getButton("Choose File")).toBeTruthy();
|
|
218
|
+
expect(result.container.querySelector('[data-file-upload="preview"] img')).toBeTruthy();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("shows an empty field after its controlled stored value is removed", () => {
|
|
222
|
+
const result = renderWithProviders(<FileUploadField value="/files/a.png" isImage />);
|
|
223
|
+
result.rerender(<FileUploadField value="" isImage />);
|
|
224
|
+
expect(result.container.querySelector('[data-file-upload="preview"]')).toBeNull();
|
|
225
|
+
expect(result.getButton("From Library")).toBeTruthy();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("keeps locked stored attachments free of replacement actions", () => {
|
|
229
|
+
const result = renderWithProviders(<FileUploadField value="/files/a.png" isImage disabled />);
|
|
230
|
+
expect(result.getButton("Replace")).toBeUndefined();
|
|
231
|
+
expect(result.getButton("From Library")).toBeUndefined();
|
|
232
|
+
expect(result.container.querySelector('[data-file-upload="preview"] img')).toBeTruthy();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("keeps the newly selected file visible when replacing a controlled stored URL", async () => {
|
|
237
|
+
function Controlled() {
|
|
238
|
+
const [value, setValue] = useState<unknown>("/files/old.pdf");
|
|
239
|
+
return <FileUploadField value={value} onChange={setValue} />;
|
|
240
|
+
}
|
|
241
|
+
const result = renderWithProviders(<Controlled />);
|
|
242
|
+
await act(async () => {
|
|
243
|
+
fireEvent.change(nativePicker(result.container)!, {
|
|
244
|
+
target: { files: [new File(["new"], "new.pdf", { type: "application/pdf" })] },
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
expect(result.container.textContent).toContain("new.pdf");
|
|
248
|
+
expect(result.container.textContent).not.toContain("Choose File");
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("paints and removes a stored URL bound through a form", async () => {
|
|
252
|
+
let readValue: () => unknown = () => undefined;
|
|
253
|
+
function Harness() {
|
|
254
|
+
const form = useForm({ defaultValues: { attachment: "/files/old.png" } });
|
|
255
|
+
readValue = () => form.state.values.attachment;
|
|
256
|
+
return (
|
|
257
|
+
<Form form={form}>
|
|
258
|
+
<FileUploadField form={form} name="attachment" isImage />
|
|
259
|
+
</Form>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
const result = renderWithProviders(<Harness />);
|
|
263
|
+
expect(result.container.querySelector('[data-file-upload="preview"] img')).toBeTruthy();
|
|
264
|
+
await act(async () => {
|
|
265
|
+
fireEvent.click(result.getButton("Remove old.png")!);
|
|
266
|
+
});
|
|
267
|
+
expect(readValue()).toBe("");
|
|
268
|
+
expect(result.container.textContent).toContain("Choose File");
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("keeps multiple files visible when replacing a controlled stored URL", async () => {
|
|
272
|
+
function Harness() {
|
|
273
|
+
const [value, setValue] = useState<unknown>("/files/old.pdf");
|
|
274
|
+
return <FileUploadField value={value} onChange={setValue} multiple />;
|
|
275
|
+
}
|
|
276
|
+
const result = renderWithProviders(<Harness />);
|
|
277
|
+
await act(async () => {
|
|
278
|
+
fireEvent.change(nativePicker(result.container)!, {
|
|
279
|
+
target: {
|
|
280
|
+
files: [
|
|
281
|
+
new File(["one"], "one.pdf", { type: "application/pdf" }),
|
|
282
|
+
new File(["two"], "two.pdf", { type: "application/pdf" }),
|
|
283
|
+
],
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
expect(result.container.textContent).toContain("one.pdf");
|
|
288
|
+
expect(result.container.textContent).toContain("two.pdf");
|
|
289
|
+
});
|
|
@@ -172,3 +172,12 @@ export const InTable = {
|
|
|
172
172
|
);
|
|
173
173
|
},
|
|
174
174
|
};
|
|
175
|
+
|
|
176
|
+
export const StoredImage = () => {
|
|
177
|
+
const [value, setValue] = useState<unknown>(
|
|
178
|
+
"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/10.png",
|
|
179
|
+
);
|
|
180
|
+
return (
|
|
181
|
+
<FileUploadField label="Sprite" isImage value={value} onChange={setValue} libraryFiles={[]} />
|
|
182
|
+
);
|
|
183
|
+
};
|
|
@@ -3,12 +3,20 @@ import type {
|
|
|
3
3
|
FileUploadHandler,
|
|
4
4
|
FormFieldProps,
|
|
5
5
|
} from "@multiplatform.one/forms";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
Button,
|
|
8
|
+
FileUpload,
|
|
9
|
+
Field,
|
|
10
|
+
getFieldError,
|
|
11
|
+
mergeFieldHandler,
|
|
12
|
+
useFormField,
|
|
13
|
+
useResolvedValidators,
|
|
14
|
+
} from "@multiplatform.one/forms";
|
|
7
15
|
import { FolderOpenIcon } from "@phosphor-icons/react";
|
|
8
16
|
import type { DeepKeys } from "@tanstack/form-core";
|
|
9
17
|
import { useState } from "react";
|
|
10
18
|
import { useTranslation } from "react-i18next";
|
|
11
|
-
import { useProps } from "tamagui";
|
|
19
|
+
import { useMedia, useProps } from "tamagui";
|
|
12
20
|
import { AttachLibrary } from "../../FileBrowser/AttachLibrary";
|
|
13
21
|
import { useFrappeConfig } from "../../FrappeProvider";
|
|
14
22
|
import type { FileBrowserFile } from "../../FileBrowser/types";
|
|
@@ -68,8 +76,51 @@ export type FileUploadFieldProps<
|
|
|
68
76
|
export function FileUploadField<
|
|
69
77
|
TData extends Record<string, unknown> = Record<string, unknown>,
|
|
70
78
|
TName extends string = string,
|
|
79
|
+
>(props: FileUploadFieldProps<TData, TName>) {
|
|
80
|
+
const { resolvedForm, knobProps, id } = useFormField({ form: props.form, id: props.id });
|
|
81
|
+
const validators = useResolvedValidators(
|
|
82
|
+
props.required,
|
|
83
|
+
props.validators,
|
|
84
|
+
props.label,
|
|
85
|
+
props.name,
|
|
86
|
+
);
|
|
87
|
+
if (!resolvedForm || !props.name) {
|
|
88
|
+
return <FileUploadFieldControl {...props} size={props.size ?? knobProps.sizeToken} />;
|
|
89
|
+
}
|
|
90
|
+
return (
|
|
91
|
+
<Field
|
|
92
|
+
form={resolvedForm}
|
|
93
|
+
name={props.name as any}
|
|
94
|
+
defaultValue={props.defaultValue}
|
|
95
|
+
validators={validators}
|
|
96
|
+
mode={props.mode}
|
|
97
|
+
preserveValue={props.preserveValue}
|
|
98
|
+
>
|
|
99
|
+
{(field) => (
|
|
100
|
+
<FileUploadFieldControl
|
|
101
|
+
{...props}
|
|
102
|
+
id={id}
|
|
103
|
+
name={undefined}
|
|
104
|
+
size={props.size ?? knobProps.sizeToken}
|
|
105
|
+
value={field.state.value}
|
|
106
|
+
error={getFieldError(field, props.error)}
|
|
107
|
+
onChange={(next) => {
|
|
108
|
+
field.handleChange(next as any);
|
|
109
|
+
props.onChange?.(next);
|
|
110
|
+
}}
|
|
111
|
+
onBlur={mergeFieldHandler(field, "handleBlur", props.onBlur)}
|
|
112
|
+
/>
|
|
113
|
+
)}
|
|
114
|
+
</Field>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function FileUploadFieldControl<
|
|
119
|
+
TData extends Record<string, unknown> = Record<string, unknown>,
|
|
120
|
+
TName extends string = string,
|
|
71
121
|
>(props: FileUploadFieldProps<TData, TName>) {
|
|
72
122
|
const { t } = useTranslation();
|
|
123
|
+
const media = useMedia();
|
|
73
124
|
const {
|
|
74
125
|
defaultValue,
|
|
75
126
|
form,
|
|
@@ -112,11 +163,15 @@ export function FileUploadField<
|
|
|
112
163
|
form={form}
|
|
113
164
|
validators={validators}
|
|
114
165
|
defaultValue={(stored ? undefined : resolvedDefaultValue) as any}
|
|
115
|
-
existing={
|
|
166
|
+
existing={
|
|
167
|
+
stored
|
|
168
|
+
? { src: resolveStoredFileUrl(stored, baseURL), isImage: isImage || undefined }
|
|
169
|
+
: undefined
|
|
170
|
+
}
|
|
116
171
|
onExistingRemove={
|
|
117
172
|
stored && !disabled && !fieldProps.readOnly ? () => onChange?.("") : undefined
|
|
118
173
|
}
|
|
119
|
-
|
|
174
|
+
onChange={onChange as any}
|
|
120
175
|
label={fieldProps.label}
|
|
121
176
|
labelProps={fieldProps.labelProps}
|
|
122
177
|
error={fieldProps.error}
|
|
@@ -125,6 +180,7 @@ export function FileUploadField<
|
|
|
125
180
|
skeleton={fieldProps.skeleton}
|
|
126
181
|
required={fieldProps.required}
|
|
127
182
|
id={fieldProps.id}
|
|
183
|
+
onBlur={fieldProps.onBlur}
|
|
128
184
|
size={fieldProps.size}
|
|
129
185
|
disabled={disabled}
|
|
130
186
|
accept={resolvedAccept}
|
|
@@ -134,11 +190,16 @@ export function FileUploadField<
|
|
|
134
190
|
actions={
|
|
135
191
|
library ? (
|
|
136
192
|
<Button
|
|
137
|
-
size=
|
|
193
|
+
size={fieldProps.size}
|
|
194
|
+
alignSelf="stretch"
|
|
195
|
+
flex={media.xs ? undefined : 1}
|
|
138
196
|
outlined
|
|
139
197
|
icon={FolderOpenIcon}
|
|
140
198
|
disabled={disabled || fieldProps.readOnly}
|
|
141
|
-
onPress={() =>
|
|
199
|
+
onPress={(event) => {
|
|
200
|
+
event.stopPropagation();
|
|
201
|
+
setLibraryOpen(true);
|
|
202
|
+
}}
|
|
142
203
|
>
|
|
143
204
|
{t("From Library")}
|
|
144
205
|
</Button>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useRegisterPageHeading } from "@multiplatform.one/components";
|
|
1
|
+
import { useRegisterPageHeading, Text } from "@multiplatform.one/components";
|
|
2
2
|
import { Skeleton } from "@multiplatform.one/forms";
|
|
3
3
|
import { sizeRecipeEscape, useResolvedKnobs, sizeTokenStep } from "@multiplatform.one/theme";
|
|
4
4
|
import type React from "react";
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
H3,
|
|
11
11
|
H4,
|
|
12
12
|
Separator,
|
|
13
|
-
Text,
|
|
13
|
+
Text as TamaguiText,
|
|
14
14
|
XStack,
|
|
15
15
|
YStack,
|
|
16
16
|
type YStackProps,
|
|
@@ -174,14 +174,14 @@ export function Heading({
|
|
|
174
174
|
<YStack gap={descriptionGap} paddingBottom={showDescription ? "$1" : undefined}>
|
|
175
175
|
{headingContent}
|
|
176
176
|
{showDescription && (
|
|
177
|
-
<
|
|
177
|
+
<TamaguiText
|
|
178
178
|
fontSize={knobProps.sizeToken}
|
|
179
179
|
{...knobProps.body}
|
|
180
180
|
color="$color10"
|
|
181
181
|
paddingInlineStart={canCollapse ? "$6" : undefined}
|
|
182
182
|
>
|
|
183
183
|
{resolvedDescription}
|
|
184
|
-
</
|
|
184
|
+
</TamaguiText>
|
|
185
185
|
)}
|
|
186
186
|
</YStack>
|
|
187
187
|
{showSeparator && (
|
|
@@ -30,9 +30,10 @@ import {
|
|
|
30
30
|
import { useEffect, useState, type ComponentType, type ReactNode } from "react";
|
|
31
31
|
import { useTranslation } from "react-i18next";
|
|
32
32
|
import type { FontSizeTokens, LabelProps, SizeTokens } from "tamagui";
|
|
33
|
-
import {
|
|
33
|
+
import { YStack } from "tamagui";
|
|
34
34
|
import { sizeRecipeForToken, useResolvedKnobs, sizeTokenStep } from "@multiplatform.one/theme";
|
|
35
35
|
import { EditorPreviewPanes, PreviewSurface } from "../shared/EditorPreviewPanes";
|
|
36
|
+
import { Paragraph } from "@multiplatform.one/components";
|
|
36
37
|
|
|
37
38
|
// ---------------------------------------------------------------------------
|
|
38
39
|
// Preview (lazy house Markdown renderer)
|
|
@@ -9,7 +9,8 @@ import type { FormFieldProps, FieldComponentProps } from "@multiplatform.one/for
|
|
|
9
9
|
import { Stepper as FormsStepper, formCommonColors, useForm } from "@multiplatform.one/forms";
|
|
10
10
|
import type { DeepKeys } from "@tanstack/form-core";
|
|
11
11
|
import { useEffect, useRef } from "react";
|
|
12
|
-
import {
|
|
12
|
+
import { XStack, YStack, useProps } from "tamagui";
|
|
13
|
+
import { Text } from "@multiplatform.one/components";
|
|
13
14
|
|
|
14
15
|
export type NumericType = "Int" | "Float" | "Currency" | "Percent";
|
|
15
16
|
|
|
@@ -7,20 +7,21 @@
|
|
|
7
7
|
* inside a 46-tall / radius-5 / #f7f7f7 frame; ours is a real Input.Button
|
|
8
8
|
* tab stop. Frame stays measured mpo 44/9 on $color2 (chain step 1).
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* generated end-cap recipe
|
|
10
|
+
* The reveal is the shared PasswordReveal, the field's trailing action
|
|
11
|
+
* (LC-149): a chromeless eye inside the Box that rings its own glyph (LC-71)
|
|
12
|
+
* and squares off the generated end-cap recipe.
|
|
13
13
|
*/
|
|
14
|
-
import { EyeIcon, EyeSlashIcon } from "@phosphor-icons/react";
|
|
15
14
|
import type { FormFieldProps, FieldComponentProps } from "@multiplatform.one/forms";
|
|
16
15
|
import {
|
|
17
16
|
Field,
|
|
18
17
|
FieldLayout,
|
|
19
18
|
Input as FormsInput,
|
|
19
|
+
PasswordReveal,
|
|
20
20
|
Skeleton,
|
|
21
21
|
getFieldError,
|
|
22
22
|
mergeFieldHandler,
|
|
23
23
|
useFormField,
|
|
24
|
+
usePasswordReveal,
|
|
24
25
|
useResolvedValidators,
|
|
25
26
|
} from "@multiplatform.one/forms";
|
|
26
27
|
import {
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
} from "@multiplatform.one/theme";
|
|
32
33
|
import type { DeepKeys } from "@tanstack/form-core";
|
|
33
34
|
import type { SizeTokens, TamaguiElement } from "tamagui";
|
|
34
|
-
import { useCallback,
|
|
35
|
+
import { useCallback, useRef, useState } from "react";
|
|
35
36
|
import { useProps } from "tamagui";
|
|
36
37
|
|
|
37
38
|
export type PasswordProps<
|
|
@@ -69,32 +70,6 @@ export type PasswordProps<
|
|
|
69
70
|
size?: import("tamagui").SizeTokens;
|
|
70
71
|
};
|
|
71
72
|
|
|
72
|
-
const SHOW_PASSWORD = "Show password";
|
|
73
|
-
const HIDE_PASSWORD = "Hide password";
|
|
74
|
-
|
|
75
|
-
type Selection = { start: number; end: number };
|
|
76
|
-
|
|
77
|
-
function nativeInput(node: unknown, id?: string): HTMLInputElement | null {
|
|
78
|
-
const fromRef = node as { selectionStart?: number; setSelectionRange?: unknown } | null;
|
|
79
|
-
if (fromRef && typeof fromRef.setSelectionRange === "function") {
|
|
80
|
-
return fromRef as HTMLInputElement;
|
|
81
|
-
}
|
|
82
|
-
if (typeof document === "undefined" || !id) return null;
|
|
83
|
-
return document.getElementById(id) as HTMLInputElement | null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function readSelection(node: unknown, id?: string): Selection | null {
|
|
87
|
-
const el = nativeInput(node, id);
|
|
88
|
-
if (!el || typeof el.selectionStart !== "number") return null;
|
|
89
|
-
return { start: el.selectionStart, end: el.selectionEnd ?? el.selectionStart };
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function restoreSelection(node: unknown, sel: Selection | null, id?: string) {
|
|
93
|
-
const el = nativeInput(node, id);
|
|
94
|
-
el?.focus();
|
|
95
|
-
if (sel) el?.setSelectionRange(sel.start, sel.end);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
73
|
export function Password<
|
|
99
74
|
TData extends Record<string, unknown> = Record<string, unknown>,
|
|
100
75
|
TName extends string = string,
|
|
@@ -137,19 +112,8 @@ export function Password<
|
|
|
137
112
|
const isControlled = value !== undefined;
|
|
138
113
|
const [internalText, setInternalText] = useState(String(defaultValue ?? ""));
|
|
139
114
|
const text = isControlled ? String(value ?? "") : internalText;
|
|
140
|
-
const [revealed, setRevealed] = useState(false);
|
|
141
115
|
const inputRef = useRef<TamaguiElement>(null);
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
useEffect(() => {
|
|
145
|
-
if (!text) setRevealed(false);
|
|
146
|
-
}, [text]);
|
|
147
|
-
|
|
148
|
-
useLayoutEffect(() => {
|
|
149
|
-
if (!pendingSelection.current) return;
|
|
150
|
-
restoreSelection(inputRef.current, pendingSelection.current, id);
|
|
151
|
-
pendingSelection.current = null;
|
|
152
|
-
}, [id, revealed]);
|
|
116
|
+
const { revealed, toggle: toggleReveal } = usePasswordReveal({ inputRef, id, text });
|
|
153
117
|
|
|
154
118
|
const handleChangeText = useCallback(
|
|
155
119
|
(next: string) => {
|
|
@@ -160,11 +124,6 @@ export function Password<
|
|
|
160
124
|
[disabled, isControlled, onChange],
|
|
161
125
|
);
|
|
162
126
|
|
|
163
|
-
const toggleReveal = useCallback(() => {
|
|
164
|
-
pendingSelection.current = readSelection(inputRef.current, id);
|
|
165
|
-
setRevealed((open) => !open);
|
|
166
|
-
}, [id]);
|
|
167
|
-
|
|
168
127
|
const boxContract = {
|
|
169
128
|
size: resolvedSize,
|
|
170
129
|
"data-size-token": String(resolvedSize),
|
|
@@ -193,7 +152,7 @@ export function Password<
|
|
|
193
152
|
handleChange?: (text: string) => void,
|
|
194
153
|
hasError?: boolean,
|
|
195
154
|
) => (
|
|
196
|
-
<FormsInput.Box {...boxContract} disabled={disabled}>
|
|
155
|
+
<FormsInput.Box {...boxContract} disabled={disabled} paddingInlineEnd={0}>
|
|
197
156
|
<FormsInput.Area
|
|
198
157
|
ref={inputRef}
|
|
199
158
|
{...(areaInputProps as object)}
|
|
@@ -215,28 +174,13 @@ export function Password<
|
|
|
215
174
|
handleChangeText(next);
|
|
216
175
|
}}
|
|
217
176
|
/>
|
|
218
|
-
<
|
|
219
|
-
|
|
220
|
-
|
|
177
|
+
<PasswordReveal
|
|
178
|
+
revealed={revealed}
|
|
179
|
+
onToggle={toggleReveal}
|
|
180
|
+
controls={id}
|
|
221
181
|
disabled={disabled}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
aria-controls={id}
|
|
225
|
-
hitSlop={belowFloor ? pressTargetHitSlop(visualHeight) : undefined}
|
|
226
|
-
onPress={disabled || fieldProps.readOnly ? undefined : toggleReveal}
|
|
227
|
-
onKeyDown={
|
|
228
|
-
((e: KeyboardEvent) => {
|
|
229
|
-
if (disabled || fieldProps.readOnly) return;
|
|
230
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
231
|
-
e.preventDefault();
|
|
232
|
-
e.stopPropagation();
|
|
233
|
-
toggleReveal();
|
|
234
|
-
}
|
|
235
|
-
}) as unknown as () => void
|
|
236
|
-
}
|
|
237
|
-
>
|
|
238
|
-
<FormsInput.Icon aria-hidden>{revealed ? <EyeSlashIcon /> : <EyeIcon />}</FormsInput.Icon>
|
|
239
|
-
</FormsInput.Button>
|
|
182
|
+
size={resolvedSize}
|
|
183
|
+
/>
|
|
240
184
|
</FormsInput.Box>
|
|
241
185
|
);
|
|
242
186
|
|
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
sizeTokenStep,
|
|
19
19
|
} from "@multiplatform.one/theme";
|
|
20
20
|
import { useMemo } from "react";
|
|
21
|
-
import { Text, XStack, YStack, type YStackProps } from "tamagui";
|
|
21
|
+
import { Text as TamaguiText, XStack, YStack, type YStackProps } from "tamagui";
|
|
22
|
+
import { Text } from "@multiplatform.one/components";
|
|
22
23
|
|
|
23
24
|
export type ReadOnlyType =
|
|
24
25
|
| "Data"
|
|
@@ -193,15 +194,15 @@ export function ReadOnly({
|
|
|
193
194
|
return (
|
|
194
195
|
<XStack alignItems="center">
|
|
195
196
|
{renderColorSwatch()}
|
|
196
|
-
<
|
|
197
|
+
<TamaguiText {...knobProps.body} color={valueColor} fontFamily="$mono">
|
|
197
198
|
{displayValue}
|
|
198
|
-
</
|
|
199
|
+
</TamaguiText>
|
|
199
200
|
</XStack>
|
|
200
201
|
);
|
|
201
202
|
}
|
|
202
203
|
if (type === "Link" && (linkHref || onLinkPress) && !isEmpty) {
|
|
203
204
|
return (
|
|
204
|
-
<
|
|
205
|
+
<TamaguiText
|
|
205
206
|
{...knobProps.body}
|
|
206
207
|
color="$accentColor"
|
|
207
208
|
textDecorationLine="underline"
|
|
@@ -210,7 +211,7 @@ export function ReadOnly({
|
|
|
210
211
|
hoverStyle={{ opacity: 0.8 }}
|
|
211
212
|
>
|
|
212
213
|
{displayValue}
|
|
213
|
-
</
|
|
214
|
+
</TamaguiText>
|
|
214
215
|
);
|
|
215
216
|
}
|
|
216
217
|
if (type === "Check") {
|
|
@@ -236,23 +237,23 @@ export function ReadOnly({
|
|
|
236
237
|
</Text>
|
|
237
238
|
) : null}
|
|
238
239
|
</XStack>
|
|
239
|
-
<
|
|
240
|
+
<TamaguiText {...knobProps.body} color={valueColor}>
|
|
240
241
|
{displayValue}
|
|
241
|
-
</
|
|
242
|
+
</TamaguiText>
|
|
242
243
|
</XStack>
|
|
243
244
|
);
|
|
244
245
|
}
|
|
245
246
|
if (type === "LongText" || type === "Text" || type === "SmallText") {
|
|
246
247
|
return (
|
|
247
|
-
<
|
|
248
|
+
<TamaguiText {...knobProps.body} color={valueColor} whiteSpace="pre-wrap">
|
|
248
249
|
{displayValue}
|
|
249
|
-
</
|
|
250
|
+
</TamaguiText>
|
|
250
251
|
);
|
|
251
252
|
}
|
|
252
253
|
return (
|
|
253
|
-
<
|
|
254
|
+
<TamaguiText {...knobProps.body} color={valueColor}>
|
|
254
255
|
{displayValue}
|
|
255
|
-
</
|
|
256
|
+
</TamaguiText>
|
|
256
257
|
);
|
|
257
258
|
};
|
|
258
259
|
|
|
@@ -2,10 +2,11 @@ import { action } from "@multiplatform.one/storybook";
|
|
|
2
2
|
import { Button } from "@multiplatform.one/forms";
|
|
3
3
|
import { DataTable, type DataTableColumn } from "@multiplatform.one/table";
|
|
4
4
|
import { useState } from "react";
|
|
5
|
-
import {
|
|
5
|
+
import { YStack } from "tamagui";
|
|
6
6
|
import { fieldtypeToTableField } from "../../fieldRegistry";
|
|
7
7
|
import { FrappeStoryProvider } from "../../frappeStoryTarget";
|
|
8
8
|
import { TextEditor, type TextEditorProps } from ".";
|
|
9
|
+
import { Text } from "@multiplatform.one/components";
|
|
9
10
|
|
|
10
11
|
export default {
|
|
11
12
|
title: "FrappeUI/TextEditor",
|
|
@@ -145,10 +145,11 @@ describe("Frappe remainder wrappers — design-law 100%", () => {
|
|
|
145
145
|
expect(source).not.toContain("<Tint");
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
-
it("Desk pages use body fragment, not sizeToken as fontSize; form back is house
|
|
148
|
+
it("Desk pages use body fragment, not sizeToken as fontSize; form back is the house PageBackButton", () => {
|
|
149
149
|
const form = read("desk/DeskFormPage.tsx");
|
|
150
150
|
const list = read("desk/DeskListPage.tsx");
|
|
151
|
-
expect(form).toMatch(/
|
|
151
|
+
expect(form).toMatch(/page=\{\{\s*back:/);
|
|
152
|
+
expect(read("FrappeForm.tsx")).toMatch(/<PageBackButton\b/);
|
|
152
153
|
expect(form).not.toMatch(/fontSize=\{knobProps\.sizeToken\}/);
|
|
153
154
|
expect(list).not.toMatch(/fontSize=\{knobProps\.sizeToken\}/);
|
|
154
155
|
expect(form).toContain("formCommonColors.muted");
|
|
@@ -190,6 +190,16 @@ function button(container: HTMLElement, label: string): HTMLElement {
|
|
|
190
190
|
return found as HTMLElement;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
// LC-145: a record page keeps its secondary actions (Delete) in the top bar's "…" menu.
|
|
194
|
+
async function menuEntry(label: string): Promise<HTMLElement | null> {
|
|
195
|
+
const trigger = screen.queryByTestId("frappe-form-menu");
|
|
196
|
+
if (!trigger) return null;
|
|
197
|
+
fireEvent.click(trigger);
|
|
198
|
+
const entry = await screen.findByRole("menuitem", { name: label }).catch(() => null);
|
|
199
|
+
fireEvent.keyDown(document.activeElement ?? document.body, { key: "Escape" });
|
|
200
|
+
return entry;
|
|
201
|
+
}
|
|
202
|
+
|
|
193
203
|
function input(container: HTMLElement, label: string): HTMLInputElement {
|
|
194
204
|
const field = screen.getByLabelText(label, { exact: false });
|
|
195
205
|
if (field instanceof HTMLInputElement) return field;
|
|
@@ -373,8 +383,9 @@ describe("FrappeForm with a route", () => {
|
|
|
373
383
|
it("deletes through delete_doc and returns to the list", async () => {
|
|
374
384
|
const { container, pushed } = renderAt("/moves/d4e5f6", "form");
|
|
375
385
|
await waitFor(() => expect(input(container, "Move Name").value).toBe("vine-whip"));
|
|
376
|
-
await
|
|
377
|
-
fireEvent.click(
|
|
386
|
+
await screen.findByTestId("frappe-form-menu");
|
|
387
|
+
fireEvent.click(screen.getByTestId("frappe-form-menu"));
|
|
388
|
+
fireEvent.click(await screen.findByRole("menuitem", { name: "Delete" }));
|
|
378
389
|
|
|
379
390
|
await waitFor(() => expect(pushed).toEqual(["/moves"]));
|
|
380
391
|
expect(confirmDelete).toHaveBeenCalledTimes(1);
|
|
@@ -391,7 +402,8 @@ describe("FrappeForm with a route", () => {
|
|
|
391
402
|
expect(input(container, "Power").value).toBe("40");
|
|
392
403
|
expect(screen.queryByText(`Failed to load ${doctype} form`)).toBeNull();
|
|
393
404
|
expect(() => button(container, "Edit")).toThrow();
|
|
394
|
-
expect(
|
|
405
|
+
expect(await menuEntry("Edit")).toBeNull();
|
|
406
|
+
expect(await menuEntry("Delete")).toBeNull();
|
|
395
407
|
});
|
|
396
408
|
|
|
397
409
|
it("draws no field for the collection's own $ keys on a reader's record", async () => {
|
|
@@ -415,7 +427,8 @@ describe("FrappeForm with a route", () => {
|
|
|
415
427
|
true,
|
|
416
428
|
);
|
|
417
429
|
expect(() => button(container, "Edit")).toThrow();
|
|
418
|
-
expect(
|
|
430
|
+
expect(await menuEntry("Edit")).toBeNull();
|
|
431
|
+
expect(await menuEntry("Delete")).toBeNull();
|
|
419
432
|
});
|
|
420
433
|
|
|
421
434
|
it("renders a reader's edit page read-only with no Save", async () => {
|
|
@@ -444,13 +457,14 @@ describe("FrappeForm with a route", () => {
|
|
|
444
457
|
const own = renderAt("/moves/a1b2c3", "form");
|
|
445
458
|
await waitFor(() => expect(input(own.container, "Move Name").value).toBe("tackle"));
|
|
446
459
|
await waitFor(() => expect(button(own.container, "Edit")).toBeTruthy());
|
|
447
|
-
expect(
|
|
460
|
+
expect(await menuEntry("Delete")).not.toBeNull();
|
|
448
461
|
cleanup();
|
|
449
462
|
|
|
450
463
|
const others = renderAt("/moves/d4e5f6", "form");
|
|
451
464
|
await waitFor(() => expect(input(others.container, "Move Name").value).toBe("vine-whip"));
|
|
452
465
|
await sessionSettled();
|
|
453
466
|
expect(() => button(others.container, "Edit")).toThrow();
|
|
454
|
-
expect(
|
|
467
|
+
expect(await menuEntry("Edit")).toBeNull();
|
|
468
|
+
expect(await menuEntry("Delete")).toBeNull();
|
|
455
469
|
});
|
|
456
470
|
});
|
package/src/index.ts
CHANGED
|
@@ -53,7 +53,12 @@ export {
|
|
|
53
53
|
// ---------------------------------------------------------------------------
|
|
54
54
|
|
|
55
55
|
export { FrappeTable, filterValueToFrappeTuple, type FrappeTableProps } from "./FrappeTable";
|
|
56
|
-
export {
|
|
56
|
+
export {
|
|
57
|
+
FrappeForm,
|
|
58
|
+
type FrappeConnectionRows,
|
|
59
|
+
type FrappeFormPage,
|
|
60
|
+
type FrappeFormProps,
|
|
61
|
+
} from "./FrappeForm";
|
|
57
62
|
export {
|
|
58
63
|
useFrappeForm,
|
|
59
64
|
type FrappeFormConnectionConfig,
|
|
@@ -120,6 +125,7 @@ export {
|
|
|
120
125
|
} from "./list/ListToolsSheet";
|
|
121
126
|
export { ShufflePanel, type ShufflePanelProps } from "./list/ShufflePanel";
|
|
122
127
|
export { FacetBadge, type FacetBadgeProps } from "./list/FacetBadge";
|
|
128
|
+
export { facetBadgeSteps } from "./list/facetBadgeSteps";
|
|
123
129
|
export { ImageWell, type ImageWellProps } from "./list/ImageWell";
|
|
124
130
|
export { RecordCard, type RecordCardBadge, type RecordCardProps } from "./list/RecordCard";
|
|
125
131
|
export { recordTitle, type FrappeRecordLook, type FrappeRecordSlide } from "./list/recordLook";
|
|
@@ -78,14 +78,14 @@ export function InsightsLeaders<TDoc>({
|
|
|
78
78
|
accessorKey: "title",
|
|
79
79
|
header: t("Record"),
|
|
80
80
|
cell: ({ row }) => {
|
|
81
|
-
const
|
|
81
|
+
const tint = record.tint(row.original.doc);
|
|
82
82
|
const code = record.code(row.original.doc);
|
|
83
83
|
return (
|
|
84
84
|
<XStack gap="$2" alignItems="center" minWidth={0}>
|
|
85
85
|
<ImageWell
|
|
86
86
|
sources={record.images(row.original.doc)}
|
|
87
87
|
alt={row.original.title}
|
|
88
|
-
|
|
88
|
+
tint={tint}
|
|
89
89
|
inset={0.04}
|
|
90
90
|
width={nestedPx}
|
|
91
91
|
data-nested-px={nestedPx}
|