@unofficialbox/box-open-elements 0.11.0 → 0.13.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 (59) hide show
  1. package/dist/components/feedback/alert.d.ts +2 -0
  2. package/dist/components/feedback/alert.js +41 -8
  3. package/dist/components/feedback/indicator.d.ts +34 -0
  4. package/dist/components/feedback/indicator.js +167 -0
  5. package/dist/components/feedback/nudge.js +0 -1
  6. package/dist/components/feedback/toast.d.ts +4 -5
  7. package/dist/components/feedback/toast.js +19 -46
  8. package/dist/components/feedback/tone.d.ts +18 -0
  9. package/dist/components/feedback/tone.js +23 -0
  10. package/dist/components/forms/calendar.d.ts +25 -0
  11. package/dist/components/forms/calendar.js +94 -2
  12. package/dist/components/forms/tile-group.d.ts +58 -0
  13. package/dist/components/forms/tile-group.js +280 -0
  14. package/dist/components/output/code-block.d.ts +49 -0
  15. package/dist/components/output/code-block.js +236 -0
  16. package/dist/components/output/formatted-date.d.ts +38 -0
  17. package/dist/components/output/formatted-date.js +90 -0
  18. package/dist/components/output/formatted-file-size.d.ts +31 -0
  19. package/dist/components/output/formatted-file-size.js +61 -0
  20. package/dist/components/output/formatted-number.d.ts +37 -0
  21. package/dist/components/output/formatted-number.js +106 -0
  22. package/dist/components/output/formatted-value.d.ts +44 -0
  23. package/dist/components/output/formatted-value.js +100 -0
  24. package/dist/components/output/index.d.ts +6 -0
  25. package/dist/components/output/index.js +9 -0
  26. package/dist/components/output/relative-time.d.ts +41 -0
  27. package/dist/components/output/relative-time.js +82 -0
  28. package/dist/element-maps.d.ts +17 -1
  29. package/dist/entries/code-block.d.ts +1 -0
  30. package/dist/entries/code-block.js +1 -0
  31. package/dist/entries/comment-thread.d.ts +1 -0
  32. package/dist/entries/comment-thread.js +1 -0
  33. package/dist/entries/formatted-date.d.ts +1 -0
  34. package/dist/entries/formatted-date.js +1 -0
  35. package/dist/entries/formatted-file-size.d.ts +1 -0
  36. package/dist/entries/formatted-file-size.js +1 -0
  37. package/dist/entries/formatted-number.d.ts +1 -0
  38. package/dist/entries/formatted-number.js +1 -0
  39. package/dist/entries/indicator.d.ts +1 -0
  40. package/dist/entries/indicator.js +1 -0
  41. package/dist/entries/relative-time.d.ts +1 -0
  42. package/dist/entries/relative-time.js +1 -0
  43. package/dist/entries/tile-group.d.ts +1 -0
  44. package/dist/entries/tile-group.js +1 -0
  45. package/dist/foundations/format/format.d.ts +82 -0
  46. package/dist/foundations/format/format.js +122 -0
  47. package/dist/foundations/format/index.d.ts +1 -0
  48. package/dist/foundations/format/index.js +3 -0
  49. package/dist/index.d.ts +10 -0
  50. package/dist/index.js +12 -0
  51. package/dist/patterns/comments/comment-thread.d.ts +79 -0
  52. package/dist/patterns/comments/comment-thread.js +561 -0
  53. package/dist/patterns/comments/index.d.ts +2 -0
  54. package/dist/patterns/comments/index.js +5 -0
  55. package/dist/patterns/comments/types.d.ts +39 -0
  56. package/dist/patterns/comments/types.js +8 -0
  57. package/dist/patterns/preview/annotation-thread.d.ts +67 -48
  58. package/dist/patterns/preview/annotation-thread.js +96 -440
  59. package/package.json +1 -1
