@leavepulse/ui 0.57.0 → 0.58.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 (150) hide show
  1. package/dist/chunks/{ContextMenuItems-BtKU7074.js → ContextMenuItems-BY5sTVQF.js} +1 -1
  2. package/dist/chunks/{LayoutCanvas-BkaGXTjx.js → LayoutCanvas-BcGLJVBq.js} +1 -1
  3. package/dist/chunks/{LayoutNode-B3_9E1Xa.js → LayoutNode-BkBn6dvM.js} +1 -1
  4. package/dist/chunks/{LpActionBar-C3hkVsFz.js → LpActionBar-DCN-_pZP.js} +2 -2
  5. package/dist/chunks/{LpAddressInput-NUHmplCd.js → LpAddressInput-Dio6Sqed.js} +7 -7
  6. package/dist/chunks/{LpAlert-B6ilrM7T.js → LpAlert-CXMn1GYE.js} +1 -1
  7. package/dist/chunks/{LpAppShell-Bl1Ch68N.js → LpAppShell-Be6T96td.js} +3 -3
  8. package/dist/chunks/{LpAutocomplete-C8IgSMsi.js → LpAutocomplete-hJ_6CHlh.js} +1 -1
  9. package/dist/chunks/{LpAvatar-LTvy0OkE.js → LpAvatar-BxNs23Xu.js} +2 -2
  10. package/dist/chunks/{LpBreadcrumbs-D4TsoFju.js → LpBreadcrumbs-BLzOEgAF.js} +1 -1
  11. package/dist/chunks/{LpButton-BdfZFNqi.js → LpButton-vhlwmpBy.js} +1 -1
  12. package/dist/chunks/{LpCalendar-DrA2McTU.js → LpCalendar-BLoE8Qm7.js} +1 -1
  13. package/dist/chunks/{LpCard-DbjO5yaF.js → LpCard-DhR7u0d8.js} +1 -1
  14. package/dist/chunks/{LpCheckbox-DvVYeOD-.js → LpCheckbox-B_C8sOoT.js} +1 -1
  15. package/dist/chunks/{LpCodeBlock-ca7ANFyW.js → LpCodeBlock-CXsqJwDy.js} +1 -1
  16. package/dist/chunks/{LpColorPicker-D1sQqtXS.js → LpColorPicker-DQ88niXq.js} +2 -2
  17. package/dist/chunks/{LpConfirmDialog-CrbUZgJE.js → LpConfirmDialog-DxlSdjmk.js} +3 -3
  18. package/dist/chunks/{LpConfirmHost-BgMIV8r9.js → LpConfirmHost-BcrmTNu_.js} +1 -1
  19. package/dist/chunks/{LpContextMenu-EF_90u3g.js → LpContextMenu-B1NGfpp1.js} +2 -2
  20. package/dist/chunks/{LpDatePicker-BrdFtSTy.js → LpDatePicker-B-VMHMgy.js} +3 -3
  21. package/dist/chunks/{LpDateRangePicker-CxV5jW7p.js → LpDateRangePicker-B68KPKPl.js} +2 -2
  22. package/dist/chunks/{LpDisclosure-Cc23-JOT.js → LpDisclosure-Ct-VBHxt.js} +1 -1
  23. package/dist/chunks/{LpDrawer-D9lLOC0C.js → LpDrawer-DSknigxH.js} +1 -1
  24. package/dist/chunks/{LpDropdownMenu-DrpJJBp0.js → LpDropdownMenu-C7oHVlKY.js} +2 -2
  25. package/dist/chunks/{LpEmptyState-BJbZXC8D.js → LpEmptyState-CBwwkkdA.js} +1 -1
  26. package/dist/chunks/{LpFieldNotice-wtieLUTj.js → LpFieldNotice-9hH4ITZa.js} +1 -1
  27. package/dist/chunks/{LpFileTree-3E4w4Rjr.js → LpFileTree-CMA0_rsB.js} +2 -2
  28. package/dist/chunks/{LpFileTreeNode-B4uB8Ks_.js → LpFileTreeNode-B4T258hF.js} +3 -3
  29. package/dist/chunks/{LpFormField-CtVYj6tO.js → LpFormField-BpQ6WJPe.js} +1 -1
  30. package/dist/chunks/{LpHintLayer-CI1oZ9Pd.js → LpHintLayer-B5-6FyEf.js} +1 -1
  31. package/dist/chunks/LpHints-BqoZXHZk.js +109 -0
  32. package/dist/chunks/{LpIcon-DYtaid0K.js → LpIcon-B5guGKrW.js} +1 -1
  33. package/dist/chunks/{LpInput-D-YGQbEv.js → LpInput-WvyP02ID.js} +2 -2
  34. package/dist/chunks/{LpLightbox-EVXzAq62.js → LpLightbox-Dq-e36uT.js} +1 -1
  35. package/dist/chunks/{LpLogViewer-BfgtXVKm.js → LpLogViewer-DwiYE32z.js} +2 -2
  36. package/dist/chunks/{LpMapPicker-Cc84LaM3.js → LpMapPicker-BH5csaBt.js} +1 -1
  37. package/dist/chunks/{LpMediaGallery-BnlkN_1f.js → LpMediaGallery-B1kDypJ-.js} +2 -2
  38. package/dist/chunks/{LpModal-JNa3B_Lr.js → LpModal-BxYssnXg.js} +1 -1
  39. package/dist/chunks/{LpModalNav-DXyAyhQl.js → LpModalNav-Bn2ws64b.js} +4 -4
  40. package/dist/chunks/{LpNotificationBell-DEL-RoHS.js → LpNotificationBell-DJfs4JjQ.js} +4 -4
  41. package/dist/chunks/{LpNumberField-B77O-z28.js → LpNumberField-CJPjmoDz.js} +1 -1
  42. package/dist/chunks/{LpPagination-BcDlo3r_.js → LpPagination-DehAaJLY.js} +1 -1
  43. package/dist/chunks/{LpPasswordInput-eKzQhbQP.js → LpPasswordInput-Bg5uTZbx.js} +2 -2
  44. package/dist/chunks/{LpPhoneInput-BCbrrhgE.js → LpPhoneInput-DStwcbnQ.js} +2 -2
  45. package/dist/chunks/{LpPie-CXka8Jvx.js → LpPie-DeTkbbOK.js} +2 -2
  46. package/dist/chunks/{LpRangeCalendar-DZuaRV0W.js → LpRangeCalendar-D5sDID9W.js} +1 -1
  47. package/dist/chunks/{LpSection-tKEH0jYf.js → LpSection-B19VPYmr.js} +1 -1
  48. package/dist/chunks/{LpSegmented-C09EEam2.js → LpSegmented-D3Eam8sa.js} +1 -1
  49. package/dist/chunks/{LpSelect-DNIL6MB9.js → LpSelect-DynjWK1A.js} +1 -1
  50. package/dist/chunks/{LpSidebar-hZ8D1cVr.js → LpSidebar-CshW0fqC.js} +3 -3
  51. package/dist/chunks/{LpSidebarNav-C9dHu-2b.js → LpSidebarNav-C9b3i9G2.js} +2 -2
  52. package/dist/chunks/{LpStat-B-7udBRP.js → LpStat-BS2TEXYK.js} +1 -1
  53. package/dist/chunks/{LpStepper-C7XiVKZj.js → LpStepper-BSglWF45.js} +1 -1
  54. package/dist/chunks/{LpTableFilter-CrW7_Rj4.js → LpTableFilter-CwHXVxJt.js} +2 -2
  55. package/dist/chunks/{LpTabs-BMSBB78h.js → LpTabs-BBGRHY38.js} +1 -1
  56. package/dist/chunks/{LpTagsInput-D1SuqbhB.js → LpTagsInput-CHbQoAAA.js} +3 -3
  57. package/dist/chunks/{LpTextarea-uuScWo6-.js → LpTextarea-Bz2IWhTH.js} +1 -1
  58. package/dist/chunks/{LpThemeSwitcher-Fz85BCRS.js → LpThemeSwitcher-B_qhSl7q.js} +2 -2
  59. package/dist/chunks/{LpTimeField-Cqe7fXnh.js → LpTimeField-DvGXgdES.js} +1 -1
  60. package/dist/chunks/{LpToaster-DTtWuKvq.js → LpToaster-Bo9Q4QBP.js} +1 -1
  61. package/dist/chunks/{LpTour-C1TC2GyY.js → LpTour-D7m9ZxNk.js} +26 -7
  62. package/dist/chunks/{MenuTitle-J3ZDYjpV.js → MenuTitle-DQP6hc2N.js} +1 -1
  63. package/dist/chunks/{TourCard-BQS3ztqj.js → TourCard-DCHOjr6e.js} +2 -2
  64. package/dist/chunks/icons-QqBscG5I.js +43 -0
  65. package/dist/component-names.d.ts +1 -1
  66. package/dist/components/ContextMenuItems.vue.js +1 -1
  67. package/dist/components/LayoutCanvas.vue.js +1 -1
  68. package/dist/components/LayoutNode.vue.js +1 -1
  69. package/dist/components/LpActionBar.vue.js +1 -1
  70. package/dist/components/LpAddressInput.vue.js +1 -1
  71. package/dist/components/LpAlert.vue.js +1 -1
  72. package/dist/components/LpAppShell.vue.js +1 -1
  73. package/dist/components/LpAutocomplete.vue.js +1 -1
  74. package/dist/components/LpAvatar.vue.js +1 -1
  75. package/dist/components/LpBreadcrumbs.vue.js +1 -1
  76. package/dist/components/LpButton.vue.js +1 -1
  77. package/dist/components/LpCalendar.vue.js +1 -1
  78. package/dist/components/LpCard.vue.js +1 -1
  79. package/dist/components/LpChart.vue.js +2 -2
  80. package/dist/components/LpCheckbox.vue.js +1 -1
  81. package/dist/components/LpCodeBlock.vue.js +1 -1
  82. package/dist/components/LpColorPicker.vue.js +1 -1
  83. package/dist/components/LpCommandPalette.vue.js +2 -2
  84. package/dist/components/LpConfirmDialog.vue.js +1 -1
  85. package/dist/components/LpConfirmHost.vue.js +1 -1
  86. package/dist/components/LpContextMenu.vue.js +1 -1
  87. package/dist/components/LpDatePicker.vue.js +1 -1
  88. package/dist/components/LpDateRangePicker.vue.js +1 -1
  89. package/dist/components/LpDisclosure.vue.js +1 -1
  90. package/dist/components/LpDrawer.vue.js +1 -1
  91. package/dist/components/LpDropdownMenu.vue.js +1 -1
  92. package/dist/components/LpDropzone.vue.js +1 -1
  93. package/dist/components/LpEmptyState.vue.js +1 -1
  94. package/dist/components/LpFieldNotice.vue.js +1 -1
  95. package/dist/components/LpFileTree.vue.js +1 -1
  96. package/dist/components/LpFileTreeNode.vue.js +1 -1
  97. package/dist/components/LpFormField.vue.js +1 -1
  98. package/dist/components/LpHintLayer.vue.js +1 -1
  99. package/dist/components/LpHints.vue.d.ts +20 -0
  100. package/dist/components/LpHints.vue.js +4 -0
  101. package/dist/components/LpIcon.vue.js +1 -1
  102. package/dist/components/LpImageEditor.vue.js +2 -2
  103. package/dist/components/LpInput.vue.js +1 -1
  104. package/dist/components/LpLightbox.vue.js +1 -1
  105. package/dist/components/LpLogViewer.vue.js +1 -1
  106. package/dist/components/LpMapPicker.vue.js +1 -1
  107. package/dist/components/LpMediaGallery.vue.js +1 -1
  108. package/dist/components/LpModal.vue.js +1 -1
  109. package/dist/components/LpModalNav.vue.js +1 -1
  110. package/dist/components/LpNotificationBell.vue.js +1 -1
  111. package/dist/components/LpNumberField.vue.js +1 -1
  112. package/dist/components/LpPagination.vue.js +1 -1
  113. package/dist/components/LpPaletteFacts.vue.js +1 -1
  114. package/dist/components/LpPaletteHeader.vue.js +2 -2
  115. package/dist/components/LpPasswordInput.vue.js +1 -1
  116. package/dist/components/LpPhoneInput.vue.js +1 -1
  117. package/dist/components/LpPie.vue.js +1 -1
  118. package/dist/components/LpRangeCalendar.vue.js +1 -1
  119. package/dist/components/LpSection.vue.js +1 -1
  120. package/dist/components/LpSegmented.vue.js +1 -1
  121. package/dist/components/LpSelect.vue.js +1 -1
  122. package/dist/components/LpShortcutsDialog.vue.js +1 -1
  123. package/dist/components/LpSidebar.vue.js +1 -1
  124. package/dist/components/LpSidebarNav.vue.js +1 -1
  125. package/dist/components/LpStat.vue.js +1 -1
  126. package/dist/components/LpStepper.vue.js +1 -1
  127. package/dist/components/LpTable.vue.js +6 -6
  128. package/dist/components/LpTableFilter.vue.js +1 -1
  129. package/dist/components/LpTabs.vue.js +1 -1
  130. package/dist/components/LpTagsInput.vue.js +1 -1
  131. package/dist/components/LpTextarea.vue.js +1 -1
  132. package/dist/components/LpThemeSwitcher.vue.js +1 -1
  133. package/dist/components/LpTimeField.vue.js +1 -1
  134. package/dist/components/LpToaster.vue.js +1 -1
  135. package/dist/components/LpTour.vue.js +1 -1
  136. package/dist/components/MenuTitle.vue.js +1 -1
  137. package/dist/components/TourCard.vue.js +1 -1
  138. package/dist/composables/useHintSystem.d.ts +195 -0
  139. package/dist/composables/useHintSystem.js +334 -0
  140. package/dist/icons-all.js +1 -1
  141. package/dist/index.d.ts +3 -0
  142. package/dist/index.js +73 -64
  143. package/package.json +1 -1
  144. package/src/component-names.ts +1 -0
  145. package/src/components/LpHints.vue +116 -0
  146. package/src/components/LpTour.vue +26 -6
  147. package/src/composables/useHintSystem.ts +512 -0
  148. package/src/index.ts +17 -0
  149. package/src/kit-icons.ts +1 -1
  150. package/dist/chunks/icons-CkA0njzm.js +0 -43
