forty-cdk 0.7.0 → 0.9.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.
- package/README.md +3 -3
- package/aspect-ratio/README.md +19 -0
- package/avatar/README.md +3 -3
- package/breadcrumbs/README.md +12 -0
- package/calendar/README.md +20 -17
- package/context-menu/README.md +20 -19
- package/date-picker/README.md +22 -63
- package/dialog/README.md +1 -1
- package/drag-drop/README.md +2 -2
- package/dropdown-menu/README.md +20 -19
- package/fesm2022/forty-cdk-accordion.mjs +2 -15
- package/fesm2022/forty-cdk-accordion.mjs.map +1 -1
- package/fesm2022/forty-cdk-aspect-ratio.mjs +11 -15
- package/fesm2022/forty-cdk-aspect-ratio.mjs.map +1 -1
- package/fesm2022/forty-cdk-avatar.mjs +8 -4
- package/fesm2022/forty-cdk-avatar.mjs.map +1 -1
- package/fesm2022/forty-cdk-breadcrumbs.mjs +32 -21
- package/fesm2022/forty-cdk-breadcrumbs.mjs.map +1 -1
- package/fesm2022/forty-cdk-button.mjs +253 -20
- package/fesm2022/forty-cdk-button.mjs.map +1 -1
- package/fesm2022/forty-cdk-calendar.mjs +119 -76
- package/fesm2022/forty-cdk-calendar.mjs.map +1 -1
- package/fesm2022/forty-cdk-checkbox.mjs +2 -15
- package/fesm2022/forty-cdk-checkbox.mjs.map +1 -1
- package/fesm2022/forty-cdk-combobox.mjs +124 -97
- package/fesm2022/forty-cdk-combobox.mjs.map +1 -1
- package/fesm2022/forty-cdk-context-menu.mjs +11 -2
- package/fesm2022/forty-cdk-context-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-core.mjs +1513 -1176
- package/fesm2022/forty-cdk-core.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-field.mjs +3 -0
- package/fesm2022/forty-cdk-date-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-picker.mjs +35 -70
- package/fesm2022/forty-cdk-date-picker.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-range-field.mjs +25 -106
- package/fesm2022/forty-cdk-date-range-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-dialog.mjs +31 -17
- package/fesm2022/forty-cdk-dialog.mjs.map +1 -1
- package/fesm2022/forty-cdk-disclosure.mjs +2 -15
- package/fesm2022/forty-cdk-disclosure.mjs.map +1 -1
- package/fesm2022/forty-cdk-drag-drop.mjs +81 -15
- package/fesm2022/forty-cdk-drag-drop.mjs.map +1 -1
- package/fesm2022/forty-cdk-drawer.mjs +37 -23
- package/fesm2022/forty-cdk-drawer.mjs.map +1 -1
- package/fesm2022/forty-cdk-dropdown-menu.mjs +11 -2
- package/fesm2022/forty-cdk-dropdown-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-field.mjs +2 -15
- package/fesm2022/forty-cdk-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-fieldset.mjs +2 -15
- package/fesm2022/forty-cdk-fieldset.mjs.map +1 -1
- package/fesm2022/forty-cdk-file-upload.mjs +44 -46
- package/fesm2022/forty-cdk-file-upload.mjs.map +1 -1
- package/fesm2022/forty-cdk-input.mjs +2 -15
- package/fesm2022/forty-cdk-input.mjs.map +1 -1
- package/fesm2022/forty-cdk-internationalized-date.mjs +30 -8
- package/fesm2022/forty-cdk-internationalized-date.mjs.map +1 -1
- package/fesm2022/forty-cdk-listbox.mjs +87 -3
- package/fesm2022/forty-cdk-listbox.mjs.map +1 -1
- package/fesm2022/forty-cdk-menu.mjs +17 -2
- package/fesm2022/forty-cdk-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-menubar.mjs +7 -0
- package/fesm2022/forty-cdk-menubar.mjs.map +1 -1
- package/fesm2022/forty-cdk-meter.mjs +31 -29
- package/fesm2022/forty-cdk-meter.mjs.map +1 -1
- package/fesm2022/forty-cdk-navigation-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-number-input.mjs +1 -1
- package/fesm2022/forty-cdk-number-input.mjs.map +1 -1
- package/fesm2022/forty-cdk-otp-input.mjs +4 -17
- package/fesm2022/forty-cdk-otp-input.mjs.map +1 -1
- package/fesm2022/forty-cdk-pane-resizer.mjs +2 -15
- package/fesm2022/forty-cdk-pane-resizer.mjs.map +1 -1
- package/fesm2022/forty-cdk-popover.mjs +44 -7
- package/fesm2022/forty-cdk-popover.mjs.map +1 -1
- package/fesm2022/forty-cdk-progress.mjs +25 -14
- package/fesm2022/forty-cdk-progress.mjs.map +1 -1
- package/fesm2022/forty-cdk-radio-group.mjs +6 -5
- package/fesm2022/forty-cdk-radio-group.mjs.map +1 -1
- package/fesm2022/forty-cdk-search.mjs +136 -38
- package/fesm2022/forty-cdk-search.mjs.map +1 -1
- package/fesm2022/forty-cdk-select.mjs +308 -162
- package/fesm2022/forty-cdk-select.mjs.map +1 -1
- package/fesm2022/forty-cdk-separator.mjs +1 -15
- package/fesm2022/forty-cdk-separator.mjs.map +1 -1
- package/fesm2022/forty-cdk-slider.mjs +79 -90
- package/fesm2022/forty-cdk-slider.mjs.map +1 -1
- package/fesm2022/forty-cdk-stepper.mjs +13 -6
- package/fesm2022/forty-cdk-stepper.mjs.map +1 -1
- package/fesm2022/forty-cdk-switch.mjs +2 -15
- package/fesm2022/forty-cdk-switch.mjs.map +1 -1
- package/fesm2022/forty-cdk-table.mjs +420 -138
- package/fesm2022/forty-cdk-table.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-field.mjs +3 -0
- package/fesm2022/forty-cdk-time-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-picker.mjs +61 -129
- package/fesm2022/forty-cdk-time-picker.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-range-field.mjs +64 -111
- package/fesm2022/forty-cdk-time-range-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-toggle.mjs +5 -6
- package/fesm2022/forty-cdk-toggle.mjs.map +1 -1
- package/fesm2022/forty-cdk-toolbar.mjs +10 -3
- package/fesm2022/forty-cdk-toolbar.mjs.map +1 -1
- package/fesm2022/forty-cdk-tree.mjs +36 -19
- package/fesm2022/forty-cdk-tree.mjs.map +1 -1
- package/fesm2022/forty-cdk-virtualization.mjs +34 -18
- package/fesm2022/forty-cdk-virtualization.mjs.map +1 -1
- package/file-upload/README.md +4 -4
- package/listbox/README.md +1 -1
- package/menu/README.md +15 -0
- package/meter/README.md +12 -10
- package/package.json +1 -1
- package/popover/README.md +1 -1
- package/progress/README.md +3 -1
- package/radio-group/README.md +2 -2
- package/search/README.md +34 -15
- package/select/README.md +7 -1
- package/signal-forms/README.md +1 -1
- package/stepper/README.md +13 -0
- package/table/README.md +31 -36
- package/time-range-field/README.md +17 -12
- package/toggle/README.md +1 -1
- package/toolbar/README.md +4 -4
- package/tree/README.md +11 -9
- package/types/forty-cdk-accordion.d.ts +3 -20
- package/types/forty-cdk-aspect-ratio.d.ts +11 -20
- package/types/forty-cdk-avatar.d.ts +2 -2
- package/types/forty-cdk-breadcrumbs.d.ts +18 -8
- package/types/forty-cdk-button.d.ts +6 -22
- package/types/forty-cdk-calendar.d.ts +33 -9
- package/types/forty-cdk-checkbox.d.ts +2 -20
- package/types/forty-cdk-combobox.d.ts +66 -9
- package/types/forty-cdk-context-menu.d.ts +11 -3
- package/types/forty-cdk-core.d.ts +702 -313
- package/types/forty-cdk-date-field.d.ts +1 -0
- package/types/forty-cdk-date-picker.d.ts +21 -31
- package/types/forty-cdk-date-range-field.d.ts +1 -0
- package/types/forty-cdk-dialog.d.ts +21 -7
- package/types/forty-cdk-disclosure.d.ts +3 -20
- package/types/forty-cdk-drag-drop.d.ts +42 -7
- package/types/forty-cdk-drawer.d.ts +21 -6
- package/types/forty-cdk-dropdown-menu.d.ts +11 -3
- package/types/forty-cdk-field.d.ts +1 -20
- package/types/forty-cdk-fieldset.d.ts +1 -20
- package/types/forty-cdk-file-upload.d.ts +31 -34
- package/types/forty-cdk-input.d.ts +1 -20
- package/types/forty-cdk-internationalized-date.d.ts +10 -6
- package/types/forty-cdk-listbox.d.ts +34 -2
- package/types/forty-cdk-menu.d.ts +22 -5
- package/types/forty-cdk-menubar.d.ts +14 -8
- package/types/forty-cdk-meter.d.ts +29 -27
- package/types/forty-cdk-navigation-menu.d.ts +7 -2
- package/types/forty-cdk-otp-input.d.ts +6 -23
- package/types/forty-cdk-pane-resizer.d.ts +1 -20
- package/types/forty-cdk-popover.d.ts +50 -7
- package/types/forty-cdk-progress.d.ts +31 -11
- package/types/forty-cdk-radio-group.d.ts +8 -7
- package/types/forty-cdk-search.d.ts +137 -34
- package/types/forty-cdk-select.d.ts +122 -125
- package/types/forty-cdk-separator.d.ts +1 -20
- package/types/forty-cdk-slider.d.ts +7 -17
- package/types/forty-cdk-stepper.d.ts +20 -4
- package/types/forty-cdk-switch.d.ts +1 -20
- package/types/forty-cdk-table.d.ts +70 -39
- package/types/forty-cdk-time-field.d.ts +1 -0
- package/types/forty-cdk-time-picker.d.ts +47 -77
- package/types/forty-cdk-time-range-field.d.ts +30 -5
- package/types/forty-cdk-toggle.d.ts +9 -4
- package/types/forty-cdk-toolbar.d.ts +1 -0
- package/types/forty-cdk-tree.d.ts +21 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forty-cdk-accordion.mjs","sources":["../../../projects/forty-cdk/accordion/src/accordion-context.ts","../../../projects/forty-cdk/accordion/src/accordion.ts","../../../projects/forty-cdk/accordion/src/accordion-item.ts","../../../projects/forty-cdk/accordion/src/accordion-trigger.ts","../../../projects/forty-cdk/accordion/src/accordion-content.ts","../../../projects/forty-cdk/accordion/src/accordion-defaults.ts","../../../projects/forty-cdk/accordion/src/forty-cdk-accordion.ts"],"sourcesContent":["import { inject, InjectionToken, type Signal } from '@angular/core';\n\nimport { type ListNavigationAction, type WritingDirection } from 'forty-cdk/core';\n\n/**\n * Registry entry for one `ForAccordionTrigger`. Triggers register their host\n * element so the root can drive keyboard navigation over its own triggers\n * without an unscoped DOM query that would leak into nested accordions.\n */\nexport interface ForAccordionTriggerHandle {\n readonly host: HTMLElement;\n readonly disabled: Signal<boolean>;\n}\n\n/**\n * Coordination contract owned by the `ForAccordion` root.\n * Items derive their state from this context; triggers route clicks and\n * keyboard navigation through it.\n */\nexport interface ForAccordionContext {\n readonly multiple: Signal<boolean>;\n readonly collapsible: Signal<boolean>;\n /** Whether the whole accordion is disabled; each item ORs this into its own disabled state. */\n readonly disabled: Signal<boolean>;\n readonly orientation: Signal<'horizontal' | 'vertical'>;\n readonly dir: Signal<WritingDirection>;\n isExpanded(itemValue: string): boolean;\n toggle(itemValue: string): void;\n /** Whether the given item is allowed to collapse right now. */\n canCollapse(itemValue: string): boolean;\n /**\n * Focus a sibling trigger relative to the one currently focused. Disabled\n * triggers are skipped. `currentTrigger` is the element from which the\n * keyboard event originated. Navigation stays within this accordion's own\n * registered triggers, so a nested accordion does not cross-contaminate.\n */\n focusByOffset(currentTrigger: HTMLElement, action: ListNavigationAction): void;\n registerTrigger(handle: ForAccordionTriggerHandle): void;\n unregisterTrigger(handle: ForAccordionTriggerHandle): void;\n}\n\n/**\n * Per-item state contract. Provided by `ForAccordionItem`, consumed by\n * its `ForAccordionTrigger` and `ForAccordionContent`.\n */\nexport interface ForAccordionItemContext {\n readonly expanded: Signal<boolean>;\n readonly disabled: Signal<boolean>;\n readonly value: Signal<string>;\n readonly triggerId: Signal<string>;\n readonly contentId: Signal<string>;\n /** Adopts a consumer-set static `id` on the trigger host into `triggerId`. */\n adoptTriggerId(el: HTMLElement): void;\n /** Adopts a consumer-set static `id` on the content host into `contentId`. */\n adoptContentId(el: HTMLElement): void;\n toggle(): void;\n}\n\nexport const FOR_ACCORDION_CONTEXT = new InjectionToken<ForAccordionContext>(\n 'FOR_ACCORDION_CONTEXT',\n);\n\nexport const FOR_ACCORDION_ITEM_CONTEXT = new InjectionToken<ForAccordionItemContext>(\n 'FOR_ACCORDION_ITEM_CONTEXT',\n);\n\nexport function injectAccordionContext(piece: string): ForAccordionContext {\n const ctx = inject(FOR_ACCORDION_CONTEXT, { optional: true });\n if (!ctx) {\n throw new Error(`[forty-cdk/accordion] ${piece} must be used inside a [forAccordion] element.`);\n }\n return ctx;\n}\n\nexport function injectAccordionItemContext(piece: string): ForAccordionItemContext {\n const ctx = inject(FOR_ACCORDION_ITEM_CONTEXT, { optional: true });\n if (!ctx) {\n throw new Error(\n `[forty-cdk/accordion] ${piece} must be used inside a [forAccordionItem] element.`,\n );\n }\n return ctx;\n}\n","import { booleanAttribute, Directive, input, model } from '@angular/core';\n\nimport {\n Collection,\n type ListNavigationAction,\n moveIndex,\n type WritingDirection,\n injectTextDirection,\n} from 'forty-cdk/core';\nimport {\n FOR_ACCORDION_CONTEXT,\n type ForAccordionContext,\n type ForAccordionTriggerHandle,\n} from './accordion-context';\n\n/**\n * Root of the Accordion primitive. Holds the open value(s) and orchestrates\n * single/multiple expansion, collapse rules, and keyboard navigation between\n * triggers.\n *\n * Implements the [WAI-ARIA Accordion pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/).\n *\n * State is modeled as `value: readonly string[]` regardless of mode:\n * - In single mode (`multiple=false`, default), the array has 0 or 1 element.\n * - In multiple mode, any number of items can be open.\n *\n * @example\n * ```html\n * <div forAccordion [(value)]=\"open\" collapsible>\n * <div forAccordionItem value=\"a\">\n * <h3><button type=\"button\" forAccordionTrigger>A</button></h3>\n * <section forAccordionContent>...</section>\n * </div>\n * <div forAccordionItem value=\"b\">...</div>\n * </div>\n * ```\n */\n@Directive({\n selector: '[forAccordion]',\n exportAs: 'forAccordion',\n host: {\n '[attr.data-orientation]': 'orientation()',\n '[attr.data-disabled]': 'disabled() ? \"\" : null',\n '[attr.dir]': 'dir()',\n },\n providers: [{ provide: FOR_ACCORDION_CONTEXT, useExisting: ForAccordion }],\n})\nexport class ForAccordion implements ForAccordionContext {\n readonly #triggers = new Collection<ForAccordionTriggerHandle>();\n\n /** When true, multiple items can be expanded simultaneously. */\n readonly multiple = input(false, { transform: booleanAttribute });\n\n /**\n * When true, the whole accordion is disabled: every item's trigger reflects\n * the native `disabled` attribute (dropped from the Tab order and skipped by\n * arrow-key navigation) and cannot toggle. Composes with a per-item\n * `[disabled]` — an item is effectively disabled when either is set. Mirrors\n * the root `disabled` on `ForTabs` / `ForStepper` / `ForDisclosure`.\n */\n readonly disabled = input(false, { transform: booleanAttribute });\n\n /**\n * Single mode only: when true, the open item can be collapsed by clicking\n * its trigger. When false, exactly one item stays open at all times once\n * any has been opened.\n */\n readonly collapsible = input(false, { transform: booleanAttribute });\n\n /**\n * Layout direction of the trigger list. `'vertical'` (default) maps\n * ArrowUp/Down to prev/next; `'horizontal'` maps ArrowLeft/Right (with RTL\n * swap when `dir='rtl'`).\n */\n readonly orientation = input<'horizontal' | 'vertical'>('vertical');\n\n /**\n * Writing direction. Only relevant when `orientation='horizontal'`. When\n * unset (default `null`), the inherited ambient direction is resolved from\n * the nearest ancestor carrying a `dir` attribute (or `<html dir>`),\n * defaulting to `'ltr'`. An explicit `[dir]` always wins. The resolved\n * value is reflected to the host `dir` attribute and drives arrow-key\n * semantics.\n */\n readonly _dirInput = input<WritingDirection | null>(null, { alias: 'dir' });\n readonly dir = injectTextDirection(this._dirInput);\n\n /**\n * When true (default), arrow navigation between triggers wraps at the ends —\n * moving past the last trigger focuses the first and vice versa. Set `false`\n * to stop at the boundaries. Mirrors the `loop` input on `ForTabs` and\n * `ForListbox`.\n */\n readonly loop = input(true, { transform: booleanAttribute });\n\n /**\n * Two-way bindable. List of currently expanded item values. In single\n * mode the array has 0 or 1 element. The `model()` change emitter\n * (`(valueChange)`) fires only on internal toggles, never on consumer\n * writes via `[(value)]` — observe transitions without binding back.\n */\n readonly value = model<readonly string[]>([]);\n\n isExpanded(itemValue: string): boolean {\n return this.value().includes(itemValue);\n }\n\n toggle(itemValue: string): void {\n const current = this.value();\n const isOpen = current.includes(itemValue);\n\n if (isOpen) {\n if (!this.canCollapse(itemValue)) {\n return;\n }\n this.value.set(current.filter((v) => v !== itemValue));\n return;\n }\n\n if (this.multiple()) {\n this.value.set([...current, itemValue]);\n } else {\n this.value.set([itemValue]);\n }\n }\n\n canCollapse(_itemValue: string): boolean {\n return this.multiple() || this.collapsible();\n }\n\n focusByOffset(currentTrigger: HTMLElement, action: ListNavigationAction): void {\n const triggers = this.#triggers.items();\n if (triggers.length === 0) {\n return;\n }\n const currentIndex = triggers.findIndex((t) => t.host === currentTrigger);\n if (currentIndex === -1 && action !== 'first' && action !== 'last') {\n return;\n }\n const next = moveIndex(currentIndex < 0 ? 0 : currentIndex, triggers.length, action, {\n loop: this.loop(),\n isDisabled: (i) => triggers[i]?.disabled() ?? false,\n });\n if (next !== null) {\n triggers[next]?.host.focus();\n }\n }\n\n registerTrigger(handle: ForAccordionTriggerHandle): void {\n this.#triggers.register(handle);\n }\n\n unregisterTrigger(handle: ForAccordionTriggerHandle): void {\n this.#triggers.unregister(handle);\n }\n}\n","import { booleanAttribute, computed, Directive, inject, input, signal } from '@angular/core';\n\nimport { adoptHostId, IdGenerator } from 'forty-cdk/core';\nimport {\n FOR_ACCORDION_ITEM_CONTEXT,\n type ForAccordionItemContext,\n injectAccordionContext,\n} from './accordion-context';\n\n/**\n * One section of a `ForAccordion`. Owns the unique `value` identifying this\n * item to the root and exposes the per-item context that the trigger and\n * content read.\n */\n@Directive({\n selector: '[forAccordionItem]',\n exportAs: 'forAccordionItem',\n host: {\n '[attr.data-state]': 'expanded() ? \"open\" : \"closed\"',\n '[attr.data-disabled]': 'disabled() ? \"\" : null',\n '[attr.data-orientation]': 'parent.orientation()',\n },\n providers: [{ provide: FOR_ACCORDION_ITEM_CONTEXT, useExisting: ForAccordionItem }],\n})\nexport class ForAccordionItem implements ForAccordionItemContext {\n protected readonly parent = injectAccordionContext('ForAccordionItem');\n readonly #idGen = inject(IdGenerator);\n\n /** Unique identifier of this item within the accordion. Required. */\n readonly value = input.required<string>();\n\n /**\n * When true, this item's trigger ignores clicks and reflects the native\n * `disabled` attribute (not `aria-disabled`): dropped from the Tab order and\n * skipped by arrow-key navigation, but kept in the accessibility tree so\n * screen readers still announce it. See `ForAccordionTrigger` for the\n * rationale (rule #561 D2). Bind via `[disabled]`; read the composed\n * {@link disabled} for state.\n */\n readonly disabledInput = input(false, { transform: booleanAttribute, alias: 'disabled' });\n\n /**\n * Effective disabled: this item's own `[disabled]` OR'd with the root\n * `[forAccordion]`'s `disabled`. Everything that gates on the item's disabled\n * state — native attribute reflection, trigger click, arrow-navigation skip,\n * `data-disabled` — reads this, so disabling the whole accordion disables\n * every item.\n */\n readonly disabled = computed(() => this.disabledInput() || this.parent.disabled());\n\n readonly #triggerId = signal(this.#idGen.next('for-accordion-trigger'));\n readonly #contentId = signal(this.#idGen.next('for-accordion-content'));\n\n readonly triggerId = this.#triggerId.asReadonly();\n readonly contentId = this.#contentId.asReadonly();\n\n readonly expanded = computed(() => this.parent.isExpanded(this.value()));\n\n /**\n * Adopts a consumer-set static `id` on the `[forAccordionTrigger]` host into\n * `triggerId` (preserving anchors / external `aria-labelledby` references /\n * label `for`) instead of letting the `[id]` host binding clobber it.\n */\n adoptTriggerId(el: HTMLElement): void {\n adoptHostId(el, this.#triggerId);\n }\n\n /** Adopts a consumer-set static `id` on the content host into `contentId`. */\n adoptContentId(el: HTMLElement): void {\n adoptHostId(el, this.#contentId);\n }\n\n toggle(): void {\n if (this.disabled()) {\n return;\n }\n this.parent.toggle(this.value());\n }\n}\n","import { computed, Directive, ElementRef, inject } from '@angular/core';\n\nimport { registerHandle, reflectDisabled, resolveListNavigation } from 'forty-cdk/core';\nimport { injectAccordionContext, injectAccordionItemContext } from './accordion-context';\n\n/**\n * Header button for a `ForAccordionItem`. Apply on a `<button>` wrapped in a\n * heading element (`<h2>`–`<h6>`) so APG landmark navigation works. The\n * directive host-binds `type=\"button\"` so a trigger inside a `<form>` never\n * submits it on toggle.\n *\n * Handles ARIA wiring, click-to-toggle, and the recommended keyboard\n * navigation (ArrowDown / ArrowUp / Home / End).\n *\n * `aria-controls` is emitted only while the item is expanded — mirroring the\n * overlay triggers' open-only gating — so the reference never dangles at an\n * unmounted panel under the recommended `@if (item.expanded())` mount pattern.\n */\n@Directive({\n selector: '[forAccordionTrigger]',\n exportAs: 'forAccordionTrigger',\n host: {\n type: 'button',\n '[id]': 'item.triggerId()',\n '[attr.aria-expanded]': 'item.expanded() ? \"true\" : \"false\"',\n '[attr.aria-controls]': 'item.expanded() ? item.contentId() : null',\n '[attr.aria-disabled]': 'ariaDisabled() ? \"true\" : null',\n '[attr.data-state]': 'item.expanded() ? \"open\" : \"closed\"',\n '[attr.data-orientation]': 'parent.orientation()',\n '(click)': 'item.toggle()',\n '(keydown)': 'onKeyDown($event)',\n },\n})\nexport class ForAccordionTrigger {\n readonly #host = inject<ElementRef<HTMLElement>>(ElementRef);\n protected readonly parent = injectAccordionContext('ForAccordionTrigger');\n protected readonly item = injectAccordionItemContext('ForAccordionTrigger');\n\n /**\n * APG: aria-disabled is true only when the panel is open AND the accordion\n * disallows collapse. A real `disabled` item is reflected via the native\n * `disabled` attribute instead — the sanctioned exception in rule #561 (D2):\n * the trigger is a real single-purpose `<button>`, not a roving collection\n * item (every trigger stays independently in the Tab order; the arrow-key\n * navigation is an APG-optional enhancement layered on top, not a\n * roving-tabindex collection), so native `disabled` is correct here. The\n * button stays in the accessibility tree — screen readers still announce it\n * as unavailable in browse mode — while being dropped from the Tab order and\n * the arrow-key navigation (which `focusByOffset` already skips), keeping\n * disabled triggers uniformly unreachable. The APG Accordion pattern does not\n * require disabled headers to remain focusable.\n */\n protected readonly ariaDisabled = computed(() => {\n if (this.item.disabled()) {\n return false;\n }\n return this.item.expanded() && !this.parent.canCollapse(this.item.value());\n });\n\n constructor() {\n this.item.adoptTriggerId(this.#host.nativeElement);\n const handle = {\n host: this.#host.nativeElement,\n disabled: this.item.disabled,\n };\n registerHandle(\n handle,\n (h) => this.parent.registerTrigger(h),\n (h) => this.parent.unregisterTrigger(h),\n );\n reflectDisabled(this.item.disabled);\n }\n\n protected onKeyDown(event: KeyboardEvent): void {\n const action = resolveListNavigation(event, {\n orientation: this.parent.orientation(),\n dir: this.parent.dir(),\n });\n if (!action) {\n return;\n }\n event.preventDefault();\n this.parent.focusByOffset(this.#host.nativeElement, action);\n }\n}\n","import { Directive, ElementRef, inject } from '@angular/core';\n\nimport { injectAccordionContext, injectAccordionItemContext } from './accordion-context';\n\n/**\n * Panel revealed by a `ForAccordionTrigger`. The directive does not manage\n * DOM presence — wrap with `@if (item.expanded())` so panels mount and\n * unmount with the expanded state and `animate.enter` / `animate.leave`\n * work natively. If the consumer prefers to keep the panel mounted (for\n * CSS-only transitions or to preserve internal state), the directive\n * reflects `aria-hidden=\"true\"` and `inert` while closed so the panel is\n * removed from the accessibility tree and focus order automatically.\n *\n * APG note: `role=\"region\"` adds the panel to the landmark navigation tree.\n * If the accordion has 6+ simultaneously expandable panels, consider not\n * using region — the directive will gain an opt-out input when this comes up\n * in real usage.\n */\n@Directive({\n selector: '[forAccordionContent]',\n exportAs: 'forAccordionContent',\n host: {\n '[id]': 'item.contentId()',\n '[attr.role]': '\"region\"',\n '[attr.aria-labelledby]': 'item.triggerId()',\n '[attr.aria-hidden]': 'item.expanded() ? null : \"true\"',\n '[attr.inert]': 'item.expanded() ? null : \"\"',\n '[attr.data-state]': 'item.expanded() ? \"open\" : \"closed\"',\n '[attr.data-orientation]': 'parent.orientation()',\n },\n})\nexport class ForAccordionContent {\n protected readonly parent = injectAccordionContext('ForAccordionContent');\n protected readonly item = injectAccordionItemContext('ForAccordionContent');\n\n constructor() {\n this.item.adoptContentId(inject<ElementRef<HTMLElement>>(ElementRef).nativeElement);\n }\n}\n","import { type Provider } from '@angular/core';\n\nimport { createDefaults } from 'forty-cdk/core';\n\n/**\n * Defaults inherited by descendant accordions in the surrounding injector\n * scope. Configure with `provideForAccordionDefaults`. The shape is a stub\n * today — present so future per-scope tuning can land without churning the\n * public surface.\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface ForAccordionDefaults {}\n\nconst FALLBACK: ForAccordionDefaults = {};\n\nconst { token, provideDefaults } = createDefaults<ForAccordionDefaults>(\n 'FOR_ACCORDION_DEFAULTS',\n FALLBACK,\n);\n\n/** Token holding the resolved accordion defaults for the current scope. */\nexport const FOR_ACCORDION_DEFAULTS = token;\n\n/**\n * Configures forty-cdk accordion defaults for this injector scope. Partial\n * overrides inherit unspecified keys from the parent scope (or library\n * defaults at the root).\n */\nexport function provideForAccordionDefaults(\n defaults: Partial<ForAccordionDefaults> = {},\n): Provider[] {\n return provideDefaults(defaults);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;MA0Da,qBAAqB,GAAG,IAAI,cAAc,CACrD,uBAAuB;MAGZ,0BAA0B,GAAG,IAAI,cAAc,CAC1D,4BAA4B;AAGxB,SAAU,sBAAsB,CAAC,KAAa,EAAA;AAClD,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,qBAAqB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC7D,IAAI,CAAC,GAAG,EAAE;AACR,QAAA,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,CAAA,8CAAA,CAAgD,CAAC;IACjG;AACA,IAAA,OAAO,GAAG;AACZ;AAEM,SAAU,0BAA0B,CAAC,KAAa,EAAA;AACtD,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,0BAA0B,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAClE,IAAI,CAAC,GAAG,EAAE;AACR,QAAA,MAAM,IAAI,KAAK,CACb,yBAAyB,KAAK,CAAA,kDAAA,CAAoD,CACnF;IACH;AACA,IAAA,OAAO,GAAG;AACZ;;ACnEA;;;;;;;;;;;;;;;;;;;;;AAqBG;MAWU,YAAY,CAAA;AACd,IAAA,SAAS,GAAG,IAAI,UAAU,EAA6B;;IAGvD,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAEjE;;;;;;AAMG;IACM,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAEjE;;;;AAIG;IACM,WAAW,GAAG,KAAK,CAAC,KAAK,mFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAEpE;;;;AAIG;IACM,WAAW,GAAG,KAAK,CAA4B,UAAU;oFAAC;AAEnE;;;;;;;AAOG;IACM,SAAS,GAAG,KAAK,CAA0B,IAAI,iFAAI,KAAK,EAAE,KAAK,EAAA,CAAG;AAClE,IAAA,GAAG,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC;AAElD;;;;;AAKG;IACM,IAAI,GAAG,KAAK,CAAC,IAAI,4EAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAE5D;;;;;AAKG;IACM,KAAK,GAAG,KAAK,CAAoB,EAAE;8EAAC;AAE7C,IAAA,UAAU,CAAC,SAAiB,EAAA;QAC1B,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;IACzC;AAEA,IAAA,MAAM,CAAC,SAAiB,EAAA;AACtB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE;QAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;QAE1C,IAAI,MAAM,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE;gBAChC;YACF;AACA,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC;YACtD;QACF;AAEA,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACnB,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,CAAC,CAAC;QACzC;aAAO;YACL,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QAC7B;IACF;AAEA,IAAA,WAAW,CAAC,UAAkB,EAAA;QAC5B,OAAO,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,WAAW,EAAE;IAC9C;IAEA,aAAa,CAAC,cAA2B,EAAE,MAA4B,EAAA;QACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;AACvC,QAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;YACzB;QACF;AACA,QAAA,MAAM,YAAY,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC;AACzE,QAAA,IAAI,YAAY,KAAK,CAAC,CAAC,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,MAAM,EAAE;YAClE;QACF;QACA,MAAM,IAAI,GAAG,SAAS,CAAC,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE;AACnF,YAAA,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;AACjB,YAAA,UAAU,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,KAAK;AACpD,SAAA,CAAC;AACF,QAAA,IAAI,IAAI,KAAK,IAAI,EAAE;YACjB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE;QAC9B;IACF;AAEA,IAAA,eAAe,CAAC,MAAiC,EAAA;AAC/C,QAAA,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;IACjC;AAEA,IAAA,iBAAiB,CAAC,MAAiC,EAAA;AACjD,QAAA,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC;IACnC;uGA3GW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAZ,YAAY,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,KAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,KAAA,EAAA,aAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,uBAAA,EAAA,eAAA,EAAA,oBAAA,EAAA,0BAAA,EAAA,UAAA,EAAA,OAAA,EAAA,EAAA,EAAA,SAAA,EAFZ,CAAC,EAAE,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC,EAAA,QAAA,EAAA,CAAA,cAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAE/D,YAAY,EAAA,UAAA,EAAA,CAAA;kBAVxB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,gBAAgB;AAC1B,oBAAA,QAAQ,EAAE,cAAc;AACxB,oBAAA,IAAI,EAAE;AACJ,wBAAA,yBAAyB,EAAE,eAAe;AAC1C,wBAAA,sBAAsB,EAAE,wBAAwB;AAChD,wBAAA,YAAY,EAAE,OAAO;AACtB,qBAAA;oBACD,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAA,YAAc,EAAE,CAAC;AAC3E,iBAAA;;;ACrCD;;;;AAIG;MAWU,gBAAgB,CAAA;AACR,IAAA,MAAM,GAAG,sBAAsB,CAAC,kBAAkB,CAAC;AAC7D,IAAA,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC;;IAG5B,KAAK,GAAG,KAAK,CAAC,QAAQ;8EAAU;AAEzC;;;;;;;AAOG;AACM,IAAA,aAAa,GAAG,KAAK,CAAC,KAAK,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,eAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,GAAG;AAEzF;;;;;;AAMG;AACM,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;iFAAC;IAEzE,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC;mFAAC;IAC9D,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC;mFAAC;AAE9D,IAAA,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE;AACxC,IAAA,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE;AAExC,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;iFAAC;AAExE;;;;AAIG;AACH,IAAA,cAAc,CAAC,EAAe,EAAA;AAC5B,QAAA,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC;IAClC;;AAGA,IAAA,cAAc,CAAC,EAAe,EAAA;AAC5B,QAAA,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC;IAClC;IAEA,MAAM,GAAA;AACJ,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB;QACF;QACA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAClC;uGArDW,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAhB,gBAAgB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,oCAAA,EAAA,oBAAA,EAAA,0BAAA,EAAA,uBAAA,EAAA,sBAAA,EAAA,EAAA,EAAA,SAAA,EAFhB,CAAC,EAAE,OAAO,EAAE,0BAA0B,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC,EAAA,QAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAExE,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAV5B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,oBAAoB;AAC9B,oBAAA,QAAQ,EAAE,kBAAkB;AAC5B,oBAAA,IAAI,EAAE;AACJ,wBAAA,mBAAmB,EAAE,gCAAgC;AACrD,wBAAA,sBAAsB,EAAE,wBAAwB;AAChD,wBAAA,yBAAyB,EAAE,sBAAsB;AAClD,qBAAA;oBACD,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,0BAA0B,EAAE,WAAW,EAAA,gBAAkB,EAAE,CAAC;AACpF,iBAAA;;;AClBD;;;;;;;;;;;;AAYG;MAgBU,mBAAmB,CAAA;AACrB,IAAA,KAAK,GAAG,MAAM,CAA0B,UAAU,CAAC;AACzC,IAAA,MAAM,GAAG,sBAAsB,CAAC,qBAAqB,CAAC;AACtD,IAAA,IAAI,GAAG,0BAA0B,CAAC,qBAAqB,CAAC;AAE3E;;;;;;;;;;;;;AAaG;AACgB,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;AAC9C,QAAA,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE;AACxB,YAAA,OAAO,KAAK;QACd;QACA,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC5E,CAAC;qFAAC;AAEF,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;AAClD,QAAA,MAAM,MAAM,GAAG;AACb,YAAA,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa;AAC9B,YAAA,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ;SAC7B;AACD,QAAA,cAAc,CACZ,MAAM,EACN,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,EACrC,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CACxC;AACD,QAAA,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;IACrC;AAEU,IAAA,SAAS,CAAC,KAAoB,EAAA;AACtC,QAAA,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,EAAE;AAC1C,YAAA,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;AACtC,YAAA,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE;AACvB,SAAA,CAAC;QACF,IAAI,CAAC,MAAM,EAAE;YACX;QACF;QACA,KAAK,CAAC,cAAc,EAAE;AACtB,QAAA,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC;IAC7D;uGAlDW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAnB,mBAAmB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,SAAA,EAAA,EAAA,OAAA,EAAA,eAAA,EAAA,SAAA,EAAA,mBAAA,EAAA,EAAA,UAAA,EAAA,EAAA,IAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,wCAAA,EAAA,oBAAA,EAAA,2CAAA,EAAA,oBAAA,EAAA,kCAAA,EAAA,iBAAA,EAAA,yCAAA,EAAA,uBAAA,EAAA,sBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAnB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAf/B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,uBAAuB;AACjC,oBAAA,QAAQ,EAAE,qBAAqB;AAC/B,oBAAA,IAAI,EAAE;AACJ,wBAAA,IAAI,EAAE,QAAQ;AACd,wBAAA,MAAM,EAAE,kBAAkB;AAC1B,wBAAA,sBAAsB,EAAE,oCAAoC;AAC5D,wBAAA,sBAAsB,EAAE,2CAA2C;AACnE,wBAAA,sBAAsB,EAAE,gCAAgC;AACxD,wBAAA,mBAAmB,EAAE,qCAAqC;AAC1D,wBAAA,yBAAyB,EAAE,sBAAsB;AACjD,wBAAA,SAAS,EAAE,eAAe;AAC1B,wBAAA,WAAW,EAAE,mBAAmB;AACjC,qBAAA;AACF,iBAAA;;;AC5BD;;;;;;;;;;;;;AAaG;MAcU,mBAAmB,CAAA;AACX,IAAA,MAAM,GAAG,sBAAsB,CAAC,qBAAqB,CAAC;AACtD,IAAA,IAAI,GAAG,0BAA0B,CAAC,qBAAqB,CAAC;AAE3E,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAA0B,UAAU,CAAC,CAAC,aAAa,CAAC;IACrF;uGANW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAnB,mBAAmB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,IAAA,EAAA,kBAAA,EAAA,WAAA,EAAA,YAAA,EAAA,sBAAA,EAAA,kBAAA,EAAA,kBAAA,EAAA,mCAAA,EAAA,YAAA,EAAA,+BAAA,EAAA,iBAAA,EAAA,yCAAA,EAAA,uBAAA,EAAA,sBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAnB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAb/B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,uBAAuB;AACjC,oBAAA,QAAQ,EAAE,qBAAqB;AAC/B,oBAAA,IAAI,EAAE;AACJ,wBAAA,MAAM,EAAE,kBAAkB;AAC1B,wBAAA,aAAa,EAAE,UAAU;AACzB,wBAAA,wBAAwB,EAAE,kBAAkB;AAC5C,wBAAA,oBAAoB,EAAE,iCAAiC;AACvD,wBAAA,cAAc,EAAE,6BAA6B;AAC7C,wBAAA,mBAAmB,EAAE,qCAAqC;AAC1D,wBAAA,yBAAyB,EAAE,sBAAsB;AAClD,qBAAA;AACF,iBAAA;;;ACjBD,MAAM,QAAQ,GAAyB,EAAE;AAEzC,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,cAAc,CAC/C,wBAAwB,EACxB,QAAQ,CACT;AAED;AACO,MAAM,sBAAsB,GAAG;AAEtC;;;;AAIG;AACG,SAAU,2BAA2B,CACzC,QAAA,GAA0C,EAAE,EAAA;AAE5C,IAAA,OAAO,eAAe,CAAC,QAAQ,CAAC;AAClC;;AChCA;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"forty-cdk-accordion.mjs","sources":["../../../projects/forty-cdk/accordion/src/accordion-context.ts","../../../projects/forty-cdk/accordion/src/accordion.ts","../../../projects/forty-cdk/accordion/src/accordion-item.ts","../../../projects/forty-cdk/accordion/src/accordion-trigger.ts","../../../projects/forty-cdk/accordion/src/accordion-content.ts","../../../projects/forty-cdk/accordion/src/forty-cdk-accordion.ts"],"sourcesContent":["import { inject, InjectionToken, type Signal } from '@angular/core';\n\nimport { type ListNavigationAction, type WritingDirection } from 'forty-cdk/core';\n\n/**\n * Registry entry for one `ForAccordionTrigger`. Triggers register their host\n * element so the root can drive keyboard navigation over its own triggers\n * without an unscoped DOM query that would leak into nested accordions.\n */\nexport interface ForAccordionTriggerHandle {\n readonly host: HTMLElement;\n readonly disabled: Signal<boolean>;\n}\n\n/**\n * Coordination contract owned by the `ForAccordion` root.\n * Items derive their state from this context; triggers route clicks and\n * keyboard navigation through it.\n */\nexport interface ForAccordionContext {\n readonly multiple: Signal<boolean>;\n readonly collapsible: Signal<boolean>;\n /** Whether the whole accordion is disabled; each item ORs this into its own disabled state. */\n readonly disabled: Signal<boolean>;\n readonly orientation: Signal<'horizontal' | 'vertical'>;\n readonly dir: Signal<WritingDirection>;\n isExpanded(itemValue: string): boolean;\n toggle(itemValue: string): void;\n /** Whether the given item is allowed to collapse right now. */\n canCollapse(itemValue: string): boolean;\n /**\n * Focus a sibling trigger relative to the one currently focused. Disabled\n * triggers are skipped. `currentTrigger` is the element from which the\n * keyboard event originated. Navigation stays within this accordion's own\n * registered triggers, so a nested accordion does not cross-contaminate.\n */\n focusByOffset(currentTrigger: HTMLElement, action: ListNavigationAction): void;\n registerTrigger(handle: ForAccordionTriggerHandle): void;\n unregisterTrigger(handle: ForAccordionTriggerHandle): void;\n}\n\n/**\n * Per-item state contract. Provided by `ForAccordionItem`, consumed by\n * its `ForAccordionTrigger` and `ForAccordionContent`.\n */\nexport interface ForAccordionItemContext {\n readonly expanded: Signal<boolean>;\n readonly disabled: Signal<boolean>;\n readonly value: Signal<string>;\n readonly triggerId: Signal<string>;\n readonly contentId: Signal<string>;\n /** Adopts a consumer-set static `id` on the trigger host into `triggerId`. */\n adoptTriggerId(el: HTMLElement): void;\n /** Adopts a consumer-set static `id` on the content host into `contentId`. */\n adoptContentId(el: HTMLElement): void;\n toggle(): void;\n}\n\nexport const FOR_ACCORDION_CONTEXT = new InjectionToken<ForAccordionContext>(\n 'FOR_ACCORDION_CONTEXT',\n);\n\nexport const FOR_ACCORDION_ITEM_CONTEXT = new InjectionToken<ForAccordionItemContext>(\n 'FOR_ACCORDION_ITEM_CONTEXT',\n);\n\nexport function injectAccordionContext(piece: string): ForAccordionContext {\n const ctx = inject(FOR_ACCORDION_CONTEXT, { optional: true });\n if (!ctx) {\n throw new Error(`[forty-cdk/accordion] ${piece} must be used inside a [forAccordion] element.`);\n }\n return ctx;\n}\n\nexport function injectAccordionItemContext(piece: string): ForAccordionItemContext {\n const ctx = inject(FOR_ACCORDION_ITEM_CONTEXT, { optional: true });\n if (!ctx) {\n throw new Error(\n `[forty-cdk/accordion] ${piece} must be used inside a [forAccordionItem] element.`,\n );\n }\n return ctx;\n}\n","import { booleanAttribute, Directive, input, model } from '@angular/core';\n\nimport {\n Collection,\n type ListNavigationAction,\n moveIndex,\n type WritingDirection,\n injectTextDirection,\n} from 'forty-cdk/core';\nimport {\n FOR_ACCORDION_CONTEXT,\n type ForAccordionContext,\n type ForAccordionTriggerHandle,\n} from './accordion-context';\n\n/**\n * Root of the Accordion primitive. Holds the open value(s) and orchestrates\n * single/multiple expansion, collapse rules, and keyboard navigation between\n * triggers.\n *\n * Implements the [WAI-ARIA Accordion pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/).\n *\n * State is modeled as `value: readonly string[]` regardless of mode:\n * - In single mode (`multiple=false`, default), the array has 0 or 1 element.\n * - In multiple mode, any number of items can be open.\n *\n * @example\n * ```html\n * <div forAccordion [(value)]=\"open\" collapsible>\n * <div forAccordionItem value=\"a\">\n * <h3><button type=\"button\" forAccordionTrigger>A</button></h3>\n * <section forAccordionContent>...</section>\n * </div>\n * <div forAccordionItem value=\"b\">...</div>\n * </div>\n * ```\n */\n@Directive({\n selector: '[forAccordion]',\n exportAs: 'forAccordion',\n host: {\n '[attr.data-orientation]': 'orientation()',\n '[attr.data-disabled]': 'disabled() ? \"\" : null',\n '[attr.dir]': 'dir()',\n },\n providers: [{ provide: FOR_ACCORDION_CONTEXT, useExisting: ForAccordion }],\n})\nexport class ForAccordion implements ForAccordionContext {\n readonly #triggers = new Collection<ForAccordionTriggerHandle>();\n\n /** When true, multiple items can be expanded simultaneously. */\n readonly multiple = input(false, { transform: booleanAttribute });\n\n /**\n * When true, the whole accordion is disabled: every item's trigger reflects\n * the native `disabled` attribute (dropped from the Tab order and skipped by\n * arrow-key navigation) and cannot toggle. Composes with a per-item\n * `[disabled]` — an item is effectively disabled when either is set. Mirrors\n * the root `disabled` on `ForTabs` / `ForStepper` / `ForDisclosure`.\n */\n readonly disabled = input(false, { transform: booleanAttribute });\n\n /**\n * Single mode only: when true, the open item can be collapsed by clicking\n * its trigger. When false, exactly one item stays open at all times once\n * any has been opened.\n */\n readonly collapsible = input(false, { transform: booleanAttribute });\n\n /**\n * Layout direction of the trigger list. `'vertical'` (default) maps\n * ArrowUp/Down to prev/next; `'horizontal'` maps ArrowLeft/Right (with RTL\n * swap when `dir='rtl'`).\n */\n readonly orientation = input<'horizontal' | 'vertical'>('vertical');\n\n /**\n * Writing direction. Only relevant when `orientation='horizontal'`. When\n * unset (default `null`), the inherited ambient direction is resolved from\n * the nearest ancestor carrying a `dir` attribute (or `<html dir>`),\n * defaulting to `'ltr'`. An explicit `[dir]` always wins. The resolved\n * value is reflected to the host `dir` attribute and drives arrow-key\n * semantics.\n */\n readonly _dirInput = input<WritingDirection | null>(null, { alias: 'dir' });\n readonly dir = injectTextDirection(this._dirInput);\n\n /**\n * When true (default), arrow navigation between triggers wraps at the ends —\n * moving past the last trigger focuses the first and vice versa. Set `false`\n * to stop at the boundaries. Mirrors the `loop` input on `ForTabs` and\n * `ForListbox`.\n */\n readonly loop = input(true, { transform: booleanAttribute });\n\n /**\n * Two-way bindable. List of currently expanded item values. In single\n * mode the array has 0 or 1 element. The `model()` change emitter\n * (`(valueChange)`) fires only on internal toggles, never on consumer\n * writes via `[(value)]` — observe transitions without binding back.\n */\n readonly value = model<readonly string[]>([]);\n\n isExpanded(itemValue: string): boolean {\n return this.value().includes(itemValue);\n }\n\n toggle(itemValue: string): void {\n const current = this.value();\n const isOpen = current.includes(itemValue);\n\n if (isOpen) {\n if (!this.canCollapse(itemValue)) {\n return;\n }\n this.value.set(current.filter((v) => v !== itemValue));\n return;\n }\n\n if (this.multiple()) {\n this.value.set([...current, itemValue]);\n } else {\n this.value.set([itemValue]);\n }\n }\n\n canCollapse(_itemValue: string): boolean {\n return this.multiple() || this.collapsible();\n }\n\n focusByOffset(currentTrigger: HTMLElement, action: ListNavigationAction): void {\n const triggers = this.#triggers.items();\n if (triggers.length === 0) {\n return;\n }\n const currentIndex = triggers.findIndex((t) => t.host === currentTrigger);\n if (currentIndex === -1 && action !== 'first' && action !== 'last') {\n return;\n }\n const next = moveIndex(currentIndex < 0 ? 0 : currentIndex, triggers.length, action, {\n loop: this.loop(),\n isDisabled: (i) => triggers[i]?.disabled() ?? false,\n });\n if (next !== null) {\n triggers[next]?.host.focus();\n }\n }\n\n registerTrigger(handle: ForAccordionTriggerHandle): void {\n this.#triggers.register(handle);\n }\n\n unregisterTrigger(handle: ForAccordionTriggerHandle): void {\n this.#triggers.unregister(handle);\n }\n}\n","import { booleanAttribute, computed, Directive, inject, input, signal } from '@angular/core';\n\nimport { adoptHostId, IdGenerator } from 'forty-cdk/core';\nimport {\n FOR_ACCORDION_ITEM_CONTEXT,\n type ForAccordionItemContext,\n injectAccordionContext,\n} from './accordion-context';\n\n/**\n * One section of a `ForAccordion`. Owns the unique `value` identifying this\n * item to the root and exposes the per-item context that the trigger and\n * content read.\n */\n@Directive({\n selector: '[forAccordionItem]',\n exportAs: 'forAccordionItem',\n host: {\n '[attr.data-state]': 'expanded() ? \"open\" : \"closed\"',\n '[attr.data-disabled]': 'disabled() ? \"\" : null',\n '[attr.data-orientation]': 'parent.orientation()',\n },\n providers: [{ provide: FOR_ACCORDION_ITEM_CONTEXT, useExisting: ForAccordionItem }],\n})\nexport class ForAccordionItem implements ForAccordionItemContext {\n protected readonly parent = injectAccordionContext('ForAccordionItem');\n readonly #idGen = inject(IdGenerator);\n\n /** Unique identifier of this item within the accordion. Required. */\n readonly value = input.required<string>();\n\n /**\n * When true, this item's trigger ignores clicks and reflects the native\n * `disabled` attribute (not `aria-disabled`): dropped from the Tab order and\n * skipped by arrow-key navigation, but kept in the accessibility tree so\n * screen readers still announce it. See `ForAccordionTrigger` for the\n * rationale (rule #561 D2). Bind via `[disabled]`; read the composed\n * {@link disabled} for state.\n */\n readonly disabledInput = input(false, { transform: booleanAttribute, alias: 'disabled' });\n\n /**\n * Effective disabled: this item's own `[disabled]` OR'd with the root\n * `[forAccordion]`'s `disabled`. Everything that gates on the item's disabled\n * state — native attribute reflection, trigger click, arrow-navigation skip,\n * `data-disabled` — reads this, so disabling the whole accordion disables\n * every item.\n */\n readonly disabled = computed(() => this.disabledInput() || this.parent.disabled());\n\n readonly #triggerId = signal(this.#idGen.next('for-accordion-trigger'));\n readonly #contentId = signal(this.#idGen.next('for-accordion-content'));\n\n readonly triggerId = this.#triggerId.asReadonly();\n readonly contentId = this.#contentId.asReadonly();\n\n readonly expanded = computed(() => this.parent.isExpanded(this.value()));\n\n /**\n * Adopts a consumer-set static `id` on the `[forAccordionTrigger]` host into\n * `triggerId` (preserving anchors / external `aria-labelledby` references /\n * label `for`) instead of letting the `[id]` host binding clobber it.\n */\n adoptTriggerId(el: HTMLElement): void {\n adoptHostId(el, this.#triggerId);\n }\n\n /** Adopts a consumer-set static `id` on the content host into `contentId`. */\n adoptContentId(el: HTMLElement): void {\n adoptHostId(el, this.#contentId);\n }\n\n toggle(): void {\n if (this.disabled()) {\n return;\n }\n this.parent.toggle(this.value());\n }\n}\n","import { computed, Directive, ElementRef, inject } from '@angular/core';\n\nimport { registerHandle, reflectDisabled, resolveListNavigation } from 'forty-cdk/core';\nimport { injectAccordionContext, injectAccordionItemContext } from './accordion-context';\n\n/**\n * Header button for a `ForAccordionItem`. Apply on a `<button>` wrapped in a\n * heading element (`<h2>`–`<h6>`) so APG landmark navigation works. The\n * directive host-binds `type=\"button\"` so a trigger inside a `<form>` never\n * submits it on toggle.\n *\n * Handles ARIA wiring, click-to-toggle, and the recommended keyboard\n * navigation (ArrowDown / ArrowUp / Home / End).\n *\n * `aria-controls` is emitted only while the item is expanded — mirroring the\n * overlay triggers' open-only gating — so the reference never dangles at an\n * unmounted panel under the recommended `@if (item.expanded())` mount pattern.\n */\n@Directive({\n selector: '[forAccordionTrigger]',\n exportAs: 'forAccordionTrigger',\n host: {\n type: 'button',\n '[id]': 'item.triggerId()',\n '[attr.aria-expanded]': 'item.expanded() ? \"true\" : \"false\"',\n '[attr.aria-controls]': 'item.expanded() ? item.contentId() : null',\n '[attr.aria-disabled]': 'ariaDisabled() ? \"true\" : null',\n '[attr.data-state]': 'item.expanded() ? \"open\" : \"closed\"',\n '[attr.data-orientation]': 'parent.orientation()',\n '(click)': 'item.toggle()',\n '(keydown)': 'onKeyDown($event)',\n },\n})\nexport class ForAccordionTrigger {\n readonly #host = inject<ElementRef<HTMLElement>>(ElementRef);\n protected readonly parent = injectAccordionContext('ForAccordionTrigger');\n protected readonly item = injectAccordionItemContext('ForAccordionTrigger');\n\n /**\n * APG: aria-disabled is true only when the panel is open AND the accordion\n * disallows collapse. A real `disabled` item is reflected via the native\n * `disabled` attribute instead — the sanctioned exception in rule #561 (D2):\n * the trigger is a real single-purpose `<button>`, not a roving collection\n * item (every trigger stays independently in the Tab order; the arrow-key\n * navigation is an APG-optional enhancement layered on top, not a\n * roving-tabindex collection), so native `disabled` is correct here. The\n * button stays in the accessibility tree — screen readers still announce it\n * as unavailable in browse mode — while being dropped from the Tab order and\n * the arrow-key navigation (which `focusByOffset` already skips), keeping\n * disabled triggers uniformly unreachable. The APG Accordion pattern does not\n * require disabled headers to remain focusable.\n */\n protected readonly ariaDisabled = computed(() => {\n if (this.item.disabled()) {\n return false;\n }\n return this.item.expanded() && !this.parent.canCollapse(this.item.value());\n });\n\n constructor() {\n this.item.adoptTriggerId(this.#host.nativeElement);\n const handle = {\n host: this.#host.nativeElement,\n disabled: this.item.disabled,\n };\n registerHandle(\n handle,\n (h) => this.parent.registerTrigger(h),\n (h) => this.parent.unregisterTrigger(h),\n );\n reflectDisabled(this.item.disabled);\n }\n\n protected onKeyDown(event: KeyboardEvent): void {\n const action = resolveListNavigation(event, {\n orientation: this.parent.orientation(),\n dir: this.parent.dir(),\n });\n if (!action) {\n return;\n }\n event.preventDefault();\n this.parent.focusByOffset(this.#host.nativeElement, action);\n }\n}\n","import { Directive, ElementRef, inject } from '@angular/core';\n\nimport { injectAccordionContext, injectAccordionItemContext } from './accordion-context';\n\n/**\n * Panel revealed by a `ForAccordionTrigger`. The directive does not manage\n * DOM presence — wrap with `@if (item.expanded())` so panels mount and\n * unmount with the expanded state and `animate.enter` / `animate.leave`\n * work natively. If the consumer prefers to keep the panel mounted (for\n * CSS-only transitions or to preserve internal state), the directive\n * reflects `aria-hidden=\"true\"` and `inert` while closed so the panel is\n * removed from the accessibility tree and focus order automatically.\n *\n * APG note: `role=\"region\"` adds the panel to the landmark navigation tree.\n * If the accordion has 6+ simultaneously expandable panels, consider not\n * using region — the directive will gain an opt-out input when this comes up\n * in real usage.\n */\n@Directive({\n selector: '[forAccordionContent]',\n exportAs: 'forAccordionContent',\n host: {\n '[id]': 'item.contentId()',\n '[attr.role]': '\"region\"',\n '[attr.aria-labelledby]': 'item.triggerId()',\n '[attr.aria-hidden]': 'item.expanded() ? null : \"true\"',\n '[attr.inert]': 'item.expanded() ? null : \"\"',\n '[attr.data-state]': 'item.expanded() ? \"open\" : \"closed\"',\n '[attr.data-orientation]': 'parent.orientation()',\n },\n})\nexport class ForAccordionContent {\n protected readonly parent = injectAccordionContext('ForAccordionContent');\n protected readonly item = injectAccordionItemContext('ForAccordionContent');\n\n constructor() {\n this.item.adoptContentId(inject<ElementRef<HTMLElement>>(ElementRef).nativeElement);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { input, numberAttribute, computed, Directive } from '@angular/core';
|
|
3
|
-
import { createDefaults } from 'forty-cdk/core';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Headless aspect-ratio container. Locks the host element's box to a fixed
|
|
@@ -11,6 +10,16 @@ import { createDefaults } from 'forty-cdk/core';
|
|
|
11
10
|
* The directive only writes the `aspect-ratio` style; sizing rules (width,
|
|
12
11
|
* max-width, background, etc.) stay with the consumer.
|
|
13
12
|
*
|
|
13
|
+
* This ships as a dedicated primitive — rather than leaving consumers to write
|
|
14
|
+
* a static `aspect-ratio` CSS declaration — because it is more than one line of
|
|
15
|
+
* CSS: it exposes a reactive `ratio` input that recomputes as the value
|
|
16
|
+
* changes, guards `0` / negative / non-finite ratios so the host never emits
|
|
17
|
+
* invalid CSS, is SSR-safe (the style is bound, never touched imperatively),
|
|
18
|
+
* and offers the same headless API shape as the other primitives. Consumers who
|
|
19
|
+
* only need a fixed, never-changing ratio can skip it and set the native CSS
|
|
20
|
+
* `aspect-ratio` property directly; reach for `[forAspectRatio]` when the ratio
|
|
21
|
+
* is dynamic or must be validated.
|
|
22
|
+
*
|
|
14
23
|
* @example
|
|
15
24
|
* ```html
|
|
16
25
|
* <div forAspectRatio [ratio]="16 / 9">
|
|
@@ -53,22 +62,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
53
62
|
}]
|
|
54
63
|
}], propDecorators: { ratio: [{ type: i0.Input, args: [{ isSignal: true, alias: "ratio", required: false }] }] } });
|
|
55
64
|
|
|
56
|
-
const FALLBACK = {};
|
|
57
|
-
const { token, provideDefaults } = createDefaults('FOR_ASPECT_RATIO_DEFAULTS', FALLBACK);
|
|
58
|
-
/** Token holding the resolved aspect-ratio defaults for the current scope. */
|
|
59
|
-
const FOR_ASPECT_RATIO_DEFAULTS = token;
|
|
60
|
-
/**
|
|
61
|
-
* Configures forty-cdk aspect-ratio defaults for this injector scope. Partial
|
|
62
|
-
* overrides inherit unspecified keys from the parent scope (or library
|
|
63
|
-
* defaults at the root).
|
|
64
|
-
*/
|
|
65
|
-
function provideForAspectRatioDefaults(defaults = {}) {
|
|
66
|
-
return provideDefaults(defaults);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
65
|
/**
|
|
70
66
|
* Generated bundle index. Do not edit.
|
|
71
67
|
*/
|
|
72
68
|
|
|
73
|
-
export {
|
|
69
|
+
export { ForAspectRatio };
|
|
74
70
|
//# sourceMappingURL=forty-cdk-aspect-ratio.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forty-cdk-aspect-ratio.mjs","sources":["../../../projects/forty-cdk/aspect-ratio/src/aspect-ratio.ts","../../../projects/forty-cdk/aspect-ratio/src/
|
|
1
|
+
{"version":3,"file":"forty-cdk-aspect-ratio.mjs","sources":["../../../projects/forty-cdk/aspect-ratio/src/aspect-ratio.ts","../../../projects/forty-cdk/aspect-ratio/src/forty-cdk-aspect-ratio.ts"],"sourcesContent":["import { Directive, computed, input, numberAttribute } from '@angular/core';\n\n/**\n * Headless aspect-ratio container. Locks the host element's box to a fixed\n * `width / height` ratio via the native CSS `aspect-ratio` property — useful\n * for media (video, image, iframe) and skeletons that must reserve space\n * before content loads.\n *\n * The directive only writes the `aspect-ratio` style; sizing rules (width,\n * max-width, background, etc.) stay with the consumer.\n *\n * This ships as a dedicated primitive — rather than leaving consumers to write\n * a static `aspect-ratio` CSS declaration — because it is more than one line of\n * CSS: it exposes a reactive `ratio` input that recomputes as the value\n * changes, guards `0` / negative / non-finite ratios so the host never emits\n * invalid CSS, is SSR-safe (the style is bound, never touched imperatively),\n * and offers the same headless API shape as the other primitives. Consumers who\n * only need a fixed, never-changing ratio can skip it and set the native CSS\n * `aspect-ratio` property directly; reach for `[forAspectRatio]` when the ratio\n * is dynamic or must be validated.\n *\n * @example\n * ```html\n * <div forAspectRatio [ratio]=\"16 / 9\">\n * <img src=\"cover.jpg\" alt=\"\" />\n * </div>\n *\n * <div forAspectRatio ratio=\"1\"> <!-- square -->\n * <video src=\"clip.mp4\" controls></video>\n * </div>\n * ```\n */\n@Directive({\n selector: '[forAspectRatio]',\n exportAs: 'forAspectRatio',\n host: {\n '[style.aspect-ratio]': 'resolvedRatio()',\n },\n})\nexport class ForAspectRatio {\n /**\n * Width / height ratio, e.g. `16 / 9`, `4 / 3`, `1`. Accepts numeric inputs\n * (`[ratio]=\"16 / 9\"`) and string attributes (`ratio=\"1.5\"`). Defaults to\n * `1` (square). Non-positive or non-finite values fall back to `1` so the\n * host never emits an invalid `aspect-ratio`.\n */\n readonly ratio = input(1, { transform: numberAttribute });\n\n /**\n * The host `aspect-ratio` style value, guarded so a `0`, negative, or\n * non-finite `ratio` never produces invalid CSS — it falls back to `1`.\n */\n protected readonly resolvedRatio = computed(() => {\n const value = this.ratio();\n return String(Number.isFinite(value) && value > 0 ? value : 1);\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;MAQU,cAAc,CAAA;AACzB;;;;;AAKG;IACM,KAAK,GAAG,KAAK,CAAC,CAAC,6EAAI,SAAS,EAAE,eAAe,EAAA,CAAG;AAEzD;;;AAGG;AACgB,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;AAC/C,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE;QAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAChE,CAAC;sFAAC;uGAhBS,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAd,cAAc,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,oBAAA,EAAA,iBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA,gBAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAd,cAAc,EAAA,UAAA,EAAA,CAAA;kBAP1B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,kBAAkB;AAC5B,oBAAA,QAAQ,EAAE,gBAAgB;AAC1B,oBAAA,IAAI,EAAE;AACJ,wBAAA,sBAAsB,EAAE,iBAAiB;AAC1C,qBAAA;AACF,iBAAA;;;ACtCD;;AAEG;;;;"}
|
|
@@ -156,13 +156,15 @@ class ForAvatarImage {
|
|
|
156
156
|
* if the consumer wants to log analytics, swap to a different src on
|
|
157
157
|
* error, etc.
|
|
158
158
|
*/
|
|
159
|
-
|
|
159
|
+
loadStatusChange = output();
|
|
160
160
|
constructor() {
|
|
161
161
|
if (!this.#parent) {
|
|
162
162
|
throw new Error('[forty-cdk/avatar] ForAvatarImage must be used inside a [forAvatar] element.');
|
|
163
163
|
}
|
|
164
164
|
const parent = this.#parent;
|
|
165
165
|
const host = this.#host;
|
|
166
|
+
let destroyed = false;
|
|
167
|
+
inject(DestroyRef).onDestroy(() => (destroyed = true));
|
|
166
168
|
afterNextRender(() => {
|
|
167
169
|
this.#syncFromAttr();
|
|
168
170
|
});
|
|
@@ -181,12 +183,14 @@ class ForAvatarImage {
|
|
|
181
183
|
let last = null;
|
|
182
184
|
let lastReportedToken = -1;
|
|
183
185
|
const emit = (status) => {
|
|
186
|
+
if (destroyed)
|
|
187
|
+
return;
|
|
184
188
|
if (last === status && lastReportedToken === this.#requestToken)
|
|
185
189
|
return;
|
|
186
190
|
last = status;
|
|
187
191
|
lastReportedToken = this.#requestToken;
|
|
188
192
|
parent.reportStatus(status);
|
|
189
|
-
this.
|
|
193
|
+
this.loadStatusChange.emit(status);
|
|
190
194
|
};
|
|
191
195
|
this.#emit = emit;
|
|
192
196
|
}
|
|
@@ -262,7 +266,7 @@ class ForAvatarImage {
|
|
|
262
266
|
/** The `src` the latest `#syncFromAttr` observed, used to match native events. */
|
|
263
267
|
#requestSrc = null;
|
|
264
268
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForAvatarImage, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
265
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForAvatarImage, isStandalone: true, selector: "img[forAvatarImage]", outputs: {
|
|
269
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForAvatarImage, isStandalone: true, selector: "img[forAvatarImage]", outputs: { loadStatusChange: "loadStatusChange" }, host: { listeners: { "load": "onLoad()", "error": "onError()" }, properties: { "attr.data-status": "status()" } }, exportAs: ["forAvatarImage"], ngImport: i0 });
|
|
266
270
|
}
|
|
267
271
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForAvatarImage, decorators: [{
|
|
268
272
|
type: Directive,
|
|
@@ -275,7 +279,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
275
279
|
'(error)': 'onError()',
|
|
276
280
|
},
|
|
277
281
|
}]
|
|
278
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
282
|
+
}], ctorParameters: () => [], propDecorators: { loadStatusChange: [{ type: i0.Output, args: ["loadStatusChange"] }] } });
|
|
279
283
|
|
|
280
284
|
/**
|
|
281
285
|
* Marker for the avatar's fallback content (initials, generic icon, …).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forty-cdk-avatar.mjs","sources":["../../../projects/forty-cdk/avatar/src/avatar-context.ts","../../../projects/forty-cdk/avatar/src/avatar-defaults.ts","../../../projects/forty-cdk/avatar/src/avatar.ts","../../../projects/forty-cdk/avatar/src/avatar-image.ts","../../../projects/forty-cdk/avatar/src/avatar-fallback.ts","../../../projects/forty-cdk/avatar/src/forty-cdk-avatar.ts"],"sourcesContent":["import { inject, InjectionToken, type Signal } from '@angular/core';\n\n/**\n * Lifecycle stages of the avatar's image:\n * - `idle`: no `src` set yet.\n * - `loading`: `src` set, waiting for the network.\n * - `loaded`: image rendered successfully.\n * - `error`: image failed to load.\n */\nexport type ForAvatarStatus = 'idle' | 'loading' | 'loaded' | 'error';\n\nexport interface ForAvatarContext {\n /** Current status of the avatar's image. */\n readonly status: Signal<ForAvatarStatus>;\n /**\n * `true` when the consumer should render the fallback. Drives `@if` in\n * the consumer's template. Honors `fallbackDelayMs` for `idle` / `loading`\n * states; `error` flips it to `true` immediately.\n */\n readonly shouldShowFallback: Signal<boolean>;\n /**\n * Internal — reported by `[forAvatarImage]` so the root can transition\n * its state machine. Consumers should not call this.\n */\n reportStatus(status: ForAvatarStatus): void;\n}\n\nexport const FOR_AVATAR_CONTEXT = new InjectionToken<ForAvatarContext>('FOR_AVATAR_CONTEXT');\n\n/**\n * Injects the nearest {@link ForAvatarContext}, throwing a descriptive error\n * when used outside a `[forAvatar]` element.\n *\n * @param piece Name of the calling directive, used in the error message.\n */\nexport function injectAvatarContext(piece: string): ForAvatarContext {\n const ctx = inject(FOR_AVATAR_CONTEXT, { optional: true });\n if (!ctx) {\n throw new Error(`[forty-cdk/avatar] ${piece} must be used inside a [forAvatar] element.`);\n }\n return ctx;\n}\n","import { type Provider } from '@angular/core';\n\nimport { createDefaults } from 'forty-cdk/core';\n\n/**\n * Defaults inherited by descendant avatars in the surrounding injector\n * scope. Configure with `provideForAvatarDefaults` either at the\n * application root or in any component's `providers` array; partial\n * overrides merge with the parent scope.\n */\nexport interface ForAvatarDefaults {\n /**\n * Milliseconds to defer the fallback for fast loads, avoiding a brief\n * \"initials → image\" flicker. Set to `0` to show immediately during\n * `idle` / `loading`, or to e.g. `500` to skip rendering during quick\n * cached loads. `error` always shows the fallback immediately.\n */\n fallbackDelayMs: number;\n}\n\n/**\n * Library fallback for avatar defaults, read at the root injector when no\n * consumer has called `provideForAvatarDefaults`. Exported for the shared defaults\n * contract spec; not re-exported from the primitive's public entry.\n */\nexport const FOR_AVATAR_FALLBACK_DEFAULTS: ForAvatarDefaults = {\n fallbackDelayMs: 0,\n};\n\nconst { token, provideDefaults } = createDefaults<ForAvatarDefaults>(\n 'FOR_AVATAR_DEFAULTS',\n FOR_AVATAR_FALLBACK_DEFAULTS,\n);\n\n/** Token holding the resolved avatar defaults for the current scope. */\nexport const FOR_AVATAR_DEFAULTS = token;\n\n/**\n * Configures forty-cdk avatar defaults for this injector scope. Partial\n * overrides inherit unspecified keys from the parent scope (or library\n * defaults at the root).\n */\nexport function provideForAvatarDefaults(defaults: Partial<ForAvatarDefaults> = {}): Provider[] {\n return provideDefaults(defaults);\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport {\n computed,\n DestroyRef,\n Directive,\n effect,\n inject,\n input,\n linkedSignal,\n numberAttribute,\n PLATFORM_ID,\n signal,\n} from '@angular/core';\n\nimport { FOR_AVATAR_CONTEXT, type ForAvatarContext, type ForAvatarStatus } from './avatar-context';\nimport { FOR_AVATAR_DEFAULTS } from './avatar-defaults';\n\n/**\n * Headless avatar root. Tracks the load lifecycle of an inner\n * `[forAvatarImage]` and exposes `status` + `shouldShowFallback` so the\n * consumer can swap the image for fallback content (initials, generic icon)\n * via `@if`.\n *\n * No ARIA role is imposed — avatars are typically presentational. If the\n * surrounding component conveys identity (a person's name in the header,\n * a chat bubble), the consumer should provide an `aria-label` on the\n * relevant ancestor or pair the avatar with visible text.\n *\n * @example\n * ```html\n * <span forAvatar #a=\"forAvatar\" fallbackDelayMs=\"500\">\n * <img forAvatarImage [src]=\"user.avatarUrl\" [alt]=\"user.name\" />\n * @if (a.shouldShowFallback()) {\n * <span forAvatarFallback>{{ user.initials }}</span>\n * }\n * </span>\n * ```\n */\n@Directive({\n selector: '[forAvatar]',\n exportAs: 'forAvatar',\n host: {\n '[attr.data-status]': 'status()',\n },\n providers: [{ provide: FOR_AVATAR_CONTEXT, useExisting: ForAvatar }],\n})\nexport class ForAvatar implements ForAvatarContext {\n readonly #defaults = inject(FOR_AVATAR_DEFAULTS);\n\n /**\n * Milliseconds to defer the fallback for fast loads, avoiding a brief\n * \"initials → image\" flicker. Set to `0` (default) to show immediately\n * during `idle` / `loading`, or to e.g. `500` to skip rendering during\n * quick cached loads. `error` always shows the fallback immediately.\n * The default is read from `provideForAvatarDefaults` for the\n * surrounding scope.\n */\n readonly fallbackDelayMs = input(this.#defaults.fallbackDelayMs, {\n transform: numberAttribute,\n });\n\n readonly #status = signal<ForAvatarStatus>('idle');\n readonly status = this.#status.asReadonly();\n\n // Whether the deferred-fallback timer has fired for the current status/delay.\n // `linkedSignal` resets it to `false` whenever the source changes (the\n // canonical replacement for resetting state inside an effect); the timer\n // callback in the constructor flips it to `true`.\n readonly #timerElapsed = linkedSignal<{ status: ForAvatarStatus; delay: number }, boolean>({\n source: () => ({ status: this.#status(), delay: this.fallbackDelayMs() }),\n computation: () => false,\n });\n #timer: ReturnType<typeof setTimeout> | null = null;\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly shouldShowFallback = computed(() => {\n const status = this.#status();\n if (status === 'loaded') return false;\n if (status === 'error') return true;\n // idle | loading: an immediate (delay <= 0) gate shows the fallback right\n // away; a deferred gate waits for the timer armed in the effect below.\n if (this.fallbackDelayMs() <= 0) return true;\n return this.#timerElapsed();\n });\n\n /** @internal */\n reportStatus(status: ForAvatarStatus): void {\n this.#status.set(status);\n }\n\n constructor() {\n // Imperative timer integration: the effect's only job is to (re)arm a\n // setTimeout for the deferred-fallback case (idle | loading with a positive\n // delay). The synchronous branches (loaded / error / delay <= 0) are pure\n // derivations and live in `shouldShowFallback`. The signal write happens\n // inside the timer callback, which runs outside the effect's reactive\n // scope, so this does NOT create a self-cycle in the reactive graph.\n effect(() => {\n const status = this.#status();\n const delay = this.fallbackDelayMs();\n this.#cancelTimer();\n if (this.#isBrowser && (status === 'idle' || status === 'loading') && delay > 0) {\n this.#timer = setTimeout(() => {\n this.#timer = null;\n this.#timerElapsed.set(true);\n }, delay);\n }\n });\n\n inject(DestroyRef).onDestroy(() => this.#cancelTimer());\n }\n\n #cancelTimer(): void {\n if (this.#timer !== null) {\n clearTimeout(this.#timer);\n this.#timer = null;\n }\n }\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport {\n afterNextRender,\n DestroyRef,\n Directive,\n ElementRef,\n inject,\n output,\n PLATFORM_ID,\n} from '@angular/core';\n\nimport { FOR_AVATAR_CONTEXT, type ForAvatarStatus } from './avatar-context';\n\n/**\n * Wraps an `<img>` and reports its load lifecycle to the surrounding\n * `[forAvatar]`. The native `src` / `alt` bindings are owned by the\n * consumer — this directive only observes.\n *\n * Reflects `data-status` on the image element so the consumer can hide it\n * via CSS while loading or after an error (e.g. `img[data-status=\"error\"]\n * { display: none }`).\n */\n@Directive({\n selector: 'img[forAvatarImage]',\n exportAs: 'forAvatarImage',\n host: {\n '[attr.data-status]': 'status()',\n '(load)': 'onLoad()',\n '(error)': 'onError()',\n },\n})\nexport class ForAvatarImage {\n readonly #host = inject<ElementRef<HTMLImageElement>>(ElementRef).nativeElement;\n readonly #parent = inject(FOR_AVATAR_CONTEXT, { optional: true });\n\n /**\n * Emits whenever the image lifecycle transitions to a new state. Useful\n * if the consumer wants to log analytics, swap to a different src on\n * error, etc.\n */\n readonly loadStatusChanged = output<ForAvatarStatus>();\n\n constructor() {\n if (!this.#parent) {\n throw new Error(\n '[forty-cdk/avatar] ForAvatarImage must be used inside a [forAvatar] element.',\n );\n }\n const parent = this.#parent;\n const host = this.#host;\n\n afterNextRender(() => {\n this.#syncFromAttr();\n });\n\n if (isPlatformBrowser(inject(PLATFORM_ID)) && typeof MutationObserver !== 'undefined') {\n const observer = new MutationObserver(() => {\n this.#syncFromAttr();\n });\n observer.observe(host, { attributes: true, attributeFilter: ['src'] });\n inject(DestroyRef).onDestroy(() => observer.disconnect());\n }\n\n // Re-emit upstream whenever the parent's status changes due to our writes.\n // De-dupe on the (request, status) pair rather than status alone: a new\n // `src` opens a fresh request token, so an identical status (e.g. a second\n // image that also `loaded`) still re-reports for the new request, while a\n // repeated status within the same request is suppressed.\n let last: ForAvatarStatus | null = null;\n let lastReportedToken = -1;\n const emit = (status: ForAvatarStatus): void => {\n if (last === status && lastReportedToken === this.#requestToken) return;\n last = status;\n lastReportedToken = this.#requestToken;\n parent.reportStatus(status);\n this.loadStatusChanged.emit(status);\n };\n this.#emit = emit;\n }\n\n protected status(): ForAvatarStatus {\n return this.#parent!.status();\n }\n\n protected onLoad(): void {\n // Ignore a `load` that fires for a request the host has already moved past\n // (the native event can arrive after `src` was reassigned).\n if (!this.#isCurrentRequest()) return;\n this.#emit('loaded');\n }\n\n protected onError(): void {\n if (!this.#isCurrentRequest()) return;\n this.#emit('error');\n }\n\n /**\n * True when the `src` the host currently carries is the one the latest\n * `#syncFromAttr` observed, so a native load/error event belongs to the\n * in-flight request rather than a superseded one.\n */\n #isCurrentRequest(): boolean {\n return this.#host.getAttribute('src') === this.#requestSrc;\n }\n\n #syncFromAttr(): void {\n const src = this.#host.getAttribute('src');\n this.#requestToken++;\n this.#requestSrc = src;\n if (!src) {\n this.#emit('idle');\n return;\n }\n if (this.#host.complete) {\n // Cached image: load/error events may not fire — derive from naturalWidth.\n if (this.#host.naturalWidth > 0) {\n this.#emit('loaded');\n return;\n }\n // A complete image with zero intrinsic width is ambiguous: it may be a\n // broken image OR a valid SVG with no intrinsic dimensions. Don't\n // pessimistically flag `error` and hide a valid image — verify with\n // `decode()`, which resolves for a decodable (even zero-size) image and\n // rejects for a broken one. Stay `loading` until it settles.\n this.#emit('loading');\n this.#verifyCachedZeroSize(src);\n return;\n }\n this.#emit('loading');\n }\n\n #verifyCachedZeroSize(src: string): void {\n const decode = this.#host.decode?.bind(this.#host);\n if (!decode) {\n // No `decode()` (older engines / jsdom): keep the legacy heuristic.\n this.#emit('error');\n return;\n }\n decode().then(\n () => {\n if (this.#host.getAttribute('src') === src) {\n this.#emit('loaded');\n }\n },\n () => {\n if (this.#host.getAttribute('src') === src) {\n this.#emit('error');\n }\n },\n );\n }\n\n // Initialized in constructor.\n #emit!: (status: ForAvatarStatus) => void;\n\n /** Monotonic id bumped on every `src` change so stale events are ignored. */\n #requestToken = 0;\n /** The `src` the latest `#syncFromAttr` observed, used to match native events. */\n #requestSrc: string | null = null;\n}\n","import { Directive } from '@angular/core';\n\nimport { injectAvatarContext } from './avatar-context';\n\n/**\n * Marker for the avatar's fallback content (initials, generic icon, …).\n * Reflects `data-status` from the parent `[forAvatar]` so the consumer can\n * style for the `error` state separately from `idle` / `loading` if needed.\n *\n * The decision of *whether* to render the fallback lives on the root —\n * drive `@if` with `forAvatar.shouldShowFallback()`.\n */\n@Directive({\n selector: '[forAvatarFallback]',\n exportAs: 'forAvatarFallback',\n host: {\n '[attr.data-status]': 'parent.status()',\n },\n})\nexport class ForAvatarFallback {\n protected readonly parent = injectAvatarContext('ForAvatarFallback');\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"forty-cdk-avatar.mjs","sources":["../../../projects/forty-cdk/avatar/src/avatar-context.ts","../../../projects/forty-cdk/avatar/src/avatar-defaults.ts","../../../projects/forty-cdk/avatar/src/avatar.ts","../../../projects/forty-cdk/avatar/src/avatar-image.ts","../../../projects/forty-cdk/avatar/src/avatar-fallback.ts","../../../projects/forty-cdk/avatar/src/forty-cdk-avatar.ts"],"sourcesContent":["import { inject, InjectionToken, type Signal } from '@angular/core';\n\n/**\n * Lifecycle stages of the avatar's image:\n * - `idle`: no `src` set yet.\n * - `loading`: `src` set, waiting for the network.\n * - `loaded`: image rendered successfully.\n * - `error`: image failed to load.\n */\nexport type ForAvatarStatus = 'idle' | 'loading' | 'loaded' | 'error';\n\nexport interface ForAvatarContext {\n /** Current status of the avatar's image. */\n readonly status: Signal<ForAvatarStatus>;\n /**\n * `true` when the consumer should render the fallback. Drives `@if` in\n * the consumer's template. Honors `fallbackDelayMs` for `idle` / `loading`\n * states; `error` flips it to `true` immediately.\n */\n readonly shouldShowFallback: Signal<boolean>;\n /**\n * Internal — reported by `[forAvatarImage]` so the root can transition\n * its state machine. Consumers should not call this.\n */\n reportStatus(status: ForAvatarStatus): void;\n}\n\nexport const FOR_AVATAR_CONTEXT = new InjectionToken<ForAvatarContext>('FOR_AVATAR_CONTEXT');\n\n/**\n * Injects the nearest {@link ForAvatarContext}, throwing a descriptive error\n * when used outside a `[forAvatar]` element.\n *\n * @param piece Name of the calling directive, used in the error message.\n */\nexport function injectAvatarContext(piece: string): ForAvatarContext {\n const ctx = inject(FOR_AVATAR_CONTEXT, { optional: true });\n if (!ctx) {\n throw new Error(`[forty-cdk/avatar] ${piece} must be used inside a [forAvatar] element.`);\n }\n return ctx;\n}\n","import { type Provider } from '@angular/core';\n\nimport { createDefaults } from 'forty-cdk/core';\n\n/**\n * Defaults inherited by descendant avatars in the surrounding injector\n * scope. Configure with `provideForAvatarDefaults` either at the\n * application root or in any component's `providers` array; partial\n * overrides merge with the parent scope.\n */\nexport interface ForAvatarDefaults {\n /**\n * Milliseconds to defer the fallback for fast loads, avoiding a brief\n * \"initials → image\" flicker. Set to `0` to show immediately during\n * `idle` / `loading`, or to e.g. `500` to skip rendering during quick\n * cached loads. `error` always shows the fallback immediately.\n */\n fallbackDelayMs: number;\n}\n\n/**\n * Library fallback for avatar defaults, read at the root injector when no\n * consumer has called `provideForAvatarDefaults`. Exported for the shared defaults\n * contract spec; not re-exported from the primitive's public entry.\n */\nexport const FOR_AVATAR_FALLBACK_DEFAULTS: ForAvatarDefaults = {\n fallbackDelayMs: 0,\n};\n\nconst { token, provideDefaults } = createDefaults<ForAvatarDefaults>(\n 'FOR_AVATAR_DEFAULTS',\n FOR_AVATAR_FALLBACK_DEFAULTS,\n);\n\n/** Token holding the resolved avatar defaults for the current scope. */\nexport const FOR_AVATAR_DEFAULTS = token;\n\n/**\n * Configures forty-cdk avatar defaults for this injector scope. Partial\n * overrides inherit unspecified keys from the parent scope (or library\n * defaults at the root).\n */\nexport function provideForAvatarDefaults(defaults: Partial<ForAvatarDefaults> = {}): Provider[] {\n return provideDefaults(defaults);\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport {\n computed,\n DestroyRef,\n Directive,\n effect,\n inject,\n input,\n linkedSignal,\n numberAttribute,\n PLATFORM_ID,\n signal,\n} from '@angular/core';\n\nimport { FOR_AVATAR_CONTEXT, type ForAvatarContext, type ForAvatarStatus } from './avatar-context';\nimport { FOR_AVATAR_DEFAULTS } from './avatar-defaults';\n\n/**\n * Headless avatar root. Tracks the load lifecycle of an inner\n * `[forAvatarImage]` and exposes `status` + `shouldShowFallback` so the\n * consumer can swap the image for fallback content (initials, generic icon)\n * via `@if`.\n *\n * No ARIA role is imposed — avatars are typically presentational. If the\n * surrounding component conveys identity (a person's name in the header,\n * a chat bubble), the consumer should provide an `aria-label` on the\n * relevant ancestor or pair the avatar with visible text.\n *\n * @example\n * ```html\n * <span forAvatar #a=\"forAvatar\" fallbackDelayMs=\"500\">\n * <img forAvatarImage [src]=\"user.avatarUrl\" [alt]=\"user.name\" />\n * @if (a.shouldShowFallback()) {\n * <span forAvatarFallback>{{ user.initials }}</span>\n * }\n * </span>\n * ```\n */\n@Directive({\n selector: '[forAvatar]',\n exportAs: 'forAvatar',\n host: {\n '[attr.data-status]': 'status()',\n },\n providers: [{ provide: FOR_AVATAR_CONTEXT, useExisting: ForAvatar }],\n})\nexport class ForAvatar implements ForAvatarContext {\n readonly #defaults = inject(FOR_AVATAR_DEFAULTS);\n\n /**\n * Milliseconds to defer the fallback for fast loads, avoiding a brief\n * \"initials → image\" flicker. Set to `0` (default) to show immediately\n * during `idle` / `loading`, or to e.g. `500` to skip rendering during\n * quick cached loads. `error` always shows the fallback immediately.\n * The default is read from `provideForAvatarDefaults` for the\n * surrounding scope.\n */\n readonly fallbackDelayMs = input(this.#defaults.fallbackDelayMs, {\n transform: numberAttribute,\n });\n\n readonly #status = signal<ForAvatarStatus>('idle');\n readonly status = this.#status.asReadonly();\n\n // Whether the deferred-fallback timer has fired for the current status/delay.\n // `linkedSignal` resets it to `false` whenever the source changes (the\n // canonical replacement for resetting state inside an effect); the timer\n // callback in the constructor flips it to `true`.\n readonly #timerElapsed = linkedSignal<{ status: ForAvatarStatus; delay: number }, boolean>({\n source: () => ({ status: this.#status(), delay: this.fallbackDelayMs() }),\n computation: () => false,\n });\n #timer: ReturnType<typeof setTimeout> | null = null;\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly shouldShowFallback = computed(() => {\n const status = this.#status();\n if (status === 'loaded') return false;\n if (status === 'error') return true;\n // idle | loading: an immediate (delay <= 0) gate shows the fallback right\n // away; a deferred gate waits for the timer armed in the effect below.\n if (this.fallbackDelayMs() <= 0) return true;\n return this.#timerElapsed();\n });\n\n /** @internal */\n reportStatus(status: ForAvatarStatus): void {\n this.#status.set(status);\n }\n\n constructor() {\n // Imperative timer integration: the effect's only job is to (re)arm a\n // setTimeout for the deferred-fallback case (idle | loading with a positive\n // delay). The synchronous branches (loaded / error / delay <= 0) are pure\n // derivations and live in `shouldShowFallback`. The signal write happens\n // inside the timer callback, which runs outside the effect's reactive\n // scope, so this does NOT create a self-cycle in the reactive graph.\n effect(() => {\n const status = this.#status();\n const delay = this.fallbackDelayMs();\n this.#cancelTimer();\n if (this.#isBrowser && (status === 'idle' || status === 'loading') && delay > 0) {\n this.#timer = setTimeout(() => {\n this.#timer = null;\n this.#timerElapsed.set(true);\n }, delay);\n }\n });\n\n inject(DestroyRef).onDestroy(() => this.#cancelTimer());\n }\n\n #cancelTimer(): void {\n if (this.#timer !== null) {\n clearTimeout(this.#timer);\n this.#timer = null;\n }\n }\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport {\n afterNextRender,\n DestroyRef,\n Directive,\n ElementRef,\n inject,\n output,\n PLATFORM_ID,\n} from '@angular/core';\n\nimport { FOR_AVATAR_CONTEXT, type ForAvatarStatus } from './avatar-context';\n\n/**\n * Wraps an `<img>` and reports its load lifecycle to the surrounding\n * `[forAvatar]`. The native `src` / `alt` bindings are owned by the\n * consumer — this directive only observes.\n *\n * Reflects `data-status` on the image element so the consumer can hide it\n * via CSS while loading or after an error (e.g. `img[data-status=\"error\"]\n * { display: none }`).\n */\n@Directive({\n selector: 'img[forAvatarImage]',\n exportAs: 'forAvatarImage',\n host: {\n '[attr.data-status]': 'status()',\n '(load)': 'onLoad()',\n '(error)': 'onError()',\n },\n})\nexport class ForAvatarImage {\n readonly #host = inject<ElementRef<HTMLImageElement>>(ElementRef).nativeElement;\n readonly #parent = inject(FOR_AVATAR_CONTEXT, { optional: true });\n\n /**\n * Emits whenever the image lifecycle transitions to a new state. Useful\n * if the consumer wants to log analytics, swap to a different src on\n * error, etc.\n */\n readonly loadStatusChange = output<ForAvatarStatus>();\n\n constructor() {\n if (!this.#parent) {\n throw new Error(\n '[forty-cdk/avatar] ForAvatarImage must be used inside a [forAvatar] element.',\n );\n }\n const parent = this.#parent;\n const host = this.#host;\n\n let destroyed = false;\n inject(DestroyRef).onDestroy(() => (destroyed = true));\n\n afterNextRender(() => {\n this.#syncFromAttr();\n });\n\n if (isPlatformBrowser(inject(PLATFORM_ID)) && typeof MutationObserver !== 'undefined') {\n const observer = new MutationObserver(() => {\n this.#syncFromAttr();\n });\n observer.observe(host, { attributes: true, attributeFilter: ['src'] });\n inject(DestroyRef).onDestroy(() => observer.disconnect());\n }\n\n // Re-emit upstream whenever the parent's status changes due to our writes.\n // De-dupe on the (request, status) pair rather than status alone: a new\n // `src` opens a fresh request token, so an identical status (e.g. a second\n // image that also `loaded`) still re-reports for the new request, while a\n // repeated status within the same request is suppressed.\n let last: ForAvatarStatus | null = null;\n let lastReportedToken = -1;\n const emit = (status: ForAvatarStatus): void => {\n if (destroyed) return;\n if (last === status && lastReportedToken === this.#requestToken) return;\n last = status;\n lastReportedToken = this.#requestToken;\n parent.reportStatus(status);\n this.loadStatusChange.emit(status);\n };\n this.#emit = emit;\n }\n\n protected status(): ForAvatarStatus {\n return this.#parent!.status();\n }\n\n protected onLoad(): void {\n // Ignore a `load` that fires for a request the host has already moved past\n // (the native event can arrive after `src` was reassigned).\n if (!this.#isCurrentRequest()) return;\n this.#emit('loaded');\n }\n\n protected onError(): void {\n if (!this.#isCurrentRequest()) return;\n this.#emit('error');\n }\n\n /**\n * True when the `src` the host currently carries is the one the latest\n * `#syncFromAttr` observed, so a native load/error event belongs to the\n * in-flight request rather than a superseded one.\n */\n #isCurrentRequest(): boolean {\n return this.#host.getAttribute('src') === this.#requestSrc;\n }\n\n #syncFromAttr(): void {\n const src = this.#host.getAttribute('src');\n this.#requestToken++;\n this.#requestSrc = src;\n if (!src) {\n this.#emit('idle');\n return;\n }\n if (this.#host.complete) {\n // Cached image: load/error events may not fire — derive from naturalWidth.\n if (this.#host.naturalWidth > 0) {\n this.#emit('loaded');\n return;\n }\n // A complete image with zero intrinsic width is ambiguous: it may be a\n // broken image OR a valid SVG with no intrinsic dimensions. Don't\n // pessimistically flag `error` and hide a valid image — verify with\n // `decode()`, which resolves for a decodable (even zero-size) image and\n // rejects for a broken one. Stay `loading` until it settles.\n this.#emit('loading');\n this.#verifyCachedZeroSize(src);\n return;\n }\n this.#emit('loading');\n }\n\n #verifyCachedZeroSize(src: string): void {\n const decode = this.#host.decode?.bind(this.#host);\n if (!decode) {\n // No `decode()` (older engines / jsdom): keep the legacy heuristic.\n this.#emit('error');\n return;\n }\n decode().then(\n () => {\n if (this.#host.getAttribute('src') === src) {\n this.#emit('loaded');\n }\n },\n () => {\n if (this.#host.getAttribute('src') === src) {\n this.#emit('error');\n }\n },\n );\n }\n\n // Initialized in constructor.\n #emit!: (status: ForAvatarStatus) => void;\n\n /** Monotonic id bumped on every `src` change so stale events are ignored. */\n #requestToken = 0;\n /** The `src` the latest `#syncFromAttr` observed, used to match native events. */\n #requestSrc: string | null = null;\n}\n","import { Directive } from '@angular/core';\n\nimport { injectAvatarContext } from './avatar-context';\n\n/**\n * Marker for the avatar's fallback content (initials, generic icon, …).\n * Reflects `data-status` from the parent `[forAvatar]` so the consumer can\n * style for the `error` state separately from `idle` / `loading` if needed.\n *\n * The decision of *whether* to render the fallback lives on the root —\n * drive `@if` with `forAvatar.shouldShowFallback()`.\n */\n@Directive({\n selector: '[forAvatarFallback]',\n exportAs: 'forAvatarFallback',\n host: {\n '[attr.data-status]': 'parent.status()',\n },\n})\nexport class ForAvatarFallback {\n protected readonly parent = injectAvatarContext('ForAvatarFallback');\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, Directive, booleanAttribute } from '@angular/core';
|
|
2
|
+
import { inject, input, Directive, booleanAttribute } from '@angular/core';
|
|
3
3
|
import { createDefaults } from 'forty-cdk/core';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Library fallback for breadcrumbs defaults, read at the root injector when no
|
|
7
|
+
* consumer has called `provideForBreadcrumbsDefaults`. Exported for the shared
|
|
8
|
+
* defaults contract spec; not re-exported from the primitive's public entry.
|
|
9
|
+
*/
|
|
10
|
+
const FOR_BREADCRUMBS_FALLBACK_DEFAULTS = {
|
|
11
|
+
label: 'Breadcrumb',
|
|
12
|
+
};
|
|
13
|
+
const { token, provideDefaults } = createDefaults('FOR_BREADCRUMBS_DEFAULTS', FOR_BREADCRUMBS_FALLBACK_DEFAULTS);
|
|
14
|
+
/** Token holding the resolved breadcrumbs defaults for the current scope. */
|
|
15
|
+
const FOR_BREADCRUMBS_DEFAULTS = token;
|
|
16
|
+
/**
|
|
17
|
+
* Configures forty-cdk breadcrumbs defaults for this injector scope. Partial
|
|
18
|
+
* overrides inherit unspecified keys from the parent scope (or library
|
|
19
|
+
* defaults at the root).
|
|
20
|
+
*/
|
|
21
|
+
function provideForBreadcrumbsDefaults(defaults = {}) {
|
|
22
|
+
return provideDefaults(defaults);
|
|
23
|
+
}
|
|
24
|
+
|
|
5
25
|
/**
|
|
6
26
|
* Headless breadcrumb trail implementing the
|
|
7
27
|
* [WAI-ARIA Breadcrumb pattern](https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/):
|
|
@@ -32,17 +52,21 @@ import { createDefaults } from 'forty-cdk/core';
|
|
|
32
52
|
* ```
|
|
33
53
|
*/
|
|
34
54
|
class ForBreadcrumbs {
|
|
55
|
+
#defaults = inject(FOR_BREADCRUMBS_DEFAULTS);
|
|
35
56
|
/**
|
|
36
|
-
* Accessible label for the navigation landmark. Defaults to
|
|
37
|
-
*
|
|
38
|
-
*
|
|
57
|
+
* Accessible label for the navigation landmark. Defaults to the scope's
|
|
58
|
+
* `label` (`'Breadcrumb'` unless overridden via
|
|
59
|
+
* `provideForBreadcrumbsDefaults`), so a bare `<nav forBreadcrumbs>` is
|
|
60
|
+
* already a correctly labelled landmark — the conventional name for this
|
|
61
|
+
* pattern. Override it per-instance via `[ariaLabel]` (or point a native
|
|
39
62
|
* `aria-labelledby` at a visible heading) when the page hosts more than one
|
|
40
|
-
* breadcrumb trail and they need to be told apart
|
|
63
|
+
* breadcrumb trail and they need to be told apart; set it to `null` to drop
|
|
64
|
+
* the attribute and rely on `aria-labelledby`.
|
|
41
65
|
*/
|
|
42
|
-
ariaLabel = input(
|
|
66
|
+
ariaLabel = input(this.#defaults.label, /* @ts-ignore */
|
|
43
67
|
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
44
68
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForBreadcrumbs, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
45
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForBreadcrumbs, isStandalone: true, selector: "[forBreadcrumbs]", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "navigation" }, properties: { "attr.aria-label": "ariaLabel()
|
|
69
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForBreadcrumbs, isStandalone: true, selector: "[forBreadcrumbs]", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "navigation" }, properties: { "attr.aria-label": "ariaLabel()" } }, exportAs: ["forBreadcrumbs"], ngImport: i0 });
|
|
46
70
|
}
|
|
47
71
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForBreadcrumbs, decorators: [{
|
|
48
72
|
type: Directive,
|
|
@@ -51,7 +75,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
51
75
|
exportAs: 'forBreadcrumbs',
|
|
52
76
|
host: {
|
|
53
77
|
role: 'navigation',
|
|
54
|
-
'[attr.aria-label]':
|
|
78
|
+
'[attr.aria-label]': 'ariaLabel()',
|
|
55
79
|
},
|
|
56
80
|
}]
|
|
57
81
|
}], propDecorators: { ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
@@ -104,19 +128,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
104
128
|
}]
|
|
105
129
|
}] });
|
|
106
130
|
|
|
107
|
-
const FALLBACK = {};
|
|
108
|
-
const { token, provideDefaults } = createDefaults('FOR_BREADCRUMBS_DEFAULTS', FALLBACK);
|
|
109
|
-
/** Token holding the resolved breadcrumbs defaults for the current scope. */
|
|
110
|
-
const FOR_BREADCRUMBS_DEFAULTS = token;
|
|
111
|
-
/**
|
|
112
|
-
* Configures forty-cdk breadcrumbs defaults for this injector scope. Partial
|
|
113
|
-
* overrides inherit unspecified keys from the parent scope (or library
|
|
114
|
-
* defaults at the root).
|
|
115
|
-
*/
|
|
116
|
-
function provideForBreadcrumbsDefaults(defaults = {}) {
|
|
117
|
-
return provideDefaults(defaults);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
131
|
/**
|
|
121
132
|
* Generated bundle index. Do not edit.
|
|
122
133
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forty-cdk-breadcrumbs.mjs","sources":["../../../projects/forty-cdk/breadcrumbs/src/breadcrumbs.ts","../../../projects/forty-cdk/breadcrumbs/src/
|
|
1
|
+
{"version":3,"file":"forty-cdk-breadcrumbs.mjs","sources":["../../../projects/forty-cdk/breadcrumbs/src/breadcrumbs-defaults.ts","../../../projects/forty-cdk/breadcrumbs/src/breadcrumbs.ts","../../../projects/forty-cdk/breadcrumbs/src/breadcrumb-item.ts","../../../projects/forty-cdk/breadcrumbs/src/breadcrumb-separator.ts","../../../projects/forty-cdk/breadcrumbs/src/forty-cdk-breadcrumbs.ts"],"sourcesContent":["import { type Provider } from '@angular/core';\n\nimport { createDefaults } from 'forty-cdk/core';\n\n/**\n * Defaults inherited by descendant breadcrumb trails in the surrounding\n * injector scope. Configure with `provideForBreadcrumbsDefaults` either at the\n * application root or in any component's `providers` array; partial overrides\n * merge with the parent scope.\n */\nexport interface ForBreadcrumbsDefaults {\n /**\n * Accessible name for the breadcrumb `navigation` landmark, for trails that\n * don't set `[ariaLabel]` locally. Localize it here to translate every\n * breadcrumb landmark in the scope.\n */\n label: string;\n}\n\n/**\n * Library fallback for breadcrumbs defaults, read at the root injector when no\n * consumer has called `provideForBreadcrumbsDefaults`. Exported for the shared\n * defaults contract spec; not re-exported from the primitive's public entry.\n */\nexport const FOR_BREADCRUMBS_FALLBACK_DEFAULTS: ForBreadcrumbsDefaults = {\n label: 'Breadcrumb',\n};\n\nconst { token, provideDefaults } = createDefaults<ForBreadcrumbsDefaults>(\n 'FOR_BREADCRUMBS_DEFAULTS',\n FOR_BREADCRUMBS_FALLBACK_DEFAULTS,\n);\n\n/** Token holding the resolved breadcrumbs defaults for the current scope. */\nexport const FOR_BREADCRUMBS_DEFAULTS = token;\n\n/**\n * Configures forty-cdk breadcrumbs defaults for this injector scope. Partial\n * overrides inherit unspecified keys from the parent scope (or library\n * defaults at the root).\n */\nexport function provideForBreadcrumbsDefaults(\n defaults: Partial<ForBreadcrumbsDefaults> = {},\n): Provider[] {\n return provideDefaults(defaults);\n}\n","import { Directive, inject, input } from '@angular/core';\n\nimport { FOR_BREADCRUMBS_DEFAULTS } from './breadcrumbs-defaults';\n\n/**\n * Headless breadcrumb trail implementing the\n * [WAI-ARIA Breadcrumb pattern](https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/):\n * a `navigation` landmark wrapping a set of links that reveal the page's\n * position within the site hierarchy.\n *\n * The directive contributes only the landmark role + accessible name; the\n * consumer owns the markup structure (an `<ol>` of `<li>` links is the APG\n * recommendation) and applies their own styles. Each link decorated with\n * `[forBreadcrumbItem]` can mark itself the current page via `current`, and\n * visual dividers decorated with `[forBreadcrumbSeparator]` are hidden from\n * assistive technology.\n *\n * There is no keyboard interaction or focus management beyond what the native\n * links provide — breadcrumb links are ordinary tab stops.\n *\n * @example\n * ```html\n * <nav forBreadcrumbs>\n * <ol>\n * <li><a forBreadcrumbItem href=\"/\">Home</a></li>\n * <li forBreadcrumbSeparator aria-hidden=\"true\">/</li>\n * <li><a forBreadcrumbItem href=\"/library\">Library</a></li>\n * <li forBreadcrumbSeparator aria-hidden=\"true\">/</li>\n * <li><a forBreadcrumbItem href=\"/library/data\" current>Data</a></li>\n * </ol>\n * </nav>\n * ```\n */\n@Directive({\n selector: '[forBreadcrumbs]',\n exportAs: 'forBreadcrumbs',\n host: {\n role: 'navigation',\n '[attr.aria-label]': 'ariaLabel()',\n },\n})\nexport class ForBreadcrumbs {\n readonly #defaults = inject(FOR_BREADCRUMBS_DEFAULTS);\n\n /**\n * Accessible label for the navigation landmark. Defaults to the scope's\n * `label` (`'Breadcrumb'` unless overridden via\n * `provideForBreadcrumbsDefaults`), so a bare `<nav forBreadcrumbs>` is\n * already a correctly labelled landmark — the conventional name for this\n * pattern. Override it per-instance via `[ariaLabel]` (or point a native\n * `aria-labelledby` at a visible heading) when the page hosts more than one\n * breadcrumb trail and they need to be told apart; set it to `null` to drop\n * the attribute and rely on `aria-labelledby`.\n */\n readonly ariaLabel = input<string | null>(this.#defaults.label);\n}\n","import { booleanAttribute, Directive, input } from '@angular/core';\n\n/**\n * A single link within a breadcrumb trail. Apply on an `<a>` so navigation is\n * native. Set `current` on the link that points to the page the user is on —\n * it reflects [`aria-current=\"page\"`](https://www.w3.org/TR/wai-aria-1.2/#aria-current)\n * so assistive technology announces it as the current location.\n */\n@Directive({\n selector: '[forBreadcrumbItem]',\n exportAs: 'forBreadcrumbItem',\n host: {\n '[attr.aria-current]': 'current() ? \"page\" : null',\n },\n})\nexport class ForBreadcrumbItem {\n /**\n * Whether this item represents the page the user is currently on. The\n * current item reflects `aria-current=\"page\"`; all others emit no\n * `aria-current` attribute.\n */\n readonly current = input(false, { transform: booleanAttribute });\n}\n","import { Directive } from '@angular/core';\n\n/**\n * Decorative divider rendered between breadcrumb items (a `/`, `>`, chevron,\n * etc.). Reflects `aria-hidden=\"true\"` so assistive technology skips it — the\n * trail's structure is already conveyed by the list and the links, making the\n * visual separator redundant in the accessibility tree.\n */\n@Directive({\n selector: '[forBreadcrumbSeparator]',\n exportAs: 'forBreadcrumbSeparator',\n host: {\n 'aria-hidden': 'true',\n },\n})\nexport class ForBreadcrumbSeparator {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|