@fuzdev/fuz_ui 0.201.0 → 0.203.0

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 (85) 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 +11 -10
  8. package/dist/ContextmenuEntry.svelte.d.ts +1 -1
  9. package/dist/ContextmenuEntry.svelte.d.ts.map +1 -1
  10. package/dist/ContextmenuLinkEntry.svelte +30 -12
  11. package/dist/ContextmenuLinkEntry.svelte.d.ts +2 -1
  12. package/dist/ContextmenuLinkEntry.svelte.d.ts.map +1 -1
  13. package/dist/ContextmenuMenu.svelte +207 -0
  14. package/dist/ContextmenuMenu.svelte.d.ts +41 -0
  15. package/dist/ContextmenuMenu.svelte.d.ts.map +1 -0
  16. package/dist/ContextmenuRoot.svelte +58 -260
  17. package/dist/ContextmenuRoot.svelte.d.ts +2 -60
  18. package/dist/ContextmenuRoot.svelte.d.ts.map +1 -1
  19. package/dist/ContextmenuRootForSafariCompatibility.svelte +72 -283
  20. package/dist/ContextmenuRootForSafariCompatibility.svelte.d.ts +2 -58
  21. package/dist/ContextmenuRootForSafariCompatibility.svelte.d.ts.map +1 -1
  22. package/dist/ContextmenuSeparator.svelte +2 -1
  23. package/dist/ContextmenuSeparator.svelte.d.ts.map +1 -1
  24. package/dist/ContextmenuSubmenu.svelte +27 -23
  25. package/dist/ContextmenuSubmenu.svelte.d.ts +1 -1
  26. package/dist/ContextmenuSubmenu.svelte.d.ts.map +1 -1
  27. package/dist/ContextmenuTextEntry.svelte +7 -3
  28. package/dist/ContextmenuTextEntry.svelte.d.ts +2 -1
  29. package/dist/ContextmenuTextEntry.svelte.d.ts.map +1 -1
  30. package/dist/CopyToClipboard.svelte +5 -2
  31. package/dist/CopyToClipboard.svelte.d.ts.map +1 -1
  32. package/dist/DeclarationLink.svelte +15 -2
  33. package/dist/DeclarationLink.svelte.d.ts +7 -0
  34. package/dist/DeclarationLink.svelte.d.ts.map +1 -1
  35. package/dist/DialogContent.svelte +3 -1
  36. package/dist/DialogContent.svelte.d.ts.map +1 -1
  37. package/dist/Docs.svelte +11 -8
  38. package/dist/Docs.svelte.d.ts.map +1 -1
  39. package/dist/DocsLink.svelte +3 -1
  40. package/dist/DocsLink.svelte.d.ts.map +1 -1
  41. package/dist/DocsSearch.svelte +4 -1
  42. package/dist/DocsSearch.svelte.d.ts.map +1 -1
  43. package/dist/DocsTertiaryNav.svelte +2 -1
  44. package/dist/DocsTertiaryNav.svelte.d.ts.map +1 -1
  45. package/dist/LibraryDetail.svelte +9 -3
  46. package/dist/LibraryDetail.svelte.d.ts +1 -1
  47. package/dist/LibraryDetail.svelte.d.ts.map +1 -1
  48. package/dist/ModuleLink.svelte +2 -1
  49. package/dist/ModuleLink.svelte.d.ts.map +1 -1
  50. package/dist/Svg.svelte +46 -9
  51. package/dist/Svg.svelte.d.ts.map +1 -1
  52. package/dist/TypeLink.svelte +2 -1
  53. package/dist/TypeLink.svelte.d.ts.map +1 -1
  54. package/dist/contextmenu_helpers.d.ts +324 -1
  55. package/dist/contextmenu_helpers.d.ts.map +1 -1
  56. package/dist/contextmenu_helpers.js +403 -2
  57. package/dist/contextmenu_state.svelte.d.ts +61 -15
  58. package/dist/contextmenu_state.svelte.d.ts.map +1 -1
  59. package/dist/contextmenu_state.svelte.js +206 -119
  60. package/dist/declaration.svelte.d.ts +1 -0
  61. package/dist/declaration.svelte.d.ts.map +1 -1
  62. package/dist/declaration.svelte.js +2 -1
  63. package/dist/icons.d.ts +469 -0
  64. package/dist/icons.d.ts.map +1 -0
  65. package/dist/icons.js +578 -0
  66. package/dist/library.svelte.d.ts +30 -3
  67. package/dist/library.svelte.d.ts.map +1 -1
  68. package/dist/library.svelte.js +38 -0
  69. package/dist/logos.d.ts +1 -3
  70. package/dist/logos.d.ts.map +1 -1
  71. package/dist/logos.js +1 -1
  72. package/dist/module.svelte.d.ts +62 -1
  73. package/dist/module.svelte.d.ts.map +1 -1
  74. package/dist/module.svelte.js +71 -1
  75. package/dist/svg.d.ts +69 -10
  76. package/dist/svg.d.ts.map +1 -1
  77. package/package.json +2 -2
  78. package/src/lib/contextmenu_helpers.ts +546 -3
  79. package/src/lib/contextmenu_state.svelte.ts +219 -119
  80. package/src/lib/declaration.svelte.ts +2 -1
  81. package/src/lib/icons.ts +671 -0
  82. package/src/lib/library.svelte.ts +43 -1
  83. package/src/lib/logos.ts +1 -1
  84. package/src/lib/module.svelte.ts +97 -2
  85. package/src/lib/svg.ts +70 -9