@@ -0,0 +1,334 @@
1
+ import { provide, reactive, computed, inject, watch } from "vue";
2
+ import { anyModalOpen } from "../components/modalDepth.js";
3
+ import { hints } from "./useHints.js";
4
+ const RANK = { seen: 0, explained: 1, used: 2 };
5
+ const DAY = 24 * 3600 * 1e3;
6
+ const DEFAULT_TIMING = {
7
+ settle: 2500,
8
+ offerAgain: 3 * DAY,
9
+ offersMax: 2,
10
+ freshLimit: 3,
11
+ nudgeAgain: 7 * DAY,
12
+ flush: 2e3
13
+ };
14
+ function localHintStorage(key = "lp-hints") {
15
+ const read = () => {
16
+ try {
17
+ return JSON.parse(localStorage.getItem(key) || "{}");
18
+ } catch {
19
+ return {};
20
+ }
21
+ };
22
+ return {
23
+ load: read,
24
+ save(deltas) {
25
+ const all = read();
26
+ for (const d of deltas) all[d.key] = merge(all[d.key], d);
27
+ try {
28
+ localStorage.setItem(key, JSON.stringify(all));
29
+ } catch {
30
+ return;
31
+ }
32
+ }
33
+ };
34
+ }
35
+ function merge(record, delta) {
36
+ const base = record ?? { state: "seen", dismissed: false, count: 0, updatedAt: "" };
37
+ return {
38
+ ...base,
39
+ state: delta.state && RANK[delta.state] > RANK[base.state] ? delta.state : base.state,
40
+ dismissed: delta.dismissed ?? base.dismissed,
41
+ count: base.count + (delta.add ?? 0),
42
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
43
+ };
44
+ }
45
+ const hintKey = {
46
+ feature: (id, rev = 1) => `f:${id}:${rev}`,
47
+ page: (page) => `t:${page}`,
48
+ news: (id) => `c:${id}`,
49
+ nudge: (id) => `n:${id}`
50
+ };
51
+ function hintSummary(records, features, page) {
52
+ const own = Object.entries(features).filter(([, f]) => f.page === page);
53
+ const knows = (id, f) => RANK[records.get(hintKey.feature(id, f.rev))?.state ?? "seen"] >= RANK.explained;
54
+ const tour = records.get(hintKey.page(page));
55
+ return {
56
+ tour: tour && RANK[tour.state] >= RANK.explained ? "done" : tour?.assigned ? "assigned" : tour?.dismissed ? "declined" : tour ? "offered" : "never",
57
+ offers: tour?.count ?? 0,
58
+ known: own.filter(([id, f]) => knows(id, f)).length,
59
+ total: own.length,
60
+ missing: own.filter(([id, f]) => f.required && !knows(id, f)).map(([, f]) => f.title)
61
+ };
62
+ }
63
+ function typing() {
64
+ const el = document.activeElement;
65
+ return el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLElement && el.isContentEditable;
66
+ }
67
+ function createHintSystem(options) {
68
+ const timing = { ...DEFAULT_TIMING, ...options.timing };
69
+ const features = options.features;
70
+ const pages = options.pages ?? {};
71
+ const news = options.news ?? [];
72
+ const storage = options.storage ?? localHintStorage();
73
+ const sessionKey = options.sessionKey ?? "lp-hints:interrupted";
74
+ const state = reactive({
75
+ records: /* @__PURE__ */ new Map(),
76
+ loaded: false,
77
+ page: "",
78
+ tour: { open: false, step: 0, steps: [], ids: [], page: "" },
79
+ offer: null,
80
+ candidate: null,
81
+ settledAt: 0,
82
+ intent: false
83
+ });
84
+ const pending = /* @__PURE__ */ new Map();
85
+ let flushTimer;
86
+ const featureKey = (id) => hintKey.feature(id, features[id]?.rev);
87
+ const pageKey = hintKey.page;
88
+ const newsKey = hintKey.news;
89
+ const nudgeKey = hintKey.nudge;
90
+ function interrupted() {
91
+ try {
92
+ return sessionStorage.getItem(sessionKey) === "1";
93
+ } catch {
94
+ return false;
95
+ }
96
+ }
97
+ function spend() {
98
+ try {
99
+ sessionStorage.setItem(sessionKey, "1");
100
+ } catch {
101
+ return;
102
+ }
103
+ }
104
+ async function flush() {
105
+ clearTimeout(flushTimer);
106
+ flushTimer = void 0;
107
+ if (!pending.size) return;
108
+ const deltas = [...pending.values()];
109
+ pending.clear();
110
+ try {
111
+ await storage.save(deltas);
112
+ } catch {
113
+ for (const d of deltas) if (!pending.has(d.key)) pending.set(d.key, d);
114
+ }
115
+ }
116
+ function flushOnLeave() {
117
+ if (!pending.size) return;
118
+ const deltas = [...pending.values()];
119
+ pending.clear();
120
+ if (storage.saveOnLeave) storage.saveOnLeave(deltas);
121
+ else void storage.save(deltas);
122
+ }
123
+ function record(key, delta) {
124
+ state.records.set(key, merge(state.records.get(key), delta));
125
+ const queued = pending.get(key);
126
+ pending.set(key, {
127
+ key,
128
+ state: delta.state ?? queued?.state,
129
+ dismissed: delta.dismissed ?? queued?.dismissed,
130
+ add: (queued?.add ?? 0) + (delta.add ?? 0)
131
+ });
132
+ flushTimer ??= setTimeout(() => void flush(), timing.flush);
133
+ }
134
+ const present = (page) => Object.keys(features).filter((id) => features[id].page === page && hints.present(id));
135
+ function knownBefore(page) {
136
+ const marker = pages[page]?.known;
137
+ if (!marker) return false;
138
+ try {
139
+ return Object.keys(localStorage).some((key) => key.startsWith(marker));
140
+ } catch {
141
+ return false;
142
+ }
143
+ }
144
+ function baseline(page) {
145
+ for (const id of present(page)) if (!state.records.has(featureKey(id))) record(featureKey(id), { state: "seen" });
146
+ }
147
+ const fresh = computed(() => {
148
+ const page = state.page;
149
+ if (!page || !state.loaded || state.tour.open || !state.records.has(pageKey(page))) return [];
150
+ return present(page).filter((id) => {
151
+ const f = features[id];
152
+ const rec = state.records.get(featureKey(id));
153
+ if (!rec) return !f.conditional || (f.rev ?? 1) > 1;
154
+ return !!f.required && RANK[rec.state] < RANK.explained && !rec.dismissed;
155
+ }).sort((a, b) => Number(!!features[b].required) - Number(!!features[a].required) || (features[a].order ?? 0) - (features[b].order ?? 0)).slice(0, timing.freshLimit);
156
+ });
157
+ const notes = computed(
158
+ () => Object.fromEntries(Object.entries(features).map(([id, f]) => [id, { title: f.title, text: f.text }]))
159
+ );
160
+ const hasTour = (page = state.page) => Object.values(features).some((f) => f.page === page);
161
+ function startTour(page = state.page, only) {
162
+ const entries = Object.entries(features).filter(([id, f]) => f.page === page && (!only || only.includes(id)) && (!!f.target || !!f.enter || hints.present(id))).sort(([, a], [, b]) => (a.order ?? 0) - (b.order ?? 0));
163
+ if (!entries.length) return;
164
+ state.offer = null;
165
+ Object.assign(state.tour, {
166
+ open: true,
167
+ step: 0,
168
+ page,
169
+ ids: entries.map(([id]) => id),
170
+ steps: entries.map(([id, f]) => ({
171
+ target: f.target ?? id,
172
+ title: f.title,
173
+ text: f.text,
174
+ keys: f.keys,
175
+ try: f.try,
176
+ side: f.side,
177
+ enter: f.enter
178
+ }))
179
+ });
180
+ }
181
+ const unread = (page) => news.filter((n) => (!page || n.page === page) && !state.records.has(newsKey(n.id)) && (!page || !n.feature || hints.present(n.feature)));
182
+ function readNews(page) {
183
+ for (const n of unread(page)) record(newsKey(n.id), { state: "explained" });
184
+ }
185
+ function considerOffer() {
186
+ const page = state.page;
187
+ const ready = state.loaded && !state.tour.open && !state.offer && !anyModalOpen() && !typing() && Date.now() - state.settledAt > timing.settle;
188
+ if (!page || !ready) return;
189
+ const rec = state.records.get(pageKey(page));
190
+ if (rec?.assigned && RANK[rec.state] < RANK.explained && hasTour(page)) {
191
+ state.offer = { kind: "assigned", page };
192
+ return;
193
+ }
194
+ if (state.intent || interrupted()) return;
195
+ if (!rec && knownBefore(page)) {
196
+ record(pageKey(page), { state: "seen" });
197
+ baseline(page);
198
+ } else if (!rec || !rec.dismissed && RANK[rec.state] < RANK.explained && rec.count < timing.offersMax && Date.now() - Date.parse(rec.updatedAt || "0") > timing.offerAgain) {
199
+ if (!hasTour(page)) return;
200
+ spend();
201
+ if (!rec) {
202
+ record(pageKey(page), { state: "seen" });
203
+ baseline(page);
204
+ readNews(page);
205
+ }
206
+ state.offer = { kind: "tour", page };
207
+ return;
208
+ }
209
+ const items = unread(page);
210
+ if (items.length) {
211
+ spend();
212
+ state.offer = { kind: "news", page, items: items.slice(0, 3) };
213
+ return;
214
+ }
215
+ const n = state.candidate;
216
+ if (!n || n.page !== page) return;
217
+ const seen = state.records.get(nudgeKey(n.id));
218
+ if (seen?.dismissed || state.records.get(featureKey(n.feature))?.state === "used" || !hints.present(n.feature)) return;
219
+ if (seen && Date.now() - Date.parse(seen.updatedAt) < timing.nudgeAgain) return;
220
+ state.candidate = null;
221
+ spend();
222
+ record(nudgeKey(n.id), { add: 1 });
223
+ state.offer = { kind: "nudge", page, nudge: n };
224
+ }
225
+ let stops = [];
226
+ function start() {
227
+ if (stops.length) return;
228
+ const stopPage = watch(
229
+ options.page,
230
+ (page) => {
231
+ state.page = page;
232
+ state.settledAt = Date.now();
233
+ if (state.offer && state.offer.page !== page) state.offer = null;
234
+ if (state.candidate && state.candidate.page !== page) state.candidate = null;
235
+ setTimeout(() => state.intent = false, timing.settle * 2);
236
+ },
237
+ { immediate: true }
238
+ );
239
+ const poll = setInterval(() => {
240
+ try {
241
+ considerOffer();
242
+ } catch (error) {
243
+ console.warn("[hints] disabled after an error:", error);
244
+ stop();
245
+ }
246
+ }, 1e3);
247
+ window.addEventListener("pagehide", flushOnLeave);
248
+ stops = [
249
+ stopPage,
250
+ hints.on("used", (id) => {
251
+ if (features[id]) record(featureKey(id), { state: "used", add: 1 });
252
+ }),
253
+ () => clearInterval(poll),
254
+ () => window.removeEventListener("pagehide", flushOnLeave)
255
+ ];
256
+ }
257
+ function stop() {
258
+ for (const s of stops.splice(0)) s();
259
+ flushOnLeave();
260
+ }
261
+ return {
262
+ state,
263
+ fresh,
264
+ notes,
265
+ start,
266
+ stop,
267
+ hasTour,
268
+ startTour,
269
+ async load() {
270
+ state.records.clear();
271
+ try {
272
+ for (const [key, rec] of Object.entries(await storage.load())) state.records.set(key, rec);
273
+ state.loaded = true;
274
+ } catch {
275
+ state.loaded = false;
276
+ }
277
+ },
278
+ /** Ask for a nudge; it shows when the budget and the page allow. */
279
+ nudge(n) {
280
+ state.candidate = { ...n, page: state.page };
281
+ },
282
+ /** The user navigated on purpose (palette, notification): do not interrupt this arrival. */
283
+ markIntent() {
284
+ state.intent = true;
285
+ },
286
+ unreadNews: (page) => unread(page),
287
+ readNews,
288
+ pageTitle: (page) => pages[page]?.title ?? page,
289
+ readFresh(id) {
290
+ record(featureKey(id), { state: "explained" });
291
+ },
292
+ tourShown(index) {
293
+ const id = state.tour.ids[index];
294
+ if (id) record(featureKey(id), { state: "explained" });
295
+ },
296
+ tourEnded(finished) {
297
+ record(pageKey(state.tour.page), finished ? { state: "explained" } : { add: 1 });
298
+ baseline(state.tour.page);
299
+ },
300
+ answer(choice) {
301
+ const offer = state.offer;
302
+ state.offer = null;
303
+ if (!offer) return;
304
+ if (offer.kind === "news") {
305
+ const ids = offer.items.map((n) => n.feature).filter((id) => !!id);
306
+ readNews(offer.page);
307
+ if (choice === "show" && ids.length) startTour(offer.page, ids);
308
+ } else if (offer.kind === "nudge") {
309
+ if (choice === "show") startTour(features[offer.nudge.feature].page, [offer.nudge.feature]);
310
+ else record(nudgeKey(offer.nudge.id), { dismissed: true });
311
+ } else if (choice === "show") {
312
+ startTour(offer.page);
313
+ } else {
314
+ record(pageKey(offer.page), { add: 1, dismissed: choice === "never" });
315
+ baseline(offer.page);
316
+ }
317
+ }
318
+ };
319
+ }
320
+ const HINT_SYSTEM = /* @__PURE__ */ Symbol.for("lp-hint-system");
321
+ function provideHintSystem(system) {
322
+ provide(HINT_SYSTEM, system);
323
+ }
324
+ function useHintSystem() {
325
+ return inject(HINT_SYSTEM, null);
326
+ }
327
+ export {
328
+ createHintSystem,
329
+ hintKey,
330
+ hintSummary,
331
+ localHintStorage,
332
+ provideHintSystem,
333
+ useHintSystem
334
+ };
package/dist/icons-all.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import lucide from "@iconify-json/lucide/icons.json";
2
- import { a as registerIconCollection } from "./chunks/icons-CkA0njzm.js";
2
+ import { a as registerIconCollection } from "./chunks/icons-QqBscG5I.js";
3
3
  registerIconCollection(lucide);
