@oxy.so/bloom 4.3.1 → 4.5.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 (134) hide show
  1. package/docs/ai-chat.mdx +4 -0
  2. package/docs/chart-cards.mdx +13 -0
  3. package/docs/layout.mdx +36 -0
  4. package/docs/page-header.mdx +16 -0
  5. package/docs/sidebar.mdx +16 -0
  6. package/lib/commonjs/ai-chat/AiChatContainer.js +16 -13
  7. package/lib/commonjs/ai-chat/AiChatContainer.js.map +1 -1
  8. package/lib/commonjs/chart-cards/sparkline.js +13 -0
  9. package/lib/commonjs/chart-cards/sparkline.js.map +1 -0
  10. package/lib/commonjs/index.js +21 -0
  11. package/lib/commonjs/index.js.map +1 -1
  12. package/lib/commonjs/index.web.js +21 -0
  13. package/lib/commonjs/index.web.js.map +1 -1
  14. package/lib/commonjs/layout/StickySection.js +106 -0
  15. package/lib/commonjs/layout/StickySection.js.map +1 -0
  16. package/lib/commonjs/layout/header-dock.js +61 -0
  17. package/lib/commonjs/layout/header-dock.js.map +1 -0
  18. package/lib/commonjs/layout/index.js +20 -0
  19. package/lib/commonjs/layout/index.js.map +1 -1
  20. package/lib/commonjs/page-header/PageHeader.js +38 -14
  21. package/lib/commonjs/page-header/PageHeader.js.map +1 -1
  22. package/lib/commonjs/sidebar/Sidebar.js +129 -103
  23. package/lib/commonjs/sidebar/Sidebar.js.map +1 -1
  24. package/lib/commonjs/sidebar/SidebarFolder.js +109 -85
  25. package/lib/commonjs/sidebar/SidebarFolder.js.map +1 -1
  26. package/lib/commonjs/sidebar/SidebarRail.js +70 -48
  27. package/lib/commonjs/sidebar/SidebarRail.js.map +1 -1
  28. package/lib/commonjs/styles/web-view-style.js +6 -0
  29. package/lib/commonjs/styles/web-view-style.js.map +1 -1
  30. package/lib/module/ai-chat/AiChatContainer.js +17 -14
  31. package/lib/module/ai-chat/AiChatContainer.js.map +1 -1
  32. package/lib/module/chart-cards/sparkline.js +5 -0
  33. package/lib/module/chart-cards/sparkline.js.map +1 -0
  34. package/lib/module/index.js +1 -1
  35. package/lib/module/index.js.map +1 -1
  36. package/lib/module/index.web.js +1 -1
  37. package/lib/module/index.web.js.map +1 -1
  38. package/lib/module/layout/StickySection.js +101 -0
  39. package/lib/module/layout/StickySection.js.map +1 -0
  40. package/lib/module/layout/header-dock.js +54 -0
  41. package/lib/module/layout/header-dock.js.map +1 -0
  42. package/lib/module/layout/index.js +2 -0
  43. package/lib/module/layout/index.js.map +1 -1
  44. package/lib/module/page-header/PageHeader.js +38 -14
  45. package/lib/module/page-header/PageHeader.js.map +1 -1
  46. package/lib/module/sidebar/Sidebar.js +129 -103
  47. package/lib/module/sidebar/Sidebar.js.map +1 -1
  48. package/lib/module/sidebar/SidebarFolder.js +109 -85
  49. package/lib/module/sidebar/SidebarFolder.js.map +1 -1
  50. package/lib/module/sidebar/SidebarRail.js +70 -48
  51. package/lib/module/sidebar/SidebarRail.js.map +1 -1
  52. package/lib/module/styles/web-view-style.js +5 -0
  53. package/lib/module/styles/web-view-style.js.map +1 -1
  54. package/lib/typescript/commonjs/ai-chat/AiChatContainer.d.ts +1 -1
  55. package/lib/typescript/commonjs/ai-chat/AiChatContainer.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/ai-chat/types.d.ts +2 -0
  57. package/lib/typescript/commonjs/ai-chat/types.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/chart-cards/sparkline.d.ts +4 -0
  59. package/lib/typescript/commonjs/chart-cards/sparkline.d.ts.map +1 -0
  60. package/lib/typescript/commonjs/index.d.ts +2 -1
  61. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  62. package/lib/typescript/commonjs/index.web.d.ts +2 -1
  63. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/layout/StickySection.d.ts +8 -0
  65. package/lib/typescript/commonjs/layout/StickySection.d.ts.map +1 -0
  66. package/lib/typescript/commonjs/layout/header-dock.d.ts +21 -0
  67. package/lib/typescript/commonjs/layout/header-dock.d.ts.map +1 -0
  68. package/lib/typescript/commonjs/layout/index.d.ts +3 -0
  69. package/lib/typescript/commonjs/layout/index.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/page-header/PageHeader.d.ts.map +1 -1
  71. package/lib/typescript/commonjs/page-header/types.d.ts +10 -6
  72. package/lib/typescript/commonjs/page-header/types.d.ts.map +1 -1
  73. package/lib/typescript/commonjs/sidebar/Sidebar.d.ts.map +1 -1
  74. package/lib/typescript/commonjs/sidebar/SidebarFolder.d.ts.map +1 -1
  75. package/lib/typescript/commonjs/sidebar/SidebarRail.d.ts +1 -1
  76. package/lib/typescript/commonjs/sidebar/SidebarRail.d.ts.map +1 -1
  77. package/lib/typescript/commonjs/sidebar/types.d.ts +16 -0
  78. package/lib/typescript/commonjs/sidebar/types.d.ts.map +1 -1
  79. package/lib/typescript/commonjs/styles/web-view-style.d.ts +2 -0
  80. package/lib/typescript/commonjs/styles/web-view-style.d.ts.map +1 -1
  81. package/lib/typescript/module/ai-chat/AiChatContainer.d.ts +1 -1
  82. package/lib/typescript/module/ai-chat/AiChatContainer.d.ts.map +1 -1
  83. package/lib/typescript/module/ai-chat/types.d.ts +2 -0
  84. package/lib/typescript/module/ai-chat/types.d.ts.map +1 -1
  85. package/lib/typescript/module/chart-cards/sparkline.d.ts +4 -0
  86. package/lib/typescript/module/chart-cards/sparkline.d.ts.map +1 -0
  87. package/lib/typescript/module/index.d.ts +2 -1
  88. package/lib/typescript/module/index.d.ts.map +1 -1
  89. package/lib/typescript/module/index.web.d.ts +2 -1
  90. package/lib/typescript/module/index.web.d.ts.map +1 -1
  91. package/lib/typescript/module/layout/StickySection.d.ts +8 -0
  92. package/lib/typescript/module/layout/StickySection.d.ts.map +1 -0
  93. package/lib/typescript/module/layout/header-dock.d.ts +21 -0
  94. package/lib/typescript/module/layout/header-dock.d.ts.map +1 -0
  95. package/lib/typescript/module/layout/index.d.ts +3 -0
  96. package/lib/typescript/module/layout/index.d.ts.map +1 -1
  97. package/lib/typescript/module/page-header/PageHeader.d.ts.map +1 -1
  98. package/lib/typescript/module/page-header/types.d.ts +10 -6
  99. package/lib/typescript/module/page-header/types.d.ts.map +1 -1
  100. package/lib/typescript/module/sidebar/Sidebar.d.ts.map +1 -1
  101. package/lib/typescript/module/sidebar/SidebarFolder.d.ts.map +1 -1
  102. package/lib/typescript/module/sidebar/SidebarRail.d.ts +1 -1
  103. package/lib/typescript/module/sidebar/SidebarRail.d.ts.map +1 -1
  104. package/lib/typescript/module/sidebar/types.d.ts +16 -0
  105. package/lib/typescript/module/sidebar/types.d.ts.map +1 -1
  106. package/lib/typescript/module/styles/web-view-style.d.ts +2 -0
  107. package/lib/typescript/module/styles/web-view-style.d.ts.map +1 -1
  108. package/package.json +18 -1
  109. package/src/ai-chat/AiChatContainer.tsx +4 -1
  110. package/src/ai-chat/types.ts +2 -0
  111. package/src/chart-cards/sparkline.ts +3 -0
  112. package/src/index.ts +4 -0
  113. package/src/index.web.ts +4 -0
  114. package/src/layout/StickySection.tsx +75 -0
  115. package/src/layout/header-dock.tsx +42 -0
  116. package/src/layout/index.ts +4 -0
  117. package/src/page-header/PageHeader.tsx +26 -12
  118. package/src/page-header/types.ts +10 -6
  119. package/src/sidebar/Sidebar.tsx +10 -2
  120. package/src/sidebar/SidebarFolder.tsx +18 -4
  121. package/src/sidebar/SidebarRail.tsx +6 -1
  122. package/src/sidebar/types.ts +16 -0
  123. package/src/styles/web-view-style.ts +5 -0
  124. package/src/__tests__/support/adoption-matrix.ts +0 -703
  125. package/src/__tests__/support/collision-fixture-barrel.ts +0 -20
  126. package/src/__tests__/support/commerce-harness.tsx +0 -97
  127. package/src/__tests__/support/composite.ts +0 -68
  128. package/src/__tests__/support/constructed-style-sheets.ts +0 -68
  129. package/src/__tests__/support/press-host.ts +0 -30
  130. package/src/__tests__/support/rendered-style.ts +0 -99
  131. package/src/__tests__/support/unread-hook-fixture.ts +0 -33
  132. package/src/theme/__tests__/__fixtures__/golden-resolved-tokens.json +0 -9346
  133. package/src/theme/__tests__/__fixtures__/tonal-glass-primary-failures.json +0 -69
  134. package/src/theme/__tests__/fixtures/color-engine-golden.json +0 -1
