@entifix/react-controls 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/i18n/catalog/en.d.ts.map +1 -1
  2. package/dist/i18n/catalog/en.js +3 -0
  3. package/dist/i18n/catalog/en.js.map +1 -1
  4. package/dist/i18n/catalog/es.d.ts +4 -1
  5. package/dist/i18n/catalog/es.d.ts.map +1 -1
  6. package/dist/i18n/catalog/es.js +4 -1
  7. package/dist/i18n/catalog/es.js.map +1 -1
  8. package/dist/i18n/catalog/index.d.ts +6 -0
  9. package/dist/i18n/catalog/index.d.ts.map +1 -1
  10. package/dist/preferences/use-viewport-mode.d.ts +0 -1
  11. package/dist/preferences/use-viewport-mode.d.ts.map +1 -1
  12. package/dist/preferences/use-viewport-mode.js +0 -1
  13. package/dist/preferences/use-viewport-mode.js.map +1 -1
  14. package/dist/ui/actions/action-surfaces.d.ts +3 -3
  15. package/dist/ui/actions/action-surfaces.js +4 -4
  16. package/dist/ui/actions/action-surfaces.js.map +1 -1
  17. package/dist/ui/actions/render-link.d.ts +8 -4
  18. package/dist/ui/actions/render-link.d.ts.map +1 -1
  19. package/dist/ui/actions/render-link.js.map +1 -1
  20. package/dist/ui/atoms/field-control/field-control.d.ts +1 -1
  21. package/dist/ui/atoms/field-control/field-control.js +1 -1
  22. package/dist/ui/atoms/field-control/field-control.js.map +1 -1
  23. package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.d.ts +2 -2
  24. package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js.map +1 -1
  25. package/dist/ui/molecules/bulk-result/bulk-result.js.map +1 -1
  26. package/dist/ui/molecules/loading-boundary/loading-boundary.d.ts +1 -1
  27. package/dist/ui/molecules/loading-boundary/loading-boundary.js +1 -1
  28. package/dist/ui/molecules/loading-boundary/loading-boundary.js.map +1 -1
  29. package/dist/ui/molecules/pagination/index.d.ts +2 -0
  30. package/dist/ui/molecules/pagination/index.d.ts.map +1 -1
  31. package/dist/ui/molecules/pagination/index.js +2 -0
  32. package/dist/ui/molecules/pagination/index.js.map +1 -1
  33. package/dist/ui/molecules/pagination/page-math.d.ts +23 -0
  34. package/dist/ui/molecules/pagination/page-math.d.ts.map +1 -0
  35. package/dist/ui/molecules/pagination/page-math.js +47 -0
  36. package/dist/ui/molecules/pagination/page-math.js.map +1 -0
  37. package/dist/ui/molecules/pagination/pagination-links.d.ts +33 -0
  38. package/dist/ui/molecules/pagination/pagination-links.d.ts.map +1 -0
  39. package/dist/ui/molecules/pagination/pagination-links.js +94 -0
  40. package/dist/ui/molecules/pagination/pagination-links.js.map +1 -0
  41. package/dist/ui/molecules/pagination/pagination.d.ts +6 -1
  42. package/dist/ui/molecules/pagination/pagination.d.ts.map +1 -1
  43. package/dist/ui/molecules/pagination/pagination.js +8 -2
  44. package/dist/ui/molecules/pagination/pagination.js.map +1 -1
  45. package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.d.ts +2 -2
  46. package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js +2 -2
  47. package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js.map +1 -1
  48. package/dist/ui/organisms/entity-form/entity-form.js +4 -4
  49. package/dist/ui/organisms/entity-form/entity-form.js.map +1 -1
  50. package/dist/ui/organisms/entity-form/entity-form.types.d.ts +2 -2
  51. package/dist/ui/organisms/entity-form/entity-form.types.js.map +1 -1
  52. package/dist/ui/organisms/entity-table/entity-table-tree.d.ts +33 -0
  53. package/dist/ui/organisms/entity-table/entity-table-tree.d.ts.map +1 -0
  54. package/dist/ui/organisms/entity-table/entity-table-tree.js +80 -0
  55. package/dist/ui/organisms/entity-table/entity-table-tree.js.map +1 -0
  56. package/dist/ui/organisms/entity-table/entity-table.d.ts.map +1 -1
  57. package/dist/ui/organisms/entity-table/entity-table.js +41 -9
  58. package/dist/ui/organisms/entity-table/entity-table.js.map +1 -1
  59. package/dist/ui/organisms/wizard/wizard.d.ts +1 -2
  60. package/dist/ui/organisms/wizard/wizard.d.ts.map +1 -1
  61. package/dist/ui/organisms/wizard/wizard.js +2 -3
  62. package/dist/ui/organisms/wizard/wizard.js.map +1 -1
  63. package/dist/ui/organisms/wizard/wizard.types.d.ts +2 -2
  64. package/dist/ui/organisms/wizard/wizard.types.js.map +1 -1
  65. package/dist/ui/utils/active-section/active-section.d.ts +1 -1
  66. package/dist/ui/utils/active-section/active-section.js +1 -1
  67. package/dist/ui/utils/active-section/active-section.js.map +1 -1
  68. package/dist/ui/utils/keep-section/keep-section.d.ts +1 -1
  69. package/dist/ui/utils/keep-section/keep-section.js +1 -1
  70. package/dist/ui/utils/keep-section/keep-section.js.map +1 -1
  71. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../../src/i18n/catalog/en.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,KAAK,UAAU,GAAG,cAAc,SAAS,EAAE,QAAQ,CAAC;AAEpD,eAAO,MAAM,QAAQ,EAAE,UAmNtB,CAAC"}
1
+ {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../../src/i18n/catalog/en.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,KAAK,UAAU,GAAG,cAAc,SAAS,EAAE,QAAQ,CAAC;AAEpD,eAAO,MAAM,QAAQ,EAAE,UAsNtB,CAAC"}
@@ -16,6 +16,8 @@
16
16
  error: 'Could not load records',
17
17
  selection: 'Selection',
18
18
  selectRow: 'Select {{record}}',
19
+ expandRow: 'Expand {{record}}',
20
+ collapseRow: 'Collapse {{record}}',
19
21
  selectAllOnPage: 'Select all on this page',
20
22
  selectAllMatching_one: 'Select {{count}} match',
21
23
  selectAllMatching_other: 'Select all {{count}} matches',
@@ -49,6 +51,7 @@
49
51
  loading: 'Loading…'
50
52
  },