package/dist/index.d.ts CHANGED
@@ -161,6 +161,9 @@ export { default as LpTour } from "./components/LpTour.vue";
161
161
  export type { TourContext, TourStep } from "./components/LpTour.vue";
162
162
  export { holeOf, openContextMenu, panelsAround } from "./components/tour";
163
163
  export { default as LpHintLayer } from "./components/LpHintLayer.vue";
164
+ export { default as LpHints } from "./components/LpHints.vue";
165
+ export { createHintSystem, hintKey, hintSummary, localHintStorage, provideHintSystem, useHintSystem } from "./composables/useHintSystem";
166
+ export type { HintDelta, HintFeature, HintLevel, HintNews, HintNudge, HintOffer, HintPage, HintRecord, HintStorage, HintSummary, HintSystem, HintSystemOptions, HintTiming, } from "./composables/useHintSystem";
164
167
  export type { HintNote } from "./components/LpHintLayer.vue";
165
168
  export { default as LpTooltipProvider } from "./components/LpTooltipProvider.vue";
166
169
  export { default as LpTopologyCanvas } from "./components/LpTopologyCanvas.vue";
package/dist/index.js CHANGED
@@ -1,24 +1,24 @@
1
- import { _ } from "./chunks/LayoutCanvas-BkaGXTjx.js";
2
- import { _ as _2 } from "./chunks/LpAddressInput-NUHmplCd.js";
3
- import { _ as _3 } from "./chunks/LpMapPicker-Cc84LaM3.js";
1
+ import { _ } from "./chunks/LayoutCanvas-BcGLJVBq.js";
2
+ import { _ as _2 } from "./chunks/LpAddressInput-Dio6Sqed.js";
3
+ import { _ as _3 } from "./chunks/LpMapPicker-BH5csaBt.js";
4
4
  import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
