bitboss-ui 3.0.0-beta.24 → 3.0.0-beta.25

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 (189) hide show
  1. package/dist/ai/BbBaseCheckbox.md +1 -0
  2. package/dist/ai/BbBaseCheckboxGroup.md +2 -1
  3. package/dist/ai/BbBaseColorInput.md +1 -0
  4. package/dist/ai/BbBaseInputContainer.md +1 -0
  5. package/dist/ai/BbBaseNumberInput.md +1 -0
  6. package/dist/ai/BbBaseRadio.md +1 -0
  7. package/dist/ai/BbBaseRadioGroup.md +1 -0
  8. package/dist/ai/BbBaseSelect.md +1 -0
  9. package/dist/ai/BbBaseSwitch.md +1 -0
  10. package/dist/ai/BbBaseSwitchGroup.md +2 -1
  11. package/dist/ai/BbBaseTag.md +1 -0
  12. package/dist/ai/BbBaseTextInput.md +1 -0
  13. package/dist/ai/BbBaseTextarea.md +1 -0
  14. package/dist/ai/BbCheckbox.md +1 -0
  15. package/dist/ai/BbCheckboxGroup.md +90 -0
  16. package/dist/ai/BbColorInput.md +1 -0
  17. package/dist/ai/BbDatePickerInput.md +1 -0
  18. package/dist/ai/BbDropdown.md +262 -4
  19. package/dist/ai/BbNumberInput.md +1 -0
  20. package/dist/ai/BbRadio.md +1 -0
  21. package/dist/ai/BbRadioGroup.md +80 -0
  22. package/dist/ai/BbRating.md +1 -0
  23. package/dist/ai/BbSelect.md +171 -0
  24. package/dist/ai/BbSelectPopover.md +97 -0
  25. package/dist/ai/BbSlider.md +1 -0
  26. package/dist/ai/BbSwitch.md +1 -0
  27. package/dist/ai/BbSwitchGroup.md +81 -0
  28. package/dist/ai/BbTag.md +1 -0
  29. package/dist/ai/BbTextInput.md +33 -0
  30. package/dist/ai/BbTextarea.md +1 -0
  31. package/dist/ai/BbTimePickerInput.md +1 -0
  32. package/dist/ai/FlatListBox.md +1 -0
  33. package/dist/ai/GroupedListBox.md +1 -0
  34. package/dist/ai/ListBox.md +1 -0
  35. package/dist/ai/changelog.json +11 -3
  36. package/dist/ai/components.json +212 -8
  37. package/dist/ai/guides/migration/components/bb-dropdown.md +28 -8
  38. package/dist/ai/guides/options-items-playbook.md +57 -1
  39. package/dist/ai/source/BbBaseCheckbox.md +5 -0
  40. package/dist/ai/source/BbBaseCheckboxGroup.md +64 -2
  41. package/dist/ai/source/BbBaseColorInput.md +5 -0
  42. package/dist/ai/source/BbBaseInputContainer.md +85 -29
  43. package/dist/ai/source/BbBaseNumberInput.md +5 -0
  44. package/dist/ai/source/BbBaseRadio.md +5 -0
  45. package/dist/ai/source/BbBaseRadioGroup.md +64 -2
  46. package/dist/ai/source/BbBaseSelect.md +27 -1
  47. package/dist/ai/source/BbBaseSwitch.md +1 -0
  48. package/dist/ai/source/BbBaseSwitchGroup.md +43 -2
  49. package/dist/ai/source/BbBaseTag.md +5 -0
  50. package/dist/ai/source/BbBaseTextInput.md +5 -0
  51. package/dist/ai/source/BbBaseTextarea.md +5 -0
  52. package/dist/ai/source/BbCheckbox.md +22 -1
  53. package/dist/ai/source/BbCheckboxGroup.md +37 -0
  54. package/dist/ai/source/BbColorInput.md +22 -1
  55. package/dist/ai/source/BbDatePickerInput.md +18 -0
  56. package/dist/ai/source/BbDropdown.md +81 -8
  57. package/dist/ai/source/BbDropdownGroup.md +72 -3
  58. package/dist/ai/source/BbNumberInput.md +22 -1
  59. package/dist/ai/source/BbRadio.md +22 -1
  60. package/dist/ai/source/BbRadioGroup.md +37 -0
  61. package/dist/ai/source/BbRating.md +18 -0
  62. package/dist/ai/source/BbSelect.md +45 -1
  63. package/dist/ai/source/BbSelectPopover.md +81 -2
  64. package/dist/ai/source/BbSlider.md +18 -0
  65. package/dist/ai/source/BbSwitch.md +22 -1
  66. package/dist/ai/source/BbSwitchGroup.md +21 -0
  67. package/dist/ai/source/BbTag.md +22 -1
  68. package/dist/ai/source/BbTextInput.md +22 -1
  69. package/dist/ai/source/BbTextarea.md +22 -1
  70. package/dist/ai/source/BbTimePickerInput.md +18 -0
  71. package/dist/ai/source/FlatListBox.md +75 -3
  72. package/dist/ai/source/GroupedListBox.md +88 -3
  73. package/dist/ai/source/ListBox.md +16 -2
  74. package/dist/ai/source/OptionsContainer.md +50 -2
  75. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue_vue_type_script_setup_true_lang.js +2 -0
  76. package/dist/components/BbBaseCheckbox/types.d.ts +4 -0
  77. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue_vue_type_script_setup_true_lang.js +87 -82
  78. package/dist/components/BbBaseCheckboxGroup/types.d.ts +21 -0
  79. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue_vue_type_script_setup_true_lang.js +3 -0
  80. package/dist/components/BbBaseColorInput/types.d.ts +4 -0
  81. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue_vue_type_script_setup_true_lang.js +88 -79
  82. package/dist/components/BbBaseInputContainer/types.d.ts +14 -0
  83. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue_vue_type_script_setup_true_lang.js +3 -0
  84. package/dist/components/BbBaseNumberInput/types.d.ts +4 -0
  85. package/dist/components/BbBaseRadio/BbBaseRadio.vue_vue_type_script_setup_true_lang.js +2 -0
  86. package/dist/components/BbBaseRadio/types.d.ts +4 -0
  87. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue_vue_type_script_setup_true_lang.js +76 -71
  88. package/dist/components/BbBaseRadioGroup/types.d.ts +21 -0
  89. package/dist/components/BbBaseSelect/BbBaseSelect.vue_vue_type_script_setup_true_lang.js +19 -10
  90. package/dist/components/BbBaseSelect/types.d.ts +24 -0
  91. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue_vue_type_script_setup_true_lang.js +2 -0
  92. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue_vue_type_script_setup_true_lang.js +87 -82
  93. package/dist/components/BbBaseTag/BbBaseTag.vue_vue_type_script_setup_true_lang.js +3 -0
  94. package/dist/components/BbBaseTag/types.d.ts +4 -0
  95. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue_vue_type_script_setup_true_lang.js +3 -0
  96. package/dist/components/BbBaseTextInput/types.d.ts +4 -0
  97. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue_vue_type_script_setup_true_lang.js +3 -0
  98. package/dist/components/BbBaseTextarea/types.d.ts +4 -0
  99. package/dist/components/BbCheckbox/BbCheckbox.vue_vue_type_script_setup_true_lang.js +31 -25
  100. package/dist/components/BbCheckbox/types.d.ts +14 -0
  101. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +38 -31
  102. package/dist/components/BbCheckboxGroup/types.d.ts +31 -0
  103. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +43 -37
  104. package/dist/components/BbColorInput/types.d.ts +14 -0
  105. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +39 -35
  106. package/dist/components/BbDatePickerInput/types.d.ts +14 -0
  107. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +239 -239
  108. package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +261 -247
  109. package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +102 -91
  110. package/dist/components/BbDropdown/normalizeGroups.js +34 -31
  111. package/dist/components/BbDropdown/types.d.ts +59 -3
  112. package/dist/components/BbDropdown/types.js +2 -2
  113. package/dist/components/BbDropdown/useDropdownGroupRegistry.d.ts +1 -0
  114. package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +10 -4
  115. package/dist/components/BbNumberInput/types.d.ts +14 -0
  116. package/dist/components/BbRadio/BbRadio.vue_vue_type_script_setup_true_lang.js +33 -27
  117. package/dist/components/BbRadio/types.d.ts +14 -0
  118. package/dist/components/BbRadioGroup/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +41 -34
  119. package/dist/components/BbRadioGroup/types.d.ts +31 -0
  120. package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +35 -31
  121. package/dist/components/BbRating/types.d.ts +14 -0
  122. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +15 -5
  123. package/dist/components/BbSelect/types.d.ts +38 -0
  124. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +209 -198
  125. package/dist/components/BbSelectPopover/types.d.ts +24 -0
  126. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +36 -32
  127. package/dist/components/BbSlider/types.d.ts +14 -0
  128. package/dist/components/BbSwitch/BbSwitch.vue_vue_type_script_setup_true_lang.js +31 -25
  129. package/dist/components/BbSwitch/types.d.ts +14 -0
  130. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +38 -31
  131. package/dist/components/BbSwitchGroup/types.d.ts +16 -0
  132. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +47 -41
  133. package/dist/components/BbTag/types.d.ts +14 -0
  134. package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +10 -4
  135. package/dist/components/BbTextInput/types.d.ts +14 -0
  136. package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +43 -37
  137. package/dist/components/BbTextarea/types.d.ts +14 -0
  138. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +35 -31
  139. package/dist/components/BbTimePickerInput/types.d.ts +14 -0
  140. package/dist/components/FlatListBox/FlatListBox.vue_vue_type_script_setup_true_lang.js +119 -82
  141. package/dist/components/FlatListBox/types.d.ts +8 -0
  142. package/dist/components/GroupedListBox/GroupedListBox.vue_vue_type_script_setup_true_lang.js +139 -102
  143. package/dist/components/GroupedListBox/types.d.ts +8 -0
  144. package/dist/components/ListBox/ListBox.vue_vue_type_script_setup_true_lang.js +77 -66
  145. package/dist/components/ListBox/types.d.ts +8 -0
  146. package/dist/components/OptionsContainer/OptionsContainer.vue_vue_type_script_setup_true_lang.js +50 -29
  147. package/dist/components/OptionsContainer/types.d.ts +12 -0
  148. package/dist/composables/useBaseOptions.d.ts +12 -1
  149. package/dist/composables/useBaseOptions.js +47 -25
  150. package/dist/composables/useBbDropdownContext.d.ts +5 -0
  151. package/dist/llms-full.txt +928 -15
  152. package/dist/styles.css +1 -1
  153. package/dist/types/ItemProps.d.ts +37 -0
  154. package/dist/types/Option.d.ts +6 -0
  155. package/dist/utilities/functions/itemProps.d.ts +46 -0
  156. package/dist/utilities/functions/itemProps.js +47 -0
  157. package/dist/utilities/misc/listboxMetrics.d.ts +7 -1
  158. package/dist/utilities/misc/listboxMetrics.js +5 -2
  159. package/dist/validated/BbCheckbox.vue.d.ts +3 -1
  160. package/dist/validated/BbCheckbox.vue_vue_type_script_setup_true_lang.js +26 -22
  161. package/dist/validated/BbCheckboxGroup.vue.d.ts +2 -0
  162. package/dist/validated/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +29 -24
  163. package/dist/validated/BbColorInput.vue.d.ts +9 -7
  164. package/dist/validated/BbColorInput.vue_vue_type_script_setup_true_lang.js +28 -24
  165. package/dist/validated/BbDatePickerInput.vue.d.ts +11 -9
  166. package/dist/validated/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +30 -26
  167. package/dist/validated/BbNumberInput.vue.d.ts +9 -7
  168. package/dist/validated/BbNumberInput.vue_vue_type_script_setup_true_lang.js +28 -24
  169. package/dist/validated/BbRadioGroup.vue.d.ts +2 -0
  170. package/dist/validated/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +29 -24
  171. package/dist/validated/BbRating.vue.d.ts +6 -4
  172. package/dist/validated/BbRating.vue_vue_type_script_setup_true_lang.js +25 -21
  173. package/dist/validated/BbSelect.vue.d.ts +2 -0
  174. package/dist/validated/BbSelect.vue_vue_type_script_setup_true_lang.js +39 -31
  175. package/dist/validated/BbSlider.vue.d.ts +9 -7
  176. package/dist/validated/BbSlider.vue_vue_type_script_setup_true_lang.js +28 -24
  177. package/dist/validated/BbSwitch.vue.d.ts +3 -1
  178. package/dist/validated/BbSwitch.vue_vue_type_script_setup_true_lang.js +26 -22
  179. package/dist/validated/BbSwitchGroup.vue.d.ts +2 -0
  180. package/dist/validated/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +29 -24
  181. package/dist/validated/BbTag.vue.d.ts +9 -7
  182. package/dist/validated/BbTag.vue_vue_type_script_setup_true_lang.js +28 -24
  183. package/dist/validated/BbTextInput.vue.d.ts +9 -7
  184. package/dist/validated/BbTextInput.vue_vue_type_script_setup_true_lang.js +28 -24
  185. package/dist/validated/BbTextarea.vue.d.ts +9 -7
  186. package/dist/validated/BbTextarea.vue_vue_type_script_setup_true_lang.js +28 -24
  187. package/dist/validated/BbTimePickerInput.vue.d.ts +9 -7
  188. package/dist/validated/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +28 -24
  189. package/package.json +1 -1
