@entifix/react-controls 0.1.1 → 0.1.3

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 (155) hide show
  1. package/README.md +5 -5
  2. package/dist/i18n/catalog/es.d.ts +2 -2
  3. package/dist/i18n/catalog/es.js +2 -2
  4. package/dist/i18n/catalog/es.js.map +1 -1
  5. package/dist/i18n/entity-labels.d.ts +2 -1
  6. package/dist/i18n/entity-labels.d.ts.map +1 -1
  7. package/dist/i18n/entity-labels.js +2 -1
  8. package/dist/i18n/entity-labels.js.map +1 -1
  9. package/dist/index.d.ts +12 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +12 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/primitives.d.ts +12 -0
  14. package/dist/primitives.d.ts.map +1 -1
  15. package/dist/primitives.js +12 -0
  16. package/dist/primitives.js.map +1 -1
  17. package/dist/theme/index.d.ts +1 -0
  18. package/dist/theme/index.d.ts.map +1 -1
  19. package/dist/theme/index.js +1 -0
  20. package/dist/theme/index.js.map +1 -1
  21. package/dist/theme/theme-script.d.ts +26 -0
  22. package/dist/theme/theme-script.d.ts.map +1 -0
  23. package/dist/theme/theme-script.js +38 -0
  24. package/dist/theme/theme-script.js.map +1 -0
  25. package/dist/ui/actions/index.d.ts +1 -0
  26. package/dist/ui/actions/index.d.ts.map +1 -1
  27. package/dist/ui/actions/index.js +1 -0
  28. package/dist/ui/actions/index.js.map +1 -1
  29. package/dist/ui/actions/render-link.d.ts +40 -0
  30. package/dist/ui/actions/render-link.d.ts.map +1 -0
  31. package/dist/ui/actions/render-link.js +8 -0
  32. package/dist/ui/actions/render-link.js.map +1 -0
  33. package/dist/ui/atoms/external-link/external-link.d.ts +9 -0
  34. package/dist/ui/atoms/external-link/external-link.d.ts.map +1 -0
  35. package/dist/ui/atoms/external-link/external-link.js +13 -0
  36. package/dist/ui/atoms/external-link/external-link.js.map +1 -0
  37. package/dist/ui/atoms/external-link/index.d.ts +2 -0
  38. package/dist/ui/atoms/external-link/index.d.ts.map +1 -0
  39. package/dist/ui/atoms/external-link/index.js +3 -0
  40. package/dist/ui/atoms/external-link/index.js.map +1 -0
  41. package/dist/ui/atoms/switch/index.d.ts +2 -0
  42. package/dist/ui/atoms/switch/index.d.ts.map +1 -0
  43. package/dist/ui/atoms/switch/index.js +3 -0
  44. package/dist/ui/atoms/switch/index.js.map +1 -0
  45. package/dist/ui/atoms/switch/switch.d.ts +10 -0
  46. package/dist/ui/atoms/switch/switch.d.ts.map +1 -0
  47. package/dist/ui/atoms/switch/switch.js +43 -0
  48. package/dist/ui/atoms/switch/switch.js.map +1 -0
  49. package/dist/ui/atoms/text/text.d.ts +5 -0
  50. package/dist/ui/atoms/text/text.d.ts.map +1 -1
  51. package/dist/ui/atoms/text/text.js +5 -1
  52. package/dist/ui/atoms/text/text.js.map +1 -1
  53. package/dist/ui/molecules/nav-menu/index.d.ts +2 -0
  54. package/dist/ui/molecules/nav-menu/index.d.ts.map +1 -0
  55. package/dist/ui/molecules/nav-menu/index.js +3 -0
  56. package/dist/ui/molecules/nav-menu/index.js.map +1 -0
  57. package/dist/ui/molecules/nav-menu/nav-menu.d.ts +30 -0
  58. package/dist/ui/molecules/nav-menu/nav-menu.d.ts.map +1 -0
  59. package/dist/ui/molecules/nav-menu/nav-menu.js +58 -0
  60. package/dist/ui/molecules/nav-menu/nav-menu.js.map +1 -0
  61. package/dist/ui/molecules/segmented-control/index.d.ts +2 -0
  62. package/dist/ui/molecules/segmented-control/index.d.ts.map +1 -0
  63. package/dist/ui/molecules/segmented-control/index.js +3 -0
  64. package/dist/ui/molecules/segmented-control/index.js.map +1 -0
  65. package/dist/ui/molecules/segmented-control/segmented-control.d.ts +21 -0
  66. package/dist/ui/molecules/segmented-control/segmented-control.d.ts.map +1 -0
  67. package/dist/ui/molecules/segmented-control/segmented-control.js +55 -0
  68. package/dist/ui/molecules/segmented-control/segmented-control.js.map +1 -0
  69. package/dist/ui/molecules/segmented-nav/index.d.ts +2 -0
  70. package/dist/ui/molecules/segmented-nav/index.d.ts.map +1 -0
  71. package/dist/ui/molecules/segmented-nav/index.js +3 -0
  72. package/dist/ui/molecules/segmented-nav/index.js.map +1 -0
  73. package/dist/ui/molecules/segmented-nav/segment-classes.d.ts +9 -0
  74. package/dist/ui/molecules/segmented-nav/segment-classes.d.ts.map +1 -0
  75. package/dist/ui/molecules/segmented-nav/segment-classes.js +9 -0
  76. package/dist/ui/molecules/segmented-nav/segment-classes.js.map +1 -0
  77. package/dist/ui/molecules/segmented-nav/segmented-nav.d.ts +30 -0
  78. package/dist/ui/molecules/segmented-nav/segmented-nav.d.ts.map +1 -0
  79. package/dist/ui/molecules/segmented-nav/segmented-nav.js +46 -0
  80. package/dist/ui/molecules/segmented-nav/segmented-nav.js.map +1 -0
  81. package/dist/ui/molecules/split-button/index.d.ts +2 -0
  82. package/dist/ui/molecules/split-button/index.d.ts.map +1 -0
  83. package/dist/ui/molecules/split-button/index.js +3 -0
  84. package/dist/ui/molecules/split-button/index.js.map +1 -0
  85. package/dist/ui/molecules/split-button/split-button.d.ts +21 -0
  86. package/dist/ui/molecules/split-button/split-button.d.ts.map +1 -0
  87. package/dist/ui/molecules/split-button/split-button.js +35 -0
  88. package/dist/ui/molecules/split-button/split-button.js.map +1 -0
  89. package/dist/ui/molecules/split-view/index.d.ts +2 -0
  90. package/dist/ui/molecules/split-view/index.d.ts.map +1 -0
  91. package/dist/ui/molecules/split-view/index.js +3 -0
  92. package/dist/ui/molecules/split-view/index.js.map +1 -0
  93. package/dist/ui/molecules/split-view/split-view.d.ts +35 -0
  94. package/dist/ui/molecules/split-view/split-view.d.ts.map +1 -0
  95. package/dist/ui/molecules/split-view/split-view.js +76 -0
  96. package/dist/ui/molecules/split-view/split-view.js.map +1 -0
  97. package/dist/ui/organisms/entity-form/entity-form.d.ts +1 -1
  98. package/dist/ui/organisms/entity-form/entity-form.d.ts.map +1 -1
  99. package/dist/ui/organisms/entity-form/entity-form.js +12 -10
  100. package/dist/ui/organisms/entity-form/entity-form.js.map +1 -1
  101. package/dist/ui/organisms/entity-form/entity-form.types.d.ts +6 -0
  102. package/dist/ui/organisms/entity-form/entity-form.types.d.ts.map +1 -1
  103. package/dist/ui/organisms/entity-form/entity-form.types.js.map +1 -1
  104. package/dist/ui/organisms/entity-table/entity-table.d.ts +1 -1
  105. package/dist/ui/organisms/entity-table/entity-table.d.ts.map +1 -1
  106. package/dist/ui/organisms/entity-table/entity-table.js +16 -7
  107. package/dist/ui/organisms/entity-table/entity-table.js.map +1 -1
  108. package/dist/ui/organisms/entity-table/entity-table.types.d.ts +7 -0
  109. package/dist/ui/organisms/entity-table/entity-table.types.d.ts.map +1 -1
  110. package/dist/ui/organisms/entity-table/entity-table.types.js.map +1 -1
  111. package/dist/ui/utils/active-heading/active-heading.d.ts +16 -0
  112. package/dist/ui/utils/active-heading/active-heading.d.ts.map +1 -0
  113. package/dist/ui/utils/active-heading/active-heading.js +68 -0
  114. package/dist/ui/utils/active-heading/active-heading.js.map +1 -0
  115. package/dist/ui/utils/active-heading/index.d.ts +2 -0
  116. package/dist/ui/utils/active-heading/index.d.ts.map +1 -0
  117. package/dist/ui/utils/active-heading/index.js +3 -0
  118. package/dist/ui/utils/active-heading/index.js.map +1 -0
  119. package/dist/ui/utils/active-section/active-section.d.ts +11 -0
  120. package/dist/ui/utils/active-section/active-section.d.ts.map +1 -0
  121. package/dist/ui/utils/active-section/active-section.js +45 -0
  122. package/dist/ui/utils/active-section/active-section.js.map +1 -0
  123. package/dist/ui/utils/active-section/index.d.ts +2 -0
  124. package/dist/ui/utils/active-section/index.d.ts.map +1 -0
  125. package/dist/ui/utils/active-section/index.js +3 -0
  126. package/dist/ui/utils/active-section/index.js.map +1 -0
  127. package/dist/ui/utils/fold-script/fold-script.d.ts +20 -0
  128. package/dist/ui/utils/fold-script/fold-script.d.ts.map +1 -0
  129. package/dist/ui/utils/fold-script/fold-script.js +30 -0
  130. package/dist/ui/utils/fold-script/fold-script.js.map +1 -0
  131. package/dist/ui/utils/fold-script/index.d.ts +2 -0
  132. package/dist/ui/utils/fold-script/index.d.ts.map +1 -0
  133. package/dist/ui/utils/fold-script/index.js +3 -0
  134. package/dist/ui/utils/fold-script/index.js.map +1 -0
  135. package/dist/ui/utils/keep-section/index.d.ts +2 -0
  136. package/dist/ui/utils/keep-section/index.d.ts.map +1 -0
  137. package/dist/ui/utils/keep-section/index.js +3 -0
  138. package/dist/ui/utils/keep-section/index.js.map +1 -0
  139. package/dist/ui/utils/keep-section/keep-section.d.ts +8 -0
  140. package/dist/ui/utils/keep-section/keep-section.d.ts.map +1 -0
  141. package/dist/ui/utils/keep-section/keep-section.js +24 -0
  142. package/dist/ui/utils/keep-section/keep-section.js.map +1 -0
  143. package/dist/ui/utils/media-query/index.d.ts +2 -0
  144. package/dist/ui/utils/media-query/index.d.ts.map +1 -0
  145. package/dist/ui/utils/media-query/index.js +3 -0
  146. package/dist/ui/utils/media-query/index.js.map +1 -0
  147. package/dist/ui/utils/media-query/media-query.d.ts +7 -0
  148. package/dist/ui/utils/media-query/media-query.d.ts.map +1 -0
  149. package/dist/ui/utils/media-query/media-query.js +18 -0
  150. package/dist/ui/utils/media-query/media-query.js.map +1 -0
  151. package/package.json +5 -8
  152. package/dist/i18n/spec-support/catalogs.d.ts +0 -2
  153. package/dist/i18n/spec-support/catalogs.d.ts.map +0 -1
  154. package/dist/i18n/spec-support/catalogs.js +0 -142
  155. package/dist/i18n/spec-support/catalogs.js.map +0 -1
@@ -1,4 +1,4 @@
1
1
  import { type Entity } from '@entifix/core';
2
2
  import type { EntityTableProps } from './entity-table.types.js';
3
- export declare function EntityTable<TEntity extends Entity>({ entityConstructor, isLoading, skeleton, error, items, totalItems, currentPage, pageSize, onPageChange, onPageSizeChange, hrefFor, newHref, onSelect, preferencesKey, showControls, pivotBreakpoint, filtering, sorting, onFilteringChange, onSortingChange, selection, onSelectionChange, metadata, isMetadataLoading, onBulkUseCase, onUseCase, bulkOutcomes, onBulkDismiss, onBulkRetry, isBulkRunning, children, }: EntityTableProps<TEntity>): import("react").JSX.Element;
3
+ export declare function EntityTable<TEntity extends Entity>({ entityConstructor, isLoading, skeleton, error, items, totalItems, currentPage, pageSize, onPageChange, onPageSizeChange, hrefFor, newHref, renderLink, onSelect, preferencesKey, showControls, pivotBreakpoint, filtering, sorting, onFilteringChange, onSortingChange, selection, onSelectionChange, metadata, isMetadataLoading, onBulkUseCase, onUseCase, bulkOutcomes, onBulkDismiss, onBulkRetry, isBulkRunning, children, }: EntityTableProps<TEntity>): import("react").JSX.Element;
4
4
  //# sourceMappingURL=entity-table.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entity-table.d.ts","sourceRoot":"","sources":["../../../../src/ui/organisms/entity-table/entity-table.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,MAAM,EAUZ,MAAM,eAAe,CAAC;AA8BvB,OAAO,KAAK,EAGV,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AAwDjC,wBAAgB,WAAW,CAAC,OAAO,SAAS,MAAM,EAAE,EAClD,iBAAiB,EACjB,SAAS,EACT,QAAe,EACf,KAAK,EACL,KAAK,EACL,UAAU,EACV,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,OAAO,EACP,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAmB,EACnB,eAAsB,EACtB,SAAS,EACT,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,iBAAyB,EACzB,aAAa,EACb,SAAS,EACT,YAAY,EACZ,aAAa,EACb,WAAW,EACX,aAAqB,EACrB,QAAQ,GACT,EAAE,gBAAgB,CAAC,OAAO,CAAC,+BAopB3B"}