5
- import { _ as _4 } from "./chunks/LpActionBar-C3hkVsFz.js";
6
- import { _ as _5 } from "./chunks/LpAlert-B6ilrM7T.js";
7
- import { _ as _6 } from "./chunks/LpAppShell-Bl1Ch68N.js";
8
- import { _ as _7 } from "./chunks/LpAutocomplete-C8IgSMsi.js";
9
- import { _ as _8 } from "./chunks/LpAvatar-LTvy0OkE.js";
5
+ import { _ as _4 } from "./chunks/LpActionBar-DCN-_pZP.js";
6
+ import { _ as _5 } from "./chunks/LpAlert-CXMn1GYE.js";
7
+ import { _ as _6 } from "./chunks/LpAppShell-Be6T96td.js";
8
+ import { _ as _7 } from "./chunks/LpAutocomplete-hJ_6CHlh.js";
9
+ import { _ as _8 } from "./chunks/LpAvatar-BxNs23Xu.js";
10
10
  import { _ as _9 } from "./chunks/LpBadge-Fe0D1bYx.js";
11
- import { _ as _10 } from "./chunks/LpBreadcrumbs-D4TsoFju.js";
12
- import { _ as _11 } from "./chunks/LpButton-BdfZFNqi.js";
13
- import { _ as _12 } from "./chunks/LpCalendar-DrA2McTU.js";
14
- import { _ as _13 } from "./chunks/LpCard-DbjO5yaF.js";
11
+ import { _ as _10 } from "./chunks/LpBreadcrumbs-BLzOEgAF.js";
12
+ import { _ as _11 } from "./chunks/LpButton-vhlwmpBy.js";
13
+ import { _ as _12 } from "./chunks/LpCalendar-BLoE8Qm7.js";
14
+ import { _ as _13 } from "./chunks/LpCard-DhR7u0d8.js";
15
15
  import { default as default2 } from "./components/LpChart.vue.js";