51
53
  pagination: {
54
+ label: 'Pages',
52
55
  summary: 'Page {{current}} of {{total}} · {{items}} items',
53
56
  rows: 'Rows',
54
57
  previous: 'Previous',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/i18n/catalog/en.ts"],"sourcesContent":["/**\n * The `es` shape is the contract: annotating with it makes a key that exists in\n * Spanish but not here a *compile* error, so a half-translated locale cannot\n * reach a build. `tools/check-i18n.mjs` covers what types cannot — empty values,\n * and keys present here but absent from `es`.\n */\ntype EsControls = typeof import('./es.js').controls;\n\nexport const controls: EsControls = {\n table: {\n open: 'Open',\n select: 'Select',\n actions: 'Actions',\n new: 'New',\n filters: 'Filters',\n sorting: 'Sorting',\n loading: 'Loading…',\n empty: 'No records',\n error: 'Could not load records',\n selection: 'Selection',\n selectRow: 'Select {{record}}',\n selectAllOnPage: 'Select all on this page',\n selectAllMatching_one: 'Select {{count}} match',\n selectAllMatching_other: 'Select all {{count}} matches',\n selectedCount_one: '{{count}} selected',\n selectedCount_other: '{{count}} selected',\n clearSelection: 'Clear selection',\n },\n bulk: {\n running: 'Running…',\n succeeded_one: '{{count}} record updated',\n succeeded_other: '{{count}} records updated',\n failed_one: '{{count}} record failed',\n failed_other: '{{count}} records failed',\n retryFailed: 'Retry the failures',\n dismiss: 'Dismiss result',\n resultLabel: 'Bulk action result',\n barLabel: 'Actions on the selection',\n },\n form: {\n details: 'Details',\n new: 'New',\n view: 'View',\n edit: 'Edit',\n save: 'Save',\n saving: 'Saving…',\n delete: 'Delete',\n deleting: 'Deleting…',\n clone: 'Duplicate',\n moreActions: 'More actions',\n back: 'Back',\n loading: 'Loading…',\n },\n pagination: {\n summary: 'Page {{current}} of {{total}} · {{items}} items',\n rows: 'Rows',\n previous: 'Previous',\n next: 'Next',\n },\n columns: {\n title: 'Columns',\n subtitle: 'Visibility and order',\n reset: 'Reset to default',\n moveUp: 'Move {{column}} up',\n moveDown: 'Move {{column}} down',\n },\n filter: {\n match: 'Match',\n all: 'all',\n any: 'any',\n add: 'Add filter',\n apply: 'Apply',\n clear: 'Clear',\n none: 'No filterable members on this entity.',\n listPlaceholder: 'comma, separated, values',\n matchAria: 'Match all or any filter',\n member: 'Filter member',\n operator: 'Filter operator',\n value: 'Filter value',\n rangeEnd: 'Filter range end',\n remove: 'Remove filter',\n applyAria: 'Apply filters',\n clearAria: 'Clear filters',\n },\n sort: {\n by: 'Sort by',\n then: 'then by',\n ascending: 'ascending',\n descending: 'descending',\n add: 'Add sort',\n apply: 'Apply',\n clear: 'Clear',\n none: 'No sortable members on this entity.',\n member: 'Sort member',\n direction: 'Sort direction',\n raisePriority: 'Raise sort priority',\n lowerPriority: 'Lower sort priority',\n remove: 'Remove sort',\n applyAria: 'Apply sorting',\n clearAria: 'Clear sorting',\n },\n tabs: {\n close: 'Close {{label}}',\n new: 'Open a new tab',\n },\n link: {\n search: 'Search {{field}}',\n suggestAria: 'Show {{field}} suggestions',\n browseAria: 'Browse {{field}}',\n browseTitle: 'Select {{field}}',\n clear: 'Clear {{field}}',\n empty: '— unassigned —',\n loading: 'Loading…',\n noResults: 'No matches',\n error: 'Could not load options',\n close: 'Close',\n },\n detail: {\n addRow: 'Add row',\n removeRow: 'Remove row {{row}}',\n rowActions: 'Row actions',\n empty: 'No rows yet.',\n errorSummary_one: '{{count}} cell has errors',\n errorSummary_other: '{{count}} cells have errors',\n },\n value: {\n none: '— none —',\n yes: 'Yes',\n no: 'No',\n /**\n * A `composition` in a table: its rows are edited on the master's own\n * screen rather than in the cell, so the cell says how many there are.\n */\n rowCount_one: '{{count}} row',\n rowCount_other: '{{count}} rows',\n },\n /**\n * `required`…`option` are the metadata-derived rules. The rest are the\n * vocabulary an entity's Standard Schema writes its messages in: a schema\n * carries the *key*, never a sentence, so a rule stays translatable.\n *\n * `field` is the only parameter available — a Standard Schema issue exposes a\n * message and a path, nothing else — so these stay unquantified. A rule that\n * has to state its bound writes its own key in its domain catalog and passes\n * it namespaced (`entity:product-specification.validation.codeLength`).\n */\n validation: {\n required: '{{field}} is required',\n number: '{{field}} must be a number',\n date: '{{field}} must be a date',\n option: '{{field}} is not a valid option',\n minLength: '{{field}} is too short',\n maxLength: '{{field}} is too long',\n min: '{{field}} is too small',\n max: '{{field}} is too large',\n pattern: '{{field}} has an invalid format',\n minItems_one: '{{field}} needs at least {{count}} item',\n minItems_other: '{{field}} needs at least {{count}} items',\n maxItems_one: '{{field}} takes at most {{count}} item',\n maxItems_other: '{{field}} takes at most {{count}} items',\n notBefore: '{{field}} cannot be before {{other}}',\n locale: '{{field}} has no {{locale}} text',\n },\n operator: {\n eq: 'is',\n ne: 'is not',\n gt: 'greater than',\n gte: 'greater or equal',\n lt: 'less than',\n lte: 'less or equal',\n in: 'is one of',\n nin: 'is none of',\n between: 'between',\n nbetween: 'not between',\n like: 'contains',\n nlike: 'does not contain',\n isNull: 'is empty',\n isNotNull: 'is not empty',\n },\n theme: {\n label: 'Theme',\n },\n themes: {\n aurora: 'Aurora',\n sunset: 'Sunset',\n midnight: 'Midnight',\n ocean: 'Ocean (runtime)',\n marketplace: 'Marketplace',\n marketplaceDark: 'Marketplace dark',\n auth: 'Identity',\n authDark: 'Identity dark',\n },\n confirm: {\n confirm: 'Confirm',\n cancel: 'Cancel',\n title: 'Confirm',\n },\n breadcrumbs: {\n label: 'Breadcrumb',\n },\n wizard: {\n steps: 'Steps',\n previous: 'Back',\n next: 'Continue',\n finish: 'Finish',\n submitting: 'Submitting…',\n stepOf: 'Step {{current}} of {{total}}',\n goToStep: 'Back to {{label}}',\n status: {\n pending: 'pending',\n active: 'in progress',\n complete: 'completed',\n error: 'has errors',\n },\n resume: {\n title: 'Picking up where you left off',\n dismiss: 'Got it',\n },\n },\n};\n"],"names":["controls","table","open","select","actions","new","filters","sorting","loading","empty","error","selection","selectRow","selectAllOnPage","selectAllMatching_one","selectAllMatching_other","selectedCount_one","selectedCount_other","clearSelection","bulk","running","succeeded_one","succeeded_other","failed_one","failed_other","retryFailed","dismiss","resultLabel","barLabel","form","details","view","edit","save","saving","delete","deleting","clone","moreActions","back","pagination","summary","rows","previous","next","columns","title","subtitle","reset","moveUp","moveDown","filter","match","all","any","add","apply","clear","none","listPlaceholder","matchAria","member","operator","value","rangeEnd","remove","applyAria","clearAria","sort","by","then","ascending","descending","direction","raisePriority","lowerPriority","tabs","close","link","search","suggestAria","browseAria","browseTitle","noResults","detail","addRow","removeRow","rowActions","errorSummary_one","errorSummary_other","yes","no","rowCount_one","rowCount_other","validation","required","number","date","option","minLength","maxLength","min","max","pattern","minItems_one","minItems_other","maxItems_one","maxItems_other","notBefore","locale","eq","ne","gt","gte","lt","lte","in","nin","between","nbetween","like","nlike","isNull","isNotNull","theme","label","themes","aurora","sunset","midnight","ocean","marketplace","marketplaceDark","auth","authDark","confirm","cancel","breadcrumbs","wizard","steps","finish","submitting","stepOf","goToStep","status","pending","active","complete","resume"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/i18n/catalog/en.ts"],"sourcesContent":["/**\n * The `es` shape is the contract: annotating with it makes a key that exists in\n * Spanish but not here a *compile* error, so a half-translated locale cannot\n * reach a build. `tools/check-i18n.mjs` covers what types cannot — empty values,\n * and keys present here but absent from `es`.\n */\ntype EsControls = typeof import('./es.js').controls;\n\nexport const controls: EsControls = {\n table: {\n open: 'Open',\n select: 'Select',\n actions: 'Actions',\n new: 'New',\n filters: 'Filters',\n sorting: 'Sorting',\n loading: 'Loading…',\n empty: 'No records',\n error: 'Could not load records',\n selection: 'Selection',\n selectRow: 'Select {{record}}',\n expandRow: 'Expand {{record}}',\n collapseRow: 'Collapse {{record}}',\n selectAllOnPage: 'Select all on this page',\n selectAllMatching_one: 'Select {{count}} match',\n selectAllMatching_other: 'Select all {{count}} matches',\n selectedCount_one: '{{count}} selected',\n selectedCount_other: '{{count}} selected',\n clearSelection: 'Clear selection',\n },\n bulk: {\n running: 'Running…',\n succeeded_one: '{{count}} record updated',\n succeeded_other: '{{count}} records updated',\n failed_one: '{{count}} record failed',\n failed_other: '{{count}} records failed',\n retryFailed: 'Retry the failures',\n dismiss: 'Dismiss result',\n resultLabel: 'Bulk action result',\n barLabel: 'Actions on the selection',\n },\n form: {\n details: 'Details',\n new: 'New',\n view: 'View',\n edit: 'Edit',\n save: 'Save',\n saving: 'Saving…',\n delete: 'Delete',\n deleting: 'Deleting…',\n clone: 'Duplicate',\n moreActions: 'More actions',\n back: 'Back',\n loading: 'Loading…',\n },\n pagination: {\n label: 'Pages',\n summary: 'Page {{current}} of {{total}} · {{items}} items',\n rows: 'Rows',\n previous: 'Previous',\n next: 'Next',\n },\n columns: {\n title: 'Columns',\n subtitle: 'Visibility and order',\n reset: 'Reset to default',\n moveUp: 'Move {{column}} up',\n moveDown: 'Move {{column}} down',\n },\n filter: {\n match: 'Match',\n all: 'all',\n any: 'any',\n add: 'Add filter',\n apply: 'Apply',\n clear: 'Clear',\n none: 'No filterable members on this entity.',\n listPlaceholder: 'comma, separated, values',\n matchAria: 'Match all or any filter',\n member: 'Filter member',\n operator: 'Filter operator',\n value: 'Filter value',\n rangeEnd: 'Filter range end',\n remove: 'Remove filter',\n applyAria: 'Apply filters',\n clearAria: 'Clear filters',\n },\n sort: {\n by: 'Sort by',\n then: 'then by',\n ascending: 'ascending',\n descending: 'descending',\n add: 'Add sort',\n apply: 'Apply',\n clear: 'Clear',\n none: 'No sortable members on this entity.',\n member: 'Sort member',\n direction: 'Sort direction',\n raisePriority: 'Raise sort priority',\n lowerPriority: 'Lower sort priority',\n remove: 'Remove sort',\n applyAria: 'Apply sorting',\n clearAria: 'Clear sorting',\n },\n tabs: {\n close: 'Close {{label}}',\n new: 'Open a new tab',\n },\n link: {\n search: 'Search {{field}}',\n suggestAria: 'Show {{field}} suggestions',\n browseAria: 'Browse {{field}}',\n browseTitle: 'Select {{field}}',\n clear: 'Clear {{field}}',\n empty: '— unassigned —',\n loading: 'Loading…',\n noResults: 'No matches',\n error: 'Could not load options',\n close: 'Close',\n },\n detail: {\n addRow: 'Add row',\n removeRow: 'Remove row {{row}}',\n rowActions: 'Row actions',\n empty: 'No rows yet.',\n errorSummary_one: '{{count}} cell has errors',\n errorSummary_other: '{{count}} cells have errors',\n },\n value: {\n none: '— none —',\n yes: 'Yes',\n no: 'No',\n /**\n * A `composition` in a table: its rows are edited on the master's own\n * screen rather than in the cell, so the cell says how many there are.\n */\n rowCount_one: '{{count}} row',\n rowCount_other: '{{count}} rows',\n },\n /**\n * `required`…`option` are the metadata-derived rules. The rest are the\n * vocabulary an entity's Standard Schema writes its messages in: a schema\n * carries the *key*, never a sentence, so a rule stays translatable.\n *\n * `field` is the only parameter available — a Standard Schema issue exposes a\n * message and a path, nothing else — so these stay unquantified. A rule that\n * has to state its bound writes its own key in its domain catalog and passes\n * it namespaced (`entity:product-specification.validation.codeLength`).\n */\n validation: {\n required: '{{field}} is required',\n number: '{{field}} must be a number',\n date: '{{field}} must be a date',\n option: '{{field}} is not a valid option',\n minLength: '{{field}} is too short',\n maxLength: '{{field}} is too long',\n min: '{{field}} is too small',\n max: '{{field}} is too large',\n pattern: '{{field}} has an invalid format',\n minItems_one: '{{field}} needs at least {{count}} item',\n minItems_other: '{{field}} needs at least {{count}} items',\n maxItems_one: '{{field}} takes at most {{count}} item',\n maxItems_other: '{{field}} takes at most {{count}} items',\n notBefore: '{{field}} cannot be before {{other}}',\n locale: '{{field}} has no {{locale}} text',\n },\n operator: {\n eq: 'is',\n ne: 'is not',\n gt: 'greater than',\n gte: 'greater or equal',\n lt: 'less than',\n lte: 'less or equal',\n in: 'is one of',\n nin: 'is none of',\n between: 'between',\n nbetween: 'not between',\n like: 'contains',\n nlike: 'does not contain',\n isNull: 'is empty',\n isNotNull: 'is not empty',\n },\n theme: {\n label: 'Theme',\n },\n themes: {\n aurora: 'Aurora',\n sunset: 'Sunset',\n midnight: 'Midnight',\n ocean: 'Ocean (runtime)',\n marketplace: 'Marketplace',\n marketplaceDark: 'Marketplace dark',\n auth: 'Identity',\n authDark: 'Identity dark',\n },\n confirm: {\n confirm: 'Confirm',\n cancel: 'Cancel',\n title: 'Confirm',\n },\n breadcrumbs: {\n label: 'Breadcrumb',\n },\n wizard: {\n steps: 'Steps',\n previous: 'Back',\n next: 'Continue',\n finish: 'Finish',\n submitting: 'Submitting…',\n stepOf: 'Step {{current}} of {{total}}',\n goToStep: 'Back to {{label}}',\n status: {\n pending: 'pending',\n active: 'in progress',\n complete: 'completed',\n error: 'has errors',\n },\n resume: {\n title: 'Picking up where you left off',\n dismiss: 'Got it',\n },\n },\n};\n"],"names":["controls","table","open","select","actions","new","filters","sorting","loading","empty","error","selection","selectRow","expandRow","collapseRow","selectAllOnPage","selectAllMatching_one","selectAllMatching_other","selectedCount_one","selectedCount_other","clearSelection","bulk","running","succeeded_one","succeeded_other","failed_one","failed_other","retryFailed","dismiss","resultLabel","barLabel","form","details","view","edit","save","saving","delete","deleting","clone","moreActions","back","pagination","label","summary","rows","previous","next","columns","title","subtitle","reset","moveUp","moveDown","filter","match","all","any","add","apply","clear","none","listPlaceholder","matchAria","member","operator","value","rangeEnd","remove","applyAria","clearAria","sort","by","then","ascending","descending","direction","raisePriority","lowerPriority","tabs","close","link","search","suggestAria","browseAria","browseTitle","noResults","detail","addRow","removeRow","rowActions","errorSummary_one","errorSummary_other","yes","no","rowCount_one","rowCount_other","validation","required","number","date","option","minLength","maxLength","min","max","pattern","minItems_one","minItems_other","maxItems_one","maxItems_other","notBefore","locale","eq","ne","gt","gte","lt","lte","in","nin","between","nbetween","like","nlike","isNull","isNotNull","theme","themes","aurora","sunset","midnight","ocean","marketplace","marketplaceDark","auth","authDark","confirm","cancel","breadcrumbs","wizard","steps","finish","submitting","stepOf","goToStep","status","pending","active","complete","resume"],"mappings":"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"}
