bitboss-ui 3.0.0-beta.30 → 3.0.0-beta.31

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 (114) hide show
  1. package/README.md +29 -29
  2. package/bin/bitboss-ui-mcp.mjs +2 -1
  3. package/bin/bitboss-ui.mjs +50 -29
  4. package/dist/ai/BbBadge.md +8 -3
  5. package/dist/ai/BbBreadcrumbs.md +4 -1
  6. package/dist/ai/BbCalendar.md +73 -0
  7. package/dist/ai/BbColorInput.md +3 -3
  8. package/dist/ai/BbColorPalette.md +10 -9
  9. package/dist/ai/BbDatePicker.md +50 -11
  10. package/dist/ai/BbDatePickerInput.md +11 -3
  11. package/dist/ai/BbDialog.md +3 -3
  12. package/dist/ai/BbDropdown.md +249 -33
  13. package/dist/ai/BbDropdownButton.md +18 -7
  14. package/dist/ai/BbIcon.md +1 -1
  15. package/dist/ai/BbOffCanvas.md +2 -2
  16. package/dist/ai/BbPopover.md +9 -21
  17. package/dist/ai/BbSelect.md +3 -3
  18. package/dist/ai/BbSelectPopover.md +7 -15
  19. package/dist/ai/BbTable.md +4 -0
  20. package/dist/ai/BbTabs.md +18 -13
  21. package/dist/ai/BbTabsList.md +2 -1
  22. package/dist/ai/BbTabsPanes.md +1 -1
  23. package/dist/ai/BbTimePicker.md +9 -8
  24. package/dist/ai/BbTimePickerInput.md +4 -3
  25. package/dist/ai/BbTree.md +11 -1
  26. package/dist/ai/changelog.json +32 -3
  27. package/dist/ai/components.json +519 -89
  28. package/dist/ai/guides/ai-router.md +3 -5
  29. package/dist/ai/guides/component-picker.md +26 -25
  30. package/dist/ai/guides/design-language.md +1 -1
  31. package/dist/ai/guides/design-tokens.md +8 -8
  32. package/dist/ai/guides/icons-policy.md +5 -4
  33. package/dist/ai/guides/installation-and-plugin-setup.md +4 -4
  34. package/dist/ai/guides/migration/components/bb-dropdown.md +11 -10
  35. package/dist/ai/guides/migration/v2-to-v3.md +25 -25
  36. package/dist/ai/guides/passthrough.md +33 -10
  37. package/dist/ai/source/BbBadge.md +4 -2
  38. package/dist/ai/source/BbBadgeButton.md +43 -3
  39. package/dist/ai/source/BbBreadcrumbs.md +5 -0
  40. package/dist/ai/source/BbCalendar.md +4 -0
  41. package/dist/ai/source/BbColorInput.md +2 -2
  42. package/dist/ai/source/BbColorPalette.md +24 -15
  43. package/dist/ai/source/BbDatePicker.md +43 -21
  44. package/dist/ai/source/BbDatePickerInput.md +5 -2
  45. package/dist/ai/source/BbDialog.md +3 -3
  46. package/dist/ai/source/BbDropdown.md +92 -13
  47. package/dist/ai/source/BbDropdownButton.md +27 -7
  48. package/dist/ai/source/BbDropdownGroup.md +76 -10
  49. package/dist/ai/source/BbForm.md +2 -2
  50. package/dist/ai/source/BbOffCanvas.md +3 -3
  51. package/dist/ai/source/BbPopover.md +12 -13
  52. package/dist/ai/source/BbRating.md +2 -2
  53. package/dist/ai/source/BbSelect.md +2 -2
  54. package/dist/ai/source/BbSelectPopover.md +18 -15
  55. package/dist/ai/source/BbTable.md +37 -10
  56. package/dist/ai/source/BbTabs.md +13 -3
  57. package/dist/ai/source/BbTabsList.md +12 -2
  58. package/dist/ai/source/BbTabsPanes.md +12 -2
  59. package/dist/ai/source/BbTabsRoot.md +12 -2
  60. package/dist/ai/source/BbTimePicker.md +12 -9
  61. package/dist/ai/source/BbTimePickerInput.md +9 -7
  62. package/dist/ai/source/BbTree.md +6 -0
  63. package/dist/ai/source/CommonPopover.md +1 -4
  64. package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +1 -1
  65. package/dist/components/BbBadge/BbBadgeButton.vue_vue_type_script_setup_true_lang.js +24 -8
  66. package/dist/components/BbBadge/types.d.ts +3 -1
  67. package/dist/components/BbBreadcrumbs/types.d.ts +5 -0
  68. package/dist/components/BbCalendar/types.d.ts +4 -0
  69. package/dist/components/BbColorInput/types.d.ts +2 -2
  70. package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +101 -101
  71. package/dist/components/BbColorPalette/types.d.ts +11 -8
  72. package/dist/components/BbDatePicker/BbDatePicker.vue_vue_type_script_setup_true_lang.js +6 -3
  73. package/dist/components/BbDatePicker/types.d.ts +10 -7
  74. package/dist/components/BbDatePickerInput/types.d.ts +5 -2
  75. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +79 -74
  76. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +57 -58
  77. package/dist/components/BbDropdown/BbDropdownList.vue.d.ts +6 -0
  78. package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +283 -262
  79. package/dist/components/BbDropdown/normalizeGroups.js +1 -0
  80. package/dist/components/BbDropdown/types.d.ts +75 -10
  81. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +34 -35
  82. package/dist/components/BbDropdownButton/types.d.ts +12 -3
  83. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +169 -169
  84. package/dist/components/BbPopover/types.d.ts +6 -7
  85. package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +84 -85
  86. package/dist/components/BbSelect/types.d.ts +2 -2
  87. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +262 -261
  88. package/dist/components/BbSelectPopover/types.d.ts +6 -6
  89. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +800 -795
  90. package/dist/components/BbTable/types.d.ts +6 -0
  91. package/dist/components/BbTable/utils.d.ts +1 -1
  92. package/dist/components/BbTable/utils.js +3 -3
  93. package/dist/components/BbTabs/types.d.ts +12 -2
  94. package/dist/components/BbTimePicker/BbTimePicker.vue_vue_type_script_setup_true_lang.js +116 -113
  95. package/dist/components/BbTimePicker/types.d.ts +6 -5
  96. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +219 -216
  97. package/dist/components/BbTimePickerInput/types.d.ts +2 -2
  98. package/dist/components/BbTree/types.d.ts +6 -0
  99. package/dist/components/CommonPopover/CommonPopover.vue_vue_type_script_setup_true_lang.js +23 -22
  100. package/dist/index.d.ts +1 -1
  101. package/dist/llms-full.txt +616 -234
  102. package/dist/llms-medium.txt +34 -35
  103. package/dist/llms.txt +1 -1
  104. package/dist/styles.css +1 -1
  105. package/dist/types/BadgeVariant.d.ts +6 -4
  106. package/dist/utils/passthrough.d.ts +7 -0
  107. package/dist/utils/passthrough.js +21 -17
  108. package/dist/validated/BbForm.vue_vue_type_script_setup_true_lang.js +2 -3
  109. package/dist/vite-plugin.d.ts +3 -4
  110. package/dist/vite.js +3 -3
  111. package/llms.txt +1 -1
  112. package/package.json +1 -1
  113. package/scripts/lib/mcp-config.mjs +49 -24
  114. package/scripts/lib/validate-bb-markup.mjs +6 -1
