@xenide-io/the-old-ui-theme 0.7.0 → 0.9.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 (109) hide show
  1. package/README.md +9 -10
  2. package/dist/{Chip-Cq3AiAji.d.mts → Chip-BzuNgJIa.d.mts} +81 -23
  3. package/dist/{Chip-Cq3AiAji.d.ts → Chip-BzuNgJIa.d.ts} +81 -23
  4. package/dist/{ai-message-blocknote-WABTHFY7.mjs → ai-message-blocknote-D4Z6DUCJ.mjs} +9 -3
  5. package/dist/chunk-2EO5VCXP.mjs +3912 -0
  6. package/dist/chunk-APKRZQRO.mjs +251 -0
  7. package/dist/chunk-BS7BZI5W.mjs +19 -0
  8. package/dist/chunk-IULORI3A.mjs +8 -0
  9. package/dist/index.d.mts +3 -3
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.js +997 -576
  12. package/dist/index.mjs +49 -45
  13. package/dist/suite.d.mts +157 -55
  14. package/dist/suite.d.ts +157 -55
  15. package/dist/suite.js +4249 -801
  16. package/dist/suite.mjs +2578 -594
  17. package/dist/theme-boot-P-oqKVZF.d.mts +74 -0
  18. package/dist/theme-boot-P-oqKVZF.d.ts +74 -0
  19. package/dist/theme-boot.d.mts +2 -0
  20. package/dist/theme-boot.d.ts +2 -0
  21. package/dist/theme-boot.js +44 -0
  22. package/dist/theme-boot.mjs +8 -0
  23. package/dist/ui.d.mts +5 -29
  24. package/dist/ui.d.ts +5 -29
  25. package/dist/ui.js +647 -352
  26. package/dist/ui.mjs +10 -12
  27. package/docs/README.md +34 -0
  28. package/docs/ai-quick-reference.md +56 -0
  29. package/docs/component-library-improvement-plan.md +751 -0
  30. package/docs/component-reference.md +81 -0
  31. package/docs/components.md +48 -0
  32. package/docs/demos.md +19 -0
  33. package/docs/installation.md +117 -0
  34. package/docs/suite-audit.md +34 -0
  35. package/docs/theme-token-reference.md +67 -0
  36. package/docs/themes.md +164 -0
  37. package/package.json +22 -21
  38. package/public/fonts/OpenRunde-Bold.woff2 +0 -0
  39. package/public/fonts/OpenRunde-Medium.woff2 +0 -0
  40. package/public/fonts/OpenRunde-Regular.woff2 +0 -0
  41. package/public/fonts/OpenRunde-Semibold.woff2 +0 -0
  42. package/scripts/package-smoke.mjs +43 -0
  43. package/src/app/globals.css +2 -1
  44. package/src/components/ui/Accordion.tsx +20 -6
  45. package/src/components/ui/Avatar.tsx +5 -3
  46. package/src/components/ui/Calendar.tsx +187 -63
  47. package/src/components/ui/Card.test.tsx +38 -0
  48. package/src/components/ui/Card.tsx +77 -14
  49. package/src/components/ui/CollapsibleSection.tsx +12 -4
  50. package/src/components/ui/CommandPalette.test.tsx +91 -4
  51. package/src/components/ui/CommandPalette.tsx +138 -128
  52. package/src/components/ui/EmptyState.tsx +2 -2
  53. package/src/components/ui/FormField.tsx +1 -1
  54. package/src/components/ui/Input.tsx +42 -18
  55. package/src/components/ui/Kbd.tsx +18 -3
  56. package/src/components/ui/Modal.tsx +3 -1
  57. package/src/components/ui/Progress.tsx +14 -5
  58. package/src/components/ui/SegmentedControl.tsx +2 -2
  59. package/src/components/ui/SettingsLayout.tsx +1 -1
  60. package/src/components/ui/Stat.tsx +3 -2
  61. package/src/components/ui/Table.tsx +8 -3
  62. package/src/components/ui/Tooltip.test.tsx +70 -1
  63. package/src/components/ui/Tooltip.tsx +53 -29
  64. package/src/components/ui/Typography.tsx +103 -49
  65. package/src/components/ui/avatar-stat.test.tsx +23 -0
  66. package/src/components/ui/calendar.test.tsx +88 -0
  67. package/src/components/ui/disclosure.test.tsx +39 -0
  68. package/src/components/ui/index.ts +44 -6
  69. package/src/components/ui/progress.test.tsx +15 -0
  70. package/src/components/ui/typography.test.tsx +26 -1
  71. package/src/styles/suite-skin.css +8 -2
  72. package/src/styles/themes.css +184 -68
  73. package/src/suite/components/ai-message-blocknote.tsx +13 -2
  74. package/src/suite/components/ai-panel.tsx +41 -10
  75. package/src/suite/components/app-switcher.test.tsx +21 -6
  76. package/src/suite/components/app-switcher.tsx +7 -11
  77. package/src/suite/components/suite-app-layout.tsx +12 -3
  78. package/src/suite/components/suite-bottom-nav.tsx +0 -1
  79. package/src/suite/components/suite-clients-projects-directory.test.tsx +71 -0
  80. package/src/suite/components/suite-clients-projects-directory.tsx +943 -0
  81. package/src/suite/components/suite-integration-picker.test.tsx +224 -0
  82. package/src/suite/components/suite-integration-picker.tsx +939 -0
  83. package/src/suite/components/suite-integration-rules.test.tsx +157 -0
  84. package/src/suite/components/suite-integration-rules.tsx +471 -0
  85. package/src/suite/components/suite-mobile-drawer.test.tsx +18 -2
  86. package/src/suite/components/suite-mobile-drawer.tsx +65 -98
  87. package/src/suite/components/suite-notification-bell.tsx +29 -4
  88. package/src/suite/components/suite-sidebar.tsx +25 -25
  89. package/src/suite/components/suite-skeleton.tsx +2 -2
  90. package/src/suite/components/suite-user-menu.tsx +9 -8
  91. package/src/suite/components/theme-provider.test.tsx +87 -3
  92. package/src/suite/components/theme-provider.tsx +144 -23
  93. package/src/suite/components/today-ui.tsx +79 -68
  94. package/src/suite/components/workspace-switcher.test.tsx +56 -0
  95. package/src/suite/components/workspace-switcher.tsx +3 -3
  96. package/src/suite/icons/app-accents.ts +12 -12
  97. package/src/suite/icons/glyphs.ts +6 -12
  98. package/src/suite/index.ts +27 -0
  99. package/src/suite/lib/apps.test.ts +9 -1
  100. package/src/suite/lib/apps.ts +14 -8
  101. package/src/suite/lib/cookies.ts +53 -0
  102. package/src/suite/lib/theme-boot.ts +32 -0
  103. package/src/suite/lib/theme-cookie.ts +7 -0
  104. package/src/suite/lib/use-sidebar-width.ts +5 -51
  105. package/dist/chunk-KDR6HI6F.mjs +0 -1075
  106. package/dist/chunk-NOI42JNZ.mjs +0 -151
  107. package/dist/chunk-VXISSXTB.mjs +0 -2564
  108. package/src/suite/lib/use-lock-mobile-page-zoom.test.tsx +0 -65
  109. package/src/suite/lib/use-lock-mobile-page-zoom.ts +0 -51
