@xmesh/system-design 0.0.1

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 (175) hide show
  1. package/README.md +472 -0
  2. package/assets/brand-lockup-dark.svg +9 -0
  3. package/assets/brand-lockup-light.svg +9 -0
  4. package/assets/brand-mark.svg +9 -0
  5. package/colors_and_type.css +11 -0
  6. package/dist/lit/components/alert/index.css +201 -0
  7. package/dist/lit/components/alert/index.d.ts +25 -0
  8. package/dist/lit/components/alert/index.js +191 -0
  9. package/dist/lit/components/app-bar/index.css +80 -0
  10. package/dist/lit/components/app-bar/index.d.ts +19 -0
  11. package/dist/lit/components/app-bar/index.js +120 -0
  12. package/dist/lit/components/artifact/index.css +166 -0
  13. package/dist/lit/components/artifact/index.d.ts +37 -0
  14. package/dist/lit/components/artifact/index.js +294 -0
  15. package/dist/lit/components/autocomplete/index.css +171 -0
  16. package/dist/lit/components/autocomplete/index.d.ts +47 -0
  17. package/dist/lit/components/autocomplete/index.js +404 -0
  18. package/dist/lit/components/avatar/index.css +62 -0
  19. package/dist/lit/components/avatar/index.d.ts +19 -0
  20. package/dist/lit/components/avatar/index.js +112 -0
  21. package/dist/lit/components/avatar-group/index.css +60 -0
  22. package/dist/lit/components/avatar-group/index.d.ts +19 -0
  23. package/dist/lit/components/avatar-group/index.js +97 -0
  24. package/dist/lit/components/badge/index.css +72 -0
  25. package/dist/lit/components/badge/index.d.ts +18 -0
  26. package/dist/lit/components/badge/index.js +115 -0
  27. package/dist/lit/components/brand-mark/index.css +109 -0
  28. package/dist/lit/components/brand-mark/index.d.ts +24 -0
  29. package/dist/lit/components/brand-mark/index.js +116 -0
  30. package/dist/lit/components/breadcrumbs/index.css +91 -0
  31. package/dist/lit/components/breadcrumbs/index.d.ts +19 -0
  32. package/dist/lit/components/breadcrumbs/index.js +104 -0
  33. package/dist/lit/components/bubble/index.css +182 -0
  34. package/dist/lit/components/bubble/index.d.ts +72 -0
  35. package/dist/lit/components/bubble/index.js +617 -0
  36. package/dist/lit/components/button/index.css +342 -0
  37. package/dist/lit/components/button/index.d.ts +32 -0
  38. package/dist/lit/components/button/index.js +202 -0
  39. package/dist/lit/components/card/index.css +99 -0
  40. package/dist/lit/components/card/index.d.ts +20 -0
  41. package/dist/lit/components/card/index.js +133 -0
  42. package/dist/lit/components/chat/index.css +292 -0
  43. package/dist/lit/components/chat/index.d.ts +74 -0
  44. package/dist/lit/components/chat/index.js +589 -0
  45. package/dist/lit/components/checkbox/index.css +126 -0
  46. package/dist/lit/components/checkbox/index.d.ts +21 -0
  47. package/dist/lit/components/checkbox/index.js +138 -0
  48. package/dist/lit/components/chip/index.css +145 -0
  49. package/dist/lit/components/chip/index.d.ts +30 -0
  50. package/dist/lit/components/chip/index.js +230 -0
  51. package/dist/lit/components/chip-group/index.css +19 -0
  52. package/dist/lit/components/chip-group/index.d.ts +24 -0
  53. package/dist/lit/components/chip-group/index.js +171 -0
  54. package/dist/lit/components/code/index.css +42 -0
  55. package/dist/lit/components/code/index.d.ts +12 -0
  56. package/dist/lit/components/code/index.js +68 -0
  57. package/dist/lit/components/composer/index.css +548 -0
  58. package/dist/lit/components/composer/index.d.ts +67 -0
  59. package/dist/lit/components/composer/index.js +713 -0
  60. package/dist/lit/components/data-table/index.css +166 -0
  61. package/dist/lit/components/data-table/index.d.ts +55 -0
  62. package/dist/lit/components/data-table/index.js +390 -0
  63. package/dist/lit/components/dialog/index.css +124 -0
  64. package/dist/lit/components/dialog/index.d.ts +24 -0
  65. package/dist/lit/components/dialog/index.js +199 -0
  66. package/dist/lit/components/divider/index.css +27 -0
  67. package/dist/lit/components/divider/index.d.ts +13 -0
  68. package/dist/lit/components/divider/index.js +67 -0
  69. package/dist/lit/components/empty-state/index.css +69 -0
  70. package/dist/lit/components/empty-state/index.d.ts +21 -0
  71. package/dist/lit/components/empty-state/index.js +123 -0
  72. package/dist/lit/components/expansion-panel/index.css +120 -0
  73. package/dist/lit/components/expansion-panel/index.d.ts +22 -0
  74. package/dist/lit/components/expansion-panel/index.js +174 -0
  75. package/dist/lit/components/field/index.css +223 -0
  76. package/dist/lit/components/field/index.d.ts +106 -0
  77. package/dist/lit/components/field/index.js +388 -0
  78. package/dist/lit/components/file-input/index.css +257 -0
  79. package/dist/lit/components/file-input/index.d.ts +30 -0
  80. package/dist/lit/components/file-input/index.js +298 -0
  81. package/dist/lit/components/form/index.css +29 -0
  82. package/dist/lit/components/form/index.d.ts +38 -0
  83. package/dist/lit/components/form/index.js +192 -0
  84. package/dist/lit/components/grid/index.css +53 -0
  85. package/dist/lit/components/grid/index.d.ts +14 -0
  86. package/dist/lit/components/grid/index.js +82 -0
  87. package/dist/lit/components/kbd/index.css +35 -0
  88. package/dist/lit/components/kbd/index.d.ts +11 -0
  89. package/dist/lit/components/kbd/index.js +43 -0
  90. package/dist/lit/components/list/index.css +15 -0
  91. package/dist/lit/components/list/index.d.ts +28 -0
  92. package/dist/lit/components/list/index.js +188 -0
  93. package/dist/lit/components/list-item/index.css +119 -0
  94. package/dist/lit/components/list-item/index.d.ts +20 -0
  95. package/dist/lit/components/list-item/index.js +127 -0
  96. package/dist/lit/components/menu/index.css +94 -0
  97. package/dist/lit/components/menu/index.d.ts +47 -0
  98. package/dist/lit/components/menu/index.js +386 -0
  99. package/dist/lit/components/navigation-drawer/index.css +114 -0
  100. package/dist/lit/components/navigation-drawer/index.d.ts +29 -0
  101. package/dist/lit/components/navigation-drawer/index.js +218 -0
  102. package/dist/lit/components/overlay/index.css +171 -0
  103. package/dist/lit/components/overlay/index.d.ts +65 -0
  104. package/dist/lit/components/overlay/index.js +566 -0
  105. package/dist/lit/components/pagination/index.css +102 -0
  106. package/dist/lit/components/pagination/index.d.ts +22 -0
  107. package/dist/lit/components/pagination/index.js +184 -0
  108. package/dist/lit/components/primitives/index.css +504 -0
  109. package/dist/lit/components/primitives/index.d.ts +25 -0
  110. package/dist/lit/components/primitives/index.js +283 -0
  111. package/dist/lit/components/progress/index.css +143 -0
  112. package/dist/lit/components/progress/index.d.ts +23 -0
  113. package/dist/lit/components/progress/index.js +180 -0
  114. package/dist/lit/components/radio-group/index.css +178 -0
  115. package/dist/lit/components/radio-group/index.d.ts +35 -0
  116. package/dist/lit/components/radio-group/index.js +292 -0
  117. package/dist/lit/components/select/index.css +151 -0
  118. package/dist/lit/components/select/index.d.ts +50 -0
  119. package/dist/lit/components/select/index.js +390 -0
  120. package/dist/lit/components/sidebar-item/index.css +133 -0
  121. package/dist/lit/components/sidebar-item/index.d.ts +20 -0
  122. package/dist/lit/components/sidebar-item/index.js +105 -0
  123. package/dist/lit/components/skeleton/index.css +81 -0
  124. package/dist/lit/components/skeleton/index.d.ts +19 -0
  125. package/dist/lit/components/skeleton/index.js +119 -0
  126. package/dist/lit/components/slider/index.css +171 -0
  127. package/dist/lit/components/slider/index.d.ts +36 -0
  128. package/dist/lit/components/slider/index.js +302 -0
  129. package/dist/lit/components/snackbar/index.css +279 -0
  130. package/dist/lit/components/snackbar/index.d.ts +33 -0
  131. package/dist/lit/components/snackbar/index.js +195 -0
  132. package/dist/lit/components/stack/index.css +41 -0
  133. package/dist/lit/components/stack/index.d.ts +20 -0
  134. package/dist/lit/components/stack/index.js +103 -0
  135. package/dist/lit/components/switch/index.css +126 -0
  136. package/dist/lit/components/switch/index.d.ts +17 -0
  137. package/dist/lit/components/switch/index.js +116 -0
  138. package/dist/lit/components/table/index.css +85 -0
  139. package/dist/lit/components/table/index.d.ts +25 -0
  140. package/dist/lit/components/table/index.js +139 -0
  141. package/dist/lit/components/tabs/index.css +116 -0
  142. package/dist/lit/components/tabs/index.d.ts +49 -0
  143. package/dist/lit/components/tabs/index.js +320 -0
  144. package/dist/lit/components/text-field/index.css +90 -0
  145. package/dist/lit/components/text-field/index.d.ts +17 -0
  146. package/dist/lit/components/text-field/index.js +101 -0
  147. package/dist/lit/components/textarea/index.css +55 -0
  148. package/dist/lit/components/textarea/index.d.ts +26 -0
  149. package/dist/lit/components/textarea/index.js +124 -0
  150. package/dist/lit/components/tooltip/index.css +37 -0
  151. package/dist/lit/components/tooltip/index.d.ts +31 -0
  152. package/dist/lit/components/tooltip/index.js +196 -0
  153. package/dist/lit/components/validation/index.css +386 -0
  154. package/dist/lit/components/validation/index.d.ts +45 -0
  155. package/dist/lit/components/validation/index.js +318 -0
  156. package/dist/lit/index.d.ts +50 -0
  157. package/dist/lit/index.js +59 -0
  158. package/package.json +81 -0
  159. package/styles/README.md +346 -0
  160. package/styles/_elevation.css +24 -0
  161. package/styles/_fonts.css +6 -0
  162. package/styles/_layout.css +37 -0
  163. package/styles/_primitives.css +154 -0
  164. package/styles/_scroll.css +75 -0
  165. package/styles/_semantic.css +146 -0
  166. package/styles/_space.css +61 -0
  167. package/styles/_type.css +139 -0
  168. package/styles/_xmesh-extensions.css +232 -0
  169. package/styles/index.css +44 -0
  170. package/styles/md3/_color.css +102 -0
  171. package/styles/md3/_elevation.css +26 -0
  172. package/styles/md3/_motion.css +35 -0
  173. package/styles/md3/_shape.css +22 -0
  174. package/styles/md3/_state.css +22 -0
  175. package/styles/md3/_type.css +111 -0