package/README.md CHANGED
@@ -244,7 +244,8 @@ npx bitboss-ui ai-init
244
244
  # same as: npx bitboss-ui ai-init --update
245
245
  ```
246
246
 
247
- Idempotently writes:
247
+ Idempotently writes the pointer files below **and** sets up the MCP server
248
+ (next section); `--no-mcp` skips the server:
248
249
 
249
250
  | File | Harness |
250
251
  | --------------------------------------- | ------------------------ |
@@ -256,49 +257,48 @@ Idempotently writes:
256
257
 
257
258
  Re-run after upgrading `bitboss-ui` so versioned pointers stay fresh.
258
259
 
259
- ### MCP server (optional)
260
+ ### MCP server
260
261
 
261
- The kickstart above writes static pointer files. Add `--mcp` to also register a
262
- live [Model Context Protocol](https://modelcontextprotocol.io) server so agents
263
- can **query** the knowledge base (search components, read a contract, validate
264
- markup) instead of reading files blind:
262
+ Besides the static pointer files, `ai-init` registers a live
263
+ [Model Context Protocol](https://modelcontextprotocol.io) server so agents can
264
+ **query** the knowledge base (search components, read a contract, validate
265
+ markup) instead of reading files blind. It is on by default; opt out with:
265
266
 
266
267
  ```bash
267
- npm i -D @modelcontextprotocol/sdk zod
268
- npx bitboss-ui ai-init --mcp
268
+ npx bitboss-ui ai-init --no-mcp
269
269
  ```
270
270
 
271
- Those two are **optional peer dependencies**, not dependencies: together they
272
- weigh ~12 MB — more than every runtime dependency of the component library
273
- combined — and nothing but the MCP server loads them, so installing
274
- `bitboss-ui` never drags them in. `ai-init --mcp` warns if they are missing,
275
- and `bitboss-ui mcp` tells you what to install rather than dying on a module
276
- resolution error.
271
+ The server needs `@modelcontextprotocol/sdk` and `zod`. They are **optional
272
+ peer dependencies**, not dependencies: together they weigh ~12 MB — more than
273
+ every runtime dependency of the component library combined — and nothing but
274
+ the MCP server loads them, so installing `bitboss-ui` never drags them in.
275
+ `ai-init` installs them as dev dependencies with your package manager (npm,
276
+ pnpm, yarn or bun, from your lockfile); if that fails it prints the command to
277
+ run, and `bitboss-ui mcp` tells you what to install rather than dying on a
278
+ module resolution error. `--no-mcp` skips the install too.
277
279
 
278
280
  The agent harness launches the server itself (`node node_modules/bitboss-ui/bin/bitboss-ui.mjs mcp`,
279
281
  the installed binary rather than `npx`, so it can never fetch from the registry, its optional
280
282
  peers resolve in your project, and it cannot drift behind an upgrade) on demand —
281
- you never run it by hand. `--mcp` merges the server entry into each harness's
283
+ you never run it by hand. `ai-init` merges the server entry into each harness's
282
284
  own config (never overwriting other servers you've registered), and each write
283
285
  is idempotent:
284
286
 
285
- | File | Harness | Scope |
286
- | ------------------------------------- | ----------------- | -------------------------- |
287
- | `.mcp.json` | Claude Code | project |
288
- | `.cursor/mcp.json` | Cursor | project |
289
- | `.vscode/mcp.json` | VS Code / Copilot | project |
290
- | `~/.codeium/windsurf/mcp_config.json` | Windsurf | **global (whole machine)** |
287
+ | File | Harness |
288
+ | ------------------ | ----------------- |
289
+ | `.mcp.json` | Claude Code |
290
+ | `.cursor/mcp.json` | Cursor |
291
+ | `.vscode/mcp.json` | VS Code / Copilot |
291
292
 
292
- > **Windsurf is global.** Cascade only reads one config in your home directory —
293
- > it has no per-project scope — so registering it affects **every** project on
294
- > your machine, not just this one. That is why the dev-server auto-registration
295
- > below deliberately skips Windsurf; only the explicit `ai-init --mcp` command
296
- > writes it.
293
+ Windsurf only reads a global config in your home directory, so the server is
294
+ not registered for it — add the same entry to
295
+ `~/.codeium/windsurf/mcp_config.json` yourself if you use it. Its
296
+ `.windsurf/rules` pointer is written as above.
297
297
 
298
- **Zero-command option (dev server):** instead of running `ai-init --mcp`, pass
298
+ **Zero-command option (dev server):** instead of running `ai-init`, pass
299
299
  `mcp: true` to the Vite/Nuxt plugin and the dev server registers the
300
- project-scoped harnesses (Claude Code, Cursor, VS Code) automatically on boot —
301
- idempotent, and it leaves Windsurf's global config alone:
300
+ same harnesses automatically on boot — idempotent, and it never installs
301
+ anything (run `ai-init` once for the peers):
302
302
 
303
303
  ```ts
304
304
  bitbossUi({ iconDir: './assets/icons', mcp: true });
@@ -25,7 +25,8 @@
25
25
  * is stable across zod 3 and 4, so the lower bound costs nothing.
26
26
  *
27
27
  * Run standalone: `npx bitboss-ui mcp` (delegated from bin/bitboss-ui.mjs).
28
- * Register with an MCP-capable harness via `npx bitboss-ui ai-init --mcp`.
28
+ * Registered with every MCP-capable harness by `npx bitboss-ui ai-init`
29
+ * (on by default; `--no-mcp` skips it).
29
30
  */
30
31
 
31
32
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
@@ -11,8 +11,10 @@
11
11
  * - .github/copilot-instructions.md fragment (GitHub Copilot)
12
12
  * - .claude/skills/bitboss-ui/SKILL.md (Claude Code)
13
13
  * - .windsurf/rules/bitboss-ui.md (Windsurf)
14
- * Accepts an optional --mcp flag (combinable with --update) to also
15
- * register the `bitboss-ui mcp` server in .mcp.json.
14
+ * Also registers the `bitboss-ui mcp` server for Claude Code,
15
+ * Cursor and VS Code and installs its optional peers
16
+ * (`@modelcontextprotocol/sdk`, `zod`) with the project's package
17
+ * manager; pass --no-mcp to skip both.
16
18
  * check Validate Bb* markup in .vue/.md files against the installed
