@mmlogic/components 0.5.13 → 0.5.14

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 (41) hide show
  1. package/dist/cjs/{cell-renderer-BBebjBVz.js → cell-renderer-mjS630f1.js} +8 -0
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/mosterdcomponents.cjs.js +1 -1
  4. package/dist/cjs/mrd-boolean-field_25.cjs.entry.js +148 -28
  5. package/dist/cjs/mrd-merge-view.cjs.entry.js +1 -1
  6. package/dist/collection/components/table/mrd-table/mrd-table.css +36 -0
  7. package/dist/collection/components/table/mrd-table/mrd-table.js +137 -25
  8. package/dist/collection/components/table/mrd-table/table-parts.js +6 -2
  9. package/dist/collection/components/table/mrd-table/table-query.js +6 -0
  10. package/dist/collection/utils/i18n.js +8 -0
  11. package/dist/components/i18n.js +1 -1
  12. package/dist/components/mrd-table2.js +1 -1
  13. package/dist/esm/{cell-renderer-CC8-MtvQ.js → cell-renderer-BDY8UXkH.js} +8 -0
  14. package/dist/esm/loader.js +1 -1
  15. package/dist/esm/mosterdcomponents.js +1 -1
  16. package/dist/esm/mrd-boolean-field_25.entry.js +148 -28
  17. package/dist/esm/mrd-merge-view.entry.js +1 -1
  18. package/dist/mosterdcomponents/cell-renderer-B8u5BCK-.js.map +1 -0
  19. package/dist/mosterdcomponents/client-layout-Bc42CfJB.js.map +1 -0
  20. package/dist/mosterdcomponents/document-attachments-BufPmMRv.js.map +1 -0
  21. package/dist/mosterdcomponents/field-helpers-CNQcI3Hf.js.map +1 -0
  22. package/dist/mosterdcomponents/file-upload-common-C9wp47CB.js.map +1 -0
  23. package/dist/mosterdcomponents/format-gcecItcD.js.map +1 -0
  24. package/dist/mosterdcomponents/i18n-ydNM87-Q.js.map +1 -0
  25. package/dist/mosterdcomponents/index-1ayBojyN.js.map +1 -0
  26. package/dist/mosterdcomponents/index-DhffneUF.js.map +1 -0
  27. package/dist/mosterdcomponents/index.esm.js.map +1 -0
  28. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  29. package/dist/mosterdcomponents/mosterdcomponents.esm.js.map +1 -0
  30. package/dist/mosterdcomponents/p-Dkm4WxMy.js +1 -0
  31. package/dist/mosterdcomponents/{p-07b148b2.entry.js → p-c834951a.entry.js} +2 -2
  32. package/dist/mosterdcomponents/{p-a7e8f6a3.entry.js → p-e8b0880f.entry.js} +1 -1
  33. package/dist/mosterdcomponents/purify.es-_duHfPgC.js.map +1 -0
  34. package/dist/mosterdcomponents/query-params-BZbQoeYF.js.map +1 -0
  35. package/dist/mosterdcomponents/quill-C9pgw_k-.js.map +1 -0
  36. package/dist/mosterdcomponents/validation-CjjTt66G.js.map +1 -0
  37. package/dist/types/components/table/mrd-table/mrd-table.d.ts +48 -1
  38. package/dist/types/components/table/mrd-table/table-parts.d.ts +15 -0
  39. package/dist/types/components/table/mrd-table/table-query.d.ts +6 -0
  40. package/package.json +1 -1
  41. package/dist/mosterdcomponents/p-D5ZPfX3-.js +0 -1
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, c as createEvent, h, H as Host, g as getElement, w as writeTask } from './index-CDiBvvJU.js';
2
- import { t, p as parseLocalizedNumber, f as formatNumber, a as formatDate, b as formatDateTime, c as formatCurrency, C as CellRenderer, d as formatPercentage } from './cell-renderer-CC8-MtvQ.js';
2
+ import { t, p as parseLocalizedNumber, f as formatNumber, a as formatDate, b as formatDateTime, c as formatCurrency, C as CellRenderer, d as formatPercentage } from './cell-renderer-BDY8UXkH.js';
3
3
  import { b as ClientLayoutItemFieldDataType, e as ClientLayoutNavigateBehaviour, a as ClientLayoutItemType, c as ClientLayoutItemRelationDisplayType, d as ClientLayoutItemRelationEditBehavior, r as resolveArchetype, A as ARCHETYPE_DOCUMENT, h as ARCHETYPE_INVOICE_LINE, f as ARCHETYPE_INVOICE, g as ARCHETYPE_EMAIL } from './client-layout-Bc42CfJB.js';
4
4
 
5
5
  const mrdBooleanFieldCss = () => `.sc-mrd-boolean-field-h{display:block}.mrd-boolean-field.sc-mrd-boolean-field{display:flex;align-items:center;width:100%}.mrd-boolean-field__toggle-label.sc-mrd-boolean-field{display:flex;align-items:center;gap:var(--mrd-space-3);cursor:pointer;user-select:none}.mrd-boolean-field__checkbox.sc-mrd-boolean-field{position:absolute;opacity:0;width:0;height:0;pointer-events:none}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:checked+.mrd-boolean-field__toggle.sc-mrd-boolean-field{background-color:var(--mrd-color-primary)}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:checked+.mrd-boolean-field__toggle.sc-mrd-boolean-field::after{transform:translateX(20px)}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:focus+.mrd-boolean-field__toggle.sc-mrd-boolean-field{box-shadow:var(--mrd-shadow-focus)}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:disabled+.mrd-boolean-field__toggle.sc-mrd-boolean-field{opacity:0.5;cursor:not-allowed}.mrd-boolean-field__toggle.sc-mrd-boolean-field{position:relative;display:inline-block;width:44px;height:24px;background-color:var(--mrd-color-neutral-300);border-radius:var(--mrd-border-radius-full);transition:background-color var(--mrd-transition);flex-shrink:0}.mrd-boolean-field__toggle.sc-mrd-boolean-field::after{content:"";position:absolute;top:2px;left:2px;width:20px;height:20px;background-color:var(--mrd-color-white);border-radius:50%;transition:transform var(--mrd-transition);box-shadow:var(--mrd-shadow-sm)}.mrd-boolean-field__text.sc-mrd-boolean-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800)}.mrd-boolean-field__text--required.sc-mrd-boolean-field::after{content:" *";color:var(--mrd-color-danger)}`;
@@ -6221,6 +6221,10 @@ const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
6221
6221
  const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
6222
6222
  /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
6223
6223
  const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
