@leavepulse/ui 0.71.1 → 0.71.2

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 (79) hide show
  1. package/dist/assets/{LpCommandPalette-DgPZX0us.css → LpCommandPalette-Rtbg669l.css} +19 -19
  2. package/dist/assets/{LpNumberFlow-rZkwQwlU.css → LpNumberFlow-Chp9pEDe.css} +8 -0
  3. package/dist/assets/LpTabs-DT0XPTc2.css +18 -0
  4. package/dist/chunks/{LpAddressInput-CD0bzrt-.js → LpAddressInput-Bu6ws3Fp.js} +1 -1
  5. package/dist/chunks/{LpAppShell-1RmBp6xQ.js → LpAppShell-C5YW5pI7.js} +1 -1
  6. package/dist/chunks/{LpCodeDisplay-BK2FHbtM.js → LpCodeDisplay-C9pIMF2R.js} +1 -1
  7. package/dist/chunks/{LpCommandScope-ubtWDMa0.js → LpCommandScope-BlKcgBnK.js} +1 -1
  8. package/dist/chunks/{LpCountdown-DTdMF8DL.js → LpCountdown-CXrEK0ev.js} +1 -1
  9. package/dist/chunks/{LpGauge-BdjPGnqw.js → LpGauge-DFdt33x8.js} +1 -1
  10. package/dist/chunks/{LpModalNav-BH4ANQGJ.js → LpModalNav-Cuna8c_3.js} +1 -1
  11. package/dist/chunks/{LpNumberFlow-5khYxsfX.js → LpNumberFlow-Dwb9MV1A.js} +6 -5
  12. package/dist/chunks/{LpPaletteTheme-CqWNRwHE.js → LpPaletteTheme-DkikZ362.js} +5 -3
  13. package/dist/chunks/{LpPie-DdFSTbGE.js → LpPie-C1uIUFxu.js} +1 -1
  14. package/dist/chunks/{LpProgress-BX33EKkN.js → LpProgress-WNaH4emv.js} +1 -1
  15. package/dist/chunks/{LpQuota-DqNv1yjs.js → LpQuota-Cz9PvklM.js} +1 -1
  16. package/dist/chunks/{LpSelect-DYX2-u5A.js → LpSelect-D3pRJfRY.js} +4 -4
  17. package/dist/chunks/{LpSidebar-D44peKq2.js → LpSidebar-Bk7b-K4l.js} +1 -1
  18. package/dist/chunks/{LpSidebarNav--VwkXO_a.js → LpSidebarNav-BR2AW3KT.js} +6 -1
  19. package/dist/chunks/{LpStat-DIsQfbeD.js → LpStat-Dzn6WFzi.js} +4 -4
  20. package/dist/chunks/{LpThemeStudio-B2nPaG-h.js → LpThemeStudio-IupHqP0x.js} +2 -2
  21. package/dist/chunks/{LpThemeSwitcher-C0A5sg_E.js → LpThemeSwitcher-DarPHuX8.js} +4 -3
  22. package/dist/chunks/{LpTopologyCanvas-B0wEvAoq.js → LpTopologyCanvas-Cq-MiJwo.js} +42 -12
  23. package/dist/chunks/{LpUptimeBar-DRadGq4Y.js → LpUptimeBar-BbhVTPnL.js} +1 -1
  24. package/dist/chunks/{palette-BiY7yQZL.js → palette-Cvxl_1tM.js} +1 -1
  25. package/dist/components/LpAddressInput.vue.js +1 -1
  26. package/dist/components/LpAppShell.vue.js +1 -1
  27. package/dist/components/LpChart.vue.js +22 -4
  28. package/dist/components/LpCodeDisplay.vue.js +1 -1
  29. package/dist/components/LpCommandPalette.vue.js +43 -22
  30. package/dist/components/LpCommandScope.vue.js +1 -1
  31. package/dist/components/LpCountdown.vue.js +1 -1
  32. package/dist/components/LpGauge.vue.js +1 -1
  33. package/dist/components/LpModalNav.vue.js +1 -1
  34. package/dist/components/LpNumberFlow.vue.js +1 -1
  35. package/dist/components/LpPaletteStats.vue.js +1 -1
  36. package/dist/components/LpPaletteTheme.vue.d.ts +2 -0
  37. package/dist/components/LpPaletteTheme.vue.js +1 -1
  38. package/dist/components/LpPie.vue.js +1 -1
  39. package/dist/components/LpProgress.vue.js +1 -1
  40. package/dist/components/LpQuota.vue.js +1 -1
  41. package/dist/components/LpSelect.vue.js +1 -1
  42. package/dist/components/LpSidebar.vue.js +1 -1
  43. package/dist/components/LpSidebarNav.vue.js +1 -1
  44. package/dist/components/LpStat.vue.js +1 -1
  45. package/dist/components/LpTabs.vue.d.ts +8 -0
  46. package/dist/components/LpTabs.vue.js +7 -5
  47. package/dist/components/LpThemeStudio.vue.js +1 -1
  48. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  49. package/dist/components/LpTopologyCanvas.vue.d.ts +3 -1
  50. package/dist/components/LpTopologyCanvas.vue.js +1 -1
  51. package/dist/components/LpUptimeBar.vue.js +1 -1
  52. package/dist/components/chart.d.ts +14 -0
  53. package/dist/components/chart.js +13 -0
  54. package/dist/components/format.d.ts +10 -3
  55. package/dist/components/format.js +14 -2
  56. package/dist/composables/usePaletteCommands.js +1 -0
  57. package/dist/composables/useReveal.js +1 -22
  58. package/dist/index.d.ts +1 -1
  59. package/dist/index.js +21 -20
  60. package/dist/theme/palette.d.ts +3 -0
  61. package/package.json +1 -1
  62. package/src/components/LpChart.vue +23 -3
  63. package/src/components/LpCommandPalette.vue +23 -5
  64. package/src/components/LpNumberFlow.vue +19 -7
  65. package/src/components/LpPaletteTheme.vue +3 -3
  66. package/src/components/LpSelect.vue +5 -4
  67. package/src/components/LpSidebarNav.vue +8 -1
  68. package/src/components/LpStat.vue +5 -3
  69. package/src/components/LpTabs.vue +10 -2
  70. package/src/components/LpThemeStudio.vue +1 -1
  71. package/src/components/LpThemeSwitcher.vue +4 -1
  72. package/src/components/LpTopologyCanvas.vue +35 -4
  73. package/src/components/chart.ts +26 -0
  74. package/src/components/format.ts +31 -5
  75. package/src/composables/usePaletteCommands.ts +3 -0
  76. package/src/composables/useReveal.ts +7 -30
  77. package/src/index.ts +1 -1
  78. package/src/theme/palette.ts +4 -2
  79. package/dist/assets/LpTabs-CO3EcsNV.css +0 -18