@@ -17,6 +17,7 @@
17
17
  | Prop | Type | Default | Required | Description |
18
18
  | --- | --- | --- | --- | --- |
19
19
  | `ariaDescribedby` | `string \| undefined` | | | ID of the element that describes this checkbox for assistive technologies. Forwarded to the input as `aria-describedby`. |
20
+ | `ariaLabelledby` | `string \| undefined` | | | Id(s) of the element(s) naming this control, forwarded as `aria-labelledby`. |
20
21
  | `autofocus` | `Booleanish \| undefined` | `false` | | Automatically focuses the checkbox when the page/component loads. Use sparingly to avoid usability issues. |
21
22
  | `checked` | `boolean \| undefined` | `undefined` | | Forces the checkbox checked state (controlled prop). When omitted, the checked state is derived from `modelValue === trueValue`. Deliberately `undefined` rather than `false`, so "unset" stays distinguishable from an explicit `:checked="fals… |
22
23
  | `disabled` | `boolean \| undefined` | `false` | | Disables user interaction. Also applied when `readonly` is set, since native checkboxes do not support `readonly`. |
@@ -27,9 +27,10 @@
27
27
  | `hasWarning` | `boolean \| undefined` | `false` | | Puts the component into a warning state. Errors take priority when both are set. |
28
28
  | `hideLabel` | `boolean \| undefined` | `false` | | Visually hides each option's label text (the text rendered next to every input) while keeping it accessible to screen readers. |
29
29
  | `id` | `string \| undefined` | | | Identifier of the group. Used to derive per-option IDs for accessible labeling. |
30
+ | `itemProps` | `ItemProps<T, OptionGroupItemFields> \| undefined` | | | ADDITIONAL row fields resolved from each item — never its text or value (those stay on `itemText` / `itemValue`). Option groups accept one field: - `description` — a muted line under the option label, beside the control; it may wrap. Either… |
30
31
  | `items` | `T[] \| ((prefill: boolean, modelValue?: any) => T[] \| Promise<T[]>)` | `[]` | yes | Items provider. Can be: - An array of items - A sync/async function `(prefill, modelValue) => items` When a function is provided, it is invoked on prefill and when dependencies change to load options dynamically. |
31
32
  | `itemText` | `(T extends object ? string \| ((item: T) => string) : (item: T) => string) \| undefined` | `JSON.stringify(item)` | | Defines how to derive the display text from an item. Accepts a nested key path into the item or a function `(item) => string`. |
32
- | `itemValue` | `(T extends object ? string \| ((item: T) => string) : (item: T) => any) \| undefined` | `JSON.stringify(item)` | | Defines how to derive the value from an item. Accepts a nested key path into the item or a function `(item) => any`. |
33
+ | `itemValue` | `(T extends object ? string \| ((item: T) => string) : (item: T) => any) \| undefined` | | | |
33
34
  | `loadingText` | `string \| undefined` | `'Loading...'` | | Text displayed while items are loading. |
34
35
  | `max` | `number \| undefined` | `Infinity` | | Maximum number of selectable items. |
35
36
  | `modelValue` | `any` | | yes | Selected values for the group. Used with `v-model`. Single value when `multiple` is false, array when `multiple` is true. |
@@ -20,6 +20,7 @@
20
20
  | `alpha` | `boolean \| undefined` | `false` | | Enable the alpha channel. When true the picker shows an opacity slider and emits / accepts `#RRGGBBAA` hex8 values. |