@@ -15,7 +15,49 @@ import {
15
15
  url_npm_package,
16
16
  } from '@fuzdev/fuz_util/package_helpers.js';
17
17
 
18
- export const library_context = create_context<Library>();
18
+ /**
19
+ * Holds a getter to the active `Library` for the current subtree.
20
+ *
21
+ * The getter form keeps consumers reactive when the library changes without
22
+ * requiring a remount — set it with a closure over reactive state, e.g.
23
+ * `library_context.set(() => library)`. Components that accept a `library`
24
+ * prop (`LibraryDetail`, `ApiIndex`, `ApiModule`) project the prop into this
25
+ * context for their subtree, so descendants like `ModuleLink`,
26
+ * `DeclarationLink`, and TSDoc-rendered `DocsLink` resolve against the same
27
+ * library — including when an aggregator renders a foreign library that
28
+ * differs from the site-level context.
29
+ */
30
+ export const library_context = create_context<() => Library>();
31
+
32
+ /**
33
+ * Sets `library_context` for the component's subtree to a getter that prefers
34
+ * the component's `library` prop and falls back to the ancestor's value,
35
+ * returning the resolved getter.
36
+ *
37
+ * Pass `get_library_prop` as a getter (not a snapshot) so prop changes remain
38
+ * reactive. The ancestor lookup happens once at component init, before the
39
+ * projection — the fallback sees the parent value, not the projection.
40
+ *
41
+ * @param get_library_prop - Getter for the component's `library` prop. A thunk so the prop stays reactive.
42
+ * @param component_name - Used in the error when neither the prop nor the context provides a library.
43
+ * @returns getter for the resolved library; read it lazily, e.g. `$derived(get_library())`
44
+ * @initializes
45
+ */
46
+ export const set_library_context_with_fallback = (
47
+ get_library_prop: () => Library | undefined,
48
+ component_name: string,
49
+ ): (() => Library) => {
50
+ const get_outer = library_context.get_maybe();
51
+ const get_library = (): Library => {
52
+ const value = get_library_prop() ?? get_outer?.();
53
+ if (!value) {
54
+ throw Error(`${component_name} requires a \`library\` prop or a set \`library_context\``);
55
+ }
56
+ return value;
57
+ };
58
+ library_context.set(get_library);
59
+ return get_library;
60
+ };
19
61
 