@@ -22,6 +22,8 @@ export declare const controls: {
22
22
  */
23
23
  selection: string;
24
24
  selectRow: string;
25
+ expandRow: string;
26
+ collapseRow: string;
25
27
  selectAllOnPage: string;
26
28
  /**
27
29
  * La segunda selección — la que el servidor evalúa — lleva el número
@@ -63,6 +65,7 @@ export declare const controls: {
63
65
  loading: string;
64
66
  };
65
67
  pagination: {
68
+ label: string;
66
69
  summary: string;
67
70
  rows: string;
68
71
  previous: string;
@@ -250,7 +253,7 @@ export declare const controls: {
250
253
  finish: string;
251
254
  /**
252
255
  * Un envío que **no** resuelve. El asistente entrega el trabajo y vuelve
253
- * antes de que la escritura termine (ADR 0043), así que dice "enviando" y
256
+ * antes de que la escritura termine, así que dice "enviando" y
254
257
  * nunca "guardado": lo segundo sería una afirmación que el control no puede
255
258
  * comprobar.
256
259
  */
@@ -1 +1 @@
1
- {"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../../src/i18n/catalog/es.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;QAWjB;;;;WAIG;;;;QAIH;;;WAGG;;;;;;;IAOL;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8EH;;;;OAIG;;;;;;;;;;;;;IAaH;;;;;;OAMG;;;;;;;;;;;;;QAaD;;;WAGG;;;;IAIL;;;;;;;;;;OAUG;;;;;;;;;;;;;;;;;;IAkBH;;;;OAIG;;;;;;;;;;;;;;;;;;;;IAoBH;;;;;OAKG;;;;;;;;;;;;;;;;;;;IAmBH;;;;OAIG;;;;QAID;;;;WAIG;;;QAGH;;;;;WAKG;;;;QAIH;;;WAGG;;;;;;;QAOH;;;;WAIG;;;;;;CAMN,CAAC"}
1
+ {"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../../src/i18n/catalog/es.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;QAWjB;;;;WAIG;;;;;;QAMH;;;WAGG;;;;;;;IAOL;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA+EH;;;;OAIG;;;;;;;;;;;;;IAaH;;;;;;OAMG;;;;;;;;;;;;;QAaD;;;WAGG;;;;IAIL;;;;;;;;;;OAUG;;;;;;;;;;;;;;;;;;IAkBH;;;;OAIG;;;;;;;;;;;;;;;;;;;;IAoBH;;;;;OAKG;;;;;;;;;;;;;;;;;;;IAmBH;;;;OAIG;;;;QAID;;;;WAIG;;;QAGH;;;;;WAKG;;;;QAIH;;;WAGG;;;;;;;QAOH;;;;WAIG;;;;;;CAMN,CAAC"}
@@ -20,6 +20,8 @@
20
20
  * encabezado en cada fila no diría cuál es.
21
21
  */ selection: 'Selección',
22
22
  selectRow: 'Seleccionar {{record}}',
23
+ expandRow: 'Expandir {{record}}',
24
+ collapseRow: 'Contraer {{record}}',
23
25
  selectAllOnPage: 'Seleccionar todo en esta página',
24
26
  /**
25
27
  * La segunda selección — la que el servidor evalúa — lleva el número
@@ -59,6 +61,7 @@
59
61
  loading: 'Cargando…'
60
62
  },
61
63
  pagination: {
64
+ label: 'Páginas',
62
65
  summary: 'Página {{current}} de {{total}} · {{items}} registros',
63
66
  rows: 'Filas',
64
67
  previous: 'Anterior',
@@ -238,7 +241,7 @@
238
241
  finish: 'Finalizar',
239
242
  /**
240
243
  * Un envío que **no** resuelve. El asistente entrega el trabajo y vuelve
241
- * antes de que la escritura termine (ADR 0043), así que dice "enviando" y
244
+ * antes de que la escritura termine, así que dice "enviando" y
242
245
  * nunca "guardado": lo segundo sería una afirmación que el control no puede
243
246
  * comprobar.
244
247
  */ submitting: 'Enviando…',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/i18n/catalog/es.ts"],"sourcesContent":["/**\n * Copy owned by `@entifix/react-controls` — the agnostic entity UI. It lives\n * here rather than next to the components because the typed-key augmentation has\n * to see every namespace from one module, and `@entifix/tooling` (T0) may not\n * import a T3 package.\n */\nexport const controls = {\n table: {\n open: 'Abrir',\n select: 'Seleccionar',\n actions: 'Acciones',\n new: 'Nuevo',\n filters: 'Filtros',\n sorting: 'Orden',\n loading: 'Cargando…',\n empty: 'Sin registros',\n error: 'No se pudieron cargar los registros',\n /**\n * La columna de selección. `selectRow` nombra la fila porque una casilla\n * sin etiqueta visible sólo se anuncia por su `aria-label`, y repetir el\n * encabezado en cada fila no diría cuál es.\n */\n selection: 'Selección',\n selectRow: 'Seleccionar {{record}}',\n selectAllOnPage: 'Seleccionar todo en esta página',\n /**\n * La segunda selección — la que el servidor evalúa — lleva el número\n * siempre: es la diferencia entre actuar sobre 25 filas y sobre 3.200.\n */\n selectAllMatching_one: 'Seleccionar {{count}} coincidencia',\n selectAllMatching_other: 'Seleccionar las {{count}} coincidencias',\n selectedCount_one: '{{count}} seleccionado',\n selectedCount_other: '{{count}} seleccionados',\n clearSelection: 'Limpiar selección',\n },\n /**\n * Una acción sobre una selección. El resultado es por fila, nunca un aviso\n * único: 40 seleccionadas y 3 fallidas no es ni un éxito ni un error.\n */\n bulk: {\n running: 'Ejecutando…',\n succeeded_one: '{{count}} registro actualizado',\n succeeded_other: '{{count}} registros actualizados',\n failed_one: '{{count}} registro falló',\n failed_other: '{{count}} registros fallaron',\n retryFailed: 'Reintentar los fallidos',\n dismiss: 'Cerrar resultado',\n resultLabel: 'Resultado de la acción masiva',\n barLabel: 'Acciones sobre la selección',\n },\n form: {\n details: 'Detalles',\n new: 'Nuevo',\n view: 'Ver',\n edit: 'Editar',\n save: 'Guardar',\n saving: 'Guardando…',\n delete: 'Eliminar',\n deleting: 'Eliminando…',\n clone: 'Duplicar',\n moreActions: 'Más acciones',\n back: 'Volver',\n loading: 'Cargando…',\n },\n pagination: {\n summary: 'Página {{current}} de {{total}} · {{items}} registros',\n rows: 'Filas',\n previous: 'Anterior',\n next: 'Siguiente',\n },\n columns: {\n title: 'Columnas',\n subtitle: 'Visibilidad y orden',\n reset: 'Restablecer',\n moveUp: 'Subir {{column}}',\n moveDown: 'Bajar {{column}}',\n },\n filter: {\n match: 'Coincidir',\n all: 'todos',\n any: 'cualquiera',\n add: 'Añadir filtro',\n apply: 'Aplicar',\n clear: 'Limpiar',\n none: 'Esta entidad no tiene miembros filtrables.',\n listPlaceholder: 'valores, separados, por comas',\n matchAria: 'Coincidir todos o cualquiera de los filtros',\n member: 'Miembro del filtro',\n operator: 'Operador del filtro',\n value: 'Valor del filtro',\n rangeEnd: 'Fin del rango del filtro',\n remove: 'Quitar filtro',\n applyAria: 'Aplicar filtros',\n clearAria: 'Limpiar filtros',\n },\n sort: {\n by: 'Ordenar por',\n then: 'después por',\n ascending: 'ascendente',\n descending: 'descendente',\n add: 'Añadir orden',\n apply: 'Aplicar',\n clear: 'Limpiar',\n none: 'Esta entidad no tiene miembros ordenables.',\n member: 'Miembro de orden',\n direction: 'Dirección de orden',\n raisePriority: 'Subir prioridad de orden',\n lowerPriority: 'Bajar prioridad de orden',\n remove: 'Quitar orden',\n applyAria: 'Aplicar orden',\n clearAria: 'Limpiar orden',\n },\n tabs: {\n close: 'Cerrar {{label}}',\n new: 'Abrir una pestaña nueva',\n },\n /**\n * El editor de una relación. `search` es la búsqueda rápida y `browse` abre el\n * catálogo completo; ambos botones son iconos, así que sus etiquetas `aria` son\n * lo único que un lector de pantalla anuncia.\n */\n link: {\n search: 'Buscar {{field}}',\n suggestAria: 'Ver sugerencias de {{field}}',\n browseAria: 'Examinar {{field}}',\n browseTitle: 'Seleccionar {{field}}',\n clear: 'Quitar {{field}}',\n empty: '— sin asignar —',\n loading: 'Cargando…',\n noResults: 'Sin coincidencias',\n error: 'No se pudieron cargar las opciones',\n close: 'Cerrar',\n },\n /**\n * La rejilla de detalle: las filas que un registro **posee** — las líneas de\n * un pedido, los renglones de una factura. `errorSummary` es el único\n * `role=\"alert\"` del control: un aviso por celda anunciaría la rejilla entera\n * en cada pulsación, y un mensaje que sólo vive en la celda es inalcanzable\n * cuando la fila que falla está fuera de pantalla.\n */\n detail: {\n addRow: 'Añadir fila',\n removeRow: 'Quitar fila {{row}}',\n rowActions: 'Acciones de fila',\n empty: 'Todavía no hay filas.',\n errorSummary_one: '{{count}} celda con errores',\n errorSummary_other: '{{count}} celdas con errores',\n },\n value: {\n none: '— ninguno —',\n yes: 'Sí',\n no: 'No',\n /**\n * Una `composition` en una tabla: sus filas se editan en la pantalla del\n * maestro, no en la celda, así que la celda dice cuántas hay.\n */\n rowCount_one: '{{count}} fila',\n rowCount_other: '{{count}} filas',\n },\n /**\n * `required`…`option` son las reglas derivadas de la metadata. El resto es el\n * vocabulario en el que un Standard Schema de una entidad escribe sus\n * mensajes: el esquema lleva la *clave*, nunca una frase, para que la regla\n * siga siendo traducible.\n *\n * `field` es el único parámetro disponible — un issue de Standard Schema\n * expone un mensaje y una ruta, nada más — así que estos mensajes no indican\n * el límite. Una regla que deba enunciarlo escribe su propia clave en el\n * catálogo de su dominio (`entity:product-specification.validation.codeLength`).\n */\n validation: {\n required: '{{field}} es obligatorio',\n number: '{{field}} debe ser un número',\n date: '{{field}} debe ser una fecha',\n option: '{{field}} no es una opción válida',\n minLength: '{{field}} es demasiado corto',\n maxLength: '{{field}} es demasiado largo',\n min: '{{field}} es demasiado pequeño',\n max: '{{field}} es demasiado grande',\n pattern: '{{field}} tiene un formato inválido',\n minItems_one: '{{field}} necesita al menos {{count}} elemento',\n minItems_other: '{{field}} necesita al menos {{count}} elementos',\n maxItems_one: '{{field}} admite como máximo {{count}} elemento',\n maxItems_other: '{{field}} admite como máximo {{count}} elementos',\n notBefore: '{{field}} no puede ser anterior a {{other}}',\n locale: '{{field}} no tiene texto en {{locale}}',\n },\n /**\n * The filter vocabulary shown to a user. Deliberately distinct from\n * `RSQL_TOKENS` in `@entifix/core` — those are wire tokens (`==`, `=gt=`)\n * and must never be translated.\n */\n operator: {\n eq: 'es',\n ne: 'no es',\n gt: 'mayor que',\n gte: 'mayor o igual',\n lt: 'menor que',\n lte: 'menor o igual',\n in: 'es uno de',\n nin: 'no es ninguno de',\n between: 'entre',\n nbetween: 'fuera de',\n like: 'contiene',\n nlike: 'no contiene',\n isNull: 'está vacío',\n isNotNull: 'no está vacío',\n },\n theme: {\n label: 'Tema',\n },\n /**\n * Captions for the theme presets shipped by `@entifix/style`, plus the\n * per-app brand sets. They name design-system tokens, not app copy, so they\n * live beside the switcher that renders them and stay reachable from\n * Storybook, where no shell is mounted.\n */\n themes: {\n aurora: 'Aurora',\n sunset: 'Atardecer',\n midnight: 'Medianoche',\n ocean: 'Océano (en runtime)',\n marketplace: 'Marketplace',\n marketplaceDark: 'Marketplace oscuro',\n auth: 'Identidad',\n authDark: 'Identidad oscura',\n },\n confirm: {\n confirm: 'Confirmar',\n cancel: 'Cancelar',\n title: 'Confirmar',\n },\n breadcrumbs: {\n label: 'Ruta de navegación',\n },\n /**\n * El asistente. Las etiquetas de cada paso las traduce quien declara el\n * asistente, no el control: un paso es del dominio que lo definió, y su copy\n * vive en `shell:` junto al resto de sus nombres.\n */\n wizard: {\n steps: 'Pasos',\n previous: 'Atrás',\n /**\n * \"Continuar\" y no \"Siguiente\": una tabla dentro de un paso trae su propio\n * paginador, cuyo botón **es** \"Siguiente\". Dos controles con el mismo\n * nombre en la misma pantalla se anuncian igual y hacen cosas distintas.\n */\n next: 'Continuar',\n finish: 'Finalizar',\n /**\n * Un envío que **no** resuelve. El asistente entrega el trabajo y vuelve\n * antes de que la escritura termine (ADR 0043), así que dice \"enviando\" y\n * nunca \"guardado\": lo segundo sería una afirmación que el control no puede\n * comprobar.\n */\n submitting: 'Enviando…',\n stepOf: 'Paso {{current}} de {{total}}',\n goToStep: 'Volver a {{label}}',\n /**\n * El estado de cada paso, anunciado además de mostrarse. El color por sí\n * solo no lo dice, y un lector de pantalla recorre la lista sin verlo.\n */\n status: {\n pending: 'pendiente',\n active: 'en curso',\n complete: 'completado',\n error: 'con errores',\n },\n /**\n * El recordatorio al retomar. La persistencia da el \"continuar\" gratis; lo\n * que no da es acordarse de lo ya decidido, que es la falla conocida de los\n * asistentes largos.\n */\n resume: {\n title: 'Retomando donde lo dejaste',\n dismiss: 'Entendido',\n },\n },\n};\n"],"names":["controls","table","open","select","actions","new","filters","sorting","loading","empty","error","selection","selectRow","selectAllOnPage","selectAllMatching_one","selectAllMatching_other","selectedCount_one","selectedCount_other","clearSelection","bulk","running","succeeded_one","succeeded_other","failed_one","failed_other","retryFailed","dismiss","resultLabel","barLabel","form","details","view","edit","save","saving","delete","deleting","clone","moreActions","back","pagination","summary","rows","previous","next","columns","title","subtitle","reset","moveUp","moveDown","filter","match","all","any","add","apply","clear","none","listPlaceholder","matchAria","member","operator","value","rangeEnd","remove","applyAria","clearAria","sort","by","then","ascending","descending","direction","raisePriority","lowerPriority","tabs","close","link","search","suggestAria","browseAria","browseTitle","noResults","detail","addRow","removeRow","rowActions","errorSummary_one","errorSummary_other","yes","no","rowCount_one","rowCount_other","validation","required","number","date","option","minLength","maxLength","min","max","pattern","minItems_one","minItems_other","maxItems_one","maxItems_other","notBefore","locale","eq","ne","gt","gte","lt","lte","in","nin","between","nbetween","like","nlike","isNull","isNotNull","theme","label","themes","aurora","sunset","midnight","ocean","marketplace","marketplaceDark","auth","authDark","confirm","cancel","breadcrumbs","wizard","steps","finish","submitting","stepOf","goToStep","status","pending","active","complete","resume"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/i18n/catalog/es.ts"],"sourcesContent":["/**\n * Copy owned by `@entifix/react-controls` — the agnostic entity UI. It lives\n * here rather than next to the components because the typed-key augmentation has\n * to see every namespace from one module, and `@entifix/tooling` (T0) may not\n * import a T3 package.\n */\nexport const controls = {\n table: {\n open: 'Abrir',\n select: 'Seleccionar',\n actions: 'Acciones',\n new: 'Nuevo',\n filters: 'Filtros',\n sorting: 'Orden',\n loading: 'Cargando…',\n empty: 'Sin registros',\n error: 'No se pudieron cargar los registros',\n /**\n * La columna de selección. `selectRow` nombra la fila porque una casilla\n * sin etiqueta visible sólo se anuncia por su `aria-label`, y repetir el\n * encabezado en cada fila no diría cuál es.\n */\n selection: 'Selección',\n selectRow: 'Seleccionar {{record}}',\n expandRow: 'Expandir {{record}}',\n collapseRow: 'Contraer {{record}}',\n selectAllOnPage: 'Seleccionar todo en esta página',\n /**\n * La segunda selección — la que el servidor evalúa — lleva el número\n * siempre: es la diferencia entre actuar sobre 25 filas y sobre 3.200.\n */\n selectAllMatching_one: 'Seleccionar {{count}} coincidencia',\n selectAllMatching_other: 'Seleccionar las {{count}} coincidencias',\n selectedCount_one: '{{count}} seleccionado',\n selectedCount_other: '{{count}} seleccionados',\n clearSelection: 'Limpiar selección',\n },\n /**\n * Una acción sobre una selección. El resultado es por fila, nunca un aviso\n * único: 40 seleccionadas y 3 fallidas no es ni un éxito ni un error.\n */\n bulk: {\n running: 'Ejecutando…',\n succeeded_one: '{{count}} registro actualizado',\n succeeded_other: '{{count}} registros actualizados',\n failed_one: '{{count}} registro falló',\n failed_other: '{{count}} registros fallaron',\n retryFailed: 'Reintentar los fallidos',\n dismiss: 'Cerrar resultado',\n resultLabel: 'Resultado de la acción masiva',\n barLabel: 'Acciones sobre la selección',\n },\n form: {\n details: 'Detalles',\n new: 'Nuevo',\n view: 'Ver',\n edit: 'Editar',\n save: 'Guardar',\n saving: 'Guardando…',\n delete: 'Eliminar',\n deleting: 'Eliminando…',\n clone: 'Duplicar',\n moreActions: 'Más acciones',\n back: 'Volver',\n loading: 'Cargando…',\n },\n pagination: {\n label: 'Páginas',\n summary: 'Página {{current}} de {{total}} · {{items}} registros',\n rows: 'Filas',\n previous: 'Anterior',\n next: 'Siguiente',\n },\n columns: {\n title: 'Columnas',\n subtitle: 'Visibilidad y orden',\n reset: 'Restablecer',\n moveUp: 'Subir {{column}}',\n moveDown: 'Bajar {{column}}',\n },\n filter: {\n match: 'Coincidir',\n all: 'todos',\n any: 'cualquiera',\n add: 'Añadir filtro',\n apply: 'Aplicar',\n clear: 'Limpiar',\n none: 'Esta entidad no tiene miembros filtrables.',\n listPlaceholder: 'valores, separados, por comas',\n matchAria: 'Coincidir todos o cualquiera de los filtros',\n member: 'Miembro del filtro',\n operator: 'Operador del filtro',\n value: 'Valor del filtro',\n rangeEnd: 'Fin del rango del filtro',\n remove: 'Quitar filtro',\n applyAria: 'Aplicar filtros',\n clearAria: 'Limpiar filtros',\n },\n sort: {\n by: 'Ordenar por',\n then: 'después por',\n ascending: 'ascendente',\n descending: 'descendente',\n add: 'Añadir orden',\n apply: 'Aplicar',\n clear: 'Limpiar',\n none: 'Esta entidad no tiene miembros ordenables.',\n member: 'Miembro de orden',\n direction: 'Dirección de orden',\n raisePriority: 'Subir prioridad de orden',\n lowerPriority: 'Bajar prioridad de orden',\n remove: 'Quitar orden',\n applyAria: 'Aplicar orden',\n clearAria: 'Limpiar orden',\n },\n tabs: {\n close: 'Cerrar {{label}}',\n new: 'Abrir una pestaña nueva',\n },\n /**\n * El editor de una relación. `search` es la búsqueda rápida y `browse` abre el\n * catálogo completo; ambos botones son iconos, así que sus etiquetas `aria` son\n * lo único que un lector de pantalla anuncia.\n */\n link: {\n search: 'Buscar {{field}}',\n suggestAria: 'Ver sugerencias de {{field}}',\n browseAria: 'Examinar {{field}}',\n browseTitle: 'Seleccionar {{field}}',\n clear: 'Quitar {{field}}',\n empty: '— sin asignar —',\n loading: 'Cargando…',\n noResults: 'Sin coincidencias',\n error: 'No se pudieron cargar las opciones',\n close: 'Cerrar',\n },\n /**\n * La rejilla de detalle: las filas que un registro **posee** — las líneas de\n * un pedido, los renglones de una factura. `errorSummary` es el único\n * `role=\"alert\"` del control: un aviso por celda anunciaría la rejilla entera\n * en cada pulsación, y un mensaje que sólo vive en la celda es inalcanzable\n * cuando la fila que falla está fuera de pantalla.\n */\n detail: {\n addRow: 'Añadir fila',\n removeRow: 'Quitar fila {{row}}',\n rowActions: 'Acciones de fila',\n empty: 'Todavía no hay filas.',\n errorSummary_one: '{{count}} celda con errores',\n errorSummary_other: '{{count}} celdas con errores',\n },\n value: {\n none: '— ninguno —',\n yes: 'Sí',\n no: 'No',\n /**\n * Una `composition` en una tabla: sus filas se editan en la pantalla del\n * maestro, no en la celda, así que la celda dice cuántas hay.\n */\n rowCount_one: '{{count}} fila',\n rowCount_other: '{{count}} filas',\n },\n /**\n * `required`…`option` son las reglas derivadas de la metadata. El resto es el\n * vocabulario en el que un Standard Schema de una entidad escribe sus\n * mensajes: el esquema lleva la *clave*, nunca una frase, para que la regla\n * siga siendo traducible.\n *\n * `field` es el único parámetro disponible — un issue de Standard Schema\n * expone un mensaje y una ruta, nada más — así que estos mensajes no indican\n * el límite. Una regla que deba enunciarlo escribe su propia clave en el\n * catálogo de su dominio (`entity:product-specification.validation.codeLength`).\n */\n validation: {\n required: '{{field}} es obligatorio',\n number: '{{field}} debe ser un número',\n date: '{{field}} debe ser una fecha',\n option: '{{field}} no es una opción válida',\n minLength: '{{field}} es demasiado corto',\n maxLength: '{{field}} es demasiado largo',\n min: '{{field}} es demasiado pequeño',\n max: '{{field}} es demasiado grande',\n pattern: '{{field}} tiene un formato inválido',\n minItems_one: '{{field}} necesita al menos {{count}} elemento',\n minItems_other: '{{field}} necesita al menos {{count}} elementos',\n maxItems_one: '{{field}} admite como máximo {{count}} elemento',\n maxItems_other: '{{field}} admite como máximo {{count}} elementos',\n notBefore: '{{field}} no puede ser anterior a {{other}}',\n locale: '{{field}} no tiene texto en {{locale}}',\n },\n /**\n * The filter vocabulary shown to a user. Deliberately distinct from\n * `RSQL_TOKENS` in `@entifix/core` — those are wire tokens (`==`, `=gt=`)\n * and must never be translated.\n */\n operator: {\n eq: 'es',\n ne: 'no es',\n gt: 'mayor que',\n gte: 'mayor o igual',\n lt: 'menor que',\n lte: 'menor o igual',\n in: 'es uno de',\n nin: 'no es ninguno de',\n between: 'entre',\n nbetween: 'fuera de',\n like: 'contiene',\n nlike: 'no contiene',\n isNull: 'está vacío',\n isNotNull: 'no está vacío',\n },\n theme: {\n label: 'Tema',\n },\n /**\n * Captions for the theme presets shipped by `@entifix/style`, plus the\n * per-app brand sets. They name design-system tokens, not app copy, so they\n * live beside the switcher that renders them and stay reachable from\n * Storybook, where no shell is mounted.\n */\n themes: {\n aurora: 'Aurora',\n sunset: 'Atardecer',\n midnight: 'Medianoche',\n ocean: 'Océano (en runtime)',\n marketplace: 'Marketplace',\n marketplaceDark: 'Marketplace oscuro',\n auth: 'Identidad',\n authDark: 'Identidad oscura',\n },\n confirm: {\n confirm: 'Confirmar',\n cancel: 'Cancelar',\n title: 'Confirmar',\n },\n breadcrumbs: {\n label: 'Ruta de navegación',\n },\n /**\n * El asistente. Las etiquetas de cada paso las traduce quien declara el\n * asistente, no el control: un paso es del dominio que lo definió, y su copy\n * vive en `shell:` junto al resto de sus nombres.\n */\n wizard: {\n steps: 'Pasos',\n previous: 'Atrás',\n /**\n * \"Continuar\" y no \"Siguiente\": una tabla dentro de un paso trae su propio\n * paginador, cuyo botón **es** \"Siguiente\". Dos controles con el mismo\n * nombre en la misma pantalla se anuncian igual y hacen cosas distintas.\n */\n next: 'Continuar',\n finish: 'Finalizar',\n /**\n * Un envío que **no** resuelve. El asistente entrega el trabajo y vuelve\n * antes de que la escritura termine, así que dice \"enviando\" y\n * nunca \"guardado\": lo segundo sería una afirmación que el control no puede\n * comprobar.\n */\n submitting: 'Enviando…',\n stepOf: 'Paso {{current}} de {{total}}',\n goToStep: 'Volver a {{label}}',\n /**\n * El estado de cada paso, anunciado además de mostrarse. El color por sí\n * solo no lo dice, y un lector de pantalla recorre la lista sin verlo.\n */\n status: {\n pending: 'pendiente',\n active: 'en curso',\n complete: 'completado',\n error: 'con errores',\n },\n /**\n * El recordatorio al retomar. La persistencia da el \"continuar\" gratis; lo\n * que no da es acordarse de lo ya decidido, que es la falla conocida de los\n * asistentes largos.\n */\n resume: {\n title: 'Retomando donde lo dejaste',\n dismiss: 'Entendido',\n },\n },\n};\n"],"names":["controls","table","open","select","actions","new","filters","sorting","loading","empty","error","selection","selectRow","expandRow","collapseRow","selectAllOnPage","selectAllMatching_one","selectAllMatching_other","selectedCount_one","selectedCount_other","clearSelection","bulk","running","succeeded_one","succeeded_other","failed_one","failed_other","retryFailed","dismiss","resultLabel","barLabel","form","details","view","edit","save","saving","delete","deleting","clone","moreActions","back","pagination","label","summary","rows","previous","next","columns","title","subtitle","reset","moveUp","moveDown","filter","match","all","any","add","apply","clear","none","listPlaceholder","matchAria","member","operator","value","rangeEnd","remove","applyAria","clearAria","sort","by","then","ascending","descending","direction","raisePriority","lowerPriority","tabs","close","link","search","suggestAria","browseAria","browseTitle","noResults","detail","addRow","removeRow","rowActions","errorSummary_one","errorSummary_other","yes","no","rowCount_one","rowCount_other","validation","required","number","date","option","minLength","maxLength","min","max","pattern","minItems_one","minItems_other","maxItems_one","maxItems_other","notBefore","locale","eq","ne","gt","gte","lt","lte","in","nin","between","nbetween","like","nlike","isNull","isNotNull","theme","themes","aurora","sunset","midnight","ocean","marketplace","marketplaceDark","auth","authDark","confirm","cancel","breadcrumbs","wizard","steps","finish","submitting","stepOf","goToStep","status","pending","active","complete","resume"],"mappings":"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"}