@@ -0,0 +1,39 @@
1
+ import { fireEvent, render, screen } from "@testing-library/react";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import { Accordion } from "./Accordion";
5
+ import { CollapsibleSection } from "./CollapsibleSection";
6
+
7
+ describe("disclosure components", () => {
8
+ it("keeps closed accordion content out of keyboard navigation", () => {
9
+ render(
10
+ <Accordion
11
+ items={[{ id: "details", title: "Details", content: <a href="/more">More</a> }]}
12
+ />,
13
+ );
14
+
15
+ const trigger = screen.getByRole("button", { name: "Details" });
16
+ const content = document.getElementById(trigger.getAttribute("aria-controls")!);
17
+ expect(trigger).toHaveAttribute("aria-expanded", "false");
18
+ expect(content).toHaveAttribute("aria-hidden", "true");
19
+ expect(content).toHaveAttribute("inert");
20
+
21
+ fireEvent.click(trigger);
22
+ expect(trigger).toHaveAttribute("aria-expanded", "true");
23
+ expect(content).toHaveAttribute("aria-hidden", "false");
24
+ expect(content).not.toHaveAttribute("inert");
25
+ });
26
+
27
+ it("keeps closed collapsible content out of keyboard navigation", () => {
28
+ render(
29
+ <CollapsibleSection title="Tokens" defaultOpen={false}>
30
+ <button type="button">Copy token</button>
31
+ </CollapsibleSection>,
32
+ );
33
+
34
+ const trigger = screen.getByRole("button", { name: "Tokens" });
35
+ const content = document.getElementById(trigger.getAttribute("aria-controls")!);
36
+ expect(content).toHaveAttribute("aria-hidden", "true");
37
+ expect(content).toHaveAttribute("inert");
38
+ });
39
+ });
@@ -143,10 +143,25 @@ export {
143
143
  type IconProps as IconProps,
144
144
  type IconName as IconName,
145
145
  } from "@/components/icons";
