bubble-toolbar 1.0.0 → 1.2.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { HTMLAttributes, ReactNode, CSSProperties, ButtonHTMLAttributes, ForwardRefExoticComponent, RefAttributes } from 'react';
2
+ import { HTMLAttributes, ReactNode, CSSProperties, ButtonHTMLAttributes, RefAttributes, ReactElement, ForwardRefExoticComponent } from 'react';
3
3
 
4
4
  interface BubbleActivityValue {
5
5
  isBusy: boolean;
@@ -59,8 +59,8 @@ interface BubbleToolbarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'child
59
59
  */
60
60
  blurred?: boolean;
61
61
  /**
62
- * Amount of backdrop blur in pixels or CSS string.
63
- * @default 16
62
+ * Amount of backdrop blur in pixels or CSS string. Negative numbers are clamped to 0.
63
+ * When omitted, the `--bubble-blur` CSS token is used (16px by default).
64
64
  */
65
65
  blurAmount?: number | string;
66
66
  /**
@@ -96,6 +96,11 @@ interface BubbleToolbarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'child
96
96
  * @default 'Toolbar'
97
97
  */
98
98
  ariaLabel?: string;
99
+ /**
100
+ * Controller from useBubbleLiveActivity. While an activity is shown, the groups collapse
101
+ * into a single pill (and then a card) and are restored afterwards, keeping their state.
102
+ */
103
+ liveActivity?: BubbleLiveActivityController;
99
104
  }
100
105
  interface BubbleGroupProps extends HTMLAttributes<HTMLDivElement>, BubbleActivityProps {
101
106
  /**
@@ -166,11 +171,226 @@ interface BubbleAreaProps extends HTMLAttributes<HTMLDivElement> {
166
171
  */
167
172
  maxWidth?: number | string;
168
173
  }
