@joanroucoux/cairn-ui 0.8.2 → 0.9.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.
Files changed (124) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/fesm2022/joanroucoux-cairn-ui-action-bar.mjs +57 -53
  3. package/fesm2022/joanroucoux-cairn-ui-action-bar.mjs.map +1 -1
  4. package/fesm2022/joanroucoux-cairn-ui-alert.mjs +155 -47
  5. package/fesm2022/joanroucoux-cairn-ui-alert.mjs.map +1 -1
  6. package/fesm2022/joanroucoux-cairn-ui-amount.mjs +220 -110
  7. package/fesm2022/joanroucoux-cairn-ui-amount.mjs.map +1 -1
  8. package/fesm2022/joanroucoux-cairn-ui-async.mjs +392 -216
  9. package/fesm2022/joanroucoux-cairn-ui-async.mjs.map +1 -1
  10. package/fesm2022/joanroucoux-cairn-ui-avatar.mjs +145 -68
  11. package/fesm2022/joanroucoux-cairn-ui-avatar.mjs.map +1 -1
  12. package/fesm2022/joanroucoux-cairn-ui-back-link.mjs +87 -47
  13. package/fesm2022/joanroucoux-cairn-ui-back-link.mjs.map +1 -1
  14. package/fesm2022/joanroucoux-cairn-ui-badge.mjs +83 -43
  15. package/fesm2022/joanroucoux-cairn-ui-badge.mjs.map +1 -1
  16. package/fesm2022/joanroucoux-cairn-ui-button.mjs +184 -104
  17. package/fesm2022/joanroucoux-cairn-ui-button.mjs.map +1 -1
  18. package/fesm2022/joanroucoux-cairn-ui-card.mjs +232 -137
  19. package/fesm2022/joanroucoux-cairn-ui-card.mjs.map +1 -1
  20. package/fesm2022/joanroucoux-cairn-ui-choice-chips.mjs +298 -102
  21. package/fesm2022/joanroucoux-cairn-ui-choice-chips.mjs.map +1 -1
  22. package/fesm2022/joanroucoux-cairn-ui-control.mjs +4 -17
  23. package/fesm2022/joanroucoux-cairn-ui-control.mjs.map +1 -1
  24. package/fesm2022/joanroucoux-cairn-ui-delta.mjs +150 -83
  25. package/fesm2022/joanroucoux-cairn-ui-delta.mjs.map +1 -1
  26. package/fesm2022/joanroucoux-cairn-ui-dialog.mjs +508 -471
  27. package/fesm2022/joanroucoux-cairn-ui-dialog.mjs.map +1 -1
  28. package/fesm2022/joanroucoux-cairn-ui-donut.mjs +255 -157
  29. package/fesm2022/joanroucoux-cairn-ui-donut.mjs.map +1 -1
  30. package/fesm2022/joanroucoux-cairn-ui-drawer.mjs +303 -0
  31. package/fesm2022/joanroucoux-cairn-ui-drawer.mjs.map +1 -0
  32. package/fesm2022/joanroucoux-cairn-ui-empty.mjs +76 -35
  33. package/fesm2022/joanroucoux-cairn-ui-empty.mjs.map +1 -1
  34. package/fesm2022/joanroucoux-cairn-ui-external-link.mjs +40 -31
  35. package/fesm2022/joanroucoux-cairn-ui-external-link.mjs.map +1 -1
  36. package/fesm2022/joanroucoux-cairn-ui-fact.mjs +188 -79
  37. package/fesm2022/joanroucoux-cairn-ui-fact.mjs.map +1 -1
  38. package/fesm2022/joanroucoux-cairn-ui-field.mjs +309 -173
  39. package/fesm2022/joanroucoux-cairn-ui-field.mjs.map +1 -1
  40. package/fesm2022/joanroucoux-cairn-ui-filter-chips.mjs +165 -87
  41. package/fesm2022/joanroucoux-cairn-ui-filter-chips.mjs.map +1 -1
  42. package/fesm2022/joanroucoux-cairn-ui-group-header.mjs +269 -0
  43. package/fesm2022/joanroucoux-cairn-ui-group-header.mjs.map +1 -0
  44. package/fesm2022/joanroucoux-cairn-ui-input.mjs +205 -85
  45. package/fesm2022/joanroucoux-cairn-ui-input.mjs.map +1 -1
  46. package/fesm2022/joanroucoux-cairn-ui-line-chart.mjs +838 -512
  47. package/fesm2022/joanroucoux-cairn-ui-line-chart.mjs.map +1 -1
  48. package/fesm2022/joanroucoux-cairn-ui-menu.mjs +401 -225
  49. package/fesm2022/joanroucoux-cairn-ui-menu.mjs.map +1 -1
  50. package/fesm2022/joanroucoux-cairn-ui-meter.mjs +143 -57
  51. package/fesm2022/joanroucoux-cairn-ui-meter.mjs.map +1 -1
  52. package/fesm2022/joanroucoux-cairn-ui-motion.mjs +367 -399
  53. package/fesm2022/joanroucoux-cairn-ui-motion.mjs.map +1 -1
  54. package/fesm2022/joanroucoux-cairn-ui-nav-item.mjs +73 -44
  55. package/fesm2022/joanroucoux-cairn-ui-nav-item.mjs.map +1 -1
  56. package/fesm2022/joanroucoux-cairn-ui-result-group.mjs +191 -0
  57. package/fesm2022/joanroucoux-cairn-ui-result-group.mjs.map +1 -0
  58. package/fesm2022/joanroucoux-cairn-ui-row.mjs +408 -146
  59. package/fesm2022/joanroucoux-cairn-ui-row.mjs.map +1 -1
  60. package/fesm2022/joanroucoux-cairn-ui-segmented.mjs +183 -81
  61. package/fesm2022/joanroucoux-cairn-ui-segmented.mjs.map +1 -1
  62. package/fesm2022/joanroucoux-cairn-ui-select-pill.mjs +270 -0
  63. package/fesm2022/joanroucoux-cairn-ui-select-pill.mjs.map +1 -0
  64. package/fesm2022/joanroucoux-cairn-ui-select.mjs +121 -67
  65. package/fesm2022/joanroucoux-cairn-ui-select.mjs.map +1 -1
  66. package/fesm2022/joanroucoux-cairn-ui-skeleton.mjs +129 -51
  67. package/fesm2022/joanroucoux-cairn-ui-skeleton.mjs.map +1 -1
  68. package/fesm2022/joanroucoux-cairn-ui-stale-link.mjs +80 -39
  69. package/fesm2022/joanroucoux-cairn-ui-stale-link.mjs.map +1 -1
  70. package/fesm2022/joanroucoux-cairn-ui-stat.mjs +85 -55
  71. package/fesm2022/joanroucoux-cairn-ui-stat.mjs.map +1 -1
  72. package/fesm2022/joanroucoux-cairn-ui-switch.mjs +48 -35
  73. package/fesm2022/joanroucoux-cairn-ui-switch.mjs.map +1 -1
  74. package/fesm2022/joanroucoux-cairn-ui-tab-bar.mjs +113 -69
  75. package/fesm2022/joanroucoux-cairn-ui-tab-bar.mjs.map +1 -1
  76. package/fesm2022/joanroucoux-cairn-ui-table.mjs +1036 -310
  77. package/fesm2022/joanroucoux-cairn-ui-table.mjs.map +1 -1
  78. package/fesm2022/joanroucoux-cairn-ui-toast.mjs +240 -127
  79. package/fesm2022/joanroucoux-cairn-ui-toast.mjs.map +1 -1
  80. package/fesm2022/joanroucoux-cairn-ui.mjs +0 -4
  81. package/package.json +17 -1
  82. package/styles/motion.css +1 -13
  83. package/styles/tokens.css +35 -64
  84. package/types/joanroucoux-cairn-ui-action-bar.d.ts +9 -14
  85. package/types/joanroucoux-cairn-ui-alert.d.ts +29 -15
  86. package/types/joanroucoux-cairn-ui-amount.d.ts +64 -32
  87. package/types/joanroucoux-cairn-ui-async.d.ts +85 -38
  88. package/types/joanroucoux-cairn-ui-avatar.d.ts +34 -22
  89. package/types/joanroucoux-cairn-ui-back-link.d.ts +20 -15
  90. package/types/joanroucoux-cairn-ui-badge.d.ts +22 -14
  91. package/types/joanroucoux-cairn-ui-button.d.ts +36 -18
  92. package/types/joanroucoux-cairn-ui-card.d.ts +48 -23
  93. package/types/joanroucoux-cairn-ui-choice-chips.d.ts +91 -35
  94. package/types/joanroucoux-cairn-ui-control.d.ts +9 -18
  95. package/types/joanroucoux-cairn-ui-delta.d.ts +46 -24
  96. package/types/joanroucoux-cairn-ui-dialog.d.ts +124 -57
  97. package/types/joanroucoux-cairn-ui-donut.d.ts +83 -46
  98. package/types/joanroucoux-cairn-ui-drawer.d.ts +73 -0
  99. package/types/joanroucoux-cairn-ui-empty.d.ts +20 -13
  100. package/types/joanroucoux-cairn-ui-external-link.d.ts +6 -10
  101. package/types/joanroucoux-cairn-ui-fact.d.ts +49 -25
  102. package/types/joanroucoux-cairn-ui-field.d.ts +72 -49
  103. package/types/joanroucoux-cairn-ui-filter-chips.d.ts +35 -20
  104. package/types/joanroucoux-cairn-ui-group-header.d.ts +58 -0
  105. package/types/joanroucoux-cairn-ui-input.d.ts +59 -37
  106. package/types/joanroucoux-cairn-ui-line-chart.d.ts +199 -89
  107. package/types/joanroucoux-cairn-ui-menu.d.ts +81 -44
  108. package/types/joanroucoux-cairn-ui-meter.d.ts +44 -22
  109. package/types/joanroucoux-cairn-ui-motion.d.ts +61 -75
  110. package/types/joanroucoux-cairn-ui-nav-item.d.ts +15 -13
  111. package/types/joanroucoux-cairn-ui-result-group.d.ts +52 -0
  112. package/types/joanroucoux-cairn-ui-row.d.ts +92 -37
  113. package/types/joanroucoux-cairn-ui-segmented.d.ts +51 -27
  114. package/types/joanroucoux-cairn-ui-select-pill.d.ts +59 -0
  115. package/types/joanroucoux-cairn-ui-select.d.ts +28 -18
  116. package/types/joanroucoux-cairn-ui-skeleton.d.ts +35 -18
  117. package/types/joanroucoux-cairn-ui-stale-link.d.ts +23 -16
  118. package/types/joanroucoux-cairn-ui-stat.d.ts +26 -21
  119. package/types/joanroucoux-cairn-ui-switch.d.ts +7 -11
  120. package/types/joanroucoux-cairn-ui-tab-bar.d.ts +20 -17
  121. package/types/joanroucoux-cairn-ui-table.d.ts +251 -89
  122. package/types/joanroucoux-cairn-ui-toast.d.ts +46 -36
  123. package/types/joanroucoux-cairn-ui.d.ts +1 -2
  124. package/fesm2022/joanroucoux-cairn-ui.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"joanroucoux-cairn-ui-motion.mjs","sources":["../../../projects/ui/motion/internal/flip-items.ts","../../../projects/ui/motion/internal/tokens.ts","../../../projects/ui/motion/reduced-motion.ts","../../../projects/ui/motion/flip-list.ts","../../../projects/ui/motion/highlight.ts","../../../projects/ui/motion/settle-transitions.ts","../../../projects/ui/motion/joanroucoux-cairn-ui-motion.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\n@Injectable()\nexport class FlipItems {\n private readonly items = new Set<HTMLElement>();\n private readonly destroyed = new Set<HTMLElement>();\n private used = false;\n\n get marked(): boolean {\n return this.used;\n }\n\n add(item: HTMLElement): void {\n this.used = true;\n this.items.add(item);\n }\n\n remove(item: HTMLElement): void {\n this.destroyed.add(item);\n }\n\n inside(host: HTMLElement): HTMLElement[] {\n const inside: HTMLElement[] = [];\n for (const item of this.items) {\n if (host.contains(item)) {\n inside.push(item);\n } else if (this.destroyed.has(item)) {\n this.items.delete(item);\n this.destroyed.delete(item);\n }\n }\n return inside;\n }\n}\n","export function readDuration(element: Element, name: string, fallback: number): number {\n const raw = getComputedStyle(element).getPropertyValue(name).trim();\n const value = parseFloat(raw);\n if (Number.isNaN(value)) {\n return fallback;\n }\n return raw.endsWith('ms') ? value : value * 1000;\n}\n\nexport function readEasing(element: Element, name: string, fallback: string): string {\n return getComputedStyle(element).getPropertyValue(name).trim() || fallback;\n}\n","import { DestroyRef, type Signal, inject, signal } from '@angular/core';\n\nconst QUERY = '(prefers-reduced-motion: reduce)';\n\n/**\n * A signal that follows the user's `prefers-reduced-motion` preference live.\n * Call it in an injection context; the listener is removed with that context.\n *\n * @example\n * protected readonly reduced = injectReducedMotion();\n */\nexport function injectReducedMotion(): Signal<boolean> {\n if (typeof matchMedia === 'undefined') {\n return signal(false).asReadonly();\n }\n\n const query = matchMedia(QUERY);\n const reduced = signal(query.matches);\n const listener = (event: { matches: boolean }): void => reduced.set(event.matches);\n\n query.addEventListener('change', listener);\n inject(DestroyRef).onDestroy(() => query.removeEventListener('change', listener));\n\n return reduced.asReadonly();\n}\n","import { DestroyRef, Directive, ElementRef, afterNextRender, inject } from '@angular/core';\n\nimport { FlipItems } from './internal/flip-items';\nimport { readDuration, readEasing } from './internal/tokens';\nimport { injectReducedMotion } from './reduced-motion';\n\nfunction translateY(element: Element): number {\n const matrix = /^matrix\\((.+)\\)$/.exec(getComputedStyle(element).transform);\n return matrix ? parseFloat((matrix[1] as string).split(',')[5] as string) : 0;\n}\n\n/**\n * Slides the items of a list into place when one is removed or inserted (FLIP): it measures every item\n * before and after the change, from the top of the list itself, then animates the shift in `translateY`\n * over `--duration-base` `--ease-out`. Pair it with `animate.leave=\"ui-leave-fade\"` on the item so it fades\n * out first. Nothing moves under `prefers-reduced-motion`: the list closes up at once.\n *\n * By default the items are the direct children of the list. Mark them with `uiFlipItem` instead when they\n * sit deeper, for instance a page of several groups: put `uiFlipList` on the element around every group and\n * `uiFlipItem` on each group heading and row, so a removal also slides the groups below. An item may sit\n * inside another item (a row inside a card): it then moves by its own share and its card carries the rest.\n * Only an item added or removed starts a slide; a change inside an item does not. Positions leave out the\n * translate of any animation running inside the list (a slide in progress, an enter fade-up).\n *\n * @example\n * <ul uiFlipList>\n * @for (key of keys(); track key.id) {\n * <li uiListRow animate.leave=\"ui-leave-fade\">...</li>\n * }\n * </ul>\n *\n * <table uiTable uiFlipList>\n * @for (group of groups(); track group.id) {\n * <tbody>\n * <tr uiTr group uiFlipItem>...</tr>\n * @for (row of group.rows; track row.id) {\n * <tr uiTr uiFlipItem animate.leave=\"ui-leave-fade\">...</tr>\n * }\n * </tbody>\n * }\n * </table>\n */\n@Directive({\n selector: '[uiFlipList]',\n providers: [FlipItems],\n})\nexport class UiFlipList {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly reduced = injectReducedMotion();\n private readonly mutations = new MutationObserver(() => this.onChange());\n private readonly resizes = new ResizeObserver(() => {\n this.tops = this.measure();\n });\n private readonly running = new Map<HTMLElement, Animation>();\n private readonly watched = new Set<HTMLElement>();\n private readonly items = inject(FlipItems, { self: true });\n private tops = new Map<HTMLElement, number>();\n private shifts = new Map<Element, number>();\n\n constructor() {\n afterNextRender(() => {\n this.tops = this.measure();\n this.mutations.observe(this.host, { childList: true, subtree: true });\n this.resizes.observe(this.host);\n });\n\n inject(DestroyRef).onDestroy(() => {\n this.mutations.disconnect();\n this.resizes.disconnect();\n });\n }\n\n private tracked(): HTMLElement[] {\n if (!this.items.marked) {\n return Array.from(this.host.children).filter((child): child is HTMLElement => child instanceof HTMLElement);\n }\n return this.items.inside(this.host);\n }\n\n private measure(): Map<HTMLElement, number> {\n const elements = this.tracked();\n const origin = this.host.getBoundingClientRect().top - this.host.scrollTop;\n const tops = new Map(elements.map((element) => [element, element.getBoundingClientRect().top - origin]));\n\n this.shifts = new Map();\n for (const animation of this.host.getAnimations({ subtree: true })) {\n const target = (animation.effect as KeyframeEffect).target as Element;\n if (target !== this.host) {\n this.shifts.set(target, translateY(target));\n }\n }\n for (const [moving, shift] of this.shifts) {\n for (const [element, top] of tops) {\n if (moving.contains(element)) {\n tops.set(element, top - shift);\n }\n }\n }\n\n for (const element of elements) {\n if (!this.watched.has(element)) {\n this.watched.add(element);\n this.resizes.observe(element);\n }\n }\n for (const element of this.watched) {\n if (!tops.has(element)) {\n this.watched.delete(element);\n this.running.delete(element);\n this.resizes.unobserve(element);\n }\n }\n return tops;\n }\n\n private onChange(): void {\n const before = this.tops;\n const after = this.measure();\n this.tops = after;\n\n const changed = after.size !== before.size || Array.from(after.keys()).some((element) => !before.has(element));\n if (this.reduced() || !changed) {\n return;\n }\n\n const duration = readDuration(this.host, '--duration-base', 260);\n const easing = readEasing(this.host, '--ease-out', 'ease-out');\n const moved = (element: HTMLElement): number => (before.get(element) ?? 0) - (after.get(element) ?? 0);\n\n for (const [element] of after) {\n if (!before.has(element)) {\n continue;\n }\n const own = moved(element) - moved(this.parentItem(element, before, after));\n if (Math.abs(own) < 0.5) {\n continue;\n }\n const from = own + (this.shifts.get(element) ?? 0);\n this.running.get(element)?.cancel();\n const animation = element.animate([{ transform: `translateY(${from}px)` }, { transform: 'translateY(0)' }], {\n duration,\n easing,\n });\n animation.onfinish = () => {\n if (this.running.get(element) === animation) {\n this.running.delete(element);\n }\n };\n this.running.set(element, animation);\n }\n }\n\n private parentItem(\n element: HTMLElement,\n before: Map<HTMLElement, number>,\n after: Map<HTMLElement, number>,\n ): HTMLElement {\n let node = element.parentElement as HTMLElement;\n while (node !== this.host && !(before.has(node) && after.has(node))) {\n node = node.parentElement as HTMLElement;\n }\n return node;\n }\n}\n\n/**\n * Marks an element as an item of the nearest `uiFlipList`, at any depth: a group heading, a row inside a\n * group, a card. Once one item is marked, the list follows its marked items only.\n *\n * @example\n * <tr uiTr uiFlipItem animate.leave=\"ui-leave-fade\">...</tr>\n */\n@Directive({\n selector: '[uiFlipItem]',\n})\nexport class UiFlipItem {\n constructor() {\n const items = inject(FlipItems, { optional: true });\n if (items) {\n const element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n items.add(element);\n inject(DestroyRef).onDestroy(() => items.remove(element));\n }\n }\n}\n","import { DestroyRef, Directive, ElementRef, effect, inject, input, untracked } from '@angular/core';\n\nimport { readDuration, readEasing } from './internal/tokens';\nimport { injectReducedMotion } from './reduced-motion';\n\nconst HOLD_MS = 200;\nconst SCROLL_SETTLE_MS = 200;\nconst SCROLL_START_MS = 300;\n\nfunction paintedElements(host: HTMLElement): HTMLElement[] {\n if (host.tagName === 'TR') {\n return Array.from(host.children).filter((cell): cell is HTMLElement => cell instanceof HTMLElement);\n }\n if (host.hasAttribute('ui-group-cell') && host.firstElementChild instanceof HTMLElement) {\n return [host.firstElementChild];\n }\n return [host];\n}\n\n/**\n * Draws the eye to an element that just changed: scrolls it into view when it is off screen, holds the\n * `--soft` fill for 200 ms, then fades back to the element's own background over `--duration-highlight`.\n * Each new non-null token plays once, so pass a fresh value per event (an object or a counter), not a\n * boolean. A non-null token already present at first render plays on arrival. On a `tr` it paints the\n * cells, on a `td[ui-group-cell]` the band, anywhere else the host. Under `prefers-reduced-motion` the\n * scroll is instant and the fade lasts 600 ms.\n *\n * It starts on the next frame and, when the element is still playing a finite animation of its own (an\n * `animate.enter` fade on a new row), once that animation has finished, waiting no longer than\n * `--duration-base`: the element fades in, then lights up. Both can sit on the same element.\n *\n * Give the element `scroll-margin-top` and `scroll-margin-bottom` equal to what is pinned above and\n * below it (header, tab bar, action bar): a row under them counts as off screen and is scrolled out.\n * For an arrival on a page opened at the element, scroll to it at once first (`scrollIntoView` in\n * `afterNextRender`) and set the token afterwards: a token present at first render scrolls smoothly\n * from where the page is.\n *\n * @example\n * <a ui-row [uiHighlight]=\"changed() === holding.id ? token() : null\" routerLink=\"/holdings/1\">...</a>\n */\n@Directive({\n selector: '[uiHighlight]',\n})\nexport class UiHighlight {\n readonly uiHighlight = input<unknown>(null);\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly reduced = injectReducedMotion();\n private cancel: (() => void) | null = null;\n\n constructor() {\n effect(() => {\n const token = this.uiHighlight();\n if (token === null || token === undefined) {\n return;\n }\n untracked(() => this.play());\n });\n\n inject(DestroyRef).onDestroy(() => this.cancel?.());\n }\n\n private play(): void {\n this.cancel?.();\n\n if (this.isVisible()) {\n this.cancel = this.flash();\n return;\n }\n\n const reduced = this.reduced();\n this.host.scrollIntoView({ behavior: reduced ? 'auto' : 'smooth', block: 'center' });\n\n if (reduced) {\n this.cancel = this.flash();\n return;\n }\n\n let stopFlash: (() => void) | null = null;\n let timer: ReturnType<typeof setTimeout>;\n const moves = (event: Event): boolean =>\n event.target === document || (event.target instanceof Node && event.target.contains(this.host));\n const start = (): void => {\n stopListening();\n stopFlash = this.flash();\n };\n const onScrollEnd = (event: Event): void => {\n if (moves(event)) {\n start();\n }\n };\n const onScroll = (event: Event): void => {\n if (moves(event)) {\n clearTimeout(timer);\n timer = setTimeout(start, SCROLL_SETTLE_MS);\n }\n };\n const stopListening = (): void => {\n clearTimeout(timer);\n window.removeEventListener('scrollend', onScrollEnd, true);\n window.removeEventListener('scroll', onScroll, true);\n };\n timer = setTimeout(start, SCROLL_START_MS);\n window.addEventListener('scrollend', onScrollEnd, true);\n window.addEventListener('scroll', onScroll, true);\n\n this.cancel = () => {\n stopListening();\n stopFlash?.();\n };\n }\n\n private isVisible(): boolean {\n const rect = this.host.getBoundingClientRect();\n const style = getComputedStyle(this.host);\n const top = parseFloat(style.scrollMarginTop) || 0;\n const bottom = parseFloat(style.scrollMarginBottom) || 0;\n return rect.top >= top && rect.bottom <= window.innerHeight - bottom;\n }\n\n private flash(): () => void {\n const painted = paintedElements(this.host);\n let animations: Animation[] = [];\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const paint = (): void => {\n const fade = readDuration(this.host, '--duration-highlight', 1200);\n const easing = readEasing(this.host, '--ease-out', 'ease-out');\n const total = HOLD_MS + fade;\n animations = painted.map((element) =>\n element.animate(\n [\n { backgroundColor: 'var(--soft)', offset: 0 },\n { backgroundColor: 'var(--soft)', offset: HOLD_MS / total, easing },\n { offset: 1 },\n ],\n { duration: total },\n ),\n );\n };\n\n const frame = requestAnimationFrame(() => {\n const remaining = Array.from(new Set([this.host, ...painted]))\n .flatMap((element) => element.getAnimations())\n .map((animation) => {\n const timing = (animation.effect as AnimationEffect).getComputedTiming();\n return Number(timing.endTime) - Number(timing.localTime ?? 0);\n })\n .filter((left) => Number.isFinite(left));\n if (remaining.length === 0) {\n paint();\n return;\n }\n timer = setTimeout(paint, Math.min(Math.max(...remaining), readDuration(this.host, '--duration-base', 260)));\n });\n\n return () => {\n cancelAnimationFrame(frame);\n clearTimeout(timer);\n animations.forEach((animation) => animation.cancel());\n };\n }\n}\n","import { ElementRef, afterNextRender, inject } from '@angular/core';\n\n/**\n * Holds the transitions of the host and of everything inside it until two frames after its first\n * render, through the `data-ui-settling` attribute and the matching rule of `styles/motion.css`.\n * A route's elements are created a tick before their classes are bound; a layout read in between\n * would otherwise turn the bound fill, colour or switch track into a transition on page open. Call it\n * in an injection context. A host whose view is never refreshed (a detached change detector) keeps the\n * attribute, and with it no transition.\n *\n * @example\n * constructor() {\n * holdTransitionsUntilRendered();\n * }\n */\nexport function holdTransitionsUntilRendered(): void {\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n host.setAttribute('data-ui-settling', '');\n afterNextRender({\n read: () => {\n requestAnimationFrame(() => requestAnimationFrame(() => host.removeAttribute('data-ui-settling')));\n },\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"joanroucoux-cairn-ui-motion.mjs","names":[],"sources":["../../../projects/ui/motion/internal/flip-items.ts","../../../projects/ui/motion/internal/tokens.ts","../../../projects/ui/motion/reduced-motion.ts","../../../projects/ui/motion/flip-list.ts","../../../projects/ui/motion/highlight.ts","../../../projects/ui/motion/settle-transitions.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\n@Injectable()\nexport class FlipItems {\n private readonly items = new Set<HTMLElement>();\n private readonly destroyed = new Set<HTMLElement>();\n private used = false;\n\n get marked(): boolean {\n return this.used;\n }\n\n add(item: HTMLElement): void {\n this.used = true;\n this.items.add(item);\n }\n\n remove(item: HTMLElement): void {\n this.destroyed.add(item);\n }\n\n inside(host: HTMLElement): HTMLElement[] {\n const inside: HTMLElement[] = [];\n for (const item of this.items) {\n if (host.contains(item)) {\n inside.push(item);\n } else if (this.destroyed.has(item)) {\n this.items.delete(item);\n this.destroyed.delete(item);\n }\n }\n return inside;\n }\n}\n","export function readDuration(element: Element, name: string, fallback: number): number {\n const raw = getComputedStyle(element).getPropertyValue(name).trim();\n const value = parseFloat(raw);\n if (Number.isNaN(value)) {\n return fallback;\n }\n return raw.endsWith('ms') ? value : value * 1000;\n}\n\nexport function readEasing(element: Element, name: string, fallback: string): string {\n return getComputedStyle(element).getPropertyValue(name).trim() || fallback;\n}\n","import { DestroyRef, type Signal, inject, signal } from '@angular/core';\n\nconst QUERY = '(prefers-reduced-motion: reduce)';\n\n/**\n * A signal that follows the user's `prefers-reduced-motion` preference. Call it in an injection\n * context.\n *\n * @example\n * protected readonly reduced = injectReducedMotion();\n */\nexport function injectReducedMotion(): Signal<boolean> {\n if (typeof matchMedia === 'undefined') {\n return signal(false).asReadonly();\n }\n\n const query = matchMedia(QUERY);\n const reduced = signal(query.matches);\n const listener = (event: { matches: boolean }): void => reduced.set(event.matches);\n\n query.addEventListener('change', listener);\n inject(DestroyRef).onDestroy(() => query.removeEventListener('change', listener));\n\n return reduced.asReadonly();\n}\n","import { DestroyRef, Directive, ElementRef, afterNextRender, inject } from '@angular/core';\n\nimport { FlipItems } from './internal/flip-items';\nimport { readDuration, readEasing } from './internal/tokens';\nimport { injectReducedMotion } from './reduced-motion';\n\nfunction translateY(element: Element): number {\n const matrix = /^matrix\\((.+)\\)$/.exec(getComputedStyle(element).transform);\n return matrix ? parseFloat((matrix[1] as string).split(',')[5] as string) : 0;\n}\n\n/**\n * Slides the items of a list into place when one is removed or inserted (FLIP). Pair it with\n * `animate.leave=\"ui-leave-fade\"` on the item so it fades out first. Nothing moves under\n * `prefers-reduced-motion`.\n *\n * The items are the direct children of the list. Mark them with `uiFlipItem` instead when they sit\n * deeper, so a removal also slides the groups below. Only an item added or removed starts a slide;\n * a change inside an item does not.\n *\n * @example\n * <ul uiFlipList>\n * @for (key of keys(); track key.id) {\n * <li uiListRow animate.leave=\"ui-leave-fade\">...</li>\n * }\n * </ul>\n *\n * <table uiTable uiFlipList>\n * @for (group of groups(); track group.id) {\n * <tbody>\n * <tr uiTr group uiFlipItem>...</tr>\n * @for (row of group.rows; track row.id) {\n * <tr uiTr uiFlipItem animate.leave=\"ui-leave-fade\">...</tr>\n * }\n * </tbody>\n * }\n * </table>\n */\n@Directive({\n selector: '[uiFlipList]',\n providers: [FlipItems],\n})\nexport class UiFlipList {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly reduced = injectReducedMotion();\n private readonly mutations = new MutationObserver(() => this.onChange());\n private readonly resizes = new ResizeObserver(() => {\n this.tops = this.measure();\n });\n private readonly running = new Map<HTMLElement, Animation>();\n private readonly watched = new Set<HTMLElement>();\n private readonly items = inject(FlipItems, { self: true });\n private tops = new Map<HTMLElement, number>();\n private shifts = new Map<Element, number>();\n\n constructor() {\n afterNextRender(() => {\n this.tops = this.measure();\n this.mutations.observe(this.host, { childList: true, subtree: true });\n this.resizes.observe(this.host);\n });\n\n inject(DestroyRef).onDestroy(() => {\n this.mutations.disconnect();\n this.resizes.disconnect();\n });\n }\n\n private tracked(): HTMLElement[] {\n if (!this.items.marked) {\n return Array.from(this.host.children).filter((child): child is HTMLElement => child instanceof HTMLElement);\n }\n return this.items.inside(this.host);\n }\n\n private measure(): Map<HTMLElement, number> {\n const elements = this.tracked();\n const origin = this.host.getBoundingClientRect().top - this.host.scrollTop;\n const tops = new Map(elements.map((element) => [element, element.getBoundingClientRect().top - origin]));\n\n this.shifts = new Map();\n for (const animation of this.host.getAnimations({ subtree: true })) {\n const target = (animation.effect as KeyframeEffect).target as Element;\n if (target !== this.host) {\n this.shifts.set(target, translateY(target));\n }\n }\n for (const [moving, shift] of this.shifts) {\n for (const [element, top] of tops) {\n if (moving.contains(element)) {\n tops.set(element, top - shift);\n }\n }\n }\n\n for (const element of elements) {\n if (!this.watched.has(element)) {\n this.watched.add(element);\n this.resizes.observe(element);\n }\n }\n for (const element of this.watched) {\n if (!tops.has(element)) {\n this.watched.delete(element);\n this.running.delete(element);\n this.resizes.unobserve(element);\n }\n }\n return tops;\n }\n\n private onChange(): void {\n const before = this.tops;\n const after = this.measure();\n this.tops = after;\n\n const changed = after.size !== before.size || Array.from(after.keys()).some((element) => !before.has(element));\n if (this.reduced() || !changed) {\n return;\n }\n\n const duration = readDuration(this.host, '--duration-base', 260);\n const easing = readEasing(this.host, '--ease-out', 'ease-out');\n const moved = (element: HTMLElement): number => (before.get(element) ?? 0) - (after.get(element) ?? 0);\n\n for (const [element] of after) {\n if (!before.has(element)) {\n continue;\n }\n const own = moved(element) - moved(this.parentItem(element, before, after));\n if (Math.abs(own) < 0.5) {\n continue;\n }\n const from = own + (this.shifts.get(element) ?? 0);\n this.running.get(element)?.cancel();\n const animation = element.animate([{ transform: `translateY(${from}px)` }, { transform: 'translateY(0)' }], {\n duration,\n easing,\n });\n animation.onfinish = () => {\n if (this.running.get(element) === animation) {\n this.running.delete(element);\n }\n };\n this.running.set(element, animation);\n }\n }\n\n private parentItem(\n element: HTMLElement,\n before: Map<HTMLElement, number>,\n after: Map<HTMLElement, number>,\n ): HTMLElement {\n let node = element.parentElement as HTMLElement;\n while (node !== this.host && !(before.has(node) && after.has(node))) {\n node = node.parentElement as HTMLElement;\n }\n return node;\n }\n}\n\n/**\n * Marks an element as an item of the nearest `uiFlipList`, at any depth. Once one item is marked,\n * the list follows its marked items only.\n *\n * @example\n * <tr uiTr uiFlipItem animate.leave=\"ui-leave-fade\">...</tr>\n */\n@Directive({\n selector: '[uiFlipItem]',\n})\nexport class UiFlipItem {\n constructor() {\n const items = inject(FlipItems, { optional: true });\n if (items) {\n const element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n items.add(element);\n inject(DestroyRef).onDestroy(() => items.remove(element));\n }\n }\n}\n","import { DestroyRef, Directive, ElementRef, effect, inject, input, untracked } from '@angular/core';\n\nimport { readDuration, readEasing } from './internal/tokens';\nimport { injectReducedMotion } from './reduced-motion';\n\nconst HOLD_MS = 200;\nconst SCROLL_SETTLE_MS = 200;\nconst SCROLL_START_MS = 300;\n\nfunction paintedElements(host: HTMLElement): HTMLElement[] {\n if (host.tagName === 'TR') {\n return Array.from(host.children).filter((cell): cell is HTMLElement => cell instanceof HTMLElement);\n }\n if (host.hasAttribute('ui-group-cell') && host.firstElementChild instanceof HTMLElement) {\n return [host.firstElementChild];\n }\n return [host];\n}\n\n/**\n * Draws the eye to an element that just changed: scrolls it into view when off screen, flashes the\n * `--soft` fill, then fades back. Each new non-null token plays once, so pass a fresh value per\n * event (an object or a counter), not a boolean. A non-null token present at first render plays on\n * arrival. Can sit on the same element as `animate.enter`: it waits for that fade to finish.\n *\n * Give the element `scroll-margin-top` and `scroll-margin-bottom` equal to what is pinned above and\n * below it (header, tab bar, action bar), or a row under them counts as on screen. For an arrival\n * on a page opened at the element, scroll to it first (`scrollIntoView` in `afterNextRender`) and\n * set the token afterwards, otherwise it scrolls smoothly from where the page is.\n *\n * @example\n * <a ui-row [uiHighlight]=\"changed() === holding.id ? token() : null\" routerLink=\"/holdings/1\">...</a>\n */\n@Directive({\n selector: '[uiHighlight]',\n})\nexport class UiHighlight {\n readonly uiHighlight = input<unknown>(null);\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private readonly reduced = injectReducedMotion();\n private cancel: (() => void) | null = null;\n\n constructor() {\n effect(() => {\n const token = this.uiHighlight();\n if (token === null || token === undefined) {\n return;\n }\n untracked(() => this.play());\n });\n\n inject(DestroyRef).onDestroy(() => this.cancel?.());\n }\n\n private play(): void {\n this.cancel?.();\n\n if (this.isVisible()) {\n this.cancel = this.flash();\n return;\n }\n\n const reduced = this.reduced();\n this.host.scrollIntoView({ behavior: reduced ? 'auto' : 'smooth', block: 'center' });\n\n if (reduced) {\n this.cancel = this.flash();\n return;\n }\n\n let stopFlash: (() => void) | null = null;\n let timer: ReturnType<typeof setTimeout>;\n const moves = (event: Event): boolean =>\n event.target === document || (event.target instanceof Node && event.target.contains(this.host));\n const start = (): void => {\n stopListening();\n stopFlash = this.flash();\n };\n const onScrollEnd = (event: Event): void => {\n if (moves(event)) {\n start();\n }\n };\n const onScroll = (event: Event): void => {\n if (moves(event)) {\n clearTimeout(timer);\n timer = setTimeout(start, SCROLL_SETTLE_MS);\n }\n };\n const stopListening = (): void => {\n clearTimeout(timer);\n window.removeEventListener('scrollend', onScrollEnd, true);\n window.removeEventListener('scroll', onScroll, true);\n };\n timer = setTimeout(start, SCROLL_START_MS);\n window.addEventListener('scrollend', onScrollEnd, true);\n window.addEventListener('scroll', onScroll, true);\n\n this.cancel = () => {\n stopListening();\n stopFlash?.();\n };\n }\n\n private isVisible(): boolean {\n const rect = this.host.getBoundingClientRect();\n const style = getComputedStyle(this.host);\n const top = parseFloat(style.scrollMarginTop) || 0;\n const bottom = parseFloat(style.scrollMarginBottom) || 0;\n return rect.top >= top && rect.bottom <= window.innerHeight - bottom;\n }\n\n private flash(): () => void {\n const painted = paintedElements(this.host);\n let animations: Animation[] = [];\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const paint = (): void => {\n const fade = readDuration(this.host, '--duration-highlight', 1200);\n const easing = readEasing(this.host, '--ease-out', 'ease-out');\n const total = HOLD_MS + fade;\n animations = painted.map((element) =>\n element.animate(\n [\n { backgroundColor: 'var(--soft)', offset: 0 },\n { backgroundColor: 'var(--soft)', offset: HOLD_MS / total, easing },\n { offset: 1 },\n ],\n { duration: total },\n ),\n );\n };\n\n const frame = requestAnimationFrame(() => {\n const remaining = Array.from(new Set([this.host, ...painted]))\n .flatMap((element) => element.getAnimations())\n .map((animation) => {\n const timing = (animation.effect as AnimationEffect).getComputedTiming();\n return Number(timing.endTime) - Number(timing.localTime ?? 0);\n })\n .filter((left) => Number.isFinite(left));\n if (remaining.length === 0) {\n paint();\n return;\n }\n timer = setTimeout(paint, Math.min(Math.max(...remaining), readDuration(this.host, '--duration-base', 260)));\n });\n\n return () => {\n cancelAnimationFrame(frame);\n clearTimeout(timer);\n animations.forEach((animation) => animation.cancel());\n };\n }\n}\n","import { ElementRef, afterNextRender, inject } from '@angular/core';\n\n/**\n * Holds the transitions of the host and of everything inside it until two frames after its first\n * render, so bound classes do not animate on page open. Call it in an injection context. A host\n * whose view is never refreshed (a detached change detector) never gets its transitions back.\n *\n * @example\n * constructor() {\n * holdTransitionsUntilRendered();\n * }\n */\nexport function holdTransitionsUntilRendered(): void {\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n host.setAttribute('data-ui-settling', '');\n afterNextRender({\n read: () => {\n requestAnimationFrame(() => requestAnimationFrame(() => host.removeAttribute('data-ui-settling')));\n },\n });\n}\n"],"mappings":"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"}
@@ -1,45 +1,74 @@
1
- import * as i0 from '@angular/core';
2
- import { input, booleanAttribute, computed, Component } from '@angular/core';
3
- import { holdTransitionsUntilRendered } from '@joanroucoux/cairn-ui/motion';
4
-
5
- const BASE_CLASSES = 'flex items-center gap-3 h-10 px-3 rounded-control text-label leading-normal font-medium transition-[scale,background-color] [transition-duration:var(--duration-press),var(--duration-fast)] ease-out active:scale-(--press-scale) hover:bg-(--glow) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
6
- const ACTIVE_CLASSES = 'bg-[image:linear-gradient(var(--soft),var(--soft))] text-(--foreground)';
7
- const IDLE_CLASSES = 'text-(--muted-foreground) active:bg-(--soft)';
8
- /**
9
- * One destination of the sidebar navigation (Portfolio, Holdings, Allocation, Accounts). The active
10
- * fill and text colour switch at once on navigation; only the hover fill fades.
11
- *
12
- * @example
13
- * <a ui-nav-item [active]="url === '/'" routerLink="/">
14
- * <lucide-icon navIcon name="house" />
15
- * Portfolio
16
- * </a>
17
- */
18
- class UiNavItem {
19
- active = input(false, { ...(ngDevMode ? { debugName: "active" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
20
- classes = computed(() => `${BASE_CLASSES} ${this.active() ? ACTIVE_CLASSES : IDLE_CLASSES}`, /* @ts-ignore */
21
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
22
- constructor() {
23
- holdTransitionsUntilRendered();
24
- }
25
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiNavItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
26
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiNavItem, isStandalone: true, selector: "a[ui-nav-item]", inputs: { active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-current": "active() ? 'page' : null" } }, ngImport: i0, template: '<ng-content select="[navIcon]" /><ng-content />', isInline: true });
27
- }
28
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiNavItem, decorators: [{
29
- type: Component,
30
- args: [{
31
- selector: 'a[ui-nav-item]',
32
- template: '<ng-content select="[navIcon]" /><ng-content />',
33
- host: {
34
- '[class]': 'classes()',
35
- '[attr.aria-current]': "active() ? 'page' : null",
36
- },
37
- }]
38
- }], ctorParameters: () => [], propDecorators: { active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }] } });
39
-
40
- /**
41
- * Generated bundle index. Do not edit.
42
- */
43
-
1
+ import * as i0 from "@angular/core";
2
+ import { Component, booleanAttribute, computed, input } from "@angular/core";
3
+ import { holdTransitionsUntilRendered } from "@joanroucoux/cairn-ui/motion";
4
+ const BASE_CLASSES = "flex items-center gap-3 h-10 px-3 rounded-control text-label leading-normal font-medium transition-[scale,background-color] [transition-duration:var(--duration-press),var(--duration-fast)] ease-out active:scale-(--press-scale) hover:bg-(--glow) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)";
5
+ const ACTIVE_CLASSES = "bg-[image:linear-gradient(var(--soft),var(--soft))] text-(--foreground)";
6
+ const IDLE_CLASSES = "text-(--muted-foreground) active:bg-(--soft)";
7
+ var UiNavItem = class UiNavItem {
8
+ active = input(false, {
9
+ ...ngDevMode ? { debugName: "active" } : /* istanbul ignore next */ {},
10
+ transform: booleanAttribute
11
+ });
12
+ classes = computed(() => `${BASE_CLASSES} ${this.active() ? ACTIVE_CLASSES : IDLE_CLASSES}`, ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
13
+ constructor() {
14
+ holdTransitionsUntilRendered();
15
+ }
16
+ static ɵfac = i0.ɵɵngDeclareFactory({
17
+ minVersion: "12.0.0",
18
+ version: "22.2.0",
19
+ ngImport: i0,
20
+ type: UiNavItem,
21
+ deps: [],
22
+ target: i0.ɵɵFactoryTarget.Component
23
+ });
24
+ static ɵcmp = i0.ɵɵngDeclareComponent({
25
+ minVersion: "17.1.0",
26
+ version: "22.2.0",
27
+ type: UiNavItem,
28
+ isStandalone: true,
29
+ selector: "a[ui-nav-item]",
30
+ inputs: { active: {
31
+ classPropertyName: "active",
32
+ publicName: "active",
33
+ isSignal: true,
34
+ isRequired: false,
35
+ transformFunction: null
36
+ } },
37
+ host: { properties: {
38
+ "class": "classes()",
39
+ "attr.aria-current": "active() ? 'page' : null"
40
+ } },
41
+ ngImport: i0,
42
+ template: "<ng-content select=\"[navIcon]\" /><ng-content />",
43
+ isInline: true
44
+ });
45
+ };
46
+ i0.ɵɵngDeclareClassMetadata({
47
+ minVersion: "12.0.0",
48
+ version: "22.2.0",
49
+ ngImport: i0,
50
+ type: UiNavItem,
51
+ decorators: [{
52
+ type: Component,
53
+ args: [{
54
+ selector: "a[ui-nav-item]",
55
+ template: "<ng-content select=\"[navIcon]\" /><ng-content />",
56
+ host: {
57
+ "[class]": "classes()",
58
+ "[attr.aria-current]": "active() ? 'page' : null"
59
+ }
60
+ }]
61
+ }],
62
+ ctorParameters: () => [],
63
+ propDecorators: { active: [{
64
+ type: i0.Input,
65
+ args: [{
66
+ isSignal: true,
67
+ alias: "active",
68
+ required: false
69
+ }]
70
+ }] }
71
+ });
44
72
  export { UiNavItem };
45
- //# sourceMappingURL=joanroucoux-cairn-ui-nav-item.mjs.map
73
+
74
+ //# sourceMappingURL=joanroucoux-cairn-ui-nav-item.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"joanroucoux-cairn-ui-nav-item.mjs","sources":["../../../projects/ui/nav-item/nav-item.ts","../../../projects/ui/nav-item/joanroucoux-cairn-ui-nav-item.ts"],"sourcesContent":["import { Component, booleanAttribute, computed, input } from '@angular/core';\n\nimport { holdTransitionsUntilRendered } from '@joanroucoux/cairn-ui/motion';\n\nconst BASE_CLASSES =\n 'flex items-center gap-3 h-10 px-3 rounded-control text-label leading-normal font-medium transition-[scale,background-color] [transition-duration:var(--duration-press),var(--duration-fast)] ease-out active:scale-(--press-scale) hover:bg-(--glow) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';\n\nconst ACTIVE_CLASSES = 'bg-[image:linear-gradient(var(--soft),var(--soft))] text-(--foreground)';\n\nconst IDLE_CLASSES = 'text-(--muted-foreground) active:bg-(--soft)';\n\n/**\n * One destination of the sidebar navigation (Portfolio, Holdings, Allocation, Accounts). The active\n * fill and text colour switch at once on navigation; only the hover fill fades.\n *\n * @example\n * <a ui-nav-item [active]=\"url === '/'\" routerLink=\"/\">\n * <lucide-icon navIcon name=\"house\" />\n * Portfolio\n * </a>\n */\n@Component({\n selector: 'a[ui-nav-item]',\n template: '<ng-content select=\"[navIcon]\" /><ng-content />',\n host: {\n '[class]': 'classes()',\n '[attr.aria-current]': \"active() ? 'page' : null\",\n },\n})\nexport class UiNavItem {\n readonly active = input(false, { transform: booleanAttribute });\n\n protected readonly classes = computed(() => `${BASE_CLASSES} ${this.active() ? ACTIVE_CLASSES : IDLE_CLASSES}`);\n\n constructor() {\n holdTransitionsUntilRendered();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAIA,MAAM,YAAY,GAChB,uWAAuW;AAEzW,MAAM,cAAc,GAAG,yEAAyE;AAEhG,MAAM,YAAY,GAAG,8CAA8C;AAEnE;;;;;;;;;AASG;MASU,SAAS,CAAA;IACX,MAAM,GAAG,KAAK,CAAC,KAAK,8EAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;IAE5C,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,IAAI,CAAC,MAAM,EAAE,GAAG,cAAc,GAAG,YAAY,CAAA,CAAE;gFAAC;AAE/G,IAAA,WAAA,GAAA;AACE,QAAA,4BAA4B,EAAE;IAChC;uGAPW,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAT,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,SAAS,kTANV,iDAAiD,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAMhD,SAAS,EAAA,UAAA,EAAA,CAAA;kBARrB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,gBAAgB;AAC1B,oBAAA,QAAQ,EAAE,iDAAiD;AAC3D,oBAAA,IAAI,EAAE;AACJ,wBAAA,SAAS,EAAE,WAAW;AACtB,wBAAA,qBAAqB,EAAE,0BAA0B;AAClD,qBAAA;AACF,iBAAA;;;AC5BD;;AAEG;;;;"}
1
+ {"version":3,"file":"joanroucoux-cairn-ui-nav-item.mjs","names":[],"sources":["../../../projects/ui/nav-item/nav-item.ts"],"sourcesContent":["import { Component, booleanAttribute, computed, input } from '@angular/core';\n\nimport { holdTransitionsUntilRendered } from '@joanroucoux/cairn-ui/motion';\n\nconst BASE_CLASSES =\n 'flex items-center gap-3 h-10 px-3 rounded-control text-label leading-normal font-medium transition-[scale,background-color] [transition-duration:var(--duration-press),var(--duration-fast)] ease-out active:scale-(--press-scale) hover:bg-(--glow) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';\n\nconst ACTIVE_CLASSES = 'bg-[image:linear-gradient(var(--soft),var(--soft))] text-(--foreground)';\n\nconst IDLE_CLASSES = 'text-(--muted-foreground) active:bg-(--soft)';\n\n/**\n * One destination of the sidebar navigation.\n *\n * @example\n * <a ui-nav-item [active]=\"url === '/'\" routerLink=\"/\">\n * <lucide-icon navIcon name=\"house\" />\n * Portfolio\n * </a>\n */\n@Component({\n selector: 'a[ui-nav-item]',\n template: '<ng-content select=\"[navIcon]\" /><ng-content />',\n host: {\n '[class]': 'classes()',\n '[attr.aria-current]': \"active() ? 'page' : null\",\n },\n})\nexport class UiNavItem {\n readonly active = input(false, { transform: booleanAttribute });\n\n protected readonly classes = computed(() => `${BASE_CLASSES} ${this.active() ? ACTIVE_CLASSES : IDLE_CLASSES}`);\n\n constructor() {\n holdTransitionsUntilRendered();\n }\n}\n"],"mappings":";;;AAIA,MAAM,eACJ;AAEF,MAAM,iBAAiB;AAEvB,MAAM,eAAe;AAmBrB,IAAa,YAAb,MAAa,UAAS;CACX,SAAS,MAAM,OAAK;EAAA,GAAA,YAAA,EAAA,WAAA,SAAA,+BAAA,CAAA;EAAI,WAAW;CAAgB,CAAA;CAEzC,UAAU,eAAe,GAAG,aAAY,GAAI,KAAK,OAAM,IAAK,iBAAiB,gBAAe,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAE/G,cAAA;EACE,6BAA4B;CAC9B;CAPW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAS,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAT,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAS,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,QAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,MAAA,EAAA,YAAA;GAAA,SAAA;GAAA,qBAAA;EAAA,EAAA;EAAA,UAAA;EAAA,UANV;EAAiD,UAAA;CAAA,CAAA;;AAMhD,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAS,YAAA,CAAA;EARrB,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,UAAU;GACV,MAAM;IACJ,WAAW;IACX,uBAAuB;GACxB;EACF,CAAA"}
@@ -0,0 +1,191 @@
1
+ import * as i0 from "@angular/core";
2
+ import { Component, computed, input, output } from "@angular/core";
3
+ import { UiAsync } from "@joanroucoux/cairn-ui/async";
4
+ const PULSE_ANIMATION = "cairn-pulse var(--pulse-duration) var(--ease-out) infinite alternate";
5
+ const BAR_CLASSES = "block h-4 rounded-control bg-(--muted)";
6
+ var UiResultGroup = class UiResultGroup {
7
+ label = input.required(...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
8
+ hint = input(...ngDevMode ? [void 0, { debugName: "hint" }] : /* istanbul ignore next */ []);
9
+ state = input("ready", ...ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []);
10
+ errorMessage = input(...ngDevMode ? [void 0, { debugName: "errorMessage" }] : /* istanbul ignore next */ []);
11
+ retryLabel = input(...ngDevMode ? [void 0, { debugName: "retryLabel" }] : /* istanbul ignore next */ []);
12
+ retry = output();
13
+ name = computed(() => this.hint() ? `${this.label()}, ${this.hint()}` : this.label(), ...ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []);
14
+ animation = PULSE_ANIMATION;
15
+ static ɵfac = i0.ɵɵngDeclareFactory({
16
+ minVersion: "12.0.0",
17
+ version: "22.2.0",
18
+ ngImport: i0,
19
+ type: UiResultGroup,
20
+ deps: [],
21
+ target: i0.ɵɵFactoryTarget.Component
22
+ });
23
+ static ɵcmp = i0.ɵɵngDeclareComponent({
24
+ minVersion: "17.0.0",
25
+ version: "22.2.0",
26
+ type: UiResultGroup,
27
+ isStandalone: true,
28
+ selector: "ui-result-group",
29
+ inputs: {
30
+ label: {
31
+ classPropertyName: "label",
32
+ publicName: "label",
33
+ isSignal: true,
34
+ isRequired: true,
35
+ transformFunction: null
36
+ },
37
+ hint: {
38
+ classPropertyName: "hint",
39
+ publicName: "hint",
40
+ isSignal: true,
41
+ isRequired: false,
42
+ transformFunction: null
43
+ },
44
+ state: {
45
+ classPropertyName: "state",
46
+ publicName: "state",
47
+ isSignal: true,
48
+ isRequired: false,
49
+ transformFunction: null
50
+ },
51
+ errorMessage: {
52
+ classPropertyName: "errorMessage",
53
+ publicName: "errorMessage",
54
+ isSignal: true,
55
+ isRequired: false,
56
+ transformFunction: null
57
+ },
58
+ retryLabel: {
59
+ classPropertyName: "retryLabel",
60
+ publicName: "retryLabel",
61
+ isSignal: true,
62
+ isRequired: false,
63
+ transformFunction: null
64
+ }
65
+ },
66
+ outputs: { retry: "retry" },
67
+ host: {
68
+ attributes: { "role": "group" },
69
+ properties: { "attr.aria-label": "name()" },
70
+ classAttribute: "block"
71
+ },
72
+ ngImport: i0,
73
+ template: "\n <div class=\"text-caption flex items-baseline gap-1.5 pt-3 pr-2.5 pb-1 pl-2.5 tracking-(--tracking-caption)\">\n <span class=\"font-semibold text-(--foreground)\">{{ label() }}</span>\n @if (hint()) {\n <span class=\"text-(--subtle-foreground)\">{{ hint() }}</span>\n }\n </div>\n <ui-async\n variant=\"inline\"\n [errorMessage]=\"errorMessage()\"\n [retryIcon]=\"false\"\n [retryLabel]=\"retryLabel()\"\n [state]=\"state()\"\n (retry)=\"retry.emit()\"\n >\n <div asyncLoading class=\"flex flex-col gap-3.5 px-2.5 pt-2.5 pb-3\">\n <span class=\"flex justify-between\">\n <span class=\"block h-4 rounded-control bg-(--muted) w-50\" [style.animation]=\"animation\"></span>\n <span class=\"block h-4 rounded-control bg-(--muted) w-16\" [style.animation]=\"animation\"></span>\n </span>\n <span class=\"flex justify-between\">\n <span class=\"block h-4 rounded-control bg-(--muted) w-40\" [style.animation]=\"animation\"></span>\n <span class=\"block h-4 rounded-control bg-(--muted) w-16\" [style.animation]=\"animation\"></span>\n </span>\n </div>\n <div asyncEmpty class=\"text-label px-2.5 pt-1 pb-2.5 text-pretty text-(--muted-foreground) empty:hidden\">\n <ng-content select=\"[resultGroupMessage]\" />\n </div>\n <ng-content />\n </ui-async>\n ",
74
+ isInline: true,
75
+ dependencies: [{
76
+ kind: "component",
77
+ type: UiAsync,
78
+ selector: "ui-async",
79
+ inputs: [
80
+ "state",
81
+ "errorTitle",
82
+ "errorMessage",
83
+ "retryLabel",
84
+ "retryIcon",
85
+ "variant",
86
+ "align",
87
+ "card",
88
+ "fill"
89
+ ],
90
+ outputs: ["retry"]
91
+ }]
92
+ });
93
+ };
94
+ i0.ɵɵngDeclareClassMetadata({
95
+ minVersion: "12.0.0",
96
+ version: "22.2.0",
97
+ ngImport: i0,
98
+ type: UiResultGroup,
99
+ decorators: [{
100
+ type: Component,
101
+ args: [{
102
+ selector: "ui-result-group",
103
+ imports: [UiAsync],
104
+ template: `
105
+ <div class="text-caption flex items-baseline gap-1.5 pt-3 pr-2.5 pb-1 pl-2.5 tracking-(--tracking-caption)">
106
+ <span class="font-semibold text-(--foreground)">{{ label() }}</span>
107
+ @if (hint()) {
108
+ <span class="text-(--subtle-foreground)">{{ hint() }}</span>
109
+ }
110
+ </div>
111
+ <ui-async
112
+ variant="inline"
113
+ [errorMessage]="errorMessage()"
114
+ [retryIcon]="false"
115
+ [retryLabel]="retryLabel()"
116
+ [state]="state()"
117
+ (retry)="retry.emit()"
118
+ >
119
+ <div asyncLoading class="flex flex-col gap-3.5 px-2.5 pt-2.5 pb-3">
120
+ <span class="flex justify-between">
121
+ <span class="${BAR_CLASSES} w-50" [style.animation]="animation"></span>
122
+ <span class="${BAR_CLASSES} w-16" [style.animation]="animation"></span>
123
+ </span>
124
+ <span class="flex justify-between">
125
+ <span class="${BAR_CLASSES} w-40" [style.animation]="animation"></span>
126
+ <span class="${BAR_CLASSES} w-16" [style.animation]="animation"></span>
127
+ </span>
128
+ </div>
129
+ <div asyncEmpty class="text-label px-2.5 pt-1 pb-2.5 text-pretty text-(--muted-foreground) empty:hidden">
130
+ <ng-content select="[resultGroupMessage]" />
131
+ </div>
132
+ <ng-content />
133
+ </ui-async>
134
+ `,
135
+ host: {
136
+ class: "block",
137
+ role: "group",
138
+ "[attr.aria-label]": "name()"
139
+ }
140
+ }]
141
+ }],
142
+ propDecorators: {
143
+ label: [{
144
+ type: i0.Input,
145
+ args: [{
146
+ isSignal: true,
147
+ alias: "label",
148
+ required: true
149
+ }]
150
+ }],
151
+ hint: [{
152
+ type: i0.Input,
153
+ args: [{
154
+ isSignal: true,
155
+ alias: "hint",
156
+ required: false
157
+ }]
158
+ }],
159
+ state: [{
160
+ type: i0.Input,
161
+ args: [{
162
+ isSignal: true,
163
+ alias: "state",
164
+ required: false
165
+ }]
166
+ }],
167
+ errorMessage: [{
168
+ type: i0.Input,
169
+ args: [{
170
+ isSignal: true,
171
+ alias: "errorMessage",
172
+ required: false
173
+ }]
174
+ }],
175
+ retryLabel: [{
176
+ type: i0.Input,
177
+ args: [{
178
+ isSignal: true,
179
+ alias: "retryLabel",
180
+ required: false
181
+ }]
182
+ }],
183
+ retry: [{
184
+ type: i0.Output,
185
+ args: ["retry"]
186
+ }]
187
+ }
188
+ });
189
+ export { UiResultGroup };
190
+
191
+ //# sourceMappingURL=joanroucoux-cairn-ui-result-group.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"joanroucoux-cairn-ui-result-group.mjs","names":[],"sources":["../../../projects/ui/result-group/result-group.ts"],"sourcesContent":["import { Component, computed, input, output } from '@angular/core';\n\nimport { type AsyncState, UiAsync } from '@joanroucoux/cairn-ui/async';\n\nconst PULSE_ANIMATION = 'cairn-pulse var(--pulse-duration) var(--ease-out) infinite alternate';\n\nconst BAR_CLASSES = 'block h-4 rounded-control bg-(--muted)';\n\n/**\n * One source of a search: a two-tone heading, then its rows, or a skeleton while it answers, a\n * message when it has nothing, or an inline error with a retry.\n *\n * @example\n * <ui-result-group label=\"Yahoo Finance\" hint=\"cours en continu\" [state]=\"state()\"\n * errorMessage=\"Yahoo Finance n'a pas répondu.\" retryLabel=\"Réessayer\" (retry)=\"search()\">\n * <button ui-row size=\"dense\" type=\"button\">...</button>\n * <span resultGroupMessage>Aucun résultat chez Yahoo Finance.</span>\n * </ui-result-group>\n */\n@Component({\n selector: 'ui-result-group',\n imports: [UiAsync],\n template: `\n <div class=\"text-caption flex items-baseline gap-1.5 pt-3 pr-2.5 pb-1 pl-2.5 tracking-(--tracking-caption)\">\n <span class=\"font-semibold text-(--foreground)\">{{ label() }}</span>\n @if (hint()) {\n <span class=\"text-(--subtle-foreground)\">{{ hint() }}</span>\n }\n </div>\n <ui-async\n variant=\"inline\"\n [errorMessage]=\"errorMessage()\"\n [retryIcon]=\"false\"\n [retryLabel]=\"retryLabel()\"\n [state]=\"state()\"\n (retry)=\"retry.emit()\"\n >\n <div asyncLoading class=\"flex flex-col gap-3.5 px-2.5 pt-2.5 pb-3\">\n <span class=\"flex justify-between\">\n <span class=\"${BAR_CLASSES} w-50\" [style.animation]=\"animation\"></span>\n <span class=\"${BAR_CLASSES} w-16\" [style.animation]=\"animation\"></span>\n </span>\n <span class=\"flex justify-between\">\n <span class=\"${BAR_CLASSES} w-40\" [style.animation]=\"animation\"></span>\n <span class=\"${BAR_CLASSES} w-16\" [style.animation]=\"animation\"></span>\n </span>\n </div>\n <div asyncEmpty class=\"text-label px-2.5 pt-1 pb-2.5 text-pretty text-(--muted-foreground) empty:hidden\">\n <ng-content select=\"[resultGroupMessage]\" />\n </div>\n <ng-content />\n </ui-async>\n `,\n host: {\n class: 'block',\n role: 'group',\n '[attr.aria-label]': 'name()',\n },\n})\nexport class UiResultGroup {\n readonly label = input.required<string>();\n readonly hint = input<string>();\n readonly state = input<AsyncState>('ready');\n readonly errorMessage = input<string>();\n readonly retryLabel = input<string>();\n readonly retry = output<void>();\n\n protected readonly name = computed(() => (this.hint() ? `${this.label()}, ${this.hint()}` : this.label()));\n protected readonly animation = PULSE_ANIMATION;\n}\n"],"mappings":";;;AAIA,MAAM,kBAAkB;AAExB,MAAM,cAAc;AAqDpB,IAAa,gBAAb,MAAa,cAAa;CACf,QAAQ,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAChC,OAAO,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CACtB,QAAQ,MAAkB,SAAQ,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAClC,eAAe,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAC9B,aAAa,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAC5B,QAAQ,OAAM;CAEJ,OAAO,eAAgB,KAAK,KAAI,IAAK,GAAG,KAAK,MAAK,EAAE,IAAK,KAAK,KAAI,MAAO,KAAK,MAAK,GAAI,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CACvF,YAAY;CATpB,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAa,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAb,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAa,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,cAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,YAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA,EAAA,OAAA,QAAA;EAAA,MAAA;GAAA,YAAA,EAAA,QAAA,QAAA;GAAA,YAAA,EAAA,mBAAA,SAAA;GAAA,gBAAA;EAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MAtCd;GAAO,UAAA;GAAA,QAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;GAAA;GAAA,SAAA,CAAA,OAAA;EAAA,CAAA;CAAA,CAAA;;AAsCN,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAa,YAAA,CAAA;EAxCzB,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS,CAAC,OAAO;GACjB,UAAU;;;;;;;;;;;;;;;;;yBAiBa,YAAW;yBACX,YAAW;;;yBAGX,YAAW;yBACX,YAAW;;;;;;;;;GASlC,MAAM;IACJ,OAAO;IACP,MAAM;IACN,qBAAqB;GACtB;EACF,CAAA"}