@@ -78,14 +78,39 @@ const COMPACT_UNITS: readonly (readonly [number, string])[] = [
78
78
  [1e12, "T"],
79
79
  ]
80
80
 
81
+ /*
82
+ * The unit word and the gap before it as the locale writes them: "тыс." with a
83
+ * no-break space in Russian, "K" glued on in English. Taken from Intl's compact
84
+ * notation rather than a table, so any locale reads its own.
85
+ */
86
+ const compactSuffixes = new Map<string, string>()
87
+
88
+ function compactSuffix(locale: string, step: number): string {
89
+ const key = `${locale}|${step}`
90
+ let found = compactSuffixes.get(key)
91
+ if (found === undefined) {
92
+ const parts = numberFormat(locale, { notation: "compact", compactDisplay: "short" }).formatToParts(COMPACT_UNITS[step][0])
93
+ const at = parts.findIndex((p) => p.type === "compact")
94
+ found = at < 0 ? COMPACT_UNITS[step][1] : (parts[at - 1]?.type === "literal" ? parts[at - 1].value : "") + parts[at].value
95
+ compactSuffixes.set(key, found)
96
+ }
97
+ return found
98
+ }
99
+
81
100
  export interface CompactNumberOptions {
82
101
  /**
83
102
  * Writes the decimal separator the locale's way ("1,2k" in Russian). The
84
103
  * k/M/B/T suffixes stay: Intl's own compact notation changes the shape of
85
- * the figure per locale ("1,2 тыс."), which a tick label or a rolling
86
- * counter cannot absorb. Unset keeps a plain "." whatever the browser says.
104
+ * the figure per locale ("1,2 тыс."), which a tick label cannot absorb.
105
+ * Unset keeps a plain "." whatever the browser says.
87
106
  */
88
107
  locale?: string
108
+ /**
109
+ * With a locale, write the unit as that locale does: "11,9 тыс." in Russian.
110
+ * For a figure read on its own (a stat tile, a counter), where "11,9k" looks
111
+ * foreign; not for axis ticks, where the longer word crowds the axis.
112
+ */
113
+ words?: boolean
89
114
  /** Places for a figure below a thousand (12.25). Default 2. */
90
115
  plainDecimals?: number
91
116
  /** Places once a unit is in play (1.2k). Default 1. */
@@ -98,7 +123,8 @@ export interface CompactNumberOptions {
98
123
  }
99
124
 
100
125
  /**
101
- * A figure shortened with k/M/B/T: 1 200 → "1.2k", 3 400 000 → "3.4M".
126
+ * A figure shortened with k/M/B/T: 1 200 → "1.2k", 3 400 000 → "3.4M"; with
127
+ * `words` and a locale in that locale's own words, "1,2 тыс." in Russian.
102
128
  *
103
129
  * The unit is picked by what will PRINT, not by the raw size: 999 950 at one
104
130
  * place rounds to "1000k", which reads as the next unit up, so it becomes
@@ -106,7 +132,7 @@ export interface CompactNumberOptions {
106
132
  */
107
133
  export function compactNumber(value: number, options: CompactNumberOptions = {}): string {
108
134
  if (!Number.isFinite(value)) return String(value)
109
- const { locale, plainDecimals = 2, decimals = 1, fixed = false } = options
135
+ const { locale, plainDecimals = 2, decimals = 1, fixed = false, words = false } = options
110
136
  const abs = Math.abs(value)
111
137
  let i = COMPACT_UNITS.length - 1
112
138
  while (i > 0 && abs < COMPACT_UNITS[i][0]) i--
@@ -132,7 +158,7 @@ export function compactNumber(value: number, options: CompactNumberOptions = {})
132
158
  maximumFractionDigits: places,
133
159
  useGrouping: false,
134
160
  }).format(scaled)
