bitboss-ui 3.0.0-beta.21 → 3.0.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/README.md +55 -3
  2. package/bin/bitboss-ui-mcp.mjs +419 -9
  3. package/bin/bitboss-ui.mjs +293 -22
  4. package/dist/ai/BbAccordion.md +21 -23
  5. package/dist/ai/BbAlert.md +6 -12
  6. package/dist/ai/BbAvatar.md +60 -24
  7. package/dist/ai/BbBadge.md +12 -20
  8. package/dist/ai/BbBaseButton.md +14 -16
  9. package/dist/ai/BbBaseCheckboxIcon.md +6 -10
  10. package/dist/ai/BbBaseRadioIcon.md +6 -10
  11. package/dist/ai/BbBaseSwitchIcon.md +5 -9
  12. package/dist/ai/BbBreadcrumbs.md +23 -34
  13. package/dist/ai/BbButton.md +35 -47
  14. package/dist/ai/BbCheckbox.md +21 -37
  15. package/dist/ai/BbCheckboxGroup.md +13 -13
  16. package/dist/ai/BbCollapsible.md +14 -26
  17. package/dist/ai/BbColorInput.md +13 -23
  18. package/dist/ai/BbColorPalette.md +23 -35
  19. package/dist/ai/BbConfirm.md +17 -32
  20. package/dist/ai/BbDatePickerInput.md +15 -21
  21. package/dist/ai/BbDialog.md +159 -62
  22. package/dist/ai/BbDropdown.md +21 -25
  23. package/dist/ai/BbDropdownButton.md +13 -30
  24. package/dist/ai/BbDropzone.md +9 -11
  25. package/dist/ai/BbIcon.md +44 -33
  26. package/dist/ai/BbIndicator.md +2 -2
  27. package/dist/ai/BbNumberInput.md +18 -20
  28. package/dist/ai/BbOffCanvas.md +42 -42
  29. package/dist/ai/BbPagination.md +21 -23
  30. package/dist/ai/BbPopover.md +15 -17
  31. package/dist/ai/BbProgress.md +40 -51
  32. package/dist/ai/BbRadio.md +9 -9
  33. package/dist/ai/BbRadioGroup.md +7 -11
  34. package/dist/ai/BbRating.md +8 -12
  35. package/dist/ai/BbSelect.md +32 -36
  36. package/dist/ai/BbSelectPopover.md +19 -31
  37. package/dist/ai/BbSlider.md +15 -19
  38. package/dist/ai/BbSmoothHeight.md +16 -31
  39. package/dist/ai/BbSpinner.md +118 -74
  40. package/dist/ai/BbSwitch.md +25 -18
  41. package/dist/ai/BbSwitchGroup.md +9 -14
  42. package/dist/ai/BbTable.md +102 -55
  43. package/dist/ai/BbTabs.md +59 -82
  44. package/dist/ai/BbTag.md +12 -23
  45. package/dist/ai/BbTextInput.md +20 -26
  46. package/dist/ai/BbTextarea.md +28 -34
  47. package/dist/ai/BbToast.md +14 -34
  48. package/dist/ai/BbTooltip.md +22 -20
  49. package/dist/ai/BbTree.md +46 -72
  50. package/dist/ai/changelog.json +169 -62
  51. package/dist/ai/components.json +1467 -9
  52. package/dist/ai/composables/useConfirm.md +5 -2
  53. package/dist/ai/composables/useToast.md +4 -2
  54. package/dist/ai/guides/agent-contract.md +7 -4
  55. package/dist/ai/guides/ai-router.md +37 -22
  56. package/dist/ai/guides/component-picker.md +23 -18
  57. package/dist/ai/guides/design-language.md +141 -13
  58. package/dist/ai/guides/design-tokens.md +29 -4
  59. package/dist/ai/guides/icons-policy.md +46 -21
  60. package/dist/ai/guides/installation-and-plugin-setup.md +253 -17
  61. package/dist/ai/guides/migration/components/bb-rating.md +26 -1
  62. package/dist/ai/guides/migration/components/bb-tooltip.md +18 -0
  63. package/dist/ai/guides/migration/v2-to-v3.md +50 -23
  64. package/dist/ai/index.md +1 -1
  65. package/dist/ai/recipes/inertia/approvals-inbox.md +3 -3
  66. package/dist/ai/recipes/inertia/inline-edit-workspace.md +2 -2
  67. package/dist/ai/recipes/inertia/onboarding.md +2 -2
  68. package/dist/ai/recipes/inertia/ownership-atlas.md +6 -6
  69. package/dist/ai/recipes/inertia/record-form.md +5 -5
  70. package/dist/ai/recipes/inertia/records-workspace.md +4 -4
  71. package/dist/ai/recipes/inertia/upload-center.md +6 -6
  72. package/dist/ai/recipes/inertia/wizard-form.md +5 -5
  73. package/dist/ai/recipes/nuxt/approvals-inbox.md +3 -3
  74. package/dist/ai/recipes/nuxt/inline-edit-workspace.md +2 -2
  75. package/dist/ai/recipes/nuxt/onboarding.md +2 -2
  76. package/dist/ai/recipes/nuxt/record-form.md +5 -5
  77. package/dist/ai/recipes/nuxt/records-workspace.md +4 -4
  78. package/dist/ai/recipes/nuxt/upload-center.md +6 -6
  79. package/dist/ai/recipes/nuxt/wizard-form.md +5 -5
  80. package/dist/ai/recipes/vue/approvals-inbox.md +3 -3
  81. package/dist/ai/recipes/vue/inline-edit-workspace.md +2 -2
  82. package/dist/ai/recipes/vue/onboarding.md +2 -2
  83. package/dist/ai/recipes/vue/record-form.md +10 -10
  84. package/dist/ai/recipes/vue/records-workspace.md +4 -4
  85. package/dist/ai/recipes/vue/upload-center.md +6 -6
  86. package/dist/ai/recipes/vue/wizard-form.md +5 -5
  87. package/dist/ai/source/BbBadge.md +1 -1
  88. package/dist/ai/source/BbBaseCheckbox.md +1 -1
  89. package/dist/ai/source/BbBaseDatePicker.md +5 -5
  90. package/dist/ai/source/BbBaseDatePickerInput.md +2 -2
  91. package/dist/ai/source/BbBaseRadio.md +1 -1
  92. package/dist/ai/source/BbBaseRating.md +5 -5
  93. package/dist/ai/source/BbBaseSelect.md +1 -1
  94. package/dist/ai/source/BbBaseSlider.md +5 -5
  95. package/dist/ai/source/BbBaseSwitch.md +1 -1
  96. package/dist/ai/source/BbBaseTimePickerInput.md +1 -1
  97. package/dist/ai/source/BbBreadcrumbs.md +20 -1
  98. package/dist/ai/source/BbButton.md +2 -2
  99. package/dist/ai/source/BbDialog.md +39 -8
  100. package/dist/ai/source/BbDropdown.md +1 -1
  101. package/dist/ai/source/BbDropzone.md +5 -5
  102. package/dist/ai/source/BbIcon.md +23 -10
  103. package/dist/ai/source/BbOffCanvas.md +50 -28
  104. package/dist/ai/source/BbPagination.md +2 -2
  105. package/dist/ai/source/BbPopover.md +12 -1
  106. package/dist/ai/source/BbSelectPopover.md +45 -7
  107. package/dist/ai/source/BbSpinner.md +2 -2
  108. package/dist/ai/source/BbTable.md +11 -11
  109. package/dist/ai/source/BbTooltip.md +57 -10
  110. package/dist/ai/source/ChipsBox.md +1 -1
  111. package/dist/ai/source/CommaBox.md +1 -1
  112. package/dist/ai/source/GuidesComponent.md +14 -7
  113. package/dist/ai/source/OptionsContainer.md +1 -1
  114. package/dist/components/BbBadge/BadgeBodyContent.vue_vue_type_script_setup_true_lang.js +1 -1
  115. package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +1 -1
  116. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue_vue_type_script_setup_true_lang.js +1 -1
  117. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue_vue_type_script_setup_true_lang.js +4 -4
  118. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue_vue_type_script_setup_true_lang.js +1 -1
  119. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue_vue_type_script_setup_true_lang.js +1 -1
  120. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.d.ts +1 -1
  121. package/dist/components/BbBaseRadio/BbBaseRadio.vue_vue_type_script_setup_true_lang.js +1 -1
  122. package/dist/components/BbBaseRating/BbBaseRating.vue_vue_type_script_setup_true_lang.js +3 -3
  123. package/dist/components/BbBaseSelect/BbBaseSelect.vue_vue_type_script_setup_true_lang.js +1 -1
  124. package/dist/components/BbBaseSlider/BbBaseSlider.vue_vue_type_script_setup_true_lang.js +3 -3
  125. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue_vue_type_script_setup_true_lang.js +1 -1
  126. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue_vue_type_script_setup_true_lang.js +1 -1
  127. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +71 -71
  128. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +2 -2
  129. package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +102 -97
  130. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +1 -1
  131. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +58 -58
  132. package/dist/components/BbDropzone/BbDropzone.vue_vue_type_script_setup_true_lang.js +2 -2
  133. package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +33 -35
  134. package/dist/components/BbIcon/iconCache.d.ts +30 -0
  135. package/dist/components/BbIcon/iconCache.js +21 -3
  136. package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +57 -56
  137. package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +2 -2
  138. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +138 -138
  139. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +43 -43
  140. package/dist/components/BbSpinner/BbSpinner.vue_vue_type_script_setup_true_lang.js +1 -1
  141. package/dist/components/BbSpinner/types.d.ts +1 -1
  142. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +8 -8
  143. package/dist/components/BbTable/BbTableDataRow.js +2 -2
  144. package/dist/components/BbToast/BbToastRegion.vue_vue_type_script_setup_true_lang.js +62 -62
  145. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +81 -78
  146. package/dist/components/BbTooltip/types.d.ts +8 -1
  147. package/dist/components/ChipsBox/ChipsBox.vue_vue_type_script_setup_true_lang.js +1 -1
  148. package/dist/components/CommaBox/CommaBox.vue_vue_type_script_setup_true_lang.js +1 -1
  149. package/dist/components/OptionsContainer/OptionsContainer.vue_vue_type_script_setup_true_lang.js +1 -1
  150. package/dist/composables/useConfirm.d.ts +22 -0
  151. package/dist/composables/useConfirm.js +43 -40
  152. package/dist/composables/useSafeAreaInternal.js +1 -1
  153. package/dist/composables/useToast.d.ts +16 -0
  154. package/dist/composables/useToast.js +20 -16
  155. package/dist/composables/useViewportWidth.d.ts +20 -6
  156. package/dist/composables/useViewportWidth.js +8 -7
  157. package/dist/icon-scan.d.ts +276 -0
  158. package/dist/icon-scan.js +485 -0
  159. package/dist/icons-whitelist.d.ts +5 -4
  160. package/dist/llms-full.txt +1979 -1527
  161. package/dist/llms-medium.txt +461 -74
  162. package/dist/llms.txt +1 -1
  163. package/dist/nuxt.js +10 -7
  164. package/dist/plugin.js +1 -0
  165. package/dist/runtime/nuxt-plugin.js +2 -1
  166. package/dist/styles.css +1 -1
  167. package/dist/types/Config.d.ts +18 -0
  168. package/dist/utils/cssLayers.d.ts +91 -0
  169. package/dist/utils/cssLayers.js +43 -0
  170. package/dist/utils/injectLibraryStyles.d.ts +3 -1
  171. package/dist/utils/injectLibraryStyles.js +24 -23
  172. package/dist/vite-plugin.d.ts +74 -11
  173. package/dist/vite.js +292 -253
  174. package/llms.txt +1 -1
  175. package/package.json +7 -5
  176. package/scripts/lib/ensure-manifest.mjs +28 -5
  177. package/scripts/lib/eslint-plugin.d.ts +35 -0
  178. package/scripts/lib/eslint-plugin.mjs +299 -3
  179. package/scripts/lib/hand-roll-hints.mjs +50 -6
  180. package/scripts/lib/html-attributes.mjs +42 -0
  181. package/scripts/lib/mcp-config.mjs +38 -34
  182. package/scripts/lib/public-type-exports.mjs +246 -0
  183. package/scripts/lib/validate-bb-markup.mjs +205 -12
