@skra/ui 0.4.0 → 0.6.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.
Files changed (72) hide show
  1. package/consumer-guide/README.md +88 -85
  2. package/consumer-guide/custom-components.md +154 -0
  3. package/consumer-guide/wrapping-patterns.md +98 -90
  4. package/fesm2022/skra-ui-accordion.mjs +2 -2
  5. package/fesm2022/skra-ui-accordion.mjs.map +1 -1
  6. package/fesm2022/skra-ui-alert.mjs +2 -2
  7. package/fesm2022/skra-ui-alert.mjs.map +1 -1
  8. package/fesm2022/skra-ui-avatar.mjs.map +1 -1
  9. package/fesm2022/skra-ui-badge.mjs.map +1 -1
  10. package/fesm2022/skra-ui-button.mjs +2 -2
  11. package/fesm2022/skra-ui-button.mjs.map +1 -1
  12. package/fesm2022/skra-ui-checkbox.mjs +2 -2
  13. package/fesm2022/skra-ui-checkbox.mjs.map +1 -1
  14. package/fesm2022/skra-ui-chip.mjs +2 -2
  15. package/fesm2022/skra-ui-chip.mjs.map +1 -1
  16. package/fesm2022/skra-ui-combobox.mjs +120 -120
  17. package/fesm2022/skra-ui-combobox.mjs.map +1 -1
  18. package/fesm2022/skra-ui-core.mjs +64 -39
  19. package/fesm2022/skra-ui-core.mjs.map +1 -1
  20. package/fesm2022/skra-ui-counter.mjs.map +1 -1
  21. package/fesm2022/skra-ui-datepicker.mjs +605 -190
  22. package/fesm2022/skra-ui-datepicker.mjs.map +1 -1
  23. package/fesm2022/skra-ui-dialog.mjs.map +1 -1
  24. package/fesm2022/skra-ui-field.mjs.map +1 -1
  25. package/fesm2022/skra-ui-icon.mjs.map +1 -1
  26. package/fesm2022/skra-ui-input.mjs +2 -2
  27. package/fesm2022/skra-ui-input.mjs.map +1 -1
  28. package/fesm2022/skra-ui-kbd.mjs.map +1 -1
  29. package/fesm2022/skra-ui-layout.mjs.map +1 -1
  30. package/fesm2022/skra-ui-link.mjs +2 -2
  31. package/fesm2022/skra-ui-link.mjs.map +1 -1
  32. package/fesm2022/skra-ui-loading-indicator.mjs.map +1 -1
  33. package/fesm2022/skra-ui-menu.mjs +40 -16
  34. package/fesm2022/skra-ui-menu.mjs.map +1 -1
  35. package/fesm2022/skra-ui-multi-select.mjs +94 -94
  36. package/fesm2022/skra-ui-multi-select.mjs.map +1 -1
  37. package/fesm2022/skra-ui-native-select.mjs +2 -2
  38. package/fesm2022/skra-ui-native-select.mjs.map +1 -1
  39. package/fesm2022/skra-ui-popover.mjs +25 -9
  40. package/fesm2022/skra-ui-popover.mjs.map +1 -1
  41. package/fesm2022/skra-ui-progress.mjs.map +1 -1
  42. package/fesm2022/skra-ui-radio.mjs +2 -2
  43. package/fesm2022/skra-ui-radio.mjs.map +1 -1
  44. package/fesm2022/skra-ui-rating-display.mjs +2 -2
  45. package/fesm2022/skra-ui-rating-display.mjs.map +1 -1
  46. package/fesm2022/skra-ui-select.mjs +92 -92
  47. package/fesm2022/skra-ui-select.mjs.map +1 -1
  48. package/fesm2022/skra-ui-skeleton.mjs +8 -8
  49. package/fesm2022/skra-ui-skeleton.mjs.map +1 -1
  50. package/fesm2022/skra-ui-star-rating.mjs +2 -2
  51. package/fesm2022/skra-ui-star-rating.mjs.map +1 -1
  52. package/fesm2022/skra-ui-status-dot.mjs.map +1 -1
  53. package/fesm2022/skra-ui-switch.mjs +2 -2
  54. package/fesm2022/skra-ui-switch.mjs.map +1 -1
  55. package/fesm2022/skra-ui-tabs.mjs +2 -2
  56. package/fesm2022/skra-ui-tabs.mjs.map +1 -1
  57. package/fesm2022/skra-ui-textarea.mjs +2 -2
  58. package/fesm2022/skra-ui-textarea.mjs.map +1 -1
  59. package/fesm2022/skra-ui-toast.mjs +2 -2
  60. package/fesm2022/skra-ui-toast.mjs.map +1 -1
  61. package/fesm2022/skra-ui-tooltip.mjs +7 -2
  62. package/fesm2022/skra-ui-tooltip.mjs.map +1 -1
  63. package/fesm2022/skra-ui-typography.mjs.map +1 -1
  64. package/package.json +3 -3
  65. package/types/skra-ui-core.d.ts.map +1 -1
  66. package/types/skra-ui-datepicker.d.ts +146 -46
  67. package/types/skra-ui-datepicker.d.ts.map +1 -1
  68. package/types/skra-ui-menu.d.ts +18 -6
  69. package/types/skra-ui-menu.d.ts.map +1 -1
  70. package/types/skra-ui-popover.d.ts +13 -4
  71. package/types/skra-ui-popover.d.ts.map +1 -1
  72. package/types/skra-ui-tooltip.d.ts.map +1 -1
@@ -37,8 +37,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
37
37
  }], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }] } });
38
38
 
39
39
  /** A focusable trigger is required (WCAG 2.1.1); used only for the dev-mode nudge. */