1
+ {"version":3,"file":"entity-table.d.ts","sourceRoot":"","sources":["../../../../src/ui/organisms/entity-table/entity-table.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,MAAM,EAUZ,MAAM,eAAe,CAAC;AAkCvB,OAAO,KAAK,EAGV,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AAwDjC,wBAAgB,WAAW,CAAC,OAAO,SAAS,MAAM,EAAE,EAClD,iBAAiB,EACjB,SAAS,EACT,QAAe,EACf,KAAK,EACL,KAAK,EACL,UAAU,EACV,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,OAAO,EACP,OAAO,EACP,UAAyB,EACzB,QAAQ,EACR,cAAc,EACd,YAAmB,EACnB,eAAsB,EACtB,SAAS,EACT,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,iBAAyB,EACzB,aAAa,EACb,SAAS,EACT,YAAY,EACZ,aAAa,EACb,WAAW,EACX,aAAqB,EACrB,QAAQ,GACT,EAAE,gBAAgB,CAAC,OAAO,CAAC,+BA+pB3B"}
@@ -3,13 +3,13 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { emptySelection, EntifixLogicError, extractMetaEntity, isSelected, selectionSize, toggleSelected } from '@entifix/core';
4
4
  import { Fragment, useRef, useState } from 'react';
5
5
  import { useErrorMessage, useT, useTranslateKey } from '../../../i18n/index.js';
6
- import { OVERFLOW_GLYPH, useCasesForSurface } from '../../actions/index.js';
6
+ import { OVERFLOW_GLYPH, renderAnchor, useCasesForSurface } from '../../actions/index.js';
7
7
  import { Button } from '../../atoms/button/index.js';
8
8
  import { CellValue } from '../../atoms/cell-value/index.js';
9
9
  import { Checkbox } from '../../atoms/field/index.js';
10
10
  import { Skeleton } from '../../atoms/skeleton/index.js';
11
11
  import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableMessageRow, TableRow } from '../../atoms/table/index.js';
12
- import { Link } from '../../atoms/text/index.js';
12
+ import { linkClassName } from '../../atoms/text/index.js';
13
13
  import { BulkActionBar } from '../../molecules/bulk-action-bar/index.js';
14
14
  import { BulkResult } from '../../molecules/bulk-result/index.js';
15
15
  import { ColumnSettings } from '../../molecules/column-settings/index.js';
@@ -50,7 +50,7 @@ import { useEntityTableColumns } from './use-entity-table-columns.js';
50
50
  * a fifty-row page would otherwise paint fifty shimmer rows to stand in for
51
51
  * content that arrives below the fold anyway.
52
52
  */ const SKELETON_ROW_CAP = 5;
53
- export function EntityTable({ entityConstructor, isLoading, skeleton = true, error, items, totalItems, currentPage, pageSize, onPageChange, onPageSizeChange, hrefFor, newHref, onSelect, preferencesKey, showControls = true, pivotBreakpoint = 'md', filtering, sorting, onFilteringChange, onSortingChange, selection, onSelectionChange, metadata, isMetadataLoading = false, onBulkUseCase, onUseCase, bulkOutcomes, onBulkDismiss, onBulkRetry, isBulkRunning = false, children }) {
53
+ export function EntityTable({ entityConstructor, isLoading, skeleton = true, error, items, totalItems, currentPage, pageSize, onPageChange, onPageSizeChange, hrefFor, newHref, renderLink = renderAnchor, onSelect, preferencesKey, showControls = true, pivotBreakpoint = 'md', filtering, sorting, onFilteringChange, onSortingChange, selection, onSelectionChange, metadata, isMetadataLoading = false, onBulkUseCase, onUseCase, bulkOutcomes, onBulkDismiss, onBulkRetry, isBulkRunning = false, children }) {
54
54
  var _ref;
55
55
  const t = useT();
56
56
  // A descriptor's label is a runtime catalog key — the typed gate cannot see
@@ -270,9 +270,14 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
270
270
  size: "sm",
271
271
  onClick: ()=>onSelect(item),
272
272
  children: t('table.select')
273
- }) : hrefFor ? /*#__PURE__*/ _jsx(Link, {
273
+ }) : hrefFor ? renderLink({
274
274
  href: hrefFor(item.id),
275
- children: t('table.open')
275
+ className: linkClassName,
276
+ children: t('table.open'),
277
+ intent: {
278
+ kind: 'open',
279
+ id: item.id
280
+ }
276
281
  }) : undefined;
277
282
  const menu = rowMenu(item);
278
283
  if (!menu) return primary;
