@unofficialbox/box-open-elements 0.5.0 → 0.7.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 (227) hide show
  1. package/README.md +27 -73
  2. package/dist/components/collections/table.d.ts +113 -3
  3. package/dist/components/collections/table.js +540 -37
  4. package/dist/components/feedback/due-badge.d.ts +38 -0
  5. package/dist/components/feedback/due-badge.js +168 -0
  6. package/dist/components/feedback/due-types.d.ts +32 -0
  7. package/dist/components/feedback/due-types.js +91 -0
  8. package/dist/components/feedback/progress-steps.d.ts +51 -5
  9. package/dist/components/feedback/progress-steps.js +200 -22
  10. package/dist/components/feedback/stage-path.d.ts +44 -0
  11. package/dist/components/feedback/stage-path.js +235 -0
  12. package/dist/components/forms/select.d.ts +21 -0
  13. package/dist/components/forms/select.js +100 -3
  14. package/dist/components/forms/text-field.d.ts +21 -0
  15. package/dist/components/forms/text-field.js +100 -1
  16. package/dist/components/layout/nav-sidebar.d.ts +14 -0
  17. package/dist/components/layout/nav-sidebar.js +49 -0
  18. package/dist/components/layout/split-view.d.ts +14 -0
  19. package/dist/components/layout/split-view.js +80 -1
  20. package/dist/components/overlays/command-palette.d.ts +62 -0
  21. package/dist/components/overlays/command-palette.js +537 -0
  22. package/dist/components/overlays/command-types.d.ts +90 -0
  23. package/dist/components/overlays/command-types.js +259 -0
  24. package/dist/components/overlays/drawer.d.ts +18 -0
  25. package/dist/components/overlays/drawer.js +135 -9
  26. package/dist/components/overlays/shortcuts-overlay.d.ts +48 -0
  27. package/dist/components/overlays/shortcuts-overlay.js +385 -0
  28. package/dist/components/overlays/tooltip.js +1 -1
  29. package/dist/core/index.d.ts +4 -0
  30. package/dist/core/index.js +2 -0
  31. package/dist/core/offset-window.d.ts +70 -0
  32. package/dist/core/offset-window.js +134 -0
  33. package/dist/core/virtualize.d.ts +71 -0
  34. package/dist/core/virtualize.js +67 -0
  35. package/dist/element-maps.d.ts +292 -0
  36. package/dist/element-maps.js +1 -0
  37. package/dist/entries/activity-density.d.ts +1 -0
  38. package/dist/entries/activity-density.js +1 -0
  39. package/dist/entries/agent-chat.d.ts +1 -0
  40. package/dist/entries/agent-chat.js +1 -0
  41. package/dist/entries/audit-log.d.ts +1 -0
  42. package/dist/entries/audit-log.js +1 -0
  43. package/dist/entries/command-palette.d.ts +1 -0
  44. package/dist/entries/command-palette.js +1 -0
  45. package/dist/entries/compare-view.d.ts +1 -0
  46. package/dist/entries/compare-view.js +1 -0
  47. package/dist/entries/diff-viewer.d.ts +1 -0
  48. package/dist/entries/diff-viewer.js +1 -0
  49. package/dist/entries/due-badge.d.ts +1 -0
  50. package/dist/entries/due-badge.js +1 -0
  51. package/dist/entries/form-wizard.d.ts +1 -0
  52. package/dist/entries/form-wizard.js +1 -0
  53. package/dist/entries/lineage-graph.d.ts +1 -0
  54. package/dist/entries/lineage-graph.js +1 -0
  55. package/dist/entries/notification-bell.d.ts +1 -0
  56. package/dist/entries/notification-bell.js +1 -0
  57. package/dist/entries/notification-inbox.d.ts +1 -0
  58. package/dist/entries/notification-inbox.js +1 -0
  59. package/dist/entries/provenance-strip.d.ts +1 -0
  60. package/dist/entries/provenance-strip.js +1 -0
  61. package/dist/entries/run-trace.d.ts +1 -0
  62. package/dist/entries/run-trace.js +1 -0
  63. package/dist/entries/shortcuts-overlay.d.ts +1 -0
  64. package/dist/entries/shortcuts-overlay.js +1 -0
  65. package/dist/entries/signature-ceremony.d.ts +1 -0
  66. package/dist/entries/signature-ceremony.js +1 -0
  67. package/dist/entries/stage-path.d.ts +1 -0
  68. package/dist/entries/stage-path.js +1 -0
  69. package/dist/entries/timeline.d.ts +1 -0
  70. package/dist/entries/timeline.js +1 -0
  71. package/dist/entries/version-graph.d.ts +1 -0
  72. package/dist/entries/version-graph.js +1 -0
  73. package/dist/entries/version-list.d.ts +1 -0
  74. package/dist/entries/version-list.js +1 -0
  75. package/dist/entries/wizard-summary.d.ts +1 -0
  76. package/dist/entries/wizard-summary.js +1 -0
  77. package/dist/entries/work-queue.d.ts +1 -0
  78. package/dist/entries/work-queue.js +1 -0
  79. package/dist/entries/workload-board.d.ts +1 -0
  80. package/dist/entries/workload-board.js +1 -0
  81. package/dist/index.d.ts +21 -0
  82. package/dist/index.js +21 -0
  83. package/dist/patterns/agent-chat/agent-chat.d.ts +75 -0
  84. package/dist/patterns/agent-chat/agent-chat.js +820 -0
  85. package/dist/patterns/agent-chat/controller.d.ts +27 -0
  86. package/dist/patterns/agent-chat/controller.js +182 -0
  87. package/dist/patterns/agent-chat/index.d.ts +3 -0
  88. package/dist/patterns/agent-chat/index.js +6 -0
  89. package/dist/patterns/agent-chat/types.d.ts +109 -0
  90. package/dist/patterns/agent-chat/types.js +1 -0
  91. package/dist/patterns/audit/activity-density.d.ts +68 -0
  92. package/dist/patterns/audit/activity-density.js +428 -0
  93. package/dist/patterns/audit/audit-log.d.ts +182 -0
  94. package/dist/patterns/audit/audit-log.js +1082 -0
  95. package/dist/patterns/audit/index.d.ts +3 -0
  96. package/dist/patterns/audit/index.js +7 -0
  97. package/dist/patterns/audit/shared.d.ts +10 -0
  98. package/dist/patterns/audit/shared.js +50 -0
  99. package/dist/patterns/audit/types.d.ts +143 -0
  100. package/dist/patterns/audit/types.js +327 -0
  101. package/dist/patterns/audit/window.d.ts +116 -0
  102. package/dist/patterns/audit/window.js +132 -0
  103. package/dist/patterns/content-explorer/actions/controller.js +12 -2
  104. package/dist/patterns/content-explorer/box-transport.js +117 -25
  105. package/dist/patterns/content-explorer/content-explorer.d.ts +13 -1
  106. package/dist/patterns/content-explorer/content-explorer.js +36 -3
  107. package/dist/patterns/content-explorer/contracts.d.ts +24 -1
  108. package/dist/patterns/content-explorer/contracts.js +68 -11
  109. package/dist/patterns/content-explorer/controller.d.ts +16 -1
  110. package/dist/patterns/content-explorer/controller.js +130 -4
  111. package/dist/patterns/content-explorer/navigation/controller.js +11 -9
  112. package/dist/patterns/content-explorer/types.d.ts +58 -1
  113. package/dist/patterns/content-picker/content-picker.d.ts +71 -0
  114. package/dist/patterns/content-picker/content-picker.js +747 -0
  115. package/dist/patterns/content-picker/controller.d.ts +38 -0
  116. package/dist/patterns/content-picker/controller.js +141 -0
  117. package/dist/patterns/content-picker/index.d.ts +3 -0
  118. package/dist/patterns/content-picker/index.js +6 -0
  119. package/dist/patterns/content-picker/types.d.ts +52 -0
  120. package/dist/patterns/content-picker/types.js +26 -0
  121. package/dist/patterns/content-sidebar/content-sidebar.d.ts +43 -0
  122. package/dist/patterns/content-sidebar/content-sidebar.js +293 -0
  123. package/dist/patterns/content-sidebar/index.d.ts +2 -0
  124. package/dist/patterns/content-sidebar/index.js +4 -0
  125. package/dist/patterns/content-sidebar/types.d.ts +18 -0
  126. package/dist/patterns/content-sidebar/types.js +20 -0
  127. package/dist/patterns/content-uploader/box-transport.d.ts +14 -0
  128. package/dist/patterns/content-uploader/box-transport.js +54 -0
  129. package/dist/patterns/content-uploader/content-uploader.d.ts +62 -0
  130. package/dist/patterns/content-uploader/content-uploader.js +559 -0
  131. package/dist/patterns/content-uploader/controller.d.ts +39 -0
  132. package/dist/patterns/content-uploader/controller.js +227 -0
  133. package/dist/patterns/content-uploader/index.d.ts +4 -0
  134. package/dist/patterns/content-uploader/index.js +8 -0
  135. package/dist/patterns/content-uploader/types.d.ts +120 -0
  136. package/dist/patterns/content-uploader/types.js +38 -0
  137. package/dist/patterns/diff/compare-view.d.ts +47 -0
  138. package/dist/patterns/diff/compare-view.js +276 -0
  139. package/dist/patterns/diff/diff-viewer.d.ts +42 -0
  140. package/dist/patterns/diff/diff-viewer.js +434 -0
  141. package/dist/patterns/diff/engine.d.ts +22 -0
  142. package/dist/patterns/diff/engine.js +276 -0
  143. package/dist/patterns/diff/index.d.ts +4 -0
  144. package/dist/patterns/diff/index.js +8 -0
  145. package/dist/patterns/diff/types.d.ts +69 -0
  146. package/dist/patterns/diff/types.js +24 -0
  147. package/dist/patterns/form-wizard/controller.d.ts +39 -0
  148. package/dist/patterns/form-wizard/controller.js +157 -0
  149. package/dist/patterns/form-wizard/form-wizard.d.ts +63 -0
  150. package/dist/patterns/form-wizard/form-wizard.js +468 -0
  151. package/dist/patterns/form-wizard/index.d.ts +4 -0
  152. package/dist/patterns/form-wizard/index.js +8 -0
  153. package/dist/patterns/form-wizard/types.d.ts +109 -0
  154. package/dist/patterns/form-wizard/types.js +83 -0
  155. package/dist/patterns/form-wizard/wizard-summary.d.ts +62 -0
  156. package/dist/patterns/form-wizard/wizard-summary.js +324 -0
  157. package/dist/patterns/internal/safe-href.d.ts +17 -0
  158. package/dist/patterns/internal/safe-href.js +17 -0
  159. package/dist/patterns/lineage/index.d.ts +3 -0
  160. package/dist/patterns/lineage/index.js +6 -0
  161. package/dist/patterns/lineage/lineage-graph.d.ts +30 -0
  162. package/dist/patterns/lineage/lineage-graph.js +434 -0
  163. package/dist/patterns/lineage/provenance-strip.d.ts +22 -0
  164. package/dist/patterns/lineage/provenance-strip.js +194 -0
  165. package/dist/patterns/lineage/types.d.ts +53 -0
  166. package/dist/patterns/lineage/types.js +49 -0
  167. package/dist/patterns/notifications/index.d.ts +3 -0
  168. package/dist/patterns/notifications/index.js +6 -0
  169. package/dist/patterns/notifications/notification-bell.d.ts +38 -0
  170. package/dist/patterns/notifications/notification-bell.js +198 -0
  171. package/dist/patterns/notifications/notification-inbox.d.ts +46 -0
  172. package/dist/patterns/notifications/notification-inbox.js +537 -0
  173. package/dist/patterns/notifications/types.d.ts +61 -0
  174. package/dist/patterns/notifications/types.js +108 -0
  175. package/dist/patterns/preview/annotation-inspector.d.ts +25 -6
  176. package/dist/patterns/preview/annotation-inspector.js +239 -94
  177. package/dist/patterns/preview/annotation-thread.d.ts +25 -5
  178. package/dist/patterns/preview/annotation-thread.js +233 -82
  179. package/dist/patterns/preview/annotation-toolbar.d.ts +20 -6
  180. package/dist/patterns/preview/annotation-toolbar.js +162 -96
  181. package/dist/patterns/preview/content-preview-adapter.d.ts +10 -1
  182. package/dist/patterns/preview/content-preview-adapter.js +26 -1
  183. package/dist/patterns/preview/preview-element.d.ts +15 -2
  184. package/dist/patterns/preview/preview-element.js +223 -52
  185. package/dist/patterns/preview/provider-adapter.d.ts +47 -0
  186. package/dist/patterns/preview/provider-adapter.js +17 -0
  187. package/dist/patterns/run/index.d.ts +2 -0
  188. package/dist/patterns/run/index.js +4 -0
  189. package/dist/patterns/run/run-trace.d.ts +40 -0
  190. package/dist/patterns/run/run-trace.js +441 -0
  191. package/dist/patterns/run/types.d.ts +66 -0
  192. package/dist/patterns/run/types.js +152 -0
  193. package/dist/patterns/signature/index.d.ts +2 -0
  194. package/dist/patterns/signature/index.js +4 -0
  195. package/dist/patterns/signature/signature-ceremony.d.ts +33 -0
  196. package/dist/patterns/signature/signature-ceremony.js +317 -0
  197. package/dist/patterns/signature/types.d.ts +68 -0
  198. package/dist/patterns/signature/types.js +89 -0
  199. package/dist/patterns/timeline/index.d.ts +2 -0
  200. package/dist/patterns/timeline/index.js +4 -0
  201. package/dist/patterns/timeline/timeline.d.ts +27 -0
  202. package/dist/patterns/timeline/timeline.js +430 -0
  203. package/dist/patterns/timeline/types.d.ts +36 -0
  204. package/dist/patterns/timeline/types.js +27 -0
  205. package/dist/patterns/versions/graph-layout.d.ts +43 -0
  206. package/dist/patterns/versions/graph-layout.js +159 -0
  207. package/dist/patterns/versions/index.d.ts +4 -0
  208. package/dist/patterns/versions/index.js +8 -0
  209. package/dist/patterns/versions/shared.d.ts +4 -0
  210. package/dist/patterns/versions/shared.js +13 -0
  211. package/dist/patterns/versions/types.d.ts +37 -0
  212. package/dist/patterns/versions/types.js +39 -0
  213. package/dist/patterns/versions/version-graph.d.ts +36 -0
  214. package/dist/patterns/versions/version-graph.js +438 -0
  215. package/dist/patterns/versions/version-list.d.ts +39 -0
  216. package/dist/patterns/versions/version-list.js +407 -0
  217. package/dist/patterns/work-queue/controller.d.ts +26 -0
  218. package/dist/patterns/work-queue/controller.js +150 -0
  219. package/dist/patterns/work-queue/index.d.ts +4 -0
  220. package/dist/patterns/work-queue/index.js +7 -0
  221. package/dist/patterns/work-queue/types.d.ts +128 -0
  222. package/dist/patterns/work-queue/types.js +45 -0
  223. package/dist/patterns/work-queue/work-queue.d.ts +48 -0
  224. package/dist/patterns/work-queue/work-queue.js +534 -0
  225. package/dist/patterns/work-queue/workload-board.d.ts +53 -0
  226. package/dist/patterns/work-queue/workload-board.js +608 -0
  227. package/package.json +89 -5