21
21
  | `append:icon` | `string \| undefined` | | | Name of the icon to render at the right hand side of the input. |
22
22
  | `ariaDescribedby` | `string \| undefined` | | | Id(s) of element(s) describing this input for assistive tech (space-separated). Typically includes the container hint id if used within a BaseInputContainer. |
23
+ | `ariaLabelledby` | `string \| undefined` | | | Id(s) of the element(s) naming this control, forwarded as `aria-labelledby`. |
23
24
  | `autocomplete` | `string \| undefined` | `"off"` | | Autocomplete hint for the browser. |
24
25
  | `autofocus` | `Booleanish \| undefined` | | | Focus the input on mount. |
25
26
  | `clearable` | `boolean \| undefined` | `false` | | Show a clear button when the input has a value. |
@@ -44,5 +44,6 @@
44
44
 
45
45
  ## Slots
46
46
 
47
+ - `description` — scope: `BaseInputContainerLabelSlotProps` — Replaces the description text. Rendering the slot alone (no `description` prop) shows the description region and wires it into `aria-describedby`. Stacks below the label, never beside it.
47
48
  - `input` — scope: `BaseInputContainerInputSlotProps` — The form control to render, positioned in the input column. Receives pre-computed wiring attributes so the inner input can be correctly associated with the label and hint.
48
49
  - `label` — scope: `BaseInputContainerLabelSlotProps` — Replaces the default label text. The outer label element and its `for` association are always rendered.
@@ -18,6 +18,7 @@
18
18
  | --- | --- | --- | --- | --- |
19
19
  | `append:icon` | `string \| undefined` | | | Name of the icon to render at the right hand side of the input. |
20
20
  | `ariaDescribedby` | `string \| undefined` | | | Id(s) of descriptive elements announced by screen readers. |
21
+ | `ariaLabelledby` | `string \| undefined` | | | Id(s) of the element(s) naming this control, forwarded as `aria-labelledby`. |
21
22
  | `autocomplete` | `string \| undefined` | `"off"` | | Browser autocomplete hint for the field. |
22
23
  | `autofocus` | `Booleanish \| undefined` | | | Focus the input automatically after mount. |
23
24
  | `clearable` | `boolean \| undefined` | `false` | | Show a clear button whenever a value is present and the control is interactive. |
@@ -17,6 +17,7 @@
17
17
  | Prop | Type | Default | Required | Description |
18
18
  | --- | --- | --- | --- | --- |
19
19
  | `ariaDescribedby` | `string \| undefined` | | | Id(s) of descriptive elements associated with the radio. |