@@ -38,6 +38,10 @@ accessible name.
38
38
  **Photo, initials, and the built-in fallback**
39
39
 
40
40
  ```vue
41
+ <!-- Any image URL works. `timeout` is the deadline before the fallback shows
42
+ (default 400ms, meant for SSR/slow networks); a remote origin like this
43
+ one needs the headroom or the initials flash in first — see "Slow
44
+ networks, SSR and the timeout prop" below. -->
41
45
  <div class="flex items-center gap-3">
42
46
  <BbAvatar
43
47
  size="56"
@@ -147,12 +151,12 @@ separates them with a panel-colored ring (an explicit override of the
147
151
  ```vue
148
152
  <template>
149
153
  <div
150
- class="flex max-w-sm flex-col gap-3 rounded-[var(--bb-radius)] border p-3 text-sm"
154
+ class="flex max-w-sm flex-col gap-3 rounded-(--bb-radius) border p-3 text-sm"
151
155
  >
152
156
  <div class="flex items-center justify-between gap-2">
153
157
  <div class="flex flex-col gap-0.5">
154
158
  <span class="font-medium">Design review</span>
155
- <span class="text-xs text-[color:var(--bb-text-muted)]">
159
+ <span class="text-xs text-(--bb-text-muted)">
156
160
  PR #842 · {{ reviewers.length }} reviewers
