bitboss-ui 3.0.0-beta.0 → 3.0.0-beta.10

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 (87) hide show
  1. package/README.md +36 -29
  2. package/bin/bitboss-ui.mjs +133 -12
  3. package/dist/ai/BbBadge.md +10 -5
  4. package/dist/ai/BbSelect.md +8 -0
  5. package/dist/ai/BbTable.md +658 -65
  6. package/dist/ai/changelog.json +92 -2
  7. package/dist/ai/components.json +60 -18
  8. package/dist/ai/guides/ai-router.md +2 -2
  9. package/dist/ai/guides/component-picker.md +2 -2
  10. package/dist/ai/guides/design-language.md +14 -14
  11. package/dist/ai/guides/design-tokens.md +64 -17
  12. package/dist/ai/guides/installation-and-plugin-setup.md +72 -6
  13. package/dist/ai/guides/migration/components/bb-alert.md +37 -0
  14. package/dist/ai/guides/migration/components/bb-avatar.md +47 -8
  15. package/dist/ai/guides/migration/components/bb-badge.md +23 -1
  16. package/dist/ai/guides/migration/components/bb-button.md +64 -0
  17. package/dist/ai/guides/migration/components/bb-checkbox-group.md +55 -1
  18. package/dist/ai/guides/migration/components/bb-date-picker-input.md +9 -2
  19. package/dist/ai/guides/migration/components/bb-dialog.md +127 -11
  20. package/dist/ai/guides/migration/components/bb-icon.md +42 -0
  21. package/dist/ai/guides/migration/components/bb-offcanvas.md +35 -1
  22. package/dist/ai/guides/migration/components/bb-rating.md +52 -1
  23. package/dist/ai/guides/migration/components/bb-select.md +48 -0
  24. package/dist/ai/guides/migration/components/bb-table.md +577 -13
  25. package/dist/ai/guides/migration/components/bb-tabs.md +79 -1
  26. package/dist/ai/guides/migration/components/bb-text-input.md +23 -1
  27. package/dist/ai/guides/migration/components/bb-toast.md +44 -10
  28. package/dist/ai/guides/migration/components/use-confirm.md +48 -13
  29. package/dist/ai/guides/migration/v2-to-v3.md +726 -108
  30. package/dist/ai/index.md +9 -9
  31. package/dist/ai/recipes/inertia/layout-scaffold.md +5 -1
  32. package/dist/ai/recipes/inertia/ownership-atlas.md +41 -20
  33. package/dist/ai/recipes/inertia/records-workspace.md +26 -7
  34. package/dist/ai/recipes/nuxt/layout-scaffold.md +5 -1
  35. package/dist/ai/recipes/nuxt/records-workspace.md +26 -7
  36. package/dist/ai/recipes/vue/layout-scaffold.md +5 -1
  37. package/dist/ai/recipes/vue/records-workspace.md +26 -7
  38. package/dist/ai/source/BbBaseInputContainer.md +26 -0
  39. package/dist/ai/source/BbBreadcrumbs.md +31 -0
  40. package/dist/ai/source/BbButton.md +12 -1
  41. package/dist/ai/source/BbDialog.md +39 -13
  42. package/dist/ai/source/BbDropdown.md +53 -10
  43. package/dist/ai/source/BbDropdownGroup.md +53 -10
  44. package/dist/ai/source/BbOffCanvas.md +42 -12
  45. package/dist/ai/source/BbProgress.md +2 -2
  46. package/dist/ai/source/BbTable.md +2519 -945
  47. package/dist/ai/source/CommonInputWrapper.md +4 -0
  48. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +3 -1
  49. package/dist/components/BbPagination/BbPagination.vue.d.ts +1 -1
  50. package/dist/components/BbTable/BbTable.vue.d.ts +8 -4
  51. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +907 -518
  52. package/dist/components/BbTable/types.d.ts +221 -86
  53. package/dist/components/BbTable/utils.d.ts +71 -4
  54. package/dist/components/BbTable/utils.js +66 -35
  55. package/dist/i18n/locales/cs.json +4 -1
  56. package/dist/i18n/locales/da.json +4 -1
  57. package/dist/i18n/locales/de.json +4 -1
  58. package/dist/i18n/locales/el.json +4 -1
  59. package/dist/i18n/locales/en.json +4 -1
  60. package/dist/i18n/locales/es.json +4 -1
  61. package/dist/i18n/locales/fi.json +4 -1
  62. package/dist/i18n/locales/fr.json +4 -1
  63. package/dist/i18n/locales/hu.json +4 -1
  64. package/dist/i18n/locales/it.json +4 -1
  65. package/dist/i18n/locales/ja.json +4 -1
  66. package/dist/i18n/locales/ko.json +4 -1
  67. package/dist/i18n/locales/nb.json +4 -1
  68. package/dist/i18n/locales/nl.json +4 -1
  69. package/dist/i18n/locales/pl.json +4 -1
  70. package/dist/i18n/locales/pt.json +4 -1
  71. package/dist/i18n/locales/ro.json +4 -1
  72. package/dist/i18n/locales/ru.json +4 -1
  73. package/dist/i18n/locales/sv.json +4 -1
  74. package/dist/i18n/locales/tr.json +4 -1
  75. package/dist/i18n/locales/uk.json +4 -1
  76. package/dist/i18n/locales/zh-cn.json +4 -1
  77. package/dist/index.d.ts +7 -2
  78. package/dist/index.js +68 -67
  79. package/dist/llms-full.txt +3186 -512
  80. package/dist/llms-medium.txt +99 -33
  81. package/dist/llms.txt +11 -11
  82. package/dist/locale-blueprint.json +4 -1
  83. package/dist/styles.css +1 -1
  84. package/llms.txt +12 -12
  85. package/package.json +2 -1
  86. package/scripts/lib/validate-bb-markup.mjs +105 -17
  87. package/dist/assets/svgs/sort.svg_raw.js +0 -4