@@ -301,9 +306,13 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
301
306
  showControls && /*#__PURE__*/ _jsx(TableToolbar, {
302
307
  start: /*#__PURE__*/ _jsxs(_Fragment, {
303
308
  children: [
304
- newHref && /*#__PURE__*/ _jsx(Link, {
309
+ newHref && renderLink({
305
310
  href: newHref,
306
- children: t('table.new')
311
+ className: linkClassName,
312
+ children: t('table.new'),
313
+ intent: {
314
+ kind: 'new'
315
+ }
307
316
  }),
308
317
  /*#__PURE__*/ _jsx(LoadingBoundary, {
309
318
  isLoading: isMetadataLoading,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/organisms/entity-table/entity-table.tsx"],"sourcesContent":["'use client';\n\nimport {\n emptySelection,\n EntifixLogicError,\n type Entity,\n type EntityId,\n type EntitySelection,\n type EntitySorting,\n extractMetaEntity,\n type FilterGroup,\n isSelected,\n selectionSize,\n toggleSelected,\n type UseCaseDescriptor,\n} from '@entifix/core';\nimport { Fragment, type ReactNode, useRef, useState } from 'react';\n\nimport { useErrorMessage, useT, useTranslateKey } from '../../../i18n/index.js';\nimport { OVERFLOW_GLYPH, useCasesForSurface } from '../../actions/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { CellValue } from '../../atoms/cell-value/index.js';\nimport { Checkbox } from '../../atoms/field/index.js';\nimport { Skeleton } from '../../atoms/skeleton/index.js';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeaderCell,\n TableMessageRow,\n TableRow,\n} from '../../atoms/table/index.js';\nimport { Link } from '../../atoms/text/index.js';\nimport { BulkActionBar } from '../../molecules/bulk-action-bar/index.js';\nimport { BulkResult } from '../../molecules/bulk-result/index.js';\nimport { ColumnSettings } from '../../molecules/column-settings/index.js';\nimport { ConfirmDialog } from '../../molecules/confirm-dialog/index.js';\nimport { EntityRecordCard } from '../../molecules/entity-record-card/index.js';\nimport { FilterBuilder } from '../../molecules/filter-builder/index.js';\nimport { LoadingBoundary } from '../../molecules/loading-boundary/index.js';\nimport { Menu } from '../../molecules/menu/index.js';\nimport { Pagination } from '../../molecules/pagination/index.js';\nimport { SortBuilder } from '../../molecules/sort-builder/index.js';\nimport { TableToolbar } from '../../molecules/table-toolbar/index.js';\nimport type {\n EntityTableColumn,\n EntityTablePivotBreakpoint,\n EntityTableProps,\n} from './entity-table.types.js';\nimport { readEntityTableSlots } from './entity-table-slots.js';\nimport { useEntityTableColumns } from './use-entity-table-columns.js';\n\n/**\n * The grid and the card list are both rendered, and CSS picks one. A JS\n * breakpoint hook would have to guess during SSR and correct after mount —\n * a hydration mismatch on every page load. Classes are written out in full\n * because Tailwind cannot see a class name that is concatenated at runtime.\n */\nconst PIVOT_CLASS: Record<\n EntityTablePivotBreakpoint,\n { grid: string; cards: string }\n> = {\n sm: { grid: 'hidden sm:block', cards: 'sm:hidden' },\n md: { grid: 'hidden md:block', cards: 'md:hidden' },\n lg: { grid: 'hidden lg:block', cards: 'lg:hidden' },\n};\n\ntype Panel = 'none' | 'filters' | 'sorting';\n\n/**\n * How many placeholder rows the built-in skeleton draws.\n *\n * The column count is taken from the real geometry, because that is the axis a\n * mismatch shifts; the row count is capped instead of tracking `pageSize`, since\n * a fifty-row page would otherwise paint fifty shimmer rows to stand in for\n * content that arrives below the fold anyway.\n */\nconst SKELETON_ROW_CAP = 5;\n\n/**\n * A table that builds itself from an entity's metadata: columns, labels, value\n * formatting and the filter/sort controls all come from `@accessor()`\n * declarations, so listing a new entity needs no bespoke table.\n *\n * Three things layer on top of that default:\n * - **personalization** — column order and visibility, persisted through the\n * UI-preferences port (so it survives reloads and can later move server-side);\n * - **responsiveness** — below `pivotBreakpoint` rows pivot into label/value\n * cards instead of scrolling sideways;\n * - **slots** — `<EntityColumn>` / `<EntityTableHeader>` / `<EntityTableRow>` /\n * `<EntityTableToolbar>` children override any part of the default rendering.\n */\n/**\n * What a pending verb will act on once it is confirmed.\n *\n * A form has one record; a table has a row or a selection, and those reach two\n * different handlers with two different payloads. Carrying the selection itself\n * rather than reading it back at confirm time also removes a branch that could\n * not happen: the bulk bar only renders inside a truthy selection.\n */\ntype PendingTarget<TEntity extends Entity> =\n | { kind: 'row'; item: TEntity }\n | { kind: 'selection'; selection: EntitySelection<TEntity> };\n\nexport function EntityTable<TEntity extends Entity>({\n entityConstructor,\n isLoading,\n skeleton = true,\n error,\n items,\n totalItems,\n currentPage,\n pageSize,\n onPageChange,\n onPageSizeChange,\n hrefFor,\n newHref,\n onSelect,\n preferencesKey,\n showControls = true,\n pivotBreakpoint = 'md',\n filtering,\n sorting,\n onFilteringChange,\n onSortingChange,\n selection,\n onSelectionChange,\n metadata,\n isMetadataLoading = false,\n onBulkUseCase,\n onUseCase,\n bulkOutcomes,\n onBulkDismiss,\n onBulkRetry,\n isBulkRunning = false,\n children,\n}: EntityTableProps<TEntity>) {\n const t = useT();\n // A descriptor's label is a runtime catalog key — the typed gate cannot see\n // it, which is why `@r10c/i18n-check` is what catches a typo.\n const translateKey = useTranslateKey();\n const errorMessage = useErrorMessage();\n const metaEntity = extractMetaEntity(entityConstructor);\n const slots = readEntityTableSlots<TEntity>(children);\n const [panel, setPanel] = useState<Panel>('none');\n\n /**\n * A verb waiting to be confirmed, and what it will act on.\n *\n * ⚠️ **The table had no confirmation flow at all** until #216 moved a\n * destructive verb onto it. It read `confirm.tone` — only to pick a tone for\n * a button or a menu item — and then fired on the first click. `unpublish` is\n * declared `destructive`, so a verb reachable from a row menu without this\n * would have been a one-click unpublish with a red label explaining what had\n * already happened.\n *\n * The state holds the confirmation itself rather than the descriptor, so the\n * dialog cannot open for a verb that never asked for one — the same shape\n * `EntityForm` uses, and for the same reason.\n *\n * It carries the **target** too, which the form's does not need: a form has\n * one record and a table has a row or a selection, and those run through two\n * different handlers with two different payloads.\n */\n const [pending, setPending] = useState<\n | {\n key: string;\n labelKey: string;\n confirm: NonNullable<UseCaseDescriptor['confirm']>;\n target: PendingTarget<TEntity>;\n }\n | undefined\n >(undefined);\n\n const { columns, visibleColumns, hidden, setPersonalization } =\n useEntityTableColumns<TEntity>(\n entityConstructor,\n slots.columns,\n items[0],\n `entity-table:${preferencesKey ?? metaEntity.key ?? metaEntity.name}`,\n );\n\n const pivot = PIVOT_CLASS[pivotBreakpoint];\n\n // A picker's table is choosing *one* value; a multi-selection there would\n // offer a set to a form member that holds a single reference, and the two\n // controls would fight over the same row. This is a wiring mistake rather\n // than a state, so it costs the render — the same call `EntityForm` makes\n // for a link source aimed at a member no picker can edit.\n if (onSelect !== undefined && selection !== undefined) {\n throw new EntifixLogicError(\n 'EntityTable was given both `onSelect` and `selection`. A picker picks one ' +\n 'row and a selection accumulates many, so the row control cannot be both. ' +\n 'Drop `selection` inside a picker, or drop `onSelect` outside one.',\n );\n }\n\n /**\n * The selection, or `undefined` when the table is not selectable at all.\n *\n * One value rather than a `selection` prop beside a `selectable` boolean:\n * two of them means every render site has to re-test both, and the second\n * test is unreachable — which reads as a defensive check and is really dead\n * code the coverage gate then cannot close.\n */\n const selectionState =\n selection !== undefined && onSelectionChange !== undefined\n ? selection\n : undefined;\n const selectable = selectionState !== undefined;\n const rowUseCases = useCasesForSurface('row-menu', metadata?.useCases);\n const bulkUseCases = useCasesForSurface('bulk-bar', metadata?.useCases);\n const toolbarUseCases = useCasesForSurface(\n 'table-toolbar',\n metadata?.useCases,\n );\n const hasRowMenu = rowUseCases.length > 0 && onUseCase !== undefined;\n\n /**\n * What a `context-independent` collection verb acts on: everything the\n * current filter matches.\n *\n * Not an empty `ids` selection, which would say \"no rows\" — the verb is\n * available *without* a selection precisely because its subject is the\n * collection, so the honest payload is the same filter the listing is\n * showing, and the same one a \"select all matching\" escalation would send.\n */\n const everythingMatching: EntitySelection<TEntity> = {\n mode: 'matching',\n filtering,\n total: totalItems,\n excluded: new Set<EntityId>(),\n };\n\n const hasRowAction =\n onSelect !== undefined || hrefFor !== undefined || hasRowMenu;\n const columnCount =\n visibleColumns.length + (hasRowAction ? 1 : 0) + (selectable ? 1 : 0);\n\n /**\n * The first load has nothing to show and is held with a skeleton; a refetch\n * already has rows, so it keeps them and only marks the region busy. Splitting\n * the two is what stops every pagination click flashing grey.\n */\n const isFirstLoad = isLoading && items.length === 0;\n const isRefetching = isLoading && items.length > 0;\n\n /** `true`/omitted → the built-in default; a node → that node; `false` → none. */\n const customSkeleton = typeof skeleton === 'boolean' ? undefined : skeleton;\n const showSkeleton = isFirstLoad && skeleton !== false;\n const skeletonRows = Array.from(\n { length: Math.min(pageSize, SKELETON_ROW_CAP) },\n (_, index) => index,\n );\n\n /**\n * The refetch hint, and it is deliberately the only one: rows stay readable\n * and simply dim, because a second skeleton over live data would be two\n * loading signals in one region.\n */\n const busyClass = isRefetching\n ? 'opacity-60 transition-opacity duration-200 ease-smooth'\n : '';\n\n const renderCell = (\n column: EntityTableColumn<TEntity>,\n item: TEntity,\n ): ReactNode =>\n column.render ? (\n column.render(item)\n ) : (\n <CellValue\n value={(item as Record<string, unknown>)[column.name]}\n descriptor={column}\n />\n );\n\n /**\n * The row a shift-click ranges *from* — the last box the user actually\n * toggled. Held in a ref rather than state because it changes nothing on\n * screen, and re-rendering the whole table on every click to remember an\n * anchor is a cost with no visible return.\n */\n const anchorIndex = useRef<number | undefined>(undefined);\n\n const setSelection = (next: EntitySelection<TEntity>) =>\n onSelectionChange?.(next);\n\n const toggleRow = (\n index: number,\n checked: boolean,\n shiftKey: boolean,\n current: EntitySelection<TEntity>,\n ) => {\n // A shift-click extends the last toggle across the rows *on this page*, in\n // the direction the user dragged, and applies the new state to all of them.\n const from = shiftKey ? (anchorIndex.current ?? index) : index;\n const [start, end] = from <= index ? [from, index] : [index, from];\n\n let next = current;\n for (const row of items.slice(start, end + 1)) {\n next = toggleSelected(next, row.id, checked);\n }\n\n anchorIndex.current = index;\n setSelection(next);\n };\n\n /**\n * The header box, and it has three states rather than two: none of this\n * page's rows selected, all of them, or some. Without the third the box\n * reads as \"nothing is selected\" while a bulk bar sits below it saying\n * otherwise.\n */\n const pageIds = items.map(item => item.id);\n const selectedOnPage = selectionState\n ? pageIds.filter(id => isSelected(selectionState, id)).length\n : 0;\n const allOnPageSelected =\n pageIds.length > 0 && selectedOnPage === pageIds.length;\n const someOnPageSelected = selectedOnPage > 0 && !allOnPageSelected;\n\n const toggleAllOnPage = (\n checked: boolean,\n current: EntitySelection<TEntity>,\n ) => {\n let next = current;\n for (const id of pageIds) next = toggleSelected(next, id, checked);\n anchorIndex.current = undefined;\n setSelection(next);\n };\n\n /**\n * How a row names itself to a screen reader.\n *\n * The first visible column's value, because that is what the user reads the\n * row *as* — \"Seleccionar Acme\" rather than \"Seleccionar fila 3\", which tells\n * them the position they can already see and not the thing they cannot.\n */\n const rowLabel = (item: TEntity): string => {\n // The first non-identifier column **that this row actually filled in**.\n //\n // An id names a row the way \"row 3\" does: it repeats what the user can\n // already see. But skipping only the id is not enough — measured against\n // the seeded catalog, where `code` is the first non-id column and is empty\n // on every brand, so the label fell straight through to the id and never\n // reached `name`. A column that is blank on this row names it no better\n // than its position does, so the search continues past it.\n //\n // The id remains the last resort, because a row with nothing rendered\n // still has to announce itself.\n const named = visibleColumns.find(column => {\n if (column.type === 'id') return false;\n const value = (item as Record<string, unknown>)[column.name];\n return value != null && String(value) !== '';\n });\n\n return named\n ? String((item as Record<string, unknown>)[named.name])\n : String(item.id);\n };\n\n const selectionCell = (\n item: TEntity,\n index: number,\n // Passed in rather than closed over: this is only ever called under\n // `selectable`, which already proves the selection exists, and reading the\n // optional prop here would add a fallback arm that nothing can reach.\n current: EntitySelection<TEntity>,\n ) => (\n <Checkbox\n // Deliberately no `id`: both pivots are always in the DOM, so an id here\n // would be emitted twice per row. `aria-label` names the control instead,\n // and it names the *record* rather than the position.\n aria-label={t('table.selectRow', { record: rowLabel(item) })}\n checked={isSelected(current, item.id)}\n disabled={isBulkRunning}\n onChange={event =>\n toggleRow(\n index,\n event.currentTarget.checked,\n (event.nativeEvent as MouseEvent).shiftKey === true,\n current,\n )\n }\n />\n );\n\n const runTarget = (key: string, target: PendingTarget<TEntity>) => {\n if (target.kind === 'row') onUseCase?.(key, target.item);\n else onBulkUseCase?.(key, target.selection);\n };\n\n const invoke = (\n useCase: UseCaseDescriptor,\n target: PendingTarget<TEntity>,\n ) => {\n const confirm = useCase.confirm;\n if (confirm) {\n setPending({\n key: useCase.key,\n labelKey: useCase.labelKey,\n confirm,\n target,\n });\n return;\n }\n runTarget(useCase.key, target);\n };\n\n const rowMenu = (item: TEntity) =>\n hasRowMenu ? (\n <Menu>\n <Menu.Trigger aria-label={t('table.actions')}>\n {OVERFLOW_GLYPH}\n </Menu.Trigger>\n <Menu.Items>\n {rowUseCases.map(useCase => (\n <Menu.Item\n key={useCase.key}\n tone={\n useCase.confirm?.tone === 'destructive'\n ? 'destructive'\n : 'neutral'\n }\n onClick={() => invoke(useCase, { kind: 'row', item })}\n >\n {translateKey(useCase.labelKey)}\n </Menu.Item>\n ))}\n </Menu.Items>\n </Menu>\n ) : undefined;\n\n /**\n * Selection wins over navigation: a picker's row must set the value, not send\n * the user away from the form they came from.\n *\n * The row menu sits *beside* whichever of the two applies rather than\n * replacing it — \"open this record\" and \"run a verb on it\" are both true at\n * once, and folding the first into the menu would bury the action every row\n * of a list exists for.\n */\n const recordAction = (item: TEntity) => {\n const primary = onSelect ? (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => onSelect(item)}\n >\n {t('table.select')}\n </Button>\n ) : hrefFor ? (\n <Link href={hrefFor(item.id)}>{t('table.open')}</Link>\n ) : undefined;\n\n const menu = rowMenu(item);\n if (!menu) return primary;\n\n return (\n <span className=\"flex items-center gap-2xs\">\n {primary}\n {menu}\n </span>\n );\n };\n\n /**\n * \"No records\" is a statement about the data; after a failed load it would be\n * a lie about it. The distinction matters most to the user who is deciding\n * whether their catalog is empty or their backend is down.\n */\n const emptyMessage = error ? t('table.error') : t('table.empty');\n\n return (\n <div className=\"flex flex-col gap-s\">\n {/*\n One announcement for the whole table, not one per layout. Both the grid\n and the card list are always in the DOM — CSS picks which is visible —\n so a live region inside each meant assistive tech was told twice that\n the table was loading. The shimmer itself is aria-hidden, so this is the\n only thing that carries the news.\n */}\n <span role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n {isFirstLoad ? t('table.loading') : ''}\n </span>\n\n {showControls && (\n <TableToolbar\n start={\n <>\n {newHref && <Link href={newHref}>{t('table.new')}</Link>}\n {/* Collection-bound verbs that need no selection. They sit with\n `New` rather than in the bulk bar, because the bulk bar only\n exists while rows are ticked and these are always available. */}\n <LoadingBoundary isLoading={isMetadataLoading} lines={0}>\n <>\n {toolbarUseCases.map(useCase => (\n <Button\n key={useCase.key}\n type=\"button\"\n variant={\n useCase.confirm?.tone === 'destructive'\n ? 'destructive'\n : 'secondary'\n }\n size=\"sm\"\n disabled={isBulkRunning}\n onClick={() =>\n onBulkUseCase?.(useCase.key, everythingMatching)\n }\n >\n {translateKey(useCase.labelKey)}\n </Button>\n ))}\n </>\n </LoadingBoundary>\n {slots.toolbar}\n </>\n }\n end={\n <>\n <Button\n type=\"button\"\n variant={panel === 'filters' ? 'primary' : 'secondary'}\n size=\"sm\"\n onClick={() =>\n setPanel(current =>\n current === 'filters' ? 'none' : 'filters',\n )\n }\n >\n {t('table.filters')}\n </Button>\n <Button\n type=\"button\"\n variant={panel === 'sorting' ? 'primary' : 'secondary'}\n size=\"sm\"\n onClick={() =>\n setPanel(current =>\n current === 'sorting' ? 'none' : 'sorting',\n )\n }\n >\n {t('table.sorting')}\n </Button>\n <ColumnSettings\n columns={columns}\n hidden={hidden}\n onChange={setPersonalization}\n />\n </>\n }\n panel={\n panel === 'filters' ? (\n <FilterBuilder<TEntity>\n descriptors={columns.filter(column => column.filterable)}\n value={filtering}\n onChange={(applied: FilterGroup<TEntity>) =>\n onFilteringChange?.(applied)\n }\n />\n ) : panel === 'sorting' ? (\n <SortBuilder<TEntity>\n descriptors={columns.filter(column => column.sortable)}\n value={sorting}\n onChange={(applied: EntitySorting<TEntity>) =>\n onSortingChange?.(applied)\n }\n />\n ) : undefined\n }\n />\n )}\n\n {/*\n The bar appears when there is something selected and something to do\n with it. It sits above the rows rather than floating over them: a fixed\n overlay covers the last row of a short page, which is the row the user\n most likely just ticked.\n */}\n {selectionState && selectionSize(selectionState) > 0 && (\n <BulkActionBar\n count={selectionSize(selectionState)}\n useCases={bulkUseCases}\n busy={isBulkRunning}\n // Offered only when this page is fully ticked and the store holds\n // more than the page — the escalation has somewhere to escalate to.\n matchingTotal={\n selectionState.mode === 'ids' &&\n allOnPageSelected &&\n totalItems > items.length\n ? totalItems\n : undefined\n }\n onSelectAllMatching={() => setSelection(everythingMatching)}\n onClear={() => setSelection(emptySelection<TEntity>())}\n onUseCase={useCase =>\n invoke(useCase, { kind: 'selection', selection: selectionState })\n }\n />\n )}\n\n {pending && (\n <ConfirmDialog\n open\n tone={pending.confirm.tone}\n title={translateKey(pending.labelKey)}\n message={translateKey(pending.confirm.messageKey)}\n busy={isBulkRunning}\n onCancel={() => setPending(undefined)}\n onConfirm={() => {\n const { key, target } = pending;\n setPending(undefined);\n runTarget(key, target);\n }}\n />\n )}\n\n {bulkOutcomes && bulkOutcomes.length > 0 && onBulkDismiss && (\n <BulkResult\n outcomes={bulkOutcomes}\n busy={isBulkRunning}\n labelFor={id => {\n const row = items.find(item => item.id === id);\n return row ? rowLabel(row) : undefined;\n }}\n onRetryFailed={onBulkRetry}\n onDismiss={onBulkDismiss}\n />\n )}\n\n {/*\n Rendered once, outside both layouts, and independently of whether there\n are rows: a refetch that fails leaves the previous page on screen, and\n without this the user would read stale data as current.\n */}\n {error && (\n <p\n role=\"alert\"\n data-testid=\"entity-table-error\"\n className=\"rounded-sm border border-danger bg-danger-subtle px-s py-2xs text-step-sm text-danger\"\n >\n {errorMessage(error)}\n </p>\n )}\n\n {/* Wide viewports: a grid. */}\n <div className={`${pivot.grid} ${busyClass}`}>\n <Table>\n <TableHead>\n {slots.header ? (\n slots.header.render(visibleColumns)\n ) : (\n <tr>\n {selectable && (\n <TableHeaderCell>\n <Checkbox\n aria-label={t('table.selectAllOnPage')}\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n disabled={isBulkRunning || items.length === 0}\n onChange={event =>\n toggleAllOnPage(\n event.currentTarget.checked,\n selectionState,\n )\n }\n />\n </TableHeaderCell>\n )}\n {visibleColumns.map(column => (\n <TableHeaderCell key={column.name}>\n {column.header ?? column.label}\n </TableHeaderCell>\n ))}\n {hasRowAction && (\n <TableHeaderCell>{t('table.actions')}</TableHeaderCell>\n )}\n </tr>\n )}\n </TableHead>\n <TableBody aria-busy={isLoading || undefined}>\n {/* Skeleton rows rather than the word \"Loading\", and one per column\n rather than a single full-width blob: the placeholder occupies\n the real grid, so the swap to rows shifts nothing sideways.\n `TableMessageRow` is deliberately bypassed — it is one centred\n full-span cell and cannot express the geometry. */}\n {showSkeleton &&\n (customSkeleton ? (\n <TableMessageRow colSpan={columnCount}>\n {customSkeleton}\n </TableMessageRow>\n ) : (\n skeletonRows.map(row => (\n <TableRow key={row}>\n {selectable && (\n <TableCell>\n <Skeleton shape=\"line\" className=\"w-4\" />\n </TableCell>\n )}\n {visibleColumns.map(column => (\n <TableCell key={column.name}>\n <Skeleton shape=\"line\" className=\"w-full\" />\n </TableCell>\n ))}\n {hasRowAction && (\n <TableCell>\n <Skeleton shape=\"line\" className=\"w-16\" />\n </TableCell>\n )}\n </TableRow>\n ))\n ))}\n {!isLoading && items.length === 0 && (\n <TableMessageRow colSpan={columnCount}>\n {emptyMessage}\n </TableMessageRow>\n )}\n {items.map((item, index) =>\n slots.row ? (\n // A Fragment carries the key without wrapping the custom row in\n // an element `<tbody>` would reject.\n <Fragment key={String(item.id ?? index)}>\n {slots.row.render(item, visibleColumns)}\n </Fragment>\n ) : (\n <TableRow key={String(item.id ?? index)}>\n {selectionState && (\n <TableCell>\n {selectionCell(item, index, selectionState)}\n </TableCell>\n )}\n {visibleColumns.map(column => (\n <TableCell key={column.name}>\n {renderCell(column, item)}\n </TableCell>\n ))}\n {hasRowAction && <TableCell>{recordAction(item)}</TableCell>}\n </TableRow>\n ),\n )}\n </TableBody>\n </Table>\n </div>\n\n {/* Narrow viewports: the same columns pivoted into cards. */}\n <div\n className={`${pivot.cards} flex flex-col gap-2xs ${busyClass}`}\n aria-busy={isLoading || undefined}\n >\n {/* The card pivot gets card-shaped placeholders, not a bare shimmer\n block: the border, radius and padding are the geometry here. */}\n {showSkeleton &&\n (customSkeleton ??\n skeletonRows.map(row => (\n <EntityRecordCard\n key={row}\n columns={visibleColumns}\n renderCell={() => <Skeleton shape=\"line\" className=\"w-24\" />}\n />\n )))}\n {!isLoading && items.length === 0 && (\n <p className=\"text-step-sm text-content-muted\">{emptyMessage}</p>\n )}\n {items.map((item, index) => (\n <EntityRecordCard\n key={String(item.id ?? index)}\n columns={visibleColumns}\n // The card is handed the resolved columns themselves, so the\n // narrow layout goes through the exact same renderers as the grid.\n renderCell={column =>\n renderCell(column as EntityTableColumn<TEntity>, item)\n }\n leading={\n selectionState\n ? selectionCell(item, index, selectionState)\n : undefined\n }\n actions={recordAction(item)}\n />\n ))}\n </div>\n\n <Pagination\n currentPage={currentPage}\n pageSize={pageSize}\n totalItems={totalItems}\n onPageChange={onPageChange}\n onPageSizeChange={onPageSizeChange}\n />\n\n {slots.rest}\n </div>\n );\n}\n"],"names":["emptySelection","EntifixLogicError","extractMetaEntity","isSelected","selectionSize","toggleSelected","Fragment","useRef","useState","useErrorMessage","useT","useTranslateKey","OVERFLOW_GLYPH","useCasesForSurface","Button","CellValue","Checkbox","Skeleton","Table","TableBody","TableCell","TableHead","TableHeaderCell","TableMessageRow","TableRow","Link","BulkActionBar","BulkResult","ColumnSettings","ConfirmDialog","EntityRecordCard","FilterBuilder","LoadingBoundary","Menu","Pagination","SortBuilder","TableToolbar","readEntityTableSlots","useEntityTableColumns","PIVOT_CLASS","sm","grid","cards","md","lg","SKELETON_ROW_CAP","EntityTable","entityConstructor","isLoading","skeleton","error","items","totalItems","currentPage","pageSize","onPageChange","onPageSizeChange","hrefFor","newHref","onSelect","preferencesKey","showControls","pivotBreakpoint","filtering","sorting","onFilteringChange","onSortingChange","selection","onSelectionChange","metadata","isMetadataLoading","onBulkUseCase","onUseCase","bulkOutcomes","onBulkDismiss","onBulkRetry","isBulkRunning","children","t","translateKey","errorMessage","metaEntity","slots","panel","setPanel","pending","setPending","undefined","columns","visibleColumns","hidden","setPersonalization","key","name","pivot","selectionState","selectable","rowUseCases","useCases","bulkUseCases","toolbarUseCases","hasRowMenu","length","everythingMatching","mode","total","excluded","Set","hasRowAction","columnCount","isFirstLoad","isRefetching","customSkeleton","showSkeleton","skeletonRows","Array","from","Math","min","_","index","busyClass","renderCell","column","item","render","value","descriptor","anchorIndex","setSelection","next","toggleRow","checked","shiftKey","current","start","end","row","slice","id","pageIds","map","selectedOnPage","filter","allOnPageSelected","someOnPageSelected","toggleAllOnPage","rowLabel","named","find","type","String","selectionCell","aria-label","record","disabled","onChange","event","currentTarget","nativeEvent","runTarget","target","kind","invoke","useCase","confirm","labelKey","rowMenu","Trigger","Items","Item","tone","onClick","recordAction","primary","variant","size","href","menu","span","className","emptyMessage","div","role","aria-live","lines","toolbar","descriptors","filterable","applied","sortable","count","busy","matchingTotal","onSelectAllMatching","onClear","open","title","message","messageKey","onCancel","onConfirm","outcomes","labelFor","onRetryFailed","onDismiss","p","data-testid","header","tr","indeterminate","label","aria-busy","colSpan","shape","leading","actions","rest"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/ui/organisms/entity-table/entity-table.tsx"],"sourcesContent":["'use client';\n\nimport {\n emptySelection,\n EntifixLogicError,\n type Entity,\n type EntityId,\n type EntitySelection,\n type EntitySorting,\n extractMetaEntity,\n type FilterGroup,\n isSelected,\n selectionSize,\n toggleSelected,\n type UseCaseDescriptor,\n} from '@entifix/core';\nimport { Fragment, type ReactNode, useRef, useState } from 'react';\n\nimport { useErrorMessage, useT, useTranslateKey } from '../../../i18n/index.js';\nimport {\n OVERFLOW_GLYPH,\n renderAnchor,\n useCasesForSurface,\n} from '../../actions/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { CellValue } from '../../atoms/cell-value/index.js';\nimport { Checkbox } from '../../atoms/field/index.js';\nimport { Skeleton } from '../../atoms/skeleton/index.js';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeaderCell,\n TableMessageRow,\n TableRow,\n} from '../../atoms/table/index.js';\nimport { linkClassName } from '../../atoms/text/index.js';\nimport { BulkActionBar } from '../../molecules/bulk-action-bar/index.js';\nimport { BulkResult } from '../../molecules/bulk-result/index.js';\nimport { ColumnSettings } from '../../molecules/column-settings/index.js';\nimport { ConfirmDialog } from '../../molecules/confirm-dialog/index.js';\nimport { EntityRecordCard } from '../../molecules/entity-record-card/index.js';\nimport { FilterBuilder } from '../../molecules/filter-builder/index.js';\nimport { LoadingBoundary } from '../../molecules/loading-boundary/index.js';\nimport { Menu } from '../../molecules/menu/index.js';\nimport { Pagination } from '../../molecules/pagination/index.js';\nimport { SortBuilder } from '../../molecules/sort-builder/index.js';\nimport { TableToolbar } from '../../molecules/table-toolbar/index.js';\nimport type {\n EntityTableColumn,\n EntityTablePivotBreakpoint,\n EntityTableProps,\n} from './entity-table.types.js';\nimport { readEntityTableSlots } from './entity-table-slots.js';\nimport { useEntityTableColumns } from './use-entity-table-columns.js';\n\n/**\n * The grid and the card list are both rendered, and CSS picks one. A JS\n * breakpoint hook would have to guess during SSR and correct after mount —\n * a hydration mismatch on every page load. Classes are written out in full\n * because Tailwind cannot see a class name that is concatenated at runtime.\n */\nconst PIVOT_CLASS: Record<\n EntityTablePivotBreakpoint,\n { grid: string; cards: string }\n> = {\n sm: { grid: 'hidden sm:block', cards: 'sm:hidden' },\n md: { grid: 'hidden md:block', cards: 'md:hidden' },\n lg: { grid: 'hidden lg:block', cards: 'lg:hidden' },\n};\n\ntype Panel = 'none' | 'filters' | 'sorting';\n\n/**\n * How many placeholder rows the built-in skeleton draws.\n *\n * The column count is taken from the real geometry, because that is the axis a\n * mismatch shifts; the row count is capped instead of tracking `pageSize`, since\n * a fifty-row page would otherwise paint fifty shimmer rows to stand in for\n * content that arrives below the fold anyway.\n */\nconst SKELETON_ROW_CAP = 5;\n\n/**\n * A table that builds itself from an entity's metadata: columns, labels, value\n * formatting and the filter/sort controls all come from `@accessor()`\n * declarations, so listing a new entity needs no bespoke table.\n *\n * Three things layer on top of that default:\n * - **personalization** — column order and visibility, persisted through the\n * UI-preferences port (so it survives reloads and can later move server-side);\n * - **responsiveness** — below `pivotBreakpoint` rows pivot into label/value\n * cards instead of scrolling sideways;\n * - **slots** — `<EntityColumn>` / `<EntityTableHeader>` / `<EntityTableRow>` /\n * `<EntityTableToolbar>` children override any part of the default rendering.\n */\n/**\n * What a pending verb will act on once it is confirmed.\n *\n * A form has one record; a table has a row or a selection, and those reach two\n * different handlers with two different payloads. Carrying the selection itself\n * rather than reading it back at confirm time also removes a branch that could\n * not happen: the bulk bar only renders inside a truthy selection.\n */\ntype PendingTarget<TEntity extends Entity> =\n | { kind: 'row'; item: TEntity }\n | { kind: 'selection'; selection: EntitySelection<TEntity> };\n\nexport function EntityTable<TEntity extends Entity>({\n entityConstructor,\n isLoading,\n skeleton = true,\n error,\n items,\n totalItems,\n currentPage,\n pageSize,\n onPageChange,\n onPageSizeChange,\n hrefFor,\n newHref,\n renderLink = renderAnchor,\n onSelect,\n preferencesKey,\n showControls = true,\n pivotBreakpoint = 'md',\n filtering,\n sorting,\n onFilteringChange,\n onSortingChange,\n selection,\n onSelectionChange,\n metadata,\n isMetadataLoading = false,\n onBulkUseCase,\n onUseCase,\n bulkOutcomes,\n onBulkDismiss,\n onBulkRetry,\n isBulkRunning = false,\n children,\n}: EntityTableProps<TEntity>) {\n const t = useT();\n // A descriptor's label is a runtime catalog key — the typed gate cannot see\n // it, which is why `@r10c/i18n-check` is what catches a typo.\n const translateKey = useTranslateKey();\n const errorMessage = useErrorMessage();\n const metaEntity = extractMetaEntity(entityConstructor);\n const slots = readEntityTableSlots<TEntity>(children);\n const [panel, setPanel] = useState<Panel>('none');\n\n /**\n * A verb waiting to be confirmed, and what it will act on.\n *\n * ⚠️ **The table had no confirmation flow at all** until #216 moved a\n * destructive verb onto it. It read `confirm.tone` — only to pick a tone for\n * a button or a menu item — and then fired on the first click. `unpublish` is\n * declared `destructive`, so a verb reachable from a row menu without this\n * would have been a one-click unpublish with a red label explaining what had\n * already happened.\n *\n * The state holds the confirmation itself rather than the descriptor, so the\n * dialog cannot open for a verb that never asked for one — the same shape\n * `EntityForm` uses, and for the same reason.\n *\n * It carries the **target** too, which the form's does not need: a form has\n * one record and a table has a row or a selection, and those run through two\n * different handlers with two different payloads.\n */\n const [pending, setPending] = useState<\n | {\n key: string;\n labelKey: string;\n confirm: NonNullable<UseCaseDescriptor['confirm']>;\n target: PendingTarget<TEntity>;\n }\n | undefined\n >(undefined);\n\n const { columns, visibleColumns, hidden, setPersonalization } =\n useEntityTableColumns<TEntity>(\n entityConstructor,\n slots.columns,\n items[0],\n `entity-table:${preferencesKey ?? metaEntity.key ?? metaEntity.name}`,\n );\n\n const pivot = PIVOT_CLASS[pivotBreakpoint];\n\n // A picker's table is choosing *one* value; a multi-selection there would\n // offer a set to a form member that holds a single reference, and the two\n // controls would fight over the same row. This is a wiring mistake rather\n // than a state, so it costs the render — the same call `EntityForm` makes\n // for a link source aimed at a member no picker can edit.\n if (onSelect !== undefined && selection !== undefined) {\n throw new EntifixLogicError(\n 'EntityTable was given both `onSelect` and `selection`. A picker picks one ' +\n 'row and a selection accumulates many, so the row control cannot be both. ' +\n 'Drop `selection` inside a picker, or drop `onSelect` outside one.',\n );\n }\n\n /**\n * The selection, or `undefined` when the table is not selectable at all.\n *\n * One value rather than a `selection` prop beside a `selectable` boolean:\n * two of them means every render site has to re-test both, and the second\n * test is unreachable — which reads as a defensive check and is really dead\n * code the coverage gate then cannot close.\n */\n const selectionState =\n selection !== undefined && onSelectionChange !== undefined\n ? selection\n : undefined;\n const selectable = selectionState !== undefined;\n const rowUseCases = useCasesForSurface('row-menu', metadata?.useCases);\n const bulkUseCases = useCasesForSurface('bulk-bar', metadata?.useCases);\n const toolbarUseCases = useCasesForSurface(\n 'table-toolbar',\n metadata?.useCases,\n );\n const hasRowMenu = rowUseCases.length > 0 && onUseCase !== undefined;\n\n /**\n * What a `context-independent` collection verb acts on: everything the\n * current filter matches.\n *\n * Not an empty `ids` selection, which would say \"no rows\" — the verb is\n * available *without* a selection precisely because its subject is the\n * collection, so the honest payload is the same filter the listing is\n * showing, and the same one a \"select all matching\" escalation would send.\n */\n const everythingMatching: EntitySelection<TEntity> = {\n mode: 'matching',\n filtering,\n total: totalItems,\n excluded: new Set<EntityId>(),\n };\n\n const hasRowAction =\n onSelect !== undefined || hrefFor !== undefined || hasRowMenu;\n const columnCount =\n visibleColumns.length + (hasRowAction ? 1 : 0) + (selectable ? 1 : 0);\n\n /**\n * The first load has nothing to show and is held with a skeleton; a refetch\n * already has rows, so it keeps them and only marks the region busy. Splitting\n * the two is what stops every pagination click flashing grey.\n */\n const isFirstLoad = isLoading && items.length === 0;\n const isRefetching = isLoading && items.length > 0;\n\n /** `true`/omitted → the built-in default; a node → that node; `false` → none. */\n const customSkeleton = typeof skeleton === 'boolean' ? undefined : skeleton;\n const showSkeleton = isFirstLoad && skeleton !== false;\n const skeletonRows = Array.from(\n { length: Math.min(pageSize, SKELETON_ROW_CAP) },\n (_, index) => index,\n );\n\n /**\n * The refetch hint, and it is deliberately the only one: rows stay readable\n * and simply dim, because a second skeleton over live data would be two\n * loading signals in one region.\n */\n const busyClass = isRefetching\n ? 'opacity-60 transition-opacity duration-200 ease-smooth'\n : '';\n\n const renderCell = (\n column: EntityTableColumn<TEntity>,\n item: TEntity,\n ): ReactNode =>\n column.render ? (\n column.render(item)\n ) : (\n <CellValue\n value={(item as Record<string, unknown>)[column.name]}\n descriptor={column}\n />\n );\n\n /**\n * The row a shift-click ranges *from* — the last box the user actually\n * toggled. Held in a ref rather than state because it changes nothing on\n * screen, and re-rendering the whole table on every click to remember an\n * anchor is a cost with no visible return.\n */\n const anchorIndex = useRef<number | undefined>(undefined);\n\n const setSelection = (next: EntitySelection<TEntity>) =>\n onSelectionChange?.(next);\n\n const toggleRow = (\n index: number,\n checked: boolean,\n shiftKey: boolean,\n current: EntitySelection<TEntity>,\n ) => {\n // A shift-click extends the last toggle across the rows *on this page*, in\n // the direction the user dragged, and applies the new state to all of them.\n const from = shiftKey ? (anchorIndex.current ?? index) : index;\n const [start, end] = from <= index ? [from, index] : [index, from];\n\n let next = current;\n for (const row of items.slice(start, end + 1)) {\n next = toggleSelected(next, row.id, checked);\n }\n\n anchorIndex.current = index;\n setSelection(next);\n };\n\n /**\n * The header box, and it has three states rather than two: none of this\n * page's rows selected, all of them, or some. Without the third the box\n * reads as \"nothing is selected\" while a bulk bar sits below it saying\n * otherwise.\n */\n const pageIds = items.map(item => item.id);\n const selectedOnPage = selectionState\n ? pageIds.filter(id => isSelected(selectionState, id)).length\n : 0;\n const allOnPageSelected =\n pageIds.length > 0 && selectedOnPage === pageIds.length;\n const someOnPageSelected = selectedOnPage > 0 && !allOnPageSelected;\n\n const toggleAllOnPage = (\n checked: boolean,\n current: EntitySelection<TEntity>,\n ) => {\n let next = current;\n for (const id of pageIds) next = toggleSelected(next, id, checked);\n anchorIndex.current = undefined;\n setSelection(next);\n };\n\n /**\n * How a row names itself to a screen reader.\n *\n * The first visible column's value, because that is what the user reads the\n * row *as* — \"Seleccionar Acme\" rather than \"Seleccionar fila 3\", which tells\n * them the position they can already see and not the thing they cannot.\n */\n const rowLabel = (item: TEntity): string => {\n // The first non-identifier column **that this row actually filled in**.\n //\n // An id names a row the way \"row 3\" does: it repeats what the user can\n // already see. But skipping only the id is not enough — measured against\n // the seeded catalog, where `code` is the first non-id column and is empty\n // on every brand, so the label fell straight through to the id and never\n // reached `name`. A column that is blank on this row names it no better\n // than its position does, so the search continues past it.\n //\n // The id remains the last resort, because a row with nothing rendered\n // still has to announce itself.\n const named = visibleColumns.find(column => {\n if (column.type === 'id') return false;\n const value = (item as Record<string, unknown>)[column.name];\n return value != null && String(value) !== '';\n });\n\n return named\n ? String((item as Record<string, unknown>)[named.name])\n : String(item.id);\n };\n\n const selectionCell = (\n item: TEntity,\n index: number,\n // Passed in rather than closed over: this is only ever called under\n // `selectable`, which already proves the selection exists, and reading the\n // optional prop here would add a fallback arm that nothing can reach.\n current: EntitySelection<TEntity>,\n ) => (\n <Checkbox\n // Deliberately no `id`: both pivots are always in the DOM, so an id here\n // would be emitted twice per row. `aria-label` names the control instead,\n // and it names the *record* rather than the position.\n aria-label={t('table.selectRow', { record: rowLabel(item) })}\n checked={isSelected(current, item.id)}\n disabled={isBulkRunning}\n onChange={event =>\n toggleRow(\n index,\n event.currentTarget.checked,\n (event.nativeEvent as MouseEvent).shiftKey === true,\n current,\n )\n }\n />\n );\n\n const runTarget = (key: string, target: PendingTarget<TEntity>) => {\n if (target.kind === 'row') onUseCase?.(key, target.item);\n else onBulkUseCase?.(key, target.selection);\n };\n\n const invoke = (\n useCase: UseCaseDescriptor,\n target: PendingTarget<TEntity>,\n ) => {\n const confirm = useCase.confirm;\n if (confirm) {\n setPending({\n key: useCase.key,\n labelKey: useCase.labelKey,\n confirm,\n target,\n });\n return;\n }\n runTarget(useCase.key, target);\n };\n\n const rowMenu = (item: TEntity) =>\n hasRowMenu ? (\n <Menu>\n <Menu.Trigger aria-label={t('table.actions')}>\n {OVERFLOW_GLYPH}\n </Menu.Trigger>\n <Menu.Items>\n {rowUseCases.map(useCase => (\n <Menu.Item\n key={useCase.key}\n tone={\n useCase.confirm?.tone === 'destructive'\n ? 'destructive'\n : 'neutral'\n }\n onClick={() => invoke(useCase, { kind: 'row', item })}\n >\n {translateKey(useCase.labelKey)}\n </Menu.Item>\n ))}\n </Menu.Items>\n </Menu>\n ) : undefined;\n\n /**\n * Selection wins over navigation: a picker's row must set the value, not send\n * the user away from the form they came from.\n *\n * The row menu sits *beside* whichever of the two applies rather than\n * replacing it — \"open this record\" and \"run a verb on it\" are both true at\n * once, and folding the first into the menu would bury the action every row\n * of a list exists for.\n */\n const recordAction = (item: TEntity) => {\n const primary = onSelect ? (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => onSelect(item)}\n >\n {t('table.select')}\n </Button>\n ) : hrefFor ? (\n renderLink({\n href: hrefFor(item.id),\n className: linkClassName,\n children: t('table.open'),\n intent: { kind: 'open', id: item.id },\n })\n ) : undefined;\n\n const menu = rowMenu(item);\n if (!menu) return primary;\n\n return (\n <span className=\"flex items-center gap-2xs\">\n {primary}\n {menu}\n </span>\n );\n };\n\n /**\n * \"No records\" is a statement about the data; after a failed load it would be\n * a lie about it. The distinction matters most to the user who is deciding\n * whether their catalog is empty or their backend is down.\n */\n const emptyMessage = error ? t('table.error') : t('table.empty');\n\n return (\n <div className=\"flex flex-col gap-s\">\n {/*\n One announcement for the whole table, not one per layout. Both the grid\n and the card list are always in the DOM — CSS picks which is visible —\n so a live region inside each meant assistive tech was told twice that\n the table was loading. The shimmer itself is aria-hidden, so this is the\n only thing that carries the news.\n */}\n <span role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n {isFirstLoad ? t('table.loading') : ''}\n </span>\n\n {showControls && (\n <TableToolbar\n start={\n <>\n {newHref &&\n renderLink({\n href: newHref,\n className: linkClassName,\n children: t('table.new'),\n intent: { kind: 'new' },\n })}\n {/* Collection-bound verbs that need no selection. They sit with\n `New` rather than in the bulk bar, because the bulk bar only\n exists while rows are ticked and these are always available. */}\n <LoadingBoundary isLoading={isMetadataLoading} lines={0}>\n <>\n {toolbarUseCases.map(useCase => (\n <Button\n key={useCase.key}\n type=\"button\"\n variant={\n useCase.confirm?.tone === 'destructive'\n ? 'destructive'\n : 'secondary'\n }\n size=\"sm\"\n disabled={isBulkRunning}\n onClick={() =>\n onBulkUseCase?.(useCase.key, everythingMatching)\n }\n >\n {translateKey(useCase.labelKey)}\n </Button>\n ))}\n </>\n </LoadingBoundary>\n {slots.toolbar}\n </>\n }\n end={\n <>\n <Button\n type=\"button\"\n variant={panel === 'filters' ? 'primary' : 'secondary'}\n size=\"sm\"\n onClick={() =>\n setPanel(current =>\n current === 'filters' ? 'none' : 'filters',\n )\n }\n >\n {t('table.filters')}\n </Button>\n <Button\n type=\"button\"\n variant={panel === 'sorting' ? 'primary' : 'secondary'}\n size=\"sm\"\n onClick={() =>\n setPanel(current =>\n current === 'sorting' ? 'none' : 'sorting',\n )\n }\n >\n {t('table.sorting')}\n </Button>\n <ColumnSettings\n columns={columns}\n hidden={hidden}\n onChange={setPersonalization}\n />\n </>\n }\n panel={\n panel === 'filters' ? (\n <FilterBuilder<TEntity>\n descriptors={columns.filter(column => column.filterable)}\n value={filtering}\n onChange={(applied: FilterGroup<TEntity>) =>\n onFilteringChange?.(applied)\n }\n />\n ) : panel === 'sorting' ? (\n <SortBuilder<TEntity>\n descriptors={columns.filter(column => column.sortable)}\n value={sorting}\n onChange={(applied: EntitySorting<TEntity>) =>\n onSortingChange?.(applied)\n }\n />\n ) : undefined\n }\n />\n )}\n\n {/*\n The bar appears when there is something selected and something to do\n with it. It sits above the rows rather than floating over them: a fixed\n overlay covers the last row of a short page, which is the row the user\n most likely just ticked.\n */}\n {selectionState && selectionSize(selectionState) > 0 && (\n <BulkActionBar\n count={selectionSize(selectionState)}\n useCases={bulkUseCases}\n busy={isBulkRunning}\n // Offered only when this page is fully ticked and the store holds\n // more than the page — the escalation has somewhere to escalate to.\n matchingTotal={\n selectionState.mode === 'ids' &&\n allOnPageSelected &&\n totalItems > items.length\n ? totalItems\n : undefined\n }\n onSelectAllMatching={() => setSelection(everythingMatching)}\n onClear={() => setSelection(emptySelection<TEntity>())}\n onUseCase={useCase =>\n invoke(useCase, { kind: 'selection', selection: selectionState })\n }\n />\n )}\n\n {pending && (\n <ConfirmDialog\n open\n tone={pending.confirm.tone}\n title={translateKey(pending.labelKey)}\n message={translateKey(pending.confirm.messageKey)}\n busy={isBulkRunning}\n onCancel={() => setPending(undefined)}\n onConfirm={() => {\n const { key, target } = pending;\n setPending(undefined);\n runTarget(key, target);\n }}\n />\n )}\n\n {bulkOutcomes && bulkOutcomes.length > 0 && onBulkDismiss && (\n <BulkResult\n outcomes={bulkOutcomes}\n busy={isBulkRunning}\n labelFor={id => {\n const row = items.find(item => item.id === id);\n return row ? rowLabel(row) : undefined;\n }}\n onRetryFailed={onBulkRetry}\n onDismiss={onBulkDismiss}\n />\n )}\n\n {/*\n Rendered once, outside both layouts, and independently of whether there\n are rows: a refetch that fails leaves the previous page on screen, and\n without this the user would read stale data as current.\n */}\n {error && (\n <p\n role=\"alert\"\n data-testid=\"entity-table-error\"\n className=\"rounded-sm border border-danger bg-danger-subtle px-s py-2xs text-step-sm text-danger\"\n >\n {errorMessage(error)}\n </p>\n )}\n\n {/* Wide viewports: a grid. */}\n <div className={`${pivot.grid} ${busyClass}`}>\n <Table>\n <TableHead>\n {slots.header ? (\n slots.header.render(visibleColumns)\n ) : (\n <tr>\n {selectable && (\n <TableHeaderCell>\n <Checkbox\n aria-label={t('table.selectAllOnPage')}\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n disabled={isBulkRunning || items.length === 0}\n onChange={event =>\n toggleAllOnPage(\n event.currentTarget.checked,\n selectionState,\n )\n }\n />\n </TableHeaderCell>\n )}\n {visibleColumns.map(column => (\n <TableHeaderCell key={column.name}>\n {column.header ?? column.label}\n </TableHeaderCell>\n ))}\n {hasRowAction && (\n <TableHeaderCell>{t('table.actions')}</TableHeaderCell>\n )}\n </tr>\n )}\n </TableHead>\n <TableBody aria-busy={isLoading || undefined}>\n {/* Skeleton rows rather than the word \"Loading\", and one per column\n rather than a single full-width blob: the placeholder occupies\n the real grid, so the swap to rows shifts nothing sideways.\n `TableMessageRow` is deliberately bypassed — it is one centred\n full-span cell and cannot express the geometry. */}\n {showSkeleton &&\n (customSkeleton ? (\n <TableMessageRow colSpan={columnCount}>\n {customSkeleton}\n </TableMessageRow>\n ) : (\n skeletonRows.map(row => (\n <TableRow key={row}>\n {selectable && (\n <TableCell>\n <Skeleton shape=\"line\" className=\"w-4\" />\n </TableCell>\n )}\n {visibleColumns.map(column => (\n <TableCell key={column.name}>\n <Skeleton shape=\"line\" className=\"w-full\" />\n </TableCell>\n ))}\n {hasRowAction && (\n <TableCell>\n <Skeleton shape=\"line\" className=\"w-16\" />\n </TableCell>\n )}\n </TableRow>\n ))\n ))}\n {!isLoading && items.length === 0 && (\n <TableMessageRow colSpan={columnCount}>\n {emptyMessage}\n </TableMessageRow>\n )}\n {items.map((item, index) =>\n slots.row ? (\n // A Fragment carries the key without wrapping the custom row in\n // an element `<tbody>` would reject.\n <Fragment key={String(item.id ?? index)}>\n {slots.row.render(item, visibleColumns)}\n </Fragment>\n ) : (\n <TableRow key={String(item.id ?? index)}>\n {selectionState && (\n <TableCell>\n {selectionCell(item, index, selectionState)}\n </TableCell>\n )}\n {visibleColumns.map(column => (\n <TableCell key={column.name}>\n {renderCell(column, item)}\n </TableCell>\n ))}\n {hasRowAction && <TableCell>{recordAction(item)}</TableCell>}\n </TableRow>\n ),\n )}\n </TableBody>\n </Table>\n </div>\n\n {/* Narrow viewports: the same columns pivoted into cards. */}\n <div\n className={`${pivot.cards} flex flex-col gap-2xs ${busyClass}`}\n aria-busy={isLoading || undefined}\n >\n {/* The card pivot gets card-shaped placeholders, not a bare shimmer\n block: the border, radius and padding are the geometry here. */}\n {showSkeleton &&\n (customSkeleton ??\n skeletonRows.map(row => (\n <EntityRecordCard\n key={row}\n columns={visibleColumns}\n renderCell={() => <Skeleton shape=\"line\" className=\"w-24\" />}\n />\n )))}\n {!isLoading && items.length === 0 && (\n <p className=\"text-step-sm text-content-muted\">{emptyMessage}</p>\n )}\n {items.map((item, index) => (\n <EntityRecordCard\n key={String(item.id ?? index)}\n columns={visibleColumns}\n // The card is handed the resolved columns themselves, so the\n // narrow layout goes through the exact same renderers as the grid.\n renderCell={column =>\n renderCell(column as EntityTableColumn<TEntity>, item)\n }\n leading={\n selectionState\n ? selectionCell(item, index, selectionState)\n : undefined\n }\n actions={recordAction(item)}\n />\n ))}\n </div>\n\n <Pagination\n currentPage={currentPage}\n pageSize={pageSize}\n totalItems={totalItems}\n onPageChange={onPageChange}\n onPageSizeChange={onPageSizeChange}\n />\n\n {slots.rest}\n </div>\n );\n}\n"],"names":["emptySelection","EntifixLogicError","extractMetaEntity","isSelected","selectionSize","toggleSelected","Fragment","useRef","useState","useErrorMessage","useT","useTranslateKey","OVERFLOW_GLYPH","renderAnchor","useCasesForSurface","Button","CellValue","Checkbox","Skeleton","Table","TableBody","TableCell","TableHead","TableHeaderCell","TableMessageRow","TableRow","linkClassName","BulkActionBar","BulkResult","ColumnSettings","ConfirmDialog","EntityRecordCard","FilterBuilder","LoadingBoundary","Menu","Pagination","SortBuilder","TableToolbar","readEntityTableSlots","useEntityTableColumns","PIVOT_CLASS","sm","grid","cards","md","lg","SKELETON_ROW_CAP","EntityTable","entityConstructor","isLoading","skeleton","error","items","totalItems","currentPage","pageSize","onPageChange","onPageSizeChange","hrefFor","newHref","renderLink","onSelect","preferencesKey","showControls","pivotBreakpoint","filtering","sorting","onFilteringChange","onSortingChange","selection","onSelectionChange","metadata","isMetadataLoading","onBulkUseCase","onUseCase","bulkOutcomes","onBulkDismiss","onBulkRetry","isBulkRunning","children","t","translateKey","errorMessage","metaEntity","slots","panel","setPanel","pending","setPending","undefined","columns","visibleColumns","hidden","setPersonalization","key","name","pivot","selectionState","selectable","rowUseCases","useCases","bulkUseCases","toolbarUseCases","hasRowMenu","length","everythingMatching","mode","total","excluded","Set","hasRowAction","columnCount","isFirstLoad","isRefetching","customSkeleton","showSkeleton","skeletonRows","Array","from","Math","min","_","index","busyClass","renderCell","column","item","render","value","descriptor","anchorIndex","setSelection","next","toggleRow","checked","shiftKey","current","start","end","row","slice","id","pageIds","map","selectedOnPage","filter","allOnPageSelected","someOnPageSelected","toggleAllOnPage","rowLabel","named","find","type","String","selectionCell","aria-label","record","disabled","onChange","event","currentTarget","nativeEvent","runTarget","target","kind","invoke","useCase","confirm","labelKey","rowMenu","Trigger","Items","Item","tone","onClick","recordAction","primary","variant","size","href","className","intent","menu","span","emptyMessage","div","role","aria-live","lines","toolbar","descriptors","filterable","applied","sortable","count","busy","matchingTotal","onSelectAllMatching","onClear","open","title","message","messageKey","onCancel","onConfirm","outcomes","labelFor","onRetryFailed","onDismiss","p","data-testid","header","tr","indeterminate","label","aria-busy","colSpan","shape","leading","actions","rest"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { BulkOutcome, EntifixError, Entity, EntityConstructor, EntityFieldDescriptor, EntityId, EntityMetadataDocument, EntitySelection, EntitySorting, FilterGroup } from '@entifix/core';
2
2
  import type { ReactNode } from 'react';
3
+ import type { RenderLink } from '../../actions/index.js';
3
4
  /**
4
5
  * A column as the table finally renders it: the metadata descriptor plus the
5
6
  * per-column overrides a caller supplied through an `<EntityColumn>` slot.
@@ -59,6 +60,12 @@ export interface EntityTableProps<TEntity extends Entity> {
59
60
  hrefFor?: (id: EntityId) => string;
60
61
  /** Link to the create form. Omit and no `New` action is rendered. */
61
62
  newHref?: string;
63
+ /**
64
+ * Renders the `Open` and `New` links. Defaults to a plain anchor, which a
65
+ * client-routed host experiences as a full document load — pass one built on
66
+ * the host's own link component. See {@link RenderLink}.
67
+ */
68
+ renderLink?: RenderLink;
62
69
  /**
63
70
  * Picks a row instead of navigating to it — how a link picker reuses this
64
71
  * table as its browse dialog.
@@ -1 +1 @@
1
- {"version":3,"file":"entity-table.types.d.ts","sourceRoot":"","sources":["../../../../src/ui/organisms/entity-table/entity-table.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,MAAM,EACN,iBAAiB,EACjB,qBAAqB,EACrB,QAAQ,EACR,sBAAsB,EACtB,eAAe,EACf,aAAa,EACb,WAAW,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAChC,OAAO,SAAS,MAAM,CACtB,SAAQ,qBAAqB;IAC7B,wCAAwC;IACxC,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,SAAS,CAAC;IACtC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,+EAA+E;AAC/E,MAAM,MAAM,0BAA0B,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5D,MAAM,WAAW,gBAAgB,CAAC,OAAO,SAAS,MAAM;IACtD;oDACgD;IAChD,iBAAiB,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAE9C,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,gBAAgB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjD;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,MAAM,CAAC;IACnC,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAEnC,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,0BAA0B,CAAC;IAE7C;uDACmD;IACnD,SAAS,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IACjC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAEjC;sDACkD;IAClD,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAC9D,+CAA+C;IAC/C,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAE5D;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACrC,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAElE;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,6DAA6D;IAC7D,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAC3E,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAEjD,0EAA0E;IAC1E,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IACxC,oEAAoE;IACpE,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB"}
1
+ {"version":3,"file":"entity-table.types.d.ts","sourceRoot":"","sources":["../../../../src/ui/organisms/entity-table/entity-table.types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/organisms/entity-table/entity-table.types.ts"],"sourcesContent":["import type {\n BulkOutcome,\n EntifixError,\n Entity,\n EntityConstructor,\n EntityFieldDescriptor,\n EntityId,\n EntityMetadataDocument,\n EntitySelection,\n EntitySorting,\n FilterGroup,\n} from '@entifix/core';\nimport type { ReactNode } from 'react';\n\n/**\n * A column as the table finally renders it: the metadata descriptor plus the\n * per-column overrides a caller supplied through an `<EntityColumn>` slot.\n */\nexport interface EntityTableColumn<\n TEntity extends Entity,\n> extends EntityFieldDescriptor {\n /** Replaces the default header text. */\n header?: ReactNode;\n /** Replaces the default `CellValue` rendering for this column. */\n render?: (item: TEntity) => ReactNode;\n /** True when the column has no backing entity member (slot-only column). */\n virtual?: boolean;\n}\n\n/** Breakpoint at and above which the table renders as a grid, not as cards. */\nexport type EntityTablePivotBreakpoint = 'sm' | 'md' | 'lg';\n\nexport interface EntityTableProps<TEntity extends Entity> {\n /** Metadata source. Columns, labels, types and the filter/sort controls all\n * derive from this constructor's accessors. */\n entityConstructor: EntityConstructor<TEntity>;\n\n isLoading: boolean;\n /**\n * What holds the table's shape during the first load.\n *\n * `true` (the default) renders the built-in placeholder, which is derived from\n * the table's own resolved geometry — one shimmer cell per visible column, so\n * the swap to real rows shifts nothing. A node replaces that default; `false`\n * renders no placeholder at all.\n *\n * Only the *first* load is held this way. A refetch that already has rows\n * keeps them and marks the region busy instead — replacing populated rows with\n * shimmer on every pagination click is a grey flash, not a loading state.\n */\n skeleton?: boolean | ReactNode;\n /**\n * The failure of the last load, if it failed.\n *\n * A listing that renders an empty table when the service is unreachable tells\n * the user their catalog is empty — the one thing they must not conclude. So\n * this is rendered as an alert, and it also changes the empty message.\n *\n * It arrives for free from `useDataLoading`, whose whole state is spread into\n * this component.\n */\n error?: EntifixError;\n items: ReadonlyArray<TEntity>;\n totalItems: number;\n currentPage: number;\n pageSize: number;\n onPageChange: (newPage: number) => void;\n onPageSizeChange?: (newPageSize: number) => void;\n\n /**\n * Builds the link to a row's record. Supplied as a function rather than the\n * table routing by itself: this package must not depend on a router, so the\n * caller (a shell page, which does know one) owns the URL shape.\n *\n * Omit it and the actions column is not rendered at all.\n */\n hrefFor?: (id: EntityId) => string;\n /** Link to the create form. Omit and no `New` action is rendered. */\n newHref?: string;\n\n /**\n * Picks a row instead of navigating to it — how a link picker reuses this\n * table as its browse dialog.\n *\n * Takes precedence over {@link hrefFor}: inside a picker the user is choosing\n * a value, and offering to navigate away from the form they are editing is the\n * wrong affordance. Either one renders the actions column.\n */\n onSelect?: (item: TEntity) => void;\n\n /** Scope for persisted personalization. Defaults to the entity's key. */\n preferencesKey?: string;\n /** Hide the toolbar (columns, filters, sorting) — a bare listing. */\n showControls?: boolean;\n /** Viewport width at which rows stop pivoting into cards. Default `md`. */\n pivotBreakpoint?: EntityTablePivotBreakpoint;\n\n /** The filtering currently applied, seeding the filter panel so it shows\n * what is in effect rather than an empty form. */\n filtering?: FilterGroup<TEntity>;\n /** The sorting currently applied, seeding the sort panel. */\n sorting?: EntitySorting<TEntity>;\n\n /** Notified when the filter panel is **applied** — not while it is edited, so\n * the value can feed a load request directly. */\n onFilteringChange?: (filtering: FilterGroup<TEntity>) => void;\n /** Notified when the sort panel is applied. */\n onSortingChange?: (sorting: EntitySorting<TEntity>) => void;\n\n /**\n * The rows a collection-bound action would act on.\n *\n * **Controlled from above the table**, exactly as `filtering` and `sorting`\n * are, and for the same reason plus one more: a selection has to survive\n * pagination, and the page owns the pager. A selection held inside the table\n * would be reset by the very navigation the user performs to add to it.\n *\n * Omit it and no selection column is rendered — a listing that is only read\n * gains nothing from a column of empty boxes.\n */\n selection?: EntitySelection<TEntity>;\n onSelectionChange?: (selection: EntitySelection<TEntity>) => void;\n\n /**\n * What this caller may do with the entity, as the service decided it.\n *\n * The same document `EntityForm` takes. The table reads only the\n * `collection`-bound half of `useCases` — the entity-bound verbs belong to a\n * record, and a row's own overflow menu is fed from the\n * `context-dependent` ones.\n *\n * Absent keeps the pre-ADR-0026 behaviour: no bulk bar and no row menu, which\n * is what every un-migrated call site renders today.\n */\n metadata?: EntityMetadataDocument;\n isMetadataLoading?: boolean;\n\n /** Runs a `collection`-bound verb over {@link selection}. */\n onBulkUseCase?: (key: string, selection: EntitySelection<TEntity>) => void;\n /** Runs an `entity`-bound, `context-dependent` verb on one row. */\n onUseCase?: (key: string, item: TEntity) => void;\n\n /** The outcome of the last bulk run, rendered per row until dismissed. */\n bulkOutcomes?: readonly BulkOutcome[];\n onBulkDismiss?: () => void;\n onBulkRetry?: (ids: EntityId[]) => void;\n /** A bulk run is in flight — every verb is disabled while it is. */\n isBulkRunning?: boolean;\n\n /** Customization slots — see `entity-table-slots`. */\n children?: ReactNode;\n}\n"],"names":[],"mappings":"AAgCA,WAuHC"}
1
+ {"version":3,"sources":["../../../../src/ui/organisms/entity-table/entity-table.types.ts"],"sourcesContent":["import type {\n BulkOutcome,\n EntifixError,\n Entity,\n EntityConstructor,\n EntityFieldDescriptor,\n EntityId,\n EntityMetadataDocument,\n EntitySelection,\n EntitySorting,\n FilterGroup,\n} from '@entifix/core';\nimport type { ReactNode } from 'react';\n\nimport type { RenderLink } from '../../actions/index.js';\n\n/**\n * A column as the table finally renders it: the metadata descriptor plus the\n * per-column overrides a caller supplied through an `<EntityColumn>` slot.\n */\nexport interface EntityTableColumn<\n TEntity extends Entity,\n> extends EntityFieldDescriptor {\n /** Replaces the default header text. */\n header?: ReactNode;\n /** Replaces the default `CellValue` rendering for this column. */\n render?: (item: TEntity) => ReactNode;\n /** True when the column has no backing entity member (slot-only column). */\n virtual?: boolean;\n}\n\n/** Breakpoint at and above which the table renders as a grid, not as cards. */\nexport type EntityTablePivotBreakpoint = 'sm' | 'md' | 'lg';\n\nexport interface EntityTableProps<TEntity extends Entity> {\n /** Metadata source. Columns, labels, types and the filter/sort controls all\n * derive from this constructor's accessors. */\n entityConstructor: EntityConstructor<TEntity>;\n\n isLoading: boolean;\n /**\n * What holds the table's shape during the first load.\n *\n * `true` (the default) renders the built-in placeholder, which is derived from\n * the table's own resolved geometry — one shimmer cell per visible column, so\n * the swap to real rows shifts nothing. A node replaces that default; `false`\n * renders no placeholder at all.\n *\n * Only the *first* load is held this way. A refetch that already has rows\n * keeps them and marks the region busy instead — replacing populated rows with\n * shimmer on every pagination click is a grey flash, not a loading state.\n */\n skeleton?: boolean | ReactNode;\n /**\n * The failure of the last load, if it failed.\n *\n * A listing that renders an empty table when the service is unreachable tells\n * the user their catalog is empty — the one thing they must not conclude. So\n * this is rendered as an alert, and it also changes the empty message.\n *\n * It arrives for free from `useDataLoading`, whose whole state is spread into\n * this component.\n */\n error?: EntifixError;\n items: ReadonlyArray<TEntity>;\n totalItems: number;\n currentPage: number;\n pageSize: number;\n onPageChange: (newPage: number) => void;\n onPageSizeChange?: (newPageSize: number) => void;\n\n /**\n * Builds the link to a row's record. Supplied as a function rather than the\n * table routing by itself: this package must not depend on a router, so the\n * caller (a shell page, which does know one) owns the URL shape.\n *\n * Omit it and the actions column is not rendered at all.\n */\n hrefFor?: (id: EntityId) => string;\n /** Link to the create form. Omit and no `New` action is rendered. */\n newHref?: string;\n /**\n * Renders the `Open` and `New` links. Defaults to a plain anchor, which a\n * client-routed host experiences as a full document load — pass one built on\n * the host's own link component. See {@link RenderLink}.\n */\n renderLink?: RenderLink;\n\n /**\n * Picks a row instead of navigating to it — how a link picker reuses this\n * table as its browse dialog.\n *\n * Takes precedence over {@link hrefFor}: inside a picker the user is choosing\n * a value, and offering to navigate away from the form they are editing is the\n * wrong affordance. Either one renders the actions column.\n */\n onSelect?: (item: TEntity) => void;\n\n /** Scope for persisted personalization. Defaults to the entity's key. */\n preferencesKey?: string;\n /** Hide the toolbar (columns, filters, sorting) — a bare listing. */\n showControls?: boolean;\n /** Viewport width at which rows stop pivoting into cards. Default `md`. */\n pivotBreakpoint?: EntityTablePivotBreakpoint;\n\n /** The filtering currently applied, seeding the filter panel so it shows\n * what is in effect rather than an empty form. */\n filtering?: FilterGroup<TEntity>;\n /** The sorting currently applied, seeding the sort panel. */\n sorting?: EntitySorting<TEntity>;\n\n /** Notified when the filter panel is **applied** — not while it is edited, so\n * the value can feed a load request directly. */\n onFilteringChange?: (filtering: FilterGroup<TEntity>) => void;\n /** Notified when the sort panel is applied. */\n onSortingChange?: (sorting: EntitySorting<TEntity>) => void;\n\n /**\n * The rows a collection-bound action would act on.\n *\n * **Controlled from above the table**, exactly as `filtering` and `sorting`\n * are, and for the same reason plus one more: a selection has to survive\n * pagination, and the page owns the pager. A selection held inside the table\n * would be reset by the very navigation the user performs to add to it.\n *\n * Omit it and no selection column is rendered — a listing that is only read\n * gains nothing from a column of empty boxes.\n */\n selection?: EntitySelection<TEntity>;\n onSelectionChange?: (selection: EntitySelection<TEntity>) => void;\n\n /**\n * What this caller may do with the entity, as the service decided it.\n *\n * The same document `EntityForm` takes. The table reads only the\n * `collection`-bound half of `useCases` — the entity-bound verbs belong to a\n * record, and a row's own overflow menu is fed from the\n * `context-dependent` ones.\n *\n * Absent keeps the pre-ADR-0026 behaviour: no bulk bar and no row menu, which\n * is what every un-migrated call site renders today.\n */\n metadata?: EntityMetadataDocument;\n isMetadataLoading?: boolean;\n\n /** Runs a `collection`-bound verb over {@link selection}. */\n onBulkUseCase?: (key: string, selection: EntitySelection<TEntity>) => void;\n /** Runs an `entity`-bound, `context-dependent` verb on one row. */\n onUseCase?: (key: string, item: TEntity) => void;\n\n /** The outcome of the last bulk run, rendered per row until dismissed. */\n bulkOutcomes?: readonly BulkOutcome[];\n onBulkDismiss?: () => void;\n onBulkRetry?: (ids: EntityId[]) => void;\n /** A bulk run is in flight — every verb is disabled while it is. */\n isBulkRunning?: boolean;\n\n /** Customization slots — see `entity-table-slots`. */\n children?: ReactNode;\n}\n"],"names":[],"mappings":"AAkCA,WA6HC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Marks the table-of-contents anchor of the heading being read with
3
+ * `aria-current`, as `ActiveSection` marks a page's nav: an enhancement over
4
+ * anchors that already work. Renders nothing.
5
+ *
6
+ * A heading is a point, not a section, so it never stays in a band: the one
7
+ * being read is the last whose top has passed a line 30% down the window —
8
+ * none above the first. Checked once per frame while scrolling.
9
+ *
10
+ * Where the links sit in a row that scrolls sideways (a phone's strip), the
11
+ * newly marked one is scrolled to the row's middle, so it stays in sight.
12
+ */
13
+ export declare function ActiveHeading({ ids }: {
14
+ ids: readonly string[];
15
+ }): null;
16
+ //# sourceMappingURL=active-heading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-heading.d.ts","sourceRoot":"","sources":["../../../../src/ui/utils/active-heading/active-heading.tsx"],"names":[],"mappings":"AAOA;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAAE,GAAG,EAAE,EAAE;IAAE,GAAG,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,QA2ChE"}
@@ -0,0 +1,68 @@
1
+ 'use client';
2
+ import { useEffect } from 'react';
3
+ /** How far down the window a heading must have come to be the current one. */ const LINE = 0.3;
4
+ /**
5
+ * Marks the table-of-contents anchor of the heading being read with
6
+ * `aria-current`, as `ActiveSection` marks a page's nav: an enhancement over
7
+ * anchors that already work. Renders nothing.
8
+ *
9
+ * A heading is a point, not a section, so it never stays in a band: the one
10
+ * being read is the last whose top has passed a line 30% down the window —
11
+ * none above the first. Checked once per frame while scrolling.
12
+ *
13
+ * Where the links sit in a row that scrolls sideways (a phone's strip), the
14
+ * newly marked one is scrolled to the row's middle, so it stays in sight.
15
+ */ export function ActiveHeading({ ids }) {
16
+ useEffect(()=>{
17
+ const links = new Map(ids.map((id)=>[
18
+ id,
19
+ document.querySelectorAll(`a[data-section="${id}"]`)
20
+ ]));
21
+ const headings = ids.flatMap((id)=>{
22
+ const heading = document.getElementById(id);
23
+ return heading === null ? [] : [
24
+ heading
25
+ ];
26
+ });
27
+ let marked;
28
+ const mark = ()=>{
29
+ const line = window.innerHeight * LINE;
30
+ let current;
31
+ for (const heading of headings)if (heading.getBoundingClientRect().top <= line) current = heading.id;
32
+ for (const [id, anchors] of links)for (const anchor of anchors)if (id === current) anchor.setAttribute('aria-current', 'location');
33
+ else anchor.removeAttribute('aria-current');
34
+ if (current !== marked && current !== undefined) // Every heading found is one of `ids`, each with its anchors.
35
+ for (const anchor of links.get(current))reveal(anchor);
36
+ marked = current;
37
+ };
38
+ let frame = 0;
39
+ const onScroll = ()=>{
40
+ cancelAnimationFrame(frame);
41
+ frame = requestAnimationFrame(mark);
42
+ };
43
+ mark();
44
+ window.addEventListener('scroll', onScroll, {
45
+ passive: true
46
+ });
47
+ window.addEventListener('resize', onScroll, {
48
+ passive: true
49
+ });
50
+ return ()=>{
51
+ cancelAnimationFrame(frame);
52
+ window.removeEventListener('scroll', onScroll);
53
+ window.removeEventListener('resize', onScroll);
54
+ };
55
+ }, [
56
+ ids
57
+ ]);
58
+ return null;
59
+ }
60
+ /** Scrolls a link to the middle of its list, if the list scrolls sideways. */ function reveal(anchor) {
61
+ const list = anchor.closest('ol, ul');
62
+ if (list === null || list.scrollWidth <= list.clientWidth) return;
63
+ const link = anchor.getBoundingClientRect();
64
+ const box = list.getBoundingClientRect();
65
+ list.scrollLeft += link.left - box.left - (box.width - link.width) / 2;
66
+ }
67
+
68
+ //# sourceMappingURL=active-heading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/utils/active-heading/active-heading.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect } from 'react';\n\n/** How far down the window a heading must have come to be the current one. */\nconst LINE = 0.3;\n\n/**\n * Marks the table-of-contents anchor of the heading being read with\n * `aria-current`, as `ActiveSection` marks a page's nav: an enhancement over\n * anchors that already work. Renders nothing.\n *\n * A heading is a point, not a section, so it never stays in a band: the one\n * being read is the last whose top has passed a line 30% down the window —\n * none above the first. Checked once per frame while scrolling.\n *\n * Where the links sit in a row that scrolls sideways (a phone's strip), the\n * newly marked one is scrolled to the row's middle, so it stays in sight.\n */\nexport function ActiveHeading({ ids }: { ids: readonly string[] }) {\n useEffect(() => {\n const links = new Map(\n ids.map(id => [\n id,\n document.querySelectorAll<HTMLAnchorElement>(`a[data-section=\"${id}\"]`),\n ]),\n );\n const headings = ids.flatMap(id => {\n const heading = document.getElementById(id);\n return heading === null ? [] : [heading];\n });\n let marked: string | undefined;\n const mark = () => {\n const line = window.innerHeight * LINE;\n let current: string | undefined;\n for (const heading of headings)\n if (heading.getBoundingClientRect().top <= line) current = heading.id;\n for (const [id, anchors] of links)\n for (const anchor of anchors)\n if (id === current) anchor.setAttribute('aria-current', 'location');\n else anchor.removeAttribute('aria-current');\n if (current !== marked && current !== undefined)\n // Every heading found is one of `ids`, each with its anchors.\n for (const anchor of links.get(current) as Iterable<HTMLElement>)\n reveal(anchor);\n marked = current;\n };\n let frame = 0;\n const onScroll = () => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(mark);\n };\n mark();\n window.addEventListener('scroll', onScroll, { passive: true });\n window.addEventListener('resize', onScroll, { passive: true });\n return () => {\n cancelAnimationFrame(frame);\n window.removeEventListener('scroll', onScroll);\n window.removeEventListener('resize', onScroll);\n };\n }, [ids]);\n return null;\n}\n\n/** Scrolls a link to the middle of its list, if the list scrolls sideways. */\nfunction reveal(anchor: HTMLElement) {\n const list = anchor.closest('ol, ul');\n if (list === null || list.scrollWidth <= list.clientWidth) return;\n const link = anchor.getBoundingClientRect();\n const box = list.getBoundingClientRect();\n list.scrollLeft += link.left - box.left - (box.width - link.width) / 2;\n}\n"],"names":["useEffect","LINE","ActiveHeading","ids","links","Map","map","id","document","querySelectorAll","headings","flatMap","heading","getElementById","marked","mark","line","window","innerHeight","current","getBoundingClientRect","top","anchors","anchor","setAttribute","removeAttribute","undefined","get","reveal","frame","onScroll","cancelAnimationFrame","requestAnimationFrame","addEventListener","passive","removeEventListener","list","closest","scrollWidth","clientWidth","link","box","scrollLeft","left","width"],"mappings":"AAAA;AAEA,SAASA,SAAS,QAAQ,QAAQ;AAElC,4EAA4E,GAC5E,MAAMC,OAAO;AAEb;;;;;;;;;;;CAWC,GACD,OAAO,SAASC,cAAc,EAAEC,GAAG,EAA8B;IAC/DH,UAAU;QACR,MAAMI,QAAQ,IAAIC,IAChBF,IAAIG,GAAG,CAACC,CAAAA,KAAM;gBACZA;gBACAC,SAASC,gBAAgB,CAAoB,CAAC,gBAAgB,EAAEF,GAAG,EAAE,CAAC;aACvE;QAEH,MAAMG,WAAWP,IAAIQ,OAAO,CAACJ,CAAAA;YAC3B,MAAMK,UAAUJ,SAASK,cAAc,CAACN;YACxC,OAAOK,YAAY,OAAO,EAAE,GAAG;gBAACA;aAAQ;QAC1C;QACA,IAAIE;QACJ,MAAMC,OAAO;YACX,MAAMC,OAAOC,OAAOC,WAAW,GAAGjB;YAClC,IAAIkB;YACJ,KAAK,MAAMP,WAAWF,SACpB,IAAIE,QAAQQ,qBAAqB,GAAGC,GAAG,IAAIL,MAAMG,UAAUP,QAAQL,EAAE;YACvE,KAAK,MAAM,CAACA,IAAIe,QAAQ,IAAIlB,MAC1B,KAAK,MAAMmB,UAAUD,QACnB,IAAIf,OAAOY,SAASI,OAAOC,YAAY,CAAC,gBAAgB;iBACnDD,OAAOE,eAAe,CAAC;YAChC,IAAIN,YAAYL,UAAUK,YAAYO,WACpC,8DAA8D;YAC9D,KAAK,MAAMH,UAAUnB,MAAMuB,GAAG,CAACR,SAC7BS,OAAOL;YACXT,SAASK;QACX;QACA,IAAIU,QAAQ;QACZ,MAAMC,WAAW;YACfC,qBAAqBF;YACrBA,QAAQG,sBAAsBjB;QAChC;QACAA;QACAE,OAAOgB,gBAAgB,CAAC,UAAUH,UAAU;YAAEI,SAAS;QAAK;QAC5DjB,OAAOgB,gBAAgB,CAAC,UAAUH,UAAU;YAAEI,SAAS;QAAK;QAC5D,OAAO;YACLH,qBAAqBF;YACrBZ,OAAOkB,mBAAmB,CAAC,UAAUL;YACrCb,OAAOkB,mBAAmB,CAAC,UAAUL;QACvC;IACF,GAAG;QAAC3B;KAAI;IACR,OAAO;AACT;AAEA,4EAA4E,GAC5E,SAASyB,OAAOL,MAAmB;IACjC,MAAMa,OAAOb,OAAOc,OAAO,CAAC;IAC5B,IAAID,SAAS,QAAQA,KAAKE,WAAW,IAAIF,KAAKG,WAAW,EAAE;IAC3D,MAAMC,OAAOjB,OAAOH,qBAAqB;IACzC,MAAMqB,MAAML,KAAKhB,qBAAqB;IACtCgB,KAAKM,UAAU,IAAIF,KAAKG,IAAI,GAAGF,IAAIE,IAAI,GAAG,AAACF,CAAAA,IAAIG,KAAK,GAAGJ,KAAKI,KAAK,AAAD,IAAK;AACvE"}
@@ -0,0 +1,2 @@
1
+ export * from './active-heading.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/utils/active-heading/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './active-heading.js';
2
+
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/utils/active-heading/index.ts"],"sourcesContent":["export * from './active-heading.js';\n"],"names":[],"mappings":"AAAA,cAAc,sBAAsB"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Marks the nav anchor of the section in view with `aria-current`: an
3
+ * enhancement over anchors that already work (ADR 0008). Renders nothing.
4
+ *
5
+ * A section counts as in view while it crosses the band just above the
6
+ * viewport's middle; over the hero, none does.
7
+ */
8
+ export declare function ActiveSection({ sections }: {
9
+ sections: readonly string[];
10
+ }): null;
11
+ //# sourceMappingURL=active-section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-section.d.ts","sourceRoot":"","sources":["../../../../src/ui/utils/active-section/active-section.tsx"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,QAmC1E"}
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+ import { useEffect } from 'react';
3
+ /**
4
+ * Marks the nav anchor of the section in view with `aria-current`: an
5
+ * enhancement over anchors that already work (ADR 0008). Renders nothing.
6
+ *
7
+ * A section counts as in view while it crosses the band just above the
8
+ * viewport's middle; over the hero, none does.
9
+ */ export function ActiveSection({ sections }) {
10
+ useEffect(()=>{
11
+ const links = new Map(sections.map((id)=>[
12
+ id,
13
+ document.querySelectorAll(`a[data-section="${id}"]`)
14
+ ]));
15
+ const visible = new Set();
16
+ const mark = ()=>{
17
+ const current = sections.find((id)=>visible.has(id));
18
+ for (const [id, anchors] of links){
19
+ for (const anchor of anchors){
20
+ if (id === current) anchor.setAttribute('aria-current', 'location');
21
+ else anchor.removeAttribute('aria-current');
22
+ }
23
+ }
24
+ };
25
+ const observer = new IntersectionObserver((entries)=>{
26
+ for (const entry of entries){
27
+ if (entry.isIntersecting) visible.add(entry.target.id);
28
+ else visible.delete(entry.target.id);
29
+ }
30
+ mark();
31
+ }, {
32
+ rootMargin: '-40% 0px -55% 0px'
33
+ });
34
+ for (const id of sections){
35
+ const section = document.getElementById(id);
36
+ if (section) observer.observe(section);
37
+ }
38
+ return ()=>observer.disconnect();
39
+ }, [
40
+ sections
41
+ ]);
42
+ return null;
43
+ }
44
+
45
+ //# sourceMappingURL=active-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/utils/active-section/active-section.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect } from 'react';\n\n/**\n * Marks the nav anchor of the section in view with `aria-current`: an\n * enhancement over anchors that already work (ADR 0008). Renders nothing.\n *\n * A section counts as in view while it crosses the band just above the\n * viewport's middle; over the hero, none does.\n */\nexport function ActiveSection({ sections }: { sections: readonly string[] }) {\n useEffect(() => {\n const links = new Map(\n sections.map(id => [\n id,\n document.querySelectorAll<HTMLAnchorElement>(`a[data-section=\"${id}\"]`),\n ]),\n );\n const visible = new Set<string>();\n const mark = () => {\n const current = sections.find(id => visible.has(id));\n for (const [id, anchors] of links) {\n for (const anchor of anchors) {\n if (id === current) anchor.setAttribute('aria-current', 'location');\n else anchor.removeAttribute('aria-current');\n }\n }\n };\n const observer = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n if (entry.isIntersecting) visible.add(entry.target.id);\n else visible.delete(entry.target.id);\n }\n mark();\n },\n { rootMargin: '-40% 0px -55% 0px' },\n );\n for (const id of sections) {\n const section = document.getElementById(id);\n if (section) observer.observe(section);\n }\n return () => observer.disconnect();\n }, [sections]);\n return null;\n}\n"],"names":["useEffect","ActiveSection","sections","links","Map","map","id","document","querySelectorAll","visible","Set","mark","current","find","has","anchors","anchor","setAttribute","removeAttribute","observer","IntersectionObserver","entries","entry","isIntersecting","add","target","delete","rootMargin","section","getElementById","observe","disconnect"],"mappings":"AAAA;AAEA,SAASA,SAAS,QAAQ,QAAQ;AAElC;;;;;;CAMC,GACD,OAAO,SAASC,cAAc,EAAEC,QAAQ,EAAmC;IACzEF,UAAU;QACR,MAAMG,QAAQ,IAAIC,IAChBF,SAASG,GAAG,CAACC,CAAAA,KAAM;gBACjBA;gBACAC,SAASC,gBAAgB,CAAoB,CAAC,gBAAgB,EAAEF,GAAG,EAAE,CAAC;aACvE;QAEH,MAAMG,UAAU,IAAIC;QACpB,MAAMC,OAAO;YACX,MAAMC,UAAUV,SAASW,IAAI,CAACP,CAAAA,KAAMG,QAAQK,GAAG,CAACR;YAChD,KAAK,MAAM,CAACA,IAAIS,QAAQ,IAAIZ,MAAO;gBACjC,KAAK,MAAMa,UAAUD,QAAS;oBAC5B,IAAIT,OAAOM,SAASI,OAAOC,YAAY,CAAC,gBAAgB;yBACnDD,OAAOE,eAAe,CAAC;gBAC9B;YACF;QACF;QACA,MAAMC,WAAW,IAAIC,qBACnBC,CAAAA;YACE,KAAK,MAAMC,SAASD,QAAS;gBAC3B,IAAIC,MAAMC,cAAc,EAAEd,QAAQe,GAAG,CAACF,MAAMG,MAAM,CAACnB,EAAE;qBAChDG,QAAQiB,MAAM,CAACJ,MAAMG,MAAM,CAACnB,EAAE;YACrC;YACAK;QACF,GACA;YAAEgB,YAAY;QAAoB;QAEpC,KAAK,MAAMrB,MAAMJ,SAAU;YACzB,MAAM0B,UAAUrB,SAASsB,cAAc,CAACvB;YACxC,IAAIsB,SAAST,SAASW,OAAO,CAACF;QAChC;QACA,OAAO,IAAMT,SAASY,UAAU;IAClC,GAAG;QAAC7B;KAAS;IACb,OAAO;AACT"}
@@ -0,0 +1,2 @@
1
+ export * from './active-section.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/utils/active-section/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './active-section.js';
2
+
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/utils/active-section/index.ts"],"sourcesContent":["export * from './active-section.js';\n"],"names":[],"mappings":"AAAA,cAAc,sBAAsB"}
@@ -0,0 +1,20 @@
1
+ /** A disclosure to close before paint, and when: while `query` matches. */
2
+ export interface Fold {
3
+ /** A media query: `(width >= 64rem)`. */
4
+ readonly query: string;
5
+ /** The `<details>` it closes: every element the selector matches. */
6
+ readonly selector: string;
7
+ }
8
+ /**
9
+ * Closes disclosures before the page paints, by screen width: an inline
10
+ * script, placed after them in the document, that runs long before React
11
+ * hydrates. The HTML leaves them open, which is what a visitor with no script
12
+ * gets; a `<details>` it closes needs `suppressHydrationWarning`.
13
+ *
14
+ * A media query, not a container query: nothing has been laid out yet, so the
15
+ * window is the one width there is to ask.
16
+ */
17
+ export declare function FoldScript({ folds }: {
18
+ folds: readonly Fold[];
19
+ }): import("react").JSX.Element;
20
+ //# sourceMappingURL=fold-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold-script.d.ts","sourceRoot":"","sources":["../../../../src/ui/utils/fold-script/fold-script.tsx"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,MAAM,WAAW,IAAI;IACnB,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,SAAS,IAAI,EAAE,CAAA;CAAE,+BAc/D"}