@@ -4,7 +4,9 @@ export declare class Alert extends BaseElement {
4
4
  static get observedAttributes(): string[];
5
5
  private openValue;
6
6
  private alertEl;
7
+ private iconEl;
7
8
  private toneLabelEl;
9
+ private renderedTone;
8
10
  private titleEl;
9
11
  private messageEl;
10
12
  private richSlot;
@@ -1,5 +1,5 @@
1
1
  import { BaseElement } from "../../core/index.js";
2
- import { toneAccessibleLabel } from "./tone.js";
2
+ import { toneAccessibleLabel, toneIcon } from "./tone.js";
3
3
  import { boeRadius, boeSpace } from "../../foundations/geometry/index.js";
4
4
  import { boeNeutralInteractiveStyles } from "../../foundations/tokens/index.js";
5
5
  import { boeMotionDuration, boeMotionEasing } from "../../foundations/motion/index.js";
@@ -15,42 +15,64 @@ const alertStyles = `
15
15
  display: none;
16
16
  }
17
17
 
18
+ /* The accent colours the glyph only. The tinted backgrounds below are pinned
19
+ by the colour conformance manifest against upstream box-ui-elements and are
20
+ deliberately not derived from it; upstream has no glyph, so adding one
21
+ costs no conformance. */
18
22
  [part="alert"] {
23
+ --alert-accent: var(--boe-token-text-text-secondary, #6f6f6f);
24
+
19
25
  display: flex;
20
26
  align-items: start;
21
27
  justify-content: space-between;
22
28
  gap: ${boeSpace[3]};
23
29
  margin: ${boeSpace[3]} 0;
24
30
  padding: 14px 10px;
25
- border: 1px solid var(--boe-token-text-text-secondary, #6f6f6f);
26
31
  border-radius: ${boeRadius.large};
27
32
  background: var(--boe-token-surface-surface-secondary, #f4f4f4);
28
33
  color: var(--boe-token-text-text, #222222);
29
- transition: background ${boeMotionDuration.interactive} ${boeMotionEasing.standard}, border-color ${boeMotionDuration.interactive} ${boeMotionEasing.standard};
34
+ transition: background ${boeMotionDuration.interactive} ${boeMotionEasing.standard};
30
35
  }
31
36
 
32
37
  [part="alert"][data-tone="info"] {
38
+ --alert-accent: var(--boe-token-surface-surface-brand, #0061d5);
33
39
  background: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 10%, #fff);
34
- border-color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 50%, #fff);
35
40
  }
36
41
 
37
42
  [part="alert"][data-tone="success"] {
43
+ --alert-accent: var(--boe-token-surface-status-surface-success, #26c281);
38
44
  background: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26c281) 10%, #fff);
39
- border-color: var(--boe-token-surface-status-surface-success, #26c281);
40
45
  }
41
46
 
42
47
  [part="alert"][data-tone="error"] {
48
+ --alert-accent: var(--boe-token-surface-status-surface-error, #ed3757);
43
49
  background: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 10%, #fff);
44
- border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 50%, #fff);
45
50
  }
46
51
 
47
52
  [part="alert"][data-tone="warning"],
48
53
  [part="alert"][data-tone="inprogress"] {
54
+ --alert-accent: var(--boe-token-surface-status-surface-inprogress, #f5b31b);
49
55
  background: color-mix(in srgb, var(--boe-token-surface-status-surface-inprogress, #f5b31b) 10%, #fff);
50
- border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-inprogress, #f5b31b) 50%, #fff);
56
+ }
57
+
58
+ [part="icon"] {
59
+ flex: 0 0 auto;
60
+ inline-size: 20px;
61
+ block-size: 20px;
62
+ /* Full strength: with only a 10% tint behind it, the glyph is where the
63
+ tone actually reads. */
64
+ color: var(--alert-accent);
65
+ }
66
+
67
+ [part="icon"] svg {
68
+ display: block;
69
+ inline-size: 100%;
70
+ block-size: 100%;
51
71
  }
52
72
 
53
73
  [part="content"] {
74
+ flex: 1 1 auto;
75
+ min-inline-size: 0;
54
76
  display: grid;
55
77
  gap: ${boeSpace[1]};
56
78
  line-height: 1.45;
@@ -128,7 +150,9 @@ export class Alert extends BaseElement {
128
150
  }
129
151
  openValue = true;
130
152
  alertEl;
153
+ iconEl;
131
154
  toneLabelEl;
155
+ renderedTone = null;
132
156
  titleEl;
133
157
  messageEl;
134
158
  richSlot;
@@ -201,6 +225,7 @@ export class Alert extends BaseElement {
201
225
  this.shadowRoot.innerHTML = `
202
226
  <style>${alertStyles}</style>
203
227
  <div part="alert" role="status" aria-live="polite">
228
+ <span part="icon" aria-hidden="true"></span>
204
229
  <div part="content">
205
230
  <span part="tone-label" class="sr-only"></span>
206
231
  <h2 part="title" id="alert-title" hidden></h2>
@@ -211,6 +236,7 @@ export class Alert extends BaseElement {
211
236
  </div>
212
237
  `;
213
238
  this.alertEl = this.shadowRoot.querySelector('[part="alert"]');
239
+ this.iconEl = this.shadowRoot.querySelector('[part="icon"]');
214
240
  this.toneLabelEl = this.shadowRoot.querySelector('[part="tone-label"]');
215
241
  this.titleEl = this.shadowRoot.querySelector('[part="title"]');
216
242
  this.messageEl = this.shadowRoot.querySelector('[part~="description"]');
@@ -242,7 +268,14 @@ export class Alert extends BaseElement {
242
268
  return;
243
269
  }
244
270
  this.alertEl.dataset.tone = this.tone;
245
- this.toneLabelEl.textContent = toneAccessibleLabel(this.tone);
271
+ const tone = this.tone;
272
+ this.toneLabelEl.textContent = toneAccessibleLabel(tone);
273
+ // Literal markup keyed by tone, so re-writing it on every update would be
274
+ // wasted work — and would restart any transition on the glyph.
275
+ if (tone !== this.renderedTone) {
276
+ this.renderedTone = tone;
277
+ this.iconEl.innerHTML = toneIcon(tone);
278
+ }
246
279
  if (this.heading) {
247
280
  this.alertEl.setAttribute("aria-labelledby", "alert-title");
248
281
  this.alertEl.removeAttribute("aria-label");
@@ -0,0 +1,34 @@
1
+ import { BaseElement } from "../../core/index.js";
2
+ /**
3
+ * A status mark, for dense lists where a full badge would not fit.
4
+ *
5
+ * ```html
6
+ * <box-indicator tone="success" label="Signed"></box-indicator>
7
+ * ```
8
+ *
9
+ * Distinct in shape as well as colour, so a status column survives being read
10
+ * by someone who cannot separate green from amber — the same rule the alert and
11
+ * toast glyphs follow.
12
+ *
13
+ * When there is no visible `label` the tone is still stated for assistive
14
+ * technology, because a bare dot otherwise announces nothing at all. A host
15
+ * whose surrounding text already says "Signed" should pass that as the label
16
+ * rather than leaving a reader to infer it from a colour.
17
+ */
18
+ export declare class Indicator extends BaseElement {
19
+ static readonly tagName: string;
20
+ static get observedAttributes(): string[];
21
+ private shapeEl;
22
+ private labelEl;
23
+ private toneLabelEl;
24
+ private renderedTone;
25
+ /** The status. Unknown tones render the neutral disc. */
26
+ get tone(): string;
27
+ set tone(value: string);
28
+ /** Visible text beside the mark. Optional. */
29
+ get label(): string;
30
+ set label(value: string);
31
+ protected renderTemplate(): void;
32
+ protected setupListeners(): void;
33
+ protected update(): void;
34
+ }
@@ -0,0 +1,167 @@
1
+ import { BaseElement } from "../../core/index.js";
2
+ import { toneAccessibleLabel } from "./tone.js";
3
+ const DEFAULT_TAG_NAME = "box-indicator";
4
+ /**
5
+ * Indicator shapes, one per tone.
6
+ *
7
+ * The shape is the point. A row of coloured dots is unreadable to anyone who
8
+ * cannot separate the colours, and status is exactly the information a reader
9
+ * most needs from a dense list. Carbon ships both an icon and a shape
10
+ * indicator for this reason; here the shape *is* the indicator, and colour is
11
+ * the redundant channel rather than the only one.
12
+ */
13
+ const INDICATOR_SHAPES = {
14
+ // A filled disc: the neutral resting state.
15
+ info: `<svg viewBox="0 0 12 12" fill="currentColor" focusable="false"><circle cx="6" cy="6" r="5"/></svg>`,
16
+ // A disc with a tick cut into it, matching the success glyph on alert/toast.
17
+ success: `<svg viewBox="0 0 12 12" fill="currentColor" focusable="false"><path d="M6 1a5 5 0 100 10A5 5 0 006 1zm2.5 3.6L5.6 8a.7.7 0 01-1 0L3.5 6.8a.7.7 0 111-1l.6.7 2.4-2.8a.7.7 0 011 .9z"/></svg>`,
18
+ // A triangle, distinguishable from a disc at a glance and at small sizes.
19
+ warning: `<svg viewBox="0 0 12 12" fill="currentColor" focusable="false"><path d="M5.5 1.4 0.5 10a.6.6 0 00.5.9h10a.6.6 0 00.5-.9l-5-8.6a.6.6 0 00-1 0z"/></svg>`,
20
+ // A diamond: a square is too close to a disc once antialiased at 10px.
21
+ error: `<svg viewBox="0 0 12 12" fill="currentColor" focusable="false"><path d="M6 0.6 11.4 6 6 11.4.6 6z"/></svg>`,
22
+ // A hollow ring: nothing has happened yet, so nothing is filled in.
23
+ pending: `<svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" focusable="false"><circle cx="6" cy="6" r="4"/></svg>`,
24
+ };
25
+ /** The shape for a tone, falling back to the neutral disc. */
26
+ const indicatorShape = (tone) => INDICATOR_SHAPES[tone] ?? INDICATOR_SHAPES.info;
27
+ const indicatorStyles = `
28
+ :host {
29
+ display: inline-flex;
30
+ align-items: center;
31
+ gap: 0.4rem;
32
+ color: inherit;
33
+ font: inherit;
34
+ }
35
+
36
+ :host([hidden]) {
37
+ display: none;
38
+ }
39
+
40
+ [part="shape"] {
41
+ flex: 0 0 auto;
42
+ inline-size: 0.62rem;
43
+ block-size: 0.62rem;
44
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
45
+ }
46
+
47
+ [part="shape"] svg {
48
+ display: block;
49
+ inline-size: 100%;
50
+ block-size: 100%;
51
+ }
52
+
53
+ :host([tone="info"]) [part="shape"] {
54
+ color: var(--boe-token-surface-surface-brand, #0061d5);
55
+ }
56
+
57
+ :host([tone="success"]) [part="shape"] {
58
+ color: var(--boe-token-surface-status-surface-success, #26c281);
59
+ }
60
+
61
+ :host([tone="error"]) [part="shape"] {
62
+ color: var(--boe-token-surface-status-surface-error, #ed3757);
63
+ }
64
+
65
+ :host([tone="warning"]) [part="shape"] {
66
+ color: var(--boe-token-surface-status-surface-inprogress, #f5b31b);
67
+ }
68
+
69
+ [part="label"] {
70
+ min-inline-size: 0;
71
+ overflow-wrap: anywhere;
72
+ }
73
+
74
+ /* With no label the dot stands alone, and an empty span would still take a
75
+ line box and the flex gap beside it. */
76
+ [part="label"]:empty {
77
+ display: none;
78
+ }
79
+
80
+ .sr-only {
81
+ position: absolute;
82
+ inline-size: 1px;
83
+ block-size: 1px;
84
+ padding: 0;
85
+ margin: -1px;
86
+ overflow: hidden;
87
+ clip-path: inset(50%);
88
+ white-space: nowrap;
89
+ border: 0;
90
+ }
91
+ `;
92
+ /**
93
+ * A status mark, for dense lists where a full badge would not fit.
94
+ *
95
+ * ```html
96
+ * <box-indicator tone="success" label="Signed"></box-indicator>
97
+ * ```
98
+ *
99
+ * Distinct in shape as well as colour, so a status column survives being read
100
+ * by someone who cannot separate green from amber — the same rule the alert and
101
+ * toast glyphs follow.
102
+ *
103
+ * When there is no visible `label` the tone is still stated for assistive
104
+ * technology, because a bare dot otherwise announces nothing at all. A host
105
+ * whose surrounding text already says "Signed" should pass that as the label
106
+ * rather than leaving a reader to infer it from a colour.
107
+ */
108
+ export class Indicator extends BaseElement {
109
+ static tagName = DEFAULT_TAG_NAME;
110
+ static get observedAttributes() {
111
+ return ["label", "tone"];
112
+ }
113
+ shapeEl;
114
+ labelEl;
115
+ toneLabelEl;
116
+ renderedTone = null;
117
+ /** The status. Unknown tones render the neutral disc. */
118
+ get tone() {
119
+ return this.getAttribute("tone") ?? "info";
120
+ }
121
+ set tone(value) {
122
+ this.setAttribute("tone", value);
123
+ }
124
+ /** Visible text beside the mark. Optional. */
125
+ get label() {
126
+ return this.getAttribute("label") ?? "";
127
+ }
128
+ set label(value) {
129
+ if (!value) {
130
+ this.removeAttribute("label");
131
+ return;
132
+ }
133
+ this.setAttribute("label", value);
134
+ }
135
+ renderTemplate() {
136
+ if (!this.shadowRoot) {
137
+ return;
138
+ }
139
+ this.shadowRoot.innerHTML = `
140
+ <style>${indicatorStyles}</style>
141
+ <span part="shape" aria-hidden="true"></span>
142
+ <span part="tone-label" class="sr-only"></span>
143
+ <span part="label"></span>
144
+ `;
145
+ this.shapeEl = this.shadowRoot.querySelector('[part="shape"]');
146
+ this.toneLabelEl = this.shadowRoot.querySelector('[part="tone-label"]');
147
+ this.labelEl = this.shadowRoot.querySelector('[part="label"]');
148
+ }
149
+ setupListeners() {
150
+ // Display only.
151
+ }
152
+ update() {
153
+ if (!this.shapeEl) {
154
+ return;
155
+ }
156
+ const tone = this.tone;
157
+ if (tone !== this.renderedTone) {
158
+ this.renderedTone = tone;
159
+ this.shapeEl.innerHTML = indicatorShape(tone);
160
+ }
161
+ this.labelEl.textContent = this.label;
162
+ // Only speak the tone when no visible label carries it; otherwise a reader
163
+ // hears "Success Signed" where the screen says "Signed".
164
+ this.toneLabelEl.textContent = this.label ? "" : toneAccessibleLabel(tone);
165
+ }
166
+ }
167
+ Indicator.register();
@@ -14,7 +14,6 @@ const nudgeStyles = `
14
14
  align-items: flex-start;
15
15
  gap: 0.55rem;
16
16
  padding: 0.55rem 0.7rem;
17
- border: 1px solid color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 24%, var(--boe-token-surface-surface, #ffffff));
18
17
  border-radius: ${boeRadius.large};
19
18
  background: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 7%, var(--boe-token-surface-surface, #ffffff));
20
19
  color: var(--boe-token-text-text, #222222);
@@ -38,12 +38,11 @@ export declare class Toast extends BaseElement {
38
38
  get heading(): string;
39
39
  set heading(value: string);
40
40
  /**
41
- * Drop the outline for a softer, fill-only toast.
41
+ * @deprecated Every toast is borderless now, so this does nothing.
42
42
  *
43
- * Purely presentational and handled entirely in CSS, so it is deliberately
44
- * not an observed attribute — there is nothing to re-render. The default
45
- * stays bordered: that outline tracks box-ui-elements' `.notification` and
46
- * is pinned by the colour conformance manifest.
43
+ * Kept because it shipped in 0.11.0 and removing it would break hosts that
44
+ * set it for no benefit — what they asked for is what they already get. The
45
+ * attribute is still reflected so those hosts read back what they wrote.
47
46
  */
48
47
  get borderless(): boolean;
49
48
  set borderless(value: boolean);
@@ -1,5 +1,5 @@
1
1
  import { BaseElement } from "../../core/index.js";
2
- import { toneAccessibleLabel } from "./tone.js";
2
+ import { toneAccessibleLabel, toneIcon } from "./tone.js";
3
3
  import { boeRadius, boeSpace } from "../../foundations/geometry/index.js";
4
4
  import { boeFocusVisibleStyles } from "../../foundations/tokens/index.js";
5
5
  import { boeMotionDuration, boeMotionEasing } from "../../foundations/motion/index.js";
@@ -7,22 +7,6 @@ const DEFAULT_TAG_NAME = "box-toast";
7
7
  const TOAST_MODES = new Set(["dismissible", "sticky"]);
8
8
  /** Narrow an author-supplied mode, falling back to `dismissible`. */
9
9
  export const resolveToastMode = (value) => TOAST_MODES.has(value) ? value : "dismissible";
10
- /**
11
- * Status glyphs, one per tone.
12
- *
13
- * A toast is read at a glance and often out of the corner of an eye, so the
14
- * shape has to carry the meaning before the colour does — a round tick and a
15
- * warning triangle are distinguishable to a reader who cannot separate green
16
- * from amber. Literal markup, never author input, so innerHTML is safe here.
17
- */
18
- const TONE_ICONS = {
19
- info: `<svg viewBox="0 0 20 20" fill="currentColor" focusable="false"><path d="M10 2a8 8 0 100 16 8 8 0 000-16zm0 3.4a1.15 1.15 0 110 2.3 1.15 1.15 0 010-2.3zM11.1 15H8.9V9.3h2.2V15z"/></svg>`,
20
- success: `<svg viewBox="0 0 20 20" fill="currentColor" focusable="false"><path d="M10 2a8 8 0 100 16 8 8 0 000-16zm4.06 5.86-5 5.2a1 1 0 01-1.44 0L5.94 11.3A1 1 0 117.38 9.9l1.04 1.08 4.28-4.52a1 1 0 011.36 1.38z"/></svg>`,
21
- warning: `<svg viewBox="0 0 20 20" fill="currentColor" focusable="false"><path d="M9.13 2.6 1.4 15.9a1 1 0 00.87 1.5h15.46a1 1 0 00.87-1.5L10.87 2.6a1 1 0 00-1.74 0zM11.1 15.4H8.9v-2.2h2.2v2.2zm0-3.4H8.9V7.6h2.2V12z"/></svg>`,
22
- error: `<svg viewBox="0 0 20 20" fill="currentColor" focusable="false"><path d="M10 2a8 8 0 100 16 8 8 0 000-16zm0 2c1.29 0 2.48.41 3.46 1.1L5.1 13.46A6 6 0 0110 4zm0 12c-1.29 0-2.48-.41-3.46-1.1l8.36-8.36A6 6 0 0110 16z"/></svg>`,
23
- };
24
- /** The tone glyph, falling back to the info mark for an unknown tone. */
25
- const toneIcon = (tone) => TONE_ICONS[tone] ?? TONE_ICONS.info;
26
10
  const DISMISS_ICON = `<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" focusable="false"><path d="M5.5 5.5l9 9M14.5 5.5l-9 9"/></svg>`;
27
11
  const toastStyles = `
28
12
  :host {
@@ -37,11 +21,18 @@ const toastStyles = `
37
21
  display: none;
38
22
  }
