@star-ng/ui 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"star-ng-ui-data-display.mjs","names":[],"sources":["../../../projects/star-ng/data-display/data-display.ts","../../../projects/star-ng/data-display/org-chart.ts"],"sourcesContent":["import { _IdGenerator } from '@angular/cdk/a11y';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n Directive,\n inject,\n input,\n model,\n signal,\n TemplateRef,\n} from '@angular/core';\nimport {\n optionText,\n readOption,\n STAR_UI_TEXT,\n starInlineKey,\n StarOptionKey,\n} from '@star-ng/ui/core';\nimport { StarPaginator } from '@star-ng/ui/paginator';\nimport { StarTreeNode } from '@star-ng/ui/tree';\n\n// ---------------------------------------------------------------- Tree table\n\nexport interface StarTreeTableColumn {\n readonly field: string;\n readonly header: string;\n readonly width?: string;\n readonly align?: 'start' | 'center' | 'end';\n}\n\ninterface TreeRow {\n readonly node: StarTreeNode<Record<string, unknown>>;\n readonly level: number;\n readonly setSize: number;\n readonly position: number;\n}\n\n/**\n * Tree table (PrimeNG `p-treetable`): hierarchical rows with expand / collapse in a table,\n * `role=\"treegrid\"`, Right / Left on a row expand / collapse, Up / Down move between rows.\n * Node `data` holds the column values; the first column shows the tree toggle.\n *\n * `<star-tree-table [nodes]=\"budget\" [columns]=\"cols\" [(expanded)]=\"open\" ariaLabel=\"Budget\" />`\n */\n@Component({\n selector: 'star-tree-table',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-table star-tree-table' },\n template: `\n <div class=\"star-table__scroll\">\n <table role=\"treegrid\" [attr.aria-label]=\"ariaLabel()\">\n <thead>\n <tr>\n @for (column of columns(); track column.field) {\n <th\n scope=\"col\"\n [style.width]=\"column.width\"\n [class]=\"'star-table__th star-table__cell--' + (column.align ?? 'start')\"\n >\n {{ column.header }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.node.key) {\n <tr\n class=\"star-table__row\"\n [attr.aria-level]=\"row.level\"\n [attr.aria-setsize]=\"row.setSize\"\n [attr.aria-posinset]=\"row.position\"\n [attr.aria-expanded]=\"row.node.children?.length ? isOpen(row.node.key) : null\"\n [attr.tabindex]=\"focusKey() === row.node.key ? 0 : -1\"\n [attr.data-key]=\"row.node.key\"\n (keydown)=\"onKeydown($event, row)\"\n (focus)=\"focusKey.set(row.node.key)\"\n >\n @for (column of columns(); track column.field; let first = $first) {\n <td [class]=\"'star-table__cell--' + (column.align ?? 'start')\">\n @if (first) {\n <span class=\"star-tree-table__first\" [style.--star-tree-level]=\"row.level - 1\">\n @if (row.node.children?.length) {\n <button\n type=\"button\"\n class=\"star-tree__toggle star-tree-table__toggle\"\n tabindex=\"-1\"\n [attr.aria-label]=\"\n isOpen(row.node.key)\n ? text.collapseItem(row.node.label)\n : text.expandItem(row.node.label)\n \"\n (click)=\"toggle(row.node.key)\"\n >\n <i class=\"ph-bold ph-caret-right\" aria-hidden=\"true\"></i>\n </button>\n } @else {\n <span class=\"star-tree__toggle star-tree__toggle--leaf\"></span>\n }\n {{ row.node.data?.[column.field] ?? row.node.label }}\n </span>\n } @else {\n {{ row.node.data?.[column.field] }}\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n `,\n})\nexport class StarTreeTable {\n protected readonly text = inject(STAR_UI_TEXT);\n readonly nodes = input<readonly StarTreeNode<Record<string, unknown>>[]>([]);\n readonly columns = input.required<readonly StarTreeTableColumn[]>();\n readonly expanded = model<readonly string[]>([]);\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly rows = computed<TreeRow[]>(() => {\n const rows: TreeRow[] = [];\n const open = new Set(this.expanded());\n const walk = (nodes: readonly StarTreeNode<Record<string, unknown>>[], level: number) =>\n nodes.forEach((node, i) => {\n rows.push({ node, level, setSize: nodes.length, position: i + 1 });\n if (node.children?.length && open.has(node.key)) {\n walk(node.children as readonly StarTreeNode<Record<string, unknown>>[], level + 1);\n }\n });\n walk(this.nodes(), 1);\n return rows;\n });\n protected readonly focusKey = signal<string | null>(null);\n\n protected isOpen(key: string): boolean {\n return this.expanded().includes(key);\n }\n\n toggle(key: string, open = !this.isOpen(key)): void {\n this.expanded.update((keys) => (open ? [...keys, key] : keys.filter((k) => k !== key)));\n }\n\n protected onKeydown(event: KeyboardEvent, row: TreeRow): void {\n const rows = this.rows();\n const index = rows.indexOf(row);\n const focus = (target: TreeRow | undefined) => {\n if (!target) return;\n event.preventDefault();\n this.focusKey.set(target.node.key);\n const tr = (event.currentTarget as HTMLElement)\n .closest('tbody')\n ?.querySelector<HTMLElement>(`[data-key=\"${CSS.escape(target.node.key)}\"]`);\n tr?.focus();\n };\n // Arrow right opens a branch and Arrow left closes it; the two swap in right-to-left.\n const key = starInlineKey(event);\n if (key === 'ArrowDown') focus(rows[index + 1]);\n else if (key === 'ArrowUp') focus(rows[index - 1]);\n else if (key === 'ArrowRight' && row.node.children?.length) {\n event.preventDefault();\n this.toggle(row.node.key, true);\n } else if (key === 'ArrowLeft') {\n event.preventDefault();\n if (row.node.children?.length && this.isOpen(row.node.key)) this.toggle(row.node.key, false);\n else focus([...rows.slice(0, index)].reverse().find((r) => r.level < row.level));\n }\n }\n}\n\n// ---------------------------------------------------------------- Data view\n\n/** Item template: `<ng-template starDataViewItem let-item let-layout=\"layout\">`. */\n@Directive({ selector: 'ng-template[starDataViewItem]' })\nexport class StarDataViewItem<T = unknown> {\n readonly starDataViewItemOf = input<readonly T[] | null>(null);\n readonly template =\n inject<TemplateRef<{ $implicit: T; layout: 'list' | 'grid'; index: number }>>(TemplateRef);\n static ngTemplateContextGuard<T>(\n _dir: StarDataViewItem<T>,\n _ctx: unknown,\n ): _ctx is { $implicit: T; layout: 'list' | 'grid'; index: number } {\n return true;\n }\n}\n\n/**\n * Data view (PrimeNG `p-dataview`): items in a list or a responsive grid, layout switch,\n * client pagination and an empty state. It does not sort: sort the items before you pass them in.\n * You design each item with a template.\n *\n * ```html\n * <star-data-view [items]=\"products\" [(layout)]=\"layout\" paginator [rows]=\"6\">\n * <ng-template starDataViewItem let-p let-layout=\"layout\">…</ng-template>\n * </star-data-view>\n * ```\n */\n@Component({\n selector: 'star-data-view',\n imports: [NgTemplateOutlet, StarPaginator],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-data-view' },\n template: `\n <div class=\"star-data-view__header\">\n <ng-content select=\"[starDataViewHeader]\" />\n <div\n class=\"star-segmented star-segmented--sm\"\n role=\"radiogroup\"\n [attr.aria-label]=\"text.layout\"\n >\n @for (option of layouts; track option.id) {\n <button\n type=\"button\"\n role=\"radio\"\n class=\"star-segmented__item\"\n [class.star-segmented__item--on]=\"layout() === option.id\"\n [attr.aria-checked]=\"layout() === option.id\"\n [attr.aria-label]=\"option.label\"\n (click)=\"layout.set(option.id)\"\n >\n <i [class]=\"option.icon\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n </div>\n <ul class=\"star-data-view__items\" [class.star-data-view__items--grid]=\"layout() === 'grid'\">\n @for (item of pageItems(); track $index; let i = $index) {\n <li class=\"star-data-view__item\">\n @if (itemTemplate(); as custom) {\n <ng-container\n *ngTemplateOutlet=\"\n custom.template;\n context: { $implicit: item, layout: layout(), index: i }\n \"\n />\n }\n </li>\n } @empty {\n <li class=\"star-table__empty\">\n <i class=\"ph-bold ph-tray\" aria-hidden=\"true\"></i>\n {{ emptyMessage() ?? text.noData }}\n </li>\n }\n </ul>\n @if (paginator() && items().length > rows()) {\n <star-paginator\n [totalRecords]=\"items().length\"\n [(first)]=\"first\"\n [(rows)]=\"rows\"\n [rowsPerPageOptions]=\"[]\"\n />\n }\n `,\n})\nexport class StarDataView<T = unknown> {\n protected readonly text = inject(STAR_UI_TEXT);\n protected readonly layouts = [\n { id: 'list' as const, label: this.text.layoutList, icon: 'ph-bold ph-list' },\n { id: 'grid' as const, label: this.text.layoutGrid, icon: 'ph-bold ph-squares-four' },\n ];\n readonly items = input<readonly T[]>([]);\n readonly layout = model<'list' | 'grid'>('list');\n readonly paginator = input(false, { transform: booleanAttribute });\n readonly rows = model(6);\n readonly first = model(0);\n readonly emptyMessage = input<string | null>(null);\n protected readonly itemTemplate = contentChild(StarDataViewItem);\n\n protected readonly pageItems = computed(() =>\n this.paginator() ? this.items().slice(this.first(), this.first() + this.rows()) : this.items(),\n );\n}\n\n// ---------------------------------------------------------------- Order list and pick list\n\n/**\n * Order list (PrimeNG `p-orderlist`): reorder items with buttons or Alt + Arrow keys; the moved\n * item keeps focus and a live region announces its new position.\n * `<star-order-list [(value)]=\"priorities\" optionLabel=\"name\" ariaLabel=\"Queue order\" />`\n */\n@Component({\n selector: 'star-order-list',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-order-list' },\n template: `\n <div class=\"star-order-list__buttons\" role=\"group\" [attr.aria-label]=\"text.moveSelectedItem\">\n @for (action of actions; track action.id) {\n <button\n type=\"button\"\n class=\"star-select__icon-btn star-order-list__btn\"\n [attr.aria-label]=\"action.label\"\n [disabled]=\"selected() < 0 || !canMove(action.id)\"\n (click)=\"move(action.id)\"\n >\n <i [class]=\"action.icon\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <ul\n class=\"star-listbox star-order-list__list\"\n role=\"listbox\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"hintId\"\n >\n @for (item of value(); track $index; let i = $index) {\n <li\n role=\"option\"\n class=\"star-listbox__option\"\n tabindex=\"0\"\n [attr.aria-selected]=\"selected() === i\"\n [class.star-listbox__option--selected]=\"selected() === i\"\n (click)=\"selected.set(i)\"\n (focus)=\"selected.set(i)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n <i class=\"ph-bold ph-dots-six-vertical star-order-list__grip\" aria-hidden=\"true\"></i>\n {{ labelOf(item) }}\n </li>\n }\n </ul>\n <p class=\"star-sr-only\" [id]=\"hintId\">{{ text.orderListHint }}</p>\n <p class=\"star-sr-only\" aria-live=\"polite\">{{ announcement() }}</p>\n `,\n})\nexport class StarOrderList<T = unknown> {\n protected readonly text = inject(STAR_UI_TEXT);\n protected readonly hintId = inject(_IdGenerator).getId('star-order-hint-');\n readonly value = model<readonly T[]>([]);\n readonly optionLabel = input<StarOptionKey<T> | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly selected = signal(-1);\n protected readonly announcement = signal('');\n protected readonly actions = [\n { id: 'top' as const, label: this.text.moveTop, icon: 'ph-bold ph-caret-double-up' },\n { id: 'up' as const, label: this.text.moveUp, icon: 'ph-bold ph-caret-up' },\n { id: 'down' as const, label: this.text.moveDown, icon: 'ph-bold ph-caret-down' },\n { id: 'bottom' as const, label: this.text.moveBottom, icon: 'ph-bold ph-caret-double-down' },\n ];\n\n protected labelOf(item: T): string {\n return optionText(item, this.optionLabel());\n }\n\n protected canMove(direction: 'top' | 'up' | 'down' | 'bottom'): boolean {\n const i = this.selected();\n return direction === 'top' || direction === 'up' ? i > 0 : i < this.value().length - 1;\n }\n\n move(direction: 'top' | 'up' | 'down' | 'bottom'): void {\n const from = this.selected();\n if (from < 0 || !this.canMove(direction)) return;\n const last = this.value().length - 1;\n const to = { top: 0, up: from - 1, down: from + 1, bottom: last }[direction];\n const items = [...this.value()];\n const [item] = items.splice(from, 1);\n items.splice(to, 0, item);\n this.value.set(items);\n this.selected.set(to);\n this.announcement.set(this.text.itemPosition(this.labelOf(item), to + 1, items.length));\n }\n\n protected onKeydown(event: KeyboardEvent, index: number): void {\n const list = (event.currentTarget as HTMLElement).parentElement!;\n const focusAt = (i: number) =>\n queueMicrotask(() => (list.children[i] as HTMLElement | undefined)?.focus());\n if (event.altKey && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) {\n event.preventDefault();\n this.selected.set(index);\n this.move(event.key === 'ArrowUp' ? 'up' : 'down');\n focusAt(this.selected());\n } else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {\n event.preventDefault();\n focusAt(\n Math.min(Math.max(index + (event.key === 'ArrowUp' ? -1 : 1), 0), this.value().length - 1),\n );\n }\n }\n}\n\n/**\n * Pick list (PrimeNG `p-picklist`): move items between a source and a target list.\n * Double-click or Enter moves one item; buttons move the selection or everything.\n * `<star-pick-list [(source)]=\"available\" [(target)]=\"assigned\" optionLabel=\"name\" sourceHeader=\"Available\" targetHeader=\"Assigned\" />`\n */\n@Component({\n selector: 'star-pick-list',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-pick-list' },\n template: `\n @for (side of sides; track side) {\n @let items = side === 'source' ? source() : target();\n <section class=\"star-pick-list__side\" [attr.aria-labelledby]=\"ids[side]\">\n <h3 class=\"star-pick-list__header\" [id]=\"ids[side]\">\n {{\n side === 'source'\n ? (sourceHeader() ?? text.pickListSource)\n : (targetHeader() ?? text.pickListTarget)\n }}\n <span class=\"star-badge star-badge--secondary star-badge--sm\">{{ items.length }}</span>\n </h3>\n <div class=\"star-pick-list__box\">\n <ul\n class=\"star-listbox star-pick-list__list\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n [attr.aria-labelledby]=\"ids[side]\"\n >\n @for (item of items; track $index; let i = $index) {\n <li\n role=\"option\"\n class=\"star-listbox__option\"\n tabindex=\"0\"\n [attr.aria-selected]=\"isPicked(side, item)\"\n [class.star-listbox__option--selected]=\"isPicked(side, item)\"\n (click)=\"pick(side, item)\"\n (dblclick)=\"transfer(side, [item])\"\n (keydown.enter)=\"transfer(side, [item])\"\n (keydown.space)=\"$event.preventDefault(); pick(side, item)\"\n >\n {{ labelOf(item) }}\n </li>\n }\n </ul>\n <!-- Outside the listbox: a listbox may contain options and groups only. -->\n @if (!items.length) {\n <div class=\"star-listbox__empty star-pick-list__empty\" role=\"presentation\">\n {{ text.emptyMessage }}\n </div>\n }\n </div>\n </section>\n @if (side === 'source') {\n <div class=\"star-pick-list__buttons\" role=\"group\" [attr.aria-label]=\"text.transfer\">\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n [attr.aria-label]=\"text.moveSelectedToTarget\"\n [disabled]=\"!picked('source').length\"\n (click)=\"transfer('source', picked('source'))\"\n >\n <i class=\"ph-bold ph-caret-right star-icon-mirror\" aria-hidden=\"true\"></i>\n </button>\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n [attr.aria-label]=\"text.moveAllToTarget\"\n [disabled]=\"!source().length\"\n (click)=\"transfer('source', source())\"\n >\n <i class=\"ph-bold ph-caret-double-right star-icon-mirror\" aria-hidden=\"true\"></i>\n </button>\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n [attr.aria-label]=\"text.moveSelectedToSource\"\n [disabled]=\"!picked('target').length\"\n (click)=\"transfer('target', picked('target'))\"\n >\n <i class=\"ph-bold ph-caret-left star-icon-mirror\" aria-hidden=\"true\"></i>\n </button>\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n [attr.aria-label]=\"text.moveAllToSource\"\n [disabled]=\"!target().length\"\n (click)=\"transfer('target', target())\"\n >\n <i class=\"ph-bold ph-caret-double-left star-icon-mirror\" aria-hidden=\"true\"></i>\n </button>\n </div>\n }\n }\n `,\n})\nexport class StarPickList<T = unknown> {\n protected readonly text = inject(STAR_UI_TEXT);\n private readonly idGen = inject(_IdGenerator);\n protected readonly ids = {\n source: this.idGen.getId('star-pick-src-'),\n target: this.idGen.getId('star-pick-tgt-'),\n };\n protected readonly sides = ['source', 'target'] as const;\n\n readonly source = model<readonly T[]>([]);\n readonly target = model<readonly T[]>([]);\n readonly optionLabel = input<StarOptionKey<T> | null>(null);\n readonly sourceHeader = input<string | null>(null);\n readonly targetHeader = input<string | null>(null);\n\n private readonly selection = signal<{ source: readonly T[]; target: readonly T[] }>({\n source: [],\n target: [],\n });\n\n protected labelOf(item: T): string {\n return optionText(item, this.optionLabel());\n }\n protected picked(side: 'source' | 'target'): readonly T[] {\n return this.selection()[side];\n }\n protected isPicked(side: 'source' | 'target', item: T): boolean {\n return this.selection()[side].includes(item);\n }\n protected pick(side: 'source' | 'target', item: T): void {\n this.selection.update((sel) => ({\n ...sel,\n [side]: sel[side].includes(item) ? sel[side].filter((i) => i !== item) : [...sel[side], item],\n }));\n }\n\n transfer(from: 'source' | 'target', items: readonly T[]): void {\n if (!items.length) return;\n const moving = new Set(items);\n const [fromModel, toModel] =\n from === 'source' ? [this.source, this.target] : [this.target, this.source];\n fromModel.update((list) => list.filter((item) => !moving.has(item)));\n toModel.update((list) => [...list, ...items]);\n this.selection.update((sel) => ({ ...sel, [from]: [] }));\n }\n\n /** Reads a value with an optional key (exposed for custom templates). */\n read(item: T, key: StarOptionKey<T>): unknown {\n return readOption(item, key);\n }\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n contentChild,\n Directive,\n inject,\n input,\n model,\n output,\n TemplateRef,\n} from '@angular/core';\nimport { STAR_UI_TEXT } from '@star-ng/ui/core';\n\nexport interface StarOrgNode<T = unknown> {\n /** Unique id of the node in the chart. */\n readonly key: string;\n readonly label: string;\n /** Second line, for example a role. */\n readonly subtitle?: string;\n readonly data?: T;\n readonly children?: readonly StarOrgNode<T>[];\n}\n\nexport interface StarOrgNodeContext<T> {\n readonly $implicit: StarOrgNode<T>;\n readonly level: number;\n}\n\n/** Custom node content: `<ng-template starOrgNode let-node>…</ng-template>`. */\n@Directive({ selector: 'ng-template[starOrgNode]' })\nexport class StarOrgNodeTemplate<T = unknown> {\n readonly template = inject<TemplateRef<StarOrgNodeContext<T>>>(TemplateRef);\n\n static ngTemplateContextGuard<T>(\n _dir: StarOrgNodeTemplate<T>,\n _ctx: unknown,\n ): _ctx is StarOrgNodeContext<T> {\n return true;\n }\n}\n\n/**\n * Organization chart (PrimeNG `p-organizationchart`): a hierarchy drawn top-down with\n * connector lines. The markup is a nested list, so assistive technology reads the levels.\n * A node with children has a button that hides or shows its branch.\n *\n * `<star-org-chart ariaLabel=\"Safety team\" [value]=\"team\" [(collapsedKeys)]=\"closed\" selectable />`\n */\n@Component({\n selector: 'star-org-chart',\n imports: [NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-org' },\n template: `\n <div class=\"star-org__scroll\">\n <ul class=\"star-org__level star-org__level--root\" [attr.aria-label]=\"ariaLabel()\">\n <ng-container *ngTemplateOutlet=\"branch; context: { $implicit: value(), level: 0 }\" />\n </ul>\n </div>\n\n <ng-template #branch let-node let-level=\"level\">\n <li class=\"star-org__branch\">\n <div\n class=\"star-org__node\"\n [class.star-org__node--selected]=\"selectedKey() === node.key\"\n [class.star-org__node--parent]=\"!!node.children?.length && !isCollapsed(node)\"\n >\n @if (selectable()) {\n <button\n type=\"button\"\n class=\"star-org__card star-org__card--button\"\n [attr.aria-pressed]=\"selectedKey() === node.key\"\n (click)=\"select(node)\"\n >\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: node, level }\" />\n </button>\n } @else {\n <div class=\"star-org__card\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: node, level }\" />\n </div>\n }\n @if (node.children?.length) {\n <button\n type=\"button\"\n class=\"star-org__toggle\"\n [attr.aria-expanded]=\"!isCollapsed(node)\"\n [attr.aria-label]=\"\n (isCollapsed(node) ? text.expandRow : text.collapseRow) + ': ' + node.label\n \"\n (click)=\"toggle(node)\"\n >\n <i\n class=\"ph-bold\"\n [class.ph-caret-down]=\"isCollapsed(node)\"\n [class.ph-caret-up]=\"!isCollapsed(node)\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n </div>\n @if (node.children?.length && !isCollapsed(node)) {\n <ul class=\"star-org__level\">\n @for (child of node.children; track child.key) {\n <ng-container\n *ngTemplateOutlet=\"branch; context: { $implicit: child, level: level + 1 }\"\n />\n }\n </ul>\n }\n </li>\n </ng-template>\n\n <ng-template #content let-node let-level=\"level\">\n @if (nodeTemplate(); as custom) {\n <ng-container *ngTemplateOutlet=\"custom.template; context: { $implicit: node, level }\" />\n } @else {\n <span class=\"star-org__label\">{{ node.label }}</span>\n @if (node.subtitle) {\n <span class=\"star-org__subtitle\">{{ node.subtitle }}</span>\n }\n }\n </ng-template>\n `,\n})\nexport class StarOrgChart<T = unknown> {\n protected readonly text = inject(STAR_UI_TEXT);\n\n /** Root node of the chart. */\n readonly value = input.required<StarOrgNode<T>>();\n readonly ariaLabel = input<string | null>(null);\n /** Keys of the nodes whose branch is hidden. Two-way. */\n readonly collapsedKeys = model<readonly string[]>([]);\n /** Nodes are buttons; one node can be selected. */\n readonly selectable = input(false, { transform: (value: boolean | '') => value === '' || value });\n readonly selectedKey = model<string | null>(null);\n readonly nodeSelect = output<StarOrgNode<T>>();\n\n protected readonly nodeTemplate = contentChild(StarOrgNodeTemplate);\n\n protected isCollapsed(node: StarOrgNode<T>): boolean {\n return this.collapsedKeys().includes(node.key);\n }\n\n protected toggle(node: StarOrgNode<T>): void {\n this.collapsedKeys.update((keys) =>\n keys.includes(node.key) ? keys.filter((key) => key !== node.key) : [...keys, node.key],\n );\n }\n\n protected select(node: StarOrgNode<T>): void {\n this.selectedKey.set(node.key);\n this.nodeSelect.emit(node);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"star-ng-ui-data-display.mjs","names":[],"sources":["../../../projects/star-ng/data-display/tree-table-model.ts","../../../projects/star-ng/data-display/data-display.ts","../../../projects/star-ng/data-display/org-chart.ts"],"sourcesContent":["// Pure helpers of the windowed tree table: which rows are in the DOM and where the row that a\n// key targets must scroll. They hold no DOM or signal state, so they are unit tested without\n// layout. The row flattening and the key targets come from `@star-ng/ui/tree`. This file is\n// internal and is not exported from the entry point.\nimport { scrollOffsetToReveal } from '@star-ng/ui/tree';\n\n/** The rows in the DOM and the height of the two spacer rows that stand for the others. */\nexport interface RowWindow {\n /** Index of the first rendered row. */\n readonly start: number;\n /** Index after the last rendered row. */\n readonly end: number;\n /** Height in pixels of the rows before `start`. */\n readonly before: number;\n /** Height in pixels of the rows from `end` on. */\n readonly after: number;\n}\n\n/**\n * The window of rows around the scroll position, for rows of one fixed height. `bufferRows` extra\n * rows render before and after the visible ones. `scrollTop` and `viewportSize` are the scroll\n * area of the table (the header is part of both); the window is wider than the visible rows by\n * the height of the sticky header, which keeps the math independent of the header size.\n */\nexport function rowWindow(\n count: number,\n itemSize: number,\n scrollTop: number,\n viewportSize: number,\n bufferRows: number,\n): RowWindow {\n if (count <= 0 || itemSize <= 0) return { start: 0, end: 0, before: 0, after: 0 };\n const visible = Math.ceil(Math.max(0, viewportSize) / itemSize) + 1;\n // A scroll position past the end (the rows got fewer) shows the last rows, like the browser.\n const first = Math.min(\n Math.max(0, Math.floor(Math.max(0, scrollTop) / itemSize)),\n Math.max(0, count - visible),\n );\n const start = Math.max(0, first - bufferRows);\n const end = Math.min(count, first + visible + bufferRows);\n return { start, end, before: start * itemSize, after: (count - end) * itemSize };\n}\n\n/**\n * Scroll position that brings a row fully into view, below the sticky header, with the least\n * movement; null when the row is already fully visible. `headerSize` is the height of the sticky\n * header: it covers the top of the scroll area, so the rows see a viewport that is that much lower.\n */\nexport function revealRowOffset(\n index: number,\n itemSize: number,\n scrollTop: number,\n viewportSize: number,\n headerSize: number,\n): number | null {\n return scrollOffsetToReveal(\n index,\n itemSize,\n scrollTop,\n Math.max(itemSize, viewportSize - headerSize),\n );\n}\n\n/**\n * `aria-rowindex` of the row at an index of the visible rows. The header row is row 1, so the\n * first body row is 2.\n */\nexport function ariaRowIndex(index: number): number {\n return index + 2;\n}\n\n/** `aria-rowcount`: the visible rows and the header row. */\nexport function ariaRowCount(rowCount: number): number {\n return rowCount + 1;\n}\n","import { _IdGenerator } from '@angular/cdk/a11y';\nimport { DOCUMENT, NgTemplateOutlet } from '@angular/common';\nimport {\n afterEveryRender,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n isDevMode,\n linkedSignal,\n model,\n numberAttribute,\n signal,\n TemplateRef,\n untracked,\n viewChild,\n} from '@angular/core';\nimport {\n optionText,\n readOption,\n STAR_UI_TEXT,\n starInlineKey,\n StarOptionKey,\n} from '@star-ng/ui/core';\nimport { StarPaginator } from '@star-ng/ui/paginator';\nimport {\n flattenVisible,\n navigationTarget,\n parentsOf,\n rowIndexOf,\n StarTreeNode,\n stillFocusable,\n TreeRow,\n} from '@star-ng/ui/tree';\nimport {\n ariaRowCount,\n ariaRowIndex,\n revealRowOffset,\n RowWindow,\n rowWindow,\n} from './tree-table-model';\n\n// ---------------------------------------------------------------- Tree table\n\nexport interface StarTreeTableColumn {\n readonly field: string;\n readonly header: string;\n readonly width?: string;\n readonly align?: 'start' | 'center' | 'end';\n}\n\ntype TreeTableNode = StarTreeNode<Record<string, unknown>>;\ntype TreeTableRow = TreeRow<TreeTableNode>;\n\n/** One rendered row: the row and its `aria-rowindex` (null in the default rendering). */\ninterface TreeTableEntry {\n readonly row: TreeTableRow;\n readonly aria: number | null;\n}\n\n/** Natural height of a tree table row in pixels. */\nconst TREE_TABLE_ROW_HEIGHT = 53;\n/** Rows that render before and after the visible ones in windowed rendering. */\nconst BUFFER_ROWS = 8;\n/** Height of the scroll area before it is measured (the first window of windowed rendering). */\nconst FALLBACK_VIEWPORT = 600;\n\n/**\n * Tree table (PrimeNG `p-treetable`): hierarchical rows with expand / collapse in a table,\n * `role=\"treegrid\"`, Right / Left on a row expand / collapse, Up / Down, Home and End move between\n * rows. Node `data` holds the column values; the first column shows the tree toggle.\n *\n * Large tables: `virtualScroll` with `scrollHeight` and `virtualItemSize` renders only the rows in\n * and near the viewport. It is still one `<table>`: a spacer row above and one below the rendered\n * rows stand for the others, the header is sticky, and every row has the fixed height\n * `virtualItemSize`. Keys, `aria-rowcount`, `aria-rowindex`, `aria-level`, `aria-setsize` and\n * `aria-posinset` work over all open rows, also the ones that are not in the DOM.\n *\n * `<star-tree-table [nodes]=\"budget\" [columns]=\"cols\" [(expanded)]=\"open\" ariaLabel=\"Budget\" />`\n */\n@Component({\n selector: 'star-tree-table',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'star-table star-tree-table',\n '[class.star-table--sticky]': '!!scrollHeight()',\n '[class.star-table--virtual]': 'windowed()',\n '[style.--star-table-row-height.px]': 'windowed() ? virtualItemSize() : null',\n },\n template: `\n <div\n #scroller\n class=\"star-table__scroll\"\n [attr.role]=\"windowed() ? 'group' : null\"\n [attr.aria-label]=\"windowed() ? ariaLabel() : null\"\n [attr.tabindex]=\"windowed() ? (activeRendered() ? -1 : 0) : null\"\n [style.max-height]=\"scrollHeight()\"\n (scroll)=\"syncScroll()\"\n (focus)=\"onScrollerFocus()\"\n (blur)=\"parked = false\"\n (keydown)=\"onScrollerKeydown($event)\"\n >\n <table\n role=\"treegrid\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-rowcount]=\"windowed() ? ariaRowCount(rows().length) : null\"\n >\n <thead #header>\n <tr [attr.aria-rowindex]=\"windowed() ? 1 : null\">\n @for (column of columns(); track column.field) {\n <th\n scope=\"col\"\n [style.width]=\"column.width\"\n [class]=\"'star-table__th star-table__cell--' + (column.align ?? 'start')\"\n >\n {{ column.header }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (window().before > 0) {\n <tr class=\"star-table__spacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"columns().length\" [style.height.px]=\"window().before\"></td>\n </tr>\n }\n @for (entry of entries(); track entry.row.node.key) {\n @let row = entry.row;\n <tr\n class=\"star-table__row\"\n [attr.aria-rowindex]=\"entry.aria\"\n [attr.aria-level]=\"row.level\"\n [attr.aria-setsize]=\"row.setSize\"\n [attr.aria-posinset]=\"row.position\"\n [attr.aria-expanded]=\"row.node.children?.length ? isOpen(row.node.key) : null\"\n [attr.tabindex]=\"focusKey() === row.node.key ? 0 : -1\"\n [attr.data-key]=\"row.node.key\"\n (keydown)=\"onKeydown($event, row)\"\n (focusin)=\"onRowFocus($event, row.node.key)\"\n >\n @for (column of columns(); track column.field; let first = $first) {\n <td [class]=\"'star-table__cell--' + (column.align ?? 'start')\">\n @if (first) {\n <span class=\"star-tree-table__first\" [style.--star-tree-level]=\"row.level - 1\">\n @if (row.node.children?.length) {\n <button\n type=\"button\"\n class=\"star-tree__toggle star-tree-table__toggle\"\n tabindex=\"-1\"\n [attr.aria-label]=\"\n isOpen(row.node.key)\n ? text.collapseItem(row.node.label)\n : text.expandItem(row.node.label)\n \"\n (click)=\"toggle(row.node.key)\"\n >\n <i class=\"ph-bold ph-caret-right\" aria-hidden=\"true\"></i>\n </button>\n } @else {\n <span class=\"star-tree__toggle star-tree__toggle--leaf\"></span>\n }\n {{ row.node.data?.[column.field] ?? row.node.label }}\n </span>\n } @else {\n {{ row.node.data?.[column.field] }}\n }\n </td>\n }\n </tr>\n }\n @if (window().after > 0) {\n <tr class=\"star-table__spacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"columns().length\" [style.height.px]=\"window().after\"></td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n `,\n})\nexport class StarTreeTable {\n protected readonly text = inject(STAR_UI_TEXT);\n private readonly doc = inject(DOCUMENT);\n readonly nodes = input<readonly TreeTableNode[]>([]);\n readonly columns = input.required<readonly StarTreeTableColumn[]>();\n readonly expanded = model<readonly string[]>([]);\n readonly ariaLabel = input<string | null>(null);\n /**\n * Maximum height of the table (a CSS length, for example `20rem`). The table scrolls inside it\n * and the header stays at the top.\n */\n readonly scrollHeight = input<string | null>(null);\n /**\n * Windowed rendering for large tables: only the rows in and near the viewport are in the DOM.\n * Needs `scrollHeight`, and every row gets the fixed height `virtualItemSize` with its text on\n * one line. Without `scrollHeight` the table renders all rows as usual.\n */\n readonly virtualScroll = input(false, { transform: booleanAttribute });\n /**\n * Row height in pixels in windowed rendering. The default is the natural height of a row of\n * this table.\n */\n readonly virtualItemSize = input(TREE_TABLE_ROW_HEIGHT, { transform: numberAttribute });\n\n private readonly scroller = viewChild<ElementRef<HTMLElement>>('scroller');\n private readonly header = viewChild<ElementRef<HTMLElement>>('header');\n\n private readonly openKeys = computed(() => new Set(this.expanded()));\n private readonly parents = computed(() => parentsOf(this.nodes()));\n /** The rows whose parents are open, in order. The sibling numbers come from the data. */\n protected readonly rows = computed<TreeTableRow[]>(() =>\n flattenVisible(this.nodes(), this.openKeys()),\n );\n private readonly rowIndex = computed(() => rowIndexOf(this.rows()));\n\n /**\n * The active row (the one with `tabindex` 0). It stays a row after the rows change, and it is\n * kept in state, not read from the DOM: in windowed rendering its element may not exist.\n */\n protected readonly focusKey = linkedSignal<readonly TreeTableRow[], string | null>({\n source: this.rows,\n computation: (rows, previous) =>\n stillFocusable(previous?.value, this.rowIndex(), this.parents(), rows[0]?.node.key ?? null),\n });\n\n // ---- windowed rendering ----\n protected readonly windowed = computed(\n () => this.virtualScroll() && !!this.scrollHeight() && this.virtualItemSize() > 0,\n );\n private readonly scrollTop = signal(0);\n private readonly viewportHeight = signal(0);\n /** The rows that are in the DOM. Without windowed rendering: all of them. */\n protected readonly window = computed<RowWindow>(\n () => {\n if (!this.windowed()) return { start: 0, end: this.rows().length, before: 0, after: 0 };\n return rowWindow(\n this.rows().length,\n this.virtualItemSize(),\n this.scrollTop(),\n this.viewportHeight() || FALLBACK_VIEWPORT,\n BUFFER_ROWS,\n );\n },\n // A scroll of a few pixels does not change the window: skip the work after it.\n {\n equal: (a, b) =>\n a.start === b.start && a.end === b.end && a.before === b.before && a.after === b.after,\n },\n );\n protected readonly entries = computed<TreeTableEntry[]>(() => {\n const rows = this.rows();\n if (!this.windowed()) return rows.map((row) => ({ row, aria: null }));\n const { start, end } = this.window();\n return rows.slice(start, end).map((row, i) => ({ row, aria: ariaRowIndex(start + i) }));\n });\n /** The active row is in the DOM. If it is not, the scroll area takes the Tab stop. */\n protected readonly activeRendered = computed(() => {\n const index = this.rowIndex().get(this.focusKey() ?? '');\n const { start, end } = this.window();\n return index !== undefined && index >= start && index < end;\n });\n protected readonly ariaRowCount = ariaRowCount;\n /** Row to focus as soon as its element exists (it may need scrolling in first). */\n private pendingFocus: string | null = null;\n /** The focus waits on the scroll area because the focused row left the DOM. */\n protected parked = false;\n\n constructor() {\n // The rows or the window change (a scroll, a branch closes, new nodes) and the focused row\n // may leave the DOM. This effect runs before the template updates, while the row is still there.\n effect(() => {\n const window = this.window();\n this.rowIndex();\n untracked(() => {\n if (this.windowed()) this.parkFocus(window);\n });\n });\n // The scroll area changes its height with the rows (up to `scrollHeight`) and with the page.\n effect((onCleanup) => {\n const scroller = this.scroller()?.nativeElement;\n if (!this.windowed() || !scroller || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => this.syncScroll());\n observer.observe(scroller);\n onCleanup(() => observer.disconnect());\n });\n afterEveryRender({ read: () => this.syncScroll() });\n afterEveryRender(() => {\n this.applyPendingFocus();\n if (this.parked) this.restoreParkedFocus();\n });\n if (isDevMode()) {\n effect(() => {\n if (this.virtualScroll() && !this.scrollHeight()) {\n console.warn(\n 'star-tree-table: virtualScroll needs scrollHeight. Without it the table renders all rows.',\n );\n }\n });\n }\n }\n\n protected isOpen(key: string): boolean {\n return this.openKeys().has(key);\n }\n\n toggle(key: string, open = !this.isOpen(key)): void {\n this.expanded.update((keys) => {\n if (!open) return keys.filter((k) => k !== key);\n return keys.includes(key) ? keys : [...keys, key];\n });\n }\n\n /** Reads the scroll position and the height of the scroll area (windowed rendering). */\n protected syncScroll(): void {\n const scroller = this.scroller()?.nativeElement;\n if (!scroller || !this.windowed()) return;\n this.scrollTop.set(scroller.scrollTop);\n if (scroller.clientHeight) this.viewportHeight.set(scroller.clientHeight);\n }\n\n protected onRowFocus(event: FocusEvent, key: string): void {\n this.focusKey.set(key);\n this.pendingFocus = null;\n this.parked = false;\n // A row that the keyboard or a click focuses may sit under the sticky header.\n if (event.target === event.currentTarget && this.windowed()) this.revealRow(key);\n }\n\n /**\n * Moves the focus to a row. The row becomes the active row at once. In windowed rendering the\n * row is scrolled into the window first, and the focus is applied after its element renders.\n */\n private focusRow(key: string | null | undefined): void {\n if (!key) return;\n this.focusKey.set(key);\n this.pendingFocus = key;\n if (this.windowed()) this.revealRow(key);\n queueMicrotask(() => this.applyPendingFocus());\n }\n\n /** Scrolls a row fully into view, below the sticky header, with the least movement. */\n private revealRow(key: string): void {\n const scroller = this.scroller()?.nativeElement;\n const index = this.rowIndex().get(key);\n if (!scroller || index === undefined) return;\n const offset = revealRowOffset(\n index,\n this.virtualItemSize(),\n scroller.scrollTop,\n scroller.clientHeight,\n this.header()?.nativeElement.offsetHeight ?? 0,\n );\n if (offset === null) return;\n scroller.scrollTop = offset;\n this.syncScroll();\n }\n\n private rowElement(key: string): HTMLElement | null {\n return (\n this.scroller()?.nativeElement.querySelector<HTMLElement>(\n `tbody > tr[data-key=\"${CSS.escape(key)}\"]`,\n ) ?? null\n );\n }\n\n private applyPendingFocus(): void {\n const key = this.pendingFocus;\n if (key === null) return;\n if (!this.rowIndex().has(key)) {\n this.pendingFocus = null;\n return;\n }\n const row = this.rowElement(key);\n if (!row) return; // not rendered yet: the next render calls this again\n this.pendingFocus = null;\n row.focus({ preventScroll: this.windowed() });\n }\n\n /**\n * The browser drops the focus to the page body when the focused element leaves the DOM. Before\n * the focused row leaves the window, the focus moves to the scroll area; the keys still work\n * there, and the focus returns to the row when it renders again.\n */\n private parkFocus(window: RowWindow): void {\n const scroller = this.scroller()?.nativeElement;\n const active = this.doc.activeElement;\n if (!scroller || !active || active === scroller || !scroller.contains(active)) return;\n const key = active.closest<HTMLElement>('tbody > tr[data-key]')?.dataset['key'];\n const index = key === undefined ? undefined : this.rowIndex().get(key);\n if (index !== undefined && index >= window.start && index < window.end) return;\n this.parked = true;\n scroller.focus({ preventScroll: true });\n }\n\n private restoreParkedFocus(): void {\n const scroller = this.scroller()?.nativeElement;\n if (!scroller || this.doc.activeElement !== scroller) {\n this.parked = false;\n return;\n }\n const key = this.focusKey();\n if (key === null) return;\n this.rowElement(key)?.focus({ preventScroll: true });\n }\n\n /** Tab into the scroll area (no row has the Tab stop): the focus goes to the active row. */\n protected onScrollerFocus(): void {\n if (this.windowed() && !this.parked) this.focusRow(this.focusKey());\n }\n\n /** Keys on the scroll area itself (the focus is parked there): they act on the active row. */\n protected onScrollerKeydown(event: KeyboardEvent): void {\n if (!this.windowed() || event.target !== event.currentTarget) return;\n const row = this.rows()[this.rowIndex().get(this.focusKey() ?? '') ?? -1];\n if (row) this.onKeydown(event, row);\n }\n\n protected onKeydown(event: KeyboardEvent, row: TreeTableRow): void {\n const rows = this.rows();\n // A key that arrives before the last move has rendered (a held key, a far scroll) continues\n // from the row that the last move aimed at, not from the row that still has the DOM focus.\n const item =\n this.pendingFocus === null\n ? row\n : (rows[this.rowIndex().get(this.pendingFocus) ?? -1] ?? row);\n const index = this.rowIndex().get(item.node.key) ?? -1;\n const hasChildren = !!item.node.children?.length;\n const expanded = hasChildren && this.isOpen(item.node.key);\n // Arrow right opens a branch and Arrow left closes it; the two swap in right-to-left.\n const key = starInlineKey(event);\n const move = (target: string | null) => {\n if (target === null) return;\n event.preventDefault();\n this.focusRow(target);\n };\n switch (key) {\n case 'ArrowDown':\n case 'ArrowUp':\n case 'Home':\n case 'End':\n return move(navigationTarget(rows, index, key, { hasChildren, expanded }));\n case 'ArrowRight':\n if (hasChildren) {\n event.preventDefault();\n if (!expanded) this.toggle(item.node.key, true);\n }\n return;\n case 'ArrowLeft':\n event.preventDefault();\n if (expanded) this.toggle(item.node.key, false);\n else move(item.parentKey);\n return;\n }\n }\n}\n\n// ---------------------------------------------------------------- Data view\n\n/** Item template: `<ng-template starDataViewItem let-item let-layout=\"layout\">`. */\n@Directive({ selector: 'ng-template[starDataViewItem]' })\nexport class StarDataViewItem<T = unknown> {\n readonly starDataViewItemOf = input<readonly T[] | null>(null);\n readonly template =\n inject<TemplateRef<{ $implicit: T; layout: 'list' | 'grid'; index: number }>>(TemplateRef);\n static ngTemplateContextGuard<T>(\n _dir: StarDataViewItem<T>,\n _ctx: unknown,\n ): _ctx is { $implicit: T; layout: 'list' | 'grid'; index: number } {\n return true;\n }\n}\n\n/**\n * Data view (PrimeNG `p-dataview`): items in a list or a responsive grid, layout switch,\n * client pagination and an empty state. It does not sort: sort the items before you pass them in.\n * You design each item with a template.\n *\n * ```html\n * <star-data-view [items]=\"products\" [(layout)]=\"layout\" paginator [rows]=\"6\">\n * <ng-template starDataViewItem let-p let-layout=\"layout\">…</ng-template>\n * </star-data-view>\n * ```\n */\n@Component({\n selector: 'star-data-view',\n imports: [NgTemplateOutlet, StarPaginator],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-data-view' },\n template: `\n <div class=\"star-data-view__header\">\n <ng-content select=\"[starDataViewHeader]\" />\n <div\n class=\"star-segmented star-segmented--sm\"\n role=\"radiogroup\"\n [attr.aria-label]=\"text.layout\"\n >\n @for (option of layouts; track option.id) {\n <button\n type=\"button\"\n role=\"radio\"\n class=\"star-segmented__item\"\n [class.star-segmented__item--on]=\"layout() === option.id\"\n [attr.aria-checked]=\"layout() === option.id\"\n [attr.aria-label]=\"option.label\"\n (click)=\"layout.set(option.id)\"\n >\n <i [class]=\"option.icon\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n </div>\n <ul class=\"star-data-view__items\" [class.star-data-view__items--grid]=\"layout() === 'grid'\">\n @for (item of pageItems(); track $index; let i = $index) {\n <li class=\"star-data-view__item\">\n @if (itemTemplate(); as custom) {\n <ng-container\n *ngTemplateOutlet=\"\n custom.template;\n context: { $implicit: item, layout: layout(), index: i }\n \"\n />\n }\n </li>\n } @empty {\n <li class=\"star-table__empty\">\n <i class=\"ph-bold ph-tray\" aria-hidden=\"true\"></i>\n {{ emptyMessage() ?? text.noData }}\n </li>\n }\n </ul>\n @if (paginator() && items().length > rows()) {\n <star-paginator\n [totalRecords]=\"items().length\"\n [(first)]=\"first\"\n [(rows)]=\"rows\"\n [rowsPerPageOptions]=\"[]\"\n />\n }\n `,\n})\nexport class StarDataView<T = unknown> {\n protected readonly text = inject(STAR_UI_TEXT);\n protected readonly layouts = [\n { id: 'list' as const, label: this.text.layoutList, icon: 'ph-bold ph-list' },\n { id: 'grid' as const, label: this.text.layoutGrid, icon: 'ph-bold ph-squares-four' },\n ];\n readonly items = input<readonly T[]>([]);\n readonly layout = model<'list' | 'grid'>('list');\n readonly paginator = input(false, { transform: booleanAttribute });\n readonly rows = model(6);\n readonly first = model(0);\n readonly emptyMessage = input<string | null>(null);\n protected readonly itemTemplate = contentChild(StarDataViewItem);\n\n protected readonly pageItems = computed(() =>\n this.paginator() ? this.items().slice(this.first(), this.first() + this.rows()) : this.items(),\n );\n}\n\n// ---------------------------------------------------------------- Order list and pick list\n\n/**\n * Order list (PrimeNG `p-orderlist`): reorder items with buttons or Alt + Arrow keys; the moved\n * item keeps focus and a live region announces its new position.\n * `<star-order-list [(value)]=\"priorities\" optionLabel=\"name\" ariaLabel=\"Queue order\" />`\n */\n@Component({\n selector: 'star-order-list',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-order-list' },\n template: `\n <div class=\"star-order-list__buttons\" role=\"group\" [attr.aria-label]=\"text.moveSelectedItem\">\n @for (action of actions; track action.id) {\n <button\n type=\"button\"\n class=\"star-select__icon-btn star-order-list__btn\"\n [attr.aria-label]=\"action.label\"\n [disabled]=\"selected() < 0 || !canMove(action.id)\"\n (click)=\"move(action.id)\"\n >\n <i [class]=\"action.icon\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <ul\n class=\"star-listbox star-order-list__list\"\n role=\"listbox\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-describedby]=\"hintId\"\n >\n @for (item of value(); track $index; let i = $index) {\n <li\n role=\"option\"\n class=\"star-listbox__option\"\n tabindex=\"0\"\n [attr.aria-selected]=\"selected() === i\"\n [class.star-listbox__option--selected]=\"selected() === i\"\n (click)=\"selected.set(i)\"\n (focus)=\"selected.set(i)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n <i class=\"ph-bold ph-dots-six-vertical star-order-list__grip\" aria-hidden=\"true\"></i>\n {{ labelOf(item) }}\n </li>\n }\n </ul>\n <p class=\"star-sr-only\" [id]=\"hintId\">{{ text.orderListHint }}</p>\n <p class=\"star-sr-only\" aria-live=\"polite\">{{ announcement() }}</p>\n `,\n})\nexport class StarOrderList<T = unknown> {\n protected readonly text = inject(STAR_UI_TEXT);\n protected readonly hintId = inject(_IdGenerator).getId('star-order-hint-');\n readonly value = model<readonly T[]>([]);\n readonly optionLabel = input<StarOptionKey<T> | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly selected = signal(-1);\n protected readonly announcement = signal('');\n protected readonly actions = [\n { id: 'top' as const, label: this.text.moveTop, icon: 'ph-bold ph-caret-double-up' },\n { id: 'up' as const, label: this.text.moveUp, icon: 'ph-bold ph-caret-up' },\n { id: 'down' as const, label: this.text.moveDown, icon: 'ph-bold ph-caret-down' },\n { id: 'bottom' as const, label: this.text.moveBottom, icon: 'ph-bold ph-caret-double-down' },\n ];\n\n protected labelOf(item: T): string {\n return optionText(item, this.optionLabel());\n }\n\n protected canMove(direction: 'top' | 'up' | 'down' | 'bottom'): boolean {\n const i = this.selected();\n return direction === 'top' || direction === 'up' ? i > 0 : i < this.value().length - 1;\n }\n\n move(direction: 'top' | 'up' | 'down' | 'bottom'): void {\n const from = this.selected();\n if (from < 0 || !this.canMove(direction)) return;\n const last = this.value().length - 1;\n const to = { top: 0, up: from - 1, down: from + 1, bottom: last }[direction];\n const items = [...this.value()];\n const [item] = items.splice(from, 1);\n items.splice(to, 0, item);\n this.value.set(items);\n this.selected.set(to);\n this.announcement.set(this.text.itemPosition(this.labelOf(item), to + 1, items.length));\n }\n\n protected onKeydown(event: KeyboardEvent, index: number): void {\n const list = (event.currentTarget as HTMLElement).parentElement!;\n const focusAt = (i: number) =>\n queueMicrotask(() => (list.children[i] as HTMLElement | undefined)?.focus());\n if (event.altKey && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) {\n event.preventDefault();\n this.selected.set(index);\n this.move(event.key === 'ArrowUp' ? 'up' : 'down');\n focusAt(this.selected());\n } else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {\n event.preventDefault();\n focusAt(\n Math.min(Math.max(index + (event.key === 'ArrowUp' ? -1 : 1), 0), this.value().length - 1),\n );\n }\n }\n}\n\n/**\n * Pick list (PrimeNG `p-picklist`): move items between a source and a target list.\n * Double-click or Enter moves one item; buttons move the selection or everything.\n * `<star-pick-list [(source)]=\"available\" [(target)]=\"assigned\" optionLabel=\"name\" sourceHeader=\"Available\" targetHeader=\"Assigned\" />`\n */\n@Component({\n selector: 'star-pick-list',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-pick-list' },\n template: `\n @for (side of sides; track side) {\n @let items = side === 'source' ? source() : target();\n <section class=\"star-pick-list__side\" [attr.aria-labelledby]=\"ids[side]\">\n <h3 class=\"star-pick-list__header\" [id]=\"ids[side]\">\n {{\n side === 'source'\n ? (sourceHeader() ?? text.pickListSource)\n : (targetHeader() ?? text.pickListTarget)\n }}\n <span class=\"star-badge star-badge--secondary star-badge--sm\">{{ items.length }}</span>\n </h3>\n <div class=\"star-pick-list__box\">\n <ul\n class=\"star-listbox star-pick-list__list\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n [attr.aria-labelledby]=\"ids[side]\"\n >\n @for (item of items; track $index; let i = $index) {\n <li\n role=\"option\"\n class=\"star-listbox__option\"\n tabindex=\"0\"\n [attr.aria-selected]=\"isPicked(side, item)\"\n [class.star-listbox__option--selected]=\"isPicked(side, item)\"\n (click)=\"pick(side, item)\"\n (dblclick)=\"transfer(side, [item])\"\n (keydown.enter)=\"transfer(side, [item])\"\n (keydown.space)=\"$event.preventDefault(); pick(side, item)\"\n >\n {{ labelOf(item) }}\n </li>\n }\n </ul>\n <!-- Outside the listbox: a listbox may contain options and groups only. -->\n @if (!items.length) {\n <div class=\"star-listbox__empty star-pick-list__empty\" role=\"presentation\">\n {{ text.emptyMessage }}\n </div>\n }\n </div>\n </section>\n @if (side === 'source') {\n <div class=\"star-pick-list__buttons\" role=\"group\" [attr.aria-label]=\"text.transfer\">\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n [attr.aria-label]=\"text.moveSelectedToTarget\"\n [disabled]=\"!picked('source').length\"\n (click)=\"transfer('source', picked('source'))\"\n >\n <i class=\"ph-bold ph-caret-right star-icon-mirror\" aria-hidden=\"true\"></i>\n </button>\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n [attr.aria-label]=\"text.moveAllToTarget\"\n [disabled]=\"!source().length\"\n (click)=\"transfer('source', source())\"\n >\n <i class=\"ph-bold ph-caret-double-right star-icon-mirror\" aria-hidden=\"true\"></i>\n </button>\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n [attr.aria-label]=\"text.moveSelectedToSource\"\n [disabled]=\"!picked('target').length\"\n (click)=\"transfer('target', picked('target'))\"\n >\n <i class=\"ph-bold ph-caret-left star-icon-mirror\" aria-hidden=\"true\"></i>\n </button>\n <button\n type=\"button\"\n class=\"star-select__icon-btn\"\n [attr.aria-label]=\"text.moveAllToSource\"\n [disabled]=\"!target().length\"\n (click)=\"transfer('target', target())\"\n >\n <i class=\"ph-bold ph-caret-double-left star-icon-mirror\" aria-hidden=\"true\"></i>\n </button>\n </div>\n }\n }\n `,\n})\nexport class StarPickList<T = unknown> {\n protected readonly text = inject(STAR_UI_TEXT);\n private readonly idGen = inject(_IdGenerator);\n protected readonly ids = {\n source: this.idGen.getId('star-pick-src-'),\n target: this.idGen.getId('star-pick-tgt-'),\n };\n protected readonly sides = ['source', 'target'] as const;\n\n readonly source = model<readonly T[]>([]);\n readonly target = model<readonly T[]>([]);\n readonly optionLabel = input<StarOptionKey<T> | null>(null);\n readonly sourceHeader = input<string | null>(null);\n readonly targetHeader = input<string | null>(null);\n\n private readonly selection = signal<{ source: readonly T[]; target: readonly T[] }>({\n source: [],\n target: [],\n });\n\n protected labelOf(item: T): string {\n return optionText(item, this.optionLabel());\n }\n protected picked(side: 'source' | 'target'): readonly T[] {\n return this.selection()[side];\n }\n protected isPicked(side: 'source' | 'target', item: T): boolean {\n return this.selection()[side].includes(item);\n }\n protected pick(side: 'source' | 'target', item: T): void {\n this.selection.update((sel) => ({\n ...sel,\n [side]: sel[side].includes(item) ? sel[side].filter((i) => i !== item) : [...sel[side], item],\n }));\n }\n\n transfer(from: 'source' | 'target', items: readonly T[]): void {\n if (!items.length) return;\n const moving = new Set(items);\n const [fromModel, toModel] =\n from === 'source' ? [this.source, this.target] : [this.target, this.source];\n fromModel.update((list) => list.filter((item) => !moving.has(item)));\n toModel.update((list) => [...list, ...items]);\n this.selection.update((sel) => ({ ...sel, [from]: [] }));\n }\n\n /** Reads a value with an optional key (exposed for custom templates). */\n read(item: T, key: StarOptionKey<T>): unknown {\n return readOption(item, key);\n }\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n contentChild,\n Directive,\n inject,\n input,\n model,\n output,\n TemplateRef,\n} from '@angular/core';\nimport { STAR_UI_TEXT } from '@star-ng/ui/core';\n\nexport interface StarOrgNode<T = unknown> {\n /** Unique id of the node in the chart. */\n readonly key: string;\n readonly label: string;\n /** Second line, for example a role. */\n readonly subtitle?: string;\n readonly data?: T;\n readonly children?: readonly StarOrgNode<T>[];\n}\n\nexport interface StarOrgNodeContext<T> {\n readonly $implicit: StarOrgNode<T>;\n readonly level: number;\n}\n\n/** Custom node content: `<ng-template starOrgNode let-node>…</ng-template>`. */\n@Directive({ selector: 'ng-template[starOrgNode]' })\nexport class StarOrgNodeTemplate<T = unknown> {\n readonly template = inject<TemplateRef<StarOrgNodeContext<T>>>(TemplateRef);\n\n static ngTemplateContextGuard<T>(\n _dir: StarOrgNodeTemplate<T>,\n _ctx: unknown,\n ): _ctx is StarOrgNodeContext<T> {\n return true;\n }\n}\n\n/**\n * Organization chart (PrimeNG `p-organizationchart`): a hierarchy drawn top-down with\n * connector lines. The markup is a nested list, so assistive technology reads the levels.\n * A node with children has a button that hides or shows its branch.\n *\n * `<star-org-chart ariaLabel=\"Safety team\" [value]=\"team\" [(collapsedKeys)]=\"closed\" selectable />`\n */\n@Component({\n selector: 'star-org-chart',\n imports: [NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-org' },\n template: `\n <div class=\"star-org__scroll\">\n <ul class=\"star-org__level star-org__level--root\" [attr.aria-label]=\"ariaLabel()\">\n <ng-container *ngTemplateOutlet=\"branch; context: { $implicit: value(), level: 0 }\" />\n </ul>\n </div>\n\n <ng-template #branch let-node let-level=\"level\">\n <li class=\"star-org__branch\">\n <div\n class=\"star-org__node\"\n [class.star-org__node--selected]=\"selectedKey() === node.key\"\n [class.star-org__node--parent]=\"!!node.children?.length && !isCollapsed(node)\"\n >\n @if (selectable()) {\n <button\n type=\"button\"\n class=\"star-org__card star-org__card--button\"\n [attr.aria-pressed]=\"selectedKey() === node.key\"\n (click)=\"select(node)\"\n >\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: node, level }\" />\n </button>\n } @else {\n <div class=\"star-org__card\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: node, level }\" />\n </div>\n }\n @if (node.children?.length) {\n <button\n type=\"button\"\n class=\"star-org__toggle\"\n [attr.aria-expanded]=\"!isCollapsed(node)\"\n [attr.aria-label]=\"\n (isCollapsed(node) ? text.expandRow : text.collapseRow) + ': ' + node.label\n \"\n (click)=\"toggle(node)\"\n >\n <i\n class=\"ph-bold\"\n [class.ph-caret-down]=\"isCollapsed(node)\"\n [class.ph-caret-up]=\"!isCollapsed(node)\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n </div>\n @if (node.children?.length && !isCollapsed(node)) {\n <ul class=\"star-org__level\">\n @for (child of node.children; track child.key) {\n <ng-container\n *ngTemplateOutlet=\"branch; context: { $implicit: child, level: level + 1 }\"\n />\n }\n </ul>\n }\n </li>\n </ng-template>\n\n <ng-template #content let-node let-level=\"level\">\n @if (nodeTemplate(); as custom) {\n <ng-container *ngTemplateOutlet=\"custom.template; context: { $implicit: node, level }\" />\n } @else {\n <span class=\"star-org__label\">{{ node.label }}</span>\n @if (node.subtitle) {\n <span class=\"star-org__subtitle\">{{ node.subtitle }}</span>\n }\n }\n </ng-template>\n `,\n})\nexport class StarOrgChart<T = unknown> {\n protected readonly text = inject(STAR_UI_TEXT);\n\n /** Root node of the chart. */\n readonly value = input.required<StarOrgNode<T>>();\n readonly ariaLabel = input<string | null>(null);\n /** Keys of the nodes whose branch is hidden. Two-way. */\n readonly collapsedKeys = model<readonly string[]>([]);\n /** Nodes are buttons; one node can be selected. */\n readonly selectable = input(false, { transform: (value: boolean | '') => value === '' || value });\n readonly selectedKey = model<string | null>(null);\n readonly nodeSelect = output<StarOrgNode<T>>();\n\n protected readonly nodeTemplate = contentChild(StarOrgNodeTemplate);\n\n protected isCollapsed(node: StarOrgNode<T>): boolean {\n return this.collapsedKeys().includes(node.key);\n }\n\n protected toggle(node: StarOrgNode<T>): void {\n this.collapsedKeys.update((keys) =>\n keys.includes(node.key) ? keys.filter((key) => key !== node.key) : [...keys, node.key],\n );\n }\n\n protected select(node: StarOrgNode<T>): void {\n this.selectedKey.set(node.key);\n this.nodeSelect.emit(node);\n }\n}\n"],"mappings":"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"}
@@ -3,100 +3,8 @@ import { CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport }
3
3
  import { NgTemplateOutlet } from "@angular/common";
4
4
  import * as i0 from "@angular/core";
5
5
  import { ChangeDetectionStrategy, Component, ElementRef, Injector, afterNextRender, booleanAttribute, computed, contentChild, effect, inject, input, model, output, signal, viewChild } from "@angular/core";
6
- import { STAR_UI_TEXT, matchesFilter, optionText, readOption } from "@star-ng/ui/core";
6
+ import { STAR_UI_TEXT, matchesFilter, optionText, readOption, starListAriaPosition, starListHeight, starListKeyboardTarget, starListLayout, starListPageSize, starListRevealOffset, starListRevealRows, starListRowRendered, starListTypeaheadIndex } from "@star-ng/ui/core";
7
7
  import { StarOptionTemplate } from "@star-ng/ui/select";
8
- function buildLayout(options, groupOf, idPrefix) {
9
- const rows = [];
10
- const rowOfOption = [];
11
- let current = null;
12
- let groupId = null;
13
- let groupRow = -1;
14
- options.forEach((option, index) => {
15
- if (groupOf) {
16
- const label = groupOf(option);
17
- if (index === 0 || label !== current) {
18
- current = label;
19
- groupId = `${idPrefix}-group-${index}`;
20
- groupRow = rows.length;
21
- rows.push({
22
- kind: "group",
23
- key: `g:${index}`,
24
- label,
25
- id: groupId
26
- });
27
- }
28
- }
29
- rowOfOption.push(rows.length);
30
- rows.push({
31
- kind: "option",
32
- key: `o:${index}`,
33
- option,
34
- index,
35
- groupId,
36
- groupRow
37
- });
38
- });
39
- return {
40
- rows,
41
- rowOfOption
42
- };
43
- }
44
- function pageSize(viewportHeight, itemSize) {
45
- const lines = Math.floor(viewportHeight / Math.max(1, itemSize));
46
- return Math.max(1, lines - 1);
47
- }
48
- function keyboardTarget(key, active, count, page) {
49
- if (count <= 0) return -1;
50
- const last = count - 1;
51
- let target;
52
- switch (key) {
53
- case "ArrowDown":
54
- target = active + 1;
55
- break;
56
- case "ArrowUp":
57
- target = active - 1;
58
- break;
59
- case "Home":
60
- target = 0;
61
- break;
62
- case "End":
63
- target = last;
64
- break;
65
- case "PageDown":
66
- target = (active < 0 ? 0 : active) + page;
67
- break;
68
- case "PageUp": target = (active < 0 ? last : active) - page;
69
- }
70
- return Math.min(Math.max(target, 0), last);
71
- }
72
- function typeaheadIndex(count, labelAt, typed) {
73
- for (let i = 0; i < count; i++) if (labelAt(i).toLowerCase().startsWith(typed)) return i;
74
- return -1;
75
- }
76
- function revealRows(layout, index) {
77
- const row = layout.rowOfOption[index];
78
- if (row === void 0) return [0, 0];
79
- return [layout.rows[row - 1]?.kind === "group" ? row - 1 : row, row];
80
- }
81
- function revealOffset(first, last, itemSize, scrollOffset, viewportHeight) {
82
- const top = first * itemSize;
83
- const bottom = (last + 1) * itemSize;
84
- if (top < scrollOffset) return top;
85
- if (viewportHeight > 0 && bottom > scrollOffset + viewportHeight) return bottom - viewportHeight;
86
- return null;
87
- }
88
- function ariaPosition(index, count) {
89
- return {
90
- setsize: count,
91
- posinset: index + 1
92
- };
93
- }
94
- function listHeight(scrollHeight, rowCount, itemSize) {
95
- return `min(${scrollHeight}, ${rowCount * Math.max(1, itemSize)}px)`;
96
- }
97
- function isRowRendered(row, range) {
98
- return row >= range.start && row < range.end;
99
- }
100
8
  var StarListbox = class StarListbox {
101
9
  text = inject(STAR_UI_TEXT);
102
10
  listId = inject(_IdGenerator).getId("star-listbox-");
@@ -178,25 +86,25 @@ var StarListbox = class StarListbox {
178
86
  return `${this.listId}-group-${first}`;
179
87
  }
180
88
  itemSize = computed(() => Math.max(1, this.virtualItemSize()), ...ngDevMode ? [{ debugName: "itemSize" }] : /* istanbul ignore next */ []);
181
- layout = computed(() => buildLayout(this.visible(), this.optionGroup() ? (option) => this.groupOf(option) : null, this.listId), ...ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []);
182
- viewportHeight = computed(() => listHeight(this.scrollHeight(), this.layout().rows.length, this.itemSize()), ...ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []);
89
+ layout = computed(() => starListLayout(this.visible(), this.optionGroup() ? (option) => this.groupOf(option) : null, this.listId), ...ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []);
90
+ viewportHeight = computed(() => starListHeight(this.scrollHeight(), this.layout().rows.length, this.itemSize()), ...ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []);
183
91
  renderedRange = signal({
184
92
  start: 0,
185
93
  end: 0
186
94
  }, ...ngDevMode ? [{ debugName: "renderedRange" }] : /* istanbul ignore next */ []);
187
95
  trackRow = (_index, row) => row.key;
188
96
  positionOf(index) {
189
- return ariaPosition(index, this.visible().length);
97
+ return starListAriaPosition(index, this.visible().length);
190
98
  }
191
99
  describedBy(row) {
192
- return row.groupId !== null && isRowRendered(row.groupRow, this.renderedRange()) ? row.groupId : null;
100
+ return row.groupId !== null && starListRowRendered(row.groupRow, this.renderedRange()) ? row.groupId : null;
193
101
  }
194
102
  activeId = computed(() => {
195
103
  const index = this.active();
196
104
  if (index < 0 || index >= this.visible().length) return null;
197
105
  if (this.virtualScroll()) {
198
106
  const row = this.layout().rowOfOption[index];
199
- if (row === void 0 || !isRowRendered(row, this.renderedRange())) return null;
107
+ if (row === void 0 || !starListRowRendered(row, this.renderedRange())) return null;
200
108
  }
201
109
  return `${this.listId}-${index}`;
202
110
  }, ...ngDevMode ? [{ debugName: "activeId" }] : /* istanbul ignore next */ []);
@@ -259,18 +167,18 @@ var StarListbox = class StarListbox {
259
167
  }
260
168
  const viewport = this.viewport();
261
169
  if (!viewport) return;
262
- const [first, last] = revealRows(this.layout(), index);
263
- const offset = revealOffset(first, last, this.itemSize(), viewport.measureScrollOffset(), viewport.getViewportSize());
170
+ const [first, last] = starListRevealRows(this.layout(), index);
171
+ const offset = starListRevealOffset(first, last, this.itemSize(), viewport.measureScrollOffset(), viewport.getViewportSize());
264
172
  if (offset !== null) viewport.scrollToOffset(offset);
265
173
  }
266
174
  onKeydown(event) {
267
175
  const options = this.visible();
268
176
  if (!options.length || this.disabled()) return;
269
177
  const fromInput = event.target instanceof HTMLInputElement;
270
- const page = pageSize(this.viewport()?.getViewportSize() || 256, this.itemSize());
178
+ const page = starListPageSize(this.viewport()?.getViewportSize() || 256, this.itemSize());
271
179
  const move = (key) => {
272
180
  event.preventDefault();
273
- this.active.set(typeof key === "number" ? key : keyboardTarget(key, this.active(), options.length, page));
181
+ this.active.set(typeof key === "number" ? key : starListKeyboardTarget(key, this.active(), options.length, page));
274
182
  this.reveal(this.active());
275
183
  if (!this.multiple() && !fromInput) {
276
184
  const option = options[this.active()];
@@ -298,7 +206,7 @@ var StarListbox = class StarListbox {
298
206
  const now = Date.now();
299
207
  this.typeahead = (now - this.typeaheadAt > 500 ? "" : this.typeahead) + event.key.toLowerCase();
300
208
  this.typeaheadAt = now;
301
- const index = typeaheadIndex(options.length, (i) => this.labelOf(options[i]), this.typeahead);
209
+ const index = starListTypeaheadIndex(options.length, (i) => this.labelOf(options[i]), this.typeahead);
302
210
  if (index >= 0) move(index);
303
211
  }
304
212
  }
@@ -1 +1 @@
1
- {"version":3,"file":"star-ng-ui-listbox.mjs","names":[],"sources":["../../../projects/star-ng/listbox/virtual-rows.ts","../../../projects/star-ng/listbox/listbox.ts"],"sourcesContent":["/**\n * Pure helpers of the virtual list in `star-listbox`: row model, index math, keyboard target and\n * ARIA values. They have no DOM access, so unit tests can check them without layout.\n */\n\n/** One row of the virtual list. Group headings and options have the same height. */\nexport type ListboxRow<T> =\n | { readonly kind: 'group'; readonly key: string; readonly label: string; readonly id: string }\n | {\n readonly kind: 'option';\n readonly key: string;\n readonly option: T;\n /** Index in the visible options (keyboard order). */\n readonly index: number;\n /** Id of the heading row of the group, or null without groups. */\n readonly groupId: string | null;\n /** Index of the heading row of the group, or -1 without groups. */\n readonly groupRow: number;\n };\n\n/** The rows, and for each visible option the index of its row. */\nexport interface ListboxLayout<T> {\n readonly rows: readonly ListboxRow<T>[];\n readonly rowOfOption: readonly number[];\n}\n\n/**\n * Flattens headings and options into one list of rows of equal height. `options` must already be\n * in display order (each group together). A heading comes before the first option of each group.\n * The heading id has the form `<idPrefix>-group-<index of the first option of the group>`.\n */\nexport function buildLayout<T>(\n options: readonly T[],\n groupOf: ((option: T) => string) | null,\n idPrefix: string,\n): ListboxLayout<T> {\n const rows: ListboxRow<T>[] = [];\n const rowOfOption: number[] = [];\n let current: string | null = null;\n let groupId: string | null = null;\n let groupRow = -1;\n options.forEach((option, index) => {\n if (groupOf) {\n const label = groupOf(option);\n if (index === 0 || label !== current) {\n current = label;\n groupId = `${idPrefix}-group-${index}`;\n groupRow = rows.length;\n rows.push({ kind: 'group', key: `g:${index}`, label, id: groupId });\n }\n }\n rowOfOption.push(rows.length);\n rows.push({ kind: 'option', key: `o:${index}`, option, index, groupId, groupRow });\n });\n return { rows, rowOfOption };\n}\n\n/** Number of options a Page up / Page down key moves: the lines in view, minus one for overlap. */\nexport function pageSize(viewportHeight: number, itemSize: number): number {\n const lines = Math.floor(viewportHeight / Math.max(1, itemSize));\n return Math.max(1, lines - 1);\n}\n\nexport type ListNavigationKey = 'ArrowDown' | 'ArrowUp' | 'Home' | 'End' | 'PageDown' | 'PageUp';\n\n/** Index of the option a navigation key moves to, limited to the list. -1 for an empty list. */\nexport function keyboardTarget(\n key: ListNavigationKey,\n active: number,\n count: number,\n page: number,\n): number {\n if (count <= 0) return -1;\n const last = count - 1;\n let target: number;\n switch (key) {\n case 'ArrowDown':\n target = active + 1;\n break;\n case 'ArrowUp':\n target = active - 1;\n break;\n case 'Home':\n target = 0;\n break;\n case 'End':\n target = last;\n break;\n case 'PageDown':\n target = (active < 0 ? 0 : active) + page;\n break;\n case 'PageUp':\n target = (active < 0 ? last : active) - page;\n break;\n }\n return Math.min(Math.max(target, 0), last);\n}\n\n/** Index of the first option whose label starts with the typed text (compared in lower case). */\nexport function typeaheadIndex(\n count: number,\n labelAt: (index: number) => string,\n typed: string,\n): number {\n for (let i = 0; i < count; i++) {\n if (labelAt(i).toLowerCase().startsWith(typed)) return i;\n }\n return -1;\n}\n\n/** First and last row to bring into view for an option: its heading row comes with the first option. */\nexport function revealRows<T>(layout: ListboxLayout<T>, index: number): [number, number] {\n const row = layout.rowOfOption[index];\n if (row === undefined) return [0, 0];\n const above = layout.rows[row - 1];\n return [above?.kind === 'group' ? row - 1 : row, row];\n}\n\n/**\n * Scroll offset that brings rows `first` to `last` into view with the least movement, or null when\n * they are in view. Rows have the height `itemSize`.\n */\nexport function revealOffset(\n first: number,\n last: number,\n itemSize: number,\n scrollOffset: number,\n viewportHeight: number,\n): number | null {\n const top = first * itemSize;\n const bottom = (last + 1) * itemSize;\n if (top < scrollOffset) return top;\n if (viewportHeight > 0 && bottom > scrollOffset + viewportHeight) return bottom - viewportHeight;\n return null;\n}\n\n/** `aria-setsize` and `aria-posinset` of an option, for the whole list. */\nexport function ariaPosition(index: number, count: number): { setsize: number; posinset: number } {\n return { setsize: count, posinset: index + 1 };\n}\n\n/** CSS height of the list: `scrollHeight` at most, and no taller than the rows need. */\nexport function listHeight(scrollHeight: string, rowCount: number, itemSize: number): string {\n return `min(${scrollHeight}, ${rowCount * Math.max(1, itemSize)}px)`;\n}\n\n/** True when a row is inside the rendered range `[start, end)`. */\nexport function isRowRendered(row: number, range: { start: number; end: number }): boolean {\n return row >= range.start && row < range.end;\n}\n","import { _IdGenerator } from '@angular/cdk/a11y';\nimport {\n CdkFixedSizeVirtualScroll,\n CdkVirtualForOf,\n CdkVirtualScrollViewport,\n} from '@angular/cdk/scrolling';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n afterNextRender,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n effect,\n ElementRef,\n inject,\n Injector,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\nimport {\n matchesFilter,\n optionText,\n readOption,\n STAR_UI_TEXT,\n StarOptionKey,\n} from '@star-ng/ui/core';\nimport { StarOptionTemplate } from '@star-ng/ui/select';\nimport {\n ariaPosition,\n buildLayout,\n isRowRendered,\n keyboardTarget,\n ListboxRow,\n listHeight,\n ListNavigationKey,\n pageSize,\n revealOffset,\n revealRows,\n typeaheadIndex,\n} from './virtual-rows';\n\n/**\n * Inline list choice (PrimeNG `p-listbox`): single or `multiple` (checkboxes), filter,\n * option template, WAI-ARIA listbox keyboard (Arrow, Home / End, Space / Enter, typeahead).\n * Value: one value, or an array in `multiple` mode.\n *\n * `<star-listbox [options]=\"queues\" optionLabel=\"name\" optionValue=\"id\" [(value)]=\"queue\" filter ariaLabel=\"Queue\" />`\n */\n@Component({\n selector: 'star-listbox',\n imports: [NgTemplateOutlet, CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll, CdkVirtualForOf],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'star-listbox-box',\n '[class.star-listbox-box--disabled]': 'disabled()',\n '[class.star-listbox-box--invalid]': 'invalid() && touched()',\n },\n template: `\n @if (filter()) {\n <div class=\"star-panel__filter\">\n <i class=\"ph-bold ph-magnifying-glass\" aria-hidden=\"true\"></i>\n <input\n #filterInput\n type=\"search\"\n class=\"star-input star-input--sm\"\n autocomplete=\"off\"\n [attr.aria-label]=\"text.filterPlaceholder\"\n [attr.aria-controls]=\"listId\"\n [placeholder]=\"text.filterPlaceholder\"\n [value]=\"query()\"\n (input)=\"onFilterInput(filterInput.value)\"\n (keydown)=\"onKeydown($event)\"\n />\n </div>\n }\n @if (virtualScroll()) {\n <!-- Virtual scroll: the CDK viewport is the listbox. Group headings and options are rows of one height. -->\n <cdk-virtual-scroll-viewport\n #list\n class=\"star-listbox star-listbox--virtual star-listbox--viewport\"\n role=\"listbox\"\n [id]=\"listId\"\n [itemSize]=\"itemSize()\"\n [minBufferPx]=\"itemSize() * 4\"\n [maxBufferPx]=\"itemSize() * 8\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-multiselectable]=\"multiple() || null\"\n [attr.aria-activedescendant]=\"activeId()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [style.--star-item-size.px]=\"itemSize()\"\n [style.height]=\"viewportHeight()\"\n (keydown)=\"onKeydown($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"touch.emit()\"\n >\n <ng-container *cdkVirtualFor=\"let row of layout().rows; trackBy: trackRow\">\n @if (row.kind === 'group') {\n <div class=\"star-listbox__group\" role=\"presentation\" [id]=\"row.id\">\n {{ row.label }}\n </div>\n } @else {\n @let option = row.option;\n @let i = row.index;\n @let position = positionOf(i);\n <!-- Keyboard is handled on the listbox via aria-activedescendant. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"listId + '-' + i\"\n [class.star-listbox__option--active]=\"active() === i\"\n [class.star-listbox__option--selected]=\"isSelected(option)\"\n [attr.aria-selected]=\"isSelected(option)\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"describedBy(row)\"\n [attr.aria-setsize]=\"position.setsize\"\n [attr.aria-posinset]=\"position.posinset\"\n (click)=\"active.set(i); choose(option)\"\n >\n @if (multiple()) {\n <span class=\"star-check__box\" aria-hidden=\"true\">\n @if (isSelected(option)) {\n <i class=\"ph-bold ph-check\"></i>\n }\n </span>\n }\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container\n *ngTemplateOutlet=\"\n custom.template;\n context: { $implicit: option, selected: isSelected(option), index: i }\n \"\n />\n } @else {\n {{ labelOf(option) }}\n }\n </span>\n </div>\n }\n </ng-container>\n </cdk-virtual-scroll-viewport>\n @if (!visible().length) {\n <div class=\"star-listbox__empty\" role=\"presentation\">{{ text.emptyFilterMessage }}</div>\n }\n } @else {\n <ul\n #list\n class=\"star-listbox\"\n role=\"listbox\"\n [id]=\"listId\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-multiselectable]=\"multiple() || null\"\n [attr.aria-activedescendant]=\"activeId()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [style.max-height]=\"scrollHeight()\"\n (keydown)=\"onKeydown($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"touch.emit()\"\n >\n @for (option of visible(); track $index; let i = $index) {\n @if (groupHeading(i); as heading) {\n <li class=\"star-listbox__group\" role=\"presentation\" [id]=\"groupId(i)\">{{ heading }}</li>\n }\n <!-- Keyboard is handled on the listbox via aria-activedescendant. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"listId + '-' + i\"\n [class.star-listbox__option--active]=\"active() === i\"\n [class.star-listbox__option--selected]=\"isSelected(option)\"\n [attr.aria-selected]=\"isSelected(option)\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"groupId(i)\"\n (click)=\"active.set(i); choose(option)\"\n >\n @if (multiple()) {\n <span class=\"star-check__box\" aria-hidden=\"true\">\n @if (isSelected(option)) {\n <i class=\"ph-bold ph-check\"></i>\n }\n </span>\n }\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container\n *ngTemplateOutlet=\"\n custom.template;\n context: { $implicit: option, selected: isSelected(option), index: i }\n \"\n />\n } @else {\n {{ labelOf(option) }}\n }\n </span>\n </li>\n }\n </ul>\n <!-- Outside the listbox: a listbox may contain options and groups only. -->\n @if (!visible().length) {\n <div class=\"star-listbox__empty\" role=\"presentation\">{{ text.emptyFilterMessage }}</div>\n }\n }\n `,\n})\nexport class StarListbox<TOption = unknown, TValue = TOption> implements FormValueControl<\n TValue | readonly TValue[] | null\n> {\n protected readonly text = inject(STAR_UI_TEXT);\n protected readonly listId = inject(_IdGenerator).getId('star-listbox-');\n\n readonly value = model<TValue | readonly TValue[] | null>(null);\n readonly options = input<readonly TOption[]>([]);\n readonly optionLabel = input<StarOptionKey<TOption> | null>(null);\n readonly optionValue = input<StarOptionKey<TOption> | null>(null);\n readonly optionDisabled = input<StarOptionKey<TOption> | null>(null);\n /**\n * Group heading of an option (property name or function). Options with the same heading\n * show together under it, in the order in which the headings first appear.\n */\n readonly optionGroup = input<StarOptionKey<TOption> | null>(null);\n readonly multiple = input(false, { transform: booleanAttribute });\n readonly filter = input(false, { transform: booleanAttribute });\n /** Height of the list. With `virtualScroll` it is the height of the list, or less for a short list. */\n readonly scrollHeight = input('16rem');\n /**\n * Renders only the rows in and near the view (CDK virtual scroll), for lists of thousands of\n * options. Every row, group headings included, has the height `virtualItemSize` and the text\n * stays on one line. Keys and type-ahead work over all options. Page up and Page down move by\n * the lines in view.\n */\n readonly virtualScroll = input(false, { transform: booleanAttribute });\n /** Row height in pixels with `virtualScroll`. */\n readonly virtualItemSize = input(40);\n readonly ariaLabel = input<string | null>(null);\n readonly disabled = input(false, { transform: booleanAttribute });\n readonly invalid = input(false, { transform: booleanAttribute });\n readonly touched = input(false, { transform: booleanAttribute });\n readonly touch = output<void>();\n\n protected readonly optionTemplate = contentChild(StarOptionTemplate);\n private readonly list = viewChild<unknown, ElementRef<HTMLElement>>('list', { read: ElementRef });\n private readonly viewport = viewChild(CdkVirtualScrollViewport);\n private readonly injector = inject(Injector);\n protected readonly query = signal('');\n protected readonly active = signal(-1);\n private typeahead = '';\n private typeaheadAt = 0;\n\n protected readonly visible = computed(() => {\n const options = this.options().filter((option) =>\n matchesFilter(this.labelOf(option), this.query()),\n );\n if (!this.optionGroup()) return options;\n // Keep each group together, in the order in which the groups first appear.\n const order = new Map<string, number>();\n for (const option of options) {\n const group = this.groupOf(option);\n if (!order.has(group)) order.set(group, order.size);\n }\n return options\n .map((option, index) => ({ option, index, rank: order.get(this.groupOf(option)) ?? 0 }))\n .sort((a, b) => a.rank - b.rank || a.index - b.index)\n .map(({ option }) => option);\n });\n\n protected groupOf(option: TOption): string {\n const key = this.optionGroup();\n const group = key ? readOption(option, key) : null;\n return group === null || group === undefined ? '' : String(group);\n }\n\n /** Heading to show before the option at an index: the first option of each group. */\n protected groupHeading(index: number): string | null {\n if (!this.optionGroup()) return null;\n const options = this.visible();\n const group = this.groupOf(options[index]);\n return index === 0 || this.groupOf(options[index - 1]) !== group ? group : null;\n }\n\n protected groupId(index: number): string | null {\n if (!this.optionGroup()) return null;\n const options = this.visible();\n let first = index;\n while (first > 0 && this.groupOf(options[first - 1]) === this.groupOf(options[index])) first--;\n return `${this.listId}-group-${first}`;\n }\n\n // ---- Virtual scroll ----\n\n protected readonly itemSize = computed(() => Math.max(1, this.virtualItemSize()));\n\n /** Group headings and options in one list of rows of equal height. */\n protected readonly layout = computed(() =>\n buildLayout(\n this.visible(),\n this.optionGroup() ? (option) => this.groupOf(option) : null,\n this.listId,\n ),\n );\n\n protected readonly viewportHeight = computed(() =>\n listHeight(this.scrollHeight(), this.layout().rows.length, this.itemSize()),\n );\n\n /** Rows that are in the DOM now: `[start, end)`, reported by the CDK viewport. */\n private readonly renderedRange = signal({ start: 0, end: 0 });\n\n protected readonly trackRow = (_index: number, row: ListboxRow<TOption>): string => row.key;\n\n protected positionOf(index: number): { setsize: number; posinset: number } {\n return ariaPosition(index, this.visible().length);\n }\n\n /** The heading of the group, only while its row is in the DOM (the id must exist). */\n protected describedBy(row: Extract<ListboxRow<TOption>, { kind: 'option' }>): string | null {\n return row.groupId !== null && isRowRendered(row.groupRow, this.renderedRange())\n ? row.groupId\n : null;\n }\n\n /** `aria-activedescendant` only names an option that is in the DOM. */\n protected readonly activeId = computed(() => {\n const index = this.active();\n if (index < 0 || index >= this.visible().length) return null;\n if (this.virtualScroll()) {\n const row = this.layout().rowOfOption[index];\n if (row === undefined || !isRowRendered(row, this.renderedRange())) return null;\n }\n return `${this.listId}-${index}`;\n });\n\n constructor() {\n effect((onCleanup) => {\n const viewport = this.viewport();\n if (!viewport) return;\n const element = viewport.getElementRef().nativeElement;\n this.renderedRange.set(viewport.getRenderedRange());\n // The range is read after the rows have been drawn, so the ids it allows exist.\n const range = viewport.renderedRangeStream.subscribe((next) =>\n afterNextRender(() => this.renderedRange.set({ ...next }), { injector: this.injector }),\n );\n afterNextRender(\n () =>\n element\n .querySelector('.cdk-virtual-scroll-content-wrapper')\n ?.setAttribute('role', 'presentation'),\n { injector: this.injector },\n );\n // The viewport measures its height once; a new height (filter, hidden parent) needs a new measure.\n const observer =\n typeof ResizeObserver === 'undefined'\n ? null\n : new ResizeObserver(() => viewport.checkViewportSize());\n observer?.observe(element);\n onCleanup(() => {\n range.unsubscribe();\n observer?.disconnect();\n });\n });\n }\n\n protected labelOf(option: TOption): string {\n return optionText(option, this.optionLabel());\n }\n protected isDisabled(option: TOption): boolean {\n const key = this.optionDisabled();\n return key ? !!readOption(option, key) : false;\n }\n private valueOf(option: TOption): TValue {\n return readOption(option, this.optionValue()) as TValue;\n }\n protected isSelected(option: TOption): boolean {\n const value = this.value();\n const optionValue = this.valueOf(option);\n return Array.isArray(value)\n ? value.some((v) => Object.is(v, optionValue))\n : Object.is(value, optionValue);\n }\n protected firstSelectedOrZero(): number {\n return Math.max(\n 0,\n this.visible().findIndex((option) => this.isSelected(option)),\n );\n }\n\n protected choose(option: TOption): void {\n if (this.disabled() || this.isDisabled(option)) return;\n const optionValue = this.valueOf(option);\n if (this.multiple()) {\n const current = Array.isArray(this.value()) ? (this.value() as readonly TValue[]) : [];\n this.value.set(\n this.isSelected(option)\n ? current.filter((v) => !Object.is(v, optionValue))\n : [...current, optionValue],\n );\n } else {\n this.value.set(optionValue);\n }\n }\n\n protected onFilterInput(text: string): void {\n this.query.set(text);\n this.active.set(0);\n // The shorter list starts at its top.\n this.viewport()?.scrollToOffset(0);\n }\n\n protected onFocus(): void {\n if (this.active() >= 0) return;\n this.active.set(this.firstSelectedOrZero());\n if (this.virtualScroll()) this.reveal(this.active());\n }\n\n /**\n * Brings the active option into view. With `virtualScroll` the option may not be in the DOM yet:\n * the viewport scrolls to it (least movement, heading row included) and then renders it.\n */\n private reveal(index: number): void {\n if (!this.virtualScroll()) {\n queueMicrotask(() =>\n this.list()\n ?.nativeElement.querySelector(`#${CSS.escape(this.activeId() ?? '')}`)\n ?.scrollIntoView?.({ block: 'nearest' }),\n );\n return;\n }\n const viewport = this.viewport();\n if (!viewport) return;\n const [first, last] = revealRows(this.layout(), index);\n const offset = revealOffset(\n first,\n last,\n this.itemSize(),\n viewport.measureScrollOffset(),\n viewport.getViewportSize(),\n );\n if (offset !== null) viewport.scrollToOffset(offset);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const options = this.visible();\n if (!options.length || this.disabled()) return;\n const fromInput = event.target instanceof HTMLInputElement;\n const page = pageSize(this.viewport()?.getViewportSize() || 256, this.itemSize());\n const move = (key: ListNavigationKey | number) => {\n event.preventDefault();\n this.active.set(\n typeof key === 'number' ? key : keyboardTarget(key, this.active(), options.length, page),\n );\n this.reveal(this.active());\n if (!this.multiple() && !fromInput) {\n const option = options[this.active()];\n if (!this.isDisabled(option)) this.value.set(this.valueOf(option));\n }\n };\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp':\n return move(event.key);\n case 'Home':\n case 'End':\n if (fromInput) return;\n return move(event.key);\n case 'PageDown':\n case 'PageUp':\n // Without `virtualScroll` the browser scrolls the list by a page.\n if (fromInput || !this.virtualScroll()) return;\n return move(event.key);\n case ' ':\n case 'Enter':\n if (event.key === ' ' && fromInput) return;\n event.preventDefault();\n if (options[this.active()] !== undefined) this.choose(options[this.active()]);\n return;\n default:\n if (event.key.length === 1 && !fromInput) {\n const now = Date.now();\n this.typeahead =\n (now - this.typeaheadAt > 500 ? '' : this.typeahead) + event.key.toLowerCase();\n this.typeaheadAt = now;\n // Over all options, also those that are not in the DOM.\n const index = typeaheadIndex(\n options.length,\n (i) => this.labelOf(options[i]),\n this.typeahead,\n );\n if (index >= 0) move(index);\n }\n }\n }\n\n focus(): void {\n this.list()?.nativeElement.focus();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"star-ng-ui-listbox.mjs","names":[],"sources":["../../../projects/star-ng/listbox/listbox.ts"],"sourcesContent":["import { _IdGenerator } from '@angular/cdk/a11y';\nimport {\n CdkFixedSizeVirtualScroll,\n CdkVirtualForOf,\n CdkVirtualScrollViewport,\n} from '@angular/cdk/scrolling';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n afterNextRender,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n effect,\n ElementRef,\n inject,\n Injector,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\nimport {\n matchesFilter,\n optionText,\n readOption,\n STAR_UI_TEXT,\n starListAriaPosition,\n starListHeight,\n starListKeyboardTarget,\n starListLayout,\n StarListNavigationKey,\n starListPageSize,\n starListRevealOffset,\n starListRevealRows,\n starListRowRendered,\n starListTypeaheadIndex,\n StarOptionKey,\n StarWindowRow,\n} from '@star-ng/ui/core';\nimport { StarOptionTemplate } from '@star-ng/ui/select';\n\n/**\n * Inline list choice (PrimeNG `p-listbox`): single or `multiple` (checkboxes), filter,\n * option template, WAI-ARIA listbox keyboard (Arrow, Home / End, Space / Enter, typeahead).\n * Value: one value, or an array in `multiple` mode.\n *\n * `<star-listbox [options]=\"queues\" optionLabel=\"name\" optionValue=\"id\" [(value)]=\"queue\" filter ariaLabel=\"Queue\" />`\n */\n@Component({\n selector: 'star-listbox',\n imports: [NgTemplateOutlet, CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll, CdkVirtualForOf],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'star-listbox-box',\n '[class.star-listbox-box--disabled]': 'disabled()',\n '[class.star-listbox-box--invalid]': 'invalid() && touched()',\n },\n template: `\n @if (filter()) {\n <div class=\"star-panel__filter\">\n <i class=\"ph-bold ph-magnifying-glass\" aria-hidden=\"true\"></i>\n <input\n #filterInput\n type=\"search\"\n class=\"star-input star-input--sm\"\n autocomplete=\"off\"\n [attr.aria-label]=\"text.filterPlaceholder\"\n [attr.aria-controls]=\"listId\"\n [placeholder]=\"text.filterPlaceholder\"\n [value]=\"query()\"\n (input)=\"onFilterInput(filterInput.value)\"\n (keydown)=\"onKeydown($event)\"\n />\n </div>\n }\n @if (virtualScroll()) {\n <!-- Virtual scroll: the CDK viewport is the listbox. Group headings and options are rows of one height. -->\n <cdk-virtual-scroll-viewport\n #list\n class=\"star-listbox star-listbox--virtual star-listbox--viewport\"\n role=\"listbox\"\n [id]=\"listId\"\n [itemSize]=\"itemSize()\"\n [minBufferPx]=\"itemSize() * 4\"\n [maxBufferPx]=\"itemSize() * 8\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-multiselectable]=\"multiple() || null\"\n [attr.aria-activedescendant]=\"activeId()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [style.--star-item-size.px]=\"itemSize()\"\n [style.height]=\"viewportHeight()\"\n (keydown)=\"onKeydown($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"touch.emit()\"\n >\n <ng-container *cdkVirtualFor=\"let row of layout().rows; trackBy: trackRow\">\n @if (row.kind === 'group') {\n <div class=\"star-listbox__group\" role=\"presentation\" [id]=\"row.id\">\n {{ row.label }}\n </div>\n } @else {\n @let option = row.option;\n @let i = row.index;\n @let position = positionOf(i);\n <!-- Keyboard is handled on the listbox via aria-activedescendant. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"listId + '-' + i\"\n [class.star-listbox__option--active]=\"active() === i\"\n [class.star-listbox__option--selected]=\"isSelected(option)\"\n [attr.aria-selected]=\"isSelected(option)\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"describedBy(row)\"\n [attr.aria-setsize]=\"position.setsize\"\n [attr.aria-posinset]=\"position.posinset\"\n (click)=\"active.set(i); choose(option)\"\n >\n @if (multiple()) {\n <span class=\"star-check__box\" aria-hidden=\"true\">\n @if (isSelected(option)) {\n <i class=\"ph-bold ph-check\"></i>\n }\n </span>\n }\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container\n *ngTemplateOutlet=\"\n custom.template;\n context: { $implicit: option, selected: isSelected(option), index: i }\n \"\n />\n } @else {\n {{ labelOf(option) }}\n }\n </span>\n </div>\n }\n </ng-container>\n </cdk-virtual-scroll-viewport>\n @if (!visible().length) {\n <div class=\"star-listbox__empty\" role=\"presentation\">{{ text.emptyFilterMessage }}</div>\n }\n } @else {\n <ul\n #list\n class=\"star-listbox\"\n role=\"listbox\"\n [id]=\"listId\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-multiselectable]=\"multiple() || null\"\n [attr.aria-activedescendant]=\"activeId()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [style.max-height]=\"scrollHeight()\"\n (keydown)=\"onKeydown($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"touch.emit()\"\n >\n @for (option of visible(); track $index; let i = $index) {\n @if (groupHeading(i); as heading) {\n <li class=\"star-listbox__group\" role=\"presentation\" [id]=\"groupId(i)\">{{ heading }}</li>\n }\n <!-- Keyboard is handled on the listbox via aria-activedescendant. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <li\n class=\"star-listbox__option\"\n role=\"option\"\n [id]=\"listId + '-' + i\"\n [class.star-listbox__option--active]=\"active() === i\"\n [class.star-listbox__option--selected]=\"isSelected(option)\"\n [attr.aria-selected]=\"isSelected(option)\"\n [attr.aria-disabled]=\"isDisabled(option) || null\"\n [attr.aria-describedby]=\"groupId(i)\"\n (click)=\"active.set(i); choose(option)\"\n >\n @if (multiple()) {\n <span class=\"star-check__box\" aria-hidden=\"true\">\n @if (isSelected(option)) {\n <i class=\"ph-bold ph-check\"></i>\n }\n </span>\n }\n <span class=\"star-listbox__label\">\n @if (optionTemplate(); as custom) {\n <ng-container\n *ngTemplateOutlet=\"\n custom.template;\n context: { $implicit: option, selected: isSelected(option), index: i }\n \"\n />\n } @else {\n {{ labelOf(option) }}\n }\n </span>\n </li>\n }\n </ul>\n <!-- Outside the listbox: a listbox may contain options and groups only. -->\n @if (!visible().length) {\n <div class=\"star-listbox__empty\" role=\"presentation\">{{ text.emptyFilterMessage }}</div>\n }\n }\n `,\n})\nexport class StarListbox<TOption = unknown, TValue = TOption> implements FormValueControl<\n TValue | readonly TValue[] | null\n> {\n protected readonly text = inject(STAR_UI_TEXT);\n protected readonly listId = inject(_IdGenerator).getId('star-listbox-');\n\n readonly value = model<TValue | readonly TValue[] | null>(null);\n readonly options = input<readonly TOption[]>([]);\n readonly optionLabel = input<StarOptionKey<TOption> | null>(null);\n readonly optionValue = input<StarOptionKey<TOption> | null>(null);\n readonly optionDisabled = input<StarOptionKey<TOption> | null>(null);\n /**\n * Group heading of an option (property name or function). Options with the same heading\n * show together under it, in the order in which the headings first appear.\n */\n readonly optionGroup = input<StarOptionKey<TOption> | null>(null);\n readonly multiple = input(false, { transform: booleanAttribute });\n readonly filter = input(false, { transform: booleanAttribute });\n /** Height of the list. With `virtualScroll` it is the height of the list, or less for a short list. */\n readonly scrollHeight = input('16rem');\n /**\n * Renders only the rows in and near the view (CDK virtual scroll), for lists of thousands of\n * options. Every row, group headings included, has the height `virtualItemSize` and the text\n * stays on one line. Keys and type-ahead work over all options. Page up and Page down move by\n * the lines in view.\n */\n readonly virtualScroll = input(false, { transform: booleanAttribute });\n /** Row height in pixels with `virtualScroll`. */\n readonly virtualItemSize = input(40);\n readonly ariaLabel = input<string | null>(null);\n readonly disabled = input(false, { transform: booleanAttribute });\n readonly invalid = input(false, { transform: booleanAttribute });\n readonly touched = input(false, { transform: booleanAttribute });\n readonly touch = output<void>();\n\n protected readonly optionTemplate = contentChild(StarOptionTemplate);\n private readonly list = viewChild<unknown, ElementRef<HTMLElement>>('list', { read: ElementRef });\n private readonly viewport = viewChild(CdkVirtualScrollViewport);\n private readonly injector = inject(Injector);\n protected readonly query = signal('');\n protected readonly active = signal(-1);\n private typeahead = '';\n private typeaheadAt = 0;\n\n protected readonly visible = computed(() => {\n const options = this.options().filter((option) =>\n matchesFilter(this.labelOf(option), this.query()),\n );\n if (!this.optionGroup()) return options;\n // Keep each group together, in the order in which the groups first appear.\n const order = new Map<string, number>();\n for (const option of options) {\n const group = this.groupOf(option);\n if (!order.has(group)) order.set(group, order.size);\n }\n return options\n .map((option, index) => ({ option, index, rank: order.get(this.groupOf(option)) ?? 0 }))\n .sort((a, b) => a.rank - b.rank || a.index - b.index)\n .map(({ option }) => option);\n });\n\n protected groupOf(option: TOption): string {\n const key = this.optionGroup();\n const group = key ? readOption(option, key) : null;\n return group === null || group === undefined ? '' : String(group);\n }\n\n /** Heading to show before the option at an index: the first option of each group. */\n protected groupHeading(index: number): string | null {\n if (!this.optionGroup()) return null;\n const options = this.visible();\n const group = this.groupOf(options[index]);\n return index === 0 || this.groupOf(options[index - 1]) !== group ? group : null;\n }\n\n protected groupId(index: number): string | null {\n if (!this.optionGroup()) return null;\n const options = this.visible();\n let first = index;\n while (first > 0 && this.groupOf(options[first - 1]) === this.groupOf(options[index])) first--;\n return `${this.listId}-group-${first}`;\n }\n\n // ---- Virtual scroll ----\n\n protected readonly itemSize = computed(() => Math.max(1, this.virtualItemSize()));\n\n /** Group headings and options in one list of rows of equal height. */\n protected readonly layout = computed(() =>\n starListLayout(\n this.visible(),\n this.optionGroup() ? (option) => this.groupOf(option) : null,\n this.listId,\n ),\n );\n\n protected readonly viewportHeight = computed(() =>\n starListHeight(this.scrollHeight(), this.layout().rows.length, this.itemSize()),\n );\n\n /** Rows that are in the DOM now: `[start, end)`, reported by the CDK viewport. */\n private readonly renderedRange = signal({ start: 0, end: 0 });\n\n protected readonly trackRow = (_index: number, row: StarWindowRow<TOption>): string => row.key;\n\n protected positionOf(index: number): { setsize: number; posinset: number } {\n return starListAriaPosition(index, this.visible().length);\n }\n\n /** The heading of the group, only while its row is in the DOM (the id must exist). */\n protected describedBy(row: Extract<StarWindowRow<TOption>, { kind: 'option' }>): string | null {\n return row.groupId !== null && starListRowRendered(row.groupRow, this.renderedRange())\n ? row.groupId\n : null;\n }\n\n /** `aria-activedescendant` only names an option that is in the DOM. */\n protected readonly activeId = computed(() => {\n const index = this.active();\n if (index < 0 || index >= this.visible().length) return null;\n if (this.virtualScroll()) {\n const row = this.layout().rowOfOption[index];\n if (row === undefined || !starListRowRendered(row, this.renderedRange())) return null;\n }\n return `${this.listId}-${index}`;\n });\n\n constructor() {\n effect((onCleanup) => {\n const viewport = this.viewport();\n if (!viewport) return;\n const element = viewport.getElementRef().nativeElement;\n this.renderedRange.set(viewport.getRenderedRange());\n // The range is read after the rows have been drawn, so the ids it allows exist.\n const range = viewport.renderedRangeStream.subscribe((next) =>\n afterNextRender(() => this.renderedRange.set({ ...next }), { injector: this.injector }),\n );\n afterNextRender(\n () =>\n element\n .querySelector('.cdk-virtual-scroll-content-wrapper')\n ?.setAttribute('role', 'presentation'),\n { injector: this.injector },\n );\n // The viewport measures its height once; a new height (filter, hidden parent) needs a new measure.\n const observer =\n typeof ResizeObserver === 'undefined'\n ? null\n : new ResizeObserver(() => viewport.checkViewportSize());\n observer?.observe(element);\n onCleanup(() => {\n range.unsubscribe();\n observer?.disconnect();\n });\n });\n }\n\n protected labelOf(option: TOption): string {\n return optionText(option, this.optionLabel());\n }\n protected isDisabled(option: TOption): boolean {\n const key = this.optionDisabled();\n return key ? !!readOption(option, key) : false;\n }\n private valueOf(option: TOption): TValue {\n return readOption(option, this.optionValue()) as TValue;\n }\n protected isSelected(option: TOption): boolean {\n const value = this.value();\n const optionValue = this.valueOf(option);\n return Array.isArray(value)\n ? value.some((v) => Object.is(v, optionValue))\n : Object.is(value, optionValue);\n }\n protected firstSelectedOrZero(): number {\n return Math.max(\n 0,\n this.visible().findIndex((option) => this.isSelected(option)),\n );\n }\n\n protected choose(option: TOption): void {\n if (this.disabled() || this.isDisabled(option)) return;\n const optionValue = this.valueOf(option);\n if (this.multiple()) {\n const current = Array.isArray(this.value()) ? (this.value() as readonly TValue[]) : [];\n this.value.set(\n this.isSelected(option)\n ? current.filter((v) => !Object.is(v, optionValue))\n : [...current, optionValue],\n );\n } else {\n this.value.set(optionValue);\n }\n }\n\n protected onFilterInput(text: string): void {\n this.query.set(text);\n this.active.set(0);\n // The shorter list starts at its top.\n this.viewport()?.scrollToOffset(0);\n }\n\n protected onFocus(): void {\n if (this.active() >= 0) return;\n this.active.set(this.firstSelectedOrZero());\n if (this.virtualScroll()) this.reveal(this.active());\n }\n\n /**\n * Brings the active option into view. With `virtualScroll` the option may not be in the DOM yet:\n * the viewport scrolls to it (least movement, heading row included) and then renders it.\n */\n private reveal(index: number): void {\n if (!this.virtualScroll()) {\n queueMicrotask(() =>\n this.list()\n ?.nativeElement.querySelector(`#${CSS.escape(this.activeId() ?? '')}`)\n ?.scrollIntoView?.({ block: 'nearest' }),\n );\n return;\n }\n const viewport = this.viewport();\n if (!viewport) return;\n const [first, last] = starListRevealRows(this.layout(), index);\n const offset = starListRevealOffset(\n first,\n last,\n this.itemSize(),\n viewport.measureScrollOffset(),\n viewport.getViewportSize(),\n );\n if (offset !== null) viewport.scrollToOffset(offset);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const options = this.visible();\n if (!options.length || this.disabled()) return;\n const fromInput = event.target instanceof HTMLInputElement;\n const page = starListPageSize(this.viewport()?.getViewportSize() || 256, this.itemSize());\n const move = (key: StarListNavigationKey | number) => {\n event.preventDefault();\n this.active.set(\n typeof key === 'number'\n ? key\n : starListKeyboardTarget(key, this.active(), options.length, page),\n );\n this.reveal(this.active());\n if (!this.multiple() && !fromInput) {\n const option = options[this.active()];\n if (!this.isDisabled(option)) this.value.set(this.valueOf(option));\n }\n };\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp':\n return move(event.key);\n case 'Home':\n case 'End':\n if (fromInput) return;\n return move(event.key);\n case 'PageDown':\n case 'PageUp':\n // Without `virtualScroll` the browser scrolls the list by a page.\n if (fromInput || !this.virtualScroll()) return;\n return move(event.key);\n case ' ':\n case 'Enter':\n if (event.key === ' ' && fromInput) return;\n event.preventDefault();\n if (options[this.active()] !== undefined) this.choose(options[this.active()]);\n return;\n default:\n if (event.key.length === 1 && !fromInput) {\n const now = Date.now();\n this.typeahead =\n (now - this.typeaheadAt > 500 ? '' : this.typeahead) + event.key.toLowerCase();\n this.typeaheadAt = now;\n // Over all options, also those that are not in the DOM.\n const index = starListTypeaheadIndex(\n options.length,\n (i) => this.labelOf(options[i]),\n this.typeahead,\n );\n if (index >= 0) move(index);\n }\n }\n }\n\n focus(): void {\n this.list()?.nativeElement.focus();\n }\n}\n"],"mappings":"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"}