40
- const FOCUSABLE_SELECTOR = 'a[href],area[href],button,input,select,textarea,[tabindex],summary,' +
41
- '[contenteditable]:not([contenteditable="false"])';
40
+ // Keyboard-reachable only: a `disabled` control is not focusable (and in most engines fires no
41
+ // pointer events either), and `tabindex="-1"` is programmatically focusable but not tab-reachable.
42
+ // Both were false negatives before — and a tooltip on a `<button disabled>` is THE canonical
43
+ // tooltip a11y trap, i.e. exactly what this dev-mode guard exists to catch.
44
+ const FOCUSABLE_SELECTOR = 'a[href],area[href],button:not([disabled]),input:not([disabled]),' +
45
+ 'select:not([disabled]),textarea:not([disabled]),summary,' +
46
+ '[tabindex]:not([tabindex^="-"]),[contenteditable]:not([contenteditable="false"])';
42
47
  /**
43
48
  * SkraTooltip — a supplementary, non-interactive text description on a focusable trigger, shown on
44
49
  * hover AND keyboard focus (ADR 0044 native top layer via the Popover API). Applied to the consumer's
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-tooltip.mjs","sources":["../../../../libs/ui/tooltip/src/lib/tooltip/tooltip-panel.ts","../../../../libs/ui/tooltip/src/lib/tooltip/tooltip.ts","../../../../libs/ui/tooltip/src/skra-ui-tooltip.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nlet nextId = 0;\r\n\r\n/**\r\n * SkraTooltipPanel — the floating tooltip surface (ADR 0044 native top layer via the Popover API).\r\n *\r\n * INTERNAL: never placed by consumers in a template. `SkraTooltip` creates it programmatically with\r\n * `ViewContainerRef.createComponent` (Angular-idiomatic, in-tree → inherits the design-context cascade\r\n * + the O-8 Shadow-DOM bridge per ADR 0044 §3 rule 3) and drives `showPopover()`/`hidePopover()` on the\r\n * host element.\r\n *\r\n * `popover=\"manual\"` (NOT `auto`): a hover/focus tooltip's show/hide is Forge-owned, not click-toggle\r\n * light-dismiss. `role=\"tooltip\"` is the AT semantics; the trigger references this panel's `id` via\r\n * `aria-describedby` (wired by the directive). The 13-axis Universal Surface (ADR 025) + motion live in\r\n * `tooltip.scss`; geometry (`left`/`top` + `data-skra-placement`) is written by `SkraPositioner`.\r\n *\r\n * Full contract: adr/specs/component-tooltip-spec.md.\r\n */\r\n@Component({\r\n selector: 'skra-tooltip-panel',\r\n standalone: true,\r\n template: '{{ text() }}',\r\n styleUrl: './tooltip.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'tooltip',\r\n popover: 'manual',\r\n '[id]': 'panelId',\r\n },\r\n})\r\nexport class SkraTooltipPanel {\r\n /** Tooltip text; set by the directive and kept in sync. */\r\n readonly text = input<string>('');\r\n\r\n /** Stable unique id — target of the trigger's `aria-describedby`. */\r\n readonly panelId = `skra-tooltip-${nextId++}`;\r\n}\r\n","import {\r\n ComponentRef,\r\n DestroyRef,\r\n Directive,\r\n ElementRef,\r\n Renderer2,\r\n ViewContainerRef,\r\n effect,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\n\r\nimport {\r\n _attachPositioner,\r\n type SkraPlacement,\r\n type _PositionerHandle,\r\n} from '@skra/ui/core';\r\nimport { SkraTooltipPanel } from './tooltip-panel';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/** A focusable trigger is required (WCAG 2.1.1); used only for the dev-mode nudge. */\r\nconst FOCUSABLE_SELECTOR =\r\n 'a[href],area[href],button,input,select,textarea,[tabindex],summary,' +\r\n '[contenteditable]:not([contenteditable=\"false\"])';\r\n\r\n/**\r\n * SkraTooltip — a supplementary, non-interactive text description on a focusable trigger, shown on\r\n * hover AND keyboard focus (ADR 0044 native top layer via the Popover API). Applied to the consumer's\r\n * own trigger: `<button skraButton [skraTooltip]=\"'Settings'\">`.\r\n *\r\n * The bulk of this directive is the WCAG 1.4.13 (Content on Hover or Focus) state machine — the\r\n * platform's `popover=\"manual\"` gives top-layer rendering but no dismiss/Escape, so Forge wires it:\r\n * - Dismissible: Escape hides WITHOUT moving focus.\r\n * - Hoverable: a hide grace-delay lets the pointer travel trigger→panel; hovering the panel keeps it.\r\n * - Persistent: no auto-timeout.\r\n * - Keyboard: focus shows immediately (no delay).\r\n *\r\n * Accessible-name contract (ADR 033, describedby-only): the tooltip is a DESCRIPTION, never the name —\r\n * it MERGES its panel id into the trigger's `aria-describedby` (preserving any existing value) and\r\n * removes only its own token on destroy. The trigger owns its own accessible name (an icon-only button\r\n * still needs its own `aria-label`). No `ariaLabel` input, no `aria-labelledby` wiring.\r\n *\r\n * The panel is created EAGERLY (hidden) so `aria-describedby` resolves and a screen reader announces\r\n * the description on first focus. Positioning is delegated to `SkraPositioner` (single JS path,\r\n * geometry-only inline; ADR 0044 §3 rules 4–5). Full contract: adr/specs/component-tooltip-spec.md.\r\n */\r\n@Directive({\r\n selector: '[skraTooltip]',\r\n standalone: true,\r\n exportAs: 'skraTooltip',\r\n host: {\r\n '(pointerenter)': 'onPointerEnter()',\r\n '(pointerleave)': 'onPointerLeave()',\r\n '(focusin)': 'onFocusIn()',\r\n '(focusout)': 'onFocusOut()',\r\n },\r\n})\r\nexport class SkraTooltip {\r\n /** The tooltip text (bound as `[skraTooltip]=\"...\"`). */\r\n readonly skraTooltip = input.required<string>();\r\n /** Placement intent; `flip`/`shift` adjust at runtime. */\r\n readonly placement = input<SkraPlacement>('top');\r\n\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n private readonly vcr = inject(ViewContainerRef);\r\n private readonly renderer = inject(Renderer2);\r\n\r\n private readonly panelRef: ComponentRef<SkraTooltipPanel>;\r\n private readonly panelEl: HTMLElement;\r\n private readonly panelId: string;\r\n\r\n private positioner?: _PositionerHandle;\r\n private showTimer?: ReturnType<typeof setTimeout>;\r\n private hideTimer?: ReturnType<typeof setTimeout>;\r\n private docEscapeUnlisten?: () => void;\r\n\r\n private open = false;\r\n private hovered = false;\r\n private focused = false;\r\n private panelHovered = false;\r\n\r\n constructor() {\r\n // Eager, in-tree panel (ADR 0044 §3 rule 3): inherits the design-context cascade + O-8 bridge.\r\n this.panelRef = this.vcr.createComponent(SkraTooltipPanel);\r\n this.panelEl = this.panelRef.location.nativeElement as HTMLElement;\r\n this.panelId = this.panelRef.instance.panelId;\r\n\r\n // Describedby-only (ADR 033) — merge, never overwrite.\r\n this.wireDescribedBy();\r\n\r\n // Keep the panel text in sync with the input (effect runs after inputs are set).\r\n effect(() => this.panelRef.setInput('text', this.skraTooltip()));\r\n\r\n // Hoverable (WCAG 1.4.13): hovering the panel itself keeps the tooltip open.\r\n this.renderer.listen(this.panelEl, 'pointerenter', () => {\r\n this.panelHovered = true;\r\n clearTimeout(this.hideTimer);\r\n });\r\n this.renderer.listen(this.panelEl, 'pointerleave', () => {\r\n this.panelHovered = false;\r\n this.scheduleHide();\r\n });\r\n\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n this.warnIfTriggerNotFocusable();\r\n }\r\n\r\n inject(DestroyRef).onDestroy(() => this.teardown());\r\n }\r\n\r\n // ── Trigger events ──────────────────────────────────────────────────────────\r\n protected onPointerEnter(): void {\r\n this.hovered = true;\r\n this.scheduleShow();\r\n }\r\n\r\n protected onPointerLeave(): void {\r\n this.hovered = false;\r\n this.scheduleHide();\r\n }\r\n\r\n protected onFocusIn(): void {\r\n this.focused = true;\r\n // Keyboard users get it immediately (WCAG 2.1.1) — no show-delay.\r\n clearTimeout(this.showTimer);\r\n clearTimeout(this.hideTimer);\r\n this.show();\r\n }\r\n\r\n protected onFocusOut(): void {\r\n this.focused = false;\r\n this.scheduleHide();\r\n }\r\n\r\n // ── Show / hide state machine ─────────────────────────────────────────────────\r\n private scheduleShow(): void {\r\n clearTimeout(this.hideTimer);\r\n if (this.open) return;\r\n clearTimeout(this.showTimer);\r\n this.showTimer = setTimeout(\r\n () => this.show(),\r\n this.cssTimeMs('--skra-comp-tooltip-show-delay'),\r\n );\r\n }\r\n\r\n private scheduleHide(): void {\r\n clearTimeout(this.showTimer);\r\n clearTimeout(this.hideTimer);\r\n this.hideTimer = setTimeout(() => {\r\n // Only hide once nothing keeps it engaged (hoverable + focus coordination).\r\n if (!this.hovered && !this.focused && !this.panelHovered) this.hide();\r\n }, this.cssTimeMs('--skra-comp-tooltip-hide-delay'));\r\n }\r\n\r\n private show(): void {\r\n clearTimeout(this.showTimer);\r\n if (this.open) return;\r\n this.open = true;\r\n\r\n this.panelEl.showPopover?.();\r\n\r\n this.positioner?.destroy();\r\n this.positioner = _attachPositioner(\r\n this.host.nativeElement,\r\n this.panelEl,\r\n () => ({\r\n placement: this.placement(),\r\n offset: this.cssLenPx('--skra-comp-tooltip-offset'),\r\n viewportPadding: this.cssLenPx('--skra-comp-tooltip-viewport-padding'),\r\n }),\r\n );\r\n\r\n // Dismissible (WCAG 1.4.13): Escape hides without moving focus. Transient document listener\r\n // (active only while open) so Escape works even for a hover-triggered tooltip whose trigger is\r\n // not focused — `popover=\"manual\"` does not provide platform Escape.\r\n this.docEscapeUnlisten = this.renderer.listen(\r\n 'document',\r\n 'keydown',\r\n (event: KeyboardEvent) => {\r\n if (event.key === 'Escape') this.hide();\r\n },\r\n );\r\n }\r\n\r\n private hide(): void {\r\n clearTimeout(this.showTimer);\r\n clearTimeout(this.hideTimer);\r\n if (!this.open) return;\r\n this.open = false;\r\n\r\n this.panelEl.hidePopover?.();\r\n this.positioner?.destroy();\r\n this.positioner = undefined;\r\n this.docEscapeUnlisten?.();\r\n this.docEscapeUnlisten = undefined;\r\n }\r\n\r\n // ── aria-describedby merge (ADR 033 / ADR 013-style wiring) ───────────────────\r\n private wireDescribedBy(): void {\r\n const tokens = this.describedByTokens();\r\n if (!tokens.includes(this.panelId)) tokens.push(this.panelId);\r\n this.renderer.setAttribute(\r\n this.host.nativeElement,\r\n 'aria-describedby',\r\n tokens.join(' '),\r\n );\r\n }\r\n\r\n private unwireDescribedBy(): void {\r\n const remaining = this.describedByTokens().filter(\r\n (t) => t !== this.panelId,\r\n );\r\n if (remaining.length) {\r\n this.renderer.setAttribute(\r\n this.host.nativeElement,\r\n 'aria-describedby',\r\n remaining.join(' '),\r\n );\r\n } else {\r\n this.renderer.removeAttribute(\r\n this.host.nativeElement,\r\n 'aria-describedby',\r\n );\r\n }\r\n }\r\n\r\n private describedByTokens(): string[] {\r\n return (this.host.nativeElement.getAttribute('aria-describedby') ?? '')\r\n .split(/\\s+/)\r\n .filter(Boolean);\r\n }\r\n\r\n // ── token resolution helpers (read computed comp tokens at runtime) ───────────\r\n private cssTimeMs(prop: string): number {\r\n const raw = getComputedStyle(this.panelEl).getPropertyValue(prop).trim();\r\n if (raw.endsWith('ms')) return parseFloat(raw);\r\n if (raw.endsWith('s')) return parseFloat(raw) * 1000;\r\n return parseFloat(raw) || 0;\r\n }\r\n\r\n private cssLenPx(prop: string): number {\r\n const raw = getComputedStyle(this.panelEl).getPropertyValue(prop).trim();\r\n if (raw.endsWith('px')) return parseFloat(raw);\r\n if (raw.endsWith('rem')) {\r\n const rootFontSize =\r\n parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;\r\n return parseFloat(raw) * rootFontSize;\r\n }\r\n return parseFloat(raw) || 0;\r\n }\r\n\r\n private warnIfTriggerNotFocusable(): void {\r\n const el = this.host.nativeElement;\r\n if (!el.matches(FOCUSABLE_SELECTOR)) {\r\n console.warn(\r\n '[skraTooltip] host is not focusable — the tooltip is unreachable by keyboard ' +\r\n '(WCAG 2.1.1) and never shows on focus. Apply it to a button/link/form control, ' +\r\n 'or add tabindex to the trigger.',\r\n );\r\n }\r\n }\r\n\r\n private teardown(): void {\r\n clearTimeout(this.showTimer);\r\n clearTimeout(this.hideTimer);\r\n this.docEscapeUnlisten?.();\r\n this.positioner?.destroy();\r\n this.unwireDescribedBy();\r\n this.panelRef.destroy();\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skra-ui-tooltip.mjs","sources":["../../../../libs/ui/tooltip/src/lib/tooltip/tooltip-panel.ts","../../../../libs/ui/tooltip/src/lib/tooltip/tooltip.ts","../../../../libs/ui/tooltip/src/skra-ui-tooltip.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n input,\n} from '@angular/core';\n\nlet nextId = 0;\n\n/**\n * SkraTooltipPanel — the floating tooltip surface (ADR 0044 native top layer via the Popover API).\n *\n * INTERNAL: never placed by consumers in a template. `SkraTooltip` creates it programmatically with\n * `ViewContainerRef.createComponent` (Angular-idiomatic, in-tree → inherits the design-context cascade\n * + the O-8 Shadow-DOM bridge per ADR 0044 §3 rule 3) and drives `showPopover()`/`hidePopover()` on the\n * host element.\n *\n * `popover=\"manual\"` (NOT `auto`): a hover/focus tooltip's show/hide is Forge-owned, not click-toggle\n * light-dismiss. `role=\"tooltip\"` is the AT semantics; the trigger references this panel's `id` via\n * `aria-describedby` (wired by the directive). The 13-axis Universal Surface (ADR 025) + motion live in\n * `tooltip.scss`; geometry (`left`/`top` + `data-skra-placement`) is written by `SkraPositioner`.\n *\n * Full contract: adr/specs/component-tooltip-spec.md.\n */\n@Component({\n selector: 'skra-tooltip-panel',\n standalone: true,\n template: '{{ text() }}',\n styleUrl: './tooltip.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n role: 'tooltip',\n popover: 'manual',\n '[id]': 'panelId',\n },\n})\nexport class SkraTooltipPanel {\n /** Tooltip text; set by the directive and kept in sync. */\n readonly text = input<string>('');\n\n /** Stable unique id — target of the trigger's `aria-describedby`. */\n readonly panelId = `skra-tooltip-${nextId++}`;\n}\n","import {\r\n ComponentRef,\r\n DestroyRef,\r\n Directive,\r\n ElementRef,\r\n Renderer2,\r\n ViewContainerRef,\r\n effect,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\n\r\nimport {\r\n _attachPositioner,\r\n type SkraPlacement,\r\n type _PositionerHandle,\r\n} from '@skra/ui/core';\r\nimport { SkraTooltipPanel } from './tooltip-panel';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/** A focusable trigger is required (WCAG 2.1.1); used only for the dev-mode nudge. */\r\n// Keyboard-reachable only: a `disabled` control is not focusable (and in most engines fires no\r\n// pointer events either), and `tabindex=\"-1\"` is programmatically focusable but not tab-reachable.\r\n// Both were false negatives before — and a tooltip on a `<button disabled>` is THE canonical\r\n// tooltip a11y trap, i.e. exactly what this dev-mode guard exists to catch.\r\nconst FOCUSABLE_SELECTOR =\r\n 'a[href],area[href],button:not([disabled]),input:not([disabled]),' +\r\n 'select:not([disabled]),textarea:not([disabled]),summary,' +\r\n '[tabindex]:not([tabindex^=\"-\"]),[contenteditable]:not([contenteditable=\"false\"])';\r\n\r\n/**\r\n * SkraTooltip — a supplementary, non-interactive text description on a focusable trigger, shown on\r\n * hover AND keyboard focus (ADR 0044 native top layer via the Popover API). Applied to the consumer's\r\n * own trigger: `<button skraButton [skraTooltip]=\"'Settings'\">`.\r\n *\r\n * The bulk of this directive is the WCAG 1.4.13 (Content on Hover or Focus) state machine — the\r\n * platform's `popover=\"manual\"` gives top-layer rendering but no dismiss/Escape, so Forge wires it:\r\n * - Dismissible: Escape hides WITHOUT moving focus.\r\n * - Hoverable: a hide grace-delay lets the pointer travel trigger→panel; hovering the panel keeps it.\r\n * - Persistent: no auto-timeout.\r\n * - Keyboard: focus shows immediately (no delay).\r\n *\r\n * Accessible-name contract (ADR 033, describedby-only): the tooltip is a DESCRIPTION, never the name —\r\n * it MERGES its panel id into the trigger's `aria-describedby` (preserving any existing value) and\r\n * removes only its own token on destroy. The trigger owns its own accessible name (an icon-only button\r\n * still needs its own `aria-label`). No `ariaLabel` input, no `aria-labelledby` wiring.\r\n *\r\n * The panel is created EAGERLY (hidden) so `aria-describedby` resolves and a screen reader announces\r\n * the description on first focus. Positioning is delegated to `SkraPositioner` (single JS path,\r\n * geometry-only inline; ADR 0044 §3 rules 4–5). Full contract: adr/specs/component-tooltip-spec.md.\r\n */\r\n@Directive({\r\n selector: '[skraTooltip]',\r\n standalone: true,\r\n exportAs: 'skraTooltip',\r\n host: {\r\n '(pointerenter)': 'onPointerEnter()',\r\n '(pointerleave)': 'onPointerLeave()',\r\n '(focusin)': 'onFocusIn()',\r\n '(focusout)': 'onFocusOut()',\r\n },\r\n})\r\nexport class SkraTooltip {\r\n /** The tooltip text (bound as `[skraTooltip]=\"...\"`). */\r\n readonly skraTooltip = input.required<string>();\r\n /** Placement intent; `flip`/`shift` adjust at runtime. */\r\n readonly placement = input<SkraPlacement>('top');\r\n\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n private readonly vcr = inject(ViewContainerRef);\r\n private readonly renderer = inject(Renderer2);\r\n\r\n private readonly panelRef: ComponentRef<SkraTooltipPanel>;\r\n private readonly panelEl: HTMLElement;\r\n private readonly panelId: string;\r\n\r\n private positioner?: _PositionerHandle;\r\n private showTimer?: ReturnType<typeof setTimeout>;\r\n private hideTimer?: ReturnType<typeof setTimeout>;\r\n private docEscapeUnlisten?: () => void;\r\n\r\n private open = false;\r\n private hovered = false;\r\n private focused = false;\r\n private panelHovered = false;\r\n\r\n constructor() {\r\n // Eager, in-tree panel (ADR 0044 §3 rule 3): inherits the design-context cascade + O-8 bridge.\r\n this.panelRef = this.vcr.createComponent(SkraTooltipPanel);\r\n this.panelEl = this.panelRef.location.nativeElement as HTMLElement;\r\n this.panelId = this.panelRef.instance.panelId;\r\n\r\n // Describedby-only (ADR 033) — merge, never overwrite.\r\n this.wireDescribedBy();\r\n\r\n // Keep the panel text in sync with the input (effect runs after inputs are set).\r\n effect(() => this.panelRef.setInput('text', this.skraTooltip()));\r\n\r\n // Hoverable (WCAG 1.4.13): hovering the panel itself keeps the tooltip open.\r\n this.renderer.listen(this.panelEl, 'pointerenter', () => {\r\n this.panelHovered = true;\r\n clearTimeout(this.hideTimer);\r\n });\r\n this.renderer.listen(this.panelEl, 'pointerleave', () => {\r\n this.panelHovered = false;\r\n this.scheduleHide();\r\n });\r\n\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n this.warnIfTriggerNotFocusable();\r\n }\r\n\r\n inject(DestroyRef).onDestroy(() => this.teardown());\r\n }\r\n\r\n // ── Trigger events ──────────────────────────────────────────────────────────\r\n protected onPointerEnter(): void {\r\n this.hovered = true;\r\n this.scheduleShow();\r\n }\r\n\r\n protected onPointerLeave(): void {\r\n this.hovered = false;\r\n this.scheduleHide();\r\n }\r\n\r\n protected onFocusIn(): void {\r\n this.focused = true;\r\n // Keyboard users get it immediately (WCAG 2.1.1) — no show-delay.\r\n clearTimeout(this.showTimer);\r\n clearTimeout(this.hideTimer);\r\n this.show();\r\n }\r\n\r\n protected onFocusOut(): void {\r\n this.focused = false;\r\n this.scheduleHide();\r\n }\r\n\r\n // ── Show / hide state machine ─────────────────────────────────────────────────\r\n private scheduleShow(): void {\r\n clearTimeout(this.hideTimer);\r\n if (this.open) return;\r\n clearTimeout(this.showTimer);\r\n this.showTimer = setTimeout(\r\n () => this.show(),\r\n this.cssTimeMs('--skra-comp-tooltip-show-delay'),\r\n );\r\n }\r\n\r\n private scheduleHide(): void {\r\n clearTimeout(this.showTimer);\r\n clearTimeout(this.hideTimer);\r\n this.hideTimer = setTimeout(() => {\r\n // Only hide once nothing keeps it engaged (hoverable + focus coordination).\r\n if (!this.hovered && !this.focused && !this.panelHovered) this.hide();\r\n }, this.cssTimeMs('--skra-comp-tooltip-hide-delay'));\r\n }\r\n\r\n private show(): void {\r\n clearTimeout(this.showTimer);\r\n if (this.open) return;\r\n this.open = true;\r\n\r\n this.panelEl.showPopover?.();\r\n\r\n this.positioner?.destroy();\r\n this.positioner = _attachPositioner(\r\n this.host.nativeElement,\r\n this.panelEl,\r\n () => ({\r\n placement: this.placement(),\r\n offset: this.cssLenPx('--skra-comp-tooltip-offset'),\r\n viewportPadding: this.cssLenPx('--skra-comp-tooltip-viewport-padding'),\r\n }),\r\n );\r\n\r\n // Dismissible (WCAG 1.4.13): Escape hides without moving focus. Transient document listener\r\n // (active only while open) so Escape works even for a hover-triggered tooltip whose trigger is\r\n // not focused — `popover=\"manual\"` does not provide platform Escape.\r\n this.docEscapeUnlisten = this.renderer.listen(\r\n 'document',\r\n 'keydown',\r\n (event: KeyboardEvent) => {\r\n if (event.key === 'Escape') this.hide();\r\n },\r\n );\r\n }\r\n\r\n private hide(): void {\r\n clearTimeout(this.showTimer);\r\n clearTimeout(this.hideTimer);\r\n if (!this.open) return;\r\n this.open = false;\r\n\r\n this.panelEl.hidePopover?.();\r\n this.positioner?.destroy();\r\n this.positioner = undefined;\r\n this.docEscapeUnlisten?.();\r\n this.docEscapeUnlisten = undefined;\r\n }\r\n\r\n // ── aria-describedby merge (ADR 033 / ADR 013-style wiring) ───────────────────\r\n private wireDescribedBy(): void {\r\n const tokens = this.describedByTokens();\r\n if (!tokens.includes(this.panelId)) tokens.push(this.panelId);\r\n this.renderer.setAttribute(\r\n this.host.nativeElement,\r\n 'aria-describedby',\r\n tokens.join(' '),\r\n );\r\n }\r\n\r\n private unwireDescribedBy(): void {\r\n const remaining = this.describedByTokens().filter(\r\n (t) => t !== this.panelId,\r\n );\r\n if (remaining.length) {\r\n this.renderer.setAttribute(\r\n this.host.nativeElement,\r\n 'aria-describedby',\r\n remaining.join(' '),\r\n );\r\n } else {\r\n this.renderer.removeAttribute(\r\n this.host.nativeElement,\r\n 'aria-describedby',\r\n );\r\n }\r\n }\r\n\r\n private describedByTokens(): string[] {\r\n return (this.host.nativeElement.getAttribute('aria-describedby') ?? '')\r\n .split(/\\s+/)\r\n .filter(Boolean);\r\n }\r\n\r\n // ── token resolution helpers (read computed comp tokens at runtime) ───────────\r\n private cssTimeMs(prop: string): number {\r\n const raw = getComputedStyle(this.panelEl).getPropertyValue(prop).trim();\r\n if (raw.endsWith('ms')) return parseFloat(raw);\r\n if (raw.endsWith('s')) return parseFloat(raw) * 1000;\r\n return parseFloat(raw) || 0;\r\n }\r\n\r\n private cssLenPx(prop: string): number {\r\n const raw = getComputedStyle(this.panelEl).getPropertyValue(prop).trim();\r\n if (raw.endsWith('px')) return parseFloat(raw);\r\n if (raw.endsWith('rem')) {\r\n const rootFontSize =\r\n parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;\r\n return parseFloat(raw) * rootFontSize;\r\n }\r\n return parseFloat(raw) || 0;\r\n }\r\n\r\n private warnIfTriggerNotFocusable(): void {\r\n const el = this.host.nativeElement;\r\n if (!el.matches(FOCUSABLE_SELECTOR)) {\r\n console.warn(\r\n '[skraTooltip] host is not focusable — the tooltip is unreachable by keyboard ' +\r\n '(WCAG 2.1.1) and never shows on focus. Apply it to a button/link/form control, ' +\r\n 'or add tabindex to the trigger.',\r\n );\r\n }\r\n }\r\n\r\n private teardown(): void {\r\n clearTimeout(this.showTimer);\r\n clearTimeout(this.hideTimer);\r\n this.docEscapeUnlisten?.();\r\n this.positioner?.destroy();\r\n this.unwireDescribedBy();\r\n this.panelRef.destroy();\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-typography.mjs","sources":["../../../../libs/ui/typography/src/lib/typography/typography.ts","../../../../libs/ui/typography/src/skra-ui-typography.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type TypographyRole =\r\n | 'display-large'\r\n | 'display-medium'\r\n | 'display-small'\r\n | 'headline-large'\r\n | 'headline-medium'\r\n | 'headline-small'\r\n | 'title-large'\r\n | 'title-medium'\r\n | 'title-small'\r\n | 'body-large'\r\n | 'body-medium'\r\n | 'body-small'\r\n | 'label-large'\r\n | 'label-medium'\r\n | 'label-small';\r\n\r\nexport type TypographySeverity = 'error' | 'warning' | 'success';\r\nexport type TypographyTruncate = 'single' | 'multi';\r\n\r\n@Component({\r\n selector: '[skraTypography]',\r\n standalone: true,\r\n imports: [],\r\n template: '<ng-content />',\r\n styleUrl: './typography.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // ADR 021 — CSP-safe state reflection. The zero-margin reset (ADR 022)\r\n // lives in typography.scss `:host` — host-metadata bare keys would render\r\n // as junk attributes, not styles.\r\n '[attr.data-skra-typo-role]': 'role()',\r\n '[attr.data-skra-severity]': 'severity()',\r\n '[attr.data-skra-truncate]': 'truncate()',\r\n // Line-clamp count — reflected as an enumerated data-attribute, consumed by\r\n // static `-webkit-line-clamp` rules in typography.scss (buckets 2–6). NOT a\r\n // `[style.--var]` binding (ADR 021 iron boundary) — same enumerated-bucket\r\n // approach Grid/Stack use to keep CSP-safe. Values outside 2–6 fall back to\r\n // the base 2-line rule.\r\n '[attr.data-skra-line-clamp]':\r\n 'truncate() === \"multi\" ? lineClamp() : null',\r\n },\r\n})\r\nexport class SkraTypography {\r\n readonly role = input<TypographyRole>('body-medium', {\r\n alias: 'skraTypography',\r\n });\r\n readonly severity = input<TypographySeverity | null>(null);\r\n readonly truncate = input<TypographyTruncate | null>(null);\r\n readonly lineClamp = input<number>(2);\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;MAmDa,cAAc,CAAA;IAChB,IAAI,GAAG,KAAK,CAAiB,aAAa,4EACjD,KAAK,EAAE,gBAAgB,EAAA,CACvB;IACO,QAAQ,GAAG,KAAK,CAA4B,IAAI;iFAAC;IACjD,QAAQ,GAAG,KAAK,CAA4B,IAAI;iFAAC;IACjD,SAAS,GAAG,KAAK,CAAS,CAAC;kFAAC;uGAN1B,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAd,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,cAAc,6zBApBf,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,23TAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAoBf,cAAc,EAAA,UAAA,EAAA,CAAA;kBAxB1B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,kBAAkB,EAAA,UAAA,EAChB,IAAI,EAAA,OAAA,EACP,EAAE,YACD,gBAAgB,EAAA,eAAA,EAET,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;;;AAIJ,wBAAA,4BAA4B,EAAE,QAAQ;AACtC,wBAAA,2BAA2B,EAAE,YAAY;AACzC,wBAAA,2BAA2B,EAAE,YAAY;;;;;;AAMzC,wBAAA,6BAA6B,EAC3B,6CAA6C;AAChD,qBAAA,EAAA,MAAA,EAAA,CAAA,23TAAA,CAAA,EAAA;;;ACjDH;;AAEG;;;;"}
1
+ {"version":3,"file":"skra-ui-typography.mjs","sources":["../../../../libs/ui/typography/src/lib/typography/typography.ts","../../../../libs/ui/typography/src/skra-ui-typography.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n input,\n} from '@angular/core';\n\nexport type TypographyRole =\n | 'display-large'\n | 'display-medium'\n | 'display-small'\n | 'headline-large'\n | 'headline-medium'\n | 'headline-small'\n | 'title-large'\n | 'title-medium'\n | 'title-small'\n | 'body-large'\n | 'body-medium'\n | 'body-small'\n | 'label-large'\n | 'label-medium'\n | 'label-small';\n\nexport type TypographySeverity = 'error' | 'warning' | 'success';\nexport type TypographyTruncate = 'single' | 'multi';\n\n@Component({\n selector: '[skraTypography]',\n standalone: true,\n imports: [],\n template: '<ng-content />',\n styleUrl: './typography.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // ADR 021 — CSP-safe state reflection. The zero-margin reset (ADR 022)\n // lives in typography.scss `:host` — host-metadata bare keys would render\n // as junk attributes, not styles.\n '[attr.data-skra-typo-role]': 'role()',\n '[attr.data-skra-severity]': 'severity()',\n '[attr.data-skra-truncate]': 'truncate()',\n // Line-clamp count — reflected as an enumerated data-attribute, consumed by\n // static `-webkit-line-clamp` rules in typography.scss (buckets 2–6). NOT a\n // `[style.--var]` binding (ADR 021 iron boundary) — same enumerated-bucket\n // approach Grid/Stack use to keep CSP-safe. Values outside 2–6 fall back to\n // the base 2-line rule.\n '[attr.data-skra-line-clamp]':\n 'truncate() === \"multi\" ? lineClamp() : null',\n },\n})\nexport class SkraTypography {\n readonly role = input<TypographyRole>('body-medium', {\n alias: 'skraTypography',\n });\n readonly severity = input<TypographySeverity | null>(null);\n readonly truncate = input<TypographyTruncate | null>(null);\n readonly lineClamp = input<number>(2);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;MAmDa,cAAc,CAAA;IAChB,IAAI,GAAG,KAAK,CAAiB,aAAa,4EACjD,KAAK,EAAE,gBAAgB,EAAA,CACvB;IACO,QAAQ,GAAG,KAAK,CAA4B,IAAI;iFAAC;IACjD,QAAQ,GAAG,KAAK,CAA4B,IAAI;iFAAC;IACjD,SAAS,GAAG,KAAK,CAAS,CAAC;kFAAC;uGAN1B,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAd,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,cAAc,6zBApBf,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,23TAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAoBf,cAAc,EAAA,UAAA,EAAA,CAAA;kBAxB1B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,kBAAkB,EAAA,UAAA,EAChB,IAAI,EAAA,OAAA,EACP,EAAE,YACD,gBAAgB,EAAA,eAAA,EAET,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;;;AAIJ,wBAAA,4BAA4B,EAAE,QAAQ;AACtC,wBAAA,2BAA2B,EAAE,YAAY;AACzC,wBAAA,2BAA2B,EAAE,YAAY;;;;;;AAMzC,wBAAA,6BAA6B,EAC3B,6CAA6C;AAChD,qBAAA,EAAA,MAAA,EAAA,CAAA,23TAAA,CAAA,EAAA;;;ACjDH;;AAEG;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skra/ui",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "license": "Apache-2.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -10,7 +10,7 @@
10
10
  "@angular/core": ">=22.0.0 <23.0.0",
11
11
  "@angular/common": ">=22.0.0 <23.0.0",
12
12
  "@angular/cdk": ">=22.0.0 <23.0.0",
13
- "@skra/tokens": "^0.4.0"
13
+ "@skra/tokens": "^0.6.0"
14
14
  },
15
15
  "dependencies": {
16
16
  "@floating-ui/dom": "^1.7.6",
@@ -172,4 +172,4 @@
172
172
  }
173
173
  },
174
174
  "type": "module"
175
- }
175
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-core.d.ts","sources":["../../../../libs/ui/core/src/lib/select/select-types.ts","../../../../libs/ui/core/src/lib/select/option.ts","../../../../libs/ui/core/src/lib/select/option.directives.ts","../../../../libs/ui/core/src/lib/select/select-trigger.ts","../../../../libs/ui/core/src/lib/positioning/positioner.ts","../../../../libs/ui/core/src/lib/select/listbox-keyboard.ts","../../../../libs/ui/core/src/lib/select/listbox-widget-base.ts","../../../../libs/ui/core/src/lib/select/select-base.ts"],"mappings":";;;;AAEA;;;;;AAKG;UACc,gBAAgB;;AAE/B;AACA;;;;AAIG;AACH;AACA;;;;AAIG;AACH;AACD;AAED;;;;;AAKG;UACc,uBAAuB;AACtC;;;;;AAKA;AACD;AAED;;;;AAIG;AACH,cAAa,kBAAkB,EAAA,cAAA,CAAA,gBAAA;;ACvB/B;;;;;;;;;;;;;;;AAeG;AACH,cAkCa,UAAU,yBAAyB,uBAAuB;;oBAEvD,aAAA,CAAA,WAAA;;;AAKd;AACA;AAEA;AACA;AACA,mCAA6B,aAAA,CAAA,MAAA;AAC7B,kCAA4B,aAAA,CAAA,MAAA;;AAG5B,+BAAyB,aAAA,CAAA,cAAA;AAEzB;;;;AAIG;AACH,iCAA2B,aAAA,CAAA,MAAA;;AAG3B,iCAA2B,aAAA,CAAA,MAAA;;AAgB3B;AAGA;AAIA;;;;;AAKG;AACH;AAqBA;;;;oDA5EW,UAAU;sDAAV,UAAU;AAyFtB;;AC/JD;;;AAGG;AACH,cAIa,iBAAiB;oDAAjB,iBAAiB;sDAAjB,iBAAiB;AAAG;AAEjC;;;AAGG;AACH,cAIa,gBAAgB;oDAAhB,gBAAgB;sDAAhB,gBAAgB;AAAG;;AClBhC;;;;;;;;;;;;;AAaG;AACH,cAIa,iBAAiB;oDAAjB,iBAAiB;sDAAjB,iBAAiB;AAAG;;ACXjC;;;;;;;;;;;;;;AAcG;AAEH;AACM,KAAM,aAAa;UAER,kBAAkB;;eAEtB,aAAa;;;;;AAKzB;UAEgB,iBAAiB;;;AAGjC;AAED;;;;;AAKG;AACH,iBAAgB,iBAAiB,YACpB,WAAW,YACZ,WAAW,iBACN,kBAAkB,GAChC,iBAAiB;;AChDpB;;;;;;;;;;AAUG;AACH,cAAa,oBAAoB;;;;;AAM/B,mCACkB,uBAAuB;AAKzC;;;;AAIG;AACH,6BAAyB,uBAAuB;;AAiBhD,qBAAiB,aAAa;AAI9B,sBAAkB,uBAAuB;;AAKzC,oBAAgB,uBAAuB;;AAOvC;AAIA;AAID;;AC/CD;;;;;;;;;;;;;;;;;;;;;AAqBG;AACH,uBAQsB,sBAAsB,yBAC/B,gBAAgB;;0BAGP,aAAA,CAAA,WAAA;;0BAEA,aAAA,CAAA,WAAA;;wBAEF,aAAA,CAAA,WAAA,CAAA,aAAA;;uBAED,aAAA,CAAA,wBAAA;uBACA,aAAA,CAAA,wBAAA;AAEjB,gCAA0B,aAAA,CAAA,MAAA,UAAA,UAAA;AAE1B,mCAA6B,aAAA,CAAA,MAAA,CAAA,UAAA,CAAA,WAAA;AAC7B,iCAA2B,aAAA,CAAA,MAAA,CAAA,UAAA,CAAA,WAAA;AAE3B,gCAA0B,gBAAA;AAC1B,iCAA2B,oBAAA;;AAG3B,+BAAyB,aAAA,CAAA,cAAA;AACzB,uCAAiC,aAAA,CAAA,cAAA;;;;AAQjC,mCAA6B,aAAA,CAAA,MAAA;AAG7B,mCAA6B,aAAA,CAAA,MAAA;AAG7B,iCAA2B,aAAA,CAAA,MAAA;AAG3B,mCAA6B,aAAA,CAAA,MAAA;AAG7B,kCAA4B,aAAA,CAAA,MAAA;AAG5B,oCAA8B,aAAA,CAAA,MAAA;;;AAgB9B;;AAEA;;AAEA;;AAEA,yCAAqC,uBAAuB;AAG5D,mCAA+B,KAAK;AAOpC;;;;;AAKG;AACH,mCAA+B,WAAW;AAI1C;AAqBA;;;;;;AAqBA;AAaA;oDA/IoB,sBAAsB;sDAAtB,sBAAsB;AAmJ3C;;ACtMD;;;;;;;;;;;;AAYG;AACH,uBACsB,eAAe,sBAE3B,sBAAsB;;AAE9B;;AAGA,wCAAkC,aAAA,CAAA,MAAA,CAAA,WAAA;AAKlC,oCAAgC,UAAU;AAK1C,sCAAkC,aAAa;oDAjB3B,eAAe;sDAAf,eAAe;AAuDpC;;;;","names":[]}
1
+ {"version":3,"file":"skra-ui-core.d.ts","sources":["../../../../libs/ui/core/src/lib/select/select-types.ts","../../../../libs/ui/core/src/lib/select/option.ts","../../../../libs/ui/core/src/lib/select/option.directives.ts","../../../../libs/ui/core/src/lib/select/select-trigger.ts","../../../../libs/ui/core/src/lib/positioning/positioner.ts","../../../../libs/ui/core/src/lib/select/listbox-keyboard.ts","../../../../libs/ui/core/src/lib/select/listbox-widget-base.ts","../../../../libs/ui/core/src/lib/select/select-base.ts"],"mappings":";;;;AAEA;;;;;AAKG;UACc,gBAAgB;;AAE/B;AACA;;;;AAIG;AACH;AACA;;;;AAIG;AACH;AACD;AAED;;;;;AAKG;UACc,uBAAuB;AACtC;;;;;AAKA;AACD;AAED;;;;AAIG;AACH,cAAa,kBAAkB,EAAA,cAAA,CAAA,gBAAA;;ACvB/B;;;;;;;;;;;;;;;AAeG;AACH,cAkCa,UAAU,yBAAyB,uBAAuB;;oBAEvD,aAAA,CAAA,WAAA;;;AAKd;AACA;AAEA;AACA;AACA,mCAA6B,aAAA,CAAA,MAAA;AAC7B,kCAA4B,aAAA,CAAA,MAAA;;AAG5B,+BAAyB,aAAA,CAAA,cAAA;AAEzB;;;;AAIG;AACH,iCAA2B,aAAA,CAAA,MAAA;;AAG3B,iCAA2B,aAAA,CAAA,MAAA;;AAgB3B;AAGA;AAIA;;;;;AAKG;AACH;AAqBA;;;;oDA5EW,UAAU;sDAAV,UAAU;AAyFtB;;AC/JD;;;AAGG;AACH,cAIa,iBAAiB;oDAAjB,iBAAiB;sDAAjB,iBAAiB;AAAG;AAEjC;;;AAGG;AACH,cAIa,gBAAgB;oDAAhB,gBAAgB;sDAAhB,gBAAgB;AAAG;;AClBhC;;;;;;;;;;;;;AAaG;AACH,cAIa,iBAAiB;oDAAjB,iBAAiB;sDAAjB,iBAAiB;AAAG;;ACXjC;;;;;;;;;;;;;;AAcG;AAEH;AACM,KAAM,aAAa;UAER,kBAAkB;;eAEtB,aAAa;;;;;AAKzB;UAEgB,iBAAiB;;;AAGjC;AAED;;;;;AAKG;AACH,iBAAgB,iBAAiB,YACpB,WAAW,YACZ,WAAW,iBACN,kBAAkB,GAChC,iBAAiB;;AChDpB;;;;;;;;;;AAUG;AACH,cAAa,oBAAoB;;;;;AAM/B,mCACkB,uBAAuB;AAKzC;;;;AAIG;AACH,6BAAyB,uBAAuB;;AAiBhD,qBAAiB,aAAa;AAI9B,sBAAkB,uBAAuB;;AAKzC,oBAAgB,uBAAuB;;AAOvC;AAIA;AAID;;AC/CD;;;;;;;;;;;;;;;;;;;;;AAqBG;AACH,uBAQsB,sBAAsB,yBAC/B,gBAAgB;;0BAGP,aAAA,CAAA,WAAA;;0BAEA,aAAA,CAAA,WAAA;;wBAEF,aAAA,CAAA,WAAA,CAAA,aAAA;;uBAED,aAAA,CAAA,wBAAA;uBACA,aAAA,CAAA,wBAAA;AAEjB,gCAA0B,aAAA,CAAA,MAAA,UAAA,UAAA;AAE1B,mCAA6B,aAAA,CAAA,MAAA,CAAA,UAAA,CAAA,WAAA;AAC7B,iCAA2B,aAAA,CAAA,MAAA,CAAA,UAAA,CAAA,WAAA;AAE3B,gCAA0B,gBAAA;AAC1B,iCAA2B,oBAAA;;AAG3B,+BAAyB,aAAA,CAAA,cAAA;AACzB,uCAAiC,aAAA,CAAA,cAAA;;;;AAQjC,mCAA6B,aAAA,CAAA,MAAA;AAG7B,mCAA6B,aAAA,CAAA,MAAA;AAG7B,iCAA2B,aAAA,CAAA,MAAA;AAG3B,mCAA6B,aAAA,CAAA,MAAA;AAG7B,kCAA4B,aAAA,CAAA,MAAA;AAG5B,oCAA8B,aAAA,CAAA,MAAA;;;AAgB9B;;AAEA;;AAEA;;AAEA,yCAAqC,uBAAuB;AAG5D,mCAA+B,KAAK;AAOpC;;;;;AAKG;AACH,mCAA+B,WAAW;AAI1C;AAqBA;;;;;;AAqBA;AAaA;oDA/IoB,sBAAsB;sDAAtB,sBAAsB;AAmJ3C;;ACtMD;;;;;;;;;;;;AAYG;AACH,uBACsB,eAAe,sBAE3B,sBAAsB;;AAE9B;;AAGA,wCAAkC,aAAA,CAAA,MAAA,CAAA,WAAA;AAKlC,oCAAgC,UAAU;AAK1C,sCAAkC,aAAa;oDAjB3B,eAAe;sDAAf,eAAe;AAgEpC;;;;","names":[]}
@@ -10,40 +10,70 @@ interface WeekdayHeader {
10
10
  readonly long: string;
11
11
  }
12
12
 
13
- interface DayCell {
13
+ /** The granularity of the emitted value (ADR 0057 R1). `'year'` is reserved, not yet implemented. */
14
+ type SkraDatePrecision = 'day' | 'month';
15
+
16
+ /**
17
+ * One cell of the calendar grid — a day in `day` view, a month in `month` view. ONE model for both
18
+ * (ADR 0057 R8): the views differ in what a cell means, never in how a cell behaves.
19
+ */
20
+ interface GridCell {
14
21
  readonly key: string;
22
+ /** The value this cell commits, at the active precision. `null` = layout padding (day view only). */
15
23
  readonly iso: string | null;
16
- readonly dayNum: string;
17
- readonly srName: string;
24
+ /** Visible text — the localized day number, or the localized full month name. */
25
+ readonly label: string;
26
+ /**
27
+ * The ADR 033 Path-2 `[skra-sr-only]` extension, INCLUDING its leading separator, and never a
28
+ * restatement of `label` (ADR 0057 R6).
29
+ */
30
+ readonly srExt: string;
18
31
  readonly today: boolean;
19
32
  readonly selected: boolean;
20
33
  readonly disabled: boolean;
21
34
  readonly focused: boolean;
22
35
  }
23
- interface WeekRow {
36
+ interface GridRow {
24
37
  readonly key: number;
25
- readonly days: DayCell[];
38
+ readonly cells: GridCell[];
26
39
  }
27
40
  /**
28
- * SkraDatePicker — pick a single **calendar date** from an APG Date Picker grid in the native top layer.
29
- * Second Tier-3 component. A value-display **trigger** (`<button>`) opens a non-modal top-layer **calendar
30
- * panel** (Popover API, `popover="auto"`, ADR 0044). The value is an **ISO 8601 date-only string**
31
- * (`YYYY-MM-DD`), consumer-owned (ADR 0050/037 — NO `@angular/forms`); all date math is the zoneless
32
- * UTC-calculator discipline in `calendar-math` (no date library). Localization (month/weekday names,
33
- * first-day-of-week, digits) is `Intl`-derived in `calendar-intl`; the 2-D grid keyboard is the
34
- * hand-rolled `SkraCalendarKeyboard` (ADR 0044 §7 — roving REAL focus, not aria-activedescendant).
41
+ * SkraDatePicker — pick a **calendar date** or a **calendar month** from an APG Date Picker grid in the
42
+ * native top layer. Second Tier-3 component. A value-display **trigger** (`<button>`) opens a non-modal
43
+ * top-layer **calendar panel** (Popover API, `popover="auto"`, ADR 0044). The value is an **ISO 8601 string**
44
+ * truncated to the active `precision` (`YYYY-MM-DD` / `YYYY-MM`), consumer-owned (ADR 0050/0057/037 — NO
45
+ * `@angular/forms`); all date math is the zoneless UTC-calculator discipline in `calendar-math` (no date
46
+ * library). Localization (month/weekday names, first-day-of-week, digits) is `Intl`-derived in
47
+ * `calendar-intl`; the 2-D grid keyboard is the hand-rolled `SkraCalendarKeyboard` (ADR 0044 §7 — roving
48
+ * REAL focus, not aria-activedescendant).
49
+ *
50
+ * **Precision is a runtime axis, not a second component (ADR 0057).** `precision="month"` swaps the 7×N day
51
+ * grid for a 3×4 quarter-aligned month grid inside the SAME trigger, panel, positioner, field DI wiring,
52
+ * dismissal model, selection model and keyboard controller. The value channel does not widen — `YYYY-MM` is
53
+ * a truncation of `YYYY-MM-DD`, both `string` — which is exactly why this is an input and cardinality
54
+ * (ADR 0046) is not. `week` / `time` / `datetime-local` are excluded by rule (ADR 0057 R5): they need a
55
+ * second calendar coordinate system or are not grids at all, and stay the native `skraInput` path.
35
56
  *
36
- * No projected content: the calendar days are GENERATED (the structural divergence from select/combobox —
37
- * there is no `skra-option` reuse). The only focusable element in the open panel is the roving day cell;
38
- * the month-nav buttons are pointer affordances (`tabindex="-1"`, driven by PageUp/PageDown on keyboard),
39
- * and Tab dismisses — so no focus-containment machinery is needed (spec Q-1).
57
+ * No projected content: the cells are GENERATED (the structural divergence from select/combobox — there is
58
+ * no `skra-option` reuse). The only focusable element in the open panel is the roving cell; the period-nav
59
+ * buttons are pointer affordances (`tabindex="-1"`, driven by PageUp/PageDown on keyboard), and Tab
60
+ * dismisses — so no focus-containment machinery is needed (spec Q-1).
40
61
  *
41
62
  * Full contract: adr/specs/component-datepicker-spec.md.
42
63
  */
43
64
  declare class SkraDatePicker {
44
- /** Consumer-owned value: ISO 8601 date-only (`YYYY-MM-DD`); `''` = unset. NEVER a Date (ADR 0050/037). */
65
+ /**
66
+ * Consumer-owned value: an ISO 8601 key truncated to `precision` — `YYYY-MM-DD` (`day`) or `YYYY-MM`
67
+ * (`month`); `''` = unset. NEVER a Date (ADR 0050/0057/037).
68
+ */
45
69
  readonly value: _angular_core.InputSignal<string>;
46
- /** Inclusive lower bound (ISO); `''` = unbounded (ADR 0050 §2). */
70
+ /**
71
+ * Value granularity (ADR 0057 R1). `'day'` (default) emits `YYYY-MM-DD` over a 7×N day grid; `'month'`
72
+ * emits `YYYY-MM` over a 3×4 quarter-aligned month grid. NOT a look input, NOT a cardinality flag, and
73
+ * NOT reflected to a `data-skra-*` attribute — precision is configuration, not state.
74
+ */
75
+ readonly precision: _angular_core.InputSignal<SkraDatePrecision>;
76
+ /** Inclusive lower bound (ISO); `''` = unbounded (ADR 0050 §2, truncated to `precision` per ADR 0057 R4). */
47
77
  readonly min: _angular_core.InputSignal<string>;
48
78
  /** Inclusive upper bound (ISO); `''` = unbounded. */
49
79
  readonly max: _angular_core.InputSignal<string>;
@@ -58,7 +88,7 @@ declare class SkraDatePicker {
58
88
  /** Standalone availability source — `SkraFieldContext` wins when present. */
59
89
  readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
60
90
  readonly readonly: _angular_core.InputSignalWithTransform<boolean, unknown>;
61
- /** Fires ONLY on user date selection — never on a programmatic `value()` change (ADR 037/0050). */
91
+ /** Fires ONLY on user selection — never on a programmatic `value()`/`precision()` change (ADR 037/0057 R3). */
62
92
  readonly valueChange: _angular_core.OutputEmitterRef<string>;
63
93
  private readonly triggerRef;
64
94
  private readonly panelRef;
@@ -66,12 +96,28 @@ declare class SkraDatePicker {
66
96
  private readonly injector;
67
97
  private readonly keyboard;
68
98
  readonly panelId: string;
69
- readonly monthYearId: string;
99
+ readonly periodId: string;
70
100
  protected readonly isOpen: _angular_core.WritableSignal<boolean>;
101
+ /**
102
+ * Which grid is on screen. Seeded from `precision` and writable in between (ADR 0057 R9) so the deferred
103
+ * month/year quick-pick — stepping UP from the day grid to pick a month, then back down — is an additive
104
+ * change rather than a rewrite. In MVP nothing writes it, so `view() === precision()` always.
105
+ *
106
+ * NOTE for whoever lands quick-pick: it adds a second focusable element to the open panel and therefore
107
+ * RE-OPENS spec Q-1, which was resolved on the premise that the panel holds exactly one focusable stop
108
+ * and Tab dismisses. Re-resolve Q-1 first.
109
+ */
110
+ protected readonly view: _angular_core.WritableSignal<SkraDatePrecision>;
71
111
  /** Today's LOCAL date (ADR 0050 §3) — stable for the session. */
72
112
  private readonly todayIso;
73
- /** The roving-focus day; SINGLE source of truth for what the grid shows AND which cell is focusable. */
74
- private readonly focusedIso;
113
+ /** The roving-focus cell; SINGLE source of truth for what the grid shows AND which cell is focusable. */
114
+ private readonly focusedKey;
115
+ /**
116
+ * The focused key re-keyed to the active view. A `precision` flip while the panel is closed leaves a key
117
+ * at the previous granularity behind; re-keying defensively keeps every downstream `computed` total
118
+ * without an effect or a reset cascade. `onOpen` re-seeds properly from the value.
119
+ */
120
+ private readonly focusedAt;
75
121
  private positioner?;
76
122
  /** Set when a close should return focus to the trigger (keyboard/select), not on outside-click. */
77
123
  private returnFocus;
@@ -81,50 +127,80 @@ declare class SkraDatePicker {
81
127
  protected readonly isRequired: _angular_core.Signal<boolean>;
82
128
  protected readonly triggerId: _angular_core.Signal<string | null>;
83
129
  protected readonly describedBy: _angular_core.Signal<string | null>;
84
- /** The committed value, defensively normalized: invalid/out-of-range → `''` for display (ADR 0050 §1). */
85
- protected readonly selectedIso: _angular_core.Signal<string>;
130
+ /**
131
+ * The committed value, defensively normalized: wrong-format-for-precision, invalid or out-of-range → `''`
132
+ * for display (ADR 0050 §1 as amended by ADR 0057 R3). Keyed on `precision` (what the value IS), not on
133
+ * `view` (what is on screen) — the two only diverge once quick-pick lands.
134
+ */
135
+ protected readonly selectedKey: _angular_core.Signal<string>;
86
136
  protected readonly formattedValue: _angular_core.Signal<string>;
87
137
  private readonly firstDow;
88
- /** The month being shown — always the focused day's month (keeps the roving tabindex valid). */
89
- private readonly displayedMonth;
90
- protected readonly monthYearLabel: _angular_core.Signal<string>;
91
- protected readonly prevMonthLabel: _angular_core.Signal<string>;
92
- protected readonly nextMonthLabel: _angular_core.Signal<string>;
138
+ /**
139
+ * The container the grid shows — the focused cell's MONTH in day view, its YEAR in month view (`m` is
140
+ * then meaningless). Always derived from the focused cell, which keeps the roving tabindex valid.
141
+ */
142
+ private readonly displayed;
143
+ protected readonly periodLabel: _angular_core.Signal<string>;
144
+ protected readonly prevPeriodLabel: _angular_core.Signal<string>;
145
+ protected readonly nextPeriodLabel: _angular_core.Signal<string>;
146
+ /**
147
+ * `aria-current` token for the cell holding today. ARIA 1.2 has no `month` value, and `date` is
148
+ * defined as the current DATE within a collection of dates — accurate for a day cell, a stretch for a
149
+ * month cell, where the generic `true` ("current item within a set") is the honest mapping.
150
+ */
151
+ protected readonly currentToken: _angular_core.Signal<"true" | "date">;
93
152
  protected readonly weekdayHeadersView: _angular_core.Signal<WeekdayHeader[]>;
94
- protected readonly weeks: _angular_core.Signal<WeekRow[]>;
153
+ /** ONE grid renderer, parameterized by view — the ADR 0057 R8 claim, made structural. */
154
+ protected readonly rows: _angular_core.Signal<GridRow[]>;
95
155
  constructor();
156
+ /**
157
+ * The dev-mode diagnostic, or `null` when the inputs are coherent. Split out of the constructor so it
158
+ * is a plain reactive expression rather than a closure buried in a lifecycle hook.
159
+ */
160
+ private readonly devWarning;
96
161
  protected onTriggerClick(event: MouseEvent): void;
97
162
  protected onTriggerKeydown(event: KeyboardEvent): void;
98
163
  protected onGridKeydown(event: KeyboardEvent): void;
99
- protected goToPreviousMonth(): void;
100
- protected goToNextMonth(): void;
101
- protected selectDate(iso: string): void;
164
+ protected goToPreviousPeriod(): void;
165
+ protected goToNextPeriod(): void;
166
+ /** One period = one month (day view) / one year (month view). */
167
+ private stepPeriod;
168
+ protected selectCell(iso: string): void;
102
169
  protected onPanelToggle(event: Event): void;
103
170
  private onOpen;
104
171
  private onClose;
105
172
  private open;
106
173
  private close;
107
- /** Seed the focused day on open: the valid current value, else today, clamped into `[min,max]`. */
174
+ /** Seed the focused cell on open: the valid current value, else today, clamped into `[min,max]`. */
108
175
  private seedFocus;
109
- private monthOffsetLabel;
176
+ private buildDayRows;
177
+ private buildMonthRows;
178
+ /**
179
+ * The accessible-name separator is baked into the extension rather than left to the template or to the
180
+ * engine: `[skra-sr-only]` is absolutely positioned, so whether the name computation inserts a space
181
+ * between the visible text and the extension is engine-dependent. One explicit space, asserted by test.
182
+ */
183
+ private srExtension;
184
+ private periodOffsetLabel;
110
185
  private emptyCell;
111
186
  private scheduleFocus;
112
- private focusActiveDay;
187
+ private focusActiveCell;
113
188
  /** Read a length comp token (px/rem) off the panel computed style for the positioner. */
114
189
  private cssLenPx;
115
190
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkraDatePicker, never>;
116
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkraDatePicker, "skra-datepicker", ["skraDatePicker"], { "value": { "alias": "value"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "firstDayOfWeek": { "alias": "firstDayOfWeek"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "placement": { "alias": "placement"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
191
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkraDatePicker, "skra-datepicker", ["skraDatePicker"], { "value": { "alias": "value"; "required": false; "isSignal": true; }; "precision": { "alias": "precision"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "firstDayOfWeek": { "alias": "firstDayOfWeek"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "placement": { "alias": "placement"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
117
192
  }
118
193
 
119
194
  /**
120
195
  * The intent a key produces in the calendar grid. The controller is PURE (no DOM, no focus, no signals);
121
- * the `skra-datepicker` component applies the intent — sets `focusedIso`/`displayedMonth` and moves REAL
122
- * DOM focus (roving). `monthChanged` tells the component the grid will re-stamp so it must re-`focus()`.
196
+ * the `skra-datepicker` component applies the intent — sets `focusedKey`/the displayed period and moves REAL
197
+ * DOM focus (roving). The component re-focuses unconditionally after a `focus` intent, so the intent
198
+ * carries no "did the period change" hint: a field nothing reads is public API that only costs (dropped
199
+ * in the ADR 0057 review, together with its `monthChanged` predecessor).
123
200
  */
124
201
  type CalendarKeyIntent = {
125
202
  readonly type: 'focus';
126
203
  readonly iso: string;
127
- readonly monthChanged: boolean;
128
204
  } | {
129
205
  readonly type: 'select';
130
206
  } | {
@@ -133,20 +209,37 @@ type CalendarKeyIntent = {
133
209
  readonly type: 'none';
134
210
  };
135
211
  interface CalendarKeyContext {
136
- /** The currently focused day (ISO). */
212
+ /** The currently focused cell, as an ISO key AT `view` precision (`YYYY-MM-DD` or `YYYY-MM`). */
137
213
  readonly focusedIso: string;
138
- /** First day of week, ISO 1=Mon … 7=Sun (already resolved by `calendar-intl`). */
214
+ /** First day of week, ISO 1=Mon … 7=Sun (already resolved by `calendar-intl`). Day view only. */
139
215
  readonly firstDayOfWeek: number;
216
+ /** Which grid is on screen — the ADR 0057 precision axis. */
217
+ readonly view: SkraDatePrecision;
140
218
  }
141
219
  /**
142
220
  * SkraCalendarKeyboard — the WAI-ARIA APG **Date Picker Dialog** grid keyboard model (2-D), confined to
143
221
  * ONE file. The THIRD per-pattern keyboard controller and the FIRST that does NOT wrap a CDK key manager:
144
222
  * neither `FocusKeyManager` (Menu) nor `ActiveDescendantKeyManager` (Select/Combobox) models a 2-D grid
145
- * whose focusable cell set is recomputed on month change (ADR 0044 §7 note, 2026-06-14). Date arithmetic
223
+ * whose focusable cell set is recomputed on period change (ADR 0044 §7 note, 2026-06-14). Date arithmetic
146
224
  * is delegated to `calendar-math` (the ADR 0050 single math site); this controller only maps keys to
147
225
  * intents. Roving REAL focus (NOT `aria-activedescendant`) — the divergence from Select/Combobox.
148
226
  *
149
- * Navigation is unclamped (a user may move onto a disabled out-of-range day — APG-discoverable); only
227
+ * **One model, two unit sets (ADR 0057 R8).** The `day` and `month` views share every key, every intent and
228
+ * the whole `switch` below; they differ ONLY in what a step, a row and a page mean. That parameterization is
229
+ * the falsifiable claim behind treating precision as a runtime axis rather than a second component — if this
230
+ * ever needs a second `resolve`, the classification was wrong and the feature splits.
231
+ *
232
+ * | Key | `day` view | `month` view |
233
+ * | --------------------- | ----------------------------- | ----------------------------- |
234
+ * | Left / Right | ∓1 day | ∓1 month |
235
+ * | Up / Down | ∓7 days (one week row) | ∓3 months (one quarter row) |
236
+ * | Home / End | first / last day of the week | first / last month of the quarter |
237
+ * | PageUp / PageDown | ∓1 month (clamped) | ∓1 year |
238
+ * | Shift+PageUp / -Down | ∓1 year (clamped) | ∓10 years |
239
+ *
240
+ * Home/End stay ROW-scoped in both views — APG grid semantics, and one rule beats two.
241
+ *
242
+ * Navigation is unclamped (a user may move onto a disabled out-of-range cell — APG-discoverable); only
150
243
  * SELECTION is range-guarded, and that guard lives in the component (one place, shared with pointer click).
151
244
  */
152
245
  declare class SkraCalendarKeyboard {
@@ -154,11 +247,18 @@ declare class SkraCalendarKeyboard {
154
247
  key: string;
155
248
  shiftKey: boolean;
156
249
  }, ctx: CalendarKeyContext): CalendarKeyIntent;
250
+ /** One cell = one day / one month. */
251
+ private step;
252
+ /** Row start: the week (day view) / the calendar quarter (month view). */
253
+ private rowStart;
254
+ /** Row end: last day of the week / last month of the quarter. */
255
+ private rowEnd;
256
+ /** Page = the next container up; Shift = the one above that. Day math stays clamped (ADR 0050 §4). */
257
+ private page;
157
258
  private toFocus;
158
- private monthChanged;
159
259
  private weekStart;
160
260
  }
161
261
 
162
262
  export { SkraCalendarKeyboard, SkraDatePicker };
163
- export type { CalendarKeyContext, CalendarKeyIntent };
263
+ export type { CalendarKeyContext, CalendarKeyIntent, SkraDatePrecision };
164
264
  //# sourceMappingURL=skra-ui-datepicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-datepicker.d.ts","sources":["../../../../libs/ui/datepicker/src/lib/datepicker/calendar-intl.ts","../../../../libs/ui/datepicker/src/lib/datepicker/datepicker.ts","../../../../libs/ui/datepicker/src/lib/datepicker/calendar-keyboard.ts"],"mappings":";;;;AAWA;UACiB,aAAa;;AAE5B;AACA;AACA;AACD;;AC2BD,UAAU,OAAO;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACD;AAED,UAAU,OAAO;AACf;AACA,mBAAe,OAAO;AACvB;AAID;;;;;;;;;;;;;;;AAeG;AACH,cAyJa,cAAc;;oBAEX,aAAA,CAAA,WAAA;;kBAEF,aAAA,CAAA,WAAA;;kBAEA,aAAA,CAAA,WAAA;;qBAEG,aAAA,CAAA,WAAA;;6BAEQ,aAAA,CAAA,WAAA;;0BAEH,aAAA,CAAA,WAAA;;wBAEF,aAAA,CAAA,WAAA,CAAA,aAAA;;uBAED,aAAA,CAAA,wBAAA;uBACA,aAAA,CAAA,wBAAA;;0BAGG,aAAA,CAAA,gBAAA;AAEpB;AAEA;AAEA;AACA;AACA;;;AAIA,+BAAyB,aAAA,CAAA,cAAA;;AAGzB;;AAEA;;;;AAOA,mCAA6B,aAAA,CAAA,MAAA;AAG7B,mCAA6B,aAAA,CAAA,MAAA;AAG7B,iCAA2B,aAAA,CAAA,MAAA;AAG3B,mCAA6B,aAAA,CAAA,MAAA;AAG7B,kCAA4B,aAAA,CAAA,MAAA;AAG5B,oCAA8B,aAAA,CAAA,MAAA;;AAM9B,oCAA8B,aAAA,CAAA,MAAA;AAI9B,uCAAiC,aAAA,CAAA,MAAA;AAGjC;;AAIA;AAIA,uCAAiC,aAAA,CAAA,MAAA;AAOjC,uCAAiC,aAAA,CAAA,MAAA;AACjC,uCAAiC,aAAA,CAAA,MAAA;AACjC,2CAAqC,aAAA,CAAA,MAAA,CAAAA,aAAA;AAGrC,8BAAwB,aAAA,CAAA,MAAA,CAAA,OAAA;;AAqDxB,oCAAgC,UAAU;AAI1C,sCAAkC,aAAa;AAS/C,mCAA+B,aAAa;;;AAwC5C;AAQA,mCAA+B,KAAK;AAOpC;AAiBA;AASA;AAGA;;AAKA;AAMA;AAMA;AAaA;AAIA;;AASA;oDA7RW,cAAc;sDAAd,cAAc;AAyS1B;;ACxgBD;;;;AAIG;AACG,KAAM,iBAAiB;AAEvB;AACA;AACA;;AAEA;;AACA;;AACA;;UAEW,kBAAkB;;AAEjC;;AAEA;AACD;AAID;;;;;;;;;;AAUG;AACH,cAAa,oBAAoB;;;;AAEY,YACpC,kBAAkB,GACtB,iBAAiB;AA8CpB;AAQA;AAMA;AAMD;;;;","names":["__calendar_intl.WeekdayHeader"]}
1
+ {"version":3,"file":"skra-ui-datepicker.d.ts","sources":["../../../../libs/ui/datepicker/src/lib/datepicker/calendar-intl.ts","../../../../libs/ui/datepicker/src/lib/datepicker/calendar-math.ts","../../../../libs/ui/datepicker/src/lib/datepicker/datepicker.ts","../../../../libs/ui/datepicker/src/lib/datepicker/calendar-keyboard.ts"],"mappings":";;;;AA6BA;UACiB,aAAa;;AAE5B;AACA;AACA;AACD;;ACsID;KACY,iBAAiB;;AChH7B;;;AAGG;AACH,UAAU,QAAQ;AAChB;;AAEA;;AAEA;AACA;;;AAGG;AACH;AACA;AACA;AACA;AACA;AACD;AAED,UAAU,OAAO;AACf;AACA,oBAAgB,QAAQ;AACzB;AAID;;;;;;;;;;;;;;;;;;;;;;;AAuBG;AACH,cA+Ja,cAAc;AACzB;;;AAGG;oBACW,aAAA,CAAA,WAAA;AACd;;;;AAIG;wBACe,aAAA,CAAA,WAAA,CAAA,iBAAA;;kBAEN,aAAA,CAAA,WAAA;;kBAEA,aAAA,CAAA,WAAA;;qBAEG,aAAA,CAAA,WAAA;;6BAEQ,aAAA,CAAA,WAAA;;0BAEH,aAAA,CAAA,WAAA;;wBAEF,aAAA,CAAA,WAAA,CAAA,aAAA;;uBAED,aAAA,CAAA,wBAAA;uBACA,aAAA,CAAA,wBAAA;;0BAGG,aAAA,CAAA,gBAAA;AAEpB;AAEA;AAEA;AACA;AACA;;;AAIA,+BAAyB,aAAA,CAAA,cAAA;AAEzB;;;;;;;;AAQG;AACH,6BAAuB,aAAA,CAAA,cAAA,CAAA,iBAAA;;AAGvB;;AAEA;AACA;;;;AAIG;AACH;;;;AAUA,mCAA6B,aAAA,CAAA,MAAA;AAG7B,mCAA6B,aAAA,CAAA,MAAA;AAG7B,iCAA2B,aAAA,CAAA,MAAA;AAG3B,mCAA6B,aAAA,CAAA,MAAA;AAG7B,kCAA4B,aAAA,CAAA,MAAA;AAG5B,oCAA8B,aAAA,CAAA,MAAA;AAK9B;;;;AAIG;AACH,oCAA8B,aAAA,CAAA,MAAA;AAQ9B,uCAAiC,aAAA,CAAA,MAAA;AAKjC;AAGA;;;AAGG;AACH;AASA,oCAA8B,aAAA,CAAA,MAAA;AAM9B,wCAAkC,aAAA,CAAA,MAAA;AAGlC,wCAAkC,aAAA,CAAA,MAAA;AAGlC;;;;AAIG;AACH,qCAA+B,aAAA,CAAA,MAAA;AAG/B,2CAAqC,aAAA,CAAA,MAAA,CAAAA,aAAA;;AAIrC,6BAAuB,aAAA,CAAA,MAAA,CAAA,OAAA;;AAgCvB;;;AAGG;AACH;AAsCA,oCAAgC,UAAU;AAI1C,sCAAkC,aAAa;AAS/C,mCAA+B,aAAa;;;;AAwC5C;AAUA;AAuBA,mCAA+B,KAAK;AAOpC;AAiBA;AASA;AAGA;;AAKA;AAQA;AA0BA;AAwBA;;;;AAIG;AACH;AAIA;AAQA;AAaA;AAIA;;AASA;oDArcW,cAAc;sDAAd,cAAc;AAid1B;;ACjtBD;;;;;;AAMG;AACG,KAAM,iBAAiB;AAEvB;AACA;;AAEA;;AACA;;AACA;;UAEW,kBAAkB;;AAEjC;;AAEA;;AAEA,mBAAe,iBAAiB;AACjC;AAOD;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;AACH,cAAa,oBAAoB;;;;AAEY,YACpC,kBAAkB,GACtB,iBAAiB;;AA+BpB;;AAOA;;AAOA;;AAOA;AAYA;AAIA;AAMD;;;;","names":["__calendar_intl.WeekdayHeader"]}
@@ -31,11 +31,16 @@ interface SkraMenuPanel {
31
31
  * <button skraButton popovertarget="actions" aria-haspopup="menu">Actions</button>
32
32
  * <skra-menu id="actions">
33
33
  * <button skraMenuItem (click)="edit()">Edit</button>
34
- * <button skraMenuItem disabled (click)="archive()">Archive</button>
34
+ * <button skraMenuItem aria-disabled="true" (click)="archive()">Archive</button>
35
35
  * <button skraMenuItem (click)="remove()">Delete</button>
36
36
  * </skra-menu>
37
37
  *
38
- * Forge adds, on top of the Popover substrate: the `role="menu"` keyboard model via `SkraMenuKeyboard`
38
+ * A disabled item is `aria-disabled="true"` set by the CONSUMER — never native `disabled` (boundary
39
+ * #9, native-attr-first): the item stays focusable and in the roving order per APG, and a
40
+ * capture-phase guard on the panel blocks activation. Native `disabled` would keep it in the roving
41
+ * order but make `focus()` a no-op, so arrow navigation would silently dead-end on that row.
42
+ *
43
+ * Skra adds, on top of the Popover substrate: the `role="menu"` keyboard model via `SkraMenuKeyboard`
39
44
  * (CDK `FocusKeyManager` — Down/Up roving + wrap, Home/End, type-ahead, Tab-dismiss), **focus moving
40
45
  * INTO the menu on open** (a composite widget — unlike non-modal Popover; the per-component ADR 0044
41
46
  * §3 rule-8 decision), and the trigger's disclosure ARIA (`aria-haspopup="menu"` / `aria-controls` /
@@ -52,9 +57,10 @@ declare class SkraMenu implements SkraMenuPanel {
52
57
  private readonly host;
53
58
  private readonly renderer;
54
59
  private readonly keyboard;
55
- /** The consumer's `[popovertarget]` button, resolved once (lazily-idempotent via `resolved`). */
60
+ /** The consumer's `[popovertarget]` button; resolution is retried until it succeeds. */
56
61
  private trigger;
57
- private resolved;
62
+ /** Latches the dev warning, NOT the resolution — see `ensureTrigger()`. */
63
+ private warned;
58
64
  private positioner?;
59
65
  constructor();
60
66
  /** SKRA_MENU contract — close on item activation (native focus-return to the trigger). */
@@ -67,8 +73,14 @@ declare class SkraMenu implements SkraMenuPanel {
67
73
  private onClose;
68
74
  /**
69
75
  * Resolve the `[popovertarget]` trigger and establish the menu disclosure ARIA on it (sanctioned a11y
70
- * wiring, ADR 013-style — not style mutation). Idempotent. Returns the trigger (or null for an orphan
71
- * menu, dev-warned once).
76
+ * wiring, ADR 013-style — not style mutation). Returns the trigger (or null for an orphan menu,
77
+ * dev-warned once).
78
+ *
79
+ * Idempotent on SUCCESS only — see the same note on `SkraPopover.ensureTrigger()`. Latching on
80
+ * failure would permanently strand a trigger rendered behind an `@if` / lazy route / `@defer`:
81
+ * no disclosure ARIA, and `onOpen()` bails on the null anchor so the panel opens unpositioned at
82
+ * viewport 0,0 — the exact signature of impl-finding #1 in the spec. The dev warning latches
83
+ * separately via `warned`.
72
84
  */
73
85
  private ensureTrigger;
74
86
  /** Read a length comp token (px/rem) off the host computed style for the positioner. */
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-menu.d.ts","sources":["../../../../libs/ui/menu/src/lib/menu/menu-types.ts","../../../../libs/ui/menu/src/lib/menu/menu.ts","../../../../libs/ui/menu/src/lib/menu/menu-item.ts"],"mappings":";;;;AAEA;;;;AAIG;UACc,oBAAoB;;;;AAIpC;AAED;UACiB,aAAa;;;AAG7B;;ACQD;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BG;AACH,cAoBa,QAAS,YAAW,aAAa;;wBAE1BA,EAAA,CAAA,WAAA,CAAA,aAAA;AAElB;AAIA;AACA;AACA;;;;;;;AAoCA;;AAKA;AAWA;AAKA;AAIA;AAmBA;AAQA;;;;AAIG;AACH;;AA0CA;;AAcA;AAUA;yCAzKW,QAAQ;2CAAR,QAAQ;AAsLpB;;AClPD;;;;;;;;;;;;;;;;;AAiBG;AACH,cAea,YAAa,YAAW,oBAAoB;AACvD;AACA;;AAcA;AAGA;;AAIA;AAIA,gCAA4B,UAAU;yCA3B3B,YAAY;2CAAZ,YAAY;AAsCxB;;;;","names":["_angular_core"]}
1
+ {"version":3,"file":"skra-ui-menu.d.ts","sources":["../../../../libs/ui/menu/src/lib/menu/menu-types.ts","../../../../libs/ui/menu/src/lib/menu/menu.ts","../../../../libs/ui/menu/src/lib/menu/menu-item.ts"],"mappings":";;;;AAEA;;;;AAIG;UACc,oBAAoB;;;;AAIpC;AAED;UACiB,aAAa;;;AAG7B;;ACQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;AACH,cAoBa,QAAS,YAAW,aAAa;;wBAE1BA,EAAA,CAAA,WAAA,CAAA,aAAA;AAElB;AAIA;AACA;AACA;;;;;;;;AAqCA;;AAKA;AAWA;AAKA;AAIA;AAmBA;AAQA;;;;;;;;;;AAUG;AACH;;AAgDA;;AAcA;AAUA;yCAtLW,QAAQ;2CAAR,QAAQ;AAmMpB;;ACpQD;;;;;;;;;;;;;;;;;AAiBG;AACH,cAea,YAAa,YAAW,oBAAoB;AACvD;AACA;;AAcA;AAGA;;AAIA;AAIA,gCAA4B,UAAU;yCA3B3B,YAAY;2CAAZ,YAAY;AAyCxB;;;;","names":["_angular_core"]}
@@ -32,9 +32,10 @@ declare class SkraPopover {
32
32
  readonly placement: i0.InputSignal<SkraPlacement>;
33
33
  private readonly host;
34
34
  private readonly renderer;
35
- /** The consumer's `[popovertarget]` button, resolved once (lazily-idempotent via `resolved`). */
35
+ /** The consumer's `[popovertarget]` button; resolution is retried until it succeeds. */
36
36
  private trigger;
37
- private resolved;
37
+ /** Latches the dev warning, NOT the resolution — see `ensureTrigger()`. */
38
+ private warned;
38
39
  private positioner?;
39
40
  constructor();
40
41
  private readonly onToggleNative;
@@ -42,8 +43,16 @@ declare class SkraPopover {
42
43
  private onClose;
43
44
  /**
44
45
  * Resolve the `[popovertarget]` trigger and establish the disclosure ARIA on it (sanctioned a11y
45
- * wiring, ADR 013-style — not style mutation). Idempotent: runs at most once. Returns the trigger
46
- * (or null for an orphan popover, dev-warned once).
46
+ * wiring, ADR 013-style — not style mutation). Returns the trigger (or null for an orphan
47
+ * popover, dev-warned once).
48
+ *
49
+ * Idempotent on SUCCESS only. It deliberately does NOT latch on failure: a trigger behind an
50
+ * `@if`, a lazy route or a `@defer` block is simply not in the DOM at the `afterNextRender` tick,
51
+ * and latching there would strand it forever — no disclosure ARIA and, because `onOpen()` bails
52
+ * on a null anchor, an unpositioned panel at viewport 0,0. Retrying on each open is cheap (one
53
+ * `querySelectorAll` per open, only while still unresolved) and makes the `onOpen()` call a real
54
+ * safety net rather than the dead code it was. The dev warning latches separately via `warned`
55
+ * so a late-rendered trigger does not spam the console once per open.
47
56
  */
48
57
  private ensureTrigger;
49
58
  /** Read a length comp token (px/rem) off the host computed style for the positioner. */
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-popover.d.ts","sources":["../../../../libs/ui/popover/src/lib/popover/popover.ts"],"mappings":";;;;AAoBA;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AACH,cAkBa,WAAW;;wBAEJA,EAAA,CAAA,WAAA,CAAA,aAAA;AAElB;AACA;;;;;;AAqBA;AAKA;AAoBA;AAQA;;;;AAIG;AACH;;AAyCA;AAaA;yCAtHW,WAAW;2CAAX,WAAW;AA8HvB;;;;","names":["_angular_core"]}
1
+ {"version":3,"file":"skra-ui-popover.d.ts","sources":["../../../../libs/ui/popover/src/lib/popover/popover.ts"],"mappings":";;;;AAoBA;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AACH,cAkBa,WAAW;;wBAEJA,EAAA,CAAA,WAAA,CAAA,aAAA;AAElB;AACA;;;;;;;AAsBA;AAKA;AAoBA;AAQA;;;;;;;;;;;;AAYG;AACH;;AAgDA;AAaA;yCAtIW,WAAW;2CAAX,WAAW;AA8IvB;;;;","names":["_angular_core"]}
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-tooltip.d.ts","sources":["../../../../libs/ui/tooltip/src/lib/tooltip/tooltip.ts","../../../../libs/ui/tooltip/src/lib/tooltip/tooltip-panel.ts"],"mappings":";;;;AA0BA;;;;;;;;;;;;;;;;;;;;AAoBG;AACH,cAWa,WAAW;;0BAEFA,EAAA,CAAA,WAAA;;wBAEFA,EAAA,CAAA,WAAA,CAAA,aAAA;AAElB;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;AAkEA;AAUA;AASA;AA8BA;AAcA;AAUA;AAkBA;AAOA;AAOA;AAWA;AAWA;yCA7MW,WAAW;2CAAX,WAAW;AAqNvB;;ACtQD;;;;;;;;;;;;;;AAcG;AACH,cAaa,gBAAgB;;mBAEdA,EAAA,CAAA,WAAA;;;yCAFF,gBAAgB;2CAAhB,gBAAgB;AAM5B;;;;","names":["_angular_core"]}
1
+ {"version":3,"file":"skra-ui-tooltip.d.ts","sources":["../../../../libs/ui/tooltip/src/lib/tooltip/tooltip.ts","../../../../libs/ui/tooltip/src/lib/tooltip/tooltip-panel.ts"],"mappings":";;;;AA+BA;;;;;;;;;;;;;;;;;;;;AAoBG;AACH,cAWa,WAAW;;0BAEFA,EAAA,CAAA,WAAA;;wBAEFA,EAAA,CAAA,WAAA,CAAA,aAAA;AAElB;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;AAkEA;AAUA;AASA;AA8BA;AAcA;AAUA;AAkBA;AAOA;AAOA;AAWA;AAWA;yCA7MW,WAAW;2CAAX,WAAW;AAqNvB;;AC3QD;;;;;;;;;;;;;;AAcG;AACH,cAaa,gBAAgB;;mBAEdA,EAAA,CAAA,WAAA;;;yCAFF,gBAAgB;2CAAhB,gBAAgB;AAM5B;;;;","names":["_angular_core"]}