16
16
  import { backgroundOf, csvField, downloadFile, fileStem, inlineSvg, resolveCssColor, svgToPng, toCsv } from "./components/exportData.js";
17
17
  import { CHART_PALETTE, axisTicks, chartSummary, formatTick, markerIndex, niceScale, resolveSlices } from "./components/chart.js";
18
- import { _ as _14 } from "./chunks/LpCheckbox-DvVYeOD-.js";
19
- import { _ as _15 } from "./chunks/LpCodeBlock-ca7ANFyW.js";
18
+ import { _ as _14 } from "./chunks/LpCheckbox-B_C8sOoT.js";
19
+ import { _ as _15 } from "./chunks/LpCodeBlock-CXsqJwDy.js";
20
20
  import { tokenizeLines } from "./components/codeHighlight.js";
21
- import { _ as _16 } from "./chunks/LpColorPicker-D1sQqtXS.js";
21
+ import { _ as _16 } from "./chunks/LpColorPicker-DQ88niXq.js";
22
22
  import { DEFAULT_SWATCHES, clampHsv, formatColor, hsvToHsl, hsvToRgb, isLight, normalizeHue, opaqueCss, parseColor, parseHex, rgbToHex, rgbToHsv } from "./components/color.js";
23
23
  import { default as default3 } from "./components/LpCommandPalette.vue.js";