174
+ /** A search result or suggestion. Its shape is fixed so the listbox layout stays intact. */
175
+ interface BubbleSearchItem {
176
+ /** Stable identifier, used as React key. */
177
+ id: string;
178
+ /** Main line of the option. */
179
+ title: string;
180
+ /** Optional secondary line, e.g. a path. */
181
+ description?: string;
182
+ }
183
+ /** Visible and accessible texts of BubbleSearch. */
184
+ interface BubbleSearchLabels {
185
+ /** Accessible name of the search group. @default 'Search' */
186
+ group: string;
187
+ /** Accessible name of the search button. @default 'Search' */
188
+ button: string;
189
+ /** Accessible name of the combobox input. @default 'Search' */
190
+ input: string;
191
+ /** Accessible name of the results listbox. @default 'Results' */
192
+ listbox: string;
193
+ /** @default 'Search…' */
194
+ placeholder: string;
195
+ /** @default 'Searching…' */
196
+ searching: string;
197
+ /** @default 'No results. Try another term or explore a suggestion.' */
198
+ noResults: string;
199
+ /** @default 'Suggestions' */
200
+ suggestions: string;
201
+ /** @default (count) => '1 result' | `${count} results` */
202
+ results: (count: number) => string;
203
+ /** @default '↑ ↓ to explore · Enter to select · Esc to close' */
204
+ hint: string;
205
+ }
206
+ /**
207
+ * Visual tokens of BubbleSearch, written as CSS custom properties `--bubble-search-*`.
208
+ * Numbers are px for lengths and ms for `duration`. Structure and layout are not customizable.
209
+ */
210
+ interface BubbleSearchTokens {
211
+ /** Expanded width, capped to the viewport. @default 360px */
212
+ width?: number | string;
213
+ /** Corner radius of the expanded search. @default 24px */
214
+ radius?: number | string;
215
+ /** Divider between the header and the results. @default rgb(128 128 128 / 18%) */
216
+ divider?: string;
217
+ /** Focus ring of the header. @default #818cf8 */
218
+ focusRing?: string;
219
+ /** Background of the hovered / active option. @default rgb(129 140 248 / 18%) */
220
+ optionActiveBg?: string;
221
+ /** @default 12px */
222
+ optionRadius?: number | string;
223
+ /** Option title size, clamped to 10–20px. @default 13px */
224
+ titleSize?: number | string;
225
+ /** @default 600 */
226
+ titleWeight?: number | string;
227
+ /** Size of descriptions, status and hint, clamped to 9–16px. @default 11px */
228
+ metaSize?: number | string;
229
+ /** Opacity of secondary texts, clamped to 0.4–1. @default 0.7 */
230
+ mutedOpacity?: number | string;
231
+ /** Results max height, capped to the viewport. @default 220px */
232
+ resultsMaxHeight?: number | string;
233
+ /** Panel padding, clamped to 0–16px. @default 8px */
234
+ panelPadding?: number | string;
235
+ /** Expand / collapse duration, clamped to 0–600ms. @default 180ms */
236
+ duration?: number | string;
237
+ /** @default ease */
238
+ easing?: string;
239
+ }
240
+ interface BubbleSearchProps<T extends BubbleSearchItem = BubbleSearchItem> {
241
+ /**
242
+ * Async search. Receives the trimmed, lower-cased query and an AbortSignal that is
243
+ * aborted when the query changes, the search closes or the component unmounts.
244
+ */
245
+ onSearch: (query: string, signal: AbortSignal) => Promise<T[]>;
246
+ /** Called when an option is chosen. The search closes and focus returns to the button. */
247
+ onSelect: (item: T) => void;
248
+ /** Shown while the query is empty and when nothing matches. */
249
+ suggestions?: T[];
250
+ /** Receives errors from onSearch, except cancellations. The status then shows no results. */
251
+ onError?: (error: unknown) => void;
252
+ /** Controlled open state. */
253
+ open?: boolean;
254
+ /** @default false */
255
+ defaultOpen?: boolean;
256
+ onOpenChange?: (open: boolean) => void;
257
+ /** Wait before searching. 0 searches immediately. @default 0 */
258
+ debounceMs?: number;
259
+ labels?: Partial<BubbleSearchLabels>;
260
+ tokens?: BubbleSearchTokens;
261
+ /** Class for the search group, useful to scope tokens in CSS. */
262
+ className?: string;
263
+ }
264
+ /** A breadcrumb level. The last item is the current page. */
265
+ interface BubbleBreadcrumbItem {
266
+ label: string;
267
+ href?: string;
268
+ }
269
+ interface BubbleBreadcrumbSearchLabels extends BubbleSearchLabels {
270
+ /** Accessible name of the breadcrumb navigation. @default 'Breadcrumb' */
271
+ location: string;
272
+ }
273
+ /** BubbleSearch tokens plus `--bubble-breadcrumb-*` tokens. */
274
+ interface BubbleBreadcrumbSearchTokens extends BubbleSearchTokens {
275
+ /** Breadcrumb text size, clamped to 10–16px. @default 12px */
276
+ breadcrumbSize?: number | string;
277
+ /** @default currentColor */
278
+ breadcrumbSeparatorColor?: string;
279
+ /** Weight of the current page. @default 500 */
280
+ breadcrumbCurrentWeight?: number | string;
281
+ /** Opacity of parent levels, clamped to 0.4–1. @default 0.7 */
282
+ breadcrumbMutedOpacity?: number | string;
283
+ }
284
+ interface BubbleBreadcrumbSearchProps<T extends BubbleSearchItem = BubbleSearchItem> extends Omit<BubbleSearchProps<T>, 'labels' | 'tokens'> {
285
+ /** Current location, controlled by the app (usually its router). */
286
+ items: BubbleBreadcrumbItem[];
287
+ /** Text between levels. @default '/' */
288
+ separator?: string;
289
+ labels?: Partial<BubbleBreadcrumbSearchLabels>;
290
+ tokens?: BubbleBreadcrumbSearchTokens;
291
+ }
292
+ /** Content of a Live Activity. Its shape is fixed so the pill and the card keep their layout. */
293
+ interface BubbleLiveContent {
294
+ title: string;
295
+ description?: string;
296
+ /** Replaces the default spinner / outcome icon. */
297
+ icon?: ReactNode;
298
+ /** @default 'success' after a resolved task, 'error' after a rejected one, otherwise 'neutral' */
299
+ tone?: 'neutral' | 'success' | 'error';
300
+ }
301
+ type BubbleLiveState = 'idle' | 'compact' | 'expanded';
302
+ interface BubbleLiveRunOptions<T> {
303
+ /** Shown in the compact pill while the task runs. Defaults to `labels.pending`. */
304
+ pending?: BubbleLiveContent;
305
+ /** Card shown when the task resolves. Defaults to `labels.success`. */
306
+ success?: (value: T) => BubbleLiveContent;
307
+ /** Card shown when the task rejects. Defaults to `labels.error`. */
308
+ error?: (error: unknown) => BubbleLiveContent;
309
+ /** Milliseconds the card stays visible; 0 keeps it until dismissed. Defaults to the controller's. */
310
+ duration?: number;
311
+ }
312
+ /** Texts of the Live Activity. */
313
+ interface BubbleLiveLabels {
314
+ /** @default 'Working…' */
315
+ pending: string;
316
+ /** @default 'Done' */
317
+ success: string;
318
+ /** @default 'Something went wrong' */
319
+ error: string;
320
+ /** Accessible name of the close button. @default 'Dismiss' */
321
+ close: string;
322
+ /** Accessible name of the live group. @default 'Live activity' */
323
+ group: string;
324
+ }
325
+ /**
326
+ * Visual tokens of the Live Activity, written as `--bubble-live-*` custom properties.
327
+ * Numbers are px for lengths and ms for `duration`.
328
+ */
329
+ interface BubbleLiveTokens {
330
+ /** Width of the compact pill, capped to the viewport. @default 200px */
331
+ compactWidth?: number | string;
332
+ /** Width of the card, capped to the viewport. @default 360px */
333
+ width?: number | string;
334
+ /** Corner radius of the card. @default 24px */
335
+ radius?: number | string;
336
+ /** Remaining-time bar. @default currentColor at 40% */
337
+ progressColor?: string;
338
+ /** @default #22c55e */
339
+ successColor?: string;
340
+ /** @default #ef4444 */
341
+ errorColor?: string;
342
+ /** Title size, clamped to 11–18px. @default 13px */
343
+ titleSize?: number | string;
344
+ /** Description size, clamped to 9–14px. @default 11px */
345
+ metaSize?: number | string;
346
+ /** Morph duration, clamped to 0–600ms. @default 320ms */
347
+ duration?: number | string;
348
+ }
349
+ interface BubbleLiveActivityOptions {
350
+ /** Default card duration in ms; 0 keeps cards until dismissed. @default 4000 */
351
+ duration?: number;
352
+ /** Minimum time the compact pill stays, so fast tasks do not flicker. @default 600 */
353
+ minPendingMs?: number;
354
+ labels?: Partial<BubbleLiveLabels>;
355
+ tokens?: BubbleLiveTokens;
356
+ }
357
+ /** Controller returned by useBubbleLiveActivity. Stable across renders; usable from anywhere. */
358
+ interface BubbleLiveActivityController {
359
+ /** Shows the task in the toolbar and returns its own promise (value or original error). */
360
+ run: <T>(task: () => Promise<T> | T, options?: BubbleLiveRunOptions<T>) => Promise<T>;
361
+ /** Queues a card without a task. */
362
+ show: (content: BubbleLiveContent, options?: {
363
+ duration?: number;
364
+ }) => void;
365
+ /** Closes the current activity and moves to the next queued one. */
366
+ dismiss: () => void;
367
+ /** Current state, for tests or custom UI. Not reactive; subscribe for updates. */
368
+ readonly state: BubbleLiveState;
369
+ subscribe: (listener: () => void) => () => void;
370
+ }
169
371
 
