bubble-toolbar 0.1.0 → 1.0.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/CHANGELOG.md +3 -0
- package/README.md +247 -127
- package/dist/index.d.mts +27 -12
- package/dist/index.d.ts +27 -12
- package/dist/index.js +234 -106
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +239 -94
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +75 -5
- package/package.json +87 -54
package/CHANGELOG.md
ADDED
package/README.md
CHANGED
|
@@ -1,195 +1,315 @@
|
|
|
1
1
|
# 🫧 Bubble Toolbar
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/bubble-toolbar)
|
|
4
|
+
[](https://react.dev/)
|
|
5
|
+
[](./tsconfig.json)
|
|
6
|
+
[](./.storybook/main.ts)
|
|
7
|
+
[](./eslint.config.mjs)
|
|
8
|
+
[](./biome.json)
|
|
9
|
+
[](./LICENSE)
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
A responsive floating toolbar with a frosted glass effect for React 18 and 19. Built with TypeScript, it arranges content into groups that adapt from circles to pills based on their children.
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
## Features
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
- **React 18 and 19 support:** typed components with forwarded refs.
|
|
16
|
+
- **Group-based composition:** pass arrays of nodes or use `BubbleToolbar.Group` children.
|
|
17
|
+
- **Adaptive shapes:** a single child creates a circle; multiple children create a pill.
|
|
18
|
+
- **Frosted glass:** background blur, subtle borders, soft shadows, and glass, light, dark, or automatic themes.
|
|
19
|
+
- **Responsive layout:** fixed or relative positioning, automatic centering, and horizontal scrolling on smaller screens.
|
|
20
|
+
- **Tests and examples:** Jest and React Testing Library tests, plus interactive Storybook stories.
|
|
10
21
|
|
|
11
|
-
|
|
12
|
-
- 🔮 **Definición por Grupos**: Define la barra pasando arreglos de nodos o mediante sintaxis de componentes compuestos (`BubbleToolbar.Group`).
|
|
13
|
-
- 🔘 **Morfología Adaptativa Dinámica**:
|
|
14
|
-
- **1 solo nodo** $\rightarrow$ se renderiza como un **círculo** perfecto (`aspect-ratio: 1/1`).
|
|
15
|
-
- **Más de 1 nodo** $\rightarrow$ se convierte en un **rectángulo redondeado (cápsula / pill)**, respetando la curvatura en los extremos para mantener el equilibrio visual exacto con las burbujas circulares.
|
|
16
|
-
- 🪟 **Blurred Glass (Frosted Glassmorphism)**: Efecto translúcido con desenfoque de fondo (`backdrop-filter: blur(16px)`), bordes frosted, sombras suaves y soporte para temas claro, oscuro o automático.
|
|
17
|
-
- 📱 **Flotante y Responsivo**: Posicionamiento fijo o relativo, centrado automático y desplazamiento horizontal suave sin barras de scroll invasivas en pantallas móviles.
|
|
18
|
-
- 🧪 **100% Testeado con Jest**: Suite integral de pruebas unitarias y de integración con `@testing-library/react`.
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## 📦 Instalación
|
|
22
|
+
## Installation
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
npm install bubble-toolbar
|
|
26
|
-
#
|
|
26
|
+
# Or use pnpm:
|
|
27
27
|
pnpm add bubble-toolbar
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
## Quick start
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
### Group arrays
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
```tsx
|
|
35
|
+
import { BubbleArea, BubbleIconButton, BubbleToolbar } from 'bubble-toolbar';
|
|
36
|
+
import 'bubble-toolbar/styles.css';
|
|
37
|
+
|
|
38
|
+
const App = () => (
|
|
39
|
+
<BubbleToolbar
|
|
40
|
+
position="bottom"
|
|
41
|
+
theme="glass"
|
|
42
|
+
groups={[
|
|
43
|
+
// One child: circle.
|
|
44
|
+
[<BubbleIconButton key="logo" name="logo" />],
|
|
45
|
+
|
|
46
|
+
// Multiple children: pill.
|
|
47
|
+
[
|
|
48
|
+
<BubbleIconButton key="search" name="search" />,
|
|
49
|
+
<BubbleArea key="area">
|
|
50
|
+
<input aria-label="Search" placeholder="Search or type /" />
|
|
51
|
+
</BubbleArea>,
|
|
52
|
+
],
|
|
53
|
+
|
|
54
|
+
// Each group below becomes a circle.
|
|
55
|
+
[<BubbleIconButton key="theme" name="theme" />],
|
|
56
|
+
[<BubbleIconButton key="chat" name="chat" />],
|
|
57
|
+
[<BubbleIconButton key="notifications" name="notifications" badge={3} />],
|
|
58
|
+
]}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
```
|
|
35
62
|
|
|
36
|
-
|
|
63
|
+
### Compound components
|
|
37
64
|
|
|
38
65
|
```tsx
|
|
39
|
-
import
|
|
40
|
-
import
|
|
41
|
-
|
|
66
|
+
import { BubbleArea, BubbleIconButton, BubbleToolbar } from 'bubble-toolbar';
|
|
67
|
+
import 'bubble-toolbar/styles.css';
|
|
68
|
+
|
|
69
|
+
const FloatingMenu = () => (
|
|
70
|
+
<BubbleToolbar position="bottom" theme="glass">
|
|
71
|
+
<BubbleToolbar.Group>
|
|
72
|
+
<BubbleIconButton name="logo" />
|
|
73
|
+
</BubbleToolbar.Group>
|
|
74
|
+
|
|
75
|
+
<BubbleToolbar.Group>
|
|
76
|
+
<BubbleIconButton name="search" />
|
|
77
|
+
<BubbleArea>
|
|
78
|
+
<input aria-label="Search" placeholder="Search…" />
|
|
79
|
+
</BubbleArea>
|
|
80
|
+
</BubbleToolbar.Group>
|
|
81
|
+
|
|
82
|
+
<BubbleToolbar.Group>
|
|
83
|
+
<BubbleIconButton name="theme" />
|
|
84
|
+
</BubbleToolbar.Group>
|
|
85
|
+
</BubbleToolbar>
|
|
86
|
+
);
|
|
87
|
+
```
|
|
42
88
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
[<BubbleIconButton key="notif" name="notifications" badge={3} />],
|
|
64
|
-
]}
|
|
65
|
-
/>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
89
|
+
The components include inline glass styles. Import the stylesheet for additional styling, including automatic dark theme support and focus indicators.
|
|
90
|
+
|
|
91
|
+
## Async activity
|
|
92
|
+
|
|
93
|
+
Import `bubble-toolbar/styles.css` to enable the rotating border and glow. Activity is indeterminate: it does not disable controls, cancel tasks, or display success or error states.
|
|
94
|
+
|
|
95
|
+
### External control
|
|
96
|
+
|
|
97
|
+
Set `busy` on the toolbar to illuminate every group, or on a group to illuminate only that bubble:
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
<BubbleToolbar busy={isSaving}>
|
|
101
|
+
<BubbleToolbar.Group>
|
|
102
|
+
<BubbleIconButton name="logo" />
|
|
103
|
+
</BubbleToolbar.Group>
|
|
104
|
+
<BubbleToolbar.Group busy={isSearching}>
|
|
105
|
+
<BubbleIconButton name="search" />
|
|
106
|
+
<BubbleArea>Search results</BubbleArea>
|
|
107
|
+
</BubbleToolbar.Group>
|
|
108
|
+
</BubbleToolbar>
|
|
68
109
|
```
|
|
69
110
|
|
|
70
|
-
###
|
|
111
|
+
### Track tasks from inside a group
|
|
112
|
+
|
|
113
|
+
`useBubbleActivity()` returns `{ isBusy, run }`. It targets the nearest group, including groups created through the `groups` prop. Calling it outside a group throws a descriptive error.
|
|
71
114
|
|
|
72
115
|
```tsx
|
|
73
|
-
import {
|
|
116
|
+
import { useState } from 'react';
|
|
117
|
+
import { BubbleIconButton, BubbleToolbar, useBubbleActivity } from 'bubble-toolbar';
|
|
118
|
+
import 'bubble-toolbar/styles.css';
|
|
119
|
+
|
|
120
|
+
const SaveAction = ({ save }: { save: () => Promise<void> }) => {
|
|
121
|
+
const { isBusy, run } = useBubbleActivity();
|
|
122
|
+
const [error, setError] = useState<string | null>(null);
|
|
74
123
|
|
|
75
|
-
function FloatingMenu() {
|
|
76
124
|
return (
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
</BubbleToolbar.Group>
|
|
90
|
-
|
|
91
|
-
{/* 1 nodo: Círculo */}
|
|
92
|
-
<BubbleToolbar.Group>
|
|
93
|
-
<BubbleIconButton name="theme" />
|
|
94
|
-
</BubbleToolbar.Group>
|
|
95
|
-
</BubbleToolbar>
|
|
125
|
+
<BubbleIconButton
|
|
126
|
+
name="chat"
|
|
127
|
+
tooltip={error ?? (isBusy ? 'Saving…' : 'Save')}
|
|
128
|
+
onClick={async () => {
|
|
129
|
+
setError(null);
|
|
130
|
+
try {
|
|
131
|
+
await run(save);
|
|
132
|
+
} catch {
|
|
133
|
+
setError('Save failed. Try again.');
|
|
134
|
+
}
|
|
135
|
+
}}
|
|
136
|
+
/>
|
|
96
137
|
);
|
|
97
|
-
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Render SaveAction inside a group:
|
|
141
|
+
// <BubbleToolbar.Group><SaveAction save={saveChanges} /></BubbleToolbar.Group>
|
|
98
142
|
```
|
|
99
143
|
|
|
100
|
-
|
|
144
|
+
`run<T>(task: () => Promise<T>): Promise<T>` returns the task's result and propagates synchronous exceptions and rejected promises. Handle errors in your application. Concurrent tasks keep the group busy until the last task settles. Unmounting the group does not cancel the consumer's task.
|
|
101
145
|
|
|
102
|
-
|
|
146
|
+
A group is busy when **any** of the following is true: the toolbar's `busy` prop, the group's `busy` prop, or a pending local task. Passing `busy={false}` does not hide activity from another source. Each group exposes its effective state through `aria-busy`.
|
|
103
147
|
|
|
104
|
-
|
|
105
|
-
| :--- | :---: | :--- |
|
|
106
|
-
| **1 Nodo** (`[<Logo />]`) | 🟡 **Círculo** | Ancho y alto fijados a `--bubble-size` (por defecto `48px`). `aspect-ratio: 1 / 1`. Contenido centrado. |
|
|
107
|
-
| **> 1 Nodo** (`[<Search />, <Area />]`) | 💊 **Cápsula / Pill** | Altura fijada a `--bubble-size`, ancho dinámico según contenido con padding lateral. Los extremos redondeados coinciden exactamente con el diámetro de las burbujas circulares adyacentes para una armonía visual simétrica. |
|
|
148
|
+
Both toolbar and group accept these props; group appearance overrides the toolbar defaults:
|
|
108
149
|
|
|
109
|
-
|
|
150
|
+
| Prop | Type | Default | Description |
|
|
151
|
+
| :--- | :--- | :--- | :--- |
|
|
152
|
+
| `busy` | `boolean` | `false` | Adds externally managed activity. |
|
|
153
|
+
| `activityColors` | `readonly [string, string, string]` | `['#22d3ee', '#8b5cf6', '#ec4899']` | Three CSS colors for the gradient. |
|
|
154
|
+
| `activityDuration` | `number` | `2.4` | Seconds per rotation; non-positive or non-finite values fall back to 2.4. |
|
|
110
155
|
|
|
111
|
-
|
|
156
|
+
The effect follows circular and pill shapes without changing their dimensions. With `prefers-reduced-motion: reduce`, the border remains visible and static. Browsers without animated custom property support retain a static gradient; browsers without CSS masking retain a static colored border.
|
|
157
|
+
|
|
158
|
+
## Adaptive shapes
|
|
159
|
+
|
|
160
|
+
| Group content | Shape | Behavior |
|
|
161
|
+
| :--- | :--- | :--- |
|
|
162
|
+
| One child | Circle | Equal width and height, with centered content. The default diameter is 48px. |
|
|
163
|
+
| Multiple children | Pill | Fixed height, content-based width, horizontal spacing, and rounded ends. |
|
|
164
|
+
|
|
165
|
+
Use the `shape` prop on a group to override its automatic shape.
|
|
166
|
+
|
|
167
|
+
## API reference
|
|
112
168
|
|
|
113
169
|
### `<BubbleToolbar />`
|
|
114
170
|
|
|
115
|
-
| Prop |
|
|
116
|
-
| :--- | :--- |
|
|
117
|
-
| `groups` | `ReactNode[][]` | `undefined` |
|
|
118
|
-
| `children` | `ReactNode` | `undefined` |
|
|
119
|
-
| `position` | `'bottom' \| 'top' \| 'static' \| 'custom'` | `'bottom'` |
|
|
120
|
-
| `theme` | `'glass' \| 'light' \| 'dark' \| 'auto'` | `'glass'` |
|
|
121
|
-
| `size` | `'sm' \| 'md' \| 'lg' \| number` | `'md'` |
|
|
122
|
-
| `blurred` | `boolean` | `true` |
|
|
123
|
-
| `blurAmount
|
|
124
|
-
| `groupGap` | `number \| string` | `8` |
|
|
125
|
-
| `itemGap` | `number \| string` | `8` |
|
|
126
|
-
| `bordered` | `boolean` | `true` |
|
|
127
|
-
| `shadow` | `boolean \| string` | `true` |
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
|
133
|
-
|
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
171
|
+
| Prop | Type | Default | Description |
|
|
172
|
+
| :--- | :--- | :--- | :--- |
|
|
173
|
+
| `groups` | `ReactNode[][]` | `undefined` | Arrays of grouped nodes. |
|
|
174
|
+
| `children` | `ReactNode` | `undefined` | Children such as `<BubbleToolbar.Group>`. |
|
|
175
|
+
| `position` | `'bottom' \| 'top' \| 'static' \| 'custom'` | `'bottom'` | Toolbar placement. Use `style` to set custom positioning. |
|
|
176
|
+
| `theme` | `'glass' \| 'light' \| 'dark' \| 'auto'` | `'glass'` | Visual theme. |
|
|
177
|
+
| `size` | `'sm' \| 'md' \| 'lg' \| number` | `'md'` | Group height and circle diameter: 40px, 48px, 56px, or a custom pixel value. |
|
|
178
|
+
| `blurred` | `boolean` | `true` | Enables background blur. |
|
|
179
|
+
| `blurAmount` | `number \| string` | `16` | Blur radius in pixels or a CSS length. |
|
|
180
|
+
| `groupGap` | `number \| string` | `8` | Space between groups, in pixels or a CSS length. |
|
|
181
|
+
| `itemGap` | `number \| string` | `8` | Space between children within a pill. |
|
|
182
|
+
| `bordered` | `boolean` | `true` | Shows subtle borders. |
|
|
183
|
+
| `shadow` | `boolean \| string` | `true` | Enables the default shadow or supplies a custom CSS shadow. |
|
|
184
|
+
| `ariaLabel` | `string` | `'Toolbar'` | Accessible toolbar label. |
|
|
185
|
+
|
|
186
|
+
### `<BubbleGroup />` / `<BubbleToolbar.Group />`
|
|
187
|
+
|
|
188
|
+
| Prop | Type | Default | Description |
|
|
189
|
+
| :--- | :--- | :--- | :--- |
|
|
190
|
+
| `children` | `ReactNode` | `undefined` | Group content. |
|
|
191
|
+
| `shape` | `'circle' \| 'pill'` | Automatic | Overrides the shape inferred from the child count. |
|
|
192
|
+
| `size` | `'sm' \| 'md' \| 'lg' \| number` | Inherited | Overrides the toolbar's group size. |
|
|
193
|
+
| `itemGap` | `number \| string` | Inherited | Overrides spacing between children. |
|
|
137
194
|
|
|
138
195
|
### `<BubbleIconButton />`
|
|
139
196
|
|
|
140
|
-
| Prop |
|
|
141
|
-
| :--- | :--- |
|
|
142
|
-
| `name` | `
|
|
143
|
-
| `icon` | `ReactNode` | `undefined` |
|
|
144
|
-
| `badge` | `ReactNode
|
|
145
|
-
| `active` | `boolean` | `false` |
|
|
146
|
-
| `tooltip` | `string` | `undefined` |
|
|
147
|
-
|
|
148
|
-
---
|
|
197
|
+
| Prop | Type | Default | Description |
|
|
198
|
+
| :--- | :--- | :--- | :--- |
|
|
199
|
+
| `name` | `string` | `undefined` | Built-in icon: `search`, `theme`, `chat`, `notifications`, `logo`, or `close`. |
|
|
200
|
+
| `icon` | `ReactNode` | `undefined` | Custom icon content. |
|
|
201
|
+
| `badge` | `ReactNode` | `undefined` | Notification indicator or count. |
|
|
202
|
+
| `active` | `boolean` | `false` | Applies active styling. |
|
|
203
|
+
| `tooltip` | `string` | `undefined` | Tooltip and fallback accessible label. |
|
|
204
|
+
| `ariaLabel` | `string` | Derived | Explicit accessible label; falls back to the tooltip or icon name. |
|
|
149
205
|
|
|
150
|
-
|
|
206
|
+
### `<BubbleArea />`
|
|
151
207
|
|
|
152
|
-
|
|
208
|
+
| Prop | Type | Default | Description |
|
|
209
|
+
| :--- | :--- | :--- | :--- |
|
|
210
|
+
| `children` | `ReactNode` | `undefined` | Content such as a search input, label, or slider. |
|
|
211
|
+
| `minWidth` | `number \| string` | `120` | Minimum width in pixels or a CSS length. |
|
|
212
|
+
| `maxWidth` | `number \| string` | `undefined` | Maximum width in pixels or a CSS length. |
|
|
153
213
|
|
|
154
|
-
|
|
155
|
-
npm test
|
|
156
|
-
```
|
|
214
|
+
All components accept `className`, `style`, and standard attributes for their underlying element. Toolbar, group, and area refs point to a `div`; icon button refs point to a `button`.
|
|
157
215
|
|
|
158
|
-
|
|
216
|
+
## Development
|
|
159
217
|
|
|
160
218
|
```bash
|
|
161
|
-
npm
|
|
219
|
+
npm ci
|
|
162
220
|
```
|
|
163
221
|
|
|
164
|
-
|
|
222
|
+
ESLint 10 uses `createEslintConfig` from `super-configs/eslint` with the React and Jest presets. Biome extends `super-configs/biome` for linting, formatting, and import organization.
|
|
165
223
|
|
|
166
224
|
```bash
|
|
167
|
-
npm run
|
|
225
|
+
npm run lint # Run ESLint with zero warnings allowed
|
|
226
|
+
npm run lint:fix # Apply ESLint fixes
|
|
227
|
+
npm run format:check # Check with Biome
|
|
228
|
+
npm run format # Apply Biome fixes
|
|
229
|
+
npm run typecheck # Check TypeScript types
|
|
230
|
+
npm test # Run Jest tests
|
|
231
|
+
npm run test:coverage # Generate a coverage report
|
|
232
|
+
npm run check # Run ESLint, Biome, TypeScript, and Jest
|
|
168
233
|
```
|
|
169
234
|
|
|
170
|
-
###
|
|
235
|
+
### Storybook
|
|
171
236
|
|
|
172
|
-
|
|
237
|
+
The story environment uses Storybook 10 and Vite 8.3.4. Explore components, themes, and adaptive shapes locally:
|
|
173
238
|
|
|
174
239
|
```bash
|
|
175
240
|
npm run storybook
|
|
176
241
|
```
|
|
177
242
|
|
|
178
|
-
|
|
243
|
+
Build the static Storybook site:
|
|
179
244
|
|
|
180
245
|
```bash
|
|
181
246
|
npm run build-storybook
|
|
182
247
|
```
|
|
183
248
|
|
|
184
|
-
|
|
249
|
+
### Library build
|
|
250
|
+
|
|
251
|
+
Build the library for distribution as ESM, CommonJS, and TypeScript declarations:
|
|
185
252
|
|
|
186
253
|
```bash
|
|
187
254
|
npm run build
|
|
188
255
|
```
|
|
189
256
|
|
|
190
|
-
|
|
257
|
+
Preview the npm package contents:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
npm pack --dry-run
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Releases and deployment
|
|
264
|
+
|
|
265
|
+
The workflows follow the same release pattern as `react-dockbar` and `super-configs`:
|
|
266
|
+
|
|
267
|
+
- **CI:** pull requests and pushes to branches other than `main` run type checks, tests, and builds with React 18 and 19. React 19 also runs ESLint, Biome, Storybook, and a package-content check. Pull request commits are validated with commitlint.
|
|
268
|
+
- **npm:** after CI passes on `main`, semantic-release calculates the version, generates `CHANGELOG.md` and GitHub release notes, updates package versions, creates a `vX.Y.Z` tag, and publishes `bubble-toolbar` with provenance.
|
|
269
|
+
- **GitHub Packages:** each new npm release is mirrored as `@eljijuna/bubble-toolbar` from its release tag. The name change happens only in the publishing job.
|
|
270
|
+
- **GitHub Pages:** every validated push to `main` deploys Storybook to [eljijuna.github.io/bubble-toolbar](https://eljijuna.github.io/bubble-toolbar/), even when there is no new package release. Deployment is independent of npm publishing.
|
|
271
|
+
|
|
272
|
+
### Conventional Commits
|
|
273
|
+
|
|
274
|
+
Use `type(optional-scope): description` for commits and squash-merge titles:
|
|
275
|
+
|
|
276
|
+
| Commit | Version change |
|
|
277
|
+
| :--- | :--- |
|
|
278
|
+
| `fix: correct activity cleanup` | Patch |
|
|
279
|
+
| `perf: reduce activity renders` | Patch |
|
|
280
|
+
| `feat: add activity colors` | Minor |
|
|
281
|
+
| `feat!: replace the group API` | Major |
|
|
282
|
+
| Any type with a `BREAKING CHANGE:` footer | Major |
|
|
283
|
+
| `docs:`, `test:`, `chore:`, `ci:`, `build:`, `refactor:`, `style:` without breaking changes | No release by themselves |
|
|
284
|
+
|
|
285
|
+
The highest applicable change determines the release. Without a previous release tag, semantic-release starts at **1.0.0**. Release commits use `chore(release): X.Y.Z [skip ci]` to avoid a release loop. Do not edit release versions or changelog entries manually.
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
printf 'feat: add activity colors\n' | npm run commitlint
|
|
289
|
+
npm run release:dry-run
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The dry run needs access to the GitHub repository and publishing credentials to verify permissions. It does not publish a version. Release tooling uses Node.js 24 in CI; use Node.js 24.15 or newer for local release tooling.
|
|
293
|
+
|
|
294
|
+
### Repository configuration
|
|
295
|
+
|
|
296
|
+
- Set the Actions secret `NPM_TOKEN` to an npm granular token with publish access to `bubble-toolbar`, allowing the CI publishing workflow to bypass 2FA. It must belong to an account authorized to publish the package name.
|
|
297
|
+
- Keep **Settings → Pages → Build and deployment → Source** set to **GitHub Actions**.
|
|
298
|
+
- The workflows declare the required `GITHUB_TOKEN` permissions for releases, package publishing, and Pages. If branch protection blocks release commits, allow the release automation to update `main` using an appropriate GitHub App token.
|
|
299
|
+
- The **Release** workflow can also be dispatched manually on `main`. To retry a failed mirror after npm succeeded, rerun the failed GitHub Packages job.
|
|
300
|
+
|
|
301
|
+
Install the mirror with an npm configuration that routes its scope to GitHub Packages:
|
|
302
|
+
|
|
303
|
+
```ini
|
|
304
|
+
@eljijuna:registry=https://npm.pkg.github.com
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
npm install @eljijuna/bubble-toolbar
|
|
309
|
+
```
|
|
191
310
|
|
|
192
|
-
|
|
311
|
+
GitHub Packages installation requires GitHub authentication with package read access. Publishing and deployment happen when the workflows run on GitHub; local setup does not publish packages.
|
|
193
312
|
|
|
194
|
-
|
|
313
|
+
## License
|
|
195
314
|
|
|
315
|
+
[MIT](./LICENSE) © ElJijuna
|
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode, CSSProperties, ButtonHTMLAttributes, ForwardRefExoticComponent, RefAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
interface BubbleActivityValue {
|
|
5
|
+
isBusy: boolean;
|
|
6
|
+
run: <T>(task: () => Promise<T>) => Promise<T>;
|
|
7
|
+
}
|
|
8
|
+
declare const useBubbleActivity: () => BubbleActivityValue;
|
|
3
9
|
|
|
4
10
|
type BubbleToolbarTheme = 'light' | 'dark' | 'auto' | 'glass';
|
|
5
11
|
type BubbleToolbarPosition = 'bottom' | 'top' | 'static' | 'custom';
|
|
6
12
|
type BubbleToolbarSize = 'sm' | 'md' | 'lg' | number;
|
|
7
13
|
type BubbleShape = 'circle' | 'pill';
|
|
8
|
-
|
|
14
|
+
/** Activity appearance inherited by each bubble group. */
|
|
15
|
+
interface BubbleActivityProps {
|
|
16
|
+
/** Adds external activity; false does not hide pending local tasks. */
|
|
17
|
+
busy?: boolean;
|
|
18
|
+
/** Three CSS colors used by the rotating activity border. */
|
|
19
|
+
activityColors?: readonly [string, string, string];
|
|
20
|
+
/** Seconds per rotation. Defaults to 2.4. */
|
|
21
|
+
activityDuration?: number;
|
|
22
|
+
}
|
|
23
|
+
interface BubbleToolbarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'>, BubbleActivityProps {
|
|
9
24
|
/**
|
|
10
25
|
* Definition of items by groups.
|
|
11
26
|
* Example:
|
|
@@ -82,7 +97,7 @@ interface BubbleToolbarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'child
|
|
|
82
97
|
*/
|
|
83
98
|
ariaLabel?: string;
|
|
84
99
|
}
|
|
85
|
-
interface BubbleGroupProps extends HTMLAttributes<HTMLDivElement
|
|
100
|
+
interface BubbleGroupProps extends HTMLAttributes<HTMLDivElement>, BubbleActivityProps {
|
|
86
101
|
/**
|
|
87
102
|
* Elements inside this group.
|
|
88
103
|
* 1 node renders as a circle.
|
|
@@ -152,18 +167,18 @@ interface BubbleAreaProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
152
167
|
maxWidth?: number | string;
|
|
153
168
|
}
|
|
154
169
|
|
|
155
|
-
declare const BubbleGroup:
|
|
170
|
+
declare const BubbleGroup: react.ForwardRefExoticComponent<BubbleGroupProps & react.RefAttributes<HTMLDivElement>>;
|
|
156
171
|
|
|
157
|
-
interface BubbleToolbarComponent extends
|
|
172
|
+
interface BubbleToolbarComponent extends ForwardRefExoticComponent<BubbleToolbarProps & RefAttributes<HTMLDivElement>> {
|
|
158
173
|
Group: typeof BubbleGroup;
|
|
159
174
|
}
|
|
160
175
|
declare const BubbleToolbar: BubbleToolbarComponent;
|
|
161
176
|
|
|
162
|
-
declare const
|
|
177
|
+
declare const BubbleArea: react.ForwardRefExoticComponent<BubbleAreaProps & react.RefAttributes<HTMLDivElement>>;
|
|
163
178
|
|
|
164
|
-
declare const
|
|
179
|
+
declare const BubbleIconButton: react.ForwardRefExoticComponent<BubbleIconButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
165
180
|
|
|
166
|
-
interface BubbleToolbarContextValue {
|
|
181
|
+
interface BubbleToolbarContextValue extends BubbleActivityProps {
|
|
167
182
|
size: BubbleToolbarSize;
|
|
168
183
|
theme: BubbleToolbarTheme;
|
|
169
184
|
blurred: boolean;
|
|
@@ -172,12 +187,12 @@ interface BubbleToolbarContextValue {
|
|
|
172
187
|
bordered: boolean;
|
|
173
188
|
shadow: boolean | string;
|
|
174
189
|
}
|
|
175
|
-
declare const BubbleToolbarContext:
|
|
190
|
+
declare const BubbleToolbarContext: react.Context<BubbleToolbarContextValue>;
|
|
176
191
|
declare const useBubbleToolbar: () => BubbleToolbarContextValue;
|
|
177
192
|
|
|
178
193
|
/**
|
|
179
194
|
* Returns an array of non-null, non-undefined, non-boolean child elements.
|
|
180
|
-
* Unpacks
|
|
195
|
+
* Unpacks Fragment if encountered at the top level.
|
|
181
196
|
*/
|
|
182
197
|
declare function getValidChildren(children: ReactNode): ReactNode[];
|
|
183
198
|
|
|
@@ -185,4 +200,4 @@ declare function resolveSize(size: BubbleToolbarSize): number;
|
|
|
185
200
|
declare function formatPx(val: number | string): string;
|
|
186
201
|
declare function getGlassStyles(theme: BubbleToolbarTheme, blurred: boolean, blurAmount: number | string, bordered: boolean, shadow: boolean | string): CSSProperties;
|
|
187
202
|
|
|
188
|
-
export { 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, useBubbleToolbar };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode, CSSProperties, ButtonHTMLAttributes, ForwardRefExoticComponent, RefAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
interface BubbleActivityValue {
|
|
5
|
+
isBusy: boolean;
|
|
6
|
+
run: <T>(task: () => Promise<T>) => Promise<T>;
|
|
7
|
+
}
|
|
8
|
+
declare const useBubbleActivity: () => BubbleActivityValue;
|
|
3
9
|
|
|
4
10
|
type BubbleToolbarTheme = 'light' | 'dark' | 'auto' | 'glass';
|
|
5
11
|
type BubbleToolbarPosition = 'bottom' | 'top' | 'static' | 'custom';
|
|
6
12
|
type BubbleToolbarSize = 'sm' | 'md' | 'lg' | number;
|
|
7
13
|
type BubbleShape = 'circle' | 'pill';
|
|
8
|
-
|
|
14
|
+
/** Activity appearance inherited by each bubble group. */
|
|
15
|
+
interface BubbleActivityProps {
|
|
16
|
+
/** Adds external activity; false does not hide pending local tasks. */
|
|
17
|
+
busy?: boolean;
|
|
18
|
+
/** Three CSS colors used by the rotating activity border. */
|
|
19
|
+
activityColors?: readonly [string, string, string];
|
|
20
|
+
/** Seconds per rotation. Defaults to 2.4. */
|
|
21
|
+
activityDuration?: number;
|
|
22
|
+
}
|
|
23
|
+
interface BubbleToolbarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'>, BubbleActivityProps {
|
|
9
24
|
/**
|
|
10
25
|
* Definition of items by groups.
|
|
11
26
|
* Example:
|
|
@@ -82,7 +97,7 @@ interface BubbleToolbarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'child
|
|
|
82
97
|
*/
|
|
83
98
|
ariaLabel?: string;
|
|
84
99
|
}
|
|
85
|
-
interface BubbleGroupProps extends HTMLAttributes<HTMLDivElement
|
|
100
|
+
interface BubbleGroupProps extends HTMLAttributes<HTMLDivElement>, BubbleActivityProps {
|
|
86
101
|
/**
|
|
87
102
|
* Elements inside this group.
|
|
88
103
|
* 1 node renders as a circle.
|
|
@@ -152,18 +167,18 @@ interface BubbleAreaProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
152
167
|
maxWidth?: number | string;
|
|
153
168
|
}
|
|
154
169
|
|
|
155
|
-
declare const BubbleGroup:
|
|
170
|
+
declare const BubbleGroup: react.ForwardRefExoticComponent<BubbleGroupProps & react.RefAttributes<HTMLDivElement>>;
|
|
156
171
|
|
|
157
|
-
interface BubbleToolbarComponent extends
|
|
172
|
+
interface BubbleToolbarComponent extends ForwardRefExoticComponent<BubbleToolbarProps & RefAttributes<HTMLDivElement>> {
|
|
158
173
|
Group: typeof BubbleGroup;
|
|
159
174
|
}
|
|
160
175
|
declare const BubbleToolbar: BubbleToolbarComponent;
|
|
161
176
|
|
|
162
|
-
declare const
|
|
177
|
+
declare const BubbleArea: react.ForwardRefExoticComponent<BubbleAreaProps & react.RefAttributes<HTMLDivElement>>;
|
|
163
178
|
|
|
164
|
-
declare const
|
|
179
|
+
declare const BubbleIconButton: react.ForwardRefExoticComponent<BubbleIconButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
165
180
|
|
|
166
|
-
interface BubbleToolbarContextValue {
|
|
181
|
+
interface BubbleToolbarContextValue extends BubbleActivityProps {
|
|
167
182
|
size: BubbleToolbarSize;
|
|
168
183
|
theme: BubbleToolbarTheme;
|
|
169
184
|
blurred: boolean;
|
|
@@ -172,12 +187,12 @@ interface BubbleToolbarContextValue {
|
|
|
172
187
|
bordered: boolean;
|
|
173
188
|
shadow: boolean | string;
|
|
174
189
|
}
|
|
175
|
-
declare const BubbleToolbarContext:
|
|
190
|
+
declare const BubbleToolbarContext: react.Context<BubbleToolbarContextValue>;
|
|
176
191
|
declare const useBubbleToolbar: () => BubbleToolbarContextValue;
|
|
177
192
|
|
|
178
193
|
/**
|
|
179
194
|
* Returns an array of non-null, non-undefined, non-boolean child elements.
|
|
180
|
-
* Unpacks
|
|
195
|
+
* Unpacks Fragment if encountered at the top level.
|
|
181
196
|
*/
|
|
182
197
|
declare function getValidChildren(children: ReactNode): ReactNode[];
|
|
183
198
|
|
|
@@ -185,4 +200,4 @@ declare function resolveSize(size: BubbleToolbarSize): number;
|
|
|
185
200
|
declare function formatPx(val: number | string): string;
|
|
186
201
|
declare function getGlassStyles(theme: BubbleToolbarTheme, blurred: boolean, blurAmount: number | string, bordered: boolean, shadow: boolean | string): CSSProperties;
|
|
187
202
|
|
|
188
|
-
export { 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, useBubbleToolbar };
|
|
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 };
|