39
23
 
40
- /* Fill, border, text colour and shadow all track box-ui-elements'
41
- .notification and are pinned by the colour conformance manifest — they are
42
- deliberately not derived from the tone accent. The --toast-accent property
43
- exists only to colour the status glyph, which upstream has no equivalent
44
- for, so adding it costs no conformance. */
24
+ /* Fill, text colour and shadow track box-ui-elements' .notification and are
25
+ pinned by the colour conformance manifest — they are deliberately not
26
+ derived from the tone accent. The --toast-accent property exists only to
27
+ colour the status glyph, which upstream has no equivalent for, so adding it
28
+ costs no conformance.
29
+
30
+ There is no border. Upstream .notification has one, and box-open-elements
31
+ matched it until the outline was judged too heavy; the claim that pinned it
32
+ was retired rather than left describing something no longer painted. Tone
33
+ survives that in three places — the tinted fill, the full-strength glyph,
34
+ and the visually-hidden tone label — so it was never carried by the border
35
+ alone. */
45
36
  [part="toast"] {
46
37
  --toast-accent: var(--boe-token-text-text, #222222);
47
38
 
@@ -53,28 +44,14 @@ const toastStyles = `
53
44
  min-height: 48px;
54
45
  max-inline-size: min(100%, 572px);
55
46
  padding: 10px 10px 10px 20px;
56
- border: 2px solid var(--boe-token-text-text, #222222);
57
47
  border-radius: ${boeRadius.large};
58
48
  background: var(--boe-token-surface-surface-secondary, #f4f4f4);
59
49
  color: var(--boe-token-text-text, #222222);
60
50
  box-shadow: 0 2px 6px rgb(0 0 0 / 15%);
61
51
  }
62
52
 
63
- /* Opt-in softer treatment: the outline goes, the geometry does not. Setting
64
- the colour to transparent rather than the width to 0 keeps the 2px in the
65
- box model, so a borderless toast is exactly the size of a bordered one and
66
- the two can sit in the same stack without jumping. The background paints
67
- under the border by default, so the fill simply extends into it.
68
-
69
- The bordered default stays: the 2px solid text-colour rule below is pinned
70
- by the colour conformance manifest against upstream's .notification, and
71
- strict mode fails if that declaration goes. */
72
- :host([borderless]) [part="toast"] {
73
- border-color: transparent;
74
- }
75
-
76
- /* The neutral toast keeps upstream's grey fill and near-black border, so the
77
- glyph is the only place the "this is information" signal can live. */
53
+ /* The neutral toast keeps upstream's grey fill, so the glyph is the only
54
+ place the "this is information" signal can live. */
78
55
  [part="toast"][data-tone="info"] {
79
56
  --toast-accent: var(--boe-token-surface-surface-brand, #0061d5);
80
57
  }
@@ -82,20 +59,17 @@ const toastStyles = `
82
59
  [part="toast"][data-tone="success"] {
83
60
  --toast-accent: var(--boe-token-surface-status-surface-success, #26c281);
84
61
  background: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26c281) 20%, #fff);
85
- border-color: var(--boe-token-surface-status-surface-success, #26c281);
86
62
  }
87
63
 
88
64
  [part="toast"][data-tone="error"] {
89
65
  --toast-accent: var(--boe-token-surface-status-surface-error, #ed3757);
90
66
  background: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 20%, #fff);
91
- border-color: var(--boe-token-surface-status-surface-error, #ed3757);
92
67
  }
93
68
 
94
69
  [part="toast"][data-tone="warning"],
95
70
  [part="toast"][data-tone="inprogress"] {
96
71
  --toast-accent: var(--boe-token-surface-status-surface-inprogress, #f5b31b);
97
72
  background: color-mix(in srgb, var(--boe-token-surface-status-surface-inprogress, #f5b31b) 20%, #fff);
98
- border-color: var(--boe-token-surface-status-surface-inprogress, #f5b31b);
99
73
  }
100
74
 
101
75
  .sr-only {
@@ -304,12 +278,11 @@ export class Toast extends BaseElement {
304
278
  this.setAttribute("heading", value);
305
279
  }
306
280
  /**
307
- * Drop the outline for a softer, fill-only toast.
281
+ * @deprecated Every toast is borderless now, so this does nothing.
308
282
  *
309
- * Purely presentational and handled entirely in CSS, so it is deliberately
310
- * not an observed attribute — there is nothing to re-render. The default
311
- * stays bordered: that outline tracks box-ui-elements' `.notification` and
312
- * is pinned by the colour conformance manifest.
283
+ * Kept because it shipped in 0.11.0 and removing it would break hosts that
284
+ * set it for no benefit — what they asked for is what they already get. The
285
+ * attribute is still reflected so those hosts read back what they wrote.
313
286
  */
314
287
  get borderless() {
315
288
  return this.hasAttribute("borderless");
@@ -5,6 +5,10 @@
5
5
  * readers, and both must say the *same* words: a reader who hears "In progress"
6
6
  * from an alert should not hear "Inprogress" from a toast reporting the same
7
7
  * thing. One definition is what keeps them in step.
8
+ *
9
+ * The glyphs live here for the same reason. Both surfaces render them, and a
10
+ * success tick that differs between an alert and a toast reporting the same
11
+ * outcome is a defect a reader would notice before either team did.
8
12
  */
9
13
  /**
10
14
  * The tone as a word, for assistive technology.
@@ -14,3 +18,17 @@
14
18
  * a host that invents a tone should still get something spoken.
15
19
  */
16
20
  export declare const toneAccessibleLabel: (tone: string) => string;
21
+ /**
22
+ * Status glyphs, one per tone.
23
+ *
24
+ * These surfaces are read at a glance, often out of the corner of an eye, so
25
+ * the shape has to carry the meaning before the colour does — a round tick and
26
+ * a warning triangle are distinguishable to a reader who cannot separate green
27
+ * from amber. That matters most where the fill is faint: `box-alert` tints its
28
+ * background by only 10%, which on its own is a weak signal.
29
+ *
30
+ * Literal markup, never author input, so innerHTML is safe here.
31
+ */
32
+ export declare const TONE_ICONS: Record<string, string>;
33
+ /** The tone glyph, falling back to the info mark for an unknown tone. */
34
+ export declare const toneIcon: (tone: string) => string;
@@ -5,6 +5,10 @@
5
5
  * readers, and both must say the *same* words: a reader who hears "In progress"
6
6
  * from an alert should not hear "Inprogress" from a toast reporting the same
7
7
  * thing. One definition is what keeps them in step.
8
+ *
9
+ * The glyphs live here for the same reason. Both surfaces render them, and a
10
+ * success tick that differs between an alert and a toast reporting the same
11
+ * outcome is a defect a reader would notice before either team did.
8
12
  */
9
13
  /**
10
14
  * The tone as a word, for assistive technology.
@@ -29,3 +33,22 @@ export const toneAccessibleLabel = (tone) => {
29
33
  return tone.charAt(0).toUpperCase() + tone.slice(1);
30
34
  }
31
35
  };
36
+ /**
37
+ * Status glyphs, one per tone.
38
+ *
39
+ * These surfaces are read at a glance, often out of the corner of an eye, so
40
+ * the shape has to carry the meaning before the colour does — a round tick and
41
+ * a warning triangle are distinguishable to a reader who cannot separate green
42
+ * from amber. That matters most where the fill is faint: `box-alert` tints its
43
+ * background by only 10%, which on its own is a weak signal.
44
+ *
45
+ * Literal markup, never author input, so innerHTML is safe here.
46
+ */
47
+ export const TONE_ICONS = {
48
+ info: `<svg viewBox="0 0 20 20" fill="currentColor" focusable="false"><path d="M10 2a8 8 0 100 16 8 8 0 000-16zm0 3.4a1.15 1.15 0 110 2.3 1.15 1.15 0 010-2.3zM11.1 15H8.9V9.3h2.2V15z"/></svg>`,
49
+ success: `<svg viewBox="0 0 20 20" fill="currentColor" focusable="false"><path d="M10 2a8 8 0 100 16 8 8 0 000-16zm4.06 5.86-5 5.2a1 1 0 01-1.44 0L5.94 11.3A1 1 0 117.38 9.9l1.04 1.08 4.28-4.52a1 1 0 011.36 1.38z"/></svg>`,
50
+ warning: `<svg viewBox="0 0 20 20" fill="currentColor" focusable="false"><path d="M9.13 2.6 1.4 15.9a1 1 0 00.87 1.5h15.46a1 1 0 00.87-1.5L10.87 2.6a1 1 0 00-1.74 0zM11.1 15.4H8.9v-2.2h2.2v2.2zm0-3.4H8.9V7.6h2.2V12z"/></svg>`,
51
+ error: `<svg viewBox="0 0 20 20" fill="currentColor" focusable="false"><path d="M10 2a8 8 0 100 16 8 8 0 000-16zm0 2c1.29 0 2.48.41 3.46 1.1L5.1 13.46A6 6 0 0110 4zm0 12c-1.29 0-2.48-.41-3.46-1.1l8.36-8.36A6 6 0 0110 16z"/></svg>`,
52
+ };
53
+ /** The tone glyph, falling back to the info mark for an unknown tone. */
54
+ export const toneIcon = (tone) => TONE_ICONS[tone] ?? TONE_ICONS.info;
@@ -27,6 +27,31 @@ export declare class Calendar extends BaseElement {
27
27
  private isOutOfRange;
28
28
  private goToMonth;
29
29
  private shiftMonth;
30
+ /**
31
+ * `single` (default) or `range`.
32
+ *
33
+ * Range mode uses `start`/`end` rather than overloading `value`: a single
34
+ * attribute holding two dates would have to invent a separator, and every
35
+ * host would then have to parse it back out.
36
+ */
37
+ get mode(): string;
38
+ set mode(next: string);
39
+ /** First date of the range, ISO. */
40
+ get start(): string;
41
+ set start(next: string);
42
+ /** Last date of the range, ISO. Empty while only one end has been picked. */
43
+ get end(): string;
44
+ set end(next: string);
45
+ /**
46
+ * Advance the range by one click.
47
+ *
48
+ * Three states, cycling: nothing chosen picks a start; a start alone closes
49
+ * the range; a complete range starts over. Picking an earlier day as the
50
+ * second click swaps the ends rather than rejecting it — a reader dragging
51
+ * backwards through a calendar means the same thing as dragging forwards,
52
+ * and refusing it would be pedantry.
53
+ */
54
+ private selectRange;
30
55
  private selectDate;
31
56
  /** Move roving focus by `delta` days, following into the neighbouring month if needed. */
32
57
  private moveActive;