20
62
  /**
21
63
  * Normalizes a URL prefix: ensures leading `/`, strips trailing `/`, returns `''` for falsy and non-string values.
package/src/lib/logos.ts CHANGED
@@ -73,7 +73,7 @@ export const logo_fuz_css = {
73
73
  label: 'a fuzzy tuft of green moss',
74
74
  fill: '#3db33d',
75
75
  paths: logo_fuz.paths,
76
- attrs: {style: 'transform: scaleX(-1) rotate(180deg)'},
76
+ style: 'transform: scaleX(-1) rotate(180deg)',
77
77
  } satisfies SvgData;
78
78
 
79
79
  export const logo_fuz_ui = {
@@ -1,9 +1,34 @@
1
- import type {ModuleJsonInput} from 'svelte-docinfo/types.js';
1
+ import type {
2
+ ModuleJsonInput,
3
+ ReExportJsonInput,
4
+ ExternalReExportJsonInput,
5
+ } from 'svelte-docinfo/types.js';
2
6
 
3
7
  import {Declaration} from './declaration.svelte.js';
4
8
  import type {Library} from './library.svelte.js';
5
9
  import {url_github_file} from '@fuzdev/fuz_util/package_helpers.js';
6
10
 
11
+ /**
12
+ * Groups entries by a string key, with groups sorted by key. Entries within
13
+ * each group keep their input order.
14
+ */
15
+ const group_sorted = <T>(
16
+ entries: Array<T>,
17
+ get_key: (entry: T) => string,
18
+ ): Map<string, Array<T>> => {
19
+ const by_key: Map<string, Array<T>> = new Map();
20
+ for (const entry of entries) {
21
+ const key = get_key(entry);
22
+ let group = by_key.get(key);
23
+ if (!group) {
24
+ group = [];
25
+ by_key.set(key, group);
26
+ }
27
+ group.push(entry);
28
+ }
29
+ return new Map([...by_key].sort(([a], [b]) => a.localeCompare(b)));
30
+ };
31
+
7
32
  /**
8
33
  * Rich runtime representation of a module with computed properties.
9
34
  *
@@ -76,7 +101,11 @@ export class Module {
76
101
  : undefined,
77
102
  );
78
103
 
79
- has_declarations: boolean = $derived((this.module_json.declarations?.length ?? 0) > 0);
104
+ /**
105
+ * Whether the module has renderable declarations (after the default-export
106
+ * filter in `declarations`).
107
+ */
108
+ has_declarations: boolean = $derived(this.declarations.length > 0);
80
109
 
81
110
  has_module_comment: boolean = $derived(!!this.module_comment);
82
111
 