157
161
  </span>
158
162
  </div>
@@ -168,7 +172,7 @@ separates them with a panel-colored ring (an explicit override of the
168
172
  :alt="reviewer.name"
169
173
  size="40"
170
174
  :src="reviewer.src"
171
- :timeout="demoAvatarTimeout"
175
+ :timeout="avatarTimeout"
172
176
  >
173
177
  {{ reviewer.initials }}
174
178
  </BbAvatar>
@@ -186,7 +190,20 @@ separates them with a panel-colored ring (an explicit override of the
186
190
  <script setup lang="ts">
187
191
  import { computed, ref } from 'vue';
188
192
  import { BbAvatar, BbButton } from 'bitboss-ui';
189
- import { demoAvatarTimeout, demoFaces } from './demoAvatars';
193
+
194
+ // Self-contained demo data. Any image URL works here — these are stock
195
+ // portraits; swap in your own. `timeout` is BbAvatar's deadline before the
196
+ // fallback shows (default 400ms, meant for SSR/slow networks): a remote demo
197
+ // origin needs headroom or the initials flash in first. See the guide §
198
+ // "Slow networks, SSR and the timeout prop".
199
+ const avatarTimeout = 4000;
200
+ const face = (photoId: string) =>
201
+ `https://images.unsplash.com/${photoId}?w=256&h=256&fit=crop&crop=faces&auto=format`;
202
+ const faces = {
203
+ ada: face('photo-1494790108377-be9c29b29330'),
204
+ alan: face('photo-1507003211169-0a1dd7228f2d'),
205
+ margaret: face('photo-1580489944761-15a19d654956'),
206
+ };
190
207
 
191
208
  type Reviewer = {
192
209
  name: string;
@@ -197,11 +214,11 @@ type Reviewer = {
197
214
  // The overflow indicator is just another avatar with the count in its slot —
198
215
  // same size, same ring, no special markup.
199
216
  const reviewers: Reviewer[] = [
200
- { name: 'Ada Lovelace', src: demoFaces.ada },
217
+ { name: 'Ada Lovelace', src: faces.ada },
201
218
  { name: 'Grace Hopper', initials: 'GH' },
202
- { name: 'Alan Turing', src: demoFaces.alan },
219
+ { name: 'Alan Turing', src: faces.alan },
203
220
  { name: 'Katherine Johnson', initials: 'KJ' },
204
- { name: 'Margaret Hamilton', src: demoFaces.margaret },
221
+ { name: 'Margaret Hamilton', src: faces.margaret },
205
222
  ];
206
223
  const maxVisible = 3;
207
224
 
@@ -242,12 +259,12 @@ list — the row markup stays identical whether a member has a photo or not.
242
259
  ```vue
243
260
  <template>
244
261
  <div
245
- class="flex max-w-sm flex-col gap-3 rounded-[var(--bb-radius)] border p-3 text-sm"
262
+ class="flex max-w-sm flex-col gap-3 rounded-(--bb-radius) border p-3 text-sm"
246
263
  >
247
264
  <div class="flex items-center justify-between gap-2">
248
265
  <div class="flex flex-col gap-0.5">
249
266
  <span class="font-medium">Team</span>
250
- <span class="text-xs text-[color:var(--bb-text-muted)]">
267
+ <span class="text-xs text-(--bb-text-muted)">
251
268
  {{ visible.length }} of {{ members.length }} members
252
269
  </span>
253
270
  </div>
@@ -274,14 +291,14 @@ list — the row markup stays identical whether a member has a photo or not.
274
291
  :alt="member.name"
275
292
  size="40"
276
293
  :src="member.src"
277
- :timeout="demoAvatarTimeout"
294
+ :timeout="avatarTimeout"
278
295
  >
279
296
  {{ member.initials }}
280
297
  </BbAvatar>
281
298
  </BbIndicator>
282
299
  <span class="flex min-w-0 flex-1 flex-col">
283
300
  <span class="truncate font-medium">{{ member.name }}</span>
284
- <span class="truncate text-xs text-[color:var(--bb-text-muted)]">
301
+ <span class="truncate text-xs text-(--bb-text-muted)">
285
302
  {{ member.role }} · {{ member.online ? 'Online' : 'Away' }}
286
303
  </span>
287
304
  </span>
@@ -293,7 +310,19 @@ list — the row markup stays identical whether a member has a photo or not.
293
310
  <script setup lang="ts">
294
311
  import { computed, ref } from 'vue';
295
312
  import { BbAvatar, BbIndicator, BbButton } from 'bitboss-ui';
296
- import { demoAvatarTimeout, demoFaces } from './demoAvatars';
313
+
314
+ // Self-contained demo data. Any image URL works here — these are stock
315
+ // portraits; swap in your own. `timeout` is BbAvatar's deadline before the
316
+ // fallback shows (default 400ms, meant for SSR/slow networks): a remote demo
317
+ // origin needs headroom or the initials flash in first. See the guide §
318
+ // "Slow networks, SSR and the timeout prop".
319
+ const avatarTimeout = 4000;
320
+ const face = (photoId: string) =>
321
+ `https://images.unsplash.com/${photoId}?w=256&h=256&fit=crop&crop=faces&auto=format`;
322
+ const faces = {
323
+ ada: face('photo-1494790108377-be9c29b29330'),
324
+ alan: face('photo-1507003211169-0a1dd7228f2d'),
325
+ };
297
326
 
298
327
  type Member = {
299
328
  name: string;
@@ -310,7 +339,7 @@ const members: Member[] = [
310
339
  name: 'Ada Lovelace',
311
340
  role: 'Engineering',
312
341
  online: true,
313
- src: demoFaces.ada,
342
+ src: faces.ada,
314
343
  },
315
344
  {
316
345
  name: 'Grace Hopper',
@@ -322,7 +351,7 @@ const members: Member[] = [
322
351
  name: 'Alan Turing',
323
352
  role: 'Research',
324
353
  online: false,
325
- src: demoFaces.alan,
354
+ src: faces.alan,
326
355
  },
327
356
  {
328
357
  name: 'Katherine Johnson',
@@ -362,13 +391,11 @@ it for you.
362
391
  ```vue
363
392
  <template>
364
393
  <div
365
- class="flex max-w-sm flex-col gap-3 rounded-[var(--bb-radius)] border p-3 text-sm"
394
+ class="flex max-w-sm flex-col gap-3 rounded-(--bb-radius) border p-3 text-sm"
366
395
  >
367
396
  <div class="flex items-center justify-between gap-2">
368
397
  <span class="font-medium">Release activity</span>
369
- <span class="text-xs text-[color:var(--bb-text-muted)]"
370
- >main · production</span
371
- >
398
+ <span class="text-xs text-(--bb-text-muted)">main · production</span>
372
399
  </div>
373
400
 
374
401
  <ul class="flex flex-col gap-2">
@@ -377,7 +404,7 @@ it for you.
377
404
  :alt="entry.actor"
378
405
  size="40"
379
406
  :src="entry.src"
380
- :timeout="demoAvatarTimeout"
407
+ :timeout="avatarTimeout"
381
408
  >
382
409
  <BbIcon v-if="entry.bot" :icon="releaseBotMark" size="sm" />
383
410
  <template v-else>{{ entry.initials }}</template>
@@ -387,9 +414,7 @@ it for you.
387
414
  <span class="font-medium">{{ entry.actor }}</span>
388
415
  {{ entry.action }}
389
416
  </span>
390
- <span class="text-xs text-[color:var(--bb-text-muted)]">{{
391
- entry.time
392
- }}</span>
417
+ <span class="text-xs text-(--bb-text-muted)">{{ entry.time }}</span>
393
418
  </span>
394
419
  </li>
395
420
  </ul>
@@ -402,7 +427,18 @@ import { BbAvatar, BbIcon } from 'bitboss-ui';
402
427
  // brand art that lives in no icon collection. It paints in `currentColor`,
403
428
  // so on the avatar's fallback surface it inherits `--bb-primary-fg`.
404
429
  import releaseBotMark from '@/assets/icons/sparkles.svg?raw';
405
- import { demoAvatarTimeout, demoFaces } from './demoAvatars';
430
+
431
+ // Self-contained demo data. Any image URL works here — these are stock
432
+ // portraits; swap in your own. `timeout` is BbAvatar's deadline before the
433
+ // fallback shows (default 400ms, meant for SSR/slow networks): a remote demo
434
+ // origin needs headroom or the initials flash in first. See the guide §
435
+ // "Slow networks, SSR and the timeout prop".
436
+ const avatarTimeout = 4000;
437
+ const face = (photoId: string) =>
438
+ `https://images.unsplash.com/${photoId}?w=256&h=256&fit=crop&crop=faces&auto=format`;
439
+ const faces = {
440
+ ada: face('photo-1494790108377-be9c29b29330'),
441
+ };
406
442
 
407
443
  type FeedEntry = {
408
444
  id: number;
@@ -429,7 +465,7 @@ const feed: FeedEntry[] = [
429
465
  actor: 'Ada Lovelace',
430
466
  action: 'approved the release',
431
467
  time: '14 minutes ago',
432
- src: demoFaces.ada,
468
+ src: faces.ada,
433
469
  initials: 'AL',
434
470
  },
435
471
  {
@@ -62,12 +62,10 @@ the soft palette from
62
62
 
63
63
  ```vue
64
64
  <template>
65
- <div
66
- class="flex max-w-md flex-col gap-3 rounded-[var(--bb-radius)] border p-3"
67
- >
65
+ <div class="flex max-w-md flex-col gap-3 rounded-(--bb-radius) border p-3">
68
66
  <div class="flex flex-col gap-0.5">
69
67
  <p class="text-sm font-medium">Invoice status</p>
70
- <p class="text-xs text-[color:var(--bb-text-muted)]">
68
+ <p class="text-xs text-(--bb-text-muted)">
71
69
  Soft accents for a small, fixed status set — not every row color.
72
70
  </p>
73
71
  </div>
@@ -80,16 +78,14 @@ the soft palette from
80
78
  >
81
79
  <span class="min-w-0 truncate">
82
80
  <span class="font-medium">{{ row.number }}</span>
83
- <span class="text-[color:var(--bb-text-muted)]">
84
- · {{ row.client }}</span
85
- >
81
+ <span class="text-(--bb-text-muted)"> · {{ row.client }}</span>
86
82
  </span>
87
83
  <BbBadge size="sm" :variant="row.variant">{{ row.status }}</BbBadge>
88
84
  </li>
89
85
  </ul>
90
86
 
91
87
  <div class="flex flex-wrap items-center gap-1.5 border-t pt-3">
92
- <span class="mr-1 text-xs text-[color:var(--bb-text-muted)]">Plan</span>
88
+ <span class="mr-1 text-xs text-(--bb-text-muted)">Plan</span>
93
89
  <BbBadge size="sm" variant="soft-gray">Free</BbBadge>
94
90
  <BbBadge size="sm" variant="soft-blue">Pro</BbBadge>
95
91
  <BbBadge size="sm" variant="soft-amber">Enterprise</BbBadge>
@@ -186,17 +182,15 @@ yourself (`99+`) — there is no `max` prop.
186
182
  <template>
187
183
  <nav
188
184
  aria-label="Mail folders"
189
- class="flex max-w-56 flex-col gap-0.5 rounded-[var(--bb-radius)] border p-1.5 text-sm"
185
+ class="flex max-w-56 flex-col gap-0.5 rounded-(--bb-radius) border p-1.5 text-sm"
190
186
  >
191
187
  <a
192
188
  v-for="folder in folders"
193
189
  :key="folder.href"
194
190
  :aria-current="folder.active ? 'page' : undefined"
195
- class="flex items-center justify-between gap-2 rounded-[var(--bb-radius-sm)] px-2 py-1"
191
+ class="flex items-center justify-between gap-2 rounded-(--bb-radius-sm) px-2 py-1"
196
192
  :class="
197
- folder.active
198
- ? 'bg-[color:var(--bb-muted)] font-medium'
199
- : 'text-[color:var(--bb-text)]'
193
+ folder.active ? 'bg-(--bb-muted) font-medium' : 'text-(--bb-text)'
200
194
  "
201
195
  :href="folder.href"
202
196
  >
@@ -355,16 +349,14 @@ button. Reserve `sm` for dense in-table status pills, and omit `size`
355
349
 
356
350
  ```vue
357
351
  <template>
358
- <div
359
- class="flex max-w-md flex-col gap-2 rounded-[var(--bb-radius)] border p-3"
360
- >
352
+ <div class="flex max-w-md flex-col gap-2 rounded-(--bb-radius) border p-3">
361
353
  <div class="flex items-center justify-between gap-2">
362
354
  <p class="text-sm font-medium">Invoices</p>
363
- <p class="text-xs text-[color:var(--bb-text-muted)]">{{ resultLabel }}</p>
355
+ <p class="text-xs text-(--bb-text-muted)">{{ resultLabel }}</p>
364
356
  </div>
365
357
 
366
358
  <div class="flex flex-wrap items-center gap-1.5">
367
- <span class="text-xs text-[color:var(--bb-text-muted)]">Filtered by</span>
359
+ <span class="text-xs text-(--bb-text-muted)">Filtered by</span>
368
360
  <BbBadge
369
361
  v-for="filter in filters"
370
362
  :key="filter.id"
@@ -539,9 +531,9 @@ anchor an overlay directly — no wrapper element, no `defineExpose`:
539
531
  ```vue
540
532
  <template>
541
533
  <div
542
- class="flex max-w-sm flex-wrap items-center gap-2 rounded-[var(--bb-radius)] border p-3"
534
+ class="flex max-w-sm flex-wrap items-center gap-2 rounded-(--bb-radius) border p-3"
543
535
  >
544
- <span class="text-xs text-[color:var(--bb-text-muted)]">Filters</span>
536
+ <span class="text-xs text-(--bb-text-muted)">Filters</span>
545
537
 
546
538
  <BbBadge
547
539
  append:icon="lucide:chevron-down"
@@ -65,27 +65,27 @@ primitive brings no look of its own):
65
65
  <div class="flex flex-wrap items-center gap-2 text-sm">
66
66
  <!-- No href/to → a native <button>. -->
67
67
  <BbBaseButton
68
- class="rounded-[var(--bb-radius)] bg-[var(--bb-primary)] px-3 py-1.5 text-[var(--bb-primary-fg)]"
68
+ class="rounded-(--bb-radius) bg-(--bb-primary) px-3 py-1.5 text-(--bb-primary-fg)"
69
69
  @click="pinged = true"
70
70
  >
71
71
  Native button
72
72
  </BbBaseButton>
73
73
  <!-- Same-origin href → an <a>. -->
74
74
  <BbBaseButton
75
- class="rounded-[var(--bb-radius)] px-3 py-1.5 text-[color:var(--bb-primary)] underline"
75
+ class="rounded-(--bb-radius) px-3 py-1.5 text-(--bb-primary) underline"
76
76
  href="#docs"
77
77
  >
78
78
  Anchor link
79
79
  </BbBaseButton>
80
80
  <!-- href + target → a plain <a target="_blank"> with rel secured. -->
81
81
  <BbBaseButton
82
- class="rounded-[var(--bb-radius)] px-3 py-1.5 underline"
82
+ class="rounded-(--bb-radius) px-3 py-1.5 underline"
83
83
  href="https://example.com"
84
84
  target="_blank"
85
85
  >
86
86
  External ↗
87
87
  </BbBaseButton>
88
- <span class="text-xs text-[color:var(--bb-text-muted)]">{{
88
+ <span class="text-xs text-(--bb-text-muted)">{{
89
89
  pinged ? 'button clicked' : ''
90
90
  }}</span>
91
91
  </div>
@@ -120,7 +120,7 @@ the right base for a clickable card or a bespoke nav item:
120
120
  <!-- Styled entirely by utility classes — neutral hover chrome. -->
121
121
  <BbBaseButton
122
122
  href="#b"
123
- class="rounded-[var(--bb-radius)] border border-[var(--bb-border)] px-3 py-1 font-medium hover:bg-[color:var(--bb-hover)]"
123
+ class="rounded-(--bb-radius) border border-(--bb-border) px-3 py-1 font-medium hover:bg-(--bb-hover)"
124
124
  >
125
125
  Branded pill
126
126
  </BbBaseButton>
@@ -140,21 +140,19 @@ A whole card as a single navigable element — the primitive's signature use:
140
140
  <BbBaseButton
141
141
  v-for="project in projects"
142
142
  :key="project.name"
143
- class="project-card flex flex-col items-start gap-1.5 rounded-[var(--bb-radius)] border border-[var(--bb-border)] bg-[var(--bb-panel)] p-3 text-left hover:bg-[color:var(--bb-surface-hover)]"
143
+ class="project-card flex flex-col items-start gap-1.5 rounded-(--bb-radius) border border-(--bb-border) bg-(--bb-panel) p-3 text-left hover:bg-(--bb-surface-hover)"
144
144
  :href="project.href"
145
145
  >
146
146
  <span class="flex w-full items-center justify-between gap-2">
147
147
  <span
148
- class="flex size-7 shrink-0 items-center justify-center rounded-[var(--bb-radius-sm)] bg-[color:var(--bb-muted)] text-[color:var(--bb-text-muted)]"
148
+ class="flex size-7 shrink-0 items-center justify-center rounded-(--bb-radius-sm) bg-(--bb-muted) text-(--bb-text-muted)"
149
149
  >
150
150
  <BbIcon :icon="project.icon" size="sm" />
151
151
  </span>
152
152
  <BbBadge variant="secondary">{{ project.status }}</BbBadge>
153
153
  </span>
154
154
  <span class="text-sm font-medium">{{ project.name }}</span>
155
- <span class="text-xs text-[color:var(--bb-text-muted)]">{{
156
- project.meta
157
- }}</span>
155
+ <span class="text-xs text-(--bb-text-muted)">{{ project.meta }}</span>
158
156
  </BbBaseButton>
159
157
  </div>
160
158
  </template>
@@ -269,7 +267,7 @@ The classic home for this is a settings sidebar — every item is a bare
269
267
  <template>
270
268
  <nav
271
269
  aria-label="Settings"
272
- class="grid w-full max-w-xs gap-0.5 rounded-[var(--bb-radius)] border border-[var(--bb-border)] bg-[var(--bb-panel)] p-1.5"
270
+ class="grid w-full max-w-xs gap-0.5 rounded-(--bb-radius) border border-(--bb-border) bg-(--bb-panel) p-1.5"
273
271
  >
274
272
  <!-- Each nav item is a bare BbBaseButton: element resolution and active
275
273
  matching come from the primitive, the entire look comes from these
@@ -279,7 +277,7 @@ The classic home for this is a settings sidebar — every item is a bare
279
277
  v-for="item in items"
280
278
  :key="item.label"
281
279
  block
282
- class="settings-nav-item flex items-center gap-2 rounded-[var(--bb-radius-sm)] px-2 py-1.5 text-left text-sm text-[color:var(--bb-text-muted)] hover:bg-[color:var(--bb-hover)] hover:text-[color:var(--bb-text)]"
280
+ class="settings-nav-item flex items-center gap-2 rounded-(--bb-radius-sm) px-2 py-1.5 text-left text-sm text-(--bb-text-muted) hover:bg-(--bb-hover) hover:text-(--bb-text)"
283
281
  exact-active-class="settings-nav-active"
284
282
  :href="item.href"
285
283
  >
@@ -347,7 +345,7 @@ attribute. On a link it keeps the element in place but strips navigation: the
347
345
  <div class="flex items-center gap-2 text-sm">
348
346
  <BbBaseButton
349
347
  disabled
350
- class="rounded-[var(--bb-radius)] bg-[var(--bb-primary)] px-3 py-1.5 text-[var(--bb-primary-fg)] opacity-50"
348
+ class="rounded-(--bb-radius) bg-(--bb-primary) px-3 py-1.5 text-(--bb-primary-fg) opacity-50"
351
349
  >
352
350
  Disabled button
353
351
  </BbBaseButton>
@@ -379,11 +377,11 @@ When it renders as a native button you can retune the element:
379
377
  ```vue
380
378
  <template>
381
379
  <form
382
- class="grid max-w-xs gap-2 rounded-[var(--bb-radius)] border border-[var(--bb-border)] bg-[var(--bb-panel)] p-3"
380
+ class="grid max-w-xs gap-2 rounded-(--bb-radius) border border-(--bb-border) bg-(--bb-panel) p-3"
383
381
  @submit.prevent="sent = true"
384
382
  >
385
383
  <p class="text-sm font-medium">New workspace</p>
386
- <p class="text-xs text-[color:var(--bb-text-muted)]">
384
+ <p class="text-xs text-(--bb-text-muted)">
387
385
  {{
388
386
  sent
389
387
  ? 'Submitted via the native form event.'
@@ -392,7 +390,7 @@ When it renders as a native button you can retune the element:
392
390
  </p>
393
391
  <BbBaseButton
394
392
  block
395
- class="rounded-[var(--bb-radius)] bg-[var(--bb-primary)] px-3 py-1.5 text-sm text-[var(--bb-primary-fg)]"
393
+ class="rounded-(--bb-radius) bg-(--bb-primary) px-3 py-1.5 text-sm text-(--bb-primary-fg)"
396
394
  type="submit"
397
395
  >
398
396
  Create workspace
@@ -51,12 +51,10 @@ around it.
51
51
 
52
52
  ```vue
53
53
  <template>
54
- <div
55
- class="flex max-w-sm flex-col gap-2 rounded-[var(--bb-radius)] border p-3"
56
- >
54
+ <div class="flex max-w-sm flex-col gap-2 rounded-(--bb-radius) border p-3">
57
55
  <div class="flex flex-col gap-0.5">
58
56
  <p class="text-sm font-medium">Invoice alerts</p>
59
- <p class="text-xs text-[color:var(--bb-text-muted)]">
57
+ <p class="text-xs text-(--bb-text-muted)">
60
58
  Northwind · overdue notices for INV-1042 and later
61
59
  </p>
62
60
  </div>
@@ -66,11 +64,11 @@ around it.
66
64
  <label
67
65
  v-for="channel in channels"
68
66
  :key="channel.id"
69
- class="flex cursor-pointer items-center gap-2.5 rounded-[var(--bb-radius)] border p-2.5 transition-colors"
67
+ class="flex cursor-pointer items-center gap-2.5 rounded-(--bb-radius) border p-2.5 transition-colors"
70
68
  :class="
71
69
  selected.includes(channel.id)
72
- ? 'border-[color:var(--bb-primary)] bg-[color:var(--bb-muted)]'
73
- : 'border-[color:var(--bb-border)] hover:bg-[color:var(--bb-surface-hover)]'
70
+ ? 'border-(--bb-primary) bg-(--bb-muted)'
71
+ : 'border-(--bb-border) hover:bg-(--bb-surface-hover)'
74
72
  "
75
73
  >
76
74
  <!-- Glyph is decorative; the sr-only input owns focus, keyboard, and form state. -->
@@ -83,9 +81,7 @@ around it.
83
81
  <BbBaseCheckboxIcon :checked="selected.includes(channel.id)" />
84
82
  <span class="flex min-w-0 flex-col">
85
83
  <span class="text-sm font-medium">{{ channel.label }}</span>
86
- <span class="text-xs text-[color:var(--bb-text-muted)]">{{
87
- channel.hint
88
- }}</span>
84
+ <span class="text-xs text-(--bb-text-muted)">{{ channel.hint }}</span>
89
85
  </span>
90
86
  </label>
91
87
  </fieldset>
@@ -50,12 +50,10 @@ and arrow-key navigation for free.
50
50
 
51
51
  ```vue
52
52
  <template>
53
- <div
54
- class="flex max-w-sm flex-col gap-2 rounded-[var(--bb-radius)] border p-3"
55
- >
53
+ <div class="flex max-w-sm flex-col gap-2 rounded-(--bb-radius) border p-3">
56
54
  <div class="flex flex-col gap-0.5">
57
55
  <p class="text-sm font-medium">Workspace plan</p>
58
- <p class="text-xs text-[color:var(--bb-text-muted)]">
56
+ <p class="text-xs text-(--bb-text-muted)">
59
57
  Billed monthly · cancel anytime
60
58
  </p>
61
59
  </div>
@@ -65,11 +63,11 @@ and arrow-key navigation for free.
65
63
  <label
66
64
  v-for="plan in plans"
67
65
  :key="plan.id"
68
- class="flex cursor-pointer items-center gap-2.5 rounded-[var(--bb-radius)] border p-2.5 transition-colors"
66
+ class="flex cursor-pointer items-center gap-2.5 rounded-(--bb-radius) border p-2.5 transition-colors"
69
67
  :class="
70
68
  selected === plan.id
71
- ? 'border-[color:var(--bb-primary)] bg-[color:var(--bb-muted)]'
72
- : 'border-[color:var(--bb-border)] hover:bg-[color:var(--bb-surface-hover)]'
69
+ ? 'border-(--bb-primary) bg-(--bb-muted)'
70
+ : 'border-(--bb-border) hover:bg-(--bb-surface-hover)'
73
71
  "
74
72
  >
75
73
  <!-- Native radios sharing `name` give exclusive selection + arrow keys. -->
@@ -84,9 +82,7 @@ and arrow-key navigation for free.
84
82
  <span class="flex min-w-0 flex-1 items-start justify-between gap-3">
85
83
  <span class="flex min-w-0 flex-col">
86
84
  <span class="text-sm font-medium">{{ plan.label }}</span>
87
- <span class="text-xs text-[color:var(--bb-text-muted)]">{{
88
- plan.hint
89
- }}</span>
85
+ <span class="text-xs text-(--bb-text-muted)">{{ plan.hint }}</span>
90
86
  </span>
91
87
  <span class="shrink-0 text-xs font-medium tabular-nums">
92
88
  {{ plan.price }}
@@ -50,27 +50,23 @@ keyboard support, focus, and switch semantics for free.
50
50
 
51
51
  ```vue
52
52
  <template>
53
- <div
54
- class="flex max-w-sm flex-col gap-2 rounded-[var(--bb-radius)] border p-3"
55
- >
53
+ <div class="flex max-w-sm flex-col gap-2 rounded-(--bb-radius) border p-3">
56
54
  <div class="flex flex-col gap-0.5">
57
55
  <p class="text-sm font-medium">Workspace experiments</p>
58
- <p class="text-xs text-[color:var(--bb-text-muted)]">
56
+ <p class="text-xs text-(--bb-text-muted)">
59
57
  Northwind Billing · flags apply to every seat
60
58
  </p>
61
59
  </div>
62
60
 
63
- <div class="flex flex-col divide-y rounded-[var(--bb-radius)] border">
61
+ <div class="flex flex-col divide-y rounded-(--bb-radius) border">
64
62
  <label
65
63
  v-for="flag in flags"
66
64
  :key="flag.id"
67
- class="flex cursor-pointer items-center justify-between gap-3 px-2.5 py-2 hover:bg-[color:var(--bb-surface-hover)]"
65
+ class="flex cursor-pointer items-center justify-between gap-3 px-2.5 py-2 hover:bg-(--bb-surface-hover)"
68
66
  >
69
67
  <span class="flex min-w-0 flex-col">
70
68
  <span class="text-sm font-medium">{{ flag.label }}</span>
71
- <span class="text-xs text-[color:var(--bb-text-muted)]">{{
72
- flag.hint
73
- }}</span>
69
+ <span class="text-xs text-(--bb-text-muted)">{{ flag.hint }}</span>
74
70
  </span>
75
71
  <!-- Glyph tracks state; the checkbox + role="switch" owns a11y. -->
76
72
  <input