135
- return `${number}${COMPACT_UNITS[i][1]}`
161
+ return `${number}${words && locale !== undefined && i > 0 ? compactSuffix(locale, i) : COMPACT_UNITS[i][1]}`
136
162
  }
137
163
 
138
164
  /**
@@ -31,6 +31,9 @@ function numbered(entries: readonly PaletteRegistration[]): Command[] {
31
31
  for (const entry of entries) {
32
32
  for (const command of entry.commands()) {
33
33
  if (!entry.automatic) {
34
+ // Two mounts of one component (a header switcher and its phone twin)
35
+ // register the same command: it is one command, listed once.
36
+ if (manual.has(command.id)) continue
34
37
  manual.add(command.id)
35
38
  out.push(command)
36
39
  continue
@@ -1,6 +1,5 @@
1
1
  import { onBeforeUnmount, ref, toValue, watch, type MaybeRefOrGetter, type Ref } from "vue"
2
2
  import { prefersReducedMotion } from "./easing"
3
- import { atScrollEnd } from "./scroll"
4
3
 
5
4
  /*
6
5
  * "Has this element actually been SEEN yet?"
@@ -60,7 +59,13 @@ export interface UseReveal {
60
59
  }
61
60
 
62
61
  export function useReveal(options: UseRevealOptions = {}): UseReveal {
63
- const { threshold = 0.25, rootMargin = "0px 0px -10% 0px" } = options
62
+ /*
63
+ * No margin by default. Shrinking the viewport from below meant whatever sat
64
+ * in the bottom strip of the screen showed its starting state (a 0, an empty
65
+ * bar) while plainly on screen, which reads as "no data" rather than as an
66
+ * entrance yet to come; a quarter of the element in view is arrival enough.
67
+ */
68
+ const { threshold = 0.25, rootMargin = "0px" } = options
64
69
 
65
70
  const el = ref<Element | null>(null)
66
71
  // SSR has no viewport to intersect with, and no animation runs there either;
@@ -68,16 +73,10 @@ export function useReveal(options: UseRevealOptions = {}): UseReveal {
68
73
  const revealed = ref(typeof window === "undefined")
69
74
 
70
75
  let observer: IntersectionObserver | null = null
71
- let edge: IntersectionObserver | null = null
72
- let onScroll: (() => void) | null = null
73
76
 
74
77
  function stop() {
75
78
  observer?.disconnect()
76
79
  observer = null
77
- edge?.disconnect()
78
- edge = null
79
- if (onScroll) window.removeEventListener("scroll", onScroll, true)
80
- onScroll = null
81
80
  }
82
81
 
83
82
  function reveal() {
@@ -110,28 +109,6 @@ export function useReveal(options: UseRevealOptions = {}): UseReveal {
110
109
  { threshold, rootMargin },
111
110
  )
112
111
  observer.observe(node)
113
-
114
- /*
115
- * The margin shrinks the viewport from below, so the last element of a
116
- * page sits in that strip for good: there is no more scroll to lift it
117
- * out, and its count-up never started (a figure at the bottom of a
118
- * dashboard stayed at 0). On screen with nowhere left to scroll is an
119
- * arrival too.
120
- */
121
- let onScreen = false
122
- const check = () => {
123
- if (onScreen && atScrollEnd(node)) reveal()
124
- }
125
- edge = new IntersectionObserver(
126
- (entries) => {
127
- onScreen = entries.some((entry) => entry.isIntersecting)
128
- check()
129
- },
130
- { threshold },
131
- )
132
- edge.observe(node)
133
- onScroll = check
134
- window.addEventListener("scroll", onScroll, { capture: true, passive: true })
135
112
  },
136
113
  { immediate: true, flush: "post" },
137
114
  )
