{"version":3,"file":"table.cjs","names":[],"sources":["../src/content/table/table.ts"],"sourcesContent":["import { bind, define, getHost, html, onMounted, prop, watchEffect } from '@vielzeug/ore';\n\nimport { reducedMotionMixin, tableBaseMixin } from '../../styles';\nimport componentStyles from './table.css?inline';\n\n/* ── Types ───────────────────────────────────────────────────────────────── */\n\n/** Table component properties */\nexport type OreTableProps = {\n  /** Adds a thicker outer border */\n  bordered?: boolean;\n  /** Visible caption text — also used as the accessible table label via `aria-label` */\n  caption?: string;\n  /** Cell density: `'compact'` | `'cozy'` (default) | `'comfortable'` */\n  density?: 'compact' | 'cozy' | 'comfortable';\n  /** Expands the table to 100% of its container width */\n  fullwidth?: boolean;\n  /** Applies a busy/disabled state with reduced opacity */\n  loading?: boolean;\n  /** Enables sticky column headers with a vertical scroll container */\n  sticky?: boolean;\n  /** Alternating row stripe backgrounds */\n  striped?: boolean;\n};\n\n/* ── Child element markers ───────────────────────────────────────────────── */\n// ore-tr, ore-th, ore-td are lightweight light-DOM markers.\n// ore-table reads them and constructs a fully-native shadow <table> so that\n// browser features that require real table elements (colspan/rowspan,\n// position:sticky on <thead>, table layout algorithm) all work correctly.\n// Attributes on ore-th/ore-td are mirrored to the generated native cells.\n\n/**\n * Light-DOM row marker consumed by `<ore-table>`.\n *\n * @element ore-tr\n * @attr {boolean} head - Places the row in the generated `<thead>` section\n * @attr {boolean} foot - Places the row in the generated `<tfoot>` section\n *\n * @example\n * ```html\n * <ore-table>\n *   <ore-tr head><ore-th>Name</ore-th><ore-th>Role</ore-th></ore-tr>\n *   <ore-tr><ore-td>Alice</ore-td><ore-td>Admin</ore-td></ore-tr>\n * </ore-table>\n * ```\n */\nif (!customElements.get('ore-tr')) customElements.define('ore-tr', class extends HTMLElement {});\n\n/**\n * Light-DOM header cell marker consumed by `<ore-table>`.\n *\n * @element ore-th\n * @attr {number} colspan  - Mirrors to native `<th colspan>`\n * @attr {number} rowspan  - Mirrors to native `<th rowspan>`\n * @attr {string} scope    - Mirrors to native `<th scope>`: 'col' | 'row' | 'colgroup' | 'rowgroup'\n * @attr {string} headers  - Mirrors to native `<th headers>`\n *\n * @example\n * ```html\n * <ore-tr head>\n *   <ore-th scope=\"col\">Name</ore-th>\n *   <ore-th scope=\"col\" colspan=\"2\">Address</ore-th>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-th')) customElements.define('ore-th', class extends HTMLElement {});\n\n/**\n * Light-DOM data cell marker consumed by `<ore-table>`.\n *\n * @element ore-td\n * @attr {number} colspan  - Mirrors to native `<td colspan>`\n * @attr {number} rowspan  - Mirrors to native `<td rowspan>`\n * @attr {string} headers  - Mirrors to native `<td headers>`\n *\n * @example\n * ```html\n * <ore-tr>\n *   <ore-td>Alice</ore-td>\n *   <ore-td colspan=\"2\">123 Main St, Springfield</ore-td>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-td')) customElements.define('ore-td', class extends HTMLElement {});\n\n/* ── Proxy/mirror helpers ────────────────────────────────────────────────── */\n\n// Attributes forwarded from ore-th/ore-td to the generated native cell.\n// scope is intentionally excluded — it requires fallback logic and is handled separately.\nconst CELL_ATTRS = ['colspan', 'rowspan', 'headers', 'abbr'];\n\n/**\n * Sync text content and tracked attributes from a light-DOM marker to its\n * native mirror. `fallbackScope` is applied when the source element carries no\n * explicit `scope` attribute, ensuring the auto-inferred value is always\n * present and is restored if an explicit override is later removed.\n */\nfunction syncCell(source: Element, native: HTMLTableCellElement, fallbackScope?: string): void {\n  if (source.childElementCount > 0) {\n    // Source has element children — deep-clone them into the native cell so\n    // components like ore-skeleton render correctly inside the shadow table.\n    // Guard: skip re-clone if the serialised content is identical to avoid\n    // redundant DOM work on every MutationObserver tick (e.g. 250+ cells\n    // of skeleton loaders all cloning on each attribute change).\n    const snapshot = source.innerHTML;\n\n    if (native.getAttribute('data-src-html') === snapshot) return;\n\n    native.setAttribute('data-src-html', snapshot);\n    native.textContent = '';\n\n    for (const child of source.childNodes) {\n      native.appendChild(child.cloneNode(true));\n    }\n  } else {\n    const text = source.textContent ?? '';\n\n    if (native.textContent !== text) native.textContent = text;\n  }\n\n  for (const attr of CELL_ATTRS) {\n    const val = source.getAttribute(attr);\n\n    if (val !== null) native.setAttribute(attr, val);\n    else native.removeAttribute(attr);\n  }\n\n  // scope: explicit attribute wins; otherwise restore the inferred fallback.\n  const explicitScope = source.getAttribute('scope');\n\n  if (explicitScope !== null) native.setAttribute('scope', explicitScope);\n  else if (fallbackScope) native.scope = fallbackScope;\n  else native.removeAttribute('scope');\n}\n\n/** Entry stored in the cell map: native mirror element + its inferred scope fallback. */\ntype CellEntry = { inferredScope: string | undefined; native: HTMLTableCellElement };\n\n/**\n * (Re)build the entire native shadow table from the current light-DOM markers.\n * Returns a WeakMap of source marker → CellEntry for targeted sync by the\n * content observer. Storing `inferredScope` per cell ensures that removing an\n * explicit `scope` attribute reverts to the auto-inferred value rather than\n * dropping it entirely.\n */\nfunction buildTable(\n  host: HTMLElement,\n  thead: HTMLTableSectionElement,\n  tbody: HTMLTableSectionElement,\n  tfoot: HTMLTableSectionElement,\n): WeakMap<Element, CellEntry> {\n  const cellMap = new WeakMap<Element, CellEntry>();\n\n  thead.textContent = '';\n  tbody.textContent = '';\n  tfoot.textContent = '';\n\n  for (const child of host.children) {\n    if (child.localName !== 'ore-tr') continue;\n\n    const section = child.hasAttribute('head') ? thead : child.hasAttribute('foot') ? tfoot : tbody;\n    const tr = document.createElement('tr');\n\n    for (const cell of child.children) {\n      if (cell.localName !== 'ore-th' && cell.localName !== 'ore-td') continue;\n\n      const isHeader = cell.localName === 'ore-th';\n      const native = document.createElement(isHeader ? 'th' : 'td');\n      // Auto-infer scope for <th> elements; undefined for <td>.\n      const inferredScope = isHeader ? (section === thead ? 'col' : 'row') : undefined;\n\n      native.setAttribute('part', section === tbody ? 'cell' : 'header-cell');\n      native.removeAttribute('data-src-html');\n      syncCell(cell, native, inferredScope);\n      cellMap.set(cell, { inferredScope, native });\n      tr.appendChild(native);\n    }\n\n    section.appendChild(tr);\n  }\n\n  return cellMap;\n}\n\n/**\n * Data table component.\n *\n * Reads light-DOM `<ore-tr>`/`<ore-th>`/`<ore-td>` markers and projects them\n * into a fully-native shadow `<table>`. Cell attributes (`colspan`, `rowspan`,\n * `scope`, etc.) are mirrored. Changes are observed and synced incrementally.\n *\n * Native table features — sticky headers, colspan/rowspan, the table layout\n * algorithm — all work because the shadow tree contains real table elements.\n *\n * @element ore-table\n *\n * @attr {boolean} bordered  - Thicker outer border\n * @attr {string}  caption   - Caption text shown above the table\n * @attr {boolean} fullwidth - Expands to 100% container width\n * @attr {boolean} loading   - Busy state: reduced opacity, no pointer events\n * @attr {string}  density   - Cell density: 'compact' | 'cozy' | 'comfortable' (default: 'cozy')\n * @attr {boolean} sticky    - Sticky `<thead>` with scroll container\n * @attr {boolean} striped   - Alternating row backgrounds\n *\n * @part scroll       - Scroll container that hosts the generated native table\n * @part table        - Generated native `<table>` element\n * @part head         - Generated native `<thead>` section\n * @part body         - Generated native `<tbody>` section\n * @part foot         - Generated native `<tfoot>` section\n * @part cell         - Every native `<td>` in `<tbody>` rows\n * @part header-cell  - Every native `<th>` / `<td>` in `<thead>` and `<tfoot>` rows\n *\n * @cssprop --table-bg                - Table background color\n * @cssprop --table-border-color      - Cell separator and outer border color\n * @cssprop --table-radius            - Corner radius of the table container\n * @cssprop --table-shadow            - Box shadow of the table container\n * @cssprop --table-header-bg         - Background of header and footer rows\n * @cssprop --table-accent            - Accent color for interactive states\n * @cssprop --table-row-hover-bg      - Row hover background\n * @cssprop --table-stripe-bg         - Even-row stripe background\n * @cssprop --table-cell-padding-x    - Cell horizontal padding\n * @cssprop --table-cell-padding-y    - Cell vertical padding\n * @cssprop --table-font-size         - Base font size for cells\n * @cssprop --table-sticky-max-height - Max height of the sticky scroll container\n * @cssprop --table-sticky-header-bg  - Background of sticky header cells\n * @cssprop --table-sticky-blur       - Backdrop blur applied to sticky headers\n *\n * @example\n * ```html\n * <ore-table caption=\"Top repositories\" striped bordered sticky>\n *   <ore-tr head>\n *     <ore-th>Repository</ore-th>\n *     <ore-th>Stars</ore-th>\n *   </ore-tr>\n *   <ore-tr>\n *     <ore-td>vielzeug/refine</ore-td>\n *     <ore-td>1 200</ore-td>\n *   </ore-tr>\n * </ore-table>\n * ```\n */\nexport const TABLE_TAG = 'ore-table' as const;\ndefine<OreTableProps>(TABLE_TAG, {\n  props: {\n    bordered: prop.bool(false),\n    caption: prop.string(),\n    density: prop.string<'compact' | 'cozy' | 'comfortable'>(),\n    fullwidth: prop.bool(false),\n    loading: prop.bool(false),\n    sticky: prop.bool(false),\n    striped: prop.bool(false),\n  },\n\n  setup(props) {\n    const el = getHost();\n    const watch = watchEffect;\n\n    bind({\n      attr: {\n        'aria-busy': props.loading,\n        'aria-label': props.caption,\n      },\n    });\n\n    // Build the native shadow table via DOM APIs (not innerHTML) to avoid\n    // HTML-parser foster-parenting, which ejects table section elements from\n    // their intended positions in the tree.\n    onMounted(() => {\n      const scrollContainer = el.shadowRoot?.querySelector('.scroll-container')!;\n\n      const table = document.createElement('table');\n      const captionEl = document.createElement('caption');\n      const thead = document.createElement('thead');\n      const tbody = document.createElement('tbody');\n      const tfoot = document.createElement('tfoot');\n\n      scrollContainer.setAttribute('part', 'scroll');\n      table.setAttribute('part', 'table');\n      thead.setAttribute('part', 'head');\n      tbody.setAttribute('part', 'body');\n      tfoot.setAttribute('part', 'foot');\n      table.append(captionEl, thead, tbody, tfoot);\n      scrollContainer.appendChild(table);\n\n      // Reactively sync caption text and visibility from prop.\n      watch(() => {\n        const text = props.caption.value ?? '';\n\n        captionEl.textContent = text;\n        captionEl.hidden = text === '';\n      });\n\n      // Initial full build.\n      let cellMap = buildTable(el, thead, tbody, tfoot);\n\n      // Content observer: syncs text/attribute changes inside ore-th/ore-td.\n      // Remains connected throughout the component lifetime — no\n      // disconnect/reconnect during structural rebuilds. Records that arrive\n      // for cells no longer in cellMap (after a rebuild) are silently ignored\n      // by the `if (entry)` guard, so there is no correctness risk.\n      const contentObserver = new MutationObserver((records) => {\n        for (const rec of records) {\n          const sourceCell = (rec.target instanceof Element ? rec.target : rec.target.parentElement)?.closest(\n            'ore-th, ore-td',\n          );\n\n          if (sourceCell) {\n            const entry = cellMap.get(sourceCell);\n\n            if (entry) syncCell(sourceCell, entry.native, entry.inferredScope);\n          }\n        }\n      });\n\n      contentObserver.observe(el, {\n        // Include 'scope' in attributeFilter so explicit scope changes are picked\n        // up and the fallback-restore logic in syncCell runs correctly.\n        attributeFilter: [...CELL_ATTRS, 'scope'],\n        attributes: true,\n        characterData: true,\n        childList: true,\n        subtree: true,\n      });\n\n      // Structure observer: triggers a full rebuild when ore-tr elements are\n      // added, removed, or reordered. Scoped to direct children only so it\n      // never fires for cell-level mutations.\n      const structureObserver = new MutationObserver(() => {\n        cellMap = buildTable(el, thead, tbody, tfoot);\n      });\n\n      structureObserver.observe(el, { childList: true });\n\n      return () => {\n        structureObserver.disconnect();\n        contentObserver.disconnect();\n      };\n    });\n\n    return html`\n      <div class=\"scroll-container\"></div>\n    `;\n  },\n\n  styles: [reducedMotionMixin, tableBaseMixin('table'), componentStyles],\n});\n"],"mappings":"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"}