@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,168 @@
1
+ import { DUE_BUCKET_LABELS, formatDueLabel, resolveDueBucket } from "./due-types.js";
2
+ import { BaseElement } from "../../core/index.js";
3
+ const DEFAULT_TAG_NAME = "box-due-badge";
4
+ const escapeHtml = (value) => value
5
+ .replaceAll("&", "&")
6
+ .replaceAll("<", "&lt;")
7
+ .replaceAll(">", "&gt;")
8
+ .replaceAll('"', "&quot;")
9
+ .replaceAll("'", "&#39;");
10
+ const elementStyles = `
11
+ :host {
12
+ display: inline-block;
13
+ }
14
+
15
+ [part="badge"] {
16
+ display: inline-flex;
17
+ align-items: center;
18
+ gap: 0.28rem;
19
+ padding: 0.14rem 0.45rem;
20
+ border-radius: 999px;
21
+ border: 1px solid transparent;
22
+ font-size: 0.74rem;
23
+ font-weight: 600;
24
+ white-space: nowrap;
25
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
26
+ background: color-mix(in srgb, var(--boe-token-surface-surface-hover, #f4f4f4) 80%, transparent);
27
+ }
28
+
29
+ [part="badge"][data-bucket="overdue"] {
30
+ background: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 14%, transparent);
31
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 76%, black 24%);
32
+ border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 32%, transparent);
33
+ }
34
+
35
+ [part="badge"][data-bucket="today"] {
36
+ background: color-mix(in srgb, var(--boe-token-surface-status-surface-warning, #f5b31b) 18%, transparent);
37
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-warning, #f5b31b) 46%, black 54%);
38
+ border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-warning, #f5b31b) 38%, transparent);
39
+ }
40
+
41
+ [part="badge"][data-bucket="this-week"] {
42
+ background: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 10%, transparent);
43
+ color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 78%, black 22%);
44
+ border-color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 26%, transparent);
45
+ }
46
+
47
+ [part="marker"] {
48
+ inline-size: 0.42rem;
49
+ block-size: 0.42rem;
50
+ border-radius: 999px;
51
+ background: currentColor;
52
+ }
53
+
54
+ /* Tone is never the only signal: the label always states the urgency
55
+ in words, so the dot is decoration and stays out of the a11y tree. */
56
+ [part="badge"][data-bucket="later"] [part="marker"],
57
+ [part="badge"][data-bucket="none"] [part="marker"] {
58
+ background: color-mix(in srgb, currentColor 45%, transparent);
59
+ }
60
+
61
+ [part="badge"][data-compact="true"] {
62
+ padding: 0.1rem 0.35rem;
63
+ font-size: 0.7rem;
64
+ }
65
+ `;
66
+ /**
67
+ * SLA / aging urgency for a due date — the badge the work-queue rows and
68
+ * record headers were specified to share.
69
+ *
70
+ * The label states the urgency in words ("Overdue by 3 days"), so colour is
71
+ * never the only signal, and the day count answers the question a due badge
72
+ * exists for: *how late is this?* A bare date makes the reader do that
73
+ * arithmetic themselves.
74
+ *
75
+ * `reference-time` pins "now" so rendering is deterministic — the same
76
+ * inputs always produce the same badge, in tests and in screenshots.
77
+ */
78
+ export class DueBadge extends BaseElement {
79
+ static tagName = DEFAULT_TAG_NAME;
80
+ static get observedAttributes() {
81
+ return ["compact", "due-at", "label", "reference-time"];
82
+ }
83
+ badgeEl;
84
+ textEl;
85
+ /** ISO timestamp the badge describes. Absent renders the no-due-date state. */
86
+ get dueAt() {
87
+ return this.getAttribute("due-at") ?? "";
88
+ }
89
+ set dueAt(value) {
90
+ this.setAttribute("due-at", value);
91
+ }
92
+ /** Overrides the derived wording; the bucket still drives the tone. */
93
+ get label() {
94
+ return this.getAttribute("label") ?? "";
95
+ }
96
+ set label(value) {
97
+ this.setAttribute("label", value);
98
+ }
99
+ get compact() {
100
+ return this.hasAttribute("compact");
101
+ }
102
+ set compact(value) {
103
+ this.toggleAttribute("compact", value);
104
+ }
105
+ get referenceTime() {
106
+ return this.getAttribute("reference-time") ?? "";
107
+ }
108
+ set referenceTime(value) {
109
+ this.setAttribute("reference-time", value);
110
+ }
111
+ now() {
112
+ const raw = this.referenceTime;
113
+ if (raw) {
114
+ const parsed = new Date(raw);
115
+ if (!Number.isNaN(parsed.getTime())) {
116
+ return parsed;
117
+ }
118
+ }
119
+ return new Date();
120
+ }
121
+ /** The urgency bucket currently rendered. */
122
+ get bucket() {
123
+ return resolveDueBucket(this.dueAt || undefined, this.now());
124
+ }
125
+ /** The rendered wording, derived unless `label` overrides it. */
126
+ get resolvedLabel() {
127
+ return this.label || formatDueLabel(this.dueAt || undefined, this.now());
128
+ }
129
+ renderTemplate() {
130
+ if (!this.shadowRoot) {
131
+ return;
132
+ }
133
+ this.shadowRoot.innerHTML = `
134
+ <style>${elementStyles}</style>
135
+ <span part="badge">
136
+ <span part="marker" aria-hidden="true"></span>
137
+ <span part="text"></span>
138
+ </span>
139
+ `;
140
+ this.badgeEl = this.shadowRoot.querySelector('[part="badge"]');
141
+ this.textEl = this.shadowRoot.querySelector('[part="text"]');
142
+ }
143
+ setupListeners() {
144
+ // Presentational: no interaction to wire.
145
+ }
146
+ update() {
147
+ if (!this.badgeEl) {
148
+ return;
149
+ }
150
+ const bucket = this.bucket;
151
+ const label = this.resolvedLabel;
152
+ this.badgeEl.setAttribute("data-bucket", bucket);
153
+ this.badgeEl.setAttribute("data-compact", String(this.compact));
154
+ this.textEl.textContent = label;
155
+ // A machine-readable date for anything consuming the DOM, and a title so
156
+ // the exact timestamp stays reachable when the label is relative.
157
+ if (this.dueAt && bucket !== "none") {
158
+ this.badgeEl.setAttribute("title", this.dueAt);
159
+ this.setAttribute("datetime", this.dueAt);
160
+ }
161
+ else {
162
+ this.badgeEl.removeAttribute("title");
163
+ this.removeAttribute("datetime");
164
+ }
165
+ this.badgeEl.setAttribute("aria-label", bucket === "none" ? escapeHtml(DUE_BUCKET_LABELS.none) : escapeHtml(label));
166
+ }
167
+ }
168
+ DueBadge.register();
@@ -0,0 +1,32 @@
1
+ /**
2
+ * SLA / aging urgency model, shared by `box-due-badge` and the work-queue
3
+ * pattern. Pure and timezone-independent.
4
+ *
5
+ * This lives with the component rather than the pattern because patterns
6
+ * compose components, not the other way round. `patterns/work-queue/types`
7
+ * re-exports it, so its public import path is unchanged.
8
+ */
9
+ /** Urgency buckets, most urgent first. */
10
+ export type DueBucket = "overdue" | "today" | "this-week" | "later" | "none";
11
+ export declare const DUE_BUCKET_ORDER: readonly DueBucket[];
12
+ export declare const DUE_BUCKET_LABELS: Record<DueBucket, string>;
13
+ /**
14
+ * Bucket a due timestamp relative to `now`. Pure and timezone-independent:
15
+ * callers supply the reference time and day boundaries resolve against the
16
+ * reference time's UTC day, so the same inputs bucket identically on every
17
+ * host. A host that wants local-day semantics offsets the reference time it
18
+ * passes.
19
+ */
20
+ export declare const resolveDueBucket: (dueAt: string | undefined, now: Date) => DueBucket;
21
+ /**
22
+ * Whole days between `dueAt` and `now`, negative when overdue. Measured
23
+ * between UTC day boundaries rather than by elapsed milliseconds, so
24
+ * "tomorrow" is 1 whether it is 23 hours away or 25.
25
+ */
26
+ export declare const daysUntilDue: (dueAt: string | undefined, now: Date) => number | null;
27
+ /**
28
+ * Human phrasing for a due date: "Overdue by 3 days", "Due today",
29
+ * "Due tomorrow", "Due in 5 days". Aging is stated in days rather than as a
30
+ * bare date because an SLA badge exists to answer "how late is this?".
31
+ */
32
+ export declare const formatDueLabel: (dueAt: string | undefined, now: Date) => string;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * SLA / aging urgency model, shared by `box-due-badge` and the work-queue
3
+ * pattern. Pure and timezone-independent.
4
+ *
5
+ * This lives with the component rather than the pattern because patterns
6
+ * compose components, not the other way round. `patterns/work-queue/types`
7
+ * re-exports it, so its public import path is unchanged.
8
+ */
9
+ export const DUE_BUCKET_ORDER = [
10
+ "overdue",
11
+ "today",
12
+ "this-week",
13
+ "later",
14
+ "none",
15
+ ];
16
+ export const DUE_BUCKET_LABELS = {
17
+ overdue: "Overdue",
18
+ today: "Due today",
19
+ "this-week": "Due this week",
20
+ later: "Later",
21
+ none: "No due date",
22
+ };
23
+ const DAY_MS = 24 * 60 * 60 * 1000;
24
+ /**
25
+ * Bucket a due timestamp relative to `now`. Pure and timezone-independent:
26
+ * callers supply the reference time and day boundaries resolve against the
27
+ * reference time's UTC day, so the same inputs bucket identically on every
28
+ * host. A host that wants local-day semantics offsets the reference time it
29
+ * passes.
30
+ */
31
+ export const resolveDueBucket = (dueAt, now) => {
32
+ if (!dueAt) {
33
+ return "none";
34
+ }
35
+ const due = new Date(dueAt);
36
+ if (Number.isNaN(due.getTime())) {
37
+ return "none";
38
+ }
39
+ if (due.getTime() < now.getTime()) {
40
+ return "overdue";
41
+ }
42
+ const endOfToday = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1) - 1;
43
+ if (due.getTime() <= endOfToday) {
44
+ return "today";
45
+ }
46
+ if (due.getTime() <= endOfToday + 6 * DAY_MS) {
47
+ return "this-week";
48
+ }
49
+ return "later";
50
+ };
51
+ /**
52
+ * Whole days between `dueAt` and `now`, negative when overdue. Measured
53
+ * between UTC day boundaries rather than by elapsed milliseconds, so
54
+ * "tomorrow" is 1 whether it is 23 hours away or 25.
55
+ */
56
+ export const daysUntilDue = (dueAt, now) => {
57
+ if (!dueAt) {
58
+ return null;
59
+ }
60
+ const due = new Date(dueAt);
61
+ if (Number.isNaN(due.getTime())) {
62
+ return null;
63
+ }
64
+ const dueDay = Date.UTC(due.getUTCFullYear(), due.getUTCMonth(), due.getUTCDate());
65
+ const nowDay = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
66
+ return Math.round((dueDay - nowDay) / DAY_MS);
67
+ };
68
+ /**
69
+ * Human phrasing for a due date: "Overdue by 3 days", "Due today",
70
+ * "Due tomorrow", "Due in 5 days". Aging is stated in days rather than as a
71
+ * bare date because an SLA badge exists to answer "how late is this?".
72
+ */
73
+ export const formatDueLabel = (dueAt, now) => {
74
+ const days = daysUntilDue(dueAt, now);
75
+ if (days === null) {
76
+ return DUE_BUCKET_LABELS.none;
77
+ }
78
+ if (days < 0) {
79
+ const overdue = Math.abs(days);
80
+ return `Overdue by ${String(overdue)} ${overdue === 1 ? "day" : "days"}`;
81
+ }
82
+ if (days === 0) {
83
+ // A same-day deadline that has already passed is overdue by hours, not
84
+ // days — the bucket knows, the day count does not.
85
+ return resolveDueBucket(dueAt, now) === "overdue" ? "Overdue" : "Due today";
86
+ }
87
+ if (days === 1) {
88
+ return "Due tomorrow";
89
+ }
90
+ return `Due in ${String(days)} days`;
91
+ };
@@ -1,25 +1,71 @@
1
1
  import { BaseElement } from "../../core/index.js";