24
24
  import { applyQueryFilters, highlightParts, parseCommandQuery, parsePaletteQuery, rankCommandItems } from "./components/commandSearch.js";
@@ -30,46 +30,46 @@ import { default as default6 } from "./components/LpPaletteStats.vue.js";
30
30
  import { default as default7 } from "./components/LpPaletteSwatches.vue.js";
31
31
  import { default as default8 } from "./components/LpKeys.vue.js";
32
32
  import { comboKeys, comboSteps } from "./components/keys.js";
33
- import { _ as _18 } from "./chunks/LpConfirmDialog-CrbUZgJE.js";
34
- import { _ as _19 } from "./chunks/LpConfirmHost-BgMIV8r9.js";
33
+ import { _ as _18 } from "./chunks/LpConfirmDialog-DxlSdjmk.js";
34
+ import { _ as _19 } from "./chunks/LpConfirmHost-BcrmTNu_.js";
35
35
  import { confirm, useConfirm } from "./components/confirm.js";
36
- import { _ as _20 } from "./chunks/LpContextMenu-EF_90u3g.js";
37
- import { _ as _21 } from "./chunks/LpDatePicker-BrdFtSTy.js";
38
- import { _ as _22 } from "./chunks/LpDateRangePicker-CxV5jW7p.js";
39
- import { _ as _23 } from "./chunks/LpRangeCalendar-DZuaRV0W.js";
36
+ import { _ as _20 } from "./chunks/LpContextMenu-B1NGfpp1.js";
37
+ import { _ as _21 } from "./chunks/LpDatePicker-B-VMHMgy.js";
38
+ import { _ as _22 } from "./chunks/LpDateRangePicker-B68KPKPl.js";
39
+ import { _ as _23 } from "./chunks/LpRangeCalendar-D5sDID9W.js";
40
40
  import { clampRange, defaultRangePresets, formatRange, normalizeRange, sameRange } from "./components/dateRange.js";
41
- import { _ as _24 } from "./chunks/LpDisclosure-Cc23-JOT.js";
41
+ import { _ as _24 } from "./chunks/LpDisclosure-Ct-VBHxt.js";
42
42
  import { _ as _25 } from "./chunks/LpDivider-CUX46KR0.js";
43
- import { _ as _26 } from "./chunks/LpDrawer-D9lLOC0C.js";
44
- import { _ as _27 } from "./chunks/LpDropdownMenu-DrpJJBp0.js";
43
+ import { _ as _26 } from "./chunks/LpDrawer-DSknigxH.js";
44
+ import { _ as _27 } from "./chunks/LpDropdownMenu-C7oHVlKY.js";
45
45
  import { default as default9 } from "./components/LpDropzone.vue.js";
46
- import { _ as _28 } from "./chunks/LpEmptyState-BJbZXC8D.js";
47
- import { _ as _29 } from "./chunks/LpFileTree-3E4w4Rjr.js";
46
+ import { _ as _28 } from "./chunks/LpEmptyState-CBwwkkdA.js";
47
+ import { _ as _29 } from "./chunks/LpFileTree-CMA0_rsB.js";
48
48
  import { ancestorIds, checkStateOf, checkedCount, computeStats, fileIcon, formatModified, formatSize, sortNodes, subtreeIds, subtreeSize } from "./components/fileTree.js";
49
- import { _ as _30 } from "./chunks/LpFieldNotice-wtieLUTj.js";
50
- import { _ as _31 } from "./chunks/LpFormField-CtVYj6tO.js";
51
- import { _ as _32 } from "./chunks/LpIcon-DYtaid0K.js";
52
- import { i, b, a, c } from "./chunks/icons-CkA0njzm.js";
49
+ import { _ as _30 } from "./chunks/LpFieldNotice-9hH4ITZa.js";
50
+ import { _ as _31 } from "./chunks/LpFormField-BpQ6WJPe.js";
51
+ import { _ as _32 } from "./chunks/LpIcon-B5guGKrW.js";
52
+ import { i, b, a, c } from "./chunks/icons-QqBscG5I.js";
53
53
  import { default as default10 } from "./components/LpImageEditor.vue.js";
54
54
  import { _ as _33 } from "./chunks/LpInfraNode-Ds_8SZgN.js";