@@ -0,0 +1,434 @@
1
+ import { isLineageNodeRecord, resolveLineageDeviation } from "./types.js";
2
+ import { computeVersionGraphLayout } from "../versions/graph-layout.js";
3
+ import { formatItemDate } from "../content-explorer/adapters/item-summary.js";
4
+ import { BaseElement } from "../../core/index.js";
5
+ import { boeMotionDuration, boeMotionEasing } from "../../foundations/motion/index.js";
6
+ import { boePanel, boeRadius } from "../../foundations/geometry/index.js";
7
+ const DEFAULT_TAG_NAME = "box-lineage-graph";
8
+ const escapeHtml = (value) => value
9
+ .replaceAll("&", "&")
10
+ .replaceAll("<", "&lt;")
11
+ .replaceAll(">", "&gt;")
12
+ .replaceAll('"', "&quot;")
13
+ .replaceAll("'", "&#39;");
14
+ const LANE_WIDTH = 26;
15
+ const ROW_HEIGHT = 56;
16
+ const EDGE_PAD = 8;
17
+ const DEVIATION_LABELS = {
18
+ none: "in sync",
19
+ minor: "minor deviation",
20
+ major: "major deviation",
21
+ };
22
+ const elementStyles = `
23
+ [hidden] {
24
+ display: none !important;
25
+ }
26
+
27
+ :host {
28
+ display: block;
29
+ color: inherit;
30
+ font: inherit;
31
+ }
32
+
33
+ section[part="panel"] {
34
+ display: grid;
35
+ gap: ${boePanel.gap};
36
+ padding: ${boePanel.padding};
37
+ border: 1px solid color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 82%, transparent);
38
+ border-radius: ${boePanel.radius};
39
+ background: ${boePanel.background};
40
+ }
41
+
42
+ [part="title"] {
43
+ margin: 0;
44
+ font: inherit;
45
+ font-size: 1.1rem;
46
+ font-weight: 700;
47
+ color: var(--boe-token-text-text, #1f1e1b);
48
+ }
49
+
50
+ [part="graph"] {
51
+ position: relative;
52
+ overflow-x: auto;
53
+ }
54
+
55
+ [part="edges"] {
56
+ position: absolute;
57
+ inset-block-start: 0;
58
+ inset-inline-start: 0;
59
+ pointer-events: none;
60
+ }
61
+
62
+ [part="edge"] {
63
+ fill: none;
64
+ stroke: color-mix(in srgb, var(--boe-token-text-text-secondary, #6f6f6f) 45%, transparent);
65
+ stroke-width: 2;
66
+ }
67
+
68
+ [part="edge"][data-deviation="minor"] {
69
+ stroke: color-mix(in srgb, var(--boe-token-surface-status-surface-warning, #f5b31b) 75%, transparent);
70
+ }
71
+
72
+ [part="edge"][data-deviation="major"] {
73
+ stroke: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 70%, transparent);
74
+ }
75
+
76
+ [part="rows"] {
77
+ list-style: none;
78
+ margin: 0;
79
+ padding: 0;
80
+ position: relative;
81
+ }
82
+
83
+ [part="row"] {
84
+ position: relative;
85
+ display: flex;
86
+ flex-wrap: wrap;
87
+ align-items: center;
88
+ gap: 0.45rem;
89
+ block-size: ${ROW_HEIGHT}px;
90
+ border-radius: ${boeRadius.med};
91
+ }
92
+
93
+ [part="node"] {
94
+ position: absolute;
95
+ inset-block-start: 50%;
96
+ transform: translate(-50%, -50%);
97
+ appearance: none;
98
+ padding: 0;
99
+ inline-size: 0.9rem;
100
+ block-size: 0.9rem;
101
+ border-radius: 999px;
102
+ border: 2px solid var(--boe-token-text-text-secondary, #6f6f6f);
103
+ background: var(--boe-token-surface-surface, #ffffff);
104
+ cursor: pointer;
105
+ }
106
+
107
+ [part="node"][data-kind="clause"] {
108
+ border-color: var(--boe-token-surface-surface-brand, #0061d5);
109
+ background: var(--boe-token-surface-surface-brand, #0061d5);
110
+ }
111
+
112
+ [part="node"][data-kind="template"] {
113
+ border-radius: ${boeRadius.size};
114
+ }
115
+
116
+ [part="node"][data-kind="contract"] {
117
+ background: var(--boe-token-text-text-secondary, #6f6f6f);
118
+ }
119
+
120
+ [part="node"]:focus-visible {
121
+ outline: none;
122
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 45%, transparent);
123
+ }
124
+
125
+ [part="row-label"] {
126
+ font-weight: 700;
127
+ color: var(--boe-token-text-text, #1f1e1b);
128
+ }
129
+
130
+ [part="kind"] {
131
+ display: inline-flex;
132
+ padding: 0.1rem 0.4rem;
133
+ border-radius: 999px;
134
+ background: var(--boe-token-surface-item-surface-selected, #f2f7fd);
135
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
136
+ font-size: 0.72rem;
137
+ font-weight: 700;
138
+ text-transform: capitalize;
139
+ }
140
+
141
+ [part="row-meta"] {
142
+ font-size: 0.78rem;
143
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
144
+ }
145
+
146
+ [part="edge-chip"] {
147
+ appearance: none;
148
+ font: inherit;
149
+ font-size: 0.74rem;
150
+ font-weight: 600;
151
+ padding: 0.2rem 0.5rem;
152
+ border-radius: 999px;
153
+ border: 1px solid color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 60%, transparent);
154
+ background: var(--boe-token-surface-surface, #ffffff);
155
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
156
+ cursor: pointer;
157
+ transition: background ${boeMotionDuration.interactive} ${boeMotionEasing.standard};
158
+ }
159
+
160
+ [part="edge-chip"]:hover {
161
+ background: var(--boe-token-surface-surface-hover, #f4f4f4);
162
+ }
163
+
164
+ [part="edge-chip"][data-deviation="minor"] {
165
+ border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-warning, #f5b31b) 55%, transparent);
166
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-warning, #f5b31b) 46%, black 54%);
167
+ }
168
+
169
+ [part="edge-chip"][data-deviation="major"] {
170
+ border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 45%, transparent);
171
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 74%, black 26%);
172
+ }
173
+
174
+ [part="edge-chip"]:focus-visible {
175
+ outline: none;
176
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 18%, transparent);
177
+ }
178
+
179
+ [part="empty"] {
180
+ padding: ${boePanel.padding};
181
+ border-radius: ${boeRadius.large};
182
+ border: 1px dashed color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 70%, transparent);
183
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
184
+ }
185
+ `;
186
+ /**
187
+ * Provenance DAG for clause lineage (opportunity 2): source clause →
188
+ * template versions → executed contracts, laid out by the versions
189
+ * pattern's `computeVersionGraphLayout` and rendered with tone-coloured
190
+ * deviation edges. Every node is an HTML button (`node-selected`), and every
191
+ * derivation edge is ALSO a per-row chip button (`edge-selected` with the
192
+ * parent/child pair — the diff viewer's input), so edge activation is
193
+ * keyboard-accessible without SVG hit targets: the row rail is the
194
+ * accessible contract, the SVG is presentation.
195
+ */
196
+ export class LineageGraph extends BaseElement {
197
+ static tagName = DEFAULT_TAG_NAME;
198
+ static get observedAttributes() {
199
+ return ["heading", "nodes"];
200
+ }
201
+ nodesValue = [];
202
+ rovingId = null;
203
+ hostEl;
204
+ get heading() {
205
+ return this.getAttribute("heading") ?? "Clause lineage";
206
+ }
207
+ set heading(value) {
208
+ this.setAttribute("heading", value);
209
+ }
210
+ get nodes() {
211
+ return this.nodesValue;
212
+ }
213
+ set nodes(value) {
214
+ this.nodesValue = Array.isArray(value) ? value.filter(isLineageNodeRecord) : [];
215
+ if (this.rovingId && !this.nodesValue.some(node => node.id === this.rovingId)) {
216
+ this.rovingId = null;
217
+ }
218
+ if (this.isRendered) {
219
+ this.update();
220
+ }
221
+ }
222
+ attributeChangedCallback(name, oldValue, newValue) {
223
+ if (name === "nodes") {
224
+ this.nodesValue = this.parseNodesAttribute(newValue);
225
+ if (this.rovingId && !this.nodesValue.some(node => node.id === this.rovingId)) {
226
+ this.rovingId = null;
227
+ }
228
+ }
229
+ super.attributeChangedCallback(name, oldValue, newValue);
230
+ }
231
+ parseNodesAttribute(raw) {
232
+ if (!raw) {
233
+ return [];
234
+ }
235
+ try {
236
+ const parsed = JSON.parse(raw);
237
+ return Array.isArray(parsed) ? parsed.filter(isLineageNodeRecord) : [];
238
+ }
239
+ catch {
240
+ return [];
241
+ }
242
+ }
243
+ getNode(id) {
244
+ return this.nodesValue.find(node => node.id === id);
245
+ }
246
+ nodeButtons() {
247
+ return Array.from(this.hostEl.querySelectorAll('[part="node"]'));
248
+ }
249
+ renderTemplate() {
250
+ if (!this.shadowRoot) {
251
+ return;
252
+ }
253
+ this.shadowRoot.innerHTML = `
254
+ <style>${elementStyles}</style>
255
+ <div part="content-host"></div>
256
+ `;
257
+ this.hostEl = this.shadowRoot.querySelector('[part="content-host"]');
258
+ }
259
+ setupListeners() {
260
+ this.hostEl.addEventListener("click", event => {
261
+ const target = event.target;
262
+ const edgeChip = target.closest('[part="edge-chip"]');
263
+ if (edgeChip && this.hostEl.contains(edgeChip)) {
264
+ const parent = this.getNode(edgeChip.getAttribute("data-parent-id") ?? "");
265
+ const child = this.getNode(edgeChip.getAttribute("data-child-id") ?? "");
266
+ if (!parent || !child) {
267
+ return;
268
+ }
269
+ const link = (child.parents ?? []).find(entry => entry.id === parent.id);
270
+ this.dispatchEvent(new CustomEvent("edge-selected", {
271
+ bubbles: true,
272
+ composed: true,
273
+ detail: {
274
+ parent,
275
+ child,
276
+ deviation: resolveLineageDeviation(link?.deviation),
277
+ ...(link?.note ? { note: link.note } : {}),
278
+ },
279
+ }));
280
+ return;
281
+ }
282
+ const nodeButton = target.closest('[part="node"]');
283
+ if (nodeButton && this.hostEl.contains(nodeButton)) {
284
+ const node = this.getNode(nodeButton.getAttribute("data-id") ?? "");
285
+ if (!node) {
286
+ return;
287
+ }
288
+ this.rovingId = node.id;
289
+ this.dispatchEvent(new CustomEvent("node-selected", {
290
+ bubbles: true,
291
+ composed: true,
292
+ detail: { node },
293
+ }));
294
+ }
295
+ });
296
+ this.hostEl.addEventListener("keydown", event => {
297
+ const target = event.target;
298
+ if (target.getAttribute("part") !== "node") {
299
+ return;
300
+ }
301
+ const buttons = this.nodeButtons();
302
+ const index = buttons.indexOf(target);
303
+ if (index === -1) {
304
+ return;
305
+ }
306
+ let next = null;
307
+ if (event.key === "ArrowDown") {
308
+ next = Math.min(index + 1, buttons.length - 1);
309
+ }
310
+ else if (event.key === "ArrowUp") {
311
+ next = Math.max(index - 1, 0);
312
+ }
313
+ else if (event.key === "Home") {
314
+ next = 0;
315
+ }
316
+ else if (event.key === "End") {
317
+ next = buttons.length - 1;
318
+ }
319
+ if (next === null || next === index) {
320
+ return;
321
+ }
322
+ event.preventDefault();
323
+ const button = buttons[next];
324
+ this.rovingId = button.getAttribute("data-id");
325
+ for (const other of buttons) {
326
+ other.tabIndex = other === button ? 0 : -1;
327
+ }
328
+ button.focus();
329
+ });
330
+ }
331
+ update() {
332
+ if (!this.hostEl) {
333
+ return;
334
+ }
335
+ const active = this.shadowRoot?.activeElement;
336
+ const focusedId = active && this.hostEl.contains(active) && active.getAttribute("part") === "node"
337
+ ? active.getAttribute("data-id")
338
+ : null;
339
+ // The versions layout engine only needs the id topology; deviation data
340
+ // stays on the lineage links and decorates the produced edges.
341
+ const layout = computeVersionGraphLayout(this.nodesValue.map(node => ({
342
+ id: node.id,
343
+ label: node.label,
344
+ parents: (node.parents ?? []).map(link => link.id),
345
+ })));
346
+ const byId = new Map(this.nodesValue.map(node => [node.id, node]));
347
+ const deviationFor = (parentId, childId) => {
348
+ const link = (byId.get(childId)?.parents ?? []).find(entry => entry.id === parentId);
349
+ return resolveLineageDeviation(link?.deviation);
350
+ };
351
+ const graphWidth = EDGE_PAD * 2 + layout.laneCount * LANE_WIDTH;
352
+ const graphHeight = layout.rowCount * ROW_HEIGHT;
353
+ const centerX = (lane) => EDGE_PAD + lane * LANE_WIDTH + LANE_WIDTH / 2;
354
+ const centerY = (row) => row * ROW_HEIGHT + ROW_HEIGHT / 2;
355
+ const edgePaths = layout.edges
356
+ .map(edge => {
357
+ const x1 = centerX(edge.fromLane);
358
+ const y1 = centerY(edge.fromRow);
359
+ const x2 = centerX(edge.toLane);
360
+ const y2 = centerY(edge.toRow);
361
+ const d = edge.fromLane === edge.toLane
362
+ ? `M ${x1} ${y1} L ${x2} ${y2}`
363
+ : `M ${x1} ${y1} C ${x1} ${y1 - ROW_HEIGHT / 2}, ${x2} ${y2 + ROW_HEIGHT / 2}, ${x2} ${y2}`;
364
+ return `<path part="edge" data-deviation="${deviationFor(edge.fromId, edge.toId)}" d="${d}"></path>`;
365
+ })
366
+ .join("");
367
+ const rovingId = this.rovingId && byId.has(this.rovingId)
368
+ ? this.rovingId
369
+ : (layout.placements[0]?.id ?? null);
370
+ const rows = layout.placements
371
+ .map(placement => {
372
+ const node = byId.get(placement.id);
373
+ const kind = node.kind ?? "";
374
+ const when = node.timestamp ? formatItemDate(node.timestamp) : "";
375
+ const ariaLabel = [node.label, kind, node.actor?.name ?? ""].filter(Boolean).join(", ");
376
+ const edgeChips = (node.parents ?? [])
377
+ .filter(link => byId.has(link.id))
378
+ .map(link => {
379
+ const parent = byId.get(link.id);
380
+ const deviation = resolveLineageDeviation(link.deviation);
381
+ return `
382
+ <button
383
+ type="button"
384
+ part="edge-chip"
385
+ data-parent-id="${escapeHtml(parent.id)}"
386
+ data-child-id="${escapeHtml(node.id)}"
387
+ data-deviation="${deviation}"
388
+ aria-label="Compare with ${escapeHtml(parent.label)} (${DEVIATION_LABELS[deviation]})"
389
+ >⇠ ${escapeHtml(parent.label)} · ${DEVIATION_LABELS[deviation]}</button>
390
+ `;
391
+ })
392
+ .join("");
393
+ return `
394
+ <li part="row" data-id="${escapeHtml(node.id)}"${kind ? ` data-kind="${escapeHtml(kind)}"` : ""} style="padding-inline-start: ${String(graphWidth + 10)}px;">
395
+ <button
396
+ type="button"
397
+ part="node"
398
+ data-id="${escapeHtml(node.id)}"
399
+ ${kind ? `data-kind="${escapeHtml(kind)}"` : ""}
400
+ tabindex="${node.id === rovingId ? "0" : "-1"}"
401
+ aria-label="${escapeHtml(ariaLabel)}"
402
+ style="inset-inline-start: ${String(centerX(placement.lane))}px;"
403
+ ></button>
404
+ <span part="row-label">${escapeHtml(node.label)}</span>
405
+ ${kind ? `<span part="kind">${escapeHtml(kind)}</span>` : ""}
406
+ <span part="row-meta">${[node.actor?.name, when].filter(Boolean).map(text => escapeHtml(text)).join(" · ")}</span>
407
+ ${edgeChips}
408
+ </li>
409
+ `;
410
+ })
411
+ .join("");
412
+ this.hostEl.innerHTML = `
413
+ <section part="panel" aria-label="${escapeHtml(this.heading)}">
414
+ <h2 part="title">${escapeHtml(this.heading)}</h2>
415
+ ${layout.placements.length > 0
416
+ ? `
417
+ <div part="graph">
418
+ <svg part="edges" width="${String(graphWidth)}" height="${String(graphHeight)}" viewBox="0 0 ${String(graphWidth)} ${String(graphHeight)}" aria-hidden="true">${edgePaths}</svg>
419
+ <ol part="rows" role="list">${rows}</ol>
420
+ </div>
421
+ `
422
+ : `<div part="empty">No lineage.</div>`}
423
+ </section>
424
+ `;
425
+ if (focusedId) {
426
+ const buttons = this.nodeButtons();
427
+ const target = buttons.find(button => button.getAttribute("data-id") === focusedId) ??
428
+ buttons.find(button => button.tabIndex === 0) ??
429
+ buttons[0];
430
+ target?.focus();
431
+ }
432
+ }
433
+ }
434
+ LineageGraph.register();
@@ -0,0 +1,22 @@
1
+ import type { LineageNode } from "./types.js";
2
+ import { BaseElement } from "../../core/index.js";
3
+ /**
4
+ * The cheap, high-frequency lineage sibling: a linear ancestry strip
5
+ * (Library clause v5 → Template 2026 → MSA_Acme §4.2) for record headers
6
+ * and the sidebar. Renders the chain oldest-first from the same topology
7
+ * contract as `box-lineage-graph` (branched input degrades to topological
8
+ * order), marks the newest entry as current, and emits `node-selected`.
9
+ */
10
+ export declare class ProvenanceStrip extends BaseElement {
11
+ static readonly tagName: string;
12
+ static get observedAttributes(): string[];
13
+ private nodesValue;
14
+ private hostEl;
15
+ get nodes(): LineageNode[];
16
+ set nodes(value: LineageNode[]);
17
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
18
+ private parseNodesAttribute;
19
+ protected renderTemplate(): void;
20
+ protected setupListeners(): void;
21
+ protected update(): void;
22
+ }
@@ -0,0 +1,194 @@
1
+ import { isLineageNodeRecord } from "./types.js";
2
+ import { computeVersionGraphLayout } from "../versions/graph-layout.js";
3
+ import { BaseElement } from "../../core/index.js";
4
+ import { boeMotionDuration, boeMotionEasing } from "../../foundations/motion/index.js";
5
+ import { boeRadius } from "../../foundations/geometry/index.js";
6
+ const DEFAULT_TAG_NAME = "box-provenance-strip";
7
+ const escapeHtml = (value) => value
8
+ .replaceAll("&", "&amp;")
9
+ .replaceAll("<", "&lt;")
10
+ .replaceAll(">", "&gt;")
11
+ .replaceAll('"', "&quot;")
12
+ .replaceAll("'", "&#39;");
13
+ const elementStyles = `
14
+ [hidden] {
15
+ display: none !important;
16
+ }
17
+
18
+ :host {
19
+ display: block;
20
+ color: inherit;
21
+ font: inherit;
22
+ }
23
+
24
+ [part="strip"] {
25
+ display: flex;
26
+ flex-wrap: wrap;
27
+ align-items: center;
28
+ gap: 0.35rem;
29
+ margin: 0;
30
+ padding: 0;
31
+ list-style: none;
32
+ }
33
+
34
+ [part="item"] {
35
+ display: inline-flex;
36
+ align-items: center;
37
+ gap: 0.35rem;
38
+ }
39
+
40
+ [part="chip"] {
41
+ appearance: none;
42
+ display: inline-flex;
43
+ align-items: center;
44
+ gap: 0.3rem;
45
+ font: inherit;
46
+ font-size: 0.8rem;
47
+ font-weight: 600;
48
+ padding: 0.22rem 0.55rem;
49
+ border-radius: 999px;
50
+ border: 1px solid color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 60%, transparent);
51
+ background: var(--boe-token-surface-surface, #ffffff);
52
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
53
+ cursor: pointer;
54
+ transition: background ${boeMotionDuration.interactive} ${boeMotionEasing.standard};
55
+ }
56
+
57
+ [part="chip"]:hover {
58
+ background: var(--boe-token-surface-surface-hover, #f4f4f4);
59
+ }
60
+
61
+ [part="chip"][aria-current="true"] {
62
+ border-color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 45%, transparent);
63
+ color: var(--boe-token-surface-surface-brand, #0061d5);
64
+ background: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 8%, var(--boe-token-surface-surface, #ffffff));
65
+ }
66
+
67
+ [part="chip"]:focus-visible {
68
+ outline: none;
69
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 18%, transparent);
70
+ border-radius: ${boeRadius.large};
71
+ }
72
+
73
+ [part="kind-dot"] {
74
+ inline-size: 0.45rem;
75
+ block-size: 0.45rem;
76
+ border-radius: 999px;
77
+ background: var(--boe-token-text-text-secondary, #6f6f6f);
78
+ }
79
+
80
+ [part="item"][data-kind="clause"] [part="kind-dot"] {
81
+ background: var(--boe-token-surface-surface-brand, #0061d5);
82
+ }
83
+
84
+ [part="item"][data-kind="template"] [part="kind-dot"] {
85
+ border-radius: 2px;
86
+ }
87
+
88
+ [part="separator"] {
89
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
90
+ user-select: none;
91
+ }
92
+ `;
93
+ /**
94
+ * The cheap, high-frequency lineage sibling: a linear ancestry strip
95
+ * (Library clause v5 → Template 2026 → MSA_Acme §4.2) for record headers
96
+ * and the sidebar. Renders the chain oldest-first from the same topology
97
+ * contract as `box-lineage-graph` (branched input degrades to topological
98
+ * order), marks the newest entry as current, and emits `node-selected`.
99
+ */
100
+ export class ProvenanceStrip extends BaseElement {
101
+ static tagName = DEFAULT_TAG_NAME;
102
+ static get observedAttributes() {
103
+ return ["nodes"];
104
+ }
105
+ nodesValue = [];
106
+ hostEl;
107
+ get nodes() {
108
+ return this.nodesValue;
109
+ }
110
+ set nodes(value) {
111
+ this.nodesValue = Array.isArray(value) ? value.filter(isLineageNodeRecord) : [];
112
+ if (this.isRendered) {
113
+ this.update();
114
+ }
115
+ }
116
+ attributeChangedCallback(name, oldValue, newValue) {
117
+ if (name === "nodes") {
118
+ this.nodesValue = this.parseNodesAttribute(newValue);
119
+ }
120
+ super.attributeChangedCallback(name, oldValue, newValue);
121
+ }
122
+ parseNodesAttribute(raw) {
123
+ if (!raw) {
124
+ return [];
125
+ }
126
+ try {
127
+ const parsed = JSON.parse(raw);
128
+ return Array.isArray(parsed) ? parsed.filter(isLineageNodeRecord) : [];
129
+ }
130
+ catch {
131
+ return [];
132
+ }
133
+ }
134
+ renderTemplate() {
135
+ if (!this.shadowRoot) {
136
+ return;
137
+ }
138
+ this.shadowRoot.innerHTML = `
139
+ <style>${elementStyles}</style>
140
+ <div part="content-host"></div>
141
+ `;
142
+ this.hostEl = this.shadowRoot.querySelector('[part="content-host"]');
143
+ }
144
+ setupListeners() {
145
+ this.hostEl.addEventListener("click", event => {
146
+ const chip = event.target.closest('[part="chip"]');
147
+ if (!chip || !this.hostEl.contains(chip)) {
148
+ return;
149
+ }
150
+ const node = this.nodesValue.find(entry => entry.id === chip.getAttribute("data-id"));
151
+ if (node) {
152
+ this.dispatchEvent(new CustomEvent("node-selected", {
153
+ bubbles: true,
154
+ composed: true,
155
+ detail: { node },
156
+ }));
157
+ }
158
+ });
159
+ }
160
+ update() {
161
+ if (!this.hostEl) {
162
+ return;
163
+ }
164
+ // Placements come newest-first; the strip reads oldest → newest.
165
+ const layout = computeVersionGraphLayout(this.nodesValue.map(node => ({
166
+ id: node.id,
167
+ label: node.label,
168
+ parents: (node.parents ?? []).map(link => link.id),
169
+ })));
170
+ const byId = new Map(this.nodesValue.map(node => [node.id, node]));
171
+ const chain = [...layout.placements].reverse().map(placement => byId.get(placement.id));
172
+ const items = chain
173
+ .map((node, index) => {
174
+ const isCurrent = index === chain.length - 1;
175
+ const kind = node.kind ?? "";
176
+ return `
177
+ <li part="item"${kind ? ` data-kind="${escapeHtml(kind)}"` : ""}>
178
+ ${index > 0 ? `<span part="separator" aria-hidden="true">→</span>` : ""}
179
+ <button
180
+ type="button"
181
+ part="chip"
182
+ data-id="${escapeHtml(node.id)}"
183
+ ${isCurrent ? `aria-current="true"` : ""}
184
+ ><span part="kind-dot" aria-hidden="true"></span>${escapeHtml(node.label)}</button>
185
+ </li>
186
+ `;
187
+ })
188
+ .join("");
189
+ this.hostEl.innerHTML = chain.length
190
+ ? `<ol part="strip" aria-label="Provenance">${items}</ol>`
191
+ : "";
192
+ }
193
+ }
194
+ ProvenanceStrip.register();