170
372
  declare const BubbleGroup: react.ForwardRefExoticComponent<BubbleGroupProps & react.RefAttributes<HTMLDivElement>>;
171
373
 
374
+ /**
375
+ * Shows the current location as a breadcrumb and turns into a search when its button is pressed.
376
+ * The last item is the current page; it stays visible while parents truncate first.
377
+ */
378
+ declare const BubbleBreadcrumbSearch: (<T extends BubbleSearchItem>(props: BubbleBreadcrumbSearchProps<T> & RefAttributes<HTMLDivElement>) => ReactElement | null) & {
379
+ displayName?: string;
380
+ };
381
+
382
+ /**
383
+ * Search bubble: a button that expands into a combobox with async results.
384
+ * Use it inside BubbleToolbar. Customize it through `labels` and `tokens`.
385
+ */
386
+ declare const BubbleSearch: (<T extends BubbleSearchItem>(props: BubbleSearchProps<T> & RefAttributes<HTMLDivElement>) => ReactElement | null) & {
387
+ displayName?: string;
388
+ };
389
+
172
390
  interface BubbleToolbarComponent extends ForwardRefExoticComponent<BubbleToolbarProps & RefAttributes<HTMLDivElement>> {
173
391
  Group: typeof BubbleGroup;
392
+ Search: typeof BubbleSearch;
393
+ BreadcrumbSearch: typeof BubbleBreadcrumbSearch;
174
394
  }