@@ -0,0 +1,201 @@
1
+ /* ============================================
2
+ Alert — inline notification banner.
3
+
4
+ Lightweight inline surface for notice/warning/success/critical
5
+ context. Sits between snackbar (modal-ish backend-error tunnel)
6
+ and a plain message: the host drops it inline in a chat thread,
7
+ a settings pane, or any content surface.
8
+
9
+ Severity is communicated by the icon glyph and copy ONLY — every
10
+ variant uses the same neutral surface and ink. `--md-sys-color-error*`
11
+ is forbidden in components (POLICIES.md rule 3a); status pastels
12
+ are not part of this design system.
13
+
14
+ Grid:
15
+ icon · body · action-slot · close
16
+ The icon column and close column are auto-sized; the body fills.
17
+ ============================================ */
18
+
19
+ .alert {
20
+ /* Component-local vars — neutral surface, border, and ink for every
21
+ severity (matches the rest of the design system). Severity carries
22
+ hue ONLY on the icon and its chip — this is the targeted exception
23
+ to the "no hue for severity" rule, scoped tightly so the alert
24
+ reads as chrome with a glanceable severity marker, not a loud
25
+ full-banner tint. Defaults are info; .alert--{severity} swaps the
26
+ icon vars. */
27
+ --alert-bg: var(--md-sys-color-surface-container-high);
28
+ --alert-border: var(--md-sys-color-outline-variant);
29
+ --alert-ink: var(--md-sys-color-on-surface);
30
+ --alert-ink-soft: var(--md-sys-color-on-surface-variant);
31
+ --alert-icon-ink: var(--xm-alert-info-ink);
32
+ --alert-icon-chip: var(--xm-alert-info-chip);
33
+
34
+ position: relative;
35
+ display: grid;
36
+ grid-template-columns: auto 1fr auto auto;
37
+ align-items: center;
38
+ gap: var(--s-3);
39
+ width: 100%;
40
+ padding: var(--s-3) var(--s-3) var(--s-3) var(--s-4);
41
+ background: var(--alert-bg);
42
+ border: 1px solid var(--alert-border);
43
+ border-radius: var(--md-sys-shape-corner-medium);
44
+ color: var(--alert-ink);
45
+ font-family: var(--md-sys-typescale-body-medium-font);
46
+ animation: alert-in var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard) both;
47
+ }
48
+ .alert--static { animation: none; }
49
+
50
+ @keyframes alert-in {
51
+ from {
52
+ opacity: 0;
53
+ transform: translateY(4px);
54
+ }
55
+ to {
56
+ opacity: 1;
57
+ transform: translateY(0);
58
+ }
59
+ }
60
+
61
+ /* Severity modifiers — swap ONLY the icon's ink and chip. Surface,
62
+ border, and body text stay neutral. */
63
+ .alert--info {
64
+ --alert-icon-ink: var(--xm-alert-info-ink);
65
+ --alert-icon-chip: var(--xm-alert-info-chip);
66
+ }
67
+ .alert--success {
68
+ --alert-icon-ink: var(--xm-alert-success-ink);
69
+ --alert-icon-chip: var(--xm-alert-success-chip);
70
+ }
71
+ .alert--warning {
72
+ --alert-icon-ink: var(--xm-alert-warning-ink);
73
+ --alert-icon-chip: var(--xm-alert-warning-chip);
74
+ }
75
+ .alert--critical {
76
+ --alert-icon-ink: var(--xm-alert-critical-ink);
77
+ --alert-icon-chip: var(--xm-alert-critical-chip);
78
+ }
79
+
80
+ /* ── Prominent / banner modifier (Story 4.6) ───────────────────────────
81
+ A high-importance, persistent layout. Changes PROMINENCE / LAYOUT ONLY:
82
+ wider full-width feel, larger padding, a left severity accent rail, and a
83
+ larger icon chip — while the body surface stays NEUTRAL and the per-severity
84
+ hue stays scoped to the icon chip + ink + the rail (the same --alert-icon-*
85
+ mechanism, the sole sanctioned severity-hue exception). No new severity
86
+ hues, no --md-sys-color-error*, no full-banner tint. The contract (severity
87
+ model, slots, events) is unchanged. */
88
+ .alert--prominent {
89
+ padding: var(--s-5) var(--s-5) var(--s-5) var(--s-6);
90
+ border-radius: var(--md-sys-shape-corner-large);
91
+ /* The left severity rail — a hairline-respecting accent band drawn from the
92
+ per-severity chip, scoped to the edge so the body reads neutral. 3px is a
93
+ decorative rail, not a border (borders stay hairline; 2px is focus/drag). */
94
+ border-left: 3px solid var(--alert-icon-chip);
95
+ column-gap: var(--s-4);
96
+ }
97
+ .alert--prominent .alert__icon {
98
+ width: 40px;
99
+ height: 40px;
100
+ align-self: start;
101
+ }
102
+ .alert--prominent .alert__heading {
103
+ font-size: var(--md-sys-typescale-body-large-size);
104
+ }
105
+ .alert--prominent .alert__text {
106
+ font-size: var(--md-sys-typescale-body-medium-size);
107
+ }
108
+ /* In the banner layout the action drops below the body so the message has the
109
+ full row width — a persistent banner reads as a block, not a one-liner. */
110
+ .alert--prominent .alert__action {
111
+ grid-column: 2 / 3;
112
+ grid-row: 2;
113
+ justify-content: flex-start;
114
+ margin-top: var(--s-1);
115
+ }
116
+
117
+ .alert__icon {
118
+ display: inline-flex;
119
+ align-items: center;
120
+ justify-content: center;
121
+ width: 32px;
122
+ height: 32px;
123
+ border-radius: var(--md-sys-shape-corner-small);
124
+ /* Per-severity tint chip behind the glyph — the ONLY hued region in
125
+ the alert. Sits on top of the neutral alert surface. */
126
+ background: color-mix(in oklab, var(--alert-icon-chip) 38%, transparent);
127
+ color: var(--alert-icon-ink);
128
+ flex-shrink: 0;
129
+ }
130
+
131
+ .alert__body {
132
+ min-width: 0;
133
+ display: flex;
134
+ flex-direction: column;
135
+ gap: var(--s-0-5);
136
+ }
137
+ .alert__heading {
138
+ font-size: var(--md-sys-typescale-body-medium-size);
139
+ font-weight: 600;
140
+ color: var(--alert-ink);
141
+ /* Heading wraps when narrow rather than truncating — alerts are read,
142
+ not glanced at like snackbars. */
143
+ text-wrap: pretty;
144
+ }
145
+ .alert__text {
146
+ font-size: var(--md-sys-typescale-body-medium-size);
147
+ line-height: 1.45;
148
+ color: var(--alert-ink-soft);
149
+ text-wrap: pretty;
150
+ }
151
+ .alert__text.is-empty { display: none; }
152
+ .alert__heading.is-empty { display: none; }
153
+
154
+ .alert__action {
155
+ display: inline-flex;
156
+ align-items: center;
157
+ flex-shrink: 0;
158
+ }
159
+ .alert__action.is-empty { display: none; }
160
+
161
+ .alert__close {
162
+ appearance: none;
163
+ border: none;
164
+ background: transparent;
165
+ color: var(--alert-ink-soft);
166
+ width: 28px;
167
+ height: 28px;
168
+ border-radius: var(--md-sys-shape-corner-small);
169
+ cursor: pointer;
170
+ display: inline-flex;
171
+ align-items: center;
172
+ justify-content: center;
173
+ transition:
174
+ background var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard),
175
+ color var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard);
176
+ flex-shrink: 0;
177
+ }
178
+ .alert__close:hover {
179
+ background: color-mix(in oklab, var(--alert-ink) 10%, transparent);
180
+ color: var(--alert-ink);
181
+ }
182
+ .alert__close:focus-visible {
183
+ outline: none;
184
+ box-shadow: var(--xm-state-focus-ring);
185
+ }
186
+
187
+ /* Compact: when the row gets narrow, drop the action below the body
188
+ so nothing wraps awkwardly. The dismiss stays inline. The 520px literal
189
+ mirrors --xm-breakpoint-sm (styles/_layout.css) — @media can't read the
190
+ token (docs/adr/0001), so the literal is the source-of-truth's echo. */
191
+ @media (max-width: 520px) {
192
+ .alert {
193
+ grid-template-columns: auto 1fr auto;
194
+ grid-template-rows: auto auto;
195
+ row-gap: var(--s-2);
196
+ }
197
+ .alert__action {
198
+ grid-column: 2 / -1;
199
+ justify-content: flex-end;
200
+ }
201
+ }
@@ -0,0 +1,25 @@
1
+ import { LitElement } from "lit";
2
+ import type { TemplateResult } from "lit";
3
+ type AlertSeverity = "info" | "success" | "warning" | "critical";
4
+ type AlertVariant = "inline" | "banner";
5
+ declare class XmAlert extends LitElement {
6
+ severity: AlertSeverity;
7
+ heading: string;
8
+ dismissible: boolean;
9
+ static: boolean;
10
+ prominent: boolean;
11
+ variant: AlertVariant;
12
+ private _hasBodyText;
13
+ private _hasAction;
14
+ render(): TemplateResult;
15
+ private _onDefaultSlot;
16
+ private _onActionSlot;
17
+ private _onActionClick;
18
+ private _onDismiss;
19
+ }
20
+ declare global {
21
+ interface HTMLElementTagNameMap {
22
+ "xm-alert": XmAlert;
23
+ }
24
+ }
25
+ export {};
@@ -0,0 +1,191 @@
1
+ /*
2
+ alert/index.ts — inline notification banner.
3
+
4
+ <xm-alert> — lightweight banner for notice / warning / success /
5
+ critical context. Sits inline in any content surface.
6
+
7
+ Authoring:
8
+ <xm-alert severity="warning" heading="Rate limit approaching" dismissible>
9
+ You've used 80% of your monthly quota.
10
+ <xm-button slot="action" variant="ghost" size="sm">View usage</xm-button>
11
+ </xm-alert>
12
+
13
+ Properties:
14
+ severity "info" | "success" | "warning" | "critical" (default "info")
15
+ heading short title string (sentence case)
16
+ dismissible boolean — render the trailing × close button
17
+ static boolean — preview-only, suppresses entry animation
18
+ prominent boolean — high-importance persistent BANNER layout. Changes
19
+ PROMINENCE / LAYOUT ONLY (full-width feel, larger padding, a
20
+ left severity accent rail, stacked action). It does NOT change
21
+ the severity model, add severities, rename slots/events, or
22
+ fork the API — the per-severity --xm-alert-* hue stays scoped
23
+ to the icon chip + ink exactly as the inline alert. `variant`
24
+ is an alias: variant="banner" === prominent.
25
+ variant "inline" | "banner" (default "inline"); "banner" === prominent
26
+
27
+ Slots:
28
+ default — body copy
29
+ action — single trailing control (typically <xm-button variant="ghost">)
30
+
31
+ Events:
32
+ alert-dismiss — fired when × is clicked
33
+ alert-action — fired when any element in the action slot fires click
34
+
35
+ Shadow DOM. Loads components/alert/index.css inside the shadow root via
36
+ <link> using the same path-resolution pattern as <xm-button>. Severity
37
+ is communicated by the icon glyph only — every variant uses the same
38
+ neutral surface and ink (POLICIES.md rule 3a forbids `--md-sys-color-error*`).
39
+ */
40
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
41
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
42
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
43
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
44
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
45
+ };
46
+ import { LitElement, html, svg, nothing } from "lit";
47
+ import { customElement, property } from "lit/decorators.js";
48
+ // Resolve CSS path relative to the *built* file location:
49
+ // `lit/build/components/alert/index.js` — 3 levels up reach `lit/`,
50
+ // then into `components/`. Mirrors button/index.ts.
51
+ const ALERT_CSS = new URL("../alert/index.css", import.meta.url).href;
52
+ const SHELL = (paths, size = 18, strokeWidth = 1.8) => svg `
53
+ <svg width="${size}" height="${size}" viewBox="0 0 24 24"
54
+ fill="none" stroke="currentColor" stroke-width="${strokeWidth}"
55
+ stroke-linecap="round" stroke-linejoin="round" class="ds-icon">
56
+ ${paths}
57
+ </svg>
58
+ `;
59
+ const SEVERITY_ICON = {
60
+ info: () => SHELL(svg `
61
+ <circle cx="12" cy="12" r="9" />
62
+ <path d="M12 11v5" />
63
+ <path d="M12 8h.01" />
64
+ `),
65
+ success: () => SHELL(svg `
66
+ <circle cx="12" cy="12" r="9" />
67
+ <polyline points="8.5 12.5 11 15 15.5 9.5" />
68
+ `),
69
+ warning: () => SHELL(svg `
70
+ <path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
71
+ <path d="M12 9v4" />
72
+ <path d="M12 17h.01" />
73
+ `, 18, 2),
74
+ critical: () => SHELL(svg `
75
+ <polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86" />
76
+ <path d="M9 9l6 6M15 9l-6 6" />
77
+ `, 18, 2),
78
+ };
79
+ const CLOSE_ICON = () => SHELL(svg `
80
+ <path d="M6 6l12 12M18 6L6 18" />
81
+ `, 14, 2);
82
+ const SEVERITY_LABEL = {
83
+ info: "Information",
84
+ success: "Success",
85
+ warning: "Warning",
86
+ critical: "Critical",
87
+ };
88
+ let XmAlert = class XmAlert extends LitElement {
89
+ constructor() {
90
+ super(...arguments);
91
+ this.severity = "info";
92
+ this.heading = "";
93
+ this.dismissible = false;
94
+ this.static = false;
95
+ this.prominent = false;
96
+ this.variant = "inline";
97
+ this._hasBodyText = true;
98
+ this._hasAction = false;
99
+ this._onDefaultSlot = (e) => {
100
+ const slot = e.target;
101
+ const nodes = slot.assignedNodes({ flatten: true });
102
+ const has = nodes.some((n) => {
103
+ if (n.nodeType === Node.TEXT_NODE)
104
+ return !!n.textContent?.trim();
105
+ if (n.nodeType === Node.ELEMENT_NODE)
106
+ return true;
107
+ return false;
108
+ });
109
+ if (has !== this._hasBodyText) {
110
+ this._hasBodyText = has;
111
+ this.requestUpdate();
112
+ }
113
+ };
114
+ this._onActionSlot = (e) => {
115
+ const slot = e.target;
116
+ const has = slot.assignedElements().length > 0;
117
+ if (has !== this._hasAction) {
118
+ this._hasAction = has;
119
+ this.requestUpdate();
120
+ }
121
+ };
122
+ this._onActionClick = () => {
123
+ this.dispatchEvent(new CustomEvent("alert-action", { bubbles: true, composed: true }));
124
+ };
125
+ this._onDismiss = () => {
126
+ this.dispatchEvent(new CustomEvent("alert-dismiss", { bubbles: true, composed: true }));
127
+ };
128
+ }
129
+ render() {
130
+ const sev = this.severity === "success" || this.severity === "warning" || this.severity === "critical"
131
+ ? this.severity
132
+ : "info";
133
+ const isProminent = this.prominent || this.variant === "banner";
134
+ const cls = `alert alert--${sev}${this.static ? " alert--static" : ""}${isProminent ? " alert--prominent" : ""}`;
135
+ return html `
136
+ <link rel="stylesheet" href="${ALERT_CSS}">
137
+ <style>
138
+ :host { display: block; }
139
+ :host([hidden]) { display: none; }
140
+ </style>
141
+ <div
142
+ class="${cls}"
143
+ role="${sev === "critical" || sev === "warning" ? "alert" : "status"}"
144
+ aria-label="${SEVERITY_LABEL[sev]}"
145
+ >
146
+ <span class="alert__icon" aria-hidden="true">${SEVERITY_ICON[sev]()}</span>
147
+ <div class="alert__body">
148
+ <span class="alert__heading ${this.heading ? "" : "is-empty"}">${this.heading}</span>
149
+ <span class="alert__text ${this._hasBodyText ? "" : "is-empty"}"
150
+ ><slot @slotchange=${this._onDefaultSlot}></slot></span>
151
+ </div>
152
+ <span class="alert__action ${this._hasAction ? "" : "is-empty"}"
153
+ ><slot
154
+ name="action"
155
+ @slotchange=${this._onActionSlot}
156
+ @click=${this._onActionClick}
157
+ ></slot></span>
158
+ ${this.dismissible
159
+ ? html `
160
+ <button
161
+ type="button"
162
+ class="alert__close"
163
+ aria-label="Dismiss"
164
+ @click=${this._onDismiss}
165
+ >${CLOSE_ICON()}</button>`
166
+ : nothing}
167
+ </div>
168
+ `;
169
+ }
170
+ };
171
+ __decorate([
172
+ property({ type: String })
173
+ ], XmAlert.prototype, "severity", void 0);
174
+ __decorate([
175
+ property({ type: String })
176
+ ], XmAlert.prototype, "heading", void 0);
177
+ __decorate([
178
+ property({ type: Boolean })
179
+ ], XmAlert.prototype, "dismissible", void 0);
180
+ __decorate([
181
+ property({ type: Boolean })
182
+ ], XmAlert.prototype, "static", void 0);
183
+ __decorate([
184
+ property({ type: Boolean })
185
+ ], XmAlert.prototype, "prominent", void 0);
186
+ __decorate([
187
+ property({ type: String })
188
+ ], XmAlert.prototype, "variant", void 0);
189
+ XmAlert = __decorate([
190
+ customElement("xm-alert")
191
+ ], XmAlert);
@@ -0,0 +1,80 @@
1
+ /* ============================================
2
+ <xm-app-bar> — screen header on the desk surface.
3
+
4
+ Surface / ink (AD-13): the app bar belongs to the DESK family —
5
+ background var(--md-sys-color-surface), title ink var(--md-sys-color-on-surface),
6
+ secondary var(--md-sys-color-on-surface-variant). NOT the inverse-surface ink
7
+ used by cards / drawers.
8
+
9
+ Hairline: a single 1px bottom border (--md-sys-color-outline-variant).
10
+ Never 2px.
11
+
12
+ BEM: block `app-bar`; elements `__leading` `__title` `__action`;
13
+ modifiers `--xs|--sm|--md|--lg`. Sticky is driven from :host([sticky]).
14
+ ============================================ */
15
+
16
+ .app-bar {
17
+ display: flex;
18
+ align-items: center;
19
+ gap: var(--s-3);
20
+ box-sizing: border-box;
21
+ width: 100%;
22
+ padding: 0 var(--s-4);
23
+ background: var(--md-sys-color-surface);
24
+ color: var(--md-sys-color-on-surface);
25
+ border-bottom: 1px solid var(--md-sys-color-outline-variant);
26
+ }
27
+
28
+ /* ---------- Sizes — one shared bar height per size ---------- */
29
+ .app-bar--xs { min-height: 40px; }
30
+ .app-bar--sm { min-height: 48px; }
31
+ .app-bar--md { min-height: 56px; }
32
+ .app-bar--lg { min-height: 64px; }
33
+
34
+ /* ---------- Leading ---------- */
35
+ .app-bar__leading {
36
+ display: inline-flex;
37
+ align-items: center;
38
+ gap: var(--s-2);
39
+ flex-shrink: 0;
40
+ }
41
+ .app-bar__leading.is-empty {
42
+ display: none;
43
+ }
44
+
45
+ /* ---------- Title ---------- */
46
+ .app-bar__title {
47
+ flex: 1 1 auto;
48
+ min-width: 0;
49
+ display: flex;
50
+ align-items: center;
51
+ gap: var(--s-2);
52
+ font-family: var(--md-sys-typescale-title-medium-font);
53
+ font-size: var(--md-sys-typescale-title-medium-size);
54
+ line-height: var(--md-sys-typescale-title-medium-line-height);
55
+ font-weight: var(--md-sys-typescale-title-medium-weight);
56
+ letter-spacing: var(--md-sys-typescale-title-medium-tracking);
57
+ color: var(--md-sys-color-on-surface);
58
+ overflow: hidden;
59
+ white-space: nowrap;
60
+ text-overflow: ellipsis;
61
+ }
62
+
63
+ /* ---------- Action (singular trailing region) ---------- */
64
+ .app-bar__action {
65
+ display: inline-flex;
66
+ align-items: center;
67
+ gap: var(--s-2);
68
+ flex-shrink: 0;
69
+ margin-inline-start: auto;
70
+ }
71
+ .app-bar__action.is-empty {
72
+ display: none;
73
+ }
74
+
75
+ /* ---------- Sticky ---------- */
76
+ :host([sticky]) .app-bar {
77
+ position: sticky;
78
+ top: 0;
79
+ z-index: 1;
80
+ }
@@ -0,0 +1,19 @@
1
+ import { LitElement } from "lit";
2
+ import type { TemplateResult } from "lit";
3
+ type AppBarSize = "xs" | "sm" | "md" | "lg";
4
+ declare class XmAppBar extends LitElement {
5
+ size: AppBarSize;
6
+ sticky: boolean;
7
+ private _mo;
8
+ render(): TemplateResult;
9
+ private _slotEmpty;
10
+ private _onSlot;
11
+ connectedCallback(): void;
12
+ disconnectedCallback(): void;
13
+ }
14
+ declare global {
15
+ interface HTMLElementTagNameMap {
16
+ "xm-app-bar": XmAppBar;
17
+ }
18
+ }
19
+ export {};
@@ -0,0 +1,120 @@
1
+ /*
2
+ app-bar/index.ts — <xm-app-bar>, the screen header.
3
+
4
+ <xm-app-bar> — a top bar with leading, title, and trailing-action regions.
5
+ Belongs to the DESK surface family (surface*), unlike the card / drawer
6
+ (inverse-surface). Title ink is on-surface — a mismatched inverse ink is a
7
+ dark-on-dark bug one theme hides (AD-13).
8
+
9
+ Authoring:
10
+ <xm-app-bar size="md" sticky>
11
+ <xm-button slot="leading" variant="ghost" icon-only>…</xm-button>
12
+ Routing pipeline
13
+ <xm-button slot="action" variant="ghost" size="sm">Share</xm-button>
14
+ <xm-button slot="action" variant="primary" size="sm">Run</xm-button>
15
+ </xm-app-bar>
16
+
17
+ Properties:
18
+ size "xs" | "sm" | "md" | "lg" (default "md") — shared bar height
19
+ sticky boolean (reflected) — position: sticky; top: 0
20
+
21
+ Slots:
22
+ leading leading region (menu toggle / brand)
23
+ default title (sentence case; tech identifiers stay caps)
24
+ action SINGULAR trailing-action region (multiple buttons as children)
25
+
26
+ Shadow DOM; Lit from lit; sibling CSS via the
27
+ built-file-relative new URL(...). BEM block `app-bar`.
28
+ */
29
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
30
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
31
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
32
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
33
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
34
+ };
35
+ import { LitElement, html } from "lit";
36
+ import { customElement, property } from "lit/decorators.js";
37
+ // Resolve CSS relative to the *built* file:
38
+ // lit/build/components/app-bar/index.js → ../app-bar/index.css.
39
+ const APP_BAR_CSS = new URL("../app-bar/index.css", import.meta.url).href;
40
+ let XmAppBar = class XmAppBar extends LitElement {
41
+ constructor() {
42
+ super(...arguments);
43
+ this.size = "md";
44
+ this.sticky = false;
45
+ this._mo = null;
46
+ this._onSlot = () => {
47
+ this.requestUpdate();
48
+ };
49
+ }
50
+ render() {
51
+ const size = ["xs", "sm", "md", "lg"].includes(this.size)
52
+ ? this.size
53
+ : "md";
54
+ const leadingEmpty = this._slotEmpty("leading");
55
+ const actionEmpty = this._slotEmpty("action");
56
+ return html `
57
+ <link rel="stylesheet" href="${APP_BAR_CSS}" />
58
+ <style>
59
+ :host {
60
+ display: block;
61
+ }
62
+ :host([hidden]) {
63
+ display: none;
64
+ }
65
+ </style>
66
+ <header class="app-bar app-bar--${size}">
67
+ <div class="app-bar__leading ${leadingEmpty ? "is-empty" : ""}">
68
+ <slot name="leading" @slotchange=${this._onSlot}></slot>
69
+ </div>
70
+ <div class="app-bar__title">
71
+ <slot @slotchange=${this._onSlot}></slot>
72
+ </div>
73
+ <div class="app-bar__action ${actionEmpty ? "is-empty" : ""}">
74
+ <slot name="action" @slotchange=${this._onSlot}></slot>
75
+ </div>
76
+ </header>
77
+ `;
78
+ }
79
+ _slotEmpty(name) {
80
+ for (const node of this.childNodes) {
81
+ if (node.nodeType === Node.ELEMENT_NODE) {
82
+ const slotName = node.getAttribute("slot");
83
+ const target = name || null;
84
+ const matches = (target === null && !slotName) || slotName === target;
85
+ if (matches)
86
+ return false;
87
+ }
88
+ else if (node.nodeType === Node.TEXT_NODE && !name) {
89
+ if (node.textContent?.trim())
90
+ return false;
91
+ }
92
+ }
93
+ return true;
94
+ }
95
+ connectedCallback() {
96
+ super.connectedCallback();
97
+ if (!this._mo) {
98
+ this._mo = new MutationObserver(() => this.requestUpdate());
99
+ this._mo.observe(this, {
100
+ childList: true,
101
+ characterData: true,
102
+ subtree: true,
103
+ });
104
+ }
105
+ }
106
+ disconnectedCallback() {
107
+ super.disconnectedCallback();
108
+ this._mo?.disconnect();
109
+ this._mo = null;
110
+ }
111
+ };
112
+ __decorate([
113
+ property({ type: String })
114
+ ], XmAppBar.prototype, "size", void 0);
115
+ __decorate([
116
+ property({ type: Boolean, reflect: true })
117
+ ], XmAppBar.prototype, "sticky", void 0);
118
+ XmAppBar = __decorate([
119
+ customElement("xm-app-bar")
120
+ ], XmAppBar);