@tensor_1/react 2.46.0 → 2.48.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 (204) hide show
  1. package/README.md +509 -1
  2. package/dist/{SchedulingCalendar-B6TakO2h.d.ts → SchedulingCalendar-WWyFL3Eo.d.ts} +51 -2
  3. package/dist/announce.d.ts +10 -0
  4. package/dist/announce.js +30 -0
  5. package/dist/chart-analytic.cjs +33 -25
  6. package/dist/chart-preset.cjs +23 -15
  7. package/dist/chart.cjs +23 -15
  8. package/dist/combobox-model.d.ts +10 -1
  9. package/dist/combobox-model.js +15 -0
  10. package/dist/command-palette-model.d.ts +44 -0
  11. package/dist/command-palette-model.js +36 -0
  12. package/dist/components/AccountMenu.d.ts +44 -0
  13. package/dist/components/AccountMenu.js +43 -0
  14. package/dist/components/AppShell.d.ts +45 -2
  15. package/dist/components/AppShell.js +116 -5
  16. package/dist/components/AuditLog.d.ts +128 -0
  17. package/dist/components/AuditLog.js +196 -0
  18. package/dist/components/BrandProfiles.js +4 -3
  19. package/dist/components/Breadcrumbs.d.ts +9 -2
  20. package/dist/components/Breadcrumbs.js +3 -2
  21. package/dist/components/BusyBar.d.ts +13 -0
  22. package/dist/components/BusyBar.js +10 -0
  23. package/dist/components/BusyRegion.d.ts +18 -0
  24. package/dist/components/BusyRegion.js +12 -0
  25. package/dist/components/Button.d.ts +33 -5
  26. package/dist/components/Button.js +12 -6
  27. package/dist/components/ButtonFeedback.d.ts +30 -0
  28. package/dist/components/ButtonFeedback.js +78 -0
  29. package/dist/components/Card.d.ts +18 -1
  30. package/dist/components/Card.js +5 -1
  31. package/dist/components/ChangeHighlight.d.ts +30 -0
  32. package/dist/components/ChangeHighlight.js +21 -0
  33. package/dist/components/ChartCore.js +2 -1
  34. package/dist/components/Checkbox.d.ts +27 -1
  35. package/dist/components/Checkbox.js +31 -2
  36. package/dist/components/CodeDisplay.d.ts +65 -0
  37. package/dist/components/CodeDisplay.js +124 -0
  38. package/dist/components/Combobox.d.ts +27 -6
  39. package/dist/components/Combobox.js +195 -58
  40. package/dist/components/CommandPalette.d.ts +36 -1
  41. package/dist/components/CommandPalette.js +254 -2
  42. package/dist/components/ContactCard.d.ts +66 -0
  43. package/dist/components/ContactCard.js +74 -0
  44. package/dist/components/Count.d.ts +24 -0
  45. package/dist/components/Count.js +32 -0
  46. package/dist/components/DataWorkspace.d.ts +167 -0
  47. package/dist/components/DataWorkspace.js +383 -0
  48. package/dist/components/DateFieldParts.d.ts +2 -1
  49. package/dist/components/DateFieldParts.js +7 -0
  50. package/dist/components/DatePicker.d.ts +9 -2
  51. package/dist/components/DatePicker.js +67 -28
  52. package/dist/components/DateRangePicker.d.ts +12 -2
  53. package/dist/components/DateRangePicker.js +13 -12
  54. package/dist/components/DelayedRender.d.ts +15 -0
  55. package/dist/components/DelayedRender.js +10 -0
  56. package/dist/components/DetailPage.d.ts +7 -1
  57. package/dist/components/DetailPage.js +2 -1
  58. package/dist/components/Dialogs.d.ts +71 -10
  59. package/dist/components/Dialogs.js +130 -30
  60. package/dist/components/DiffViewer.d.ts +23 -3
  61. package/dist/components/DiffViewer.js +26 -12
  62. package/dist/components/DiscardPrompt.d.ts +1 -0
  63. package/dist/components/DiscardPrompt.js +16 -0
  64. package/dist/components/DisplayPreferences.d.ts +83 -0
  65. package/dist/components/DisplayPreferences.js +185 -0
  66. package/dist/components/Drawer.d.ts +1 -0
  67. package/dist/components/EditorialHome.d.ts +23 -3
  68. package/dist/components/EditorialHome.js +16 -11
  69. package/dist/components/EntityPicker.d.ts +20 -3
  70. package/dist/components/EntityPicker.js +32 -13
  71. package/dist/components/FilterEditor.d.ts +18 -4
  72. package/dist/components/FilterEditor.js +141 -19
  73. package/dist/components/InfoTip.js +11 -12
  74. package/dist/components/InlineEdit.d.ts +87 -20
  75. package/dist/components/InlineEdit.js +197 -54
  76. package/dist/components/Input.d.ts +12 -2
  77. package/dist/components/Input.js +5 -3
  78. package/dist/components/Kbd.d.ts +6 -1
  79. package/dist/components/Kbd.js +6 -6
  80. package/dist/components/Lightbox.d.ts +41 -5
  81. package/dist/components/Lightbox.js +95 -9
  82. package/dist/components/MatchReview.d.ts +40 -1
  83. package/dist/components/MatchReview.js +130 -4
  84. package/dist/components/MetricInput.js +3 -2
  85. package/dist/components/Modal.d.ts +3 -1
  86. package/dist/components/Modal.js +13 -4
  87. package/dist/components/NavFavourites.d.ts +5 -0
  88. package/dist/components/NavFavourites.js +7 -7
  89. package/dist/components/OtpInput.d.ts +33 -0
  90. package/dist/components/OtpInput.js +123 -0
  91. package/dist/components/PageHeader.d.ts +7 -1
  92. package/dist/components/PageHeader.js +2 -2
  93. package/dist/components/Pagination.js +6 -5
  94. package/dist/components/PasswordInput.d.ts +34 -0
  95. package/dist/components/PasswordInput.js +101 -0
  96. package/dist/components/Peek.js +3 -3
  97. package/dist/components/Popover.js +2 -0
  98. package/dist/components/PrintLayout.d.ts +63 -0
  99. package/dist/components/PrintLayout.js +114 -0
  100. package/dist/components/QrCode.d.ts +47 -0
  101. package/dist/components/QrCode.js +55 -0
  102. package/dist/components/QrScanner.d.ts +95 -0
  103. package/dist/components/QrScanner.js +266 -0
  104. package/dist/components/RelationshipGraph.d.ts +32 -1
  105. package/dist/components/RelationshipGraph.js +18 -5
  106. package/dist/components/RelationshipGraphLayered.d.ts +1 -1
  107. package/dist/components/RelationshipGraphLayered.js +190 -115
  108. package/dist/components/RelationshipGraphList.js +33 -6
  109. package/dist/components/RuleBuilder.js +39 -7
  110. package/dist/components/SaveStatus.d.ts +7 -1
  111. package/dist/components/SaveStatus.js +13 -4
  112. package/dist/components/SchedulingAgenda.d.ts +3 -1
  113. package/dist/components/SchedulingCalendar.d.ts +3 -1
  114. package/dist/components/SchedulingCalendar.js +43 -4
  115. package/dist/components/SchedulingResourceDay.d.ts +57 -0
  116. package/dist/components/SchedulingResourceDay.js +287 -0
  117. package/dist/components/SchedulingTimeGrid.d.ts +3 -1
  118. package/dist/components/SchedulingTimeline.d.ts +3 -1
  119. package/dist/components/SearchBar.d.ts +1 -0
  120. package/dist/components/SearchSuggest.d.ts +23 -3
  121. package/dist/components/SearchSuggest.js +48 -17
  122. package/dist/components/Segmented.d.ts +39 -4
  123. package/dist/components/Segmented.js +31 -3
  124. package/dist/components/Select.d.ts +3 -2
  125. package/dist/components/Select.js +1 -1
  126. package/dist/components/ShortcutHint.d.ts +11 -10
  127. package/dist/components/ShortcutHint.js +44 -38
  128. package/dist/components/Sidebar.d.ts +36 -4
  129. package/dist/components/Sidebar.js +37 -12
  130. package/dist/components/SortableList.d.ts +45 -0
  131. package/dist/components/SortableList.js +134 -0
  132. package/dist/components/Spinner.d.ts +7 -1
  133. package/dist/components/Spinner.js +7 -1
  134. package/dist/components/Stat.d.ts +28 -3
  135. package/dist/components/Stat.js +13 -3
  136. package/dist/components/States.d.ts +7 -1
  137. package/dist/components/States.js +7 -1
  138. package/dist/components/StatusPill.d.ts +14 -3
  139. package/dist/components/StatusPill.js +11 -3
  140. package/dist/components/Steps.js +2 -1
  141. package/dist/components/Table.d.ts +16 -2
  142. package/dist/components/Table.js +8 -4
  143. package/dist/components/TableControls.js +18 -58
  144. package/dist/components/TableOverflowProbe.d.ts +12 -0
  145. package/dist/components/TableOverflowProbe.js +27 -0
  146. package/dist/components/Tabs.d.ts +2 -1
  147. package/dist/components/Tabs.js +1 -0
  148. package/dist/components/TagInput.d.ts +67 -0
  149. package/dist/components/TagInput.js +342 -0
  150. package/dist/components/Textarea.d.ts +5 -0
  151. package/dist/components/Textarea.js +2 -2
  152. package/dist/components/TimePicker.d.ts +80 -0
  153. package/dist/components/TimePicker.js +347 -0
  154. package/dist/components/Toast.js +3 -2
  155. package/dist/components/Tooltip.d.ts +8 -4
  156. package/dist/components/Tooltip.js +24 -21
  157. package/dist/components/Tree.d.ts +8 -0
  158. package/dist/components/Tree.js +11 -5
  159. package/dist/display-preferences-model.d.ts +53 -0
  160. package/dist/display-preferences-model.js +64 -0
  161. package/dist/emoji.cjs +28 -35
  162. package/dist/filter-model.d.ts +59 -3
  163. package/dist/filter-model.js +67 -2
  164. package/dist/hooks/useChangeHighlight.d.ts +33 -0
  165. package/dist/hooks/useChangeHighlight.js +44 -0
  166. package/dist/hooks/useDelayedPending.d.ts +22 -0
  167. package/dist/hooks/useDelayedPending.js +35 -0
  168. package/dist/hooks/useDialog.d.ts +5 -0
  169. package/dist/hooks/useDialog.js +3 -2
  170. package/dist/hooks/useOptimisticValue.d.ts +51 -0
  171. package/dist/hooks/useOptimisticValue.js +61 -0
  172. package/dist/hooks/useReducedMotion.d.ts +4 -1
  173. package/dist/hooks/useReducedMotion.js +7 -1
  174. package/dist/hooks/useResolvedFilterLabels.d.ts +15 -0
  175. package/dist/hooks/useResolvedFilterLabels.js +34 -0
  176. package/dist/hooks/useVirtualRows.d.ts +21 -2
  177. package/dist/hooks/useVirtualRows.js +30 -3
  178. package/dist/icons/Icon.d.ts +1 -1
  179. package/dist/index.cjs +18977 -13378
  180. package/dist/index.d.cts +3065 -664
  181. package/dist/index.d.ts +46 -16
  182. package/dist/index.js +149 -7
  183. package/dist/labels-context.d.ts +93 -3
  184. package/dist/motion-timing.d.ts +8 -0
  185. package/dist/motion-timing.js +8 -0
  186. package/dist/overlay-stack.d.ts +6 -0
  187. package/dist/overlay-stack.js +13 -0
  188. package/dist/qr-model.d.ts +65 -0
  189. package/dist/qr-model.js +323 -0
  190. package/dist/relationship-graph-model.d.ts +78 -3
  191. package/dist/relationship-graph-model.js +112 -5
  192. package/dist/reorder.d.ts +30 -0
  193. package/dist/reorder.js +74 -0
  194. package/dist/rich-text.cjs +4 -2
  195. package/dist/scheduling-resource-model.d.ts +76 -0
  196. package/dist/scheduling-resource-model.js +74 -0
  197. package/dist/search-suggest-model.js +3 -1
  198. package/dist/shell-context.d.ts +11 -0
  199. package/dist/shell-context.js +7 -0
  200. package/dist/time-field-model.d.ts +46 -0
  201. package/dist/time-field-model.js +152 -0
  202. package/dist/toast-store.d.ts +17 -1
  203. package/dist/toast-store.js +23 -7
  204. package/package.json +2 -1
