@12-apps/ui 6.64.1 → 6.66.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.
Files changed (173) hide show
  1. package/dist/_internal/components/data-display/Badge/Badge.js +2 -2
  2. package/dist/_internal/components/data-display/Chart/Chart.js +4 -4
  3. package/dist/_internal/components/data-display/Chart/SpecChart.js +5 -5
  4. package/dist/_internal/components/data-display/Chart/chart-context.js +2 -2
  5. package/dist/_internal/components/data-display/Chart/chart-renderers.js +3 -3
  6. package/dist/_internal/components/data-display/DataViews/DataViewsBoard.js +1 -1
  7. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +14 -13
  8. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +16 -15
  9. package/dist/_internal/components/data-display/DataViews/base-card.js +2 -2
  10. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +5 -5
  11. package/dist/_internal/components/data-display/DataViews/base-list-card-layout.js +6 -6
  12. package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +4 -4
  13. package/dist/_internal/components/data-display/DataViews/base-list-card.js +8 -8
  14. package/dist/_internal/components/data-display/DataViews/data-views-card-body.js +35 -0
  15. package/dist/_internal/components/data-display/DataViews/data-views-card-body.js.map +1 -0
  16. package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +4 -4
  17. package/dist/_internal/components/data-display/DataViews/data-views-display-tabs.js +3 -3
  18. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +6 -5
  19. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +12 -11
  20. package/dist/_internal/components/data-display/DataViews/data-views-layout-context.js +2 -2
  21. package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +3 -3
  22. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +6 -6
  23. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +5 -5
  24. package/dist/_internal/components/data-display/DataViews/data-views-types.js +1 -1
  25. package/dist/_internal/components/data-display/DataViews/list-card-rails.js +3 -3
  26. package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +2 -2
  27. package/dist/_internal/components/data-display/DataViews/use-saved-views-controller.js +2 -2
  28. package/dist/_internal/components/data-display/Sheet/Sheet.js +1 -1
  29. package/dist/_internal/components/data-display/index.js +8 -8
  30. package/dist/_internal/components/form/PickerSheet/PickerSheet.js +3 -3
  31. package/dist/_internal/components/form/PickerSheet/PickerSheet.parts.js +2 -2
  32. package/dist/_internal/components/form/PickerSheet/PickerSheet.styles.js +1 -1
  33. package/dist/_internal/components/index.js +16 -16
  34. package/dist/_internal/components/navigation/AppHeader/AppHeader.details.js +2 -2
  35. package/dist/_internal/components/navigation/SectionNav/SectionNav.bar.js +6 -6
  36. package/dist/_internal/components/navigation/SectionNav/SectionNav.js +9 -9
  37. package/dist/_internal/components/navigation/SectionNav/SectionNav.parts.js +3 -3
  38. package/dist/_internal/components/navigation/SectionNav/SectionNav.primary.js +4 -4
  39. package/dist/_internal/components/navigation/SectionNav/SectionNav.rail.js +5 -5
  40. package/dist/_internal/components/navigation/SectionNav/SectionNav.railCreate.js +4 -4
  41. package/dist/_internal/components/navigation/SectionNav/SectionNav.sheet.js +4 -4
  42. package/dist/_internal/components/navigation/index.js +11 -11
  43. package/dist/charts.js +5 -5
  44. package/dist/{chunk-FL2DRDTS.js → chunk-2VMIHFMX.js} +2 -2
  45. package/dist/{chunk-OR6JKOQ5.js → chunk-33XGC4YU.js} +2 -2
  46. package/dist/{chunk-BQNYX3VM.js → chunk-35L5YMYQ.js} +2 -2
  47. package/dist/{chunk-LDCHE6QS.js → chunk-3WLS7Z7D.js} +3 -3
  48. package/dist/{chunk-RNLLDK5L.js → chunk-67XUBKJC.js} +3 -3
  49. package/dist/{chunk-CZVAVX5L.js → chunk-6ATXOJVQ.js} +2 -2
  50. package/dist/{chunk-GLBK6X5Z.js → chunk-7J5JR33K.js} +2 -2
  51. package/dist/{chunk-NHHWNA5W.js → chunk-7TCOYCD7.js} +2 -2
  52. package/dist/chunk-7TCOYCD7.js.map +1 -0
  53. package/dist/{chunk-ANJAAGN3.js → chunk-AKGXNC4R.js} +2 -2
  54. package/dist/{chunk-5357QUVE.js → chunk-AMLHEKSV.js} +5 -5
  55. package/dist/{chunk-HR7YTBR7.js → chunk-BI7YMVKZ.js} +2 -2
  56. package/dist/{chunk-YOEZTW4T.js → chunk-FNFDXJWR.js} +3 -3
  57. package/dist/chunk-FNFDXJWR.js.map +1 -0
  58. package/dist/{chunk-642NSD7N.js → chunk-HG7MCNRR.js} +2 -1
  59. package/dist/{chunk-642NSD7N.js.map → chunk-HG7MCNRR.js.map} +1 -1
  60. package/dist/{chunk-OLT6ZXK5.js → chunk-IDRVQVDL.js} +2 -2
  61. package/dist/chunk-IICBAAL7.js +128 -0
  62. package/dist/chunk-IICBAAL7.js.map +1 -0
  63. package/dist/{chunk-ULBOCFST.js → chunk-J6DYHBID.js} +7 -7
  64. package/dist/{chunk-MQNL5UME.js → chunk-JXW6DZDN.js} +2 -2
  65. package/dist/{chunk-GVEWFA3Z.js → chunk-JY5YINUH.js} +21 -53
  66. package/dist/chunk-JY5YINUH.js.map +1 -0
  67. package/dist/{chunk-MO52X5WW.js → chunk-JYMXYSDP.js} +2 -2
  68. package/dist/{chunk-PEHYS7TU.js → chunk-K6KBASL2.js} +2 -2
  69. package/dist/{chunk-EMHG2ZQN.js → chunk-KDQEJAKH.js} +2 -2
  70. package/dist/{chunk-T3SZYWWN.js → chunk-L6MGAPBX.js} +2 -2
  71. package/dist/{chunk-YLBZ3SKU.js → chunk-L7OWFJUU.js} +6 -5
  72. package/dist/chunk-L7OWFJUU.js.map +1 -0
  73. package/dist/{chunk-5YDTSJNY.js → chunk-LMIOWP6H.js} +2 -2
  74. package/dist/{chunk-WYRDR4T5.js → chunk-LZJHHMOF.js} +8 -6
  75. package/dist/chunk-LZJHHMOF.js.map +1 -0
  76. package/dist/{chunk-GGG6TDET.js → chunk-M6V7Y7CP.js} +3 -3
  77. package/dist/chunk-M6V7Y7CP.js.map +1 -0
  78. package/dist/{chunk-6DO672AG.js → chunk-N5PVD4J5.js} +7 -7
  79. package/dist/{chunk-LHHAYZ55.js → chunk-O2P2KTKN.js} +1 -1
  80. package/dist/chunk-O2P2KTKN.js.map +1 -0
  81. package/dist/{chunk-GWL5FYPN.js → chunk-OZGKIHAA.js} +2 -2
  82. package/dist/{chunk-NMGNKIXF.js → chunk-QQWW6T4Q.js} +2 -2
  83. package/dist/{chunk-R52N5UCS.js → chunk-SB2SEGR6.js} +2 -2
  84. package/dist/{chunk-OT5JBIBT.js → chunk-SUZLGB5I.js} +3 -3
  85. package/dist/chunk-SZSS5KKX.js +51 -0
  86. package/dist/chunk-SZSS5KKX.js.map +1 -0
  87. package/dist/{chunk-JG733RMP.js → chunk-TZC6KIK2.js} +5 -5
  88. package/dist/{chunk-B7PKBFA4.js → chunk-UZ2CEJOO.js} +2 -2
  89. package/dist/{chunk-E2VVEXEX.js → chunk-VJB63DUM.js} +2 -2
  90. package/dist/{chunk-CJ7KAM3S.js → chunk-XBTSKYYY.js} +4 -4
  91. package/dist/{chunk-IZBQL4HZ.js → chunk-ZDT4ZGP4.js} +3 -3
  92. package/dist/data-display/Badge.js +2 -2
  93. package/dist/data-display/CardKit.js +3 -3
  94. package/dist/data-display/Chart.js +5 -5
  95. package/dist/data-display/DataViews.js +22 -21
  96. package/dist/data-display/Sheet.js +1 -1
  97. package/dist/form/PickerSheet.js +3 -3
  98. package/dist/navigation/AppHeader.js +2 -2
  99. package/dist/navigation/SectionNav.js +9 -9
  100. package/dist/types/components/data-display/DataViews/DataViewsBoard.d.ts +2 -1
  101. package/dist/types/components/data-display/DataViews/DataViewsBoard.d.ts.map +1 -1
  102. package/dist/types/components/data-display/DataViews/DataViewsGrid.d.ts +10 -0
  103. package/dist/types/components/data-display/DataViews/DataViewsGrid.d.ts.map +1 -1
  104. package/dist/types/components/data-display/DataViews/DataViewsTableBase.d.ts +7 -0
  105. package/dist/types/components/data-display/DataViews/DataViewsTableBase.d.ts.map +1 -1
  106. package/dist/types/components/data-display/DataViews/data-views-card-body.d.ts +26 -0
  107. package/dist/types/components/data-display/DataViews/data-views-card-body.d.ts.map +1 -0
  108. package/dist/types/components/data-display/DataViews/data-views-grid-bodies.d.ts +2 -0
  109. package/dist/types/components/data-display/DataViews/data-views-grid-bodies.d.ts.map +1 -1
  110. package/dist/types/components/data-display/DataViews/data-views-grid-parts.d.ts +2 -0
  111. package/dist/types/components/data-display/DataViews/data-views-grid-parts.d.ts.map +1 -1
  112. package/dist/types/components/data-display/DataViews/data-views-types.d.ts +2 -1
  113. package/dist/types/components/data-display/DataViews/data-views-types.d.ts.map +1 -1
  114. package/dist/types/components/data-display/Sheet/Sheet.d.ts.map +1 -1
  115. package/dist/types/components/data-display/Sheet/Sheet.types.d.ts +2 -0
  116. package/dist/types/components/data-display/Sheet/Sheet.types.d.ts.map +1 -1
  117. package/dist/types/components/form/PickerSheet/PickerSheet.d.ts.map +1 -1
  118. package/dist/types/components/form/PickerSheet/PickerSheet.styles.d.ts.map +1 -1
  119. package/dist/types/components/form/PickerSheet/PickerSheet.types.d.ts +2 -0
  120. package/dist/types/components/form/PickerSheet/PickerSheet.types.d.ts.map +1 -1
  121. package/package.json +1 -1
  122. package/src/components/data-display/DataViews/DataViewsBoard.tsx +4 -3
  123. package/src/components/data-display/DataViews/DataViewsGrid.tsx +10 -0
  124. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +7 -0
  125. package/src/components/data-display/DataViews/RESPONSIVE-BEHAVIOUR.md +27 -1
  126. package/src/components/data-display/DataViews/data-views-card-body.tsx +73 -0
  127. package/src/components/data-display/DataViews/data-views-grid-bodies.tsx +29 -77
  128. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +3 -1
  129. package/src/components/data-display/DataViews/data-views-types.ts +2 -1
  130. package/src/components/data-display/Sheet/Sheet.md +1 -0
  131. package/src/components/data-display/Sheet/Sheet.tsx +1 -0
  132. package/src/components/data-display/Sheet/Sheet.types.ts +2 -0
  133. package/src/components/form/PickerSheet/PickerSheet.md +1 -0
  134. package/src/components/form/PickerSheet/PickerSheet.styles.ts +12 -5
  135. package/src/components/form/PickerSheet/PickerSheet.tsx +22 -4
  136. package/src/components/form/PickerSheet/PickerSheet.types.ts +2 -0
  137. package/dist/chunk-GGG6TDET.js.map +0 -1
  138. package/dist/chunk-GVEWFA3Z.js.map +0 -1
  139. package/dist/chunk-LHHAYZ55.js.map +0 -1
  140. package/dist/chunk-NHHWNA5W.js.map +0 -1
  141. package/dist/chunk-TX3B7OAA.js +0 -108
  142. package/dist/chunk-TX3B7OAA.js.map +0 -1
  143. package/dist/chunk-WYRDR4T5.js.map +0 -1
  144. package/dist/chunk-YLBZ3SKU.js.map +0 -1
  145. package/dist/chunk-YOEZTW4T.js.map +0 -1
  146. /package/dist/{chunk-FL2DRDTS.js.map → chunk-2VMIHFMX.js.map} +0 -0
  147. /package/dist/{chunk-OR6JKOQ5.js.map → chunk-33XGC4YU.js.map} +0 -0
  148. /package/dist/{chunk-BQNYX3VM.js.map → chunk-35L5YMYQ.js.map} +0 -0
  149. /package/dist/{chunk-LDCHE6QS.js.map → chunk-3WLS7Z7D.js.map} +0 -0
  150. /package/dist/{chunk-RNLLDK5L.js.map → chunk-67XUBKJC.js.map} +0 -0
  151. /package/dist/{chunk-CZVAVX5L.js.map → chunk-6ATXOJVQ.js.map} +0 -0
  152. /package/dist/{chunk-GLBK6X5Z.js.map → chunk-7J5JR33K.js.map} +0 -0
  153. /package/dist/{chunk-ANJAAGN3.js.map → chunk-AKGXNC4R.js.map} +0 -0
  154. /package/dist/{chunk-5357QUVE.js.map → chunk-AMLHEKSV.js.map} +0 -0
  155. /package/dist/{chunk-HR7YTBR7.js.map → chunk-BI7YMVKZ.js.map} +0 -0
  156. /package/dist/{chunk-OLT6ZXK5.js.map → chunk-IDRVQVDL.js.map} +0 -0
  157. /package/dist/{chunk-ULBOCFST.js.map → chunk-J6DYHBID.js.map} +0 -0
  158. /package/dist/{chunk-MQNL5UME.js.map → chunk-JXW6DZDN.js.map} +0 -0
  159. /package/dist/{chunk-MO52X5WW.js.map → chunk-JYMXYSDP.js.map} +0 -0
  160. /package/dist/{chunk-PEHYS7TU.js.map → chunk-K6KBASL2.js.map} +0 -0
  161. /package/dist/{chunk-EMHG2ZQN.js.map → chunk-KDQEJAKH.js.map} +0 -0
  162. /package/dist/{chunk-T3SZYWWN.js.map → chunk-L6MGAPBX.js.map} +0 -0
  163. /package/dist/{chunk-5YDTSJNY.js.map → chunk-LMIOWP6H.js.map} +0 -0
  164. /package/dist/{chunk-6DO672AG.js.map → chunk-N5PVD4J5.js.map} +0 -0
  165. /package/dist/{chunk-GWL5FYPN.js.map → chunk-OZGKIHAA.js.map} +0 -0
  166. /package/dist/{chunk-NMGNKIXF.js.map → chunk-QQWW6T4Q.js.map} +0 -0
  167. /package/dist/{chunk-R52N5UCS.js.map → chunk-SB2SEGR6.js.map} +0 -0
  168. /package/dist/{chunk-OT5JBIBT.js.map → chunk-SUZLGB5I.js.map} +0 -0
  169. /package/dist/{chunk-JG733RMP.js.map → chunk-TZC6KIK2.js.map} +0 -0
  170. /package/dist/{chunk-B7PKBFA4.js.map → chunk-UZ2CEJOO.js.map} +0 -0
  171. /package/dist/{chunk-E2VVEXEX.js.map → chunk-VJB63DUM.js.map} +0 -0
  172. /package/dist/{chunk-CJ7KAM3S.js.map → chunk-XBTSKYYY.js.map} +0 -0
  173. /package/dist/{chunk-IZBQL4HZ.js.map → chunk-ZDT4ZGP4.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/DataViews/DataViewsBoard.tsx"],"sourcesContent":["\"use client\";\n\nimport { useTheme, type Theme } from \"@mui/material/styles/index.js\";\n\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\nimport { Box } from \"../../../mui/Box\";\nimport { Text } from \"../../typography/Text\";\n\nimport type { DataViewCardSelection } from \"./data-views-types\";\nimport { rem } from \"../../../tokens/relative\";\n\n/**\n * One column of the board — a single value of the grouping field, with the label\n * to print above it.\n *\n * `tone` is an opaque palette hint (e.g. `\"success\"`, `\"error\"`) the host picks\n * from its own state machine; the board only uses it to colour the column's\n * header accent, so an unknown tone degrades to the default rather than throwing.\n */\nexport interface BoardGroup {\n value: string;\n label: string;\n tone?: string;\n}\n\n/**\n * The BOARD layout's configuration: the same page the table rendered, laid out\n * as columns of the entity's own card.\n *\n * The board earns its place when a page's buckets are STATES IN A STATE MACHINE\n * rather than arbitrary groupings — payments are exactly that shape. Derive\n * `groups` and the table's `scopes` from ONE state-machine definition: two\n * hand-maintained lists of the same states will drift, and the drift shows up as\n * a column the tabs do not have.\n */\nexport interface BoardConfig<T extends Record<string, unknown>> {\n /** The row field whose value places a card in a column. */\n groupBy: keyof T & string;\n /** The columns, in DELIBERATE reading order — the board renders this order. */\n groups: BoardGroup[];\n /** Optional numeric row field summed per column (e.g. the amount in cents). */\n sumBy?: keyof T & string;\n /**\n * Formats a column's total. The PAGE's own formatter, so the board prints\n * money in the store's currency instead of inventing a second convention.\n * Omitted ⇒ the raw sum.\n */\n formatSum?: (total: number) => string;\n /** Header for the column collecting rows in states the front end does not declare. */\n extraLabel?: string;\n}\n\n/** The default header for the catch-all column (see {@link groupRows}). */\nconst DEFAULT_EXTRA_LABEL = \"Sem etapa\";\n\n/** One resolved column: a declared group (or the catch-all) plus its loaded rows. */\ninterface ResolvedColumn<T> {\n key: string;\n label: string;\n tone?: string;\n rows: T[];\n}\n\n/** Read the grouping value off a row as a string (`null`/`undefined` ⇒ \"\"). */\nfunction groupValueOf<T extends Record<string, unknown>>(row: T, groupBy: string): string {\n const value = row[groupBy];\n return value === null || value === undefined ? \"\" : String(value);\n}\n\n/**\n * Place every loaded row into a column, in the DECLARED order, and collect the\n * leftovers into one extra column at the end.\n *\n * Nothing is ever dropped, and that is the point: a state added to the back end\n * before the front end knows about it must not make rows disappear. On a\n * payments board, a silently dropped row is money nobody can see. The extra\n * column only exists when something landed in it — once every row is placed it\n * is gone, so the common case shows exactly the declared columns.\n *\n * A declared group with no rows KEEPS its position: the order is a reading\n * order chosen by the host, not a ranking derived from the data.\n */\nexport function groupRows<T extends Record<string, unknown>>(\n rows: T[],\n board: BoardConfig<T>,\n): ResolvedColumn<T>[] {\n const declared = new Map<string, T[]>(board.groups.map((group) => [group.value, []]));\n const extra: T[] = [];\n for (const row of rows) {\n const bucket = declared.get(groupValueOf(row, board.groupBy));\n if (bucket) bucket.push(row);\n else extra.push(row);\n }\n const columns: ResolvedColumn<T>[] = board.groups.map((group) => ({\n key: group.value,\n label: group.label,\n tone: group.tone,\n rows: declared.get(group.value) ?? [],\n }));\n if (extra.length > 0) {\n columns.push({ key: \"__extra__\", label: board.extraLabel ?? DEFAULT_EXTRA_LABEL, rows: extra });\n }\n return columns;\n}\n\n/** A column's total over the rows ON THIS PAGE, or null when nothing is summed. */\nfunction sumOf<T extends Record<string, unknown>>(rows: T[], sumBy: string | undefined): number | null {\n if (!sumBy) return null;\n return rows.reduce((total, row) => {\n const value = row[sumBy];\n return typeof value === \"number\" && Number.isFinite(value) ? total + value : total;\n }, 0);\n}\n\n/** Map a `tone` hint onto a theme colour, defaulting for anything unrecognised. */\nfunction toneColor(tone: string | undefined): string {\n const known = [\"primary\", \"secondary\", \"success\", \"warning\", \"error\", \"info\"];\n return tone && known.includes(tone) ? `${tone}.main` : \"divider\";\n}\n\n/**\n * A column's heading: the label, the page count and the optional sum.\n *\n * The count is labelled \"nesta página\" EVERYWHERE it appears, including in its\n * accessible name. The scope tabs above the board show whole-query totals from\n * the server; an unlabelled column count would contradict them the moment there\n * is a second page, and the reader has no way to tell which number to believe.\n */\nfunction BoardColumnHeader({\n label,\n count,\n sum,\n testId,\n}: {\n label: string;\n count: number;\n /** The formatted total, or null when the board sums nothing. */\n sum: string | null;\n testId: string;\n}): React.JSX.Element {\n const copy = useDataViewsCopy();\n return (\n <Box sx={{ display: \"flex\", flexDirection: \"column\", gap: 0.25 }}>\n <Box sx={{ display: \"flex\", alignItems: \"baseline\", justifyContent: \"space-between\", gap: 1 }}>\n <Text variant=\"caption\" as=\"span\">\n <Box component=\"span\" sx={{ fontWeight: 600 }}>\n {label}\n </Box>\n </Text>\n <Text variant=\"caption\" as=\"span\">\n <Box\n component=\"span\"\n data-testid={`${testId}-count`}\n aria-label={copy.board.countOnPage(label, count)}\n sx={{ color: \"text.secondary\", whiteSpace: \"nowrap\" }}\n >\n {copy.board.onThisPage(count)}\n </Box>\n </Text>\n </Box>\n {sum !== null && (\n <Text variant=\"caption\" as=\"span\">\n <Box\n component=\"span\"\n data-testid={`${testId}-sum`}\n aria-label={copy.board.pageSum(sum)}\n sx={{ color: \"text.secondary\" }}\n >\n {sum}\n </Box>\n </Text>\n )}\n </Box>\n );\n}\n\ninterface BoardColumnProps<T extends Record<string, unknown>> {\n column: ResolvedColumn<T>;\n board: BoardConfig<T>;\n getRowId: (row: T) => string | number;\n renderCard: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n selectedIds: Set<string | number>;\n onToggleId: (id: string | number) => void;\n cardScale: number;\n /** The column's width as CSS, already through the type scale. */\n width: string;\n testId: string;\n}\n\n/** One column: its header over a vertical stack of the entity's own cards. */\nfunction BoardColumn<T extends Record<string, unknown>>({\n column,\n board,\n getRowId,\n renderCard,\n selectedIds,\n onToggleId,\n cardScale,\n width,\n testId,\n}: BoardColumnProps<T>): React.JSX.Element {\n const copy = useDataViewsCopy();\n const total = sumOf(column.rows, board.sumBy);\n return (\n <Box\n data-testid={testId}\n sx={{\n flex: `0 0 ${width}`,\n minWidth: width,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 1,\n borderTop: (theme: Theme) => `${rem(theme, 3)} solid`,\n borderStyle: \"solid\",\n borderColor: toneColor(column.tone),\n borderRadius: 1,\n bgcolor: \"action.hover\",\n p: 1,\n }}\n >\n <BoardColumnHeader\n label={column.label}\n count={column.rows.length}\n sum={total === null ? null : String(board.formatSum ? board.formatSum(total) : total)}\n testId={testId}\n />\n {column.rows.length === 0 ? (\n <Text variant=\"caption\" as=\"p\">\n <Box component=\"span\" data-testid={`${testId}-empty`} sx={{ color: \"text.disabled\" }}>\n {copy.board.emptyColumn}\n </Box>\n </Text>\n ) : (\n column.rows.map((row) => {\n const id = getRowId(row);\n return (\n <Box key={id}>\n {renderCard(row, {\n selected: selectedIds.has(id),\n onToggleSelect: () => onToggleId(id),\n scale: cardScale,\n })}\n </Box>\n );\n })\n )}\n </Box>\n );\n}\n\ninterface DataViewsBoardProps<T extends Record<string, unknown>> {\n /** The LOADED page, verbatim. The board never filters, sorts or paginates. */\n rows: T[];\n board: BoardConfig<T>;\n getRowId: (row: T) => string | number;\n renderCard: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n selectedIds: Set<string | number>;\n onToggleId: (id: string | number) => void;\n /** Card size multiplier from the toolbar zoom slider — the same knob as cards. */\n cardScale: number;\n dataTestId?: string;\n}\n\n/**\n * The board's column width: 240 design px at scale 1, which the zoom slider\n * multiplies, and never narrower than 220 however far the zoom is wound down\n * (touch targets) — through the type scale.\n */\nconst columnWidth = (theme: Theme, cardScale: number): string =>\n rem(theme, Math.max(220, Math.round(240 * cardScale)));\n\n/**\n * The BOARD layout: the loaded page distributed into columns of the entity's own\n * card. A rendering, not a second source of truth — switching to it emits no\n * query, and it shows exactly the rows the table showed.\n *\n * The board scrolls HORIZONTALLY inside its own box rather than letting the page\n * scroll sideways, and its columns keep a usable width at every zoom, so a phone\n * gets a real board instead of six unreadable slivers.\n *\n * Cards are not draggable between columns. Dragging a payment from Recusado to\n * Pago is a domain transition with side effects, not a re-render: it needs the\n * allowed-transition set from the state machine plus a confirmation, and\n * `RowAction.isVisible` is the existing per-row guard to reuse when that lands.\n */\nexport function DataViewsBoard<T extends Record<string, unknown>>({\n rows,\n board,\n getRowId,\n renderCard,\n selectedIds,\n onToggleId,\n cardScale,\n dataTestId,\n}: DataViewsBoardProps<T>): React.JSX.Element {\n const copy = useDataViewsCopy();\n const theme = useTheme();\n const columns = groupRows(rows, board);\n const width = columnWidth(theme, cardScale);\n const testId = dataTestId ? `${dataTestId}-board` : \"data-views-board\";\n return (\n <Box sx={{ mt: 1.5 }}>\n <Text variant=\"caption\" as=\"p\">\n <Box component=\"span\" data-testid={`${testId}-scale-note`} sx={{ color: \"text.secondary\" }}>\n {copy.board.pageScopeNote}\n </Box>\n </Text>\n <Box\n data-testid={testId}\n sx={{\n mt: 1,\n display: \"flex\",\n alignItems: \"flex-start\",\n gap: 1.5,\n // The BOARD scrolls, not the page: without `maxWidth` the flex row\n // widens its parent and the whole document scrolls sideways.\n maxWidth: \"100%\",\n overflowX: \"auto\",\n pb: 1,\n }}\n >\n {columns.map((column) => (\n <BoardColumn\n key={column.key}\n column={column}\n board={board}\n getRowId={getRowId}\n renderCard={renderCard}\n selectedIds={selectedIds}\n onToggleId={onToggleId}\n cardScale={cardScale}\n width={width}\n testId={`${testId}-column-${column.key}`}\n />\n ))}\n </Box>\n </Box>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAEA,SAAS,gBAA4B;AA6I/B,SAEI,KAFJ;AA1FN,IAAM,sBAAsB;AAW5B,SAAS,aAAgD,KAAQ,SAAyB;AACxF,QAAM,QAAQ,IAAI,OAAO;AACzB,SAAO,UAAU,QAAQ,UAAU,SAAY,KAAK,OAAO,KAAK;AAClE;AAeO,SAAS,UACd,MACA,OACqB;AACrB,QAAM,WAAW,IAAI,IAAiB,MAAM,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;AACpF,QAAM,QAAa,CAAC;AACpB,aAAW,OAAO,MAAM;AACtB,UAAM,SAAS,SAAS,IAAI,aAAa,KAAK,MAAM,OAAO,CAAC;AAC5D,QAAI,OAAQ,QAAO,KAAK,GAAG;AAAA,QACtB,OAAM,KAAK,GAAG;AAAA,EACrB;AACA,QAAM,UAA+B,MAAM,OAAO,IAAI,CAAC,WAAW;AAAA,IAChE,KAAK,MAAM;AAAA,IACX,OAAO,MAAM;AAAA,IACb,MAAM,MAAM;AAAA,IACZ,MAAM,SAAS,IAAI,MAAM,KAAK,KAAK,CAAC;AAAA,EACtC,EAAE;AACF,MAAI,MAAM,SAAS,GAAG;AACpB,YAAQ,KAAK,EAAE,KAAK,aAAa,OAAO,MAAM,cAAc,qBAAqB,MAAM,MAAM,CAAC;AAAA,EAChG;AACA,SAAO;AACT;AAGA,SAAS,MAAyC,MAAW,OAA0C;AACrG,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,KAAK,OAAO,CAAC,OAAO,QAAQ;AACjC,UAAM,QAAQ,IAAI,KAAK;AACvB,WAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ,QAAQ;AAAA,EAC/E,GAAG,CAAC;AACN;AAGA,SAAS,UAAU,MAAkC;AACnD,QAAM,QAAQ,CAAC,WAAW,aAAa,WAAW,WAAW,SAAS,MAAM;AAC5E,SAAO,QAAQ,MAAM,SAAS,IAAI,IAAI,GAAG,IAAI,UAAU;AACzD;AAUA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMsB;AACpB,QAAM,OAAO,iBAAiB;AAC9B,SACE,qBAACA,UAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,KAAK,GAC7D;AAAA,yBAACA,UAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,YAAY,gBAAgB,iBAAiB,KAAK,EAAE,GAC1F;AAAA,0BAAC,QAAK,SAAQ,WAAU,IAAG,QACzB,8BAACA,UAAA,EAAI,WAAU,QAAO,IAAI,EAAE,YAAY,IAAI,GACzC,iBACH,GACF;AAAA,MACA,oBAAC,QAAK,SAAQ,WAAU,IAAG,QACzB;AAAA,QAACA;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,eAAa,GAAG,MAAM;AAAA,UACtB,cAAY,KAAK,MAAM,YAAY,OAAO,KAAK;AAAA,UAC/C,IAAI,EAAE,OAAO,kBAAkB,YAAY,SAAS;AAAA,UAEnD,eAAK,MAAM,WAAW,KAAK;AAAA;AAAA,MAC9B,GACF;AAAA,OACF;AAAA,IACC,QAAQ,QACP,oBAAC,QAAK,SAAQ,WAAU,IAAG,QACzB;AAAA,MAACA;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,eAAa,GAAG,MAAM;AAAA,QACtB,cAAY,KAAK,MAAM,QAAQ,GAAG;AAAA,QAClC,IAAI,EAAE,OAAO,iBAAiB;AAAA,QAE7B;AAAA;AAAA,IACH,GACF;AAAA,KAEJ;AAEJ;AAgBA,SAAS,YAA+C;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2C;AACzC,QAAM,OAAO,iBAAiB;AAC9B,QAAM,QAAQ,MAAM,OAAO,MAAM,MAAM,KAAK;AAC5C,SACE;AAAA,IAACA;AAAA,IAAA;AAAA,MACC,eAAa;AAAA,MACb,IAAI;AAAA,QACF,MAAM,OAAO,KAAK;AAAA,QAClB,UAAU;AAAA,QACV,SAAS;AAAA,QACT,eAAe;AAAA,QACf,KAAK;AAAA,QACL,WAAW,CAAC,UAAiB,GAAG,IAAI,OAAO,CAAC,CAAC;AAAA,QAC7C,aAAa;AAAA,QACb,aAAa,UAAU,OAAO,IAAI;AAAA,QAClC,cAAc;AAAA,QACd,SAAS;AAAA,QACT,GAAG;AAAA,MACL;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,OAAO;AAAA,YACd,OAAO,OAAO,KAAK;AAAA,YACnB,KAAK,UAAU,OAAO,OAAO,OAAO,MAAM,YAAY,MAAM,UAAU,KAAK,IAAI,KAAK;AAAA,YACpF;AAAA;AAAA,QACF;AAAA,QACC,OAAO,KAAK,WAAW,IACtB,oBAAC,QAAK,SAAQ,WAAU,IAAG,KACzB,8BAACA,UAAA,EAAI,WAAU,QAAO,eAAa,GAAG,MAAM,UAAU,IAAI,EAAE,OAAO,gBAAgB,GAChF,eAAK,MAAM,aACd,GACF,IAEA,OAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,gBAAM,KAAK,SAAS,GAAG;AACvB,iBACE,oBAACA,UAAA,EACE,qBAAW,KAAK;AAAA,YACf,UAAU,YAAY,IAAI,EAAE;AAAA,YAC5B,gBAAgB,MAAM,WAAW,EAAE;AAAA,YACnC,OAAO;AAAA,UACT,CAAC,KALO,EAMV;AAAA,QAEJ,CAAC;AAAA;AAAA;AAAA,EAEL;AAEJ;AAoBA,IAAM,cAAc,CAAC,OAAc,cACjC,IAAI,OAAO,KAAK,IAAI,KAAK,KAAK,MAAM,MAAM,SAAS,CAAC,CAAC;AAgBhD,SAAS,eAAkD;AAAA,EAChE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA8C;AAC5C,QAAM,OAAO,iBAAiB;AAC9B,QAAM,QAAQ,SAAS;AACvB,QAAM,UAAU,UAAU,MAAM,KAAK;AACrC,QAAM,QAAQ,YAAY,OAAO,SAAS;AAC1C,QAAM,SAAS,aAAa,GAAG,UAAU,WAAW;AACpD,SACE,qBAACA,UAAA,EAAI,IAAI,EAAE,IAAI,IAAI,GACjB;AAAA,wBAAC,QAAK,SAAQ,WAAU,IAAG,KACzB,8BAACA,UAAA,EAAI,WAAU,QAAO,eAAa,GAAG,MAAM,eAAe,IAAI,EAAE,OAAO,iBAAiB,GACtF,eAAK,MAAM,eACd,GACF;AAAA,IACA;AAAA,MAACA;AAAA,MAAA;AAAA,QACC,eAAa;AAAA,QACb,IAAI;AAAA,UACF,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,KAAK;AAAA;AAAA;AAAA,UAGL,UAAU;AAAA,UACV,WAAW;AAAA,UACX,IAAI;AAAA,QACN;AAAA,QAEC,kBAAQ,IAAI,CAAC,WACZ;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,QAAQ,GAAG,MAAM,WAAW,OAAO,GAAG;AAAA;AAAA,UATjC,OAAO;AAAA,QAUd,CACD;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;","names":["default"]}