6224
+ /** Wait this long (ms) after the user stops typing in the free-text search box
6225
+ * before firing the search request — mirrors REQUEST_DEBOUNCE_MS's purpose
6226
+ * (skip intermediate keystrokes) but is tuned for typing, not scrolling. */
6227
+ const SEARCH_DEBOUNCE_MS = 400;
6224
6228
  function parseDefaultSort(defaultSort) {
6225
6229
  var _a;
6226
6230
  if (!defaultSort)
@@ -6245,6 +6249,8 @@ function buildTableQueryParams(opts) {
6245
6249
  if (opts.filterClass)
6246
6250
  p.set('type', opts.filterClass);
6247
6251
  applyViewFilters(p, opts.viewFilters);
6252
+ if (opts.query)
6253
+ p.set('q', opts.query);
6248
6254
  for (const f of opts.activeFilters) {
6249
6255
  if (f.operator === 'isEmpty') {
6250
6256
  p.set(f.field, '');
@@ -6394,6 +6400,7 @@ function datetimeFilterToDisplay(existing) {
6394
6400
  * component; these components receive plain values and callbacks.
6395
6401
  */
6396
6402
  const FilterIcon = () => (h("span", { class: "mrd-table__filter-icon", "aria-hidden": "true" }, h("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "currentColor" }, h("path", { d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" }))));
6403
+ const SearchIcon = ({ class: cls }) => (h("svg", { class: cls, viewBox: "0 0 24 24", width: "16", height: "16", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M15.5 14h-.79l-.28-.27a6.5 6.5 0 1 0-.7.7l.27.28v.79l5 4.99L20.49 19zM9.5 14A4.5 4.5 0 1 1 14 9.5 4.5 4.5 0 0 1 9.5 14" })));
6397
6404
  const TEXTBLOCK_MAX = 200;
6398
6405
  const TableCell = ({ col, row, locale, onDownload, onOpenTextblock, onOpenJson }) => {
6399
6406
  var _a, _b, _c;
@@ -6473,11 +6480,14 @@ const JsonModal = ({ html, locale, onClose }) => {
6473
6480
  return null;
6474
6481
  return (h("div", { class: "mrd-table__modal-backdrop", onClick: onClose, role: "dialog", "aria-modal": "true" }, h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-table__modal-close", onClick: onClose, "aria-label": t('close', locale) }, "\u2715"), h("pre", { class: "mrd-table__modal-json", innerHTML: html }))));
6475
6482
  };
6476
- const Toolbar = ({ locale, filterCount, actions, views, activeViewIdx, viewPopoverOpen, createPickerOpen, createTypes, readOnly, cb }) => {
6483
+ const Toolbar = ({ locale, filterCount, actions, views, activeViewIdx, viewPopoverOpen, createPickerOpen, createTypes, readOnly, searchEnabled, searchOpen, searchQuery, cb }) => {
6477
6484
  var _a;
6478
6485
  const hasActions = actions.length > 0;
6479
6486
  const hasViewSwitcher = views.length > 1;
6480
- return (h("div", { class: "mrd-table__toolbar" }, h("div", { class: "mrd-table__toolbar-left" }, filterCount > 0 && (h("button", { class: "mrd-table__action mrd-table__action--secondary mrd-table__filter-clear", onClick: cb.onClearAllFilters }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })), h("span", { class: "mrd-table__filter-clear-label" }, t('table_filter_clear_all', locale), " (", filterCount, ")")))), hasViewSwitcher && (h("div", { class: "mrd-table__toolbar-center" }, h("div", { class: "mrd-table__view-switcher" }, h("button", { class: "mrd-table__view-arrow", "aria-label": "Previous view", onClick: () => cb.onViewSwitch((activeViewIdx - 1 + views.length) % views.length) }, "\u25C0"), h("div", { class: "mrd-table__view-title-wrap" }, h("button", { class: "mrd-table__view-title", onClick: (e) => cb.onToggleViewPopover(e) }, (_a = views[activeViewIdx]) === null || _a === void 0 ? void 0 : _a.label), viewPopoverOpen && (h("div", { class: "mrd-table__view-popover", onClick: (e) => e.stopPropagation() }, views.map((v, i) => (h("button", { key: String(i), class: `mrd-table__view-popover-item${i === activeViewIdx ? ' mrd-table__view-popover-item--active' : ''}`, onClick: () => {
6487
+ return (h("div", { class: "mrd-table__toolbar" }, h("div", { class: "mrd-table__toolbar-left" }, searchEnabled && (searchOpen ? (h("span", { class: "mrd-table__search-box" }, h(SearchIcon, null), h("input", { type: "text", class: "mrd-table__search-input", value: searchQuery !== null && searchQuery !== void 0 ? searchQuery : '', placeholder: t('search_placeholder', locale), ref: cb.onSearchInputRef, onInput: (e) => cb.onSearchInput(e.target.value), onKeyDown: (e) => {
6488
+ if (e.key === 'Escape')
6489
+ cb.onCloseSearch();
6490
+ } }), h("button", { type: "button", class: "mrd-table__search-clear", "aria-label": t('clear', locale), onClick: cb.onCloseSearch }, "\u2715"))) : (h("button", { type: "button", class: "mrd-table__action mrd-table__action--secondary mrd-table__search-toggle", onClick: cb.onToggleSearch }, h(SearchIcon, { class: "mrd-table__action-icon" }), h("span", { class: "mrd-table__action-tooltip" }, t('table_search', locale))))), filterCount > 0 && (h("button", { class: "mrd-table__action mrd-table__action--secondary mrd-table__filter-clear", onClick: cb.onClearAllFilters }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })), h("span", { class: "mrd-table__filter-clear-label" }, t('table_filter_clear_all', locale), " (", filterCount, ")")))), hasViewSwitcher && (h("div", { class: "mrd-table__toolbar-center" }, h("div", { class: "mrd-table__view-switcher" }, h("button", { class: "mrd-table__view-arrow", "aria-label": "Previous view", onClick: () => cb.onViewSwitch((activeViewIdx - 1 + views.length) % views.length) }, "\u25C0"), h("div", { class: "mrd-table__view-title-wrap" }, h("button", { class: "mrd-table__view-title", onClick: (e) => cb.onToggleViewPopover(e) }, (_a = views[activeViewIdx]) === null || _a === void 0 ? void 0 : _a.label), viewPopoverOpen && (h("div", { class: "mrd-table__view-popover", onClick: (e) => e.stopPropagation() }, views.map((v, i) => (h("button", { key: String(i), class: `mrd-table__view-popover-item${i === activeViewIdx ? ' mrd-table__view-popover-item--active' : ''}`, onClick: () => {
6481
6491
  if (i !== activeViewIdx)
6482
6492
  cb.onViewSwitch(i);
6483
6493
  cb.onCloseViewPopover();
@@ -6651,7 +6661,7 @@ function getStalePages(requestedAt, now, timeoutMs) {
6651
6661
  return stale;
6652
6662
  }
6653
6663
 
6654
- const mrdTableCss = () => `.sc-mrd-table-h{display:block;width:100%}.mrd-table.sc-mrd-table{overflow-x:auto}.mrd-table__scroll.sc-mrd-table{overflow-y:auto;overflow-x:auto;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow-anchor:none}.mrd-table__table.sc-mrd-table{width:auto;min-width:100%;border-collapse:collapse;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900)}.mrd-table__scroll.sc-mrd-table .mrd-table__table.sc-mrd-table{min-width:max-content}.mrd-table__header.sc-mrd-table{position:sticky;top:0;z-index:1;background:var(--mrd-color-white);text-align:left;padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:2px solid var(--mrd-border-color);color:var(--mrd-color-neutral-600);font-weight:var(--mrd-font-weight-medium);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:var(--mrd-font-size-xs);text-transform:uppercase;letter-spacing:0.04em}.mrd-table__header--sortable.sc-mrd-table{cursor:pointer;user-select:none}.mrd-table__header--sortable.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-800)}.mrd-table__header--sorted-asc.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header--filtered.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header-label.sc-mrd-table{margin-right:var(--mrd-space-1)}.mrd-table__col-resizer.sc-mrd-table{position:absolute;top:0;right:0;width:9px;height:100%;cursor:col-resize;touch-action:none;user-select:none}.mrd-table__col-resizer.sc-mrd-table::after{content:"";position:absolute;top:25%;right:4px;width:1px;height:50%;background:var(--mrd-border-color)}.mrd-table__col-resizer.sc-mrd-table:hover::after{width:2px;right:3px;background:var(--mrd-color-primary)}.mrd-table__col-resizer--active.sc-mrd-table::after{width:2px;right:3px;height:100%;top:0;background:var(--mrd-color-primary)}.mrd-table--resizing.sc-mrd-table{cursor:col-resize;user-select:none}.mrd-table__sort-icon.sc-mrd-table{font-size:0.85rem;opacity:0.4;vertical-align:middle}.mrd-table__header--sorted-asc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table{opacity:1;color:var(--mrd-color-primary)}.mrd-table__filter-icon.sc-mrd-table{display:inline-flex;align-items:center;vertical-align:middle;margin-left:var(--mrd-space-1);color:var(--mrd-color-primary)}.mrd-table__row.sc-mrd-table{border-bottom:1px solid var(--mrd-border-color)}.mrd-table__row.sc-mrd-table:hover{background:var(--mrd-color-neutral-200) !important}.mrd-table__row--clickable.sc-mrd-table{cursor:pointer}.mrd-table__row--loading.sc-mrd-table{background:transparent}.mrd-table__row--failed.sc-mrd-table{background:transparent}.mrd-table__spacer.sc-mrd-table{border:none}.mrd-table__spacer.sc-mrd-table td.sc-mrd-table{padding:0;border:none}.mrd-table__cell.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);vertical-align:top;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__cell--numeric.sc-mrd-table{text-align:right;font-variant-numeric:tabular-nums}.mrd-table__cell--placeholder.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__cell--failed.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__placeholder-bar.sc-mrd-table{display:block;height:0.75rem;width:55%;border-radius:var(--mrd-border-radius-sm);background:linear-gradient(90deg, var(--mrd-color-neutral-200) 25%, var(--mrd-color-neutral-100) 50%, var(--mrd-color-neutral-200) 75%);background-size:200% 100%;animation:mrd-shimmer 1.4s ease infinite}.mrd-table__retry-button.sc-mrd-table{border:none;background:none;padding:0;color:var(--mrd-color-danger);font-size:inherit;cursor:pointer;text-decoration:underline}.mrd-table__toolbar.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding-bottom:var(--mrd-space-2)}.mrd-table__toolbar-left.sc-mrd-table,.mrd-table__toolbar-right.sc-mrd-table{display:flex;gap:var(--mrd-space-2);align-items:center}.mrd-table__toolbar-center.sc-mrd-table{flex:1;display:flex;justify-content:center;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-switcher.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-arrow.sc-mrd-table{background:none;border:none;cursor:pointer;padding:0 var(--mrd-space-1);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-xs);line-height:1}.mrd-table__view-arrow.sc-mrd-table:hover{color:var(--mrd-color-neutral-800)}.mrd-table__view-title-wrap.sc-mrd-table{position:relative}.mrd-table__view-title.sc-mrd-table{font-size:var(--mrd-font-size-sm);font-weight:600;color:var(--mrd-color-neutral-800);font-family:var(--mrd-font-family);background:none;border:none;outline:none;cursor:pointer;padding:0 var(--mrd-space-1);max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__view-title.sc-mrd-table:hover{color:var(--mrd-color-primary)}.mrd-table__view-popover.sc-mrd-table{position:absolute;top:calc(100% + var(--mrd-space-1));left:50%;transform:translateX(-50%);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-radius-md);box-shadow:var(--mrd-shadow-md);z-index:100;min-width:160px;padding:var(--mrd-space-1) 0}.mrd-table__view-popover-item.sc-mrd-table{display:block;width:100%;text-align:left;background:none;border:none;cursor:pointer;padding:var(--mrd-space-2) var(--mrd-space-3);font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-700);white-space:nowrap}.mrd-table__view-popover-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50)}.mrd-table__view-popover-item--active.sc-mrd-table{font-weight:600;color:var(--mrd-color-primary)}.mrd-table__action.sc-mrd-table{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--mrd-border-radius);cursor:pointer;color:var(--mrd-color-neutral-400);transition:background-color 0.15s, border-color 0.15s, color 0.15s}.mrd-table__action.sc-mrd-table:hover{background-color:var(--mrd-color-neutral-100);border-color:var(--mrd-color-neutral-300);color:var(--mrd-color-neutral-700)}.mrd-table__action.sc-mrd-table:hover .mrd-table__action-tooltip.sc-mrd-table{display:block}.mrd-table__action.sc-mrd-table:disabled{opacity:0.4;cursor:not-allowed}.mrd-table__action--primary.sc-mrd-table{color:var(--mrd-color-neutral-500)}.mrd-table__action--primary.sc-mrd-table:hover{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__action--danger.sc-mrd-table{color:var(--mrd-color-error)}.mrd-table__action--danger.sc-mrd-table:hover{background-color:var(--mrd-color-error-light, #fef2f2);border-color:var(--mrd-color-error)}.mrd-table__action-icon.sc-mrd-table{width:1.25rem;height:1.25rem;pointer-events:none;fill:currentColor}.mrd-table__action-tooltip.sc-mrd-table{display:none;position:absolute;bottom:calc(100% + 6px);right:0;padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);white-space:nowrap;background:var(--mrd-color-tooltip, #fffce1);color:var(--mrd-color-neutral-900);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-sm, var(--mrd-border-radius));pointer-events:none;z-index:10}.mrd-table__create-picker-wrap.sc-mrd-table{position:relative}.mrd-table__create-picker.sc-mrd-table{position:absolute;right:0;top:calc(100% + 4px);background:var(--mrd-color-white, #fff);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:10;min-width:10rem;padding:var(--mrd-space-1) 0}.mrd-table__create-picker-item.sc-mrd-table{display:block;width:100%;text-align:left;padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-800)}.mrd-table__create-picker-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-900)}.mrd-table__filter-clear.sc-mrd-table{width:auto;gap:var(--mrd-space-1);padding:0 var(--mrd-space-2);color:var(--mrd-color-primary);border-color:var(--mrd-color-primary)}.mrd-table__filter-clear.sc-mrd-table:hover{color:var(--mrd-color-primary);border-color:var(--mrd-color-primary)}.mrd-table__filter-clear-label.sc-mrd-table{font-size:var(--mrd-font-size-sm);white-space:nowrap}.mrd-table__filter-popup.sc-mrd-table{position:fixed;width:280px;background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:var(--mrd-z-dropdown, 200);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-popup-header.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding:var(--mrd-space-2) var(--mrd-space-3);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__filter-popup-title.sc-mrd-table{font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-close.sc-mrd-table{background:transparent;border:none;cursor:pointer;color:var(--mrd-color-neutral-500);font-size:0.9rem;padding:2px 4px;border-radius:3px;line-height:1}.mrd-table__filter-close.sc-mrd-table:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-table__filter-section.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-3)}.mrd-table__filter-section-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);text-transform:uppercase;letter-spacing:0.04em;color:var(--mrd-color-neutral-500);margin-bottom:var(--mrd-space-2)}.mrd-table__filter-sort-buttons.sc-mrd-table{display:flex;gap:var(--mrd-space-2)}.mrd-table__filter-sort-btn.sc-mrd-table{flex:1;padding:var(--mrd-space-1) var(--mrd-space-2);background:transparent;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-700)}.mrd-table__filter-sort-btn.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-sort-btn--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-divider.sc-mrd-table{height:1px;background:var(--mrd-border-color);margin:0}.mrd-table__filter-editor.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-table__filter-select.sc-mrd-table,.mrd-table__filter-input.sc-mrd-table{width:100%;padding:var(--mrd-space-1) var(--mrd-space-2);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900);background:var(--mrd-color-white);box-sizing:border-box}.mrd-table__filter-select.sc-mrd-table:focus,.mrd-table__filter-input.sc-mrd-table:focus{outline:none;border-color:var(--mrd-color-primary);box-shadow:0 0 0 2px rgba(0, 0, 0, 0.06)}.mrd-table__filter-range.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__filter-range.sc-mrd-table .mrd-table__filter-input.sc-mrd-table{flex:1;min-width:0}.mrd-table__filter-range--stacked.sc-mrd-table{flex-direction:column;align-items:stretch;gap:var(--mrd-space-2)}.mrd-table__filter-range-sep.sc-mrd-table{color:var(--mrd-color-neutral-400);flex-shrink:0}.mrd-table__filter-range-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-bottom:2px}.mrd-table__filter-radio-group.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-table__filter-radio-group--inline.sc-mrd-table{flex-direction:row;gap:var(--mrd-space-3)}.mrd-table__filter-radio-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-list.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1);max-height:180px;overflow-y:auto}.mrd-table__filter-list-controls.sc-mrd-table{display:flex;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-1)}.mrd-table__filter-list-btn.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-primary);background:transparent;border:none;cursor:pointer;padding:0;text-decoration:underline}.mrd-table__filter-checkbox-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-no-support.sc-mrd-table{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);margin:0;font-style:italic}.mrd-table__filter-popup-footer.sc-mrd-table{display:flex;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-3);border-top:1px solid var(--mrd-border-color)}.mrd-table__filter-btn.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-3);border-radius:var(--mrd-border-radius);border:1px solid var(--mrd-border-color);font-size:var(--mrd-font-size-sm);cursor:pointer}.mrd-table__filter-btn--clear.sc-mrd-table{background:transparent;color:var(--mrd-color-neutral-600)}.mrd-table__filter-btn--clear.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-btn--apply.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-btn--apply.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary))}.mrd-table__totals-row.sc-mrd-table{border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell.sc-mrd-table{position:sticky;bottom:0;z-index:2;padding:var(--mrd-space-2) var(--mrd-space-4);background:var(--mrd-color-white);font-weight:var(--mrd-font-weight-medium);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell--numeric.sc-mrd-table{text-align:right}.mrd-table__footer.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);text-align:right}.mrd-table__empty.sc-mrd-table{padding:var(--mrd-space-4) var(--mrd-space-3);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-sm);text-align:center;margin:0}.mrd-table__file-btn.sc-mrd-table{display:inline-flex;align-items:center;gap:var(--mrd-space-1);background:none;border:none;padding:0;cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;max-width:100%;overflow:hidden}.mrd-table__file-btn.sc-mrd-table:hover{text-decoration:underline;color:var(--mrd-color-primary-dark)}.mrd-table__file-icon.sc-mrd-table{flex-shrink:0;width:1rem;height:1rem}.mrd-table__textblock-btn.sc-mrd-table{display:inline;background:none;border:none;padding:0 0 0 var(--mrd-space-1);cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;line-height:inherit;vertical-align:middle}.mrd-table__textblock-btn.sc-mrd-table:hover{color:var(--mrd-color-primary-dark)}.mrd-table__modal-backdrop.sc-mrd-table{position:fixed;inset:0;background:rgba(0, 0, 0, 0.4);z-index:var(--mrd-z-modal, 300);display:flex;align-items:center;justify-content:center}.mrd-table__modal.sc-mrd-table{background:#fff;border-radius:var(--mrd-radius-md, 0.5rem);padding:var(--mrd-space-6);max-width:min(600px, 90vw);max-height:70vh;overflow-y:auto;position:relative;box-shadow:var(--mrd-shadow-lg)}.mrd-table__modal-close.sc-mrd-table{position:absolute;top:var(--mrd-space-3);right:var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:1.25rem;line-height:1;color:var(--mrd-color-text-muted, #6b7280);padding:0}.mrd-table__modal-close.sc-mrd-table:hover{color:var(--mrd-color-text, #111827)}.mrd-table__modal-text.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);white-space:pre-wrap;word-break:break-word;font-size:var(--mrd-font-size-sm);line-height:1.6}.mrd-table__json-preview.sc-mrd-table{font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:inline-block;max-width:calc(100% - 1.5rem);vertical-align:middle}.mrd-table__modal-json.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);white-space:pre-wrap;word-break:break-word;line-height:1.6;background:none;border:none}@keyframes mrd-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}`;
6664
+ const mrdTableCss = () => `.sc-mrd-table-h{display:block;width:100%}.mrd-table.sc-mrd-table{overflow-x:auto}.mrd-table__scroll.sc-mrd-table{overflow-y:auto;overflow-x:auto;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow-anchor:none}.mrd-table__table.sc-mrd-table{width:auto;min-width:100%;border-collapse:collapse;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900)}.mrd-table__scroll.sc-mrd-table .mrd-table__table.sc-mrd-table{min-width:max-content}.mrd-table__header.sc-mrd-table{position:sticky;top:0;z-index:1;background:var(--mrd-color-white);text-align:left;padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:2px solid var(--mrd-border-color);color:var(--mrd-color-neutral-600);font-weight:var(--mrd-font-weight-medium);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:var(--mrd-font-size-xs);text-transform:uppercase;letter-spacing:0.04em}.mrd-table__header--sortable.sc-mrd-table{cursor:pointer;user-select:none}.mrd-table__header--sortable.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-800)}.mrd-table__header--sorted-asc.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header--filtered.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header-label.sc-mrd-table{margin-right:var(--mrd-space-1)}.mrd-table__col-resizer.sc-mrd-table{position:absolute;top:0;right:0;width:9px;height:100%;cursor:col-resize;touch-action:none;user-select:none}.mrd-table__col-resizer.sc-mrd-table::after{content:"";position:absolute;top:25%;right:4px;width:1px;height:50%;background:var(--mrd-border-color)}.mrd-table__col-resizer.sc-mrd-table:hover::after{width:2px;right:3px;background:var(--mrd-color-primary)}.mrd-table__col-resizer--active.sc-mrd-table::after{width:2px;right:3px;height:100%;top:0;background:var(--mrd-color-primary)}.mrd-table--resizing.sc-mrd-table{cursor:col-resize;user-select:none}.mrd-table__sort-icon.sc-mrd-table{font-size:0.85rem;opacity:0.4;vertical-align:middle}.mrd-table__header--sorted-asc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table{opacity:1;color:var(--mrd-color-primary)}.mrd-table__filter-icon.sc-mrd-table{display:inline-flex;align-items:center;vertical-align:middle;margin-left:var(--mrd-space-1);color:var(--mrd-color-primary)}.mrd-table__row.sc-mrd-table{border-bottom:1px solid var(--mrd-border-color)}.mrd-table__row.sc-mrd-table:hover{background:var(--mrd-color-neutral-200) !important}.mrd-table__row--clickable.sc-mrd-table{cursor:pointer}.mrd-table__row--loading.sc-mrd-table{background:transparent}.mrd-table__row--failed.sc-mrd-table{background:transparent}.mrd-table__spacer.sc-mrd-table{border:none}.mrd-table__spacer.sc-mrd-table td.sc-mrd-table{padding:0;border:none}.mrd-table__cell.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);vertical-align:top;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__cell--numeric.sc-mrd-table{text-align:right;font-variant-numeric:tabular-nums}.mrd-table__cell--placeholder.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__cell--failed.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__placeholder-bar.sc-mrd-table{display:block;height:0.75rem;width:55%;border-radius:var(--mrd-border-radius-sm);background:linear-gradient(90deg, var(--mrd-color-neutral-200) 25%, var(--mrd-color-neutral-100) 50%, var(--mrd-color-neutral-200) 75%);background-size:200% 100%;animation:mrd-shimmer 1.4s ease infinite}.mrd-table__retry-button.sc-mrd-table{border:none;background:none;padding:0;color:var(--mrd-color-danger);font-size:inherit;cursor:pointer;text-decoration:underline}.mrd-table__toolbar.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding-bottom:var(--mrd-space-2)}.mrd-table__toolbar-left.sc-mrd-table,.mrd-table__toolbar-right.sc-mrd-table{display:flex;gap:var(--mrd-space-2);align-items:center}.mrd-table__toolbar-center.sc-mrd-table{flex:1;display:flex;justify-content:center;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-switcher.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-arrow.sc-mrd-table{background:none;border:none;cursor:pointer;padding:0 var(--mrd-space-1);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-xs);line-height:1}.mrd-table__view-arrow.sc-mrd-table:hover{color:var(--mrd-color-neutral-800)}.mrd-table__view-title-wrap.sc-mrd-table{position:relative}.mrd-table__view-title.sc-mrd-table{font-size:var(--mrd-font-size-sm);font-weight:600;color:var(--mrd-color-neutral-800);font-family:var(--mrd-font-family);background:none;border:none;outline:none;cursor:pointer;padding:0 var(--mrd-space-1);max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__view-title.sc-mrd-table:hover{color:var(--mrd-color-primary)}.mrd-table__view-popover.sc-mrd-table{position:absolute;top:calc(100% + var(--mrd-space-1));left:50%;transform:translateX(-50%);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-radius-md);box-shadow:var(--mrd-shadow-md);z-index:100;min-width:160px;padding:var(--mrd-space-1) 0}.mrd-table__view-popover-item.sc-mrd-table{display:block;width:100%;text-align:left;background:none;border:none;cursor:pointer;padding:var(--mrd-space-2) var(--mrd-space-3);font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-700);white-space:nowrap}.mrd-table__view-popover-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50)}.mrd-table__view-popover-item--active.sc-mrd-table{font-weight:600;color:var(--mrd-color-primary)}.mrd-table__action.sc-mrd-table{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--mrd-border-radius);cursor:pointer;color:var(--mrd-color-neutral-400);transition:background-color 0.15s, border-color 0.15s, color 0.15s}.mrd-table__action.sc-mrd-table:hover{background-color:var(--mrd-color-neutral-100);border-color:var(--mrd-color-neutral-300);color:var(--mrd-color-neutral-700)}.mrd-table__action.sc-mrd-table:hover .mrd-table__action-tooltip.sc-mrd-table{display:block}.mrd-table__action.sc-mrd-table:disabled{opacity:0.4;cursor:not-allowed}.mrd-table__action--primary.sc-mrd-table{color:var(--mrd-color-neutral-500)}.mrd-table__action--primary.sc-mrd-table:hover{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__action--danger.sc-mrd-table{color:var(--mrd-color-error)}.mrd-table__action--danger.sc-mrd-table:hover{background-color:var(--mrd-color-error-light, #fef2f2);border-color:var(--mrd-color-error)}.mrd-table__action-icon.sc-mrd-table{width:1.25rem;height:1.25rem;pointer-events:none;fill:currentColor}.mrd-table__action-tooltip.sc-mrd-table{display:none;position:absolute;bottom:calc(100% + 6px);right:0;padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);white-space:nowrap;background:var(--mrd-color-tooltip, #fffce1);color:var(--mrd-color-neutral-900);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-sm, var(--mrd-border-radius));pointer-events:none;z-index:10}.mrd-table__search-box.sc-mrd-table{display:inline-flex;align-items:center;gap:var(--mrd-space-1);height:2rem;padding:0 var(--mrd-space-2);border:1px solid var(--mrd-border-color-focus, var(--mrd-color-primary));border-radius:var(--mrd-border-radius);background:var(--mrd-color-white, #fff);box-shadow:var(--mrd-shadow-focus, none);color:var(--mrd-color-neutral-400)}.mrd-table__search-input.sc-mrd-table{border:none;outline:none;background:transparent;font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-800);width:12rem}.mrd-table__search-clear.sc-mrd-table{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;padding:0;cursor:pointer;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-xs);line-height:1}.mrd-table__search-clear.sc-mrd-table:hover{color:var(--mrd-color-neutral-700)}.mrd-table__create-picker-wrap.sc-mrd-table{position:relative}.mrd-table__create-picker.sc-mrd-table{position:absolute;right:0;top:calc(100% + 4px);background:var(--mrd-color-white, #fff);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:10;min-width:10rem;padding:var(--mrd-space-1) 0}.mrd-table__create-picker-item.sc-mrd-table{display:block;width:100%;text-align:left;padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-800)}.mrd-table__create-picker-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-900)}.mrd-table__filter-clear.sc-mrd-table{width:auto;gap:var(--mrd-space-1);padding:0 var(--mrd-space-2);color:var(--mrd-color-primary);border-color:var(--mrd-color-primary)}.mrd-table__filter-clear.sc-mrd-table:hover{color:var(--mrd-color-primary);border-color:var(--mrd-color-primary)}.mrd-table__filter-clear-label.sc-mrd-table{font-size:var(--mrd-font-size-sm);white-space:nowrap}.mrd-table__filter-popup.sc-mrd-table{position:fixed;width:280px;background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:var(--mrd-z-dropdown, 200);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-popup-header.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding:var(--mrd-space-2) var(--mrd-space-3);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__filter-popup-title.sc-mrd-table{font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-close.sc-mrd-table{background:transparent;border:none;cursor:pointer;color:var(--mrd-color-neutral-500);font-size:0.9rem;padding:2px 4px;border-radius:3px;line-height:1}.mrd-table__filter-close.sc-mrd-table:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-table__filter-section.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-3)}.mrd-table__filter-section-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);text-transform:uppercase;letter-spacing:0.04em;color:var(--mrd-color-neutral-500);margin-bottom:var(--mrd-space-2)}.mrd-table__filter-sort-buttons.sc-mrd-table{display:flex;gap:var(--mrd-space-2)}.mrd-table__filter-sort-btn.sc-mrd-table{flex:1;padding:var(--mrd-space-1) var(--mrd-space-2);background:transparent;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-700)}.mrd-table__filter-sort-btn.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-sort-btn--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-divider.sc-mrd-table{height:1px;background:var(--mrd-border-color);margin:0}.mrd-table__filter-editor.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-table__filter-select.sc-mrd-table,.mrd-table__filter-input.sc-mrd-table{width:100%;padding:var(--mrd-space-1) var(--mrd-space-2);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900);background:var(--mrd-color-white);box-sizing:border-box}.mrd-table__filter-select.sc-mrd-table:focus,.mrd-table__filter-input.sc-mrd-table:focus{outline:none;border-color:var(--mrd-color-primary);box-shadow:0 0 0 2px rgba(0, 0, 0, 0.06)}.mrd-table__filter-range.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__filter-range.sc-mrd-table .mrd-table__filter-input.sc-mrd-table{flex:1;min-width:0}.mrd-table__filter-range--stacked.sc-mrd-table{flex-direction:column;align-items:stretch;gap:var(--mrd-space-2)}.mrd-table__filter-range-sep.sc-mrd-table{color:var(--mrd-color-neutral-400);flex-shrink:0}.mrd-table__filter-range-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-bottom:2px}.mrd-table__filter-radio-group.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-table__filter-radio-group--inline.sc-mrd-table{flex-direction:row;gap:var(--mrd-space-3)}.mrd-table__filter-radio-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-list.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1);max-height:180px;overflow-y:auto}.mrd-table__filter-list-controls.sc-mrd-table{display:flex;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-1)}.mrd-table__filter-list-btn.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-primary);background:transparent;border:none;cursor:pointer;padding:0;text-decoration:underline}.mrd-table__filter-checkbox-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-no-support.sc-mrd-table{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);margin:0;font-style:italic}.mrd-table__filter-popup-footer.sc-mrd-table{display:flex;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-3);border-top:1px solid var(--mrd-border-color)}.mrd-table__filter-btn.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-3);border-radius:var(--mrd-border-radius);border:1px solid var(--mrd-border-color);font-size:var(--mrd-font-size-sm);cursor:pointer}.mrd-table__filter-btn--clear.sc-mrd-table{background:transparent;color:var(--mrd-color-neutral-600)}.mrd-table__filter-btn--clear.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-btn--apply.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-btn--apply.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary))}.mrd-table__totals-row.sc-mrd-table{border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell.sc-mrd-table{position:sticky;bottom:0;z-index:2;padding:var(--mrd-space-2) var(--mrd-space-4);background:var(--mrd-color-white);font-weight:var(--mrd-font-weight-medium);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell--numeric.sc-mrd-table{text-align:right}.mrd-table__footer.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);text-align:right}.mrd-table__empty.sc-mrd-table{padding:var(--mrd-space-4) var(--mrd-space-3);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-sm);text-align:center;margin:0}.mrd-table__file-btn.sc-mrd-table{display:inline-flex;align-items:center;gap:var(--mrd-space-1);background:none;border:none;padding:0;cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;max-width:100%;overflow:hidden}.mrd-table__file-btn.sc-mrd-table:hover{text-decoration:underline;color:var(--mrd-color-primary-dark)}.mrd-table__file-icon.sc-mrd-table{flex-shrink:0;width:1rem;height:1rem}.mrd-table__textblock-btn.sc-mrd-table{display:inline;background:none;border:none;padding:0 0 0 var(--mrd-space-1);cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;line-height:inherit;vertical-align:middle}.mrd-table__textblock-btn.sc-mrd-table:hover{color:var(--mrd-color-primary-dark)}.mrd-table__modal-backdrop.sc-mrd-table{position:fixed;inset:0;background:rgba(0, 0, 0, 0.4);z-index:var(--mrd-z-modal, 300);display:flex;align-items:center;justify-content:center}.mrd-table__modal.sc-mrd-table{background:#fff;border-radius:var(--mrd-radius-md, 0.5rem);padding:var(--mrd-space-6);max-width:min(600px, 90vw);max-height:70vh;overflow-y:auto;position:relative;box-shadow:var(--mrd-shadow-lg)}.mrd-table__modal-close.sc-mrd-table{position:absolute;top:var(--mrd-space-3);right:var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:1.25rem;line-height:1;color:var(--mrd-color-text-muted, #6b7280);padding:0}.mrd-table__modal-close.sc-mrd-table:hover{color:var(--mrd-color-text, #111827)}.mrd-table__modal-text.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);white-space:pre-wrap;word-break:break-word;font-size:var(--mrd-font-size-sm);line-height:1.6}.mrd-table__json-preview.sc-mrd-table{font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:inline-block;max-width:calc(100% - 1.5rem);vertical-align:middle}.mrd-table__modal-json.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);white-space:pre-wrap;word-break:break-word;line-height:1.6;background:none;border:none}@keyframes mrd-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}`;
6655
6665
 
6656
6666
  /** How often (ms) to scan outstanding page requests for staleness. */
6657
6667
  const STALE_CHECK_INTERVAL_MS = 2000;
@@ -6682,6 +6692,17 @@ const MrdTable = class {
6682
6692
  this.keydownHandler = null;
6683
6693
  this.createPickerClickHandler = null;
6684
6694
  this.viewPopoverClickHandler = null;
6695
+ /** Debounce timer for the free-text search box — separate from debounceTimer
6696
+ * (pending-page requests), since typing and scrolling debounce independently. */
6697
+ this.searchDebounceTimer = null;
6698
+ /** The rendered search <input>, captured so it can be focused the instant it mounts. */
6699
+ this.searchInputEl = null;
6700
+ /** Set by toggleSearch() when the box just expanded; consumed and cleared in componentDidRender(). */
6701
+ this.searchNeedsFocus = false;
6702
+ /** Column filters stashed by stashFiltersForSearch() while the search box is open — the
6703
+ * backend can't combine `q` with column filters. Restored by restoreFiltersAfterSearch()
6704
+ * on close, unless the user applied a fresh filter of their own in the meantime. */
6705
+ this.stashedFilters = null;
6685
6706
  /** Watches the host for gaining a box (e.g. its tab pane being shown) — see componentDidLoad. */
6686
6707
  this.resizeObserver = null;
6687
6708
  /** Guards against scheduling more than one column-width measurement per freeze. */
@@ -6736,6 +6757,10 @@ const MrdTable = class {
6736
6757
  this.sortDir = 'asc';
6737
6758
  /** Active filters keyed by field name. */
6738
6759
  this.activeFilters = new Map();
6760
+ /** True while the toolbar's magnifying glass is expanded into the search input. */
6761
+ this.searchOpen = false;
6762
+ /** Current free-text search query — sent as `q` on every mrdLoadPage/aggregations request. */
6763
+ this.searchQuery = '';
6739
6764
  /** Field name of the currently open filter popup (null = closed). */
6740
6765
  this.openFilterCol = null;
6741
6766
  /** Filter state being edited in the open popup. */
@@ -6789,6 +6814,11 @@ const MrdTable = class {
6789
6814
  this.colWidthMeasureScheduled = false;
6790
6815
  this.colWidthsUserSet = false;
6791
6816
  this.fixedContentMeasured = false;
6817
+ // A new item is a different table (possibly not even a VIEW any more) — a leftover
6818
+ // query from the old one should not silently keep filtering it.
6819
+ this.searchOpen = false;
6820
+ this.searchQuery = '';
6821
+ this.stashedFilters = null;
6792
6822
  }
6793
6823
  // ── Lifecycle ──────────────────────────────────────────────────────────────
6794
6824
  componentWillLoad() {
@@ -6896,7 +6926,12 @@ const MrdTable = class {
6896
6926
  if (pageNumber === 0 && this.aggregationsPending) {
6897
6927
  this.aggregationsPending = false;
6898
6928
  const hasAggColumns = this.columns.some(c => c.type === 'FIELD' && c.aggregate);
6899
- if (!isLastPage || hasAggColumns) {
6929
+ // The aggregations endpoint doesn't support the `q` free-text param, so a request
6930
+ // sent while searching would silently return unfiltered totals. Leave aggregations
6931
+ // (and aggregationsTotal) at null instead — TotalsRow already renders nothing when
6932
+ // aggregations is null, so the totals row just disappears for the duration of the
6933
+ // search rather than showing numbers that don't match the filtered rows.
6934
+ if (!this.searchQuery && (!isLastPage || hasAggColumns)) {
6900
6935
  this.emitLoadAggregations();
6901
6936
  }
6902
6937
  }
@@ -6935,10 +6970,18 @@ const MrdTable = class {
6935
6970
  document.removeEventListener('click', this.viewPopoverClickHandler);
6936
6971
  this.viewPopoverClickHandler = null;
6937
6972
  }
6973
+ if (this.searchDebounceTimer !== null) {
6974
+ clearTimeout(this.searchDebounceTimer);
6975
+ this.searchDebounceTimer = null;
6976
+ }
6938
6977
  }
6939
6978
  componentDidRender() {
6940
6979
  this.freezeColWidths();
6941
6980
  this.growToFixedContent();
6981
+ if (this.searchNeedsFocus && this.searchInputEl) {
6982
+ this.searchInputEl.focus();
6983
+ this.searchNeedsFocus = false;
6984
+ }
6942
6985
  }
6943
6986
  /** Freeze the column widths once the first data page has rendered.
6944
6987
  *
@@ -7257,7 +7300,13 @@ const MrdTable = class {
7257
7300
  dataClass: v.dataClass,
7258
7301
  });
7259
7302
  }
7260
- /** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
7303
+ /** Build query params for a page request from current sort, view filters, filterClass and active column filters.
7304
+ *
7305
+ * `q` and column filters are mutually exclusive on the backend — combining them breaks
7306
+ * the search. stashFiltersForSearch() already empties activeFilters for the duration of
7307
+ * a search, but this guard is the actual guarantee: even if a filter is applied through
7308
+ * a column header while the search box is still open (before the query is cleared),
7309
+ * activeFilters is dropped from the request rather than sent alongside `q`. */
7261
7310
  buildQueryParams(page) {
7262
7311
  var _a;
7263
7312
  const v = this.allViews[this.activeViewIdx];
@@ -7266,7 +7315,8 @@ const MrdTable = class {
7266
7315
  sort: this.sortParam(),
7267
7316
  filterClass: v === null || v === void 0 ? void 0 : v.filterClass,
7268
7317
  viewFilters: (_a = v === null || v === void 0 ? void 0 : v.view) === null || _a === void 0 ? void 0 : _a.filter,
7269
- activeFilters: this.activeFilters.values(),
7318
+ activeFilters: this.searchQuery ? [] : this.activeFilters.values(),
7319
+ query: this.searchQuery,
7270
7320
  });
7271
7321
  }
7272
7322
  /** True when the table is in paginated / virtual-scroll mode rather than driven by the
@@ -7572,6 +7622,18 @@ const MrdTable = class {
7572
7622
  const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
7573
7623
  this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
7574
7624
  }
7625
+ /** Common reload after activeFilters or searchQuery changed: drop stale aggregations
7626
+ * (the next setPage(0) re-requests them, guarded against `q` in setPage() itself) and
7627
+ * re-fetch page 0. Shared by the filter popup, clear-all, and free-text search. */
7628
+ reloadAfterQueryChange() {
7629
+ this.aggregations = null;
7630
+ this.aggregationsTotal = null;
7631
+ this.aggregationsPending = true;
7632
+ if (this.isPaginated) {
7633
+ this.resetPages();
7634
+ this.emitPagesForWindow(this.renderStart, this.renderEnd);
7635
+ }
7636
+ }
7575
7637
  applyFilter() {
7576
7638
  const f = this.pendingFilter;
7577
7639
  if (!(f === null || f === void 0 ? void 0 : f.field)) {
@@ -7588,13 +7650,7 @@ const MrdTable = class {
7588
7650
  }
7589
7651
  this.activeFilters = next;
7590
7652
  this.closeFilterPopup();
7591
- this.aggregations = null;
7592
- this.aggregationsTotal = null;
7593
- this.aggregationsPending = true;
7594
- if (this.isPaginated) {
7595
- this.resetPages();
7596
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
7597
- }
7653
+ this.reloadAfterQueryChange();
7598
7654
  }
7599
7655
  clearFilter() {
7600
7656
  const name = this.openFilterCol;
@@ -7603,24 +7659,81 @@ const MrdTable = class {
7603
7659
  next.delete(name);
7604
7660
  this.activeFilters = next;
7605
7661
  this.closeFilterPopup();
7606
- this.aggregations = null;
7607
- this.aggregationsTotal = null;
7608
- this.aggregationsPending = true;
7609
- if (this.isPaginated) {
7610
- this.resetPages();
7611
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
7612
- }
7662
+ this.reloadAfterQueryChange();
7613
7663
  }
7614
7664
  clearAllFilters() {
7615
7665
  this.activeFilters = new Map();
7616
- this.aggregations = null;
7617
- this.aggregationsTotal = null;
7618
- this.aggregationsPending = true;
7619
- if (this.isPaginated) {
7620
- this.resetPages();
7621
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
7666
+ this.reloadAfterQueryChange();
7667
+ }
7668
+ // ── Free-text search ───────────────────────────────────────────────────────
7669
+ /** Search is a VIEW-only affordance — a RELATED_VIEW table is already scoped to
7670
+ * its parent record, so a free-text box there would invite confusion about what
7671
+ * it searches across. */
7672
+ get searchEnabled() {
7673
+ var _a;
7674
+ return ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'VIEW';
7675
+ }
7676
+ toggleSearch() {
7677
+ if (this.searchOpen) {
7678
+ this.closeSearch();
7679
+ }
7680
+ else {
7681
+ this.searchOpen = true;
7682
+ this.searchNeedsFocus = true;
7683
+ this.stashFiltersForSearch();
7622
7684
  }
7623
7685
  }
7686
+ /** Collapses the box back to the icon. Clearing a non-empty query and restoring any
7687
+ * stashed filters can each independently require a reload — reloadAfterQueryChange()
7688
+ * is called at most once here regardless of how many of the two actually changed. */
7689
+ closeSearch() {
7690
+ this.searchOpen = false;
7691
+ if (this.searchDebounceTimer !== null) {
7692
+ clearTimeout(this.searchDebounceTimer);
7693
+ this.searchDebounceTimer = null;
7694
+ }
7695
+ const hadQuery = this.searchQuery !== '';
7696
+ this.searchQuery = '';
7697
+ const filtersRestored = this.restoreFiltersAfterSearch();
7698
+ if (hadQuery || filtersRestored)
7699
+ this.reloadAfterQueryChange();
7700
+ }
7701
+ handleSearchInput(value) {
7702
+ this.searchQuery = value;
7703
+ if (this.searchDebounceTimer !== null)
7704
+ clearTimeout(this.searchDebounceTimer);
7705
+ this.searchDebounceTimer = setTimeout(() => this.applySearch(), SEARCH_DEBOUNCE_MS);
7706
+ }
7707
+ /** Reloads from page 0 with the current searchQuery, same reset as applyFilter(). */
7708
+ applySearch() {
7709
+ this.searchDebounceTimer = null;
7710
+ this.reloadAfterQueryChange();
7711
+ }
7712
+ /** Column filters and the free-text `q` param are mutually exclusive on the backend —
7713
+ * sending both breaks the search. Opening the search box stashes any active filters
7714
+ * and clears them (the header filter icons and the clear-all button disappear along
7715
+ * with activeFilters, so there is nothing extra to hide) and reloads unfiltered. */
7716
+ stashFiltersForSearch() {
7717
+ if (this.activeFilters.size === 0)
7718
+ return;
7719
+ this.stashedFilters = this.activeFilters;
7720
+ this.activeFilters = new Map();
7721
+ this.reloadAfterQueryChange();
7722
+ }
7723
+ /** Restores filters stashed by stashFiltersForSearch(), unless the user applied a fresh
7724
+ * filter of their own while the search box was open — that explicit choice wins over
7725
+ * reinstating the old one. Returns whether activeFilters actually changed, so the
7726
+ * caller can decide whether a reload is needed. */
7727
+ restoreFiltersAfterSearch() {
7728
+ if (!this.stashedFilters)
7729
+ return false;
7730
+ const stashed = this.stashedFilters;
7731
+ this.stashedFilters = null;
7732
+ if (this.activeFilters.size > 0)
7733
+ return false;
7734
+ this.activeFilters = stashed;
7735
+ return true;
7736
+ }
7624
7737
  // ── View switcher ──────────────────────────────────────────────────────────
7625
7738
  handleViewSwitch(targetIdx) {
7626
7739
  var _a, _b;
@@ -7630,6 +7743,9 @@ const MrdTable = class {
7630
7743
  this.activeViewIdx = targetIdx;
7631
7744
  this.applyDefaultSort((_b = (_a = target.view) === null || _a === void 0 ? void 0 : _a.defaultSort) !== null && _b !== void 0 ? _b : '');
7632
7745
  this.activeFilters = new Map();
7746
+ this.searchOpen = false;
7747
+ this.searchQuery = '';
7748
+ this.stashedFilters = null;
7633
7749
  this.init();
7634
7750
  }
7635
7751
  toggleViewPopover(e) {
@@ -7652,7 +7768,7 @@ const MrdTable = class {
7652
7768
  // ── Render: toolbar ────────────────────────────────────────────────────────
7653
7769
  renderToolbar() {
7654
7770
  var _a;
7655
- return (h(Toolbar, { locale: this.locale, filterCount: this.activeFilters.size, actions: this.tableActions, views: this.allViews, activeViewIdx: this.activeViewIdx, viewPopoverOpen: this.viewPopoverOpen, createPickerOpen: this.createPickerOpen, createTypes: (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes, readOnly: this.readOnly, cb: {
7771
+ return (h(Toolbar, { locale: this.locale, filterCount: this.activeFilters.size, actions: this.tableActions, views: this.allViews, activeViewIdx: this.activeViewIdx, viewPopoverOpen: this.viewPopoverOpen, createPickerOpen: this.createPickerOpen, createTypes: (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes, readOnly: this.readOnly, searchEnabled: this.searchEnabled, searchOpen: this.searchOpen, searchQuery: this.searchQuery, cb: {
7656
7772
  onClearAllFilters: () => this.clearAllFilters(),
7657
7773
  onViewSwitch: idx => this.handleViewSwitch(idx),
7658
7774
  onToggleViewPopover: e => this.toggleViewPopover(e),
@@ -7663,6 +7779,10 @@ const MrdTable = class {
7663
7779
  this.closeCreatePicker();
7664
7780
  },
7665
7781
  onAction: action => this.mrdAction.emit(this.buildActionDetail(action)),
7782
+ onToggleSearch: () => this.toggleSearch(),
7783
+ onSearchInput: value => this.handleSearchInput(value),
7784
+ onCloseSearch: () => this.closeSearch(),
7785
+ onSearchInputRef: el => (this.searchInputEl = el !== null && el !== void 0 ? el : null),
7666
7786
  } }));
7667
7787
  }
7668
7788
  // ── Render: filter popup ───────────────────────────────────────────────────
@@ -1,6 +1,6 @@
1
1
  import { h, r as registerInstance, c as createEvent, H as Host, g as getElement } from './index-CDiBvvJU.js';
2
2
  import { a as ClientLayoutItemType } from './client-layout-Bc42CfJB.js';
3
- import { t, C as CellRenderer, a as formatDate } from './cell-renderer-CC8-MtvQ.js';
3
+ import { t, C as CellRenderer, a as formatDate } from './cell-renderer-BDY8UXkH.js';
4
4
 
5
5
  /**
6
6
  * Whether a layout item can appear in the merge diff at all. m-n relations
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell-renderer-B8u5BCK-.js","sources":["src/utils/cell-renderer.ts"],"sourcesContent":["import { formatNumber, formatPercentage, formatCurrency, formatDate, formatDateTime, formatTime } from './format';\nimport { ClientLayoutItem, ClientLayoutItemType } from '../types/client-layout';\n\n/** TableColumn is an alias for ClientLayoutItem — used for table column definitions. */\nexport type TableColumn = ClientLayoutItem;\n\n/** One entry in the alternativeViews array for mrd-table. */\nexport interface AlternativeView {\n /** Named view identifier, emitted in mrdSwitchView. */\n name: string;\n /** Display text; falls back to name when absent. */\n label?: string;\n /** Optional class override (TypeFQN); emitted in mrdSwitchView. */\n class?: string;\n}\n\n/** Defines a toolbar action button for mrd-table. */\nexport interface TableAction {\n /** Machine-readable identifier, e.g. 'create' | 'export'. Emitted in mrdAction event. */\n action: string;\n /** Tooltip text (and label fallback when no icon is provided). */\n label: string;\n /** SVG sprite href, e.g. \"assets/sprites.svg#icon-plus\". Optional. */\n icon?: string;\n /** Button style variant. Defaults to 'secondary'. */\n variant?: 'primary' | 'secondary' | 'danger';\n disabled?: boolean;\n basicType?: string;\n}\n\n/** Represents an active filter on a single column. */\nexport interface ColumnFilter {\n field: string;\n dataType: string;\n /** Text operator — only relevant for text-like data types. */\n operator?: 'contains' | 'startsWith' | 'equals' | 'isEmpty' | 'isNotEmpty';\n /** Single value (boolean, exact text/number/date). */\n value?: string | number | boolean | null;\n /** Range start (≥) — future API support. */\n from?: string | number | null;\n /** Range end (≤) — future API support. */\n to?: string | number | null;\n /** LIST: keys of selected items to include. */\n values?: string[];\n}\n\nexport class CellRenderer {\n static render(column: TableColumn, row: Record<string, any>, locale: string): string {\n if (column.type === ClientLayoutItemType.RELATION) {\n const name = column.name ?? '';\n const link = row?._links?.[name];\n if (!link) return '';\n if (Array.isArray(link)) return link.map((l: any) => l.name ?? '').filter(Boolean).join(', ');\n return link.name ?? '';\n }\n\n if (column.type !== ClientLayoutItemType.FIELD) return '';\n\n const name = column.name ?? '';\n const dataType = column.dataType;\n const listItems = column.listItems;\n let raw = row?.[name];\n // History-enabled fields are stored as { current, history: [...] } — render\n // the current value, same as mrd-layout-section's field rendering.\n if (column.historyEnabled && raw != null && typeof raw === 'object' && !Array.isArray(raw) && 'current' in raw) {\n raw = (raw as any).current;\n }\n if (raw == null || raw === '') return '';\n\n const values = Array.isArray(raw) ? raw : [raw];\n return values\n .map(v => CellRenderer.renderValue(dataType ?? 'TEXT', v, listItems ?? [], locale))\n .filter(s => s !== '')\n .join(', ');\n }\n\n static renderValue(\n dataType: string,\n value: any,\n listItems: Array<{ key: string; label: string }>,\n locale: string,\n ): string {\n switch (dataType) {\n case 'INTEGER':\n return formatNumber(Number(value), locale, { maximumFractionDigits: 0 });\n case 'DECIMAL':\n return formatNumber(Number(value), locale);\n case 'PERCENTAGE':\n return formatPercentage(Number(value), locale);\n case 'CURRENCY': {\n const { amount, currency } = typeof value === 'object' && value !== null\n ? value\n : { amount: value, currency: '' };\n return currency\n ? formatCurrency(Number(amount), currency, locale)\n : formatNumber(Number(amount), locale);\n }\n case 'DATE':\n return formatDate(value, locale);\n case 'DATETIME':\n return formatDateTime(value, locale);\n case 'TIME':\n return formatTime(value, locale);\n case 'BOOLEAN':\n return value ? '✓' : '';\n case 'FILE':\n case 'IMAGE':\n return typeof value === 'object' && value !== null ? (value.fileName ?? '') : '';\n case 'LIST': {\n const item = listItems.find(li => li.key === String(value));\n return item?.label ?? String(value);\n }\n case 'TEXTBLOCK': {\n const stripped = String(value).replace(/<[^>]*>/g, '');\n const txt = document.createElement('textarea');\n txt.innerHTML = stripped;\n return txt.value.trim();\n }\n case 'LONGTEXT':\n return String(value).replace(/[\\r\\n]+/g, ' ').trim();\n case 'JSON': {\n const str = typeof value === 'object' ? JSON.stringify(value) : String(value);\n return str.replace(/[\\r\\n]+/g, ' ').trim();\n }\n case 'SECRET':\n return value ? '••••••••' : '';\n default:\n return String(value);\n }\n }\n\n /**\n * Returns syntax-highlighted JSON as an HTML string with inline styles.\n * compact=true → single line (no indentation); compact=false → pretty-printed.\n */\n static formatJson(value: any, compact = false): string {\n try {\n const parsed = typeof value === 'string' ? JSON.parse(value) : value;\n const json = compact ? JSON.stringify(parsed) : JSON.stringify(parsed, null, 2);\n return json.replace(\n /(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g,\n match => {\n let style = 'color:#2aa198';\n if (/^\"/.test(match)) {\n style = /:$/.test(match) ? 'color:#881391' : 'color:#268bd2';\n } else if (/true|false/.test(match)) {\n style = 'color:#b58900';\n } else if (/null/.test(match)) {\n style = 'color:#dc322f';\n }\n return `<span style=\"${style}\">${match}</span>`;\n },\n );\n } catch {\n return String(value);\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-layout-Bc42CfJB.js","sources":["src/types/client-layout.ts"],"sourcesContent":["// ─── Layout type ──────────────────────────────────────────────────────────────\n\nexport enum ClientLayoutType {\n OBJECT_FORM_DASHBOARD = 'OBJECT_FORM_DASHBOARD',\n CLASS_DASHBOARD = 'CLASS_DASHBOARD',\n GENERAL_DASHBOARD = 'GENERAL_DASHBOARD',\n NAVIGATION_PANE = 'NAVIGATION_PANE',\n}\n\n// ─── Item types ───────────────────────────────────────────────────────────────\n\nexport enum ClientLayoutItemType {\n // Form / data input\n FIELD = 'FIELD',\n RELATION = 'RELATION',\n // Layout structure\n SECTION = 'SECTION',\n GROUP = 'GROUP',\n // Read-only / display\n HEADER = 'HEADER',\n TEXT = 'TEXT',\n // Navigation / actions\n NAVIGATE = 'NAVIGATE',\n ACTION = 'ACTION',\n SEARCH = 'SEARCH',\n // Dashboard views\n VIEW = 'VIEW',\n RELATED_VIEW = 'RELATED_VIEW',\n RELATED_OBJECT = 'RELATED_OBJECT',\n}\n\n// ─── Field data types ─────────────────────────────────────────────────────────\n\nexport enum ClientLayoutItemFieldDataType {\n TEXT = 'TEXT',\n TEXTBLOCK = 'TEXTBLOCK',\n INTEGER = 'INTEGER',\n DECIMAL = 'DECIMAL',\n PERCENTAGE = 'PERCENTAGE',\n CURRENCY = 'CURRENCY',\n BOOLEAN = 'BOOLEAN',\n DATE = 'DATE',\n DATETIME = 'DATETIME',\n TIME = 'TIME',\n EMAIL = 'EMAIL',\n HYPERLINK = 'HYPERLINK',\n LIST = 'LIST',\n FILE = 'FILE',\n IMAGE = 'IMAGE',\n LONGTEXT = 'LONGTEXT',\n JSON = 'JSON',\n SECRET = 'SECRET',\n}\n\n// ─── Relation display / edit behaviour ───────────────────────────────────────\n\nexport enum ClientLayoutItemRelationDisplayType {\n SEARCH = 'SEARCH',\n DROPDOWN = 'DROPDOWN',\n CHECKBOX = 'CHECKBOX',\n}\n\nexport enum ClientLayoutItemRelationEditBehavior {\n SEARCH = 'SEARCH',\n DROPDOWN = 'DROPDOWN',\n CHECKBOX = 'CHECKBOX',\n}\n\n// ─── VIEW / RELATED_VIEW navigate behaviour ──────────────────────────────────\n\n/** How navigating from a row/document in this VIEW or RELATED_VIEW should open\n * its target: a full page navigation, or an overlay on top of the current page. */\nexport enum ClientLayoutNavigateBehaviour {\n PAGE = 'PAGE',\n OVERLAY_PAGE = 'OVERLAY_PAGE',\n}\n\n// ─── Data object link types (API _links shape) ───────────────────────────────\n\n/** A single sub-link within a multi-value relation link. */\nexport interface DataObjectSubLink {\n href: string;\n name: string;\n}\n\n/** Link object as returned by the API on a data object's `_links` map. */\nexport interface DataObjectLink {\n href: string;\n name?: string;\n values?: DataObjectSubLink[];\n}\n\n// ─── Shared value types ───────────────────────────────────────────────────────\n\n/** A selectable list item as returned by the API. */\nexport interface ClientListValue {\n /** Raw key stored in the database (API uses `key`, older code used `value`). */\n key: string;\n label: string;\n color?: string | null;\n backgroundColor?: string | null;\n}\n\nexport interface CurrencyValue {\n amount: number | null;\n currency: string;\n decimals?: number;\n}\n\nexport interface HyperlinkValue {\n href: string;\n name?: string;\n}\n\nexport interface RelationSearchResult {\n id: string;\n label: string;\n description?: string;\n}\n\n/** A single file belonging to a `commons.document`-archetype record. The host\n * resolves `href` to a signed URL and decides how (or whether) to render it\n * inline — the component only ever hands over the reference. */\nexport interface DocumentAttachment {\n href: string;\n fileName: string;\n mimeType?: string;\n}\n\n// ─── Archetypes (semantic type contracts) ────────────────────────────────────\n\n/**\n * A resolved archetype binding as published on a dashboard.\n * `archetype` is the platform-defined id (e.g. `commons.document`); `slots` maps\n * each slot name to the concrete field/relation name on this type. The client\n * keys on the archetype id and reads values from the data endpoint via the map;\n * the slot kind (value vs relation) is known from the archetype id itself and is\n * not published.\n */\nexport interface ClientArchetype {\n archetype: string;\n slots: Record<string, string>;\n}\n\n/** Well-known archetype ids the client renders specially. */\nexport const ARCHETYPE_DOCUMENT = 'commons.document';\nexport const ARCHETYPE_INVOICE = 'commons.invoice';\nexport const ARCHETYPE_EMAIL = 'commons.email';\n/** Bound by a `commons.invoice`'s `lines` relation target class. Used to find the\n * RELATED_VIEW item for the line items generically, by archetype id rather than\n * by name/class string. */\nexport const ARCHETYPE_INVOICE_LINE = 'commons.invoiceLine';\n\n/**\n * Find a binding for `archetypeId` in a published `archetypes` list.\n * Returns `undefined` when the archetype is absent — callers fall back to the\n * generic table/field rendering.\n */\nexport function resolveArchetype(\n archetypes: ClientArchetype[] | null | undefined,\n archetypeId: string,\n): ClientArchetype | undefined {\n return (archetypes ?? []).find(a => a.archetype === archetypeId);\n}\n\n// ─── Item definitions ─────────────────────────────────────────────────────────\n\nexport interface ClientLayoutItemField {\n name: string;\n label: string;\n dataType: ClientLayoutItemFieldDataType;\n required: boolean;\n disabled?: boolean;\n multiple?: boolean;\n header?: boolean;\n defaultValue?: string | null;\n listItems?: ClientListValue[] | null;\n // UI hints — optional, not sent by API\n placeholder?: string;\n accept?: string;\n maxSize?: number;\n decimalPrecision?: number;\n currencyCode?: string;\n /** Aggregate function to render in the table totals row. */\n aggregate?: 'sum' | 'avg' | 'count' | null;\n historyEnabled?: boolean;\n /** Render the item on an OBJECT_DASHBOARD even when it has no value. */\n showEmpty?: boolean;\n}\n\n/** Response shape from the /aggregations endpoint. */\nexport interface AggregationResult {\n total?: number;\n count?: Record<string, number>;\n sum?: Record<string, number>;\n avg?: Record<string, number>;\n}\n\nexport interface ClientLayoutItemRelation {\n name: string;\n label: string;\n relatedClass: string;\n mostSignificantClass?: string;\n displayType?: ClientLayoutItemRelationDisplayType;\n editBehavior?: ClientLayoutItemRelationEditBehavior | null;\n commonRelation?: string;\n required: boolean;\n disabled?: boolean;\n multiple?: boolean;\n defaultValue?: string | null;\n dropdownValues?: ClientListValue[];\n /** Render the item on an OBJECT_DASHBOARD even when it has no value. */\n showEmpty?: boolean;\n}\n\nexport interface ClientLayoutItemNavigate {\n dataClass: string;\n icon?: string | null;\n navigationType?: string | null;\n}\n\nexport interface ClientLayoutItemRelatedView {\n name: string;\n fromClass?: string | null;\n relatedClass: string;\n filterClass?: string | null;\n showTitle: boolean;\n}\n\nexport interface ClientLayoutItemRelatedObject {\n name: string;\n relatedClass: string;\n}\n\nexport interface ClientLayoutItemSearch {\n dataClass: string;\n showTitle: boolean;\n}\n\n// ─── Generic item ─────────────────────────────────────────────────────────────\n\nexport interface ClientCreateType {\n type: string;\n label: string;\n}\n\n/**\n * A single item in a ClientLayout. The `type` discriminator determines which\n * optional fields are present. Components should only act on types they\n * understand and ignore others.\n */\nexport interface ClientLayoutItem {\n type: ClientLayoutItemType;\n label?: string;\n\n // FIELD\n field?: ClientLayoutItemField;\n\n // RELATION\n relation?: ClientLayoutItemRelation;\n\n // SECTION / GROUP — nested items\n items?: ClientLayoutItem[];\n\n // NAVIGATE\n navigate?: ClientLayoutItemNavigate;\n\n // VIEW — embedded view config (new flat format)\n view?: ClientViewMetadata;\n\n // RELATED_VIEW\n relatedView?: ClientLayoutItemRelatedView;\n\n // RELATED_OBJECT\n relatedObject?: ClientLayoutItemRelatedObject;\n\n // SEARCH\n search?: ClientLayoutItemSearch;\n\n /**\n * Archetype bindings for this item. The API publishes them on the item itself\n * (sibling of `view`), for two cases:\n * - object dashboard top-level: the type of the object itself → mrd-layout-section\n * renders a recognisable single-document view instead of generic fields;\n * - a VIEW / RELATED_VIEW item: → mrd-layout-section offers the document\n * collection view (folder tree) alongside the generic table.\n */\n archetypes?: ClientArchetype[];\n\n // ─── Flat API fields ──────────────────────────────────────────────────────\n // Shared / ACTION / VIEW\n name?: string;\n showTitle?: boolean;\n /** Embedded alternative view configs (new flat format). */\n alternativeViews?: Array<{ label?: string; dataClass?: string; fromClass?: string | null; filterClass?: string | null; view?: ClientViewMetadata }>;\n /** Toolbar buttons for embedded views. null/omitted = [\"NEW\",\"EXPORT\"]; [] = none. */\n actions?: string[] | null;\n /** Concrete subtypes available for create. When set, the NEW button expands into one button per entry. */\n createTypes?: ClientCreateType[] | null;\n\n // FIELD (flat)\n dataType?: ClientLayoutItemFieldDataType;\n required?: boolean;\n disabled?: boolean;\n multiple?: boolean;\n header?: boolean;\n defaultValue?: string | null;\n listItems?: ClientListValue[] | null;\n aggregate?: 'sum' | 'avg' | 'count' | null;\n placeholder?: string;\n accept?: string;\n maxSize?: number;\n decimalPrecision?: number;\n currencyCode?: string;\n historyEnabled?: boolean;\n /** FIELD / RELATION — render the item on an OBJECT_DASHBOARD even when it has\n * no value, instead of hiding it (the default). */\n showEmpty?: boolean;\n\n // RELATION (flat)\n relatedClass?: string;\n mostSignificantClass?: string;\n displayType?: ClientLayoutItemRelationDisplayType;\n editBehavior?: ClientLayoutItemRelationEditBehavior | null;\n commonRelation?: string;\n dropdownValues?: ClientListValue[];\n\n // VIEW / NAVIGATE / SEARCH (flat) — API sends 'dataClass' (renamed from reserved 'class')\n dataClass?: string;\n\n // RELATED_VIEW (flat)\n fromClass?: string | null;\n filterClass?: string | null;\n /** Name of the relation on the related object that points back to the\n * `fromClass` parent (e.g. a document's `dossier` relation). When it equals\n * the `commons.document` archetype's `container` slot, the view is a single\n * container context (see mrd-document-list seeding). */\n inverseRelation?: string | null;\n /** How navigating out of this VIEW/RELATED_VIEW opens its target. Defaults to\n * `PAGE` (full navigation) when absent. mrd-layout-section reads this off the\n * item and includes it in the mrdNavigate event detail it relays upward. */\n navigateBehaviour?: ClientLayoutNavigateBehaviour;\n\n // NAVIGATE (flat)\n icon?: string | null;\n navigationType?: string | null;\n\n // ACTION (flat)\n actionType?: string;\n}\n\n// ─── Layout ───────────────────────────────────────────────────────────────────\n\nexport interface ClientLayout {\n type?: ClientLayoutType;\n label?: string;\n /** Used as the form title (mrd-form). */\n title?: string;\n tabPage?: boolean;\n items: ClientLayoutItem[];\n}\n\n// ─── ViewMetadata (from DashboardMetadata.views) ─────────────────────────────\n\nexport interface ViewFilter {\n name: string;\n value?: string | null;\n operator?: 'EQUALS' | 'FROM' | 'TO' | 'STARTS_WITH' | 'NOT_EMPTY' | 'EMPTY' | null;\n}\n\nexport interface ClientViewMetadata {\n name: string | null;\n defaultView: boolean;\n defaultSort?: string | null;\n /** Column definitions — each item is a FIELD or RELATION item. */\n values: ClientLayoutItem[];\n /** Static query-param filters baked into the view definition. */\n filter?: ViewFilter[] | null;\n type?: string;\n referenceType?: string | null;\n filterType?: string | null;\n singularLabel?: string;\n pluralLabel?: string;\n /**\n * Archetype bindings published on this VIEW / RELATED_VIEW item. When it\n * contains `commons.document`, mrd-layout-section offers the document\n * collection view (folder tree) alongside the generic table.\n */\n archetypes?: ClientArchetype[];\n}\n\n// ─── DashboardMetadata ────────────────────────────────────────────────────────\n\nexport interface ClientDashboardMetadata {\n layouts: ClientLayout[];\n /** Top-level archetypes on an object dashboard (the object's own type). Drives the\n * single-document view; passed to the main layout's mrd-layout-section. */\n archetypes?: ClientArchetype[];\n /** Legacy: view metadata map keyed by generated name. Absent in new flat format. */\n views?: Record<string, ClientViewMetadata>;\n layoutType: ClientLayoutType;\n _links?: Record<string, { href: string }>;\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-attachments-BufPmMRv.js","sources":["src/utils/document-attachments.ts"],"sourcesContent":["import { ClientArchetype, DocumentAttachment } from '../types/client-layout';\n\n/**\n * Extract an archetype's file slot from a data record as a `DocumentAttachment[]` —\n * empty when the slot is unmapped or has no value. `slot` defaults to `'file'` (the\n * commons.document single-file slot); pass `'attachments'` for the multi-file slots\n * on commons.email / commons.invoice. A single-object slot value yields a one-entry\n * array, an array-valued slot yields one entry per item.\n * Shared by mrd-document-view / mrd-invoice-view / mrd-email-view (on load/data-change)\n * and mrd-document-container (row-click prefetch on mrdNavigate), so all report the\n * exact same shape.\n */\nexport function attachmentsFromRecord(\n archetype: ClientArchetype | null | undefined,\n record: Record<string, unknown> | null | undefined,\n slot: string = 'file',\n): DocumentAttachment[] {\n const field = archetype?.slots?.[slot];\n if (!field) return [];\n const raw = (record as any)?.[field];\n if (!raw) return [];\n const items = Array.isArray(raw) ? raw : [raw];\n return items.filter(Boolean).map(item => ({\n href: item.href,\n fileName: item.fileName ?? String(item),\n mimeType: item.mimeType ?? item.contentType ?? undefined,\n }));\n}\n\n/** Dedup key for the componentDidLoad/@Watch('data') \"emit mrdAttachments only on\n * change\" guard shared by mrd-document-view / mrd-invoice-view / mrd-email-view. */\nexport function attachmentsKey(attachments: DocumentAttachment[]): string {\n return attachments.map(a => a.href).join('|');\n}\n"],"names":[],"mappings":"AAEA;;;;;;;;;AASG;AACG,SAAU,qBAAqB,CACnC,SAA6C,EAC7C,MAAkD,EAClD,OAAe,MAAM,EAAA;;IAErB,MAAM,KAAK,GAAG,CAAA,EAAA,GAAA,SAAS,KAAA,IAAA,IAAT,SAAS,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAT,SAAS,CAAE,KAAK,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAG,IAAI,CAAC;AACtC,IAAA,IAAI,CAAC,KAAK;AAAE,QAAA,OAAO,EAAE;IACrB,MAAM,GAAG,GAAI,MAAc,KAAA,IAAA,IAAd,MAAM,uBAAN,MAAM,CAAW,KAAK,CAAC;AACpC,IAAA,IAAI,CAAC,GAAG;AAAE,QAAA,OAAO,EAAE;AACnB,IAAA,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAC9C,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,IAAG;;AAAC,QAAA,QAAC;YACxC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,QAAQ,EAAE,MAAA,IAAI,CAAC,QAAQ,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAI,MAAM,CAAC,IAAI,CAAC;AACvC,YAAA,QAAQ,EAAE,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,IAAI,CAAC,QAAQ,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAI,IAAI,CAAC,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAI,SAAS;AACzD,SAAA;AAAC,KAAA,CAAC;AACL;AAEA;AACqF;AAC/E,SAAU,cAAc,CAAC,WAAiC,EAAA;AAC9D,IAAA,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC/C;;;;"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-helpers-CNQcI3Hf.js","sources":["src/components/fields/field-helpers.tsx"],"sourcesContent":["import { FunctionalComponent, h } from '@stencil/core';\nimport { t } from '../../utils/i18n';\nimport { validateRequired } from '../../utils/validation';\n\n/**\n * Shared building blocks for the leaf field components.\n * `base` is the BEM block name, e.g. 'mrd-text-field'.\n */\n\nexport const FieldLabel: FunctionalComponent<{ base: string; label: string; required: boolean }> = ({ base, label, required }) =>\n label ? <label class={`${base}__label${required ? ` ${base}__label--required` : ''}`}>{label}</label> : null;\n\nexport const FieldError: FunctionalComponent<{ base: string; error: string }> = ({ base, error }) =>\n error ? <span class={`${base}__error`}>{error}</span> : null;\n\n/** Class string for the form control, with the --error modifier when applicable. */\nexport function controlClass(base: string, hasError: boolean, element: string = 'input'): string {\n return `${base}__${element}${hasError ? ` ${base}__${element}--error` : ''}`;\n}\n\n/** Returns the localised required-error, or '' when the value passes. */\nexport function requiredError(value: unknown, required: boolean, locale: string): string {\n return required && !validateRequired(value) ? t('required', locale) : '';\n}\n"],"names":[],"mappings":";;;;AAIA;;;AAGG;MAEU,UAAU,GAA4E,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAC3H,KAAK,GAAG,aAAO,KAAK,EAAE,CAAA,EAAG,IAAI,CAAA,OAAA,EAAU,QAAQ,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,iBAAA,CAAmB,GAAG,EAAE,CAAA,CAAE,IAAG,KAAK,CAAS,GAAG;AAEnG,MAAM,UAAU,GAAyD,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAC9F,KAAK,GAAG,CAAA,CAAA,MAAA,EAAA,EAAM,KAAK,EAAE,GAAG,IAAI,CAAA,OAAA,CAAS,EAAA,EAAG,KAAK,CAAQ,GAAG;AAE1D;AACM,SAAU,YAAY,CAAC,IAAY,EAAE,QAAiB,EAAE,UAAkB,OAAO,EAAA;AACrF,IAAA,OAAO,GAAG,IAAI,CAAA,EAAA,EAAK,OAAO,CAAA,EAAG,QAAQ,GAAG,IAAI,IAAI,CAAA,EAAA,EAAK,OAAO,CAAA,OAAA,CAAS,GAAG,EAAE,EAAE;AAC9E;AAEA;SACgB,aAAa,CAAC,KAAc,EAAE,QAAiB,EAAE,MAAc,EAAA;IAC7E,OAAO,QAAQ,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,EAAE;AAC1E;;;;"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-upload-common-C9wp47CB.js","sources":["src/components/fields/file-upload-common.ts"],"sourcesContent":["import { t } from '../../utils/i18n';\n\n/**\n * Shared upload behaviour for mrd-file-field and mrd-image-field:\n * file validation, drop-zone class building and drag-drop wiring.\n */\n\n/** A resolved file/image value, matching the shape the API returns for an already-persisted\n * file (mrd-table cell renderer, mrd-document-view, mrd-layout-section all read `.href` /\n * `.fileName` the same way) — also what a freshly-completed upload resolves to (host builds\n * `{ href: uri, fileName: file.name }` client-side). May carry extra metadata (`contentType`,\n * `size`, …) that this library ignores. */\nexport interface UploadedFileRef {\n href: string;\n fileName: string;\n [key: string]: unknown;\n}\n\n/** A single field entry: a pending `File` (upload in progress), a resolved `UploadedFileRef`,\n * or a bare href string (legacy shape — still supported so older hosts keep working unchanged). */\nexport type FileEntry = File | UploadedFileRef | string;\n\n/** True while the entry is still a local `File` awaiting upload resolution. */\nexport function isPending(entry: FileEntry): boolean {\n return entry instanceof File;\n}\n\n/** Display name for an entry: the `File`'s own name, the resolved `fileName`, or — for the\n * legacy bare-href shape — a best-effort basename of the URI. */\nexport function entryLabel(entry: FileEntry): string {\n if (entry instanceof File) return entry.name;\n if (typeof entry !== 'string') return entry.fileName || entry.href;\n const base = entry.split('/').pop() ?? entry;\n try {\n return decodeURIComponent(base);\n } catch {\n return base;\n }\n}\n\n/** Validates a selected/dropped file; returns a localised error message or '' when accepted. */\nexport function validateUploadFile(file: File, maxSize: number, locale: string, requireImage = false): string {\n if (maxSize > 0 && file.size > maxSize) return t('file_too_large', locale);\n if (requireImage && !file.type.startsWith('image/')) return t('invalid_image', locale);\n return '';\n}\n\n/** BEM class string for the drop zone, e.g. base 'mrd-file-field' → 'mrd-file-field__zone …'. */\nexport function uploadZoneClass(base: string, opts: { dragging: boolean; error: boolean; disabled: boolean }): string {\n return [\n `${base}__zone`,\n opts.dragging ? `${base}__zone--dragging` : '',\n opts.error ? `${base}__zone--error` : '',\n opts.disabled ? `${base}__zone--disabled` : '',\n ].filter(Boolean).join(' ');\n}\n\n/** Drag-drop handlers for the drop zone; the component owns the dragging state and file handling. */\nexport function makeDragHandlers(setDragging: (dragging: boolean) => void, onFiles: (files: File[]) => void) {\n return {\n onDragOver: (e: DragEvent) => {\n e.preventDefault();\n setDragging(true);\n },\n onDragLeave: () => setDragging(false),\n onDrop: (e: DragEvent) => {\n e.preventDefault();\n setDragging(false);\n onFiles(Array.from(e.dataTransfer?.files ?? []));\n },\n };\n}\n"],"names":[],"mappings":";;AAsBA;AACM,SAAU,SAAS,CAAC,KAAgB,EAAA;IACxC,OAAO,KAAK,YAAY,IAAI;AAC9B;AAEA;AACkE;AAC5D,SAAU,UAAU,CAAC,KAAgB,EAAA;;IACzC,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,KAAK,CAAC,IAAI;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ;AAAE,QAAA,OAAO,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI;AAClE,IAAA,MAAM,IAAI,GAAG,CAAA,EAAA,GAAA,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAI,KAAK;AAC5C,IAAA,IAAI;AACF,QAAA,OAAO,kBAAkB,CAAC,IAAI,CAAC;;IAC/B,OAAA,EAAA,EAAM;AACN,QAAA,OAAO,IAAI;;AAEf;AAEA;AACM,SAAU,kBAAkB,CAAC,IAAU,EAAE,OAAe,EAAE,MAAc,EAAE,YAAY,GAAG,KAAK,EAAA;IAClG,IAAI,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,OAAO;AAAE,QAAA,OAAO,CAAC,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAC1E,IAAI,YAAY,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AAAE,QAAA,OAAO,CAAC,CAAC,eAAe,EAAE,MAAM,CAAC;AACtF,IAAA,OAAO,EAAE;AACX;AAEA;AACM,SAAU,eAAe,CAAC,IAAY,EAAE,IAA8D,EAAA;IAC1G,OAAO;AACL,QAAA,CAAA,EAAG,IAAI,CAAA,MAAA,CAAQ;QACf,IAAI,CAAC,QAAQ,GAAG,CAAA,EAAG,IAAI,CAAA,gBAAA,CAAkB,GAAG,EAAE;QAC9C,IAAI,CAAC,KAAK,GAAG,CAAA,EAAG,IAAI,CAAA,aAAA,CAAe,GAAG,EAAE;QACxC,IAAI,CAAC,QAAQ,GAAG,CAAA,EAAG,IAAI,CAAA,gBAAA,CAAkB,GAAG,EAAE;KAC/C,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC7B;AAEA;AACM,SAAU,gBAAgB,CAAC,WAAwC,EAAE,OAAgC,EAAA;IACzG,OAAO;AACL,QAAA,UAAU,EAAE,CAAC,CAAY,KAAI;YAC3B,CAAC,CAAC,cAAc,EAAE;YAClB,WAAW,CAAC,IAAI,CAAC;SAClB;AACD,QAAA,WAAW,EAAE,MAAM,WAAW,CAAC,KAAK,CAAC;AACrC,QAAA,MAAM,EAAE,CAAC,CAAY,KAAI;;YACvB,CAAC,CAAC,cAAc,EAAE;YAClB,WAAW,CAAC,KAAK,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAA,CAAA,EAAA,GAAA,CAAC,CAAC,YAAY,0CAAE,KAAK,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAI,EAAE,CAAC,CAAC;SACjD;KACF;AACH;;;;"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-gcecItcD.js","sources":["src/utils/format.ts"],"sourcesContent":["export function formatNumber(value: number, locale: string, options?: Intl.NumberFormatOptions): string {\n if (value === null || value === undefined || isNaN(value)) return '';\n return new Intl.NumberFormat(locale, options).format(value);\n}\n\nexport function formatCurrency(amount: number, currency: string, locale: string): string {\n if (amount === null || amount === undefined || isNaN(amount)) return '';\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(amount);\n}\n\nexport function formatPercentage(value: number, locale: string, decimalPrecision = 2): string {\n if (value === null || value === undefined || isNaN(value)) return '';\n return new Intl.NumberFormat(locale, {\n style: 'percent',\n minimumFractionDigits: decimalPrecision,\n maximumFractionDigits: decimalPrecision,\n }).format(value);\n}\n\nexport function formatDate(value: string | Date, locale: string): string {\n if (!value) return '';\n const date = typeof value === 'string' ? new Date(value) : value;\n if (isNaN(date.getTime())) return '';\n return new Intl.DateTimeFormat(locale, { year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);\n}\n\nexport function formatDateTime(value: string | Date, locale: string): string {\n if (!value) return '';\n const date = typeof value === 'string' ? new Date(value) : value;\n if (isNaN(date.getTime())) return '';\n return new Intl.DateTimeFormat(locale, {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n }).format(date);\n}\n\nexport function formatTime(value: string, locale: string): string {\n if (!value) return '';\n // value is HH:MM or HH:MM:SS\n const [hours, minutes] = value.split(':').map(Number);\n const date = new Date();\n date.setHours(hours, minutes, 0, 0);\n return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);\n}\n\nexport function parseLocalizedNumber(str: string, locale: string): number | null {\n if (!str || !str.trim()) return null;\n // Detect decimal and thousands separators from the locale\n const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);\n const groupSep = parts.find((p: Intl.NumberFormatPart) => p.type === 'group')?.value ?? ',';\n const decimalSep = parts.find((p: Intl.NumberFormatPart) => p.type === 'decimal')?.value ?? '.';\n\n // Remove group separators, replace decimal separator with '.'\n const normalized = str\n .replace(new RegExp(`\\\\${groupSep}`, 'g'), '')\n .replace(new RegExp(`\\\\${decimalSep}`), '.')\n .replace('%', '')\n .trim();\n\n const parsed = parseFloat(normalized);\n return isNaN(parsed) ? null : parsed;\n}\n"],"names":[],"mappings":"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"}