20
+ | `ariaLabelledby` | `string \| undefined` | | | Id(s) of the element(s) naming this control, forwarded as `aria-labelledby`. |
20
21
  | `autofocus` | `Booleanish \| undefined` | | | Focus the control automatically after mount. |
21
22
  | `checked` | `boolean \| undefined` | `undefined` | | Force the radio into a checked state regardless of `modelValue`. |
22
23
  | `disabled` | `boolean \| undefined` | `false` | | Disable the radio. When combined with `readonly`, the control is also disabled to mimic native behaviour. |
@@ -28,6 +28,7 @@
28
28
  | `hasWarning` | `boolean \| undefined` | `false` | | Apply warning styling to the group. Errors take priority when both are set. |
29
29
  | `hideLabel` | `boolean \| undefined` | `false` | | Hide the visual label while keeping it accessible. |
30
30
  | `id` | `string \| undefined` | | | Explicit id for the fieldset. Used to generate ids for individual radios. |
31
+ | `itemProps` | `ItemProps<T, OptionGroupItemFields> \| undefined` | | | ADDITIONAL row fields resolved from each item — never its text or value (those stay on `itemText` / `itemValue`). Option groups accept one field: - `description` — a muted line under the option label, beside the control; it may wrap. Either… |
31
32
  | `items` | `T[] \| ((prefill: boolean, modelValue?: any) => T[] \| Promise<T[]>)` | `[]` | yes | Array of items or function to load them asynchronously. |
32
33
  | `itemText` | `(T extends object ? NestedKeyOf<T> \| ((item: T) => string) : ((item: T) => string) \| undefined) \| undefined` | | | Path to item property for display text or function to extract it. |
33
34
  | `itemValue` | `(T extends object ? NestedKeyOf<T> \| ((item: T) => string) : ((item: T) => any) \| undefined) \| undefined` | | | Path to item property for value or function to extract it. |
@@ -36,6 +36,7 @@
36
36
  | `headerHeight` | `number \| undefined` | | | Height of group headers in the listbox (px). |
37
37
  | `id` | `string \| undefined` | | | Explicit id for the control element. Also used to generate listbox and search input ids. |
38
38
  | `itemHeight` | `number \| undefined` | | | Height of options in the listbox (px). |