@@ -1,108 +0,0 @@
1
- import {
2
- PickerSheetHead,
3
- PickerSheetList,
4
- PickerSheetSearch
5
- } from "./chunk-OLT6ZXK5.js";
6
- import {
7
- usePickerSheet
8
- } from "./chunk-WSMUOFWF.js";
9
- import {
10
- bodySx,
11
- dialogPaperSx,
12
- footSx,
13
- sheetPaperSx
14
- } from "./chunk-WYRDR4T5.js";
15
- import {
16
- METRICS
17
- } from "./chunk-VPGDYI63.js";
18
- import {
19
- stackedOverlayZIndex
20
- } from "./chunk-MFU4Y25U.js";
21
-
22
- // src/components/form/PickerSheet/PickerSheet.tsx
23
- import { useId } from "react";
24
- import Box from "@mui/material/Box/index.js";
25
- import Dialog from "@mui/material/Dialog/index.js";
26
- import Drawer from "@mui/material/Drawer/index.js";
27
- import { useTheme } from "@mui/material/styles/index.js";
28
- import useMediaQuery from "@mui/material/useMediaQuery/index.js";
29
- import { jsx, jsxs } from "react/jsx-runtime";
30
- var ABOVE_SHEETS = { zIndex: stackedOverlayZIndex };
31
- function PickerSheetSurface({ open, sheet, onClose, titleId, dataTestId, children }) {
32
- const close = () => onClose();
33
- if (sheet) {
34
- const paper2 = {
35
- sx: sheetPaperSx,
36
- role: "dialog",
37
- "aria-modal": true,
38
- "aria-labelledby": titleId,
39
- "data-testid": dataTestId
40
- };
41
- return /* @__PURE__ */ jsx(Drawer, { anchor: "bottom", open, onClose: close, sx: ABOVE_SHEETS, slotProps: { paper: paper2 }, children });
42
- }
43
- const paper = { sx: dialogPaperSx, "data-testid": dataTestId };
44
- return /* @__PURE__ */ jsx(Dialog, { open, onClose: close, "aria-labelledby": titleId, sx: ABOVE_SHEETS, slotProps: { paper }, children });
45
- }
46
- function PickerSheet(props) {
47
- const { open, onClose, kicker, title, searchPlaceholder, searchLabel, closeLabel, createLabel, createMeta, emptyText, foot } = props;
48
- const dataTestId = props.dataTestId ?? "picker-sheet";
49
- const theme = useTheme();
50
- const sheet = useMediaQuery(theme.breakpoints.down(METRICS.sheetBreakpoint));
51
- const baseId = useId();
52
- const titleId = `${baseId}-title`;
53
- const listId = `${baseId}-list`;
54
- const rowId = (index) => `${baseId}-row-${index}`;
55
- const state = usePickerSheet(props);
56
- return /* @__PURE__ */ jsxs(PickerSheetSurface, { open, sheet, onClose, titleId, dataTestId, children: [
57
- /* @__PURE__ */ jsx(
58
- PickerSheetHead,
59
- {
60
- kicker,
61
- title,
62
- titleId,
63
- closeLabel,
64
- onClose,
65
- dataTestId
66
- }
67
- ),
68
- /* @__PURE__ */ jsxs(Box, { sx: bodySx, children: [
69
- /* @__PURE__ */ jsx(
70
- PickerSheetSearch,
71
- {
72
- query: state.query,
73
- placeholder: searchPlaceholder,
74
- label: searchLabel,
75
- listId,
76
- activeId: state.activeIndex >= 0 ? rowId(state.activeIndex) : void 0,
77
- expanded: state.view.rowCount > 0,
78
- inputRef: state.searchInputRef,
79
- onQueryChange: state.setQuery,
80
- onKeyDown: state.onSearchKeyDown,
81
- dataTestId
82
- }
83
- ),
84
- /* @__PURE__ */ jsx(
85
- PickerSheetList,
86
- {
87
- view: state.view,
88
- activeIndex: state.activeIndex,
89
- cursorShown: state.cursorShown,
90
- listId,
91
- rowId,
92
- listRef: state.listRef,
93
- createLabel,
94
- createMeta,
95
- emptyText,
96
- onChoose: state.choose,
97
- dataTestId
98
- }
99
- ),
100
- foot ? /* @__PURE__ */ jsx(Box, { component: "p", sx: footSx, "data-testid": `${dataTestId}-foot`, children: foot }) : null
101
- ] })
102
- ] });
103
- }
104
-
105
- export {
106
- PickerSheet
107
- };
108
- //# sourceMappingURL=chunk-TX3B7OAA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/form/PickerSheet/PickerSheet.tsx"],"sourcesContent":["'use client';\n\nimport { useId } from 'react';\nimport Box from '@mui/material/Box/index.js';\nimport Dialog from '@mui/material/Dialog/index.js';\nimport Drawer from '@mui/material/Drawer/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport useMediaQuery from '@mui/material/useMediaQuery/index.js';\n\nimport { METRICS as CATEGORY_SELECT_METRICS } from '../CategorySelect/CategorySelect.styles';\nimport { stackedOverlayZIndex } from '../../../tokens/layers';\nimport { PickerSheetHead, PickerSheetList, PickerSheetSearch } from './PickerSheet.parts';\nimport { bodySx, dialogPaperSx, footSx, sheetPaperSx } from './PickerSheet.styles';\nimport type { PickerSheetProps } from './PickerSheet.types';\nimport { usePickerSheet } from './usePickerSheet';\n\n/**\n * Both surfaces clear the sheet ladder rather than taking MUI's default — the\n * same rule as `CategoryPanelSurface`. A `Dialog` sits at `zIndex.modal` and a\n * temporary `Drawer` a step lower, while `StackedModal` puts its second panel\n * at 1310: a picker opened from a stacked editor painted UNDER it (FUT-806).\n * See `tokens/layers`.\n */\nconst ABOVE_SHEETS = { zIndex: stackedOverlayZIndex } as const;\n\ninterface SurfaceProps {\n open: boolean;\n /** True below the sheet breakpoint — a bottom sheet instead of a centred dialog. */\n sheet: boolean;\n onClose: () => void;\n titleId: string;\n dataTestId: string;\n children: React.ReactNode;\n}\n\n/**\n * Where the sheet lives. Both surfaces are modal, which gives Esc, the\n * tap-outside dismissal and focus containment for free.\n */\nfunction PickerSheetSurface({ open, sheet, onClose, titleId, dataTestId, children }: SurfaceProps): React.JSX.Element {\n const close = (): void => onClose();\n if (sheet) {\n // A Drawer's paper carries no dialog semantics of its own, so it is given them.\n const paper = {\n sx: sheetPaperSx,\n role: 'dialog',\n 'aria-modal': true,\n 'aria-labelledby': titleId,\n 'data-testid': dataTestId,\n };\n return (\n <Drawer anchor=\"bottom\" open={open} onClose={close} sx={ABOVE_SHEETS} slotProps={{ paper }}>\n {children}\n </Drawer>\n );\n }\n const paper = { sx: dialogPaperSx, 'data-testid': dataTestId };\n return (\n <Dialog open={open} onClose={close} aria-labelledby={titleId} sx={ABOVE_SHEETS} slotProps={{ paper }}>\n {children}\n </Dialog>\n );\n}\n\n/**\n * A searchable pick-or-create sheet: a title, a search box, a list of rows\n * (optionally a tree), and a create row when the query names nothing yet.\n *\n * A centred dialog on a pointer and a bottom sheet under `CategorySelect`'s\n * sheet breakpoint. Typing filters (case-insensitive substring over each\n * item's label and `searchText`, accents aside) and flattens the tree; ↑↓ move\n * the cursor, Enter picks,\n * Esc or a tap outside closes. Picking calls `onPick` and nothing else — the\n * caller decides when to close. All copy comes from the caller.\n */\nexport function PickerSheet(props: PickerSheetProps): React.JSX.Element {\n const { open, onClose, kicker, title, searchPlaceholder, searchLabel, closeLabel, createLabel, createMeta, emptyText, foot } =\n props;\n const dataTestId = props.dataTestId ?? 'picker-sheet';\n const theme = useTheme();\n const sheet = useMediaQuery(theme.breakpoints.down(CATEGORY_SELECT_METRICS.sheetBreakpoint));\n const baseId = useId();\n const titleId = `${baseId}-title`;\n const listId = `${baseId}-list`;\n const rowId = (index: number): string => `${baseId}-row-${index}`;\n const state = usePickerSheet(props);\n\n return (\n <PickerSheetSurface open={open} sheet={sheet} onClose={onClose} titleId={titleId} dataTestId={dataTestId}>\n <PickerSheetHead\n kicker={kicker}\n title={title}\n titleId={titleId}\n closeLabel={closeLabel}\n onClose={onClose}\n dataTestId={dataTestId}\n />\n <Box sx={bodySx}>\n <PickerSheetSearch\n query={state.query}\n placeholder={searchPlaceholder}\n label={searchLabel}\n listId={listId}\n activeId={state.activeIndex >= 0 ? rowId(state.activeIndex) : undefined}\n expanded={state.view.rowCount > 0}\n inputRef={state.searchInputRef}\n onQueryChange={state.setQuery}\n onKeyDown={state.onSearchKeyDown}\n dataTestId={dataTestId}\n />\n <PickerSheetList\n view={state.view}\n activeIndex={state.activeIndex}\n cursorShown={state.cursorShown}\n listId={listId}\n rowId={rowId}\n listRef={state.listRef}\n createLabel={createLabel}\n createMeta={createMeta}\n emptyText={emptyText}\n onChoose={state.choose}\n dataTestId={dataTestId}\n />\n {foot ? (\n <Box component=\"p\" sx={footSx} data-testid={`${dataTestId}-foot`}>\n {foot}\n </Box>\n ) : null}\n </Box>\n </PickerSheetSurface>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAEA,SAAS,aAAa;AACtB,OAAO,SAAS;AAChB,OAAO,YAAY;AACnB,OAAO,YAAY;AACnB,SAAS,gBAAgB;AACzB,OAAO,mBAAmB;AA4CpB,cA8CA,YA9CA;AA5BN,IAAM,eAAe,EAAE,QAAQ,qBAAqB;AAgBpD,SAAS,mBAAmB,EAAE,MAAM,OAAO,SAAS,SAAS,YAAY,SAAS,GAAoC;AACpH,QAAM,QAAQ,MAAY,QAAQ;AAClC,MAAI,OAAO;AAET,UAAMA,SAAQ;AAAA,MACZ,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,cAAc;AAAA,MACd,mBAAmB;AAAA,MACnB,eAAe;AAAA,IACjB;AACA,WACE,oBAAC,UAAO,QAAO,UAAS,MAAY,SAAS,OAAO,IAAI,cAAc,WAAW,EAAE,OAAAA,OAAM,GACtF,UACH;AAAA,EAEJ;AACA,QAAM,QAAQ,EAAE,IAAI,eAAe,eAAe,WAAW;AAC7D,SACE,oBAAC,UAAO,MAAY,SAAS,OAAO,mBAAiB,SAAS,IAAI,cAAc,WAAW,EAAE,MAAM,GAChG,UACH;AAEJ;AAaO,SAAS,YAAY,OAA4C;AACtE,QAAM,EAAE,MAAM,SAAS,QAAQ,OAAO,mBAAmB,aAAa,YAAY,aAAa,YAAY,WAAW,KAAK,IACzH;AACF,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,QAAQ,SAAS;AACvB,QAAM,QAAQ,cAAc,MAAM,YAAY,KAAK,QAAwB,eAAe,CAAC;AAC3F,QAAM,SAAS,MAAM;AACrB,QAAM,UAAU,GAAG,MAAM;AACzB,QAAM,SAAS,GAAG,MAAM;AACxB,QAAM,QAAQ,CAAC,UAA0B,GAAG,MAAM,QAAQ,KAAK;AAC/D,QAAM,QAAQ,eAAe,KAAK;AAElC,SACE,qBAAC,sBAAmB,MAAY,OAAc,SAAkB,SAAkB,YAChF;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IACA,qBAAC,OAAI,IAAI,QACP;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,MAAM;AAAA,UACb,aAAa;AAAA,UACb,OAAO;AAAA,UACP;AAAA,UACA,UAAU,MAAM,eAAe,IAAI,MAAM,MAAM,WAAW,IAAI;AAAA,UAC9D,UAAU,MAAM,KAAK,WAAW;AAAA,UAChC,UAAU,MAAM;AAAA,UAChB,eAAe,MAAM;AAAA,UACrB,WAAW,MAAM;AAAA,UACjB;AAAA;AAAA,MACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,MAAM;AAAA,UACZ,aAAa,MAAM;AAAA,UACnB,aAAa,MAAM;AAAA,UACnB;AAAA,UACA;AAAA,UACA,SAAS,MAAM;AAAA,UACf;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU,MAAM;AAAA,UAChB;AAAA;AAAA,MACF;AAAA,MACC,OACC,oBAAC,OAAI,WAAU,KAAI,IAAI,QAAQ,eAAa,GAAG,UAAU,SACtD,gBACH,IACE;AAAA,OACN;AAAA,KACF;AAEJ;","names":["paper"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/form/PickerSheet/PickerSheet.styles.ts"],"sourcesContent":["import { alpha, type CSSObject, type Theme } from '@mui/material/styles/index.js';\n\nimport { fieldBorder, fieldHeight } from '../../../tokens/field-height';\nimport { fieldRadiusPx } from '../../../tokens/field-radius';\nimport { fieldWell, uiInk } from '../../../tokens/ink';\nimport { rem, rems } from '../../../tokens/relative';\nimport { surfaces } from '../../../tokens/surfaces';\n\n/**\n * The prototype's measurements, verbatim, in the design's px.\n *\n * Each is drawn through `rem()` where it is read, so the sheet follows a\n * density mode the way every other surface in the package does. Colours come\n * from the palette (a white-labelled tenant and dark mode carry through).\n */\nconst METRICS = {\n dialogWidthPx: 520,\n dialogMaxHeightPx: 780,\n dialogRadiusPx: 14,\n /** The gap a centred dialog keeps from the viewport edge. */\n dialogMarginPx: 32,\n sheetRadiusPx: 16,\n headGapPx: 10,\n closeButtonPx: 36,\n controlRadiusPx: 8,\n bodyPaddingPx: 16,\n bodyGapPx: 12,\n listMaxHeightPx: 380,\n listGapPx: 2,\n rowPaddingPx: 10,\n rowMinHeightPx: 44,\n /** Left padding per level of `indent` (`.pitem.ind{padding-left:28px}` at depth 1). */\n rowIndentStepPx: 28,\n checkGlyphPx: 16,\n closeGlyphPx: 18,\n searchGlyphPx: 16,\n /** The magnifier's inset from the field's inner edge, and the gap before the text. */\n searchGlyphInsetPx: 10,\n searchGlyphGapPx: 6,\n /** The prototype's body line-height; the sheet sets it rather than inheriting a host's. */\n lineHeight: 1.4,\n} as const;\n\n/** The panel's shadow: `0 16px 48px` of ink at 0.28. */\nconst panelShadow = (theme: Theme): string =>\n `${rems(theme, 0, 16, 48)} ${alpha(uiInk(theme).panelShadowInk, 0.28)}`;\n\n/** The centred dialog's paper, on a pointer. */\nexport const dialogPaperSx = (theme: Theme): CSSObject => ({\n width: rem(theme, METRICS.dialogWidthPx),\n maxWidth: `calc(100% - ${rem(theme, METRICS.dialogMarginPx)})`,\n maxHeight: `min(${rem(theme, METRICS.dialogMaxHeightPx)}, calc(100% - ${rem(theme, METRICS.dialogMarginPx * 2)}))`,\n margin: 0,\n borderRadius: rem(theme, METRICS.dialogRadiusPx),\n boxShadow: panelShadow(theme),\n // The raised step (`uiSurfaces.raised`): a sheet is nearer than the page.\n background: surfaces(theme).raised,\n backgroundImage: 'none',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n});\n\n/** The bottom sheet's paper, on a phone: full width, no grab handle. */\nexport const sheetPaperSx = (theme: Theme): CSSObject => ({\n width: '100%',\n maxHeight: '88%',\n borderRadius: rems(theme, METRICS.sheetRadiusPx, METRICS.sheetRadiusPx, 0, 0),\n boxShadow: panelShadow(theme),\n // The raised step (`uiSurfaces.raised`): a sheet is nearer than the page.\n background: surfaces(theme).raised,\n backgroundImage: 'none',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n});\n\n/** `.sh` — kicker and title on the left, the close button on the right. */\nexport const headSx = (theme: Theme): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n gap: rem(theme, METRICS.headGapPx),\n padding: rems(theme, 14, 16),\n // A shade under the controls' own border: the rule separates, it does not frame.\n borderBottom: `1px solid ${alpha(theme.palette.divider, 0.6)}`,\n flex: '0 0 auto',\n});\n\nexport const kickerSx = (theme: Theme): CSSObject => ({\n fontSize: rem(theme, 11.5),\n color: theme.palette.text.secondary,\n lineHeight: METRICS.lineHeight,\n});\n\nexport const titleSx = (theme: Theme): CSSObject => ({\n margin: 0,\n fontSize: rem(theme, 14),\n fontWeight: 700,\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.primary,\n});\n\nexport const closeButtonSx = (theme: Theme): CSSObject => ({\n flex: '0 0 auto',\n width: rem(theme, METRICS.closeButtonPx),\n height: rem(theme, METRICS.closeButtonPx),\n display: 'grid',\n placeItems: 'center',\n padding: 0,\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: rem(theme, METRICS.controlRadiusPx),\n background: 'transparent',\n color: theme.palette.text.primary,\n cursor: 'pointer',\n '& svg': { width: rem(theme, METRICS.closeGlyphPx), height: rem(theme, METRICS.closeGlyphPx) },\n '&:hover': { background: theme.palette.action.hover },\n '&:focus-visible': { outline: `${rem(theme, 2)} solid ${theme.palette.primary.main}`, outlineOffset: rem(theme, 1) },\n});\n\n/** `.sb` — the scrolling body: search, list, foot. */\nexport const bodySx = (theme: Theme): CSSObject => ({\n display: 'flex',\n flexDirection: 'column',\n gap: rem(theme, METRICS.bodyGapPx),\n padding: rem(theme, METRICS.bodyPaddingPx),\n overflow: 'auto',\n minHeight: 0,\n flex: '1 1 auto',\n});\n\n/**\n * The search field: the library's field height, border and corner, with a\n * leading magnifier. White on the light sheet, so the field reads as a field\n * against the paper behind it.\n */\nexport const searchFieldSx = (theme: Theme): CSSObject => ({\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n flex: '0 0 auto',\n '& > svg': {\n position: 'absolute',\n // + 1 for the input's own border, which the glyph sits inside of.\n left: rem(theme, METRICS.searchGlyphInsetPx + 1),\n width: rem(theme, METRICS.searchGlyphPx),\n height: rem(theme, METRICS.searchGlyphPx),\n color: theme.palette.text.secondary,\n pointerEvents: 'none',\n zIndex: 1,\n },\n '& input': {\n width: '100%',\n height: fieldHeight(theme),\n boxSizing: 'border-box',\n padding: rems(theme, 0, 10, 0, METRICS.searchGlyphInsetPx + METRICS.searchGlyphPx + METRICS.searchGlyphGapPx),\n fontSize: rem(theme, 14),\n border: fieldBorder(theme),\n borderRadius: fieldRadiusPx(theme),\n background: fieldWell(theme),\n color: theme.palette.text.primary,\n '&:focus': {\n outline: 'none',\n borderColor: theme.palette.primary.main,\n boxShadow: `0 0 0 ${rem(theme, 3)} ${alpha(theme.palette.primary.main, 0.15)}`,\n },\n },\n});\n\n/** The list: a column, scrolling on its own past 380px. */\nexport const listSx = (theme: Theme): CSSObject => ({\n display: 'flex',\n flexDirection: 'column',\n gap: rem(theme, METRICS.listGapPx),\n maxHeight: rem(theme, METRICS.listMaxHeightPx),\n overflow: 'auto',\n overscrollBehavior: 'contain',\n margin: 0,\n padding: 0,\n listStyle: 'none',\n flex: '0 1 auto',\n});\n\n/** Left padding for a row at `depth` — the row's own 10px at depth 0, 28px per level below it. */\nexport const rowPaddingLeft = (theme: Theme, depth: number): string =>\n rem(theme, depth > 0 ? METRICS.rowIndentStepPx * depth : METRICS.rowPaddingPx);\n\n/** Background of a row: selected wins over the keyboard cursor, which wins over rest. */\nfunction rowBackground(theme: Theme, selected: boolean, active: boolean): string {\n if (selected) return alpha(theme.palette.primary.main, 0.1);\n return active ? theme.palette.action.hover : 'transparent';\n}\n\n/** `.pitem` — a row. `active` is the keyboard cursor, drawn as a ring so it reads apart from `selected`. */\nexport const rowSx = (theme: Theme, selected: boolean, active: boolean): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n gap: rem(theme, 10),\n padding: rem(theme, METRICS.rowPaddingPx),\n minHeight: rem(theme, METRICS.rowMinHeightPx),\n // The list is a capped flex column: without this a row with a meta line\n // shrinks to the 44px floor and the two lines overprint.\n flexShrink: 0,\n boxSizing: 'border-box',\n borderRadius: rem(theme, METRICS.controlRadiusPx),\n textAlign: 'left',\n cursor: 'pointer',\n userSelect: 'none',\n color: theme.palette.text.primary,\n background: rowBackground(theme, selected, active),\n boxShadow: active ? `inset 0 0 0 ${rem(theme, 1)} ${alpha(theme.palette.primary.main, 0.3)}` : 'none',\n '&:hover': { background: selected ? alpha(theme.palette.primary.main, 0.1) : theme.palette.action.hover },\n});\n\nexport const rowTextSx: CSSObject = { flex: '1 1 auto', minWidth: 0 };\n\nexport const rowLabelSx = (theme: Theme): CSSObject => ({\n display: 'block',\n fontSize: rem(theme, 14),\n lineHeight: METRICS.lineHeight,\n});\n\nexport const rowMetaSx = (theme: Theme): CSSObject => ({\n display: 'block',\n fontSize: rem(theme, 12),\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.secondary,\n});\n\nexport const checkSx = (theme: Theme): CSSObject => ({\n flex: '0 0 auto',\n display: 'grid',\n color: theme.palette.primary.main,\n '& svg': { width: rem(theme, METRICS.checkGlyphPx), height: rem(theme, METRICS.checkGlyphPx) },\n});\n\n/** The create row's text: the accent, at 600. */\nexport const createLabelSx = (theme: Theme): CSSObject => ({\n ...rowLabelSx(theme),\n color: theme.palette.primary.main,\n fontWeight: 600,\n});\n\nexport const emptySx = (theme: Theme): CSSObject => ({\n fontSize: rem(theme, 12),\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.secondary,\n padding: rem(theme, 10),\n});\n\nexport const footSx = (theme: Theme): CSSObject => ({\n margin: 0,\n fontSize: rem(theme, 12),\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.secondary,\n});\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/DataViews/data-views-grid-parts.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\nimport { TableFilter } from \"../../layout/TableFilter\";\nimport { Stack } from \"../../../mui/Stack\";\n\nimport {\n DataViewsLayoutProvider,\n useDataViewsLayout,\n type DataViewsLayout,\n} from \"./data-views-layout-context\";\nimport { FilterDialog, GridFilterPanel } from \"./data-views-filter-panel\";\nimport { GridMain } from \"./data-views-grid-bodies\";\nimport type { ListGroupConfig } from \"./list-card-rails\";\nimport { InlineFilterControls } from \"./data-views-inline-bar\";\nimport { toOverflowFields, useFilterOverflow, type OverflowSplit } from \"./data-views-overflow\";\nimport { GridHeaderRow } from \"./data-views-header-row\";\nimport { allOnPageSelected, resolveSelectionExtra, type SelectionExtraRender } from \"./data-views-selection-extra\";\nimport { ShellToolbar } from \"./data-views-shell-toolbar\";\nimport type { DisplayPanelView } from \"./data-views-display-panel\";\nimport type { DataViewExport } from \"./data-views-export\";\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\nimport { DataViewsEmpty } from \"./data-views-empty\";\nimport { DataViewsPagination } from \"./data-views-pagination\";\nimport type { BoardConfig } from \"./DataViewsBoard\";\nimport { type ScopeConfig } from \"./data-views-scopes\";\nimport { ScopeTabsSlot } from \"./data-views-scope-tabs\";\nimport { togglePillValues } from \"./data-views-grid-helpers\";\nimport type {\n DataViewCardSelection,\n FilterFieldConfig,\n RangeFieldConfig,\n RangeValue,\n RowAction,\n} from \"./data-views-types\";\nimport type { DataViewRowDetail } from \"./data-views-row-detail\";\nimport type { DataViewsController } from \"./use-data-views-state\";\n\n/* ── Layout ⇄ view-state mirror ──────────────────────────────────────────── */\n\n/**\n * Mirrors the LIVE layout back into the view state, so saving a view captures\n * the layout the user is actually looking at.\n *\n * A component rather than a callback prop because only something INSIDE the\n * provider can read the layout, and only the controller can write the state.\n * The `stored !== layout` guard is what makes it idempotent: `c` is rebuilt on\n * every render, so an unguarded effect here would patch → re-render → patch.\n *\n * It re-fires when `stored` changes too, which is the case that matters after\n * applying a saved view: `appliedState` REPLACES the state, so a view saved\n * before layouts were captured clears `state.layout`, and the mirror puts the\n * current one back rather than leaving the next save with nothing to store.\n */\nfunction LayoutStateSync<T extends Record<string, unknown>>({\n c,\n}: {\n c: DataViewsController<T>;\n}): null {\n const { layout } = useDataViewsLayout();\n const stored = c.state.layout;\n useEffect(() => {\n if (stored !== layout) c.patch({ layout });\n // `c` is intentionally out of the deps — see the guard above.\n }, [layout, stored]);\n return null;\n}\n\n/* ── Shell (composes toolbar + body + panel) ─────────────────────────────── */\n\n/** The shared filter-surface props consumed by the inline bar, panel, and modal. */\ninterface FilterSurfaceProps<T extends Record<string, unknown>> {\n testIdPrefix: string;\n search: string;\n fields: FilterFieldConfig<T>[];\n rangeFields: RangeFieldConfig<T>[];\n pills: Record<string, string[]>;\n ranges: Record<string, RangeValue>;\n onSearchChange: (value: string) => void;\n onTogglePill: (fieldId: string, value: string, checked: boolean) => void;\n onChangeRange: (fieldId: string, range: RangeValue) => void;\n onClearField: (fieldId: string) => void;\n onClearAll: () => void;\n}\n\n/**\n * Derives the responsive filter state (which surface to show at this width) and\n * the filter-mutation handlers from the controller — pulled out of `GridShell`\n * so the component body stays under the size/complexity budget.\n */\n/** Grouped rather than positional: the list had grown past readability. */\ninterface GridShellFiltersArgs<T extends Record<string, unknown>> {\n c: DataViewsController<T>;\n inlineFilters: boolean;\n fields: FilterFieldConfig<T>[];\n rangeFields: RangeFieldConfig<T>[];\n testIdPrefix: string;\n alwaysShowSearch: boolean;\n /** Is \"Exportar\" on the bar? Half the right cluster's cost when it is not. */\n hasExport: boolean;\n}\n\nfunction useGridShellFilters<T extends Record<string, unknown>>({\n c,\n inlineFilters,\n fields,\n rangeFields,\n testIdPrefix,\n alwaysShowSearch,\n hasExport,\n}: GridShellFiltersArgs<T>): {\n showInline: boolean;\n useModal: boolean;\n inlineVisible: boolean;\n filterProps: FilterSurfaceProps<T>;\n split: OverflowSplit<T>;\n onControlOpenChange: (open: boolean) => void;\n} {\n const { state } = c;\n // How many filter controls are open. A COUNT, not a flag: closing one popover\n // by opening another overlaps, and a boolean would unfreeze mid-handover.\n const [openControls, setOpenControls] = useState(0);\n // ONE measurement for the whole shell: the filter row decides which controls\n // it can keep, and the TOOLBAR needs the same answer to drop its labels.\n // Measuring twice would let the two disagree at the crossover width.\n const split = useFilterOverflow(\n toOverflowFields(fields, rangeFields),\n state.pills,\n c.ranges,\n openControls > 0,\n hasExport,\n );\n // THE BAR RENDERS AT EVERY WIDTH. It used to be swapped for a full-screen\n // filter MODAL below `lg`, which was the responsive strategy before the\n // measured ladder existed — and the two now do the same job, badly together:\n // the modal took the bar away at 1199px, and with it the very degradation\n // (labels off, search collapsed, filters into \"Mais\") that exists to make a\n // narrow bar work. So a 900px window got no bar and no ladder, and the\n // operator lost the search entirely rather than gaining a compact one.\n //\n // The ladder is measured, so it already covers every width the modal did.\n const showInline = inlineFilters;\n const useModal = false;\n const inlineVisible =\n showInline &&\n (alwaysShowSearch || fields.length > 0 || rangeFields.length > 0 || state.search !== \"\");\n const filterProps: FilterSurfaceProps<T> = {\n testIdPrefix,\n search: state.search,\n fields,\n rangeFields,\n pills: state.pills,\n ranges: c.ranges,\n onSearchChange: (value) => c.patch({ search: value }),\n // Updater, never the render's `state` — see {@link DataViewStatePatch}.\n onTogglePill: (fieldId, value, checked) =>\n c.patch(({ pills }) => ({ pills: { ...pills, [fieldId]: togglePillValues(pills[fieldId], value, checked) } })),\n onChangeRange: (fieldId, range) => c.patch({ ranges: { ...c.ranges, [fieldId]: range } }),\n onClearField: (fieldId) => c.patch({ pills: { ...state.pills, [fieldId]: [] } }),\n onClearAll: () => c.patch({ search: \"\", pills: {}, ranges: {} }),\n };\n return {\n showInline,\n useModal,\n inlineVisible,\n filterProps,\n split,\n onControlOpenChange: (open) =>\n setOpenControls((count) => Math.max(0, count + (open ? 1 : -1))),\n };\n}\n\ninterface GridShellProps<T extends Record<string, unknown>> {\n c: DataViewsController<T>;\n rows: T[];\n fields: FilterFieldConfig<T>[];\n rangeFields: RangeFieldConfig<T>[];\n getRowId: (row: T) => string | number;\n testIdPrefix: string;\n dataTestId?: string;\n emptyState?: React.ReactNode;\n toolbarRightSlot?: React.ReactNode;\n rowActions?: RowAction<T>[];\n bulkActions?: (selectedRows: T[], clearSelection: () => void) => React.ReactNode;\n /** A widening control beside the selection count — see `resolveSelectionExtra`. */\n selectionExtra?: SelectionExtraRender<T>;\n /** Opt-in \"Grade\" (cards) layout: renders each row as an entity-supplied card.\n * Omit ⇒ table only (no layout toggle). */\n renderCard?: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n /**\n * Opt-in \"Quadro\" (board) layout. Needs `renderCard` too — the board reuses\n * the entity's card, so a board config without one simply offers no board\n * rather than failing: that is a config gap, not a runtime error.\n */\n board?: BoardConfig<T>;\n /** Opt-in \"Lista\" layout: one full-width, entity-rendered row per record. */\n renderListRow?: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n /** The Lista's shared columns, so its rows line up by construction. */\n listGroup?: ListGroupConfig<T>;\n /** Opt-in expandable rows, drawn by the table layout only. */\n rowDetail?: DataViewRowDetail<T>;\n /** The page-level partition rendered as tabs under the toolbar. */\n scopes?: ScopeConfig[];\n /**\n * The row field the scopes partition by. Compared against the board's\n * `groupBy` so the two are not shown as the same partition twice.\n */\n scopeFieldId?: string;\n /** Per-sort-field value kind, so directions read in the column's own terms. */\n sortKinds?: Record<string, string>;\n /** The saved-view chrome bracketing the Exibir panel. */\n displayView?: DisplayPanelView;\n /** Injected export — the host re-queries; the grid never fetches. */\n exportConfig?: DataViewExport;\n /** Page title in the grid's own header row, above the scopes + toolbar. */\n title?: string;\n /** Primary page actions rendered at the header row's right. */\n headerActions?: React.ReactNode;\n /** Which layout to show first when the user has expressed no preference (default \"table\"). */\n defaultLayout?: DataViewsLayout;\n /** Pin to `defaultLayout`, ignoring the remembered preference (stories/docs). */\n ignoreStoredLayout?: boolean;\n /**\n * Opt into the responsive inline filter UX: a collapsible filter row below the\n * toolbar on wide screens and a modal on narrow ones. When false (default),\n * keep the classic slide-in filter panel opened by the \"Filtros\" button.\n */\n inlineFilters?: boolean;\n /**\n * Keep the inline search box on screen even with no filter fields and no\n * active search. Without it a grid whose only filter IS the search (`fields`\n * empty) can never OFFER one: the row renders only once a search exists, so\n * the operator would have to hand-edit the URL to start one. Default false —\n * every grid that ships filter fields already shows the row.\n */\n alwaysShowSearch?: boolean;\n}\n\n/** The scrollable content region: scope tabs, toolbar, filter bar, body, pager. */\nfunction ShellStack<T extends Record<string, unknown>>({\n props,\n filters,\n}: {\n props: GridShellProps<T>;\n filters: ReturnType<typeof useGridShellFilters<T>>;\n}): React.JSX.Element {\n const copy = useDataViewsCopy();\n const { c, testIdPrefix, dataTestId, scopes = [], emptyState, inlineFilters = false } = props;\n const { showInline, useModal, inlineVisible, filterProps, split, onControlOpenChange } = filters;\n // The grid renders the FILTERED empty state itself — it is the only party\n // that knows a filter is applied. See {@link DataViewsEmpty}.\n const body = (\n <DataViewsEmpty\n filtered={c.activeFilterCount > 0 || c.state.search !== \"\"}\n onClearFilters={() => c.patch({ search: \"\", pills: {}, ranges: {} })}\n emptyState={emptyState}\n testIdPrefix={testIdPrefix}\n />\n );\n return (\n <TableFilter\n copy={copy.tableFilter} open={c.filterOpen} onOpenChange={c.setFilterOpen}\n hasActiveFilters={c.activeFilterCount > 0}\n >\n <Stack spacing={0} data-testid={dataTestId ? `${dataTestId}-container` : undefined}>\n <GridHeaderRow title={props.title} headerActions={props.headerActions} testIdPrefix={testIdPrefix} />\n <ShellToolbar\n c={c}\n rows={props.rows}\n sortKinds={props.sortKinds}\n displayView={props.displayView}\n exportConfig={props.exportConfig}\n filterControls={\n inlineVisible ? (\n <InlineFilterControls\n {...filterProps} split={split} activeFilterCount={c.activeFilterCount}\n onControlOpenChange={onControlOpenChange}\n />\n ) : undefined\n }\n barRef={split.barRef}\n testIdPrefix={testIdPrefix}\n rowActions={props.rowActions}\n bulkActions={props.bulkActions}\n selectionExtra={resolveSelectionExtra(props)}\n allOnPageSelected={allOnPageSelected(c, props.getRowId)}\n toolbarRightSlot={props.toolbarRightSlot}\n compactControls={showInline && split.compactControls}\n counterHidden={showInline && split.counterHidden}\n showInline={showInline}\n />\n <ScopeTabsSlot\n scopes={scopes} scopeFieldId={props.scopeFieldId} board={props.board}\n value={c.scope} onChange={c.setScope} counts={c.scopeCounts}\n testIdPrefix={testIdPrefix}\n />\n <TableFilter.Layout>\n <TableFilter.Main>\n <GridMain\n c={c}\n getRowId={props.getRowId}\n renderCard={props.renderCard}\n renderListRow={props.renderListRow}\n listGroup={props.listGroup}\n board={props.board}\n rowDetail={props.rowDetail}\n dataTestId={dataTestId}\n testIdPrefix={testIdPrefix}\n emptyState={body}\n />\n <DataViewsPagination c={c} testIdPrefix={testIdPrefix} />\n </TableFilter.Main>\n {inlineFilters ? null : <GridFilterPanel {...filterProps} />}\n </TableFilter.Layout>\n {useModal && <FilterDialog open={c.filterOpen} onClose={() => c.setFilterOpen(false)} {...filterProps} />}\n </Stack>\n </TableFilter>\n );\n}\n\nexport function GridShell<T extends Record<string, unknown>>(props: GridShellProps<T>): React.JSX.Element {\n const {\n c,\n fields,\n rangeFields,\n testIdPrefix,\n renderCard,\n renderListRow,\n board,\n defaultLayout,\n ignoreStoredLayout,\n inlineFilters = false,\n alwaysShowSearch = false,\n } = props;\n const filters = useGridShellFilters({\n c,\n inlineFilters,\n fields,\n rangeFields,\n testIdPrefix,\n alwaysShowSearch,\n hasExport: props.exportConfig !== undefined,\n });\n return (\n <DataViewsLayoutProvider\n canUseCards={Boolean(renderCard)}\n canUseList={Boolean(renderListRow)}\n // The board reuses the entity's card, so it needs BOTH — a `board` with no\n // `renderCard` offers no board rather than throwing.\n canUseBoard={Boolean(board && renderCard)}\n defaultLayout={defaultLayout}\n ignoreStoredLayout={ignoreStoredLayout}\n viewLayout={c.state.layout}\n >\n <LayoutStateSync c={c} />\n <ShellStack props={props} filters={filters} />\n </DataViewsLayoutProvider>\n );\n}\n"],"mappings":"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","names":["default"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/DataViews/DataViewsTableBase.tsx"],"sourcesContent":["\"use client\";\n\nimport type { SortFieldDefinition } from \"../../layout/ContentToolbar\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { DataViewsGrid } from \"./DataViewsGrid\";\nimport type { SelectionExtraRender } from \"./data-views-selection-extra\";\nimport type { ListGroupConfig } from \"./list-card-rails\";\nimport type { DisplayPanelView } from \"./data-views-display-panel\";\nimport { viewStateKey } from \"./data-views-dirty\";\nimport { DeleteViewDialog } from \"./DeleteViewDialog\";\nimport type { BoardConfig } from \"./DataViewsBoard\";\nimport type { DataViewExport } from \"./data-views-export\";\nimport type { ScopeConfig } from \"./data-views-scopes\";\nimport type { DataViewRowDetail } from \"./data-views-row-detail\";\nimport { ViewDialogs, ViewMutationErrorAlert } from \"./data-views-table-parts\";\nimport { useUrlEchoGuard, useUrlSyncState } from \"./data-views-url-echo\";\nimport {\n useSavedViewsController,\n type SavedViewsController,\n} from \"./use-saved-views-controller\";\nimport {\n type DataViewColumn,\n type DataViewsLayout,\n type DataViewServer,\n type DataViewState,\n type DataViewPersistence,\n type DataViewRouter,\n type FilterFieldConfig,\n type RangeFieldConfig,\n type DataViewCardSelection,\n type RowAction,\n type SavedViewSummary,\n} from \"./data-views-types\";\n\nexport interface DataViewsTableBaseProps<T extends Record<string, unknown>> {\n /** The applied-view id read from the URL (`?view=`) on load, or null. */\n initialViewId?: string | null;\n /** Injected saved-view persistence (create/update/delete). */\n persistence: DataViewPersistence;\n /** Injected router side-effects (URL sync + refresh). */\n router: DataViewRouter;\n rows: T[];\n columns: DataViewColumn<T>[];\n fields: FilterFieldConfig<T>[];\n /** Optional numeric min/max range filters (advanced \"filter by amount\"). */\n rangeFields?: RangeFieldConfig<T>[];\n getRowId: (row: T) => string | number;\n onRowClick?: (row: T) => void;\n emptyState?: React.ReactNode;\n dataTestId?: string;\n testIdPrefix?: string;\n /** The user's + shared views for this table (from the server). */\n views: SavedViewSummary[];\n /** Big page title in the table header, beside the funnel + gear (GTA layout). */\n title?: string;\n /** Primary page actions (e.g. \"Novo produto\") rendered at the header's right. */\n headerActions?: React.ReactNode;\n /** Sort options for the toolbar's \"Sort By\" dropdown (defaults to sortable columns). */\n sortFields?: SortFieldDefinition[];\n /**\n * Per-sort-field VALUE KIND (`\"currency\" | \"number\" | \"date\" | \"text\"`), so the\n * Exibir panel phrases the direction in that column's own terms. \"Crescente\"\n * on a currency column is a puzzle; \"Menor → maior\" is not. Defaults to text.\n */\n sortKinds?: Record<string, string>;\n /**\n * Opt-in \"Exportar\" control. The grid hands the host the current query,\n * UNPAGINATED, and the host re-queries — the grid never fetches, and an\n * export therefore follows the filters rather than the loaded page.\n */\n exportConfig?: DataViewExport;\n /** Notified with the currently-visible (filtered) rows, so Export matches the view. */\n onVisibleRowsChange?: (rows: T[]) => void;\n /** Reusable row actions driving both the row \"⋮\" kebab and the bulk menu. */\n rowActions?: RowAction<T>[];\n /** Leading control in the auto kebab column (e.g. a favourite star). */\n rowActionsLeading?: (row: T) => React.ReactNode;\n /** Low-level bulk-action override; prefer `rowActions`. */\n bulkActions?: (selectedRows: T[], clearSelection: () => void) => React.ReactNode;\n /** A selection-widening control beside the count (e.g. \"select all matching\"). */\n selectionExtra?: SelectionExtraRender<T>;\n /** Bespoke per-row menu (an entity's self-contained 3-dots menu) instead of the auto kebab. */\n renderRowMenu?: (row: T) => React.ReactNode;\n /** Opt-in expandable rows (table layout only) — see {@link DataViewRowDetail}. */\n rowDetail?: DataViewRowDetail<T>;\n /** Opt-in \"Grade\" (cards) layout — a card renderer per row; adds a Grade/Tabela toggle. */\n renderCard?: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n /** Opt-in \"Quadro\" (board) layout — the loaded page as columns of one field. Needs `renderCard`. */\n board?: BoardConfig<T>;\n /** Opt-in \"Lista\" layout — one full-width, entity-rendered row per record (FUT-733). */\n renderListRow?: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n /** The Lista's shared columns, so its rows line up by construction not convention. */\n listGroup?: ListGroupConfig<T>;\n /** The page-level partition rendered as tabs under the toolbar (server mode only). */\n scopes?: ScopeConfig[];\n /** The row field the scopes partition by — used only to reject a pill over the same field. */\n scopeFieldId?: string;\n /** Which layout to show first when the user has expressed no preference (default \"table\"). */\n defaultLayout?: DataViewsLayout;\n /**\n * Ignore the remembered cross-screen layout preference and pin to\n * `defaultLayout`. For tables that exist to SHOW a layout — stories, docs,\n * screenshots — not for real screens.\n */\n ignoreStoredLayout?: boolean;\n /** Opt into the responsive inline filter UX (collapsible row / modal). Default keeps the panel. */\n inlineFilters?: boolean;\n /** Keep the inline search visible with no filter fields and no active search. */\n alwaysShowSearch?: boolean;\n /** Server-mode wiring (FUT-180): backend-driven rows/total + re-fetch. Omit for client mode. */\n server?: DataViewServer;\n /** Seed the initial view state (search/pills/ranges/sort) from the URL when no saved view applies. */\n initialState?: DataViewState;\n}\n\n/**\n * Resolve the initial applied view: a `?view=<id>` shortcut (FUT-90) wins, else\n * the user's default view, else none. Drives the seed state + trigger label.\n */\nfunction resolveInitialView(\n views: SavedViewSummary[],\n requestedId: string | null,\n): SavedViewSummary | undefined {\n const requested = requestedId ? views.find((view) => view.id === requestedId) : undefined;\n return requested ?? views.find((view) => view.isDefault);\n}\n\n/**\n * The Exibir panel's view chrome, assembled from the saved-views controller.\n * Extracted so {@link DataViewsTableBase} stays inside its size budget.\n */\nfunction buildDisplayView({\n ctl,\n views,\n activeView,\n dirty,\n onRequestDelete,\n}: {\n ctl: SavedViewsController;\n views: SavedViewSummary[];\n activeView: SavedViewSummary | undefined;\n dirty: boolean;\n /** Opens the confirmation; the delete itself happens on confirm. */\n onRequestDelete: (view: SavedViewSummary) => void;\n}): DisplayPanelView {\n return {\n activeViewName: ctl.activeViewName,\n dirty,\n onReset: () => (activeView ? ctl.applyView(activeView) : ctl.selectMain()),\n // Only offer \"Atualizar\" when there IS a view to update — otherwise the\n // single footer button is a plain \"Salvar visão\".\n onUpdate: activeView ? () => ctl.openEdit(activeView) : undefined,\n onSaveAs: ctl.openCreate,\n // The views themselves, not a dropdown: the panel renders them in its own\n // body (see `data-views-view-nav`), so there is no second popover to clip\n // the row actions.\n nav: {\n views,\n activeViewId: activeView?.id ?? null,\n onSelectView: (id) => {\n const next = id === null ? null : views.find((view) => view.id === id);\n if (next) ctl.applyView(next);\n else ctl.selectMain();\n },\n onEditView: ctl.openEdit,\n onPatchView: (view, changes) => void ctl.patchView(view, changes),\n onDeleteView: onRequestDelete,\n },\n };\n}\n\n/**\n * \"Are there unsaved changes?\" — the dot on Exibir, and whether Redefinir and\n * Salvar visão are live.\n *\n * Two things it gets right that the inline version did not. It compares\n * NORMALISED states (`viewStateKey`), so a filter applied and then removed is\n * clean again rather than clean-looking but flagged; and it re-baselines after\n * a SAVE, because the state just written is the clean one from that point.\n *\n * The baseline is the first state the grid emits for a view, not the view\n * itself: the grid normalises what it is handed — resolving visible columns,\n * filling in layout — so the applied view is never byte-identical to the state\n * it produces.\n */\nfunction useDirtyTracking(ctl: SavedViewsController): {\n dirty: boolean;\n noteState: (state: DataViewState) => void;\n markSaved: () => void;\n} {\n const [dirty, setDirty] = useState(false);\n const [savedAt, setSavedAt] = useState(0);\n const baseline = useRef<string | null>(null);\n const appliedKey = JSON.stringify(ctl.applied ?? null);\n\n useEffect(() => {\n baseline.current = null;\n setDirty(false);\n }, [appliedKey, savedAt]);\n\n return {\n dirty,\n noteState: (state) => {\n ctl.currentRef.current = state;\n const key = viewStateKey(state);\n if (baseline.current === null) {\n baseline.current = key;\n setDirty(false);\n return;\n }\n const next = key !== baseline.current;\n setDirty((prev) => (prev === next ? prev : next));\n },\n markSaved: () => setSavedAt((tick) => tick + 1),\n };\n}\n\n/**\n * The reusable admin table (FUT-89): the DataViews grid plus the full saved-views\n * experience — a views dropdown, a save/edit modal (with preview), and a manage\n * dialog. Framework-agnostic: saved-view persistence and router side-effects are\n * INJECTED (`persistence`, `router`, `initialViewId`) so the host app wires them\n * to its backend + framework router. A default view auto-applies on load; applying\n * a view restores its filters + columns + sort. Each table supplies its own columns\n * + filter fields; everything else is shared.\n */\nexport function DataViewsTableBase<T extends Record<string, unknown>>(\n props: DataViewsTableBaseProps<T>,\n): React.JSX.Element {\n // Forwarded as a whole rather than restated name-by-name twice (as in\n // DataViewsGrid): this component only ADDS the saved-views chrome, and a\n // 30-name destructure repeated in the JSX is exactly where a newly added prop\n // silently stops being passed on.\n const {\n initialViewId = null,\n persistence,\n router,\n columns,\n fields,\n testIdPrefix = \"table\",\n views,\n server,\n initialState,\n } = props;\n const initialView = resolveInitialView(views, initialViewId);\n const columnIds = columns.map((col) => col.id);\n const ctl = useSavedViewsController(persistence, router, columnIds, views, initialView, initialState);\n // Unsaved-changes flag for the Exibir panel. Set from `onStateChange` rather\n // than derived in render because the live state lives in a REF (the grid owns\n // it); the equality bail-out in `setDirty` is what stops the update loop.\n const { dirty, noteState, markSaved } = useDirtyTracking(ctl);\n // Deleting a saved view is confirmed, not immediate — see `DeleteViewDialog`.\n const [pendingDelete, setPendingDelete] = useState<SavedViewSummary | null>(null);\n // The view the panel's \"Redefinir\" restores: the applied one, or the built-in\n // \"Visão principal\" when none is.\n const activeView = views.find((view) => view.name === ctl.activeViewName);\n const displayView = buildDisplayView({\n ctl,\n views,\n activeView,\n dirty,\n onRequestDelete: setPendingDelete,\n });\n // Server-mode lists re-apply URL-derived controls on back/forward (not just\n // the mount seed), but never the grid's own query echoing back through the URL.\n const echo = useUrlEchoGuard(server);\n const syncState = useUrlSyncState(echo.server, initialState, echo.consumeEcho);\n\n return (\n <>\n <ViewMutationErrorAlert error={ctl.mutationError} onClose={ctl.clearMutationError} testIdPrefix={testIdPrefix} />\n <DataViewsGrid<T>\n {...props}\n server={echo.server}\n testIdPrefix={testIdPrefix}\n appliedState={ctl.applied}\n syncState={syncState}\n onStateChange={noteState}\n // The saved-views menu is NOT a toolbar control any more: it lives in\n // the Exibir panel's VISÃO header, passed through `displayView`.\n displayView={displayView}\n />\n {renderViewDialogs(ctl, fields, columns, views, testIdPrefix, markSaved)}\n <DeleteViewDialog\n view={pendingDelete}\n onClose={() => setPendingDelete(null)}\n onConfirm={(view) => {\n void ctl.handleDelete(view);\n setPendingDelete(null);\n }}\n testIdPrefix={testIdPrefix}\n />\n </>\n );\n}\n\n/** The save + manage saved-view dialogs, split out to keep the base thin. */\nfunction renderViewDialogs<T extends Record<string, unknown>>(\n ctl: SavedViewsController,\n fields: DataViewsTableBaseProps<T>[\"fields\"],\n columns: DataViewsTableBaseProps<T>[\"columns\"],\n views: SavedViewSummary[],\n testIdPrefix: string,\n onSaved: () => void,\n): React.JSX.Element {\n return (\n <ViewDialogs<T>\n saveOpen={ctl.saveOpen}\n onCloseSave={ctl.closeSave}\n currentState={ctl.editing ? ctl.editing.state : ctl.currentRef.current}\n fields={fields}\n columns={columns}\n editing={ctl.editing}\n onSave={async (payload) => {\n await ctl.handleSave(payload);\n // The saved state is the clean one from here on.\n onSaved();\n }}\n manageOpen={ctl.manageOpen}\n onCloseManage={() => ctl.setManageOpen(false)}\n views={views}\n onEditFromManage={ctl.editFromManage}\n onDelete={(view) => void ctl.handleDelete(view)}\n testIdPrefix={testIdPrefix}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAGA,SAAS,WAAW,QAAQ,gBAAgB;AA2QxC,mBACE,KADF;AAtJJ,SAAS,mBACP,OACA,aAC8B;AAC9B,QAAM,YAAY,cAAc,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,WAAW,IAAI;AAChF,SAAO,aAAa,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS;AACzD;AAMA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOqB;AACnB,SAAO;AAAA,IACL,gBAAgB,IAAI;AAAA,IACpB;AAAA,IACA,SAAS,MAAO,aAAa,IAAI,UAAU,UAAU,IAAI,IAAI,WAAW;AAAA;AAAA;AAAA,IAGxE,UAAU,aAAa,MAAM,IAAI,SAAS,UAAU,IAAI;AAAA,IACxD,UAAU,IAAI;AAAA;AAAA;AAAA;AAAA,IAId,KAAK;AAAA,MACH;AAAA,MACA,cAAc,YAAY,MAAM;AAAA,MAChC,cAAc,CAAC,OAAO;AACpB,cAAM,OAAO,OAAO,OAAO,OAAO,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,EAAE;AACrE,YAAI,KAAM,KAAI,UAAU,IAAI;AAAA,YACvB,KAAI,WAAW;AAAA,MACtB;AAAA,MACA,YAAY,IAAI;AAAA,MAChB,aAAa,CAAC,MAAM,YAAY,KAAK,IAAI,UAAU,MAAM,OAAO;AAAA,MAChE,cAAc;AAAA,IAChB;AAAA,EACF;AACF;AAgBA,SAAS,iBAAiB,KAIxB;AACA,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,KAAK;AACxC,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,CAAC;AACxC,QAAM,WAAW,OAAsB,IAAI;AAC3C,QAAM,aAAa,KAAK,UAAU,IAAI,WAAW,IAAI;AAErD,YAAU,MAAM;AACd,aAAS,UAAU;AACnB,aAAS,KAAK;AAAA,EAChB,GAAG,CAAC,YAAY,OAAO,CAAC;AAExB,SAAO;AAAA,IACL;AAAA,IACA,WAAW,CAAC,UAAU;AACpB,UAAI,WAAW,UAAU;AACzB,YAAM,MAAM,aAAa,KAAK;AAC9B,UAAI,SAAS,YAAY,MAAM;AAC7B,iBAAS,UAAU;AACnB,iBAAS,KAAK;AACd;AAAA,MACF;AACA,YAAM,OAAO,QAAQ,SAAS;AAC9B,eAAS,CAAC,SAAU,SAAS,OAAO,OAAO,IAAK;AAAA,IAClD;AAAA,IACA,WAAW,MAAM,WAAW,CAAC,SAAS,OAAO,CAAC;AAAA,EAChD;AACF;AAWO,SAAS,mBACd,OACmB;AAKnB,QAAM;AAAA,IACJ,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,cAAc,mBAAmB,OAAO,aAAa;AAC3D,QAAM,YAAY,QAAQ,IAAI,CAAC,QAAQ,IAAI,EAAE;AAC7C,QAAM,MAAM,wBAAwB,aAAa,QAAQ,WAAW,OAAO,aAAa,YAAY;AAIpG,QAAM,EAAE,OAAO,WAAW,UAAU,IAAI,iBAAiB,GAAG;AAE5D,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAkC,IAAI;AAGhF,QAAM,aAAa,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,cAAc;AACxE,QAAM,cAAc,iBAAiB;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,EACnB,CAAC;AAGD,QAAM,OAAO,gBAAgB,MAAM;AACnC,QAAM,YAAY,gBAAgB,KAAK,QAAQ,cAAc,KAAK,WAAW;AAE7E,SACE,iCACE;AAAA,wBAAC,0BAAuB,OAAO,IAAI,eAAe,SAAS,IAAI,oBAAoB,cAA4B;AAAA,IAC/G;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,QAAQ,KAAK;AAAA,QACb;AAAA,QACA,cAAc,IAAI;AAAA,QAClB;AAAA,QACA,eAAe;AAAA,QAGf;AAAA;AAAA,IACF;AAAA,IACC,kBAAkB,KAAK,QAAQ,SAAS,OAAO,cAAc,SAAS;AAAA,IACvE;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,MAAM,iBAAiB,IAAI;AAAA,QACpC,WAAW,CAAC,SAAS;AACnB,eAAK,IAAI,aAAa,IAAI;AAC1B,2BAAiB,IAAI;AAAA,QACvB;AAAA,QACA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAGA,SAAS,kBACP,KACA,QACA,SACA,OACA,cACA,SACmB;AACnB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU,IAAI;AAAA,MACd,aAAa,IAAI;AAAA,MACjB,cAAc,IAAI,UAAU,IAAI,QAAQ,QAAQ,IAAI,WAAW;AAAA,MAC/D;AAAA,MACA;AAAA,MACA,SAAS,IAAI;AAAA,MACb,QAAQ,OAAO,YAAY;AACzB,cAAM,IAAI,WAAW,OAAO;AAE5B,gBAAQ;AAAA,MACV;AAAA,MACA,YAAY,IAAI;AAAA,MAChB,eAAe,MAAM,IAAI,cAAc,KAAK;AAAA,MAC5C;AAAA,MACA,kBAAkB,IAAI;AAAA,MACtB,UAAU,CAAC,SAAS,KAAK,IAAI,aAAa,IAAI;AAAA,MAC9C;AAAA;AAAA,EACF;AAEJ;","names":[]}