@puredesktop/puredesktop-ui-bridge 2.1.4 → 2.1.6

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 (183) hide show
  1. package/package.json +19 -1
  2. package/src/agents/runtime/mapAgentSnapshot.test.ts +1 -3
  3. package/src/agents/runtime/mapAgentSnapshot.ts +8 -4
  4. package/src/agents/runtime/mergeUsageTurn.ts +1 -2
  5. package/src/agents/runtime/pendingToolCalls.test.ts +1 -3
  6. package/src/agents/runtime/unresolvedToolCalls.ts +1 -2
  7. package/src/bridge/agentModelTiers.ts +9 -4
  8. package/src/bridge/agents.mjs +3 -1
  9. package/src/bridge/calendarDraftIntent.ts +12 -4
  10. package/src/bridge/calendarInviteIntent.ts +18 -5
  11. package/src/bridge/client.mjs +45 -45
  12. package/src/bridge/dialog.d.mts +8 -8
  13. package/src/bridge/dialog.mjs +40 -40
  14. package/src/bridge/dialog.test.ts +73 -73
  15. package/src/bridge/fs.d.mts +41 -41
  16. package/src/bridge/fs.mjs +56 -56
  17. package/src/bridge/fs.test.ts +83 -83
  18. package/src/bridge/fs.ts +28 -28
  19. package/src/bridge/googleAuth.ts +3 -1
  20. package/src/bridge/methods.d.mts +6 -0
  21. package/src/bridge/methods.mjs +7 -0
  22. package/src/bridge/network.d.mts +17 -17
  23. package/src/bridge/network.mjs +22 -22
  24. package/src/bridge/pureRender/base.css +324 -76
  25. package/src/bridge/pureRender/compiler.ts +1 -1
  26. package/src/bridge/pureRender/document.test.ts +2 -2
  27. package/src/bridge/pureRender/extraction.test.ts +24 -12
  28. package/src/bridge/pureRender/extraction.ts +10 -7
  29. package/src/bridge/pureRender/flow.css +17 -3
  30. package/src/bridge/pureRender/normalize.ts +28 -26
  31. package/src/bridge/pureRender/presets.ts +7 -7
  32. package/src/bridge/pureRender/profiles/book.css +122 -19
  33. package/src/bridge/pureRender/profiles/manuscript.css +57 -11
  34. package/src/bridge/pureRender/profiles/writer.css +48 -10
  35. package/src/bridge/pureRender/reset.css +20 -5
  36. package/src/bridge/pureRender/theme.ts +37 -9
  37. package/src/bridge/pureRender/tokens/default.css +45 -33
  38. package/src/bridge/react/usePlatformAgentRunLiveState.tsx +4 -1
  39. package/src/bridge/react/usePlatformAgentSessionDrive.tsx +13 -4
  40. package/src/bridge/screenAnnotation.test.ts +4 -1
  41. package/src/bridge/screenAnnotation.ts +6 -2
  42. package/src/bridge/storage.d.mts +27 -27
  43. package/src/bridge/storage.mjs +18 -18
  44. package/src/bridge/storage.test.ts +49 -49
  45. package/src/bridge/types.ts +62 -58
  46. package/src/bridge/window.d.mts +3 -1
  47. package/src/bridge/workspace.d.mts +7 -0
  48. package/src/bridge/workspace.mjs +8 -0
  49. package/src/bridge/workspace.ts +1 -0
  50. package/src/commitments/commitments.test.ts +10 -3
  51. package/src/commitments/commitments.ts +18 -4
  52. package/src/components/accessibility/AccessibilityReviewDialog.tsx +7 -2
  53. package/src/components/accessibility/accessibilityReview.test.ts +11 -4
  54. package/src/components/accessibility/accessibilityReview.ts +18 -10
  55. package/src/components/agent-feedback/ScreenAnnotationAgentDialog.tsx +9 -2
  56. package/src/components/agents/AgentContextUsageBar.tsx +5 -3
  57. package/src/components/agents/AgentDrawerPanel.test.tsx +15 -3
  58. package/src/components/agents/AgentMessageBubble.tsx +1 -3
  59. package/src/components/agents/AgentQuestionPromptList.tsx +3 -3
  60. package/src/components/agents/AgentToolApprovalActions.tsx +1 -3
  61. package/src/components/agents/agentPanelStyles.ts +1 -1
  62. package/src/components/agents/agentToolDisplay.ts +4 -1
  63. package/src/components/assets/asset-library/AssetLibraryDialog.tsx +2 -0
  64. package/src/components/assets/asset-library/AssetLibraryWorkspace.tsx +2 -0
  65. package/src/components/assets/asset-library/detail/AssetLibraryDetailHeader.test.tsx +40 -0
  66. package/src/components/assets/asset-library/detail/AssetLibraryDetailHeader.tsx +7 -3
  67. package/src/components/assets/asset-library/detail/AssetLibraryDetailPreview.tsx +8 -8
  68. package/src/components/assets/asset-library/hooks/useAssetLibraryDialog.ts +13 -2
  69. package/src/components/assets/asset-library/hooks/useAssetLibraryMutations.ts +18 -1
  70. package/src/components/assets/asset-library/sidebar/AssetLibraryListRow.tsx +9 -6
  71. package/src/components/assets/asset-library/sidebar/AssetLibrarySidebarToolbar.tsx +3 -1
  72. package/src/components/assets/asset-library/sidebar/AssetListThumbnail.tsx +1 -1
  73. package/src/components/assets/asset-library/types.ts +6 -0
  74. package/src/components/chrome/OverlayActionCapsule.tsx +2 -2
  75. package/src/components/chrome/PanelTabStrip.tsx +3 -2
  76. package/src/components/chrome/PureAppWordmark.tsx +15 -15
  77. package/src/components/chrome/WorkspaceTabStrip.tsx +19 -14
  78. package/src/components/chrome/documentChromePolicy.test.ts +34 -0
  79. package/src/components/chrome/documentChromePolicy.ts +15 -0
  80. package/src/components/chrome/index.ts +4 -0
  81. package/src/components/chrome/workspaceTabTypes.ts +2 -0
  82. package/src/components/common/buttons/Button.tsx +60 -10
  83. package/src/components/common/buttons/ChoiceChip.tsx +2 -2
  84. package/src/components/common/buttons/IconButton.tsx +26 -0
  85. package/src/components/common/buttons/SegmentedControl.tsx +23 -7
  86. package/src/components/common/canvas/CanvasElementFrame.tsx +37 -28
  87. package/src/components/common/canvas/canvasGeometry.test.ts +4 -5
  88. package/src/components/common/canvas/canvasGeometry.ts +1 -4
  89. package/src/components/common/canvas/useCanvasDragResize.test.tsx +10 -10
  90. package/src/components/common/canvas/useCanvasDragResize.ts +1 -4
  91. package/src/components/common/cards/OpenReviewCard.tsx +6 -6
  92. package/src/components/common/chat/ChatBox.test.tsx +9 -1
  93. package/src/components/common/chat/ChatBox.tsx +3 -4
  94. package/src/components/common/chat/ChatMarkdown.tsx +1 -1
  95. package/src/components/common/chat/ChatModelMenu.tsx +1 -1
  96. package/src/components/common/chat/ChatThinkingIndicator.tsx +1 -1
  97. package/src/components/common/chat/ChatThread.tsx +2 -1
  98. package/src/components/common/chat/ChatToolRow.tsx +2 -2
  99. package/src/components/common/chat/ChatUserBubble.tsx +1 -1
  100. package/src/components/common/connections/ConnectionSetup.tsx +6 -6
  101. package/src/components/common/containers/AppFrame.test.tsx +37 -36
  102. package/src/components/common/containers/AppFrame.tsx +15 -0
  103. package/src/components/common/containers/AppHeader.tsx +6 -3
  104. package/src/components/common/containers/SurfacePanel.tsx +1 -0
  105. package/src/components/common/containers/useOpacityPresence.ts +10 -15
  106. package/src/components/common/context/ContextSelector.tsx +10 -10
  107. package/src/components/common/desk/CreationDesk.tsx +23 -11
  108. package/src/components/common/desk/DailyBrief.tsx +18 -7
  109. package/src/components/common/desk/DeskCard.tsx +11 -6
  110. package/src/components/common/dropdown/MenuButtonDropdown.tsx +58 -6
  111. package/src/components/common/dropdown/MenuDropdownItem.tsx +23 -3
  112. package/src/components/common/dropdown/MenuPanel.tsx +8 -8
  113. package/src/components/common/dropdown/SelectMenu.tsx +8 -3
  114. package/src/components/common/dropdown/menuTypes.ts +2 -1
  115. package/src/components/common/evidence/StructuredEvidenceView.tsx +9 -5
  116. package/src/components/common/feedback/Badge.tsx +19 -5
  117. package/src/components/common/feedback/CapabilityPills.tsx +1 -1
  118. package/src/components/common/feedback/InfoHint.tsx +2 -2
  119. package/src/components/common/feedback/PlatformChip.tsx +9 -9
  120. package/src/components/common/feedback/QuietPill.tsx +5 -8
  121. package/src/components/common/feedback/WorkProgressPanel.tsx +14 -14
  122. package/src/components/common/files/FileTable.tsx +8 -2
  123. package/src/components/common/inputs/Checkbox.tsx +1 -1
  124. package/src/components/common/inputs/EditableSecretField.tsx +1 -3
  125. package/src/components/common/inputs/InlineComposer.tsx +2 -2
  126. package/src/components/common/inputs/PaletteDropdown.tsx +33 -23
  127. package/src/components/common/inputs/SurfacePalettePicker.tsx +1 -1
  128. package/src/components/common/inputs/ToggleSwitch.tsx +2 -2
  129. package/src/components/common/inputs/WorkspacePicker.tsx +3 -3
  130. package/src/components/common/lists/listRowStyles.ts +4 -2
  131. package/src/components/common/lists/quiet-ledger/index.ts +1 -4
  132. package/src/components/common/lists/reorderable/DragHandle.tsx +1 -1
  133. package/src/components/common/lists/reorderable/ReorderableSections.tsx +2 -1
  134. package/src/components/common/media/ImageReferencePicker.tsx +22 -14
  135. package/src/components/common/narrative/NarrativeMention.tsx +15 -9
  136. package/src/components/common/navigation/NavigationCardRow.tsx +2 -2
  137. package/src/components/common/navigation/UnderlineTabs.tsx +1 -0
  138. package/src/components/common/overlays/Modal.tsx +52 -3
  139. package/src/components/common/overlays/ObjectActionStrip.tsx +2 -2
  140. package/src/components/common/people/AutoUpdateReviewList.tsx +2 -2
  141. package/src/components/common/people/EntityList.tsx +7 -3
  142. package/src/components/common/people/EntityPortrait.tsx +6 -1
  143. package/src/components/common/people/LinkedDossierList.tsx +3 -1
  144. package/src/components/common/people/RelationshipMap.tsx +3 -9
  145. package/src/components/common/research/EvidenceDossier.tsx +24 -20
  146. package/src/components/common/tiles/CatalogCard.tsx +1 -1
  147. package/src/components/credentials/CredentialsPanel.tsx +2 -6
  148. package/src/components/data/DataChart.tsx +119 -94
  149. package/src/components/data/dataTable.ts +4 -1
  150. package/src/components/editor/DocumentAppChrome.tsx +172 -0
  151. package/src/components/editor/EditorCommentPromptDialog.tsx +1 -1
  152. package/src/components/editor/EditorLinkPromptDialog.tsx +1 -1
  153. package/src/components/print-design/PrintDesignPanel.test.tsx +8 -6
  154. package/src/components/print-design/PrintDesignPanel.tsx +18 -25
  155. package/src/components/proofing/PagedProofDialog.tsx +17 -4
  156. package/src/editor/EditorViewModeToggle.tsx +6 -2
  157. package/src/editor/index.ts +6 -0
  158. package/src/theme/ThemeProvider.tsx +5 -2
  159. package/src/theme/appAccents.test.ts +51 -0
  160. package/src/theme/appAccents.ts +151 -88
  161. package/src/theme/appIdentityCss.mjs +256 -0
  162. package/src/theme/appIdentityCss.ts +256 -0
  163. package/src/theme/composePlatformTheme.test.ts +43 -14
  164. package/src/theme/platformFont.d.mts +2 -2
  165. package/src/theme/platformFont.mjs +4 -3
  166. package/src/theme/reportsShellChromeSelectors.ts +14 -132
  167. package/src/theme/surfaceCss.mjs +37 -0
  168. package/src/theme/surfaceCss.ts +37 -0
  169. package/src/theme/surfacePalettes.ts +120 -79
  170. package/src/theme/surfaceRoleSelectors.ts +135 -71
  171. package/src/theme/themes/dark.ts +44 -43
  172. package/src/theme/themes/light.ts +40 -38
  173. package/src/theme/themes/palette.ts +32 -30
  174. package/src/theme/themes/shared.ts +17 -17
  175. package/src/theme/utils/GlobalStyles.ts +10 -6
  176. package/src/theme/utils/appFrameDocumentStyles.mjs +6 -1
  177. package/src/theme/utils/cssVariables.ts +169 -0
  178. package/src/writing/DraftAssistantDialog.tsx +85 -85
  179. package/src/writing/WritingStyleManager.tsx +6 -3
  180. package/src/writing/draftTextWithAgent.ts +47 -50
  181. package/src/writing/styleStore.ts +4 -3
  182. package/src/writing/writingStyle.test.ts +8 -2
  183. package/src/writing/writingStyle.ts +19 -8