55
- import { _ as _34 } from "./chunks/LpInput-D-YGQbEv.js";
56
- import { _ as _35 } from "./chunks/LpLightbox-EVXzAq62.js";
55
+ import { _ as _34 } from "./chunks/LpInput-WvyP02ID.js";
56
+ import { _ as _35 } from "./chunks/LpLightbox-Dq-e36uT.js";
57
57
  import { fileNameOf } from "./components/lightbox.js";
58
58
  import { _ as _36 } from "./chunks/LpLink-Krkjhe_y.js";
59
- import { _ as _37 } from "./chunks/LpLogViewer-BfgtXVKm.js";
59
+ import { _ as _37 } from "./chunks/LpLogViewer-DwiYE32z.js";
60
60
  import { countLevels, matchPositions, matchesTerm, ringWindow, stepMatch } from "./components/logSearch.js";
61
- import { _ as _38 } from "./chunks/LpMediaGallery-BnlkN_1f.js";
62
- import { _ as _39 } from "./chunks/LpModal-JNa3B_Lr.js";
63
- import { _ as _40 } from "./chunks/LpModalNav-DXyAyhQl.js";
64
- import { _ as _41 } from "./chunks/LpNotificationBell-DEL-RoHS.js";
65
- import { _ as _42 } from "./chunks/LpNumberField-B77O-z28.js";
66
- import { _ as _43 } from "./chunks/LpTimeField-Cqe7fXnh.js";
61
+ import { _ as _38 } from "./chunks/LpMediaGallery-B1kDypJ-.js";
62
+ import { _ as _39 } from "./chunks/LpModal-BxYssnXg.js";
63
+ import { _ as _40 } from "./chunks/LpModalNav-Bn2ws64b.js";
64
+ import { _ as _41 } from "./chunks/LpNotificationBell-DJfs4JjQ.js";
65
+ import { _ as _42 } from "./chunks/LpNumberField-CJPjmoDz.js";
66
+ import { _ as _43 } from "./chunks/LpTimeField-DvGXgdES.js";
67
67
  import { _ as _44 } from "./chunks/LpNumberFlow-z4WPZcZu.js";
68
68
  import { _ as _45 } from "./chunks/LpOtpInput-PbeNJ5In.js";
69
- import { _ as _46 } from "./chunks/LpPagination-BcDlo3r_.js";
70
- import { _ as _47 } from "./chunks/LpPasswordInput-eKzQhbQP.js";
71
- import { _ as _48 } from "./chunks/LpPie-CXka8Jvx.js";
72
- import { _ as _49 } from "./chunks/LpPhoneInput-BCbrrhgE.js";
69
+ import { _ as _46 } from "./chunks/LpPagination-DehAaJLY.js";
70
+ import { _ as _47 } from "./chunks/LpPasswordInput-Bg5uTZbx.js";
71
+ import { _ as _48 } from "./chunks/LpPie-DeTkbbOK.js";
72
+ import { _ as _49 } from "./chunks/LpPhoneInput-DStwcbnQ.js";
73
73
  import { filterCountries, flagEmoji, loadCountries, matchCountryByValue } from "./components/countries.js";
74
74
  import { _ as _50 } from "./chunks/LpPopover-DCKeqiVn.js";
75
75
  import { _ as _51 } from "./chunks/LpProgress-CBU1iI69.js";
@@ -77,39 +77,41 @@ import { _ as _52 } from "./chunks/LpRadio-CWA5Eb3M.js";
77
77
  import { _ as _53 } from "./chunks/LpRadioGroup-CCn-Q2_c.js";
78
78
  import { _ as _54 } from "./chunks/LpRollingText-DB7upf-5.js";
79
79
  import { _ as _55 } from "./chunks/LpScrollArea-Hz3-JWUG.js";