package/README.md CHANGED
@@ -36,46 +36,53 @@ Full detail: `ai/guides/installation-and-plugin-setup.md`.
36
36
 
37
37
  ### Composables
38
38
 
39
- | Composable | Role |
40
- | ----------------------------- | ---------------------------------------------------------- |
41
- | `useBbConfig` | Global options for the kit (locale, defaults, etc.). |
42
- | `useBroadcastChannelInstance` | Shared `BroadcastChannel` helper for cross-tab messaging. |
43
- | `useConfirm` | Programmatic confirm / modal flows. |
44
- | `useCountdown` | Countdown timer state. |
45
- | `useMobile` | Mobile / viewport-oriented behaviour. |
46
- | `useQueue` | Simple async task queue. |
47
- | `useSafeArea` | Claim a screen edge for a docked panel so toasts avoid it. |
48
- | `useToast` | Toast notifications API. |
49
-
50
- ### Base\* components (primitives) _(reference-only - prefer `Bb*` equivalents for consumer code)_
51
-
52
- Headless or low-level pieces used inside **Bb\*** wrappers or your own compositions:
53
-
54
- - **Actions:** `BbBaseButton`
55
- - **Text & numbers:** `BaseTextInput`, `BaseTextarea`, `BaseNumberInput`, `BaseTag`
56
- - **Choice:** `BaseCheckbox`, `BaseCheckboxGroup`, `BaseRadio`, `BaseRadioGroup`, `BaseSwitch`, `BaseSwitchGroup`, `BaseSlider`, `BaseRating`
57
- - **Choice glyphs (presentational SVGs):** `BbBaseCheckboxIcon`, `BbBaseRadioIcon`, `BbBaseSwitchIcon`
58
- - **Rich inputs:** `BaseSelect`, `BaseColorInput`, `BaseDatePicker`, `BaseDatePickerInput`
59
- - **Layout / chrome:** `BaseInputContainer`, `BaseDialog`
39
+ | Composable | Role |
40
+ | ---------------------- | --------------------------------------------------------------------- |
41
+ | `useBbConfig` | Global options for the kit (locale, defaults, etc.). |
42
+ | `useBbDropdownContext` | Read a `BbDropdown`'s resolved groups/selections from anywhere by id. |
43
+ | `useBbTableContext` | Imperative handle onto a `BbTable` by id. |
44
+ | `useBbTabsContext` | Programmatic tab selection for a `BbTabs` by id. |
45
+ | `useConfirm` | Programmatic confirm / modal flows. |
46
+ | `useCountdown` | Countdown timer state. |
47
+ | `useId` | SSR-safe unique ids. |
48
+ | `useMobile` | Mobile / viewport-oriented behaviour. |
49
+ | `useSafeArea` | Claim a screen edge for a docked panel so toasts avoid it. |
50
+ | `useToast` | Toast notifications API. |
51
+
52
+ ### Utilities
53
+
54
+ - **`slotKey`** — the normalizer behind every dynamic per-item named slot (`BbDropdown`, `BbTable`, `BbTabs`, `BbTree`, `BbBreadcrumbs`). Import it when building slot names programmatically instead of restating the rule.
55
+
56
+ ### Directives
57
+
58
+ `vBbTooltip`, `vBbDropdown`, `vBbColor`, `vBbDate`, `vBbTime` — plus a
59
+ `Bb*DirectivePlugin` for each, for app-level registration. Prefer the directive
60
+ over the component for simple no-slot cases.
61
+
62
+ ### Base\* primitives
63
+
64
+ The styled `Base*` input controls and the input chrome (`BbBaseInputContainer`,
65
+ `CommonInputWrapper` — label, prepend/append, prefix/suffix, clear button,
66
+ spacing) are **internal composition layers and are not exported**. Use the full
67
+ public inputs (`BbTextInput`, `BbSelect`, …); pass `hideLabel` for a
68
+ bare/inline control. The exported primitives are **`BbBaseButton`** and the
69
+ presentational glyphs **`BbBaseCheckboxIcon`**, **`BbBaseRadioIcon`**,
70
+ **`BbBaseSwitchIcon`**.
60
71
 