@@ -3,36 +3,37 @@ import { createRoot, type Root } from 'react-dom/client'
3
3
  import { afterEach, describe, expect, it, vi } from 'vitest'
4
4
  import { MENU_PORTAL_ID } from '../dropdown/menuPortalConstants.js'
5
5
  import { PLATFORM_APP_FRAME_BASE_STYLE_ID } from '../../../theme/utils/appFrameDocumentStyles.js'
6
- import { darkTheme } from '../../../theme/themes/dark.js'
7
- import { AppFrame } from './AppFrame.js'
8
-
9
- vi.mock('../../../bridge/react/usePlatformBridge.js', () => ({
10
- usePlatformBridge: vi.fn(() => ({
11
- bridge: null,
12
- error: null,
13
- meta: null,
14
- ready: false,
15
- })),
16
- }))
17
-
18
- vi.mock('../../../bridge/react/usePlatformAppManifest.js', () => ({
19
- usePlatformAppManifest: vi.fn(() => ({
20
- error: null,
21
- loading: false,
22
- manifest: null,
23
- })),
24
- }))
25
-
26
- vi.mock('../../../bridge/react/usePlatformThemeDocumentAttrs.js', () => ({
27
- usePlatformThemeDocumentAttrs: vi.fn(() => ({
28
- mode: '',
29
- surfacePalette: '',
30
- })),
31
- }))
32
-
33
- vi.mock('../../../bridge/react/usePlatformThemeFromBridge.js', () => ({
34
- usePlatformThemeFromBridge: vi.fn(),
35
- }))
6
+ import { darkTheme } from '../../../theme/themes/dark.js'
7
+ import { PLATFORM_FONT_STYLESHEET_ID } from '../../../theme/platformFont.js'
8
+ import { AppFrame } from './AppFrame.js'
9
+
10
+ vi.mock('../../../bridge/react/usePlatformBridge.js', () => ({
11
+ usePlatformBridge: vi.fn(() => ({
12
+ bridge: null,
13
+ error: null,
14
+ meta: { appSlug: 'tasks' },
15
+ ready: true,
16
+ })),
17
+ }))
18
+
19
+ vi.mock('../../../bridge/react/usePlatformAppManifest.js', () => ({
20
+ usePlatformAppManifest: vi.fn(() => ({
21
+ error: null,
22
+ loading: false,
23
+ manifest: null,
24
+ })),
25
+ }))
26
+
27
+ vi.mock('../../../bridge/react/usePlatformThemeDocumentAttrs.js', () => ({
28
+ usePlatformThemeDocumentAttrs: vi.fn(() => ({
29
+ mode: '',
30
+ surfacePalette: '',
31
+ })),
32
+ }))
33
+
34
+ vi.mock('../../../bridge/react/usePlatformThemeFromBridge.js', () => ({
35
+ usePlatformThemeFromBridge: vi.fn(),
36
+ }))
36
37
 
