@multiplatform.one/frappe-ui 7.65.2 → 7.67.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/FormSidebar.cjs +95 -194
- package/dist/cjs/FormSidebar.native.js +107 -217
- package/dist/cjs/FormSidebar.native.js.map +1 -1
- package/dist/cjs/FrappeConnectionIndicator.cjs +5 -24
- package/dist/cjs/FrappeConnectionIndicator.native.js +5 -24
- package/dist/cjs/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/cjs/FrappeImageView.cjs +46 -65
- package/dist/cjs/FrappeImageView.native.js +46 -68
- package/dist/cjs/FrappeImageView.native.js.map +1 -1
- package/dist/cjs/FrappeListView.cjs +24 -67
- package/dist/cjs/FrappeListView.native.js +25 -71
- package/dist/cjs/FrappeListView.native.js.map +1 -1
- package/dist/cjs/FrappeRecordView.cjs +4 -0
- package/dist/cjs/FrappeRecordView.native.js +4 -0
- package/dist/cjs/FrappeRecordView.native.js.map +1 -1
- package/dist/cjs/FrappeReportBuilder.cjs +21 -18
- package/dist/cjs/FrappeReportBuilder.native.js +21 -18
- package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
- package/dist/cjs/SyncErrorNotice.cjs +8 -36
- package/dist/cjs/SyncErrorNotice.native.js +8 -36
- package/dist/cjs/SyncErrorNotice.native.js.map +1 -1
- package/dist/cjs/desk/DeskFormSidebar.cjs +1 -6
- package/dist/cjs/desk/DeskFormSidebar.native.js +1 -6
- package/dist/cjs/desk/DeskFormSidebar.native.js.map +1 -1
- package/dist/cjs/desk/DeskShell.native.js.map +1 -1
- package/dist/cjs/fields/Date/catalog.native.js +0 -1
- package/dist/cjs/fields/Date/catalog.native.js.map +1 -1
- package/dist/cjs/fields/Date/index.native.js +4 -363
- package/dist/cjs/fields/Date/index.native.js.map +1 -1
- package/dist/cjs/insights/InsightsFacetTags.cjs +16 -92
- package/dist/cjs/insights/InsightsFacetTags.native.js +15 -97
- package/dist/cjs/insights/InsightsFacetTags.native.js.map +1 -1
- package/dist/cjs/list/FacetBadge.cjs +4 -28
- package/dist/cjs/list/FacetBadge.native.js +4 -28
- package/dist/cjs/list/FacetBadge.native.js.map +1 -1
- package/dist/cjs/list/FacetRail.cjs +37 -128
- package/dist/cjs/list/FacetRail.native.js +32 -130
- package/dist/cjs/list/FacetRail.native.js.map +1 -1
- package/dist/cjs/list/RecordCard.cjs +107 -127
- package/dist/cjs/list/RecordCard.native.js +86 -96
- package/dist/cjs/list/RecordCard.native.js.map +1 -1
- package/dist/cjs/list/ShufflePanel.cjs +57 -36
- package/dist/cjs/list/ShufflePanel.native.js +64 -39
- package/dist/cjs/list/ShufflePanel.native.js.map +1 -1
- package/dist/cjs/record/RecordHero.cjs +7 -85
- package/dist/cjs/record/RecordHero.native.js +7 -85
- package/dist/cjs/record/RecordHero.native.js.map +1 -1
- package/dist/cjs/record/RecordPage.cjs +1 -0
- package/dist/cjs/record/RecordPage.native.js +1 -0
- package/dist/cjs/record/RecordPage.native.js.map +1 -1
- package/dist/cjs/report/ReportViewToolbar.cjs +70 -39
- package/dist/cjs/report/ReportViewToolbar.native.js +73 -40
- package/dist/cjs/report/ReportViewToolbar.native.js.map +1 -1
- package/dist/esm/FormSidebar.mjs +98 -197
- package/dist/esm/FormSidebar.mjs.map +1 -1
- package/dist/esm/FormSidebar.native.js +110 -220
- package/dist/esm/FormSidebar.native.js.map +1 -1
- package/dist/esm/FrappeConnectionIndicator.mjs +7 -26
- package/dist/esm/FrappeConnectionIndicator.mjs.map +1 -1
- package/dist/esm/FrappeConnectionIndicator.native.js +7 -26
- package/dist/esm/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/esm/FrappeImageView.mjs +48 -67
- package/dist/esm/FrappeImageView.mjs.map +1 -1
- package/dist/esm/FrappeImageView.native.js +48 -70
- package/dist/esm/FrappeImageView.native.js.map +1 -1
- package/dist/esm/FrappeListView.mjs +25 -68
- package/dist/esm/FrappeListView.mjs.map +1 -1
- package/dist/esm/FrappeListView.native.js +26 -72
- package/dist/esm/FrappeListView.native.js.map +1 -1
- package/dist/esm/FrappeRecordView.mjs +4 -0
- package/dist/esm/FrappeRecordView.mjs.map +1 -1
- package/dist/esm/FrappeRecordView.native.js +4 -0
- package/dist/esm/FrappeRecordView.native.js.map +1 -1
- package/dist/esm/FrappeReportBuilder.mjs +21 -18
- package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
- package/dist/esm/FrappeReportBuilder.native.js +21 -18
- package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
- package/dist/esm/SyncErrorNotice.mjs +10 -38
- package/dist/esm/SyncErrorNotice.mjs.map +1 -1
- package/dist/esm/SyncErrorNotice.native.js +10 -38
- package/dist/esm/SyncErrorNotice.native.js.map +1 -1
- package/dist/esm/desk/DeskFormSidebar.mjs +1 -6
- package/dist/esm/desk/DeskFormSidebar.mjs.map +1 -1
- package/dist/esm/desk/DeskFormSidebar.native.js +1 -6
- package/dist/esm/desk/DeskFormSidebar.native.js.map +1 -1
- package/dist/esm/desk/DeskShell.mjs.map +1 -1
- package/dist/esm/desk/DeskShell.native.js.map +1 -1
- package/dist/esm/fields/Date/catalog.mjs.map +1 -1
- package/dist/esm/fields/Date/catalog.native.js +0 -1
- package/dist/esm/fields/Date/catalog.native.js.map +1 -1
- package/dist/esm/fields/Date/index.native.js +2 -361
- package/dist/esm/fields/Date/index.native.js.map +1 -1
- package/dist/esm/insights/InsightsFacetTags.mjs +18 -94
- package/dist/esm/insights/InsightsFacetTags.mjs.map +1 -1
- package/dist/esm/insights/InsightsFacetTags.native.js +17 -99
- package/dist/esm/insights/InsightsFacetTags.native.js.map +1 -1
- package/dist/esm/list/FacetBadge.mjs +5 -29
- package/dist/esm/list/FacetBadge.mjs.map +1 -1
- package/dist/esm/list/FacetBadge.native.js +5 -29
- package/dist/esm/list/FacetBadge.native.js.map +1 -1
- package/dist/esm/list/FacetRail.mjs +40 -131
- package/dist/esm/list/FacetRail.mjs.map +1 -1
- package/dist/esm/list/FacetRail.native.js +35 -133
- package/dist/esm/list/FacetRail.native.js.map +1 -1
- package/dist/esm/list/RecordCard.mjs +107 -127
- package/dist/esm/list/RecordCard.mjs.map +1 -1
- package/dist/esm/list/RecordCard.native.js +86 -96
- package/dist/esm/list/RecordCard.native.js.map +1 -1
- package/dist/esm/list/ShufflePanel.mjs +59 -38
- package/dist/esm/list/ShufflePanel.mjs.map +1 -1
- package/dist/esm/list/ShufflePanel.native.js +66 -41
- package/dist/esm/list/ShufflePanel.native.js.map +1 -1
- package/dist/esm/record/RecordHero.mjs +8 -86
- package/dist/esm/record/RecordHero.mjs.map +1 -1
- package/dist/esm/record/RecordHero.native.js +8 -86
- package/dist/esm/record/RecordHero.native.js.map +1 -1
- package/dist/esm/record/RecordPage.mjs +2 -1
- package/dist/esm/record/RecordPage.mjs.map +1 -1
- package/dist/esm/record/RecordPage.native.js +2 -1
- package/dist/esm/record/RecordPage.native.js.map +1 -1
- package/dist/esm/report/ReportViewToolbar.mjs +72 -41
- package/dist/esm/report/ReportViewToolbar.mjs.map +1 -1
- package/dist/esm/report/ReportViewToolbar.native.js +75 -42
- package/dist/esm/report/ReportViewToolbar.native.js.map +1 -1
- package/dist/jsx/FormSidebar.mjs +98 -197
- package/dist/jsx/FormSidebar.mjs.map +1 -1
- package/dist/jsx/FormSidebar.native.js +107 -217
- package/dist/jsx/FormSidebar.native.js.map +1 -1
- package/dist/jsx/FrappeConnectionIndicator.mjs +7 -26
- package/dist/jsx/FrappeConnectionIndicator.mjs.map +1 -1
- package/dist/jsx/FrappeConnectionIndicator.native.js +5 -24
- package/dist/jsx/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/jsx/FrappeImageView.mjs +48 -67
- package/dist/jsx/FrappeImageView.mjs.map +1 -1
- package/dist/jsx/FrappeImageView.native.js +46 -68
- package/dist/jsx/FrappeImageView.native.js.map +1 -1
- package/dist/jsx/FrappeListView.mjs +25 -68
- package/dist/jsx/FrappeListView.mjs.map +1 -1
- package/dist/jsx/FrappeListView.native.js +25 -71
- package/dist/jsx/FrappeListView.native.js.map +1 -1
- package/dist/jsx/FrappeRecordView.mjs +4 -0
- package/dist/jsx/FrappeRecordView.mjs.map +1 -1
- package/dist/jsx/FrappeRecordView.native.js +4 -0
- package/dist/jsx/FrappeRecordView.native.js.map +1 -1
- package/dist/jsx/FrappeReportBuilder.mjs +21 -18
- package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
- package/dist/jsx/FrappeReportBuilder.native.js +21 -18
- package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
- package/dist/jsx/SyncErrorNotice.mjs +10 -38
- package/dist/jsx/SyncErrorNotice.mjs.map +1 -1
- package/dist/jsx/SyncErrorNotice.native.js +8 -36
- package/dist/jsx/SyncErrorNotice.native.js.map +1 -1
- package/dist/jsx/desk/DeskFormSidebar.mjs +1 -6
- package/dist/jsx/desk/DeskFormSidebar.mjs.map +1 -1
- package/dist/jsx/desk/DeskFormSidebar.native.js +1 -6
- package/dist/jsx/desk/DeskFormSidebar.native.js.map +1 -1
- package/dist/jsx/desk/DeskShell.mjs.map +1 -1
- package/dist/jsx/desk/DeskShell.native.js.map +1 -1
- package/dist/jsx/fields/Date/catalog.mjs.map +1 -1
- package/dist/jsx/fields/Date/catalog.native.js +0 -1
- package/dist/jsx/fields/Date/catalog.native.js.map +1 -1
- package/dist/jsx/fields/Date/index.native.js +4 -363
- package/dist/jsx/fields/Date/index.native.js.map +1 -1
- package/dist/jsx/insights/InsightsFacetTags.mjs +18 -94
- package/dist/jsx/insights/InsightsFacetTags.mjs.map +1 -1
- package/dist/jsx/insights/InsightsFacetTags.native.js +15 -97
- package/dist/jsx/insights/InsightsFacetTags.native.js.map +1 -1
- package/dist/jsx/list/FacetBadge.mjs +5 -29
- package/dist/jsx/list/FacetBadge.mjs.map +1 -1
- package/dist/jsx/list/FacetBadge.native.js +4 -28
- package/dist/jsx/list/FacetBadge.native.js.map +1 -1
- package/dist/jsx/list/FacetRail.mjs +40 -131
- package/dist/jsx/list/FacetRail.mjs.map +1 -1
- package/dist/jsx/list/FacetRail.native.js +32 -130
- package/dist/jsx/list/FacetRail.native.js.map +1 -1
- package/dist/jsx/list/RecordCard.mjs +107 -127
- package/dist/jsx/list/RecordCard.mjs.map +1 -1
- package/dist/jsx/list/RecordCard.native.js +86 -96
- package/dist/jsx/list/RecordCard.native.js.map +1 -1
- package/dist/jsx/list/ShufflePanel.mjs +59 -38
- package/dist/jsx/list/ShufflePanel.mjs.map +1 -1
- package/dist/jsx/list/ShufflePanel.native.js +64 -39
- package/dist/jsx/list/ShufflePanel.native.js.map +1 -1
- package/dist/jsx/record/RecordHero.mjs +8 -86
- package/dist/jsx/record/RecordHero.mjs.map +1 -1
- package/dist/jsx/record/RecordHero.native.js +7 -85
- package/dist/jsx/record/RecordHero.native.js.map +1 -1
- package/dist/jsx/record/RecordPage.mjs +2 -1
- package/dist/jsx/record/RecordPage.mjs.map +1 -1
- package/dist/jsx/record/RecordPage.native.js +1 -0
- package/dist/jsx/record/RecordPage.native.js.map +1 -1
- package/dist/jsx/report/ReportViewToolbar.mjs +72 -41
- package/dist/jsx/report/ReportViewToolbar.mjs.map +1 -1
- package/dist/jsx/report/ReportViewToolbar.native.js +73 -40
- package/dist/jsx/report/ReportViewToolbar.native.js.map +1 -1
- package/package.json +16 -16
- package/src/FormSidebar.stories.tsx +1 -1
- package/src/FormSidebar.tsx +128 -253
- package/src/FrappeConnectionIndicator.tsx +6 -28
- package/src/FrappeImageView.stories.tsx +1 -6
- package/src/FrappeImageView.tsx +52 -66
- package/src/FrappeListView.controls.spec.tsx +3 -2
- package/src/FrappeListView.tsx +23 -55
- package/src/FrappeRecordView.tsx +16 -3
- package/src/FrappeReportBuilder.tsx +21 -19
- package/src/SyncErrorNotice.spec.tsx +7 -12
- package/src/SyncErrorNotice.stories.tsx +2 -4
- package/src/SyncErrorNotice.tsx +13 -41
- package/src/desk/DeskFormSidebar.tsx +1 -2
- package/src/desk/DeskShell.tsx +1 -0
- package/src/fields/Date/catalog.tsx +6 -7
- package/src/fields/Date/nativeIsCatalog.spec.tsx +26 -0
- package/src/fields/Date/typeParity.spec.tsx +20 -98
- package/src/frappeRemainder.designLaw.spec.ts +8 -7
- package/src/insights/InsightsFacetTags.tsx +21 -102
- package/src/list/FacetBadge.tsx +7 -29
- package/src/list/FacetRail.spec.tsx +11 -10
- package/src/list/FacetRail.tsx +49 -161
- package/src/list/RecordCard.native.tsx +63 -64
- package/src/list/RecordCard.spec.tsx +8 -5
- package/src/list/RecordCard.tsx +116 -129
- package/src/list/ShufflePanel.tsx +65 -38
- package/src/record/RecordHero.tsx +11 -51
- package/src/record/RecordPage.tsx +6 -1
- package/src/report/ReportViewToolbar.spec.tsx +45 -3
- package/src/report/ReportViewToolbar.tsx +109 -56
- package/types/FormSidebar.d.ts +13 -3
- package/types/FormSidebar.d.ts.map +1 -1
- package/types/FrappeConnectionIndicator.d.ts +2 -1
- package/types/FrappeConnectionIndicator.d.ts.map +1 -1
- package/types/FrappeImageView.d.ts.map +1 -1
- package/types/FrappeListView.d.ts.map +1 -1
- package/types/FrappeRecordView.d.ts.map +1 -1
- package/types/FrappeReportBuilder.d.ts.map +1 -1
- package/types/SyncErrorNotice.d.ts +4 -6
- package/types/SyncErrorNotice.d.ts.map +1 -1
- package/types/desk/DeskFormSidebar.d.ts.map +1 -1
- package/types/desk/DeskShell.d.ts.map +1 -1
- package/types/fields/Date/catalog.d.ts +5 -4
- package/types/fields/Date/catalog.d.ts.map +1 -1
- package/types/insights/InsightsFacetTags.d.ts +4 -1
- package/types/insights/InsightsFacetTags.d.ts.map +1 -1
- package/types/list/FacetBadge.d.ts +3 -3
- package/types/list/FacetBadge.d.ts.map +1 -1
- package/types/list/FacetRail.d.ts +7 -5
- package/types/list/FacetRail.d.ts.map +1 -1
- package/types/list/RecordCard.d.ts +6 -6
- package/types/list/RecordCard.d.ts.map +1 -1
- package/types/list/RecordCard.native.d.ts +4 -3
- package/types/list/RecordCard.native.d.ts.map +1 -1
- package/types/list/ShufflePanel.d.ts +8 -3
- package/types/list/ShufflePanel.d.ts.map +1 -1
- package/types/record/RecordHero.d.ts +5 -1
- package/types/record/RecordHero.d.ts.map +1 -1
- package/types/record/RecordPage.d.ts.map +1 -1
- package/types/report/ReportViewToolbar.d.ts.map +1 -1
- package/dist/cjs/fields/Date/dateTimePickerLoader.cjs +0 -38
- package/dist/cjs/fields/Date/dateTimePickerLoader.native.js +0 -42
- package/dist/cjs/fields/Date/dateTimePickerLoader.native.js.map +0 -1
- package/dist/cjs/fields/Date/sheetKeyboard.cjs +0 -54
- package/dist/cjs/fields/Date/sheetKeyboard.native.js +0 -57
- package/dist/cjs/fields/Date/sheetKeyboard.native.js.map +0 -1
- package/dist/esm/fields/Date/dateTimePickerLoader.mjs +0 -13
- package/dist/esm/fields/Date/dateTimePickerLoader.mjs.map +0 -1
- package/dist/esm/fields/Date/dateTimePickerLoader.native.js +0 -14
- package/dist/esm/fields/Date/dateTimePickerLoader.native.js.map +0 -1
- package/dist/esm/fields/Date/sheetKeyboard.mjs +0 -21
- package/dist/esm/fields/Date/sheetKeyboard.mjs.map +0 -1
- package/dist/esm/fields/Date/sheetKeyboard.native.js +0 -21
- package/dist/esm/fields/Date/sheetKeyboard.native.js.map +0 -1
- package/dist/jsx/fields/Date/dateTimePickerLoader.mjs +0 -13
- package/dist/jsx/fields/Date/dateTimePickerLoader.mjs.map +0 -1
- package/dist/jsx/fields/Date/dateTimePickerLoader.native.js +0 -42
- package/dist/jsx/fields/Date/dateTimePickerLoader.native.js.map +0 -1
- package/dist/jsx/fields/Date/sheetKeyboard.mjs +0 -21
- package/dist/jsx/fields/Date/sheetKeyboard.mjs.map +0 -1
- package/dist/jsx/fields/Date/sheetKeyboard.native.js +0 -57
- package/dist/jsx/fields/Date/sheetKeyboard.native.js.map +0 -1
- package/src/fields/Date/dateTimePickerLoader.ts +0 -25
- package/src/fields/Date/index.native.tsx +0 -445
- package/src/fields/Date/nativeFallback.spec.tsx +0 -21
- package/src/fields/Date/nativePresentation.spec.tsx +0 -278
- package/src/fields/Date/sheetKeyboard.spec.ts +0 -60
- package/src/fields/Date/sheetKeyboard.ts +0 -45
- package/types/fields/Date/dateTimePickerLoader.d.ts +0 -11
- package/types/fields/Date/dateTimePickerLoader.d.ts.map +0 -1
- package/types/fields/Date/index.native.d.ts +0 -14
- package/types/fields/Date/index.native.d.ts.map +0 -1
- package/types/fields/Date/sheetKeyboard.d.ts +0 -20
- package/types/fields/Date/sheetKeyboard.d.ts.map +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Frappe `Date` field has no native fork (FZ-8000, LC-175): iOS and
|
|
3
|
+
* Android resolve the same catalog field the web does, and forms'
|
|
4
|
+
* `DatePicker`, `DatetimePicker` and `TimePicker` open the OS sheet
|
|
5
|
+
* themselves (`OsDateTimeSheet`, with the catalog overlay when the optional
|
|
6
|
+
* `@react-native-community/datetimepicker` peer is absent, FZ-7357).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
import * as catalog from "./catalog";
|
|
13
|
+
import * as entry from "./index";
|
|
14
|
+
|
|
15
|
+
const here = (file: string) => fileURLToPath(new URL(file, import.meta.url));
|
|
16
|
+
|
|
17
|
+
describe("native Date field", () => {
|
|
18
|
+
it("is not forked: no index.native.tsx sits beside the catalog field", () => {
|
|
19
|
+
expect(existsSync(here("./index.tsx"))).toBe(true);
|
|
20
|
+
expect(existsSync(here("./index.native.tsx"))).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("is the catalog field on every platform", () => {
|
|
24
|
+
expect(entry.Date).toBe(catalog.Date);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -5,16 +5,12 @@
|
|
|
5
5
|
* The web field used to render ONE date-only calendar whatever the type
|
|
6
6
|
* (SB-M-617): a `Datetime` dropped its time component from the picker, and a
|
|
7
7
|
* `Time` rendered EMPTY, because the calendar adopts its value through
|
|
8
|
-
* `coerceToDate` and `new Date("09:00")` is an Invalid Date.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* The suite runs on web, so the native half's two native-only edges are mocked
|
|
16
|
-
* exactly as `nativePresentation.spec.tsx` mocks them: the OS picker (recorded
|
|
17
|
-
* rather than rendered) and the platform flags. The web half imports neither.
|
|
8
|
+
* `coerceToDate` and `new Date("09:00")` is an Invalid Date. These cases pin
|
|
9
|
+
* the three web controls — display, edit, and the exact wire string — and
|
|
10
|
+
* then assert the moment an OS sheet commits on native serializes to the same
|
|
11
|
+
* bytes. Native has no fork of this field (FZ-8000): the same catalog field
|
|
12
|
+
* runs there, forms' pickers commit a `Date` from `OsDateTimeSheet`, and the
|
|
13
|
+
* catalog writes it through the one `wire.ts` body.
|
|
18
14
|
*/
|
|
19
15
|
|
|
20
16
|
import { describe, it, expect, vi, beforeAll, beforeEach } from "vitest";
|
|
@@ -23,38 +19,6 @@ import { describe, it, expect, vi, beforeAll, beforeEach } from "vitest";
|
|
|
23
19
|
// import transforms the whole fields graph.
|
|
24
20
|
vi.setConfig({ testTimeout: 240_000 });
|
|
25
21
|
|
|
26
|
-
const mockState = vi.hoisted(() => ({
|
|
27
|
-
isIos: true,
|
|
28
|
-
isAndroid: false,
|
|
29
|
-
/** Props of every mounted OS picker, newest last. */
|
|
30
|
-
picks: [] as Record<string, unknown>[],
|
|
31
|
-
}));
|
|
32
|
-
|
|
33
|
-
vi.mock("./dateTimePickerLoader", () => ({
|
|
34
|
-
loadDateTimePicker: () => (props: Record<string, unknown>) => {
|
|
35
|
-
mockState.picks.push(props);
|
|
36
|
-
return null;
|
|
37
|
-
},
|
|
38
|
-
}));
|
|
39
|
-
|
|
40
|
-
vi.mock("@multiplatform.one/platform", async (importOriginal) => {
|
|
41
|
-
const actual = (await importOriginal()) as Record<string, unknown>;
|
|
42
|
-
const real = actual.platform as Record<string, unknown>;
|
|
43
|
-
return {
|
|
44
|
-
...actual,
|
|
45
|
-
platform: new Proxy(
|
|
46
|
-
{},
|
|
47
|
-
{
|
|
48
|
-
get(_target, prop) {
|
|
49
|
-
if (prop === "isIos") return mockState.isIos;
|
|
50
|
-
if (prop === "isAndroid") return mockState.isAndroid;
|
|
51
|
-
return real[prop as string];
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
),
|
|
55
|
-
};
|
|
56
|
-
});
|
|
57
|
-
|
|
58
22
|
// Mock react-native-reanimated to prevent ESM module resolution failures
|
|
59
23
|
// (same shim as tests/fieldRenderers.spec.tsx).
|
|
60
24
|
vi.mock("react-native-reanimated", () => ({
|
|
@@ -95,9 +59,9 @@ vi.mock("react-native-reanimated", () => ({
|
|
|
95
59
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
96
60
|
import { act, cleanup, fireEvent, waitFor } from "@testing-library/react";
|
|
97
61
|
import React from "react";
|
|
62
|
+
import { toFrappeDateValue } from "./wire";
|
|
98
63
|
|
|
99
64
|
const loadWebDateField = async () => (await import(".")).Date;
|
|
100
|
-
const loadNativeDateField = async () => (await import("./index.native")).Date;
|
|
101
65
|
|
|
102
66
|
/** Intl puts a narrow no-break space before the meridiem; no test should care. */
|
|
103
67
|
const norm = (value: string) => value.replace(/\s+/gu, " ").trim();
|
|
@@ -180,16 +144,13 @@ async function selectPeriod(period: "AM" | "PM") {
|
|
|
180
144
|
// (110-155s quiet, past 240s under load), and charging it to an assertion made
|
|
181
145
|
// whichever case ran first time out.
|
|
182
146
|
beforeAll(async () => {
|
|
183
|
-
await
|
|
147
|
+
await loadWebDateField();
|
|
184
148
|
}, 900_000);
|
|
185
149
|
|
|
186
150
|
beforeEach(() => {
|
|
187
151
|
// Both halves portal their surfaces, so a previous case's chrome would
|
|
188
152
|
// otherwise still be in the document when the next one queries it.
|
|
189
153
|
cleanup();
|
|
190
|
-
mockState.picks.length = 0;
|
|
191
|
-
mockState.isIos = true;
|
|
192
|
-
mockState.isAndroid = false;
|
|
193
154
|
});
|
|
194
155
|
|
|
195
156
|
// ---------------------------------------------------------------------------
|
|
@@ -356,41 +317,14 @@ describe("web Date field — type=datetime renders date AND time", () => {
|
|
|
356
317
|
// Cross-half parity — the reason one `wire.ts` body is shared
|
|
357
318
|
// ---------------------------------------------------------------------------
|
|
358
319
|
|
|
359
|
-
/**
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
):
|
|
366
|
-
|
|
367
|
-
const onChange = vi.fn();
|
|
368
|
-
const result = renderWithProviders(
|
|
369
|
-
<DateField label="Field" value={value} onChange={onChange} type={type} />,
|
|
370
|
-
);
|
|
371
|
-
await pressText(result.container, triggerText);
|
|
372
|
-
await waitFor(() => expect(mockState.picks.length).toBeGreaterThan(0), { timeout: 30_000 });
|
|
373
|
-
|
|
374
|
-
for (const [index, step] of steps.entries()) {
|
|
375
|
-
const onPickerChange = mockState.picks[mockState.picks.length - 1].onChange as (
|
|
376
|
-
event: unknown,
|
|
377
|
-
date?: Date,
|
|
378
|
-
) => void;
|
|
379
|
-
await act(async () => {
|
|
380
|
-
onPickerChange({ type: "set" }, step);
|
|
381
|
-
});
|
|
382
|
-
// A datetime runs calendar → Next → wheel; the sheet's Next is the seam.
|
|
383
|
-
if (index === 0 && steps.length > 1) {
|
|
384
|
-
await pressText(document.body, "Next");
|
|
385
|
-
await waitFor(() => expect(mockState.picks[mockState.picks.length - 1].mode).toBe("time"), {
|
|
386
|
-
timeout: 30_000,
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
await pressText(document.body, "Done");
|
|
391
|
-
|
|
392
|
-
expect(onChange).toHaveBeenCalledTimes(1);
|
|
393
|
-
return onChange.mock.calls[0][0] as string;
|
|
320
|
+
/**
|
|
321
|
+
* What the catalog writes for the moment an OS sheet commits on native: forms'
|
|
322
|
+
* native `DatePicker` and `DatetimePicker` hand the field a `Date`, and its
|
|
323
|
+
* `TimePicker` an `HH:mm:ss` string, through the same `onChange` the web
|
|
324
|
+
* pickers use.
|
|
325
|
+
*/
|
|
326
|
+
function nativeWrite(type: "date" | "datetime" | "time", committed: Date): string {
|
|
327
|
+
return toFrappeDateValue(committed, type);
|
|
394
328
|
}
|
|
395
329
|
|
|
396
330
|
/** Drive the web half through the equivalent pick and return the last string. */
|
|
@@ -419,9 +353,7 @@ describe("web and native persist byte-identical wire strings", () => {
|
|
|
419
353
|
fireEvent.click(dayCell(15)!);
|
|
420
354
|
});
|
|
421
355
|
});
|
|
422
|
-
|
|
423
|
-
mockState.picks.length = 0;
|
|
424
|
-
const native = await nativePick("date", "2026-03-05", "Mar 5, 2026", [new Date(2026, 2, 15)]);
|
|
356
|
+
const native = nativeWrite("date", new Date(2026, 2, 15));
|
|
425
357
|
|
|
426
358
|
expect({ web, native }).toEqual({ web: "2026-03-15", native: "2026-03-15" });
|
|
427
359
|
expect(web).toBe(native);
|
|
@@ -431,11 +363,7 @@ describe("web and native persist byte-identical wire strings", () => {
|
|
|
431
363
|
const web = await webPick("time", "09:00:00", async () => {
|
|
432
364
|
await selectPeriod("PM");
|
|
433
365
|
});
|
|
434
|
-
|
|
435
|
-
mockState.picks.length = 0;
|
|
436
|
-
const native = await nativePick("time", "09:00:00", "9:00 AM", [
|
|
437
|
-
new Date(2026, 2, 5, 21, 0, 0),
|
|
438
|
-
]);
|
|
366
|
+
const native = nativeWrite("time", new Date(2026, 2, 5, 21, 0, 0));
|
|
439
367
|
|
|
440
368
|
expect({ web, native }).toEqual({ web: "21:00:00", native: "21:00:00" });
|
|
441
369
|
expect(web).toBe(native);
|
|
@@ -448,14 +376,8 @@ describe("web and native persist byte-identical wire strings", () => {
|
|
|
448
376
|
fireEvent.click(dayCell(20)!);
|
|
449
377
|
});
|
|
450
378
|
});
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
// The native two-step: the calendar commits the day (dropping the clock,
|
|
454
|
-
// which is why the wheel step re-supplies it), then the wheel commits it.
|
|
455
|
-
const native = await nativePick("datetime", "2026-03-05 14:30:00", "Mar 5, 2026, 2:30 PM", [
|
|
456
|
-
new Date(2026, 2, 20),
|
|
457
|
-
new Date(2026, 0, 1, 14, 30),
|
|
458
|
-
]);
|
|
379
|
+
// The OS sheet's calendar-then-wheel commits one moment from both halves.
|
|
380
|
+
const native = nativeWrite("datetime", new Date(2026, 2, 20, 14, 30));
|
|
459
381
|
|
|
460
382
|
expect({ web, native }).toEqual({
|
|
461
383
|
web: "2026-03-20 14:30:00",
|
|
@@ -84,13 +84,14 @@ describe("Frappe remainder wrappers — design-law 100%", () => {
|
|
|
84
84
|
expect(stories).toMatch(/from ["']\.\/ChartCard["']/);
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
it("FrappeImageView
|
|
87
|
+
it("FrappeImageView is the MPO ImageGrid photos grid, controlIcon icons, and no media pip (R11/R12, LC-264)", () => {
|
|
88
88
|
const source = read("FrappeImageView.tsx");
|
|
89
|
-
expect(source).
|
|
89
|
+
expect(source).toMatch(/ImageGrid[\s\S]*from "@multiplatform.one\/components"/);
|
|
90
|
+
expect(source).toContain('variant="photos"');
|
|
90
91
|
expect(source).toContain("controlIcon");
|
|
91
92
|
expect(source).not.toMatch(/size=\{48\}/);
|
|
92
93
|
expect(source).not.toContain("<Tint");
|
|
93
|
-
expect(source).
|
|
94
|
+
expect(source).toMatch(/no pip/i);
|
|
94
95
|
});
|
|
95
96
|
|
|
96
97
|
it("FrappeTreeView uses label fragment and controlIcon, not 12/14px", () => {
|
|
@@ -156,10 +157,10 @@ describe("Frappe remainder wrappers — design-law 100%", () => {
|
|
|
156
157
|
expect(list).toContain("formCommonColors.muted");
|
|
157
158
|
});
|
|
158
159
|
|
|
159
|
-
it("native Date
|
|
160
|
-
const source = read("fields/Date/
|
|
161
|
-
expect(source).toMatch(/
|
|
162
|
-
expect(
|
|
160
|
+
it("native Date is the catalog field on the forms pickers, not a fork (LC-175)", () => {
|
|
161
|
+
const source = read("fields/Date/catalog.tsx");
|
|
162
|
+
expect(source).toMatch(/DatePicker[\s\S]*from "@multiplatform.one\/forms"/);
|
|
163
|
+
expect(read("fields/Date/index.tsx")).toContain('export { Date } from "./catalog"');
|
|
163
164
|
});
|
|
164
165
|
|
|
165
166
|
it("fieldRegistry TextEditor fallback is Skeleton; SmallText/LongText use textAreaProps", () => {
|
|
@@ -1,97 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
ensureFocusVisibleRing,
|
|
4
|
-
ensureKeyboardModalityTracking,
|
|
5
|
-
keyboardFocusRingProps,
|
|
6
|
-
useResolvedKnobs,
|
|
7
|
-
wasKeyboardFocus,
|
|
8
|
-
} from "@multiplatform.one/theme";
|
|
9
|
-
import { useState } from "react";
|
|
1
|
+
import { Chip, Tags } from "@multiplatform.one/components";
|
|
10
2
|
import { useTranslation } from "react-i18next";
|
|
11
3
|
import type { InsightsCount } from "./insightsData";
|
|
12
4
|
|
|
13
|
-
const chipFocusRing = ensureFocusVisibleRing(keyboardFocusRingProps);
|
|
14
|
-
|
|
15
|
-
interface FacetTagChipProps {
|
|
16
|
-
value: string;
|
|
17
|
-
count: number;
|
|
18
|
-
label: string;
|
|
19
|
-
tint?: string;
|
|
20
|
-
onPress: () => void;
|
|
21
|
-
testID?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* A pressable facet value painted from its tint's ramp (DF-04), at the
|
|
26
|
-
* compact nestedControl height with the press target restored by hitSlop
|
|
27
|
-
* (LC-54, LC-73); the keyboard ring rides the whole chip (LC-71).
|
|
28
|
-
*/
|
|
29
|
-
function FacetTagChip({ value, count, label, tint = "gray", onPress, testID }: FacetTagChipProps) {
|
|
30
|
-
const { t } = useTranslation();
|
|
31
|
-
const { knobProps } = useResolvedKnobs();
|
|
32
|
-
const nested = knobProps.nestedControl;
|
|
33
|
-
const [kbFocus, setKbFocus] = useState(false);
|
|
34
|
-
if (isWeb) ensureKeyboardModalityTracking();
|
|
35
|
-
return (
|
|
36
|
-
<XStack
|
|
37
|
-
{...knobProps.borderRadius}
|
|
38
|
-
role="button"
|
|
39
|
-
tabIndex={0}
|
|
40
|
-
aria-label={t("{{value}}, {{count}} records", { value: label, count })}
|
|
41
|
-
cursor="pointer"
|
|
42
|
-
alignItems="center"
|
|
43
|
-
gap="$1.5"
|
|
44
|
-
paddingHorizontal="$2"
|
|
45
|
-
minHeight={nested.px}
|
|
46
|
-
height={nested.px}
|
|
47
|
-
hitSlop={nested.hitSlop}
|
|
48
|
-
data-nested-px={nested.px}
|
|
49
|
-
backgroundColor={`$${tint}3` as never}
|
|
50
|
-
hoverStyle={{ backgroundColor: `$${tint}4` as never }}
|
|
51
|
-
pressStyle={{ backgroundColor: `$${tint}5` as never }}
|
|
52
|
-
outlineWidth={0}
|
|
53
|
-
focusStyle={{ outlineWidth: 0 }}
|
|
54
|
-
focusVisibleStyle={chipFocusRing}
|
|
55
|
-
{...(isWeb
|
|
56
|
-
? {
|
|
57
|
-
onFocus: () => {
|
|
58
|
-
if (wasKeyboardFocus()) setKbFocus(true);
|
|
59
|
-
},
|
|
60
|
-
onBlur: () => setKbFocus(false),
|
|
61
|
-
onKeyDown: (event: { key?: string; preventDefault?: () => void }) => {
|
|
62
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
63
|
-
event.preventDefault?.();
|
|
64
|
-
onPress();
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
}
|
|
68
|
-
: undefined)}
|
|
69
|
-
{...(kbFocus ? keyboardFocusRingProps : undefined)}
|
|
70
|
-
onPress={onPress}
|
|
71
|
-
testID={testID ? `${testID}-${value}` : undefined}
|
|
72
|
-
>
|
|
73
|
-
<XStack
|
|
74
|
-
width="$1"
|
|
75
|
-
height="$1"
|
|
76
|
-
borderRadius={1000}
|
|
77
|
-
backgroundColor={`$${tint}9` as never}
|
|
78
|
-
flexShrink={0}
|
|
79
|
-
/>
|
|
80
|
-
<Text
|
|
81
|
-
{...knobProps.label}
|
|
82
|
-
color={`$${tint}11` as never}
|
|
83
|
-
textTransform="capitalize"
|
|
84
|
-
userSelect="none"
|
|
85
|
-
>
|
|
86
|
-
{label}
|
|
87
|
-
</Text>
|
|
88
|
-
<Text {...knobProps.label} color={`$${tint}11` as never} opacity={0.7} userSelect="none">
|
|
89
|
-
{count}
|
|
90
|
-
</Text>
|
|
91
|
-
</XStack>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
5
|
export interface InsightsFacetTagsProps {
|
|
96
6
|
distribution: readonly InsightsCount[];
|
|
97
7
|
label: (value: string) => string;
|
|
@@ -100,7 +10,10 @@ export interface InsightsFacetTagsProps {
|
|
|
100
10
|
testID?: string;
|
|
101
11
|
}
|
|
102
12
|
|
|
103
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* A facet's values with their record counts as MPO `Chip`s painted from each
|
|
15
|
+
* value's ramp (DF-04, LC-175), each opening the list narrowed to it.
|
|
16
|
+
*/
|
|
104
17
|
export function InsightsFacetTags({
|
|
105
18
|
distribution,
|
|
106
19
|
label,
|
|
@@ -115,16 +28,22 @@ export function InsightsFacetTags({
|
|
|
115
28
|
enableAdd={false}
|
|
116
29
|
enableRemove={false}
|
|
117
30
|
labels={{ noTags: t("No values yet") }}
|
|
118
|
-
renderTag={(tag) =>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
31
|
+
renderTag={(tag) => {
|
|
32
|
+
const count = distribution.find((entry) => entry.value === tag.id)?.count ?? 0;
|
|
33
|
+
const hue = tint?.(tag.id) ?? "gray";
|
|
34
|
+
return (
|
|
35
|
+
<Chip
|
|
36
|
+
color={hue}
|
|
37
|
+
swatch={`$${hue}9` as never}
|
|
38
|
+
count={count}
|
|
39
|
+
aria-label={t("{{value}}, {{count}} records", { value: tag.label, count })}
|
|
40
|
+
onPress={() => onSelect(tag.id)}
|
|
41
|
+
testID={testID ? `${testID}-${tag.id}` : undefined}
|
|
42
|
+
>
|
|
43
|
+
{tag.label}
|
|
44
|
+
</Chip>
|
|
45
|
+
);
|
|
46
|
+
}}
|
|
128
47
|
/>
|
|
129
48
|
);
|
|
130
49
|
}
|
package/src/list/FacetBadge.tsx
CHANGED
|
@@ -1,44 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { hairlineWidth, sizeTokenStep, useResolvedKnobs } from "@multiplatform.one/theme";
|
|
1
|
+
import { Chip, type ChipSize } from "@multiplatform.one/components";
|
|
3
2
|
import type { SizeTokens } from "tamagui";
|
|
4
|
-
import { facetBadgeSteps } from "./facetBadgeSteps";
|
|
5
3
|
|
|
6
4
|
export interface FacetBadgeProps {
|
|
7
5
|
label: string;
|
|
8
6
|
/** Theme ramp (`"green"`) painting the badge (LC-147). */
|
|
9
7
|
tint?: string;
|
|
10
|
-
/** Size token (Tamagui's own `size`);
|
|
8
|
+
/** Size token (Tamagui's own `size`); omitted, the chip takes the ambient size. */
|
|
11
9
|
size?: SizeTokens;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
|
-
* One facet value as a static
|
|
16
|
-
* step-4 fill
|
|
13
|
+
* One facet value as a static MPO `Chip` tinted from its ramp: the ramp's
|
|
14
|
+
* step-4 fill and step-12 ink, AA in both schemes (DF-04, LC-175).
|
|
17
15
|
*/
|
|
18
16
|
export function FacetBadge({ label, tint = "gray", size }: FacetBadgeProps) {
|
|
19
|
-
const { knobProps } = useResolvedKnobs({ size });
|
|
20
|
-
const small = sizeTokenStep(knobProps.sizeToken) < 0;
|
|
21
17
|
return (
|
|
22
|
-
<
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
paddingVertical={small ? "$0.5" : "$1"}
|
|
26
|
-
backgroundColor={`$${tint}${facetBadgeSteps.fill}` as never}
|
|
27
|
-
borderColor={`$${tint}${facetBadgeSteps.border}` as never}
|
|
28
|
-
borderWidth={hairlineWidth}
|
|
29
|
-
alignItems="center"
|
|
30
|
-
>
|
|
31
|
-
<Text
|
|
32
|
-
{...knobProps.label}
|
|
33
|
-
{...knobProps.body}
|
|
34
|
-
textTransform="capitalize"
|
|
35
|
-
fontWeight="700"
|
|
36
|
-
color={`$${tint}${facetBadgeSteps.ink}` as never}
|
|
37
|
-
{...(small ? { fontSize: "$1" as const } : null)}
|
|
38
|
-
letterSpacing={0.3}
|
|
39
|
-
>
|
|
40
|
-
{label}
|
|
41
|
-
</Text>
|
|
42
|
-
</XStack>
|
|
18
|
+
<Chip color={tint} size={size as ChipSize | undefined}>
|
|
19
|
+
{label}
|
|
20
|
+
</Chip>
|
|
43
21
|
);
|
|
44
22
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
2
|
+
import { chipFrameGeometry, chipTextSize } from "@multiplatform.one/components";
|
|
2
3
|
import {
|
|
3
4
|
applyThemeScale,
|
|
4
5
|
createDefaultThemeConfig,
|
|
5
6
|
DEFAULT_SCALE_ID,
|
|
6
7
|
densePreset,
|
|
7
8
|
Surface,
|
|
8
|
-
sizeRecipeForToken,
|
|
9
9
|
sizeKeyBelow,
|
|
10
10
|
} from "@multiplatform.one/theme";
|
|
11
11
|
import { cleanup, fireEvent } from "@testing-library/react";
|
|
@@ -22,26 +22,25 @@ const options = [
|
|
|
22
22
|
{ value: "fire", label: "Fire", count: 2 },
|
|
23
23
|
];
|
|
24
24
|
|
|
25
|
-
describe("FacetRail
|
|
25
|
+
describe("FacetRail chips are MPO Chips (LC-175)", () => {
|
|
26
26
|
for (const scaleId of [DEFAULT_SCALE_ID, "dense"]) {
|
|
27
27
|
for (const size of ["$true", "$3", "$5"] as const) {
|
|
28
|
-
it(`${scaleId} at ${size} paints one full step below its controls`, () => {
|
|
28
|
+
it(`${scaleId} at ${size} paints the MPO chip one full step below its controls`, () => {
|
|
29
29
|
applyThemeScale(config.scales![scaleId]);
|
|
30
30
|
const token = sizeKeyBelow(size);
|
|
31
|
-
const
|
|
32
|
-
const
|
|
31
|
+
const geometry = chipFrameGeometry(token);
|
|
32
|
+
const font = chipTextSize(token as "$2");
|
|
33
33
|
const result = renderWithProviders(
|
|
34
34
|
<Surface size={size}>
|
|
35
35
|
<FacetRail label="Type" value="" options={options} onChange={() => {}} />
|
|
36
36
|
</Surface>,
|
|
37
37
|
);
|
|
38
38
|
const frame = result.getByRole("radio", { name: "Fire 2" });
|
|
39
|
+
expect(frame.hasAttribute("data-chip")).toBe(true);
|
|
39
40
|
const style = getComputedStyle(frame);
|
|
40
|
-
expect(style.
|
|
41
|
-
expect(
|
|
42
|
-
expect(
|
|
43
|
-
expect(getComputedStyle(result.getByText("Fire")).fontSize).toBe(`${recipe.fontSize}px`);
|
|
44
|
-
expect(getComputedStyle(result.getByText("2")).fontSize).toBe(`${count.fontSize}px`);
|
|
41
|
+
expect(style.paddingLeft).toBe(`${geometry.paddingHorizontal}px`);
|
|
42
|
+
expect(getComputedStyle(result.getByText("Fire")).fontSize).toBe(`${font}px`);
|
|
43
|
+
expect(getComputedStyle(result.getByText("2")).fontSize).toBe(`${font}px`);
|
|
45
44
|
});
|
|
46
45
|
}
|
|
47
46
|
}
|
|
@@ -53,6 +52,8 @@ describe("FacetRail chip recipes", () => {
|
|
|
53
52
|
);
|
|
54
53
|
const fire = result.getByRole("radio", { name: "Fire 2" });
|
|
55
54
|
expect(fire.getAttribute("aria-checked")).toBe("true");
|
|
55
|
+
expect(fire.getAttribute("tabindex")).toBe("0");
|
|
56
|
+
expect(result.getByRole("radio", { name: "All 6" }).getAttribute("tabindex")).toBe("-1");
|
|
56
57
|
fireEvent.click(fire);
|
|
57
58
|
expect(onChange).toHaveBeenLastCalledWith("");
|
|
58
59
|
fireEvent.keyDown(fire, { key: "ArrowLeft" });
|