61
72
  ### Bb\* components (composed)
62
73
 
63
74
  Product-ready components with labels, hints, errors, and consistent styling:
64
75
 
65
- - **Forms & actions:** `BbTextInput`, `BbTextarea`, `BbNumberInput`, `BbSelect`, `BbCheckbox`, `BbCheckboxGroup`, `BbRadio`, `BbRadioGroup`, `BbSwitch`, `BbSwitchGroup`, `BbSlider`, `BbRating`, `BbColorInput`, `BbDatePickerInput`, `BbButton`, `BbBadge`, `BbIndicator`, `BbTag`, `BbDropdown`, `BbDropdownButton`
66
- - **Feedback:** `BbAlert`, `BbProgress`, `BbSpinner`, `BbToast`, `BbTooltip`
67
- - **Layout & navigation:** `BbAccordion`, `BbCollapsible`, `BbTab`, `BbBreadcrumbs`, `BbPagination`,`BbSmoothHeight`
76
+ - **Forms & actions:** `BbTextInput`, `BbTextarea`, `BbNumberInput`, `BbSelect`, `BbSelectPopover`, `BbCheckbox`, `BbCheckboxGroup`, `BbRadio`, `BbRadioGroup`, `BbSwitch`, `BbSwitchGroup`, `BbSlider`, `BbRating`, `BbColorInput`, `BbColorPalette`, `BbDatePicker`, `BbDatePickerInput`, `BbTimePicker`, `BbTimePickerInput`, `BbButton`, `BbBadge`, `BbBadgeButton`, `BbIndicator`, `BbTag`, `BbDropdown`, `BbDropdownGroup`, `BbDropdownButton`, `BbAsterisk`
77
+ - **Feedback:** `BbAlert`, `BbProgress`, `BbSpinner`, `BbToast`, `BbToastPortal`, `BbTooltip`
78
+ - **Layout & navigation:** `BbAccordion`, `BbCollapsible`, `BbTabs` (+ `BbTabsRoot`, `BbTabsList`, `BbTabsPanes`), `BbBreadcrumbs`, `BbPagination`, `BbSmoothHeight`
68
79
  - **Overlays & panels:** `BbDialog`, `BbConfirm`, `BbConfirmPortal`, `BbOffCanvas`, `BbPopover`