@@ -1,8 +1,15 @@
1
+ /**
2
+ * A colour that a node or an edge shares with a legend item (HAR-1639). Colour is never the only
3
+ * signal: say the same thing in the node's text, the edge's `description` or its `variant`.
4
+ */
5
+ type RelationshipGraphTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger' | 'accent';
1
6
  interface RelationshipGraphNode {
2
7
  id: string;
3
8
  label: string;
4
9
  type?: string;
5
10
  description?: string;
11
+ /** Layered layout: the node's border and edge mark take this tone (HAR-1639). */
12
+ tone?: RelationshipGraphTone;
6
13
  x?: number;
7
14
  y?: number;
8
15
  /** Layered layout: the node's column. Omitted → BFS distance from the root along source→target. */
@@ -20,6 +27,18 @@ interface RelationshipGraphEdge {
20
27
  arrow?: RelationshipGraphArrow;
21
28
  /** Layered layout: always draw this edge's label, whatever the label policy. */
22
29
  emphasis?: boolean;
30
+ /**
31
+ * `dashed` draws the line dashed, e.g. an expected relation that is missing (HAR-1639). Default
32
+ * `solid`; a lateral or cycle edge is dashed either way.
33
+ */
34
+ variant?: 'solid' | 'dashed';
35
+ /** The line and arrowhead take this tone (HAR-1639). */
36
+ tone?: RelationshipGraphTone;
37
+ /**
38
+ * Said to assistive technology with the relationship, on both nodes it joins, e.g. "expected,
39
+ * missing" (HAR-1639). The drawn line itself is decoration; the nodes carry the relationship.
40
+ */
41
+ description?: string;
23
42
  }
24
43
  interface PositionedRelationshipNode extends RelationshipGraphNode {
25
44
  x: number;
@@ -35,7 +54,12 @@ declare function boundRelationshipGraph(nodes: RelationshipGraphNode[], edges: R
35
54
  declare function relationshipNeighbors(nodeId: string, edges: RelationshipGraphEdge[]): string[];
36
55
  declare function layoutRelationshipGraph(nodes: RelationshipGraphNode[], edges: RelationshipGraphEdge[], rootId?: string): PositionedRelationshipNode[];
37
56
  declare function traverseRelationshipNode(nodes: RelationshipGraphNode[], currentId: string | undefined, direction: -1 | 1): string | undefined;
38
- type LayeredEdgeKind = 'forward' | 'lateral' | 'cycle';
57
+ /**
58
+ * `forward` steps one column right; `skip` goes right across more than one column; `lateral`
59
+ * stays in its column; `back` goes left without closing a loop; `cycle` goes left and closes one
60
+ * (HAR-1639: only a cycle is flagged as one, and only lateral and cycle edges are dashed).
61
+ */
62
+ type LayeredEdgeKind = 'forward' | 'skip' | 'lateral' | 'back' | 'cycle';
39
63
  interface LayeredLayoutOptions {
40
64
  rootId?: string;
41
65
  /** Minimum sibling group size that collapses into a cluster. Default 6; 0 disables. */
@@ -70,7 +94,7 @@ interface LayeredItem {
70
94
  children: string[];
71
95
  /** Set on the first member of an expanded cluster: the group its collapse control belongs to. */
72
96
  expandedGroup?: RelationshipGraphCluster;
73
- /** True when a lateral or cycle edge touches this node. */
97
+ /** True when a cycle edge touches this node (HAR-1639: no longer set by skip, lateral or back edges). */
74
98
  inCycle: boolean;
75
99
  /** Edges (any kind) touching this item. */
76
100
  degree: number;
@@ -87,6 +111,10 @@ interface RoutedEdge {
87
111
  label?: string;
88
112
  arrow: RelationshipGraphArrow;
89
113
  emphasis: boolean;
114
+ /** The first underlying edge's `variant`, `tone` and `description`. */
115
+ variant: 'solid' | 'dashed';
116
+ tone?: RelationshipGraphTone;
117
+ description?: string;
90
118
  path: string;
91
119
  labelX: number;
92
120
  labelY: number;
@@ -96,6 +124,17 @@ interface RoutedEdge {
96
124
  arrowAngle: number;
97
125
  /** Label policy `auto` shows this label without interaction. */
98
126
  autoLabel: boolean;
127
+ /**
128
+ * The label is said once by the target column's header (`LayeredColumn.edgeLabel`), so the
129
+ * edge itself never draws it under `edgeLabels="auto"` (HAR-1387: 197 of 200 labels on a
130
+ * 300-node map read "depends on").
131
+ */
132
+ columnLabel: boolean;
133
+ /**
134
+ * One of a busy node's forward edges, drawn as a bus: along a shared trunk in the column gap
135
+ * and a short stub into the target, so a fan-out reads as one line, not a black fan (HAR-1387).
136
+ */
137
+ bus: boolean;
99
138
  /** The label wrapped to fit the column gap (at most two lines). */
100
139
  labelLines: string[];
101
140
  }
@@ -104,6 +143,11 @@ interface LayeredColumn {
104
143
  x: number;
105
144
  /** Underlying nodes in the column, cluster members included. */
106
145
  count: number;
146
+ /**
147
+ * The relation most forward edges into this column share, when the column takes more than a
148
+ * few of them: the header says it once and those edges draw no label (HAR-1387).
149
+ */
150
+ edgeLabel?: string;
107
151
  }
108
152
  interface LayeredLayout {
109
153
  rootId: string | undefined;
@@ -135,8 +179,39 @@ declare function classifyLayeredEdges(nodes: RelationshipGraphNode[], edges: Rel
135
179
  declare function clusterIdFor(parentId: string, type: string | undefined, edgeType: string | undefined): string;
136
180
  /** Layered, clustered, crossing-reduced layout for `RelationshipGraph layout="layered"`. */
137
181
  declare function layoutLayeredGraph(nodes: RelationshipGraphNode[], edges: RelationshipGraphEdge[], options?: LayeredLayoutOptions): LayeredLayout;
182
+ /** An edge label's box on the stage, for `separateEdgeLabels`. */
183
+ interface EdgeLabelBox {
184
+ id: string;
185
+ /** Centre of the label. */
186
+ x: number;
187
+ y: number;
188
+ width: number;
189
+ height: number;
190
+ }
191
+ /** Where a label is drawn after `separateEdgeLabels`, or that it is left out. */
192
+ interface PlacedEdgeLabel {
193
+ x: number;
194
+ y: number;
195
+ hidden: boolean;
196
+ }
197
+ /** The box a wrapped edge label takes, from its lines (the meta type size, as `wrapEdgeLabel` assumes). */
198
+ declare function edgeLabelSize(lines: readonly string[]): {
199
+ width: number;
200
+ height: number;
201
+ };
202
+ /**
203
+ * Moves edge labels apart where they would be drawn over each other (HAR-1639: two labels on top
204
+ * of each other in a dense layered column). Labels are taken top to bottom; one that overlaps a
205
+ * label already placed moves down just below it. A label that would have to move further than
206
+ * `maxShift` from its edge is left out instead (the relationship is still in the nodes'
207
+ * descriptions and in the list). Deterministic: the same boxes give the same placement.
208
+ */
209
+ declare function separateEdgeLabels(boxes: readonly EdgeLabelBox[], options?: {
210
+ gap?: number;
211
+ maxShift?: number;
212
+ }): Map<string, PlacedEdgeLabel>;
138
213
  type LayeredNavigationKey = 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight' | 'Home' | 'End';
139
214
  /** Keyboard traversal over a layered layout: ←/→ along forward edges, ↑/↓ within a column. */
140
215
  declare function layeredNeighbor(layout: LayeredLayout, currentId: string | undefined, key: LayeredNavigationKey): string | undefined;
141
216
 
142
- export { type BoundedRelationshipGraph, type LayeredColumn, type LayeredEdgeClassification, type LayeredEdgeKind, type LayeredItem, type LayeredLayout, type LayeredLayoutOptions, type LayeredNavigationKey, type PositionedRelationshipNode, type RelationshipGraphArrow, type RelationshipGraphCluster, type RelationshipGraphEdge, type RelationshipGraphNode, type RoutedEdge, boundRelationshipGraph, classifyLayeredEdges, clusterIdFor, layeredNeighbor, layoutLayeredGraph, layoutRelationshipGraph, relationshipNeighbors, traverseRelationshipNode, wrapEdgeLabel };
217
+ export { type BoundedRelationshipGraph, type EdgeLabelBox, type LayeredColumn, type LayeredEdgeClassification, type LayeredEdgeKind, type LayeredItem, type LayeredLayout, type LayeredLayoutOptions, type LayeredNavigationKey, type PlacedEdgeLabel, type PositionedRelationshipNode, type RelationshipGraphArrow, type RelationshipGraphCluster, type RelationshipGraphEdge, type RelationshipGraphNode, type RelationshipGraphTone, type RoutedEdge, boundRelationshipGraph, classifyLayeredEdges, clusterIdFor, edgeLabelSize, layeredNeighbor, layoutLayeredGraph, layoutRelationshipGraph, relationshipNeighbors, separateEdgeLabels, traverseRelationshipNode, wrapEdgeLabel };
@@ -142,6 +142,8 @@ function classifyLayeredEdges(nodes, edges, rootId = nodes[0]?.id) {
142
142
  const list = forwardOut.get(edge.source);
143
143
  if (list) list.push(edge.target);
144
144
  else forwardOut.set(edge.source, [edge.target]);
145
+ } else if (to > from + 1) {
146
+ kindById.set(edge.id, "skip");
145
147
  } else if (to < from) {
146
148
  backEdges.push(edge);
147
149
  } else {
@@ -166,13 +168,20 @@ function classifyLayeredEdges(nodes, edges, rootId = nodes[0]?.id) {
166
168
  }
167
169
  }
168
170
  }
169
- kindById.set(edge.id, closes ? "cycle" : "lateral");
171
+ kindById.set(edge.id, closes ? "cycle" : "back");
170
172
  }
171
173
  return { depthById, kindById };
172
174
  }
173
175
  function clusterIdFor(parentId, type, edgeType) {
174
176
  return `cluster:${parentId}:${type ?? ""}:${edgeType ?? ""}`;
175
177
  }
178
+ function busPath(startX, startY, trunk, endX, endY) {
179
+ const dy = endY - startY;
180
+ if (Math.abs(dy) < 1) return `M${round1(startX)} ${round1(startY)} H${round1(endX)}`;
181
+ const r = Math.min(8, Math.abs(dy) / 2, trunk - startX, endX - trunk);
182
+ const dir = Math.sign(dy);
183
+ return `M${round1(startX)} ${round1(startY)} H${round1(trunk - r)} Q${round1(trunk)} ${round1(startY)} ${round1(trunk)} ${round1(startY + dir * r)} V${round1(endY - dir * r)} Q${round1(trunk)} ${round1(endY)} ${round1(trunk + r)} ${round1(endY)} H${round1(endX)}`;
184
+ }
176
185
  const mean = (values) => values.reduce((sum, value) => sum + value, 0) / values.length;
177
186
  const round1 = (value) => Math.round(value * 10) / 10;
178
187
  function layoutLayeredGraph(nodes, edges, options = {}) {
@@ -200,6 +209,7 @@ function layoutLayeredGraph(nodes, edges, options = {}) {
200
209
  const forwardParents = /* @__PURE__ */ new Map();
201
210
  const forwardChildCount = /* @__PURE__ */ new Map();
202
211
  const inCycle = /* @__PURE__ */ new Set();
212
+ const crossLinked = /* @__PURE__ */ new Set();
203
213
  const nodeDegree = /* @__PURE__ */ new Map();
204
214
  for (const edge of drawable) {
205
215
  nodeDegree.set(edge.source, (nodeDegree.get(edge.source) ?? 0) + 1);
@@ -210,14 +220,18 @@ function layoutLayeredGraph(nodes, edges, options = {}) {
210
220
  else forwardParents.set(edge.target, [edge]);
211
221
  forwardChildCount.set(edge.source, (forwardChildCount.get(edge.source) ?? 0) + 1);
212
222
  } else {
213
- inCycle.add(edge.source);
214
- inCycle.add(edge.target);
223
+ crossLinked.add(edge.source);
224
+ crossLinked.add(edge.target);
225
+ if (kindById.get(edge.id) === "cycle") {
226
+ inCycle.add(edge.source);
227
+ inCycle.add(edge.target);
228
+ }
215
229
  }
216
230
  }
217
231
  const groups = /* @__PURE__ */ new Map();
218
232
  if (threshold > 0) {
219
233
  for (const node of nodes) {
220
- if (node.id === rootId || inCycle.has(node.id) || (forwardChildCount.get(node.id) ?? 0) > 0) continue;
234
+ if (node.id === rootId || crossLinked.has(node.id) || (forwardChildCount.get(node.id) ?? 0) > 0) continue;
221
235
  const parents = forwardParents.get(node.id) ?? [];
222
236
  if (parents.length !== 1) continue;
223
237
  const via = parents[0];
@@ -369,7 +383,33 @@ function layoutLayeredGraph(nodes, edges, options = {}) {
369
383
  let labelY;
370
384
  let startAngle;
371
385
  let endAngle;
372
- if (kind === "forward") {
386
+ if (kind === "skip") {
387
+ startX = from.x + from.width;
388
+ startY = from.y + from.height / 2;
389
+ endX = to.x;
390
+ endY = to.y + to.height / 2;
391
+ let floor = Math.max(startY, endY);
392
+ for (const item of itemById.values()) if (item.depth > from.depth && item.depth < to.depth) floor = Math.max(floor, item.y + item.height);
393
+ const channel = floor + 18;
394
+ const half = columnGap / 2;
395
+ path = `M${round1(startX)} ${round1(startY)} C${round1(startX + half)} ${round1(startY)} ${round1(startX + half)} ${round1(channel)} ${round1(startX + half)} ${round1(channel)} L${round1(endX - half)} ${round1(channel)} C${round1(endX - half)} ${round1(channel)} ${round1(endX - half)} ${round1(endY)} ${round1(endX)} ${round1(endY)}`;
396
+ labelX = (startX + endX) / 2;
397
+ labelY = channel;
398
+ startAngle = Math.PI;
399
+ endAngle = 0;
400
+ height = Math.max(height, channel + 8);
401
+ } else if (kind === "forward" && from.children.length > AUTO_LABEL_MAX_FANOUT) {
402
+ startX = from.x + from.width;
403
+ startY = from.y + from.height / 2;
404
+ endX = to.x;
405
+ endY = to.y + to.height / 2;
406
+ const trunk = startX + columnGap / 2;
407
+ path = busPath(startX, startY, trunk, endX, endY);
408
+ labelX = (trunk + endX) / 2;
409
+ labelY = endY;
410
+ startAngle = Math.PI;
411
+ endAngle = 0;
412
+ } else if (kind === "forward") {
373
413
  startX = from.x + from.width;
374
414
  startY = from.y + from.height / 2;
375
415
  endX = to.x;
@@ -415,6 +455,7 @@ function layoutLayeredGraph(nodes, edges, options = {}) {
415
455
  edgeIds: [edge.id],
416
456
  arrow,
417
457
  emphasis: edge.emphasis === true,
458
+ variant: edge.variant === "dashed" ? "dashed" : "solid",
418
459
  path,
419
460
  labelX: round1(labelX),
420
461
  labelY: round1(labelY),
@@ -422,13 +463,48 @@ function layoutLayeredGraph(nodes, edges, options = {}) {
422
463
  arrowY: round1(atStart ? startY : endY),
423
464
  arrowAngle: atStart ? startAngle : endAngle,
424
465
  labelLines: [],
466
+ columnLabel: false,
467
+ bus: kind === "forward" && from.children.length > AUTO_LABEL_MAX_FANOUT,
425
468
  autoLabel: to.kind !== "cluster" && (edge.emphasis === true || kind === "forward" && from.children.length <= AUTO_LABEL_MAX_FANOUT)
426
469
  };
427
470
  if (edge.type !== void 0) entry.type = edge.type;
471
+ if (edge.tone !== void 0) entry.tone = edge.tone;
472
+ if (edge.description !== void 0) entry.description = edge.description;
428
473
  const label = edge.label ?? edge.type;
429
474
  if (label !== void 0) entry.label = label;
430
475
  routed.set(key, entry);
431
476
  }
477
+ const intoColumn = /* @__PURE__ */ new Map();
478
+ for (const entry of routed.values()) {
479
+ if (entry.kind !== "forward" || entry.label === void 0) continue;
480
+ const depth = itemById.get(entry.target).depth;
481
+ const list = intoColumn.get(depth);
482
+ if (list) list.push(entry);
483
+ else intoColumn.set(depth, [entry]);
484
+ }
485
+ for (const [depth, entries] of intoColumn) {
486
+ if (entries.length <= AUTO_LABEL_MAX_FANOUT) continue;
487
+ const counts = /* @__PURE__ */ new Map();
488
+ for (const entry of entries) counts.set(entry.label, (counts.get(entry.label) ?? 0) + 1);
489
+ let dominant;
490
+ let most = 1;
491
+ for (const [label, count] of counts) if (count > most) {
492
+ dominant = label;
493
+ most = count;
494
+ }
495
+ if (dominant === void 0) continue;
496
+ const column = columns.find((candidate) => candidate.depth === depth);
497
+ if (column) column.edgeLabel = dominant;
498
+ for (const entry of entries) {
499
+ if (entry.emphasis) continue;
500
+ if (entry.label === dominant) {
501
+ entry.columnLabel = true;
502
+ entry.autoLabel = false;
503
+ } else if (itemById.get(entry.target).kind !== "cluster") {
504
+ entry.autoLabel = true;
505
+ }
506
+ }
507
+ }
432
508
  const seenLabels = /* @__PURE__ */ new Set();
433
509
  for (const entry of routed.values()) {
434
510
  if (entry.label === void 0) continue;
@@ -452,6 +528,35 @@ function layoutLayeredGraph(nodes, edges, options = {}) {
452
528
  headerHeight: LAYERED_HEADER
453
529
  };
454
530
  }
531
+ function edgeLabelSize(lines) {
532
+ const longest = lines.reduce((max, line) => Math.max(max, line.length), 0);
533
+ return { width: longest * LABEL_CHAR_WIDTH + 8, height: Math.max(1, lines.length) * 13 + 2 };
534
+ }
535
+ function separateEdgeLabels(boxes, options = {}) {
536
+ const gap = options.gap ?? 2;
537
+ const maxShift = options.maxShift ?? 40;
538
+ const placed = [];
539
+ const result = /* @__PURE__ */ new Map();
540
+ const ordered = [...boxes].sort((a, b) => a.y - b.y || a.x - b.x || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
541
+ for (const box of ordered) {
542
+ const left = box.x - box.width / 2;
543
+ const right = box.x + box.width / 2;
544
+ let top = box.y - box.height / 2;
545
+ for (let guard = 0; guard <= placed.length; guard += 1) {
546
+ const hit = placed.find((other) => left < other.right && other.left < right && top < other.bottom + gap && other.top - gap < top + box.height);
547
+ if (!hit) break;
548
+ top = hit.bottom + gap;
549
+ }
550
+ const shift = top - (box.y - box.height / 2);
551
+ if (shift > maxShift) {
552
+ result.set(box.id, { x: box.x, y: box.y, hidden: true });
553
+ continue;
554
+ }
555
+ placed.push({ left, right, top, bottom: top + box.height });
556
+ result.set(box.id, { x: box.x, y: round1(top + box.height / 2), hidden: false });
557
+ }
558
+ return result;
559
+ }
455
560
  function layeredNeighbor(layout, currentId, key) {
456
561
  const root = layout.rootId !== void 0 ? layout.itemOf[layout.rootId] : layout.items[0]?.id;
457
562
  const current = layout.items.find((item) => item.id === currentId);
@@ -478,10 +583,12 @@ export {
478
583
  boundRelationshipGraph,
479
584
  classifyLayeredEdges,
480
585
  clusterIdFor,
586
+ edgeLabelSize,
481
587
  layeredNeighbor,
482
588
  layoutLayeredGraph,
483
589
  layoutRelationshipGraph,
484
590
  relationshipNeighbors,
591
+ separateEdgeLabels,
485
592
  traverseRelationshipNode,
486
593
  wrapEdgeLabel
487
594
  };
@@ -0,0 +1,30 @@
1
+ import { PointerEvent } from 'react';
2
+
3
+ /** Move `id` to `index` within `ids`. Returns `ids` itself when nothing moves. */
4
+ declare function placeId(ids: readonly string[], id: string, index: number): readonly string[];
5
+ /** True when two orders hold the same ids in the same order. */
6
+ declare const sameOrder: (a: readonly string[], b: readonly string[]) => boolean;
7
+ /**
8
+ * Where a dragged row lands: how many of the OTHER rows have their middle above the pointer.
9
+ * The rows reorder live while dragging, so counting the dragged row itself would push it one
10
+ * slot past the pointer every time it moves down.
11
+ */
12
+ declare function dropIndex(rows: readonly Element[], dragged: Element | null, clientY: number): number;
13
+ interface RowDragHandlers {
14
+ over: (id: string, index: number) => void;
15
+ drop: (id: string) => void;
16
+ /** The drag was cancelled (Escape, or the browser took the pointer): put the starting order back. */
17
+ cancel?: (id: string) => void;
18
+ }
19
+ /**
20
+ * Pointer drag for a list whose rows reorder live. It listens on the window for the whole drag:
21
+ * React moves the dragged row's DOM node when the order changes, which releases pointer capture on
22
+ * its grip, so after the first move down the grip itself stops receiving move and up events.
23
+ * Nothing animates: the row is placed where the pointer is, frame by frame.
24
+ */
25
+ declare function useRowDrag(rowSelector: string, handlers: RowDragHandlers): {
26
+ dragging: string | null;
27
+ start: (event: PointerEvent<HTMLElement>, id: string) => void;
28
+ };
29
+
30
+ export { type RowDragHandlers, dropIndex, placeId, sameOrder, useRowDrag };
@@ -0,0 +1,74 @@
1
+ "use client";
2
+ import { useEffect, useRef, useState } from "react";
3
+ function placeId(ids, id, index) {
4
+ const from = ids.indexOf(id);
5
+ const to = Math.max(0, Math.min(index, ids.length - 1));
6
+ if (from < 0 || from === to) return ids;
7
+ const next = ids.filter((other) => other !== id);
8
+ next.splice(to, 0, id);
9
+ return next;
10
+ }
11
+ const sameOrder = (a, b) => a.length === b.length && a.every((id, i) => id === b[i]);
12
+ function dropIndex(rows, dragged, clientY) {
13
+ let index = 0;
14
+ for (const row of rows) {
15
+ if (row === dragged) continue;
16
+ const box = row.getBoundingClientRect();
17
+ if (clientY > box.top + box.height / 2) index++;
18
+ }
19
+ return index;
20
+ }
21
+ function useRowDrag(rowSelector, handlers) {
22
+ const [dragging, setDragging] = useState(null);
23
+ const drag = useRef(null);
24
+ const latest = useRef(handlers);
25
+ latest.current = handlers;
26
+ useEffect(() => {
27
+ if (!dragging) return;
28
+ const move = (event) => {
29
+ const current = drag.current;
30
+ if (!current) return;
31
+ latest.current.over(current.id, dropIndex(Array.from(current.list.querySelectorAll(`:scope > ${rowSelector}`)), current.row, event.clientY));
32
+ };
33
+ const finish = (kind) => {
34
+ const current = drag.current;
35
+ drag.current = null;
36
+ setDragging(null);
37
+ if (!current) return;
38
+ if (kind === "drop") latest.current.drop(current.id);
39
+ else latest.current.cancel?.(current.id);
40
+ };
41
+ const end = () => finish("drop");
42
+ const cancel = () => finish("cancel");
43
+ const escape = (event) => {
44
+ if (event.key !== "Escape") return;
45
+ event.preventDefault();
46
+ event.stopPropagation();
47
+ finish("cancel");
48
+ };
49
+ window.addEventListener("pointermove", move);
50
+ window.addEventListener("pointerup", end);
51
+ window.addEventListener("pointercancel", cancel);
52
+ window.addEventListener("keydown", escape, true);
53
+ return () => {
54
+ window.removeEventListener("pointermove", move);
55
+ window.removeEventListener("pointerup", end);
56
+ window.removeEventListener("pointercancel", cancel);
57
+ window.removeEventListener("keydown", escape, true);
58
+ };
59
+ }, [dragging, rowSelector]);
60
+ const start = (event, id) => {
61
+ const row = event.currentTarget.closest("li");
62
+ if (!row?.parentElement) return;
63
+ event.currentTarget.setPointerCapture?.(event.pointerId);
64
+ drag.current = { id, list: row.parentElement, row };
65
+ setDragging(id);
66
+ };
67
+ return { dragging, start };
68
+ }
69
+ export {
70
+ dropIndex,
71
+ placeId,
72
+ sameOrder,
73
+ useRowDrag
74
+ };
@@ -1700,6 +1700,8 @@ function Popover({
1700
1700
  };
1701
1701
  const onKeyDown = (event) => {
1702
1702
  if (event.key !== "Escape" || !isPopoverOpen(el)) return;
1703
+ event.preventDefault();
1704
+ event.stopPropagation();
1703
1705
  window.clearTimeout(timer);
1704
1706
  const hadFocus = el.contains(el.ownerDocument.activeElement);
1705
1707
  try {
@@ -2170,11 +2172,11 @@ function Markdown({
2170
2172
  var import_react6 = require("react");
2171
2173
  var import_jsx_runtime7 = require("react/jsx-runtime");
2172
2174
  var Textarea = (0, import_react6.forwardRef)(
2173
- ({ invalid, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2175
+ ({ invalid, size = "md", className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2174
2176
  "textarea",
2175
2177
  {
2176
2178
  ref,
2177
- className: cx("uix-textarea", className),
2179
+ className: cx("uix-textarea", size === "lg" && "uix-textarea--lg", className),
2178
2180
  "aria-invalid": invalid || void 0,
2179
2181
  ...props
2180
2182
  }
@@ -0,0 +1,76 @@
1
+ /** What a span of a resource's day is: open to book, booked, or not working. */
2
+ type SchedulingAvailabilityKind = 'free' | 'booked' | 'off';
3
+ /** One column of the resource day, e.g. a practitioner. */
4
+ interface SchedulingResource {
5
+ id: string;
6
+ /** The column heading and the start of every slot's accessible name. */
7
+ label: string;
8
+ /** A second line under the heading, e.g. the speciality or the room. */
9
+ description?: string;
10
+ }
11
+ /** A stretch of one resource's day, as the server composed it. */
12
+ interface SchedulingResourceSpan {
13
+ id: string;
14
+ resourceId: string;
15
+ /** ISO 8601 instants, half-open `[start, end)`. */
16
+ start: string;
17
+ end: string;
18
+ kind: SchedulingAvailabilityKind;
19
+ /** Shown on the span, e.g. the patient's name on a booking or "Lunch" on time off. */
20
+ label?: string;
21
+ /** The complete accessible name, in the consumer's words. Replaces the built one. */
22
+ accessibleName?: string;
23
+ }
24
+ /** One row of the slot axis. */
25
+ interface ResourceDaySlot {
26
+ /** Epoch milliseconds of the slot's start and end. */
27
+ start: number;
28
+ end: number;
29
+ /** The local time it starts, `HH:MM`, in the display zone. */
30
+ label: string;
31
+ }
32
+ interface ResourceDaySlotOptions {
33
+ /** The first local time shown, `HH:MM`. Default `'07:00'`. */
34
+ dayStart?: string;
35
+ /** The local time the axis ends, `HH:MM` (exclusive). Default `'19:00'`. */
36
+ dayEnd?: string;
37
+ /** Minutes per slot. Default 15. */
38
+ slotMinutes?: number;
39
+ }
40
+ /** One drawn piece of a column: a bookable slot of a free span, a booking, or time off. */
41
+ interface ResourceDayItem {
42
+ key: string;
43
+ span: SchedulingResourceSpan;
44
+ kind: SchedulingAvailabilityKind;
45
+ /** Epoch milliseconds of what this piece covers (a free span is cut at slot edges). */
46
+ start: number;
47
+ end: number;
48
+ /** Slots from the top of the axis to the piece's start (fractional). */
49
+ offset: number;
50
+ /** Slots the piece is long (fractional). */
51
+ length: number;
52
+ lane: number;
53
+ lanes: number;
54
+ /** The span starts before or ends after the axis. */
55
+ continuesBefore: boolean;
56
+ continuesAfter: boolean;
57
+ }
58
+ /**
59
+ * The slot axis of `date` in `timeZone`: one slot per `slotMinutes` of real time from the first
60
+ * local time at or after `dayStart` to the last before `dayEnd`. On a clock-change day the axis
61
+ * is as long as the day really is (a skipped hour has no slots; a repeated hour has two sets).
62
+ */
63
+ declare function resourceDaySlots(date: string, timeZone: string, options?: ResourceDaySlotOptions): ResourceDaySlot[];
64
+ /**
65
+ * Where the spans of one resource go on the slot axis. Free spans are cut at slot edges, so each
66
+ * bookable slot is its own piece; bookings and time off stay whole. Pieces outside the axis are
67
+ * dropped, pieces across its edges are clipped. Overlapping pieces (a double booking) get lanes.
68
+ */
69
+ declare function layoutResourceColumn(spans: readonly SchedulingResourceSpan[], slots: readonly ResourceDaySlot[]): ResourceDayItem[];
70
+ /** The stretches of the axis no span covers: shown as "no schedule", never as free. */
71
+ declare function resourceDayGaps(items: readonly ResourceDayItem[], slots: readonly ResourceDaySlot[]): Array<{
72
+ start: number;
73
+ end: number;
74
+ }>;
75
+
76
+ export { type ResourceDayItem, type ResourceDaySlot, type ResourceDaySlotOptions, type SchedulingAvailabilityKind, type SchedulingResource, type SchedulingResourceSpan, layoutResourceColumn, resourceDayGaps, resourceDaySlots };
@@ -0,0 +1,74 @@
1
+ import { packLanes, zonedDayBounds, zonedTimeOfDay } from "./calendar-model.js";
2
+ const MINUTE = 6e4;
3
+ const TIME = /^([01]\d|2[0-3]):[0-5]\d$/;
4
+ function resourceDaySlots(date, timeZone, options = {}) {
5
+ const dayStart = options.dayStart && TIME.test(options.dayStart) ? options.dayStart : "07:00";
6
+ const dayEnd = options.dayEnd && TIME.test(options.dayEnd) ? options.dayEnd : "19:00";
7
+ const minutes = Number.isFinite(options.slotMinutes) && options.slotMinutes >= 5 ? Math.floor(options.slotMinutes) : 15;
8
+ const step = minutes * MINUTE;
9
+ const bounds = zonedDayBounds(date, timeZone);
10
+ const all = [];
11
+ for (let at = bounds.start.getTime(); at < bounds.end.getTime(); at += step) {
12
+ all.push({ start: at, end: Math.min(at + step, bounds.end.getTime()), label: zonedTimeOfDay(at, timeZone) });
13
+ }
14
+ const first = all.findIndex((slot) => slot.label >= dayStart);
15
+ let last = -1;
16
+ all.forEach((slot, index) => {
17
+ if (slot.label < dayEnd) last = index;
18
+ });
19
+ if (first === -1 || last < first) return [];
20
+ return all.slice(first, last + 1);
21
+ }
22
+ function layoutResourceColumn(spans, slots) {
23
+ if (slots.length === 0) return [];
24
+ const axisStart = slots[0].start;
25
+ const axisEnd = slots[slots.length - 1].end;
26
+ const slotMs = slots[0].end - slots[0].start;
27
+ const pieces = [];
28
+ const seen = /* @__PURE__ */ new Set();
29
+ for (const span of spans) {
30
+ if (seen.has(span.id)) continue;
31
+ seen.add(span.id);
32
+ const start = new Date(span.start).getTime();
33
+ const end = new Date(span.end).getTime();
34
+ if (!(end > start) || end <= axisStart || start >= axisEnd) continue;
35
+ const from = Math.max(start, axisStart);
36
+ const to = Math.min(end, axisEnd);
37
+ const edges = { continuesBefore: start < axisStart, continuesAfter: end > axisEnd };
38
+ if (span.kind === "free") {
39
+ for (const slot of slots) {
40
+ const a = Math.max(from, slot.start);
41
+ const b = Math.min(to, slot.end);
42
+ if (b > a) pieces.push({ key: `${span.id}@${a}`, span, kind: "free", start: a, end: b, ...edges });
43
+ }
44
+ } else pieces.push({ key: span.id, span, kind: span.kind, start: from, end: to, ...edges });
45
+ }
46
+ const packed = packLanes(pieces.map((piece) => ({ id: piece.key, start: piece.start, end: piece.end })), Infinity);
47
+ return pieces.map((piece) => {
48
+ const placement = packed.lanes[piece.key];
49
+ return {
50
+ ...piece,
51
+ offset: (piece.start - axisStart) / slotMs,
52
+ length: (piece.end - piece.start) / slotMs,
53
+ lane: placement.lane ?? 0,
54
+ lanes: packed.clusters[placement.cluster].laneCount || 1
55
+ };
56
+ }).sort((a, b) => a.start - b.start || a.lane - b.lane);
57
+ }
58
+ function resourceDayGaps(items, slots) {
59
+ if (slots.length === 0) return [];
60
+ const gaps = [];
61
+ let at = slots[0].start;
62
+ for (const item of [...items].sort((a, b) => a.start - b.start)) {
63
+ if (item.start > at) gaps.push({ start: at, end: item.start });
64
+ at = Math.max(at, item.end);
65
+ }
66
+ const axisEnd = slots[slots.length - 1].end;
67
+ if (at < axisEnd) gaps.push({ start: at, end: axisEnd });
68
+ return gaps;
69
+ }
70
+ export {
71
+ layoutResourceColumn,
72
+ resourceDayGaps,
73
+ resourceDaySlots
74
+ };
@@ -1,11 +1,13 @@
1
1
  const COMBINING_MARK = /\p{M}/u;
2
+ const STROKED = { "\u0111": "d", "\xF8": "o", "\u0142": "l", "\u0131": "i", "\u0127": "h", "\u0167": "t" };
2
3
  function foldForSearch(text) {
3
4
  let folded = "";
4
5
  const source = [];
5
6
  const sourceEnd = [];
6
7
  let index = 0;
7
8
  for (const char of text) {
8
- const base = char === "\xDF" || char === "\u1E9E" ? "ss" : char.toLowerCase().normalize("NFD");
9
+ const lower = char.toLowerCase();
10
+ const base = char === "\xDF" || char === "\u1E9E" ? "ss" : STROKED[lower] ?? lower.normalize("NFD");
9
11
  for (const part of base) {
10
12
  if (COMBINING_MARK.test(part)) continue;
11
13
  folded += part;
@@ -0,0 +1,11 @@
1
+ import * as react from 'react';
2
+
3
+ /**
4
+ * True inside AppShell's phone navigation drawer (HAR-1371). The sidebar there is shown full,
5
+ * whatever tier a person chose on a wide screen: a Sidebar and an AccountMenu read this and drop
6
+ * their rail form. Internal: not exported from the package.
7
+ */
8
+ declare const ShellDrawerContext: react.Context<boolean>;
9
+ declare const useInShellDrawer: () => boolean;
10
+
11
+ export { ShellDrawerContext, useInShellDrawer };
@@ -0,0 +1,7 @@
1
+ import { createContext, useContext } from "react";
2
+ const ShellDrawerContext = createContext(false);
3
+ const useInShellDrawer = () => useContext(ShellDrawerContext);
4
+ export {
5
+ ShellDrawerContext,
6
+ useInShellDrawer
7
+ };