ngwr 14.4.0 → 14.5.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 (163) hide show
  1. package/README.md +12 -6
  2. package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
  3. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  4. package/fesm2022/ngwr-cascader.mjs +15 -3
  5. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  6. package/fesm2022/ngwr-color-picker.mjs +18 -2
  7. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  8. package/fesm2022/ngwr-context-menu.mjs +35 -3
  9. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  10. package/fesm2022/ngwr-date-picker.mjs +30 -2
  11. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  12. package/fesm2022/ngwr-dialog.mjs +12 -1
  13. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  14. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  15. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  16. package/fesm2022/ngwr-drawer.mjs +48 -2
  17. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  18. package/fesm2022/ngwr-dropdown.mjs +22 -2
  19. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  20. package/fesm2022/ngwr-graph-testing.mjs +243 -0
  21. package/fesm2022/ngwr-graph-testing.mjs.map +1 -0
  22. package/fesm2022/ngwr-graph.mjs +1112 -0
  23. package/fesm2022/ngwr-graph.mjs.map +1 -0
  24. package/fesm2022/ngwr-i18n-ar.mjs +5 -0
  25. package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
  26. package/fesm2022/ngwr-i18n-cs.mjs +5 -0
  27. package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
  28. package/fesm2022/ngwr-i18n-de.mjs +5 -0
  29. package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
  30. package/fesm2022/ngwr-i18n-en.mjs +25 -5
  31. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  32. package/fesm2022/ngwr-i18n-es.mjs +5 -0
  33. package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
  34. package/fesm2022/ngwr-i18n-fr.mjs +5 -0
  35. package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
  36. package/fesm2022/ngwr-i18n-he.mjs +5 -0
  37. package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
  38. package/fesm2022/ngwr-i18n-hi.mjs +5 -0
  39. package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
  40. package/fesm2022/ngwr-i18n-id.mjs +5 -0
  41. package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
  42. package/fesm2022/ngwr-i18n-it.mjs +5 -0
  43. package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
  44. package/fesm2022/ngwr-i18n-ja.mjs +5 -0
  45. package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
  46. package/fesm2022/ngwr-i18n-ko.mjs +5 -0
  47. package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
  48. package/fesm2022/ngwr-i18n-nl.mjs +5 -0
  49. package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
  50. package/fesm2022/ngwr-i18n-pl.mjs +5 -0
  51. package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
  52. package/fesm2022/ngwr-i18n-pt.mjs +5 -0
  53. package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
  54. package/fesm2022/ngwr-i18n-ru.mjs +5 -0
  55. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  56. package/fesm2022/ngwr-i18n-sv.mjs +5 -0
  57. package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
  58. package/fesm2022/ngwr-i18n-tr.mjs +5 -0
  59. package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
  60. package/fesm2022/ngwr-i18n-uk.mjs +5 -0
  61. package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
  62. package/fesm2022/ngwr-i18n-vi.mjs +5 -0
  63. package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
  64. package/fesm2022/ngwr-i18n-zh-TW.mjs +5 -0
  65. package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
  66. package/fesm2022/ngwr-i18n-zh.mjs +5 -0
  67. package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
  68. package/fesm2022/ngwr-i18n.mjs +13 -0
  69. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  70. package/fesm2022/ngwr-lightbox.mjs +25 -4
  71. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  72. package/fesm2022/ngwr-list.mjs +2 -2
  73. package/fesm2022/ngwr-list.mjs.map +1 -1
  74. package/fesm2022/ngwr-mention.mjs +18 -2
  75. package/fesm2022/ngwr-mention.mjs.map +1 -1
  76. package/fesm2022/ngwr-overlay.mjs +119 -4
  77. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  78. package/fesm2022/ngwr-popconfirm.mjs +19 -3
  79. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  80. package/fesm2022/ngwr-popover-testing.mjs +22 -5
  81. package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
  82. package/fesm2022/ngwr-popover.mjs +215 -27
  83. package/fesm2022/ngwr-popover.mjs.map +1 -1
  84. package/fesm2022/ngwr-segmented.mjs +34 -1
  85. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  86. package/fesm2022/ngwr-select.mjs +15 -1
  87. package/fesm2022/ngwr-select.mjs.map +1 -1
  88. package/fesm2022/ngwr-table.mjs +10 -2
  89. package/fesm2022/ngwr-table.mjs.map +1 -1
  90. package/fesm2022/ngwr-toast.mjs +19 -2
  91. package/fesm2022/ngwr-toast.mjs.map +1 -1
  92. package/fesm2022/ngwr-tour.mjs +20 -6
  93. package/fesm2022/ngwr-tour.mjs.map +1 -1
  94. package/fesm2022/ngwr-tree.mjs +9 -2
  95. package/fesm2022/ngwr-tree.mjs.map +1 -1
  96. package/fesm2022/ngwr-version.mjs +1 -1
  97. package/fesm2022/ngwr-version.mjs.map +1 -1
  98. package/fesm2022/ngwr-window.mjs +18 -1
  99. package/fesm2022/ngwr-window.mjs.map +1 -1
  100. package/graph/styles/_index.scss +113 -0
  101. package/i18n/ar.json +5 -0
  102. package/i18n/cs.json +5 -0
  103. package/i18n/de.json +5 -0
  104. package/i18n/en.json +5 -0
  105. package/i18n/es.json +5 -0
  106. package/i18n/fr.json +5 -0
  107. package/i18n/he.json +5 -0
  108. package/i18n/hi.json +5 -0
  109. package/i18n/id.json +5 -0
  110. package/i18n/it.json +5 -0
  111. package/i18n/ja.json +5 -0
  112. package/i18n/ko.json +5 -0
  113. package/i18n/nl.json +5 -0
  114. package/i18n/pl.json +5 -0
  115. package/i18n/pt.json +5 -0
  116. package/i18n/ru.json +5 -0
  117. package/i18n/sv.json +5 -0
  118. package/i18n/tr.json +5 -0
  119. package/i18n/uk.json +5 -0
  120. package/i18n/vi.json +5 -0
  121. package/i18n/zh-TW.json +5 -0
  122. package/i18n/zh.json +5 -0
  123. package/llms-full.txt +13 -3
  124. package/llms.txt +20 -9
  125. package/mcp/providers.js +8 -2
  126. package/package.json +10 -1
  127. package/schematics/migrations/v14/index.js +90 -34
  128. package/schematics/migrations/v7/index.js +15 -4
  129. package/schematics/migrations/v8/index.js +13 -2
  130. package/schematics/migrations/v9/index.js +19 -10
  131. package/schematics/use/symbol-map.json +2 -0
  132. package/segmented/styles/_index.scss +8 -0
  133. package/skills/ngwr/SKILL.md +10 -5
  134. package/skills/ngwr/references/catalog.md +2 -0
  135. package/skills/ngwr/references/setup.md +2 -2
  136. package/styles.scss +1 -0
  137. package/table/styles/_index.scss +39 -12
  138. package/theme/styles/_focus.scss +7 -0
  139. package/types/ngwr-cascader.d.ts +7 -0
  140. package/types/ngwr-color-picker.d.ts +8 -0
  141. package/types/ngwr-context-menu.d.ts +10 -0
  142. package/types/ngwr-date-picker.d.ts +16 -0
  143. package/types/ngwr-dialog.d.ts +1 -0
  144. package/types/ngwr-drawer.d.ts +28 -0
  145. package/types/ngwr-dropdown.d.ts +9 -0
  146. package/types/ngwr-graph-testing.d.ts +190 -0
  147. package/types/ngwr-graph.d.ts +203 -0
  148. package/types/ngwr-i18n-en.d.ts +16 -5
  149. package/types/ngwr-i18n.d.ts +13 -0
  150. package/types/ngwr-lightbox.d.ts +15 -0
  151. package/types/ngwr-mention.d.ts +7 -0
  152. package/types/ngwr-overlay.d.ts +62 -4
  153. package/types/ngwr-popconfirm.d.ts +1 -0
  154. package/types/ngwr-popover-testing.d.ts +22 -5
  155. package/types/ngwr-popover.d.ts +28 -8
  156. package/types/ngwr-segmented.d.ts +16 -0
  157. package/types/ngwr-select.d.ts +7 -0
  158. package/types/ngwr-table.d.ts +8 -0
  159. package/types/ngwr-toast.d.ts +2 -0
  160. package/types/ngwr-tour.d.ts +6 -0
  161. package/types/ngwr-tree.d.ts +2 -1
  162. package/types/ngwr-version.d.ts +1 -1
  163. package/types/ngwr-window.d.ts +1 -0