2
- type BoxProgressStep = {
2
+ /**
3
+ * Explicit per-step status. Absent means the step derives complete / current /
4
+ * upcoming from its position relative to `value` — the behaviour existing
5
+ * hosts rely on. An explicit status wins over the positional derivation:
6
+ * `complete` marks out-of-order completion, `blocked` and `disabled` make the
7
+ * step non-interactive, `failed` stays interactive because a failed step is
8
+ * usually exactly where the user needs to go.
9
+ */
10
+ export type ProgressStepStatus = "complete" | "blocked" | "failed" | "disabled";
11
+ export interface ProgressStepItem {
3
12
  description?: string;
4
13
  label: string;
5
14
  value: string;
6
- };
15
+ status?: ProgressStepStatus;
16
+ /** Short visible note under the label explaining the status ("Waiting on legal review"). */
17
+ statusNote?: string;
18
+ }
19
+ export type ProgressStepState = "current" | "upcoming" | ProgressStepStatus;
20
+ export interface ResolvedProgressStep {
21
+ item: ProgressStepItem;
22
+ state: ProgressStepState;
23
+ /**
24
+ * True on the step `value` points at, whatever its status — currency is
25
+ * position, status is condition, and the two are stated separately so a
26
+ * failed step can still be the one the user is on.
27
+ */
28
+ isCurrent: boolean;
29
+ /** Blocked and disabled steps take no clicks and no focus. */
30
+ interactive: boolean;
31
+ }
32
+ /** Attribute payloads are author input — validate every record. */
33
+ export declare const isProgressStepRecord: (value: unknown) => value is ProgressStepItem;
34
+ /**
35
+ * The state rules, pure and DOM-free, so a host can drive its own surface
36
+ * (or decide whether "Continue" is enabled) from the same function the
37
+ * component renders from. An unknown `value` falls back to the first step,
38
+ * matching the component's long-standing behaviour.
39
+ */
40
+ export declare const resolveStepStates: (items: readonly ProgressStepItem[], value: string) => ResolvedProgressStep[];
41
+ /** Every state in words — colour never carries the meaning alone. */
42
+ export declare const STEP_STATE_LABEL: Record<ProgressStepState, string>;
7
43
  export declare class ProgressSteps extends BaseElement {
8
44
  static readonly tagName: string;
9
45
  static get observedAttributes(): string[];
10
46
  private valueInternal;
11
47
  private stepsEl;
48
+ private liveEl;
12
49
  private itemsSignature;
13
50
  get label(): string;
14
51
  set label(value: string);
15
- get items(): BoxProgressStep[];
16
- set items(value: BoxProgressStep[]);
52
+ get items(): ProgressStepItem[];
53
+ set items(value: ProgressStepItem[]);
54
+ /** The resolved states — same objects the render uses. */
55
+ get resolvedSteps(): ResolvedProgressStep[];
17
56
  get value(): string;
18
57
  set value(nextValue: string);
19
58
  attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
20
59
  protected renderTemplate(): void;
21
60
  protected setupListeners(): void;
22
61
  private selectValue;
62
+ /** A polite announcement on user-driven step changes, never on render. */
63
+ private announceStep;
64
+ /**
65
+ * The tab stop lives on the current step — unless that step is blocked or
66
+ * disabled (a host can point `value` anywhere), in which case the first
67
+ * interactive step takes it so the group stays reachable.
68
+ */
69
+ private tabbableIndex;
23
70
  protected update(): void;
24
71
  }
25
- export {};