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

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 (252) hide show
  1. package/README.md +55 -3
  2. package/bin/bitboss-ui-mcp.mjs +419 -9
  3. package/bin/bitboss-ui.mjs +293 -22
  4. package/dist/ai/BbAccordion.md +21 -23
  5. package/dist/ai/BbAlert.md +6 -12
  6. package/dist/ai/BbAvatar.md +60 -24
  7. package/dist/ai/BbBadge.md +12 -20
  8. package/dist/ai/BbBaseButton.md +14 -16
  9. package/dist/ai/BbBaseCheckboxIcon.md +6 -10
  10. package/dist/ai/BbBaseColorInput.md +1 -0
  11. package/dist/ai/BbBaseDatePickerInput.md +1 -0
  12. package/dist/ai/BbBaseNumberInput.md +1 -0
  13. package/dist/ai/BbBaseRadioIcon.md +6 -10
  14. package/dist/ai/BbBaseSelect.md +1 -0
  15. package/dist/ai/BbBaseSwitchIcon.md +5 -9
  16. package/dist/ai/BbBaseTag.md +1 -0
  17. package/dist/ai/BbBaseTextInput.md +2 -1
  18. package/dist/ai/BbBaseTextarea.md +1 -0
  19. package/dist/ai/BbBaseTimePickerInput.md +1 -0
  20. package/dist/ai/BbBreadcrumbs.md +23 -34
  21. package/dist/ai/BbButton.md +35 -47
  22. package/dist/ai/BbCheckbox.md +21 -37
  23. package/dist/ai/BbCheckboxGroup.md +13 -13
  24. package/dist/ai/BbCollapsible.md +14 -26
  25. package/dist/ai/BbColorInput.md +27 -23
  26. package/dist/ai/BbColorPalette.md +23 -35
  27. package/dist/ai/BbConfirm.md +17 -32
  28. package/dist/ai/BbDatePickerInput.md +29 -21
  29. package/dist/ai/BbDialog.md +159 -62
  30. package/dist/ai/BbDropdown.md +21 -25
  31. package/dist/ai/BbDropdownButton.md +13 -30
  32. package/dist/ai/BbDropzone.md +9 -11
  33. package/dist/ai/BbIcon.md +44 -33
  34. package/dist/ai/BbIndicator.md +2 -2
  35. package/dist/ai/BbNumberInput.md +32 -20
  36. package/dist/ai/BbOffCanvas.md +42 -42
  37. package/dist/ai/BbPagination.md +21 -23
  38. package/dist/ai/BbPopover.md +15 -17
  39. package/dist/ai/BbProgress.md +40 -51
  40. package/dist/ai/BbRadio.md +9 -9
  41. package/dist/ai/BbRadioGroup.md +7 -11
  42. package/dist/ai/BbRating.md +8 -12
  43. package/dist/ai/BbSelect.md +46 -36
  44. package/dist/ai/BbSelectPopover.md +19 -31
  45. package/dist/ai/BbSlider.md +15 -19
  46. package/dist/ai/BbSmoothHeight.md +16 -31
  47. package/dist/ai/BbSpinner.md +118 -74
  48. package/dist/ai/BbSwitch.md +25 -18
  49. package/dist/ai/BbSwitchGroup.md +9 -14
  50. package/dist/ai/BbTable.md +102 -55
  51. package/dist/ai/BbTabs.md +59 -82
  52. package/dist/ai/BbTag.md +26 -23
  53. package/dist/ai/BbTextInput.md +63 -27
  54. package/dist/ai/BbTextarea.md +42 -34
  55. package/dist/ai/BbTimePickerInput.md +14 -0
  56. package/dist/ai/BbToast.md +14 -34
  57. package/dist/ai/BbTooltip.md +22 -20
  58. package/dist/ai/BbTree.md +46 -72
  59. package/dist/ai/CommonInputWrapper.md +1 -0
  60. package/dist/ai/changelog.json +170 -62
  61. package/dist/ai/components.json +1678 -11
  62. package/dist/ai/composables/useConfirm.md +5 -2
  63. package/dist/ai/composables/useToast.md +4 -2
  64. package/dist/ai/guides/agent-contract.md +7 -4
  65. package/dist/ai/guides/ai-router.md +37 -22
  66. package/dist/ai/guides/component-picker.md +23 -18
  67. package/dist/ai/guides/design-language.md +151 -21
  68. package/dist/ai/guides/design-tokens.md +29 -4
  69. package/dist/ai/guides/icons-policy.md +46 -21
  70. package/dist/ai/guides/installation-and-plugin-setup.md +286 -17
  71. package/dist/ai/guides/migration/components/bb-rating.md +26 -1
  72. package/dist/ai/guides/migration/components/bb-tooltip.md +18 -0
  73. package/dist/ai/guides/migration/v2-to-v3.md +50 -23
  74. package/dist/ai/index.md +1 -1
  75. package/dist/ai/recipes/inertia/approvals-inbox.md +3 -3
  76. package/dist/ai/recipes/inertia/inline-edit-workspace.md +2 -2
  77. package/dist/ai/recipes/inertia/onboarding.md +2 -2
  78. package/dist/ai/recipes/inertia/ownership-atlas.md +6 -6
  79. package/dist/ai/recipes/inertia/record-form.md +5 -5
  80. package/dist/ai/recipes/inertia/records-workspace.md +4 -4
  81. package/dist/ai/recipes/inertia/upload-center.md +6 -6
  82. package/dist/ai/recipes/inertia/wizard-form.md +5 -5
  83. package/dist/ai/recipes/nuxt/approvals-inbox.md +3 -3
  84. package/dist/ai/recipes/nuxt/inline-edit-workspace.md +2 -2
  85. package/dist/ai/recipes/nuxt/onboarding.md +2 -2
  86. package/dist/ai/recipes/nuxt/record-form.md +5 -5
  87. package/dist/ai/recipes/nuxt/records-workspace.md +4 -4
  88. package/dist/ai/recipes/nuxt/upload-center.md +6 -6
  89. package/dist/ai/recipes/nuxt/wizard-form.md +5 -5
  90. package/dist/ai/recipes/vue/approvals-inbox.md +3 -3
  91. package/dist/ai/recipes/vue/inline-edit-workspace.md +2 -2
  92. package/dist/ai/recipes/vue/onboarding.md +2 -2
  93. package/dist/ai/recipes/vue/record-form.md +10 -10
  94. package/dist/ai/recipes/vue/records-workspace.md +4 -4
  95. package/dist/ai/recipes/vue/upload-center.md +6 -6
  96. package/dist/ai/recipes/vue/wizard-form.md +5 -5
  97. package/dist/ai/source/BbBadge.md +1 -1
  98. package/dist/ai/source/BbBaseCheckbox.md +1 -1
  99. package/dist/ai/source/BbBaseColorInput.md +7 -0
  100. package/dist/ai/source/BbBaseDatePicker.md +5 -5
  101. package/dist/ai/source/BbBaseDatePickerInput.md +9 -2
  102. package/dist/ai/source/BbBaseNumberInput.md +7 -0
  103. package/dist/ai/source/BbBaseRadio.md +1 -1
  104. package/dist/ai/source/BbBaseRating.md +5 -5
  105. package/dist/ai/source/BbBaseSelect.md +8 -1
  106. package/dist/ai/source/BbBaseSlider.md +5 -5
  107. package/dist/ai/source/BbBaseSwitch.md +1 -1
  108. package/dist/ai/source/BbBaseTag.md +7 -0
  109. package/dist/ai/source/BbBaseTextInput.md +7 -0
  110. package/dist/ai/source/BbBaseTextarea.md +7 -0
  111. package/dist/ai/source/BbBaseTimePickerInput.md +8 -1
  112. package/dist/ai/source/BbBreadcrumbs.md +20 -1
  113. package/dist/ai/source/BbButton.md +2 -2
  114. package/dist/ai/source/BbColorInput.md +14 -0
  115. package/dist/ai/source/BbDatePickerInput.md +14 -0
  116. package/dist/ai/source/BbDialog.md +39 -8
  117. package/dist/ai/source/BbDropdown.md +1 -1
  118. package/dist/ai/source/BbDropzone.md +5 -5
  119. package/dist/ai/source/BbIcon.md +23 -10
  120. package/dist/ai/source/BbNumberInput.md +14 -0
  121. package/dist/ai/source/BbOffCanvas.md +50 -28
  122. package/dist/ai/source/BbPagination.md +2 -2
  123. package/dist/ai/source/BbPopover.md +12 -1
  124. package/dist/ai/source/BbSelect.md +14 -0
  125. package/dist/ai/source/BbSelectPopover.md +45 -7
  126. package/dist/ai/source/BbSpinner.md +2 -2
  127. package/dist/ai/source/BbTable.md +11 -11
  128. package/dist/ai/source/BbTag.md +14 -0
  129. package/dist/ai/source/BbTextInput.md +14 -0
  130. package/dist/ai/source/BbTextarea.md +14 -0
  131. package/dist/ai/source/BbTimePickerInput.md +14 -0
  132. package/dist/ai/source/BbTooltip.md +57 -10
  133. package/dist/ai/source/ChipsBox.md +1 -1
  134. package/dist/ai/source/CommaBox.md +1 -1
  135. package/dist/ai/source/CommonInputWrapper.md +128 -33
  136. package/dist/ai/source/GuidesComponent.md +14 -7
  137. package/dist/ai/source/OptionsContainer.md +1 -1
  138. package/dist/components/BbBadge/BadgeBodyContent.vue_vue_type_script_setup_true_lang.js +1 -1
  139. package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +1 -1
  140. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue_vue_type_script_setup_true_lang.js +1 -1
  141. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue_vue_type_script_setup_true_lang.js +4 -1
  142. package/dist/components/BbBaseColorInput/types.d.ts +5 -0
  143. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue_vue_type_script_setup_true_lang.js +4 -4
  144. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue_vue_type_script_setup_true_lang.js +1 -1
  145. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue_vue_type_script_setup_true_lang.js +5 -2
  146. package/dist/components/BbBaseDatePickerInput/types.d.ts +5 -0
  147. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.d.ts +1 -1
  148. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue_vue_type_script_setup_true_lang.js +4 -1
  149. package/dist/components/BbBaseNumberInput/types.d.ts +5 -0
  150. package/dist/components/BbBaseRadio/BbBaseRadio.vue_vue_type_script_setup_true_lang.js +1 -1
  151. package/dist/components/BbBaseRating/BbBaseRating.vue_vue_type_script_setup_true_lang.js +3 -3
  152. package/dist/components/BbBaseSelect/BbBaseSelect.vue_vue_type_script_setup_true_lang.js +4 -1
  153. package/dist/components/BbBaseSelect/types.d.ts +5 -0
  154. package/dist/components/BbBaseSlider/BbBaseSlider.vue_vue_type_script_setup_true_lang.js +3 -3
  155. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue_vue_type_script_setup_true_lang.js +1 -1
  156. package/dist/components/BbBaseTag/BbBaseTag.vue_vue_type_script_setup_true_lang.js +4 -1
  157. package/dist/components/BbBaseTag/types.d.ts +5 -0
  158. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue_vue_type_script_setup_true_lang.js +4 -1
  159. package/dist/components/BbBaseTextInput/types.d.ts +5 -0
  160. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue_vue_type_script_setup_true_lang.js +4 -1
  161. package/dist/components/BbBaseTextarea/types.d.ts +5 -0
  162. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue_vue_type_script_setup_true_lang.js +5 -2
  163. package/dist/components/BbBaseTimePickerInput/types.d.ts +5 -0
  164. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +71 -71
  165. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +2 -2
  166. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +5 -2
  167. package/dist/components/BbColorInput/types.d.ts +12 -0
  168. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +4 -2
  169. package/dist/components/BbDatePickerInput/types.d.ts +12 -0
  170. package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +102 -97
  171. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +1 -1
  172. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +58 -58
  173. package/dist/components/BbDropzone/BbDropzone.vue_vue_type_script_setup_true_lang.js +2 -2
  174. package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +33 -35
  175. package/dist/components/BbIcon/iconCache.d.ts +30 -0
  176. package/dist/components/BbIcon/iconCache.js +21 -3
  177. package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +5 -2
  178. package/dist/components/BbNumberInput/types.d.ts +12 -0
  179. package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +57 -56
  180. package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +2 -2
  181. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +138 -138
  182. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +4 -2
  183. package/dist/components/BbSelect/types.d.ts +12 -0
  184. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +43 -43
  185. package/dist/components/BbSpinner/BbSpinner.vue_vue_type_script_setup_true_lang.js +1 -1
  186. package/dist/components/BbSpinner/types.d.ts +1 -1
  187. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +8 -8
  188. package/dist/components/BbTable/BbTableDataRow.js +2 -2
  189. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +5 -2
  190. package/dist/components/BbTag/types.d.ts +12 -0
  191. package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +5 -2
  192. package/dist/components/BbTextInput/types.d.ts +12 -0
  193. package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +5 -2
  194. package/dist/components/BbTextarea/types.d.ts +12 -0
  195. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +4 -2
  196. package/dist/components/BbTimePickerInput/types.d.ts +12 -0
  197. package/dist/components/BbToast/BbToastRegion.vue_vue_type_script_setup_true_lang.js +62 -62
  198. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +81 -78
  199. package/dist/components/BbTooltip/types.d.ts +8 -1
  200. package/dist/components/ChipsBox/ChipsBox.vue_vue_type_script_setup_true_lang.js +1 -1
  201. package/dist/components/CommaBox/CommaBox.vue_vue_type_script_setup_true_lang.js +1 -1
  202. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue.d.ts +1 -0
  203. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue_vue_type_script_setup_true_lang.js +4 -2
  204. package/dist/components/CommonInputWrapper/types.d.ts +10 -0
  205. package/dist/components/OptionsContainer/OptionsContainer.vue_vue_type_script_setup_true_lang.js +1 -1
  206. package/dist/composables/useConfirm.d.ts +22 -0
  207. package/dist/composables/useConfirm.js +43 -40
  208. package/dist/composables/useSafeAreaInternal.js +1 -1
  209. package/dist/composables/useToast.d.ts +16 -0
  210. package/dist/composables/useToast.js +20 -16
  211. package/dist/composables/useViewportWidth.d.ts +20 -6
  212. package/dist/composables/useViewportWidth.js +8 -7
  213. package/dist/icon-scan.d.ts +276 -0
  214. package/dist/icon-scan.js +485 -0
  215. package/dist/icons-whitelist.d.ts +5 -4
  216. package/dist/index.d.ts +2 -0
  217. package/dist/input-variants.d.ts +18 -0
  218. package/dist/llms-full.txt +2173 -1537
  219. package/dist/llms-medium.txt +504 -82
  220. package/dist/llms.txt +1 -1
  221. package/dist/nuxt-module.d.ts +1 -0
  222. package/dist/nuxt.js +10 -7
  223. package/dist/plugin.js +1 -0
  224. package/dist/runtime/nuxt-plugin.js +2 -1
  225. package/dist/styles.css +1 -1
  226. package/dist/types/Config.d.ts +18 -0
  227. package/dist/types/InputVariant.d.ts +22 -0
  228. package/dist/utils/cssLayers.d.ts +91 -0
  229. package/dist/utils/cssLayers.js +43 -0
  230. package/dist/utils/injectLibraryStyles.d.ts +3 -1
  231. package/dist/utils/injectLibraryStyles.js +24 -23
  232. package/dist/validated/BbColorInput.vue_vue_type_script_setup_true_lang.js +1 -0
  233. package/dist/validated/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +1 -0
  234. package/dist/validated/BbNumberInput.vue_vue_type_script_setup_true_lang.js +1 -0
  235. package/dist/validated/BbSelect.vue_vue_type_script_setup_true_lang.js +1 -0
  236. package/dist/validated/BbTag.vue_vue_type_script_setup_true_lang.js +1 -0
  237. package/dist/validated/BbTextInput.vue_vue_type_script_setup_true_lang.js +1 -0
  238. package/dist/validated/BbTextarea.vue_vue_type_script_setup_true_lang.js +1 -0
  239. package/dist/validated/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +1 -0
  240. package/dist/validated/index.d.ts +1 -0
  241. package/dist/vite-plugin.d.ts +89 -12
  242. package/dist/vite.js +331 -281
  243. package/llms.txt +1 -1
  244. package/package.json +7 -5
  245. package/scripts/lib/ensure-manifest.mjs +28 -5
  246. package/scripts/lib/eslint-plugin.d.ts +35 -0
  247. package/scripts/lib/eslint-plugin.mjs +299 -3
  248. package/scripts/lib/hand-roll-hints.mjs +50 -6
  249. package/scripts/lib/html-attributes.mjs +42 -0
  250. package/scripts/lib/mcp-config.mjs +38 -34
  251. package/scripts/lib/public-type-exports.mjs +246 -0
  252. package/scripts/lib/validate-bb-markup.mjs +205 -12
