@fuzdev/fuz_ui 0.202.0 → 0.203.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 (71) hide show
  1. package/dist/ApiIndex.svelte +6 -3
  2. package/dist/ApiIndex.svelte.d.ts +1 -1
  3. package/dist/ApiIndex.svelte.d.ts.map +1 -1
  4. package/dist/ApiModule.svelte +72 -21
  5. package/dist/ApiModule.svelte.d.ts +1 -1
  6. package/dist/ApiModule.svelte.d.ts.map +1 -1
  7. package/dist/ContextmenuEntry.svelte +15 -16
  8. package/dist/ContextmenuEntry.svelte.d.ts +3 -2
  9. package/dist/ContextmenuEntry.svelte.d.ts.map +1 -1
  10. package/dist/ContextmenuIcon.svelte +30 -0
  11. package/dist/ContextmenuIcon.svelte.d.ts +9 -0
  12. package/dist/ContextmenuIcon.svelte.d.ts.map +1 -0
  13. package/dist/ContextmenuLinkEntry.svelte +23 -12
  14. package/dist/ContextmenuLinkEntry.svelte.d.ts +2 -1
  15. package/dist/ContextmenuLinkEntry.svelte.d.ts.map +1 -1
  16. package/dist/ContextmenuMenu.svelte +207 -0
  17. package/dist/ContextmenuMenu.svelte.d.ts +41 -0
  18. package/dist/ContextmenuMenu.svelte.d.ts.map +1 -0
  19. package/dist/ContextmenuRoot.svelte +58 -260
  20. package/dist/ContextmenuRoot.svelte.d.ts +2 -60
  21. package/dist/ContextmenuRoot.svelte.d.ts.map +1 -1
  22. package/dist/ContextmenuRootForSafariCompatibility.svelte +72 -283
  23. package/dist/ContextmenuRootForSafariCompatibility.svelte.d.ts +2 -58
  24. package/dist/ContextmenuRootForSafariCompatibility.svelte.d.ts.map +1 -1
  25. package/dist/ContextmenuSeparator.svelte +2 -1
  26. package/dist/ContextmenuSeparator.svelte.d.ts.map +1 -1
  27. package/dist/ContextmenuSubmenu.svelte +31 -25
  28. package/dist/ContextmenuSubmenu.svelte.d.ts +3 -2
  29. package/dist/ContextmenuSubmenu.svelte.d.ts.map +1 -1
  30. package/dist/ContextmenuTextEntry.svelte +6 -4
  31. package/dist/ContextmenuTextEntry.svelte.d.ts +3 -1
  32. package/dist/ContextmenuTextEntry.svelte.d.ts.map +1 -1
  33. package/dist/DeclarationLink.svelte +15 -2
  34. package/dist/DeclarationLink.svelte.d.ts +7 -0
  35. package/dist/DeclarationLink.svelte.d.ts.map +1 -1
  36. package/dist/DocsLink.svelte +3 -1
  37. package/dist/DocsLink.svelte.d.ts.map +1 -1
  38. package/dist/DocsTertiaryNav.svelte +2 -1
  39. package/dist/DocsTertiaryNav.svelte.d.ts.map +1 -1
  40. package/dist/LibraryDetail.svelte +9 -3
  41. package/dist/LibraryDetail.svelte.d.ts +1 -1
  42. package/dist/LibraryDetail.svelte.d.ts.map +1 -1
  43. package/dist/ModuleLink.svelte +2 -1
  44. package/dist/ModuleLink.svelte.d.ts.map +1 -1
  45. package/dist/TypeLink.svelte +2 -1
  46. package/dist/TypeLink.svelte.d.ts.map +1 -1
  47. package/dist/contextmenu_helpers.d.ts +324 -1
  48. package/dist/contextmenu_helpers.d.ts.map +1 -1
  49. package/dist/contextmenu_helpers.js +403 -2
  50. package/dist/contextmenu_state.svelte.d.ts +61 -15
  51. package/dist/contextmenu_state.svelte.d.ts.map +1 -1
  52. package/dist/contextmenu_state.svelte.js +206 -119
  53. package/dist/declaration.svelte.d.ts +1 -0
  54. package/dist/declaration.svelte.d.ts.map +1 -1
  55. package/dist/declaration.svelte.js +2 -1
  56. package/dist/icons.d.ts +15 -3
  57. package/dist/icons.d.ts.map +1 -1
  58. package/dist/icons.js +17 -3
  59. package/dist/library.svelte.d.ts +30 -3
  60. package/dist/library.svelte.d.ts.map +1 -1
  61. package/dist/library.svelte.js +38 -0
  62. package/dist/module.svelte.d.ts +62 -1
  63. package/dist/module.svelte.d.ts.map +1 -1
  64. package/dist/module.svelte.js +71 -1
  65. package/package.json +2 -2
  66. package/src/lib/contextmenu_helpers.ts +546 -3
  67. package/src/lib/contextmenu_state.svelte.ts +219 -119
  68. package/src/lib/declaration.svelte.ts +2 -1
  69. package/src/lib/icons.ts +19 -3
  70. package/src/lib/library.svelte.ts +43 -1
  71. package/src/lib/module.svelte.ts +97 -2