175
395
  declare const BubbleToolbar: BubbleToolbarComponent;
176
396
 
@@ -182,14 +402,27 @@ interface BubbleToolbarContextValue extends BubbleActivityProps {
182
402
  size: BubbleToolbarSize;
183
403
  theme: BubbleToolbarTheme;
184
404
  blurred: boolean;
185
- blurAmount: number | string;
405
+ /** Undefined falls back to the --bubble-blur token. */
406
+ blurAmount?: number | string;
186
407
  itemGap: number | string;
187
408
  bordered: boolean;
188
409
  shadow: boolean | string;
410
+ /** Toolbar placement; undefined outside a BubbleToolbar. */
411
+ position?: BubbleToolbarPosition;
412
+ /** Live Activity controller of the toolbar, if any. */
413
+ liveActivity?: BubbleLiveActivityController;
189
414
  }
190
415
  declare const BubbleToolbarContext: react.Context<BubbleToolbarContextValue>;
191
416
  declare const useBubbleToolbar: () => BubbleToolbarContextValue;
192
417
 
418
+ /**
419
+ * Creates a stable Live Activity controller. Pass it to `<BubbleToolbar liveActivity>` and call
420
+ * `run`, `show` or `dismiss` from anywhere. Options are read on every render.
421
+ */
422
+ declare const useBubbleLiveActivity: (options?: BubbleLiveActivityOptions) => BubbleLiveActivityController;
423
+ /** Reads the controller of the surrounding BubbleToolbar. */
424
+ declare const useBubbleToolbarLiveActivity: () => BubbleLiveActivityController;
425
+
193
426
  /**
194
427
  * Returns an array of non-null, non-undefined, non-boolean child elements.
195
428
  * Unpacks Fragment if encountered at the top level.
@@ -198,6 +431,6 @@ declare function getValidChildren(children: ReactNode): ReactNode[];
198
431
 
199
432
  declare function resolveSize(size: BubbleToolbarSize): number;
200
433
  declare function formatPx(val: number | string): string;
201
- declare function getGlassStyles(theme: BubbleToolbarTheme, blurred: boolean, blurAmount: number | string, bordered: boolean, shadow: boolean | string): CSSProperties;
434
+ declare function getGlassStyles(theme: BubbleToolbarTheme, blurred: boolean, blurAmount: number | string | undefined, bordered: boolean, shadow: boolean | string): CSSProperties;
202
435
 
203
- export { type BubbleActivityProps, type BubbleActivityValue, BubbleArea, type BubbleAreaProps, BubbleGroup, type BubbleGroupProps, BubbleIconButton, type BubbleIconButtonProps, type BubbleShape, BubbleToolbar, type BubbleToolbarComponent, BubbleToolbarContext, type BubbleToolbarPosition, type BubbleToolbarProps, type BubbleToolbarSize, type BubbleToolbarTheme, formatPx, getGlassStyles, getValidChildren, resolveSize, useBubbleActivity, useBubbleToolbar };
436
+ export { type BubbleActivityProps, type BubbleActivityValue, BubbleArea, type BubbleAreaProps, type BubbleBreadcrumbItem, BubbleBreadcrumbSearch, type BubbleBreadcrumbSearchLabels, type BubbleBreadcrumbSearchProps, type BubbleBreadcrumbSearchTokens, BubbleGroup, type BubbleGroupProps, BubbleIconButton, type BubbleIconButtonProps, type BubbleLiveActivityController, type BubbleLiveActivityOptions, type BubbleLiveContent, type BubbleLiveLabels, type BubbleLiveRunOptions, type BubbleLiveState, type BubbleLiveTokens, BubbleSearch, type BubbleSearchItem, type BubbleSearchLabels, type BubbleSearchProps, type BubbleSearchTokens, type BubbleShape, BubbleToolbar, type BubbleToolbarComponent, BubbleToolbarContext, type BubbleToolbarPosition, type BubbleToolbarProps, type BubbleToolbarSize, type BubbleToolbarTheme, formatPx, getGlassStyles, getValidChildren, resolveSize, useBubbleActivity, useBubbleLiveActivity, useBubbleToolbar, useBubbleToolbarLiveActivity };