ngwr 13.0.0 → 14.0.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 +13 -6
- package/color-picker/styles/_index.scss +43 -5
- package/fesm2022/ngwr-alert.mjs +5 -5
- package/fesm2022/ngwr-alert.mjs.map +1 -1
- package/fesm2022/ngwr-back-top.mjs +11 -1
- package/fesm2022/ngwr-back-top.mjs.map +1 -1
- package/fesm2022/ngwr-blur-text.mjs +13 -2
- package/fesm2022/ngwr-blur-text.mjs.map +1 -1
- package/fesm2022/ngwr-border-glow.mjs +12 -3
- package/fesm2022/ngwr-border-glow.mjs.map +1 -1
- package/fesm2022/ngwr-breadcrumbs.mjs +14 -3
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ngwr-button.mjs +4 -4
- package/fesm2022/ngwr-button.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-testing.mjs +15 -0
- package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
- package/fesm2022/ngwr-calendar.mjs +51 -5
- package/fesm2022/ngwr-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-circular-text.mjs +20 -1
- package/fesm2022/ngwr-circular-text.mjs.map +1 -1
- package/fesm2022/ngwr-collapse.mjs.map +1 -1
- package/fesm2022/ngwr-color-picker-testing.mjs +23 -7
- package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-color-picker.mjs +89 -10
- package/fesm2022/ngwr-color-picker.mjs.map +1 -1
- package/fesm2022/ngwr-command-palette.mjs +27 -3
- package/fesm2022/ngwr-command-palette.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu.mjs +13 -3
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-date-adapters-fns.mjs +101 -33
- package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker-testing.mjs +10 -2
- package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker.mjs +103 -13
- package/fesm2022/ngwr-date-picker.mjs.map +1 -1
- package/fesm2022/ngwr-date.mjs +480 -79
- package/fesm2022/ngwr-date.mjs.map +1 -1
- package/fesm2022/ngwr-dialog.mjs +22 -16
- package/fesm2022/ngwr-dialog.mjs.map +1 -1
- package/fesm2022/ngwr-directives.mjs +5 -2
- package/fesm2022/ngwr-directives.mjs.map +1 -1
- package/fesm2022/ngwr-drag-drop.mjs +30 -2
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-drawer.mjs +24 -18
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +8 -3
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar.mjs +1 -1
- package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-file-upload.mjs +52 -12
- package/fesm2022/ngwr-file-upload.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text.mjs +21 -4
- package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
- package/fesm2022/ngwr-gradient-text.mjs +9 -2
- package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +63 -1
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +28 -1
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-i18n.mjs +150 -22
- package/fesm2022/ngwr-i18n.mjs.map +1 -1
- package/fesm2022/ngwr-icon-adapters-feather.mjs +11 -0
- package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
- package/fesm2022/ngwr-icon-adapters-lucide.mjs +22 -2
- package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
- package/fesm2022/ngwr-icon.mjs +474 -37
- package/fesm2022/ngwr-icon.mjs.map +1 -1
- package/fesm2022/ngwr-input-number.mjs +3 -3
- package/fesm2022/ngwr-input-number.mjs.map +1 -1
- package/fesm2022/ngwr-input-otp.mjs +21 -3
- package/fesm2022/ngwr-input-otp.mjs.map +1 -1
- package/fesm2022/ngwr-input.mjs +14 -7
- package/fesm2022/ngwr-input.mjs.map +1 -1
- package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
- package/fesm2022/ngwr-knob.mjs +20 -2
- package/fesm2022/ngwr-knob.mjs.map +1 -1
- package/fesm2022/ngwr-loading-bar-router.mjs +73 -0
- package/fesm2022/ngwr-loading-bar-router.mjs.map +1 -0
- package/fesm2022/ngwr-loading-bar.mjs +21 -32
- package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
- package/fesm2022/ngwr-markdown.mjs +63 -11
- package/fesm2022/ngwr-markdown.mjs.map +1 -1
- package/fesm2022/ngwr-mention.mjs +104 -14
- package/fesm2022/ngwr-mention.mjs.map +1 -1
- package/fesm2022/ngwr-overlay.mjs +36 -7
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-pagination-testing.mjs +11 -10
- package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
- package/fesm2022/ngwr-pagination.mjs +65 -30
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-popconfirm.mjs +3 -2
- package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +2 -1
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-qr.mjs +38 -1
- package/fesm2022/ngwr-qr.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +93 -34
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text.mjs +10 -3
- package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
- package/fesm2022/ngwr-splitter-testing.mjs.map +1 -1
- package/fesm2022/ngwr-squircle.mjs +2 -1
- package/fesm2022/ngwr-squircle.mjs.map +1 -1
- package/fesm2022/ngwr-statistic.mjs +35 -4
- package/fesm2022/ngwr-statistic.mjs.map +1 -1
- package/fesm2022/ngwr-table.mjs +35 -12
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs-router.mjs +158 -0
- package/fesm2022/ngwr-tabs-router.mjs.map +1 -0
- package/fesm2022/ngwr-tabs-testing.mjs +13 -11
- package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +104 -12
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-textarea.mjs +20 -1
- package/fesm2022/ngwr-textarea.mjs.map +1 -1
- package/fesm2022/ngwr-tour.mjs +1 -1
- package/fesm2022/ngwr-tour.mjs.map +1 -1
- package/fesm2022/ngwr-transfer.mjs +2 -2
- package/fesm2022/ngwr-transfer.mjs.map +1 -1
- package/fesm2022/ngwr-tree.mjs +18 -2
- package/fesm2022/ngwr-tree.mjs.map +1 -1
- package/fesm2022/ngwr-utils.mjs +143 -1
- package/fesm2022/ngwr-utils.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/fesm2022/ngwr-window-testing.mjs +10 -2
- package/fesm2022/ngwr-window-testing.mjs.map +1 -1
- package/fesm2022/ngwr-window.mjs +4 -4
- package/fesm2022/ngwr-window.mjs.map +1 -1
- package/i18n/en.json +33 -6
- package/i18n/ru.json +33 -6
- package/llms-full.txt +20 -11
- package/llms.txt +47 -16
- package/mcp/catalog.js +3 -3
- package/mcp/providers.js +11 -0
- package/package.json +11 -3
- package/schematics/migrations/v13/index.js +101 -0
- package/schematics/migrations/v14/index.js +422 -0
- package/schematics/migrations.json +10 -0
- package/schematics/page/templates.js +1 -1
- package/schematics/use/symbol-map.json +1 -0
- package/skills/ngwr/SKILL.md +4 -1
- package/skills/ngwr/references/catalog.md +2 -0
- package/skills/ngwr/references/setup.md +4 -0
- package/stepper/styles/_index.scss +19 -1
- package/textarea/styles/_index.scss +14 -6
- package/toast/styles/_index.scss +12 -4
- package/types/ngwr-alert.d.ts +3 -3
- package/types/ngwr-blur-text.d.ts +8 -0
- package/types/ngwr-breadcrumbs.d.ts +1 -0
- package/types/ngwr-button.d.ts +2 -2
- package/types/ngwr-calendar-testing.d.ts +21 -4
- package/types/ngwr-calendar.d.ts +37 -0
- package/types/ngwr-circular-text.d.ts +9 -0
- package/types/ngwr-collapse.d.ts +19 -15
- package/types/ngwr-color-picker-testing.d.ts +10 -4
- package/types/ngwr-color-picker.d.ts +70 -2
- package/types/ngwr-command-palette.d.ts +14 -0
- package/types/ngwr-context-menu.d.ts +1 -1
- package/types/ngwr-date-adapters-fns.d.ts +71 -29
- package/types/ngwr-date-picker-testing.d.ts +206 -185
- package/types/ngwr-date-picker.d.ts +7 -0
- package/types/ngwr-date.d.ts +143 -13
- package/types/ngwr-drag-drop.d.ts +19 -0
- package/types/ngwr-dropdown.d.ts +1 -1
- package/types/ngwr-event-calendar-testing.d.ts +12 -9
- package/types/ngwr-file-upload.d.ts +31 -3
- package/types/ngwr-fuzzy-text.d.ts +5 -0
- package/types/ngwr-i18n.d.ts +89 -7
- package/types/ngwr-icon-adapters-feather.d.ts +11 -0
- package/types/ngwr-icon.d.ts +42 -1
- package/types/ngwr-input-number.d.ts +1 -1
- package/types/ngwr-input-otp.d.ts +3 -0
- package/types/ngwr-input.d.ts +11 -4
- package/types/ngwr-knob-testing.d.ts +8 -4
- package/types/ngwr-knob.d.ts +18 -0
- package/types/ngwr-loading-bar-router.d.ts +35 -0
- package/types/ngwr-loading-bar.d.ts +19 -9
- package/types/ngwr-mention.d.ts +13 -0
- package/types/ngwr-pagination-testing.d.ts +11 -10
- package/types/ngwr-pagination.d.ts +39 -10
- package/types/ngwr-popconfirm.d.ts +1 -1
- package/types/ngwr-popover.d.ts +1 -1
- package/types/ngwr-select.d.ts +65 -10
- package/types/ngwr-shiny-text.d.ts +1 -0
- package/types/ngwr-splitter-testing.d.ts +9 -4
- package/types/ngwr-squircle.d.ts +1 -1
- package/types/ngwr-statistic.d.ts +22 -2
- package/types/ngwr-table.d.ts +24 -5
- package/types/ngwr-tabs-router.d.ts +67 -0
- package/types/ngwr-tabs-testing.d.ts +12 -10
- package/types/ngwr-tabs.d.ts +103 -6
- package/types/ngwr-textarea.d.ts +9 -0
- package/types/ngwr-tree.d.ts +7 -0
- package/types/ngwr-utils.d.ts +79 -1
- package/types/ngwr-version.d.ts +1 -1
- package/types/ngwr-window-testing.d.ts +11 -3
- package/types/ngwr-window.d.ts +11 -4
- package/window/styles/_index.scss +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-calendar.mjs","sources":["../../../projects/lib/calendar/calendar.ts","../../../projects/lib/calendar/calendar.html","../../../projects/lib/calendar/ngwr-calendar.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n Injector,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n model,\n signal,\n untracked,\n} from '@angular/core';\n\nimport { WrDateAdapter } from 'ngwr/date';\nimport { useI18nText } from 'ngwr/i18n';\n\nimport type { WrCalendarMode, WrCalendarRange } from './interfaces';\n\n/**\n * Stands in for the consumer input `useI18nText` expects, for labels the calendar\n * exposes no input for. Constant and read-only, so one instance is safe to share.\n */\nconst NO_OVERRIDE = signal<string | null>(null).asReadonly();\n\nconst ROWS = 6;\nconst COLS = 7;\n\n/**\n * Chips per row in the month and year views — the vertical arrows step by one\n * of these, so they have to agree with `grid-template-columns` in\n * `styles/_index.scss`. Two numbers because the two grids differ: twelve months\n * read as four rows of three, twelve years as three rows of four.\n */\nconst MONTH_COLS = 3;\nconst YEAR_COLS = 4;\n\n/**\n * Month-view calendar. Supports single-date selection (`mode=\"single\"`) or\n * date-range selection (`mode=\"range\"`). Reusable on its own; consumed by\n * `<wr-date-picker>` inside an overlay.\n *\n * Uses {@link WrDateAdapter} for all date math and formatting — register\n * one via {@link provideWrDateAdapter} at bootstrap.\n *\n * @example\n * ```html\n * <wr-calendar [(date)]=\"picked\" [min]=\"minDate\" />\n *\n * <wr-calendar mode=\"range\" [(range)]=\"[start, end]\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/calendar\n */\n@Component({\n selector: 'wr-calendar',\n templateUrl: './calendar.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n // No `role=\"grid\"` here: the host also wraps the nav header, and a grid may\n // only own rows. The role sits on `.wr-calendar__body`, which is the day\n // matrix and nothing else.\n '(keydown)': 'onKeyDown($event)',\n },\n})\nexport class WrCalendar {\n /** Selection mode. @default 'single' */\n readonly mode = input<WrCalendarMode>('single');\n\n /** Two-way bindable single value (used when `mode === 'single'`). */\n readonly date = model<Date | null>(null);\n\n /** Two-way bindable `[start, end]` (used when `mode === 'range'`). */\n readonly range = model<WrCalendarRange>([null, null]);\n\n /** Min selectable date (inclusive). */\n readonly min = input<Date | null>(null);\n\n /** Max selectable date (inclusive). */\n readonly max = input<Date | null>(null);\n\n /** Predicate — return `false` to disable specific dates (e.g. weekends only). */\n readonly dateFilter = input<((date: Date) => boolean) | null>(null);\n\n /**\n * Move real focus onto the roving cell as soon as the grid is on screen.\n *\n * Off by default: a standalone `<wr-calendar>` sitting in a page must not\n * steal focus on load. `wr-date-picker` turns it on for the popup it opens\n * from its trigger, where the user asked to be taken to the calendar.\n * @default false\n */\n readonly autoFocus = input(false, { transform: coerceBooleanProperty });\n\n /** Disable interaction entirely. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n private readonly adapter = inject<WrDateAdapter<Date>>(WrDateAdapter);\n private readonly dir = inject(Directionality, { optional: true });\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n\n /** Currently displayed month (any date inside it). */\n protected readonly viewDate = signal(this.adapter.today());\n\n /** Date currently focused by keyboard (single roving tabindex). */\n protected readonly focusedDate = signal(this.adapter.today());\n\n /** Hovered date during range-mode end-pick — drives the preview highlight. */\n protected readonly hoverDate = signal<Date | null>(null);\n\n /** Which sub-view is currently shown. Cycles `day → month → year` on header click. */\n protected readonly viewMode = signal<'day' | 'month' | 'year'>('day');\n\n /**\n * Chip the month / year listbox has moved its ring to, as an index into\n * `monthsView()` / `yearsView()`. `null` means \"nobody has pressed an arrow\n * yet\", which resolves to the month or year on screen — see {@link activeChip}.\n *\n * Reset on every view change rather than remembered: coming back to the month\n * list should ring the month you are looking at, not the one an earlier visit\n * happened to leave the ring on.\n */\n private readonly rovedChip = signal<number | null>(null);\n\n // The four month/year strings have been in both catalogs since they were written\n // and nothing read them: the template hard-coded the same English beside them, so a\n // localized app announced its calendar's arrows in English. `nullSignal()` is the\n // shim for exactly this — a label with no consumer input to forward.\n private readonly prevMonthLabel = useI18nText(NO_OVERRIDE, 'calendar.prevMonth', 'Previous month');\n private readonly nextMonthLabel = useI18nText(NO_OVERRIDE, 'calendar.nextMonth', 'Next month');\n private readonly prevYearLabel = useI18nText(NO_OVERRIDE, 'calendar.prevYear', 'Previous year');\n private readonly nextYearLabel = useI18nText(NO_OVERRIDE, 'calendar.nextYear', 'Next year');\n private readonly prevYearsLabel = useI18nText(NO_OVERRIDE, 'calendar.prevYears', 'Previous 12 years');\n private readonly nextYearsLabel = useI18nText(NO_OVERRIDE, 'calendar.nextYears', 'Next 12 years');\n\n /** What the ← button does from here — a month, a year, or a 12-year page. */\n protected readonly prevLabel = computed(() => {\n switch (this.viewMode()) {\n case 'year':\n return this.prevYearsLabel();\n case 'month':\n return this.prevYearLabel();\n default:\n return this.prevMonthLabel();\n }\n });\n\n /** What the → button does from here. */\n protected readonly nextLabel = computed(() => {\n switch (this.viewMode()) {\n case 'year':\n return this.nextYearsLabel();\n case 'month':\n return this.nextYearLabel();\n default:\n return this.nextMonthLabel();\n }\n });\n\n protected readonly today = computed(() => this.adapter.today());\n\n protected readonly weekdayNames = computed(() => this.adapter.getDayOfWeekNames('short'));\n\n protected readonly monthsView = computed(() => this.adapter.getMonthNames('short'));\n\n /** 12-year window centered on the floor-aligned decade containing `viewDate`. */\n protected readonly yearsView = computed<readonly number[]>(() => {\n const y = this.adapter.getYear(this.viewDate());\n const start = Math.floor(y / 12) * 12;\n return Array.from({ length: 12 }, (_, i) => start + i);\n });\n\n protected readonly headerLabel = computed(() => {\n const v = this.viewDate();\n switch (this.viewMode()) {\n case 'day': {\n const monthNames = this.adapter.getMonthNames('long');\n return `${monthNames[this.adapter.getMonth(v)]} ${this.adapter.getYear(v)}`;\n }\n case 'month':\n return `${this.adapter.getYear(v)}`;\n case 'year': {\n const years = this.yearsView();\n return `${years[0]} – ${years[years.length - 1]}`;\n }\n }\n });\n\n /** 6×7 day grid covering the current month plus spillover. */\n protected readonly weeks = computed<readonly (readonly Date[])[]>(() => {\n const view = this.viewDate();\n const year = this.adapter.getYear(view);\n const month = this.adapter.getMonth(view);\n const firstOfMonth = this.adapter.createDate(year, month, 1);\n const firstWeekday = this.adapter.getDayOfWeek(firstOfMonth);\n const firstDayOfWeek = this.adapter.getFirstDayOfWeek();\n const lead = (firstWeekday - firstDayOfWeek + 7) % 7;\n const gridStart = this.adapter.addDays(firstOfMonth, -lead);\n\n const out: Date[][] = [];\n for (let w = 0; w < ROWS; w++) {\n const row: Date[] = [];\n for (let d = 0; d < COLS; d++) {\n row.push(this.adapter.addDays(gridStart, w * COLS + d));\n }\n out.push(row);\n }\n return out;\n });\n\n /**\n * The chip carrying the listbox's only `tabindex=\"0\"` — where the ring is, and\n * where Tab lands.\n *\n * A listbox owns its arrows, and these two did not: twelve months were twelve\n * tab stops, so the role promised an interaction model the component never\n * implemented. One tab stop plus arrow keys is the roving-tabindex half of the\n * pattern the day grid already uses.\n *\n * Routed through {@link nearestEnabledChip} on BOTH paths — the seed and every\n * arrow — for the reason the grid learned first: `.focus()` on a\n * `<button disabled>` is a no-op, so parking the sole tab stop on a month a\n * `[min]` has closed off leaves the whole view unreachable by keyboard.\n * `-1` on the day view, where there are no chips at all.\n */\n protected readonly activeChip = computed(() => {\n if (this.viewMode() === 'day') return -1;\n return this.nearestEnabledChip(this.rovedChip() ?? this.currentChip());\n });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-calendar', `wr-calendar--${this.mode()}`];\n if (this.disabled()) parts.push('wr-calendar--disabled');\n return parts.join(' ');\n });\n\n constructor() {\n // Initial focus: selected date if any, else today. Also snap viewDate to\n // that month.\n //\n // Stepped onto an ENABLED day, because the roving tabindex puts the grid's\n // only `tabindex=\"0\"` on this cell: seed it on a disabled one — which is\n // exactly what a `min` in the future does to \"today\" — and the sole tab\n // stop is an unfocusable button, leaving the grid unreachable by keyboard.\n afterNextRender(() => {\n const initial = this.nearestEnabled(this.date() ?? this.range()[0] ?? this.adapter.today());\n this.focusedDate.set(initial);\n this.viewDate.set(initial);\n\n // A second, NESTED hook: the lines above only SET the signals, which\n // schedules another change-detection pass — the `--focused` class and the\n // `tabindex` are not in the DOM until that one has run.\n if (this.autoFocus()) {\n afterNextRender(() => this.focusActiveCell(), { injector: this.injector });\n }\n });\n\n // Keep viewDate in sync when date / range changes externally to a\n // different month. The viewDate read must stay untracked — otherwise\n // the effect re-runs on every internal navigation (month stepping,\n // year picking) and snaps the view back to the selected month.\n effect(() => {\n const candidate = this.mode() === 'single' ? this.date() : this.range()[0];\n if (!candidate) return;\n untracked(() => {\n if (!this.adapter.isSameMonth(candidate, this.viewDate())) {\n this.viewDate.set(candidate);\n }\n });\n });\n }\n\n // Navigation\n\n /** Header `‹` button — steps by month / year / decade based on the active view. */\n protected prev(): void {\n this.viewDate.set(this.stepViewDate(-1));\n }\n\n /** Header `›` button — steps by month / year / decade based on the active view. */\n protected next(): void {\n this.viewDate.set(this.stepViewDate(1));\n }\n\n /** Header label click — zooms out (`day → month → year`). No-op at year view. */\n protected onLabelClick(): void {\n if (this.disabled()) return;\n if (this.viewMode() === 'day') {\n this.setViewMode('month');\n } else if (this.viewMode() === 'month') {\n this.setViewMode('year');\n }\n }\n\n protected onMonthSelect(monthIdx: number): void {\n if (this.isMonthDisabled(monthIdx)) return;\n const v = this.viewDate();\n this.viewDate.set(this.adapter.createDate(this.adapter.getYear(v), monthIdx, 1));\n this.setViewMode('day');\n }\n\n protected onYearSelect(year: number): void {\n if (this.isYearDisabled(year)) return;\n const v = this.viewDate();\n this.viewDate.set(this.adapter.createDate(year, this.adapter.getMonth(v), 1));\n this.setViewMode('month');\n }\n\n /**\n * Switch views and drop the chip ring with them.\n *\n * Every view change is the only thing that changes what the chips MEAN, so it\n * is the one place the ring has to forget where it was — otherwise a year\n * picked at index 7 rings the eighth MONTH on the way back down.\n */\n private setViewMode(view: 'day' | 'month' | 'year'): void {\n this.rovedChip.set(null);\n this.viewMode.set(view);\n }\n\n private stepViewDate(direction: -1 | 1): Date {\n const v = this.viewDate();\n switch (this.viewMode()) {\n case 'day':\n return this.adapter.addMonths(v, direction);\n case 'month':\n return this.adapter.addYears(v, direction);\n case 'year':\n return this.adapter.addYears(v, direction * 12);\n }\n }\n\n // Cell state predicates (used by template)\n\n protected isToday(date: Date): boolean {\n return this.adapter.isSameDay(date, this.today());\n }\n\n protected isOutOfMonth(date: Date): boolean {\n return !this.adapter.isSameMonth(date, this.viewDate());\n }\n\n protected isSelected(date: Date): boolean {\n if (this.mode() === 'single') {\n const v = this.date();\n return v ? this.adapter.isSameDay(date, v) : false;\n }\n const [start, end] = this.range();\n if (start && this.adapter.isSameDay(date, start)) return true;\n if (end && this.adapter.isSameDay(date, end)) return true;\n return false;\n }\n\n protected isInRange(date: Date): boolean {\n if (this.mode() !== 'range') return false;\n const [start, end] = this.range();\n if (!start || !end) return false;\n return this.adapter.compareDate(date, start) > 0 && this.adapter.compareDate(date, end) < 0;\n }\n\n protected isInRangePreview(date: Date): boolean {\n if (this.mode() !== 'range') return false;\n const [start, end] = this.range();\n const hover = this.hoverDate();\n if (!start || end || !hover) return false;\n const before = this.adapter.compareDate(start, hover) <= 0;\n const lo = before ? start : hover;\n const hi = before ? hover : start;\n return this.adapter.compareDate(date, lo) > 0 && this.adapter.compareDate(date, hi) < 0;\n }\n\n protected isFocused(date: Date): boolean {\n return this.adapter.isSameDay(date, this.focusedDate());\n }\n\n protected isDisabled(date: Date): boolean {\n if (this.disabled()) return true;\n const min = this.min();\n if (min && this.adapter.compareDate(date, min) < 0) return true;\n const max = this.max();\n if (max && this.adapter.compareDate(date, max) > 0) return true;\n const filter = this.dateFilter();\n if (filter && !filter(date)) return true;\n return false;\n }\n\n // Month / year view predicates\n\n protected isMonthCurrent(monthIdx: number): boolean {\n return this.adapter.getMonth(this.viewDate()) === monthIdx;\n }\n\n protected isMonthSelected(monthIdx: number): boolean {\n const v = this.mode() === 'single' ? this.date() : this.range()[0];\n if (!v) return false;\n return this.adapter.getYear(v) === this.adapter.getYear(this.viewDate()) && this.adapter.getMonth(v) === monthIdx;\n }\n\n protected isMonthDisabled(monthIdx: number): boolean {\n if (this.disabled()) return true;\n const year = this.adapter.getYear(this.viewDate());\n const monthStart = this.adapter.createDate(year, monthIdx, 1);\n const monthEnd = this.adapter.createDate(year, monthIdx, this.adapter.getDaysInMonth(monthStart));\n const min = this.min();\n if (min && this.adapter.compareDate(monthEnd, min) < 0) return true;\n const max = this.max();\n if (max && this.adapter.compareDate(monthStart, max) > 0) return true;\n return false;\n }\n\n protected isYearCurrent(year: number): boolean {\n return this.adapter.getYear(this.viewDate()) === year;\n }\n\n protected isYearSelected(year: number): boolean {\n const v = this.mode() === 'single' ? this.date() : this.range()[0];\n return v ? this.adapter.getYear(v) === year : false;\n }\n\n protected isYearDisabled(year: number): boolean {\n if (this.disabled()) return true;\n const min = this.min();\n if (min && year < this.adapter.getYear(min)) return true;\n const max = this.max();\n if (max && year > this.adapter.getYear(max)) return true;\n return false;\n }\n\n // Interaction\n\n protected onCellClick(date: Date): void {\n if (this.isDisabled(date)) return;\n if (this.mode() === 'single') {\n this.date.set(this.adapter.clone(date));\n } else {\n this.applyRangeClick(date);\n }\n this.focusedDate.set(date);\n if (!this.adapter.isSameMonth(date, this.viewDate())) {\n this.viewDate.set(date);\n }\n }\n\n protected onCellEnter(date: Date): void {\n if (this.mode() === 'range') this.hoverDate.set(date);\n }\n\n protected onCellLeave(): void {\n if (this.mode() === 'range') this.hoverDate.set(null);\n }\n\n private applyRangeClick(date: Date): void {\n const [start, end] = this.range();\n if (!start || (start && end)) {\n this.range.set([this.adapter.clone(date), null]);\n return;\n }\n if (this.adapter.compareDate(date, start) < 0) {\n this.range.set([this.adapter.clone(date), start]);\n } else {\n this.range.set([start, this.adapter.clone(date)]);\n }\n this.hoverDate.set(null);\n }\n\n // Keyboard\n\n protected onKeyDown(event: KeyboardEvent): void {\n if (this.disabled()) return;\n\n // The listener sits on the HOST, which also wraps the nav header — so\n // without this every key aimed at a `‹` button drove the day grid instead,\n // and the `preventDefault()` below cancelled the button's own activation:\n // Enter on `‹` picked a day the user never touched, ArrowDown on the header\n // yanked real focus into the grid. The host element itself is deliberately\n // let through: `WrCalendarHarness` sends its keys to `<wr-calendar>` rather\n // than to a cell, because the calendar moves focus in an `afterNextRender`\n // and jsdom often has focus nowhere at all.\n const target = event.target as Element | null;\n if (target !== this.host.nativeElement && target?.closest('.wr-calendar__header')) return;\n\n // The month and year views are listboxes, and the arrows belong to them\n // while they are up — there is no day grid on screen to drive. Their chips\n // are real `<button>`s, so Enter and Space fall through to the browser's own\n // activation and must not be swallowed here.\n if (this.viewMode() !== 'day') {\n this.onChipKeyDown(event);\n return;\n }\n\n const current = this.focusedDate();\n let next: Date | null = null;\n // Which way the key travels, so a landing on a closed-off day can keep\n // going instead of stopping on it. See `nearestEnabledToward`.\n let dir: 1 | -1 = 1;\n\n switch (this.inlineKey(event.key)) {\n case 'ArrowLeft':\n next = this.adapter.addDays(current, -1);\n dir = -1;\n break;\n case 'ArrowRight':\n next = this.adapter.addDays(current, 1);\n break;\n case 'ArrowUp':\n next = this.adapter.addDays(current, -7);\n dir = -1;\n break;\n case 'ArrowDown':\n next = this.adapter.addDays(current, 7);\n break;\n case 'Home': {\n const dow = this.adapter.getDayOfWeek(current);\n const first = this.adapter.getFirstDayOfWeek();\n next = this.adapter.addDays(current, -((dow - first + 7) % 7));\n dir = -1;\n break;\n }\n case 'End': {\n const dow = this.adapter.getDayOfWeek(current);\n const first = this.adapter.getFirstDayOfWeek();\n next = this.adapter.addDays(current, 6 - ((dow - first + 7) % 7));\n break;\n }\n case 'PageUp':\n next = event.shiftKey ? this.adapter.addYears(current, -1) : this.adapter.addMonths(current, -1);\n dir = -1;\n break;\n case 'PageDown':\n next = event.shiftKey ? this.adapter.addYears(current, 1) : this.adapter.addMonths(current, 1);\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n this.onCellClick(current);\n return;\n }\n\n if (!next) return;\n event.preventDefault();\n\n // The seed is routed through `nearestEnabled` for a reason, and navigation\n // needs the same care: a cell renders `disabled` AND carries the grid's only\n // `tabindex=\"0\"`, so parking the ring on a closed-off day leaves zero\n // tabbable cells — the user tabs out of the calendar and can never tab back\n // in. Real focus splits from the ring too, because `.focus()` on a disabled\n // button is a no-op. Reached by nothing more exotic than `[minDate]`.\n const landing = this.nearestEnabledToward(next, dir);\n if (!landing) return;\n next = landing;\n\n this.focusedDate.set(next);\n if (!this.adapter.isSameMonth(next, this.viewDate())) {\n this.viewDate.set(next);\n }\n // `afterNextRender`, NOT `queueMicrotask`. Under zoneless CD the scheduler\n // runs change detection in a macrotask, so a microtask fires FIRST — the\n // `--focused` class is still on the cell we just left, and this focuses\n // that one. The ring moved and real focus did not, permanently: a screen\n // reader kept announcing the previous day.\n afterNextRender(() => this.focusActiveCell(), { injector: this.injector });\n }\n\n /**\n * Arrow / Home / End inside the month or year listbox — the roving half of the\n * pattern their `role` has always claimed.\n *\n * Steps by one along the row and by a full row vertically, and the inline pair\n * mirrors under `dir=\"rtl\"` for the same reason the grid's does: those two keys\n * name a side of the screen. The page does NOT wrap or spill into the next\n * one — a month list is twelve fixed cells, and the header's `‹` / `›` are what\n * change which twelve. Anything else (Enter, Space, Tab, Escape) is left to the\n * button and to whatever owns the calendar.\n */\n private onChipKeyDown(event: KeyboardEvent): void {\n const cols = this.viewMode() === 'month' ? MONTH_COLS : YEAR_COLS;\n const count = this.chipCount();\n const current = this.activeChip();\n // Assigned on every branch that does not return, so it needs no placeholder.\n let next: number;\n // Which way to keep looking when the landing chip is closed off, exactly as\n // `nearestEnabledToward` does for days.\n let dir: 1 | -1 = 1;\n\n switch (this.inlineKey(event.key)) {\n case 'ArrowLeft':\n next = current - 1;\n dir = -1;\n break;\n case 'ArrowRight':\n next = current + 1;\n break;\n case 'ArrowUp':\n next = current - cols;\n dir = -1;\n break;\n case 'ArrowDown':\n next = current + cols;\n break;\n case 'Home':\n next = 0;\n break;\n case 'End':\n next = count - 1;\n dir = -1;\n break;\n default:\n return;\n }\n\n const landing = this.enabledChipToward(next, dir);\n if (landing === null) return;\n\n event.preventDefault();\n this.rovedChip.set(landing);\n // `afterNextRender`, not `queueMicrotask` — same trap as the grid: under\n // zoneless CD the microtask runs before the new `tabindex` is in the DOM, so\n // the focus call would land on the chip the ring just left.\n afterNextRender(() => this.focusActiveChip(), { injector: this.injector });\n }\n\n /** How many chips the current view renders — twelve either way, read rather than assumed. */\n private chipCount(): number {\n return this.viewMode() === 'month' ? this.monthsView().length : this.yearsView().length;\n }\n\n /** Whether the chip at `index` refuses selection in the current view. */\n private isChipDisabled(index: number): boolean {\n if (this.viewMode() === 'month') return this.isMonthDisabled(index);\n const year = this.yearsView()[index];\n return year === undefined || this.isYearDisabled(year);\n }\n\n /** The chip the view itself points at: the month or year currently on screen. */\n private currentChip(): number {\n if (this.viewMode() === 'month') return this.adapter.getMonth(this.viewDate());\n const index = this.yearsView().indexOf(this.adapter.getYear(this.viewDate()));\n return index === -1 ? 0 : index;\n }\n\n /**\n * The first selectable chip at or after `from`, else the first before it, else\n * `from` unchanged when the whole page is closed off — the chip version of\n * {@link nearestEnabled}, and it exists for the same reason: the ring carries\n * the only `tabindex=\"0\"`, and a disabled button cannot hold it.\n */\n private nearestEnabledChip(from: number): number {\n const count = this.chipCount();\n const start = Math.min(Math.max(from, 0), count - 1);\n if (!this.isChipDisabled(start)) return start;\n\n for (const step of [1, -1] as const) {\n const found = this.enabledChipToward(start + step, step);\n if (found !== null) return found;\n }\n return start;\n }\n\n /**\n * The first selectable chip at `from` or beyond it in `step`'s direction, else\n * null when that whole direction is closed off — which is the answer for an\n * ArrowLeft on the first chip: stay put.\n */\n private enabledChipToward(from: number, step: 1 | -1): number | null {\n for (let i = from; i >= 0 && i < this.chipCount(); i += step) {\n if (!this.isChipDisabled(i)) return i;\n }\n return null;\n }\n\n private focusActiveChip(): void {\n // By the tab stop, not by index: it is the same element the ring is on, and\n // asking for it this way cannot drift out of step with the template.\n this.host.nativeElement.querySelector<HTMLElement>('.wr-calendar__chip[tabindex=\"0\"]')?.focus();\n }\n\n /**\n * The first selectable day at or after `candidate`, else the first before it,\n * else `candidate` unchanged when everything nearby is closed off. Bounded at\n * a year each way so a pathological `dateFilter` cannot spin.\n */\n private nearestEnabled(candidate: Date): Date {\n if (!this.isDisabled(candidate)) return candidate;\n\n for (const step of [1, -1] as const) {\n let probe = candidate;\n for (let i = 0; i < 366; i++) {\n probe = this.adapter.addDays(probe, step);\n if (!this.isDisabled(probe)) return probe;\n }\n }\n return candidate;\n }\n\n /**\n * The first selectable day at `candidate` or beyond it in `step`'s direction,\n * else null when that whole direction is closed off — which is the answer for\n * an ArrowLeft that would cross `min`: stay put.\n *\n * Direction matters. Reusing `nearestEnabled`, which probes forward first,\n * would send an ArrowLeft over a disabled weekend straight back to the day it\n * started from, so the ring could never cross the hole.\n */\n private nearestEnabledToward(candidate: Date, step: 1 | -1): Date | null {\n let probe = candidate;\n for (let i = 0; i < 366; i++) {\n if (!this.isDisabled(probe)) return probe;\n probe = this.adapter.addDays(probe, step);\n }\n return null;\n }\n\n private focusActiveCell(): void {\n const el = this.host.nativeElement.querySelector('.wr-calendar__day--focused');\n (el as HTMLElement | null)?.focus();\n }\n\n /** Used by the template's `track` expression. */\n protected trackByTime(_: number, date: Date): number {\n return date.getTime();\n }\n\n /**\n * The key as the GRID sees it.\n *\n * Arrow keys follow visual order, and a calendar grid mirrors under\n * `dir=\"rtl\"`: the day to the visual right of today is yesterday. Only the\n * inline pair swaps — Up/Down step a week either way, and PageUp/PageDown and\n * Home/End are semantic rather than physical.\n */\n private inlineKey(key: string): string {\n if (this.dir?.value !== 'rtl') return key;\n if (key === 'ArrowRight') return 'ArrowLeft';\n if (key === 'ArrowLeft') return 'ArrowRight';\n return key;\n }\n}\n","<div class=\"wr-calendar__header\">\n <button\n type=\"button\"\n class=\"wr-calendar__nav wr-calendar__nav--prev\"\n [attr.aria-label]=\"prevLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"prev()\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"wr-calendar__label\"\n [disabled]=\"disabled() || viewMode() === 'year'\"\n (click)=\"onLabelClick()\"\n >\n {{ headerLabel() }}\n </button>\n <button\n type=\"button\"\n class=\"wr-calendar__nav wr-calendar__nav--next\"\n [attr.aria-label]=\"nextLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"next()\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n</div>\n\n@switch (viewMode()) {\n @case ('day') {\n <!--\n The weekday strip and the week rows are one grid, so they share a wrapper:\n `role=\"grid\"` may only own rows, and as siblings the header row had no grid\n parent at all. `.wr-calendar__body` repeats the host's column gap, so the\n rendered spacing is unchanged.\n -->\n <div class=\"wr-calendar__body\" role=\"grid\">\n <div class=\"wr-calendar__weekdays\" role=\"row\">\n @for (name of weekdayNames(); track name) {\n <span class=\"wr-calendar__weekday\" role=\"columnheader\">{{ name }}</span>\n }\n </div>\n\n <div class=\"wr-calendar__grid\" role=\"rowgroup\" (mouseleave)=\"onCellLeave()\">\n @for (week of weeks(); track $index) {\n <div class=\"wr-calendar__week\" role=\"row\">\n @for (day of week; track trackByTime($index, day)) {\n <button\n type=\"button\"\n class=\"wr-calendar__day\"\n role=\"gridcell\"\n [class.wr-calendar__day--today]=\"isToday(day)\"\n [class.wr-calendar__day--out-of-month]=\"isOutOfMonth(day)\"\n [class.wr-calendar__day--selected]=\"isSelected(day)\"\n [class.wr-calendar__day--in-range]=\"isInRange(day)\"\n [class.wr-calendar__day--range-preview]=\"isInRangePreview(day)\"\n [class.wr-calendar__day--focused]=\"isFocused(day)\"\n [disabled]=\"isDisabled(day)\"\n [attr.tabindex]=\"isFocused(day) ? 0 : -1\"\n [attr.aria-selected]=\"isSelected(day)\"\n [attr.aria-disabled]=\"isDisabled(day)\"\n (click)=\"onCellClick(day)\"\n (mouseenter)=\"onCellEnter(day)\"\n >\n {{ day.getDate() }}\n </button>\n }\n </div>\n }\n </div>\n </div>\n }\n\n @case ('month') {\n <!--\n A listbox owns its arrows, so its options share ONE tab stop: twelve months\n that were each tabbable announced a keyboard model — arrow to a month, Tab\n out of the list — that the component did not have. `activeChip()` is where\n the ring is, and it is always an enabled chip.\n -->\n <div class=\"wr-calendar__months\" role=\"listbox\">\n @for (name of monthsView(); track name) {\n <button\n type=\"button\"\n class=\"wr-calendar__chip\"\n role=\"option\"\n [class.wr-calendar__chip--current]=\"isMonthCurrent($index)\"\n [class.wr-calendar__chip--selected]=\"isMonthSelected($index)\"\n [disabled]=\"isMonthDisabled($index)\"\n [attr.tabindex]=\"activeChip() === $index ? 0 : -1\"\n [attr.aria-selected]=\"isMonthSelected($index)\"\n [attr.aria-disabled]=\"isMonthDisabled($index)\"\n (click)=\"onMonthSelect($index)\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n @case ('year') {\n <div class=\"wr-calendar__years\" role=\"listbox\">\n @for (year of yearsView(); track year) {\n <button\n type=\"button\"\n class=\"wr-calendar__chip\"\n role=\"option\"\n [class.wr-calendar__chip--current]=\"isYearCurrent(year)\"\n [class.wr-calendar__chip--selected]=\"isYearSelected(year)\"\n [disabled]=\"isYearDisabled(year)\"\n [attr.tabindex]=\"activeChip() === $index ? 0 : -1\"\n [attr.aria-selected]=\"isYearSelected(year)\"\n [attr.aria-disabled]=\"isYearDisabled(year)\"\n (click)=\"onYearSelect(year)\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\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":"ngwr-calendar.mjs","sources":["../../../projects/lib/calendar/calendar.ts","../../../projects/lib/calendar/calendar.html","../../../projects/lib/calendar/ngwr-calendar.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n Injector,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n model,\n signal,\n untracked,\n} from '@angular/core';\n\nimport { WrDateAdapter } from 'ngwr/date';\nimport { useI18nFormatter, useI18nText } from 'ngwr/i18n';\n\nimport type { WrCalendarMode, WrCalendarRange } from './interfaces';\n\n/**\n * Stands in for the consumer input `useI18nText` expects, for labels the calendar\n * exposes no input for. Constant and read-only, so one instance is safe to share.\n */\nconst NO_OVERRIDE = signal<string | null>(null).asReadonly();\n\nconst ROWS = 6;\nconst COLS = 7;\n\n/**\n * Chips per row in the month and year views — the vertical arrows step by one\n * of these, so they have to agree with `grid-template-columns` in\n * `styles/_index.scss`. Two numbers because the two grids differ: twelve months\n * read as four rows of three, twelve years as three rows of four.\n */\nconst MONTH_COLS = 3;\nconst YEAR_COLS = 4;\n\n/**\n * Month-view calendar. Supports single-date selection (`mode=\"single\"`) or\n * date-range selection (`mode=\"range\"`). Reusable on its own; consumed by\n * `<wr-date-picker>` inside an overlay.\n *\n * Uses {@link WrDateAdapter} for all date math and formatting — register\n * one via {@link provideWrDateAdapter} at bootstrap.\n *\n * @example\n * ```html\n * <wr-calendar [(date)]=\"picked\" [min]=\"minDate\" />\n *\n * <wr-calendar mode=\"range\" [(range)]=\"[start, end]\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/calendar\n */\n@Component({\n selector: 'wr-calendar',\n templateUrl: './calendar.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n // No `role=\"grid\"` here: the host also wraps the nav header, and a grid may\n // only own rows. The role sits on `.wr-calendar__body`, which is the day\n // matrix and nothing else.\n '(keydown)': 'onKeyDown($event)',\n },\n})\nexport class WrCalendar {\n /** Selection mode. @default 'single' */\n readonly mode = input<WrCalendarMode>('single');\n\n /** Two-way bindable single value (used when `mode === 'single'`). */\n readonly date = model<Date | null>(null);\n\n /** Two-way bindable `[start, end]` (used when `mode === 'range'`). */\n readonly range = model<WrCalendarRange>([null, null]);\n\n /** Min selectable date (inclusive). */\n readonly min = input<Date | null>(null);\n\n /** Max selectable date (inclusive). */\n readonly max = input<Date | null>(null);\n\n /** Predicate — return `false` to disable specific dates (e.g. weekends only). */\n readonly dateFilter = input<((date: Date) => boolean) | null>(null);\n\n /**\n * Move real focus onto the roving cell as soon as the grid is on screen.\n *\n * Off by default: a standalone `<wr-calendar>` sitting in a page must not\n * steal focus on load. `wr-date-picker` turns it on for the popup it opens\n * from its trigger, where the user asked to be taken to the calendar.\n * @default false\n */\n readonly autoFocus = input(false, { transform: coerceBooleanProperty });\n\n /** Disable interaction entirely. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n private readonly adapter = inject<WrDateAdapter<Date>>(WrDateAdapter);\n private readonly dir = inject(Directionality, { optional: true });\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n\n /** Currently displayed month (any date inside it). */\n protected readonly viewDate = signal(this.adapter.today());\n\n /** Date currently focused by keyboard (single roving tabindex). */\n protected readonly focusedDate = signal(this.adapter.today());\n\n /** Hovered date during range-mode end-pick — drives the preview highlight. */\n protected readonly hoverDate = signal<Date | null>(null);\n\n /** Which sub-view is currently shown. Cycles `day → month → year` on header click. */\n protected readonly viewMode = signal<'day' | 'month' | 'year'>('day');\n\n /**\n * Chip the month / year listbox has moved its ring to, as an index into\n * `monthsView()` / `yearsView()`. `null` means \"nobody has pressed an arrow\n * yet\", which resolves to the month or year on screen — see {@link activeChip}.\n *\n * Reset on every view change rather than remembered: coming back to the month\n * list should ring the month you are looking at, not the one an earlier visit\n * happened to leave the ring on.\n */\n private readonly rovedChip = signal<number | null>(null);\n\n // The four month/year strings have been in both catalogs since they were written\n // and nothing read them: the template hard-coded the same English beside them, so a\n // localized app announced its calendar's arrows in English. `nullSignal()` is the\n // shim for exactly this — a label with no consumer input to forward.\n private readonly prevMonthLabel = useI18nText(NO_OVERRIDE, 'calendar.prevMonth', 'Previous month');\n private readonly nextMonthLabel = useI18nText(NO_OVERRIDE, 'calendar.nextMonth', 'Next month');\n private readonly prevYearLabel = useI18nText(NO_OVERRIDE, 'calendar.prevYear', 'Previous year');\n private readonly nextYearLabel = useI18nText(NO_OVERRIDE, 'calendar.nextYear', 'Next year');\n private readonly prevYearsLabel = useI18nText(NO_OVERRIDE, 'calendar.prevYears', 'Previous 12 years');\n private readonly nextYearsLabel = useI18nText(NO_OVERRIDE, 'calendar.nextYears', 'Next 12 years');\n\n /** What the ← button does from here — a month, a year, or a 12-year page. */\n protected readonly prevLabel = computed(() => {\n switch (this.viewMode()) {\n case 'year':\n return this.prevYearsLabel();\n case 'month':\n return this.prevYearLabel();\n default:\n return this.prevMonthLabel();\n }\n });\n\n /** What the → button does from here. */\n protected readonly nextLabel = computed(() => {\n switch (this.viewMode()) {\n case 'year':\n return this.nextYearsLabel();\n case 'month':\n return this.nextYearLabel();\n default:\n return this.nextMonthLabel();\n }\n });\n\n protected readonly today = computed(() => this.adapter.today());\n\n protected readonly weekdayNames = computed(() => this.adapter.getDayOfWeekNames('short'));\n\n protected readonly monthsView = computed(() => this.adapter.getMonthNames('short'));\n\n /** 12-year window centered on the floor-aligned decade containing `viewDate`. */\n protected readonly yearsView = computed<readonly number[]>(() => {\n const y = this.adapter.getYear(this.viewDate());\n const start = Math.floor(y / 12) * 12;\n return Array.from({ length: 12 }, (_, i) => start + i);\n });\n\n /**\n * The header above the grid.\n *\n * Both templated strings used to be assembled here: `${month} ${year}` and\n * `${first} – ${last}`. That is English word order with an English separator\n * baked into TypeScript, and no catalog could move either — ja-JP writes\n * 2026年3月, which is not a translation of any word in `March 2026` but a\n * different arrangement of the same two values. So the arrangement is the\n * translatable unit, and `calendar.header` / `calendar.yearRange` are it.\n */\n protected readonly headerLabel = computed(() => {\n const v = this.viewDate();\n switch (this.viewMode()) {\n case 'day': {\n const monthNames = this.adapter.getMonthNames('long');\n return this.headerText({\n month: monthNames[this.adapter.getMonth(v)],\n year: this.adapter.getYear(v),\n });\n }\n case 'month':\n return `${this.adapter.getYear(v)}`;\n case 'year': {\n const years = this.yearsView();\n return this.yearRangeText({ from: years[0], to: years[years.length - 1] });\n }\n }\n });\n\n private readonly headerText = useI18nFormatter('calendar.header', '{{month}} {{year}}');\n private readonly yearRangeText = useI18nFormatter('calendar.yearRange', '{{from}} – {{to}}');\n private readonly dayLabelText = useI18nFormatter('calendar.dayLabel', '{{weekday}}, {{date}}');\n\n /**\n * Long weekday names for the cell names.\n *\n * `getDayOfWeekNames` returns them in COLUMN order — index 0 is\n * `getFirstDayOfWeek()`, not Sunday — which is what the header strip wants and\n * what a `getDayOfWeek()` result (0 = Sunday) must be rotated into. Indexing\n * it directly reads Monday's name for a Sunday in every locale that starts its\n * week on Monday, which is most of them.\n */\n private readonly longWeekdays = computed(() => this.adapter.getDayOfWeekNames('long'));\n\n /**\n * A day cell's accessible name — \"Sunday, March 15, 2026\".\n *\n * The cell had none. Its only content is the day NUMBER, and `role=\"gridcell\"`\n * does not inherit a name from the grid's header or from the column header\n * above it, so every date in the month announced as a bare number: the month,\n * the year and the weekday were all on screen and none of them reachable.\n *\n * `{{date}}` is the adapter's `longDate`, so its field order, its separators\n * and its digits are `Intl`'s — the catalog decides only where the weekday\n * goes. Building it from `getMonthNames('long')` instead would have hard-coded\n * the nominative month, which Russian and Finnish inflect inside a date.\n */\n protected dayLabel(date: Date): string {\n return this.dayLabelText({\n weekday: this.longWeekdays()[(this.adapter.getDayOfWeek(date) - this.adapter.getFirstDayOfWeek() + 7) % 7],\n date: this.adapter.format(date, 'longDate'),\n });\n }\n\n /** 6×7 day grid covering the current month plus spillover. */\n protected readonly weeks = computed<readonly (readonly Date[])[]>(() => {\n const view = this.viewDate();\n const year = this.adapter.getYear(view);\n const month = this.adapter.getMonth(view);\n const firstOfMonth = this.adapter.createDate(year, month, 1);\n const firstWeekday = this.adapter.getDayOfWeek(firstOfMonth);\n const firstDayOfWeek = this.adapter.getFirstDayOfWeek();\n const lead = (firstWeekday - firstDayOfWeek + 7) % 7;\n const gridStart = this.adapter.addDays(firstOfMonth, -lead);\n\n const out: Date[][] = [];\n for (let w = 0; w < ROWS; w++) {\n const row: Date[] = [];\n for (let d = 0; d < COLS; d++) {\n row.push(this.adapter.addDays(gridStart, w * COLS + d));\n }\n out.push(row);\n }\n return out;\n });\n\n /**\n * The chip carrying the listbox's only `tabindex=\"0\"` — where the ring is, and\n * where Tab lands.\n *\n * A listbox owns its arrows, and these two did not: twelve months were twelve\n * tab stops, so the role promised an interaction model the component never\n * implemented. One tab stop plus arrow keys is the roving-tabindex half of the\n * pattern the day grid already uses.\n *\n * Routed through {@link nearestEnabledChip} on BOTH paths — the seed and every\n * arrow — for the reason the grid learned first: `.focus()` on a\n * `<button disabled>` is a no-op, so parking the sole tab stop on a month a\n * `[min]` has closed off leaves the whole view unreachable by keyboard.\n * `-1` on the day view, where there are no chips at all.\n */\n protected readonly activeChip = computed(() => {\n if (this.viewMode() === 'day') return -1;\n return this.nearestEnabledChip(this.rovedChip() ?? this.currentChip());\n });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-calendar', `wr-calendar--${this.mode()}`];\n if (this.disabled()) parts.push('wr-calendar--disabled');\n return parts.join(' ');\n });\n\n constructor() {\n // Initial focus: selected date if any, else today. Also snap viewDate to\n // that month.\n //\n // Stepped onto an ENABLED day, because the roving tabindex puts the grid's\n // only `tabindex=\"0\"` on this cell: seed it on a disabled one — which is\n // exactly what a `min` in the future does to \"today\" — and the sole tab\n // stop is an unfocusable button, leaving the grid unreachable by keyboard.\n afterNextRender(() => {\n const initial = this.nearestEnabled(this.date() ?? this.range()[0] ?? this.adapter.today());\n this.focusedDate.set(initial);\n this.viewDate.set(initial);\n\n // A second, NESTED hook: the lines above only SET the signals, which\n // schedules another change-detection pass — the `--focused` class and the\n // `tabindex` are not in the DOM until that one has run.\n if (this.autoFocus()) {\n afterNextRender(() => this.focusActiveCell(), { injector: this.injector });\n }\n });\n\n // Keep viewDate in sync when date / range changes externally to a\n // different month. The viewDate read must stay untracked — otherwise\n // the effect re-runs on every internal navigation (month stepping,\n // year picking) and snaps the view back to the selected month.\n effect(() => {\n const candidate = this.mode() === 'single' ? this.date() : this.range()[0];\n if (!candidate) return;\n untracked(() => {\n if (!this.adapter.isSameMonth(candidate, this.viewDate())) {\n this.viewDate.set(candidate);\n }\n });\n });\n }\n\n // Navigation\n\n /** Header `‹` button — steps by month / year / decade based on the active view. */\n protected prev(): void {\n this.viewDate.set(this.stepViewDate(-1));\n }\n\n /** Header `›` button — steps by month / year / decade based on the active view. */\n protected next(): void {\n this.viewDate.set(this.stepViewDate(1));\n }\n\n /** Header label click — zooms out (`day → month → year`). No-op at year view. */\n protected onLabelClick(): void {\n if (this.disabled()) return;\n if (this.viewMode() === 'day') {\n this.setViewMode('month');\n } else if (this.viewMode() === 'month') {\n this.setViewMode('year');\n }\n }\n\n protected onMonthSelect(monthIdx: number): void {\n if (this.isMonthDisabled(monthIdx)) return;\n const v = this.viewDate();\n this.viewDate.set(this.adapter.createDate(this.adapter.getYear(v), monthIdx, 1));\n this.setViewMode('day');\n }\n\n protected onYearSelect(year: number): void {\n if (this.isYearDisabled(year)) return;\n const v = this.viewDate();\n this.viewDate.set(this.adapter.createDate(year, this.adapter.getMonth(v), 1));\n this.setViewMode('month');\n }\n\n /**\n * Switch views and drop the chip ring with them.\n *\n * Every view change is the only thing that changes what the chips MEAN, so it\n * is the one place the ring has to forget where it was — otherwise a year\n * picked at index 7 rings the eighth MONTH on the way back down.\n */\n private setViewMode(view: 'day' | 'month' | 'year'): void {\n this.rovedChip.set(null);\n this.viewMode.set(view);\n }\n\n private stepViewDate(direction: -1 | 1): Date {\n const v = this.viewDate();\n switch (this.viewMode()) {\n case 'day':\n return this.adapter.addMonths(v, direction);\n case 'month':\n return this.adapter.addYears(v, direction);\n case 'year':\n return this.adapter.addYears(v, direction * 12);\n }\n }\n\n // Cell state predicates (used by template)\n\n protected isToday(date: Date): boolean {\n return this.adapter.isSameDay(date, this.today());\n }\n\n protected isOutOfMonth(date: Date): boolean {\n return !this.adapter.isSameMonth(date, this.viewDate());\n }\n\n protected isSelected(date: Date): boolean {\n if (this.mode() === 'single') {\n const v = this.date();\n return v ? this.adapter.isSameDay(date, v) : false;\n }\n const [start, end] = this.range();\n if (start && this.adapter.isSameDay(date, start)) return true;\n if (end && this.adapter.isSameDay(date, end)) return true;\n return false;\n }\n\n protected isInRange(date: Date): boolean {\n if (this.mode() !== 'range') return false;\n const [start, end] = this.range();\n if (!start || !end) return false;\n return this.adapter.compareDate(date, start) > 0 && this.adapter.compareDate(date, end) < 0;\n }\n\n protected isInRangePreview(date: Date): boolean {\n if (this.mode() !== 'range') return false;\n const [start, end] = this.range();\n const hover = this.hoverDate();\n if (!start || end || !hover) return false;\n const before = this.adapter.compareDate(start, hover) <= 0;\n const lo = before ? start : hover;\n const hi = before ? hover : start;\n return this.adapter.compareDate(date, lo) > 0 && this.adapter.compareDate(date, hi) < 0;\n }\n\n protected isFocused(date: Date): boolean {\n return this.adapter.isSameDay(date, this.focusedDate());\n }\n\n protected isDisabled(date: Date): boolean {\n if (this.disabled()) return true;\n const min = this.min();\n if (min && this.adapter.compareDate(date, min) < 0) return true;\n const max = this.max();\n if (max && this.adapter.compareDate(date, max) > 0) return true;\n const filter = this.dateFilter();\n if (filter && !filter(date)) return true;\n return false;\n }\n\n // Month / year view predicates\n\n protected isMonthCurrent(monthIdx: number): boolean {\n return this.adapter.getMonth(this.viewDate()) === monthIdx;\n }\n\n protected isMonthSelected(monthIdx: number): boolean {\n const v = this.mode() === 'single' ? this.date() : this.range()[0];\n if (!v) return false;\n return this.adapter.getYear(v) === this.adapter.getYear(this.viewDate()) && this.adapter.getMonth(v) === monthIdx;\n }\n\n protected isMonthDisabled(monthIdx: number): boolean {\n if (this.disabled()) return true;\n const year = this.adapter.getYear(this.viewDate());\n const monthStart = this.adapter.createDate(year, monthIdx, 1);\n const monthEnd = this.adapter.createDate(year, monthIdx, this.adapter.getDaysInMonth(monthStart));\n const min = this.min();\n if (min && this.adapter.compareDate(monthEnd, min) < 0) return true;\n const max = this.max();\n if (max && this.adapter.compareDate(monthStart, max) > 0) return true;\n return false;\n }\n\n protected isYearCurrent(year: number): boolean {\n return this.adapter.getYear(this.viewDate()) === year;\n }\n\n protected isYearSelected(year: number): boolean {\n const v = this.mode() === 'single' ? this.date() : this.range()[0];\n return v ? this.adapter.getYear(v) === year : false;\n }\n\n protected isYearDisabled(year: number): boolean {\n if (this.disabled()) return true;\n const min = this.min();\n if (min && year < this.adapter.getYear(min)) return true;\n const max = this.max();\n if (max && year > this.adapter.getYear(max)) return true;\n return false;\n }\n\n // Interaction\n\n protected onCellClick(date: Date): void {\n if (this.isDisabled(date)) return;\n if (this.mode() === 'single') {\n this.date.set(this.adapter.clone(date));\n } else {\n this.applyRangeClick(date);\n }\n this.focusedDate.set(date);\n if (!this.adapter.isSameMonth(date, this.viewDate())) {\n this.viewDate.set(date);\n }\n }\n\n protected onCellEnter(date: Date): void {\n if (this.mode() === 'range') this.hoverDate.set(date);\n }\n\n protected onCellLeave(): void {\n if (this.mode() === 'range') this.hoverDate.set(null);\n }\n\n private applyRangeClick(date: Date): void {\n const [start, end] = this.range();\n if (!start || (start && end)) {\n this.range.set([this.adapter.clone(date), null]);\n return;\n }\n if (this.adapter.compareDate(date, start) < 0) {\n this.range.set([this.adapter.clone(date), start]);\n } else {\n this.range.set([start, this.adapter.clone(date)]);\n }\n this.hoverDate.set(null);\n }\n\n // Keyboard\n\n protected onKeyDown(event: KeyboardEvent): void {\n if (this.disabled()) return;\n\n // The listener sits on the HOST, which also wraps the nav header — so\n // without this every key aimed at a `‹` button drove the day grid instead,\n // and the `preventDefault()` below cancelled the button's own activation:\n // Enter on `‹` picked a day the user never touched, ArrowDown on the header\n // yanked real focus into the grid. The host element itself is deliberately\n // let through: `WrCalendarHarness` sends its keys to `<wr-calendar>` rather\n // than to a cell, because the calendar moves focus in an `afterNextRender`\n // and jsdom often has focus nowhere at all.\n const target = event.target as Element | null;\n if (target !== this.host.nativeElement && target?.closest('.wr-calendar__header')) return;\n\n // The month and year views are listboxes, and the arrows belong to them\n // while they are up — there is no day grid on screen to drive. Their chips\n // are real `<button>`s, so Enter and Space fall through to the browser's own\n // activation and must not be swallowed here.\n if (this.viewMode() !== 'day') {\n this.onChipKeyDown(event);\n return;\n }\n\n const current = this.focusedDate();\n let next: Date | null = null;\n // Which way the key travels, so a landing on a closed-off day can keep\n // going instead of stopping on it. See `nearestEnabledToward`.\n let dir: 1 | -1 = 1;\n\n switch (this.inlineKey(event.key)) {\n case 'ArrowLeft':\n next = this.adapter.addDays(current, -1);\n dir = -1;\n break;\n case 'ArrowRight':\n next = this.adapter.addDays(current, 1);\n break;\n case 'ArrowUp':\n next = this.adapter.addDays(current, -7);\n dir = -1;\n break;\n case 'ArrowDown':\n next = this.adapter.addDays(current, 7);\n break;\n case 'Home': {\n const dow = this.adapter.getDayOfWeek(current);\n const first = this.adapter.getFirstDayOfWeek();\n next = this.adapter.addDays(current, -((dow - first + 7) % 7));\n dir = -1;\n break;\n }\n case 'End': {\n const dow = this.adapter.getDayOfWeek(current);\n const first = this.adapter.getFirstDayOfWeek();\n next = this.adapter.addDays(current, 6 - ((dow - first + 7) % 7));\n break;\n }\n case 'PageUp':\n next = event.shiftKey ? this.adapter.addYears(current, -1) : this.adapter.addMonths(current, -1);\n dir = -1;\n break;\n case 'PageDown':\n next = event.shiftKey ? this.adapter.addYears(current, 1) : this.adapter.addMonths(current, 1);\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n this.onCellClick(current);\n return;\n }\n\n if (!next) return;\n event.preventDefault();\n\n // The seed is routed through `nearestEnabled` for a reason, and navigation\n // needs the same care: a cell renders `disabled` AND carries the grid's only\n // `tabindex=\"0\"`, so parking the ring on a closed-off day leaves zero\n // tabbable cells — the user tabs out of the calendar and can never tab back\n // in. Real focus splits from the ring too, because `.focus()` on a disabled\n // button is a no-op. Reached by nothing more exotic than `[minDate]`.\n const landing = this.nearestEnabledToward(next, dir);\n if (!landing) return;\n next = landing;\n\n this.focusedDate.set(next);\n if (!this.adapter.isSameMonth(next, this.viewDate())) {\n this.viewDate.set(next);\n }\n // `afterNextRender`, NOT `queueMicrotask`. Under zoneless CD the scheduler\n // runs change detection in a macrotask, so a microtask fires FIRST — the\n // `--focused` class is still on the cell we just left, and this focuses\n // that one. The ring moved and real focus did not, permanently: a screen\n // reader kept announcing the previous day.\n afterNextRender(() => this.focusActiveCell(), { injector: this.injector });\n }\n\n /**\n * Arrow / Home / End inside the month or year listbox — the roving half of the\n * pattern their `role` has always claimed.\n *\n * Steps by one along the row and by a full row vertically, and the inline pair\n * mirrors under `dir=\"rtl\"` for the same reason the grid's does: those two keys\n * name a side of the screen. The page does NOT wrap or spill into the next\n * one — a month list is twelve fixed cells, and the header's `‹` / `›` are what\n * change which twelve. Anything else (Enter, Space, Tab, Escape) is left to the\n * button and to whatever owns the calendar.\n */\n private onChipKeyDown(event: KeyboardEvent): void {\n const cols = this.viewMode() === 'month' ? MONTH_COLS : YEAR_COLS;\n const count = this.chipCount();\n const current = this.activeChip();\n // Assigned on every branch that does not return, so it needs no placeholder.\n let next: number;\n // Which way to keep looking when the landing chip is closed off, exactly as\n // `nearestEnabledToward` does for days.\n let dir: 1 | -1 = 1;\n\n switch (this.inlineKey(event.key)) {\n case 'ArrowLeft':\n next = current - 1;\n dir = -1;\n break;\n case 'ArrowRight':\n next = current + 1;\n break;\n case 'ArrowUp':\n next = current - cols;\n dir = -1;\n break;\n case 'ArrowDown':\n next = current + cols;\n break;\n case 'Home':\n next = 0;\n break;\n case 'End':\n next = count - 1;\n dir = -1;\n break;\n default:\n return;\n }\n\n const landing = this.enabledChipToward(next, dir);\n if (landing === null) return;\n\n event.preventDefault();\n this.rovedChip.set(landing);\n // `afterNextRender`, not `queueMicrotask` — same trap as the grid: under\n // zoneless CD the microtask runs before the new `tabindex` is in the DOM, so\n // the focus call would land on the chip the ring just left.\n afterNextRender(() => this.focusActiveChip(), { injector: this.injector });\n }\n\n /** How many chips the current view renders — twelve either way, read rather than assumed. */\n private chipCount(): number {\n return this.viewMode() === 'month' ? this.monthsView().length : this.yearsView().length;\n }\n\n /** Whether the chip at `index` refuses selection in the current view. */\n private isChipDisabled(index: number): boolean {\n if (this.viewMode() === 'month') return this.isMonthDisabled(index);\n const year = this.yearsView()[index];\n return year === undefined || this.isYearDisabled(year);\n }\n\n /** The chip the view itself points at: the month or year currently on screen. */\n private currentChip(): number {\n if (this.viewMode() === 'month') return this.adapter.getMonth(this.viewDate());\n const index = this.yearsView().indexOf(this.adapter.getYear(this.viewDate()));\n return index === -1 ? 0 : index;\n }\n\n /**\n * The first selectable chip at or after `from`, else the first before it, else\n * `from` unchanged when the whole page is closed off — the chip version of\n * {@link nearestEnabled}, and it exists for the same reason: the ring carries\n * the only `tabindex=\"0\"`, and a disabled button cannot hold it.\n */\n private nearestEnabledChip(from: number): number {\n const count = this.chipCount();\n const start = Math.min(Math.max(from, 0), count - 1);\n if (!this.isChipDisabled(start)) return start;\n\n for (const step of [1, -1] as const) {\n const found = this.enabledChipToward(start + step, step);\n if (found !== null) return found;\n }\n return start;\n }\n\n /**\n * The first selectable chip at `from` or beyond it in `step`'s direction, else\n * null when that whole direction is closed off — which is the answer for an\n * ArrowLeft on the first chip: stay put.\n */\n private enabledChipToward(from: number, step: 1 | -1): number | null {\n for (let i = from; i >= 0 && i < this.chipCount(); i += step) {\n if (!this.isChipDisabled(i)) return i;\n }\n return null;\n }\n\n private focusActiveChip(): void {\n // By the tab stop, not by index: it is the same element the ring is on, and\n // asking for it this way cannot drift out of step with the template.\n this.host.nativeElement.querySelector<HTMLElement>('.wr-calendar__chip[tabindex=\"0\"]')?.focus();\n }\n\n /**\n * The first selectable day at or after `candidate`, else the first before it,\n * else `candidate` unchanged when everything nearby is closed off. Bounded at\n * a year each way so a pathological `dateFilter` cannot spin.\n */\n private nearestEnabled(candidate: Date): Date {\n if (!this.isDisabled(candidate)) return candidate;\n\n for (const step of [1, -1] as const) {\n let probe = candidate;\n for (let i = 0; i < 366; i++) {\n probe = this.adapter.addDays(probe, step);\n if (!this.isDisabled(probe)) return probe;\n }\n }\n return candidate;\n }\n\n /**\n * The first selectable day at `candidate` or beyond it in `step`'s direction,\n * else null when that whole direction is closed off — which is the answer for\n * an ArrowLeft that would cross `min`: stay put.\n *\n * Direction matters. Reusing `nearestEnabled`, which probes forward first,\n * would send an ArrowLeft over a disabled weekend straight back to the day it\n * started from, so the ring could never cross the hole.\n */\n private nearestEnabledToward(candidate: Date, step: 1 | -1): Date | null {\n let probe = candidate;\n for (let i = 0; i < 366; i++) {\n if (!this.isDisabled(probe)) return probe;\n probe = this.adapter.addDays(probe, step);\n }\n return null;\n }\n\n private focusActiveCell(): void {\n const el = this.host.nativeElement.querySelector('.wr-calendar__day--focused');\n (el as HTMLElement | null)?.focus();\n }\n\n /** Used by the template's `track` expression. */\n protected trackByTime(_: number, date: Date): number {\n return date.getTime();\n }\n\n /**\n * The key as the GRID sees it.\n *\n * Arrow keys follow visual order, and a calendar grid mirrors under\n * `dir=\"rtl\"`: the day to the visual right of today is yesterday. Only the\n * inline pair swaps — Up/Down step a week either way, and PageUp/PageDown and\n * Home/End are semantic rather than physical.\n */\n private inlineKey(key: string): string {\n if (this.dir?.value !== 'rtl') return key;\n if (key === 'ArrowRight') return 'ArrowLeft';\n if (key === 'ArrowLeft') return 'ArrowRight';\n return key;\n }\n}\n","<div class=\"wr-calendar__header\">\n <button\n type=\"button\"\n class=\"wr-calendar__nav wr-calendar__nav--prev\"\n [attr.aria-label]=\"prevLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"prev()\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"wr-calendar__label\"\n [disabled]=\"disabled() || viewMode() === 'year'\"\n (click)=\"onLabelClick()\"\n >\n {{ headerLabel() }}\n </button>\n <button\n type=\"button\"\n class=\"wr-calendar__nav wr-calendar__nav--next\"\n [attr.aria-label]=\"nextLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"next()\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n</div>\n\n@switch (viewMode()) {\n @case ('day') {\n <!--\n The weekday strip and the week rows are one grid, so they share a wrapper:\n `role=\"grid\"` may only own rows, and as siblings the header row had no grid\n parent at all. `.wr-calendar__body` repeats the host's column gap, so the\n rendered spacing is unchanged.\n -->\n <div class=\"wr-calendar__body\" role=\"grid\">\n <div class=\"wr-calendar__weekdays\" role=\"row\">\n @for (name of weekdayNames(); track name) {\n <span class=\"wr-calendar__weekday\" role=\"columnheader\">{{ name }}</span>\n }\n </div>\n\n <div class=\"wr-calendar__grid\" role=\"rowgroup\" (mouseleave)=\"onCellLeave()\">\n @for (week of weeks(); track $index) {\n <div class=\"wr-calendar__week\" role=\"row\">\n @for (day of week; track trackByTime($index, day)) {\n <button\n type=\"button\"\n class=\"wr-calendar__day\"\n role=\"gridcell\"\n [class.wr-calendar__day--today]=\"isToday(day)\"\n [class.wr-calendar__day--out-of-month]=\"isOutOfMonth(day)\"\n [class.wr-calendar__day--selected]=\"isSelected(day)\"\n [class.wr-calendar__day--in-range]=\"isInRange(day)\"\n [class.wr-calendar__day--range-preview]=\"isInRangePreview(day)\"\n [class.wr-calendar__day--focused]=\"isFocused(day)\"\n [disabled]=\"isDisabled(day)\"\n [attr.tabindex]=\"isFocused(day) ? 0 : -1\"\n [attr.aria-label]=\"dayLabel(day)\"\n [attr.aria-selected]=\"isSelected(day)\"\n [attr.aria-disabled]=\"isDisabled(day)\"\n (click)=\"onCellClick(day)\"\n (mouseenter)=\"onCellEnter(day)\"\n >\n {{ day.getDate() }}\n </button>\n }\n </div>\n }\n </div>\n </div>\n }\n\n @case ('month') {\n <!--\n A listbox owns its arrows, so its options share ONE tab stop: twelve months\n that were each tabbable announced a keyboard model — arrow to a month, Tab\n out of the list — that the component did not have. `activeChip()` is where\n the ring is, and it is always an enabled chip.\n -->\n <div class=\"wr-calendar__months\" role=\"listbox\">\n @for (name of monthsView(); track name) {\n <button\n type=\"button\"\n class=\"wr-calendar__chip\"\n role=\"option\"\n [class.wr-calendar__chip--current]=\"isMonthCurrent($index)\"\n [class.wr-calendar__chip--selected]=\"isMonthSelected($index)\"\n [disabled]=\"isMonthDisabled($index)\"\n [attr.tabindex]=\"activeChip() === $index ? 0 : -1\"\n [attr.aria-selected]=\"isMonthSelected($index)\"\n [attr.aria-disabled]=\"isMonthDisabled($index)\"\n (click)=\"onMonthSelect($index)\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n @case ('year') {\n <div class=\"wr-calendar__years\" role=\"listbox\">\n @for (year of yearsView(); track year) {\n <button\n type=\"button\"\n class=\"wr-calendar__chip\"\n role=\"option\"\n [class.wr-calendar__chip--current]=\"isYearCurrent(year)\"\n [class.wr-calendar__chip--selected]=\"isYearSelected(year)\"\n [disabled]=\"isYearDisabled(year)\"\n [attr.tabindex]=\"activeChip() === $index ? 0 : -1\"\n [attr.aria-selected]=\"isYearSelected(year)\"\n [attr.aria-disabled]=\"isYearDisabled(year)\"\n (click)=\"onYearSelect(year)\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;AAAA;;;;;AAKG;AAwBH;;;AAGG;AACH,MAAM,WAAW,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC,UAAU,EAAE;AAE5D,MAAM,IAAI,GAAG,CAAC;AACd,MAAM,IAAI,GAAG,CAAC;AAEd;;;;;AAKG;AACH,MAAM,UAAU,GAAG,CAAC;AACpB,MAAM,SAAS,GAAG,CAAC;AAEnB;;;;;;;;;;;;;;;;AAgBG;MAaU,UAAU,CAAA;;IAEZ,IAAI,GAAG,KAAK,CAAiB,QAAQ;6EAAC;;IAGtC,IAAI,GAAG,KAAK,CAAc,IAAI;6EAAC;;AAG/B,IAAA,KAAK,GAAG,KAAK,CAAkB,CAAC,IAAI,EAAE,IAAI,CAAC;8EAAC;;IAG5C,GAAG,GAAG,KAAK,CAAc,IAAI;4EAAC;;IAG9B,GAAG,GAAG,KAAK,CAAc,IAAI;4EAAC;;IAG9B,UAAU,GAAG,KAAK,CAAmC,IAAI;mFAAC;AAEnE;;;;;;;AAOG;IACM,SAAS,GAAG,KAAK,CAAC,KAAK,iFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;IAG9D,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;AAErD,IAAA,OAAO,GAAG,MAAM,CAAsB,aAAa,CAAC;IACpD,GAAG,GAAG,MAAM,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAChD,IAAA,IAAI,GAAG,MAAM,CAA0B,UAAU,CAAC;AAClD,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;;IAGzB,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;iFAAC;;IAGvC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;oFAAC;;IAG1C,SAAS,GAAG,MAAM,CAAc,IAAI;kFAAC;;IAGrC,QAAQ,GAAG,MAAM,CAA2B,KAAK;iFAAC;AAErE;;;;;;;;AAQG;IACc,SAAS,GAAG,MAAM,CAAgB,IAAI;kFAAC;;;;;IAMvC,cAAc,GAAG,WAAW,CAAC,WAAW,EAAE,oBAAoB,EAAE,gBAAgB,CAAC;IACjF,cAAc,GAAG,WAAW,CAAC,WAAW,EAAE,oBAAoB,EAAE,YAAY,CAAC;IAC7E,aAAa,GAAG,WAAW,CAAC,WAAW,EAAE,mBAAmB,EAAE,eAAe,CAAC;IAC9E,aAAa,GAAG,WAAW,CAAC,WAAW,EAAE,mBAAmB,EAAE,WAAW,CAAC;IAC1E,cAAc,GAAG,WAAW,CAAC,WAAW,EAAE,oBAAoB,EAAE,mBAAmB,CAAC;IACpF,cAAc,GAAG,WAAW,CAAC,WAAW,EAAE,oBAAoB,EAAE,eAAe,CAAC;;AAG9E,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAK;AAC3C,QAAA,QAAQ,IAAI,CAAC,QAAQ,EAAE;AACrB,YAAA,KAAK,MAAM;AACT,gBAAA,OAAO,IAAI,CAAC,cAAc,EAAE;AAC9B,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,IAAI,CAAC,aAAa,EAAE;AAC7B,YAAA;AACE,gBAAA,OAAO,IAAI,CAAC,cAAc,EAAE;;IAElC,CAAC;kFAAC;;AAGiB,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAK;AAC3C,QAAA,QAAQ,IAAI,CAAC,QAAQ,EAAE;AACrB,YAAA,KAAK,MAAM;AACT,gBAAA,OAAO,IAAI,CAAC,cAAc,EAAE;AAC9B,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,IAAI,CAAC,aAAa,EAAE;AAC7B,YAAA;AACE,gBAAA,OAAO,IAAI,CAAC,cAAc,EAAE;;IAElC,CAAC;kFAAC;IAEiB,KAAK,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;8EAAC;AAE5C,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC;qFAAC;AAEtE,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC;mFAAC;;AAGhE,IAAA,SAAS,GAAG,QAAQ,CAAoB,MAAK;AAC9D,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;AAC/C,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE;QACrC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC;IACxD,CAAC;kFAAC;AAEF;;;;;;;;;AASG;AACgB,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;AAC7C,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE;AACzB,QAAA,QAAQ,IAAI,CAAC,QAAQ,EAAE;YACrB,KAAK,KAAK,EAAE;gBACV,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC;gBACrD,OAAO,IAAI,CAAC,UAAU,CAAC;oBACrB,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;oBAC3C,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9B,iBAAA,CAAC;YACJ;AACA,YAAA,KAAK,OAAO;gBACV,OAAO,CAAA,EAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA,CAAE;YACrC,KAAK,MAAM,EAAE;AACX,gBAAA,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;gBAC9B,OAAO,IAAI,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;YAC5E;;IAEJ,CAAC;oFAAC;AAEe,IAAA,UAAU,GAAG,gBAAgB,CAAC,iBAAiB,EAAE,oBAAoB,CAAC;AACtE,IAAA,aAAa,GAAG,gBAAgB,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;AAC3E,IAAA,YAAY,GAAG,gBAAgB,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;AAE9F;;;;;;;;AAQG;AACc,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC;qFAAC;AAEtF;;;;;;;;;;;;AAYG;AACO,IAAA,QAAQ,CAAC,IAAU,EAAA;QAC3B,OAAO,IAAI,CAAC,YAAY,CAAC;YACvB,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YAC1G,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC;AAC5C,SAAA,CAAC;IACJ;;AAGmB,IAAA,KAAK,GAAG,QAAQ,CAA+B,MAAK;AACrE,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;AACzC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC;QAC5D,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE;QACvD,MAAM,IAAI,GAAG,CAAC,YAAY,GAAG,cAAc,GAAG,CAAC,IAAI,CAAC;AACpD,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC;QAE3D,MAAM,GAAG,GAAa,EAAE;AACxB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE;YAC7B,MAAM,GAAG,GAAW,EAAE;AACtB,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE;AAC7B,gBAAA,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;YACzD;AACA,YAAA,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;QACf;AACA,QAAA,OAAO,GAAG;IACZ,CAAC;8EAAC;AAEF;;;;;;;;;;;;;;AAcG;AACgB,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAK;AAC5C,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,KAAK;YAAE,OAAO,CAAC,CAAC;AACxC,QAAA,OAAO,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;IACxE,CAAC;mFAAC;AAEiB,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,KAAK,GAAG,CAAC,aAAa,EAAE,CAAA,aAAA,EAAgB,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE,CAAC;QAC5D,IAAI,IAAI,CAAC,QAAQ,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC;AACxD,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;IACxB,CAAC;gFAAC;AAEF,IAAA,WAAA,GAAA;;;;;;;;QAQE,eAAe,CAAC,MAAK;YACnB,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;AAC3F,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC;AAC7B,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;;;;AAK1B,YAAA,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE;AACpB,gBAAA,eAAe,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5E;AACF,QAAA,CAAC,CAAC;;;;;QAMF,MAAM,CAAC,MAAK;YACV,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC1E,YAAA,IAAI,CAAC,SAAS;gBAAE;YAChB,SAAS,CAAC,MAAK;AACb,gBAAA,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE;AACzD,oBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;gBAC9B;AACF,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;IACJ;;;IAKU,IAAI,GAAA;AACZ,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C;;IAGU,IAAI,GAAA;AACZ,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACzC;;IAGU,YAAY,GAAA;QACpB,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,KAAK,EAAE;AAC7B,YAAA,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;QAC3B;AAAO,aAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,OAAO,EAAE;AACtC,YAAA,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;QAC1B;IACF;AAEU,IAAA,aAAa,CAAC,QAAgB,EAAA;AACtC,QAAA,IAAI,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC;YAAE;AACpC,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE;QACzB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;AAChF,QAAA,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;IACzB;AAEU,IAAA,YAAY,CAAC,IAAY,EAAA;AACjC,QAAA,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;YAAE;AAC/B,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE;QACzB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7E,QAAA,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;IAC3B;AAEA;;;;;;AAMG;AACK,IAAA,WAAW,CAAC,IAA8B,EAAA;AAChD,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;IACzB;AAEQ,IAAA,YAAY,CAAC,SAAiB,EAAA;AACpC,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE;AACzB,QAAA,QAAQ,IAAI,CAAC,QAAQ,EAAE;AACrB,YAAA,KAAK,KAAK;gBACR,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC;AAC7C,YAAA,KAAK,OAAO;gBACV,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC;AAC5C,YAAA,KAAK,MAAM;AACT,gBAAA,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,GAAG,EAAE,CAAC;;IAErD;;AAIU,IAAA,OAAO,CAAC,IAAU,EAAA;AAC1B,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IACnD;AAEU,IAAA,YAAY,CAAC,IAAU,EAAA;AAC/B,QAAA,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IACzD;AAEU,IAAA,UAAU,CAAC,IAAU,EAAA;AAC7B,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,QAAQ,EAAE;AAC5B,YAAA,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;AACrB,YAAA,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,KAAK;QACpD;QACA,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE;QACjC,IAAI,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC;AAAE,YAAA,OAAO,IAAI;QAC7D,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC;AAAE,YAAA,OAAO,IAAI;AACzD,QAAA,OAAO,KAAK;IACd;AAEU,IAAA,SAAS,CAAC,IAAU,EAAA;AAC5B,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,OAAO;AAAE,YAAA,OAAO,KAAK;QACzC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE;AACjC,QAAA,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG;AAAE,YAAA,OAAO,KAAK;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC;IAC7F;AAEU,IAAA,gBAAgB,CAAC,IAAU,EAAA;AACnC,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,OAAO;AAAE,YAAA,OAAO,KAAK;QACzC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE;AACjC,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAA,IAAI,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC,KAAK;AAAE,YAAA,OAAO,KAAK;AACzC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;QAC1D,MAAM,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK;QACjC,MAAM,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC;IACzF;AAEU,IAAA,SAAS,CAAC,IAAU,EAAA;AAC5B,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;IACzD;AAEU,IAAA,UAAU,CAAC,IAAU,EAAA;QAC7B,IAAI,IAAI,CAAC,QAAQ,EAAE;AAAE,YAAA,OAAO,IAAI;AAChC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AACtB,QAAA,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC;AAAE,YAAA,OAAO,IAAI;AAC/D,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AACtB,QAAA,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC;AAAE,YAAA,OAAO,IAAI;AAC/D,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE;AAChC,QAAA,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AAAE,YAAA,OAAO,IAAI;AACxC,QAAA,OAAO,KAAK;IACd;;AAIU,IAAA,cAAc,CAAC,QAAgB,EAAA;AACvC,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,QAAQ;IAC5D;AAEU,IAAA,eAAe,CAAC,QAAgB,EAAA;QACxC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAClE,QAAA,IAAI,CAAC,CAAC;AAAE,YAAA,OAAO,KAAK;AACpB,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ;IACnH;AAEU,IAAA,eAAe,CAAC,QAAgB,EAAA;QACxC,IAAI,IAAI,CAAC,QAAQ,EAAE;AAAE,YAAA,OAAO,IAAI;AAChC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;AAClD,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;AACjG,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AACtB,QAAA,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC;AAAE,YAAA,OAAO,IAAI;AACnE,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AACtB,QAAA,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC;AAAE,YAAA,OAAO,IAAI;AACrE,QAAA,OAAO,KAAK;IACd;AAEU,IAAA,aAAa,CAAC,IAAY,EAAA;AAClC,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI;IACvD;AAEU,IAAA,cAAc,CAAC,IAAY,EAAA;QACnC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAClE,QAAA,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,KAAK;IACrD;AAEU,IAAA,cAAc,CAAC,IAAY,EAAA;QACnC,IAAI,IAAI,CAAC,QAAQ,EAAE;AAAE,YAAA,OAAO,IAAI;AAChC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QACtB,IAAI,GAAG,IAAI,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;AAAE,YAAA,OAAO,IAAI;AACxD,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QACtB,IAAI,GAAG,IAAI,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;AAAE,YAAA,OAAO,IAAI;AACxD,QAAA,OAAO,KAAK;IACd;;AAIU,IAAA,WAAW,CAAC,IAAU,EAAA;AAC9B,QAAA,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE;AAC3B,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,QAAQ,EAAE;AAC5B,YAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC;aAAO;AACL,YAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;QAC5B;AACA,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE;AACpD,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QACzB;IACF;AAEU,IAAA,WAAW,CAAC,IAAU,EAAA;AAC9B,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,OAAO;AAAE,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;IACvD;IAEU,WAAW,GAAA;AACnB,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,OAAO;AAAE,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;IACvD;AAEQ,IAAA,eAAe,CAAC,IAAU,EAAA;QAChC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE;QACjC,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,GAAG,CAAC,EAAE;AAC5B,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;YAChD;QACF;AACA,QAAA,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;AAC7C,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;QACnD;aAAO;AACL,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD;AACA,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;IAC1B;;AAIU,IAAA,SAAS,CAAC,KAAoB,EAAA;QACtC,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;;;;;;;;;AAUrB,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAwB;AAC7C,QAAA,IAAI,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,MAAM,EAAE,OAAO,CAAC,sBAAsB,CAAC;YAAE;;;;;AAMnF,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,KAAK,EAAE;AAC7B,YAAA,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;YACzB;QACF;AAEA,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE;QAClC,IAAI,IAAI,GAAgB,IAAI;;;QAG5B,IAAI,GAAG,GAAW,CAAC;QAEnB,QAAQ,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC;AAC/B,YAAA,KAAK,WAAW;AACd,gBAAA,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACxC,GAAG,GAAG,CAAC,CAAC;gBACR;AACF,YAAA,KAAK,YAAY;gBACf,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBACvC;AACF,YAAA,KAAK,SAAS;AACZ,gBAAA,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACxC,GAAG,GAAG,CAAC,CAAC;gBACR;AACF,YAAA,KAAK,WAAW;gBACd,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBACvC;YACF,KAAK,MAAM,EAAE;gBACX,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC;gBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE;gBAC9C,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC9D,GAAG,GAAG,CAAC,CAAC;gBACR;YACF;YACA,KAAK,KAAK,EAAE;gBACV,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC;gBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE;gBAC9C,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;gBACjE;YACF;AACA,YAAA,KAAK,QAAQ;AACX,gBAAA,IAAI,GAAG,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBAChG,GAAG,GAAG,CAAC,CAAC;gBACR;AACF,YAAA,KAAK,UAAU;AACb,gBAAA,IAAI,GAAG,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC9F;AACF,YAAA,KAAK,OAAO;AACZ,YAAA,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;gBACzB;;AAGJ,QAAA,IAAI,CAAC,IAAI;YAAE;QACX,KAAK,CAAC,cAAc,EAAE;;;;;;;QAQtB,MAAM,OAAO,GAAG,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC;AACpD,QAAA,IAAI,CAAC,OAAO;YAAE;QACd,IAAI,GAAG,OAAO;AAEd,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE;AACpD,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QACzB;;;;;;AAMA,QAAA,eAAe,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC5E;AAEA;;;;;;;;;;AAUG;AACK,IAAA,aAAa,CAAC,KAAoB,EAAA;AACxC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,OAAO,GAAG,UAAU,GAAG,SAAS;AACjE,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE;;AAEjC,QAAA,IAAI,IAAY;;;QAGhB,IAAI,GAAG,GAAW,CAAC;QAEnB,QAAQ,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC;AAC/B,YAAA,KAAK,WAAW;AACd,gBAAA,IAAI,GAAG,OAAO,GAAG,CAAC;gBAClB,GAAG,GAAG,CAAC,CAAC;gBACR;AACF,YAAA,KAAK,YAAY;AACf,gBAAA,IAAI,GAAG,OAAO,GAAG,CAAC;gBAClB;AACF,YAAA,KAAK,SAAS;AACZ,gBAAA,IAAI,GAAG,OAAO,GAAG,IAAI;gBACrB,GAAG,GAAG,CAAC,CAAC;gBACR;AACF,YAAA,KAAK,WAAW;AACd,gBAAA,IAAI,GAAG,OAAO,GAAG,IAAI;gBACrB;AACF,YAAA,KAAK,MAAM;gBACT,IAAI,GAAG,CAAC;gBACR;AACF,YAAA,KAAK,KAAK;AACR,gBAAA,IAAI,GAAG,KAAK,GAAG,CAAC;gBAChB,GAAG,GAAG,CAAC,CAAC;gBACR;AACF,YAAA;gBACE;;QAGJ,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC;QACjD,IAAI,OAAO,KAAK,IAAI;YAAE;QAEtB,KAAK,CAAC,cAAc,EAAE;AACtB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;;;;AAI3B,QAAA,eAAe,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC5E;;IAGQ,SAAS,GAAA;QACf,OAAO,IAAI,CAAC,QAAQ,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM;IACzF;;AAGQ,IAAA,cAAc,CAAC,KAAa,EAAA;AAClC,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,OAAO;AAAE,YAAA,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;QACnE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC;QACpC,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;IACxD;;IAGQ,WAAW,GAAA;AACjB,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9E,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC7E,QAAA,OAAO,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;IACjC;AAEA;;;;;AAKG;AACK,IAAA,kBAAkB,CAAC,IAAY,EAAA;AACrC,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC;AACpD,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;AAAE,YAAA,OAAO,KAAK;QAE7C,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAU,EAAE;AACnC,YAAA,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,GAAG,IAAI,EAAE,IAAI,CAAC;YACxD,IAAI,KAAK,KAAK,IAAI;AAAE,gBAAA,OAAO,KAAK;QAClC;AACA,QAAA,OAAO,KAAK;IACd;AAEA;;;;AAIG;IACK,iBAAiB,CAAC,IAAY,EAAE,IAAY,EAAA;QAClD,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE;AAC5D,YAAA,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAAE,gBAAA,OAAO,CAAC;QACvC;AACA,QAAA,OAAO,IAAI;IACb;IAEQ,eAAe,GAAA;;;AAGrB,QAAA,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,CAAc,kCAAkC,CAAC,EAAE,KAAK,EAAE;IACjG;AAEA;;;;AAIG;AACK,IAAA,cAAc,CAAC,SAAe,EAAA;AACpC,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;AAAE,YAAA,OAAO,SAAS;QAEjD,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAU,EAAE;YACnC,IAAI,KAAK,GAAG,SAAS;AACrB,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;gBAC5B,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;AACzC,gBAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;AAAE,oBAAA,OAAO,KAAK;YAC3C;QACF;AACA,QAAA,OAAO,SAAS;IAClB;AAEA;;;;;;;;AAQG;IACK,oBAAoB,CAAC,SAAe,EAAE,IAAY,EAAA;QACxD,IAAI,KAAK,GAAG,SAAS;AACrB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AAC5B,YAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;AAAE,gBAAA,OAAO,KAAK;YACzC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;QAC3C;AACA,QAAA,OAAO,IAAI;IACb;IAEQ,eAAe,GAAA;AACrB,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,4BAA4B,CAAC;QAC7E,EAAyB,EAAE,KAAK,EAAE;IACrC;;IAGU,WAAW,CAAC,CAAS,EAAE,IAAU,EAAA;AACzC,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE;IACvB;AAEA;;;;;;;AAOG;AACK,IAAA,SAAS,CAAC,GAAW,EAAA;AAC3B,QAAA,IAAI,IAAI,CAAC,GAAG,EAAE,KAAK,KAAK,KAAK;AAAE,YAAA,OAAO,GAAG;QACzC,IAAI,GAAG,KAAK,YAAY;AAAE,YAAA,OAAO,WAAW;QAC5C,IAAI,GAAG,KAAK,WAAW;AAAE,YAAA,OAAO,YAAY;AAC5C,QAAA,OAAO,GAAG;IACZ;uGA/sBW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,2rCC5EvB,47JAmJA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDvEa,UAAU,EAAA,UAAA,EAAA,CAAA;kBAZtB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,aAAa,EAAA,aAAA,EAER,iBAAiB,CAAC,IAAI,EAAA,IAAA,EAC/B;AACJ,wBAAA,SAAS,EAAE,WAAW;;;;AAItB,wBAAA,WAAW,EAAE,mBAAmB;AACjC,qBAAA,EAAA,QAAA,EAAA,47JAAA,EAAA;;;AE1EH;;AAEG;;;;"}
|
|
@@ -66,6 +66,15 @@ class WrCircularText {
|
|
|
66
66
|
platform = inject(WrPlatform);
|
|
67
67
|
rotation = null;
|
|
68
68
|
hovered = false;
|
|
69
|
+
/**
|
|
70
|
+
* The effect below reaches `startOrSwap()` through a `queueMicrotask`, so the
|
|
71
|
+
* ring can be destroyed between the two. Without this flag the continuation
|
|
72
|
+
* then starts an infinite Web Animation on a host Angular has already
|
|
73
|
+
* detached — and an animation keeps its target alive, so the whole `#spin`
|
|
74
|
+
* subtree is retained for the life of the page. Same hazard, and same flag, as
|
|
75
|
+
* `wr-split-text` and `wr-fuzzy-text`.
|
|
76
|
+
*/
|
|
77
|
+
destroyed = false;
|
|
69
78
|
/** Active spin duration in seconds — base, or hover-modified. */
|
|
70
79
|
effectiveDuration() {
|
|
71
80
|
const base = this.spinDuration();
|
|
@@ -87,6 +96,15 @@ class WrCircularText {
|
|
|
87
96
|
constructor() {
|
|
88
97
|
if (!this.isBrowser)
|
|
89
98
|
return;
|
|
99
|
+
// Component-scoped, NOT inside the render hook below: `startOrSwap()` is
|
|
100
|
+
// reachable from the effect's microtask, which can create the animation
|
|
101
|
+
// before that hook has run — and a cleanup registered inside a callback that
|
|
102
|
+
// never ran is not registered at all. The listeners stay paired with the
|
|
103
|
+
// element they are added to.
|
|
104
|
+
this.destroyRef.onDestroy(() => {
|
|
105
|
+
this.destroyed = true;
|
|
106
|
+
this.rotation?.cancel();
|
|
107
|
+
});
|
|
90
108
|
afterNextRender(() => {
|
|
91
109
|
this.startOrSwap();
|
|
92
110
|
const host = this.spinEl().nativeElement.parentElement;
|
|
@@ -103,7 +121,6 @@ class WrCircularText {
|
|
|
103
121
|
this.destroyRef.onDestroy(() => {
|
|
104
122
|
host.removeEventListener('mouseenter', onEnter);
|
|
105
123
|
host.removeEventListener('mouseleave', onLeave);
|
|
106
|
-
this.rotation?.cancel();
|
|
107
124
|
});
|
|
108
125
|
});
|
|
109
126
|
// React to input changes (spinDuration, onHover) — and the OS
|
|
@@ -120,6 +137,8 @@ class WrCircularText {
|
|
|
120
137
|
* current angle. If the new mode is `pause`, just pause the animation.
|
|
121
138
|
*/
|
|
122
139
|
startOrSwap() {
|
|
140
|
+
if (this.destroyed)
|
|
141
|
+
return;
|
|
123
142
|
if (!this.spinEl())
|
|
124
143
|
return;
|
|
125
144
|
// Reduced motion: hold the ring still — the circular layout is the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-circular-text.mjs","sources":["../../../projects/lib/circular-text/circular-text.ts","../../../projects/lib/circular-text/circular-text.html","../../../projects/lib/circular-text/ngwr-circular-text.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n *\n * Angular adaptation of the CircularText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/circular-text\n *\n * Reactbits drives the rotation with `motion/react`, which lets the spin\n * angle persist across speed changes. CSS keyframes can't do that — when\n * `animation-duration` changes mid-flight, the browser recomputes the\n * progress as `(elapsed % newDuration) / newDuration`, which visibly\n * jumps the rotation. So this port drives the rotation through the\n * Web Animations API and preserves the current angle when hover swaps\n * the duration. Bonkers `scale` is still CSS-driven (no conflict — the\n * rotation lives on an inner wrapper).\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n type ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrCircularTextHover } from './interfaces';\n\ninterface Char {\n readonly ch: string;\n readonly transform: string;\n}\n\n/**\n * Text laid out around a circle, with the whole circle spinning. Hover\n * behaviour swaps the spin rate (or pauses it) — the current rotation\n * angle is preserved across the swap so there's no visible jump.\n *\n * @example\n * ```html\n * <wr-circular-text text=\"HELLO * NGWR * \" />\n * <wr-circular-text text=\"GO BONKERS\" onHover=\"goBonkers\" [spinDuration]=\"12\" />\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/circular-text\n */\n@Component({\n selector: 'wr-circular-text',\n templateUrl: './circular-text.html',\n styleUrl: './circular-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-circular-text',\n '[class.wr-circular-text--bonkers]': \"onHover() === 'goBonkers'\",\n },\n})\nexport class WrCircularText {\n /** Text to lay out around the circle. */\n readonly text = input.required<string>();\n\n /** Seconds per full revolution at rest. @default 20 */\n readonly spinDuration = input(20, { transform: numAttr(20) });\n\n /** Hover behaviour. `null` disables hover reactivity. @default 'speedUp' */\n readonly onHover = input<WrCircularTextHover>('speedUp');\n\n protected readonly chars = computed<readonly Char[]>(() => {\n const letters = Array.from(this.text());\n const len = letters.length;\n if (len === 0) return [];\n return letters.map((ch, i) => {\n const rotation = (360 / len) * i;\n // Rotate around the spinner's centre, then push each char outward\n // by the orbit radius (set via CSS var). All chars end up on a\n // circle of constant radius — not a diagonal line.\n const transform = `rotate(${rotation}deg) translateY(calc(-1 * var(--wr-circular-text-radius)))`;\n return { ch, transform };\n });\n });\n\n private readonly spinEl = viewChild.required<ElementRef<HTMLElement>>('spin');\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n private rotation: Animation | null = null;\n private hovered = false;\n\n /** Active spin duration in seconds — base, or hover-modified. */\n private effectiveDuration(): number | 'pause' {\n const base = this.spinDuration();\n if (!this.hovered) return base;\n switch (this.onHover()) {\n case 'speedUp':\n return base / 4;\n case 'slowDown':\n return base * 2;\n case 'pause':\n return 'pause';\n case 'goBonkers':\n return base / 20;\n default:\n return base;\n }\n }\n\n constructor() {\n if (!this.isBrowser) return;\n\n afterNextRender(() => {\n this.startOrSwap();\n\n const host = this.spinEl().nativeElement.parentElement!;\n const onEnter = (): void => {\n this.hovered = true;\n this.startOrSwap();\n };\n const onLeave = (): void => {\n this.hovered = false;\n this.startOrSwap();\n };\n host.addEventListener('mouseenter', onEnter);\n host.addEventListener('mouseleave', onLeave);\n this.destroyRef.onDestroy(() => {\n host.removeEventListener('mouseenter', onEnter);\n host.removeEventListener('mouseleave', onLeave);\n this.rotation?.cancel();\n });\n });\n\n // React to input changes (spinDuration, onHover) — and the OS\n // reduced-motion setting — without losing angle.\n effect(() => {\n this.spinDuration();\n this.onHover();\n this.platform.prefersReducedMotion();\n queueMicrotask(() => this.startOrSwap());\n });\n }\n\n /**\n * Start the rotation, or swap its duration while preserving the\n * current angle. If the new mode is `pause`, just pause the animation.\n */\n private startOrSwap(): void {\n if (!this.spinEl()) return;\n\n // Reduced motion: hold the ring still — the circular layout is the\n // point of the component; only the revolution is decorative.\n if (this.platform.prefersReducedMotion()) {\n this.rotation?.pause();\n return;\n }\n\n const target = this.effectiveDuration();\n\n if (target === 'pause') {\n this.rotation?.pause();\n return;\n }\n\n const newDurMs = Math.max(1, target * 1000);\n\n // First start — no previous animation to preserve.\n if (!this.rotation) {\n this.rotation = this.spinEl().nativeElement.animate(\n [{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],\n { duration: newDurMs, iterations: Infinity, easing: 'linear' }\n );\n return;\n }\n\n // Compute the current angle (0..1 of a full turn) under the old\n // timing, then restart with the new duration seeked to the same\n // angle — keeps the visual continuous across speed changes.\n const oldEffect = this.rotation.effect as KeyframeEffect | null;\n const oldDurMs = (oldEffect?.getTiming().duration as number) || newDurMs || newDurMs;\n const oldTime = (this.rotation.currentTime as number) ?? 0;\n const ratio = (((oldTime % oldDurMs) + oldDurMs) % oldDurMs) / oldDurMs;\n\n this.rotation.cancel();\n this.rotation = this.spinEl().nativeElement.animate(\n [{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],\n { duration: newDurMs, iterations: Infinity, easing: 'linear' }\n );\n this.rotation.currentTime = ratio * newDurMs;\n }\n}\n\nexport type { WrCircularTextHover } from './interfaces';\n","<!--\n The readable text, once: the ring below is per-character spans, which a screen\n reader may read out one letter at a time. Same shape as `wr-blur-text` and\n `wr-decrypt-text` — the string is carried here and the pieces are taken out of\n the tree with one `aria-hidden` on the wrapper rather than N on the chars, so\n the attribute stays off the nodes the rotation touches. It sits OUTSIDE\n `__spin`, or it would be hidden with the chars and would spin with them.\n-->\n<span class=\"wr-circular-text__sr-only\">{{ text() }}</span>\n<span class=\"wr-circular-text__spin\" aria-hidden=\"true\" #spin>\n @for (c of chars(); track $index) {\n <span class=\"wr-circular-text__char\" [style.transform]=\"c.transform\">{{ c.ch }}</span>\n }\n</span>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;AAiBG;AA2BH;;;;;;;;;;;;AAYG;MAWU,cAAc,CAAA;;IAEhB,IAAI,GAAG,KAAK,CAAC,QAAQ;6EAAU;;AAG/B,IAAA,YAAY,GAAG,KAAK,CAAC,EAAE,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,cAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,EAAA,CAAG;;IAGpD,OAAO,GAAG,KAAK,CAAsB,SAAS;gFAAC;AAErC,IAAA,KAAK,GAAG,QAAQ,CAAkB,MAAK;QACxD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACvC,QAAA,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM;QAC1B,IAAI,GAAG,KAAK,CAAC;AAAE,YAAA,OAAO,EAAE;QACxB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,KAAI;YAC3B,MAAM,QAAQ,GAAG,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;;;;AAIhC,YAAA,MAAM,SAAS,GAAG,CAAA,OAAA,EAAU,QAAQ,4DAA4D;AAChG,YAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE;AAC1B,QAAA,CAAC,CAAC;IACJ,CAAC;8EAAC;AAEe,IAAA,MAAM,GAAG,SAAS,CAAC,QAAQ,CAA0B,MAAM;+EAAC;AAE5D,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAC/B,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAClD,IAAA,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC;IACtC,QAAQ,GAAqB,IAAI;IACjC,OAAO,GAAG,KAAK;;IAGf,iBAAiB,GAAA;AACvB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE;QAChC,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,YAAA,OAAO,IAAI;AAC9B,QAAA,QAAQ,IAAI,CAAC,OAAO,EAAE;AACpB,YAAA,KAAK,SAAS;gBACZ,OAAO,IAAI,GAAG,CAAC;AACjB,YAAA,KAAK,UAAU;gBACb,OAAO,IAAI,GAAG,CAAC;AACjB,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,OAAO;AAChB,YAAA,KAAK,WAAW;gBACd,OAAO,IAAI,GAAG,EAAE;AAClB,YAAA;AACE,gBAAA,OAAO,IAAI;;IAEjB;AAEA,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE;QAErB,eAAe,CAAC,MAAK;YACnB,IAAI,CAAC,WAAW,EAAE;YAElB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,aAAc;YACvD,MAAM,OAAO,GAAG,MAAW;AACzB,gBAAA,IAAI,CAAC,OAAO,GAAG,IAAI;gBACnB,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,CAAC;YACD,MAAM,OAAO,GAAG,MAAW;AACzB,gBAAA,IAAI,CAAC,OAAO,GAAG,KAAK;gBACpB,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,CAAC;AACD,YAAA,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,OAAO,CAAC;AAC5C,YAAA,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,OAAO,CAAC;AAC5C,YAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAK;AAC7B,gBAAA,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE,OAAO,CAAC;AAC/C,gBAAA,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE,OAAO,CAAC;AAC/C,gBAAA,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE;AACzB,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;;;QAIF,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,YAAY,EAAE;YACnB,IAAI,CAAC,OAAO,EAAE;AACd,YAAA,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE;YACpC,cAAc,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;AAC1C,QAAA,CAAC,CAAC;IACJ;AAEA;;;AAGG;IACK,WAAW,GAAA;AACjB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE;;;AAIpB,QAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE,EAAE;AACxC,YAAA,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE;YACtB;QACF;AAEA,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,EAAE;AAEvC,QAAA,IAAI,MAAM,KAAK,OAAO,EAAE;AACtB,YAAA,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE;YACtB;QACF;AAEA,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;;AAG3C,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAClB,YAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,OAAO,CACjD,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,EAChE,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAC/D;YACD;QACF;;;;AAKA,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,MAA+B;AAC/D,QAAA,MAAM,QAAQ,GAAI,SAAS,EAAE,SAAS,EAAE,CAAC,QAAmB,IAAI,QAAQ,IAAI,QAAQ;QACpF,MAAM,OAAO,GAAI,IAAI,CAAC,QAAQ,CAAC,WAAsB,IAAI,CAAC;AAC1D,QAAA,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,QAAQ,IAAI,QAAQ,IAAI,QAAQ,IAAI,QAAQ;AAEvE,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;AACtB,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,OAAO,CACjD,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,EAChE,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAC/D;QACD,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,KAAK,GAAG,QAAQ;IAC9C;uGAlIW,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,qsBCnE3B,owBAcA,EAAA,MAAA,EAAA,CAAA,6vBAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDqDa,cAAc,EAAA,UAAA,EAAA,CAAA;kBAV1B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,kBAAkB,EAAA,aAAA,EAGb,iBAAiB,CAAC,IAAI,EAAA,IAAA,EAC/B;AACJ,wBAAA,KAAK,EAAE,kBAAkB;AACzB,wBAAA,mCAAmC,EAAE,2BAA2B;AACjE,qBAAA,EAAA,QAAA,EAAA,owBAAA,EAAA,MAAA,EAAA,CAAA,6vBAAA,CAAA,EAAA;2XA0BqE,MAAM,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AE3F9E;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"ngwr-circular-text.mjs","sources":["../../../projects/lib/circular-text/circular-text.ts","../../../projects/lib/circular-text/circular-text.html","../../../projects/lib/circular-text/ngwr-circular-text.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n *\n * Angular adaptation of the CircularText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/circular-text\n *\n * Reactbits drives the rotation with `motion/react`, which lets the spin\n * angle persist across speed changes. CSS keyframes can't do that — when\n * `animation-duration` changes mid-flight, the browser recomputes the\n * progress as `(elapsed % newDuration) / newDuration`, which visibly\n * jumps the rotation. So this port drives the rotation through the\n * Web Animations API and preserves the current angle when hover swaps\n * the duration. Bonkers `scale` is still CSS-driven (no conflict — the\n * rotation lives on an inner wrapper).\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n type ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrCircularTextHover } from './interfaces';\n\ninterface Char {\n readonly ch: string;\n readonly transform: string;\n}\n\n/**\n * Text laid out around a circle, with the whole circle spinning. Hover\n * behaviour swaps the spin rate (or pauses it) — the current rotation\n * angle is preserved across the swap so there's no visible jump.\n *\n * @example\n * ```html\n * <wr-circular-text text=\"HELLO * NGWR * \" />\n * <wr-circular-text text=\"GO BONKERS\" onHover=\"goBonkers\" [spinDuration]=\"12\" />\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/circular-text\n */\n@Component({\n selector: 'wr-circular-text',\n templateUrl: './circular-text.html',\n styleUrl: './circular-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-circular-text',\n '[class.wr-circular-text--bonkers]': \"onHover() === 'goBonkers'\",\n },\n})\nexport class WrCircularText {\n /** Text to lay out around the circle. */\n readonly text = input.required<string>();\n\n /** Seconds per full revolution at rest. @default 20 */\n readonly spinDuration = input(20, { transform: numAttr(20) });\n\n /** Hover behaviour. `null` disables hover reactivity. @default 'speedUp' */\n readonly onHover = input<WrCircularTextHover>('speedUp');\n\n protected readonly chars = computed<readonly Char[]>(() => {\n const letters = Array.from(this.text());\n const len = letters.length;\n if (len === 0) return [];\n return letters.map((ch, i) => {\n const rotation = (360 / len) * i;\n // Rotate around the spinner's centre, then push each char outward\n // by the orbit radius (set via CSS var). All chars end up on a\n // circle of constant radius — not a diagonal line.\n const transform = `rotate(${rotation}deg) translateY(calc(-1 * var(--wr-circular-text-radius)))`;\n return { ch, transform };\n });\n });\n\n private readonly spinEl = viewChild.required<ElementRef<HTMLElement>>('spin');\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n private rotation: Animation | null = null;\n private hovered = false;\n\n /**\n * The effect below reaches `startOrSwap()` through a `queueMicrotask`, so the\n * ring can be destroyed between the two. Without this flag the continuation\n * then starts an infinite Web Animation on a host Angular has already\n * detached — and an animation keeps its target alive, so the whole `#spin`\n * subtree is retained for the life of the page. Same hazard, and same flag, as\n * `wr-split-text` and `wr-fuzzy-text`.\n */\n private destroyed = false;\n\n /** Active spin duration in seconds — base, or hover-modified. */\n private effectiveDuration(): number | 'pause' {\n const base = this.spinDuration();\n if (!this.hovered) return base;\n switch (this.onHover()) {\n case 'speedUp':\n return base / 4;\n case 'slowDown':\n return base * 2;\n case 'pause':\n return 'pause';\n case 'goBonkers':\n return base / 20;\n default:\n return base;\n }\n }\n\n constructor() {\n if (!this.isBrowser) return;\n\n // Component-scoped, NOT inside the render hook below: `startOrSwap()` is\n // reachable from the effect's microtask, which can create the animation\n // before that hook has run — and a cleanup registered inside a callback that\n // never ran is not registered at all. The listeners stay paired with the\n // element they are added to.\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.rotation?.cancel();\n });\n\n afterNextRender(() => {\n this.startOrSwap();\n\n const host = this.spinEl().nativeElement.parentElement!;\n const onEnter = (): void => {\n this.hovered = true;\n this.startOrSwap();\n };\n const onLeave = (): void => {\n this.hovered = false;\n this.startOrSwap();\n };\n host.addEventListener('mouseenter', onEnter);\n host.addEventListener('mouseleave', onLeave);\n this.destroyRef.onDestroy(() => {\n host.removeEventListener('mouseenter', onEnter);\n host.removeEventListener('mouseleave', onLeave);\n });\n });\n\n // React to input changes (spinDuration, onHover) — and the OS\n // reduced-motion setting — without losing angle.\n effect(() => {\n this.spinDuration();\n this.onHover();\n this.platform.prefersReducedMotion();\n queueMicrotask(() => this.startOrSwap());\n });\n }\n\n /**\n * Start the rotation, or swap its duration while preserving the\n * current angle. If the new mode is `pause`, just pause the animation.\n */\n private startOrSwap(): void {\n if (this.destroyed) return;\n if (!this.spinEl()) return;\n\n // Reduced motion: hold the ring still — the circular layout is the\n // point of the component; only the revolution is decorative.\n if (this.platform.prefersReducedMotion()) {\n this.rotation?.pause();\n return;\n }\n\n const target = this.effectiveDuration();\n\n if (target === 'pause') {\n this.rotation?.pause();\n return;\n }\n\n const newDurMs = Math.max(1, target * 1000);\n\n // First start — no previous animation to preserve.\n if (!this.rotation) {\n this.rotation = this.spinEl().nativeElement.animate(\n [{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],\n { duration: newDurMs, iterations: Infinity, easing: 'linear' }\n );\n return;\n }\n\n // Compute the current angle (0..1 of a full turn) under the old\n // timing, then restart with the new duration seeked to the same\n // angle — keeps the visual continuous across speed changes.\n const oldEffect = this.rotation.effect as KeyframeEffect | null;\n const oldDurMs = (oldEffect?.getTiming().duration as number) || newDurMs || newDurMs;\n const oldTime = (this.rotation.currentTime as number) ?? 0;\n const ratio = (((oldTime % oldDurMs) + oldDurMs) % oldDurMs) / oldDurMs;\n\n this.rotation.cancel();\n this.rotation = this.spinEl().nativeElement.animate(\n [{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],\n { duration: newDurMs, iterations: Infinity, easing: 'linear' }\n );\n this.rotation.currentTime = ratio * newDurMs;\n }\n}\n\nexport type { WrCircularTextHover } from './interfaces';\n","<!--\n The readable text, once: the ring below is per-character spans, which a screen\n reader may read out one letter at a time. Same shape as `wr-blur-text` and\n `wr-decrypt-text` — the string is carried here and the pieces are taken out of\n the tree with one `aria-hidden` on the wrapper rather than N on the chars, so\n the attribute stays off the nodes the rotation touches. It sits OUTSIDE\n `__spin`, or it would be hidden with the chars and would spin with them.\n-->\n<span class=\"wr-circular-text__sr-only\">{{ text() }}</span>\n<span class=\"wr-circular-text__spin\" aria-hidden=\"true\" #spin>\n @for (c of chars(); track $index) {\n <span class=\"wr-circular-text__char\" [style.transform]=\"c.transform\">{{ c.ch }}</span>\n }\n</span>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-collapse.mjs","sources":["../../../projects/lib/collapse/tokens/collapse-group.token.ts","../../../projects/lib/collapse/collapse.ts","../../../projects/lib/collapse/collapse.html","../../../projects/lib/collapse/collapse-group.ts","../../../projects/lib/collapse/accordion.ts","../../../projects/lib/collapse/ngwr-collapse.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * Contract a collapse uses to talk to its parent `<wr-collapse-group>`.\n *\n * @internal\n */\nexport interface WrCollapseGroupContext {\n /** When true, only one child collapse may be open at a time. */\n readonly accordion: Signal<boolean>;\n /** Called by a child when it opens — closes siblings in accordion mode. */\n notifyOpened(opener: object): void;\n /** Register a child so the group can call `closeAll()` etc. */\n register(member: { close(): void; readonly id: object }): void;\n /** Unregister on destroy. */\n unregister(memberId: object): void;\n}\n\n/**\n * Token a `<wr-collapse>` injects to register itself with — and notify of\n * open events — its parent `<wr-collapse-group>`. Drives the accordion\n * behaviour when the group has `accordion` enabled.\n *\n * @internal\n */\nexport const WR_COLLAPSE_GROUP = new InjectionToken<WrCollapseGroupContext>('WR_COLLAPSE_GROUP');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, DestroyRef, ViewEncapsulation, computed, effect, inject, input, model } from '@angular/core';\n\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_COLLAPSE_GROUP } from './tokens';\n\n/**\n * Expandable panel with a clickable header. Two-way binds the `open`\n * state. When wrapped in `<wr-collapse-group accordion>`, only one\n * sibling can be open at a time.\n *\n * @example\n * ```html\n * <wr-collapse title=\"Section title\">\n * Section body…\n * </wr-collapse>\n *\n * <wr-collapse-group accordion>\n * <wr-collapse title=\"A\">…</wr-collapse>\n * <wr-collapse title=\"B\">…</wr-collapse>\n * </wr-collapse-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-collapse',\n templateUrl: './collapse.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrCollapse {\n /** Header text. */\n readonly title = input.required<string>();\n\n /** Two-way bindable open/closed state. @default false */\n readonly open = model<boolean>(false);\n\n /** Disable interaction. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Identity used by the parent group when tracking children. @internal */\n readonly id = { name: randomId('wr-collapse') };\n\n /** DOM id for the body element, referenced by header's `aria-controls`. */\n protected readonly bodyId = `wr-collapse-body-${this.id.name}`;\n\n private readonly group = inject(WR_COLLAPSE_GROUP, { optional: true });\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-collapse'];\n if (this.open()) parts.push('wr-collapse--open');\n if (this.disabled()) parts.push('wr-collapse--disabled');\n return parts.join(' ');\n });\n\n constructor() {\n if (this.group) {\n this.group.register({ id: this.id, close: () => this.open.set(false) });\n this.destroyRef.onDestroy(() => this.group?.unregister(this.id));\n\n // Tell the group whenever we open — group decides whether to close siblings.\n effect(() => {\n if (this.open()) this.group?.notifyOpened(this.id);\n });\n }\n }\n\n /** Open the panel. */\n openPanel(): void {\n if (this.disabled()) return;\n this.open.set(true);\n }\n\n /** Close the panel. */\n close(): void {\n this.open.set(false);\n }\n\n /** Toggle the panel. */\n toggle(): void {\n if (this.disabled()) return;\n this.open.update(v => !v);\n }\n}\n","<button\n type=\"button\"\n class=\"wr-collapse__header\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n [disabled]=\"disabled()\"\n (click)=\"toggle()\"\n>\n <span class=\"wr-collapse__title\">{{ title() }}</span>\n <svg\n class=\"wr-icon__svg wr-collapse__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n</button>\n\n<div\n class=\"wr-collapse__body\"\n [attr.id]=\"bodyId\"\n [class.wr-collapse__body--open]=\"open()\"\n [attr.aria-hidden]=\"!open()\"\n [attr.inert]=\"!open() ? '' : null\"\n>\n <div class=\"wr-collapse__content\">\n <div class=\"wr-collapse__inner\">\n <ng-content />\n </div>\n </div>\n</div>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, forwardRef, input } from '@angular/core';\n\nimport { WR_COLLAPSE_GROUP, type WrCollapseGroupContext } from './tokens';\n\ninterface Member {\n close(): void;\n readonly id: object;\n}\n\n/**\n * Visual + behavioral grouping of `<wr-collapse>` children. When\n * `accordion` is true, opening one child closes the others.\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-collapse-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-collapse-group' },\n providers: [\n {\n provide: WR_COLLAPSE_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrCollapseGroup),\n },\n ],\n})\nexport class WrCollapseGroup implements WrCollapseGroupContext {\n /** When true, only one child may be open at a time. @default false */\n readonly accordion = input(false, { transform: coerceBooleanProperty });\n\n private readonly members = new Map<object, Member>();\n\n register(member: Member): void {\n this.members.set(member.id, member);\n }\n\n unregister(memberId: object): void {\n this.members.delete(memberId);\n }\n\n notifyOpened(opener: object): void {\n if (!this.accordion()) return;\n for (const [id, member] of this.members) {\n if (id !== opener) member.close();\n }\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, forwardRef, signal } from '@angular/core';\n\nimport { WR_COLLAPSE_GROUP, type WrCollapseGroupContext } from './tokens';\n\ninterface Member {\n close(): void;\n readonly id: object;\n}\n\n/**\n * Accordion — a `<wr-collapse>` container that enforces single-open\n * behavior: opening a child closes its siblings.\n *\n * Use `<wr-collapse-group>` when you only need visual grouping without\n * the mutually-exclusive open semantics.\n *\n * @example\n * ```html\n * <wr-accordion>\n * <wr-collapse title=\"Profile\">…</wr-collapse>\n * <wr-collapse title=\"Security\">…</wr-collapse>\n * <wr-collapse title=\"Notifications\">…</wr-collapse>\n * </wr-accordion>\n * ```\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-accordion',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-collapse-group wr-collapse-group--accordion' },\n providers: [\n {\n provide: WR_COLLAPSE_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrAccordion),\n },\n ],\n})\nexport class WrAccordion implements WrCollapseGroupContext {\n /** Always behaves as an accordion. Provided for context-interface symmetry. */\n readonly accordion = signal(true).asReadonly();\n\n private readonly members = new Map<object, Member>();\n\n register(member: Member): void {\n this.members.set(member.id, member);\n }\n\n unregister(memberId: object): void {\n this.members.delete(memberId);\n }\n\n notifyOpened(opener: object): void {\n for (const [id, member] of this.members) {\n if (id !== opener) member.close();\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;AAAA;;;;;AAKG;AAoBH;;;;;;AAMG;MACU,iBAAiB,GAAG,IAAI,cAAc,CAAyB,mBAAmB;;AChC/F;;;;;AAKG;AASH;;;;;;;;;;;;;;;;;;AAkBG;MAOU,UAAU,CAAA;;IAEZ,KAAK,GAAG,KAAK,CAAC,QAAQ;8EAAU;;IAGhC,IAAI,GAAG,KAAK,CAAU,KAAK;6EAAC;;IAG5B,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;IAG7D,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,EAAE;;IAG5B,MAAM,GAAG,oBAAoB,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE;IAE7C,KAAK,GAAG,MAAM,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACrD,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAE7B,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,KAAK,GAAG,CAAC,aAAa,CAAC;QAC7B,IAAI,IAAI,CAAC,IAAI,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC;QAChD,IAAI,IAAI,CAAC,QAAQ,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC;AACxD,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;IACxB,CAAC;gFAAC;AAEF,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;AACvE,YAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;YAGhE,MAAM,CAAC,MAAK;gBACV,IAAI,IAAI,CAAC,IAAI,EAAE;oBAAE,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;AACpD,YAAA,CAAC,CAAC;QACJ;IACF;;IAGA,SAAS,GAAA;QACP,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACrB;;IAGA,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;IACtB;;IAGA,MAAM,GAAA;QACJ,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3B;uGArDW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,ihBCvCvB,84BAqCA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDEa,UAAU,EAAA,UAAA,EAAA,CAAA;kBANtB,SAAS;+BACE,aAAa,EAAA,aAAA,EAER,iBAAiB,CAAC,IAAI,QAC/B,EAAE,SAAS,EAAE,WAAW,EAAE,EAAA,QAAA,EAAA,84BAAA,EAAA;;;AErClC;;;;;AAKG;AAYH;;;;;AAKG;MAcU,eAAe,CAAA;;IAEjB,SAAS,GAAG,KAAK,CAAC,KAAK,iFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;AAEtD,IAAA,OAAO,GAAG,IAAI,GAAG,EAAkB;AAEpD,IAAA,QAAQ,CAAC,MAAc,EAAA;QACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC;IACrC;AAEA,IAAA,UAAU,CAAC,QAAgB,EAAA;AACzB,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC/B;AAEA,IAAA,YAAY,CAAC,MAAc,EAAA;AACzB,QAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YAAE;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE;YACvC,IAAI,EAAE,KAAK,MAAM;gBAAE,MAAM,CAAC,KAAK,EAAE;QACnC;IACF;uGAnBW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAf,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAe,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,EAAA,SAAA,EARf;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;;AAE1B,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,eAAe,CAAC;AAC/C,aAAA;AACF,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EATS,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAWf,eAAe,EAAA,UAAA,EAAA,CAAA;kBAb3B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,mBAAmB;AAC7B,oBAAA,QAAQ,EAAE,gBAAgB;oBAC1B,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE;AACpC,oBAAA,SAAS,EAAE;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;;AAE1B,4BAAA,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC;AAC/C,yBAAA;AACF,qBAAA;AACF,iBAAA;;;ACnCD;;;;;AAKG;AAWH;;;;;;;;;;;;;;;;;AAiBG;MAcU,WAAW,CAAA;;IAEb,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;AAE7B,IAAA,OAAO,GAAG,IAAI,GAAG,EAAkB;AAEpD,IAAA,QAAQ,CAAC,MAAc,EAAA;QACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC;IACrC;AAEA,IAAA,UAAU,CAAC,QAAgB,EAAA;AACzB,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC/B;AAEA,IAAA,YAAY,CAAC,MAAc,EAAA;QACzB,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE;YACvC,IAAI,EAAE,KAAK,MAAM;gBAAE,MAAM,CAAC,KAAK,EAAE;QACnC;IACF;uGAlBW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAX,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,WAAW,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,gDAAA,EAAA,EAAA,SAAA,EARX;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;;AAE1B,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,WAAW,CAAC;AAC3C,aAAA;AACF,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EATS,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAWf,WAAW,EAAA,UAAA,EAAA,CAAA;kBAbvB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,cAAc;AACxB,oBAAA,QAAQ,EAAE,gBAAgB;oBAC1B,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE,EAAE,KAAK,EAAE,gDAAgD,EAAE;AACjE,oBAAA,SAAS,EAAE;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;;AAE1B,4BAAA,WAAW,EAAE,UAAU,CAAC,iBAAiB,CAAC;AAC3C,yBAAA;AACF,qBAAA;AACF,iBAAA;;;AC9CD;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"ngwr-collapse.mjs","sources":["../../../projects/lib/collapse/tokens/collapse-group.token.ts","../../../projects/lib/collapse/collapse.ts","../../../projects/lib/collapse/collapse.html","../../../projects/lib/collapse/collapse-group.ts","../../../projects/lib/collapse/accordion.ts","../../../projects/lib/collapse/ngwr-collapse.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * What a `<wr-collapse>` hands its parent group when it registers.\n *\n * A named export rather than the structural type it used to be spelled as. Both\n * group components declared their OWN local `interface Member`, so d.ts\n * flattening had two of one name to resolve and published the second as\n * `Member$1` — a bundler-assigned identifier in the signature of a public method,\n * which no consumer could import and nobody had authored.\n */\nexport interface WrCollapseGroupMember {\n /** Close this collapse — the group calls it on siblings in accordion mode. */\n close(): void;\n /** Identity of the registering collapse, used as the map key and by `notifyOpened`. */\n readonly id: object;\n}\n\n/**\n * Contract a collapse uses to talk to its parent `<wr-collapse-group>`.\n *\n * @internal\n */\nexport interface WrCollapseGroupContext {\n /** When true, only one child collapse may be open at a time. */\n readonly accordion: Signal<boolean>;\n /** Called by a child when it opens — closes siblings in accordion mode. */\n notifyOpened(opener: object): void;\n /** Register a child so the group can call `closeAll()` etc. */\n register(member: WrCollapseGroupMember): void;\n /** Unregister on destroy. */\n unregister(memberId: object): void;\n}\n\n/**\n * Token a `<wr-collapse>` injects to register itself with — and notify of\n * open events — its parent `<wr-collapse-group>`. Drives the accordion\n * behaviour when the group has `accordion` enabled.\n *\n * @internal\n */\nexport const WR_COLLAPSE_GROUP = new InjectionToken<WrCollapseGroupContext>('WR_COLLAPSE_GROUP');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, DestroyRef, ViewEncapsulation, computed, effect, inject, input, model } from '@angular/core';\n\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_COLLAPSE_GROUP } from './tokens';\n\n/**\n * Expandable panel with a clickable header. Two-way binds the `open`\n * state. When wrapped in `<wr-collapse-group accordion>`, only one\n * sibling can be open at a time.\n *\n * @example\n * ```html\n * <wr-collapse title=\"Section title\">\n * Section body…\n * </wr-collapse>\n *\n * <wr-collapse-group accordion>\n * <wr-collapse title=\"A\">…</wr-collapse>\n * <wr-collapse title=\"B\">…</wr-collapse>\n * </wr-collapse-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-collapse',\n templateUrl: './collapse.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrCollapse {\n /** Header text. */\n readonly title = input.required<string>();\n\n /** Two-way bindable open/closed state. @default false */\n readonly open = model<boolean>(false);\n\n /** Disable interaction. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Identity used by the parent group when tracking children. @internal */\n readonly id = { name: randomId('wr-collapse') };\n\n /** DOM id for the body element, referenced by header's `aria-controls`. */\n protected readonly bodyId = `wr-collapse-body-${this.id.name}`;\n\n private readonly group = inject(WR_COLLAPSE_GROUP, { optional: true });\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-collapse'];\n if (this.open()) parts.push('wr-collapse--open');\n if (this.disabled()) parts.push('wr-collapse--disabled');\n return parts.join(' ');\n });\n\n constructor() {\n if (this.group) {\n this.group.register({ id: this.id, close: () => this.open.set(false) });\n this.destroyRef.onDestroy(() => this.group?.unregister(this.id));\n\n // Tell the group whenever we open — group decides whether to close siblings.\n effect(() => {\n if (this.open()) this.group?.notifyOpened(this.id);\n });\n }\n }\n\n /** Open the panel. */\n openPanel(): void {\n if (this.disabled()) return;\n this.open.set(true);\n }\n\n /** Close the panel. */\n close(): void {\n this.open.set(false);\n }\n\n /** Toggle the panel. */\n toggle(): void {\n if (this.disabled()) return;\n this.open.update(v => !v);\n }\n}\n","<button\n type=\"button\"\n class=\"wr-collapse__header\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n [disabled]=\"disabled()\"\n (click)=\"toggle()\"\n>\n <span class=\"wr-collapse__title\">{{ title() }}</span>\n <svg\n class=\"wr-icon__svg wr-collapse__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n</button>\n\n<div\n class=\"wr-collapse__body\"\n [attr.id]=\"bodyId\"\n [class.wr-collapse__body--open]=\"open()\"\n [attr.aria-hidden]=\"!open()\"\n [attr.inert]=\"!open() ? '' : null\"\n>\n <div class=\"wr-collapse__content\">\n <div class=\"wr-collapse__inner\">\n <ng-content />\n </div>\n </div>\n</div>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, forwardRef, input } from '@angular/core';\n\nimport { WR_COLLAPSE_GROUP, type WrCollapseGroupContext, type WrCollapseGroupMember } from './tokens';\n\n/**\n * Visual + behavioral grouping of `<wr-collapse>` children. When\n * `accordion` is true, opening one child closes the others.\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-collapse-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-collapse-group' },\n providers: [\n {\n provide: WR_COLLAPSE_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrCollapseGroup),\n },\n ],\n})\nexport class WrCollapseGroup implements WrCollapseGroupContext {\n /** When true, only one child may be open at a time. @default false */\n readonly accordion = input(false, { transform: coerceBooleanProperty });\n\n private readonly members = new Map<object, WrCollapseGroupMember>();\n\n register(member: WrCollapseGroupMember): void {\n this.members.set(member.id, member);\n }\n\n unregister(memberId: object): void {\n this.members.delete(memberId);\n }\n\n notifyOpened(opener: object): void {\n if (!this.accordion()) return;\n for (const [id, member] of this.members) {\n if (id !== opener) member.close();\n }\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, forwardRef, signal } from '@angular/core';\n\nimport { WR_COLLAPSE_GROUP, type WrCollapseGroupContext, type WrCollapseGroupMember } from './tokens';\n\n/**\n * Accordion — a `<wr-collapse>` container that enforces single-open\n * behavior: opening a child closes its siblings.\n *\n * Use `<wr-collapse-group>` when you only need visual grouping without\n * the mutually-exclusive open semantics.\n *\n * @example\n * ```html\n * <wr-accordion>\n * <wr-collapse title=\"Profile\">…</wr-collapse>\n * <wr-collapse title=\"Security\">…</wr-collapse>\n * <wr-collapse title=\"Notifications\">…</wr-collapse>\n * </wr-accordion>\n * ```\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-accordion',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-collapse-group wr-collapse-group--accordion' },\n providers: [\n {\n provide: WR_COLLAPSE_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrAccordion),\n },\n ],\n})\nexport class WrAccordion implements WrCollapseGroupContext {\n /** Always behaves as an accordion. Provided for context-interface symmetry. */\n readonly accordion = signal(true).asReadonly();\n\n private readonly members = new Map<object, WrCollapseGroupMember>();\n\n register(member: WrCollapseGroupMember): void {\n this.members.set(member.id, member);\n }\n\n unregister(memberId: object): void {\n this.members.delete(memberId);\n }\n\n notifyOpened(opener: object): void {\n for (const [id, member] of this.members) {\n if (id !== opener) member.close();\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -24,10 +24,20 @@ class FieldHarness extends ComponentHarness {
|
|
|
24
24
|
return (await this.getInput()).getProperty('value');
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* The percentage a thumb carries, out of its inline `style`.
|
|
29
|
+
*
|
|
30
|
+
* Three properties and not two, because the surfaces do not agree on the inline
|
|
31
|
+
* axis and that disagreement is the contract: the SV canvas is a picture and
|
|
32
|
+
* keeps a physical `left`, while the hue and alpha tracks are one-value sliders
|
|
33
|
+
* that mirror under `dir="rtl"` and so are placed with `inset-inline-start`.
|
|
34
|
+
* Reading `left` off a slider thumb therefore finds nothing, which is exactly
|
|
35
|
+
* what should happen if one of them ever regresses to the physical property.
|
|
36
|
+
*/
|
|
28
37
|
const THUMB_POS = {
|
|
29
38
|
left: /(?:^|;)\s*left\s*:\s*([\d.]+)%/,
|
|
30
39
|
top: /(?:^|;)\s*top\s*:\s*([\d.]+)%/,
|
|
40
|
+
'inset-inline-start': /(?:^|;)\s*inset-inline-start\s*:\s*([\d.]+)%/,
|
|
31
41
|
};
|
|
32
42
|
/** One thumb's declared offset. See {@link WrColorPickerHarness.getThumbs} for why this is not `getCssValue()`. */
|
|
33
43
|
async function percent(thumb, side, surface) {
|
|
@@ -248,10 +258,16 @@ class WrColorPickerHarness extends ComponentHarness {
|
|
|
248
258
|
/**
|
|
249
259
|
* Where the three thumbs sit, in percent along their surfaces.
|
|
250
260
|
*
|
|
251
|
-
* The component writes these as inline
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
261
|
+
* The component writes these as inline percentages, so they are readable with no
|
|
262
|
+
* layout at all — which makes them the only evidence a spec has that the surfaces
|
|
263
|
+
* followed a colour set through the fields. A measured position would be zero for
|
|
264
|
+
* all three.
|
|
265
|
+
*
|
|
266
|
+
* The number is always "along the surface from its own start", so it is direction
|
|
267
|
+
* free: the SV canvas reports a physical `left` because it does not mirror, and
|
|
268
|
+
* the two tracks report `inset-inline-start` because they do. An RTL spec reads
|
|
269
|
+
* the same value as an LTR one, which is the point — what mirrors is where that
|
|
270
|
+
* fraction lands on screen, not the fraction.
|
|
255
271
|
*
|
|
256
272
|
* Read off the `style` ATTRIBUTE rather than through `getCssValue()`, and the
|
|
257
273
|
* difference is not cosmetic: `getCssValue()` is `getComputedStyle()`, and `left` /
|
|
@@ -267,8 +283,8 @@ class WrColorPickerHarness extends ComponentHarness {
|
|
|
267
283
|
const alpha = await this.locatorForOptional('.wr-color-picker__slider--alpha .wr-color-picker__thumb')();
|
|
268
284
|
return {
|
|
269
285
|
sv: { x: await percent(sv, 'left', 'SV'), y: await percent(sv, 'top', 'SV') },
|
|
270
|
-
hue: await percent(hue, '
|
|
271
|
-
alpha: alpha ? await percent(alpha, '
|
|
286
|
+
hue: await percent(hue, 'inset-inline-start', 'hue'),
|
|
287
|
+
alpha: alpha ? await percent(alpha, 'inset-inline-start', 'alpha') : null,
|
|
272
288
|
};
|
|
273
289
|
}
|
|
274
290
|
/** The HEX field's value without the tab check — for filters, which must not throw. */
|