@@ -9,8 +9,12 @@ var { t: s } = n(), c = e(), l = [], u = {
9
9
  yesBusy: !1,
10
10
  noBusy: !1,
11
11
  actionBusy: null
12
- }, d = o({ ...u }), f = d, p = a(/* @__PURE__ */ new Map()), m = (e, t) => (p.set(e, t), () => p.delete(e)), h = t.medium, g, _, v = 0, y = !1, b = !1, x = () => {
13
- v++, y = !0;
12
+ }, d = o({ ...u }), f = d, p = a(/* @__PURE__ */ new Map()), m = (e, t) => (p.set(e, t), () => p.delete(e)), h = t.medium, g, _, v = 0, y = !1, b, x = 1e3, S = (e) => {
13
+ process.env.NODE_ENV === "production" || y || (clearTimeout(b), b = setTimeout(() => {
14
+ y || v > 0 || e() || (y = !0, c.warn("Confirm: confirm() was called but no <BbConfirm> host is mounted — the returned promise will never settle because no dialog can render. Mount exactly one <BbConfirm /> at the app root."));
15
+ }, x));
16
+ }, C = () => {
17
+ v++, clearTimeout(b);
14
18
  let e = !1;
15
19
  return {
16
20
  count: v,
@@ -18,36 +22,36 @@ var { t: s } = n(), c = e(), l = [], u = {
18
22
  e || (e = !0, v--);
19
23
  }
20
24
  };
21
- }, S = () => {
25
+ }, w = () => {
22
26
  clearTimeout(_), clearTimeout(g), d.value = { ...u };
23
- }, C = () => {
27
+ }, T = () => {
24
28
  let e = l.shift();
25
29
  if (!e) return;
26
30
  let t = d.value.current;
27
- t && !t.settled && t.resolve(!1), S(), d.value.current = e, d.value.processing = !0, process.env.NODE_ENV !== "production" && !e.title && !e.text && !e.portal && console.warn("[BbConfirm] A confirm was opened with no title, text, or portal — the dialog will appear empty."), process.env.NODE_ENV !== "production" && e.text && e.portal && c.warn("Confirm: a message carries both `text` and `portal` — `text` takes priority and the portal is ignored. Remove one of the two."), e.duration && (d.value.current.autoClose = !0, g = setTimeout(() => {
31
+ t && !t.settled && t.resolve(!1), w(), d.value.current = e, d.value.processing = !0, process.env.NODE_ENV !== "production" && !e.title && !e.text && !e.portal && console.warn("[BbConfirm] A confirm was opened with no title, text, or portal — the dialog will appear empty."), process.env.NODE_ENV !== "production" && e.text && e.portal && c.warn("Confirm: a message carries both `text` and `portal` — `text` takes priority and the portal is ignored. Remove one of the two."), e.duration && (d.value.current.autoClose = !0, g = setTimeout(() => {
28
32
  let { current: e } = d.value;
29
- e && (w(e), l.length ? C() : D());
33
+ e && (E(e), l.length ? T() : k());
30
34
  }, e.duration));
31
- }, w = (e) => {
35
+ }, E = (e) => {
32
36
  e.settled || e.resolve(!1);
33
- }, T = (e) => {
34
- for (let t = l.length - 1; t >= 0; t--) l[t].owner === e && (w(l[t]), l.splice(t, 1));
37
+ }, D = (e) => {
38
+ for (let t = l.length - 1; t >= 0; t--) l[t].owner === e && (E(l[t]), l.splice(t, 1));
35
39
  let { current: t } = d.value;
36
- t?.owner === e && (w(t), l.length ? C() : D());
37
- }, E = () => {
38
- for (; l.length;) w(l.pop());
40
+ t?.owner === e && (E(t), l.length ? T() : k());
41
+ }, O = () => {
42
+ for (; l.length;) E(l.pop());
39
43
  let { current: e } = d.value;
40
- e && (w(e), D());
41
- }, D = () => {
42
- process.env.NODE_ENV !== "production" && d.value.current && !d.value.current.settled && c.warn("Confirm: close() was called while the current confirm() promise is still pending. The dialog is hidden, but the promise will never settle — resolve it first via the Yes/No buttons or the portal yes()/no() helpers."), clearTimeout(g), d.value.yesBusy = !1, d.value.noBusy = !1, d.value.actionBusy = null, d.value.processing = !1, clearTimeout(_), _ = setTimeout(S, h);
43
- }, O = (e, t) => {
44
+ e && (E(e), k());
45
+ }, k = () => {
46
+ process.env.NODE_ENV !== "production" && d.value.current && !d.value.current.settled && c.warn("Confirm: close() was called while the current confirm() promise is still pending. The dialog is hidden, but the promise will never settle — resolve it first via the Yes/No buttons or the portal yes()/no() helpers."), clearTimeout(g), d.value.yesBusy = !1, d.value.noBusy = !1, d.value.actionBusy = null, d.value.processing = !1, clearTimeout(_), _ = setTimeout(w, h);
47
+ }, A = (e, t) => {
44
48
  typeof e == "number" ? d.value.actionBusy = t ? e : null : e === "yes" ? d.value.yesBusy = t : d.value.noBusy = t;
45
- }, k = async (e, t = !1) => {
49
+ }, j = async (e, t = !1) => {
46
50
  let { current: n } = d.value;
47
- n && (clearTimeout(g), e ? n.yes ? await n.yes.onClick() : A(n, !0) : (t || n.dismissAsNo) && n.no ? await n.no.onClick() : A(n, !1));
48
- }, A = (e, t) => {
49
- e.resolve(t), l.length ? C() : e.autoClose && D();
50
- }, j = (e, t) => {
51
+ n && (clearTimeout(g), e ? n.yes ? await n.yes.onClick() : M(n, !0) : (t || n.dismissAsNo) && n.no ? await n.no.onClick() : M(n, !1));
52
+ }, M = (e, t) => {
53
+ e.resolve(t), l.length ? T() : e.autoClose && k();
54
+ }, N = (e, t) => {
51
55
  if (t === !1) return;
52
56
  if (t === void 0) return e;
53
57
  let n = typeof t == "string" ? { text: t } : t;
@@ -58,12 +62,11 @@ var { t: s } = n(), c = e(), l = [], u = {
58
62
  variant: n.variant ?? e.variant,
59
63
  size: n.size ?? e.size
60
64
  };
61
- }, M = (e, t) => new Promise((n, r) => {
65
+ }, P = (e, t) => new Promise((n, r) => {
62
66
  if (typeof window > "u") {
63
67
  process.env.NODE_ENV !== "production" && console.warn("[BbConfirm] confirm() was called during server-side rendering — resolved `false`. Trigger confirms from client-side code (event handlers)."), n(!1);
64
68
  return;
65
69
  }
66
- process.env.NODE_ENV !== "production" && !y && !b && (b = !0, c.warn("Confirm: confirm() was called but no <BbConfirm> host has ever mounted — the returned promise will never settle because no dialog can render. Mount exactly one <BbConfirm /> at the app root."));
67
70
  let i = (e) => {
68
71
  m.settled = !0, n(e);
69
72
  }, a = (e) => {
@@ -74,18 +77,18 @@ var { t: s } = n(), c = e(), l = [], u = {
74
77
  return {
75
78
  ...e,
76
79
  onClick: async () => {
77
- O(t, !0);
80
+ A(t, !0);
78
81
  let e = n;
79
82
  try {
80
83
  if (r) {
81
84
  let t = await r();
82
85
  d && (e = t);
83
86
  }
84
- i(e), l.length ? C() : u && D();
87
+ i(e), l.length ? T() : u && k();
85
88
  } catch (e) {
86
- a(e), D();
89
+ a(e), k();
87
90
  } finally {
88
- O(t, !1);
91
+ A(t, !1);
89
92
  }
90
93
  }
91
94
  };
@@ -95,16 +98,16 @@ var { t: s } = n(), c = e(), l = [], u = {
95
98
  dismissAsNo: !0,
96
99
  autoClose: !0,
97
100
  ...e,
98
- actions: p ? p.map((e, t) => f(j({
101
+ actions: p ? p.map((e, t) => f(N({
99
102
  size: "md",
100
103
  variant: "outline"
101
104
  }, e), t, !0)) : e.actions,
102
- yes: p ? void 0 : f(j({
105
+ yes: p ? void 0 : f(N({
103
106
  text: s("confirm.ok").value,
104
107
  size: "md",
105
108
  variant: o
106
109
  }, e.yes), "yes", !0),
107
- no: p ? void 0 : f(j({
110
+ no: p ? void 0 : f(N({
108
111
  text: s("confirm.cancel").value,
109
112
  size: "md",
110
113
  variant: "outline"
@@ -114,19 +117,19 @@ var { t: s } = n(), c = e(), l = [], u = {
114
117
  settled: !1,
115
118
  owner: t
116
119
  };
117
- l.push(m), C();
118
- }), N = () => {
120
+ l.push(m), v === 0 && S(() => m.settled), T();
121
+ }), F = () => {
119
122
  if (!r()) return {
120
- confirm: M,
121
- close: D,
122
- dismissAll: E
123
+ confirm: P,
124
+ close: k,
125
+ dismissAll: O
123
126
  };
124
127
  let e = Symbol("bb-confirm-owner");
125
- return i(() => T(e)), {
126
- confirm: (t) => M(t, e),
127
- close: D,
128
- dismissAll: E
128
+ return i(() => D(e)), {
129
+ confirm: (t) => P(t, e),
130
+ close: k,
131
+ dismissAll: O
129
132
  };
130
133
  };
131
134
  //#endregion
132
- export { h as TRANSITION_DURATION, x as __registerConfirmHost, f as confirmState, p as namedPortalRegistry, k as processMessage, m as registerNamedPortal, N as useConfirm };
135
+ export { x as NO_HOST_WARNING_DELAY, h as TRANSITION_DURATION, C as __registerConfirmHost, f as confirmState, p as namedPortalRegistry, j as processMessage, m as registerNamedPortal, F as useConfirm };
@@ -1,5 +1,5 @@
1
1
  import { useMobile as e } from "./useMobile.js";
2
- import { viewportHeight as t, viewportWidth as n } from "./useViewportWidth.js";
2
+ import { viewportClientHeight as t, viewportClientWidth as n } from "./useViewportWidth.js";
3
3
  import { useOffCanvasStack as r } from "../components/BbOffCanvas/useOffCanvasStack.js";
4
4
  import { computed as i, ref as a } from "vue";
5
5
  //#region src/composables/useSafeAreaInternal.ts
@@ -3,6 +3,22 @@ import { BbToast, BbToastDismissReason, BbToastOptions, BbToastPortalContext, Bb
3
3
  export declare const toastState: {
4
4
  toasts: BbToast[];
5
5
  };
6
+ /**
7
+ * Grace period before the zero-host warning fires. See the twin in
8
+ * `useConfirm.ts` for the full rationale — the short version: a host mounted
9
+ * in a layout rather than the app root unmounts and remounts across a route
10
+ * change, and a `toast()` landing in that gap is NOT lost. A late-mounting
11
+ * host renders the queued message (verified), so "no host right now" does not
12
+ * mean "no host is coming".
13
+ *
14
+ * At fire time we re-read the count, so the delay only has to outlast a slow
15
+ * async layout chunk; a generous value is strictly safer than a tight one.
16
+ *
17
+ * Supersedes the 2026-07-30 `hostEverMounted` latch, which went quiet for the
18
+ * whole process once ANY host had ever mounted — silencing exactly the case a
19
+ * non-root host produces.
20
+ */
21
+ export declare const NO_HOST_WARNING_DELAY = 1000;
6
22
  /**
7
23
  * Called by `<BbToast>` on mount. Internal — not re-exported from
8
24
  * `src/index.ts`. Returns the host count including this one (for the
@@ -7,8 +7,12 @@ var r = 300, i = /* @__PURE__ */ new Set([
7
7
  "info",
8
8
  "warning",
9
9
  "destructive"
10
- ]), a = t({ toasts: [] }), o = 0, s = !1, c = !1, l = () => {
11
- o++, s = !0;
10
+ ]), a = t({ toasts: [] }), o = 0, s = !1, c, l = 1e3, u = () => {
11
+ process.env.NODE_ENV === "production" || s || (clearTimeout(c), c = setTimeout(() => {
12
+ s || o > 0 || (s = !0, console.warn("[BbToast] toast() was called but no <BbToast> host is mounted — the toast is queued but nothing will render or expire it. Mount exactly one <BbToast /> at the app root."));
13
+ }, l));
14
+ }, d = () => {
15
+ o++, clearTimeout(c);
12
16
  let e = !1;
13
17
  return {
14
18
  count: o,
@@ -16,9 +20,9 @@ var r = 300, i = /* @__PURE__ */ new Set([
16
20
  e || (e = !0, o--);
17
21
  }
18
22
  };
19
- }, u = t(/* @__PURE__ */ new Map()), d = (e, t) => (u.set(e, t), () => u.delete(e)), f = 0, p = (e) => {
23
+ }, f = t(/* @__PURE__ */ new Map()), p = (e, t) => (f.set(e, t), () => f.delete(e)), m = 0, h = (e) => {
20
24
  if (e.duration !== void 0 && e.duration <= 0) throw Error("Toast duration must be a positive number of milliseconds.");
21
- let t = e.id ?? `bb-toast-${++f}`, n = Date.now(), r = a.toasts.find((e) => e.id === t), i = e.loading ?? r?.loading ?? !1, o = e.persistent ?? i, s, c;
25
+ let t = e.id ?? `bb-toast-${++m}`, n = Date.now(), r = a.toasts.find((e) => e.id === t), i = e.loading ?? r?.loading ?? !1, o = e.persistent ?? i, s, c;
22
26
  o ? (s = Infinity, c = Number.isFinite(r?.duration) ? r?.duration : r?.preLoadingDuration) : e.duration === void 0 ? r && Number.isFinite(r.duration) ? s = r.duration : r && Number.isFinite(r.preLoadingDuration) && (s = r.preLoadingDuration) : s = e.duration;
23
27
  let l = (t) => t in e ? e[t] : r?.[t], u = {
24
28
  id: t,
@@ -39,24 +43,24 @@ var r = 300, i = /* @__PURE__ */ new Set([
39
43
  preLoadingDuration: c
40
44
  };
41
45
  return r ? Object.assign(r, u) : a.toasts.push(u), t;
42
- }, m = (t, n) => {
46
+ }, g = (t, n) => {
43
47
  t.removed || (t.removed = !0, e(r).then(() => {
44
48
  a.toasts = a.toasts.filter((e) => e.id !== t.id);
45
49
  }));
46
- }, h = (e, t = "manual") => {
47
- if (e === void 0) return a.toasts.forEach((e) => m(e, t)), e;
50
+ }, _ = (e, t = "manual") => {
51
+ if (e === void 0) return a.toasts.forEach((e) => g(e, t)), e;
48
52
  let n = a.toasts.find((t) => t.id === e);
49
- return n && m(n, t), e;
50
- }, g = (e, t) => a.toasts.some((t) => t.id === e) ? p({
53
+ return n && g(n, t), e;
54
+ }, v = (e, t) => a.toasts.some((t) => t.id === e) ? h({
51
55
  ...t,
52
56
  id: e
53
- }) : e, _ = (e) => {
57
+ }) : e, y = (e) => {
54
58
  let t = typeof e == "string" ? { title: e } : e;
55
- return typeof window > "u" ? (process.env.NODE_ENV !== "production" && console.warn("[BbToast] toast() was called during server-side rendering — ignored. Trigger toasts from client-side code (onMounted, event handlers)."), t.id ?? "") : (process.env.NODE_ENV !== "production" && !s && !c && (c = !0, console.warn("[BbToast] toast() was called but no <BbToast> host has ever mounted — the toast is queued but nothing will render or expire it. Mount exactly one <BbToast /> at the app root.")), process.env.NODE_ENV !== "production" && !t.title && !t.text && !t.portal && console.warn("[BbToast] A toast was created with no title, text, or portal — it will render empty."), process.env.NODE_ENV !== "production" && t.portal && t.actions && console.warn("[BbToast] A toast carries both `portal` and `actions` — portal content owns the body, so the actions are not rendered. Render the buttons inside the portal instead."), process.env.NODE_ENV !== "production" && t.variant && t.variant !== "default" && i.has(t.variant) && !t.icon && !t.loading && !t.portal && console.warn(`[BbToast] A "${t.variant}" toast was created with no \`icon\` — the variant tints the icon and sets announcement priority, nothing else, so this renders identically to a default toast. Pass a matching \`icon\` (e.g. lucide:circle-check / lucide:circle-x) when the tone should be visible.`), p(t));
56
- }, v = (e, t) => e.position ?? t ?? n.toastPosition ?? "bottom-right", y = () => ({
57
- toast: _,
58
- dismiss: h,
59
- update: g
59
+ return typeof window > "u" ? (process.env.NODE_ENV !== "production" && console.warn("[BbToast] toast() was called during server-side rendering — ignored. Trigger toasts from client-side code (onMounted, event handlers)."), t.id ?? "") : (o === 0 && u(), process.env.NODE_ENV !== "production" && !t.title && !t.text && !t.portal && console.warn("[BbToast] A toast was created with no title, text, or portal — it will render empty."), process.env.NODE_ENV !== "production" && t.portal && t.actions && console.warn("[BbToast] A toast carries both `portal` and `actions` — portal content owns the body, so the actions are not rendered. Render the buttons inside the portal instead."), process.env.NODE_ENV !== "production" && t.variant && t.variant !== "default" && i.has(t.variant) && !t.icon && !t.loading && !t.portal && console.warn(`[BbToast] A "${t.variant}" toast was created with no \`icon\` — the variant tints the icon and sets announcement priority, nothing else, so this renders identically to a default toast. Pass a matching \`icon\` (e.g. lucide:circle-check / lucide:circle-x) when the tone should be visible.`), h(t));
60
+ }, b = (e, t) => e.position ?? t ?? n.toastPosition ?? "bottom-right", x = () => ({
61
+ toast: y,
62
+ dismiss: _,
63
+ update: v
60
64
  });
61
65
  //#endregion
62
- export { l as __registerToastHost, _ as createToast, h as dismissToast, u as namedToastPortalRegistry, d as registerToastPortal, v as resolveToastPosition, a as toastState, g as updateToast, y as useToast };
66
+ export { l as NO_HOST_WARNING_DELAY, d as __registerToastHost, y as createToast, _ as dismissToast, f as namedToastPortalRegistry, p as registerToastPortal, b as resolveToastPosition, a as toastState, v as updateToast, x as useToast };
@@ -16,13 +16,27 @@
16
16
  */
17
17
  export declare const viewportWidth: import('vue').ShallowRef<number>, viewportHeight: import('vue').ShallowRef<number>;
18
18
  /**
19
- * The scrollbar-excluded flavor of the same singleton (documentElement client
20
- * box rather than `innerWidth`/`innerHeight`). `useSafeArea` measures element
21
- * claims against this basis — counting the scrollbar would inflate every
22
- * measured claim by its width. Module-level for the same reason as above: one
23
- * shared `resize` listener per flavor instead of one per component instance.
19
+ * The scrollbar-excluded flavor of the same singleton — the LAYOUT viewport,
20
+ * the box fixed-positioned elements actually reach the edges of. `useSafeArea`
21
+ * measures element claims against this basis: counting the scrollbar would
22
+ * inflate every measured claim by its width. Module-level for the same reason
23
+ * as above: one shared `resize` listener per flavor instead of one per
24
+ * component instance.
25
+ *
26
+ * Width is `documentElement.getBoundingClientRect().width`, NOT
27
+ * `documentElement.clientWidth` (which `useWindowSize({ includeScrollbar:
28
+ * false })` reads). They differ under `scrollbar-gutter: stable` — which the
29
+ * shipped reset sets on `<html>`: Chromium keeps reporting the full width in
30
+ * `clientWidth` while the reserved gutter shrinks the box every fixed element
31
+ * lays out in. Measured 2026-09-09 in a 414px test viewport: `innerWidth` and
32
+ * `clientWidth` 414, a `position: fixed; right: 0` box ending at 399, and
33
+ * every safe-area claim over by exactly those 15px. The root element's own
34
+ * border box is the one measure that tracks the real edge, and unlike
35
+ * `visualViewport` it does not shrink under pinch-zoom. Height stays
36
+ * `clientHeight`: the gutter reserves the inline axis only.
24
37
  */
25
- export declare const viewportClientWidth: import('vue').ShallowRef<number>, viewportClientHeight: import('vue').ShallowRef<number>;
38
+ export declare const viewportClientWidth: import('vue').Ref<number, number>;
39
+ export declare const viewportClientHeight: import('vue').Ref<number, number>;
26
40
  /**
27
41
  * Re-seed every flavor from the live window, so a spec that wrote
28
42
  * `viewportWidth.value` directly cannot leak its width into later specs.
@@ -1,9 +1,10 @@
1
- import { config as e } from "virtual:bitboss-ui/config";
2
- import { useWindowSize as t } from "@vueuse/core";
1
+ import { ref as e } from "vue";
2
+ import { config as t } from "virtual:bitboss-ui/config";
3
+ import { useEventListener as n, useWindowSize as r } from "@vueuse/core";
3
4
  //#region src/composables/useViewportWidth.ts
4
- var { width: n, height: r } = t({ initialWidth: e.ssrViewportWidth }), { width: i, height: a } = t({
5
- initialWidth: e.ssrViewportWidth,
6
- includeScrollbar: !1
7
- });
5
+ var { width: i, height: a } = r({ initialWidth: t.ssrViewportWidth }), o = e(t.ssrViewportWidth), s = e(Infinity), c = () => {
6
+ typeof document > "u" || (o.value = document.documentElement.getBoundingClientRect().width, s.value = document.documentElement.clientHeight);
7
+ };
8
+ typeof window < "u" && (c(), n(window, "resize", c, { passive: !0 }));
8
9
  //#endregion
9
- export { a as viewportClientHeight, i as viewportClientWidth, r as viewportHeight, n as viewportWidth };
10
+ export { s as viewportClientHeight, o as viewportClientWidth, a as viewportHeight, i as viewportWidth };
@@ -0,0 +1,276 @@
1
+ /** Directories never descended into, matched as whole path segments. */
2
+ export declare const ALWAYS_SKIPPED_DIRS: ReadonlySet<string>;
3
+ /**
4
+ * 256 MiB. The cap exists only to keep database dumps and similar out of
5
+ * memory — a real source file is never this large, so it is never skipped.
6
+ */
7
+ export declare const DEFAULT_MAX_FILE_SIZE: number;
8
+ /**
9
+ * From this many files up, the per-file work is spread over worker threads.
10
+ * Each worker brings its own libuv thread pool, so reads, hashes and regex
11
+ * passes run in true parallel — the difference between a cold scan that is
12
+ * felt and one that is not, on a laptop with a slow disk and few cores.
13
+ */
14
+ export declare const DEFAULT_WORKER_THRESHOLD = 1500;
15
+ export declare const SCAN_CACHE_VERSION = 4;
16
+ export interface IconsScannerOptions {
17
+ /**
18
+ * Extra paths or globs scanned IN ADDITION to the project root: a vendor
19
+ * package that ships icon names, a directory outside the root. Relative
20
+ * entries resolve against the root. Additive — the root is always scanned.
21
+ *
22
+ * An entry is explicit, so the always-skip rules (`vendor`, hidden
23
+ * segments, `.gitignore` files ABOVE it) do not apply to the entry itself;
24
+ * they still apply to what lies beneath it.
25
+ */
26
+ include?: string[];
27
+ /**
28
+ * Globs removed from the scan, on top of the built-in skips. Gitignore
29
+ * syntax, matched against the path relative to the root (or to the
30
+ * `include` entry that brought the file in).
31
+ */
32
+ exclude?: string[];
33
+ /**
34
+ * Skip files larger than this many bytes. Only here to keep database
35
+ * dumps out of memory — the default is far above any source file.
36
+ *
37
+ * @defaultValue 268435456 (256 MiB)
38
+ */
39
+ maxFileSize?: number;
40
+ }
41
+ export interface IconScannerConfig {
42
+ /** Absolute Vite root. */
43
+ root: string;
44
+ /** Absolute `build.outDir`; always skipped. */
45
+ outDir: string;
46
+ scanner: IconsScannerOptions;
47
+ /** Installed set prefixes — the only `<prefix>:` sequences looked for. */
48
+ prefixes: readonly string[];
49
+ /** Whether `prefix:name` resolves in an installed set (icons + aliases). */
50
+ resolves: (prefix: string, name: string) => boolean;
51
+ /** Where the per-file cache lives. */
52
+ cacheFile: string;
53
+ /** Everything the cached results depend on besides file content. */
54
+ cacheKey: string;
55
+ /**
56
+ * File count from which worker threads are used (`Infinity` = never,
57
+ * `0` = always). Internal knob — tests force both paths.
58
+ */
59
+ workerThreshold?: number;
60
+ }
61
+ export interface ScanStats {
62
+ /** Files that passed every skip rule and were considered. */
63
+ files: number;
64
+ /** Files whose bytes were actually read. */
65
+ read: number;
66
+ /** Files whose bytes were run through the extractor (hash changed or new). */
67
+ extracted: number;
68
+ /** Files dropped for being binary or over `maxFileSize`. */
69
+ skipped: number;
70
+ /** Milliseconds, wall clock. */
71
+ elapsed: number;
72
+ /** No usable cache existed (first run, or the cache key changed). */
73
+ cold: boolean;
74
+ /** Worker threads the per-file work ran on (0 = main thread). */
75
+ workers: number;
76
+ }
77
+ /**
78
+ * The `<prefix>:<name>` matcher for a prefix list. Longest prefix first so
79
+ * `mdi-light:` never loses to `mdi:`; a name is `[a-z0-9][a-z0-9-]*`, and the
80
+ * prefix must not be the tail of a longer word (`xlucide:eye`).
81
+ */
82
+ export declare function iconLiteralRegExp(prefixes: readonly string[]): RegExp;
83
+ /**
84
+ * Every `prefix:name` candidate in `bytes`, deduplicated, in order of first
85
+ * appearance. One pass over the raw bytes (decoded 1:1 as latin1 — no UTF-8
86
+ * work, no parsing). A trailing dash is dropped so the static fragment of a
87
+ * template literal (`lucide:arrow-${dir}` → `arrow`) is still a candidate:
88
+ * a fragment that resolves costs one small chunk, which is acceptable.
89
+ */
90
+ export declare function extractIconCandidates(bytes: Buffer, regex: RegExp): string[];
91
+ /** True when a null byte sits in the first block — the file is not text. */
92
+ export declare function looksBinary(bytes: Buffer): boolean;
93
+ /** Whether a string carries glob syntax at all. */
94
+ export declare const hasGlobMagic: (pattern: string) => boolean;
95
+ /**
96
+ * A small glob → RegExp for the two places the plugin matches globs against
97
+ * NAMES rather than gitignore paths: `iconWhitelist` entries
98
+ * (`tabler:calendar-*`) and the pattern half of an `include` entry. Supports
99
+ * `*` (no slash), `**` (anything), `?`, `[…]` classes and `{a,b}` alternation.
100
+ */
101
+ export declare function globToRegExp(pattern: string): RegExp;
102
+ /** What a file scan needs to know. Plain data — it crosses the thread boundary. */
103
+ export interface FileScanOptions {
104
+ /** Set prefixes, each with its trailing colon (`lucide:`). */
105
+ needles: string[];
106
+ /** `iconLiteralRegExp(prefixes).source`. */
107
+ regexSource: string;
108
+ maxFileSize: number;
109
+ probeBytes: number;
110
+ }
111
+ export interface FileJob {
112
+ path: string;
113
+ /** The cached entry for this path, if any. */
114
+ prev: {
115
+ size: number;
116
+ mtime: number;
117
+ hash: string;
118
+ } | null;
119
+ }
120
+ export type FileScanResult =
121
+ /** Not a regular file, unreadable, over the cap, or binary. */
122
+ {
123
+ path: string;
124
+ outcome: 'skip';
125
+ read: boolean;
126
+ }
127
+ /** Size and mtime match the cache: bytes not read. */
128
+ | {
129
+ path: string;
130
+ outcome: 'fresh';
131
+ size: number;
132
+ mtime: number;
133
+ }
134
+ /** Read and hashed; the hash matches the cache, extraction skipped. */
135
+ | {
136
+ path: string;
137
+ outcome: 'same';
138
+ size: number;
139
+ mtime: number;
140
+ hash: string;
141
+ }
142
+ /** Read, hashed, extracted: raw candidates, not yet validated. */
143
+ | {
144
+ path: string;
145
+ outcome: 'new';
146
+ size: number;
147
+ mtime: number;
148
+ hash: string;
149
+ candidates: string[];
150
+ };
151
+ type FileInfo = {
152
+ isFile(): boolean;
153
+ size: number;
154
+ mtimeMs: number;
155
+ };
156
+ type FsLike = {
157
+ statSync: (p: string) => FileInfo;
158
+ fstatSync: (fd: number) => FileInfo;
159
+ openSync: (p: string, flags: string) => number;
160
+ readSync: (fd: number, buf: Buffer, offset: number, length: number, position: number) => number;
161
+ closeSync: (fd: number) => void;
162
+ };
163
+ type CryptoLike = {
164
+ hash?: (algorithm: string, data: Buffer, encoding: 'hex') => string;
165
+ createHash: (algorithm: string) => {
166
+ update: (data: Buffer) => {
167
+ digest: (encoding: 'hex') => string;
168
+ };
169
+ };
170
+ };
171
+ /**
172
+ * SYNCHRONOUS on purpose. Measured on a 10k-file project: the promise-based
173
+ * `readFile` costs four thread-pool round trips per file and ran at ~480 ms
174
+ * for the set, `openSync`+`readSync`+`closeSync` at ~190 ms. The blocking is
175
+ * harmless where this runs — inside a worker thread for any project large
176
+ * enough to notice, and for a few hundred files (or one changed file) on the
177
+ * main thread, where it is over before anything else could have run anyway.
178
+ */
179
+ export declare function createFileScanner(fs: FsLike, crypto: CryptoLike, options: FileScanOptions): (job: FileJob) => FileScanResult;
180
+ /**
181
+ * How many workers a machine gets: every core but one, at least two (a
182
+ * dual-core laptop still gains from two threads issuing reads at once — the
183
+ * cold scan is disk-bound, not CPU-bound), at most four.
184
+ */
185
+ export declare function workerCountFor(cores: number): number;
186
+ export declare class IconScanner {
187
+ private readonly cfg;
188
+ /** null when no set is installed — nothing can resolve, nothing is read. */
189
+ private readonly fileOptions;
190
+ private readonly scanOne;
191
+ private readonly workerThreshold;
192
+ private readonly excludes;
193
+ private readonly bases;
194
+ private readonly resolveMemo;
195
+ private readonly gitignoreMemo;
196
+ /** Absolute file path → cached result (the live cache). */
197
+ private entries;
198
+ private cold;
199
+ private dirty;
200
+ private lastWorkers;
201
+ constructor(cfg: IconScannerConfig);
202
+ /** Directories the dev server should watch besides the root. */
203
+ get includeDirs(): string[];
204
+ /** Every provider icon referenced somewhere in the scanned files. */
205
+ get icons(): Set<string>;
206
+ private includeBase;
207
+ private gitignoreFor;
208
+ /** Forget every parsed `.gitignore` — call when one changes on disk. */
209
+ resetGitignores(): void;
210
+ /**
211
+ * Git semantics across levels: the deepest file with a matching rule wins,
212
+ * a negation re-includes, and an ignored DIRECTORY is final for everything
213
+ * beneath it (handled by the walk pruning it).
214
+ */
215
+ private isGitignored;
216
+ private isExcluded;
217
+ /**
218
+ * Whether a directory entry beneath `base` may be entered/read. `chain` is
219
+ * the `.gitignore` chain that applies at the entry's parent.
220
+ */
221
+ private admits;
222
+ /**
223
+ * Whether `abs` would be picked up by a full walk — the dev watcher asks
224
+ * this for every changed path. Applies the same rules, segment by segment,
225
+ * from the base that owns the path.
226
+ */
227
+ isCandidate(abs: string): boolean;
228
+ private walk;
229
+ /** Every file a full scan would read, absolute, deduplicated. */
230
+ collectFiles(): Promise<string[]>;
231
+ private resolvesMemo;
232
+ /**
233
+ * Fold one per-file result into a cache entry, validating fresh
234
+ * candidates against the installed sets. `null` entry = no file to keep.
235
+ */
236
+ private fold;
237
+ /** A cache entry for a path when no set is installed: stat only. */
238
+ private statOnly;
239
+ /**
240
+ * Bring one file's cache entry up to date (the dev watcher path). Returns
241
+ * what happened so stats (and tests) can tell a skipped read from a
242
+ * skipped extraction.
243
+ */
244
+ private scanFile;
245
+ /**
246
+ * Whether a scan of about `expectedFiles` files should use the worker pool.
247
+ */
248
+ private useWorkers;
249
+ /**
250
+ * Every file's result — on the pool when there is one and the project is
251
+ * large enough to make its start-up worth it, else on the main thread. A
252
+ * worker failure of any kind degrades to the main-thread path.
253
+ */
254
+ private scanAll;
255
+ private loadCache;
256
+ /** Full walk + scan. Reuses the on-disk cache, then persists it. */
257
+ scan(): Promise<ScanStats>;
258
+ /**
259
+ * Re-scan ONE file after the watcher saw it change or appear. Returns true
260
+ * when the union of used icons changed — the caller then invalidates the
261
+ * virtual module. A path the rules reject is ignored (and a stale entry for
262
+ * it dropped).
263
+ */
264
+ updateFile(abs: string): Promise<boolean>;
265
+ /** Drop a deleted file. Returns true when the union of used icons changed. */
266
+ removeFile(abs: string): boolean;
267
+ /** Write the cache when something changed since the last write. */
268
+ persist(): Promise<void>;
269
+ }
270
+ /**
271
+ * The cache file: `node_modules/.cache/bitboss-ui/icon-scan.json` under the
272
+ * nearest `node_modules` at or above the root (Nuxt roots at `app/`, which has
273
+ * none of its own), falling back to the root's.
274
+ */
275
+ export declare function iconScanCacheFile(root: string): string;
276
+ export {};