@multiplatform.one/table 7.10.0 → 7.15.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/README.md +61 -1
- package/dist/cjs/components/ChildTable/index.cjs +8 -2
- package/dist/cjs/components/ChildTable/index.native.js +8 -2
- package/dist/cjs/components/ChildTable/index.native.js.map +1 -1
- package/dist/cjs/components/ColumnHeaderFilter/index.cjs +77 -111
- package/dist/cjs/components/ColumnHeaderFilter/index.native.js +89 -129
- package/dist/cjs/components/ColumnHeaderFilter/index.native.js.map +1 -1
- package/dist/cjs/components/DataTable/DataTableCardControls.cjs +90 -54
- package/dist/cjs/components/DataTable/DataTableCardControls.native.js +93 -56
- package/dist/cjs/components/DataTable/DataTableCardControls.native.js.map +1 -1
- package/dist/cjs/components/DataTable/DataTableRoot.cjs +68 -9
- package/dist/cjs/components/DataTable/DataTableRoot.native.js +78 -11
- package/dist/cjs/components/DataTable/DataTableRoot.native.js.map +1 -1
- package/dist/cjs/components/DataTableCell/CellModalEditor.cjs +72 -70
- package/dist/cjs/components/DataTableCell/index.cjs +2 -2
- package/dist/cjs/components/DataTableCell/index.native.js +2 -11
- package/dist/cjs/components/DataTableCell/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableDateFilter/index.cjs +135 -158
- package/dist/cjs/components/DataTableDateFilter/index.native.js +153 -183
- package/dist/cjs/components/DataTableDateFilter/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableExport/index.cjs +122 -139
- package/dist/cjs/components/DataTableExport/index.native.js +135 -157
- package/dist/cjs/components/DataTableExport/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableFilterButton/index.cjs +14 -0
- package/dist/cjs/components/DataTableFilterButton/index.native.js +15 -0
- package/dist/cjs/components/DataTableFilterButton/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableGrouping/index.cjs +192 -212
- package/dist/cjs/components/DataTableGrouping/index.native.js +209 -230
- package/dist/cjs/components/DataTableGrouping/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableSearch/index.cjs +103 -115
- package/dist/cjs/components/DataTableSearch/index.native.js +111 -123
- package/dist/cjs/components/DataTableSearch/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableToolbar/index.cjs +161 -101
- package/dist/cjs/components/DataTableToolbar/index.native.js +168 -109
- package/dist/cjs/components/DataTableToolbar/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableViewOptions/index.cjs +38 -54
- package/dist/cjs/components/DataTableViewOptions/index.native.js +40 -56
- package/dist/cjs/components/DataTableViewOptions/index.native.js.map +1 -1
- package/dist/cjs/components/FilterOperatorValueEditor/index.cjs +3 -11
- package/dist/cjs/components/FilterOperatorValueEditor/index.native.js +3 -11
- package/dist/cjs/components/FilterOperatorValueEditor/index.native.js.map +1 -1
- package/dist/cjs/components/SimpleTable/index.cjs +2 -6
- package/dist/cjs/components/SimpleTable/index.native.js +2 -6
- package/dist/cjs/components/SimpleTable/index.native.js.map +1 -1
- package/dist/cjs/components/TableInput/RowDetailEditor.cjs +190 -0
- package/dist/cjs/components/TableInput/RowDetailEditor.native.js +172 -0
- package/dist/cjs/components/TableInput/RowDetailEditor.native.js.map +1 -0
- package/dist/cjs/components/TableInput/index.cjs +42 -5
- package/dist/cjs/components/TableInput/index.native.js +64 -1
- package/dist/cjs/components/TableInput/index.native.js.map +1 -1
- package/dist/cjs/components/TableInput/shared.cjs +8 -0
- package/dist/cjs/components/TableInput/shared.native.js +10 -0
- package/dist/cjs/components/TableInput/shared.native.js.map +1 -1
- package/dist/cjs/hooks/useDataTable.cjs +43 -2
- package/dist/cjs/hooks/useDataTable.native.js +49 -3
- package/dist/cjs/hooks/useDataTable.native.js.map +1 -1
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/utils/rowPress.cjs +4 -1
- package/dist/cjs/utils/rowPress.native.js +4 -1
- package/dist/cjs/utils/rowPress.native.js.map +1 -1
- package/dist/esm/components/ChildTable/index.mjs +8 -2
- package/dist/esm/components/ChildTable/index.mjs.map +1 -1
- package/dist/esm/components/ChildTable/index.native.js +8 -2
- package/dist/esm/components/ChildTable/index.native.js.map +1 -1
- package/dist/esm/components/ColumnHeaderFilter/index.mjs +80 -114
- package/dist/esm/components/ColumnHeaderFilter/index.mjs.map +1 -1
- package/dist/esm/components/ColumnHeaderFilter/index.native.js +92 -132
- package/dist/esm/components/ColumnHeaderFilter/index.native.js.map +1 -1
- package/dist/esm/components/DataTable/DataTableCardControls.mjs +89 -54
- package/dist/esm/components/DataTable/DataTableCardControls.mjs.map +1 -1
- package/dist/esm/components/DataTable/DataTableCardControls.native.js +92 -56
- package/dist/esm/components/DataTable/DataTableCardControls.native.js.map +1 -1
- package/dist/esm/components/DataTable/DataTableRoot.mjs +70 -11
- package/dist/esm/components/DataTable/DataTableRoot.mjs.map +1 -1
- package/dist/esm/components/DataTable/DataTableRoot.native.js +80 -13
- package/dist/esm/components/DataTable/DataTableRoot.native.js.map +1 -1
- package/dist/esm/components/DataTableCell/CellModalEditor.mjs +76 -74
- package/dist/esm/components/DataTableCell/CellModalEditor.mjs.map +1 -1
- package/dist/esm/components/DataTableCell/index.mjs +3 -3
- package/dist/esm/components/DataTableCell/index.mjs.map +1 -1
- package/dist/esm/components/DataTableCell/index.native.js +3 -12
- package/dist/esm/components/DataTableCell/index.native.js.map +1 -1
- package/dist/esm/components/DataTableDateFilter/index.mjs +137 -160
- package/dist/esm/components/DataTableDateFilter/index.mjs.map +1 -1
- package/dist/esm/components/DataTableDateFilter/index.native.js +155 -185
- package/dist/esm/components/DataTableDateFilter/index.native.js.map +1 -1
- package/dist/esm/components/DataTableExport/index.mjs +124 -141
- package/dist/esm/components/DataTableExport/index.mjs.map +1 -1
- package/dist/esm/components/DataTableExport/index.native.js +137 -159
- package/dist/esm/components/DataTableExport/index.native.js.map +1 -1
- package/dist/esm/components/DataTableFilterButton/index.mjs +14 -1
- package/dist/esm/components/DataTableFilterButton/index.mjs.map +1 -1
- package/dist/esm/components/DataTableFilterButton/index.native.js +15 -1
- package/dist/esm/components/DataTableFilterButton/index.native.js.map +1 -1
- package/dist/esm/components/DataTableGrouping/index.mjs +194 -214
- package/dist/esm/components/DataTableGrouping/index.mjs.map +1 -1
- package/dist/esm/components/DataTableGrouping/index.native.js +211 -232
- package/dist/esm/components/DataTableGrouping/index.native.js.map +1 -1
- package/dist/esm/components/DataTableSearch/index.mjs +105 -117
- package/dist/esm/components/DataTableSearch/index.mjs.map +1 -1
- package/dist/esm/components/DataTableSearch/index.native.js +113 -125
- package/dist/esm/components/DataTableSearch/index.native.js.map +1 -1
- package/dist/esm/components/DataTableToolbar/index.mjs +165 -106
- package/dist/esm/components/DataTableToolbar/index.mjs.map +1 -1
- package/dist/esm/components/DataTableToolbar/index.native.js +172 -114
- package/dist/esm/components/DataTableToolbar/index.native.js.map +1 -1
- package/dist/esm/components/DataTableViewOptions/index.mjs +40 -56
- package/dist/esm/components/DataTableViewOptions/index.mjs.map +1 -1
- package/dist/esm/components/DataTableViewOptions/index.native.js +42 -58
- package/dist/esm/components/DataTableViewOptions/index.native.js.map +1 -1
- package/dist/esm/components/FilterOperatorValueEditor/index.mjs +3 -11
- package/dist/esm/components/FilterOperatorValueEditor/index.mjs.map +1 -1
- package/dist/esm/components/FilterOperatorValueEditor/index.native.js +3 -11
- package/dist/esm/components/FilterOperatorValueEditor/index.native.js.map +1 -1
- package/dist/esm/components/SimpleTable/index.mjs +3 -7
- package/dist/esm/components/SimpleTable/index.mjs.map +1 -1
- package/dist/esm/components/SimpleTable/index.native.js +3 -7
- package/dist/esm/components/SimpleTable/index.native.js.map +1 -1
- package/dist/esm/components/TableInput/RowDetailEditor.mjs +165 -0
- package/dist/esm/components/TableInput/RowDetailEditor.mjs.map +1 -0
- package/dist/esm/components/TableInput/RowDetailEditor.native.js +144 -0
- package/dist/esm/components/TableInput/RowDetailEditor.native.js.map +1 -0
- package/dist/esm/components/TableInput/index.mjs +42 -5
- package/dist/esm/components/TableInput/index.mjs.map +1 -1
- package/dist/esm/components/TableInput/index.native.js +64 -1
- package/dist/esm/components/TableInput/index.native.js.map +1 -1
- package/dist/esm/components/TableInput/shared.mjs +7 -1
- package/dist/esm/components/TableInput/shared.mjs.map +1 -1
- package/dist/esm/components/TableInput/shared.native.js +9 -1
- package/dist/esm/components/TableInput/shared.native.js.map +1 -1
- package/dist/esm/hooks/useDataTable.mjs +43 -2
- package/dist/esm/hooks/useDataTable.mjs.map +1 -1
- package/dist/esm/hooks/useDataTable.native.js +49 -3
- package/dist/esm/hooks/useDataTable.native.js.map +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/utils/rowPress.mjs +4 -1
- package/dist/esm/utils/rowPress.mjs.map +1 -1
- package/dist/esm/utils/rowPress.native.js +4 -1
- package/dist/esm/utils/rowPress.native.js.map +1 -1
- package/dist/jsx/components/ChildTable/index.mjs +8 -2
- package/dist/jsx/components/ChildTable/index.mjs.map +1 -1
- package/dist/jsx/components/ChildTable/index.native.js +8 -2
- package/dist/jsx/components/ChildTable/index.native.js.map +1 -1
- package/dist/jsx/components/ColumnHeaderFilter/index.mjs +80 -114
- package/dist/jsx/components/ColumnHeaderFilter/index.mjs.map +1 -1
- package/dist/jsx/components/ColumnHeaderFilter/index.native.js +89 -129
- package/dist/jsx/components/ColumnHeaderFilter/index.native.js.map +1 -1
- package/dist/jsx/components/DataTable/DataTableCardControls.mjs +89 -54
- package/dist/jsx/components/DataTable/DataTableCardControls.mjs.map +1 -1
- package/dist/jsx/components/DataTable/DataTableCardControls.native.js +93 -56
- package/dist/jsx/components/DataTable/DataTableCardControls.native.js.map +1 -1
- package/dist/jsx/components/DataTable/DataTableRoot.mjs +70 -11
- package/dist/jsx/components/DataTable/DataTableRoot.mjs.map +1 -1
- package/dist/jsx/components/DataTable/DataTableRoot.native.js +78 -11
- package/dist/jsx/components/DataTable/DataTableRoot.native.js.map +1 -1
- package/dist/jsx/components/DataTableCell/CellModalEditor.mjs +76 -74
- package/dist/jsx/components/DataTableCell/CellModalEditor.mjs.map +1 -1
- package/dist/jsx/components/DataTableCell/index.mjs +3 -3
- package/dist/jsx/components/DataTableCell/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableCell/index.native.js +2 -11
- package/dist/jsx/components/DataTableCell/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableDateFilter/index.mjs +137 -160
- package/dist/jsx/components/DataTableDateFilter/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableDateFilter/index.native.js +153 -183
- package/dist/jsx/components/DataTableDateFilter/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableExport/index.mjs +124 -141
- package/dist/jsx/components/DataTableExport/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableExport/index.native.js +135 -157
- package/dist/jsx/components/DataTableExport/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableFilterButton/index.mjs +14 -1
- package/dist/jsx/components/DataTableFilterButton/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableFilterButton/index.native.js +15 -0
- package/dist/jsx/components/DataTableFilterButton/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableGrouping/index.mjs +194 -214
- package/dist/jsx/components/DataTableGrouping/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableGrouping/index.native.js +209 -230
- package/dist/jsx/components/DataTableGrouping/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableSearch/index.mjs +105 -117
- package/dist/jsx/components/DataTableSearch/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableSearch/index.native.js +111 -123
- package/dist/jsx/components/DataTableSearch/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableToolbar/index.mjs +165 -106
- package/dist/jsx/components/DataTableToolbar/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableToolbar/index.native.js +168 -109
- package/dist/jsx/components/DataTableToolbar/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableViewOptions/index.mjs +40 -56
- package/dist/jsx/components/DataTableViewOptions/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableViewOptions/index.native.js +40 -56
- package/dist/jsx/components/DataTableViewOptions/index.native.js.map +1 -1
- package/dist/jsx/components/FilterOperatorValueEditor/index.mjs +3 -11
- package/dist/jsx/components/FilterOperatorValueEditor/index.mjs.map +1 -1
- package/dist/jsx/components/FilterOperatorValueEditor/index.native.js +3 -11
- package/dist/jsx/components/FilterOperatorValueEditor/index.native.js.map +1 -1
- package/dist/jsx/components/SimpleTable/index.mjs +3 -7
- package/dist/jsx/components/SimpleTable/index.mjs.map +1 -1
- package/dist/jsx/components/SimpleTable/index.native.js +2 -6
- package/dist/jsx/components/SimpleTable/index.native.js.map +1 -1
- package/dist/jsx/components/TableInput/RowDetailEditor.mjs +165 -0
- package/dist/jsx/components/TableInput/RowDetailEditor.mjs.map +1 -0
- package/dist/jsx/components/TableInput/RowDetailEditor.native.js +172 -0
- package/dist/jsx/components/TableInput/RowDetailEditor.native.js.map +1 -0
- package/dist/jsx/components/TableInput/index.mjs +42 -5
- package/dist/jsx/components/TableInput/index.mjs.map +1 -1
- package/dist/jsx/components/TableInput/index.native.js +64 -1
- package/dist/jsx/components/TableInput/index.native.js.map +1 -1
- package/dist/jsx/components/TableInput/shared.mjs +7 -1
- package/dist/jsx/components/TableInput/shared.mjs.map +1 -1
- package/dist/jsx/components/TableInput/shared.native.js +10 -0
- package/dist/jsx/components/TableInput/shared.native.js.map +1 -1
- package/dist/jsx/hooks/useDataTable.mjs +43 -2
- package/dist/jsx/hooks/useDataTable.mjs.map +1 -1
- package/dist/jsx/hooks/useDataTable.native.js +49 -3
- package/dist/jsx/hooks/useDataTable.native.js.map +1 -1
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/utils/rowPress.mjs +4 -1
- package/dist/jsx/utils/rowPress.mjs.map +1 -1
- package/dist/jsx/utils/rowPress.native.js +4 -1
- package/dist/jsx/utils/rowPress.native.js.map +1 -1
- package/package.json +16 -16
- package/src/components/ChildTable/childTable.cellHidden.spec.tsx +57 -0
- package/src/components/ChildTable/childTable.rowDetail.spec.tsx +120 -0
- package/src/components/ChildTable/index.tsx +16 -0
- package/src/components/ColumnHeaderFilter/index.tsx +89 -116
- package/src/components/DataTable/DataTable.stories.tsx +130 -6
- package/src/components/DataTable/DataTableCardControls.stories.tsx +61 -2
- package/src/components/DataTable/DataTableCardControls.tsx +92 -66
- package/src/components/DataTable/DataTableRoot.tsx +109 -18
- package/src/components/DataTable/cardLayout.spec.tsx +4 -3
- package/src/components/DataTable/cardToolbar.spec.tsx +238 -0
- package/src/components/DataTable/chromeInterplay.spec.tsx +7 -5
- package/src/components/DataTable/columnWidthLayout.spec.tsx +189 -0
- package/src/components/DataTable/dataTableCardControls.spec.tsx +3 -2
- package/src/components/DataTable/dataTableMobileCards.spec.tsx +1 -4
- package/src/components/DataTable/footerLayout.spec.tsx +250 -0
- package/src/components/DataTable/headerContainment.spec.tsx +91 -0
- package/src/components/DataTable/pinningGeometry.spec.tsx +66 -1
- package/src/components/DataTable/rowPress.spec.tsx +2 -6
- package/src/components/DataTableBulkActions/DataTableBulkActions.stories.tsx +5 -4
- package/src/components/DataTableCell/CellModalEditor.tsx +95 -75
- package/src/components/DataTableCell/cellDraftPolicy.spec.tsx +12 -2
- package/src/components/DataTableCell/cellModalEditor.spec.tsx +75 -49
- package/src/components/DataTableCell/dataTableCell.spec.tsx +31 -14
- package/src/components/DataTableCell/index.tsx +3 -2
- package/src/components/DataTableDateFilter/DataTableDateFilter.spec.tsx +6 -3
- package/src/components/DataTableDateFilter/index.tsx +151 -180
- package/src/components/DataTableExport/DataTableExport.spec.tsx +42 -18
- package/src/components/DataTableExport/index.tsx +135 -142
- package/src/components/DataTableFilterButton/index.tsx +9 -0
- package/src/components/DataTableGrouping/index.tsx +193 -195
- package/src/components/DataTableSearch/index.tsx +111 -109
- package/src/components/DataTableToolbar/index.tsx +179 -107
- package/src/components/DataTableViewOptions/DataTableViewOptions.stories.tsx +52 -0
- package/src/components/DataTableViewOptions/index.tsx +32 -40
- package/src/components/FilterOperatorValueEditor/FilterOperatorValueEditor.spec.tsx +64 -2
- package/src/components/FilterOperatorValueEditor/index.tsx +0 -8
- package/src/components/SimpleTable/index.tsx +3 -2
- package/src/components/SimpleTable/simpleTable.spec.tsx +15 -0
- package/src/components/Table/accessibility.spec.tsx +7 -19
- package/src/components/TableInput/RowDetailEditor.native.tsx +134 -0
- package/src/components/TableInput/RowDetailEditor.tsx +173 -0
- package/src/components/TableInput/index.native.tsx +49 -1
- package/src/components/TableInput/index.tsx +65 -10
- package/src/components/TableInput/shared.ts +29 -0
- package/src/components/tableDropdowns.spec.tsx +172 -0
- package/src/hooks/useDataTable.spec.ts +153 -0
- package/src/hooks/useDataTable.ts +38 -2
- package/src/index.ts +1 -0
- package/src/types.ts +14 -12
- package/src/utils/rowPress.ts +3 -0
- package/types/components/ChildTable/index.d.ts +10 -0
- package/types/components/ChildTable/index.d.ts.map +1 -1
- package/types/components/ColumnHeaderFilter/index.d.ts +1 -1
- package/types/components/ColumnHeaderFilter/index.d.ts.map +1 -1
- package/types/components/DataTable/DataTableCardControls.d.ts +3 -0
- package/types/components/DataTable/DataTableCardControls.d.ts.map +1 -1
- package/types/components/DataTable/DataTableRoot.d.ts.map +1 -1
- package/types/components/DataTableCell/CellModalEditor.d.ts +10 -7
- package/types/components/DataTableCell/CellModalEditor.d.ts.map +1 -1
- package/types/components/DataTableCell/index.d.ts.map +1 -1
- package/types/components/DataTableDateFilter/index.d.ts.map +1 -1
- package/types/components/DataTableFilterButton/index.d.ts +2 -1
- package/types/components/DataTableFilterButton/index.d.ts.map +1 -1
- package/types/components/DataTableGrouping/index.d.ts.map +1 -1
- package/types/components/DataTableSearch/index.d.ts.map +1 -1
- package/types/components/DataTableToolbar/index.d.ts +1 -0
- package/types/components/DataTableToolbar/index.d.ts.map +1 -1
- package/types/components/FilterOperatorValueEditor/index.d.ts.map +1 -1
- package/types/components/SimpleTable/index.d.ts.map +1 -1
- package/types/components/TableInput/RowDetailEditor.d.ts +24 -0
- package/types/components/TableInput/RowDetailEditor.d.ts.map +1 -0
- package/types/components/TableInput/RowDetailEditor.native.d.ts +11 -0
- package/types/components/TableInput/RowDetailEditor.native.d.ts.map +1 -0
- package/types/components/TableInput/index.d.ts +11 -2
- package/types/components/TableInput/index.d.ts.map +1 -1
- package/types/components/TableInput/index.native.d.ts +8 -1
- package/types/components/TableInput/index.native.d.ts.map +1 -1
- package/types/components/TableInput/shared.d.ts +11 -0
- package/types/components/TableInput/shared.d.ts.map +1 -1
- package/types/hooks/useDataTable.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/types.d.ts +14 -12
- package/types/types.d.ts.map +1 -1
- package/types/utils/rowPress.d.ts.map +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { Checkbox } from "@multiplatform.one/forms";
|
|
1
2
|
import { action } from "@multiplatform.one/storybook";
|
|
2
3
|
import React from "react";
|
|
3
|
-
import {
|
|
4
|
+
import { Text, XStack, YStack } from "tamagui";
|
|
4
5
|
import { type BulkAction, DataTableBulkActions, useRowSelection } from "./index";
|
|
5
6
|
|
|
6
7
|
// Define the data type
|
|
@@ -309,7 +310,7 @@ export const WithRowSelectionHook = () => {
|
|
|
309
310
|
>
|
|
310
311
|
<Checkbox
|
|
311
312
|
checked={selection.isSelected(task)}
|
|
312
|
-
|
|
313
|
+
onChange={() => {}} // Handled by onPress
|
|
313
314
|
/>
|
|
314
315
|
<YStack flex={1}>
|
|
315
316
|
<Text fontWeight="500">{task.title}</Text>
|
|
@@ -324,9 +325,9 @@ export const WithRowSelectionHook = () => {
|
|
|
324
325
|
<XStack gap="$3" alignItems="center">
|
|
325
326
|
<Checkbox
|
|
326
327
|
checked={selection.isAllSelected || selection.isIndeterminate}
|
|
327
|
-
|
|
328
|
+
onChange={() => selection.toggleAll()}
|
|
329
|
+
label="Select All"
|
|
328
330
|
/>
|
|
329
|
-
<Text>Select All</Text>
|
|
330
331
|
<Text fontSize="$2" color="$gray11">
|
|
331
332
|
({selection.selectedItems.length} selected)
|
|
332
333
|
</Text>
|
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CellModalEditor — wraps tall field types (FileUpload, Signature, RichText,
|
|
3
|
-
* etc.) in a
|
|
4
|
-
* `FieldDisplay` summary; click opens
|
|
3
|
+
* etc.) in a forms FloatingPanel that opens on cell click. The cell shows a
|
|
4
|
+
* compact `FieldDisplay` summary; a click opens the full editor in a panel
|
|
5
|
+
* that attaches to the cell it was opened from (MPO-38 cover contract), the
|
|
6
|
+
* same FloatingPanel the native variant uses (a sheet there and at 640 and
|
|
7
|
+
* below). It never grows the row (LC-06).
|
|
5
8
|
*
|
|
6
|
-
* The
|
|
9
|
+
* The panel is a staging buffer (UX-023 / Axiom 7 AGENCY): the inner editor
|
|
7
10
|
* is wired to a local draft seeded from the committed value on open — nothing
|
|
8
|
-
* reaches the row while the
|
|
11
|
+
* reaches the row while the panel is open. "Done" commits the draft once via
|
|
9
12
|
* `onCommit`; an outside click also commits (LC-21: a cell editor's draft
|
|
10
13
|
* still commits on the outside-click close); "Cancel" and Escape discard the
|
|
11
14
|
* draft and leave the row untouched. Cancel is never disabled (LC-30) and the
|
|
12
|
-
* footer stays within the two-action
|
|
15
|
+
* footer stays within the two-action budget (LC-31).
|
|
13
16
|
*/
|
|
14
17
|
|
|
15
|
-
import {
|
|
16
|
-
|
|
18
|
+
import {
|
|
19
|
+
Button,
|
|
20
|
+
FieldDisplay,
|
|
21
|
+
FloatingPanel,
|
|
22
|
+
type FieldDisplayType,
|
|
23
|
+
} from "@multiplatform.one/forms";
|
|
17
24
|
import { TableCellContext } from "@multiplatform.one/table-primitives";
|
|
18
25
|
import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
19
|
-
import { useCallback, useRef, useState, type ReactNode } from "react";
|
|
20
|
-
import {
|
|
26
|
+
import { useCallback, useEffect, useRef, useState, type ReactNode } from "react";
|
|
27
|
+
import { Text, View, XStack, YStack, isWeb } from "tamagui";
|
|
21
28
|
import { t } from "../../shared/t";
|
|
22
29
|
|
|
23
30
|
export interface CellModalEditorProps {
|
|
@@ -29,12 +36,12 @@ export interface CellModalEditorProps {
|
|
|
29
36
|
/** Commits the staged draft to the row. Fires at most once per session. */
|
|
30
37
|
onCommit: (value: any) => void;
|
|
31
38
|
/**
|
|
32
|
-
* Full editor mounted inside the
|
|
39
|
+
* Full editor mounted inside the panel, wired to the staged draft: render
|
|
33
40
|
* with `draftValue` and report edits through `onDraftChange` — never
|
|
34
41
|
* straight to the row.
|
|
35
42
|
*/
|
|
36
43
|
children: (draftValue: any, onDraftChange: (value: any) => void) => ReactNode;
|
|
37
|
-
/** Title shown in the
|
|
44
|
+
/** Title shown in the panel header. */
|
|
38
45
|
title?: string;
|
|
39
46
|
/**
|
|
40
47
|
* Accessible name for the chromeless cell trigger (column header).
|
|
@@ -56,7 +63,7 @@ export function CellModalEditor({
|
|
|
56
63
|
}: CellModalEditorProps) {
|
|
57
64
|
const { knobProps } = useResolvedKnobs();
|
|
58
65
|
const [open, setOpen] = useState(false);
|
|
59
|
-
// Draft session: exists only while the
|
|
66
|
+
// Draft session: exists only while the panel is open, seeded from the
|
|
60
67
|
// committed value so the editor starts at the cell's current value
|
|
61
68
|
// (Axiom 11 VALUE IS DATA).
|
|
62
69
|
const [draft, setDraft] = useState<{ value: any } | null>(null);
|
|
@@ -67,7 +74,7 @@ export function CellModalEditor({
|
|
|
67
74
|
const onCommitRef = useRef(onCommit);
|
|
68
75
|
onCommitRef.current = onCommit;
|
|
69
76
|
// Escape / Cancel flag the close as a discard before onOpenChange(false)
|
|
70
|
-
// lands; every other close path (Done,
|
|
77
|
+
// lands; every other close path (Done, outside click) commits.
|
|
71
78
|
const discardRef = useRef(false);
|
|
72
79
|
|
|
73
80
|
const handleOpen = useCallback(() => {
|
|
@@ -97,6 +104,18 @@ export function CellModalEditor({
|
|
|
97
104
|
[handleOpen],
|
|
98
105
|
);
|
|
99
106
|
|
|
107
|
+
// FloatingPanel reports every close as onOpenChange(false). Escape is a
|
|
108
|
+
// dismissal, not a confirm, so it is flagged in the capture phase, before
|
|
109
|
+
// the panel's own Escape listener closes it.
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (!open || !isWeb || typeof document === "undefined") return;
|
|
112
|
+
const flagEscape = (event: KeyboardEvent) => {
|
|
113
|
+
if (event.key === "Escape") discardRef.current = true;
|
|
114
|
+
};
|
|
115
|
+
document.addEventListener("keydown", flagEscape, true);
|
|
116
|
+
return () => document.removeEventListener("keydown", flagEscape, true);
|
|
117
|
+
}, [open]);
|
|
118
|
+
|
|
100
119
|
const handleCancel = useCallback(() => {
|
|
101
120
|
discardRef.current = true;
|
|
102
121
|
handleOpenChange(false);
|
|
@@ -108,76 +127,77 @@ export function CellModalEditor({
|
|
|
108
127
|
}, []);
|
|
109
128
|
|
|
110
129
|
const triggerLocked = disabled || readOnly;
|
|
111
|
-
const handleTriggerKeyDown = (event: {
|
|
130
|
+
const handleTriggerKeyDown = (event: {
|
|
131
|
+
key?: string;
|
|
132
|
+
preventDefault?: () => void;
|
|
133
|
+
stopPropagation?: () => void;
|
|
134
|
+
}) => {
|
|
112
135
|
if (triggerLocked) return;
|
|
113
136
|
if (event.key === "Enter" || event.key === " ") {
|
|
114
137
|
event.preventDefault?.();
|
|
138
|
+
event.stopPropagation?.();
|
|
115
139
|
handleOpen();
|
|
116
140
|
}
|
|
117
141
|
};
|
|
118
142
|
|
|
143
|
+
const trigger = (
|
|
144
|
+
<View
|
|
145
|
+
cursor={triggerLocked ? "default" : "pointer"}
|
|
146
|
+
opacity={disabled ? 0.5 : 1}
|
|
147
|
+
flexDirection="row"
|
|
148
|
+
alignItems="center"
|
|
149
|
+
width="100%"
|
|
150
|
+
paddingHorizontal="$1"
|
|
151
|
+
paddingVertical="$1"
|
|
152
|
+
hoverStyle={!triggerLocked ? { backgroundColor: "$backgroundHover" } : undefined}
|
|
153
|
+
// LC-71: parent CellWrapper paints the one ring on the cell boundary.
|
|
154
|
+
outlineWidth={0}
|
|
155
|
+
focusVisibleStyle={{ outlineWidth: 0 }}
|
|
156
|
+
{...(isWeb && !triggerLocked
|
|
157
|
+
? {
|
|
158
|
+
role: "button" as const,
|
|
159
|
+
tabIndex: 0,
|
|
160
|
+
"aria-label": label,
|
|
161
|
+
"aria-haspopup": "dialog" as const,
|
|
162
|
+
"aria-expanded": open,
|
|
163
|
+
onKeyDown: handleTriggerKeyDown,
|
|
164
|
+
}
|
|
165
|
+
: undefined)}
|
|
166
|
+
>
|
|
167
|
+
<FieldDisplay field={field} value={value} fieldProps={fieldProps} />
|
|
168
|
+
</View>
|
|
169
|
+
);
|
|
170
|
+
|
|
119
171
|
return (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
outlineWidth={0}
|
|
133
|
-
focusVisibleStyle={{ outlineWidth: 0 }}
|
|
134
|
-
{...(isWeb && !triggerLocked
|
|
135
|
-
? {
|
|
136
|
-
role: "button" as const,
|
|
137
|
-
tabIndex: 0,
|
|
138
|
-
"aria-label": label,
|
|
139
|
-
"aria-haspopup": "dialog" as const,
|
|
140
|
-
"aria-expanded": open,
|
|
141
|
-
onKeyDown: handleTriggerKeyDown,
|
|
142
|
-
}
|
|
143
|
-
: undefined)}
|
|
172
|
+
<FloatingPanel
|
|
173
|
+
open={open}
|
|
174
|
+
onOpenChange={handleOpenChange}
|
|
175
|
+
disabled={triggerLocked}
|
|
176
|
+
trigger={trigger}
|
|
177
|
+
>
|
|
178
|
+
<YStack
|
|
179
|
+
{...knobProps.gap}
|
|
180
|
+
width={720}
|
|
181
|
+
maxWidth="90vw"
|
|
182
|
+
data-testid="cell-modal-editor-panel"
|
|
183
|
+
data-dismiss-class="compose"
|
|
144
184
|
>
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
<
|
|
149
|
-
<
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
basis-0 wrapper collapses and its children paint over the
|
|
163
|
-
footer / past the dialog frame (LC-10). The context reset
|
|
164
|
-
restores full field chrome — the modal is not a table cell,
|
|
165
|
-
but React context flows through the Dialog portal. */}
|
|
166
|
-
<YStack flexShrink={1} minHeight={0}>
|
|
167
|
-
<TableCellContext.Provider value={{ inTableCell: false }}>
|
|
168
|
-
{children(draft ? draft.value : value, handleDraftChange)}
|
|
169
|
-
</TableCellContext.Provider>
|
|
170
|
-
</YStack>
|
|
171
|
-
<XStack {...knobProps.gap} justifyContent="flex-end">
|
|
172
|
-
{/* LC-30 CANCEL-ALWAYS-LIVE: the discard exit never disables. */}
|
|
173
|
-
<Button onPress={handleCancel}>{t("Cancel")}</Button>
|
|
174
|
-
<Button theme="accent" onPress={() => handleOpenChange(false)}>
|
|
175
|
-
{t("Done")}
|
|
176
|
-
</Button>
|
|
177
|
-
</XStack>
|
|
178
|
-
</DialogContent>
|
|
179
|
-
</Dialog.Portal>
|
|
180
|
-
</Dialog>
|
|
181
|
-
</>
|
|
185
|
+
<Text {...knobProps.heading}>{title ?? t("Edit")}</Text>
|
|
186
|
+
{/* The panel is not a table cell: restore full field chrome. React
|
|
187
|
+
context flows in because the panel renders inline (no portal). */}
|
|
188
|
+
<YStack flexShrink={1} minHeight={0}>
|
|
189
|
+
<TableCellContext.Provider value={{ inTableCell: false }}>
|
|
190
|
+
{children(draft ? draft.value : value, handleDraftChange)}
|
|
191
|
+
</TableCellContext.Provider>
|
|
192
|
+
</YStack>
|
|
193
|
+
<XStack {...knobProps.gap} justifyContent="flex-end">
|
|
194
|
+
{/* LC-30 CANCEL-ALWAYS-LIVE: the discard exit never disables. */}
|
|
195
|
+
<Button onPress={handleCancel}>{t("Cancel")}</Button>
|
|
196
|
+
<Button theme="accent" onPress={() => handleOpenChange(false)}>
|
|
197
|
+
{t("Done")}
|
|
198
|
+
</Button>
|
|
199
|
+
</XStack>
|
|
200
|
+
</YStack>
|
|
201
|
+
</FloatingPanel>
|
|
182
202
|
);
|
|
183
203
|
}
|
|
@@ -153,7 +153,8 @@ function MockRadioGroup({ value, onValueChange, options }: any) {
|
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
155
|
* Functional FloatingPanel fake: trigger toggles open; children render only
|
|
156
|
-
* while open (mirrors the popover/sheet contract
|
|
156
|
+
* while open; Escape inside closes it (mirrors the popover/sheet contract
|
|
157
|
+
* CellOptionsEditor and CellModalEditor rely on).
|
|
157
158
|
*/
|
|
158
159
|
function MockFloatingPanel({ open, onOpenChange, trigger, children, disabled }: any) {
|
|
159
160
|
return (
|
|
@@ -166,7 +167,16 @@ function MockFloatingPanel({ open, onOpenChange, trigger, children, disabled }:
|
|
|
166
167
|
>
|
|
167
168
|
{trigger}
|
|
168
169
|
</div>
|
|
169
|
-
{open ?
|
|
170
|
+
{open ? (
|
|
171
|
+
<div
|
|
172
|
+
data-testid="floating-panel-content"
|
|
173
|
+
onKeyDown={(event) => {
|
|
174
|
+
if (event.key === "Escape") onOpenChange?.(false);
|
|
175
|
+
}}
|
|
176
|
+
>
|
|
177
|
+
{children}
|
|
178
|
+
</div>
|
|
179
|
+
) : null}
|
|
170
180
|
</div>
|
|
171
181
|
);
|
|
172
182
|
}
|
|
@@ -1,33 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CellModalEditor
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* (
|
|
6
|
-
* spec locks the recipe path so it cannot regress to a handwritten frame.
|
|
2
|
+
* CellModalEditor on web (MPO-221): the tall-field editor is a FloatingPanel
|
|
3
|
+
* attached to the cell it was opened from, the same primitive the native
|
|
4
|
+
* variant uses, not a centered Dialog. The panel owns the SF-OVERLAY /
|
|
5
|
+
* E-OVERLAY surface (elevatedSurface); the staging contract rides on top.
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
import React from "react";
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
10
11
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
11
12
|
import { fireEvent, screen, waitFor } from "@testing-library/react";
|
|
12
13
|
import { describe, expect, it, vi } from "vitest";
|
|
13
14
|
|
|
14
|
-
const dialogContentProps: Record<string, unknown>[] = [];
|
|
15
|
-
|
|
16
|
-
vi.mock("@multiplatform.one/components", async (importOriginal) => {
|
|
17
|
-
const actual = await importOriginal<typeof import("@multiplatform.one/components")>();
|
|
18
|
-
return {
|
|
19
|
-
...actual,
|
|
20
|
-
DialogContent: (props: Record<string, unknown>) => {
|
|
21
|
-
dialogContentProps.push(props);
|
|
22
|
-
return React.createElement(
|
|
23
|
-
"div",
|
|
24
|
-
{ "data-testid": "cell-modal-dialog-content" },
|
|
25
|
-
props.children as React.ReactNode,
|
|
26
|
-
);
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
});
|
|
30
|
-
|
|
31
15
|
vi.mock("@multiplatform.one/forms", async (importOriginal) => ({
|
|
32
16
|
...(await importOriginal<typeof import("@multiplatform.one/forms")>()),
|
|
33
17
|
FieldDisplay: (props: { field?: string }) =>
|
|
@@ -47,36 +31,78 @@ vi.mock("@multiplatform.one/forms", async (importOriginal) => ({
|
|
|
47
31
|
|
|
48
32
|
import { CellModalEditor } from "./CellModalEditor";
|
|
49
33
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
dialogContentProps.length = 0;
|
|
53
|
-
renderWithProviders(
|
|
54
|
-
<CellModalEditor
|
|
55
|
-
field="textarea"
|
|
56
|
-
value="hello"
|
|
57
|
-
onCommit={vi.fn()}
|
|
58
|
-
title="Edit text"
|
|
59
|
-
label="Notes"
|
|
60
|
-
>
|
|
61
|
-
{(draft, onDraftChange) =>
|
|
62
|
-
React.createElement("textarea", {
|
|
63
|
-
"data-testid": "draft-editor",
|
|
64
|
-
value: draft,
|
|
65
|
-
onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) =>
|
|
66
|
-
onDraftChange(event.target.value),
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
</CellModalEditor>,
|
|
70
|
-
);
|
|
34
|
+
const panel = () =>
|
|
35
|
+
document.querySelector('[data-testid="floating-panel-viewport"]') as HTMLElement | null;
|
|
71
36
|
|
|
72
|
-
|
|
73
|
-
|
|
37
|
+
function renderEditor(onCommit = vi.fn()) {
|
|
38
|
+
const utils = renderWithProviders(
|
|
39
|
+
<CellModalEditor
|
|
40
|
+
field="textarea"
|
|
41
|
+
value="hello"
|
|
42
|
+
onCommit={onCommit}
|
|
43
|
+
title="Edit text"
|
|
44
|
+
label="Notes"
|
|
45
|
+
>
|
|
46
|
+
{(draft, onDraftChange) =>
|
|
47
|
+
React.createElement("textarea", {
|
|
48
|
+
"data-testid": "draft-editor",
|
|
49
|
+
value: draft,
|
|
50
|
+
onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) =>
|
|
51
|
+
onDraftChange(event.target.value),
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
</CellModalEditor>,
|
|
55
|
+
);
|
|
56
|
+
return { ...utils, onCommit };
|
|
57
|
+
}
|
|
74
58
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
59
|
+
describe("CellModalEditor on web — FloatingPanel, not a Dialog (MPO-221)", () => {
|
|
60
|
+
it("opens the editor inside the FloatingPanel viewport", async () => {
|
|
61
|
+
renderEditor();
|
|
62
|
+
fireEvent.click(screen.getByTestId("mock-FieldDisplay"));
|
|
63
|
+
await waitFor(() => expect(panel()).not.toBeNull());
|
|
64
|
+
expect(panel()!.contains(screen.getByTestId("draft-editor"))).toBe(true);
|
|
65
|
+
expect(panel()!.textContent).toContain("Edit text");
|
|
66
|
+
expect(document.querySelector('[role="dialog"]')).toBeNull();
|
|
79
67
|
expect(screen.getByRole("button", { name: "Cancel" })).not.toBeDisabled();
|
|
80
68
|
expect(screen.getByRole("button", { name: "Done" })).toBeTruthy();
|
|
81
69
|
});
|
|
70
|
+
|
|
71
|
+
it("anchors to the cell trigger: the panel's reference wraps the cell face", async () => {
|
|
72
|
+
renderEditor();
|
|
73
|
+
const face = screen.getByTestId("mock-FieldDisplay");
|
|
74
|
+
expect(face.closest("[data-fp-reference]")).not.toBeNull();
|
|
75
|
+
fireEvent.click(face);
|
|
76
|
+
await waitFor(() => expect(panel()).not.toBeNull());
|
|
77
|
+
expect(panel()!.style.position).toBe("fixed");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("an outside click commits the draft (LC-21)", async () => {
|
|
81
|
+
const { onCommit } = renderEditor();
|
|
82
|
+
fireEvent.click(screen.getByTestId("mock-FieldDisplay"));
|
|
83
|
+
await waitFor(() => expect(panel()).not.toBeNull());
|
|
84
|
+
fireEvent.change(screen.getByTestId("draft-editor"), { target: { value: "changed" } });
|
|
85
|
+
fireEvent.click(document.body);
|
|
86
|
+
await waitFor(() => expect(panel()).toBeNull());
|
|
87
|
+
expect(onCommit).toHaveBeenCalledTimes(1);
|
|
88
|
+
expect(onCommit).toHaveBeenCalledWith("changed");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("Escape discards the draft", async () => {
|
|
92
|
+
const { onCommit } = renderEditor();
|
|
93
|
+
fireEvent.click(screen.getByTestId("mock-FieldDisplay"));
|
|
94
|
+
await waitFor(() => expect(panel()).not.toBeNull());
|
|
95
|
+
const editor = screen.getByTestId("draft-editor");
|
|
96
|
+
fireEvent.change(editor, { target: { value: "changed" } });
|
|
97
|
+
fireEvent.keyDown(editor, { key: "Escape" });
|
|
98
|
+
await waitFor(() => expect(panel()).toBeNull());
|
|
99
|
+
expect(onCommit).not.toHaveBeenCalled();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("the web source no longer mounts a Tamagui Dialog", () => {
|
|
103
|
+
const source = readFileSync(join(__dirname, "CellModalEditor.tsx"), "utf8");
|
|
104
|
+
expect(source).not.toMatch(/\bDialog\b.*from "tamagui"/);
|
|
105
|
+
expect(source).not.toMatch(/DialogContent|DialogOverlay/);
|
|
106
|
+
expect(source).toMatch(/<FloatingPanel/);
|
|
107
|
+
});
|
|
82
108
|
});
|
|
@@ -19,10 +19,11 @@ import { describe, expect, it, vi } from "vitest";
|
|
|
19
19
|
// ── Mock form components ──────────────────────────────────────
|
|
20
20
|
|
|
21
21
|
function createMock(name: string) {
|
|
22
|
-
const Comp = React.forwardRef((
|
|
22
|
+
const Comp = React.forwardRef((props: any, ref: any) =>
|
|
23
23
|
React.createElement("div", {
|
|
24
24
|
"data-testid": `mock-${name}`,
|
|
25
25
|
"data-component": name,
|
|
26
|
+
"data-currency": props.currency,
|
|
26
27
|
ref,
|
|
27
28
|
}),
|
|
28
29
|
);
|
|
@@ -187,6 +188,17 @@ describe("DataTableCell field type parity", () => {
|
|
|
187
188
|
expectNotRendered(container, "Input");
|
|
188
189
|
});
|
|
189
190
|
|
|
191
|
+
it("a currency stepper cell hands the currency to Stepper (MPO-221)", () => {
|
|
192
|
+
const { container } = renderCell({
|
|
193
|
+
field: "stepper",
|
|
194
|
+
value: 42,
|
|
195
|
+
fieldProps: { currency: "USD" },
|
|
196
|
+
});
|
|
197
|
+
expect(
|
|
198
|
+
container.querySelector('[data-component="Stepper"]')?.getAttribute("data-currency"),
|
|
199
|
+
).toBe("USD");
|
|
200
|
+
});
|
|
201
|
+
|
|
190
202
|
it("rating renders Rating, not custom star icons", () => {
|
|
191
203
|
const { container } = renderCell({
|
|
192
204
|
field: "rating",
|
|
@@ -217,10 +229,15 @@ describe("DataTableCell field type parity", () => {
|
|
|
217
229
|
expect(display?.getAttribute("data-field")).toBe(fieldType);
|
|
218
230
|
// Editor is not mounted until the cell is clicked
|
|
219
231
|
expectNotRendered(baseElement, editorName);
|
|
220
|
-
// Clicking the cell opens the
|
|
232
|
+
// Clicking the cell opens the panel containing the real editor. The
|
|
233
|
+
// panel renders inline (no portal), so the cell FACE is the trigger
|
|
234
|
+
// subtree and the editor lives in the panel content beside it.
|
|
221
235
|
fireEvent.click(display!);
|
|
222
236
|
await waitFor(() => expectRendered(baseElement, editorName));
|
|
223
|
-
|
|
237
|
+
const face = container.querySelector('[data-testid="floating-panel-trigger"]') as HTMLElement;
|
|
238
|
+
const panel = container.querySelector('[data-testid="floating-panel-content"]') as HTMLElement;
|
|
239
|
+
expectRendered(panel, editorName);
|
|
240
|
+
return { container, baseElement, face, panel };
|
|
224
241
|
}
|
|
225
242
|
|
|
226
243
|
it("fileupload renders FileUpload, not custom FileUploadCell", async () => {
|
|
@@ -234,14 +251,14 @@ describe("DataTableCell field type parity", () => {
|
|
|
234
251
|
});
|
|
235
252
|
|
|
236
253
|
it("signature renders Signature, not status text", async () => {
|
|
237
|
-
const {
|
|
254
|
+
const { face } = await expectModalEditor(
|
|
238
255
|
{ field: "signature", value: "" },
|
|
239
256
|
"signature",
|
|
240
257
|
"Signature",
|
|
241
258
|
);
|
|
242
259
|
// Old implementation showed "Not signed" / "Sign" in the cell
|
|
243
|
-
expect(
|
|
244
|
-
expect(
|
|
260
|
+
expect(face.textContent).not.toContain("Not signed");
|
|
261
|
+
expect(face.textContent).not.toContain("Sign");
|
|
245
262
|
});
|
|
246
263
|
|
|
247
264
|
it("geolocation renders Geolocation, not two plain Inputs", async () => {
|
|
@@ -271,16 +288,16 @@ describe("DataTableCell field type parity", () => {
|
|
|
271
288
|
});
|
|
272
289
|
|
|
273
290
|
it("barcode routes through the modal editor (LC-06), never inline in the cell", async () => {
|
|
274
|
-
const {
|
|
291
|
+
const { face, panel } = await expectModalEditor(
|
|
275
292
|
{ field: "barcode", value: "SKU-001234" },
|
|
276
293
|
"barcode",
|
|
277
294
|
"Barcode",
|
|
278
295
|
);
|
|
279
296
|
// The full editor (with its camera scanner surface) must not mount inline
|
|
280
|
-
// in the cell — only inside the
|
|
281
|
-
expectNotRendered(
|
|
282
|
-
// The
|
|
283
|
-
expectRendered(
|
|
297
|
+
// in the cell face — only inside the panel after click.
|
|
298
|
+
expectNotRendered(face, "Barcode");
|
|
299
|
+
// The panel also carries the large scannable preview.
|
|
300
|
+
expectRendered(panel, "BarcodePreview");
|
|
284
301
|
});
|
|
285
302
|
|
|
286
303
|
it("custom render receives the cell's honest state as the render context (D-18.4)", () => {
|
|
@@ -372,13 +389,13 @@ describe("DataTableCell field type parity", () => {
|
|
|
372
389
|
});
|
|
373
390
|
|
|
374
391
|
it("textarea routes through the modal editor (LC-06), never inline in the cell", async () => {
|
|
375
|
-
const {
|
|
392
|
+
const { face, panel } = await expectModalEditor(
|
|
376
393
|
{ field: "textarea", value: "line one\nline two" },
|
|
377
394
|
"textarea",
|
|
378
395
|
"TextArea",
|
|
379
396
|
);
|
|
380
|
-
expectNotRendered(
|
|
381
|
-
expectRendered(
|
|
397
|
+
expectNotRendered(face, "TextArea");
|
|
398
|
+
expectRendered(panel, "TextArea");
|
|
382
399
|
});
|
|
383
400
|
|
|
384
401
|
it("cell chrome carries the LC-71 composite ring class (keyboard-only, not mouse-within)", () => {
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
ColorPicker,
|
|
47
47
|
// Read-only display variants
|
|
48
48
|
FieldDisplay,
|
|
49
|
+
containsAcrossPanels,
|
|
49
50
|
} from "@multiplatform.one/forms";
|
|
50
51
|
import { CellModalEditor } from "./CellModalEditor";
|
|
51
52
|
import { CellOptionsEditor } from "./CellOptionsEditor";
|
|
@@ -380,6 +381,7 @@ export function DataTableCell({
|
|
|
380
381
|
max={max}
|
|
381
382
|
step={step ?? 1}
|
|
382
383
|
precision={precision ?? 0}
|
|
384
|
+
currency={currency}
|
|
383
385
|
disabled={disabled}
|
|
384
386
|
readOnly={readOnly}
|
|
385
387
|
placeholder={placeholder || "0"}
|
|
@@ -1167,8 +1169,7 @@ function DraftFieldEditor({
|
|
|
1167
1169
|
if (event.key === "Escape") cancelDraft();
|
|
1168
1170
|
};
|
|
1169
1171
|
const handleDocPointerDown = (event: PointerEvent) => {
|
|
1170
|
-
|
|
1171
|
-
if (node && event.target instanceof Node && node.contains(event.target)) return;
|
|
1172
|
+
if (containsAcrossPanels(containerRef.current, event.target)) return;
|
|
1172
1173
|
setSessionActive(false);
|
|
1173
1174
|
commitDraft();
|
|
1174
1175
|
};
|
|
@@ -156,12 +156,15 @@ describe("DataTableDateFilter - DatePicker integration", () => {
|
|
|
156
156
|
/**
|
|
157
157
|
* Open the picker behind `placeholder` and click a day in its calendar.
|
|
158
158
|
* A just-closed picker panel lingers mounted (with live handlers!) until
|
|
159
|
-
* its close timer fires, so first wait until
|
|
160
|
-
* the day query can safely be global (forms
|
|
159
|
+
* its close timer fires, so first wait until the filter's own panel is the
|
|
160
|
+
* only one mounted — then the day query can safely be global (forms
|
|
161
|
+
* DatePicker spec pattern). Panels portal to the page (MPO-335), so a
|
|
162
|
+
* picker panel is a sibling of the filter panel, not inside it.
|
|
161
163
|
*/
|
|
164
|
+
const panels = '[data-testid="floating-panel-viewport"]';
|
|
162
165
|
const pickDay = async (placeholder: string, day: number) => {
|
|
163
166
|
await waitFor(() => {
|
|
164
|
-
expect(document.querySelectorAll(
|
|
167
|
+
expect(document.querySelectorAll(panels).length).toBe(1);
|
|
165
168
|
});
|
|
166
169
|
fireEvent.click(screen.getByPlaceholderText(placeholder));
|
|
167
170
|
await waitFor(() => {
|