@@ -22,6 +22,8 @@ export declare const controlsCatalogs: {
22
22
  error: string;
23
23
  selection: string;
24
24
  selectRow: string;
25
+ expandRow: string;
26
+ collapseRow: string;
25
27
  selectAllOnPage: string;
26
28
  selectAllMatching_one: string;
27
29
  selectAllMatching_other: string;
@@ -55,6 +57,7 @@ export declare const controlsCatalogs: {
55
57
  loading: string;
56
58
  };
57
59
  pagination: {
60
+ label: string;
58
61
  summary: string;
59
62
  rows: string;
60
63
  previous: string;
@@ -222,6 +225,8 @@ export declare const controlsCatalogs: {
222
225
  error: string;
223
226
  selection: string;
224
227
  selectRow: string;
228
+ expandRow: string;
229
+ collapseRow: string;
225
230
  selectAllOnPage: string;
226
231
  selectAllMatching_one: string;
227
232
  selectAllMatching_other: string;
@@ -255,6 +260,7 @@ export declare const controlsCatalogs: {
255
260
  loading: string;
256
261
  };
257
262
  pagination: {
263
+ label: string;
258
264
  summary: string;
259
265
  rows: string;
260
266
  previous: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/i18n/catalog/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGnB,CAAC;AAEX,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AAEhE,eAAO,MAAM,mBAAmB,uBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/i18n/catalog/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGnB,CAAC;AAEX,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AAEhE,eAAO,MAAM,mBAAmB,uBAAwB,CAAC"}
@@ -16,7 +16,6 @@ export type ViewportMode = 'compact' | 'rail' | 'wide';
16
16
  * with `flex-wrap`/`flex-basis`/`gap`, and `Sidebar` still does. Choosing
17
17
  * between a drawer and a persistent rail is not laying out a box — it is picking
18
18
  * a navigation *mode*, and no amount of intrinsic sizing produces a focus trap.
19
- * See ADR 0041.
20
19
  *
21
20
  * It lives beside the UI preferences rather than in `ui/` because it belongs to
22
21
  * the same decision: what the viewport allows and what the person chose are the
@@ -1 +1 @@
1
- {"version":3,"file":"use-viewport-mode.d.ts","sourceRoot":"","sources":["../../src/preferences/use-viewport-mode.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAUvD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,IAAI,YAAY,CA+B9C;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,UA3DJ,MAAM,KAAG,YA2DK,CAAC"}
1
+ {"version":3,"file":"use-viewport-mode.d.ts","sourceRoot":"","sources":["../../src/preferences/use-viewport-mode.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAUvD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,IAAI,YAAY,CA+B9C;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,UA1DJ,MAAM,KAAG,YA0DK,CAAC"}
@@ -15,7 +15,6 @@ const modeFor = (width)=>{
15
15
  * with `flex-wrap`/`flex-basis`/`gap`, and `Sidebar` still does. Choosing
16
16
  * between a drawer and a persistent rail is not laying out a box — it is picking
17
17
  * a navigation *mode*, and no amount of intrinsic sizing produces a focus trap.
18
- * See ADR 0041.
19
18
  *
20
19
  * It lives beside the UI preferences rather than in `ui/` because it belongs to
21
20
  * the same decision: what the viewport allows and what the person chose are the
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/preferences/use-viewport-mode.ts"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\n\n/**\n * How much room the viewport has for chrome.\n *\n * - `compact` — under 768px. Navigation belongs behind a drawer; there is no\n * room for a persistent rail beside the content.\n * - `rail` — 768px to 1024px. Enough for icons, not for labels.\n * - `wide` — 1024px and up. The stored preference decides.\n */\nexport type ViewportMode = 'compact' | 'rail' | 'wide';\n\nconst RAIL_MIN = 768;\nconst WIDE_MIN = 1024;\n\nconst modeFor = (width: number): ViewportMode => {\n if (width < RAIL_MIN) return 'compact';\n return width < WIDE_MIN ? 'rail' : 'wide';\n};\n\n/**\n * The viewport mode, as a media query the shell may branch on.\n *\n * ⚠️ This is the one place in the design system that asks about the viewport,\n * and it is deliberate. `docs/FRONTEND.md`'s no-media-query rule governs the\n * **layout primitives** in `ui/layout/`: they lay themselves out intrinsically\n * with `flex-wrap`/`flex-basis`/`gap`, and `Sidebar` still does. Choosing\n * between a drawer and a persistent rail is not laying out a box — it is picking\n * a navigation *mode*, and no amount of intrinsic sizing produces a focus trap.\n * See ADR 0041.\n *\n * It lives beside the UI preferences rather than in `ui/` because it belongs to\n * the same decision: what the viewport allows and what the person chose are the\n * two inputs to one answer, and only the second is a preference.\n *\n * Resolved in an effect, not during render, and defaulting to `wide`. The server\n * has no viewport, so any other default would render markup the first client\n * pass immediately contradicts — the same reason `useUiPreference` reads after\n * mount rather than during it.\n */\nexport function useViewportMode(): ViewportMode {\n const [mode, setMode] = useState<ViewportMode>('wide');\n\n useEffect(() => {\n // `typeof`, not `'matchMedia' in window`: jsdom declares the property and\n // leaves it uncallable, so the `in` check passes and the call then throws\n // inside a passive effect — which surfaces as a broken shell, not a missing\n // media query.\n if (\n typeof window === 'undefined' ||\n typeof window.matchMedia !== 'function'\n )\n return;\n\n const compact = window.matchMedia(`(max-width: ${RAIL_MIN - 1}px)`);\n const wide = window.matchMedia(`(min-width: ${WIDE_MIN}px)`);\n\n const sync = () => {\n setMode(compact.matches ? 'compact' : wide.matches ? 'wide' : 'rail');\n };\n\n sync();\n compact.addEventListener('change', sync);\n wide.addEventListener('change', sync);\n return () => {\n compact.removeEventListener('change', sync);\n wide.removeEventListener('change', sync);\n };\n }, []);\n\n return mode;\n}\n\n/** Exported for tests and for callers that already hold a width. */\nexport const viewportModeFor = modeFor;\n"],"names":["useEffect","useState","RAIL_MIN","WIDE_MIN","modeFor","width","useViewportMode","mode","setMode","window","matchMedia","compact","wide","sync","matches","addEventListener","removeEventListener","viewportModeFor"],"mappings":"AAAA;AAEA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAY5C,MAAMC,WAAW;AACjB,MAAMC,WAAW;AAEjB,MAAMC,UAAU,CAACC;IACf,IAAIA,QAAQH,UAAU,OAAO;IAC7B,OAAOG,QAAQF,WAAW,SAAS;AACrC;AAEA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,SAASG;IACd,MAAM,CAACC,MAAMC,QAAQ,GAAGP,SAAuB;IAE/CD,UAAU;QACR,0EAA0E;QAC1E,0EAA0E;QAC1E,4EAA4E;QAC5E,eAAe;QACf,IACE,OAAOS,WAAW,eAClB,OAAOA,OAAOC,UAAU,KAAK,YAE7B;QAEF,MAAMC,UAAUF,OAAOC,UAAU,CAAC,CAAC,YAAY,EAAER,WAAW,EAAE,GAAG,CAAC;QAClE,MAAMU,OAAOH,OAAOC,UAAU,CAAC,CAAC,YAAY,EAAEP,SAAS,GAAG,CAAC;QAE3D,MAAMU,OAAO;YACXL,QAAQG,QAAQG,OAAO,GAAG,YAAYF,KAAKE,OAAO,GAAG,SAAS;QAChE;QAEAD;QACAF,QAAQI,gBAAgB,CAAC,UAAUF;QACnCD,KAAKG,gBAAgB,CAAC,UAAUF;QAChC,OAAO;YACLF,QAAQK,mBAAmB,CAAC,UAAUH;YACtCD,KAAKI,mBAAmB,CAAC,UAAUH;QACrC;IACF,GAAG,EAAE;IAEL,OAAON;AACT;AAEA,kEAAkE,GAClE,OAAO,MAAMU,kBAAkBb,QAAQ"}
1
+ {"version":3,"sources":["../../src/preferences/use-viewport-mode.ts"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\n\n/**\n * How much room the viewport has for chrome.\n *\n * - `compact` — under 768px. Navigation belongs behind a drawer; there is no\n * room for a persistent rail beside the content.\n * - `rail` — 768px to 1024px. Enough for icons, not for labels.\n * - `wide` — 1024px and up. The stored preference decides.\n */\nexport type ViewportMode = 'compact' | 'rail' | 'wide';\n\nconst RAIL_MIN = 768;\nconst WIDE_MIN = 1024;\n\nconst modeFor = (width: number): ViewportMode => {\n if (width < RAIL_MIN) return 'compact';\n return width < WIDE_MIN ? 'rail' : 'wide';\n};\n\n/**\n * The viewport mode, as a media query the shell may branch on.\n *\n * ⚠️ This is the one place in the design system that asks about the viewport,\n * and it is deliberate. `docs/FRONTEND.md`'s no-media-query rule governs the\n * **layout primitives** in `ui/layout/`: they lay themselves out intrinsically\n * with `flex-wrap`/`flex-basis`/`gap`, and `Sidebar` still does. Choosing\n * between a drawer and a persistent rail is not laying out a box — it is picking\n * a navigation *mode*, and no amount of intrinsic sizing produces a focus trap.\n *\n * It lives beside the UI preferences rather than in `ui/` because it belongs to\n * the same decision: what the viewport allows and what the person chose are the\n * two inputs to one answer, and only the second is a preference.\n *\n * Resolved in an effect, not during render, and defaulting to `wide`. The server\n * has no viewport, so any other default would render markup the first client\n * pass immediately contradicts — the same reason `useUiPreference` reads after\n * mount rather than during it.\n */\nexport function useViewportMode(): ViewportMode {\n const [mode, setMode] = useState<ViewportMode>('wide');\n\n useEffect(() => {\n // `typeof`, not `'matchMedia' in window`: jsdom declares the property and\n // leaves it uncallable, so the `in` check passes and the call then throws\n // inside a passive effect — which surfaces as a broken shell, not a missing\n // media query.\n if (\n typeof window === 'undefined' ||\n typeof window.matchMedia !== 'function'\n )\n return;\n\n const compact = window.matchMedia(`(max-width: ${RAIL_MIN - 1}px)`);\n const wide = window.matchMedia(`(min-width: ${WIDE_MIN}px)`);\n\n const sync = () => {\n setMode(compact.matches ? 'compact' : wide.matches ? 'wide' : 'rail');\n };\n\n sync();\n compact.addEventListener('change', sync);\n wide.addEventListener('change', sync);\n return () => {\n compact.removeEventListener('change', sync);\n wide.removeEventListener('change', sync);\n };\n }, []);\n\n return mode;\n}\n\n/** Exported for tests and for callers that already hold a width. */\nexport const viewportModeFor = modeFor;\n"],"names":["useEffect","useState","RAIL_MIN","WIDE_MIN","modeFor","width","useViewportMode","mode","setMode","window","matchMedia","compact","wide","sync","matches","addEventListener","removeEventListener","viewportModeFor"],"mappings":"AAAA;AAEA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAY5C,MAAMC,WAAW;AACjB,MAAMC,WAAW;AAEjB,MAAMC,UAAU,CAACC;IACf,IAAIA,QAAQH,UAAU,OAAO;IAC7B,OAAOG,QAAQF,WAAW,SAAS;AACrC;AAEA;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASG;IACd,MAAM,CAACC,MAAMC,QAAQ,GAAGP,SAAuB;IAE/CD,UAAU;QACR,0EAA0E;QAC1E,0EAA0E;QAC1E,4EAA4E;QAC5E,eAAe;QACf,IACE,OAAOS,WAAW,eAClB,OAAOA,OAAOC,UAAU,KAAK,YAE7B;QAEF,MAAMC,UAAUF,OAAOC,UAAU,CAAC,CAAC,YAAY,EAAER,WAAW,EAAE,GAAG,CAAC;QAClE,MAAMU,OAAOH,OAAOC,UAAU,CAAC,CAAC,YAAY,EAAEP,SAAS,GAAG,CAAC;QAE3D,MAAMU,OAAO;YACXL,QAAQG,QAAQG,OAAO,GAAG,YAAYF,KAAKE,OAAO,GAAG,SAAS;QAChE;QAEAD;QACAF,QAAQI,gBAAgB,CAAC,UAAUF;QACnCD,KAAKG,gBAAgB,CAAC,UAAUF;QAChC,OAAO;YACLF,QAAQK,mBAAmB,CAAC,UAAUH;YACtCD,KAAKI,mBAAmB,CAAC,UAAUH;QACrC;IACF,GAAG,EAAE;IAEL,OAAON;AACT;AAEA,kEAAkE,GAClE,OAAO,MAAMU,kBAAkBb,QAAQ"}
@@ -2,13 +2,13 @@ import { type UseCaseDescriptor } from '@entifix/core';
2
2
  /**
3
3
  * Where a declared verb is rendered.
4
4
  *
5
- * ADR 0026 gave a use case two independent axes and then built only one
5
+ * The use-case descriptor has two independent axes, and at first only one
6
6
  * surface, so four of the nine cells had nowhere to go: `EntityForm` filtered
7
7
  * `binding === 'entity' && placement !== 'context-dependent'` and everything
8
8
  * else was dropped without a word. This is the map that closes it —
9
9
  * **placement decides the surface, binding decides the payload** — and it lives
10
10
  * in one module so no surface re-derives it and the two axes cannot drift
11
- * apart again ([ADR 0035](../../../../../../docs/adr/0035-entity-actions-selection-and-bulk.md)).
11
+ * apart again.
12
12
  */
13
13
  export declare const ACTION_SURFACES: readonly ["form-header", "form-footer", "row-menu", "bulk-bar", "table-toolbar", "command-palette"];
14
14
  export type ActionSurface = (typeof ACTION_SURFACES)[number];
@@ -27,7 +27,7 @@ export declare const OVERFLOW_GLYPH = "\u22EF";
27
27
  *
28
28
  * ⚠️ **A verb may name more than one cell**, and that is what makes publishing
29
29
  * reachable from a form header, a row menu and a selection without becoming
30
- * three permissions (#216). The primary `binding` + `placement` come first, then
30
+ * three permissions. The primary `binding` + `placement` come first, then
31
31
  * whatever `alsoAt` adds, and each is validated the same way — an illegal cell
32
32
  * in `alsoAt` throws exactly as one in the primary pair does.
33
33
  *
@@ -2,13 +2,13 @@ import { EntifixLogicError } from '@entifix/core';
2
2
  /**
3
3
  * Where a declared verb is rendered.
4
4
  *
5
- * ADR 0026 gave a use case two independent axes and then built only one
5
+ * The use-case descriptor has two independent axes, and at first only one
6
6
  * surface, so four of the nine cells had nowhere to go: `EntityForm` filtered
7
7
  * `binding === 'entity' && placement !== 'context-dependent'` and everything
8
8
  * else was dropped without a word. This is the map that closes it —
9
9
  * **placement decides the surface, binding decides the payload** — and it lives
10
10
  * in one module so no surface re-derives it and the two axes cannot drift
11
- * apart again ([ADR 0035](../../../../../../docs/adr/0035-entity-actions-selection-and-bulk.md)).
11
+ * apart again.
12
12
  */ export const ACTION_SURFACES = [
13
13
  'form-header',
14
14
  'form-footer',
@@ -25,7 +25,7 @@ import { EntifixLogicError } from '@entifix/core';
25
25
  * page* — it is the footer that ends an object page — and a list screen has no
26
26
  * such thing to finalize, which is Fiori's own rule. Dropping it silently is
27
27
  * the fault this repo already writes an assertion against elsewhere: the verb
28
- * would be declared, granted, exported, pass every `@r10c/slices` invariant,
28
+ * would be declared, granted, exported, pass every check a register runs,
29
29
  * and simply never appear, which reads to its author as "the permission is
30
30
  * wrong" and sends them looking in the wrong place entirely.
31
31
  */ const SURFACE_BY_CELL = {
@@ -63,7 +63,7 @@ import { EntifixLogicError } from '@entifix/core';
63
63
  *
64
64
  * ⚠️ **A verb may name more than one cell**, and that is what makes publishing
65
65
  * reachable from a form header, a row menu and a selection without becoming
66
- * three permissions (#216). The primary `binding` + `placement` come first, then
66
+ * three permissions. The primary `binding` + `placement` come first, then
67
67
  * whatever `alsoAt` adds, and each is validated the same way — an illegal cell
68
68
  * in `alsoAt` throws exactly as one in the primary pair does.
69
69
  *
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/actions/action-surfaces.ts"],"sourcesContent":["import {\n EntifixLogicError,\n type UseCaseBinding,\n type UseCaseDescriptor,\n type UseCasePlacement,\n} from '@entifix/core';\n\n/**\n * Where a declared verb is rendered.\n *\n * ADR 0026 gave a use case two independent axes and then built only one\n * surface, so four of the nine cells had nowhere to go: `EntityForm` filtered\n * `binding === 'entity' && placement !== 'context-dependent'` and everything\n * else was dropped without a word. This is the map that closes it —\n * **placement decides the surface, binding decides the payload** — and it lives\n * in one module so no surface re-derives it and the two axes cannot drift\n * apart again ([ADR 0035](../../../../../../docs/adr/0035-entity-actions-selection-and-bulk.md)).\n */\nexport const ACTION_SURFACES = [\n 'form-header',\n 'form-footer',\n 'row-menu',\n 'bulk-bar',\n 'table-toolbar',\n 'command-palette',\n] as const;\nexport type ActionSurface = (typeof ACTION_SURFACES)[number];\n\n/**\n * The nine cells, exhaustively.\n *\n * `collection` + `determining` is deliberately absent, and asking for it\n * throws rather than returning `undefined`. A determining action *finalizes a\n * page* — it is the footer that ends an object page — and a list screen has no\n * such thing to finalize, which is Fiori's own rule. Dropping it silently is\n * the fault this repo already writes an assertion against elsewhere: the verb\n * would be declared, granted, exported, pass every `@r10c/slices` invariant,\n * and simply never appear, which reads to its author as \"the permission is\n * wrong\" and sends them looking in the wrong place entirely.\n */\nconst SURFACE_BY_CELL: Record<string, ActionSurface> = {\n 'entity:context-independent': 'form-header',\n 'entity:determining': 'form-footer',\n 'entity:context-dependent': 'row-menu',\n 'collection:context-dependent': 'bulk-bar',\n 'collection:context-independent': 'table-toolbar',\n 'unbound:context-dependent': 'command-palette',\n 'unbound:context-independent': 'command-palette',\n 'unbound:determining': 'command-palette',\n};\n\n/**\n * The overflow trigger's glyph.\n *\n * A constant rather than a literal in JSX, because `react/jsx-no-literals`\n * fails the build on written-in copy and is right to: it cannot tell a\n * typographic glyph from a forgotten Spanish string. The trigger's *name* is a\n * catalog key (`form.moreActions`, `table.actions`) — this is only the mark,\n * and it is never read aloud.\n */\nexport const OVERFLOW_GLYPH = '\\u22ef';\n\n/** Which surface renders one cell. Throws on a cell no surface owns. */\nfunction surfaceForCell(\n key: string,\n binding: UseCaseBinding,\n placement: UseCasePlacement,\n): ActionSurface {\n const surface = SURFACE_BY_CELL[`${binding}:${placement}`];\n\n if (surface === undefined) {\n throw new EntifixLogicError(\n `The use case \"${key}\" is declared ${binding} + ${placement}, which no surface renders. ` +\n 'A `determining` action finalizes a page — it is an object page’s footer — and a list ' +\n 'screen has no page to finalize, so a collection-bound verb cannot be determining. ' +\n 'Declare it `context-dependent` to reach the bulk bar, or `context-independent` to sit ' +\n 'in the table toolbar.',\n undefined,\n { key, binding, placement },\n );\n }\n\n return surface;\n}\n\n/**\n * Every surface this descriptor renders on.\n *\n * ⚠️ **A verb may name more than one cell**, and that is what makes publishing\n * reachable from a form header, a row menu and a selection without becoming\n * three permissions (#216). The primary `binding` + `placement` come first, then\n * whatever `alsoAt` adds, and each is validated the same way — an illegal cell\n * in `alsoAt` throws exactly as one in the primary pair does.\n *\n * Duplicates are collapsed. A descriptor that named the same cell twice would\n * otherwise render the verb twice in one menu, which reads as a bug in the\n * screen rather than in the declaration.\n */\nexport function surfacesFor(\n descriptor: UseCaseDescriptor,\n): readonly ActionSurface[] {\n const cells = [\n { binding: descriptor.binding, placement: descriptor.placement },\n ...(descriptor.alsoAt ?? []),\n ];\n\n return [\n ...new Set(\n cells.map(cell =>\n surfaceForCell(descriptor.key, cell.binding, cell.placement),\n ),\n ),\n ];\n}\n\n/**\n * The single surface this descriptor renders on.\n *\n * Kept for the callers that genuinely have one — the command palette asks \"is\n * this mine?\" of an `unbound` verb, which can only ever be in one place. Any\n * caller that renders a *list* of verbs wants {@link surfacesFor}.\n */\nexport function surfaceFor(descriptor: UseCaseDescriptor): ActionSurface {\n return surfaceForCell(\n descriptor.key,\n descriptor.binding,\n descriptor.placement,\n );\n}\n\n/**\n * The descriptors one surface should render, in declaration order.\n *\n * Every descriptor is passed through {@link surfacesFor}, so an unrenderable\n * cell throws on the **first render of any surface** rather than only on the\n * one that would have shown it — the same reason\n * `assertLinkSourcesAreEditable` runs as one pass over the registry instead of\n * per row: a check that only fires on the screen that was already looking for\n * the verb is a check that fires after the bug is reported. A cell declared in\n * `alsoAt` is validated on that same first render, not on the surface it names.\n */\nexport function useCasesForSurface(\n surface: ActionSurface,\n useCases: readonly UseCaseDescriptor[] | undefined,\n): UseCaseDescriptor[] {\n return (useCases ?? []).filter(descriptor =>\n surfacesFor(descriptor).includes(surface),\n );\n}\n"],"names":["EntifixLogicError","ACTION_SURFACES","SURFACE_BY_CELL","OVERFLOW_GLYPH","surfaceForCell","key","binding","placement","surface","undefined","surfacesFor","descriptor","cells","alsoAt","Set","map","cell","surfaceFor","useCasesForSurface","useCases","filter","includes"],"mappings":"AAAA,SACEA,iBAAiB,QAIZ,gBAAgB;AAEvB;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,kBAAkB;IAC7B;IACA;IACA;IACA;IACA;IACA;CACD,CAAU;AAGX;;;;;;;;;;;CAWC,GACD,MAAMC,kBAAiD;IACrD,8BAA8B;IAC9B,sBAAsB;IACtB,4BAA4B;IAC5B,gCAAgC;IAChC,kCAAkC;IAClC,6BAA6B;IAC7B,+BAA+B;IAC/B,uBAAuB;AACzB;AAEA;;;;;;;;CAQC,GACD,OAAO,MAAMC,iBAAiB,SAAS;AAEvC,sEAAsE,GACtE,SAASC,eACPC,GAAW,EACXC,OAAuB,EACvBC,SAA2B;IAE3B,MAAMC,UAAUN,eAAe,CAAC,GAAGI,QAAQ,CAAC,EAAEC,WAAW,CAAC;IAE1D,IAAIC,YAAYC,WAAW;QACzB,MAAM,IAAIT,kBACR,CAAC,cAAc,EAAEK,IAAI,cAAc,EAAEC,QAAQ,GAAG,EAAEC,UAAU,4BAA4B,CAAC,GACvF,0FACA,uFACA,2FACA,yBACFE,WACA;YAAEJ;YAAKC;YAASC;QAAU;IAE9B;IAEA,OAAOC;AACT;AAEA;;;;;;;;;;;;CAYC,GACD,OAAO,SAASE,YACdC,UAA6B;QAIvBA;IAFN,MAAMC,QAAQ;QACZ;YAAEN,SAASK,WAAWL,OAAO;YAAEC,WAAWI,WAAWJ,SAAS;QAAC;YAC3DI,qBAAAA,WAAWE,MAAM,YAAjBF,qBAAqB,EAAE;KAC5B;IAED,OAAO;WACF,IAAIG,IACLF,MAAMG,GAAG,CAACC,CAAAA,OACRZ,eAAeO,WAAWN,GAAG,EAAEW,KAAKV,OAAO,EAAEU,KAAKT,SAAS;KAGhE;AACH;AAEA;;;;;;CAMC,GACD,OAAO,SAASU,WAAWN,UAA6B;IACtD,OAAOP,eACLO,WAAWN,GAAG,EACdM,WAAWL,OAAO,EAClBK,WAAWJ,SAAS;AAExB;AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASW,mBACdV,OAAsB,EACtBW,QAAkD;IAElD,OAAO,CAACA,mBAAAA,WAAY,EAAE,EAAEC,MAAM,CAACT,CAAAA,aAC7BD,YAAYC,YAAYU,QAAQ,CAACb;AAErC"}
1
+ {"version":3,"sources":["../../../src/ui/actions/action-surfaces.ts"],"sourcesContent":["import {\n EntifixLogicError,\n type UseCaseBinding,\n type UseCaseDescriptor,\n type UseCasePlacement,\n} from '@entifix/core';\n\n/**\n * Where a declared verb is rendered.\n *\n * The use-case descriptor has two independent axes, and at first only one\n * surface, so four of the nine cells had nowhere to go: `EntityForm` filtered\n * `binding === 'entity' && placement !== 'context-dependent'` and everything\n * else was dropped without a word. This is the map that closes it —\n * **placement decides the surface, binding decides the payload** — and it lives\n * in one module so no surface re-derives it and the two axes cannot drift\n * apart again.\n */\nexport const ACTION_SURFACES = [\n 'form-header',\n 'form-footer',\n 'row-menu',\n 'bulk-bar',\n 'table-toolbar',\n 'command-palette',\n] as const;\nexport type ActionSurface = (typeof ACTION_SURFACES)[number];\n\n/**\n * The nine cells, exhaustively.\n *\n * `collection` + `determining` is deliberately absent, and asking for it\n * throws rather than returning `undefined`. A determining action *finalizes a\n * page* — it is the footer that ends an object page — and a list screen has no\n * such thing to finalize, which is Fiori's own rule. Dropping it silently is\n * the fault this repo already writes an assertion against elsewhere: the verb\n * would be declared, granted, exported, pass every check a register runs,\n * and simply never appear, which reads to its author as \"the permission is\n * wrong\" and sends them looking in the wrong place entirely.\n */\nconst SURFACE_BY_CELL: Record<string, ActionSurface> = {\n 'entity:context-independent': 'form-header',\n 'entity:determining': 'form-footer',\n 'entity:context-dependent': 'row-menu',\n 'collection:context-dependent': 'bulk-bar',\n 'collection:context-independent': 'table-toolbar',\n 'unbound:context-dependent': 'command-palette',\n 'unbound:context-independent': 'command-palette',\n 'unbound:determining': 'command-palette',\n};\n\n/**\n * The overflow trigger's glyph.\n *\n * A constant rather than a literal in JSX, because `react/jsx-no-literals`\n * fails the build on written-in copy and is right to: it cannot tell a\n * typographic glyph from a forgotten Spanish string. The trigger's *name* is a\n * catalog key (`form.moreActions`, `table.actions`) — this is only the mark,\n * and it is never read aloud.\n */\nexport const OVERFLOW_GLYPH = '\\u22ef';\n\n/** Which surface renders one cell. Throws on a cell no surface owns. */\nfunction surfaceForCell(\n key: string,\n binding: UseCaseBinding,\n placement: UseCasePlacement,\n): ActionSurface {\n const surface = SURFACE_BY_CELL[`${binding}:${placement}`];\n\n if (surface === undefined) {\n throw new EntifixLogicError(\n `The use case \"${key}\" is declared ${binding} + ${placement}, which no surface renders. ` +\n 'A `determining` action finalizes a page — it is an object page’s footer — and a list ' +\n 'screen has no page to finalize, so a collection-bound verb cannot be determining. ' +\n 'Declare it `context-dependent` to reach the bulk bar, or `context-independent` to sit ' +\n 'in the table toolbar.',\n undefined,\n { key, binding, placement },\n );\n }\n\n return surface;\n}\n\n/**\n * Every surface this descriptor renders on.\n *\n * ⚠️ **A verb may name more than one cell**, and that is what makes publishing\n * reachable from a form header, a row menu and a selection without becoming\n * three permissions. The primary `binding` + `placement` come first, then\n * whatever `alsoAt` adds, and each is validated the same way — an illegal cell\n * in `alsoAt` throws exactly as one in the primary pair does.\n *\n * Duplicates are collapsed. A descriptor that named the same cell twice would\n * otherwise render the verb twice in one menu, which reads as a bug in the\n * screen rather than in the declaration.\n */\nexport function surfacesFor(\n descriptor: UseCaseDescriptor,\n): readonly ActionSurface[] {\n const cells = [\n { binding: descriptor.binding, placement: descriptor.placement },\n ...(descriptor.alsoAt ?? []),\n ];\n\n return [\n ...new Set(\n cells.map(cell =>\n surfaceForCell(descriptor.key, cell.binding, cell.placement),\n ),\n ),\n ];\n}\n\n/**\n * The single surface this descriptor renders on.\n *\n * Kept for the callers that genuinely have one — the command palette asks \"is\n * this mine?\" of an `unbound` verb, which can only ever be in one place. Any\n * caller that renders a *list* of verbs wants {@link surfacesFor}.\n */\nexport function surfaceFor(descriptor: UseCaseDescriptor): ActionSurface {\n return surfaceForCell(\n descriptor.key,\n descriptor.binding,\n descriptor.placement,\n );\n}\n\n/**\n * The descriptors one surface should render, in declaration order.\n *\n * Every descriptor is passed through {@link surfacesFor}, so an unrenderable\n * cell throws on the **first render of any surface** rather than only on the\n * one that would have shown it — the same reason\n * `assertLinkSourcesAreEditable` runs as one pass over the registry instead of\n * per row: a check that only fires on the screen that was already looking for\n * the verb is a check that fires after the bug is reported. A cell declared in\n * `alsoAt` is validated on that same first render, not on the surface it names.\n */\nexport function useCasesForSurface(\n surface: ActionSurface,\n useCases: readonly UseCaseDescriptor[] | undefined,\n): UseCaseDescriptor[] {\n return (useCases ?? []).filter(descriptor =>\n surfacesFor(descriptor).includes(surface),\n );\n}\n"],"names":["EntifixLogicError","ACTION_SURFACES","SURFACE_BY_CELL","OVERFLOW_GLYPH","surfaceForCell","key","binding","placement","surface","undefined","surfacesFor","descriptor","cells","alsoAt","Set","map","cell","surfaceFor","useCasesForSurface","useCases","filter","includes"],"mappings":"AAAA,SACEA,iBAAiB,QAIZ,gBAAgB;AAEvB;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,kBAAkB;IAC7B;IACA;IACA;IACA;IACA;IACA;CACD,CAAU;AAGX;;;;;;;;;;;CAWC,GACD,MAAMC,kBAAiD;IACrD,8BAA8B;IAC9B,sBAAsB;IACtB,4BAA4B;IAC5B,gCAAgC;IAChC,kCAAkC;IAClC,6BAA6B;IAC7B,+BAA+B;IAC/B,uBAAuB;AACzB;AAEA;;;;;;;;CAQC,GACD,OAAO,MAAMC,iBAAiB,SAAS;AAEvC,sEAAsE,GACtE,SAASC,eACPC,GAAW,EACXC,OAAuB,EACvBC,SAA2B;IAE3B,MAAMC,UAAUN,eAAe,CAAC,GAAGI,QAAQ,CAAC,EAAEC,WAAW,CAAC;IAE1D,IAAIC,YAAYC,WAAW;QACzB,MAAM,IAAIT,kBACR,CAAC,cAAc,EAAEK,IAAI,cAAc,EAAEC,QAAQ,GAAG,EAAEC,UAAU,4BAA4B,CAAC,GACvF,0FACA,uFACA,2FACA,yBACFE,WACA;YAAEJ;YAAKC;YAASC;QAAU;IAE9B;IAEA,OAAOC;AACT;AAEA;;;;;;;;;;;;CAYC,GACD,OAAO,SAASE,YACdC,UAA6B;QAIvBA;IAFN,MAAMC,QAAQ;QACZ;YAAEN,SAASK,WAAWL,OAAO;YAAEC,WAAWI,WAAWJ,SAAS;QAAC;YAC3DI,qBAAAA,WAAWE,MAAM,YAAjBF,qBAAqB,EAAE;KAC5B;IAED,OAAO;WACF,IAAIG,IACLF,MAAMG,GAAG,CAACC,CAAAA,OACRZ,eAAeO,WAAWN,GAAG,EAAEW,KAAKV,OAAO,EAAEU,KAAKT,SAAS;KAGhE;AACH;AAEA;;;;;;CAMC,GACD,OAAO,SAASU,WAAWN,UAA6B;IACtD,OAAOP,eACLO,WAAWN,GAAG,EACdM,WAAWL,OAAO,EAClBK,WAAWJ,SAAS;AAExB;AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASW,mBACdV,OAAsB,EACtBW,QAAkD;IAElD,OAAO,CAACA,mBAAAA,WAAY,EAAE,EAAEC,MAAM,CAACT,CAAAA,aAC7BD,YAAYC,YAAYU,QAAQ,CAACb;AAErC"}
@@ -4,10 +4,11 @@ import type { ReactNode } from 'react';
4
4
  * What a navigation control means, so a host can do something other than follow
5
5
  * the `href`.
6
6
  *
7
- * `open` goes to a record, `new` to its create form, `back` to the list. A
8
- * workspace tab needs to know which, because it answers each by opening a tab —
9
- * and a URL alone does not say what it points at without the host parsing its
10
- * own routes back.
7
+ * `open` goes to a record, `new` to its create form, `back` to the list, and
8
+ * `page` to another page of the listing already on screen. A workspace tab
9
+ * needs to know which, because it answers each by opening a tab — and a URL
10
+ * alone does not say what it points at without the host parsing its own routes
11
+ * back.
11
12
  */
12
13
  export type NavigationIntent = {
13
14
  readonly kind: 'open';
@@ -16,6 +17,9 @@ export type NavigationIntent = {
16
17
  readonly kind: 'new';
17
18
  } | {
18
19
  readonly kind: 'back';
20
+ } | {
21
+ readonly kind: 'page';
22
+ readonly page: number;
19
23
  };
20
24
  export interface RenderLinkProps {
21
25
  /** Always a real URL: middle-click and "open in new tab" must keep working. */
@@ -1 +1 @@
1
- {"version":3,"file":"render-link.d.ts","sourceRoot":"","sources":["../../../src/ui/actions/render-link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9B,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,SAAS,CAAC;AAE/D,oCAAoC;AACpC,eAAO,MAAM,YAAY,EAAE,UAI1B,CAAC"}
1
+ {"version":3,"file":"render-link.d.ts","sourceRoot":"","sources":["../../../src/ui/actions/render-link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,SAAS,CAAC;AAE/D,oCAAoC;AACpC,eAAO,MAAM,YAAY,EAAE,UAI1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/actions/render-link.tsx"],"sourcesContent":["import type { EntityId } from '@entifix/core';\nimport type { ReactNode } from 'react';\n\n/**\n * What a navigation control means, so a host can do something other than follow\n * the `href`.\n *\n * `open` goes to a record, `new` to its create form, `back` to the list. A\n * workspace tab needs to know which, because it answers each by opening a tab —\n * and a URL alone does not say what it points at without the host parsing its\n * own routes back.\n */\nexport type NavigationIntent =\n | { readonly kind: 'open'; readonly id: EntityId }\n | { readonly kind: 'new' }\n | { readonly kind: 'back' };\n\nexport interface RenderLinkProps {\n /** Always a real URL: middle-click and \"open in new tab\" must keep working. */\n readonly href: string;\n /** The styling the control would carry as a plain anchor. */\n readonly className: string;\n readonly children: ReactNode;\n readonly intent: NavigationIntent;\n}\n\n/**\n * Renders a navigation control.\n *\n * A seam rather than a router dependency: this package runs under any router or\n * none, so a plain anchor is all it can render by itself — and a plain anchor in\n * a client-routed application is a full document load, which rebuilds the\n * bundle, empties every cache and, inside a workspace tab, leaves the workspace.\n * A host passes a renderer built on its own link component instead.\n */\nexport type RenderLink = (props: RenderLinkProps) => ReactNode;\n\n/** The fallback: a plain anchor. */\nexport const renderAnchor: RenderLink = ({ href, className, children }) => (\n <a href={href} className={className}>\n {children}\n </a>\n);\n"],"names":["renderAnchor","href","className","children","a"],"mappings":";AAqCA,kCAAkC,GAClC,OAAO,MAAMA,eAA2B,CAAC,EAAEC,IAAI,EAAEC,SAAS,EAAEC,QAAQ,EAAE,iBACpE,KAACC;QAAEH,MAAMA;QAAMC,WAAWA;kBACvBC;OAEH"}
1
+ {"version":3,"sources":["../../../src/ui/actions/render-link.tsx"],"sourcesContent":["import type { EntityId } from '@entifix/core';\nimport type { ReactNode } from 'react';\n\n/**\n * What a navigation control means, so a host can do something other than follow\n * the `href`.\n *\n * `open` goes to a record, `new` to its create form, `back` to the list, and\n * `page` to another page of the listing already on screen. A workspace tab\n * needs to know which, because it answers each by opening a tab — and a URL\n * alone does not say what it points at without the host parsing its own routes\n * back.\n */\nexport type NavigationIntent =\n | { readonly kind: 'open'; readonly id: EntityId }\n | { readonly kind: 'new' }\n | { readonly kind: 'back' }\n | { readonly kind: 'page'; readonly page: number };\n\nexport interface RenderLinkProps {\n /** Always a real URL: middle-click and \"open in new tab\" must keep working. */\n readonly href: string;\n /** The styling the control would carry as a plain anchor. */\n readonly className: string;\n readonly children: ReactNode;\n readonly intent: NavigationIntent;\n}\n\n/**\n * Renders a navigation control.\n *\n * A seam rather than a router dependency: this package runs under any router or\n * none, so a plain anchor is all it can render by itself — and a plain anchor in\n * a client-routed application is a full document load, which rebuilds the\n * bundle, empties every cache and, inside a workspace tab, leaves the workspace.\n * A host passes a renderer built on its own link component instead.\n */\nexport type RenderLink = (props: RenderLinkProps) => ReactNode;\n\n/** The fallback: a plain anchor. */\nexport const renderAnchor: RenderLink = ({ href, className, children }) => (\n <a href={href} className={className}>\n {children}\n </a>\n);\n"],"names":["renderAnchor","href","className","children","a"],"mappings":";AAuCA,kCAAkC,GAClC,OAAO,MAAMA,eAA2B,CAAC,EAAEC,IAAI,EAAEC,SAAS,EAAEC,QAAQ,EAAE,iBACpE,KAACC;QAAEH,MAAMA;QAAMC,WAAWA;kBACvBC;OAEH"}
@@ -38,7 +38,7 @@ export interface FieldControlProps {
38
38
  * picker in one level up from its `linkSources`, so the member does get an
39
39
  * editor, just not from here. A `linkCollection` has no editor anywhere yet
40
40
  * (#26), and read-only is all it gets. A `composition` is the same: its rows
41
- * need a detail grid (#122), and a text box holding `[object Object]` would be
41
+ * need a detail grid, and a text box holding `[object Object]` would be
42
42
  * strictly worse than an honest disabled field.
43
43
  *
44
44
  * A `scalarCollection` is the exception among the collections and falls through
@@ -22,7 +22,7 @@ import { Checkbox, Select, TextInput } from '../field/index.js';
22
22
  * picker in one level up from its `linkSources`, so the member does get an
23
23
  * editor, just not from here. A `linkCollection` has no editor anywhere yet
24
24
  * (#26), and read-only is all it gets. A `composition` is the same: its rows
25
- * need a detail grid (#122), and a text box holding `[object Object]` would be
25
+ * need a detail grid, and a text box holding `[object Object]` would be
26
26
  * strictly worse than an honest disabled field.
27
27
  *
28
28
  * A `scalarCollection` is the exception among the collections and falls through
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/atoms/field-control/field-control.tsx"],"sourcesContent":["'use client';\n\nimport type { EntityFieldDescriptor, MetaAccessorType } from '@entifix/core';\n\nimport { useEnumLabel } from '../../../i18n/index.js';\nimport { Checkbox, Select, TextInput } from '../field/index.js';\n\nexport interface FieldControlProps {\n descriptor: EntityFieldDescriptor;\n /**\n * ARIA wiring the caller owns, because only the caller knows the shape it is\n * rendered into.\n *\n * A form labels its control with a `<label for>` and needs none of this; a\n * detail grid's cell has no label of its own — the column header is the\n * label, and the cell's message is the description — so it points at both by\n * id. Passing them through here rather than duplicating the type→input map\n * in the grid is what keeps one control deciding what a `date` member looks\n * like.\n */\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean;\n /**\n * The draft value as a string — the shape a native input round-trips. A form\n * holds its whole draft as `Record<string, string>` and reconstructs typed\n * values only at submit, so the control never sees a domain value.\n */\n value: string;\n onChange: (value: string) => void;\n id?: string;\n}\n\n/** Native input type for the text-like controls; text is the default. */\nconst INPUT_TYPE: Partial<Record<MetaAccessorType, string>> = {\n number: 'number',\n date: 'date',\n};\n\n/**\n * The edit-mode inverse of {@link CellValue}: it turns one metadata descriptor\n * into the input that edits it. Centralizing the type→control choice is what\n * lets a form stay generic, the same way `CellValue` keeps a table generic.\n *\n * A relation (`link`/`linkCollection`) is rendered read-only here, deliberately:\n * editing one needs a picker that can search and page the target, which is a\n * different control with different dependencies. So this atom stays a pure\n * type→input map and a relation never falls back to a broken text box.\n *\n * For a to-one `link` that is only half the story — `EntityForm` wires the\n * picker in one level up from its `linkSources`, so the member does get an\n * editor, just not from here. A `linkCollection` has no editor anywhere yet\n * (#26), and read-only is all it gets. A `composition` is the same: its rows\n * need a detail grid (#122), and a text box holding `[object Object]` would be\n * strictly worse than an honest disabled field.\n *\n * A `scalarCollection` is the exception among the collections and falls through\n * to the plain text input on purpose: a `string[]` has a lossless comma form,\n * so the draft it round-trips through *is* editable text. Splitting on the\n * comma is `reconstructEntity`'s half of that same contract.\n */\nexport function FieldControl({\n descriptor,\n value,\n onChange,\n id,\n ...aria\n}: FieldControlProps) {\n const enumLabel = useEnumLabel();\n const disabled =\n descriptor.readonly ||\n descriptor.type === 'link' ||\n descriptor.type === 'linkCollection' ||\n descriptor.type === 'composition';\n\n if (descriptor.type === 'boolean') {\n return (\n <Checkbox\n id={id}\n {...aria}\n label={descriptor.label}\n checked={value === 'true'}\n disabled={disabled}\n onChange={event => onChange(String(event.currentTarget.checked))}\n />\n );\n }\n\n if (descriptor.type === 'enum') {\n return (\n <Select\n id={id}\n {...aria}\n value={value}\n disabled={disabled}\n onChange={event => onChange(event.currentTarget.value)}\n >\n <option value=\"\">—</option>\n {(descriptor.enumValues ?? []).map(option => (\n <option key={option} value={option}>\n {enumLabel(descriptor, option)}\n </option>\n ))}\n </Select>\n );\n }\n\n return (\n <TextInput\n id={id}\n {...aria}\n type={INPUT_TYPE[descriptor.type] ?? 'text'}\n value={value}\n disabled={disabled}\n onChange={event => onChange(event.currentTarget.value)}\n />\n );\n}\n"],"names":["useEnumLabel","Checkbox","Select","TextInput","INPUT_TYPE","number","date","FieldControl","descriptor","value","onChange","id","aria","enumLabel","disabled","readonly","type","label","checked","event","String","currentTarget","option","enumValues","map"],"mappings":"AAAA;;;;AAIA,SAASA,YAAY,QAAQ,yBAAyB;AACtD,SAASC,QAAQ,EAAEC,MAAM,EAAEC,SAAS,QAAQ,oBAAoB;AA4BhE,uEAAuE,GACvE,MAAMC,aAAwD;IAC5DC,QAAQ;IACRC,MAAM;AACR;AAEA;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,OAAO,SAASC,aAAa,EAMT;QANS,EAC3BC,UAAU,EACVC,KAAK,EACLC,QAAQ,EACRC,EAAE,EAEgB,OADfC;;;;;;QA6COR;IA3CV,MAAMS,YAAYb;IAClB,MAAMc,WACJN,WAAWO,QAAQ,IACnBP,WAAWQ,IAAI,KAAK,UACpBR,WAAWQ,IAAI,KAAK,oBACpBR,WAAWQ,IAAI,KAAK;IAEtB,IAAIR,WAAWQ,IAAI,KAAK,WAAW;QACjC,qBACE,KAACf;YACCU,IAAIA;WACAC;YACJK,OAAOT,WAAWS,KAAK;YACvBC,SAAST,UAAU;YACnBK,UAAUA;YACVJ,UAAUS,CAAAA,QAAST,SAASU,OAAOD,MAAME,aAAa,CAACH,OAAO;;IAGpE;IAEA,IAAIV,WAAWQ,IAAI,KAAK,QAAQ;YAUxBR;QATN,qBACE,MAACN;YACCS,IAAIA;WACAC;YACJH,OAAOA;YACPK,UAAUA;YACVJ,UAAUS,CAAAA,QAAST,SAASS,MAAME,aAAa,CAACZ,KAAK;;8BAErD,KAACa;oBAAOb,OAAM;8BAAG;;gBAChB,EAACD,yBAAAA,WAAWe,UAAU,YAArBf,yBAAyB,EAAE,EAAEgB,GAAG,CAACF,CAAAA,uBACjC,KAACA;wBAAoBb,OAAOa;kCACzBT,UAAUL,YAAYc;uBADZA;;;IAMrB;IAEA,qBACE,KAACnB;QACCQ,IAAIA;OACAC;QACJI,IAAI,GAAEZ,8BAAAA,UAAU,CAACI,WAAWQ,IAAI,CAAC,YAA3BZ,8BAA+B;QACrCK,OAAOA;QACPK,UAAUA;QACVJ,UAAUS,CAAAA,QAAST,SAASS,MAAME,aAAa,CAACZ,KAAK;;AAG3D"}
1
+ {"version":3,"sources":["../../../../src/ui/atoms/field-control/field-control.tsx"],"sourcesContent":["'use client';\n\nimport type { EntityFieldDescriptor, MetaAccessorType } from '@entifix/core';\n\nimport { useEnumLabel } from '../../../i18n/index.js';\nimport { Checkbox, Select, TextInput } from '../field/index.js';\n\nexport interface FieldControlProps {\n descriptor: EntityFieldDescriptor;\n /**\n * ARIA wiring the caller owns, because only the caller knows the shape it is\n * rendered into.\n *\n * A form labels its control with a `<label for>` and needs none of this; a\n * detail grid's cell has no label of its own — the column header is the\n * label, and the cell's message is the description — so it points at both by\n * id. Passing them through here rather than duplicating the type→input map\n * in the grid is what keeps one control deciding what a `date` member looks\n * like.\n */\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean;\n /**\n * The draft value as a string — the shape a native input round-trips. A form\n * holds its whole draft as `Record<string, string>` and reconstructs typed\n * values only at submit, so the control never sees a domain value.\n */\n value: string;\n onChange: (value: string) => void;\n id?: string;\n}\n\n/** Native input type for the text-like controls; text is the default. */\nconst INPUT_TYPE: Partial<Record<MetaAccessorType, string>> = {\n number: 'number',\n date: 'date',\n};\n\n/**\n * The edit-mode inverse of {@link CellValue}: it turns one metadata descriptor\n * into the input that edits it. Centralizing the type→control choice is what\n * lets a form stay generic, the same way `CellValue` keeps a table generic.\n *\n * A relation (`link`/`linkCollection`) is rendered read-only here, deliberately:\n * editing one needs a picker that can search and page the target, which is a\n * different control with different dependencies. So this atom stays a pure\n * type→input map and a relation never falls back to a broken text box.\n *\n * For a to-one `link` that is only half the story — `EntityForm` wires the\n * picker in one level up from its `linkSources`, so the member does get an\n * editor, just not from here. A `linkCollection` has no editor anywhere yet\n * (#26), and read-only is all it gets. A `composition` is the same: its rows\n * need a detail grid, and a text box holding `[object Object]` would be\n * strictly worse than an honest disabled field.\n *\n * A `scalarCollection` is the exception among the collections and falls through\n * to the plain text input on purpose: a `string[]` has a lossless comma form,\n * so the draft it round-trips through *is* editable text. Splitting on the\n * comma is `reconstructEntity`'s half of that same contract.\n */\nexport function FieldControl({\n descriptor,\n value,\n onChange,\n id,\n ...aria\n}: FieldControlProps) {\n const enumLabel = useEnumLabel();\n const disabled =\n descriptor.readonly ||\n descriptor.type === 'link' ||\n descriptor.type === 'linkCollection' ||\n descriptor.type === 'composition';\n\n if (descriptor.type === 'boolean') {\n return (\n <Checkbox\n id={id}\n {...aria}\n label={descriptor.label}\n checked={value === 'true'}\n disabled={disabled}\n onChange={event => onChange(String(event.currentTarget.checked))}\n />\n );\n }\n\n if (descriptor.type === 'enum') {\n return (\n <Select\n id={id}\n {...aria}\n value={value}\n disabled={disabled}\n onChange={event => onChange(event.currentTarget.value)}\n >\n <option value=\"\">—</option>\n {(descriptor.enumValues ?? []).map(option => (\n <option key={option} value={option}>\n {enumLabel(descriptor, option)}\n </option>\n ))}\n </Select>\n );\n }\n\n return (\n <TextInput\n id={id}\n {...aria}\n type={INPUT_TYPE[descriptor.type] ?? 'text'}\n value={value}\n disabled={disabled}\n onChange={event => onChange(event.currentTarget.value)}\n />\n );\n}\n"],"names":["useEnumLabel","Checkbox","Select","TextInput","INPUT_TYPE","number","date","FieldControl","descriptor","value","onChange","id","aria","enumLabel","disabled","readonly","type","label","checked","event","String","currentTarget","option","enumValues","map"],"mappings":"AAAA;;;;AAIA,SAASA,YAAY,QAAQ,yBAAyB;AACtD,SAASC,QAAQ,EAAEC,MAAM,EAAEC,SAAS,QAAQ,oBAAoB;AA4BhE,uEAAuE,GACvE,MAAMC,aAAwD;IAC5DC,QAAQ;IACRC,MAAM;AACR;AAEA;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,OAAO,SAASC,aAAa,EAMT;QANS,EAC3BC,UAAU,EACVC,KAAK,EACLC,QAAQ,EACRC,EAAE,EAEgB,OADfC;;;;;;QA6COR;IA3CV,MAAMS,YAAYb;IAClB,MAAMc,WACJN,WAAWO,QAAQ,IACnBP,WAAWQ,IAAI,KAAK,UACpBR,WAAWQ,IAAI,KAAK,oBACpBR,WAAWQ,IAAI,KAAK;IAEtB,IAAIR,WAAWQ,IAAI,KAAK,WAAW;QACjC,qBACE,KAACf;YACCU,IAAIA;WACAC;YACJK,OAAOT,WAAWS,KAAK;YACvBC,SAAST,UAAU;YACnBK,UAAUA;YACVJ,UAAUS,CAAAA,QAAST,SAASU,OAAOD,MAAME,aAAa,CAACH,OAAO;;IAGpE;IAEA,IAAIV,WAAWQ,IAAI,KAAK,QAAQ;YAUxBR;QATN,qBACE,MAACN;YACCS,IAAIA;WACAC;YACJH,OAAOA;YACPK,UAAUA;YACVJ,UAAUS,CAAAA,QAAST,SAASS,MAAME,aAAa,CAACZ,KAAK;;8BAErD,KAACa;oBAAOb,OAAM;8BAAG;;gBAChB,EAACD,yBAAAA,WAAWe,UAAU,YAArBf,yBAAyB,EAAE,EAAEgB,GAAG,CAACF,CAAAA,uBACjC,KAACA;wBAAoBb,OAAOa;kCACzBT,UAAUL,YAAYc;uBADZA;;;IAMrB;IAEA,qBACE,KAACnB;QACCQ,IAAIA;OACAC;QACJI,IAAI,GAAEZ,8BAAAA,UAAU,CAACI,WAAWQ,IAAI,CAAC,YAA3BZ,8BAA+B;QACrCK,OAAOA;QACPK,UAAUA;QACVJ,UAAUS,CAAAA,QAAST,SAASS,MAAME,aAAa,CAACZ,KAAK;;AAG3D"}
@@ -6,7 +6,7 @@ export interface BulkActionBarProps {
6
6
  * The collection-bound verbs this caller may run, already filtered against
7
7
  * the verified principal by the service. The bar renders what it is given and
8
8
  * re-checks nothing — hiding an action protects nothing, the route guard is
9
- * the enforcement (ADR 0026).
9
+ * the enforcement.
10
10
  */
11
11
  useCases: readonly UseCaseDescriptor[];
12
12
  /**
@@ -26,7 +26,7 @@ export interface BulkActionBarProps {
26
26
  * The caller has to know whether the verb asked to be confirmed, and the bar
27
27
  * is already holding the answer. Passing the key alone forced a lookup back
28
28
  * into the same list — a branch for "not found" that cannot happen, since
29
- * every key here came from this array (#216).
29
+ * every key here came from this array.
30
30
  */
31
31
  onUseCase: (useCase: UseCaseDescriptor) => void;
32
32
  /** Disables every verb while one is running. */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/molecules/bulk-action-bar/bulk-action-bar.tsx"],"sourcesContent":["'use client';\n\nimport type { UseCaseDescriptor } from '@entifix/core';\n\nimport { useT, useTranslateKey } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface BulkActionBarProps {\n /** How many rows the action would touch. */\n count: number;\n /**\n * The collection-bound verbs this caller may run, already filtered against\n * the verified principal by the service. The bar renders what it is given and\n * re-checks nothing — hiding an action protects nothing, the route guard is\n * the enforcement (ADR 0026).\n */\n useCases: readonly UseCaseDescriptor[];\n /**\n * Offered only when the selection is a page's worth of ids *and* more rows\n * match than are shown. Absent means there is no larger set to escalate to.\n *\n * It is a **separate affordance carrying the count**, never a widening of the\n * header checkbox: \"select all on this page\" and \"select all 3.200 matching\"\n * are different actions and the second has to be chosen deliberately.\n */\n matchingTotal?: number;\n onSelectAllMatching?: () => void;\n onClear: () => void;\n /**\n * Hands back the descriptor it rendered, not just its key.\n *\n * The caller has to know whether the verb asked to be confirmed, and the bar\n * is already holding the answer. Passing the key alone forced a lookup back\n * into the same list — a branch for \"not found\" that cannot happen, since\n * every key here came from this array (#216).\n */\n onUseCase: (useCase: UseCaseDescriptor) => void;\n /** Disables every verb while one is running. */\n busy?: boolean;\n className?: string;\n}\n\n/**\n * The bar that appears once rows are selected: what is selected, what can be\n * done to it, and the way out.\n *\n * It is `aria-live=\"polite\"` on the count rather than on the whole region — a\n * region that re-announces its buttons every time one more row is ticked is\n * noise, and the count is the only part that changed. `role=\"region\"` with a\n * name is what lets a screen-reader user jump to it at all, since it appears\n * without the focus moving.\n */\nexport function BulkActionBar({\n count,\n useCases,\n matchingTotal,\n onSelectAllMatching,\n onClear,\n onUseCase,\n busy = false,\n className,\n}: BulkActionBarProps) {\n const t = useT();\n const translateKey = useTranslateKey();\n\n return (\n <div\n role=\"region\"\n aria-label={t('bulk.barLabel')}\n data-testid=\"bulk-action-bar\"\n className={cn(\n 'flex flex-wrap items-center gap-2xs rounded-lg border border-border bg-surface-elevated px-s py-2xs',\n className,\n )}\n >\n <span aria-live=\"polite\" className=\"text-step-sm text-content\">\n {t('table.selectedCount', { count })}\n </span>\n\n {matchingTotal !== undefined && onSelectAllMatching && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onSelectAllMatching}\n >\n {t('table.selectAllMatching', { count: matchingTotal })}\n </Button>\n )}\n\n {useCases.map(descriptor => (\n <Button\n key={descriptor.key}\n type=\"button\"\n variant={\n descriptor.confirm?.tone === 'destructive'\n ? 'destructive'\n : 'secondary'\n }\n size=\"sm\"\n disabled={busy}\n onClick={() => onUseCase(descriptor)}\n >\n {/* A descriptor's label is a *runtime* catalog key — the type system\n cannot see a typo here, `@r10c/i18n-check` is what does. */}\n {translateKey(descriptor.labelKey)}\n </Button>\n ))}\n\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={busy}\n onClick={onClear}\n >\n {t('table.clearSelection')}\n </Button>\n </div>\n );\n}\n"],"names":["useT","useTranslateKey","Button","cn","BulkActionBar","count","useCases","matchingTotal","onSelectAllMatching","onClear","onUseCase","busy","className","t","translateKey","div","role","aria-label","data-testid","span","aria-live","undefined","type","variant","size","onClick","map","descriptor","confirm","tone","disabled","labelKey","key"],"mappings":"AAAA;;AAIA,SAASA,IAAI,EAAEC,eAAe,QAAQ,yBAAyB;AAC/D,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,EAAE,QAAQ,oBAAoB;AAqCvC;;;;;;;;;CASC,GACD,OAAO,SAASC,cAAc,EAC5BC,KAAK,EACLC,QAAQ,EACRC,aAAa,EACbC,mBAAmB,EACnBC,OAAO,EACPC,SAAS,EACTC,OAAO,KAAK,EACZC,SAAS,EACU;IACnB,MAAMC,IAAIb;IACV,MAAMc,eAAeb;IAErB,qBACE,MAACc;QACCC,MAAK;QACLC,cAAYJ,EAAE;QACdK,eAAY;QACZN,WAAWT,GACT,uGACAS;;0BAGF,KAACO;gBAAKC,aAAU;gBAASR,WAAU;0BAChCC,EAAE,uBAAuB;oBAAER;gBAAM;;YAGnCE,kBAAkBc,aAAab,qCAC9B,KAACN;gBACCoB,MAAK;gBACLC,SAAQ;gBACRC,MAAK;gBACLC,SAASjB;0BAERK,EAAE,2BAA2B;oBAAER,OAAOE;gBAAc;;YAIxDD,SAASoB,GAAG,CAACC,CAAAA;oBAKRA;qCAJJ,KAACzB;oBAECoB,MAAK;oBACLC,SACEI,EAAAA,sBAAAA,WAAWC,OAAO,qBAAlBD,oBAAoBE,IAAI,MAAK,gBACzB,gBACA;oBAENL,MAAK;oBACLM,UAAUnB;oBACVc,SAAS,IAAMf,UAAUiB;8BAIxBb,aAAaa,WAAWI,QAAQ;mBAb5BJ,WAAWK,GAAG;;0BAiBvB,KAAC9B;gBACCoB,MAAK;gBACLC,SAAQ;gBACRC,MAAK;gBACLM,UAAUnB;gBACVc,SAAShB;0BAERI,EAAE;;;;AAIX"}
1
+ {"version":3,"sources":["../../../../src/ui/molecules/bulk-action-bar/bulk-action-bar.tsx"],"sourcesContent":["'use client';\n\nimport type { UseCaseDescriptor } from '@entifix/core';\n\nimport { useT, useTranslateKey } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface BulkActionBarProps {\n /** How many rows the action would touch. */\n count: number;\n /**\n * The collection-bound verbs this caller may run, already filtered against\n * the verified principal by the service. The bar renders what it is given and\n * re-checks nothing — hiding an action protects nothing, the route guard is\n * the enforcement.\n */\n useCases: readonly UseCaseDescriptor[];\n /**\n * Offered only when the selection is a page's worth of ids *and* more rows\n * match than are shown. Absent means there is no larger set to escalate to.\n *\n * It is a **separate affordance carrying the count**, never a widening of the\n * header checkbox: \"select all on this page\" and \"select all 3.200 matching\"\n * are different actions and the second has to be chosen deliberately.\n */\n matchingTotal?: number;\n onSelectAllMatching?: () => void;\n onClear: () => void;\n /**\n * Hands back the descriptor it rendered, not just its key.\n *\n * The caller has to know whether the verb asked to be confirmed, and the bar\n * is already holding the answer. Passing the key alone forced a lookup back\n * into the same list — a branch for \"not found\" that cannot happen, since\n * every key here came from this array.\n */\n onUseCase: (useCase: UseCaseDescriptor) => void;\n /** Disables every verb while one is running. */\n busy?: boolean;\n className?: string;\n}\n\n/**\n * The bar that appears once rows are selected: what is selected, what can be\n * done to it, and the way out.\n *\n * It is `aria-live=\"polite\"` on the count rather than on the whole region — a\n * region that re-announces its buttons every time one more row is ticked is\n * noise, and the count is the only part that changed. `role=\"region\"` with a\n * name is what lets a screen-reader user jump to it at all, since it appears\n * without the focus moving.\n */\nexport function BulkActionBar({\n count,\n useCases,\n matchingTotal,\n onSelectAllMatching,\n onClear,\n onUseCase,\n busy = false,\n className,\n}: BulkActionBarProps) {\n const t = useT();\n const translateKey = useTranslateKey();\n\n return (\n <div\n role=\"region\"\n aria-label={t('bulk.barLabel')}\n data-testid=\"bulk-action-bar\"\n className={cn(\n 'flex flex-wrap items-center gap-2xs rounded-lg border border-border bg-surface-elevated px-s py-2xs',\n className,\n )}\n >\n <span aria-live=\"polite\" className=\"text-step-sm text-content\">\n {t('table.selectedCount', { count })}\n </span>\n\n {matchingTotal !== undefined && onSelectAllMatching && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onSelectAllMatching}\n >\n {t('table.selectAllMatching', { count: matchingTotal })}\n </Button>\n )}\n\n {useCases.map(descriptor => (\n <Button\n key={descriptor.key}\n type=\"button\"\n variant={\n descriptor.confirm?.tone === 'destructive'\n ? 'destructive'\n : 'secondary'\n }\n size=\"sm\"\n disabled={busy}\n onClick={() => onUseCase(descriptor)}\n >\n {/* A descriptor's label is a *runtime* catalog key — the type system\n cannot see a typo here, a host's catalog check is what does. */}\n {translateKey(descriptor.labelKey)}\n </Button>\n ))}\n\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={busy}\n onClick={onClear}\n >\n {t('table.clearSelection')}\n </Button>\n </div>\n );\n}\n"],"names":["useT","useTranslateKey","Button","cn","BulkActionBar","count","useCases","matchingTotal","onSelectAllMatching","onClear","onUseCase","busy","className","t","translateKey","div","role","aria-label","data-testid","span","aria-live","undefined","type","variant","size","onClick","map","descriptor","confirm","tone","disabled","labelKey","key"],"mappings":"AAAA;;AAIA,SAASA,IAAI,EAAEC,eAAe,QAAQ,yBAAyB;AAC/D,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,EAAE,QAAQ,oBAAoB;AAqCvC;;;;;;;;;CASC,GACD,OAAO,SAASC,cAAc,EAC5BC,KAAK,EACLC,QAAQ,EACRC,aAAa,EACbC,mBAAmB,EACnBC,OAAO,EACPC,SAAS,EACTC,OAAO,KAAK,EACZC,SAAS,EACU;IACnB,MAAMC,IAAIb;IACV,MAAMc,eAAeb;IAErB,qBACE,MAACc;QACCC,MAAK;QACLC,cAAYJ,EAAE;QACdK,eAAY;QACZN,WAAWT,GACT,uGACAS;;0BAGF,KAACO;gBAAKC,aAAU;gBAASR,WAAU;0BAChCC,EAAE,uBAAuB;oBAAER;gBAAM;;YAGnCE,kBAAkBc,aAAab,qCAC9B,KAACN;gBACCoB,MAAK;gBACLC,SAAQ;gBACRC,MAAK;gBACLC,SAASjB;0BAERK,EAAE,2BAA2B;oBAAER,OAAOE;gBAAc;;YAIxDD,SAASoB,GAAG,CAACC,CAAAA;oBAKRA;qCAJJ,KAACzB;oBAECoB,MAAK;oBACLC,SACEI,EAAAA,sBAAAA,WAAWC,OAAO,qBAAlBD,oBAAoBE,IAAI,MAAK,gBACzB,gBACA;oBAENL,MAAK;oBACLM,UAAUnB;oBACVc,SAAS,IAAMf,UAAUiB;8BAIxBb,aAAaa,WAAWI,QAAQ;mBAb5BJ,WAAWK,GAAG;;0BAiBvB,KAAC9B;gBACCoB,MAAK;gBACLC,SAAQ;gBACRC,MAAK;gBACLM,UAAUnB;gBACVc,SAAShB;0BAERI,EAAE;;;;AAIX"}