@@ -1,10 +1,11 @@
1
1
  import { onDestroy } from 'svelte';
2
2
  import { is_promise } from '@fuzdev/fuz_util/async.js';
3
- import { BROWSER } from 'esm-env';
3
+ import { BROWSER, DEV } from 'esm-env';
4
4
  import { EMPTY_OBJECT } from '@fuzdev/fuz_util/object.js';
5
5
  import { Dimensions } from './dimensions.svelte.js';
6
6
  import { create_context } from './context_helpers.js';
7
7
  import { url_to_root_relative } from './library_helpers.js';
8
+ import { icon_copy } from './icons.js';
8
9
  export const contextmenu_context = create_context();
9
10
  export const contextmenu_submenu_context = create_context();
10
11
  export const contextmenu_dimensions_context = create_context(() => new Dimensions());
@@ -23,25 +24,70 @@ export class EntryState {
23
24
  this.disabled = disabled;
24
25
  }
25
26
  }
26
- export class SubmenuState {
27
+ /**
28
+ * Shared `items` state for `SubmenuState` and `RootMenuState`.
29
+ *
30
+ * The source of truth is a plain non-reactive array because items register and
31
+ * unregister from component lifecycles that can interleave within a single batch -
32
+ * effect teardowns can observe stale signal values mid-batch, so read-copy-write
33
+ * against the reactive array can lose concurrent registrations (e.g. reopening the
34
+ * menu while it's open). Every mutation publishes an immutable snapshot, preserving
35
+ * the reassignment (not mutation) contract for readers.
36
+ */
37
+ export class ContextmenuItemsState {
38
+ #items_source = [];
39
+ #items = $state.raw([]);
40
+ get items() {
41
+ return this.#items;
42
+ }
43
+ set items(value) {
44
+ // copy for the published snapshot too, so callers mutating
45
+ // their own array can't mutate it in readers' hands
46
+ this.#items_source = [...value];
47
+ this.#items = [...value];
48
+ }
49
+ /**
50
+ * Appends `item`, publishing a new immutable `items`.
51
+ */
52
+ add_item(item) {
53
+ this.#items_source.push(item);
54
+ this.#items = [...this.#items_source];
55
+ }
56
+ /**
57
+ * Removes `item` if present, publishing a new immutable `items`.
58
+ * Safe to call from effect teardown - it reads only the non-reactive source array.
59
+ */
60
+ remove_item(item) {
61
+ const index = this.#items_source.indexOf(item);
62
+ if (index === -1)
63
+ return;
64
+ this.#items_source.splice(index, 1);
65
+ this.#items = [...this.#items_source];
66
+ }
67
+ }
68
+ export class SubmenuState extends ContextmenuItemsState {
27
69
  is_menu = true;
28
70
  menu;
29
71
  depth;
30
72
  selected = $state.raw(false);
31
- items = $state.raw([]);
32
73
  constructor(menu, depth) {
74
+ super();
33
75
  this.menu = menu;
34
76
  this.depth = depth;
35
77
  }
36
78
  }
37
- export class RootMenuState {
79
+ export class RootMenuState extends ContextmenuItemsState {
38
80
  is_menu = true;
39
81
  menu = null;
40
82
  depth = 1;
41
- items = $state.raw([]);
42
83
  }
84
+ /** Extracts a string `message` property from a thrown value or failed result, if present. */
85
+ const to_error_message = (value) => {
86
+ const message = value?.message;
87
+ return typeof message === 'string' ? message : undefined;
88
+ };
43
89
  /**
44
- * Creates a contextmenu store.
90
+ * Manages contextmenu state.
45
91
  * See usage with `ContextmenuRoot.svelte` and `Contextmenu.svelte`.
46
92
  *
47
93
  * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event}
@@ -59,10 +105,15 @@ export class ContextmenuState {
59
105
  y = $state.raw(0);
60
106
  params = $state.raw([]);
61
107
  error = $state.raw();
62
- // These arrays use immutable updates (reassignment, not mutation).
63
- // If you need reactivity, use `$contextmenu` in a reactive statement to react to all changes, and
64
- // then access the immutable `contextmenu.root_menu` and `contextmenu.selections`.
65
- // See `ContextmenuEntry.svelte` and `ContextmenuSubmenu.svelte` for reactive usage examples.
108
+ /**
109
+ * The element the menu was opened from, while opened, else `undefined`.
110
+ * Resolves the popover host when the menu opens inside a modal `<dialog>` -
111
+ * see `contextmenu_resolve_popover_host`. Deliberately not reactive -
112
+ * read it in event handlers and attachments, not in templates.
113
+ */
114
+ target = undefined;
115
+ // These arrays use immutable updates (reassignment, not mutation) - readers can depend
116
+ // on snapshot identity, and `ContextmenuItemsState` documents the publication contract.
66
117
  root_menu = new RootMenuState();
67
118
  selections = $state.raw([]);
68
119
  can_collapse = $derived(this.selections.length > 1);
@@ -70,11 +121,11 @@ export class ContextmenuState {
70
121
  const selected = this.selections.at(-1);
71
122
  return !!selected?.is_menu && selected.items.length > 0;
72
123
  });
73
- can_select_next = $derived.by(() => {
74
- const menu = this.selections.at(-1)?.menu ?? this.root_menu;
75
- return menu.items.length > 1;
76
- });
77
- can_select_previous = $derived.by(() => {
124
+ /**
125
+ * Whether `select_next` and `select_previous` can move the selection -
126
+ * the selected menu has more than one item.
127
+ */
128
+ can_select_sibling = $derived.by(() => {
78
129
  const menu = this.selections.at(-1)?.menu ?? this.root_menu;
79
130
  return menu.items.length > 1;
80
131
  });
@@ -82,6 +133,10 @@ export class ContextmenuState {
82
133
  const selected = this.selections.at(-1);
83
134
  if (!selected)
84
135
  return false;
136
+ // the selected item can unregister out from under the selection
137
+ // (e.g. its component unmounted) - its action must not run
138
+ if (!selected.menu.items.includes(selected))
139
+ return false;
85
140
  if (selected.is_menu)
86
141
  return selected.items.length > 0;
87
142
  return !selected.disabled();
@@ -91,18 +146,34 @@ export class ContextmenuState {
91
146
  this.has_custom_layout = !!layout;
92
147
  this.layout = layout ?? new Dimensions();
93
148
  }
94
- open(params, x, y) {
95
- this.selections = [];
149
+ open(params, x, y, target) {
150
+ this.#clear_selections();
96
151
  this.opened = true;
152
+ this.error = undefined;
97
153
  this.x = x;
98
154
  this.y = y;
99
155
  this.params = params;
156
+ this.target = target;
100
157
  }
101
158
  close() {
102
159
  if (!this.opened)
103
160
  return;
104
161
  this.reset_items(this.root_menu.items);
162
+ this.#clear_selections();
105
163
  this.opened = false;
164
+ this.target = undefined;
165
+ }
166
+ /**
167
+ * Deselects every selected item and empties `selections`. Items can outlive
168
+ * a selection (e.g. surviving a reopen-while-open), so clearing the array
169
+ * without deselecting would leave ghost highlights.
170
+ */
171
+ #clear_selections() {
172
+ if (!this.selections.length)
173
+ return;
174
+ for (const s of this.selections)
175
+ s.selected = false;
176
+ this.selections = [];
106
177
  }
107
178
  reset_items(items) {
108
179
  for (const item of items) {
@@ -116,84 +187,96 @@ export class ContextmenuState {
116
187
  }
117
188
  }
118
189
  }
119
- activate(item) {
120
- if (item.is_menu) {
121
- this.expand_selected();
122
- }
123
- else {
124
- if (item.disabled())
125
- return false;
126
- let returned;
127
- try {
128
- returned = item.run()();
129
- }
130
- catch (error) {
131
- const message = typeof error?.message === 'string' ? error.message : undefined;
132
- item.error_message = message ?? 'unknown error';
133
- this.error = message;
134
- }
135
- if (is_promise(returned)) {
136
- item.pending = true;
137
- item.error_message = null;
138
- const promise = (item.promise = returned
139
- .then((result) => {
140
- if (promise !== item.promise)
141
- return;
142
- if (typeof result?.ok === 'boolean') {
143
- if (result.ok) {
144
- if (result.close !== false) {
145
- this.close();
146
- }
147
- }
148
- else {
149
- const message = typeof result.message === 'string' ? result.message : undefined;
150
- item.error_message = message ?? 'unknown error';
151
- this.error = message;
152
- }
153
- }
154
- else {
155
- // void or undefined - default behavior is to close
156
- this.close();
157
- }
158
- return result;
159
- }, (err) => {
160
- if (promise !== item.promise)
161
- return;
162
- const message = typeof err?.message === 'string' ? err.message : undefined;
163
- item.error_message = message ?? 'unknown error';
164
- this.error = message;
165
- })
166
- .finally(() => {
167
- if (promise !== item.promise)
168
- return;
169
- item.pending = false;
170
- item.promise = null;
171
- }));
172
- return item.promise; // async path
173
- }
174
- // synchronous path
175
- if (typeof returned?.ok === 'boolean') {
176
- if (returned.ok) {
177
- if (returned.close !== false) {
178
- this.close();
179
- }
180
- }
181
- else {
182
- const message = typeof returned.message === 'string' ? returned.message : undefined;
183
- item.error_message = message ?? 'unknown error';
184
- this.error = message;
190
+ /**
191
+ * Sets the error state for a failed activation.
192
+ * `error_message` falls back to `'unknown error'` so the entry always displays something,
193
+ * while `error` keeps the raw message so external consumers can detect its absence.
194
+ */
195
+ #handle_error(item, message) {
196
+ item.error_message = message ?? 'unknown error';
197
+ this.error = message;
198
+ }
199
+ /**
200
+ * Applies an activation result, returning `false` when it failed.
201
+ */
202
+ #handle_result(item, result) {
203
+ if (typeof result?.ok === 'boolean') {
204
+ if (result.ok) {
205
+ if (result.close !== false) {
206
+ this.close();
185
207
  }
186
208
  }
187
209
  else {
188
- // void or undefined - default behavior is to close
189
- this.close();
210
+ this.#handle_error(item, to_error_message(result));
211
+ return false;
190
212
  }
191
213
  }
214
+ else {
215
+ // void or undefined - default behavior is to close
216
+ this.close();
217
+ }
192
218
  return true;
193
219
  }
220
+ /**
221
+ * Activates `item` - expanding submenus, running entries.
222
+ *
223
+ * @returns for async runs, the activation promise; for sync runs, `false` when the
224
+ * activation didn't run (disabled) or failed (a throw or `{ok: false}`), else `true`
225
+ */
226
+ activate(item) {
227
+ if (item.is_menu) {
228
+ // select before expanding - `expand_selected` operates on the selection
229
+ // tail, and callers aren't required to have selected (hovered) `item` first
230
+ this.select(item);
231
+ this.expand_selected();
232
+ return true;
233
+ }
234
+ if (item.disabled())
235
+ return false;
236
+ let returned;
237
+ try {
238
+ returned = item.run()();
239
+ }
240
+ catch (error) {
241
+ // keep the menu open so the entry displays the error, matching the async failure path
242
+ this.#handle_error(item, to_error_message(error));
243
+ return false;
244
+ }
245
+ if (is_promise(returned)) {
246
+ item.pending = true;
247
+ item.error_message = null;
248
+ const promise = (item.promise = returned
249
+ .then((result) => {
250
+ if (promise !== item.promise)
251
+ return;
252
+ this.#handle_result(item, result);
253
+ return result;
254
+ }, (err) => {
255
+ if (promise !== item.promise)
256
+ return;
257
+ this.#handle_error(item, to_error_message(err));
258
+ })
259
+ .finally(() => {
260
+ if (promise !== item.promise)
261
+ return;
262
+ item.pending = false;
263
+ item.promise = null;
264
+ }));
265
+ return item.promise; // async path
266
+ }
267
+ // synchronous path
268
+ return this.#handle_result(item, returned);
269
+ }
270
+ /**
271
+ * Activates the selected item, or if none is selected, selects the first.
272
+ * Returns `false` without activating when the selected item has unregistered
273
+ * out from under the selection (e.g. its component unmounted).
274
+ */
194
275
  activate_selected() {
195
276
  const selected = this.selections.at(-1);
196
277
  if (selected) {
278
+ if (!selected.menu.items.includes(selected))
279
+ return false;
197
280
  return this.activate(selected);
198
281
  }
199
282
  this.select_first();
@@ -203,7 +286,7 @@ export class ContextmenuState {
203
286
  // Could be improved but it's fine because we're using mutation and the N is very small,
204
287
  // and it allows us to have a single code path for the various selection methods.
205
288
  /**
206
- * Activates the selected entry, or if none, selects the first.
289
+ * Selects `item` and its ancestor menus, deselecting everything else.
207
290
  */
208
291
  // TODO implement focus management per APG: call .focus() on the selected item's DOM element (requires storing element refs in EntryState/SubmenuState)
209
292
  select(item) {
@@ -243,6 +326,11 @@ export class ContextmenuState {
243
326
  }
244
327
  const item = this.selections.at(-1);
245
328
  const index = item.menu.items.indexOf(item);
329
+ if (index === -1) {
330
+ // the selected item unregistered out from under the selection - restart
331
+ this.select_first();
332
+ return;
333
+ }
246
334
  this.select(item.menu.items[index === item.menu.items.length - 1 ? 0 : index + 1]);
247
335
  }
248
336
  select_previous() {
@@ -252,6 +340,11 @@ export class ContextmenuState {
252
340
  }
253
341
  const item = this.selections.at(-1);
254
342
  const index = item.menu.items.indexOf(item);
343
+ if (index === -1) {
344
+ // the selected item unregistered out from under the selection - restart
345
+ this.select_last();
346
+ return;
347
+ }
255
348
  this.select(item.menu.items[index === 0 ? item.menu.items.length - 1 : index - 1]);
256
349
  }
257
350
  select_first() {
@@ -273,10 +366,9 @@ export class ContextmenuState {
273
366
  add_entry(run, disabled = () => false) {
274
367
  const menu = contextmenu_submenu_context.get_maybe() ?? this.root_menu;
275
368
  const entry = new EntryState(menu, run, disabled);
276
- menu.items = [...menu.items, entry];
277
- // TODO messy, runs more than needed
369
+ menu.add_item(entry);
278
370
  onDestroy(() => {
279
- menu.items = [];
371
+ menu.remove_item(entry);
280
372
  });
281
373
  return entry;
282
374
  }
@@ -286,38 +378,33 @@ export class ContextmenuState {
286
378
  add_submenu() {
287
379
  const menu = contextmenu_submenu_context.get_maybe() ?? this.root_menu;
288
380
  const submenu = new SubmenuState(menu, menu.depth + 1);
289
- menu.items = [...menu.items, submenu];
381
+ menu.add_item(submenu);
290
382
  contextmenu_submenu_context.set(submenu);
291
- // TODO messy, runs more than needed
292
383
  onDestroy(() => {
293
- menu.items = [];
384
+ menu.remove_item(submenu);
294
385
  });
295
386
  return submenu;
296
387
  }
297
388
  }
389
+ // The dataset attribute is only a crawl marker for `contextmenu_query_params` -
390
+ // the params themselves live in `contextmenu_params_by_element`, keyed by element.
298
391
  // The dataset key must not have capital letters or dashes or it'll differ between JS and DOM:
299
392
  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset
300
393
  const CONTEXTMENU_DATASET_KEY = 'contextmenu';
301
394
  const CONTEXTMENU_DOM_QUERY = `a,[data-${CONTEXTMENU_DATASET_KEY}]`;
302
- const contextmenu_cache = new Map();
303
- let cache_key_counter = 0;
395
+ const contextmenu_params_by_element = new WeakMap();
304
396
  /**
305
397
  * Creates an attachment that sets up contextmenu behavior on an element.
306
398
  * @param params - contextmenu parameters or nullish to disable
307
399
  */
308
400
  export const contextmenu_attachment = (params) => (el) => {
309
- // TODO could clean up the dataset attr, maybe use a weakmap?
310
401
  if (params == null)
311
402
  return;
312
- // Only create key once per element, reuse on updates
313
- let key = el.dataset[CONTEXTMENU_DATASET_KEY];
314
- if (!key) {
315
- key = cache_key_counter++ + '';
316
- el.dataset[CONTEXTMENU_DATASET_KEY] = key;
317
- }
318
- contextmenu_cache.set(key, params);
403
+ el.dataset[CONTEXTMENU_DATASET_KEY] = '';
404
+ contextmenu_params_by_element.set(el, params);
319
405
  return () => {
320
- contextmenu_cache.delete(key);
406
+ contextmenu_params_by_element.delete(el);
407
+ delete el.dataset[CONTEXTMENU_DATASET_KEY]; // eslint-disable-line @typescript-eslint/no-dynamic-delete
321
408
  };
322
409
  };
323
410
  const CONTEXTMENU_OPEN_VIBRATE_DURATION = 17;
@@ -325,9 +412,9 @@ const CONTEXTMENU_OPEN_VIBRATE_DURATION = 17;
325
412
  * Opens the contextmenu, if appropriate,
326
413
  * querying the menu items from the DOM starting at the event target.
327
414
  * @param target - the leaf element from which to open the contextmenu
328
- * @param x - the page X coordinate at which to open the contextmenu, typically the mouse `pageX`
329
- * @param y - the page Y coordinate at which to open the contextmenu, typically the mouse `pageY`
330
- * @param contextmenu - the contextmenu store
415
+ * @param x - the client (viewport) X coordinate at which to open the contextmenu, typically the mouse `clientX` - the menu positions with `fixed`
416
+ * @param y - the client (viewport) Y coordinate at which to open the contextmenu, typically the mouse `clientY` - the menu positions with `fixed`
417
+ * @param contextmenu - the contextmenu state
331
418
  * @param options - optional configuration for filtering entries and haptic feedback
332
419
  * @returns a boolean indicating if the menu was opened or not
333
420
  */
@@ -340,7 +427,7 @@ export const contextmenu_open = (target, x, y, contextmenu, options) => {
340
427
  // No-op if empty
341
428
  if (!params?.length)
342
429
  return false;
343
- contextmenu.open(params, x, y);
430
+ contextmenu.open(params, x, y, target);
344
431
  // `navigator.vibrate()` works with `ContextmenuRoot` but gets blocked by some browsers
345
432
  // when used with `ContextmenuRootForSafariCompatibility` because its longpress
346
433
  // workaround triggers from a timeout rather than a direct user interaction.
@@ -353,20 +440,17 @@ const contextmenu_query_params = (target) => {
353
440
  let params = null;
354
441
  // crawl DOM for contextmenu entries
355
442
  let el = target;
356
- let cache_key, cached;
357
443
  while ((el = el?.closest(CONTEXTMENU_DOM_QUERY))) {
358
- if ((cache_key = el.dataset[CONTEXTMENU_DATASET_KEY])) {
359
- params ??= [];
360
- cached = contextmenu_cache.get(cache_key);
361
- if (cached === undefined) {
362
- continue;
363
- }
444
+ // Params may be missing when the element matched as a bare `<a>`, or when a
445
+ // stale marker was left behind - treat the element as having no registered entries.
446
+ const registered = contextmenu_params_by_element.get(el);
447
+ if (registered !== undefined) {
364
448
  // preserve bubbling order
365
- if (Array.isArray(cached)) {
366
- (params ??= []).push(...cached);
449
+ if (Array.isArray(registered)) {
450
+ (params ??= []).push(...registered);
367
451
  }
368
452
  else {
369
- (params ??= []).push(cached);
453
+ (params ??= []).push(registered);
370
454
  }
371
455
  }
372
456
  if (el.tagName === 'A') {
@@ -386,7 +470,7 @@ const contextmenu_query_params = (target) => {
386
470
  snippet: 'text',
387
471
  props: {
388
472
  content: 'copy text',
389
- icon: '📋',
473
+ icon: icon_copy,
390
474
  run: async () => {
391
475
  await navigator.clipboard.writeText(text);
392
476
  },
@@ -400,11 +484,14 @@ const contextmenu_query_params = (target) => {
400
484
  const non_scoped_roots = new Set();
401
485
  /**
402
486
  * Registers a contextmenu root and warns if multiple non-scoped roots are detected.
403
- * Only active in development mode. Automatically handles cleanup on unmount.
487
+ * Only active in development mode - `DEV` is a build-time constant, so production
488
+ * bundles eliminate the check. Automatically handles cleanup on unmount.
404
489
  *
405
490
  * @param get_scoped - getter function that returns the current scoped value
406
491
  */
407
492
  export const contextmenu_check_global_root = (get_scoped) => {
493
+ if (!DEV)
494
+ return;
408
495
  $effect(() => {
409
496
  const id = Symbol('contextmenu_root');
410
497
  if (!get_scoped()) {
@@ -296,6 +296,7 @@ export declare class Declaration {
296
296
  /**
297
297
  * Other modules that also export this declaration (re-export paths
298
298
  * relative to src/lib). Absent when only exported from its defining module.
299
+ * The back-link of those modules' `Module.re_exports` edges.
299
300
  */
300
301
  also_exported_from: string[] | undefined;
301
302
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"declaration.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/declaration.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,oBAAoB,EAMpB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAC;AAc/C;;;;;;;;;;GAUG;AACH,qBAAa,WAAW;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAiB;IACxC,QAAQ,CAAC,gBAAgB,EAAE,oBAAoB,CAAiB;IAEhE,OAAO,wCAAiC;IAExC;;OAEG;IACH,WAAW,SAA8B;IAEzC,IAAI,SAAwC;IAC5C,IAAI,4GAAwC;IAE5C;;OAEG;IACH,UAAU,qBAQR;IAEF;;OAEG;IACH,OAAO,SAAoF;IAE3F;;OAEG;IACH,gBAAgB,SAQd;IAEF;;OAEG;IACH,YAAY,qBAIV;IAEF;;OAEG;IAGH,YAAY,SAKV;IAEF,cAAc,qBAAiD;IAC/D,WAAW,qBAA8C;IACzD,kBAAkB,qBAAqD;IACvE,UAAU;;;;;;;;oBAAmF;IAC7F,KAAK;;;;;;;;;;;;;;;;;;;;;;;;oBAAkF;IACvF,WAAW,qBAAgE;IAC3E,kBAAkB,qBAAuE;IACzF,cAAc;;;;QAAuD;IACrE,YAAY,gCAA6E;IACzF,gBAAgB,uBAAuE;IACvF,MAAM;;;QAAgD;IACtD,KAAK,qBAAyC;IAC9C,QAAQ,WAAkD;IAC1D,QAAQ,WAAiD;IACzD;;OAEG;IACH,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAA6E;IAEpF;;;OAGG;IACH,UAAU,uBAAuE;IAEjF;;;OAGG;IACH,gBAAgB,sBAAsE;IAEtF;;;OAGG;IACH,SAAS;;;;;;;;;;;;;;;;;;;oBAAiF;IAE1F;;OAEG;IACH,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAA2C;IAEnD;;;OAGG;IACH,kBAAkB,uBAA6E;IAE/F;;OAEG;IACH,OAAO,qCAA2C;IAElD;;;;OAIG;IACH,UAAU,mEAAoE;IAE9E,YAAY,UAAsC;IAElD,aAAa,UAAmD;IAChE,iBAAiB,UAAgC;IACjD,cAAc,UAA+D;IAC7E,SAAS,UAAqD;IAC9D,YAAY,UAA4C;gBAE5C,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,oBAAoB;CAIlE"}
1
+ {"version":3,"file":"declaration.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/declaration.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,oBAAoB,EAMpB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAC;AAc/C;;;;;;;;;;GAUG;AACH,qBAAa,WAAW;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAiB;IACxC,QAAQ,CAAC,gBAAgB,EAAE,oBAAoB,CAAiB;IAEhE,OAAO,wCAAiC;IAExC;;OAEG;IACH,WAAW,SAA8B;IAEzC,IAAI,SAAwC;IAC5C,IAAI,4GAAwC;IAE5C;;OAEG;IACH,UAAU,qBAQR;IAEF;;OAEG;IACH,OAAO,SAAoF;IAE3F;;OAEG;IACH,gBAAgB,SAQd;IAEF;;OAEG;IACH,YAAY,qBAIV;IAEF;;OAEG;IAGH,YAAY,SAKV;IAEF,cAAc,qBAAiD;IAC/D,WAAW,qBAA8C;IACzD,kBAAkB,qBAAqD;IACvE,UAAU;;;;;;;;oBAAmF;IAC7F,KAAK;;;;;;;;;;;;;;;;;;;;;;;;oBAAkF;IACvF,WAAW,qBAAgE;IAC3E,kBAAkB,qBAAuE;IACzF,cAAc;;;;QAAuD;IACrE,YAAY,gCAA6E;IACzF,gBAAgB,uBAAuE;IACvF,MAAM;;;QAAgD;IACtD,KAAK,qBAAyC;IAC9C,QAAQ,WAAkD;IAC1D,QAAQ,WAAiD;IACzD;;OAEG;IACH,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAA6E;IAEpF;;;OAGG;IACH,UAAU,uBAAuE;IAEjF;;;OAGG;IACH,gBAAgB,sBAAsE;IAEtF;;;OAGG;IACH,SAAS;;;;;;;;;;;;;;;;;;;oBAAiF;IAE1F;;OAEG;IACH,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAA2C;IAEnD;;;;OAIG;IACH,kBAAkB,uBAAoD;IAEtE;;OAEG;IACH,OAAO,qCAA2C;IAElD;;;;OAIG;IACH,UAAU,mEAAoE;IAE9E,YAAY,UAAsC;IAElD,aAAa,UAAmD;IAChE,iBAAiB,UAAgC;IACjD,cAAc,UAA+D;IAC7E,SAAS,UAAqD;IAC9D,YAAY,UAA4C;gBAE5C,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,oBAAoB;CAIlE"}
@@ -102,8 +102,9 @@ export class Declaration {
102
102
  /**
103
103
  * Other modules that also export this declaration (re-export paths
104
104
  * relative to src/lib). Absent when only exported from its defining module.
105
+ * The back-link of those modules' `Module.re_exports` edges.
105
106
  */
106
- also_exported_from = $derived(field(this.declaration_json, 'alsoExportedFrom'));
107
+ also_exported_from = $derived(this.declaration_json.alsoExportedFrom);
107
108
  /**
108
109
  * Mutation documentation from `@mutates` tags, mapping parameter names to descriptions.
109
110
  */
package/dist/icons.d.ts CHANGED
@@ -130,6 +130,12 @@ export declare const icon_pause: {
130
130
  d: string;
131
131
  }[];
132
132
  };
133
+ export declare const icon_stop: {
134
+ label: string;
135
+ paths: {
136
+ d: string;
137
+ }[];
138
+ };
133
139
  export declare const icon_checkmark: {
134
140
  label: string;
135
141
  paths: {
@@ -412,19 +418,25 @@ export declare const icon_session: {
412
418
  d: string;
413
419
  }[];
414
420
  };
415
- export declare const icon_action_type_local_call: {
421
+ export declare const icon_action_local_call: {
422
+ label: string;
423
+ paths: {
424
+ d: string;
425
+ }[];
426
+ };
427
+ export declare const icon_action_remote_notification: {
416
428
  label: string;
417
429
  paths: {
418
430
  d: string;
419
431
  }[];
420
432
  };
421
- export declare const icon_action_type_remote_notification: {
433
+ export declare const icon_action_request_response: {
422
434
  label: string;
423
435
  paths: {
424
436
  d: string;
425
437
  }[];
426
438
  };
427
- export declare const icon_action_type_request_response: {
439
+ export declare const icon_link: {
428
440
  label: string;
429
441
  paths: {
430
442
  d: string;
@@ -1 +1 @@
1
- {"version":3,"file":"icons.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/icons.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/icons.ts"],"names":[],"mappings":"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"}
package/dist/icons.js CHANGED
@@ -155,6 +155,12 @@ export const icon_pause = {
155
155
  },
156
156
  ],
157
157
  };
158
+ export const icon_stop = {
159
+ label: 'stop',
160
+ paths: [
161
+ { d: 'M30 23H70A7 7 0 0 1 77 30V70A7 7 0 0 1 70 77H30A7 7 0 0 1 23 70V30A7 7 0 0 1 30 23Z' },
162
+ ],
163
+ };
158
164
  // --- Validation ---
159
165
  export const icon_checkmark = {
160
166
  label: 'checkmark',
@@ -507,7 +513,7 @@ export const icon_session = {
507
513
  ],
508
514
  };
509
515
  // --- Action Types ---
510
- export const icon_action_type_local_call = {
516
+ export const icon_action_local_call = {
511
517
  label: 'local call, lightning bolt to target',
512
518
  paths: [
513
519
  {
@@ -518,7 +524,7 @@ export const icon_action_type_local_call = {
518
524
  },
519
525
  ],
520
526
  };
521
- export const icon_action_type_remote_notification = {
527
+ export const icon_action_remote_notification = {
522
528
  label: 'remote notification, lightning bolt with signal',
523
529
  paths: [
524
530
  {
@@ -528,7 +534,7 @@ export const icon_action_type_remote_notification = {
528
534
  { d: 'M78 27a27 27 0 0 1 0 46 24 24 0 0 0 0-46z' },
529
535
  ],
530
536
  };
531
- export const icon_action_type_request_response = {
537
+ export const icon_action_request_response = {
532
538
  label: 'request response, opposing lightning bolts',
533
539
  paths: [
534
540
  {
@@ -537,6 +543,14 @@ export const icon_action_type_request_response = {
537
543
  ],
538
544
  };
539
545
  // --- Links ---
546
+ export const icon_link = {
547
+ label: 'link, diagonal chain',
548
+ paths: [
549
+ {
550
+ d: 'M34 53A20 20 0 1 1 53 34L44 33.6A11 11 0 1 0 33.6 44ZM66 47A20 20 0 1 1 47 66L56 66.4A11 11 0 1 0 66.4 56ZM34.4 41.5L58.5 65.6L65.6 58.5L41.5 34.4Z',
551
+ },
552
+ ],
553
+ };
540
554
  export const icon_external_link = {
541
555
  label: 'external link, arrow out of box',
542
556
  paths: [