package/src/index.ts CHANGED
@@ -308,7 +308,7 @@ export type { RevealOrigin } from "./theme/useTheme"
308
308
  export { detectBackdropFilter, GLASS_BACKDROP_ATTR, isBrokenBackdropEngine, NO_BACKDROP_ATTR, setGlassBackdrop } from "./theme/backdrop"
309
309
  export { DEFAULT_SURFACE } from "./theme/tokens"
310
310
  export { defineTheme, withBrand } from "./theme/define"
311
- export { STUDIO_BRANDS, STUDIO_CORNERS, STUDIO_MOTION, STUDIO_SIZES, useThemeStudio } from "./theme/studio"
311
+ export { STUDIO_BRANDS, STUDIO_CORNERS, STUDIO_MOTION, STUDIO_SIZES, STUDIO_SYSTEM, useThemeStudio } from "./theme/studio"
312
312
  export type { StudioState, ThemeStudio, ThemeStudioOptions } from "./theme/studio"
313
313
  export type { ThemeOverrides } from "./theme/define"
314
314
  export type {
@@ -1,19 +1,21 @@
1
1
  import { defineAsyncComponent, defineComponent, h, toValue, type MaybeRefOrGetter } from "vue"
2
2
  import { usePaletteCommands, usePaletteScope, type PaletteScope } from "../composables/usePaletteCommands"
3
3
  import type { PreviewableThemeStudio, ThemeStudio } from "./studio"
4
+ import type { ThemeStudioPart } from "../components/LpThemeStudio.vue"
4
5
  import { useLabels } from "../composables/useLpConfig"
5
6
 
6
7
  const Editor = defineAsyncComponent(() => import("../components/LpPaletteTheme.vue"))
7
8
 
8
9
  /** Registers the studio itself; no second list of theme options in the app. */
9
- export function usePaletteTheme(studio: MaybeRefOrGetter<ThemeStudio | undefined>, options: { id?: string; label?: string; scope?: PaletteScope } = {}) {
10
+ /** `hide` leaves out the same studio rows the app hides in its own studio. */
11
+ export function usePaletteTheme(studio: MaybeRefOrGetter<ThemeStudio | undefined>, options: { id?: string; label?: string; scope?: PaletteScope; hide?: ThemeStudioPart[] } = {}) {
10
12
  const scope = options.scope ?? usePaletteScope()
11
13
  const text = useLabels("paletteTheme", { title: "Theme" })
12
14
  const currentStudio = () => {
13
15
  const current = toValue(studio)
14
16
  return current && "preview" in current && typeof current.preview === "function" ? current as PreviewableThemeStudio : undefined
15
17
  }
16
- const preview = defineComponent({ setup: () => () => currentStudio() ? h(Editor, { studio: currentStudio()! }) : null })
18
+ const preview = defineComponent({ setup: () => () => currentStudio() ? h(Editor, { studio: currentStudio()!, hide: options.hide }) : null })
17
19
  usePaletteCommands(() => {
18
20
  const current = currentStudio()
19
21
  if (!current) return []
@@ -1,18 +0,0 @@
1
-
2
- .lp-tab-badge-enter-active[data-v-2c920d5a],
3
- .lp-tab-badge-leave-active[data-v-2c920d5a] {
4
- transition:
5
- opacity var(--duration-fast) var(--ease-emphasized),
6
- transform var(--duration-fast) var(--ease-emphasized);
7
- }
8
- .lp-tab-badge-enter-from[data-v-2c920d5a],
9
- .lp-tab-badge-leave-to[data-v-2c920d5a] {
10
- opacity: 0;
11
- transform: scale(0.6);
12
- }
13
- @media (prefers-reduced-motion: reduce) {
14
- .lp-tab-badge-enter-active[data-v-2c920d5a],
15
- .lp-tab-badge-leave-active[data-v-2c920d5a] {
16
- transition: none;
17
- }
18
- }