37
38
  function render(ui: React.ReactElement): {
38
39
  container: HTMLDivElement
@@ -61,12 +62,12 @@ describe('AppFrame', () => {
61
62
 
62
63
  expect(document.getElementById(MENU_PORTAL_ID)).not.toBeNull()
63
64
  const baseStyles = document.getElementById(PLATFORM_APP_FRAME_BASE_STYLE_ID)
64
- expect(baseStyles).not.toBeNull()
65
- expect(baseStyles?.textContent).toContain('box-sizing: border-box')
66
- expect(baseStyles?.textContent).toContain('scrollbar-color')
67
- expect(
68
- document.getElementById('platform-font-schibsted-grotesk'),
69
- ).not.toBeNull()
65
+ expect(baseStyles).not.toBeNull()
66
+ expect(baseStyles?.textContent).toContain('box-sizing: border-box')
67
+ expect(baseStyles?.textContent).toContain('scrollbar-color')
68
+ expect(document.getElementById(PLATFORM_FONT_STYLESHEET_ID)).not.toBeNull()
69
+ expect(container.querySelector('[data-app="tasks"]')).not.toBeNull()
70
+ expect(document.documentElement.dataset.app).toBe('tasks')
70
71
  expect(container.textContent).toContain('App content')
71
72
  })
72
73
 
@@ -46,6 +46,20 @@ export function AppFrame({
46
46
  injectAppFrameDocumentStyles()
47
47
  }, [])
48
48
 
49
+ useEffect(() => {
50
+ const root = document.documentElement
51
+ if (meta?.appSlug) {
52
+ root.dataset.app = meta.appSlug
53
+ } else {
54
+ delete root.dataset.app
55
+ }
56
+ return () => {
57
+ if (root.dataset.app === meta?.appSlug) {
58
+ delete root.dataset.app
59
+ }
60
+ }
61
+ }, [meta?.appSlug])
62
+
49
63
  usePlatformThemeFromBridge(themeFromBridge)
50
64
  const themeAttrs = usePlatformThemeDocumentAttrs(themeFromBridge)
51
65
 
@@ -54,6 +68,7 @@ export function AppFrame({
54
68
  <MenuPortalLayer />
55
69
  <StyledRoot
56
70
  className={className}
71
+ data-app={meta?.appSlug || undefined}
57
72
  data-platform-theme={themeAttrs.mode || undefined}
58
73
  data-platform-surface-palette={themeAttrs.surfacePalette || undefined}
59
74
  {...rest}
@@ -23,20 +23,23 @@ const StyledHeader = styled.header`
23
23
  padding: 0 14px;
24
24
  height: 36px;
25
25
  flex: 0 0 auto;
26
- border-bottom: 1px solid var(--platform-colors-divider);
27
- background: var(--platform-colors-app-viewport);
26
+ border-bottom: 1px solid
27
+ var(--pure-chrome-hairline, var(--platform-colors-divider));
28
+ background: var(--pure-chrome-wordmark-bar, #fbfbfc);
28
29
  `
29
30
 
30
31
  const ActionSlot = styled.div`
31
32
  display: flex;
32
33
  align-items: center;
33
34
  gap: 4px;
35
+ flex: 1 1 auto;
34
36
  min-width: 0;
35
37
  margin-left: auto;
38
+ justify-content: flex-end;
36
39
 
37
40
  &[data-layout='document-tools'] {
38
41
  flex: 1;
39
- justify-content: center;
42
+ justify-content: flex-start;
40
43
  margin-left: 0;
41
44
  }
42
45
  `
@@ -18,6 +18,7 @@ const StyledPanel = styled.section`
18
18
  box-sizing: border-box;
19
19
  min-width: 0;
20
20
  max-width: 100%;
21
+ box-shadow: var(--platform-shadow-sm);
21
22
  `
22
23
 
23
24
  const StyledTitle = styled.h2`
@@ -22,9 +22,7 @@ export interface OpacityPresence {
22
22
  * Fade in/out via opacity; after fade-out completes, `present` is false for display:none.
23
23
  * Unlike useOpenTransition (timeout + unmount), this waits for transitionend and keeps children mounted.
24
24
  */
25
- export function useOpacityPresence(
26
- active: boolean,
27
- ): OpacityPresence {
25
+ export function useOpacityPresence(active: boolean): OpacityPresence {
28
26
  const [phase, setPhase] = useState<OpacityPresencePhase>(() =>
29
27
  active ? 'visible' : 'hidden',
30
28
  )
@@ -57,19 +55,16 @@ export function useOpacityPresence(
57
55
  return () => cancelAnimationFrame(id)
58
56
  }, [phase])
59
57
 
60
- const onTransitionEnd = useCallback(
61
- (event: TransitionEvent<HTMLElement>) => {
62
- if (event.target !== event.currentTarget) return
63
- if (event.propertyName !== 'opacity') return
58
+ const onTransitionEnd = useCallback((event: TransitionEvent<HTMLElement>) => {
59
+ if (event.target !== event.currentTarget) return
60
+ if (event.propertyName !== 'opacity') return
64
61
 
65
- setPhase(prev => {
66
- if (prev === 'exiting') return 'hidden'
67
- if (prev === 'entering') return 'visible'
68
- return prev
69
- })
70
- },
71
- [],
72
- )
62
+ setPhase(prev => {
63
+ if (prev === 'exiting') return 'hidden'
64
+ if (prev === 'entering') return 'visible'
65
+ return prev
66
+ })
67
+ }, [])
73
68
 
74
69
  return {
75
70
  present: phase !== 'hidden',
@@ -70,7 +70,7 @@ const Trigger = styled.button`
70
70
  border: 0;
71
71
  background: transparent;
72
72
  padding: 0;
73
- color: var(--platform-colors-text-secondary, #68717c);
73
+ color: var(--platform-colors-text-secondary, #6b665e);
74
74
  font: inherit;
75
75
  font-size: 13px;
76
76
  font-weight: 750;
@@ -78,13 +78,13 @@ const Trigger = styled.button`
78
78
 
79
79
  &:hover,
80
80
  &:focus-visible {
81
- color: var(--platform-colors-text, #2e3338);
81
+ color: var(--platform-colors-text, #1c1a17);
82
82
  outline: none;
83
83
  }
84
84
  `
85
85
 
86
86
  const Count = styled.span`
87
- color: var(--platform-colors-text-secondary, #68717c);
87
+ color: var(--platform-colors-text-secondary, #6b665e);
88
88
  font-size: 12px;
89
89
  `
90
90
 
@@ -99,7 +99,7 @@ const Menu = styled.div`
99
99
  max-height: min(360px, 70vh);
100
100
  overflow: auto;
101
101
  border: 1px solid var(--platform-colors-border, rgb(46 51 56 / 12%));
102
- border-radius: 8px;
102
+ border-radius: var(--platform-radius-md, 0px);
103
103
  background: color-mix(
104
104
  in srgb,
105
105
  var(--platform-colors-elevated, #fffefa) 96%,
@@ -113,10 +113,10 @@ const OptionButton = styled.button`
113
113
  display: grid;
114
114
  gap: 3px;
115
115
  border: 0;
116
- border-radius: 6px;
116
+ border-radius: var(--platform-radius-sm, 0px);
117
117
  background: transparent;
118
118
  padding: 9px 10px;
119
- color: var(--platform-colors-text, #2e3338);
119
+ color: var(--platform-colors-text, #1c1a17);
120
120
  font: inherit;
121
121
  text-align: left;
122
122
  cursor: pointer;
@@ -134,7 +134,7 @@ const OptionTitle = styled.span`
134
134
  `
135
135
 
136
136
  const OptionMeta = styled.span`
137
- color: var(--platform-colors-text-secondary, #68717c);
137
+ color: var(--platform-colors-text-secondary, #6b665e);
138
138
  font-size: 11px;
139
139
  line-height: 1.35;
140
140
  `
@@ -151,14 +151,14 @@ const SelectedChip = styled.span`
151
151
  gap: 6px;
152
152
  max-width: 100%;
153
153
  border: 1px solid var(--platform-colors-border, rgb(46 51 56 / 12%));
154
- border-radius: 999px;
154
+ border-radius: var(--platform-radius-sm);
155
155
  background: color-mix(
156
156
  in srgb,
157
157
  var(--platform-colors-surface, #ffffff) 72%,
158
158
  transparent
159
159
  );
160
160
  padding: 3px 7px;
161
- color: var(--platform-colors-text-secondary, #68717c);
161
+ color: var(--platform-colors-text-secondary, #6b665e);
162
162
  font-size: 12px;
163
163
  `
164
164
 
@@ -166,7 +166,7 @@ const RemoveButton = styled.button`
166
166
  border: 0;
167
167
  background: transparent;
168
168
  padding: 0;
169
- color: var(--platform-colors-text-secondary, #68717c);
169
+ color: var(--platform-colors-text-secondary, #6b665e);
170
170
  font: inherit;
171
171
  cursor: pointer;
172
172
  `
@@ -42,7 +42,7 @@ export const CreationDeskSection = styled.section`
42
42
  `
43
43
 
44
44
  export const CreationDeskSectionLabel = styled.div`
45
- color: rgb(104 112 123);
45
+ color: var(--platform-colors-text-secondary, #6b665e);
46
46
  font-size: 12px;
47
47
  font-weight: 800;
48
48
  letter-spacing: 0.08em;
@@ -57,7 +57,7 @@ export const CreationDeskRow = styled.div`
57
57
  `
58
58
 
59
59
  export const CreationDeskNote = styled.div`
60
- color: rgb(104 112 123);
60
+ color: var(--platform-colors-text-secondary, #6b665e);
61
61
  font-size: 12px;
62
62
  line-height: 1.45;
63
63
  opacity: 0.68;
@@ -67,9 +67,13 @@ export const CreationDeskTextarea = styled(BareTextarea)`
67
67
  width: 100%;
68
68
  min-height: 140px;
69
69
  padding: 14px 16px;
70
- border: 1px solid rgb(127 127 127 / 24%);
71
- border-radius: 8px;
72
- background: rgb(255 255 255 / 55%);
70
+ border: 1px solid var(--platform-colors-border, #e7e4dd);
71
+ border-radius: var(--platform-radius-sm, 0px);
72
+ background: color-mix(
73
+ in srgb,
74
+ var(--platform-colors-surface, #ffffff) 78%,
75
+ transparent
76
+ );
73
77
  color: inherit;
74
78
  font: inherit;
75
79
  font-size: 14px;
@@ -81,9 +85,13 @@ export const CreationDeskFieldBox = styled.div`
81
85
  display: grid;
82
86
  gap: 12px;
83
87
  padding: 14px 16px;
84
- border: 1px solid rgb(127 127 127 / 24%);
85
- border-radius: 8px;
86
- background: rgb(255 255 255 / 55%);
88
+ border: 1px solid var(--platform-colors-border, #e7e4dd);
89
+ border-radius: var(--platform-radius-sm, 0px);
90
+ background: color-mix(
91
+ in srgb,
92
+ var(--platform-colors-surface, #ffffff) 78%,
93
+ transparent
94
+ );
87
95
  `
88
96
 
89
97
  export const CreationDeskFieldTextarea = styled(BareTextarea)`
@@ -104,9 +112,13 @@ export const CreationDeskSourceCard = styled.div`
104
112
  display: grid;
105
113
  gap: 8px;
106
114
  padding: 14px 16px;
107
- border: 1px solid rgb(127 127 127 / 20%);
108
- border-radius: 8px;
109
- background: rgb(255 255 255 / 45%);
115
+ border: 1px solid var(--platform-colors-border, #e7e4dd);
116
+ border-radius: var(--platform-radius-sm, 0px);
117
+ background: color-mix(
118
+ in srgb,
119
+ var(--platform-colors-surface, #ffffff) 72%,
120
+ transparent
121
+ );
110
122
  font-size: 13px;
111
123
  `
112
124
 
@@ -34,10 +34,11 @@ const Surface = styled.article`
34
34
  max-width: 760px;
35
35
  margin: 0 auto;
36
36
  padding: 36px 44px 38px;
37
- border: 1px solid rgba(217, 222, 229, 0.72);
38
- border-radius: 4px;
39
- background: var(--daily-brief-paper, #fffefa);
40
- box-shadow: 0 18px 54px rgba(38, 46, 55, 0.055);
37
+ border: 1px solid var(--platform-colors-border, #e7e4dd);
38
+ border-radius: var(--platform-radius-sm, 0px);
39
+ background: var(--daily-brief-paper, var(--factory-color-paper, #ffffff));
40
+ box-shadow: 0 18px 54px
41
+ color-mix(in srgb, var(--platform-colors-text, #1c1a17) 5.5%, transparent);
41
42
  color: var(--daily-brief-ink, inherit);
42
43
  `
43
44
 
@@ -46,7 +47,10 @@ const Kicker = styled.div`
46
47
  align-items: baseline;
47
48
  justify-content: space-between;
48
49
  gap: 16px;
49
- color: var(--daily-brief-faint, #9aa2ad);
50
+ color: var(
51
+ --daily-brief-faint,
52
+ var(--platform-colors-text-tertiary, #8f897f)
53
+ );
50
54
  font-size: 10px;
51
55
  font-weight: 700;
52
56
  letter-spacing: 0.07em;
@@ -68,7 +72,10 @@ const Body = styled.p`
68
72
 
69
73
  const Empty = styled.p`
70
74
  margin: 20px 0 0;
71
- color: var(--daily-brief-muted, #737b86);
75
+ color: var(
76
+ --daily-brief-muted,
77
+ var(--platform-colors-text-secondary, #6b665e)
78
+ );
72
79
  font-size: 18px;
73
80
  line-height: 1.55;
74
81
  `
@@ -77,7 +84,10 @@ const Footer = styled.div`
77
84
  display: flex;
78
85
  justify-content: flex-end;
79
86
  margin-top: 22px;
80
- color: var(--daily-brief-muted, #737b86);
87
+ color: var(
88
+ --daily-brief-muted,
89
+ var(--platform-colors-text-secondary, #6b665e)
90
+ );
81
91
  `
82
92
 
83
93
  function formatBriefDate(iso: string): string {
@@ -87,6 +97,7 @@ function formatBriefDate(iso: string): string {
87
97
  weekday: 'short',
88
98
  month: 'short',
89
99
  day: 'numeric',
100
+ year: 'numeric',
90
101
  })
91
102
  }
92
103
 
@@ -26,18 +26,21 @@ const StyledCard = styled.button<{
26
26
  margin-bottom: 8px;
27
27
  padding: 11px 13px;
28
28
  border: 1px solid
29
- ${({ $accent }) => ($accent ? '#d9dee5' : 'rgba(217, 222, 229, 0.9)')};
29
+ ${({ $accent }) =>
30
+ $accent
31
+ ? 'var(--platform-colors-border, #e7e4dd)'
32
+ : 'color-mix(in srgb, var(--platform-colors-border, #e7e4dd) 90%, transparent)'};
30
33
  border-left: ${({ $accent }) =>
31
34
  $accent
32
35
  ? '2px solid var(--desk-card-accent, var(--platform-colors-accent))'
33
- : '1px solid rgba(217, 222, 229, 0.9)'};
36
+ : '1px solid color-mix(in srgb, var(--platform-colors-border, #e7e4dd) 90%, transparent)'};
34
37
  border-radius: ${({ $accent }) => ($accent ? '0' : '6px')};
35
38
  background: ${({ $accent, $dim }) =>
36
39
  $accent
37
40
  ? 'var(--desk-card-paper, var(--platform-colors-surface))'
38
41
  : $dim
39
- ? 'rgba(255, 255, 255, 0.55)'
40
- : 'rgba(255, 255, 255, 0.85)'};
42
+ ? 'color-mix(in srgb, var(--platform-colors-surface, #ffffff) 55%, transparent)'
43
+ : 'color-mix(in srgb, var(--platform-colors-surface, #ffffff) 85%, transparent)'};
41
44
  color: inherit;
42
45
  font: inherit;
43
46
  text-align: left;
@@ -49,7 +52,7 @@ const StyledCard = styled.button<{
49
52
  right: 2px;
50
53
  left: 2px;
51
54
  height: 2px;
52
- border-radius: 999px;
55
+ border-radius: 0;
53
56
  background: ${({ $dropBefore }) =>
54
57
  $dropBefore
55
58
  ? 'var(--desk-card-accent, var(--platform-colors-accent))'
@@ -59,7 +62,9 @@ const StyledCard = styled.button<{
59
62
 
60
63
  &:hover {
61
64
  background: ${({ $accent }) =>
62
- $accent ? 'var(--desk-card-paper, #fff)' : '#ffffff'};
65
+ $accent
66
+ ? 'var(--desk-card-paper, var(--platform-colors-surface, #ffffff))'
67
+ : 'var(--platform-colors-surface, #ffffff)'};
63
68
  }
64
69
  `
65
70
 
@@ -1,7 +1,7 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react'
1
+ import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'
2
2
  import { ChevronDown } from 'lucide-react'
3
3
  import type { LucideIcon } from 'lucide-react'
4
- import { styled } from 'styled-components'
4
+ import { css, styled } from 'styled-components'
5
5
  import { PlatformIcon } from '../../chrome/PlatformIcon.js'
6
6
  import { Button } from '../buttons/Button.js'
7
7
  import { IconButton } from '../buttons/IconButton.js'
@@ -13,18 +13,51 @@ export interface MenuButtonDropdownProps {
13
13
  label: string
14
14
  items: MenuEntry[]
15
15
  icon?: LucideIcon
16
+ leadingIcon?: ReactNode
17
+ iconOnly?: boolean
16
18
  disabled?: boolean
17
19
  variant?: 'ghost' | 'subtle' | 'primary' | 'text'
18
20
  size?: 'sm' | 'md'
21
+ triggerTone?: 'default' | 'toolbar'
19
22
  sectionId?: string
20
23
  onSelectItem?: (item: MenuActionItem) => void
21
24
  }
22
25
 
23
26
  //#region styled-components
24
27
 
25
- const StyledWrap = styled.div`
28
+ const StyledWrap = styled.div<{ $triggerTone: 'default' | 'toolbar' }>`
26
29
  position: relative;
27
30
  display: inline-flex;
31
+
32
+ ${({ $triggerTone }) =>
33
+ $triggerTone === 'toolbar'
34
+ ? css`
35
+ button {
36
+ color: var(
37
+ --editor-toolbar-muted,
38
+ var(
39
+ --pure-chrome-tertiary,
40
+ var(--editor-paper-muted, #8a857c)
41
+ )
42
+ );
43
+ }
44
+
45
+ button:hover:not(:disabled) {
46
+ background: var(
47
+ --editor-toolbar-subtle,
48
+ var(
49
+ --editor-paper-subtle,
50
+ var(--platform-colors-surface-hover)
51
+ )
52
+ );
53
+ color: var(
54
+ --editor-toolbar-text,
55
+ var(--editor-paper-text, var(--platform-colors-text))
56
+ );
57
+ text-decoration: none;
58
+ }
59
+ `
60
+ : ''}
28
61
  `
29
62
 
30
63
  const TextTriggerContent = styled.span`
@@ -32,6 +65,12 @@ const TextTriggerContent = styled.span`
32
65
  align-items: center;
33
66
  gap: 6px;
34
67
  min-width: 0;
68
+
69
+ > svg {
70
+ flex: none;
71
+ width: 18px;
72
+ height: 18px;
73
+ }
35
74
  `
36
75
 
37
76
  //#endregion
@@ -40,9 +79,12 @@ export function MenuButtonDropdown({
40
79
  label,
41
80
  items,
42
81
  icon,
82
+ leadingIcon,
83
+ iconOnly = false,
43
84
  disabled = false,
44
85
  variant = 'subtle',
45
86
  size = 'sm',
87
+ triggerTone = 'default',
46
88
  sectionId = 'menu-button',
47
89
  onSelectItem,
48
90
  }: MenuButtonDropdownProps): React.ReactElement {
@@ -94,15 +136,25 @@ export function MenuButtonDropdown({
94
136
  }
95
137
 
96
138
  return (
97
- <StyledWrap onClick={event => event.stopPropagation()}>
139
+ <StyledWrap
140
+ $triggerTone={triggerTone}
141
+ onClick={event => event.stopPropagation()}
142
+ >
98
143
  {icon ? (
99
144
  <IconButton {...triggerProps} title={label} aria-label={label}>
100
145
  <PlatformIcon icon={icon} size={16} strokeWidth={1.75} />
101
146
  </IconButton>
102
147
  ) : (
103
- <Button {...triggerProps} variant={variant} size={size}>
148
+ <Button
149
+ {...triggerProps}
150
+ variant={variant}
151
+ size={size}
152
+ title={label}
153
+ aria-label={label}
154
+ >
104
155
  <TextTriggerContent>
105
- <span>{label}</span>
156
+ {leadingIcon}
157
+ {iconOnly ? null : <span>{label}</span>}
106
158
  <PlatformIcon icon={ChevronDown} size={13} strokeWidth={1.8} />
107
159
  </TextTriggerContent>
108
160
  </Button>
@@ -10,10 +10,12 @@ export interface MenuDropdownItemProps {
10
10
 
11
11
  const StyledItem = styled.button<{
12
12
  $disabled?: boolean
13
+ $hasIcon?: boolean
13
14
  $tone?: MenuActionItem['tone']
14
15
  }>`
15
16
  display: grid;
16
- grid-template-columns: minmax(0, 1fr) auto;
17
+ grid-template-columns: ${({ $hasIcon }) =>
18
+ $hasIcon ? '16px minmax(0, 1fr) auto' : 'minmax(0, 1fr) auto'};
17
19
  align-items: center;
18
20
  gap: var(--platform-spacing-md);
19
21
  width: 100%;
@@ -36,7 +38,19 @@ const StyledItem = styled.button<{
36
38
  background: var(--platform-colors-surface-hover);
37
39
  }
38
40
 
39
- & > span:first-child {
41
+ .menu-item-icon {
42
+ display: inline-flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ color: var(--platform-colors-text);
46
+
47
+ > svg {
48
+ width: 16px;
49
+ height: 16px;
50
+ }
51
+ }
52
+
53
+ .menu-item-label {
40
54
  min-width: 0;
41
55
  overflow: hidden;
42
56
  text-overflow: ellipsis;
@@ -66,6 +80,7 @@ export function MenuDropdownItem({
66
80
  role="menuitem"
67
81
  disabled={item.disabled}
68
82
  $disabled={item.disabled}
83
+ $hasIcon={Boolean(item.icon)}
69
84
  $tone={item.tone}
70
85
  onPointerDown={event => {
71
86
  if (event.pointerType === 'mouse' || event.pointerType === 'touch') {
@@ -75,7 +90,12 @@ export function MenuDropdownItem({
75
90
  }}
76
91
  onClick={selectItem}
77
92
  >
78
- <span>{item.label}</span>
93
+ {item.icon ? (
94
+ <span className="menu-item-icon" aria-hidden="true">
95
+ {item.icon}
96
+ </span>
97
+ ) : null}
98
+ <span className="menu-item-label">{item.label}</span>
79
99
  {item.shortcut ? <StyledShortcut>{item.shortcut}</StyledShortcut> : null}
80
100
  </StyledItem>
81
101
  )
@@ -12,8 +12,8 @@ export const StyledMenuPanel = styled(CollapsibleGrid)<{
12
12
  max-height: inherit;
13
13
  overflow: hidden;
14
14
  padding: var(--platform-spacing-xs, 4px);
15
- border: 1px solid var(--platform-colors-border, #d8dde5);
16
- border-radius: var(--platform-radius-md, 8px);
15
+ border: 1px solid var(--platform-colors-border, #e7e4dd);
16
+ border-radius: var(--platform-radius-md, 0);
17
17
  background: var(--platform-colors-elevated, #ffffff);
18
18
  color: var(--platform-colors-text, #25292f);
19
19
  box-shadow: var(--platform-shadow-md, 0 8px 24px rgba(46, 51, 56, 0.12));
@@ -33,11 +33,11 @@ export const StyledMenuPanel = styled(CollapsibleGrid)<{
33
33
  }
34
34
  `
35
35
 
36
- /** Chat composer menus — matches ChatBox surface (bg, 8px radius, 13px items). */
36
+ /** Chat composer menus — matches ChatBox surface (bg, square, 13px items). */
37
37
  export const StyledChatMenuPanel = styled(StyledMenuPanel)`
38
38
  min-width: 160px;
39
39
  padding: 4px;
40
- border-radius: 8px;
40
+ border-radius: var(--platform-radius-sm);
41
41
  background: var(--platform-colors-bg, #ffffff);
42
42
  box-shadow: 0 4px 16px rgb(from var(--platform-colors-text) r g b / 0.08);
43
43
 
@@ -48,7 +48,7 @@ export const StyledChatMenuPanel = styled(StyledMenuPanel)`
48
48
  button[role='menuitem'] {
49
49
  min-height: 28px;
50
50
  padding: 4px 8px;
51
- border-radius: 6px;
51
+ border-radius: var(--platform-radius-sm);
52
52
  font-size: 13px;
53
53
  line-height: 1.4;
54
54
  }
@@ -62,8 +62,8 @@ export const StyledChatMenuPanel = styled(StyledMenuPanel)`
62
62
  export const StyledPaletteMenuPanel = styled(StyledMenuPanel)`
63
63
  min-width: min(310px, calc(100vw - 24px));
64
64
  padding: 6px;
65
- border-color: var(--platform-colors-border, #d8dde5);
66
- border-radius: var(--platform-radius-md, 8px);
65
+ border-color: var(--platform-colors-border, #e7e4dd);
66
+ border-radius: var(--platform-radius-md, 0);
67
67
  background: var(--platform-colors-elevated, #ffffff);
68
68
  box-shadow: var(--platform-shadow-md, 0 8px 24px rgba(46, 51, 56, 0.12));
69
69
  `
@@ -71,5 +71,5 @@ export const StyledPaletteMenuPanel = styled(StyledMenuPanel)`
71
71
  export const StyledWorkspaceMenuPanel = styled(StyledMenuPanel)`
72
72
  min-width: min(320px, calc(100vw - 24px));
73
73
  padding: 6px;
74
- border-radius: 10px;
74
+ border-radius: var(--platform-radius-md, 0);
75
75
  `