@unofficialbox/box-open-elements 0.5.0 → 0.6.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 (219) hide show
  1. package/README.md +3 -3
  2. package/dist/components/collections/table.d.ts +57 -3
  3. package/dist/components/collections/table.js +339 -20
  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/element-maps.d.ts +292 -0
  30. package/dist/element-maps.js +1 -0
  31. package/dist/entries/activity-density.d.ts +1 -0
  32. package/dist/entries/activity-density.js +1 -0
  33. package/dist/entries/agent-chat.d.ts +1 -0
  34. package/dist/entries/agent-chat.js +1 -0
  35. package/dist/entries/audit-log.d.ts +1 -0
  36. package/dist/entries/audit-log.js +1 -0
  37. package/dist/entries/command-palette.d.ts +1 -0
  38. package/dist/entries/command-palette.js +1 -0
  39. package/dist/entries/compare-view.d.ts +1 -0
  40. package/dist/entries/compare-view.js +1 -0
  41. package/dist/entries/diff-viewer.d.ts +1 -0
  42. package/dist/entries/diff-viewer.js +1 -0
  43. package/dist/entries/due-badge.d.ts +1 -0
  44. package/dist/entries/due-badge.js +1 -0
  45. package/dist/entries/form-wizard.d.ts +1 -0
  46. package/dist/entries/form-wizard.js +1 -0
  47. package/dist/entries/lineage-graph.d.ts +1 -0
  48. package/dist/entries/lineage-graph.js +1 -0
  49. package/dist/entries/notification-bell.d.ts +1 -0
  50. package/dist/entries/notification-bell.js +1 -0
  51. package/dist/entries/notification-inbox.d.ts +1 -0
  52. package/dist/entries/notification-inbox.js +1 -0
  53. package/dist/entries/provenance-strip.d.ts +1 -0
  54. package/dist/entries/provenance-strip.js +1 -0
  55. package/dist/entries/run-trace.d.ts +1 -0
  56. package/dist/entries/run-trace.js +1 -0
  57. package/dist/entries/shortcuts-overlay.d.ts +1 -0
  58. package/dist/entries/shortcuts-overlay.js +1 -0
  59. package/dist/entries/signature-ceremony.d.ts +1 -0
  60. package/dist/entries/signature-ceremony.js +1 -0
  61. package/dist/entries/stage-path.d.ts +1 -0
  62. package/dist/entries/stage-path.js +1 -0
  63. package/dist/entries/timeline.d.ts +1 -0
  64. package/dist/entries/timeline.js +1 -0
  65. package/dist/entries/version-graph.d.ts +1 -0
  66. package/dist/entries/version-graph.js +1 -0
  67. package/dist/entries/version-list.d.ts +1 -0
  68. package/dist/entries/version-list.js +1 -0
  69. package/dist/entries/wizard-summary.d.ts +1 -0
  70. package/dist/entries/wizard-summary.js +1 -0
  71. package/dist/entries/work-queue.d.ts +1 -0
  72. package/dist/entries/work-queue.js +1 -0
  73. package/dist/entries/workload-board.d.ts +1 -0
  74. package/dist/entries/workload-board.js +1 -0
  75. package/dist/index.d.ts +21 -0
  76. package/dist/index.js +21 -0
  77. package/dist/patterns/agent-chat/agent-chat.d.ts +75 -0
  78. package/dist/patterns/agent-chat/agent-chat.js +820 -0
  79. package/dist/patterns/agent-chat/controller.d.ts +27 -0
  80. package/dist/patterns/agent-chat/controller.js +182 -0
  81. package/dist/patterns/agent-chat/index.d.ts +3 -0
  82. package/dist/patterns/agent-chat/index.js +6 -0
  83. package/dist/patterns/agent-chat/types.d.ts +109 -0
  84. package/dist/patterns/agent-chat/types.js +1 -0
  85. package/dist/patterns/audit/activity-density.d.ts +68 -0
  86. package/dist/patterns/audit/activity-density.js +428 -0
  87. package/dist/patterns/audit/audit-log.d.ts +81 -0
  88. package/dist/patterns/audit/audit-log.js +794 -0
  89. package/dist/patterns/audit/index.d.ts +3 -0
  90. package/dist/patterns/audit/index.js +7 -0
  91. package/dist/patterns/audit/shared.d.ts +10 -0
  92. package/dist/patterns/audit/shared.js +50 -0
  93. package/dist/patterns/audit/types.d.ts +143 -0
  94. package/dist/patterns/audit/types.js +327 -0
  95. package/dist/patterns/content-explorer/actions/controller.js +12 -2
  96. package/dist/patterns/content-explorer/box-transport.js +117 -25
  97. package/dist/patterns/content-explorer/content-explorer.d.ts +13 -1
  98. package/dist/patterns/content-explorer/content-explorer.js +36 -3
  99. package/dist/patterns/content-explorer/contracts.d.ts +24 -1
  100. package/dist/patterns/content-explorer/contracts.js +68 -11
  101. package/dist/patterns/content-explorer/controller.d.ts +16 -1
  102. package/dist/patterns/content-explorer/controller.js +130 -4
  103. package/dist/patterns/content-explorer/navigation/controller.js +11 -9
  104. package/dist/patterns/content-explorer/types.d.ts +58 -1
  105. package/dist/patterns/content-picker/content-picker.d.ts +71 -0
  106. package/dist/patterns/content-picker/content-picker.js +747 -0
  107. package/dist/patterns/content-picker/controller.d.ts +38 -0
  108. package/dist/patterns/content-picker/controller.js +141 -0
  109. package/dist/patterns/content-picker/index.d.ts +3 -0
  110. package/dist/patterns/content-picker/index.js +6 -0
  111. package/dist/patterns/content-picker/types.d.ts +52 -0
  112. package/dist/patterns/content-picker/types.js +26 -0
  113. package/dist/patterns/content-sidebar/content-sidebar.d.ts +43 -0
  114. package/dist/patterns/content-sidebar/content-sidebar.js +293 -0
  115. package/dist/patterns/content-sidebar/index.d.ts +2 -0
  116. package/dist/patterns/content-sidebar/index.js +4 -0
  117. package/dist/patterns/content-sidebar/types.d.ts +18 -0
  118. package/dist/patterns/content-sidebar/types.js +20 -0
  119. package/dist/patterns/content-uploader/box-transport.d.ts +14 -0
  120. package/dist/patterns/content-uploader/box-transport.js +54 -0
  121. package/dist/patterns/content-uploader/content-uploader.d.ts +62 -0
  122. package/dist/patterns/content-uploader/content-uploader.js +559 -0
  123. package/dist/patterns/content-uploader/controller.d.ts +39 -0
  124. package/dist/patterns/content-uploader/controller.js +227 -0
  125. package/dist/patterns/content-uploader/index.d.ts +4 -0
  126. package/dist/patterns/content-uploader/index.js +8 -0
  127. package/dist/patterns/content-uploader/types.d.ts +120 -0
  128. package/dist/patterns/content-uploader/types.js +38 -0
  129. package/dist/patterns/diff/compare-view.d.ts +47 -0
  130. package/dist/patterns/diff/compare-view.js +276 -0
  131. package/dist/patterns/diff/diff-viewer.d.ts +42 -0
  132. package/dist/patterns/diff/diff-viewer.js +434 -0
  133. package/dist/patterns/diff/engine.d.ts +22 -0
  134. package/dist/patterns/diff/engine.js +276 -0
  135. package/dist/patterns/diff/index.d.ts +4 -0
  136. package/dist/patterns/diff/index.js +8 -0
  137. package/dist/patterns/diff/types.d.ts +69 -0
  138. package/dist/patterns/diff/types.js +24 -0
  139. package/dist/patterns/form-wizard/controller.d.ts +39 -0
  140. package/dist/patterns/form-wizard/controller.js +157 -0
  141. package/dist/patterns/form-wizard/form-wizard.d.ts +63 -0
  142. package/dist/patterns/form-wizard/form-wizard.js +468 -0
  143. package/dist/patterns/form-wizard/index.d.ts +4 -0
  144. package/dist/patterns/form-wizard/index.js +8 -0
  145. package/dist/patterns/form-wizard/types.d.ts +109 -0
  146. package/dist/patterns/form-wizard/types.js +83 -0
  147. package/dist/patterns/form-wizard/wizard-summary.d.ts +62 -0
  148. package/dist/patterns/form-wizard/wizard-summary.js +324 -0
  149. package/dist/patterns/internal/safe-href.d.ts +17 -0
  150. package/dist/patterns/internal/safe-href.js +17 -0
  151. package/dist/patterns/lineage/index.d.ts +3 -0
  152. package/dist/patterns/lineage/index.js +6 -0
  153. package/dist/patterns/lineage/lineage-graph.d.ts +30 -0
  154. package/dist/patterns/lineage/lineage-graph.js +434 -0
  155. package/dist/patterns/lineage/provenance-strip.d.ts +22 -0
  156. package/dist/patterns/lineage/provenance-strip.js +194 -0
  157. package/dist/patterns/lineage/types.d.ts +53 -0
  158. package/dist/patterns/lineage/types.js +49 -0
  159. package/dist/patterns/notifications/index.d.ts +3 -0
  160. package/dist/patterns/notifications/index.js +6 -0
  161. package/dist/patterns/notifications/notification-bell.d.ts +38 -0
  162. package/dist/patterns/notifications/notification-bell.js +198 -0
  163. package/dist/patterns/notifications/notification-inbox.d.ts +46 -0
  164. package/dist/patterns/notifications/notification-inbox.js +537 -0
  165. package/dist/patterns/notifications/types.d.ts +61 -0
  166. package/dist/patterns/notifications/types.js +108 -0
  167. package/dist/patterns/preview/annotation-inspector.d.ts +25 -6
  168. package/dist/patterns/preview/annotation-inspector.js +239 -94
  169. package/dist/patterns/preview/annotation-thread.d.ts +25 -5
  170. package/dist/patterns/preview/annotation-thread.js +233 -82
  171. package/dist/patterns/preview/annotation-toolbar.d.ts +20 -6
  172. package/dist/patterns/preview/annotation-toolbar.js +162 -96
  173. package/dist/patterns/preview/content-preview-adapter.d.ts +10 -1
  174. package/dist/patterns/preview/content-preview-adapter.js +26 -1
  175. package/dist/patterns/preview/preview-element.d.ts +15 -2
  176. package/dist/patterns/preview/preview-element.js +223 -52
  177. package/dist/patterns/preview/provider-adapter.d.ts +47 -0
  178. package/dist/patterns/preview/provider-adapter.js +17 -0
  179. package/dist/patterns/run/index.d.ts +2 -0
  180. package/dist/patterns/run/index.js +4 -0
  181. package/dist/patterns/run/run-trace.d.ts +40 -0
  182. package/dist/patterns/run/run-trace.js +441 -0
  183. package/dist/patterns/run/types.d.ts +66 -0
  184. package/dist/patterns/run/types.js +152 -0
  185. package/dist/patterns/signature/index.d.ts +2 -0
  186. package/dist/patterns/signature/index.js +4 -0
  187. package/dist/patterns/signature/signature-ceremony.d.ts +33 -0
  188. package/dist/patterns/signature/signature-ceremony.js +317 -0
  189. package/dist/patterns/signature/types.d.ts +68 -0
  190. package/dist/patterns/signature/types.js +89 -0
  191. package/dist/patterns/timeline/index.d.ts +2 -0
  192. package/dist/patterns/timeline/index.js +4 -0
  193. package/dist/patterns/timeline/timeline.d.ts +27 -0
  194. package/dist/patterns/timeline/timeline.js +430 -0
  195. package/dist/patterns/timeline/types.d.ts +36 -0
  196. package/dist/patterns/timeline/types.js +27 -0
  197. package/dist/patterns/versions/graph-layout.d.ts +43 -0
  198. package/dist/patterns/versions/graph-layout.js +159 -0
  199. package/dist/patterns/versions/index.d.ts +4 -0
  200. package/dist/patterns/versions/index.js +8 -0
  201. package/dist/patterns/versions/shared.d.ts +4 -0
  202. package/dist/patterns/versions/shared.js +13 -0
  203. package/dist/patterns/versions/types.d.ts +37 -0
  204. package/dist/patterns/versions/types.js +39 -0
  205. package/dist/patterns/versions/version-graph.d.ts +36 -0
  206. package/dist/patterns/versions/version-graph.js +438 -0
  207. package/dist/patterns/versions/version-list.d.ts +39 -0
  208. package/dist/patterns/versions/version-list.js +407 -0
  209. package/dist/patterns/work-queue/controller.d.ts +26 -0
  210. package/dist/patterns/work-queue/controller.js +150 -0
  211. package/dist/patterns/work-queue/index.d.ts +4 -0
  212. package/dist/patterns/work-queue/index.js +7 -0
  213. package/dist/patterns/work-queue/types.d.ts +128 -0
  214. package/dist/patterns/work-queue/types.js +45 -0
  215. package/dist/patterns/work-queue/work-queue.d.ts +48 -0
  216. package/dist/patterns/work-queue/work-queue.js +534 -0
  217. package/dist/patterns/work-queue/workload-board.d.ts +53 -0
  218. package/dist/patterns/work-queue/workload-board.js +608 -0
  219. package/package.json +89 -5