146
- export { Accordion } from "@/components/ui/Accordion";
147
- export { SegmentedControl } from "@/components/ui/SegmentedControl";
148
- export { CommandPalette } from "@/components/ui/CommandPalette";
149
- export { Calendar } from "@/components/ui/Calendar";
146
+ export {
147
+ Accordion,
148
+ type AccordionItem,
149
+ type AccordionProps,
150
+ } from "@/components/ui/Accordion";
151
+ export {
152
+ SegmentedControl,
153
+ type SegmentedControlOption,
154
+ type SegmentedControlProps,
155
+ } from "@/components/ui/SegmentedControl";
156
+ export {
157
+ CommandPalette,
158
+ type CommandItem,
159
+ type CommandPaletteProps,
160
+ } from "@/components/ui/CommandPalette";
161
+ export {
162
+ Calendar,
163
+ type CalendarProps,
164
+ } from "@/components/ui/Calendar";
150
165
  export {
151
166
  Tooltip,
152
167
  TooltipProvider,
@@ -155,7 +170,10 @@ export {
155
170
  type TooltipProviderProps,
156
171
  type TooltipSide,
157
172
  } from "@/components/ui/Tooltip";
158
- export { EmptyState } from "@/components/ui/EmptyState";
173
+ export {
174
+ EmptyState,
175
+ type EmptyStateProps,
176
+ } from "@/components/ui/EmptyState";
159
177
  export {
160
178
  FilterChips,
161
179
  type FilterChip,
@@ -181,7 +199,10 @@ export {
181
199
  type ComponentPropRow,
182
200
  } from "@/components/ui/ComponentDocs";
183
201
  export { ShowcaseWrapper } from "@/components/ui/ShowcaseWrapper";
184
- export { CollapsibleSection } from "@/components/ui/CollapsibleSection";
202
+ export {
203
+ CollapsibleSection,
204
+ type CollapsibleSectionProps,
205
+ } from "@/components/ui/CollapsibleSection";
185
206
  export {
186
207
  Display,
187
208
  SectionTitle,
@@ -197,6 +218,23 @@ export {
197
218
  Lead,
198
219
  Mono,
199
220
  Label,
221
+ type CaptionProps,
222
+ type DisplayProps,
223
+ type H1Props,
224
+ type H2Props,
225
+ type H3Props,
226
+ type H4Props,
227
+ type H5Props,
228
+ type LabelProps,
229
+ type LeadProps,
230
+ type MonoProps,
231
+ type OverlineProps,
232
+ type PProps,
233
+ type SectionTitleProps,
234
+ type SmallProps,
235
+ type TextBaseProps,
236
+ type TextTone,
237
+ type TextWeight,
200
238
  } from "@/components/ui/Typography";
201
239
  export {
202
240
  Avatar as Avatar,
@@ -0,0 +1,15 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import { Progress } from "./Progress";
5
+
6
+ describe("Progress", () => {
7
+ it("normalises invalid ranges and associates its visible label", () => {
8
+ render(<Progress label="Upload" value={200} max={0} showPercentage />);
9
+
10
+ const progressbar = screen.getByRole("progressbar", { name: "Upload" });
11
+ expect(progressbar).toHaveAttribute("aria-valuenow", "100");
12
+ expect(progressbar).toHaveAttribute("aria-valuemax", "100");
13
+ expect(progressbar).toHaveStyle({ width: "100%" });
14
+ });
15
+ });
@@ -1,6 +1,7 @@
1
+ import { createRef } from "react";
1
2
  import { render, screen } from "@testing-library/react";
2
3
  import { describe, expect, it } from "vitest";
3
- import { Display, Lead, H1, SectionTitle } from "@/components/ui/Typography";
4
+ import { Display, Label, Lead, H1, SectionTitle } from "@/components/ui/Typography";
4
5
 
5
6
  describe("typography scale", () => {
6
7
  it("puts marketing headings on the fluid classes", () => {
@@ -24,4 +25,28 @@ describe("typography scale", () => {
24
25
  expect(heading).not.toHaveClass("ph-hero-title");
25
26
  expect(heading.className).toContain("font-bold");
26
27
  });
28
+
29
+ it("forwards native props and refs to its semantic elements", () => {
30
+ const headingRef = createRef<HTMLHeadingElement>();
31
+ const labelRef = createRef<HTMLLabelElement>();
32
+
33
+ render(
34
+ <>
35
+ <H1 ref={headingRef} id="reports-title" aria-describedby="reports-help">
36
+ Native report heading
37
+ </H1>
38
+ <Label ref={labelRef} htmlFor="report-name">
39
+ Report name
40
+ </Label>
41
+ <input id="report-name" />
42
+ </>,
43
+ );
44
+
45
+ const heading = screen.getByRole("heading", { name: "Native report heading" });
46
+ const label = screen.getByText("Report name");
47
+ expect(heading).toHaveAttribute("aria-describedby", "reports-help");
48
+ expect(label).toHaveAttribute("for", "report-name");
49
+ expect(headingRef.current).toBe(heading);
50
+ expect(labelRef.current).toBe(label);
51
+ });
27
52
  });
@@ -224,7 +224,7 @@ html.dark .today-page-frame__cloud--2 {
224
224
 
225
225
  /* Today primary action — compact geometry, colour supplied by the app theme. */
226
226
  .today-primary-action {
227
- color: var(--ph-ink);
227
+ color: var(--ph-text-primary);
228
228
  background: color-mix(in oklab, var(--ph-brand) 12%, var(--ph-surface));
229
229
  border: 1px solid color-mix(in oklab, var(--ph-brand) 28%, var(--ph-border));
230
230
  box-shadow: 0 1px 0 color-mix(in oklab, var(--ph-brand) 8%, transparent);
@@ -269,7 +269,7 @@ html.dark .today-page-frame__cloud--2 {
269
269
  color: var(--ph-violet, var(--ph-brand));
270
270
  }
271
271
  .today-primary-action--shellstack {
272
- background: color-mix(in oklab, var(--ph-ink) 6%, var(--ph-surface));
272
+ background: color-mix(in oklab, var(--ph-text-primary) 6%, var(--ph-surface));
273
273
  }
274
274
  .today-primary-action--active .today-primary-action__icon {
275
275
  background: var(--ph-brand);
@@ -492,6 +492,12 @@ button:hover > .ph-card {
492
492
  transition-duration: 80ms;
493
493
  }
494
494
 
495
+ /* Radix focuses the first menu item on open. The menu's highlighted state is
496
+ sufficient feedback, so do not retain an app-wide focus ring on that row. */
497
+ #app-switcher-menu .ph-dropdown-item:focus-visible {
498
+ box-shadow: none;
499
+ }
500
+
495
501
  /* ── App bar (mobile) / top bar (desktop) ───────────────────────────────
496
502
  Translucent, blurred, content scrolls beneath — like every native
497
503
  shell. Colour-mix keeps it on-theme in both modes. */
@@ -16,9 +16,9 @@
16
16
 
17
17
  --ph-text-primary: hsl(0 0% 5%);
18
18
  --ph-text-secondary: hsl(0 0% 25%);
19
- --ph-text-tertiary: hsl(0 0% 42%);
19
+ --ph-text-tertiary: hsl(0 0% 40%);
20
20
 
21
- --ph-accent: hsl(19deg 100% 48%);
21
+ --ph-accent: hsl(19deg 100% 39%);
22
22
  --ph-accent-hover: hsl(19deg 100% 42%);
23
23
  --ph-blue: hsl(228deg 100% 56%);
24
24
  --ph-violet: hsl(277deg 70% 48%);
@@ -29,6 +29,10 @@
29
29
  --ph-danger: hsl(9deg 70% 48%);
30
30
  --ph-info: hsl(217deg 90% 52%);
31
31
 
32
+ /* Legacy 3000-series tokens (--ph-text-3000, --ph-border-3000, …) are
33
+ superseded by the semantic --ph-text-*, --ph-border-*, and button tokens
34
+ above. Kept only so older custom themes keep working; do not use them in
35
+ new themes or components. */
32
36
  --ph-text-3000: #111111;
33
37
  --ph-primary-button-face: #ffffff;
34
38
  --ph-primary-button-border: #b17816;
@@ -68,7 +72,7 @@
68
72
  --ph-surface-raised: #ffffff;
69
73
  --ph-surface-overlay: #ffffff;
70
74
  --ph-border-subtle: hsl(75 14% 90%);
71
- --ph-on-accent: #211108;
75
+ --ph-on-accent: #ffffff;
72
76
  --ph-on-violet: #ffffff;
73
77
  --ph-on-success: #071b10;
74
78
  --ph-on-warning: #1c1504;
@@ -83,54 +87,55 @@
83
87
  [data-theme="hedgehog-dark"] {
84
88
  color-scheme: dark;
85
89
 
86
- --ph-canvas: hsl(220 12% 9%);
87
- --ph-surface: hsl(220 10% 13%);
88
- --ph-muted: hsl(220 9% 16%);
89
- --ph-toolbar: hsl(220 8% 19%);
90
- --ph-surface-inset: hsl(220 12% 10%);
91
- --ph-surface-raised: hsl(220 9% 16%);
92
- --ph-surface-overlay: hsl(220 8% 18%);
93
- --ph-border: hsl(220 7% 24%);
94
- --ph-border-subtle: hsl(220 8% 19%);
95
- --ph-border-strong: hsl(220 6% 38%);
96
-
97
- --ph-text-primary: hsl(0 0% 96%);
98
- --ph-text-secondary: hsl(0 0% 78%);
99
- --ph-text-tertiary: hsl(0 0% 58%);
100
-
101
- --ph-accent: hsl(19deg 100% 52%);
102
- --ph-accent-hover: hsl(19deg 100% 58%);
103
- --ph-blue: hsl(228deg 100% 68%);
104
- --ph-violet: hsl(277deg 65% 62%);
105
- --ph-purple: #a89af0;
106
-
107
- --ph-success: hsl(149deg 55% 48%);
108
- --ph-warning: hsl(43deg 85% 52%);
109
- --ph-danger: hsl(9deg 65% 55%);
110
- --ph-info: hsl(217deg 85% 58%);
111
- --ph-on-accent: hsl(220 14% 8%);
112
- --ph-on-violet: hsl(220 14% 8%);
113
- --ph-on-success: hsl(220 14% 8%);
114
- --ph-on-warning: hsl(220 14% 8%);
115
- --ph-on-danger: hsl(220 14% 8%);
116
- --ph-on-info: hsl(220 14% 8%);
117
- --ph-focus-ring: hsl(217deg 95% 72%);
118
- --ph-selected-bg: hsl(19deg 70% 18%);
119
- --ph-selected-text: hsl(19deg 100% 72%);
120
- --ph-selected-border: hsl(19deg 90% 55%);
121
-
122
- --ph-text-3000: hsl(0 0% 96%);
123
- --ph-primary-button-face: hsl(220 10% 15%);
124
- --ph-primary-button-border: #c4861f;
125
- --ph-primary-button-border-hover: #eb9d2a;
126
- --ph-primary-frame-bg: #eb9d2a;
127
- --ph-secondary-button-bg: hsl(220 8% 20%);
128
- --ph-secondary-frame-bg: hsl(220 7% 26%);
129
- --ph-secondary-button-border: hsl(220 6% 32%);
130
- --ph-secondary-button-border-hover: hsl(220 5% 42%);
90
+ /* Microsoft Copilot-style dark UI: neutral graphite surfaces, blue accent. */
91
+ --ph-canvas: hsl(240 7% 6%);
92
+ --ph-surface: hsl(240 6% 10%);
93
+ --ph-muted: hsl(240 5% 13%);
94
+ --ph-toolbar: hsl(240 5% 15%);
95
+ --ph-surface-inset: hsl(240 7% 7%);
96
+ --ph-surface-raised: hsl(240 5% 13%);
97
+ --ph-surface-overlay: hsl(240 5% 14%);
98
+ --ph-border: hsl(240 5% 21%);
99
+ --ph-border-subtle: hsl(240 5% 15%);
100
+ --ph-border-strong: hsl(240 4% 36%);
101
+
102
+ --ph-text-primary: hsl(240 8% 94%);
103
+ --ph-text-secondary: hsl(240 5% 78%);
104
+ --ph-text-tertiary: hsl(240 4% 58%);
105
+
106
+ --ph-accent: #0084e8;
107
+ --ph-accent-hover: #106ebe;
108
+ --ph-blue: #00bcf2;
109
+ --ph-violet: #b146c2;
110
+ --ph-purple: #b146c2;
131
111
 
132
- --ph-border-3000: hsl(220 7% 20%);
133
- --ph-accent-highlight-secondary: hsl(19deg 100% 52% / 14%);
112
+ --ph-success: #6bb700;
113
+ --ph-warning: #ffb900;
114
+ --ph-danger: #d13438;
115
+ --ph-info: #00bcf2;
116
+ --ph-on-accent: #111111;
117
+ --ph-on-violet: #ffffff;
118
+ --ph-on-success: #111114;
119
+ --ph-on-warning: #111114;
120
+ --ph-on-danger: #ffffff;
121
+ --ph-on-info: #111114;
122
+ --ph-focus-ring: #4ca3f5;
123
+ --ph-selected-bg: #0078d426;
124
+ --ph-selected-text: #4ca3f5;
125
+ --ph-selected-border: #0078d4;
126
+
127
+ --ph-text-3000: hsl(240 8% 94%);
128
+ --ph-primary-button-face: #0078d4;
129
+ --ph-primary-button-border: #0078d4;
130
+ --ph-primary-button-border-hover: #106ebe;
131
+ --ph-primary-frame-bg: #0078d4;
132
+ --ph-secondary-button-bg: hsl(240 5% 15%);
133
+ --ph-secondary-frame-bg: hsl(240 5% 18%);
134
+ --ph-secondary-button-border: hsl(240 4% 30%);
135
+ --ph-secondary-button-border-hover: hsl(240 4% 40%);
136
+
137
+ --ph-border-3000: hsl(240 5% 18%);
138
+ --ph-accent-highlight-secondary: #0078d424;
134
139
  }
135
140
 
136
141
  /* OneNote — brand purple #7719aa on lavender paper. */
@@ -144,7 +149,7 @@
144
149
  --ph-border-strong: #9b7bb8;
145
150
  --ph-text-primary: #2d1b3d;
146
151
  --ph-text-secondary: #5c4a6e;
147
- --ph-text-tertiary: #857396;
152
+ --ph-text-tertiary: #716080;
148
153
  --ph-accent: #7719aa;
149
154
  --ph-accent-hover: #5f1488;
150
155
  --ph-blue: #185abd;
@@ -238,7 +243,7 @@
238
243
  --ph-border-strong: hsl(69 8% 65%);
239
244
  --ph-text-primary: hsl(0 0% 5%);
240
245
  --ph-text-secondary: hsl(0 0% 25%);
241
- --ph-text-tertiary: hsl(0 0% 42%);
246
+ --ph-text-tertiary: hsl(0 0% 40%);
242
247
  --ph-accent: #1f6f43;
243
248
  --ph-accent-hover: #185c37;
244
249
  --ph-blue: #2f7f73;
@@ -282,7 +287,7 @@
282
287
  --ph-text-primary: #eef4e9;
283
288
  --ph-text-secondary: #c7d5c0;
284
289
  --ph-text-tertiary: #91a28a;
285
- --ph-accent: #3f8f57;
290
+ --ph-accent: #419359;
286
291
  --ph-accent-hover: #55a96b;
287
292
  --ph-blue: #57b3a3;
288
293
  --ph-violet: #d4861a;
@@ -291,7 +296,7 @@
291
296
  --ph-warning: #e58a12;
292
297
  --ph-danger: #e06a49;
293
298
  --ph-info: #57b3a3;
294
- --ph-on-accent: #eef4e9;
299
+ --ph-on-accent: #111111;
295
300
  --ph-on-violet: #151b17;
296
301
  --ph-on-success: #071b10;
297
302
  --ph-on-warning: #211606;
@@ -330,9 +335,9 @@
330
335
  --ph-border: #dfdad9;
331
336
  --ph-border-strong: #9893a5;
332
337
  --ph-text-primary: #575279;
333
- --ph-text-secondary: #797593;
334
- --ph-text-tertiary: #9893a5;
335
- --ph-accent: #907aa9;
338
+ --ph-text-secondary: #6a6683;
339
+ --ph-text-tertiary: #6c667b;
340
+ --ph-accent: #7e649b;
336
341
  --ph-accent-hover: #7c6594;
337
342
  --ph-blue: #56949f;
338
343
  --ph-violet: #907aa9;
@@ -384,7 +389,7 @@
384
389
  --ph-border-strong: #524f67;
385
390
  --ph-text-primary: #e0def4;
386
391
  --ph-text-secondary: #908caa;
387
- --ph-text-tertiary: #6e6a86;
392
+ --ph-text-tertiary: #a5a1b8;
388
393
  --ph-accent: #c4a7e7;
389
394
  --ph-accent-hover: #d4bcf0;
390
395
  --ph-blue: #9ccfd8;
@@ -437,7 +442,7 @@
437
442
  --ph-border-strong: #a8a8a3;
438
443
  --ph-text-primary: #242424;
439
444
  --ph-text-secondary: #4f4f4f;
440
- --ph-text-tertiary: #6b6b6b;
445
+ --ph-text-tertiary: #666666;
441
446
  --ph-accent: #242424;
442
447
  --ph-accent-hover: #000000;
443
448
  --ph-blue: #437aff;
@@ -490,7 +495,7 @@
490
495
  --ph-border-strong: #686868;
491
496
  --ph-text-primary: #f2f2f2;
492
497
  --ph-text-secondary: #c4c4c4;
493
- --ph-text-tertiary: #929292;
498
+ --ph-text-tertiary: #adadad;
494
499
  --ph-accent: #f2f2f2;
495
500
  --ph-accent-hover: #ffffff;
496
501
  --ph-blue: #7da3ff;
@@ -540,9 +545,9 @@
540
545
  --ph-border: #c4c8da;
541
546
  --ph-border-strong: #a8aecb;
542
547
  --ph-text-primary: #343b58;
543
- --ph-text-secondary: #6172b0;
544
- --ph-text-tertiary: #848cb5;
545
- --ph-accent: #2e7de9;
548
+ --ph-text-secondary: #485890;
549
+ --ph-text-tertiary: #4f5883;
550
+ --ph-accent: #155fc5;
546
551
  --ph-accent-hover: #2368c6;
547
552
  --ph-blue: #2e7de9;
548
553
  --ph-violet: #9854f1;
@@ -595,7 +600,7 @@
595
600
  --ph-border-strong: #565f89;
596
601
  --ph-text-primary: #c0caf5;
597
602
  --ph-text-secondary: #a9b1d6;
598
- --ph-text-tertiary: #565f89;
603
+ --ph-text-tertiary: #8d95b8;
599
604
  --ph-accent: #7aa2f7;
600
605
  --ph-accent-hover: #97b4f9;
601
606
  --ph-blue: #7aa2f7;
@@ -635,7 +640,7 @@
635
640
  --ph-data-7: #ff9e64;
636
641
  }
637
642
 
638
- /* Malibu — Nakama's GTA San Andreas-inspired sunset command-deck palette. */
643
+ /* Malibu — Shelly's GTA San Andreas-inspired sunset command-deck palette. */
639
644
  [data-theme="malibu-light"] {
640
645
  color-scheme: light;
641
646
  --ph-canvas: #f6efeb;
@@ -650,8 +655,8 @@
650
655
  --ph-border-strong: #b38b98;
651
656
  --ph-text-primary: #30202d;
652
657
  --ph-text-secondary: #64495a;
653
- --ph-text-tertiary: #927786;
654
- --ph-accent: #d14f74;
658
+ --ph-text-tertiary: #745c6a;
659
+ --ph-accent: #c4335c;
655
660
  --ph-accent-hover: #b93a60;
656
661
  --ph-blue: #3b8793;
657
662
  --ph-violet: #7d3ca4;
@@ -744,6 +749,116 @@
744
749
  --ph-data-7: #f54b87;
745
750
  }
746
751
 
752
+ /* Microsoft — Office Fluent neutrals with the signature brand blue. */
753
+ [data-theme="microsoft-light"] {
754
+ color-scheme: light;
755
+ --ph-canvas: #faf9f8;
756
+ --ph-surface: #ffffff;
757
+ --ph-muted: #f3f2f1;
758
+ --ph-toolbar: #edebe9;
759
+ --ph-surface-inset: #f3f2f1;
760
+ --ph-surface-raised: #ffffff;
761
+ --ph-surface-overlay: #ffffff;
762
+ --ph-border: #e1dfdd;
763
+ --ph-border-subtle: #edebe9;
764
+ --ph-border-strong: #a19f9d;
765
+ --ph-text-primary: #201f1e;
766
+ --ph-text-secondary: #605e5c;
767
+ --ph-text-tertiary: #6b6967;
768
+ --ph-accent: #0072ca;
769
+ --ph-accent-hover: #106ebe;
770
+ --ph-blue: #0078d4;
771
+ --ph-violet: #8661c5;
772
+ --ph-purple: #8764b8;
773
+ --ph-success: #107c10;
774
+ --ph-warning: #ca5010;
775
+ --ph-danger: #a4262c;
776
+ --ph-info: #0078d4;
777
+ --ph-on-accent: #ffffff;
778
+ --ph-on-violet: #ffffff;
779
+ --ph-on-success: #ffffff;
780
+ --ph-on-warning: #ffffff;
781
+ --ph-on-danger: #ffffff;
782
+ --ph-on-info: #ffffff;
783
+ --ph-focus-ring: #0078d4;
784
+ --ph-selected-bg: #eff6fc;
785
+ --ph-selected-text: #005a9e;
786
+ --ph-selected-border: #6cb8f6;
787
+ --ph-text-3000: #ffffff;
788
+ --ph-primary-button-face: #0078d4;
789
+ --ph-primary-button-border: #0078d4;
790
+ --ph-primary-button-border-hover: #106ebe;
791
+ --ph-primary-frame-bg: #106ebe;
792
+ --ph-secondary-button-bg: #f3f2f1;
793
+ --ph-secondary-frame-bg: #edebe9;
794
+ --ph-secondary-button-border: #8a8886;
795
+ --ph-secondary-button-border-hover: #605e5c;
796
+ --ph-border-3000: #e1dfdd;
797
+ --ph-accent-highlight-secondary: rgba(0, 120, 212, 0.08);
798
+ --ph-data-1: #0078d4;
799
+ --ph-data-2: #8764b8;
800
+ --ph-data-3: #038387;
801
+ --ph-data-4: #ca5010;
802
+ --ph-data-5: #107c10;
803
+ --ph-data-6: #e3008c;
804
+ --ph-data-7: #4f6bed;
805
+ --ph-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%23605e5c' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round' viewBox='0 0 24 24'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
806
+ }
807
+
808
+ [data-theme="microsoft-dark"] {
809
+ color-scheme: dark;
810
+ --ph-canvas: #1b1a19;
811
+ --ph-surface: #201f1e;
812
+ --ph-muted: #252423;
813
+ --ph-toolbar: #323130;
814
+ --ph-surface-inset: #1b1a19;
815
+ --ph-surface-raised: #252423;
816
+ --ph-surface-overlay: #3b3a39;
817
+ --ph-border: #3b3a39;
818
+ --ph-border-subtle: #292827;
819
+ --ph-border-strong: #605e5c;
820
+ --ph-text-primary: #f3f2f1;
821
+ --ph-text-secondary: #c8c6c4;
822
+ --ph-text-tertiary: #a19f9d;
823
+ --ph-accent: #2899f5;
824
+ --ph-accent-hover: #479ef5;
825
+ --ph-blue: #2899f5;
826
+ --ph-violet: #9a7fe8;
827
+ --ph-purple: #b4a0ff;
828
+ --ph-success: #54b054;
829
+ --ph-warning: #f7b355;
830
+ --ph-danger: #ff7171;
831
+ --ph-info: #2899f5;
832
+ --ph-on-accent: #1b1a19;
833
+ --ph-on-violet: #1b1a19;
834
+ --ph-on-success: #1b1a19;
835
+ --ph-on-warning: #1b1a19;
836
+ --ph-on-danger: #1b1a19;
837
+ --ph-on-info: #1b1a19;
838
+ --ph-focus-ring: #479ef5;
839
+ --ph-selected-bg: #203855;
840
+ --ph-selected-text: #6cb8f6;
841
+ --ph-selected-border: #2899f5;
842
+ --ph-text-3000: #1b1a19;
843
+ --ph-primary-button-face: #2899f5;
844
+ --ph-primary-button-border: #2899f5;
845
+ --ph-primary-button-border-hover: #479ef5;
846
+ --ph-primary-frame-bg: #479ef5;
847
+ --ph-secondary-button-bg: #252423;
848
+ --ph-secondary-frame-bg: #323130;
849
+ --ph-secondary-button-border: #605e5c;
850
+ --ph-secondary-button-border-hover: #c8c6c4;
851
+ --ph-border-3000: #323130;
852
+ --ph-accent-highlight-secondary: rgba(40, 153, 245, 0.14);
853
+ --ph-data-1: #2899f5;
854
+ --ph-data-2: #9a7fe8;
855
+ --ph-data-3: #45d1d6;
856
+ --ph-data-4: #f7b355;
857
+ --ph-data-5: #54b054;
858
+ --ph-data-6: #ff8ad4;
859
+ --ph-data-7: #7b9bff;
860
+ }
861
+
747
862
  /* Semantic button contrast for dark palettes. */
748
863
  :is(
749
864
  [data-theme="hedgehog-dark"],
@@ -752,7 +867,8 @@
752
867
  [data-theme="rosepine-dark"],
753
868
  [data-theme="kraken-dark"],
754
869
  [data-theme="deepsea-dark"],
755
- [data-theme="malibu-dark"]
870
+ [data-theme="malibu-dark"],
871
+ [data-theme="microsoft-dark"]
756
872
  ) {
757
873
  .ph-btn-signal {
758
874
  --ph-btn-face: color-mix(in oklab, var(--ph-accent) 62%, black);
@@ -1,12 +1,16 @@
1
1
  "use client";
2
2
 
3
- import { useEffect } from "react";
3
+ import { useEffect, useLayoutEffect } from "react";
4
4
  import { BlockNoteSchema, defaultBlockSpecs } from "@blocknote/core";
5
5
  import { BlockNoteViewRaw, useCreateBlockNote } from "@blocknote/react";
6
6
  import "@blocknote/react/style.css";
7
7
 
8
8
  import { useSuiteTheme } from "./theme-provider";
9
9
 
10
+ // Parse the message before first paint so the editor never flashes empty.
11
+ const useIsomorphicLayoutEffect =
12
+ typeof window !== "undefined" ? useLayoutEffect : useEffect;
13
+
10
14
  const assistantSchema = BlockNoteSchema.create({
11
15
  blockSpecs: {
12
16
  paragraph: defaultBlockSpecs.paragraph,
@@ -29,7 +33,7 @@ export default function SuiteAiBlockNoteMessage({
29
33
  const { resolvedTheme } = useSuiteTheme();
30
34
  const editor = useCreateBlockNote({ schema: assistantSchema });
31
35
 
32
- useEffect(() => {
36
+ useIsomorphicLayoutEffect(() => {
33
37
  try {
34
38
  const blocks = editor.tryParseMarkdownToBlocks(markdown);
35
39
  editor.replaceBlocks(
@@ -43,6 +47,13 @@ export default function SuiteAiBlockNoteMessage({
43
47
  }
44
48
  }, [editor, markdown]);
45
49
 
50
+ // BlockNote renders the body as a ProseMirror contenteditable (.tiptap);
51
+ // give that node an accessible name so axe's aria-input-field-name passes.
52
+ useEffect(() => {
53
+ const el = (editor as unknown as { domElement?: HTMLElement }).domElement;
54
+ el?.setAttribute("aria-label", "Assistant message");
55
+ }, [editor]);
56
+
46
57
  return (
47
58
  <BlockNoteViewRaw
48
59
  editor={editor}