@@ -94,6 +123,72 @@ export class Module {
94
123
 
95
124
  has_dependents: boolean = $derived(this.dependents.length > 0);
96
125
 
126
+ /**
127
+ * Same-name re-export edges in this module's source (`ModuleJson.reExports`)
128
+ * — the forward view of declarations' `alsoExportedFrom`, sorted by name
129
+ * then module. Renamed re-exports appear as declarations with `aliasOf`
130
+ * instead, and star exports in `star_exports`.
131
+ */
132
+ re_exports = $derived(this.module_json.reExports ?? []);
133
+
134
+ has_re_exports: boolean = $derived(this.re_exports.length > 0);
135
+
136
+ /**
137
+ * Modules fully re-exported via `export * from './module'`
138
+ * (`ModuleJson.starExports`), in source order. Star-projected symbols are
139
+ * not materialized as declarations or `re_exports` edges — this is their
140
+ * sole encoding.
141
+ */
142
+ star_exports = $derived(this.module_json.starExports ?? []);
143
+
144
+ has_star_exports: boolean = $derived(this.star_exports.length > 0);
145
+
146
+ /**
147
+ * Re-export edges grouped by canonical module path, groups sorted by path.
148
+ * Entries within each group keep their name-sorted serialized order.
149
+ */
150
+ re_exports_by_module: Map<string, Array<ReExportJsonInput>> = $derived(
151
+ group_sorted(this.re_exports, (entry) => entry.module),
152
+ );
153
+
154
+ /**
155
+ * Re-exports whose immediate target is an external package
156
+ * (`ModuleJson.externalReExports`) — `export {x} from 'pkg'` and
157
+ * `export * as ns from 'pkg'` forms, sorted by name then specifier.
158
+ */
159
+ external_re_exports = $derived(this.module_json.externalReExports ?? []);
160
+
161
+ has_external_re_exports: boolean = $derived(this.external_re_exports.length > 0);
162
+
163
+ /**
164
+ * External re-exports grouped by package specifier, groups sorted by
165
+ * specifier. Entries within each group keep their name-sorted serialized
166
+ * order.
167
+ */
168
+ external_re_exports_by_specifier: Map<string, Array<ExternalReExportJsonInput>> = $derived(
169
+ group_sorted(this.external_re_exports, (entry) => entry.specifier),
170
+ );
171
+
172
+ /**
173
+ * External packages fully re-exported via `export * from 'pkg'`
174
+ * (`ModuleJson.externalStarExports`), in source order. The projected
175
+ * names are unknown — the package isn't analyzed.
176
+ */
177
+ external_star_exports = $derived(this.module_json.externalStarExports ?? []);
178
+
179
+ has_external_star_exports: boolean = $derived(this.external_star_exports.length > 0);
180
+
181
+ /**
182
+ * Whether the module re-exports anything in any form — same-name edges,
183
+ * star exports, or the external variants of both.
184
+ */
185
+ has_any_re_exports: boolean = $derived(
186
+ this.has_re_exports ||
187
+ this.has_star_exports ||
188
+ this.has_external_re_exports ||
189
+ this.has_external_star_exports,
190
+ );
191
+
97
192
  constructor(library: Library, module_json: ModuleJsonInput) {
98
193
  this.library = library;
99
194
  this.module_json = module_json;
package/src/lib/svg.ts CHANGED
@@ -1,23 +1,84 @@
1
1
  import type {SvelteHTMLElements} from 'svelte/elements';
2
2
 
3
+ /**
4
+ * A structured icon definition rendered by `Svg.svelte`. Rendering is purely
5
+ * structural - typed fields, never raw markup - so untrusted data cannot
6
+ * introduce script execution or navigation. See `Svg.svelte` for the full
7
+ * security notes, including the residual `style` `url(...)` caveat.
8
+ */
3
9
  export interface SvgData {
4
10
  /**
5
- * Raw svg markup string that's inserted unsafely as a child of the `svg` element.
6
- * This is an escape hatch for non-`path` markup -
7
- * generally, you should instead use the `paths` property to avoid security/CSP implications.
11
+ * List of svg `path` attribute objects, spread onto each `path` element. The
12
+ * `d` attribute is required; a per-path `fill` overrides the resolved `fill`.
8
13
  */
9
- raw?: string | null;
14
+ paths?: Array<{d: string} & SvelteHTMLElements['path']> | null;
10
15
  /**
11
- * List of svg `path` attribute objects. The `d` attribute is required.
16
+ * Inline `style` applied to the root `svg` element, merged with any `style`
17
+ * passed as a component prop. Travels with the icon definition - per-instance
18
+ * svg attributes belong on the `Svg` component itself.
19
+ */
20
+ style?: string | null;
21
+ /**
22
+ * Default `fill` for every `path`, falling back to `var(--text_color, #000)`.
23
+ * Overridden by the component's `fill` prop, and per-path by a path's own `fill`.
12
24
  */
13
- paths?: Array<{d: string} & SvelteHTMLElements['path']> | null;
14
- attrs?: SvelteHTMLElements['svg'] | null;
15
25
  fill?: string | null;
16
- width?: string | null;
17
- height?: string | null;
26
+ /**
27
+ * Accessible name, applied as `aria-label`. Overridden by the component's `label` prop.
28
+ */
18
29
  label?: string | null;
19
30
  /**
20
31
  * Defaults to `"0 0 100 100"`.
21
32
  */
22
33
  viewBox?: string | null;
34
+ /**
35
+ * Gradient definitions rendered into the svg's `<defs>` block. This is the
36
+ * structured replacement for raw markup - reference a gradient from a
37
+ * path/shape `fill` or `stroke` with `url(#id)`. Most svgs need only `paths`.
38
+ */
39
+ gradients?: Array<SvgGradient> | null;
40
+ }
41
+
42
+ /**
43
+ * A gradient definition rendered into the svg's `<defs>` block. Reference it
44
+ * from a path/shape `fill` or `stroke` with `url(#id)`.
45
+ */
46
+ export interface SvgGradient {
47
+ /**
48
+ * Whether to render a `linearGradient` or `radialGradient` element.
49
+ */
50
+ type: 'linear' | 'radial';
51
+ /**
52
+ * The `id` referenced by a `fill`/`stroke` like `url(#id)`. Inline svgs share
53
+ * the document's id namespace, so pick a value unique to the icon - icons
54
+ * with colliding ids all resolve to whichever element renders first.
55
+ */
56
+ id: string;
57
+ /**
58
+ * The gradient's color stops.
59
+ */
60
+ stops: Array<SvgGradientStop>;
61
+ /**
62
+ * Additional attributes on the gradient element, e.g. `gradientUnits`,
63
+ * `gradientTransform`, `cx`/`cy`/`r` (radial), or `x1`/`y1`/`x2`/`y2` (linear).
64
+ */
65
+ attrs?: (SvelteHTMLElements['radialGradient'] & SvelteHTMLElements['linearGradient']) | null;
66
+ }
67
+
68
+ /**
69
+ * A single color stop of an `SvgGradient`.
70
+ */
71
+ export interface SvgGradientStop {
72
+ /**
73
+ * The stop's position along the gradient, e.g. `0.5` or `"50%"`.
74
+ */
75
+ offset: string | number;
76
+ /**
77
+ * The stop's color, applied as the `stop-color` attribute.
78
+ */
79
+ color: string;
80
+ /**
81
+ * The stop's opacity, applied as the `stop-opacity` attribute.
82
+ */
83
+ opacity?: string | number | null;
23
84
  }