39
+ | `itemProps` | `ItemProps<Item, SelectItemFields> \| undefined` | | | ADDITIONAL row fields resolved from each item — never its text or value (those stay on `itemText` / `itemValue`). Accepted fields: - `description` — a muted line under the option label. Setting it gives every row a fixed two-line height (th… |
39
40
  | `items` | `Item[] \| ((query: string, prefill: boolean, modelValue: any) => Promise<Item[]>) \| ((query: string, prefill: boolean, modelValue: any) => Item[])` | | yes | Array of items or async loader function. Loader functions receive `(query, prefill, modelValue)`; `modelValue` is the raw v-model: an array in `multiple` mode, the raw model value (possibly `null`) in single mode. |
40
41
  | `itemText` | `string \| ((item: Item) => string) \| undefined` | | | Path or function to extract display text from an item. |
41
42
  | `itemValue` | `string \| ((item: Item) => string) \| undefined` | | | Path or function to extract a value from an item. |
@@ -17,6 +17,7 @@
17
17
  | Prop | Type | Default | Required | Description |
18
18
  | --- | --- | --- | --- | --- |
19
19
  | `ariaDescribedby` | `string \| undefined` | | | ID of the element that describes this checkbox for assistive technologies. Forwarded to the input as `aria-describedby`. |
20
+ | `ariaLabelledby` | `string \| undefined` | | | Id(s) of the element(s) naming this control, forwarded as `aria-labelledby`. |
20
21
  | `autofocus` | `Booleanish \| undefined` | `false` | | Automatically focuses the checkbox when the page/component loads. Use sparingly to avoid usability issues. |
21
22
  | `checked` | `boolean \| undefined` | `undefined` | | Forces the checkbox checked state (controlled prop). When omitted, the checked state is derived from `modelValue === trueValue`. Deliberately `undefined` rather than `false`, so "unset" stays distinguishable from an explicit `:checked="fals… |
22
23
  | `disabled` | `boolean \| undefined` | `false` | | Disables user interaction. Also applied when `readonly` is set, since native checkboxes do not support `readonly`. |
@@ -27,9 +27,10 @@
27
27
  | `hasWarning` | `boolean \| undefined` | `false` | | Puts the component into a warning state. Errors take priority when both are set. |
28
28
  | `hideLabel` | `boolean \| undefined` | `false` | | Visually hides each option's label text (the text rendered next to every input) while keeping it accessible to screen readers. |
29
29
  | `id` | `string \| undefined` | | | Identifier of the group. Used to derive per-option IDs for accessible labeling. |
30
+ | `itemProps` | `ItemProps<T, OptionGroupItemFields> \| undefined` | | | ADDITIONAL row fields resolved from each item — never its text or value (those stay on `itemText` / `itemValue`). Option groups accept one field: - `description` — a muted line under the option label, beside the control; it may wrap. Either… |
30
31
  | `items` | `T[] \| ((prefill: boolean, modelValue?: any) => T[] \| Promise<T[]>)` | `[]` | yes | Items provider. Can be: - An array of items - A sync/async function `(prefill, modelValue) => items` When a function is provided, it is invoked on prefill and when dependencies change to load options dynamically. |
31
32
  | `itemText` | `(T extends object ? string \| ((item: T) => string) : (item: T) => string) \| undefined` | `JSON.stringify(item)` | | Defines how to derive the display text from an item. Accepts a nested key path into the item or a function `(item) => string`. |
32
- | `itemValue` | `(T extends object ? string \| ((item: T) => string) : (item: T) => any) \| undefined` | `JSON.stringify(item)` | | Defines how to derive the value from an item. Accepts a nested key path into the item or a function `(item) => any`. |
33
+ | `itemValue` | `(T extends object ? string \| ((item: T) => string) : (item: T) => any) \| undefined` | | | |
33
34
  | `loadingText` | `string \| undefined` | `'Loading...'` | | Text displayed while items are loading. |
34
35
  | `max` | `number \| undefined` | `Infinity` | | Maximum number of selectable items. |
35
36
  | `modelValue` | `any` | | yes | Selected values for the group. Used with `v-model`. Single value when `multiple` is false, array when `multiple` is true. |
@@ -18,6 +18,7 @@
18
18
  | --- | --- | --- | --- | --- |
19
19
  | `append:icon` | `string \| undefined` | | | Name of the icon to render at the right hand side of the input. |
20
20
  | `ariaDescribedby` | `string \| undefined` | | | Id(s) of elements describing this tag input for assistive technologies. |
21
+ | `ariaLabelledby` | `string \| undefined` | | | Id(s) of the element(s) naming this control, forwarded as `aria-labelledby`. |
21
22
  | `autocomplete` | `string \| undefined` | `"off"` | | Browser autocomplete hint for the input field. |
22
23
  | `autofocus` | `Booleanish \| undefined` | | | Focus the input automatically on mount. |
23
24
  | `caseSensitive` | `boolean \| undefined` | `false` | | Compare tags case-sensitively when rejecting duplicates, so `Vue` and `vue` can both exist. By default matching folds case, because two chips differing only in case read as duplicates to a user. Either way the tag is stored with the casing … |
@@ -18,6 +18,7 @@
18
18
  | --- | --- | --- | --- | --- |
19
19
  | `append:icon` | `string \| undefined` | | | Name of the icon to render at the right hand side of the input. |
20
20
  | `ariaDescribedby` | `string \| undefined` | | | Id(s) of elements describing this input for assistive technologies. |
21
+ | `ariaLabelledby` | `string \| undefined` | | | Id(s) of the element(s) naming this control, forwarded as `aria-labelledby`. |
21
22
  | `autocomplete` | `string \| undefined` | | | Browser autocomplete hint for the input field. |
22
23
  | `autofocus` | `Booleanish \| undefined` | | | Focus the input automatically on mount. |
23
24
  | `clearable` | `boolean \| undefined` | `false` | | Show a clear button whenever a value is present and the control is interactive. |
@@ -18,6 +18,7 @@
18
18
  | --- | --- | --- | --- | --- |
19
19
  | `append:icon` | `string \| undefined` | | | Name of the icon to render at the right hand side of the textarea. |
20
20
  | `ariaDescribedby` | `string \| undefined` | | | Id(s) of elements describing this textarea for assistive technologies. |
21
+ | `ariaLabelledby` | `string \| undefined` | | | Id(s) of the element(s) naming this control, forwarded as `aria-labelledby`. |
21
22
  | `autocomplete` | `string \| undefined` | | | Browser autocomplete hint for the textarea. |
22
23
  | `autofocus` | `Booleanish \| undefined` | | | Focus the textarea automatically on mount. |
23
24
  | `autoGrow` | `boolean \| undefined` | `false` | | Automatically expand the textarea height to fit its content. Composes with `rows`: when both are set, `rows` acts as the minimum-height floor the field grows past but never shrinks below. |
@@ -576,6 +576,7 @@ input on mount — use sparingly.
576
576
 
577
577
  ## Slots
578
578
 
579
+ - `description` — scope: `BbCheckboxDescriptionSlotProps` — Replaces the description text. Provided alone (no `description` prop) it still renders the description region and wires it into `aria-describedby`.
579
580
  - `icon` — scope: `BbCheckboxIconSlotProps` — Replaces the default checkmark SVG inside the checkbox box. Receives `BaseCheckbox` slot attributes plus the label text.
580
581
  - `label` — scope: `BbCheckboxLabelSlotProps` — Replaces the default label text rendered next to the checkbox.
581
582
 
@@ -97,6 +97,94 @@ prefer stable primitive ids: they survive refetches and are cheap to submit.
97
97
  Two items that resolve to the **same** `item-value` collapse to one option
98
98
  (first wins), so keep values unique.
99
99
 
100
+ #### Additional row fields: `item-props`
101
+
102
+ `item-text` and `item-value` are the option's label and identity. Anything
103
+ **additional** about a row comes from `item-props` — for option groups that is
104
+ one field, `description`: a muted line **under** the option's label, beside the
105
+ control.
106
+
107
+ ```vue
108
+ <BbCheckboxGroup
109
+ legend="Plan"
110
+ :items="plans"
111
+ item-text="name"
112
+ item-value="id"
113
+ :item-props="{ description: 'summary' }"
114
+ />
115
+ ```
116
+
117
+ **Add-ons with item descriptions and a description slot**
118
+
119
+ ```vue
120
+ <template>
121
+ <div class="grid max-w-sm gap-3 rounded-(--bb-radius) border p-3">
122
+ <BbCheckboxGroup
123
+ v-model="addons"
124
+ input-direction="vertical"
125
+ :item-props="{ description: 'summary' }"
126
+ item-text="name"
127
+ item-value="id"
128
+ :items="catalog"
129
+ legend="Add-ons"
130
+ name="addons"
131
+ >
132
+ <!-- The group's OWN description, under the legend. A slot, so it can
133
+ hold a link; `description="…"` is the plain-text form. -->
134
+ <template #description>
135
+ Billed monthly with your plan.
136
+ <a class="underline" href="#pricing">See pricing</a>
137
+ </template>
138
+ </BbCheckboxGroup>
139
+ <p class="addon-summary text-xs text-(--bb-text-muted)">
140
+ {{ addons.length }} add-on{{ addons.length === 1 ? '' : 's' }} selected
141
+ </p>
142
+ </div>
143
+ </template>
144
+ <script setup lang="ts">
145
+ import { ref } from 'vue';
146
+ import { BbCheckboxGroup } from 'bitboss-ui';
147
+
148
+ type Addon = { id: string; name: string; summary: string };
149
+
150
+ // `item-props` holds the ADDITIONAL row fields — never the text or value, which
151
+ // stay on `item-text` / `item-value`. Option groups take one field,
152
+ // `description`: a muted line under each option's label, beside the box.
153
+ // "Priority support" has an empty summary, so it renders no line at all.
154
+ const catalog: Addon[] = [
155
+ {
156
+ id: 'backups',
157
+ name: 'Daily backups',
158
+ summary: 'Kept for 30 days, restorable from the dashboard.',
159
+ },
160
+ {
161
+ id: 'sso',
162
+ name: 'Single sign-on',
163
+ summary: 'SAML and OIDC for up to 500 seats.',
164
+ },
165
+ { id: 'support', name: 'Priority support', summary: '' },
166
+ ];
167
+
168
+ const addons = ref<string[]>(['backups']);
169
+ </script>
170
+ ```
171
+
172
+ Each field takes a dot-path or a getter; or pass one function that returns the
173
+ fields: `:item-props="(plan) => ({ description: plan.summary })"`.
174
+
175
+ - **Only additional fields.** Text and value never go in `item-props`.
176
+ - **Nothing is read implicitly.** Without `item-props` no description renders,
177
+ even if your items carry a `description` field. An empty value renders no
178
+ line for that item.
179
+ - **The line may wrap**, is announced as the option's description (never part of
180
+ its name), and reaches the `#label` slot as `description`.
181
+ - **No icons here.** An option group has no place for an icon other than the
182
+ control itself, which the `#icon` slot already replaces.
183
+ - **Disabling individual options is `selectable`'s job** —
184
+ `:selectable="(plan) => plan.available"` — not a field in `item-props`.
185
+ - The group's own `description` prop is a different thing: it sits under the
186
+ legend.
187
+
100
188
  ### The array model is mandatory
101
189
 
102
190
  `multiple` defaults to **`true`**, so `modelValue` **must be an array** — seed
@@ -534,6 +622,7 @@ focuses the first option on mount — use sparingly.
534
622
  | `id` | `string \| undefined` | | | The identifier of the component. |
535
623
  | `inputDirection` | `"horizontal" \| "vertical" \| undefined` | | | Defines the direction of the inputs in the fieldset. |
536
624
  | `inputPosition` | `"left" \| "center" \| "right" \| undefined` | `"left"` | | Sets the alignment of the input. Since inputs are inline block they can be aligned just as text can. |
625
+ | `itemProps` | `ItemProps<T, OptionGroupItemFields> \| undefined` | | | ADDITIONAL row fields resolved from each item — never its text or value (those stay on `itemText` / `itemValue`). Option groups accept one field: - `description` — a muted line under the option label, beside the control; it may wrap. Either… |
537
626
  | `items` | `T[] \| ((prefill: boolean, modelValue?: any) => T[] \| Promise<T[]>)` | | yes | Used to retrieve items; can be an array or a function. |
538
627
  | `itemText` | `ItemAccessor<T, string> \| undefined` | | | Defines a path that returns a property of the object to use as text or a function that returns a string. |
539
628
  | `itemValue` | `ItemAccessor<T> \| undefined` | | | Defines a path that returns a property of the object to use as value or a function that returns any value. |
@@ -570,6 +659,7 @@ focuses the first option on mount — use sparingly.
570
659
  ## Slots
571
660
 
572
661
  - `append` — scope: `object` — Content rendered after the last option, inside the options container.
662
+ - `description` — scope: `BbCheckboxGroupDescriptionSlotProps` — Replaces the description text. Provided alone (no `description` prop) it still renders the description region and wires it into `aria-describedby`.
573
663
  - `icon` — scope: `BaseCheckboxGroupIconSlotProps<T>` — Replaces the default checkmark icon for each checkbox option.
574
664
  - `label` — scope: `BaseCheckboxGroupLabelSlotProps<T>` — Replaces the default label text for each option.
575
665
  - `legend` — scope: `BbCheckboxGroupLegendSlotProps` — Replaces the default fieldset legend text for the group.
@@ -552,6 +552,7 @@ the `BbTextInput` guide.
552
552
 
553
553
  - `append` — scope: `Record<string, never>` — Content rendered after the color picker indicator button, at the end of the inner container. Mutually exclusive with `suffix`: the `suffix` slot renders inside this slot's default content, so providing `append` replaces the suffix rendering…
554
554
  - `append-outer` — scope: `Record<string, never>` — Content rendered after the entire input control, outside the input chrome. This slot receives no scoped props.
555
+ - `description` — scope: `BbColorInputDescriptionSlotProps` — Replaces the description text. Provided alone (no `description` prop) it still renders the description region and wires it into `aria-describedby`.
555
556
  - `label` — scope: `BbColorInputLabelSlotProps` — Replaces the default label text rendered above the color input.
556
557
  - `prefix` — scope: `Record<string, never>` — Inline content rendered at the start of the input field area, before the typed text. This slot receives no scoped props.
557
558
  - `prepend` — scope: `Record<string, never>` — Content rendered before the text input, at the start of the inner container. This slot receives no scoped props.
@@ -770,6 +770,7 @@ label>')` matches nothing; query each segment by its own label instead. See
770
770
  - `append-outer` — scope: `object` — Content rendered after the entire date picker control, outside the input chrome.
771
771
  - `append:day` — scope: `{ first: boolean; highlighted: boolean; item: Dayjs; label: string; last: boolean; middle: boolean; selected: boolean; }` — Appends content below each calendar day.
772
772
  - `day` — scope: `{ first: boolean; highlighted: boolean; item: Dayjs; label: string; last: boolean; middle: boolean; selected: boolean; }` — Replaces the day button label inside each calendar day.
773
+ - `description` — scope: `BbDatePickerInputDescriptionSlotProps` — Replaces the description text. Provided alone (no `description` prop) it still renders the description region and wires it into `aria-describedby`.
773
774
  - `label` — scope: `BbDatePickerInputLabelSlotProps` — Replaces the default label text rendered above the date picker.
774
775
  - `prefix` — scope: `object` — Inline content rendered at the start of the input field area, before the date fields.
775
776
  - `prepend` — scope: `object` — Content rendered before the date fields, at the start of the inner container.
@@ -343,6 +343,34 @@ Behavior you can rely on:
343
343
  **value** (its `item-value` for pipeline groups, else its `key`) whenever any
344
344
  selectable group changes — the same value shape `BbTable` emits.
345
345
 
346
+ **Gating individual rows.** `selectable` also takes a function
347
+ `(item) => boolean`, the same contract as `BbSelect` and the option groups:
348
+
349
+ ```ts
350
+ const statusGroup = {
351
+ key: 'status',
352
+ multiple: true,
353
+ selectable: (row: { archived?: boolean }) => !row.archived,
354
+ items: statuses,
355
+ };
356
+ ```
357
+
358
+ - The group is still a selectable group (a function counts as `true`): checks,
359
+ `menuitemcheckbox` / `menuitemradio` roles, the menu stays open while
360
+ toggling.
361
+ - A row the function rejects renders **disabled**: clicks do nothing and
362
+ keyboard navigation skips it.
363
+ - The lock holds on a row that is **already selected** — it cannot be
364
+ unselected by a click.
365
+ - `max` stays a soft cap on top: at the limit, unselected rows disable but
366
+ selected ones stay live so the user can swap.
367
+ - The function receives the **row object** in a hand-written group and the
368
+ **raw fetched item** in a fetched group.
369
+ - `useBbDropdownContext(id).groups[key].selectable` stays a plain `true`.
370
+
371
+ This is also how a fetched row gets disabled — see
372
+ [why fetched rows have no `disabled`](#additional-row-fields-itemprops).
373
+
346
374
  Selection state lives on the dropdown; a companion `<BbDropdownGroup>` in the
347
375
  default slot binds to it. The companion is intentionally minimal — it takes
348
376
  only the group's `id` (which must match the group's `key` in `items`) and a
@@ -436,9 +464,10 @@ The full grammar:
436
464
  same provider drops into both.
437
465
  - `itemText` / `itemValue` — a path string or getter producing each raw item's
438
466
  label and value. `v-model` on the companion surfaces the selected value(s);
439
- internally the selection key is a hash of the value. BbBaseButton props on the
440
- raw items (`href`, `disabled`, icons, `variant`, `onClick`, …) pass through
441
- to the rendered rows.
467
+ internally the selection key is a hash of the value.
468
+ - `itemProps` every **additional** field of a row (see
469
+ [Additional row fields](#additional-row-fields-itemprops) below). Nothing
470
+ else is read off the raw item.
442
471
  - `max` — caps a multiple selection; once reached, unselected rows render
443
472
  disabled.
444
473
  - `loadingText` / `noDataText` — placeholder row text per group; the
@@ -636,6 +665,233 @@ const assigneeNames = computed(() =>
636
665
  </script>
637
666
  ```
638
667
 
668
+ ### Additional row fields: `itemProps`
669
+
670
+ A fetched row's **text** and **value** come from `itemText` and `itemValue`.
671
+ Everything **else** about the row comes from `itemProps` — and only from there.
672
+ The raw item is data: a `href`, `disabled` or `prepend:icon` field sitting on it
673
+ does nothing on its own.
674
+
675
+ ```ts
676
+ const assigneeGroup = {
677
+ key: 'assignee',
678
+ selectable: true,
679
+ items: () => api.users(),
680
+ itemText: 'name',
681
+ itemValue: 'id',
682
+ itemProps: { description: 'email', 'prepend:icon': 'avatarIcon' },
683
+ };
684
+ ```
685
+
686
+ **Fetched assignees: description, icon, selectable gate, context**
687
+
688
+ ```vue
689
+ <template>
690
+ <div
691
+ class="flex max-w-sm flex-wrap items-center gap-2 rounded-(--bb-radius) border p-2"
692
+ >
693
+ <div class="min-w-0 flex-1">
694
+ <p class="truncate text-sm font-medium">INV-2048 · Northwind</p>
695
+ <p class="assignee-emails truncate text-xs text-(--bb-text-muted)">
696
+ {{ emails || 'No assignees' }}
697
+ </p>
698
+ </div>
699
+ <BbDropdown
700
+ id="invoice-assignees"
701
+ :items="items"
702
+ loading-text="Loading team…"
703
+ :width="260"
704
+ >
705
+ <template #activator="{ props, loading }">
706
+ <BbButton
707
+ v-bind="props"
708
+ append:icon="lucide:chevron-down"
709
+ :loading="loading"
710
+ size="xs"
711
+ variant="outline"
712
+ >
713
+ Assign
714
+ </BbButton>
715
+ </template>
716
+ <BbDropdownGroup id="assignees" v-model="assignees" />
717
+ </BbDropdown>
718
+ </div>
719
+ </template>
720
+ <script setup lang="ts">
721
+ import { computed, ref } from 'vue';
722
+ import {
723
+ BbButton,
724
+ BbDropdown,
725
+ BbDropdownGroup,
726
+ useBbDropdownContext,
727
+ } from 'bitboss-ui';
728
+ import type { BbDropdownItem } from 'bitboss-ui';
729
+
730
+ type Member = { id: string; name: string; email: string; active: boolean };
731
+
732
+ const team: Member[] = [
733
+ {
734
+ id: 'u1',
735
+ name: 'Sofia Esposito',
736
+ email: 'sofia@example.com',
737
+ active: true,
738
+ },
739
+ {
740
+ id: 'u2',
741
+ name: 'Marco Bianchi',
742
+ email: 'marco@example.com',
743
+ active: false,
744
+ },
745
+ { id: 'u3', name: 'Aisha Khan', email: 'aisha@example.com', active: true },
746
+ ];
747
+
748
+ const items: BbDropdownItem[] = [
749
+ {
750
+ key: 'assignees',
751
+ label: 'Assign to',
752
+ multiple: true,
753
+ // Fetched rows take their text and value from `itemText` / `itemValue`,
754
+ // and EVERY other field only from `itemProps` — a raw `disabled` or
755
+ // `prepend:icon` sitting on the item would do nothing.
756
+ itemText: 'name',
757
+ itemValue: 'id',
758
+ itemProps: { description: 'email', 'prepend:icon': () => 'lucide:user' },
759
+ // Fetched groups are for selection, so a row is disabled by the group's
760
+ // `selectable` predicate (it receives the RAW member), not by a field.
761
+ selectable: (member: Member) => member.active,
762
+ items: async () => {
763
+ await new Promise((resolve) => setTimeout(resolve, 300));
764
+ return team;
765
+ },
766
+ },
767
+ ];
768
+
769
+ const assignees = ref<string[]>(['u1']);
770
+
771
+ // The resolved description is on the context's `selectedOptions` too — no
772
+ // second fetch to show the picked emails outside the menu.
773
+ const context = useBbDropdownContext('invoice-assignees');
774
+ const emails = computed(() =>
775
+ (context.groups.value.assignees?.selectedOptions ?? [])
776
+ .map((option) => option.description)
777
+ .filter(Boolean)
778
+ .join(', ')
779
+ );
780
+ </script>
781
+ ```
782
+
783
+ **Fetched links: function form with href and a handler**
784
+
785
+ ```vue
786
+ <template>
787
+ <div
788
+ class="flex max-w-sm items-center gap-2 rounded-(--bb-radius) border p-2"
789
+ >
790
+ <span class="flex-1 text-sm">Workspace</span>
791
+ <BbDropdown :items="items" :width="260">
792
+ <template #activator="{ props }">
793
+ <BbButton
794
+ v-bind="props"
795
+ append:icon="lucide:chevron-down"
796
+ size="xs"
797
+ variant="outline"
798
+ >
799
+ Projects
800
+ </BbButton>
801
+ </template>
802
+ </BbDropdown>
803
+ <p class="last-opened text-xs text-(--bb-text-muted)">
804
+ {{ lastOpened ?? '' }}
805
+ </p>
806
+ </div>
807
+ </template>
808
+ <script setup lang="ts">
809
+ import { ref } from 'vue';
810
+ import { BbButton, BbDropdown } from 'bitboss-ui';
811
+ import type { BbDropdownItem } from 'bitboss-ui';
812
+
813
+ type Project = { id: string; name: string; client: string; path: string };
814
+
815
+ const recent: Project[] = [
816
+ { id: 'p1', name: 'Apollo redesign', client: 'Northwind', path: '#apollo' },
817
+ { id: 'p2', name: 'Gemini billing', client: 'Contoso', path: '#gemini' },
818
+ ];
819
+
820
+ const lastOpened = ref<string | null>(null);
821
+
822
+ const items: BbDropdownItem[] = [
823
+ { key: 'new', text: 'New project', 'prepend:icon': 'lucide:plus' },
824
+ {
825
+ // A fetched group of LINKS (not selectable). Its rows get `href`, an icon,
826
+ // a description and a click handler from `itemProps`, using the function
827
+ // form. In the object form a function is a GETTER, so a handler would be
828
+ // written `onClick: (project) => () => …`; here the function form returns
829
+ // the handler directly.
830
+ key: 'recent',
831
+ label: 'Recent',
832
+ itemText: 'name',
833
+ itemValue: 'id',
834
+ itemProps: (project: Project) => ({
835
+ description: project.client,
836
+ href: project.path,
837
+ 'prepend:icon': 'lucide:folder',
838
+ onClick: () => {
839
+ lastOpened.value = project.name;
840
+ },
841
+ }),
842
+ items: async () => recent,
843
+ },
844
+ ];
845
+ </script>
846
+ ```
847
+
848
+ **Two forms.**
849
+
850
+ - **Object** — one dot-path or getter per field:
851
+ `{ description: 'email', href: (user) => '/users/' + user.id }`. Each field
852
+ resolves on its own.
853
+ - **Function** — one function returning the fields:
854
+ `(user) => ({ description: user.email, href: user.url })`. Called once per
855
+ item and cached.
856
+
857
+ In the object form **a function is always a getter**, so a handler field
858
+ returns the handler: `onClick: (user) => () => openProfile(user)`. (The types
859
+ reject the common slip `onClick: () => openProfile()`, because it doesn't return
860
+ a function.)
861
+
862
+ **Which fields.** Everything a hand-written row accepts, except its identity and
863
+ structure — `key`, `text`, `items`, `group` — and `disabled`:
864
+
865
+ - `description` — a muted second line under the text, announced as the row's
866
+ description (never part of its name), searched with the text, and exposed as
867
+ `description` on `useBbDropdownContext(id).groups[key].selectedOptions`.
868
+ - `prepend:icon`, `append:icon`, `variant`.
869
+ - `onClick`, `href`, `to`, `target`, `rel`, `download`, `external`, and the
870
+ Inertia visit options.
871
+
872
+ An empty value (`null`, `undefined`, `''`) means the field is absent — no empty
873
+ line, no blank icon, no `href=""`.
874
+
875
+ **Why there is no `disabled`: fetched groups are for selection.** This is the
876
+ subtle part, so here it is step by step.
877
+
878
+ 1. A greyed-out row can mean two different things: _"this can't be picked"_ (a
879
+ choice) or _"this can't be used"_ (an action or a link).
880
+ 2. A group holds one kind of rows. Its `items` is either hand-written rows or a
881
+ fetched source (a getter, or a raw array read through `itemText` /
882
+ `itemValue`) — never a mix. Mixing happens only **across** groups: a
883
+ hand-written "Actions" group next to a fetched "Assignees" group.
884
+ 3. A fetched group is meant to be **selectable** — assignees, labels, filters.
885
+ There, "can't be picked" is the only question, and the group's `selectable`
886
+ answers it: pass `(item) => boolean` and a rejected row renders disabled,
887
+ exactly as in `BbSelect` and the option groups.
888
+ 4. So a fetched row has no `disabled` field. The one case that loses out is a
889
+ fetched group of **actions or links** that needs to disable a single row —
890
+ no such menu exists in the library or its fixtures. If one ever does,
891
+ `disabled` can be added to `itemProps` later without breaking anything.
892
+ 5. Hand-written rows keep their `disabled` field as always — that is where
893
+ action menus live.
894
+
639
895
  ### Searchable groups
640
896
 
641
897
  A group can render **its own search field**, scoped to itself alone — the
@@ -658,6 +914,7 @@ group owns an independent query.
658
914
  items: (query, prefill, modelValue) => api.users({ q: query }),
659
915
  itemText: 'name',
660
916
  itemValue: 'id',
917
+ itemProps: { description: 'email' },
661
918
  },
662
919
  ]"
663
920
  />
@@ -671,7 +928,8 @@ What each knob does:
671
928
  **leading** argument: `(query, prefill, modelValue)`, the same shape
672
929
  `BbSelect` uses, so one provider serves both.
673
930
  - **`filterBy`** picks which raw fields the local substring match reads. Empty
674
- (the default) matches the resolved display text.
931
+ (the default) matches the resolved display text, plus the resolved
932
+ description when the group's `itemProps` gives one.
675
933
  - **`searchPlaceholder`** overrides the field's placeholder; it defaults to the
676
934
  localized label.
677
935
  - **`prefill: false`** means _search-first_ — nothing loads until the user
@@ -725,6 +725,7 @@ the `BbTextInput` guide.
725
725
 
726
726
  - `append` — scope: `BaseNumberInputStepSlotProps` — Content rendered after the number input, at the end of the inner container. Typically used to place increment/decrement buttons next to the input.
727
727
  - `append-outer` — scope: `BaseNumberInputStepSlotProps` — Content rendered after the entire input control, outside the input chrome.
728
+ - `description` — scope: `BbNumberInputDescriptionSlotProps` — Replaces the description text. Provided alone (no `description` prop) it still renders the description region and wires it into `aria-describedby`.
728
729
  - `label` — scope: `BbNumberInputLabelSlotProps` — Replaces the default label text rendered above the number input.
729
730
  - `prefix` — scope: `BaseNumberInputStepSlotProps` — Inline content rendered at the start of the input field area, before the typed number.
730
731
  - `prepend` — scope: `BaseNumberInputStepSlotProps` — Content rendered before the number input, at the start of the inner container.
@@ -381,6 +381,7 @@ listen to them for side concerns only. `autofocus` focuses the input on mount.
381
381
 
382
382
  ## Slots
383
383
 
384
+ - `description` — scope: `BbRadioDescriptionSlotProps` — Replaces the description text. Provided alone (no `description` prop) it still renders the description region and wires it into `aria-describedby`.
384
385
  - `icon` — scope: `BbRadioIconSlotProps` — Replaces the default radio dot visual inside the radio container. Receives `BaseRadio` slot attributes plus the label text.
385
386
  - `label` — scope: `BbRadioLabelSlotProps` — Replaces the default label text rendered next to the radio button.
386
387