@@ -61,7 +61,8 @@ function TreeRow({
61
61
  }) {
62
62
  const { state: hovered, onIn, onOut } = useInteractionState();
63
63
  const style: WebCssStyle = {
64
- width: '100%',
64
+ flex: 1,
65
+ minWidth: 0,
65
66
  flexDirection: 'row',
66
67
  alignItems: 'center',
67
68
  gap: 10,
@@ -74,6 +75,8 @@ function TreeRow({
74
75
  '--bloom-sidebar-ring': palette.ring,
75
76
  };
76
77
  return (
78
+ <View style={{ flexDirection: 'row', alignItems: 'center', width: '100%' }}
79
+ onPointerEnter={item.onPrefetch} onTouchStart={item.onPrefetch}>
77
80
  <Pressable
78
81
  {...(IS_WEB
79
82
  ? {
@@ -88,7 +91,9 @@ function TreeRow({
88
91
  focusable={focusable}
89
92
  onHoverIn={onIn}
90
93
  onHoverOut={onOut}
94
+ onLongPress={item.onLongPress}
91
95
  onPress={(event: GestureResponderEvent) => {
96
+ item.onPrefetch?.();
92
97
  if (!onPress) return;
93
98
  if (IS_WEB && item.href) event.preventDefault();
94
99
  onPress(item, folder);
@@ -116,6 +121,8 @@ function TreeRow({
116
121
  </View>
117
122
  ) : null}
118
123
  </Pressable>
124
+ {item.actions}
125
+ </View>
119
126
  );
120
127
  }
121
128
 
@@ -148,9 +155,9 @@ function SidebarFolderComponent({
148
155
  const reducedMotion = useReducedMotion();
149
156
  const { state: hovered, onIn, onOut } = useInteractionState();
150
157
  const [isOpen, setOpen] = useControllableState<boolean>({
151
- value: open,
158
+ value: open ?? folder.open,
152
159
  defaultValue: folder.defaultOpen ?? false,
153
- onChange: onOpenChange,
160
+ onChange: onOpenChange ?? folder.onOpenChange,
154
161
  });
155
162
  const expanded = forceOpen || isOpen;
156
163
  const Icon = expanded ? RiFolderOpenLine : RiFolderLine;
@@ -176,7 +183,8 @@ function SidebarFolderComponent({
176
183
  );
177
184
 
178
185
  const rowStyle: WebCssStyle = {
179
- width: '100%',
186
+ flex: 1,
187
+ minWidth: 0,
180
188
  flexDirection: 'row',
181
189
  alignItems: 'center',
182
190
  gap: 8,
@@ -188,6 +196,7 @@ function SidebarFolderComponent({
188
196
 
189
197
  return (
190
198
  <View testID={testID} style={[{ width: '100%', flexDirection: 'column' }, style]}>
199
+ <View style={{ flexDirection: 'row', alignItems: 'center' }}>
191
200
  <Pressable
192
201
  {...(IS_WEB ? { dataSet: { bloomSidebar: 'ring' } } : {})}
193
202
  role="button"
@@ -205,9 +214,14 @@ function SidebarFolderComponent({
205
214
  {folder.label}
206
215
  </Text>
207
216
  </Pressable>
217
+ {folder.actions}
218
+ </View>
208
219
  <Animated.View
209
220
  aria-hidden={!expanded}
210
221
  pointerEvents={expanded ? 'auto' : 'none'}
222
+ accessibilityElementsHidden={!expanded}
223
+ importantForAccessibility={expanded ? 'auto' : 'no-hide-descendants'}
224
+ {...(IS_WEB && !expanded ? { inert: true } : {})}
211
225
  style={[{ overflow: 'hidden' }, clipStyle]}>
212
226
  <View onLayout={onContentLayout} style={{ position: 'relative', width: '100%', flexDirection: 'column', gap: 2, paddingTop: 2 }}>
213
227
  <TreeConnector count={folder.items.length} color={palette.iconQuaternary} />
@@ -29,6 +29,7 @@ export function SidebarRail({
29
29
  logo,
30
30
  items = [],
31
31
  primaryAction,
32
+ contentAlignment = 'start',
32
33
  footer,
33
34
  secondaryItems = [],
34
35
  selected,
@@ -81,6 +82,8 @@ export function SidebarRail({
81
82
  style,
82
83
  ]}
83
84
  >
85
+ <View testID={`${testID ?? 'sidebar'}-main-region`} style={{ flex: 1, minHeight: 0, justifyContent: contentAlignment === 'center' ? 'center' : undefined }}>
86
+ <View style={{ minHeight: 0, flexShrink: 1, ...(contentAlignment === 'start' ? { flex: 1 } : {}) }}>
84
87
  {logo ? (
85
88
  <View style={{ flexShrink: 0, alignItems: 'center', paddingTop: 24 }}>
86
89
  <SidebarLogoView logo={logo} showWordmark={false} testID="sidebar-logo" />
@@ -90,7 +93,7 @@ export function SidebarRail({
90
93
  fadeColor={palette.flat}
91
94
  testID={testID ? `${testID}-scroll` : 'sidebar-rail-scroll'}
92
95
  {...(IS_WEB ? { dataSet: { bloomSidebarScroll: 'none' } } : {})}
93
- style={{ flex: 1 }}
96
+ style={contentAlignment === 'center' ? { flexGrow: 0, flexShrink: 1, minHeight: 0 } : { flex: 1 }}
94
97
  contentContainerStyle={{
95
98
  flexGrow: 1,
96
99
  justifyContent: 'center',
@@ -109,6 +112,8 @@ export function SidebarRail({
109
112
  {primaryAction ? <View style={{ flexShrink: 0, paddingLeft: 8, paddingRight: 8, paddingBottom: 24 }}>
110
113
  <SidebarPrimaryAction action={primaryAction} rail testID={testID ? `${testID}-primary-action` : undefined} />
111
114
  </View> : null}
115
+ </View>
116
+ </View>
112
117
  {secondaryItems.length > 0 ? (
113
118
  <View
114
119
  role="navigation"
@@ -232,6 +232,8 @@ export interface SidebarUserMenuProps {
232
232
  }
233
233
 
234
234
  export interface SidebarProps {
235
+ /** Center the main navigation group in space above the persistent footer. */
236
+ contentAlignment?: 'start' | 'center';
235
237
  /** App-owned destination content after the built-in rows/tree, inside the same
236
238
  * scroll viewport. Hidden and noninteractive while collapsed; remains mounted
237
239
  * so pagination and disclosure state survive. Not rendered in variant="rail".
@@ -298,6 +300,9 @@ export interface SidebarProps {
298
300
  showThemeToggle?: boolean;
299
301
  /** Quick search over the rows. Defaults to true. */
300
302
  showSearch?: boolean;
303
+ /** Controlled quick-search text; also lets app-owned content filter the same query. */
304
+ searchQuery?: string;
305
+ onSearchQueryChange?: (query: string) => void;
301
306
  /** Shortcut hint on the quick-search button. Defaults to "⌘L". */
302
307
  searchShortcutLabel?: string;
303
308
  /** Binds ⌘L / Ctrl+L on web. Defaults to true. */
@@ -334,6 +339,11 @@ export interface SidebarProps {
334
339
 
335
340
  /** A row under a tree folder. */
336
341
  export interface SidebarTreeItem {
342
+ /** Secondary controls beside the row, never nested inside its press target. */
343
+ actions?: ReactNode;
344
+ /** Warm navigation data on hover/touch and before selection. */
345
+ onPrefetch?: () => void;
346
+ onLongPress?: () => void;
337
347
  key: string;
338
348
  label: string;
339
349
  /** A short chip on the right, e.g. a relative time (`34m`, `now`). */
@@ -343,6 +353,10 @@ export interface SidebarTreeItem {
343
353
  }
344
354
 
345
355
  export interface SidebarTreeFolder {
356
+ /** Secondary controls beside the disclosure, such as edit/create menus. */
357
+ actions?: ReactNode;
358
+ open?: boolean;
359
+ onOpenChange?: (open: boolean) => void;
346
360
  key: string;
347
361
  label: string;
348
362
  items: ReadonlyArray<SidebarTreeItem>;
@@ -351,6 +365,8 @@ export interface SidebarTreeFolder {
351
365
  }
352
366
 
353
367
  export interface SidebarTree {
368
+ /** Collection actions, e.g. create a project, beside the section label. */
369
+ actions?: ReactNode;
354
370
  /** The section label, e.g. `Repositories`. */
355
371
  label: string;
356
372
  folders: ReadonlyArray<SidebarTreeFolder>;
@@ -118,3 +118,8 @@ export interface WebCssStyle extends ViewStyle {
118
118
  */
119
119
  [customProperty: `--${string}`]: string | undefined;
120
120
  }
121
+
122
+ /** Position a secondary sticky row below measured chrome, retaining panel inset. */
123
+ export function webSurfaceStickyTopPlus(px: number): ViewStyle['top'] {
124
+ return `calc(var(--bloom-panel-sticky-top, 0px) + ${px}px)` as ViewStyle['top'];
125
+ }