@workbench-kit/react 0.0.2-prototype.0.2.4 → 0.0.2-prototype.0.2.40

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 (221) hide show
  1. package/README.md +172 -0
  2. package/package.json +38 -21
  3. package/src/index.ts +74 -34
  4. package/src/jdw/JsonCodeEditorPane.tsx +7 -6
  5. package/src/jdw/builtins/renderBuiltinWidgetLeaf.tsx +1 -3
  6. package/src/jdw/createBuiltinJdwRegistry.ts +1 -4
  7. package/src/jdw/cssRenderBackend.tsx +1 -4
  8. package/src/jdw/fixtures/jdw-fixtures.ts +0 -15
  9. package/src/json-config/JsonConfigWorkbench.tsx +1 -1
  10. package/src/layout/index.ts +11 -2
  11. package/src/layout/panel/Panel.tsx +0 -3
  12. package/src/layout/panel/index.ts +0 -2
  13. package/src/layout/sidebar/SideBarTree.tsx +301 -0
  14. package/src/layout/sidebar/SidebarActionIconBar.tsx +3 -3
  15. package/src/layout/sidebar/WorkbenchSidebarActions.tsx +1 -1
  16. package/src/layout/sidebar/index.ts +13 -0
  17. package/src/modal/Modal.tsx +55 -25
  18. package/src/modal/ModalTitlebar.tsx +8 -8
  19. package/src/modal/modalPosition.ts +3 -6
  20. package/src/modal/useModalFocusTrap.ts +142 -0
  21. package/src/modal/useModalWindowFrame.ts +2 -2
  22. package/src/overlay/ContextMenu.tsx +133 -21
  23. package/src/overlay/context-menu-density.css +22 -0
  24. package/src/overlay/context-menu-item.ts +17 -0
  25. package/src/overlay/context-menu.css +6 -2
  26. package/src/overlay/index.ts +6 -1
  27. package/src/overlay/measureAnchoredOverlayPanel.ts +4 -6
  28. package/src/overlay/pointerPassthroughRegion.ts +17 -1
  29. package/src/overlay/usePointerPassthroughRegion.ts +35 -6
  30. package/src/primitives/absolute-box/AbsoluteBox.tsx +4 -4
  31. package/src/primitives/app-icon/AppIcon.tsx +33 -0
  32. package/src/primitives/app-icon/app-icon.css +28 -0
  33. package/src/primitives/button/Button.tsx +4 -4
  34. package/src/primitives/catalog-browse-card/CatalogBrowseCard.tsx +6 -6
  35. package/src/primitives/catalog-browse-pane/CatalogBrowsePane.tsx +39 -32
  36. package/src/primitives/catalog-browse-pane/catalog-browse-pane.css +4 -0
  37. package/src/primitives/catalog-filter-overlay/CatalogFilterOverlay.tsx +2 -2
  38. package/src/primitives/checkbox/Checkbox.tsx +1 -1
  39. package/src/primitives/chip/Chip.tsx +3 -12
  40. package/src/primitives/chip/index.ts +2 -2
  41. package/src/primitives/codicon/Codicon.tsx +1 -1
  42. package/src/primitives/file-icon/FileIcon.tsx +1 -1
  43. package/src/primitives/icon-button/IconButton.tsx +1 -1
  44. package/src/primitives/index.ts +7 -2
  45. package/src/primitives/library-detail-layout/LibraryDetailLayout.tsx +123 -9
  46. package/src/primitives/library-detail-layout/library-detail-layout.css +57 -0
  47. package/src/primitives/library-detail-layout/resolve-hero-cover-media.ts +80 -0
  48. package/src/primitives/library-facet-filter-panel/LibraryFacetFilterPanel.tsx +12 -12
  49. package/src/primitives/library-facet-filter-strip/LibraryFacetFilterStrip.tsx +4 -4
  50. package/src/primitives/number-input/NumberInput.tsx +5 -5
  51. package/src/primitives/primitives.css +1 -0
  52. package/src/primitives/record-media-hero/RecordMediaHero.tsx +10 -6
  53. package/src/primitives/scroll-area/ScrollArea.tsx +5 -5
  54. package/src/primitives/scroll-area-infinite-load/useScrollAreaInfiniteLoad.ts +5 -5
  55. package/src/primitives/searchable-multi-select/SearchableMultiSelect.tsx +7 -7
  56. package/src/primitives/select/Select.tsx +1 -13
  57. package/src/primitives/text-area/TextArea.tsx +1 -1
  58. package/src/primitives/text-input/TextInput.tsx +1 -1
  59. package/src/primitives/workbench-media-slot/WorkbenchMediaPlaceholder.tsx +2 -2
  60. package/src/primitives/workbench-media-slot/WorkbenchMediaSlot.tsx +16 -10
  61. package/src/primitives/workbench-thumbnail/WorkbenchThumbnail.tsx +4 -4
  62. package/src/scrollbars.css +2 -6
  63. package/src/styles/core.css +16 -0
  64. package/src/styles/foundation.css +4 -0
  65. package/src/styles/overlay.css +2 -0
  66. package/src/styles.css +1 -15
  67. package/src/utils/clamp.ts +4 -0
  68. package/src/utils/normalizeKeyToken.ts +13 -0
  69. package/src/utils/readNumber.ts +4 -0
  70. package/src/widget-tree/WidgetSourceEditor.tsx +0 -14
  71. package/src/widget-tree/WidgetTreeCanvasPreview.tsx +3 -10
  72. package/src/widget-tree/WidgetTreeLab.tsx +2 -23
  73. package/src/widget-tree/WidgetTreeSidePanel.tsx +0 -5
  74. package/src/widget-tree/WidgetTreeWorkspaceShell.tsx +2 -2
  75. package/src/widget-tree/index.ts +1 -5
  76. package/src/workbench/auth/WorkbenchLoginView.tsx +1 -2
  77. package/src/workbench/auth/auth-flows.css +14 -0
  78. package/src/workbench/chat/ChatCommandProposalCard.tsx +4 -4
  79. package/src/workbench/chat/ChatConversationBar.tsx +3 -3
  80. package/src/workbench/chat/ChatHistoryMenu.tsx +1 -1
  81. package/src/workbench/chat/ChatMessageCollapsible.tsx +4 -0
  82. package/src/workbench/chat/ChatMessageItem.tsx +68 -10
  83. package/src/workbench/chat/ChatMessageList.tsx +1 -1
  84. package/src/workbench/chat/ChatPanel.tsx +32 -23
  85. package/src/workbench/chat/ChatPhasedRunProgress.tsx +86 -13
  86. package/src/workbench/chat/ChatRenameDialog.tsx +1 -1
  87. package/src/workbench/chat/chat-conversation.css +2 -2
  88. package/src/workbench/chat/chat-ui.css +8 -0
  89. package/src/workbench/chat/chatConversation.ts +2 -2
  90. package/src/workbench/chat/chatMessageMeta.tsx +4 -4
  91. package/src/workbench/chat/index.ts +1 -0
  92. package/src/workbench/chat/types.ts +7 -7
  93. package/src/workbench/chat/useCancelRuntimeOnUnmount.ts +4 -4
  94. package/src/workbench/chat/useChatPrependPagination.ts +10 -10
  95. package/src/workbench/chat/useSlashCommandSuggest.ts +1 -1
  96. package/src/workbench/{WorkbenchModalPortal.tsx → chrome/WorkbenchModalPortal.tsx} +1 -1
  97. package/src/workbench/chrome/workbench-chrome.css +4 -0
  98. package/src/workbench/chrome/workbench-layout-regions.css +13 -0
  99. package/src/workbench/chrome/workbench-shell-titlebar.css +0 -8
  100. package/src/workbench/{CommandGroupShell.tsx → commands/CommandGroupShell.tsx} +2 -2
  101. package/src/workbench/{CommandList.tsx → commands/CommandList.tsx} +6 -5
  102. package/src/workbench/{CommandPalette.tsx → commands/CommandPalette.tsx} +16 -42
  103. package/src/workbench/{ConfirmationFlow.tsx → commands/ConfirmationFlow.tsx} +5 -5
  104. package/src/workbench/{ShortcutCommandBridge.tsx → commands/ShortcutCommandBridge.tsx} +17 -13
  105. package/src/workbench/commands/WorkbenchQuickOpen.tsx +462 -0
  106. package/src/workbench/{command-model.ts → commands/command-model.ts} +5 -1
  107. package/src/workbench/commands/command-ui.ts +3 -0
  108. package/src/workbench/{commands.ts → commands/commands.ts} +45 -1
  109. package/src/workbench/commands/createWorkspaceFilesQuickOpenProvider.ts +86 -0
  110. package/src/workbench/commands/quick-open-model.ts +66 -0
  111. package/src/workbench/{WorkbenchEditorTabs.tsx → editor/WorkbenchEditorTabs.tsx} +13 -3
  112. package/src/workbench/{editor-tabs-dnd.ts → editor/editor-tabs-dnd.ts} +1 -1
  113. package/src/workbench/{editorTabContextMenu.ts → editor/editorTabContextMenu.ts} +43 -4
  114. package/src/workbench/{useEditorTabsStripDnd.ts → editor/useEditorTabsStripDnd.ts} +1 -1
  115. package/src/workbench/{useWorkbenchEditorTabContextMenu.tsx → editor/useWorkbenchEditorTabContextMenu.tsx} +16 -2
  116. package/src/workbench/editor-tabs/index.ts +10 -9
  117. package/src/workbench/index.ts +114 -74
  118. package/src/workbench/management/CommandManagementSidebar.tsx +16 -30
  119. package/src/workbench/management/ExtensionManagementPanel.tsx +84 -46
  120. package/src/workbench/management/ExtensionManagementSidebar.tsx +79 -45
  121. package/src/workbench/management/IntegrationCommandActions.tsx +8 -1
  122. package/src/workbench/management/IntegrationSettingsSurface.tsx +2 -5
  123. package/src/workbench/management/IntegrationsShell.tsx +1 -1
  124. package/src/workbench/management/KeybindingCaptureField.tsx +1 -9
  125. package/src/workbench/management/WorkbenchDialogFrame.tsx +2 -2
  126. package/src/workbench/management/WorkbenchNotice.tsx +17 -12
  127. package/src/workbench/management/createWorkbenchNotify.tsx +88 -0
  128. package/src/workbench/management/extension-install-approval.ts +72 -0
  129. package/src/workbench/management/extension-management-filters.ts +38 -0
  130. package/src/workbench/management/index.ts +18 -3
  131. package/src/workbench/management/management.css +28 -0
  132. package/src/workbench/management/types.ts +23 -1
  133. package/src/workbench/management/useWorkbenchNotify.ts +10 -0
  134. package/src/workbench/{MarkdownPreview.tsx → markdown/MarkdownPreview.tsx} +22 -7
  135. package/src/workbench/markdown/markdownRemarkPlugins.ts +12 -0
  136. package/src/workbench/markdown/sanitizeMarkdownHref.ts +29 -0
  137. package/src/workbench/schema/workbenchDocumentRenderer.tsx +48 -121
  138. package/src/workbench/settings/StructuredDataForm.tsx +1 -4
  139. package/src/workbench/settings/StructuredDataSchemaPanel.tsx +39 -44
  140. package/src/workbench/settings/sectionedPanelScrollSpy.ts +0 -81
  141. package/src/workbench/settings/structuredDataFormModel.ts +2 -1
  142. package/src/workbench/settings/structuredDataSchema.ts +24 -13
  143. package/src/workbench/settings/structuredDataSchemaSection.ts +4 -0
  144. package/src/workbench/settings/structuredDataSchemaTable.ts +5 -2
  145. package/src/workbench/{ActivityBar.tsx → shell/ActivityBar.tsx} +8 -12
  146. package/src/workbench/{ArtifactShell.tsx → shell/ArtifactShell.tsx} +25 -25
  147. package/src/workbench/{SplitView.tsx → shell/SplitView.tsx} +3 -3
  148. package/src/workbench/{StatusBar.tsx → shell/StatusBar.tsx} +8 -8
  149. package/src/workbench/{StructuredArtifactEditor.tsx → shell/StructuredArtifactEditor.tsx} +9 -9
  150. package/src/workbench/{Timeline.tsx → shell/Timeline.tsx} +77 -20
  151. package/src/workbench/{WorkbenchCanvasShell.defaults.ts → shell/WorkbenchCanvasShell.defaults.ts} +1 -1
  152. package/src/workbench/{WorkbenchCanvasShell.model.ts → shell/WorkbenchCanvasShell.model.ts} +5 -5
  153. package/src/workbench/{WorkbenchCanvasShell.tsx → shell/WorkbenchCanvasShell.tsx} +6 -6
  154. package/src/workbench/{WorkbenchDesktopTitleBar.tsx → shell/WorkbenchDesktopTitleBar.tsx} +15 -15
  155. package/src/workbench/{WorkbenchShell.tsx → shell/WorkbenchShell.tsx} +45 -6
  156. package/src/workbench/{WorkbenchShellTitleBarLayoutControls.tsx → shell/WorkbenchShellTitleBarLayoutControls.tsx} +16 -19
  157. package/src/workbench/{WorkbenchStandaloneShell.tsx → shell/WorkbenchStandaloneShell.tsx} +15 -22
  158. package/src/workbench/{WorkbenchViewEditor.tsx → shell/WorkbenchViewEditor.tsx} +7 -7
  159. package/src/workbench/{WorkbenchViewSidebar.tsx → shell/WorkbenchViewSidebar.tsx} +7 -7
  160. package/src/workbench/{WorkbenchWindowChromeControls.tsx → shell/WorkbenchWindowChromeControls.tsx} +18 -15
  161. package/src/workbench/shell/activity-bar.css +47 -0
  162. package/src/workbench/{activityBarOrder.ts → shell/activityBarOrder.ts} +2 -1
  163. package/src/workbench/{shell.ts → shell/shell.ts} +20 -13
  164. package/src/workbench/{shellViewModel.ts → shell/shellViewModel.ts} +3 -3
  165. package/src/workbench/{standalone.ts → shell/standalone.ts} +14 -2
  166. package/src/workbench/{useDeferredWorkbenchMount.ts → shell/useDeferredWorkbenchMount.ts} +3 -3
  167. package/src/workbench/{useWorkbenchAppearanceDocumentSync.tsx → shell/useWorkbenchAppearanceDocumentSync.tsx} +1 -1
  168. package/src/workbench/{useWorkbenchSidebarActionBarDnd.ts → shell/useWorkbenchSidebarActionBarDnd.ts} +1 -1
  169. package/src/workbench/{useWorkbenchSidebarViewPlacementDropZone.ts → shell/useWorkbenchSidebarViewPlacementDropZone.ts} +2 -2
  170. package/src/workbench/{workbenchSidebarLayoutContext.ts → shell/workbenchSidebarLayoutContext.ts} +0 -6
  171. package/src/workbench/{workbenchViewRouteState.ts → shell/workbenchViewRouteState.ts} +4 -4
  172. package/src/workbench/{WorkbenchThemeProvider.tsx → theme/WorkbenchThemeProvider.tsx} +4 -4
  173. package/src/workbench/{theme.ts → theme/theme.ts} +1 -1
  174. package/src/workbench/{themePresets.ts → theme/themePresets.ts} +3 -2
  175. package/src/workbench/views/command-list-density.css +36 -0
  176. package/src/workbench/views/command-list.css +2 -0
  177. package/src/workbench/views/extensions-sidebar.css +2 -0
  178. package/src/workbench/views/view-hosts.css +3 -3
  179. package/src/workbench/workspace/WorkspaceEditorPanel.tsx +1 -1
  180. package/src/workbench/workspace/WorkspaceExplorer.tsx +105 -4
  181. package/src/workbench/workspace/createVirtualWorkspaceExplorerPort.ts +1 -14
  182. package/src/workbench/workspace/workspaceExplorerKeyboard.ts +109 -0
  183. package/src/workbench/workspace/workspaceJsonDiagnostics.ts +6 -5
  184. package/src/workbench-menu-surfaces.css +3 -57
  185. package/src/brand/TilepaperAppIcon.tsx +0 -181
  186. package/src/brand/index.ts +0 -2
  187. package/src/brand/tilepaper-app-icon-geometry.ts +0 -201
  188. package/src/primitives/absolute-box/index.ts +0 -1
  189. package/src/primitives/catalog-browse-card/index.ts +0 -1
  190. package/src/primitives/catalog-browse-pane/index.ts +0 -3
  191. package/src/primitives/catalog-filter-overlay/index.ts +0 -1
  192. package/src/primitives/codicon/index.ts +0 -1
  193. package/src/primitives/external-link-button/index.ts +0 -1
  194. package/src/primitives/library-detail-layout/index.ts +0 -1
  195. package/src/primitives/library-facet-filter-panel/index.ts +0 -1
  196. package/src/primitives/library-facet-filter-strip/index.ts +0 -1
  197. package/src/primitives/panel-loading/index.ts +0 -1
  198. package/src/primitives/scroll-area-infinite-load/index.ts +0 -2
  199. package/src/primitives/workbench-thumbnail/index.ts +0 -1
  200. package/src/test-utils/workbenchMonacoMock.tsx +0 -37
  201. package/src/workbench/jdw/jdw-editors.css +0 -4
  202. package/src/workbench/jdw/jdw.css +0 -2
  203. package/src/workbench/management/integration-command-action.ts +0 -25
  204. package/src/workbench/markdownRemarkPlugins.ts +0 -4
  205. package/src/workbench/workbench-chrome.css +0 -4
  206. /package/src/workbench/{WorkbenchPlatformContext.tsx → chrome/WorkbenchPlatformContext.tsx} +0 -0
  207. /package/src/workbench/{workbenchModalViewState.ts → chrome/workbenchModalViewState.ts} +0 -0
  208. /package/src/workbench/{workbenchOverlaysContext.tsx → chrome/workbenchOverlaysContext.tsx} +0 -0
  209. /package/src/workbench/{workbenchPlatformChrome.ts → chrome/workbenchPlatformChrome.ts} +0 -0
  210. /package/src/workbench/{command-execution-policy.ts → commands/command-execution-policy.ts} +0 -0
  211. /package/src/workbench/{keyboard.ts → commands/keyboard.ts} +0 -0
  212. /package/src/workbench/{workbenchContextMenu.ts → commands/workbenchContextMenu.ts} +0 -0
  213. /package/src/workbench/{appearanceLabels.ts → shell/appearanceLabels.ts} +0 -0
  214. /package/src/workbench/{hardReset.ts → shell/hardReset.ts} +0 -0
  215. /package/src/workbench/{shellPresets.ts → shell/shellPresets.ts} +0 -0
  216. /package/src/workbench/{shellState.ts → shell/shellState.ts} +0 -0
  217. /package/src/workbench/{sidebarViewPlacementDnd.ts → shell/sidebarViewPlacementDnd.ts} +0 -0
  218. /package/src/workbench/{status.ts → shell/status.ts} +0 -0
  219. /package/src/workbench/{useWorkbenchSidebarLayout.tsx → shell/useWorkbenchSidebarLayout.tsx} +0 -0
  220. /package/src/workbench/{useWorkbenchStandaloneShellStateSync.tsx → shell/useWorkbenchStandaloneShellStateSync.tsx} +0 -0
  221. /package/src/workbench/{workbenchStandaloneShellReactContext.tsx → shell/workbenchStandaloneShellReactContext.tsx} +0 -0
