@hyalo/angular 0.1.0 → 0.3.1
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/CHANGELOG.md +95 -41
- package/README.md +46 -32
- package/fesm2022/hyalo-angular-accordion.mjs +6 -6
- package/fesm2022/hyalo-angular-accordion.mjs.map +1 -1
- package/fesm2022/hyalo-angular-alert.mjs +171 -0
- package/fesm2022/hyalo-angular-alert.mjs.map +1 -0
- package/fesm2022/hyalo-angular-aspect-ratio.mjs +64 -0
- package/fesm2022/hyalo-angular-aspect-ratio.mjs.map +1 -0
- package/fesm2022/hyalo-angular-avatar.mjs +169 -0
- package/fesm2022/hyalo-angular-avatar.mjs.map +1 -0
- package/fesm2022/hyalo-angular-badge.mjs +268 -0
- package/fesm2022/hyalo-angular-badge.mjs.map +1 -0
- package/fesm2022/hyalo-angular-bento.mjs +132 -0
- package/fesm2022/hyalo-angular-bento.mjs.map +1 -0
- package/fesm2022/hyalo-angular-blocks.mjs +985 -0
- package/fesm2022/hyalo-angular-blocks.mjs.map +1 -0
- package/fesm2022/hyalo-angular-border-beam.mjs +73 -0
- package/fesm2022/hyalo-angular-border-beam.mjs.map +1 -0
- package/fesm2022/hyalo-angular-breadcrumb.mjs +77 -0
- package/fesm2022/hyalo-angular-breadcrumb.mjs.map +1 -0
- package/fesm2022/hyalo-angular-button-group.mjs +90 -0
- package/fesm2022/hyalo-angular-button-group.mjs.map +1 -0
- package/fesm2022/hyalo-angular-button.mjs +4 -3
- package/fesm2022/hyalo-angular-button.mjs.map +1 -1
- package/fesm2022/hyalo-angular-card.mjs +2 -2
- package/fesm2022/hyalo-angular-card.mjs.map +1 -1
- package/fesm2022/hyalo-angular-carousel.mjs +709 -0
- package/fesm2022/hyalo-angular-carousel.mjs.map +1 -0
- package/fesm2022/hyalo-angular-chapter-nav.mjs +336 -0
- package/fesm2022/hyalo-angular-chapter-nav.mjs.map +1 -0
- package/fesm2022/hyalo-angular-chart-engine-DSJop6He.mjs +5 -0
- package/fesm2022/hyalo-angular-chart-engine-DSJop6He.mjs.map +1 -0
- package/fesm2022/hyalo-angular-chart.mjs +391 -0
- package/fesm2022/hyalo-angular-chart.mjs.map +1 -0
- package/fesm2022/hyalo-angular-choice.mjs +2 -1
- package/fesm2022/hyalo-angular-choice.mjs.map +1 -1
- package/fesm2022/hyalo-angular-code-block-highlight-B20d5C76.mjs +40 -0
- package/fesm2022/hyalo-angular-code-block-highlight-B20d5C76.mjs.map +1 -0
- package/fesm2022/hyalo-angular-code-block.mjs +161 -0
- package/fesm2022/hyalo-angular-code-block.mjs.map +1 -0
- package/fesm2022/hyalo-angular-command.mjs +193 -0
- package/fesm2022/hyalo-angular-command.mjs.map +1 -0
- package/fesm2022/hyalo-angular-copy.mjs +138 -0
- package/fesm2022/hyalo-angular-copy.mjs.map +1 -0
- package/fesm2022/hyalo-angular-core.mjs +424 -0
- package/fesm2022/hyalo-angular-core.mjs.map +1 -0
- package/fesm2022/hyalo-angular-description-list.mjs +57 -0
- package/fesm2022/hyalo-angular-description-list.mjs.map +1 -0
- package/fesm2022/hyalo-angular-dialog.mjs +51 -22
- package/fesm2022/hyalo-angular-dialog.mjs.map +1 -1
- package/fesm2022/hyalo-angular-divider.mjs +66 -0
- package/fesm2022/hyalo-angular-divider.mjs.map +1 -0
- package/fesm2022/hyalo-angular-empty-state.mjs +123 -0
- package/fesm2022/hyalo-angular-empty-state.mjs.map +1 -0
- package/fesm2022/hyalo-angular-field.mjs +41 -9
- package/fesm2022/hyalo-angular-field.mjs.map +1 -1
- package/fesm2022/hyalo-angular-filter.mjs +309 -0
- package/fesm2022/hyalo-angular-filter.mjs.map +1 -0
- package/fesm2022/hyalo-angular-hotspot.mjs +225 -0
- package/fesm2022/hyalo-angular-hotspot.mjs.map +1 -0
- package/fesm2022/hyalo-angular-hover-card.mjs +233 -0
- package/fesm2022/hyalo-angular-hover-card.mjs.map +1 -0
- package/fesm2022/hyalo-angular-icon.mjs +42 -0
- package/fesm2022/hyalo-angular-icon.mjs.map +1 -1
- package/fesm2022/hyalo-angular-image-compare.mjs +168 -0
- package/fesm2022/hyalo-angular-image-compare.mjs.map +1 -0
- package/fesm2022/hyalo-angular-interaction.mjs +32 -41
- package/fesm2022/hyalo-angular-interaction.mjs.map +1 -1
- package/fesm2022/hyalo-angular-kbd.mjs +41 -0
- package/fesm2022/hyalo-angular-kbd.mjs.map +1 -0
- package/fesm2022/hyalo-angular-lightbox.mjs +228 -0
- package/fesm2022/hyalo-angular-lightbox.mjs.map +1 -0
- package/fesm2022/hyalo-angular-link.mjs +42 -0
- package/fesm2022/hyalo-angular-link.mjs.map +1 -0
- package/fesm2022/hyalo-angular-list.mjs +131 -0
- package/fesm2022/hyalo-angular-list.mjs.map +1 -0
- package/fesm2022/hyalo-angular-marquee.mjs +197 -0
- package/fesm2022/hyalo-angular-marquee.mjs.map +1 -0
- package/fesm2022/hyalo-angular-menu.mjs +423 -0
- package/fesm2022/hyalo-angular-menu.mjs.map +1 -0
- package/fesm2022/hyalo-angular-mesh.mjs +126 -0
- package/fesm2022/hyalo-angular-mesh.mjs.map +1 -0
- package/fesm2022/hyalo-angular-motion.mjs +620 -0
- package/fesm2022/hyalo-angular-motion.mjs.map +1 -0
- package/fesm2022/hyalo-angular-navbar.mjs +1 -1
- package/fesm2022/hyalo-angular-navbar.mjs.map +1 -1
- package/fesm2022/hyalo-angular-navigation-menu.mjs +222 -0
- package/fesm2022/hyalo-angular-navigation-menu.mjs.map +1 -0
- package/fesm2022/hyalo-angular-number-ticker.mjs +174 -0
- package/fesm2022/hyalo-angular-number-ticker.mjs.map +1 -0
- package/fesm2022/hyalo-angular-overlay.mjs +71 -2
- package/fesm2022/hyalo-angular-overlay.mjs.map +1 -1
- package/fesm2022/hyalo-angular-pagination.mjs +187 -0
- package/fesm2022/hyalo-angular-pagination.mjs.map +1 -0
- package/fesm2022/hyalo-angular-popover.mjs +34 -5
- package/fesm2022/hyalo-angular-popover.mjs.map +1 -1
- package/fesm2022/hyalo-angular-progress.mjs +209 -0
- package/fesm2022/hyalo-angular-progress.mjs.map +1 -0
- package/fesm2022/hyalo-angular-progressive-blur.mjs +73 -0
- package/fesm2022/hyalo-angular-progressive-blur.mjs.map +1 -0
- package/fesm2022/hyalo-angular-refraction-renderer-5ZA-kfsA.mjs +186 -0
- package/fesm2022/hyalo-angular-refraction-renderer-5ZA-kfsA.mjs.map +1 -0
- package/fesm2022/hyalo-angular-refraction.mjs +178 -0
- package/fesm2022/hyalo-angular-refraction.mjs.map +1 -0
- package/fesm2022/hyalo-angular-scroll-area.mjs +93 -0
- package/fesm2022/hyalo-angular-scroll-area.mjs.map +1 -0
- package/fesm2022/hyalo-angular-scroll-to-top.mjs +127 -0
- package/fesm2022/hyalo-angular-scroll-to-top.mjs.map +1 -0
- package/fesm2022/hyalo-angular-segmented.mjs +1 -1
- package/fesm2022/hyalo-angular-segmented.mjs.map +1 -1
- package/fesm2022/hyalo-angular-select.mjs +112 -15
- package/fesm2022/hyalo-angular-select.mjs.map +1 -1
- package/fesm2022/hyalo-angular-sidebar.mjs +241 -0
- package/fesm2022/hyalo-angular-sidebar.mjs.map +1 -0
- package/fesm2022/hyalo-angular-skeleton.mjs +131 -0
- package/fesm2022/hyalo-angular-skeleton.mjs.map +1 -0
- package/fesm2022/hyalo-angular-sparkline.mjs +110 -0
- package/fesm2022/hyalo-angular-sparkline.mjs.map +1 -0
- package/fesm2022/hyalo-angular-split-text.mjs +126 -0
- package/fesm2022/hyalo-angular-split-text.mjs.map +1 -0
- package/fesm2022/hyalo-angular-stat.mjs +193 -0
- package/fesm2022/hyalo-angular-stat.mjs.map +1 -0
- package/fesm2022/hyalo-angular-stepper.mjs +254 -0
- package/fesm2022/hyalo-angular-stepper.mjs.map +1 -0
- package/fesm2022/hyalo-angular-table.mjs +335 -0
- package/fesm2022/hyalo-angular-table.mjs.map +1 -0
- package/fesm2022/hyalo-angular-tabs.mjs +1 -1
- package/fesm2022/hyalo-angular-tabs.mjs.map +1 -1
- package/fesm2022/hyalo-angular-theme.mjs +1 -1
- package/fesm2022/hyalo-angular-theme.mjs.map +1 -1
- package/fesm2022/hyalo-angular-timeline.mjs +157 -0
- package/fesm2022/hyalo-angular-timeline.mjs.map +1 -0
- package/fesm2022/hyalo-angular-toast.mjs +2 -1
- package/fesm2022/hyalo-angular-toast.mjs.map +1 -1
- package/fesm2022/hyalo-angular.mjs +2 -473
- package/package.json +198 -2
- package/styles/parts/field.css +44 -36
- package/styles/parts/glass.css +2 -0
- package/styles/parts/motion.css +19 -0
- package/styles/parts/typography.css +17 -0
- package/types/hyalo-angular-accordion.d.ts +1 -1
- package/types/hyalo-angular-alert.d.ts +47 -0
- package/types/hyalo-angular-aspect-ratio.d.ts +13 -0
- package/types/hyalo-angular-avatar.d.ts +39 -0
- package/types/hyalo-angular-badge.d.ts +82 -0
- package/types/hyalo-angular-bento.d.ts +25 -0
- package/types/hyalo-angular-blocks.d.ts +272 -0
- package/types/hyalo-angular-border-beam.d.ts +15 -0
- package/types/hyalo-angular-breadcrumb.d.ts +22 -0
- package/types/hyalo-angular-button-group.d.ts +19 -0
- package/types/hyalo-angular-button.d.ts +4 -3
- package/types/hyalo-angular-card.d.ts +1 -1
- package/types/hyalo-angular-carousel.d.ts +147 -0
- package/types/hyalo-angular-chapter-nav.d.ts +79 -0
- package/types/hyalo-angular-chart.d.ts +90 -0
- package/types/hyalo-angular-code-block.d.ts +46 -0
- package/types/hyalo-angular-command.d.ts +41 -0
- package/types/hyalo-angular-copy.d.ts +39 -0
- package/types/hyalo-angular-core.d.ts +210 -0
- package/types/hyalo-angular-description-list.d.ts +16 -0
- package/types/hyalo-angular-dialog.d.ts +2 -1
- package/types/hyalo-angular-divider.d.ts +12 -0
- package/types/hyalo-angular-empty-state.d.ts +30 -0
- package/types/hyalo-angular-field.d.ts +10 -4
- package/types/hyalo-angular-filter.d.ts +122 -0
- package/types/hyalo-angular-hotspot.d.ts +70 -0
- package/types/hyalo-angular-hover-card.d.ts +47 -0
- package/types/hyalo-angular-image-compare.d.ts +55 -0
- package/types/hyalo-angular-kbd.d.ts +5 -0
- package/types/hyalo-angular-lightbox.d.ts +67 -0
- package/types/hyalo-angular-link.d.ts +5 -0
- package/types/hyalo-angular-list.d.ts +30 -0
- package/types/hyalo-angular-marquee.d.ts +48 -0
- package/types/hyalo-angular-menu.d.ts +105 -0
- package/types/hyalo-angular-mesh.d.ts +36 -0
- package/types/hyalo-angular-motion.d.ts +218 -0
- package/types/hyalo-angular-navigation-menu.d.ts +47 -0
- package/types/hyalo-angular-number-ticker.d.ts +52 -0
- package/types/hyalo-angular-overlay.d.ts +9 -0
- package/types/hyalo-angular-pagination.d.ts +59 -0
- package/types/hyalo-angular-popover.d.ts +10 -0
- package/types/hyalo-angular-progress.d.ts +46 -0
- package/types/hyalo-angular-progressive-blur.d.ts +14 -0
- package/types/hyalo-angular-refraction.d.ts +46 -0
- package/types/hyalo-angular-scroll-area.d.ts +18 -0
- package/types/hyalo-angular-scroll-to-top.d.ts +31 -0
- package/types/hyalo-angular-segmented.d.ts +1 -1
- package/types/hyalo-angular-select.d.ts +49 -3
- package/types/hyalo-angular-sidebar.d.ts +57 -0
- package/types/hyalo-angular-skeleton.d.ts +34 -0
- package/types/hyalo-angular-sparkline.d.ts +19 -0
- package/types/hyalo-angular-split-text.d.ts +24 -0
- package/types/hyalo-angular-stat.d.ts +56 -0
- package/types/hyalo-angular-stepper.d.ts +63 -0
- package/types/hyalo-angular-table.d.ts +125 -0
- package/types/hyalo-angular-timeline.d.ts +36 -0
- package/types/hyalo-angular.d.ts +2 -345
- package/fesm2022/hyalo-angular.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hyalo-angular-motion.mjs","names":["injectIsBrowser","matchesMedia"],"sources":["../../../projects/hyalo/motion/runtime/motion.ts","../../../projects/hyalo/motion/runtime/spring.ts","../../../projects/hyalo/motion/visibility.ts","../../../projects/hyalo/motion/scene.ts","../../../projects/hyalo/motion/layout.ts"],"sourcesContent":["import { DOCUMENT, DestroyRef, Injectable, computed, inject, signal } from '@angular/core';\r\nimport { HY_CONFIG } from '@hyalo/angular/core';\r\nimport {\r\n ɵinjectIsBrowser as injectIsBrowser,\r\n ɵmatchesMedia as matchesMedia,\r\n} from '@hyalo/angular/core';\r\nimport { HyFidelity } from '@hyalo/angular/core';\r\nimport type { HyGsap } from '@hyalo/angular/core';\r\n\r\n/** One named motion: duration in seconds plus matching GSAP and CSS easings. */\r\nexport interface HyMotionPreset {\r\n readonly duration: number;\r\n readonly ease: string;\r\n readonly css: string;\r\n}\r\n\r\n/**\r\n * The shared motion vocabulary. CSS has the same values as `--hy-dur-*` and\r\n * `--hy-ease-*` tokens.\r\n *\r\n * - `settle`: the default for anything that moves into place.\r\n * - `pop`: a small overshoot. Only for motion the user caused, such as a\r\n * toggle they just pressed. Never for things that appear on their own.\r\n * - `quick`: acknowledgements, like a press or a hover.\r\n * - `scene`: large, slow movements such as section reveals.\r\n */\r\nexport const MOTION = {\r\n settle: { duration: 0.44, ease: 'power3.out', css: 'cubic-bezier(0.215, 0.61, 0.355, 1)' },\r\n pop: { duration: 0.5, ease: 'back.out(1.5)', css: 'cubic-bezier(0.34, 1.56, 0.64, 1)' },\r\n quick: { duration: 0.22, ease: 'power2.out', css: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)' },\r\n scene: { duration: 0.9, ease: 'expo.out', css: 'cubic-bezier(0.16, 1, 0.3, 1)' },\r\n} as const satisfies Record<string, HyMotionPreset>;\r\n\r\n/**\r\n * Motion state for the whole app: whether the user prefers reduced motion,\r\n * whether effects may run at all, and lazy access to GSAP.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class HyMotion {\r\n private readonly config = inject(HY_CONFIG);\r\n private readonly fidelity = inject(HyFidelity);\r\n private readonly document = inject(DOCUMENT);\r\n private readonly isBrowser = injectIsBrowser();\r\n private readonly _reduced = signal(false);\r\n private gsapPromise: Promise<HyGsap | null> | undefined;\r\n\r\n /** True when the OS asks for reduced motion, or the app forced it. */\r\n readonly reduced = this._reduced.asReadonly();\r\n\r\n /** True when decorative motion (tilt, magnetic, reveal) may run. */\r\n readonly enabled = computed(() => !this._reduced() && this.fidelity.tier() !== 'low');\r\n\r\n constructor() {\r\n if (!this.isBrowser || typeof matchMedia !== 'function') return;\r\n const query = matchMedia('(prefers-reduced-motion: reduce)');\r\n const update = (): void =>\r\n this._reduced.set(\r\n query.matches || this.document.documentElement.getAttribute('data-hy-motion') === 'reduced',\r\n );\r\n update();\r\n query.addEventListener('change', update);\r\n inject(DestroyRef).onDestroy(() => query.removeEventListener('change', update));\r\n }\r\n\r\n /**\r\n * Requests reduced or normal motion without overriding the OS preference, and mirrors\r\n * the choice to `data-hy-motion` so CSS tokens follow. Pass `null` to go\r\n * back to the OS setting.\r\n */\r\n setReduced(reduced: boolean | null): void {\r\n const root = this.document.documentElement;\r\n if (reduced === null) {\r\n root.removeAttribute('data-hy-motion');\r\n this._reduced.set(matchesMedia('(prefers-reduced-motion: reduce)'));\r\n return;\r\n }\r\n root.setAttribute('data-hy-motion', reduced ? 'reduced' : 'full');\r\n this._reduced.set(reduced || matchesMedia('(prefers-reduced-motion: reduce)'));\r\n }\r\n\r\n /**\r\n * Loads GSAP once, if the app provided a loader. Resolves to `null` on the\r\n * server, without a loader, or if loading fails, so callers can fall back\r\n * to CSS.\r\n */\r\n gsap(): Promise<HyGsap | null> {\r\n const loader = this.config.gsap;\r\n if (!this.isBrowser || !loader) return Promise.resolve(null);\r\n this.gsapPromise ??= loader().catch(() => null);\r\n return this.gsapPromise;\r\n }\r\n}\r\n","/**\r\n * A spring in the two numbers Apple designs with.\r\n *\r\n * - `damping`: 1 settles without overshoot, lower values bounce.\r\n * - `response`: roughly how many seconds it takes to get there. Not a\r\n * duration; the settle time falls out of the physics.\r\n */\r\nexport interface HySpringConfig {\r\n /** Finite and greater than zero, so the spring can settle. */\r\n readonly damping: number;\r\n /** Finite and at least 1/60 second. Use set() for an immediate change. */\r\n readonly response: number;\r\n}\r\n\r\n/**\r\n * The shared springs.\r\n *\r\n * - `settle`: the default. No bounce.\r\n * - `momentum`: after a flick or a drag, when the gesture carried speed.\r\n */\r\nexport const SPRINGS = {\r\n settle: { damping: 1, response: 0.4 },\r\n momentum: { damping: 0.8, response: 0.3 },\r\n} as const satisfies Record<string, HySpringConfig>;\r\n\r\n/** Options for {@link HySpring.to}. */\r\nexport interface HySpringTarget extends Partial<HySpringConfig> {\r\n /** Starting velocity in units per second. Defaults to the current one. */\r\n readonly velocity?: number;\r\n /** Runs once the value comes to rest on the target. */\r\n readonly onRest?: () => void;\r\n}\r\n\r\nconst STEP = 1 / 240;\r\nconst MIN_RESPONSE = 1 / 60;\r\nconst MAX_STEPS = 240;\r\n\r\nfunction assertFinite(value: number, name: string): void {\r\n if (!Number.isFinite(value)) throw new RangeError(`HySpring: ${name} must be finite.`);\r\n}\r\nconst REST_DELTA = 0.1;\r\nconst REST_VELOCITY = 2;\r\n\r\n/**\r\n * Animates one number on `requestAnimationFrame`. Every `to()` starts from\r\n * the live value and keeps its velocity, so the motion can be grabbed and\r\n * redirected at any moment without a jump or a sudden stop.\r\n */\r\nexport class HySpring {\r\n /** The value on screen right now. */\r\n value: number;\r\n /** Units per second. */\r\n velocity = 0;\r\n private target = 0;\r\n private config: HySpringConfig = SPRINGS.settle;\r\n private onRest: (() => void) | null = null;\r\n private frame = 0;\r\n private last = 0;\r\n\r\n constructor(\r\n initial: number,\r\n private readonly onUpdate: (value: number) => void,\r\n ) {\r\n assertFinite(initial, 'initial value');\r\n this.value = initial;\r\n }\r\n\r\n /** True while the spring is moving. */\r\n get running(): boolean {\r\n return this.frame !== 0;\r\n }\r\n\r\n /** Springs toward `target`, from wherever it is now. */\r\n to(target: number, options: HySpringTarget = {}): void {\r\n const damping = options.damping ?? SPRINGS.settle.damping;\r\n const response = options.response ?? SPRINGS.settle.response;\r\n const velocity = options.velocity ?? this.velocity;\r\n assertFinite(target, 'target');\r\n assertFinite(this.value, 'current value');\r\n assertFinite(velocity, 'velocity');\r\n if (!Number.isFinite(damping) || damping <= 0)\r\n throw new RangeError('HySpring: damping must be finite and greater than zero.');\r\n if (!Number.isFinite(response) || response < MIN_RESPONSE)\r\n throw new RangeError('HySpring: response must be finite and at least 1/60 second.');\r\n this.target = target;\r\n this.config = { damping, response };\r\n this.velocity = velocity;\r\n this.onRest = options.onRest ?? null;\r\n if (this.frame) return;\r\n this.last = -1;\r\n this.frame = requestAnimationFrame(this.tick);\r\n }\r\n\r\n /** Jumps to a value and stops, as when a finger holds it. */\r\n set(value: number): void {\r\n assertFinite(value, 'value');\r\n this.stop();\r\n this.value = value;\r\n this.velocity = 0;\r\n this.onUpdate(value);\r\n }\r\n\r\n /** Stops where it is. A pending `onRest` is dropped. */\r\n stop(): void {\r\n cancelAnimationFrame(this.frame);\r\n this.frame = 0;\r\n this.onRest = null;\r\n }\r\n\r\n private readonly tick = (now: number): void => {\r\n // Time comes only from frame timestamps. Their clock can differ from\r\n // performance.now() (jsdom, some browsers), so mixing the two can stall\r\n // the spring. The first frame counts as one 60 Hz frame. A long frame\r\n // (a background tab, a busy main thread) is capped, so the spring slows\r\n // down instead of jumping.\r\n const dt = this.last < 0 ? 1 / 60 : Math.max(0, Math.min((now - this.last) / 1000, 1 / 15));\r\n this.last = Math.max(now, this.last);\r\n const stiffness = ((2 * Math.PI) / this.config.response) ** 2;\r\n const friction = (4 * Math.PI * this.config.damping) / this.config.response;\r\n // Stiffer springs need finer steps to stay stable.\r\n const steps = Math.max(\r\n 1,\r\n Math.min(MAX_STEPS, Math.ceil(dt / Math.min(STEP, this.config.response / 60))),\r\n );\r\n const h = dt / steps;\r\n for (let i = 0; i < steps; i++) {\r\n this.velocity += (-stiffness * (this.value - this.target) - friction * this.velocity) * h;\r\n this.value += this.velocity * h;\r\n }\r\n if (\r\n !Number.isFinite(this.value) ||\r\n !Number.isFinite(this.velocity) ||\r\n (Math.abs(this.velocity) < REST_VELOCITY && Math.abs(this.value - this.target) < REST_DELTA)\r\n ) {\r\n this.value = this.target;\r\n this.velocity = 0;\r\n this.frame = 0;\r\n const done = this.onRest;\r\n this.onRest = null;\r\n this.onUpdate(this.value);\r\n done?.();\r\n return;\r\n }\r\n this.onUpdate(this.value);\r\n this.frame = requestAnimationFrame(this.tick);\r\n };\r\n}\r\n\r\n/**\r\n * How far a flick travels before it stops, from the velocity in px per\r\n * second. This is the deceleration curve of scrolling, so a target picked\r\n * from `position + project(velocity)` lands where the gesture was going.\r\n */\r\nexport function project(velocity: number, decelerationRate = 0.998): number {\r\n return ((velocity / 1000) * decelerationRate) / (1 - decelerationRate);\r\n}\r\n\r\n/**\r\n * Resistance past a boundary. The further the overshoot, the less the\r\n * element follows, so an edge feels soft instead of frozen.\r\n */\r\nexport function rubberband(overshoot: number, dimension: number, constant = 0.55): number {\r\n if (dimension <= 0) return 0;\r\n const x = Math.abs(overshoot);\r\n return (Math.sign(overshoot) * (x * dimension * constant)) / (dimension + constant * x);\r\n}\r\n\r\n/** Velocity of a pointer from its last 100ms of movement. */\r\nexport class HyVelocityTracker {\r\n private samples: { t: number; v: number }[] = [];\r\n\r\n add(value: number, time = performance.now()): void {\r\n this.samples.push({ t: time, v: value });\r\n while (this.samples.length > 2 && time - (this.samples[0]?.t ?? time) > 100) {\r\n this.samples.shift();\r\n }\r\n }\r\n\r\n reset(): void {\r\n this.samples = [];\r\n }\r\n\r\n /** Units per second. Zero if the pointer has been still for 100ms. */\r\n velocity(now = performance.now()): number {\r\n const recent = this.samples.filter((s) => now - s.t <= 100);\r\n const first = recent[0];\r\n const last = recent[recent.length - 1];\r\n if (!first || !last || last.t === first.t) return 0;\r\n return ((last.v - first.v) / (last.t - first.t)) * 1000;\r\n }\r\n}\r\n","import {\n DestroyRef,\n ElementRef,\n afterNextRender,\n inject,\n signal,\n type Signal,\n} from '@angular/core';\n\n/** A static SSR state keeps browser measurements out of the hydration structure. */\nexport function injectHyVisibility(): Signal<boolean> {\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n const destroy = inject(DestroyRef);\n const visible = signal(false);\n afterNextRender(() => {\n const doc = host.ownerDocument;\n let intersects = typeof IntersectionObserver !== 'function';\n const update = (): void => visible.set(intersects && doc.visibilityState !== 'hidden');\n const observer =\n typeof IntersectionObserver === 'function'\n ? new IntersectionObserver((entries) => {\n intersects = entries.some((entry) => entry.isIntersecting);\n update();\n })\n : null;\n observer?.observe(host);\n update();\n doc.addEventListener('visibilitychange', update);\n destroy.onDestroy(() => {\n observer?.disconnect();\n doc.removeEventListener('visibilitychange', update);\n });\n });\n return visible.asReadonly();\n}\n","import {\n DOCUMENT,\n DestroyRef,\n Directive,\n ElementRef,\n Injectable,\n afterNextRender,\n effect,\n inject,\n} from '@angular/core';\nimport { HyMotion } from './runtime/motion';\n\nexport interface HyPointerHandlers {\n enter?(event: PointerEvent, rect: DOMRect): void;\n move(event: PointerEvent, rect: DOMRect): void;\n leave?(): void;\n destroy?(): void;\n}\ninterface Participant {\n host: HTMLElement;\n handlers: HyPointerHandlers;\n scene: boolean;\n intersecting: boolean;\n active: boolean;\n rect?: DOMRect;\n}\n\n/** One sampler per document; style writes stay on opted-in surfaces. */\n@Injectable({ providedIn: 'root' })\nexport class HySceneLight {\n private readonly document = inject(DOCUMENT);\n private readonly motion = inject(HyMotion);\n private readonly entries = new Map<HTMLElement, Participant[]>();\n private readonly observers = new Map<Element | null, IntersectionObserver>();\n private resize?: ResizeObserver;\n private abort?: AbortController;\n private event?: PointerEvent;\n private frame = 0;\n private dirty = true;\n constructor() {\n effect(() => {\n if (!this.motion.enabled()) this.reset();\n });\n inject(DestroyRef).onDestroy(() => {\n this.reset();\n this.abort?.abort();\n this.resize?.disconnect();\n this.observers.forEach((o) => o.disconnect());\n });\n }\n register(\n host: HTMLElement,\n handlers: HyPointerHandlers,\n scene = false,\n root: Element | null = null,\n ): () => void {\n if (\n typeof IntersectionObserver !== 'function' ||\n !this.document.defaultView?.matchMedia('(hover: hover) and (pointer: fine)').matches\n )\n return () => handlers.destroy?.();\n this.start();\n const entry: Participant = { host, handlers, scene, active: false, intersecting: false };\n const group = this.entries.get(host) ?? [];\n group.push(entry);\n this.entries.set(host, group);\n let observer = this.observers.get(root);\n if (!observer) {\n observer = new IntersectionObserver(\n (changes) => {\n for (const change of changes)\n for (const item of this.entries.get(change.target as HTMLElement) ?? []) {\n item.intersecting = change.isIntersecting;\n item.rect = undefined;\n if (!item.intersecting) this.leave(item);\n }\n this.schedule();\n },\n { root },\n );\n this.observers.set(root, observer);\n }\n observer.observe(host);\n this.resize?.observe(host);\n return () => {\n this.leave(entry);\n handlers.destroy?.();\n const remaining = (this.entries.get(host) ?? []).filter((item) => item !== entry);\n if (remaining.length) this.entries.set(host, remaining);\n else {\n this.entries.delete(host);\n this.observers.forEach((o) => o.unobserve(host));\n this.resize?.unobserve(host);\n }\n if (!this.entries.size) {\n this.reset();\n this.abort?.abort();\n this.abort = undefined;\n this.resize?.disconnect();\n this.resize = undefined;\n this.observers.forEach((o) => o.disconnect());\n this.observers.clear();\n }\n };\n }\n private start(): void {\n if (this.abort) return;\n const abort = (this.abort = new AbortController());\n const options = { passive: true, capture: true, signal: abort.signal };\n this.document.addEventListener(\n 'pointermove',\n (event) => {\n if (event.pointerType === 'touch') return;\n this.event = event;\n this.schedule();\n },\n options,\n );\n this.document.addEventListener(\n 'pointerout',\n (event) => {\n if (!event.relatedTarget) this.reset();\n },\n options,\n );\n this.document.addEventListener('pointercancel', () => this.reset(), options);\n this.document.addEventListener(\n 'scroll',\n () => {\n this.dirty = true;\n this.schedule();\n },\n options,\n );\n this.document.defaultView?.addEventListener(\n 'resize',\n () => {\n this.dirty = true;\n this.schedule();\n },\n options,\n );\n this.document.addEventListener(\n 'visibilitychange',\n () => {\n if (this.document.hidden) this.reset();\n },\n options,\n );\n this.resize =\n typeof ResizeObserver === 'function'\n ? new ResizeObserver(() => {\n this.dirty = true;\n this.schedule();\n })\n : undefined;\n }\n private schedule(): void {\n if (!this.frame && this.event && this.motion.enabled() && !this.document.hidden)\n this.frame = requestAnimationFrame(() => this.draw());\n }\n private draw(): void {\n this.frame = 0;\n const event = this.event;\n if (!event || !this.motion.enabled() || this.document.hidden) return;\n const work: { entry: Participant; rect: DOMRect; inside: boolean }[] = [];\n const inactive: Participant[] = [];\n for (const group of this.entries.values())\n for (const entry of group) {\n if (!entry.intersecting || !entry.host.isConnected || work.length >= 64) {\n inactive.push(entry);\n continue;\n }\n if (this.dirty || !entry.rect) entry.rect = entry.host.getBoundingClientRect();\n const rect = entry.rect;\n const inside =\n event.clientX >= rect.left &&\n event.clientX <= rect.right &&\n event.clientY >= rect.top &&\n event.clientY <= rect.bottom;\n work.push({ entry, rect, inside });\n }\n this.dirty = false;\n // Finish geometry reads before invoking handlers that write styles.\n for (const entry of inactive) this.leave(entry);\n for (const { entry, rect, inside } of work) {\n if (!inside && !entry.scene) {\n this.leave(entry);\n continue;\n }\n if (!rect.width || !rect.height) continue;\n if (!entry.active) {\n entry.active = true;\n entry.handlers.enter?.(event, rect);\n }\n entry.handlers.move(event, rect);\n }\n }\n private leave(entry: Participant): void {\n if (entry.active) {\n entry.active = false;\n entry.handlers.leave?.();\n }\n }\n private reset(): void {\n if (this.frame) cancelAnimationFrame(this.frame);\n this.frame = 0;\n this.event = undefined;\n for (const group of this.entries.values()) for (const entry of group) this.leave(entry);\n }\n}\n\n@Directive({ selector: '[hySceneLight]' })\nexport class HySceneLightDirective {\n constructor() {\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n const scene = inject(HySceneLight),\n destroy = inject(DestroyRef);\n afterNextRender(() => {\n let lastX = '',\n lastY = '';\n const unregister = scene.register(\n host,\n {\n move: (event, rect) => {\n const x = `${(((event.clientX - rect.left) / rect.width) * 100).toFixed(1)}%`;\n const y = `${(((event.clientY - rect.top) / rect.height) * 100).toFixed(1)}%`;\n if (x !== lastX) host.style.setProperty('--hy-px', (lastX = x));\n if (y !== lastY) host.style.setProperty('--hy-py', (lastY = y));\n host.style.setProperty('--hy-glow', '0.18');\n },\n leave: () => host.style.setProperty('--hy-glow', '0'),\n },\n true,\n );\n destroy.onDestroy(unregister);\n });\n }\n}\n","import {\r\n numberAttribute,\r\n DestroyRef,\r\n Directive,\r\n ElementRef,\r\n Injector,\r\n afterNextRender,\r\n effect,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\nimport { HyMotion, MOTION } from './runtime/motion';\r\nimport { injectHyVisibility } from './visibility';\r\n\r\n/** The caller owns the state change and focus; this directive only animates its own host bounds. */\r\n@Directive({ selector: '[hyFlip]', exportAs: 'hyFlip' })\r\nexport class HyFlip {\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\r\n private readonly motion = inject(HyMotion);\r\n private readonly injector = inject(Injector);\r\n private readonly destroy = inject(DestroyRef);\r\n private animation?: Animation;\r\n private generation = 0;\r\n constructor() {\r\n effect(() => {\r\n if (!this.motion.enabled()) this.animation?.cancel();\r\n });\r\n this.destroy.onDestroy(() => {\r\n this.generation++;\r\n this.animation?.cancel();\r\n });\r\n }\r\n run(change: () => void): void {\r\n const generation = ++this.generation;\r\n this.animation?.cancel();\r\n const before = this.host.getBoundingClientRect();\r\n change();\r\n if (!this.motion.enabled() || typeof this.host.animate !== 'function') return;\r\n afterNextRender(\r\n () => {\r\n if (this.destroy.destroyed || generation !== this.generation || !this.motion.enabled())\r\n return;\r\n const after = this.host.getBoundingClientRect();\r\n if (!after.width || !after.height) return;\r\n this.animation = this.host.animate(\r\n [\r\n {\r\n transform: `translate(${before.left - after.left}px, ${before.top - after.top}px) scale(${before.width / after.width}, ${before.height / after.height})`,\r\n transformOrigin: 'top left',\r\n },\r\n { transform: 'none', transformOrigin: 'top left' },\r\n ],\r\n { duration: MOTION.quick.duration * 1000, easing: MOTION.settle.css, composite: 'add' },\r\n );\r\n },\r\n { injector: this.injector },\r\n );\r\n }\r\n}\r\n\r\n@Directive({ selector: '[hyStagger]' })\r\nexport class HyStagger {\r\n readonly hyStagger = input(50, { transform: (value: unknown) => numberAttribute(value, 50) });\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\r\n private readonly visible = injectHyVisibility();\r\n private readonly motion = inject(HyMotion);\r\n private readonly seen = new WeakSet<Element>();\r\n private readonly animations = new Set<Animation>();\r\n constructor() {\r\n const destroy = inject(DestroyRef);\r\n const animate = (): void => {\r\n let index = 0;\r\n for (const child of Array.from(this.host.children)) {\r\n if (this.seen.has(child)) continue;\r\n this.seen.add(child);\r\n if (!this.motion.enabled() || typeof child.animate !== 'function') continue;\r\n const animation = child.animate(\r\n [\r\n { opacity: 0, transform: 'translateY(8px)' },\r\n { opacity: 1, transform: 'none' },\r\n ],\r\n {\r\n duration: MOTION.quick.duration * 1000,\r\n delay: Math.min(300, index++ * Math.max(0, Math.min(80, this.hyStagger()))),\r\n easing: MOTION.settle.css,\r\n fill: 'backwards',\r\n composite: 'add',\r\n },\r\n );\r\n this.animations.add(animation);\r\n void animation.finished.then(\r\n () => this.animations.delete(animation),\r\n () => this.animations.delete(animation),\r\n );\r\n }\r\n };\r\n effect(() => {\r\n if (!this.motion.enabled() || !this.visible()) {\r\n this.animations.forEach((a) => a.cancel());\r\n this.animations.clear();\r\n }\r\n if (this.visible()) animate();\r\n });\r\n afterNextRender(() => {\r\n const observer = new MutationObserver(() => {\r\n if (this.visible()) animate();\r\n });\r\n observer.observe(this.host, { childList: true });\r\n destroy.onDestroy(() => observer.disconnect());\r\n });\r\n destroy.onDestroy(() => this.animations.forEach((a) => a.cancel()));\r\n }\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
2
|
import { ChangeDetectionStrategy, Component, DestroyRef, Directive, ElementRef, afterNextRender, booleanAttribute, inject, input, model, numberAttribute, signal, viewChild } from "@angular/core";
|
|
3
3
|
import { HyIcon } from "@hyalo/angular/icon";
|
|
4
|
-
import { HyMaterialDirective, injectId } from "@hyalo/angular";
|
|
4
|
+
import { HyMaterialDirective, injectId } from "@hyalo/angular/core";
|
|
5
5
|
var HyNavbarBrand = class HyNavbarBrand {
|
|
6
6
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
7
7
|
minVersion: "12.0.0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hyalo-angular-navbar.mjs","names":[],"sources":["../../../projects/hyalo/navbar/navbar.ts","../../../projects/hyalo/navbar/navbar.html"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n DestroyRef,\r\n Directive,\r\n ElementRef,\r\n afterNextRender,\r\n booleanAttribute,\r\n inject,\r\n input,\r\n model,\r\n numberAttribute,\r\n signal,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { HyIcon } from '@hyalo/angular/icon';\r\nimport { HyMaterialDirective, injectId } from '@hyalo/angular';\r\n\r\n/** The logo or product name, at the start of the bar. */\r\n@Directive({ selector: '[hyNavbarBrand]', host: { class: 'hy-navbar__brand' } })\r\nexport class HyNavbarBrand {}\r\n\r\n/** Buttons at the end of the bar, such as sign in or a cart. Always visible. */\r\n@Directive({ selector: '[hyNavbarActions]', host: { class: 'hy-navbar__actions' } })\r\nexport class HyNavbarActions {}\r\n\r\n/**\r\n * - `floating`: a detached glass pill with space around it.\r\n * - `full`: a full-width bar. Once content scrolls under it, a soft fade\r\n * at its lower edge separates the two instead of a hard line.\r\n */\r\nexport type HyNavbarAppearance = 'floating' | 'full';\r\n\r\n/**\r\n * A glass app bar. Links go in the default slot and are wrapped in a\r\n * `<nav>`. On narrow screens they collapse behind a menu button and open as\r\n * a panel under the bar. Bind `menuOpen` if you would rather open your own\r\n * drawer.\r\n *\r\n * ```html\r\n * <hy-navbar label=\"Main\">\r\n * <a hyNavbarBrand routerLink=\"/\">Atelier</a>\r\n * <a routerLink=\"/watches\" routerLinkActive=\"active\" ariaCurrentWhenActive=\"page\">Watches</a>\r\n * <a routerLink=\"/journal\">Journal</a>\r\n * <div hyNavbarActions><button hyButton size=\"sm\">Book a visit</button></div>\r\n * </hy-navbar>\r\n * ```\r\n *\r\n * The bar compacts once the page scrolls, and with `hideOnScroll` it slides\r\n * away while scrolling down and returns on the way up. It never hides while\r\n * the menu is open or focus is inside it. The collapse point is a container\r\n * query on the navbar's own width (48rem by default).\r\n */\r\n@Component({\r\n selector: 'hy-navbar',\r\n imports: [HyIcon, HyMaterialDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-navbar',\r\n '[attr.data-appearance]': 'appearance()',\r\n '[attr.data-position]': 'position()',\r\n '[attr.data-scrolled]': 'scrolled() || null',\r\n '[attr.data-hidden]': 'hidden() || null',\r\n '[attr.data-menu-open]': 'menuOpen() || null',\r\n '(keydown.escape)': 'closeMenu(true)',\r\n '(focusin)': 'hidden.set(false)',\r\n '(click)': 'onClick($event)',\r\n },\r\n templateUrl: './navbar.html',\r\n styleUrl: './navbar.css',\r\n})\r\nexport class HyNavbar {\r\n private readonly toggle = viewChild.required<ElementRef<HTMLButtonElement>>('toggle');\r\n protected readonly linksId = injectId('navbar-links');\r\n\r\n /** Accessible name of the `<nav>` landmark. */\r\n readonly label = input('Main');\r\n /** Accessible name of the menu button on narrow screens. */\r\n readonly menuLabel = input('Menu');\r\n /** Visual style of the bar. */\r\n readonly appearance = input<HyNavbarAppearance>('floating');\r\n /** CSS positioning of the navbar. */\r\n readonly position = input<'sticky' | 'fixed' | 'static'>('sticky');\r\n /** Material of the bar. */\r\n readonly material = input<'clear' | 'frosted' | 'tinted' | 'solid' | ''>('');\r\n /** Slide away while scrolling down. */\r\n readonly hideOnScroll = input(false, { transform: booleanAttribute });\r\n /** Scroll distance in pixels after which the bar compacts. */\r\n readonly scrollThreshold = input(8, { transform: numberAttribute });\r\n /** Whether the collapsed menu is open. Two-way bindable. */\r\n readonly menuOpen = model(false);\r\n\r\n protected readonly scrolled = signal(false);\r\n protected readonly hidden = signal(false);\r\n\r\n constructor() {\r\n const destroyRef = inject(DestroyRef);\r\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\r\n afterNextRender(() => {\r\n const view = host.ownerDocument.defaultView;\r\n if (!view) return;\r\n let last = view.scrollY;\r\n const onScroll = (): void => {\r\n const y = view.scrollY;\r\n this.scrolled.set(y > this.scrollThreshold());\r\n if (\r\n this.hideOnScroll() &&\r\n !this.menuOpen() &&\r\n !host.contains(host.ownerDocument.activeElement)\r\n ) {\r\n const delta = y - last;\r\n if (Math.abs(delta) > 6) this.hidden.set(delta > 0 && y > host.offsetHeight * 2);\r\n } else {\r\n this.hidden.set(false);\r\n }\r\n last = y;\r\n };\r\n onScroll();\r\n view.addEventListener('scroll', onScroll, { passive: true });\r\n destroyRef.onDestroy(() => view.removeEventListener('scroll', onScroll));\r\n });\r\n }\r\n\r\n /** Closes the collapsed menu. */\r\n closeMenu(restoreFocus = false): void {\r\n if (!this.menuOpen()) return;\r\n this.menuOpen.set(false);\r\n if (restoreFocus) this.toggle().nativeElement.focus();\r\n }\r\n\r\n protected onClick(event: MouseEvent): void {\r\n if ((event.target as Element | null)?.closest('.hy-navbar__links a')) this.closeMenu();\r\n }\r\n}\r\n\r\n/** Everything needed to build a navbar. */\r\nexport const HY_NAVBAR = [HyNavbar, HyNavbarBrand, HyNavbarActions] as const;\r\n","<div class=\"hy-navbar__bar\" [hyMaterial]=\"material()\">\r\n <ng-content select=\"[hyNavbarBrand]\" />\r\n <nav class=\"hy-navbar__links\" [id]=\"linksId\" [attr.aria-label]=\"label()\">\r\n <ng-content />\r\n </nav>\r\n <ng-content select=\"[hyNavbarActions]\" />\r\n <button\r\n #toggle\r\n type=\"button\"\r\n class=\"hy-navbar__toggle\"\r\n [attr.aria-expanded]=\"menuOpen()\"\r\n [attr.aria-controls]=\"linksId\"\r\n [attr.aria-label]=\"menuLabel()\"\r\n (click)=\"menuOpen.set(!menuOpen())\"\r\n >\r\n <hy-icon [name]=\"menuOpen() ? 'x' : 'menu'\" />\r\n </button>\r\n</div>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hyalo-angular-navbar.mjs","names":[],"sources":["../../../projects/hyalo/navbar/navbar.ts","../../../projects/hyalo/navbar/navbar.html"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n DestroyRef,\r\n Directive,\r\n ElementRef,\r\n afterNextRender,\r\n booleanAttribute,\r\n inject,\r\n input,\r\n model,\r\n numberAttribute,\r\n signal,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { HyIcon } from '@hyalo/angular/icon';\r\nimport { HyMaterialDirective, injectId } from '@hyalo/angular/core';\r\n\r\n/** The logo or product name, at the start of the bar. */\r\n@Directive({ selector: '[hyNavbarBrand]', host: { class: 'hy-navbar__brand' } })\r\nexport class HyNavbarBrand {}\r\n\r\n/** Buttons at the end of the bar, such as sign in or a cart. Always visible. */\r\n@Directive({ selector: '[hyNavbarActions]', host: { class: 'hy-navbar__actions' } })\r\nexport class HyNavbarActions {}\r\n\r\n/**\r\n * - `floating`: a detached glass pill with space around it.\r\n * - `full`: a full-width bar. Once content scrolls under it, a soft fade\r\n * at its lower edge separates the two instead of a hard line.\r\n */\r\nexport type HyNavbarAppearance = 'floating' | 'full';\r\n\r\n/**\r\n * A glass app bar. Links go in the default slot and are wrapped in a\r\n * `<nav>`. On narrow screens they collapse behind a menu button and open as\r\n * a panel under the bar. Bind `menuOpen` if you would rather open your own\r\n * drawer.\r\n *\r\n * ```html\r\n * <hy-navbar label=\"Main\">\r\n * <a hyNavbarBrand routerLink=\"/\">Atelier</a>\r\n * <a routerLink=\"/watches\" routerLinkActive=\"active\" ariaCurrentWhenActive=\"page\">Watches</a>\r\n * <a routerLink=\"/journal\">Journal</a>\r\n * <div hyNavbarActions><button hyButton size=\"sm\">Book a visit</button></div>\r\n * </hy-navbar>\r\n * ```\r\n *\r\n * The bar compacts once the page scrolls, and with `hideOnScroll` it slides\r\n * away while scrolling down and returns on the way up. It never hides while\r\n * the menu is open or focus is inside it. The collapse point is a container\r\n * query on the navbar's own width (48rem by default).\r\n */\r\n@Component({\r\n selector: 'hy-navbar',\r\n imports: [HyIcon, HyMaterialDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-navbar',\r\n '[attr.data-appearance]': 'appearance()',\r\n '[attr.data-position]': 'position()',\r\n '[attr.data-scrolled]': 'scrolled() || null',\r\n '[attr.data-hidden]': 'hidden() || null',\r\n '[attr.data-menu-open]': 'menuOpen() || null',\r\n '(keydown.escape)': 'closeMenu(true)',\r\n '(focusin)': 'hidden.set(false)',\r\n '(click)': 'onClick($event)',\r\n },\r\n templateUrl: './navbar.html',\r\n styleUrl: './navbar.css',\r\n})\r\nexport class HyNavbar {\r\n private readonly toggle = viewChild.required<ElementRef<HTMLButtonElement>>('toggle');\r\n protected readonly linksId = injectId('navbar-links');\r\n\r\n /** Accessible name of the `<nav>` landmark. */\r\n readonly label = input('Main');\r\n /** Accessible name of the menu button on narrow screens. */\r\n readonly menuLabel = input('Menu');\r\n /** Visual style of the bar. */\r\n readonly appearance = input<HyNavbarAppearance>('floating');\r\n /** CSS positioning of the navbar. */\r\n readonly position = input<'sticky' | 'fixed' | 'static'>('sticky');\r\n /** Material of the bar. */\r\n readonly material = input<'clear' | 'frosted' | 'tinted' | 'solid' | ''>('');\r\n /** Slide away while scrolling down. */\r\n readonly hideOnScroll = input(false, { transform: booleanAttribute });\r\n /** Scroll distance in pixels after which the bar compacts. */\r\n readonly scrollThreshold = input(8, { transform: numberAttribute });\r\n /** Whether the collapsed menu is open. Two-way bindable. */\r\n readonly menuOpen = model(false);\r\n\r\n protected readonly scrolled = signal(false);\r\n protected readonly hidden = signal(false);\r\n\r\n constructor() {\r\n const destroyRef = inject(DestroyRef);\r\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\r\n afterNextRender(() => {\r\n const view = host.ownerDocument.defaultView;\r\n if (!view) return;\r\n let last = view.scrollY;\r\n const onScroll = (): void => {\r\n const y = view.scrollY;\r\n this.scrolled.set(y > this.scrollThreshold());\r\n if (\r\n this.hideOnScroll() &&\r\n !this.menuOpen() &&\r\n !host.contains(host.ownerDocument.activeElement)\r\n ) {\r\n const delta = y - last;\r\n if (Math.abs(delta) > 6) this.hidden.set(delta > 0 && y > host.offsetHeight * 2);\r\n } else {\r\n this.hidden.set(false);\r\n }\r\n last = y;\r\n };\r\n onScroll();\r\n view.addEventListener('scroll', onScroll, { passive: true });\r\n destroyRef.onDestroy(() => view.removeEventListener('scroll', onScroll));\r\n });\r\n }\r\n\r\n /** Closes the collapsed menu. */\r\n closeMenu(restoreFocus = false): void {\r\n if (!this.menuOpen()) return;\r\n this.menuOpen.set(false);\r\n if (restoreFocus) this.toggle().nativeElement.focus();\r\n }\r\n\r\n protected onClick(event: MouseEvent): void {\r\n if ((event.target as Element | null)?.closest('.hy-navbar__links a')) this.closeMenu();\r\n }\r\n}\r\n\r\n/** Everything needed to build a navbar. */\r\nexport const HY_NAVBAR = [HyNavbar, HyNavbarBrand, HyNavbarActions] as const;\r\n","<div class=\"hy-navbar__bar\" [hyMaterial]=\"material()\">\r\n <ng-content select=\"[hyNavbarBrand]\" />\r\n <nav class=\"hy-navbar__links\" [id]=\"linksId\" [attr.aria-label]=\"label()\">\r\n <ng-content />\r\n </nav>\r\n <ng-content select=\"[hyNavbarActions]\" />\r\n <button\r\n #toggle\r\n type=\"button\"\r\n class=\"hy-navbar__toggle\"\r\n [attr.aria-expanded]=\"menuOpen()\"\r\n [attr.aria-controls]=\"linksId\"\r\n [attr.aria-label]=\"menuLabel()\"\r\n (click)=\"menuOpen.set(!menuOpen())\"\r\n >\r\n <hy-icon [name]=\"menuOpen() ? 'x' : 'menu'\" />\r\n </button>\r\n</div>\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { DOCUMENT } from "@angular/common";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import { ChangeDetectionStrategy, Component, ElementRef, inject, input, signal } from "@angular/core";
|
|
4
|
+
import { injectId } from "@hyalo/angular/core";
|
|
5
|
+
import { HyIcon } from "@hyalo/angular/icon";
|
|
6
|
+
import { CdkConnectedOverlay, CdkOverlayOrigin } from "@angular/cdk/overlay";
|
|
7
|
+
var HyNavigationMenu = class HyNavigationMenu {
|
|
8
|
+
items = input.required(...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
|
|
9
|
+
label = input("Main navigation", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
10
|
+
open = signal(null, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
|
|
11
|
+
id = injectId("navigation");
|
|
12
|
+
host = inject(ElementRef);
|
|
13
|
+
document = inject(DOCUMENT);
|
|
14
|
+
trigger = null;
|
|
15
|
+
positions = [{
|
|
16
|
+
originX: "start",
|
|
17
|
+
originY: "bottom",
|
|
18
|
+
overlayX: "start",
|
|
19
|
+
overlayY: "top",
|
|
20
|
+
offsetY: 8
|
|
21
|
+
}, {
|
|
22
|
+
originX: "start",
|
|
23
|
+
originY: "top",
|
|
24
|
+
overlayX: "start",
|
|
25
|
+
overlayY: "bottom",
|
|
26
|
+
offsetY: -8
|
|
27
|
+
}];
|
|
28
|
+
outside(event) {
|
|
29
|
+
if (!this.host.nativeElement.contains(event.target)) this.open.set(null);
|
|
30
|
+
}
|
|
31
|
+
panel() {
|
|
32
|
+
return this.open() ? this.document.getElementById(this.id + "-" + this.open()) : null;
|
|
33
|
+
}
|
|
34
|
+
enterPanel(event) {
|
|
35
|
+
if (event.key !== "Tab" || event.shiftKey || !this.open()) return;
|
|
36
|
+
const first = this.panel()?.querySelector("a[href]");
|
|
37
|
+
if (first) {
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
first.focus();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
panelKeydown(event) {
|
|
43
|
+
if (event.key === "Escape") {
|
|
44
|
+
this.escape(event);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (event.key !== "Tab") return;
|
|
48
|
+
const links = [...this.panel()?.querySelectorAll("a[href]") ?? []];
|
|
49
|
+
if (event.shiftKey && event.target === links[0]) {
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
this.trigger?.focus();
|
|
52
|
+
} else if (!event.shiftKey && event.target === links[links.length - 1]) {
|
|
53
|
+
const targets = [...this.document.querySelectorAll("a[href],button:not(:disabled),input:not(:disabled),select:not(:disabled),textarea:not(:disabled),[tabindex=\"0\"]")].filter((el) => !el.closest("[hidden],[inert]") && el.getClientRects().length > 0);
|
|
54
|
+
const next = this.trigger ? targets[targets.indexOf(this.trigger) + 1] : void 0;
|
|
55
|
+
if (next) {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
this.open.set(null);
|
|
58
|
+
next.focus();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
toggle(id, event) {
|
|
63
|
+
this.trigger = event.currentTarget;
|
|
64
|
+
this.open.update((value) => value === id ? null : id);
|
|
65
|
+
}
|
|
66
|
+
escape(event) {
|
|
67
|
+
if (this.open()) {
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
event.stopPropagation();
|
|
70
|
+
this.open.set(null);
|
|
71
|
+
this.trigger?.focus();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
focusOut(event) {
|
|
75
|
+
if (event.relatedTarget && !this.host.nativeElement.contains(event.relatedTarget) && !this.panel()?.contains(event.relatedTarget)) this.open.set(null);
|
|
76
|
+
}
|
|
77
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
78
|
+
minVersion: "12.0.0",
|
|
79
|
+
version: "22.2.3",
|
|
80
|
+
ngImport: i0,
|
|
81
|
+
type: HyNavigationMenu,
|
|
82
|
+
deps: [],
|
|
83
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
84
|
+
});
|
|
85
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
86
|
+
minVersion: "17.0.0",
|
|
87
|
+
version: "22.2.3",
|
|
88
|
+
type: HyNavigationMenu,
|
|
89
|
+
isStandalone: true,
|
|
90
|
+
selector: "hy-navigation-menu",
|
|
91
|
+
inputs: {
|
|
92
|
+
items: {
|
|
93
|
+
classPropertyName: "items",
|
|
94
|
+
publicName: "items",
|
|
95
|
+
isSignal: true,
|
|
96
|
+
isRequired: true,
|
|
97
|
+
transformFunction: null
|
|
98
|
+
},
|
|
99
|
+
label: {
|
|
100
|
+
classPropertyName: "label",
|
|
101
|
+
publicName: "label",
|
|
102
|
+
isSignal: true,
|
|
103
|
+
isRequired: false,
|
|
104
|
+
transformFunction: null
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
host: { listeners: {
|
|
108
|
+
"keydown.escape": "escape($event)",
|
|
109
|
+
"focusout": "focusOut($event)"
|
|
110
|
+
} },
|
|
111
|
+
ngImport: i0,
|
|
112
|
+
template: "<nav cdkOverlayOrigin #origin=\"cdkOverlayOrigin\" [attr.aria-label]=\"label()\">\n <ul>\n @for (item of items(); track item.id) {\n <li>\n @if (item.sections?.length) {\n <button\n type=\"button\"\n [id]=\"id + '-' + item.id + '-trigger'\"\n [attr.aria-expanded]=\"open() === item.id\"\n [attr.aria-controls]=\"id + '-' + item.id\"\n (click)=\"toggle(item.id, $event)\"\n (keydown)=\"enterPanel($event)\"\n >\n {{ item.label }}<hy-icon class=\"chevron\" name=\"chevron-down\" size=\"1rem\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open() === item.id\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayViewportMargin]=\"16\"\n (overlayOutsideClick)=\"outside($event)\"\n >\n <div\n class=\"panel\"\n tabindex=\"-1\"\n role=\"region\"\n (keydown)=\"panelKeydown($event)\"\n (focusout)=\"focusOut($event)\"\n [id]=\"id + '-' + item.id\"\n [attr.aria-labelledby]=\"id + '-' + item.id + '-trigger'\"\n >\n @for (section of item.sections; track $index) {\n <section>\n <h3>{{ section.label }}</h3>\n <ul>\n @for (link of section.links; track $index) {\n <li>\n <a [href]=\"link.href\" (click)=\"open.set(null)\"\n ><strong>{{ link.label }}</strong>\n @if (link.description) {\n <span>{{ link.description }}</span>\n }\n </a>\n </li>\n }\n </ul>\n </section>\n }\n </div>\n </ng-template>\n } @else {\n <a [href]=\"item.href\">{{ item.label }}</a>\n }\n </li>\n }\n </ul>\n</nav>\n",
|
|
113
|
+
styles: [":host{display:block;position:relative;color:var(--hy-ink)}ul{list-style:none;margin:0;padding:0}nav>ul{display:flex;align-items:center;flex-wrap:wrap;gap:.25rem}a,button{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;min-block-size:44px;box-sizing:border-box;font:inherit;color:inherit;background:transparent;border:0;border-radius:var(--hy-radius-s);text-decoration:none;cursor:pointer}a:hover,button:hover,button[aria-expanded=true]{background:var(--hy-primary-wash)}.panel{inline-size:min(40rem,calc(100vw - 2rem));box-sizing:border-box;color:var(--hy-ink);display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,12rem),1fr));gap:1rem;padding:1.25rem;border:1px solid var(--hy-line-strong);border-radius:var(--hy-radius-l);background:var(--hy-surface-1);box-shadow:var(--hy-glass-shadow);max-block-size:65dvh;overflow:auto}.panel h3{font-size:.75rem;color:var(--hy-ink-3);margin:0 0 .5rem;padding-inline:1rem}.panel a{display:block}.panel strong{font-size:.875rem}.panel span{display:block;color:var(--hy-ink-2);font-size:.8125rem;margin-block-start:.25rem}:is(button,a,input):focus-visible{outline:2px solid var(--hy-primary);outline-offset:3px}.chevron{color:var(--hy-ink-3);transition:rotate var(--hy-dur-quick) var(--hy-ease-out)}button[aria-expanded=true] .chevron{rotate:180deg}@media(prefers-reduced-motion:reduce){.chevron{transition:none}}\n"],
|
|
114
|
+
dependencies: [
|
|
115
|
+
{
|
|
116
|
+
kind: "component",
|
|
117
|
+
type: HyIcon,
|
|
118
|
+
selector: "hy-icon",
|
|
119
|
+
inputs: [
|
|
120
|
+
"name",
|
|
121
|
+
"icon",
|
|
122
|
+
"label",
|
|
123
|
+
"size",
|
|
124
|
+
"strokeWidth"
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
kind: "directive",
|
|
129
|
+
type: CdkConnectedOverlay,
|
|
130
|
+
selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]",
|
|
131
|
+
inputs: [
|
|
132
|
+
"cdkConnectedOverlayOrigin",
|
|
133
|
+
"cdkConnectedOverlayPositions",
|
|
134
|
+
"cdkConnectedOverlayPositionStrategy",
|
|
135
|
+
"cdkConnectedOverlayOffsetX",
|
|
136
|
+
"cdkConnectedOverlayOffsetY",
|
|
137
|
+
"cdkConnectedOverlayWidth",
|
|
138
|
+
"cdkConnectedOverlayHeight",
|
|
139
|
+
"cdkConnectedOverlayMinWidth",
|
|
140
|
+
"cdkConnectedOverlayMinHeight",
|
|
141
|
+
"cdkConnectedOverlayBackdropClass",
|
|
142
|
+
"cdkConnectedOverlayPanelClass",
|
|
143
|
+
"cdkConnectedOverlayViewportMargin",
|
|
144
|
+
"cdkConnectedOverlayScrollStrategy",
|
|
145
|
+
"cdkConnectedOverlayOpen",
|
|
146
|
+
"cdkConnectedOverlayDisableClose",
|
|
147
|
+
"cdkConnectedOverlayTransformOriginOn",
|
|
148
|
+
"cdkConnectedOverlayHasBackdrop",
|
|
149
|
+
"cdkConnectedOverlayLockPosition",
|
|
150
|
+
"cdkConnectedOverlayFlexibleDimensions",
|
|
151
|
+
"cdkConnectedOverlayGrowAfterOpen",
|
|
152
|
+
"cdkConnectedOverlayPush",
|
|
153
|
+
"cdkConnectedOverlayDisposeOnNavigation",
|
|
154
|
+
"cdkConnectedOverlayUsePopover",
|
|
155
|
+
"cdkConnectedOverlayMatchWidth",
|
|
156
|
+
"cdkConnectedOverlay"
|
|
157
|
+
],
|
|
158
|
+
outputs: [
|
|
159
|
+
"backdropClick",
|
|
160
|
+
"positionChange",
|
|
161
|
+
"attach",
|
|
162
|
+
"detach",
|
|
163
|
+
"overlayKeydown",
|
|
164
|
+
"overlayOutsideClick"
|
|
165
|
+
],
|
|
166
|
+
exportAs: ["cdkConnectedOverlay"]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
kind: "directive",
|
|
170
|
+
type: CdkOverlayOrigin,
|
|
171
|
+
selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]",
|
|
172
|
+
exportAs: ["cdkOverlayOrigin"]
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
179
|
+
minVersion: "12.0.0",
|
|
180
|
+
version: "22.2.3",
|
|
181
|
+
ngImport: i0,
|
|
182
|
+
type: HyNavigationMenu,
|
|
183
|
+
decorators: [{
|
|
184
|
+
type: Component,
|
|
185
|
+
args: [{
|
|
186
|
+
selector: "hy-navigation-menu",
|
|
187
|
+
imports: [
|
|
188
|
+
HyIcon,
|
|
189
|
+
CdkConnectedOverlay,
|
|
190
|
+
CdkOverlayOrigin
|
|
191
|
+
],
|
|
192
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
193
|
+
host: {
|
|
194
|
+
"(keydown.escape)": "escape($event)",
|
|
195
|
+
"(focusout)": "focusOut($event)"
|
|
196
|
+
},
|
|
197
|
+
template: "<nav cdkOverlayOrigin #origin=\"cdkOverlayOrigin\" [attr.aria-label]=\"label()\">\n <ul>\n @for (item of items(); track item.id) {\n <li>\n @if (item.sections?.length) {\n <button\n type=\"button\"\n [id]=\"id + '-' + item.id + '-trigger'\"\n [attr.aria-expanded]=\"open() === item.id\"\n [attr.aria-controls]=\"id + '-' + item.id\"\n (click)=\"toggle(item.id, $event)\"\n (keydown)=\"enterPanel($event)\"\n >\n {{ item.label }}<hy-icon class=\"chevron\" name=\"chevron-down\" size=\"1rem\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open() === item.id\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayViewportMargin]=\"16\"\n (overlayOutsideClick)=\"outside($event)\"\n >\n <div\n class=\"panel\"\n tabindex=\"-1\"\n role=\"region\"\n (keydown)=\"panelKeydown($event)\"\n (focusout)=\"focusOut($event)\"\n [id]=\"id + '-' + item.id\"\n [attr.aria-labelledby]=\"id + '-' + item.id + '-trigger'\"\n >\n @for (section of item.sections; track $index) {\n <section>\n <h3>{{ section.label }}</h3>\n <ul>\n @for (link of section.links; track $index) {\n <li>\n <a [href]=\"link.href\" (click)=\"open.set(null)\"\n ><strong>{{ link.label }}</strong>\n @if (link.description) {\n <span>{{ link.description }}</span>\n }\n </a>\n </li>\n }\n </ul>\n </section>\n }\n </div>\n </ng-template>\n } @else {\n <a [href]=\"item.href\">{{ item.label }}</a>\n }\n </li>\n }\n </ul>\n</nav>\n",
|
|
198
|
+
styles: [":host{display:block;position:relative;color:var(--hy-ink)}ul{list-style:none;margin:0;padding:0}nav>ul{display:flex;align-items:center;flex-wrap:wrap;gap:.25rem}a,button{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;min-block-size:44px;box-sizing:border-box;font:inherit;color:inherit;background:transparent;border:0;border-radius:var(--hy-radius-s);text-decoration:none;cursor:pointer}a:hover,button:hover,button[aria-expanded=true]{background:var(--hy-primary-wash)}.panel{inline-size:min(40rem,calc(100vw - 2rem));box-sizing:border-box;color:var(--hy-ink);display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,12rem),1fr));gap:1rem;padding:1.25rem;border:1px solid var(--hy-line-strong);border-radius:var(--hy-radius-l);background:var(--hy-surface-1);box-shadow:var(--hy-glass-shadow);max-block-size:65dvh;overflow:auto}.panel h3{font-size:.75rem;color:var(--hy-ink-3);margin:0 0 .5rem;padding-inline:1rem}.panel a{display:block}.panel strong{font-size:.875rem}.panel span{display:block;color:var(--hy-ink-2);font-size:.8125rem;margin-block-start:.25rem}:is(button,a,input):focus-visible{outline:2px solid var(--hy-primary);outline-offset:3px}.chevron{color:var(--hy-ink-3);transition:rotate var(--hy-dur-quick) var(--hy-ease-out)}button[aria-expanded=true] .chevron{rotate:180deg}@media(prefers-reduced-motion:reduce){.chevron{transition:none}}\n"]
|
|
199
|
+
}]
|
|
200
|
+
}],
|
|
201
|
+
propDecorators: {
|
|
202
|
+
items: [{
|
|
203
|
+
type: i0.Input,
|
|
204
|
+
args: [{
|
|
205
|
+
isSignal: true,
|
|
206
|
+
alias: "items",
|
|
207
|
+
required: true
|
|
208
|
+
}]
|
|
209
|
+
}],
|
|
210
|
+
label: [{
|
|
211
|
+
type: i0.Input,
|
|
212
|
+
args: [{
|
|
213
|
+
isSignal: true,
|
|
214
|
+
alias: "label",
|
|
215
|
+
required: false
|
|
216
|
+
}]
|
|
217
|
+
}]
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
export { HyNavigationMenu };
|
|
221
|
+
|
|
222
|
+
//# sourceMappingURL=hyalo-angular-navigation-menu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hyalo-angular-navigation-menu.mjs","names":[],"sources":["../../../projects/hyalo/navigation-menu/navigation-menu.ts","../../../projects/hyalo/navigation-menu/navigation-menu.html"],"sourcesContent":["import { DOCUMENT } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n inject,\n input,\n signal,\n} from '@angular/core';\nimport { injectId } from '@hyalo/angular/core';\nimport { HyIcon } from '@hyalo/angular/icon';\nimport {\n CdkConnectedOverlay,\n CdkOverlayOrigin,\n type ConnectedPosition,\n} from '@angular/cdk/overlay';\nexport interface HyNavigationLink {\n readonly label: string;\n readonly href: string;\n readonly description?: string;\n}\nexport interface HyNavigationSection {\n readonly label: string;\n readonly links: readonly HyNavigationLink[];\n}\nexport interface HyNavigationItem {\n readonly id: string;\n readonly label: string;\n readonly href?: string;\n readonly sections?: readonly HyNavigationSection[];\n}\n@Component({\n selector: 'hy-navigation-menu',\n imports: [HyIcon, CdkConnectedOverlay, CdkOverlayOrigin],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './navigation-menu.html',\n styleUrl: './navigation-menu.css',\n host: { '(keydown.escape)': 'escape($event)', '(focusout)': 'focusOut($event)' },\n})\nexport class HyNavigationMenu {\n readonly items = input.required<readonly HyNavigationItem[]>();\n readonly label = input('Main navigation');\n readonly open = signal<string | null>(null);\n protected readonly id = injectId('navigation');\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly document = inject(DOCUMENT);\n private trigger: HTMLElement | null = null;\n protected readonly positions: ConnectedPosition[] = [\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 8 },\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -8 },\n ];\n protected outside(event: MouseEvent): void {\n if (!this.host.nativeElement.contains(event.target as Node)) this.open.set(null);\n }\n private panel(): HTMLElement | null {\n return this.open() ? this.document.getElementById(this.id + '-' + this.open()) : null;\n }\n protected enterPanel(event: KeyboardEvent): void {\n if (event.key !== 'Tab' || event.shiftKey || !this.open()) return;\n const first = this.panel()?.querySelector<HTMLAnchorElement>('a[href]');\n if (first) {\n event.preventDefault();\n first.focus();\n }\n }\n protected panelKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') {\n this.escape(event);\n return;\n }\n if (event.key !== 'Tab') return;\n const links = [...(this.panel()?.querySelectorAll<HTMLAnchorElement>('a[href]') ?? [])];\n if (event.shiftKey && event.target === links[0]) {\n event.preventDefault();\n this.trigger?.focus();\n } else if (!event.shiftKey && event.target === links[links.length - 1]) {\n const targets = [\n ...this.document.querySelectorAll<HTMLElement>(\n 'a[href],button:not(:disabled),input:not(:disabled),select:not(:disabled),textarea:not(:disabled),[tabindex=\"0\"]',\n ),\n ].filter((el) => !el.closest('[hidden],[inert]') && el.getClientRects().length > 0);\n const next = this.trigger ? targets[targets.indexOf(this.trigger) + 1] : undefined;\n if (next) {\n event.preventDefault();\n this.open.set(null);\n next.focus();\n }\n }\n }\n toggle(id: string, event: Event): void {\n this.trigger = event.currentTarget as HTMLElement;\n this.open.update((value) => (value === id ? null : id));\n }\n escape(event: Event): void {\n if (this.open()) {\n event.preventDefault();\n event.stopPropagation();\n this.open.set(null);\n this.trigger?.focus();\n }\n }\n focusOut(event: FocusEvent): void {\n if (\n event.relatedTarget &&\n !this.host.nativeElement.contains(event.relatedTarget as Node) &&\n !this.panel()?.contains(event.relatedTarget as Node)\n )\n this.open.set(null);\n }\n}\n","<nav cdkOverlayOrigin #origin=\"cdkOverlayOrigin\" [attr.aria-label]=\"label()\">\n <ul>\n @for (item of items(); track item.id) {\n <li>\n @if (item.sections?.length) {\n <button\n type=\"button\"\n [id]=\"id + '-' + item.id + '-trigger'\"\n [attr.aria-expanded]=\"open() === item.id\"\n [attr.aria-controls]=\"id + '-' + item.id\"\n (click)=\"toggle(item.id, $event)\"\n (keydown)=\"enterPanel($event)\"\n >\n {{ item.label }}<hy-icon class=\"chevron\" name=\"chevron-down\" size=\"1rem\" />\n </button>\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayOpen]=\"open() === item.id\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayViewportMargin]=\"16\"\n (overlayOutsideClick)=\"outside($event)\"\n >\n <div\n class=\"panel\"\n tabindex=\"-1\"\n role=\"region\"\n (keydown)=\"panelKeydown($event)\"\n (focusout)=\"focusOut($event)\"\n [id]=\"id + '-' + item.id\"\n [attr.aria-labelledby]=\"id + '-' + item.id + '-trigger'\"\n >\n @for (section of item.sections; track $index) {\n <section>\n <h3>{{ section.label }}</h3>\n <ul>\n @for (link of section.links; track $index) {\n <li>\n <a [href]=\"link.href\" (click)=\"open.set(null)\"\n ><strong>{{ link.label }}</strong>\n @if (link.description) {\n <span>{{ link.description }}</span>\n }\n </a>\n </li>\n }\n </ul>\n </section>\n }\n </div>\n </ng-template>\n } @else {\n <a [href]=\"item.href\">{{ item.label }}</a>\n }\n </li>\n }\n </ul>\n</nav>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, DestroyRef, Injector, afterNextRender, booleanAttribute, computed, effect, inject, input, signal, untracked } from "@angular/core";
|
|
3
|
+
import { HyLocale } from "@hyalo/angular/core";
|
|
4
|
+
import { HyMotion, HySpring, injectHyVisibility } from "@hyalo/angular/motion";
|
|
5
|
+
var HyNumberTicker = class HyNumberTicker {
|
|
6
|
+
value = input.required(...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
|
|
7
|
+
locale = input(...ngDevMode ? [void 0, { debugName: "locale" }] : /* istanbul ignore next */ []);
|
|
8
|
+
globalLocale = inject(HyLocale);
|
|
9
|
+
effectiveLocale = computed(() => this.locale() ?? this.globalLocale.locale(), ...ngDevMode ? [{ debugName: "effectiveLocale" }] : /* istanbul ignore next */ []);
|
|
10
|
+
format = input({ maximumFractionDigits: 0 }, ...ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []);
|
|
11
|
+
animate = input(false, {
|
|
12
|
+
...ngDevMode ? { debugName: "animate" } : /* istanbul ignore next */ {},
|
|
13
|
+
transform: booleanAttribute
|
|
14
|
+
});
|
|
15
|
+
prefix = input("", ...ngDevMode ? [{ debugName: "prefix" }] : /* istanbul ignore next */ []);
|
|
16
|
+
suffix = input("", ...ngDevMode ? [{ debugName: "suffix" }] : /* istanbul ignore next */ []);
|
|
17
|
+
target = computed(() => Number.isFinite(this.value()) ? this.value() : 0, ...ngDevMode ? [{ debugName: "target" }] : /* istanbul ignore next */ []);
|
|
18
|
+
live = signal(null, ...ngDevMode ? [{ debugName: "live" }] : /* istanbul ignore next */ []);
|
|
19
|
+
formatter = computed(() => new Intl.NumberFormat(this.effectiveLocale(), this.format()), ...ngDevMode ? [{ debugName: "formatter" }] : /* istanbul ignore next */ []);
|
|
20
|
+
formatted = computed(() => this.prefix() + this.formatter().format(this.live() ?? this.target()) + this.suffix(), ...ngDevMode ? [{ debugName: "formatted" }] : /* istanbul ignore next */ []);
|
|
21
|
+
accessible = computed(() => this.prefix() + this.formatter().format(this.target()) + this.suffix(), ...ngDevMode ? [{ debugName: "accessible" }] : /* istanbul ignore next */ []);
|
|
22
|
+
motion = inject(HyMotion);
|
|
23
|
+
visible = injectHyVisibility();
|
|
24
|
+
constructor() {
|
|
25
|
+
const injector = inject(Injector), destroy = inject(DestroyRef);
|
|
26
|
+
let spring;
|
|
27
|
+
afterNextRender(() => {
|
|
28
|
+
const active = spring = new HySpring(this.target(), (value) => this.live.set(value));
|
|
29
|
+
effect(() => {
|
|
30
|
+
const target = this.target(), enabled = this.animate() && this.visible() && this.motion.enabled();
|
|
31
|
+
untracked(() => {
|
|
32
|
+
if (enabled) active.to(target);
|
|
33
|
+
else active.set(target);
|
|
34
|
+
});
|
|
35
|
+
}, { injector });
|
|
36
|
+
});
|
|
37
|
+
destroy.onDestroy(() => spring?.stop());
|
|
38
|
+
}
|
|
39
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
40
|
+
minVersion: "12.0.0",
|
|
41
|
+
version: "22.2.3",
|
|
42
|
+
ngImport: i0,
|
|
43
|
+
type: HyNumberTicker,
|
|
44
|
+
deps: [],
|
|
45
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
46
|
+
});
|
|
47
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
48
|
+
minVersion: "17.1.0",
|
|
49
|
+
version: "22.2.3",
|
|
50
|
+
type: HyNumberTicker,
|
|
51
|
+
isStandalone: true,
|
|
52
|
+
selector: "hy-number-ticker",
|
|
53
|
+
inputs: {
|
|
54
|
+
value: {
|
|
55
|
+
classPropertyName: "value",
|
|
56
|
+
publicName: "value",
|
|
57
|
+
isSignal: true,
|
|
58
|
+
isRequired: true,
|
|
59
|
+
transformFunction: null
|
|
60
|
+
},
|
|
61
|
+
locale: {
|
|
62
|
+
classPropertyName: "locale",
|
|
63
|
+
publicName: "locale",
|
|
64
|
+
isSignal: true,
|
|
65
|
+
isRequired: false,
|
|
66
|
+
transformFunction: null
|
|
67
|
+
},
|
|
68
|
+
format: {
|
|
69
|
+
classPropertyName: "format",
|
|
70
|
+
publicName: "format",
|
|
71
|
+
isSignal: true,
|
|
72
|
+
isRequired: false,
|
|
73
|
+
transformFunction: null
|
|
74
|
+
},
|
|
75
|
+
animate: {
|
|
76
|
+
classPropertyName: "animate",
|
|
77
|
+
publicName: "animate",
|
|
78
|
+
isSignal: true,
|
|
79
|
+
isRequired: false,
|
|
80
|
+
transformFunction: null
|
|
81
|
+
},
|
|
82
|
+
prefix: {
|
|
83
|
+
classPropertyName: "prefix",
|
|
84
|
+
publicName: "prefix",
|
|
85
|
+
isSignal: true,
|
|
86
|
+
isRequired: false,
|
|
87
|
+
transformFunction: null
|
|
88
|
+
},
|
|
89
|
+
suffix: {
|
|
90
|
+
classPropertyName: "suffix",
|
|
91
|
+
publicName: "suffix",
|
|
92
|
+
isSignal: true,
|
|
93
|
+
isRequired: false,
|
|
94
|
+
transformFunction: null
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
ngImport: i0,
|
|
98
|
+
template: `<span aria-hidden="true">{{ formatted() }}</span
|
|
99
|
+
><span class="sr">{{ accessible() }}</span>`,
|
|
100
|
+
isInline: true,
|
|
101
|
+
styles: [":host{font-variant-numeric:tabular-nums}.sr{position:absolute;inline-size:1px;block-size:1px;clip-path:inset(50%);overflow:hidden}\n"],
|
|
102
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
106
|
+
minVersion: "12.0.0",
|
|
107
|
+
version: "22.2.3",
|
|
108
|
+
ngImport: i0,
|
|
109
|
+
type: HyNumberTicker,
|
|
110
|
+
decorators: [{
|
|
111
|
+
type: Component,
|
|
112
|
+
args: [{
|
|
113
|
+
selector: "hy-number-ticker",
|
|
114
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
115
|
+
template: `<span aria-hidden="true">{{ formatted() }}</span
|
|
116
|
+
><span class="sr">{{ accessible() }}</span>`,
|
|
117
|
+
styles: [":host{font-variant-numeric:tabular-nums}.sr{position:absolute;inline-size:1px;block-size:1px;clip-path:inset(50%);overflow:hidden}\n"]
|
|
118
|
+
}]
|
|
119
|
+
}],
|
|
120
|
+
ctorParameters: () => [],
|
|
121
|
+
propDecorators: {
|
|
122
|
+
value: [{
|
|
123
|
+
type: i0.Input,
|
|
124
|
+
args: [{
|
|
125
|
+
isSignal: true,
|
|
126
|
+
alias: "value",
|
|
127
|
+
required: true
|
|
128
|
+
}]
|
|
129
|
+
}],
|
|
130
|
+
locale: [{
|
|
131
|
+
type: i0.Input,
|
|
132
|
+
args: [{
|
|
133
|
+
isSignal: true,
|
|
134
|
+
alias: "locale",
|
|
135
|
+
required: false
|
|
136
|
+
}]
|
|
137
|
+
}],
|
|
138
|
+
format: [{
|
|
139
|
+
type: i0.Input,
|
|
140
|
+
args: [{
|
|
141
|
+
isSignal: true,
|
|
142
|
+
alias: "format",
|
|
143
|
+
required: false
|
|
144
|
+
}]
|
|
145
|
+
}],
|
|
146
|
+
animate: [{
|
|
147
|
+
type: i0.Input,
|
|
148
|
+
args: [{
|
|
149
|
+
isSignal: true,
|
|
150
|
+
alias: "animate",
|
|
151
|
+
required: false
|
|
152
|
+
}]
|
|
153
|
+
}],
|
|
154
|
+
prefix: [{
|
|
155
|
+
type: i0.Input,
|
|
156
|
+
args: [{
|
|
157
|
+
isSignal: true,
|
|
158
|
+
alias: "prefix",
|
|
159
|
+
required: false
|
|
160
|
+
}]
|
|
161
|
+
}],
|
|
162
|
+
suffix: [{
|
|
163
|
+
type: i0.Input,
|
|
164
|
+
args: [{
|
|
165
|
+
isSignal: true,
|
|
166
|
+
alias: "suffix",
|
|
167
|
+
required: false
|
|
168
|
+
}]
|
|
169
|
+
}]
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
export { HyNumberTicker };
|
|
173
|
+
|
|
174
|
+
//# sourceMappingURL=hyalo-angular-number-ticker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hyalo-angular-number-ticker.mjs","names":[],"sources":["../../../projects/hyalo/number-ticker/number-ticker.ts"],"sourcesContent":["import { booleanAttribute } from '@angular/core';\nimport { HyLocale } from '@hyalo/angular/core';\nimport {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n Injector,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n signal,\n untracked,\n} from '@angular/core';\nimport { HyMotion, HySpring, injectHyVisibility } from '@hyalo/angular/motion';\n@Component({\n selector: 'hy-number-ticker',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `<span aria-hidden=\"true\">{{ formatted() }}</span\n ><span class=\"sr\">{{ accessible() }}</span>`,\n styleUrl: './number-ticker.css',\n})\nexport class HyNumberTicker {\n readonly value = input.required<number>();\n readonly locale = input<string>();\n private readonly globalLocale = inject(HyLocale);\n private readonly effectiveLocale = computed(() => this.locale() ?? this.globalLocale.locale());\n readonly format = input<Intl.NumberFormatOptions>({ maximumFractionDigits: 0 });\n readonly animate = input(false, { transform: booleanAttribute });\n readonly prefix = input('');\n readonly suffix = input('');\n private readonly target = computed(() => (Number.isFinite(this.value()) ? this.value() : 0));\n private readonly live = signal<number | null>(null);\n private readonly formatter = computed(\n () => new Intl.NumberFormat(this.effectiveLocale(), this.format()),\n );\n readonly formatted = computed(\n () => this.prefix() + this.formatter().format(this.live() ?? this.target()) + this.suffix(),\n );\n readonly accessible = computed(\n () => this.prefix() + this.formatter().format(this.target()) + this.suffix(),\n );\n private readonly motion = inject(HyMotion);\n private readonly visible = injectHyVisibility();\n constructor() {\n const injector = inject(Injector),\n destroy = inject(DestroyRef);\n let spring: HySpring | undefined;\n afterNextRender(() => {\n const active = (spring = new HySpring(this.target(), (value) => this.live.set(value)));\n effect(\n () => {\n const target = this.target(),\n enabled = this.animate() && this.visible() && this.motion.enabled();\n untracked(() => {\n if (enabled) active.to(target);\n else active.set(target);\n });\n },\n { injector },\n );\n });\n destroy.onDestroy(() => spring?.stop());\n }\n}\n"],"mappings":"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"}
|