@@ -0,0 +1,33 @@
1
+ import type { CeremonyResolution, Signatory, SignatureMode } from "./types.js";
2
+ import { BaseElement } from "../../core/index.js";
3
+ /**
4
+ * Party-oriented signing progress: who signs, in what order, and — the part
5
+ * that matters — who can act *right now*.
6
+ *
7
+ * The rules live in `resolveCeremony`, which is pure, so a host can drive its
8
+ * own surface or its reminder emails from the same function rather than
9
+ * reimplementing the ordering logic and drifting from what the UI shows.
10
+ *
11
+ * Read-only by design. Signing happens in the signature provider's own flow,
12
+ * so this states position rather than offering a button that would have to
13
+ * duplicate that flow's authority.
14
+ */
15
+ export declare class SignatureCeremony extends BaseElement {
16
+ static readonly tagName: string;
17
+ static get observedAttributes(): string[];
18
+ private hostEl;
19
+ private signatoriesRaw;
20
+ private signatoriesCache;
21
+ get heading(): string;
22
+ set heading(value: string);
23
+ /** `sequential` (default) routes one party at a time; `parallel` sends to all. */
24
+ get mode(): SignatureMode;
25
+ set mode(value: SignatureMode);
26
+ get signatories(): Signatory[];
27
+ set signatories(value: Signatory[]);
28
+ /** The resolved ceremony — same object the render uses. */
29
+ get resolution(): CeremonyResolution;
30
+ protected renderTemplate(): void;
31
+ protected setupListeners(): void;
32
+ protected update(): void;
33
+ }
@@ -0,0 +1,317 @@
1
+ import { formatCeremonySummary, isSignatoryRecord, resolveCeremony, } from "./types.js";
2
+ import { formatUtcDay } from "../audit/types.js";
3
+ import { BaseElement } from "../../core/index.js";
4
+ import { boePanel } from "../../foundations/geometry/index.js";
5
+ const DEFAULT_TAG_NAME = "box-signature-ceremony";
6
+ const escapeHtml = (value) => value
7
+ .replaceAll("&", "&")
8
+ .replaceAll("<", "&lt;")
9
+ .replaceAll(">", "&gt;")
10
+ .replaceAll('"', "&quot;")
11
+ .replaceAll("'", "&#39;");
12
+ const initialsOf = (name) => name
13
+ .split(/\s+/)
14
+ .filter(Boolean)
15
+ .slice(0, 2)
16
+ .map(part => part[0].toUpperCase())
17
+ .join("");
18
+ /**
19
+ * `formatUtcDay` takes a date-only string or a `Date`; handing it a full ISO
20
+ * timestamp makes it concatenate a second time component and fall back to
21
+ * echoing the raw input. Signing timestamps carry a time, so parse first.
22
+ * Returns an empty string for an unparseable value, so callers can fall back.
23
+ */
24
+ const signedOnDay = (iso) => formatUtcDay(new Date(iso));
25
+ const STATE_LABEL = {
26
+ signed: "Signed",
27
+ declined: "Declined",
28
+ awaiting: "Awaiting signature",
29
+ waiting: "Not yet their turn",
30
+ };
31
+ const elementStyles = `
32
+ :host {
33
+ display: block;
34
+ }
35
+
36
+ [part="card"] {
37
+ border: ${boePanel.border};
38
+ border-radius: ${boePanel.radius};
39
+ background: ${boePanel.background};
40
+ overflow: hidden;
41
+ }
42
+
43
+ [part="header"] {
44
+ display: flex;
45
+ align-items: baseline;
46
+ gap: 0.6rem;
47
+ padding: 0.8rem 1rem;
48
+ border-block-end: 1px solid color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 70%, transparent);
49
+ }
50
+
51
+ [part="heading"] {
52
+ margin: 0;
53
+ font: inherit;
54
+ font-size: 0.95rem;
55
+ font-weight: 700;
56
+ color: var(--boe-token-text-text, #1f1e1b);
57
+ }
58
+
59
+ [part="summary"] {
60
+ margin-inline-start: auto;
61
+ font-size: 0.78rem;
62
+ font-weight: 600;
63
+ padding: 0.14rem 0.5rem;
64
+ border-radius: 999px;
65
+ border: 1px solid transparent;
66
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
67
+ background: color-mix(in srgb, var(--boe-token-surface-surface-hover, #f4f4f4) 80%, transparent);
68
+ }
69
+
70
+ [part="summary"][data-status="completed"] {
71
+ background: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 14%, transparent);
72
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 74%, black 26%);
73
+ border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 32%, transparent);
74
+ }
75
+
76
+ [part="summary"][data-status="declined"] {
77
+ background: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 14%, transparent);
78
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 76%, black 24%);
79
+ border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 32%, transparent);
80
+ }
81
+
82
+ [part="parties"] {
83
+ margin: 0;
84
+ padding: 0;
85
+ list-style: none;
86
+ }
87
+
88
+ [part="party"] {
89
+ display: grid;
90
+ grid-template-columns: auto auto 1fr auto;
91
+ align-items: center;
92
+ gap: 0.7rem;
93
+ padding: 0.65rem 1rem;
94
+ }
95
+
96
+ [part="party"] + [part="party"] {
97
+ border-block-start: 1px solid color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 45%, transparent);
98
+ }
99
+
100
+ [part="order"] {
101
+ inline-size: 1.35rem;
102
+ block-size: 1.35rem;
103
+ display: grid;
104
+ place-items: center;
105
+ border-radius: 999px;
106
+ font-size: 0.7rem;
107
+ font-weight: 700;
108
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
109
+ background: var(--boe-token-surface-surface-hover, #f4f4f4);
110
+ }
111
+
112
+ [part="party"][data-state="signed"] [part="order"] {
113
+ background: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 18%, transparent);
114
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 74%, black 26%);
115
+ }
116
+
117
+ [part="party"][data-state="declined"] [part="order"] {
118
+ background: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 16%, transparent);
119
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 76%, black 24%);
120
+ }
121
+
122
+ [part="party"][data-state="awaiting"] [part="order"] {
123
+ background: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 16%, transparent);
124
+ color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 80%, black 20%);
125
+ }
126
+
127
+ [part="avatar"] {
128
+ inline-size: 1.7rem;
129
+ block-size: 1.7rem;
130
+ display: grid;
131
+ place-items: center;
132
+ border-radius: 999px;
133
+ font-size: 0.68rem;
134
+ font-weight: 700;
135
+ color: var(--boe-token-text-text, #1f1e1b);
136
+ background: var(--boe-token-surface-surface-hover, #f4f4f4);
137
+ }
138
+
139
+ [part="identity"] {
140
+ min-inline-size: 0;
141
+ }
142
+
143
+ [part="name"] {
144
+ display: block;
145
+ font-size: 0.88rem;
146
+ color: var(--boe-token-text-text, #1f1e1b);
147
+ overflow-wrap: anywhere;
148
+ }
149
+
150
+ [part="role"] {
151
+ display: block;
152
+ font-size: 0.76rem;
153
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
154
+ }
155
+
156
+ [part="state"] {
157
+ text-align: end;
158
+ font-size: 0.76rem;
159
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
160
+ white-space: nowrap;
161
+ }
162
+
163
+ [part="party"][data-state="awaiting"] [part="state"] {
164
+ font-weight: 700;
165
+ color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 80%, black 20%);
166
+ }
167
+
168
+ [part="party"][data-state="declined"] [part="state"] {
169
+ font-weight: 700;
170
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 76%, black 24%);
171
+ }
172
+
173
+ [part="reason"] {
174
+ grid-column: 3 / -1;
175
+ font-size: 0.76rem;
176
+ font-style: italic;
177
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 70%, black 30%);
178
+ }
179
+
180
+ [part="empty"] {
181
+ padding: 1.2rem 1rem;
182
+ text-align: center;
183
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
184
+ }
185
+ `;
186
+ /**
187
+ * Party-oriented signing progress: who signs, in what order, and — the part
188
+ * that matters — who can act *right now*.
189
+ *
190
+ * The rules live in `resolveCeremony`, which is pure, so a host can drive its
191
+ * own surface or its reminder emails from the same function rather than
192
+ * reimplementing the ordering logic and drifting from what the UI shows.
193
+ *
194
+ * Read-only by design. Signing happens in the signature provider's own flow,
195
+ * so this states position rather than offering a button that would have to
196
+ * duplicate that flow's authority.
197
+ */
198
+ export class SignatureCeremony extends BaseElement {
199
+ static tagName = DEFAULT_TAG_NAME;
200
+ static get observedAttributes() {
201
+ return ["heading", "mode", "signatories"];
202
+ }
203
+ hostEl;
204
+ signatoriesRaw = null;
205
+ signatoriesCache = [];
206
+ get heading() {
207
+ return this.getAttribute("heading") ?? "Signatures";
208
+ }
209
+ set heading(value) {
210
+ this.setAttribute("heading", value);
211
+ }
212
+ /** `sequential` (default) routes one party at a time; `parallel` sends to all. */
213
+ get mode() {
214
+ return this.getAttribute("mode") === "parallel" ? "parallel" : "sequential";
215
+ }
216
+ set mode(value) {
217
+ this.setAttribute("mode", value);
218
+ }
219
+ get signatories() {
220
+ const raw = this.getAttribute("signatories");
221
+ if (!raw) {
222
+ return [...this.signatoriesCache];
223
+ }
224
+ if (raw !== this.signatoriesRaw) {
225
+ this.signatoriesRaw = raw;
226
+ try {
227
+ const parsed = JSON.parse(raw);
228
+ this.signatoriesCache =
229
+ Array.isArray(parsed) && parsed.every(isSignatoryRecord)
230
+ ? parsed
231
+ : [];
232
+ }
233
+ catch {
234
+ this.signatoriesCache = [];
235
+ }
236
+ }
237
+ return [...this.signatoriesCache];
238
+ }
239
+ set signatories(value) {
240
+ if (value.length) {
241
+ this.setAttribute("signatories", JSON.stringify(value));
242
+ return;
243
+ }
244
+ // Clear the cache too: the no-attribute branch of the getter serves from
245
+ // it, and a stale cache would make an emptied roster un-clearable.
246
+ this.signatoriesCache = [];
247
+ this.signatoriesRaw = null;
248
+ this.removeAttribute("signatories");
249
+ }
250
+ /** The resolved ceremony — same object the render uses. */
251
+ get resolution() {
252
+ return resolveCeremony(this.signatories, this.mode);
253
+ }
254
+ renderTemplate() {
255
+ if (!this.shadowRoot) {
256
+ return;
257
+ }
258
+ this.shadowRoot.innerHTML = `<style>${elementStyles}</style><div part="host"></div>`;
259
+ this.hostEl = this.shadowRoot.querySelector('[part="host"]');
260
+ }
261
+ setupListeners() {
262
+ // Read-only: signing is the provider's flow, not this component's.
263
+ }
264
+ update() {
265
+ if (!this.hostEl) {
266
+ return;
267
+ }
268
+ const resolution = this.resolution;
269
+ const rows = resolution.statuses
270
+ .map(entry => {
271
+ const { signatory, state, order } = entry;
272
+ // An unparseable timestamp falls back to the bare state rather than
273
+ // rendering "Signed " with nothing after it.
274
+ const signedDay = signatory.signedAt ? signedOnDay(signatory.signedAt) : "";
275
+ const declinedDay = signatory.declinedAt ? signedOnDay(signatory.declinedAt) : "";
276
+ // "Not yet their turn" would be a lie once someone has refused: their
277
+ // turn is not coming. A stopped ceremony says so.
278
+ const waitingLabel = resolution.status === "declined" ? "Ceremony stopped" : STATE_LABEL.waiting;
279
+ const detail = state === "signed" && signedDay
280
+ ? `Signed ${signedDay}`
281
+ : state === "declined" && declinedDay
282
+ ? `Declined ${declinedDay}`
283
+ : state === "waiting"
284
+ ? waitingLabel
285
+ : STATE_LABEL[state];
286
+ const reason = state === "declined" && signatory.declineReason
287
+ ? `<span part="reason">${escapeHtml(signatory.declineReason)}</span>`
288
+ : "";
289
+ return `
290
+ <li part="party" data-state="${state}" data-signatory-id="${escapeHtml(signatory.id)}">
291
+ <span part="order" aria-hidden="true">${String(order)}</span>
292
+ <span part="avatar" aria-hidden="true">${escapeHtml(initialsOf(signatory.name))}</span>
293
+ <span part="identity">
294
+ <span part="name">${escapeHtml(signatory.name)}</span>
295
+ ${signatory.role ? `<span part="role">${escapeHtml(signatory.role)}</span>` : ""}
296
+ </span>
297
+ <span part="state">${escapeHtml(detail)}</span>
298
+ ${reason}
299
+ </li>
300
+ `;
301
+ })
302
+ .join("");
303
+ const summary = formatCeremonySummary(resolution);
304
+ this.hostEl.innerHTML = `
305
+ <section part="card" aria-label="${escapeHtml(this.heading)}">
306
+ <div part="header">
307
+ <h3 part="heading">${escapeHtml(this.heading)}</h3>
308
+ <span part="summary" data-status="${resolution.status}">${escapeHtml(summary)}</span>
309
+ </div>
310
+ ${resolution.total
311
+ ? `<ol part="parties">${rows}</ol>`
312
+ : `<div part="empty">No signatories yet.</div>`}
313
+ </section>
314
+ `;
315
+ }
316
+ }
317
+ SignatureCeremony.register();
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Signature ceremony model and the pure engine that resolves it.
3
+ *
4
+ * DOM-free and deterministic, so the rules that decide *who may sign now* are
5
+ * testable on their own and a host can drive its own signing surface — or its
6
+ * server-side reminders — from the same function.
7
+ */
8
+ /**
9
+ * `sequential` routes the document one party at a time, in order.
10
+ * `parallel` sends it to everyone at once.
11
+ */
12
+ export type SignatureMode = "sequential" | "parallel";
13
+ /**
14
+ * `awaiting` means this party can act **now**. `waiting` means their turn has
15
+ * not come — or the ceremony has stopped and will never reach them. The
16
+ * distinction is the whole point of the component: only `awaiting` should ever
17
+ * carry a sign-now affordance.
18
+ */
19
+ export type SignatoryState = "signed" | "declined" | "awaiting" | "waiting";
20
+ export type CeremonyStatus = "completed" | "in-progress" | "declined";
21
+ export interface Signatory {
22
+ id: string;
23
+ name: string;
24
+ /** Capacity they sign in — "Counterparty", "General Counsel". */
25
+ role?: string;
26
+ email?: string;
27
+ /** ISO timestamp. Present means signed. */
28
+ signedAt?: string;
29
+ /** ISO timestamp. Present means refused, which stops the ceremony. */
30
+ declinedAt?: string;
31
+ declineReason?: string;
32
+ }
33
+ export interface SignatoryStatus {
34
+ signatory: Signatory;
35
+ state: SignatoryState;
36
+ /** 1-based: the signing position in sequential mode, display order otherwise. */
37
+ order: number;
38
+ }
39
+ export interface CeremonyResolution {
40
+ statuses: SignatoryStatus[];
41
+ status: CeremonyStatus;
42
+ signedCount: number;
43
+ total: number;
44
+ /** Parties who may act right now. Empty once the ceremony is done or stopped. */
45
+ awaiting: Signatory[];
46
+ }
47
+ /**
48
+ * Resolve every party's state from the signing order and what has happened.
49
+ *
50
+ * Three rules, in priority order:
51
+ *
52
+ * 1. **A decline stops the ceremony.** Nobody who has not already signed
53
+ * becomes `awaiting` — not even in parallel mode, where they otherwise
54
+ * could all act. This is the rule worth being strict about: a declined
55
+ * document is dead until the host revives it, and showing someone a
56
+ * sign-now affordance for it wastes their time and produces a signature
57
+ * against a document the counterparty has already refused.
58
+ * 2. **Sequential grants exactly one turn.** The first unsigned party is
59
+ * `awaiting`; everyone behind them is `waiting`. A later party can never
60
+ * appear actionable before an earlier one has signed.
61
+ * 3. **Parallel grants every turn at once** — all unsigned parties are
62
+ * `awaiting`.
63
+ */
64
+ export declare const resolveCeremony: (signatories: readonly Signatory[], mode?: SignatureMode) => CeremonyResolution;
65
+ /** Human phrasing for the ceremony as a whole. */
66
+ export declare const formatCeremonySummary: (resolution: CeremonyResolution) => string;
67
+ /** Attribute payloads are author input — validate every record. */
68
+ export declare const isSignatoryRecord: (value: unknown) => value is Signatory;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Signature ceremony model and the pure engine that resolves it.
3
+ *
4
+ * DOM-free and deterministic, so the rules that decide *who may sign now* are
5
+ * testable on their own and a host can drive its own signing surface — or its
6
+ * server-side reminders — from the same function.
7
+ */
8
+ /**
9
+ * Resolve every party's state from the signing order and what has happened.
10
+ *
11
+ * Three rules, in priority order:
12
+ *
13
+ * 1. **A decline stops the ceremony.** Nobody who has not already signed
14
+ * becomes `awaiting` — not even in parallel mode, where they otherwise
15
+ * could all act. This is the rule worth being strict about: a declined
16
+ * document is dead until the host revives it, and showing someone a
17
+ * sign-now affordance for it wastes their time and produces a signature
18
+ * against a document the counterparty has already refused.
19
+ * 2. **Sequential grants exactly one turn.** The first unsigned party is
20
+ * `awaiting`; everyone behind them is `waiting`. A later party can never
21
+ * appear actionable before an earlier one has signed.
22
+ * 3. **Parallel grants every turn at once** — all unsigned parties are
23
+ * `awaiting`.
24
+ */
25
+ export const resolveCeremony = (signatories, mode = "sequential") => {
26
+ const declined = signatories.some(signatory => signatory.declinedAt);
27
+ const signedCount = signatories.filter(signatory => signatory.signedAt && !signatory.declinedAt).length;
28
+ let turnTaken = false;
29
+ const statuses = signatories.map((signatory, index) => {
30
+ const order = index + 1;
31
+ if (signatory.declinedAt) {
32
+ return { signatory, state: "declined", order };
33
+ }
34
+ if (signatory.signedAt) {
35
+ return { signatory, state: "signed", order };
36
+ }
37
+ // Rule 1: a stopped ceremony grants no turns at all.
38
+ if (declined) {
39
+ return { signatory, state: "waiting", order };
40
+ }
41
+ if (mode === "parallel") {
42
+ return { signatory, state: "awaiting", order };
43
+ }
44
+ // Rule 2: sequential hands out a single turn, to the first unsigned party.
45
+ if (turnTaken) {
46
+ return { signatory, state: "waiting", order };
47
+ }
48
+ turnTaken = true;
49
+ return { signatory, state: "awaiting", order };
50
+ });
51
+ const status = declined
52
+ ? "declined"
53
+ : signatories.length > 0 && signedCount === signatories.length
54
+ ? "completed"
55
+ : "in-progress";
56
+ return {
57
+ statuses,
58
+ status,
59
+ signedCount,
60
+ total: signatories.length,
61
+ awaiting: statuses
62
+ .filter(entry => entry.state === "awaiting")
63
+ .map(entry => entry.signatory),
64
+ };
65
+ };
66
+ /** Human phrasing for the ceremony as a whole. */
67
+ export const formatCeremonySummary = (resolution) => {
68
+ if (resolution.total === 0) {
69
+ return "No signatories";
70
+ }
71
+ if (resolution.status === "declined") {
72
+ return "Declined";
73
+ }
74
+ if (resolution.status === "completed") {
75
+ return "Fully executed";
76
+ }
77
+ return `${String(resolution.signedCount)} of ${String(resolution.total)} signed`;
78
+ };
79
+ /** Attribute payloads are author input — validate every record. */
80
+ export const isSignatoryRecord = (value) => {
81
+ if (typeof value !== "object" || value === null) {
82
+ return false;
83
+ }
84
+ const signatory = value;
85
+ return (typeof signatory.id === "string" &&
86
+ signatory.id.length > 0 &&
87
+ typeof signatory.name === "string" &&
88
+ signatory.name.length > 0);
89
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./types.js";
2
+ export * from "./timeline.js";
@@ -0,0 +1,4 @@
1
+ // Event model and validation
2
+ export * from "./types.js";
3
+ // Composed activity-feed surface
4
+ export * from "./timeline.js";
@@ -0,0 +1,27 @@
1
+ import type { TimelineEvent } from "./types.js";
2
+ import { BaseElement } from "../../core/index.js";
3
+ export declare class Timeline extends BaseElement {
4
+ static readonly tagName: string;
5
+ static get observedAttributes(): string[];
6
+ private titleEl;
7
+ private eventsEl;
8
+ private emptyEl;
9
+ private loadMoreRegionEl;
10
+ private composerEl;
11
+ private composerInputEl;
12
+ private eventsSignature;
13
+ get heading(): string;
14
+ set heading(value: string);
15
+ /** Append-only event list; JSON records validated before rendering. */
16
+ get events(): TimelineEvent[];
17
+ set events(value: TimelineEvent[]);
18
+ get composable(): boolean;
19
+ set composable(value: boolean);
20
+ get hasMore(): boolean;
21
+ set hasMore(value: boolean);
22
+ private emitEntrySubmitted;
23
+ private rebuildEvents;
24
+ protected renderTemplate(): void;
25
+ protected setupListeners(): void;
26
+ protected update(): void;
27
+ }