69
80
  - **Data:** `BbTable`, `BbTree`
70
81
  - **Media & files:** `BbAvatar`, `BbDropzone`, `BbIcon`
71
82
 
72
- ### Shared input shells _(internal layout primitives - not for direct consumer use)_
73
-
74
- - **`CommonInputWrapper`** — the internal input-chrome primitive (label, prepend/append, prefix/suffix, clear button, spacing) that every `Bb*` input composes. Not exported; use the full public inputs (`BbTextInput`, `BbSelect`, …).
75
-
76
83
  ### Exported component types
77
84
 
78
- For most **Base\*** and **Bb\*** components, the package exports matching **props**, **events**, and (where relevant) **slots** types (for example `BbSelectProps`, `BaseSelectEvents`). Use them for typed wrappers and design-system layers; the docs list the full set per component.
85
+ For the public **Bb\*** components, the package exports matching **props**, **events**, and (where relevant) **slots** types (for example `BbSelectProps`, `BbTableEvents`), plus supporting shapes like `BbDropdownItem` and `DropdownGroupItemsGetter`. Use them for typed wrappers and design-system layers; the docs list the full set per component.
79
86
 
80
87
  ---
81
88
 
@@ -17,7 +17,17 @@
17
17
  * components.json manifest (unknown props, removed props, bad
18
18
  * v-models, unknown `<template #slot>` names, `href`/`to`/
19
19
  * `method` on a component that doesn't declare them). Exits 1
20
- * on findings; supports --json output.
20
+ * on findings; supports --json output. Every finding carries the
21
+ * source line. `--allow-component <Name>` (or package.json's
22
+ * `bitboss-ui.allowComponents`) exempts an app-owned component
23
+ * whose name happens to start with `Bb`.
24
+ *
25
+ * SCOPE: `check` knows the INSTALLED v3 API and nothing about v2.
26
+ * "was removed from X" is a recorded v2→v3 break; "is not in X's
27
+ * API" only says the prop is not a v3 prop of that component —
28
+ * it may never have been one anywhere. `printFindingLegend` says
29
+ * so in the output, because two migrating fleets each spent real
30
+ * time discovering it the hard way.
21
31
  * mcp Start a stdio MCP server exposing the dist/ai knowledge base
22
32
  * (search_components, get_component, list_recipes, get_recipe,
23
33
  * validate) to MCP-capable agent harnesses.
@@ -445,12 +455,84 @@ function summarizeFileCounts(files) {
445
455
  return exts.map((ext) => `${counts.get(ext)} ${ext}`).join(' + ');
446
456
  }
447
457
 
458
+ /**
459
+ * Component names the PROJECT owns despite the `Bb` prefix, read from disk so
460
+ * CI, the editor and a local run agree without repeating a flag.
461
+ *
462
+ * Two sources, merged: `bitboss-ui.check.json`'s `allowComponents`, and
463
+ * package.json's `bitboss-ui.allowComponents`. The package.json key is the one
464
+ * to reach for — it sits next to the `eslint.config.js` that already carries
465
+ * the same list for `no-unknown-attributes`, so the two gates stay in sync.
466
+ * Unreadable/malformed files are ignored: a broken config must not turn into a
467
+ * check failure about markup.
468
+ * @returns {string[]}
469
+ */
470
+ function configuredAllowComponents(projectRoot) {
471
+ const out = [];
472
+ const readList = (path, pick) => {
473
+ try {
474
+ if (!existsSync(path)) return;
475
+ const value = pick(JSON.parse(readFileSync(path, 'utf-8')));
476
+ if (Array.isArray(value))
477
+ for (const name of value) if (typeof name === 'string') out.push(name);
478
+ } catch {
479
+ /* malformed config — ignore, never fail the check on it */
480
+ }
481
+ };
482
+ readList(
483
+ join(projectRoot, 'bitboss-ui.check.json'),
484
+ (cfg) => cfg?.allowComponents
485
+ );
486
+ readList(
487
+ join(projectRoot, 'package.json'),
488
+ (pkg) => pkg?.['bitboss-ui']?.allowComponents
489
+ );
490
+ return out;
491
+ }
492
+
493
+ /**
494
+ * CHK-SINCE-V2 — the two unknown-prop message shapes mean OPPOSITE things and
495
+ * nothing in the output said so. One migrating fleet filed two non-findings
496
+ * against the library, and the other told the categories apart only by
497
+ * installing v2 alongside and diffing by hand. Printed once per failing run,
498
+ * and only for the kinds actually present.
499
+ *
500
+ * `check` is honest about its limits here: it validates against the INSTALLED
501
+ * v3 manifest and holds no record of v2, so "is not in X's API" is a statement
502
+ * about v3 alone. Deciding whether such a prop ever worked is the reader's job,
503
+ * and the greps in the migration guide are how it is done.
504
+ */
505
+ function printFindingLegend(findings) {
506
+ const kinds = new Set(findings.map((f) => f.kind));
507
+ const rows = [];
508
+ if (kinds.has('removed-prop'))
509
+ rows.push(
510
+ ' "was removed from X" a v2→v3 break. X really had this prop; fix the call site.'
511
+ );
512
+ if (kinds.has('unknown-prop'))
513
+ rows.push(
514
+ ' "is not in X\'s API" X does not declare this prop in v3 — and `check` cannot\n' +
515
+ ' say whether it ever did. It may be a v3 removal that\n' +
516
+ ' predates the removal register, or a name that was never\n' +
517
+ ' a prop at all and has always fallen through to the DOM\n' +
518
+ ' as an inert attribute. Check the v2 source before\n' +
519
+ ' "restoring" anything: the second case needs deleting,\n' +
520
+ ' not porting.'
521
+ );
522
+ if (rows.length === 0) return;
523
+ console.error('\nReading these findings:');
524
+ for (const row of rows) console.error(row);
525
+ console.error(
526
+ ' `check` reads the installed v3 manifest only; the package carries no v2 API.'
527
+ );
528
+ }
529
+
448
530
  /**
449
531
  * `npx bitboss-ui check [glob…] [--json]` — validate `Bb*` markup (props,
450
532
  * v-models, and `<template #slot>` names) in `.vue` and `.md` files against
451
533
  * the installed components.json manifest.
452
534
  */
453
- function checkCommand(globs, jsonMode, allowEmpty = false) {
535
+ function checkCommand(globs, { json: jsonMode, allowEmpty, allowComponents }) {
454
536
  const projectRoot = process.cwd();
455
537
 
456
538
  const manifestPath = join(PACKAGE_ROOT, 'dist', 'ai', 'components.json');
@@ -481,6 +563,15 @@ function checkCommand(globs, jsonMode, allowEmpty = false) {
481
563
  : new Set();
482
564
  const files = resolveCheckFiles(projectRoot, globs);
483
565
 
566
+ // CHK-ALLOWCOMPONENTS: `Bb` is a naming convention, not proof of ownership.
567
+ // An app component called `BbRichEditor` is not invalid library markup, and
568
+ // before this the only way to silence it was to rename the component.
569
+ const allowedComponents = [
570
+ ...configuredAllowComponents(projectRoot),
571
+ ...allowComponents,
572
+ ];
573
+ const validateOptions = { allowComponents: allowedComponents };
574
+
484
575
  const findings = [];
485
576
  /*
486
577
  * Advisory only — see scripts/lib/hand-roll-hints.mjs. Hints never touch the
@@ -493,8 +584,8 @@ function checkCommand(globs, jsonMode, allowEmpty = false) {
493
584
  const relPath = relative(projectRoot, file);
494
585
  const content = readFileSync(file, 'utf-8');
495
586
  const { findings: fileFindings } = file.endsWith('.md')
496
- ? validateMarkdown(content, manifest)
497
- : validateVueSnippet(content, manifest);
587
+ ? validateMarkdown(content, manifest, validateOptions)
588
+ : validateVueSnippet(content, manifest, validateOptions);
498
589
  for (const finding of fileFindings) {
499
590
  findings.push({ file: relPath, ...finding });
500
591
  }
@@ -573,14 +664,19 @@ function checkCommand(globs, jsonMode, allowEmpty = false) {
573
664
  finding.fenceInfo != null
574
665
  ? `fence#${finding.fenceIndex}${finding.fenceInfo ? ` (${finding.fenceInfo})` : ''} `
575
666
  : '';
667
+ // CHK-LINE: three identical `full-screen` findings under one filename
668
+ // were indistinguishable, so every automated fix had to re-parse the
669
+ // file to place them. The line comes straight off the template AST.
670
+ const at = finding.line != null ? `line ${finding.line}: ` : '';
576
671
  console.error(
577
- ` ✗ ${where ? `[${where.trim()}] ` : ''}${finding.message}`
672
+ ` ✗ ${at}${where ? `[${where.trim()}] ` : ''}${finding.message}`
578
673
  );
579
674
  if (finding.hint) console.error(` hint: ${finding.hint}`);
580
675
  }
581
676
  console.error(
582
677
  '\nFix the markup (or the component API) so it stays copy-safe for agents.'
583
678
  );
679
+ printFindingLegend(findings);
584
680
  printHints();
585
681
  process.exit(1);
586
682
  }
@@ -600,7 +696,8 @@ Commands:
600
696
  server for Claude Code (.mcp.json), Cursor (.cursor/mcp.json),
601
697
  VS Code/Copilot (.vscode/mcp.json), and Windsurf (~/.codeium
602
698
  global) — merges, never overwrites other servers.
603
- check [glob…] [--json] [--allow-empty]
699
+ check [glob…] [--json] [--allow-empty] [--allow-component <Name>]
700
+ [--no-hints]
604
701
  Validate \`Bb*\` markup in .vue/.md files against the
605
702
  installed components.json manifest (unknown/removed props,
606
703
  bad v-models, unknown \`<template #slot>\` names,
@@ -612,7 +709,27 @@ Commands:
612
709
  Exits 1 on findings, and on an explicit glob that matched
613
710
  nothing (a typo'd CI path validates zero files silently) —
614
711
  pass \`--allow-empty\` when an empty match is expected.
615
- \`--json\` prints \`{ findings: [...], files }\`.
712
+
713
+ \`--allow-component <Name>\` (repeatable) exempts a
714
+ component your APP owns whose name starts with \`Bb\` —
715
+ the prefix is a convention, not proof of provenance.
716
+ Persist the list instead of repeating the flag:
717
+ package.json { "bitboss-ui": { "allowComponents": ["BbRichEditor"] } }
718
+ or \`bitboss-ui.check.json\` \`{ "allowComponents": [...] }\`.
719
+ Same option name as the ESLint rules' \`allowComponents\`,
720
+ so both gates configure alike.
721
+
722
+ \`--json\` prints \`{ findings: [...], hints: [...], files }\`.
723
+ Each finding: \`{ file, line, component, attr, kind,
724
+ message, hint?, to? }\` (plus \`fenceIndex\`/\`fenceInfo\`
725
+ inside a markdown fence; \`line\` is absolute in the file).
726
+ \`kind\` is one of: \`removed-prop\` (a v2→v3 break — fix
727
+ it), \`unknown-prop\` (not a v3 prop of that component;
728
+ may never have been one — see the legend the text output
729
+ prints), \`unknown-model\`, \`unknown-slot\`,
730
+ \`no-default-slot\`, \`inert-nav-attr\`,
731
+ \`missing-partner-prop\`, \`partner-prop\`,
732
+ \`validated-only-prop\`.
616
733
  mcp Start a stdio MCP server exposing the dist/ai knowledge
617
734
  base (search_components, get_component, list_recipes,
618
735
  get_recipe, validate) to MCP-capable agent harnesses.
@@ -658,14 +775,18 @@ switch (command) {
658
775
  {
659
776
  json: { type: 'boolean' },
660
777
  'allow-empty': { type: 'boolean' },
778
+ 'allow-component': { type: 'string', multiple: true },
779
+ // Accepted and ignored here — read straight off argv inside
780
+ // checkCommand, but parseArgs is strict, so it must be declared.
781
+ 'no-hints': { type: 'boolean' },
661
782
  },
662
783
  { allowPositionals: true }
663
784
  );
664
- checkCommand(
665
- positionals,
666
- values.json ?? false,
667
- values['allow-empty'] ?? false
668
- );
785
+ checkCommand(positionals, {
786
+ json: values.json ?? false,
787
+ allowEmpty: values['allow-empty'] ?? false,
788
+ allowComponents: values['allow-component'] ?? [],
789
+ });
669
790
  break;
670
791
  }
671
792
  case 'mcp': {
@@ -309,9 +309,12 @@ state in the handler. Prefer `secondary` / `outline` for filter chips; reserve
309
309
  ```
310
310
 
311
311
  The clear button inherits the variant's foreground, so it reads on every surface
312
- — light on a filled `primary`, dark on a `secondary`/`outline`. Set
313
- `clearable-label` for the button's accessible name (defaults to the localized
314
- `badge.clearLabel`).
312
+ — light on a filled `primary`, dark on a `secondary`/`outline`. By default its
313
+ accessible name composes the localized verb with the badge's own text a chip
314
+ reading "Italy" announces "Remove Italy", with no per-chip wiring. Set
315
+ `clearable-label` only when that composition is wrong for the context (it
316
+ replaces the whole name). With a `BbBadgeButton` body the composition is
317
+ skipped and the button falls back to the bare localized `badge.clearLabel`.
315
318
 
316
319
  Icons combine with `clearable`: a **`prepend:icon`** stays (it leads the label);
317
320
  an **`append:icon`** shares the trailing slot with the clear button — the icon
@@ -695,8 +698,10 @@ selectors like `.bb-badge > .bb-badge__content`, which no longer match.
695
698
  - An icon-only badge (`icon`) has no visible text; the default slot is rendered
696
699
  as a screen-reader-only label — never leave it empty. In button mode that
697
700
  label is also the **button's accessible name**, so it is doubly required.
698
- - The `clearable` button has an accessible name from `clearable-label` (or the
699
- localized `badge.clearLabel`).
701
+ - The `clearable` button's accessible name is composed by default: the
702
+ localized `badge.clearLabel` verb plus the badge body's text ("Remove
703
+ Italy"). `clearable-label` replaces the whole name; with a `BbBadgeButton`
704
+ body the composition is skipped (bare verb only).
700
705
  - A clickable **and** clearable badge is two tab stops (body, then clear). That
701
706
  is intended: two actions, two controls.
702
707
  - Keyboard focus on either control rings the whole pill, so the focused target
@@ -1212,6 +1212,14 @@ Shipped behavior — never reimplement it:
1212
1212
  library default) — `direction="horizontal"` gives a label-beside-field row.
1213
1213
  Only `floating`/`inside` label modes force the vertical layout, since they
1214
1214
  embed the label in the field itself.
1215
+ - **A long `placeholder` or a long selected label never widens the control's
1216
+ track.** The trigger is a button, not an `<input>`, so the placeholder is
1217
+ real text rather than a paint-only `::placeholder` — but the field's minimum
1218
+ size is capped so that text cannot become the floor of a grid or flex track.
1219
+ Put a select with a paragraph-length placeholder in
1220
+ `grid-template-columns: repeat(3, 1fr)` and you still get three equal
1221
+ columns, with the text ellipsised inside its field. You do **not** need
1222
+ `min-w-0` on the item or `minmax(0, 1fr)` on the track to get this.
1215
1223
 
1216
1224
  ### Adaptive mobile sheet
1217
1225