@@ -168,8 +168,28 @@ declare class WrDrawer {
168
168
  private readonly overlay;
169
169
  private readonly vcr;
170
170
  private readonly destroyRef;
171
+ private readonly injector;
171
172
  private readonly focusTrapFactory;
172
173
  private readonly isBrowser;
174
+ /**
175
+ * The reading direction the open drawer has to keep up with, resolved off the
176
+ * ENVIRONMENT injector rather than this component's.
177
+ *
178
+ * That is where the CDK read it: `createOverlayRef` takes `Directionality`
179
+ * from the `Overlay`'s own injector, which `provideWrOverlay()` parents to
180
+ * the application's, so a node-level CDK `[dir]` is never in the chain. A
181
+ * panel is not IN that island either — it is appended to the overlay
182
+ * container on `<body>` — so following the node injector would not follow the
183
+ * ref at all: it would rewrite a correctly-stamped panel to the island's
184
+ * direction one pass after it opened, and `WrDrawerManager`, a root service
185
+ * with no island to read, could never do the same. Two halves of one
186
+ * component, same panel classes, same stylesheet, two answers.
187
+ *
188
+ * `null` never happens in an app — `Directionality` is root-provided — but a
189
+ * bare `TestBed` should still get a drawer that opens, with nothing ambient
190
+ * to follow.
191
+ */
192
+ private readonly dir;
173
193
  private overlayRef;
174
194
  private focusTrap;
175
195
  private previouslyFocused;
@@ -297,6 +317,14 @@ declare class WrDrawerManager {
297
317
  private readonly isBrowser;
298
318
  private readonly i18n;
299
319
  private readonly location;
320
+ /**
321
+ * The application's reading direction — the instance the CDK itself read when
322
+ * it stamped the overlay. A root service has no node injector above it, so a
323
+ * plain `inject()` here already resolves the environment one; `<wr-drawer>`,
324
+ * which does, spells that out and says why. The two halves of one component
325
+ * must not answer differently about the same panel.
326
+ */
327
+ private readonly dir;
300
328
  open<C, R = unknown, D = unknown>(component: ComponentType<C>, options?: WrDrawerOptions<D>): WrDrawerRef<C, R>;
301
329
  /**
302
330
  * Tie the drawer's lifetime to the URL it was opened on — the same treatment
@@ -73,10 +73,19 @@ declare class WrDropdown {
73
73
  readonly closed: _angular_core.OutputEmitterRef<void>;
74
74
  private readonly host;
75
75
  private readonly overlay;
76
+ /**
77
+ * The reading direction the open menu has to keep up with.
78
+ *
79
+ * Optional inject: `Directionality` is root-provided, so this is never null in
80
+ * an app — but a bare `TestBed` that provides nothing should still get a menu
81
+ * that opens, with simply nothing ambient to follow.
82
+ */
83
+ private readonly dir;
76
84
  private readonly outsideClick;
77
85
  private readonly responsiveConfig;
78
86
  private readonly vcr;
79
87
  private readonly scrollStrategies;
88
+ private readonly injector;
80
89
  private readonly destroyRef;
81
90
  /** @internal Public so host bindings can read it. */
82
91
  readonly isOpen: _angular_core.WritableSignal<boolean>;
@@ -0,0 +1,190 @@
1
+ import { BaseHarnessFilters, ComponentHarness, ComponentHarnessConstructor, HarnessPredicate } from '@angular/cdk/testing';
2
+
3
+ /**
4
+ * @license
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
8
+ */
9
+
10
+ /** Narrows which `<wr-graph>` a harness query matches. */
11
+ interface WrGraphHarnessFilters extends BaseHarnessFilters {
12
+ /**
13
+ * Match the viewport's accessible name — `ariaLabel`, or the catalog's `graph.label`
14
+ * when none is bound. A string is an exact match, a RegExp is tested.
15
+ */
16
+ readonly ariaLabel?: string | RegExp;
17
+ /**
18
+ * Match a graph that draws a node with this text (see `WrGraphNodeHarness.getText`) —
19
+ * the way to tell two graphs apart when neither was given a name of its own. A node
20
+ * of a graph nested inside one of this graph's node templates does not count, for a
21
+ * RegExp as much as for a string: the node text it is tested against leaves the
22
+ * nested graph out.
23
+ */
24
+ readonly nodeLabel?: string | RegExp;
25
+ }
26
+ /** Narrows which node of a `<wr-graph>` a harness query matches. */
27
+ interface WrGraphNodeHarnessFilters extends BaseHarnessFilters {
28
+ /**
29
+ * Match the node's DRAWN text, as `WrGraphNodeHarness.getText` reads it: the label on
30
+ * the default card, and everything a `wrGraphNode` template drew otherwise — so a
31
+ * RegExp is how to match one part of a template. A string is an exact match. A
32
+ * `<wr-graph>` the template nests inside the node is not part of that text.
33
+ */
34
+ readonly label?: string | RegExp;
35
+ }
36
+
37
+ /**
38
+ * @license
39
+ *
40
+ * Use of this source code is governed by an MIT-style license that can be
41
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
42
+ */
43
+
44
+ /**
45
+ * Test harness for one node of a `<wr-graph>` — a `role="listitem"` block.
46
+ *
47
+ * A node answers two questions, and they are kept apart on purpose. {@link getText} is
48
+ * what is DRAWN: the default card, or whatever a `wrGraphNode` template rendered.
49
+ * {@link getRelationText} is what is ANNOUNCED about its place in the graph: the
50
+ * lines are `aria-hidden`, so the visually hidden sentence naming the parents and the
51
+ * children is the only form the structure takes for a screen reader. A spec that read
52
+ * the node's whole text would get both glued together, and would keep passing on a
53
+ * graph whose relation sentences named the wrong neighbours.
54
+ *
55
+ * There is no `getId()`. The component writes a node's id nowhere in the DOM — only
56
+ * an edge carries ids, on its `data-from` / `data-to` — so a node is addressed by what
57
+ * it draws, and {@link WrGraphHarness.getEdges} is where ids are read.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const birch = await graph.getNode({ label: 'Birch' });
62
+ *
63
+ * expect(await birch.getText()).toBe('Birch');
64
+ * expect(await birch.getRelationText()).toBe('Parents: Atlas. Children: Dune.');
65
+ * ```
66
+ *
67
+ * @see https://ngwr.dev/guides/testing
68
+ */
69
+ declare class WrGraphNodeHarness extends ComponentHarness {
70
+ static hostSelector: string;
71
+ /**
72
+ * Build a predicate that narrows the query.
73
+ *
74
+ * Typed on `this`, so the predicate is built for whichever node harness it is called
75
+ * on — {@link WrGraphHarness.getNodes} narrows its own, direct-child query through
76
+ * the same options.
77
+ */
78
+ static with<T extends WrGraphNodeHarness>(this: ComponentHarnessConstructor<T>, options?: WrGraphNodeHarnessFilters): HarnessPredicate<T>;
79
+ /**
80
+ * The text the node DRAWS, trimmed, with the relation sentence left out.
81
+ *
82
+ * The sentence is a real text node inside the block — visually hidden, not removed —
83
+ * so a plain text read would end in `Parents: Atlas. Children: Dune.`. It is excluded
84
+ * rather than subtracted.
85
+ *
86
+ * A `<wr-graph>` a template nests inside the node is left out whole, cards and
87
+ * sentences alike: it is a graph of its own, and its nodes answer to its own harness.
88
+ * So a node drawing `Harbor` above an inner graph of `Kestrel` and `Lark` reads
89
+ * `Harbor`, and a `/Lark/` label does not match it.
90
+ */
91
+ getText(): Promise<string>;
92
+ /**
93
+ * The sentence a screen reader hears about the node's place in the graph — its
94
+ * parents, then its children, as the catalog words them — or `null` for a node with
95
+ * no edges, which the graph gives no sentence at all.
96
+ *
97
+ * `null` rather than `''`: the component never writes an empty sentence, so an empty
98
+ * string could only mean the element exists and says nothing, which is a different
99
+ * failure from a node that has nothing to say.
100
+ */
101
+ getRelationText(): Promise<string | null>;
102
+ }
103
+
104
+ /**
105
+ * @license
106
+ *
107
+ * Use of this source code is governed by an MIT-style license that can be
108
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
109
+ */
110
+
111
+ /**
112
+ * Test harness for `<wr-graph>` — blocks joined by parent-child lines, laid out in
113
+ * layers, display only.
114
+ *
115
+ * The graph is read the way assistive technology reads it: the viewport's name, the
116
+ * nodes as a list in READING order (layer, then inline position — which is DOM order),
117
+ * each node's drawn text and its relation sentence, and the edges as the `from` / `to`
118
+ * ids the component writes on each line. Those are what break when the data wiring
119
+ * does.
120
+ *
121
+ * Three methods are deliberately absent, and each would answer the same for a working
122
+ * graph and a broken one:
123
+ *
124
+ * - **No edge path `d`.** A path is a rendering detail: rounded to two decimals, mirrored
125
+ * under RTL, and moved by every node size and gap. The same rule as
126
+ * `WrLineChartHarness`.
127
+ * - **No node positions.** jsdom lays nothing out, so every measured box is 0×0. The
128
+ * inline `transform` IS the component's own write and would be readable, but its
129
+ * numbers belong to a layout that is internal in this release — a harness method
130
+ * returning them would make every layout improvement a breaking change to consumer
131
+ * specs. Coordinates are pinned in the layout's own pure spec, where the arithmetic is.
132
+ * - **No "is scrollable".** Overflow is layout: in jsdom `scrollWidth` and `clientWidth`
133
+ * are both 0 for a graph that fits and for one ten times wider. The viewport's
134
+ * `tabindex` is no proxy either — it is always `0`, precisely so the tab stop never
135
+ * depends on a measurement.
136
+ *
137
+ * An empty graph and a graph whose layout drew nothing render the same DOM, so the
138
+ * harness cannot tell them apart. {@link getNodes} answers `[]` for both, which is the
139
+ * honest way to assert emptiness; {@link getEdges} refuses instead, because "no edges"
140
+ * would be vacuously true of a graph that drew nothing at all.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * const graph = await loader.getHarness(WrGraphHarness.with({ ariaLabel: 'Team structure' }));
145
+ *
146
+ * expect(await graph.getEdges()).toEqual([{ from: 'atlas', to: 'birch' }]);
147
+ * const birch = await graph.getNode({ label: 'Birch' });
148
+ * expect(await birch.getRelationText()).toBe('Parents: Atlas.');
149
+ * ```
150
+ *
151
+ * @see https://ngwr.dev/guides/testing
152
+ */
153
+ declare class WrGraphHarness extends ComponentHarness {
154
+ static hostSelector: string;
155
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
156
+ static with(options?: WrGraphHarnessFilters): HarnessPredicate<WrGraphHarness>;
157
+ /**
158
+ * The viewport's accessible name — the scroller is the graph's one tab stop and the
159
+ * element that carries it, never the host.
160
+ */
161
+ getAccessibleName(): Promise<string | null>;
162
+ /**
163
+ * This graph's nodes, in reading order, narrowed by the filters.
164
+ *
165
+ * Only the graph's own: a graph drawn inside one of its node templates has nodes of
166
+ * its own, and they are not this graph's. `[]` for a graph that draws no node — see
167
+ * the class note for why that answer cannot tell empty data from a layout that drew
168
+ * nothing.
169
+ */
170
+ getNodes(filters?: WrGraphNodeHarnessFilters): Promise<WrGraphNodeHarness[]>;
171
+ /** The first node matching the filters, or a failure that says what the graph draws. */
172
+ getNode(filters: WrGraphNodeHarnessFilters): Promise<WrGraphNodeHarness>;
173
+ /**
174
+ * One `{ from, to }` per line drawn, read off the path's `data-from` / `data-to` —
175
+ * node ids, the only place the DOM writes one — in the order the edges were given,
176
+ * with the edges the graph skipped left out. Parallel edges each appear, since each is
177
+ * its own line.
178
+ *
179
+ * Throws on a graph that draws no nodes, rather than answering `[]`: that answer would
180
+ * be the same for empty data and for a layout that drew nothing, and a spec asserting
181
+ * "no edges" would pass on both.
182
+ */
183
+ getEdges(): Promise<{
184
+ from: string;
185
+ to: string;
186
+ }[]>;
187
+ }
188
+
189
+ export { WrGraphHarness, WrGraphNodeHarness };
190
+ export type { WrGraphHarnessFilters, WrGraphNodeHarnessFilters };
@@ -0,0 +1,203 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
3
+
4
+ /**
5
+ * @license
6
+ *
7
+ * Use of this source code is governed by an MIT-style license that can be
8
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
9
+ */
10
+ /**
11
+ * A parent-child link: `from` is the parent, `to` the child. The line is drawn
12
+ * with its arrow at the child.
13
+ *
14
+ * Several edges between one pair and edges that close a cycle are both legal.
15
+ * An edge naming a node that does not exist is skipped (dev mode warns).
16
+ */
17
+ interface WrGraphEdge {
18
+ /** Id of the parent node. */
19
+ readonly from: string;
20
+ /** Id of the child node. */
21
+ readonly to: string;
22
+ }
23
+
24
+ /**
25
+ * @license
26
+ *
27
+ * Use of this source code is governed by an MIT-style license that can be
28
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
29
+ */
30
+ /**
31
+ * One block in a `wr-graph`.
32
+ *
33
+ * The component knows nothing about what a node stands for — anything the
34
+ * picture needs beyond `label` travels in `data` and is drawn by the consumer's
35
+ * `ng-template[wrGraphNode]`.
36
+ */
37
+ interface WrGraphNode<TData = unknown> {
38
+ /** Unique within the graph. A repeated id is skipped after its first occurrence (dev mode warns). */
39
+ readonly id: string;
40
+ /**
41
+ * The node's name. The default card shows it, and every neighbour's relation
42
+ * text reads it out — so a custom template should render it too, or a screen
43
+ * reader hears a name no node announces.
44
+ */
45
+ readonly label: string;
46
+ /** Width in pixels. Falls back to the graph's `nodeWidth` when absent, non-finite or not positive. */
47
+ readonly width?: number;
48
+ /** Height in pixels. Falls back to the graph's `nodeHeight` when absent, non-finite or not positive. */
49
+ readonly height?: number;
50
+ /** Anything the node template needs. Never read by the component or the layout. */
51
+ readonly data?: TData;
52
+ }
53
+ /** The context an `ng-template[wrGraphNode]` receives: the node as `let-node`. */
54
+ interface WrGraphNodeContext<TData = unknown> {
55
+ readonly $implicit: WrGraphNode<TData>;
56
+ }
57
+
58
+ /**
59
+ * @license
60
+ *
61
+ * Use of this source code is governed by an MIT-style license that can be
62
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
63
+ */
64
+
65
+ /**
66
+ * Replace the default card. The node is the implicit context; its box — the
67
+ * size the layout reserved, its position and the relation text read to a screen
68
+ * reader — stays with the graph, so a template cannot break the geometry.
69
+ *
70
+ * Render `node.label` somewhere in it: the relation text of every neighbour
71
+ * names this node by its label.
72
+ *
73
+ * @example
74
+ * ```html
75
+ * <wr-graph [nodes]="nodes" [edges]="edges">
76
+ * <ng-template wrGraphNode let-node>
77
+ * <strong>{{ node.label }}</strong> {{ node.data.role }}
78
+ * </ng-template>
79
+ * </wr-graph>
80
+ * ```
81
+ */
82
+ declare class WrGraphNodeTemplate {
83
+ readonly template: TemplateRef<WrGraphNodeContext<unknown>>;
84
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrGraphNodeTemplate, never>;
85
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrGraphNodeTemplate, "ng-template[wrGraphNode]", never, {}, {}, never, never, true, never>;
86
+ }
87
+
88
+ interface DrawnNode<TData> {
89
+ readonly node: WrGraphNode<TData>;
90
+ readonly width: number;
91
+ readonly height: number;
92
+ readonly transform: string;
93
+ }
94
+ interface DrawnEdge {
95
+ readonly id: string;
96
+ readonly from: string;
97
+ readonly to: string;
98
+ readonly d: string;
99
+ }
100
+ /** What the template binds: physical pixels, already mirrored for RTL. */
101
+ interface GraphView<TData> {
102
+ readonly width: number;
103
+ readonly height: number;
104
+ readonly nodes: readonly DrawnNode<TData>[];
105
+ readonly edges: readonly DrawnEdge[];
106
+ }
107
+ /**
108
+ * A graph of blocks joined by parent-child links, laid out in layers from top to
109
+ * bottom. Display only: nothing is selectable, and the graph scrolls inside its
110
+ * own viewport rather than the page.
111
+ *
112
+ * The layout runs in a `computed` with no DOM and no measuring, so the sizes are
113
+ * the consumer's: `nodeWidth` / `nodeHeight` for every node, or `width` /
114
+ * `height` on one. A prerender therefore ships the finished picture.
115
+ *
116
+ * What the lines show is also written out: every node carries visually hidden
117
+ * text naming its parents and children, and the lines themselves are hidden
118
+ * from assistive technology.
119
+ *
120
+ * @example
121
+ * ```html
122
+ * <wr-graph [nodes]="nodes" [edges]="edges" ariaLabel="Team structure" />
123
+ * ```
124
+ *
125
+ * @see https://ngwr.dev/reference/components/graph
126
+ */
127
+ declare class WrGraph<TData = unknown> {
128
+ /**
129
+ * The nodes, in any order. Input order breaks layout ties, so the same arrays
130
+ * always produce the same picture. Never mutated.
131
+ *
132
+ * @default []
133
+ */
134
+ readonly nodes: _angular_core.InputSignal<readonly WrGraphNode<TData>[]>;
135
+ /**
136
+ * Parent-child links, `from` the parent and `to` the child. Never mutated.
137
+ *
138
+ * @default []
139
+ */
140
+ readonly edges: _angular_core.InputSignal<readonly WrGraphEdge[]>;
141
+ /**
142
+ * Width in pixels of a node that sets none of its own.
143
+ *
144
+ * @default 160
145
+ */
146
+ readonly nodeWidth: _angular_core.InputSignalWithTransform<number, unknown>;
147
+ /**
148
+ * Height in pixels of a node that sets none of its own.
149
+ *
150
+ * @default 48
151
+ */
152
+ readonly nodeHeight: _angular_core.InputSignalWithTransform<number, unknown>;
153
+ /** Accessible name of the scrolling viewport. Falls back to `graph.label`, then `'Graph'`. */
154
+ readonly ariaLabel: _angular_core.InputSignal<string | null>;
155
+ protected readonly label: _angular_core.Signal<string>;
156
+ private readonly parentsText;
157
+ private readonly childrenText;
158
+ protected readonly nodeTemplate: _angular_core.Signal<WrGraphNodeTemplate | undefined>;
159
+ /** `url(#…)` for every edge's `marker-end`. */
160
+ protected readonly markerId: string;
161
+ protected readonly markerUrl: string;
162
+ protected readonly arrowSize = 6;
163
+ private readonly engine;
164
+ private readonly dir;
165
+ private readonly i18n;
166
+ private readonly localeId;
167
+ private readonly isRtl;
168
+ private readonly locale;
169
+ /**
170
+ * The size of a node that sets none of its own. Each dimension falls back on its
171
+ * own, and the dev warning reads this same value, so it cannot name a size the
172
+ * layout did not use.
173
+ */
174
+ private readonly defaultSize;
175
+ private readonly prepared;
176
+ /** The engine's answer, as returned. A fresh signal per run: nothing aborts a synchronous layout. */
177
+ private readonly raw;
178
+ /**
179
+ * The drawable result. An asynchronous layout is declared by the interface and
180
+ * not supported by this release: a thenable draws nothing, and dev mode says so.
181
+ */
182
+ private readonly result;
183
+ /** Layout joined to the nodes and edges, direction-free, nodes in reading order. */
184
+ private readonly placed;
185
+ /**
186
+ * Physical pixels. Mirrored here rather than in CSS so nodes and lines get the
187
+ * same numbers and cannot drift apart — and kept apart from the layout so a
188
+ * direction change does not lay the graph out again.
189
+ */
190
+ protected readonly view: _angular_core.Signal<GraphView<TData>>;
191
+ /**
192
+ * The visually hidden sentence per node id: its parents, then its children, as
193
+ * name lists. Never a count — the catalogs have no plural forms. A neighbour
194
+ * linked by several edges is named once, and names follow reading order.
195
+ */
196
+ protected readonly relations: _angular_core.Signal<Map<string, string>>;
197
+ constructor();
198
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrGraph<any>, never>;
199
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrGraph<any>, "wr-graph", never, { "nodes": { "alias": "nodes"; "required": false; "isSignal": true; }; "edges": { "alias": "edges"; "required": false; "isSignal": true; }; "nodeWidth": { "alias": "nodeWidth"; "required": false; "isSignal": true; }; "nodeHeight": { "alias": "nodeHeight"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, ["nodeTemplate"], never, true, never>;
200
+ }
201
+
202
+ export { WrGraph, WrGraphNodeTemplate };
203
+ export type { WrGraphEdge, WrGraphNode, WrGraphNodeContext };
@@ -1,16 +1,27 @@
1
1
  import { WrI18nCatalog } from 'ngwr/i18n';
2
2
 
3
3
  /**
4
- * Base English catalog for ngwr built-in component strings. Spread this
5
- * into your root catalog or pass it to `provideWrI18nStaticLoader`.
4
+ * Base English catalog for ngwr built-in component strings. Register it with
5
+ * `provideWrI18nBaseCatalogs` and keep only your own keys in the loader.
6
+ *
7
+ * Do not spread it into your own catalog. A spread is shallow, so any namespace
8
+ * you share with ngwr, e.g. `common`, `validation`, `table`, keeps only the keys
9
+ * of the side spread last, and the other side's keys stop resolving with nothing
10
+ * logged: ngwr's components fall back to their English defaults, and a `wrT`
11
+ * read of a lost key renders the raw key under the default missing handler. A
12
+ * base catalog is looked up key by key underneath yours, so both halves of a
13
+ * shared namespace resolve.
6
14
  *
7
15
  * @example
8
16
  * ```ts
17
+ * import { provideWrI18n, provideWrI18nBaseCatalogs, provideWrI18nStaticLoader } from 'ngwr/i18n';
9
18
  * import { wrEn } from 'ngwr/i18n/en';
10
19
  *
11
- * provideWrI18nStaticLoader({
12
- * en: { ...wrEn, app: { title: 'My app' } },
13
- * });
20
+ * providers: [
21
+ * provideWrI18n(),
22
+ * provideWrI18nBaseCatalogs({ en: wrEn }),
23
+ * provideWrI18nStaticLoader({ en: { app: { title: 'My app' } } }),
24
+ * ]
14
25
  * ```
15
26
  */
16
27
  declare const wrEn: WrI18nCatalog;
@@ -403,6 +403,15 @@ declare function provideWrI18n(options?: ProvideWrI18nOptions): EnvironmentProvi
403
403
  /**
404
404
  * Provide a static loader — catalogs already in memory.
405
405
  *
406
+ * A loader serves only the catalog you pass it, and ngwr registers none of its
407
+ * own. Pass only your own keys here and register ngwr's catalogs with
408
+ * {@link provideWrI18nBaseCatalogs} — not `{ ...wrRu, ...yours }`. A spread is
409
+ * shallow, so any namespace you share with ngwr, e.g. `common`, `validation`,
410
+ * `table`, keeps only the keys of the side spread last, and the other side's
411
+ * keys stop resolving with nothing logged: ngwr's components fall back to their
412
+ * English defaults, and a `wrT` read of a lost key renders the raw key under the
413
+ * default missing handler.
414
+ *
406
415
  * @param catalogs Root catalogs keyed by locale.
407
416
  * @param scopes Optional per-scope catalogs served to `registerScope(name)`.
408
417
  */
@@ -428,6 +437,10 @@ declare function provideWrI18nStaticLoader(catalogs: WrI18nStaticCatalogs, scope
428
437
  *
429
438
  * Pass only the locales you ship — the ones you leave out stay out of the
430
439
  * bundle. Your own keys always win; this is a floor, not an override.
440
+ *
441
+ * Use it instead of spreading `wrRu` into your own catalog, too: the lookup
442
+ * walks these key by key after the loader's catalog misses, so a namespace both
443
+ * define keeps both halves, where a shallow spread keeps only one.
431
444
  */
432
445
  declare function provideWrI18nBaseCatalogs(catalogs: WrI18nBaseCatalogs): Provider;
433
446
  /** Provide an HTTP loader — catalogs fetched from URLs. Requires `provideHttpClient`. */
@@ -61,7 +61,22 @@ declare class WrLightbox {
61
61
  private readonly overlay;
62
62
  private readonly vcr;
63
63
  private readonly destroyRef;
64
+ private readonly injector;
64
65
  private readonly focusTrapFactory;
66
+ /**
67
+ * The reading direction the open viewer has to keep up with, resolved off the
68
+ * ENVIRONMENT injector rather than this component's — the same instance the
69
+ * CDK read when it stamped the overlay, since `createOverlayRef` takes
70
+ * `Directionality` from the `Overlay`'s injector and no node-level `[dir]` is
71
+ * in that chain. The viewer is appended to the overlay container on `<body>`,
72
+ * not into whatever region the thumbnail sits in, so reading the node
73
+ * injector would rewrite a correctly-stamped panel to an island's direction
74
+ * one pass after it opened rather than follow the application at all.
75
+ *
76
+ * `null` never happens in an app — `Directionality` is root-provided — but a
77
+ * bare `TestBed` should still get a viewer that opens.
78
+ */
79
+ private readonly dir;
65
80
  private focusTrap;
66
81
  private previouslyFocused;
67
82
  private overlayRef;
@@ -60,8 +60,15 @@ declare class WrMention<T extends WrMentionItem = WrMentionItem> {
60
60
  readonly wrMentionSelected: _angular_core.OutputEmitterRef<WrMentionCommit<T>>;
61
61
  private readonly host;
62
62
  private readonly overlay;
63
+ /**
64
+ * Optional inject: `Directionality` is root-provided, so this is never null in
65
+ * an app — but a bare `TestBed` that provides nothing should still get a
66
+ * directive that works, and defaulting to LTR is the honest fallback.
67
+ */
68
+ private readonly dir;
63
69
  private readonly scrollStrategies;
64
70
  private readonly destroyRef;
71
+ private readonly injector;
65
72
  private readonly isBrowser;
66
73
  private overlayRef;
67
74
  private panelRef;
@@ -1,7 +1,8 @@
1
- import { ConnectedPosition, OverlayRef, OverlayContainer, Overlay } from '@angular/cdk/overlay';
2
- import { Observable } from 'rxjs';
1
+ import { Directionality, Direction } from '@angular/cdk/bidi';
2
+ import { OverlayRef, ConnectedPosition, OverlayContainer, Overlay } from '@angular/cdk/overlay';
3
3
  import * as i0 from '@angular/core';
4
- import { EnvironmentProviders, InjectionToken } from '@angular/core';
4
+ import { Injector, EnvironmentProviders, InjectionToken } from '@angular/core';
5
+ import { Observable } from 'rxjs';
5
6
 
6
7
  /**
7
8
  * @license
@@ -28,6 +29,63 @@ import { EnvironmentProviders, InjectionToken } from '@angular/core';
28
29
  */
29
30
  declare function wrAppendOverlayClose(host: HTMLElement, className: string, label: string, onClose: () => void): HTMLButtonElement;
30
31
 
32
+ /**
33
+ * @license
34
+ *
35
+ * Use of this source code is governed by an MIT-style license that can be
36
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
37
+ */
38
+
39
+ /**
40
+ * Keep an OPEN overlay on the application's reading direction.
41
+ *
42
+ * The CDK reads the direction ONCE, as a string, when the overlay is created
43
+ * (`overlayConfig.direction ||= directionality.value`), writes it as the host's
44
+ * `dir` on attach, and never looks at it again — `updatePosition()` does not
45
+ * touch it and `setDirection()` is the only thing that does. So an application
46
+ * that flips direction while a panel is open mirrors the page and leaves the
47
+ * panel behind, still `ltr`, still resolving `start` to the left. This site's
48
+ * own LTR/RTL switch is the demonstration: it lives inside a `wr-dropdown`, and
49
+ * the `wr-segmented` it is built from reads `Directionality` live — so the thumb
50
+ * slides to the other slot while the pane around it still renders `ltr`, and
51
+ * parks under the wrong label.
52
+ *
53
+ * Call it once per `OverlayRef`, right after `overlay.create(...)`. The follower
54
+ * ends itself when that overlay detaches or is disposed, so a reopen — which is
55
+ * always a NEW ref in this library — needs a new call, and the returned teardown
56
+ * is only for stopping early.
57
+ *
58
+ * `onDirectionChange` is for the sites whose position LIST is itself
59
+ * direction-dependent (the four that pass their table through
60
+ * {@link wrMirrorOffsets}): it runs with the new direction already on the ref
61
+ * and before the overlay repositions, so the strategy is carrying the mirrored
62
+ * offsets by the time the CDK re-resolves them.
63
+ *
64
+ * SSR-safe: it touches no browser global of its own, and the CDK's position
65
+ * strategies no-op off the browser, so a flip on the server only rewrites the
66
+ * attribute.
67
+ *
68
+ * @param overlayRef The overlay to keep in step, freshly created.
69
+ * @param dir The `Directionality` the caller injected. `null` — an optional
70
+ * inject with no provider, i.e. a bare `TestBed` — means there is nothing
71
+ * ambient to follow and this does nothing at all.
72
+ * @param injector Owns the `valueSignal` watch; the caller's own is right.
73
+ * @param onDirectionChange Re-applies direction-dependent state, e.g.
74
+ * `strategy.withPositions(wrMirrorOffsets(TABLE, direction === 'rtl'))`.
75
+ * @returns Stops following. Idempotent, and unnecessary in the normal case.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * this.overlayRef = this.overlay.create({ positionStrategy, ... });
80
+ * wrFollowDirection(this.overlayRef, this.dir, this.injector, direction =>
81
+ * positionStrategy.withPositions(
82
+ * wrMirrorOffsets(WR_POPCONFIRM_POSITIONS[this.position()], direction === 'rtl')
83
+ * )
84
+ * );
85
+ * ```
86
+ */
87
+ declare function wrFollowDirection(overlayRef: OverlayRef, dir: Directionality | null, injector: Injector, onDirectionChange?: (direction: Direction) => void): () => void;
88
+
31
89
  /**
32
90
  * @license
33
91
  *
@@ -302,5 +360,5 @@ declare const WR_OVERLAY: InjectionToken<Overlay>;
302
360
  */
303
361
  declare const WR_OVERLAY_CONTAINER: InjectionToken<OverlayContainer>;
304
362
 
305
- export { WR_OVERLAY, WR_OVERLAY_CONTAINER, WR_RESPONSIVE_OVERLAYS, WrOutsideClick, WrOverlayContainer, provideWrOverlay, provideWrResponsiveOverlays, wrAppendOverlayClose, wrMirrorOffsets, wrPresentAsSheet };
363
+ export { WR_OVERLAY, WR_OVERLAY_CONTAINER, WR_RESPONSIVE_OVERLAYS, WrOutsideClick, WrOverlayContainer, provideWrOverlay, provideWrResponsiveOverlays, wrAppendOverlayClose, wrFollowDirection, wrMirrorOffsets, wrPresentAsSheet };
306
364
  export type { WrResponsiveOverlaysConfig };
@@ -40,6 +40,7 @@ declare class WrPopconfirm {
40
40
  private readonly outsideClick;
41
41
  private readonly vcr;
42
42
  private readonly scrollStrategies;
43
+ private readonly injector;
43
44
  private readonly destroyRef;
44
45
  /** @internal Public so the host bindings can read it. */
45
46
  readonly isOpen: _angular_core.WritableSignal<boolean>;