{"version":3,"file":"BqTable-dVsGRzCj.cjs","names":[],"sources":["../src/components/table/BqTable.ts"],"sourcesContent":["/**\r\n * Data table component.\r\n * @element bq-table\r\n * @prop {string}  columns  - JSON array of { key, label, sortable? }\r\n * @prop {string}  rows     - JSON array of row objects\r\n * @prop {string}  caption  - Accessible table caption\r\n * @prop {string}  sort-key\r\n * @prop {string}  sort-dir - asc | desc\r\n * @prop {boolean} striped\r\n * @prop {boolean} bordered\r\n * @prop {boolean} hover\r\n * @prop {boolean} loading\r\n * @fires bq-sort - { key: string, dir: string }\r\n */\r\nimport type { ComponentDefinition } from '@bquery/bquery/component';\r\nimport { component, html } from '@bquery/bquery/component';\r\nimport { escapeHtml } from '@bquery/bquery/security';\r\nimport { t } from '../../i18n/index.js';\r\nimport { getBaseStyles } from '../../utils/styles.js';\r\n\r\ntype ColDef = { key: string; label: string; sortable?: boolean };\r\ntype BqTableProps = {\r\n  columns: string;\r\n  rows: string;\r\n  caption: string;\r\n  'sort-key': string;\r\n  'sort-dir': string;\r\n  striped: boolean;\r\n  bordered: boolean;\r\n  hover: boolean;\r\n  loading: boolean;\r\n};\r\n\r\nconst definition: ComponentDefinition<BqTableProps> = {\r\n  props: {\r\n    columns: { type: String, default: '[]' },\r\n    rows: { type: String, default: '[]' },\r\n    caption: { type: String, default: '' },\r\n    'sort-key': { type: String, default: '' },\r\n    'sort-dir': { type: String, default: 'asc' },\r\n    striped: { type: Boolean, default: false },\r\n    bordered: { type: Boolean, default: false },\r\n    hover: { type: Boolean, default: false },\r\n    loading: { type: Boolean, default: false },\r\n  },\r\n  styles: `\r\n    ${getBaseStyles()}\r\n    *, *::before, *::after { box-sizing: border-box; }\r\n    :host { display: block; overflow-x: auto; }\r\n    table { width: 100%; border-collapse: collapse; font-family: var(--bq-font-family-sans); font-size: var(--bq-font-size-sm,0.875rem); }\r\n    :host([bordered]) table { border: 1px solid var(--bq-border-base,#e2e8f0); }\r\n    th, td { padding: 0.75rem 1rem; text-align: left; border-bottom: 1px solid var(--bq-border-base,#e2e8f0); }\r\n    caption { caption-side: top; text-align: left; font-size: var(--bq-font-size-sm,0.875rem); color: var(--bq-text-muted,#475569); padding: 0.5rem 1rem; font-family: var(--bq-font-family-sans); }\r\n    :host([bordered]) th, :host([bordered]) td { border: 1px solid var(--bq-border-base,#e2e8f0); }\r\n    th { background: var(--bq-bg-subtle,#f8fafc); font-weight: var(--bq-font-weight-semibold,600); color: var(--bq-text-base,#0f172a); white-space: nowrap; }\r\n    td { color: var(--bq-text-muted,#475569); }\r\n    .sortable { cursor: pointer; user-select: none; }\r\n    .sortable:hover { background: var(--bq-bg-emphasis,#e2e8f0); }\r\n    .sort-icon { display: inline-block; margin-left: 0.375rem; opacity: 0.4; }\r\n    .sort-icon[data-active=\"true\"] { opacity: 1; }\r\n    :host([striped]) tbody tr:nth-child(even) td { background: var(--bq-bg-subtle,#f8fafc); }\r\n    :host([hover]) tbody tr:hover td { background: var(--bq-bg-muted,#f1f5f9); }\r\n    .empty-row td { text-align: center; color: var(--bq-text-subtle,#94a3b8); padding: 2rem; }\r\n    .loading-overlay { text-align: center; padding: 2rem; color: var(--bq-text-muted,#475569); }\r\n  `,\r\n  connected() {\r\n    const self = this;\r\n    const sortHandler = (th: HTMLElement) => {\r\n      const key = th.getAttribute('data-sort-key') ?? '';\r\n      const curDir = self.getAttribute('sort-dir') ?? 'asc';\r\n      const curKey = self.getAttribute('sort-key') ?? '';\r\n      const newDir = key === curKey && curDir === 'asc' ? 'desc' : 'asc';\r\n      self.setAttribute('sort-key', key);\r\n      self.setAttribute('sort-dir', newDir);\r\n      self.dispatchEvent(\r\n        new CustomEvent('bq-sort', {\r\n          detail: { key, dir: newDir },\r\n          bubbles: true,\r\n          composed: true,\r\n        })\r\n      );\r\n    };\r\n    const handler = (e: Event) => {\r\n      const th = (e.target as Element).closest(\r\n        'th.sortable'\r\n      ) as HTMLElement | null;\r\n      if (!th) return;\r\n      sortHandler(th);\r\n    };\r\n    const keyHandler = (e: Event) => {\r\n      const ke = e as KeyboardEvent;\r\n      const th = (ke.target as Element).closest(\r\n        'th.sortable'\r\n      ) as HTMLElement | null;\r\n      if (!th) return;\r\n      const isSpaceKeydown = ke.type === 'keydown' && ke.key === ' ';\r\n      const isEnterKeydown =\r\n        ke.type === 'keydown' && ke.key === 'Enter' && !ke.repeat;\r\n      const isSpaceKeyup = ke.type === 'keyup' && ke.key === ' ';\r\n      if (isSpaceKeydown) {\r\n        e.preventDefault();\r\n        return;\r\n      }\r\n      if (!isEnterKeydown && !isSpaceKeyup) return;\r\n      e.preventDefault();\r\n      sortHandler(th);\r\n    };\r\n    (self as unknown as Record<string, unknown>)['_handler'] = handler;\r\n    (self as unknown as Record<string, unknown>)['_keyHandler'] = keyHandler;\r\n    self.shadowRoot?.addEventListener('click', handler);\r\n    self.shadowRoot?.addEventListener('keydown', keyHandler);\r\n    self.shadowRoot?.addEventListener('keyup', keyHandler);\r\n  },\r\n  disconnected() {\r\n    const s = this as unknown as Record<string, unknown>;\r\n    const h = s['_handler'] as EventListener | undefined;\r\n    const kh = s['_keyHandler'] as EventListener | undefined;\r\n    if (h) this.shadowRoot?.removeEventListener('click', h);\r\n    if (kh) this.shadowRoot?.removeEventListener('keydown', kh);\r\n    if (kh) this.shadowRoot?.removeEventListener('keyup', kh);\r\n  },\r\n  render({ props }) {\r\n    let cols: ColDef[] = [];\r\n    let rows: Record<string, unknown>[] = [];\r\n    try {\r\n      cols = JSON.parse(props.columns) as ColDef[];\r\n    } catch {\r\n      cols = [];\r\n    }\r\n    try {\r\n      rows = JSON.parse(props.rows) as Record<string, unknown>[];\r\n    } catch {\r\n      rows = [];\r\n    }\r\n    const sortKey = props['sort-key'];\r\n    const sortDir = props['sort-dir'];\r\n    const theads = cols\r\n      .map((col) => {\r\n        const isSorted = col.key === sortKey;\r\n        const sortIcon = col.sortable\r\n          ? `<span class=\"sort-icon\" data-active=\"${isSorted ? 'true' : 'false'}\" aria-hidden=\"true\">${isSorted && sortDir === 'desc' ? '&#9650;' : '&#9660;'}</span>`\r\n          : '';\r\n        const sortLabel = col.sortable\r\n          ? isSorted\r\n            ? sortDir === 'asc'\r\n              ? t('table.sortDescending')\r\n              : t('table.sortAscending')\r\n            : t('table.sortAscending')\r\n          : '';\r\n        const sortableAttrs = col.sortable\r\n          ? `class=\"sortable\" data-sort-key=\"${escapeHtml(col.key)}\" tabindex=\"0\" aria-sort=\"${isSorted ? (sortDir === 'asc' ? 'ascending' : 'descending') : 'none'}\" title=\"${escapeHtml(sortLabel)}\"`\r\n          : '';\r\n        return `<th part=\"th\" scope=\"col\" role=\"columnheader\" ${sortableAttrs}>${escapeHtml(col.label)}${sortIcon}</th>`;\r\n      })\r\n      .join('');\r\n    const tbodies = props.loading\r\n      ? `<tr><td colspan=\"${cols.length}\" class=\"loading-overlay\">${escapeHtml(t('table.loading'))}</td></tr>`\r\n      : rows.length === 0\r\n        ? `<tr class=\"empty-row\"><td colspan=\"${cols.length}\">${escapeHtml(t('table.noData'))}</td></tr>`\r\n        : rows\r\n            .map(\r\n              (row) =>\r\n                `<tr part=\"row\">${cols.map((col) => `<td part=\"td\">${escapeHtml(String(row[col.key] ?? ''))}</td>`).join('')}</tr>`\r\n            )\r\n            .join('');\r\n    return html`\r\n      <table part=\"table\">\r\n        ${props.caption\r\n          ? `<caption part=\"caption\">${escapeHtml(props.caption)}</caption>`\r\n          : ''}\r\n        <thead part=\"thead\">\r\n          <tr part=\"header-row\">\r\n            ${theads}\r\n          </tr>\r\n        </thead>\r\n        <tbody part=\"tbody\">\r\n          ${tbodies}\r\n        </tbody>\r\n      </table>\r\n    `;\r\n  },\r\n};\r\n\r\ncomponent<BqTableProps>('bq-table', definition);\r\n"],"mappings":"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"}