@@ -38,7 +38,7 @@ export interface LibraryFacetSection {
38
38
  * Uncontrolled initial collapsed state when `collapsibleSections` is true.
39
39
  * When omitted, sections start expanded.
40
40
  */
41
- readonly defaultCollapsed?: boolean | undefined;
41
+ readonly defaultCollapsed?: boolean;
42
42
  readonly fields: ReadonlyArray<LibraryFacetField>;
43
43
  readonly id: string;
44
44
  }
@@ -46,33 +46,33 @@ export interface LibraryFacetSection {
46
46
  export interface LibraryFacetFilterPanelLabels {
47
47
  readonly clearAll: string;
48
48
  readonly clearChipAria: (chipLabel: string) => string;
49
- readonly empty?: string | undefined;
49
+ readonly empty?: string;
50
50
  /** Aria/placeholder for searchable facet input. Default: "Search options". */
51
- readonly filterOptions?: string | undefined;
51
+ readonly filterOptions?: string;
52
52
  /** Shown when option filter matches nothing. Default: "No matching options". */
53
- readonly noMatchingOptions?: string | undefined;
53
+ readonly noMatchingOptions?: string;
54
54
  }
55
55
 
56
56
  export interface LibraryFacetFilterPanelProps {
57
- readonly activeChips?: ReadonlyArray<LibraryFacetActiveChip> | undefined;
58
- readonly className?: string | undefined;
57
+ readonly activeChips?: ReadonlyArray<LibraryFacetActiveChip>;
58
+ readonly className?: string;
59
59
  /**
60
60
  * When true, section headers toggle collapse.
61
61
  * Default false — keeps all sections expanded.
62
62
  */
63
- readonly collapsibleSections?: boolean | undefined;
64
- readonly description?: string | undefined;
63
+ readonly collapsibleSections?: boolean;
64
+ readonly description?: string;
65
65
  readonly labels: LibraryFacetFilterPanelLabels;
66
66
  /** Required when `showActiveChips` is true (chip strip Clear). Host may own Clear otherwise. */
67
- readonly onClearAll?: (() => void) | undefined;
68
- readonly onRemoveChip?: ((chipId: string) => void) | undefined;
67
+ readonly onClearAll?: () => void;
68
+ readonly onRemoveChip?: (chipId: string) => void;
69
69
  readonly onToggleFacetValue: (
70
70
  fieldId: string,
71
71
  value: string,
72
72
  kind: LibraryFacetFieldKind,
73
73
  ) => void;
74
74
  readonly resolveFieldLabel: (fieldId: string) => string;
75
- readonly resolveSectionLabel?: ((sectionId: string) => string) | undefined;
75
+ readonly resolveSectionLabel?: (sectionId: string) => string;
76
76
  readonly sections: ReadonlyArray<LibraryFacetSection>;
77
77
  readonly selectedValues: Readonly<Record<string, readonly string[]>>;
78
78
  /**
@@ -80,7 +80,7 @@ export interface LibraryFacetFilterPanelProps {
80
80
  * selection). Hosts should place Clear in their own header chrome.
81
81
  * Default true for backward compatibility.
82
82
  */
83
- readonly showActiveChips?: boolean | undefined;
83
+ readonly showActiveChips?: boolean;
84
84
  }
85
85
 
86
86
  function sectionHasSelection(
@@ -26,7 +26,7 @@ export type LibraryFacetFieldKind = 'single-select' | 'multi-select';
26
26
  export type LibraryFacetFieldPresentation = 'checklist' | 'searchable-multi';
27
27
 
28
28
  export interface LibraryFacetFieldOption {
29
- readonly count?: number | undefined;
29
+ readonly count?: number;
30
30
  readonly label: string;
31
31
  readonly value: string;
32
32
  }
@@ -43,7 +43,7 @@ export interface LibraryFacetField {
43
43
  * Panel presentation hint. When omitted, long multi-select lists use
44
44
  * `searchable-multi` and short lists use `checklist`.
45
45
  */
46
- readonly presentation?: LibraryFacetFieldPresentation | undefined;
46
+ readonly presentation?: LibraryFacetFieldPresentation;
47
47
  }
48
48
 
49
49
  export interface LibraryFacetActiveChip {
@@ -61,9 +61,9 @@ export interface LibraryFacetFilterStripProps {
61
61
  * When set with `onOpenMoreFilters`, replaces cascade show-more/less with a
62
62
  * menu item that opens the fuller facet panel/dialog.
63
63
  */
64
- readonly moreFiltersLabel?: string | undefined;
64
+ readonly moreFiltersLabel?: string;
65
65
  readonly onClearAll: () => void;
66
- readonly onOpenMoreFilters?: (() => void) | undefined;
66
+ readonly onOpenMoreFilters?: () => void;
67
67
  readonly onShowLess: () => void;
68
68
  readonly onShowMore: () => void;
69
69
  readonly onToggleFacetValue: (
@@ -17,16 +17,16 @@ export interface NumberInputProps extends Omit<
17
17
  TextInputProps,
18
18
  'defaultValue' | 'onValueChange' | 'type' | 'value'
19
19
  > {
20
- defaultValue?: number | undefined;
20
+ defaultValue?: number;
21
21
  /**
22
22
  * When true, `undefined` renders as an empty field. Clearing the input calls
23
23
  * `onEmptyValue` (preferred) instead of `onValueChange`.
24
24
  */
25
- nullable?: boolean | undefined;
25
+ nullable?: boolean;
26
26
  /** Fired when a nullable field is cleared. */
27
- onEmptyValue?: (() => void) | undefined;
28
- onValueChange?: ((value: number, event: ChangeEvent<HTMLInputElement>) => void) | undefined;
29
- value?: number | undefined;
27
+ onEmptyValue?: () => void;
28
+ onValueChange?: (value: number, event: ChangeEvent<HTMLInputElement>) => void;
29
+ value?: number;
30
30
  }
31
31
 
32
32
  function resolveStep(step: TextInputProps['step']): number {
@@ -1,5 +1,6 @@
1
1
  /* Primitives component styles — co-located per component folder.
2
2
  * Leaf files are imported from owning TSX for HMR; this hub keeps CSS-only bundles working. */
3
+ @import './app-icon/app-icon.css';
3
4
  @import './badge/badge.css';
4
5
  @import './button/button.css';
5
6
  @import './chip/chip.css';
@@ -9,12 +9,14 @@ import { WorkbenchMediaSlot } from '../workbench-media-slot';
9
9
  export type RecordMediaHeroLayout = 'banner' | 'compact' | 'background';
10
10
 
11
11
  export interface RecordMediaHeroProps extends ComponentPropsWithRef<'div'> {
12
- alt?: string | undefined;
13
- fallbackIcon?: string | undefined;
14
- imageUrl?: string | null | undefined;
15
- layout?: RecordMediaHeroLayout | undefined;
16
- logoUrl?: string | null | undefined;
17
- maxWidth?: number | string | undefined;
12
+ alt?: string;
13
+ fallbackIcon?: string;
14
+ imageUrl?: string | null;
15
+ layout?: RecordMediaHeroLayout;
16
+ logoUrl?: string | null;
17
+ maxWidth?: number | string;
18
+ /** Forwarded when the primary hero/cover image fails to load. */
19
+ onImageError?: () => void;
18
20
  }
19
21
 
20
22
  function resolveMaxWidth(maxWidth: number | string | undefined): CSSProperties['maxWidth'] {
@@ -33,6 +35,7 @@ export function RecordMediaHero({
33
35
  layout = 'banner',
34
36
  logoUrl = null,
35
37
  maxWidth,
38
+ onImageError,
36
39
  style,
37
40
  ...props
38
41
  }: RecordMediaHeroProps) {
@@ -66,6 +69,7 @@ export function RecordMediaHero({
66
69
  imageClassName="ui-record-media-hero__image"
67
70
  imageUrl={imageUrl}
68
71
  loading="eager"
72
+ onImageError={onImageError}
69
73
  />
70
74
  {logoMedia.shouldShowImage ? (
71
75
  <img
@@ -19,11 +19,11 @@ export type ScrollAreaOrientation = 'both' | 'horizontal' | 'vertical';
19
19
  export type ScrollAreaScrollbarVisibility = 'auto' | 'hidden' | 'overlay';
20
20
 
21
21
  export interface ScrollAreaProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
22
- as?: ElementType | undefined;
23
- children?: ReactNode | undefined;
24
- gutter?: ScrollAreaGutter | undefined;
25
- orientation?: ScrollAreaOrientation | undefined;
26
- scrollbars?: ScrollAreaScrollbarVisibility | undefined;
22
+ as?: ElementType;
23
+ children?: ReactNode;
24
+ gutter?: ScrollAreaGutter;
25
+ orientation?: ScrollAreaOrientation;
26
+ scrollbars?: ScrollAreaScrollbarVisibility;
27
27
  }
28
28
 
29
29
  type OverlayThumb = {
@@ -3,13 +3,13 @@ import { useEffect, useRef, type RefObject } from 'react';
3
3
  const DEFAULT_ROOT_MARGIN = '0px 0px 120px 0px';
4
4
 
5
5
  export interface UseScrollAreaInfiniteLoadOptions {
6
- enabled?: boolean | undefined;
6
+ enabled?: boolean;
7
7
  hasMore: boolean;
8
- isLoading?: boolean | undefined;
9
- isLoadingMore?: boolean | undefined;
8
+ isLoading?: boolean;
9
+ isLoadingMore?: boolean;
10
10
  onLoadMore: () => void | Promise<void>;
11
- rootMargin?: string | undefined;
12
- scrollAreaRef?: RefObject<HTMLElement | null> | undefined;
11
+ rootMargin?: string;
12
+ scrollAreaRef?: RefObject<HTMLElement | null>;
13
13
  }
14
14
 
15
15
  export interface UseScrollAreaInfiniteLoadResult {
@@ -25,24 +25,24 @@ import {
25
25
  } from './overlay';
26
26
 
27
27
  export interface SearchableMultiSelectOption {
28
- readonly count?: number | undefined;
29
- readonly disabled?: boolean | undefined;
28
+ readonly count?: number;
29
+ readonly disabled?: boolean;
30
30
  readonly label: string;
31
31
  readonly value: string;
32
32
  }
33
33
 
34
34
  export interface SearchableMultiSelectProps {
35
35
  readonly 'aria-label'?: string | undefined;
36
- readonly className?: string | undefined;
37
- readonly disabled?: boolean | undefined;
36
+ readonly className?: string;
37
+ readonly disabled?: boolean;
38
38
  /** Shown when the query matches no options. Default: "No matching options". */
39
- readonly emptyMessage?: string | undefined;
39
+ readonly emptyMessage?: string;
40
40
  /** Aria label for dismissible selected chips. Default: "Remove {label}". */
41
- readonly getRemoveChipAriaLabel?: ((optionLabel: string) => string) | undefined;
41
+ readonly getRemoveChipAriaLabel?: (optionLabel: string) => string;
42
42
  readonly onValueToggle: (value: string) => void;
43
43
  readonly options: ReadonlyArray<SearchableMultiSelectOption>;
44
44
  /** Search input placeholder. Default: "Search". */
45
- readonly searchPlaceholder?: string | undefined;
45
+ readonly searchPlaceholder?: string;
46
46
  readonly selectedValues: readonly string[];
47
47
  }
48
48
 
@@ -16,6 +16,7 @@ import type { ControlWidth } from '../text-input/TextInput';
16
16
  import { cxCodicon } from '../../utils/codicon';
17
17
  import { cx } from '../../utils/cx';
18
18
  import { getEnabledOptionIndex, parseOptions } from './options';
19
+ import { resolvePortalContainer } from '../searchable-multi-select/overlay';
19
20
  import { isTriggerVisible, measureOverlayPosition, overlayListboxStyle } from './overlay';
20
21
  import type { OverlayPosition, ParsedOption } from './types';
21
22
 
@@ -24,19 +25,6 @@ export interface SelectProps extends ComponentPropsWithRef<'select'> {
24
25
  onValueChange?: (value: string, event: ChangeEvent<HTMLSelectElement>) => void;
25
26
  }
26
27
 
27
- /**
28
- * Portaling straight to `document.body` escapes the workbench root (`[data-theme-preset]`),
29
- * which re-declares theme tokens locally and shadows whatever a contributed theme overrides
30
- * on `document.documentElement`. Prefer themed hosts / overlay roots when present.
31
- */
32
- function resolvePortalContainer(trigger: HTMLElement | null): HTMLElement {
33
- return (
34
- trigger?.closest<HTMLElement>(
35
- '[data-theme-preset], [data-theme], .ui-workbench-host-root, .ide-workbench-overlays',
36
- ) ?? document.body
37
- );
38
- }
39
-
40
28
  export function Select({
41
29
  className,
42
30
  controlWidth = 'default',
@@ -7,7 +7,7 @@ type ControlWidth = 'default' | 'wide' | 'full';
7
7
  export interface TextAreaProps extends ComponentPropsWithRef<'textarea'> {
8
8
  controlWidth?: ControlWidth;
9
9
  monospace?: boolean;
10
- resize?: CSSProperties['resize'] | undefined;
10
+ resize?: CSSProperties['resize'];
11
11
  }
12
12
 
13
13
  export function TextArea({
@@ -7,7 +7,7 @@ export type ControlWidth = 'default' | 'wide' | 'full';
7
7
  export interface TextInputProps extends ComponentPropsWithRef<'input'> {
8
8
  controlWidth?: ControlWidth;
9
9
  monospace?: boolean;
10
- onValueChange?: ((value: string, event: ChangeEvent<HTMLInputElement>) => void) | undefined;
10
+ onValueChange?: (value: string, event: ChangeEvent<HTMLInputElement>) => void;
11
11
  }
12
12
 
13
13
  export function TextInput({
@@ -4,8 +4,8 @@ import { cxCodicon } from '../../utils/codicon';
4
4
  import { cx } from '../../utils/cx';
5
5
 
6
6
  export interface WorkbenchMediaPlaceholderProps extends ComponentPropsWithRef<'span'> {
7
- icon?: string | undefined;
8
- iconClassName?: string | undefined;
7
+ icon?: string;
8
+ iconClassName?: string;
9
9
  }
10
10
 
11
11
  /**
@@ -6,20 +6,22 @@ import { useWorkbenchMediaImage } from '../../utils/useWorkbenchMediaImage';
6
6
  import { WorkbenchMediaPlaceholder } from './WorkbenchMediaPlaceholder';
7
7
 
8
8
  export interface WorkbenchMediaSlotProps extends Omit<ComponentPropsWithRef<'span'>, 'children'> {
9
- alt?: string | undefined;
10
- as?: 'div' | 'span' | undefined;
11
- fallback?: ReactNode | undefined;
12
- fallbackClassName?: string | undefined;
13
- fallbackIcon?: string | undefined;
9
+ alt?: string;
10
+ as?: 'div' | 'span';
11
+ fallback?: ReactNode;
12
+ fallbackClassName?: string;
13
+ fallbackIcon?: string;
14
14
  /** Stretch to fill the parent box (hero/cover surfaces). */
15
- fill?: boolean | undefined;
16
- imageClassName?: string | undefined;
17
- imageUrl?: string | null | undefined;
15
+ fill?: boolean;
16
+ imageClassName?: string;
17
+ imageUrl?: string | null;
18
18
  /**
19
19
  * Native image loading hint. Defaults to `lazy` for list/thumbnail surfaces.
20
20
  * Pass `eager` for above-the-fold heroes and detail identity art.
21
21
  */
22
- loading?: 'eager' | 'lazy' | undefined;
22
+ loading?: 'eager' | 'lazy';
23
+ /** Optional host callback after the slot marks the current URL as failed. */
24
+ onImageError?: () => void;
23
25
  }
24
26
 
25
27
  export function WorkbenchMediaSlot({
@@ -33,6 +35,7 @@ export function WorkbenchMediaSlot({
33
35
  imageClassName,
34
36
  imageUrl = null,
35
37
  loading = 'lazy',
38
+ onImageError,
36
39
  ...props
37
40
  }: WorkbenchMediaSlotProps) {
38
41
  const media = useWorkbenchMediaImage(imageUrl);
@@ -47,7 +50,10 @@ export function WorkbenchMediaSlot({
47
50
  alt={alt ?? ''}
48
51
  className={cx('ui-workbench-media-slot__image', imageClassName)}
49
52
  loading={loading}
50
- onError={media.onImageError}
53
+ onError={() => {
54
+ media.onImageError();
55
+ onImageError?.();
56
+ }}
51
57
  src={media.imageSrc}
52
58
  />
53
59
  ) : (
@@ -7,10 +7,10 @@ import { WorkbenchMediaSlot } from '../workbench-media-slot';
7
7
  export type WorkbenchThumbnailSize = 'sm' | 'md' | 'library' | 'icon';
8
8
 
9
9
  export interface WorkbenchThumbnailProps extends Omit<ComponentPropsWithRef<'span'>, 'children'> {
10
- alt?: string | undefined;
11
- fallbackIcon?: string | undefined;
12
- imageUrl?: string | null | undefined;
13
- size?: WorkbenchThumbnailSize | undefined;
10
+ alt?: string;
11
+ fallbackIcon?: string;
12
+ imageUrl?: string | null;
13
+ size?: WorkbenchThumbnailSize;
14
14
  }
15
15
 
16
16
  export function WorkbenchThumbnail({
@@ -117,9 +117,7 @@
117
117
  background-clip: content-box;
118
118
  }
119
119
 
120
- .ui-workbench-scrollbar--hidden,
121
- .workbench-primary-sidebar .ui-sidebar-view__body,
122
- .workbench-primary-sidebar .ui-workbench-sidebar-section__content {
120
+ .ui-workbench-scrollbar--hidden {
123
121
  scrollbar-gutter: auto;
124
122
  scrollbar-width: none;
125
123
  }
@@ -136,9 +134,7 @@
136
134
  }
137
135
 
138
136
  .ui-workbench-scrollbar--hidden::-webkit-scrollbar,
139
- .ui-workbench-scrollbar--overlay::-webkit-scrollbar,
140
- .workbench-primary-sidebar .ui-sidebar-view__body::-webkit-scrollbar,
141
- .workbench-primary-sidebar .ui-workbench-sidebar-section__content::-webkit-scrollbar {
137
+ .ui-workbench-scrollbar--overlay::-webkit-scrollbar {
142
138
  width: 0;
143
139
  height: 0;
144
140
  }
@@ -0,0 +1,16 @@
1
+ /* Core Workbench host styles.
2
+ * Auth and Chat are intentionally excluded so hosts only pay for those
3
+ * product surfaces when they opt into the full `styles.css` bundle. */
4
+ @import '@workbench-kit/tokens/styles.css';
5
+ @import '@vscode/codicons/dist/codicon.css';
6
+ @import '../scrollbars.css';
7
+ @import '../workbench/settings/settings.css';
8
+ @import '../layout/layout.css';
9
+ @import '../overlay/overlay.css';
10
+ @import '../workbench/chrome/workbench-chrome.css';
11
+ @import '../workbench/management/management.css';
12
+ @import '../workbench/views/views.css';
13
+ @import '../workbench/workspace/workspace.css';
14
+ @import '../primitives/primitives.css';
15
+ @import '../workbench/widgets/widgets.css';
16
+ @import '../modal/modal.css';
@@ -0,0 +1,4 @@
1
+ /* Shared theme, icon, and scrollbar foundation for focused CSS compositions. */
2
+ @import '@workbench-kit/tokens/styles.css';
3
+ @import '@vscode/codicons/dist/codicon.css';
4
+ @import '../scrollbars.css';
@@ -0,0 +1,2 @@
1
+ /* Context-menu overlays for focused non-shell compositions. */
2
+ @import '../overlay/overlay.css';
package/src/styles.css CHANGED
@@ -1,17 +1,3 @@
1
- @import '@workbench-kit/tokens/styles.css';
2
- @import '@vscode/codicons/dist/codicon.css';
3
- @import './scrollbars.css';
4
- @import './workbench-menu-surfaces.css';
5
- @import './workbench/settings/settings.css';
6
- @import './layout/layout.css';
7
- @import './overlay/overlay.css';
8
- @import './workbench/workbench-chrome.css';
1
+ @import './styles/core.css';
9
2
  @import './workbench/auth/auth.css';
10
- @import './workbench/management/management.css';
11
- @import './workbench/views/views.css';
12
- @import './workbench/workspace/workspace.css';
13
3
  @import './workbench/chat/chat.css';
14
- @import './primitives/primitives.css';
15
- @import './workbench/widgets/widgets.css';
16
- @import './workbench/jdw/jdw.css';
17
- @import './modal/modal.css';
@@ -0,0 +1,4 @@
1
+ /** Clamp a finite number into the inclusive `[min, max]` range. */
2
+ export function clampNumber(value: number, min: number, max: number): number {
3
+ return Math.min(Math.max(value, min), max);
4
+ }
@@ -0,0 +1,13 @@
1
+ /** Normalize a keyboard shortcut token to a stable lowercase key name. */
2
+ export function normalizeKeyToken(token: string): string {
3
+ const key = token.trim().toLowerCase();
4
+ if (key === 'del') return 'delete';
5
+ if (key === 'esc') return 'escape';
6
+ if (key === 'return') return 'enter';
7
+ if (key === 'spacebar' || key === 'space') return 'space';
8
+ if (key === 'arrowup' || key === 'up') return 'arrowup';
9
+ if (key === 'arrowdown' || key === 'down') return 'arrowdown';
10
+ if (key === 'arrowleft' || key === 'left') return 'arrowleft';
11
+ if (key === 'arrowright' || key === 'right') return 'arrowright';
12
+ return key;
13
+ }
@@ -0,0 +1,4 @@
1
+ /** Return a finite number, or `undefined` when the value is not usable as one. */
2
+ export function readNumber(value: unknown): number | undefined {
3
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
4
+ }
@@ -11,7 +11,6 @@ import {
11
11
  import {
12
12
  JsonCodeEditorPane,
13
13
  type JsonEditorRange,
14
- type JsonEditorPosition,
15
14
  type JsonEditorProblem,
16
15
  } from '../jdw/JsonCodeEditorPane.js';
17
16
  import { JDW_WIDGET_DOCUMENT_MIME } from '../jdw/document.js';
@@ -34,19 +33,6 @@ export interface WidgetSourceEditorProps {
34
33
  readonly onSelectPath?: ((path: WidgetPath) => void) | undefined;
35
34
  }
36
35
 
37
- export function resolveWidgetSourceRevealPosition(
38
- source: string,
39
- path: WidgetPath | null | undefined,
40
- ): JsonEditorPosition | null {
41
- const position = resolveWidgetSourceActiveRange(source, path);
42
- if (!position) return null;
43
-
44
- return {
45
- column: position.startColumn,
46
- lineNumber: position.startLineNumber,
47
- };
48
- }
49
-
50
36
  export function resolveWidgetSourceActiveRange(
51
37
  source: string,
52
38
  path: WidgetPath | null | undefined,
@@ -26,6 +26,7 @@ import {
26
26
  type WidgetResizeHandlePosition,
27
27
  } from '@workbench-kit/jdw';
28
28
 
29
+ import { readNumber } from '../utils/readNumber';
29
30
  import {
30
31
  WorkbenchCanvasFrameHandle,
31
32
  WorkbenchCanvasItemFrame,
@@ -40,6 +41,7 @@ import { usePreviewViewport } from '../layout/usePreviewViewport.js';
40
41
  import { JdwPreview } from '../jdw/JdwPreview.js';
41
42
  import { readWidgetPlacementAssetDragData } from './widget-placement-asset-dnd.js';
42
43
  import { canAddChildren, insertedWidgetPathForParent } from './widget-tree-layout.js';
44
+ import type { WidgetTreeAssetDropOperation } from './WidgetTreeView.js';
43
45
 
44
46
  const RESIZE_HANDLE_POSITIONS = [
45
47
  'n',
@@ -67,12 +69,7 @@ export interface WidgetTreeCanvasPreviewProps {
67
69
  readonly onSelectPath: (path: WidgetPath) => void;
68
70
  }
69
71
 
70
- export interface WidgetTreeCanvasAssetDropOperation {
71
- readonly asset: WidgetPlacementAsset;
72
- readonly parentPath: WidgetPath;
73
- readonly insertIndex: number;
74
- readonly nextPath: WidgetPath;
75
- }
72
+ export type WidgetTreeCanvasAssetDropOperation = WidgetTreeAssetDropOperation;
76
73
 
77
74
  interface WidgetTreeCanvasAssetDropTarget {
78
75
  readonly insertIndex: number;
@@ -221,10 +218,6 @@ function readPositiveInteger(value: unknown): number | null {
221
218
  return Math.floor(value);
222
219
  }
223
220
 
224
- function readNumber(value: unknown): number | undefined {
225
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
226
- }
227
-
228
221
  function appendLineRect(rect: Rect, axis: 'x' | 'y', children: readonly LayoutNodeResult[]): Rect {
229
222
  const lastChildRect = children[children.length - 1]?.rect;
230
223
  if (axis === 'x') {
@@ -31,10 +31,7 @@ import { WorkbenchLabeledPane } from '../layout/panel';
31
31
  import type { WorkspaceEditorTheme } from '../workbench/workspace/WorkspaceEditor.js';
32
32
  import type { JsonEditorProblem } from '../jdw/JsonCodeEditorPane.js';
33
33
  import { WidgetAssetPalette } from './WidgetAssetPalette.js';
34
- import {
35
- WidgetTreeCanvasPreview,
36
- type WidgetTreeCanvasAssetDropOperation,
37
- } from './WidgetTreeCanvasPreview.js';
34
+ import { WidgetTreeCanvasPreview } from './WidgetTreeCanvasPreview.js';
38
35
  import { WidgetInspectorPanel } from './WidgetInspectorPanel.js';
39
36
  import { WidgetSourceEditor } from './WidgetSourceEditor.js';
40
37
  import { WidgetTreeSidePanel } from './WidgetTreeSidePanel.js';
@@ -375,24 +372,6 @@ export function WidgetTreeLab({
375
372
  }
376
373
  };
377
374
 
378
- const handlePlaceAssetPreviewPath = (operation: WidgetTreeCanvasAssetDropOperation) => {
379
- if (!document.root) return;
380
-
381
- const parent = getWidgetAtPath(document.root, operation.parentPath);
382
- if (!parent || !canAddChildren(parent)) return;
383
-
384
- const changed = applyPatch({
385
- type: 'insert-child',
386
- parentPath: operation.parentPath,
387
- index: operation.insertIndex,
388
- child: materializeWidgetPlacementAsset(operation.asset, parent),
389
- });
390
- if (changed) {
391
- setSelection((current) => selectWidgetPath(current, operation.nextPath));
392
- focusPropertyDetailTab();
393
- }
394
- };
395
-
396
375
  const handleRemovePath = (pathToRemove: WidgetPath) => {
397
376
  if (pathToRemove.length === 0) return;
398
377
  const parentPath = pathToRemove.slice(0, -1);
@@ -518,7 +497,7 @@ export function WidgetTreeLab({
518
497
  root={document.root}
519
498
  selectedPath={selectedPath}
520
499
  onPatch={handleCanvasPatch}
521
- onPlaceAssetPath={readOnly ? undefined : handlePlaceAssetPreviewPath}
500
+ onPlaceAssetPath={readOnly ? undefined : handlePlaceAssetPath}
522
501
  onSelectPath={handlePreviewSelectPath}
523
502
  />
524
503
  </WorkbenchLabeledPane>
@@ -1,10 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
2
 
3
- /** @deprecated Side panel no longer switches tabs; all panes stay visible. */
4
- export type WidgetTreeSidePanelTab = 'outline' | 'assets' | 'properties';
5
- /** @deprecated Side panel no longer switches detail tabs. */
6
- export type WidgetTreeSidePanelDetailTab = Exclude<WidgetTreeSidePanelTab, 'outline'>;
7
-
8
3
  export interface WidgetTreeSidePanelProps {
9
4
  readonly outline: ReactNode;
10
5
  readonly properties: ReactNode;
@@ -6,8 +6,8 @@ import {
6
6
  import { validateJsonWidgetData } from '@workbench-kit/jdw';
7
7
 
8
8
  import { SideBarViewFrame } from '../layout/sidebar';
9
- import { WorkbenchShell } from '../workbench/WorkbenchShell.js';
10
- import type { StatusBarSectionModel } from '../workbench/StatusBar.js';
9
+ import { WorkbenchShell } from '../workbench/shell/WorkbenchShell.js';
10
+ import type { StatusBarSectionModel } from '../workbench/shell/StatusBar.js';
11
11
  import {
12
12
  useVirtualWorkspace,
13
13
  WorkspaceDraftsProvider,
@@ -18,11 +18,7 @@ export type {
18
18
  export { WidgetInspectorPanel } from './WidgetInspectorPanel.js';
19
19
  export type { WidgetInspectorPanelProps } from './WidgetInspectorPanel.js';
20
20
  export { WidgetTreeSidePanel } from './WidgetTreeSidePanel.js';
21
- export type {
22
- WidgetTreeSidePanelProps,
23
- WidgetTreeSidePanelDetailTab,
24
- WidgetTreeSidePanelTab,
25
- } from './WidgetTreeSidePanel.js';
21
+ export type { WidgetTreeSidePanelProps } from './WidgetTreeSidePanel.js';
26
22
  export { WidgetAssetPalette } from './WidgetAssetPalette.js';
27
23
  export type { WidgetAssetPaletteProps } from './WidgetAssetPalette.js';
28
24
  export {
@@ -1,5 +1,4 @@
1
1
  import { useId, useState, type FormEvent, type ReactNode } from 'react';
2
- import { TilepaperAppIcon } from '../../brand/TilepaperAppIcon';
3
2
  import { Button } from '../../primitives/button';
4
3
  import { TextInput } from '../../primitives/text-input';
5
4
  import { cx } from '../../utils/cx';
@@ -165,7 +164,7 @@ export interface WorkbenchPasswordResetViewProps {
165
164
  export function WorkbenchLoginBrandMark() {
166
165
  return (
167
166
  <div className="workbench-login-brand-mark" aria-hidden>
168
- <TilepaperAppIcon />
167
+ <span className="workbench-login-brand-mark__glyph">W</span>
169
168
  </div>
170
169
  );
171
170
  }
@@ -135,8 +135,22 @@
135
135
  }
136
136
 
137
137
  .workbench-login-brand-mark {
138
+ box-sizing: border-box;
139
+ display: grid;
140
+ place-items: center;
138
141
  width: 100%;
139
142
  aspect-ratio: 1;
143
+ border: 1px solid var(--color-border);
144
+ border-radius: clamp(28px, 8vw, 72px);
145
+ background: var(--color-surface);
146
+ color: var(--color-text);
147
+ }
148
+
149
+ .workbench-login-brand-mark__glyph {
150
+ font-size: clamp(72px, 14vw, 160px);
151
+ font-weight: 650;
152
+ letter-spacing: -0.08em;
153
+ line-height: 1;
140
154
  }
141
155
 
142
156
  .workbench-login-view__footer-brand {