17
19
  * components.json manifest (unknown props, removed props, bad
18
20
  * v-models, unknown `<template #slot>` names, `href`/`to`/
@@ -43,6 +45,7 @@
43
45
  * Plain ESM JavaScript on purpose: shipped as-is in the package, no build.
44
46
  */
45
47
 
48
+ import { spawnSync } from 'node:child_process';
46
49
  import {
47
50
  existsSync,
48
51
  globSync,
@@ -60,6 +63,8 @@ import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
60
63
  import { fileURLToPath } from 'node:url';
61
64
  import { parseArgs } from 'node:util';
62
65
  import {
66
+ detectPackageManager,
67
+ devInstallCommand,
63
68
  ensureMcpConfigs,
64
69
  missingMcpPeers,
65
70
  MCP_BIN_PATH,
@@ -209,7 +214,7 @@ function tryWrite(label, fn) {
209
214
  }
210
215
  }
211
216
 
212
- function aiInit({ mcp = false } = {}) {
217
+ function aiInit({ mcp = true } = {}) {
213
218
  const projectRoot = process.cwd();
214
219
  const version = packageVersion();
215
220
 
@@ -258,11 +263,7 @@ function aiInit({ mcp = false } = {}) {
258
263
  ];
259
264
 
260
265
  if (mcp) {
261
- // Explicit command → register every harness, including Windsurf's global
262
- // (home-dir) config.
263
- for (const result of ensureMcpConfigs(projectRoot, {
264
- includeWindsurf: true,
265
- })) {
266
+ for (const result of ensureMcpConfigs(projectRoot)) {
266
267
  const suffix = result.reason ? ` (${result.reason})` : '';
267
268
  results.push({
268
269
  path: `${result.path} [${result.label}]${suffix}`,
@@ -271,18 +272,34 @@ function aiInit({ mcp = false } = {}) {
271
272
  }
272
273
 
273
274
  // The harness launches the server on demand, long after this command
274
- // ran — so a missing peer would surface inside an agent as a server
275
- // that never starts. Say it here, where the person is still watching.
275
+ // ran — a missing peer would surface inside an agent as a server that
276
+ // never starts. They are optional peers (~12 MB only the server loads),
277
+ // so installing the library never adds them; registering the server is
278
+ // the moment the project opts in, so install them here.
276
279
  const missing = missingMcpPeers(projectRoot);
277
280
  if (missing.length > 0) {
278
- console.warn(
279
- `[bitboss-ui] the MCP server needs ${missing.join(' and ')}, which ${
280
- missing.length > 1 ? 'are' : 'is'
281
- } not installed:\n` +
282
- `\n npm i -D ${missing.join(' ')}\n\n` +
283
- ' Optional peers, not dependencies — ~12 MB that only the MCP\n' +
284
- ' server uses. The harness entries above are written either way.'
281
+ const [cmd, ...args] = devInstallCommand(
282
+ detectPackageManager(projectRoot),
283
+ missing
285
284
  );
285
+ const printed = [cmd, ...args].join(' ');
286
+ console.log(`[bitboss-ui] installing the MCP server's peers: ${printed}`);
287
+ const installed = spawnSync(cmd, args, {
288
+ cwd: projectRoot,
289
+ stdio: 'inherit',
290
+ // npm/pnpm/yarn are .cmd shims on Windows, which only a shell runs.
291
+ shell: process.platform === 'win32',
292
+ });
293
+ if (installed.status === 0) {
294
+ results.push({ path: missing.join(', '), action: 'installed' });
295
+ } else {
296
+ console.warn(
297
+ `[bitboss-ui] could not install ${missing.join(' and ')} — run it yourself:\n` +
298
+ `\n ${printed}\n\n` +
299
+ ' The harness entries are written either way; the server starts\n' +
300
+ ' once the peers are installed.'
301
+ );
302
+ }
286
303
  }
287
304
  }
288
305
 
@@ -295,11 +312,11 @@ function aiInit({ mcp = false } = {}) {
295
312
  );
296
313
  if (mcp) {
297
314
  console.log(
298
- 'MCP: registered the bitboss-ui server for Claude Code (.mcp.json), Cursor (.cursor/mcp.json), VS Code/Copilot (.vscode/mcp.json), and Windsurf (~/.codeium global) — restart your harness to pick it up.'
315
+ 'MCP: registered the bitboss-ui server for Claude Code (.mcp.json), Cursor (.cursor/mcp.json) and VS Code/Copilot (.vscode/mcp.json) — restart your harness to pick it up. `--no-mcp` skips this.'
299
316
  );
300
317
  } else {
301
318
  console.log(
302
- 'Tip: `npx bitboss-ui ai-init --mcp` also registers the MCP server across Claude Code / Cursor / VS Code / Windsurf so agents can query the knowledge base instead of reading files.'
319
+ 'MCP: skipped (--no-mcp). Re-run without it to let agents query the knowledge base through the bitboss-ui MCP server instead of reading files.'
303
320
  );
304
321
  }
305
322
  console.log('Re-run after upgrading bitboss-ui to refresh the pointers.');
@@ -904,14 +921,16 @@ Usage:
904
921
  npx bitboss-ui <command>
905
922
 
906
923
  Commands:
907
- ai-init [--update] [--mcp]
924
+ ai-init [--update] [--no-mcp]
908
925
  Inject AI-agent knowledge-base pointers into the current
909
926
  project (AGENTS.md, Cursor rules, Copilot instructions,
910
- Claude skill, Windsurf rules). Idempotent — safe to re-run
911
- after upgrades. \`--mcp\` also registers the bitboss-ui MCP
912
- server for Claude Code (.mcp.json), Cursor (.cursor/mcp.json),
913
- VS Code/Copilot (.vscode/mcp.json), and Windsurf (~/.codeium
914
- global) — merges, never overwrites other servers.
927
+ Claude skill, Windsurf rules), register the bitboss-ui MCP
928
+ server for Claude Code (.mcp.json), Cursor
929
+ (.cursor/mcp.json) and VS Code/Copilot (.vscode/mcp.json) —
930
+ merges, never overwrites other servers — and install its
931
+ optional peers with the project's package manager.
932
+ \`--no-mcp\` skips the server and the install. Idempotent —
933
+ safe to re-run after upgrades.
915
934
  check [glob…] [--json] [--allow-empty] [--allow-component <Name>]
916
935
  [--no-hints] [--manifest <path>]
917
936
  Validate \`Bb*\` markup in .vue/.md files against the
@@ -1000,9 +1019,11 @@ switch (command) {
1000
1019
  case 'ai-init': {
1001
1020
  const { values } = parseCommandArgs(command, commandArgs, {
1002
1021
  update: { type: 'boolean' },
1003
- mcp: { type: 'boolean' },
1022
+ // The MCP server is registered by default: people ran ai-init, got
1023
+ // the pointers, and never learned the server existed.
1024
+ 'no-mcp': { type: 'boolean' },
1004
1025
  });
1005
- aiInit({ mcp: values.mcp ?? false });
1026
+ aiInit({ mcp: !values['no-mcp'] });
1006
1027
  break;
1007
1028
  }
1008
1029
  case 'check': {
@@ -1059,7 +1080,7 @@ switch (command) {
1059
1080
  // from, so a cached copy can never see the project's node_modules no
1060
1081
  // matter what is installed there. Telling that user to install peers
1061
1082
  // they already have is what sent a consumer down a dead end
1062
- // (2026-09-09). `ai-init --mcp` now writes the local binary instead
1083
+ // (2026-09-09). `ai-init` now writes the local binary instead
1063
1084
  // of `npx`, so the fix is to rewrite the config.
1064
1085
  const fromNpxCache = /[/\\]_npx[/\\]/.test(
1065
1086
  fileURLToPath(import.meta.url)
@@ -1071,7 +1092,7 @@ switch (command) {
1071
1092
  'its optional peers resolve there, not in your project, so the server cannot start\n' +
1072
1093
  `even though this project has them installed (${MCP_PEERS.join(', ')}).\n\n` +
1073
1094
  'Fix the harness config to invoke the installed binary:\n\n' +
1074
- ' npx bitboss-ui ai-init --mcp\n\n' +
1095
+ ' npx bitboss-ui ai-init\n\n' +
1075
1096
  `which writes \`node ${MCP_BIN_PATH} mcp\`. To run it right now:\n\n` +
1076
1097
  ` node ${MCP_BIN_PATH} mcp\n\n` +
1077
1098
  `Resolution failed with: ${error.message}`
@@ -73,6 +73,11 @@ the soft palette from
73
73
  `.bb-badge--<name>` in your project stylesheet. Never invent `variant="success"`
74
74
  — that name is not built-in and ships no CSS.
75
75
 
76
+ `variant="none"` renders the badge with no variant class at all — the base
77
+ tokens stay until you set `--bg` / `--fg` on it. It is the same escape hatch
78
+ `BbButton` has; prefer a registered variant or a one-off `--bg` / `--fg`
79
+ override on a normal variant.
80
+
76
81
  **Invoice status pills + plan tiers**
77
82
 
78
83
  ```vue
@@ -559,7 +564,7 @@ anchor an overlay directly — no wrapper element, no `defineExpose`:
559
564
  variant="secondary"
560
565
  @click:clear="status = 'Open'"
561
566
  >
562
- <BbBadgeButton ref="statusChip">Status: {{ status }}</BbBadgeButton>
567
+ <BbBadgeButton ref="status-chip">Status: {{ status }}</BbBadgeButton>
563
568
  </BbBadge>
564
569
 
565
570
  <!-- The ref resolves to the rendered button element, so it anchors the
@@ -588,7 +593,7 @@ type Status = (typeof options)[number];
588
593
 
589
594
  const status = ref<Status>('Open');
590
595
  const open = ref(false);
591
- const statusChip = useTemplateRef('statusChip');
596
+ const statusChip = useTemplateRef('status-chip');
592
597
 
593
598
  const onPick = (option: Status) => {
594
599
  status.value = option;
@@ -847,7 +852,7 @@ The full grammar, the merge rules and the global map are in the
847
852
  | `loading` | `boolean \| undefined` | `false` | | Shows a spinner in place of the leftmost icon, mirroring `BbButton`: it replaces the `icon` glyph or the `prepend:icon` when one is set; when the `append:icon` is the sole icon it replaces that instead (e.g. a select-activator chevron while… |
848
853
  | `prepend:icon` | `string \| undefined` | | | Icon rendered before the label. |
849
854
  | `size` | `keyof Sizes \| undefined` | `"md"` | | Preset size of the badge. |
850
- | `variant` | `keyof BadgeVariantRegistry \| undefined` | `"primary"` | | Visual variant: `primary`, `secondary`, `destructive`, or `outline`. Register more via the vite plugin `badgeVariants` option and style `.bb-badge--<variant>` (set `--bg` / `--fg`). |
855
+ | `variant` | `BadgeVariantType \| undefined` | `"primary"` | | Visual variant: `primary`, `secondary`, `destructive`, or `outline`. Register more via the vite plugin `badgeVariants` option and style `.bb-badge--<variant>` (set `--bg` / `--fg`). `'none'` renders no variant class — an escape hatch for a … |
851
856
 
852
857
  ## Passthrough parts and states
853
858
 
@@ -707,6 +707,9 @@ States are listed in precedence order: when two are on at once and their entries
707
707
  - `item:append` — scope: `BbBreadcrumbsItemSlotProps` — Content rendered after **every** breadcrumb item's link/button. Generic fallback below a per-item `<key>:append` slot and above the item's `append:icon`.
708
708
  - `item:prepend` — scope: `BbBreadcrumbsItemSlotProps` — Content rendered before **every** breadcrumb item's link/button, in the leading edge region. Generic fallback: a per-item `<key>:prepend` slot takes precedence, and the item's `prepend:icon` is used when neither slot is present.
709
709
  - `prepend` — scope: `BbBreadcrumbsEdgeSlotProps` — Content rendered before the breadcrumb list, in a dedicated prepend region.
710
+ - `#<key>` (named from data) — scope: `BbBreadcrumbsItemSlotProps` — One crumb's label, by its `key` through `slotKey`; falls back to `item.text`. A crumb folded into the overflow menu follows BbDropdown's slot rules instead.
711
+ - `#<key>:prepend` (named from data) — scope: `BbBreadcrumbsItemSlotProps` — The glyph before one crumb's label; beats `item:prepend`, which beats its `prepend:icon`.
712
+ - `#<key>:append` (named from data) — scope: `BbBreadcrumbsItemSlotProps` — The glyph after one crumb's label; beats `item:append`, which beats its `append:icon`.
710
713
 
711
714
  ## Component tree
712
715
 
@@ -722,7 +725,7 @@ States are listed in precedence order: when two are on at once and their entries
722
725
  - `BbDropdown` _(public — [contract](./BbDropdown.md))_ — its own pt parts (`BbDropdown`): `panel` → `CommonPopover`, `root` → `CommonPopover`, `header` → `div.bb-dropdown__header`, `list` → `span.bb-dropdown__items-container`, `footer` → `div.bb-dropdown__footer`; documented CSS variables: `--menu-inset`; also mounts `CommonPopover`, `DropdownPipelineResolver`
723
726
  - `BbDropdownList` _(internal — not importable, reach it through `BbDropdown`)_ — also mounts `BbBaseButton`, `BbIcon`, `CommonPopover`, `BbDropdownList`
724
727
  - `BbBadge` _(public — [contract](./BbBadge.md))_ — its own pt parts (`BbBadge`): `spinner` → `BbSpinner`, `icon` → `BbIcon`, `clear` → `button.bb-badge__clear-button`; documented CSS variables: `--bg`, `--fg`, `--border-width`, `--ring`, `--min-size-md`, `--min-size`, `--elev`, `--r`, `--font-size`, `--icon-size`, `--gap`, `--padding-inline`, `--clear-size`, `--pad-left`; also mounts `BbIcon`, `BbSpinner`, `BadgeBodyContent`
725
- - `AdaptiveDropdown` _(internal — not importable, reach it through `BbDropdown`)_ — hands `BbOffCanvas` the pt map `{ header: 'header', footer: 'footer', sheet: 'root' }` (ours → theirs); also mounts `BbSmoothHeight`, `BbDropdownList`
728
+ - `AdaptiveDropdown` _(internal — not importable, reach it through `BbDropdown`)_ — hands `BbOffCanvas` the pt map `{ header: 'header', footer: 'footer', panel: 'root', sheet: 'root' }` (ours → theirs); also mounts `BbSmoothHeight`, `BbDropdownList`
726
729
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__body`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--handle-w`, `--handle-h`, `--handle-bg`, `--close-size`
727
730
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
728
731
  - `BbButton` _(public — [contract](./BbButton.md))_ — its own pt parts (`BbButton`): `root` → `BbBaseButton`, `spinner` → `BbSpinner`, `icon` → `BbIcon`, `text` → `span.bb-button__content`; documented CSS variables: `--h-xs`, `--h`, `--icon-size`, `--px`, `--fs`, `--r`, `--gap`, `--bg`, `--bg-hover`, `--bg-pressed`, `--fg`, `--border-color`, `--ring`, `--bw`, `--fg-hover`, `--border-hover`, `--fg-pressed`, `--border-pressed`, `--bg-disabled`, `--fg-disabled`, `--border-disabled`, `--opacity-disabled`, `--elev-tier`, `--elev`; also mounts `BbIcon`, `BbBaseButton`, `BbSpinner`
@@ -376,6 +376,77 @@ const summary = computed(() => {
376
376
  </script>
377
377
  ```
378
378
 
379
+ ### Decorating days
380
+
381
+ Four slots decorate the day grid. Each receives the day's state: `label` (the
382
+ day number), `selected`, `outside` (a day of the previous or next month),
383
+ `first` / `middle` / `last` (range edges) and `item` (the day as a dayjs
384
+ object).
385
+
386
+ | Slot | Renders |
387
+ | ---------------------- | ------------------------------------------- |
388
+ | `#day` | every day's label, **replacing** the number |
389
+ | `#append:day` | under every day (dots, prices, badges) |
390
+ | `#<YYYY_MM_DD>` | one date's label, e.g. `#2026_12_25` |
391
+ | `#append:<YYYY_MM_DD>` | under one date, e.g. `#append:2026_12_25` |
392
+
393
+ A date's slot name is its local `YYYY-MM-DD` with `_` for `-`, and it wins over
394
+ the matching every-day slot for that date. Per-date slots suit a few fixed
395
+ dates (holidays, a launch day); for data-driven marks — events from an API —
396
+ use `#append:day` and look the day up from `item`. The per-date slots cover the
397
+ day grid only, not the month and year panels. Keep decorations small: they
398
+ render in every visible cell.
399
+
400
+ **Holiday hours on specific dates**
401
+
402
+ ```vue
403
+ <template>
404
+ <div class="grid w-fit gap-3 rounded-(--bb-radius) border p-4">
405
+ <div>
406
+ <p class="m-0 text-sm font-medium">Pickup day</p>
407
+ <p class="m-0 text-xs text-(--bb-text-muted)">
408
+ The shop keeps holiday hours over Christmas.
409
+ </p>
410
+ </div>
411
+ <BbCalendar
412
+ v-model="pickup"
413
+ aria-label="Pickup day"
414
+ floating
415
+ :selectable="isOpen"
416
+ >
417
+ <!-- One slot per date: its `YYYY-MM-DD` with `_` for `-`. -->
418
+ <template #append:2026_12_24>
419
+ <span class="holiday-note">Half day</span>
420
+ </template>
421
+ <template #append:2026_12_25>
422
+ <span class="holiday-note">Closed</span>
423
+ </template>
424
+ <template #append:2026_12_26>
425
+ <span class="holiday-note">Closed</span>
426
+ </template>
427
+ </BbCalendar>
428
+ </div>
429
+ </template>
430
+
431
+ <script setup lang="ts">
432
+ import { ref } from 'vue';
433
+ import { BbCalendar } from 'bitboss-ui';
434
+
435
+ const pickup = ref<string | null>('2026-12-22');
436
+
437
+ const closed = new Set(['2026-12-25', '2026-12-26']);
438
+ const isOpen = (date: string) => !closed.has(date);
439
+ </script>
440
+
441
+ <style scoped>
442
+ .holiday-note {
443
+ color: var(--bb-text-muted);
444
+ font-size: 0.625rem;
445
+ line-height: 1;
446
+ }
447
+ </style>
448
+ ```
449
+
379
450
  ### Keyboard and accessibility
380
451
 
381
452
  The calendar is an ordinary control in the tab order: **one tab stop** lands
@@ -513,6 +584,8 @@ States are listed in precedence order: when two are on at once and their entries
513
584
 
514
585
  - `append:day` — scope: `BbCalendarDaySlotProps` — Appends content below each calendar day.
515
586
  - `day` — scope: `BbCalendarDaySlotProps` — Replaces the day button label inside each calendar day.
587
+ - `#<YYYY_MM_DD>` (named from data) — scope: `BbCalendarDaySlotProps` — One date's button label (e.g. `#2024_03_15`: the local `YYYY-MM-DD` through `slotKey`); beats `day`. Day grid only.
588
+ - `#append:<YYYY_MM_DD>` (named from data) — scope: `BbCalendarDaySlotProps` — Content under one date's cell; beats `append:day`.
516
589
 
517
590
  ## CSS custom properties
518
591
 
@@ -505,7 +505,7 @@ the `BbTextInput` guide.
505
505
 
506
506
  `pt` reaches a named part of the control with a class list — or, in the
507
507
  object form, a style and attributes — optionally only while a state is on.
508
- Parts: `root` (the container), `label`, `description`, `message` (the errors / warnings region — one node each, only one ever shows), `hint` (the helper line — shown on focus, or always with `persistent-hint`), `box` (the bordered field box), `input` (the native control), `icon` (`prepend:icon` + `append:icon` — a broadcast; the state glyphs are chrome), `spinner` (the spinner shown while `loading`), `prefix`, `suffix`, `clear` (the ✕ that empties the field). Plus `indicator` (the colour dot that opens the palette), `panel` (the palette box — the popover's painted bubble on desktop, the box inside the sheet on a phone), `sheet` (the bottom sheet the color palette opens in on a phone — no node on desktop) and `swatch` (one palette swatch, after the `swatches` prop — a broadcast).
508
+ Parts: `root` (the container), `label`, `description`, `message` (the errors / warnings region — one node each, only one ever shows), `hint` (the helper line — shown on focus, or always with `persistent-hint`), `box` (the bordered field box), `input` (the native control), `icon` (`prepend:icon` + `append:icon` — a broadcast; the state glyphs are chrome), `spinner` (the spinner shown while `loading`), `prefix`, `suffix`, `clear` (the ✕ that empties the field). Plus `indicator` (the colour dot that opens the palette), `panel` (the palette surface — the popover's painted bubble on desktop, the sheet itself on a phone), `sheet` (the bottom sheet the color palette opens in on a phone — no node on desktop) and `swatch` (one palette swatch, after the `swatches` prop — a broadcast).
509
509
  States: `errors`, `warnings` (never beside errors), `loading`, `disabled`, `readonly`, `has-value` (written `pt:box:has-value`), on every part; plus `selected` on `swatch` only — the swatch matching the value (`pt:swatch:selected`). A name outside that list is a type error and an
510
510
  ESLint error.
511
511
 
@@ -718,7 +718,7 @@ of it. The full grammar, the merge rules and the global map are in the
718
718
  | `suffix` | The `#suffix` slot's wrapper, inside the box after the input. |
719
719
  | `clear` | The ✕ that empties this control (`clearable`) — one node, never a chip's own ✕. |
720
720
  | `indicator` | The colour dot in the box that opens the palette. |
721
- | `panel` | The palette box — the popover's painted bubble on desktop, the box inside the sheet on a phone. |
721
+ | `panel` | The palette surface — the popover's painted bubble on desktop, the sheet itself on a phone. |
722
722
  | `sheet` | The bottom sheet the palette opens in on a phone — no node on desktop. |
723
723
  | `swatch` | One palette swatch (after the `swatches` prop) — a broadcast resolved per swatch. |
724
724
 
@@ -796,7 +796,7 @@ Set these on the element, or on a class you put on it, to retune this component
796
796
  - `BbColorInput` _(this component)_ — its own template binds: `controlAttrs` → `input.bb-color-input__input`, `input` → `input.bb-color-input__input`, `indicator` → `button.bb-color-input__indicator`, `suffix` → `span.bb-field-input__suffix`; hands `BbColorPalette` the pt map `{ panel: 'panel', sheet: 'sheet', swatch: 'swatch' }` (ours → theirs)
797
797
  - `CommonField` _(internal — not importable, reach it through `BbColorInput`)_ — `BbColorInput`'s pt parts land here: `root` → `div.bb-field`, `label` → `component`, `description` → `span.bb-field__description`, `hint` → `span.bb-field__hint-text`, `message` → `div.bb-field__errors`, `message` → `div.bb-field__warnings`
798
798
  - `CommonFieldInput` _(internal — not importable, reach it through `BbColorInput`)_ — `BbColorInput`'s pt parts land here: `box` → `span.bb-field-input__box`, `prefix` → `span.bb-field-input__prefix`, `icon` → `BbIcon`, `clear` → `ClearableButton`, `spinner` → `BbSpinner`, `suffix` → `span.bb-field-input__suffix`; documented CSS variables: `--bg`, `--bg-hover`, `--bg-focus`, `--bg-disabled`, `--border-color`, `--border-focus`, `--ring-size`, `--ring-color`, `--elev`, `--frost`, `--inside-label-clearance`; also mounts `ErrorIcon`, `WarningIcon`, `ClearableButton`, `BbIcon`, `BbSpinner`
799
- - `BbColorPalette` _(public — [contract](./BbColorPalette.md))_ — its own pt parts (`BbColorPalette`): `swatch` → `button.bb-color-palette__swatch`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs); also mounts `CommonPopover`
799
+ - `BbColorPalette` _(public — [contract](./BbColorPalette.md))_ — its own pt parts (`BbColorPalette`): `swatch` → `button.bb-color-palette__swatch`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ panel: 'root', sheet: 'root' }` (ours → theirs); also mounts `CommonPopover`
800
800
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__body`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--handle-w`, `--handle-h`, `--handle-bg`, `--close-size`
801
801
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
802
802
 
@@ -15,6 +15,7 @@
15
15
  | pt part | Lands on | In |
16
16
  | --- | --- | --- |
17
17
  | `pt:panel` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
18
+ | `pt:panel` | `pt:root` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
18
19
  | `pt:sheet` | `pt:root` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
19
20
 
20
21
  ## Usage & Guidelines
@@ -557,11 +558,11 @@ styling (a caret, a highlight). Two props gate interaction:
557
558
 
558
559
  `pt` reaches a named part with a class list — or, in the object form, a
559
560
  style and attributes — optionally only while a state is on. Parts: `root`
560
- (the floating element — the bottom sheet on a phone), `panel` (the palette box you
561
- see: the popover's painted bubble on desktop, the box inside the sheet on a
562
- phone — canvas, sliders, swatches; `pt:panel="px-1"`
563
- tightens its padding), `sheet` (the bottom sheet on a phone only, applied
564
- after `root`) and `swatch` (one swatch, named after the `swatches` prop — a
561
+ (the floating element — an invisible positioning wrapper, no node on a
562
+ phone), `panel` (the palette surface you see: the popover's painted bubble on
563
+ desktop, the sheet itself on a phone — canvas, sliders, swatches; `pt:panel="px-1"`
564
+ tightens the bubble's padding), `sheet` (the bottom sheet on a phone only, applied
565
+ after `panel`) and `swatch` (one swatch, named after the `swatches` prop — a
565
566
  broadcast). States: `open`, and
566
567
  `selected` per swatch (the one matching the value). The canvas and the sliders
567
568
  are not parts.
@@ -762,9 +763,9 @@ The full grammar, the merge rules and the global map are in the
762
763
 
763
764
  | Part | What it is |
764
765
  | --- | --- |
765
- | `root` | The floating element — on a phone, the bottom sheet (as on `BbPopover`). |
766
- | `panel` | The picker box you see — the popover's painted bubble on desktop, the box inside the sheet on a phone — holding the canvas, the sliders and the swatches. The canvas and the sliders are not parts. |
767
- | `sheet` | The bottom sheet on a phone only (the `BbOffCanvas` root). Applied after `root`, so it wins a conflict there. |
766
+ | `root` | The floating element — an invisible positioning wrapper; a `class` on the component lands here. No node on the phone sheet: style what you see with `panel`. |
767
+ | `panel` | The picker surface you see — the popover's painted bubble on desktop, the sheet itself on a phone — holding the canvas, the sliders and the swatches. The canvas and the sliders are not parts. |
768
+ | `sheet` | The bottom sheet on a phone only (the `BbOffCanvas` root). Applied after `panel`, so it wins a conflict there. |
768
769
  | `swatch` | One swatch (after the `swatches` prop) — a broadcast resolved per swatch. |
769
770
 
770
771
  States are listed in precedence order: when two are on at once and their entries conflict, the later one wins.
@@ -795,7 +796,7 @@ States are listed in precedence order: when two are on at once and their entries
795
796
  - **CSS custom properties** listed on a node are declared on THAT node's root and read by elements inside it. Set one on that node's root or on the element inside it that reads it — the pt part that lands there is how you reach it (`pt:box="[--border-color:…]"` on a text input) — never on `BbColorPalette`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
796
797
  - Listed nodes are the ones `BbColorPalette`'s API reaches or that declare a documented CSS variable; the rest fold into "also mounts". The complete tree, repeats and undocumented locals included, is the `tree` field of this component in `components.json`.
797
798
 
798
- - `BbColorPalette` _(this component)_ — its own template binds: `swatch` → `button.bb-color-palette__swatch`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
799
+ - `BbColorPalette` _(this component)_ — its own template binds: `swatch` → `button.bb-color-palette__swatch`, `panel` → `div`, `panel` → `CommonPopover`; hands `BbOffCanvas` the pt map `{ panel: 'root', sheet: 'root' }` (ours → theirs)
799
800
  - `BbOffCanvas` _(public — [contract](./BbOffCanvas.md))_ — its own pt parts (`BbOffCanvas`): `header` → `div.bb-offcanvas__header`, `title` → `span.bb-offcanvas__title`, `description` → `p.bb-offcanvas__description`, `close` → `CloseButton`, `content` → `div.bb-offcanvas__body`, `footer` → `div.bb-offcanvas__footer`; documented CSS variables: `--stack-x`, `--stack-fill`, `--stack-transition-duration`, `--px`, `--handle-w`, `--handle-h`, `--handle-bg`, `--close-size`
800
801
  - `CloseButton` _(internal — not importable, reach it through `BbOffCanvas`)_ — documented CSS variables: `--size`, `--p`
801
802
  - Also mounts `CommonPopover`
@@ -15,6 +15,7 @@
15
15
  | pt part | Lands on | In |
16
16
  | --- | --- | --- |
17
17
  | `pt:panel` | the root of `CommonPopover` | `CommonPopover` _(internal)_ |
18
+ | `pt:panel` | `pt:root` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
18
19
  | `pt:sheet` | `pt:root` of `BbOffCanvas` | `BbOffCanvas` ([contract](./BbOffCanvas.md)) |
19
20
 
20
21
  ## Usage & Guidelines
@@ -202,6 +203,31 @@ const time = ref<string | null>(null);
202
203
  </template>
203
204
  ```
204
205
 
206
+ ### Decorating days
207
+
208
+ The picker passes its day slots straight to the calendar inside it, so the four
209
+ day-grid slots work here unchanged:
210
+
211
+ - `#day` replaces every day's number and `#append:day` adds under every day
212
+ (event dots, prices). Both receive `label`, `selected`, `outside`,
213
+ `first` / `middle` / `last` and `item` (the day as a dayjs object).
214
+ - `#<YYYY_MM_DD>` and `#append:<YYYY_MM_DD>` do the same for one date, e.g.
215
+ `#append:2026_12_25`: its local `YYYY-MM-DD` with `_` for `-`. A date's slot
216
+ wins over the every-day one.
217
+
218
+ ```vue
219
+ <BbDatePicker v-model="pickup">
220
+ <template #activator="{ props, value }">
221
+ <BbButton v-bind="props" variant="outline">{{ value ?? 'Pickup day' }}</BbButton>
222
+ </template>
223
+ <template #append:2026_12_25><span class="text-[10px]">Closed</span></template>
224
+ </BbDatePicker>
225
+ ```
226
+
227
+ Use per-date slots for a few fixed dates; mark data-driven days through
228
+ `#append:day` and a lookup on `item`. The [BbCalendar](./BbCalendar.md) guide
229
+ has a worked example.
230
+
205
231
  ### Adaptive and positioning
206
232
 
207
233
  On mobile the calendar opens in a bottom off-canvas sheet instead of a floating
@@ -267,11 +293,11 @@ into, `BbDatePickerInput` when there is.
267
293
 
268
294
  `pt` reaches a named part with a class list — or, in the object form, a
269
295
  style and attributes — optionally only while a state is on. Parts: `root`
270
- (the floating element — the bottom sheet on a phone), `panel` (the calendar box you
271
- see: the popover's painted bubble on desktop, the box inside the sheet on a
272
- phone — it also carries the sizing tokens, so
296
+ (the floating element — an invisible positioning wrapper, no node on a
297
+ phone), `panel` (the calendar surface you see: the popover's painted bubble on
298
+ desktop, the sheet itself on a phone — it also carries the sizing tokens, so
273
299
  `pt:panel="[--pad-x:2px]"` tightens the padding and the grid width follows), `sheet` (the
274
- bottom sheet on a phone only, applied after `root`), `header` (the
300
+ bottom sheet on a phone only, applied after `panel`), `header` (the
275
301
  navigation bar), `arrow` (the previous / next buttons), `month` and `year`
276
302
  (the heading buttons), `column-header` (each weekday letter), `day` (one whole
277
303
  day cell) and `day-button` (the button inside it), `month-item` and
@@ -412,7 +438,7 @@ and digit typeahead; the time rail exposes labelled columns. Always pass a
412
438
 
413
439
  | Part | What it is |
414
440
  | --- | --- |
415
- | `root` | The floating element — on a phone, the bottom sheet (as on `BbPopover`). |
441
+ | `root` | The floating element — an invisible positioning wrapper; a `class` on the component lands here. No node on the phone sheet: style what you see with `panel`. |
416
442
  | `header` | The navigation bar: the previous / next arrows and the month / year headings. |
417
443
  | `arrow` | The previous / next buttons — a broadcast. |
418
444
  | `month` | The month heading button; it opens the month panel. |
@@ -422,8 +448,8 @@ and digit typeahead; the time rail exposes labelled columns. Always pass a
422
448
  | `day-button` | The button inside a day cell — the mark that shows selection. A broadcast resolved per day. |
423
449
  | `month-item` | One month button of the month panel (the home grid of `type="month"`) — a broadcast resolved per month. |
424
450
  | `year-item` | One year button of the year list — a broadcast resolved per year. |
425
- | `panel` | The calendar box you see — the popover's painted bubble on desktop, the box inside the sheet on a phone. It carries the calendar's sizing tokens: `pt:panel="[--cell:36px]"` widens the calendar, `pt:panel="[--pad-x:2px]"` tightens it. |
426
- | `sheet` | The bottom sheet on a phone only (the `BbOffCanvas` root). Applied after `root`, so it wins a conflict there. |
451
+ | `panel` | The calendar surface you see — the popover's painted bubble on desktop, the sheet itself on a phone. It carries the sizing tokens: `pt:panel="[--cell:36px]"` widens the calendar, `[--pad-x:2px]` tightens. |
452
+ | `sheet` | The bottom sheet on a phone only (the `BbOffCanvas` root). Applied after `panel`, so it wins a conflict there. |
427
453
 
428
454
  States are listed in precedence order: when two are on at once and their entries conflict, the later one wins.
429
455
 
@@ -457,6 +483,8 @@ States are listed in precedence order: when two are on at once and their entries
457
483
  - `activator` — scope: `BbDatePickerActivatorSlotProps` — Custom activator element. Apply `v-bind="props"` to your trigger.
458
484
  - `append:day` — scope: `BbCalendarDaySlotProps` — Appends content below each calendar day.
459
485
  - `day` — scope: `BbCalendarDaySlotProps` — Replaces the day button label inside each calendar day.
486
+ - `#<YYYY_MM_DD>` (named from data) — scope: `BbCalendarDaySlotProps` — One date's button label (e.g. `#2024_03_15`: the local `YYYY-MM-DD` through `slotKey`); beats `day`. Day grid only.
487
+ - `#append:<YYYY_MM_DD>` (named from data) — scope: `BbCalendarDaySlotProps` — Content under one date's cell; beats `append:day`.
460
488
 
461
489
  ## CSS custom properties
462
490
 
@@ -470,9 +498,20 @@ Set these on the element, or on a class you put on it, to retune this component
470
498
  | `--nav-button-h` | `.bb-date-picker__panel` | `24px` | |
471
499
  | `--day-slot-allowance` | `.bb-date-picker__panel` | `0px` | Allowance for the day slot append area - needed for the slot to be visible |
472
500
  | `--unit-row` | `.bb-date-picker__panel` | `calc(var(--cell) * 1.25)` | Row pitch for the coarse grids (month/year), where a "row" is one of four month rows rather than a week. Roomier than --cell because twelve months in a 4×3 grid have space the 6×7 day grid does not. |
473
- | `--sheet-cell` | `.bb-date-picker__panel--sheet` | `40px` | Declared on the container so the time rail (the grid's sibling inside the calendar) can align its wheels to the same column grid. |
474
- | `--cell` | `.bb-date-picker__panel--sheet` | `var(--sheet-cell)` | One touch scale for the whole sheet: 40px day cells (36px marks), and a nav row to match — on the panel, where the tokens live. |
475
- | `--nav-button-h` | `.bb-date-picker__panel--sheet` | `40px` | |
501
+ | `--sheet-cell` | `.bb-date-picker-offcanvas` | `40px` | |
502
+ | `--cell` | `.bb-date-picker-offcanvas` | `var(--sheet-cell)` | |
503
+ | `--pad-x` | `.bb-date-picker-offcanvas` | `6px` | |
504
+ | `--pad-y` | `.bb-date-picker-offcanvas` | `8px` | |
505
+ | `--nav-button-h` | `.bb-date-picker-offcanvas` | `40px` | |
506
+ | `--day-slot-allowance` | `.bb-date-picker-offcanvas` | `0px` | |
507
+ | `--unit-row` | `.bb-date-picker-offcanvas` | `calc(var(--cell) * 1.25)` | |
508
+ | `--sheet-cell` | `.bb-date-picker__panel--sheet` | `inherit` | |
509
+ | `--cell` | `.bb-date-picker__panel--sheet` | `inherit` | |
510
+ | `--pad-x` | `.bb-date-picker__panel--sheet` | `inherit` | |
511
+ | `--pad-y` | `.bb-date-picker__panel--sheet` | `inherit` | |
512
+ | `--nav-button-h` | `.bb-date-picker__panel--sheet` | `inherit` | |
513
+ | `--day-slot-allowance` | `.bb-date-picker__panel--sheet` | `inherit` | |
514
+ | `--unit-row` | `.bb-date-picker__panel--sheet` | `inherit` | |
476
515
 
477
516
  ## Component tree
478
517
 
@@ -483,7 +522,7 @@ Set these on the element, or on a class you put on it, to retune this component
483
522
  - **CSS custom properties** listed on a node are declared on THAT node's root and read by elements inside it. Set one on that node's root or on the element inside it that reads it — the pt part that lands there is how you reach it (`pt:box="[--border-color:…]"` on a text input) — never on `BbDatePicker`'s root, where the node's own declaration masks it (design-tokens guide, _Overriding one from a consumer app_, rule 0).
484
523
  - Listed nodes are the ones `BbDatePicker`'s API reaches or that declare a documented CSS variable; the rest fold into "also mounts". The complete tree, repeats and undocumented locals included, is the `tree` field of this component in `components.json`.
485
524
 
486
- - `BbDatePicker` _(this component)_ — its own template binds: `panel` → `div`, `panel` → `CommonPopover`; hands `BbCalendar` the pt map ` passthrough.forward(DATE_PICKER_CALENDAR_PARTS, BB_CALENDAR_PT.states) ` (ours → theirs); hands `BbOffCanvas` the pt map `{ sheet: 'root' }` (ours → theirs)
525
+ - `BbDatePicker` _(this component)_ — its own template binds: `panel` → `div`, `panel` → `CommonPopover`; hands `BbCalendar` the pt map ` passthrough.forward(DATE_PICKER_CALENDAR_PARTS, BB_CALENDAR_PT.states) ` (ours → theirs); hands `BbOffCanvas` the pt map `{ panel: 'root', sheet: 'root' }` (ours → theirs)
487
526
  - `BbCalendar` _(public — [contract](./BbCalendar.md))_ — its own pt parts (`BbCalendar`): `header` → `div.bb-calendar__controls`, `arrow` → `BbBaseButton`, `month` → `BbBaseButton`, `year` → `BbBaseButton`, `day` → `div.bb-calendar__date`, `day-button` → `button.bb-calendar__date-button`; documented CSS variables: `--cell`, `--day-slot-allowance`, `--unit-row`; also mounts `ScaleFade`, `Slide`, `CalendarMonthPanel`, `CalendarYearPanel`
488
527
  - `BbBaseButton` _(public — [contract](./BbBaseButton.md))_ — its own pt parts (`BbBaseButton`): `root` → `RouterComponent`, `root` → `a`, `root` → `component`; also mounts `RouterComponent`
489
528
  - `CommonTimeSelector` _(internal — not importable, reach it through `BbCalendar`)_ — documented CSS variables: `--time-mark`; also mounts `BbBaseButton`