80
- import { _ as _56 } from "./chunks/LpSegmented-C09EEam2.js";
81
- import { _ as _57 } from "./chunks/LpSection-tKEH0jYf.js";
82
- import { _ as _58 } from "./chunks/LpSelect-DNIL6MB9.js";
80
+ import { _ as _56 } from "./chunks/LpSegmented-D3Eam8sa.js";
81
+ import { _ as _57 } from "./chunks/LpSection-B19VPYmr.js";
82
+ import { _ as _58 } from "./chunks/LpSelect-DynjWK1A.js";
83
83
  import { _ as _59 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
84
84
  import { _ as _60 } from "./chunks/LpShift-DXNsauQZ.js";
85
85
  import { default as default11 } from "./components/LpShortcutsDialog.vue.js";
86
- import { _ as _61 } from "./chunks/LpSidebar-hZ8D1cVr.js";
86
+ import { _ as _61 } from "./chunks/LpSidebar-CshW0fqC.js";
87
87
  import { _ as _62 } from "./chunks/LpSkeleton-BB6XIV-w.js";
88
88
  import { _ as _63 } from "./chunks/LpSlider-Cuzmrd7p.js";
89
89
  import { _ as _64 } from "./chunks/LpRangeSlider-C1yF9-nP.js";
90
90
  import { _ as _65 } from "./chunks/LpVideoBackdrop-qWRYBOTQ.js";
91
91
  import { formatClipTime, isNativeLoop, planLoop, seamProgress, seamReached } from "./components/videoBackdrop.js";
92
92
  import { _ as _66 } from "./chunks/LpSparkline-CB80N8SJ.js";
93
- import { _ as _67 } from "./chunks/LpStat-B-7udBRP.js";
94
- import { _ as _68 } from "./chunks/LpStepper-C7XiVKZj.js";
93
+ import { _ as _67 } from "./chunks/LpStat-BS2TEXYK.js";
94
+ import { _ as _68 } from "./chunks/LpStepper-BSglWF45.js";
95
95
  import { _ as _69 } from "./chunks/LpSwitch-DG2AhXIL.js";
96
96
  import { default as default12 } from "./components/LpTable.vue.js";
97
97
  import { compareValues } from "./components/tableSort.js";
98
98
  import { _ as _70 } from "./chunks/LpTableOfContents-DYuqkByy.js";
99
- import { _ as _71 } from "./chunks/LpTabs-BMSBB78h.js";
100
- import { _ as _72 } from "./chunks/LpTagsInput-D1SuqbhB.js";
99
+ import { _ as _71 } from "./chunks/LpTabs-BBGRHY38.js";
100
+ import { _ as _72 } from "./chunks/LpTagsInput-CHbQoAAA.js";
101
101
  import { addTags, splitTags } from "./components/tags.js";
102
- import { _ as _73 } from "./chunks/LpTextarea-uuScWo6-.js";
103
- import { _ as _74 } from "./chunks/LpThemeSwitcher-Fz85BCRS.js";
102
+ import { _ as _73 } from "./chunks/LpTextarea-Bz2IWhTH.js";
103
+ import { _ as _74 } from "./chunks/LpThemeSwitcher-B_qhSl7q.js";
104
104
  import { _ as _75 } from "./chunks/LpTilt-B7KHX1zH.js";
105
- import { _ as _76 } from "./chunks/LpToaster-DTtWuKvq.js";
105
+ import { _ as _76 } from "./chunks/LpToaster-Bo9Q4QBP.js";
106
106
  import { _ as _77 } from "./chunks/LpTooltip-suFCM34F.js";
107
- import { _ as _78 } from "./chunks/LpTour-C1TC2GyY.js";
107
+ import { _ as _78 } from "./chunks/LpTour-D7m9ZxNk.js";
108
108
  import { holeOf, openContextMenu, panelsAround } from "./components/tour.js";
109
- import { _ as _79 } from "./chunks/LpHintLayer-CI1oZ9Pd.js";
110
- import { _ as _80 } from "./chunks/LpTooltipProvider-CftjV7Xc.js";
111
- import { _ as _81 } from "./chunks/LpTopologyCanvas-6ozNrQKh.js";
112
- import { _ as _82 } from "./chunks/LpUptimeBar-B4ltCfno.js";
109
+ import { _ as _79 } from "./chunks/LpHintLayer-B5-6FyEf.js";
110
+ import { _ as _80 } from "./chunks/LpHints-BqoZXHZk.js";
111
+ import { createHintSystem, hintKey, hintSummary, localHintStorage, provideHintSystem, useHintSystem } from "./composables/useHintSystem.js";
112
+ import { _ as _81 } from "./chunks/LpTooltipProvider-CftjV7Xc.js";
113
+ import { _ as _82 } from "./chunks/LpTopologyCanvas-6ozNrQKh.js";
114
+ import { _ as _83 } from "./chunks/LpUptimeBar-B4ltCfno.js";
113
115
  import { deserializeLayout, serializeLayout } from "./layout/tree.js";
114
116
  import { addLeaf, addTab, countBlocks, countLeaves, makeLayout, moveLeaf, removeBlock, removeLeaf, reorderTab, resizeAt, setActiveTab } from "./layout/tree.js";
115
117
  import { blockTitle, defineBlocks } from "./layout/registry.js";
@@ -143,7 +145,7 @@ import { useShift } from "./composables/useShift.js";
143
145
  import { useTilt } from "./composables/useTilt.js";
144
146
  import { useZoomPan } from "./composables/useZoomPan.js";
145
147
  import { useToast } from "./composables/useToast.js";
146
- import { _ as _83 } from "./chunks/LpThemeProvider-CQ2jC9TA.js";
148
+ import { _ as _84 } from "./chunks/LpThemeProvider-CQ2jC9TA.js";
147
149
  import { isInternalHref, resolveLink } from "./components/link.js";
148
150
  function defineTheme(base, overrides = {}) {
149
151
  const src = typeof base === "string" ? presets[base] : base;
@@ -216,6 +218,7 @@ export {
216
218
  _29 as LpFileTree,
217
219
  _31 as LpFormField,
218
220
  _79 as LpHintLayer,
221
+ _80 as LpHints,
219
222
  _32 as LpIcon,
220
223
  default10 as LpImageEditor,
221
224
  _33 as LpInfraNode,
@@ -267,16 +270,16 @@ export {
267
270
  _71 as LpTabs,
268
271
  _72 as LpTagsInput,
269
272
  _73 as LpTextarea,
270
- _83 as LpThemeProvider,
273
+ _84 as LpThemeProvider,
271
274
  _74 as LpThemeSwitcher,
272
275
  _75 as LpTilt,
273
276
  _43 as LpTimeField,
274
277
  _76 as LpToaster,
275
278
  _77 as LpTooltip,
276
- _80 as LpTooltipProvider,
277
- _81 as LpTopologyCanvas,
279
+ _81 as LpTooltipProvider,
280
+ _82 as LpTopologyCanvas,
278
281
  _78 as LpTour,
279
- _82 as LpUptimeBar,
282
+ _83 as LpUptimeBar,
280
283
  _65 as LpVideoBackdrop,
281
284
  N as NO_BACKDROP_ATTR,
282
285
  OSM_TILES,
@@ -314,6 +317,7 @@ export {
314
317
  countBlocks,
315
318
  countLeaves,
316
319
  countLevels,
320
+ createHintSystem,
317
321
  createNominatimProvider,
318
322
  csvField,
319
323
  g as dark,
@@ -344,6 +348,8 @@ export {
344
348
  formatSize,
345
349
  formatTick,
346
350
  highlightParts,
351
+ hintKey,
352
+ hintSummary,
347
353
  hints,
348
354
  holeOf,
349
355
  hotkeyConflicts,
@@ -361,6 +367,7 @@ export {
361
367
  l as light,
362
368
  j as lime,
363
369
  loadCountries,
370
+ localHintStorage,
364
371
  lpConfig,
365
372
  makeLayout,
366
373
  markerIndex,
@@ -397,6 +404,7 @@ export {
397
404
  project,
398
405
  provideField,
399
406
  provideGlass,
407
+ provideHintSystem,
400
408
  provideLpConfig,
401
409
  pushRecent,
402
410
  rankCommandItems,
@@ -455,6 +463,7 @@ export {
455
463
  useFormDraft,
456
464
  useGamepadNav,
457
465
  useGlass,
466
+ useHintSystem,
458
467
  useHotkeys,
459
468
  useInputFilter,
460
469
  useInputMask,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leavepulse/ui",
3
- "version": "0.57.0",
3
+ "version": "0.58.1",
4
4
  "type": "module",
5
5
  "description": "LeavePulse token-driven Vue component kit.",
6
6
  "repository": {
@@ -34,6 +34,7 @@ export const COMPONENT_NAMES = [
34
34
  "LpFileTree",
35
35
  "LpFormField",
36
36
  "LpHintLayer",
37
+ "LpHints",
37
38
  "LpIcon",
38
39
  "LpImageEditor",
39
40
  "LpInfraNode",