bitboss-ui 3.0.0-alpha.1 → 3.0.0-alpha.4
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.
- package/README.md +31 -4
- package/bin/bitboss-ui-mcp.mjs +123 -18
- package/bin/bitboss-ui.mjs +101 -17
- package/bin/bitboss-ui.node.test.mjs +113 -0
- package/dist/ai/BbAccordion.md +14 -8
- package/dist/ai/BbAlert.md +7 -4
- package/dist/ai/BbAvatar.md +13 -9
- package/dist/ai/BbBadge.md +8 -6
- package/dist/ai/BbBaseButton.md +6 -4
- package/dist/ai/BbBaseCheckbox.md +1 -1
- package/dist/ai/BbBaseCheckboxIcon.md +8 -6
- package/dist/ai/BbBaseColorInput.md +1 -1
- package/dist/ai/BbBaseInputContainer.md +4 -4
- package/dist/ai/BbBaseRadioGroup.md +1 -0
- package/dist/ai/BbBaseRadioIcon.md +11 -7
- package/dist/ai/BbBaseSelect.md +1 -1
- package/dist/ai/BbBaseSwitch.md +1 -1
- package/dist/ai/BbBaseSwitchIcon.md +9 -7
- package/dist/ai/BbBreadcrumbs.md +22 -11
- package/dist/ai/BbButton.md +94 -20
- package/dist/ai/BbCheckbox.md +36 -23
- package/dist/ai/BbCheckboxGroup.md +28 -16
- package/dist/ai/BbCollapsible.md +15 -9
- package/dist/ai/BbColorInput.md +19 -12
- package/dist/ai/BbColorPalette.md +11 -7
- package/dist/ai/BbConfirm.md +69 -22
- package/dist/ai/BbConfirmPortal.md +1 -1
- package/dist/ai/BbDatePickerInput.md +30 -16
- package/dist/ai/BbDialog.md +21 -13
- package/dist/ai/BbDropdown.md +39 -21
- package/dist/ai/BbDropdownButton.md +31 -16
- package/dist/ai/BbDropzone.md +117 -59
- package/dist/ai/BbIcon.md +12 -9
- package/dist/ai/BbIndicator.md +1 -1
- package/dist/ai/BbNumberInput.md +19 -15
- package/dist/ai/BbOffCanvas.md +36 -14
- package/dist/ai/BbPagination.md +19 -13
- package/dist/ai/BbPopover.md +18 -10
- package/dist/ai/BbProgress.md +22 -16
- package/dist/ai/BbRadio.md +19 -10
- package/dist/ai/BbRadioGroup.md +17 -6
- package/dist/ai/BbRating.md +24 -12
- package/dist/ai/BbSelect.md +44 -25
- package/dist/ai/BbSelectPopover.md +27 -11
- package/dist/ai/BbSlider.md +38 -15
- package/dist/ai/BbSmoothHeight.md +24 -11
- package/dist/ai/BbSpinner.md +3 -3
- package/dist/ai/BbSwitch.md +55 -31
- package/dist/ai/BbSwitchGroup.md +37 -19
- package/dist/ai/BbTable.md +55 -22
- package/dist/ai/BbTabs.md +69 -35
- package/dist/ai/BbTag.md +40 -17
- package/dist/ai/BbTextInput.md +47 -21
- package/dist/ai/BbTextarea.md +38 -24
- package/dist/ai/BbTimePickerInput.md +10 -6
- package/dist/ai/BbToast.md +62 -17
- package/dist/ai/BbToastPortal.md +1 -1
- package/dist/ai/BbTooltip.md +16 -6
- package/dist/ai/BbTree.md +21 -11
- package/dist/ai/CommonPopover.md +1 -1
- package/dist/ai/components.json +108 -94
- package/dist/ai/composables/useBbConfig.md +1 -1
- package/dist/ai/composables/useBbTableContext.md +5 -2
- package/dist/ai/composables/useBbTabsContext.md +1 -1
- package/dist/ai/composables/useBroadcastChannelInstance.md +1 -1
- package/dist/ai/composables/useConfirm.md +14 -7
- package/dist/ai/composables/useCountdown.md +8 -6
- package/dist/ai/composables/useToast.md +17 -9
- package/dist/ai/guides/agent-contract.md +58 -1
- package/dist/ai/guides/ai-router.md +13 -11
- package/dist/ai/guides/app-layout.md +34 -11
- package/dist/ai/guides/component-picker.md +47 -6
- package/dist/ai/guides/design-language.md +20 -3
- package/dist/ai/guides/design-tokens.md +27 -1
- package/dist/ai/guides/floating-bottom-panel.md +44 -105
- package/dist/ai/guides/icons-policy.md +1 -1
- package/dist/ai/guides/inertia-helpers.md +57 -8
- package/dist/ai/guides/inline-edit-playbook.md +9 -0
- package/dist/ai/guides/installation-and-plugin-setup.md +68 -5
- package/dist/ai/guides/migration/components/bb-icon.md +1 -1
- package/dist/ai/guides/migration/components/bb-offcanvas.md +28 -19
- package/dist/ai/guides/migration/components/bb-select-popover.md +1 -0
- package/dist/ai/guides/migration/components/bb-select.md +1 -0
- package/dist/ai/guides/migration/v2-to-v3.md +1 -1
- package/dist/ai/guides/page-shell.md +31 -232
- package/dist/ai/guides/validated-forms.md +1 -1
- package/dist/ai/index.md +10 -8
- package/dist/ai/recipes/inertia/approvals-inbox.md +65 -28
- package/dist/ai/recipes/inertia/inline-edit-workspace.md +55 -23
- package/dist/ai/recipes/inertia/layout-scaffold.md +385 -0
- package/dist/ai/recipes/inertia/onboarding.md +60 -34
- package/dist/ai/recipes/inertia/ownership-atlas.md +83 -37
- package/dist/ai/recipes/inertia/record-form.md +78 -31
- package/dist/ai/recipes/inertia/records-workspace.md +118 -30
- package/dist/ai/recipes/inertia/upload-center.md +134 -57
- package/dist/ai/recipes/inertia/wizard-form.md +56 -33
- package/dist/ai/recipes/nuxt/approvals-inbox.md +38 -21
- package/dist/ai/recipes/nuxt/inline-edit-workspace.md +30 -17
- package/dist/ai/recipes/nuxt/layout-scaffold.md +385 -0
- package/dist/ai/recipes/nuxt/onboarding.md +60 -34
- package/dist/ai/recipes/nuxt/record-form.md +76 -30
- package/dist/ai/recipes/nuxt/records-workspace.md +34 -19
- package/dist/ai/recipes/nuxt/upload-center.md +74 -35
- package/dist/ai/recipes/nuxt/wizard-form.md +56 -33
- package/dist/ai/recipes/vue/approvals-inbox.md +38 -21
- package/dist/ai/recipes/vue/inline-edit-workspace.md +29 -16
- package/dist/ai/recipes/vue/layout-scaffold.md +385 -0
- package/dist/ai/recipes/vue/onboarding.md +60 -34
- package/dist/ai/recipes/vue/record-form.md +80 -34
- package/dist/ai/recipes/vue/records-workspace.md +34 -19
- package/dist/ai/recipes/vue/upload-center.md +75 -36
- package/dist/ai/recipes/vue/wizard-form.md +56 -33
- package/dist/ai/source/BbAccordion.md +2 -1
- package/dist/ai/source/BbAlert.md +5 -0
- package/dist/ai/source/BbAvatar.md +2 -0
- package/dist/ai/source/BbBadge.md +1 -1
- package/dist/ai/source/BbBadgeButton.md +1 -1
- package/dist/ai/source/BbBaseCheckbox.md +3 -1
- package/dist/ai/source/BbBaseColorInput.md +6 -3
- package/dist/ai/source/BbBaseColorPalette.md +2 -2
- package/dist/ai/source/BbBaseDatePickerInput.md +4 -0
- package/dist/ai/source/BbBaseInputContainer.md +79 -17
- package/dist/ai/source/BbBaseNumberInput.md +2 -0
- package/dist/ai/source/BbBaseRadioGroup.md +35 -1
- package/dist/ai/source/BbBaseSelect.md +4 -1
- package/dist/ai/source/BbBaseTag.md +7 -1
- package/dist/ai/source/BbBaseTimePickerInput.md +19 -1
- package/dist/ai/source/BbBreadcrumbs.md +4 -0
- package/dist/ai/source/BbButton.md +17 -1
- package/dist/ai/source/BbCheckbox.md +8 -1
- package/dist/ai/source/BbCheckboxGroup.md +8 -1
- package/dist/ai/source/BbCollapsible.md +4 -0
- package/dist/ai/source/BbColorInput.md +8 -1
- package/dist/ai/source/BbColorPalette.md +11 -1
- package/dist/ai/source/BbConfirm.md +21 -1
- package/dist/ai/source/BbDatePicker.md +5 -1
- package/dist/ai/source/BbDatePickerInput.md +8 -1
- package/dist/ai/source/BbDialog.md +6 -0
- package/dist/ai/source/BbDropdown.md +21 -3
- package/dist/ai/source/BbDropdownButton.md +2 -0
- package/dist/ai/source/BbDropdownGroup.md +12 -2
- package/dist/ai/source/BbDropzone.md +120 -5
- package/dist/ai/source/BbIcon.md +4 -2
- package/dist/ai/source/BbIndicator.md +1 -1
- package/dist/ai/source/BbNumberInput.md +10 -1
- package/dist/ai/source/BbOffCanvas.md +6 -0
- package/dist/ai/source/BbPagination.md +6 -0
- package/dist/ai/source/BbPopover.md +15 -8
- package/dist/ai/source/BbRadio.md +10 -1
- package/dist/ai/source/BbRadioGroup.md +21 -2
- package/dist/ai/source/BbRating.md +8 -1
- package/dist/ai/source/BbSelect.md +8 -1
- package/dist/ai/source/BbSelectPopover.md +32 -7
- package/dist/ai/source/BbSlider.md +8 -1
- package/dist/ai/source/BbSmoothHeight.md +4 -0
- package/dist/ai/source/BbTable.md +86 -1
- package/dist/ai/source/BbTag.md +8 -1
- package/dist/ai/source/BbTextInput.md +8 -1
- package/dist/ai/source/BbTextarea.md +8 -1
- package/dist/ai/source/BbTimePicker.md +5 -1
- package/dist/ai/source/BbTimePickerInput.md +11 -2
- package/dist/ai/source/BbToast.md +14 -13
- package/dist/ai/source/BbTooltip.md +14 -0
- package/dist/ai/source/BbTree.md +4 -0
- package/dist/ai/source/CommonPopover.md +10 -0
- package/dist/alert-variants.d.ts +7 -0
- package/dist/assets/css/reset.css_inline.js +1 -1
- package/dist/badge-variants.d.ts +7 -6
- package/dist/button-variants.d.ts +7 -1
- package/dist/components/BbAccordion/types.d.ts +2 -1
- package/dist/components/BbAlert/types.d.ts +5 -0
- package/dist/components/BbAvatar/types.d.ts +2 -0
- package/dist/components/BbBadge/types.d.ts +1 -1
- package/dist/components/BbBaseButton/RouterComponent.vue_vue_type_script_setup_true_lang.js +13 -12
- package/dist/components/BbBaseCheckbox/types.d.ts +3 -1
- package/dist/components/BbBaseColorInput/types.d.ts +6 -3
- package/dist/components/BbBaseColorPalette/types.d.ts +2 -2
- package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue_vue_type_script_setup_true_lang.js +123 -120
- package/dist/components/BbBaseDatePickerInput/types.d.ts +2 -0
- package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue_vue_type_script_setup_true_lang.js +55 -48
- package/dist/components/BbBaseInputContainer/types.d.ts +18 -6
- package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue_vue_type_script_setup_true_lang.js +4 -0
- package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue_vue_type_script_setup_true_lang.js +60 -55
- package/dist/components/BbBaseRadioGroup/types.d.ts +8 -0
- package/dist/components/BbBaseSelect/types.d.ts +4 -1
- package/dist/components/BbBaseTag/BbBaseTag.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue_vue_type_script_setup_true_lang.js +117 -112
- package/dist/components/BbBreadcrumbs/types.d.ts +4 -0
- package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +49 -45
- package/dist/components/BbCheckbox/types.d.ts +8 -1
- package/dist/components/BbCheckboxGroup/types.d.ts +8 -1
- package/dist/components/BbCollapsible/types.d.ts +4 -0
- package/dist/components/BbColorInput/types.d.ts +8 -1
- package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +44 -43
- package/dist/components/BbColorPalette/types.d.ts +6 -0
- package/dist/components/BbConfirm/BbConfirm.vue_vue_type_script_setup_true_lang.js +70 -62
- package/dist/components/BbDatePicker/types.d.ts +5 -1
- package/dist/components/BbDatePickerInput/types.d.ts +8 -1
- package/dist/components/BbDialog/BbDialog.vue.d.ts +6 -0
- package/dist/components/BbDropdown/AdaptiveDropdown.vue.d.ts +6 -0
- package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +221 -220
- package/dist/components/BbDropdown/BbDropdownList.vue.d.ts +5 -1
- package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +191 -185
- package/dist/components/BbDropdown/types.d.ts +12 -2
- package/dist/components/BbDropdownButton/types.d.ts +2 -0
- package/dist/components/BbDropzone/BbDropzone.vue_vue_type_script_setup_true_lang.js +140 -116
- package/dist/components/BbDropzone/types.d.ts +22 -1
- package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/BbIndicator/types.d.ts +1 -1
- package/dist/components/BbNumberInput/types.d.ts +10 -1
- package/dist/components/BbOffCanvas/BbOffCanvas.vue.d.ts +6 -0
- package/dist/components/BbPagination/BbPagination.vue.d.ts +6 -0
- package/dist/components/BbPopover/BbPopover.vue.d.ts +6 -0
- package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +116 -117
- package/dist/components/BbPopover/types.d.ts +6 -0
- package/dist/components/BbRadio/types.d.ts +10 -1
- package/dist/components/BbRadioGroup/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +29 -27
- package/dist/components/BbRadioGroup/types.d.ts +8 -1
- package/dist/components/BbRating/types.d.ts +8 -1
- package/dist/components/BbSelect/types.d.ts +8 -1
- package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +334 -332
- package/dist/components/BbSelectPopover/types.d.ts +8 -3
- package/dist/components/BbSlider/types.d.ts +8 -1
- package/dist/components/BbSmoothHeight/types.d.ts +4 -0
- package/dist/components/BbTable/BbTable.vue.d.ts +5 -0
- package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +383 -372
- package/dist/components/BbTable/types.d.ts +37 -0
- package/dist/components/BbTag/types.d.ts +8 -1
- package/dist/components/BbTextInput/types.d.ts +8 -1
- package/dist/components/BbTextarea/types.d.ts +8 -1
- package/dist/components/BbTimePicker/types.d.ts +5 -1
- package/dist/components/BbTimePickerInput/types.d.ts +11 -2
- package/dist/components/BbToast/BbToast.vue_vue_type_script_setup_true_lang.js +23 -19
- package/dist/components/BbTooltip/BbTooltip.vue.d.ts +6 -0
- package/dist/components/BbTooltip/types.d.ts +8 -0
- package/dist/components/BbTree/BbTree.vue.d.ts +2 -0
- package/dist/components/BbTree/types.d.ts +2 -0
- package/dist/components/CommonPopover/CommonPopover.vue.d.ts +6 -0
- package/dist/components/CommonPopover/types.d.ts +4 -0
- package/dist/components/Transitions/ScaleFade.vue.d.ts +2 -2
- package/dist/components/Transitions/Slide.vue.d.ts +15 -0
- package/dist/components/Transitions/Slide.vue.js +1 -1
- package/dist/composables/useBbTabsContext.js +38 -32
- package/dist/composables/useClosingInert.d.ts +28 -0
- package/dist/composables/useClosingInert.js +23 -0
- package/dist/composables/useConfirm.d.ts +25 -5
- package/dist/composables/useConfirm.js +61 -53
- package/dist/composables/useSegmentedFields.d.ts +2 -1
- package/dist/composables/useSegmentedFields.js +82 -75
- package/dist/composables/useToast.d.ts +26 -0
- package/dist/composables/useToast.js +22 -13
- package/dist/confirm-variants.d.ts +7 -0
- package/dist/deprecation/ai-deprecations.json.d.ts +1 -1
- package/dist/deprecation/ai-deprecations.json.js +1 -1
- package/dist/directives/createPopoverDirective.js +2 -3
- package/dist/dropdown-item-variants.d.ts +7 -0
- package/dist/index.d.ts +5 -3
- package/dist/indicator-variants.d.ts +7 -0
- package/dist/llms-full.txt +4423 -1793
- package/dist/llms-medium.txt +206 -26
- package/dist/llms.txt +9 -7
- package/dist/locale-registry.d.ts +37 -0
- package/dist/reset.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/toast-variants.d.ts +7 -0
- package/dist/tooltip-variants.d.ts +7 -0
- package/dist/types/CommonProps.d.ts +4 -0
- package/dist/validated/BbCheckbox.vue.d.ts +3 -3
- package/dist/validated/BbCheckbox.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/validated/BbCheckboxGroup.vue.d.ts +2 -2
- package/dist/validated/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +10 -4
- package/dist/validated/BbColorInput.vue.d.ts +2 -2
- package/dist/validated/BbColorInput.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/validated/BbDatePickerInput.vue.d.ts +3 -2
- package/dist/validated/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/validated/BbDropzone.vue.d.ts +2 -2
- package/dist/validated/BbDropzone.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/validated/BbNumberInput.vue.d.ts +2 -2
- package/dist/validated/BbNumberInput.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/validated/BbRadioGroup.vue.d.ts +2 -2
- package/dist/validated/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/validated/BbRating.vue.d.ts +2 -2
- package/dist/validated/BbRating.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/validated/BbSelect.vue.d.ts +2 -2
- package/dist/validated/BbSelect.vue_vue_type_script_setup_true_lang.js +14 -5
- package/dist/validated/BbSlider.vue.d.ts +2 -2
- package/dist/validated/BbSlider.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/validated/BbSwitch.vue.d.ts +3 -3
- package/dist/validated/BbSwitch.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/validated/BbSwitchGroup.vue.d.ts +2 -2
- package/dist/validated/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +10 -4
- package/dist/validated/BbTag.vue.d.ts +2 -2
- package/dist/validated/BbTag.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/validated/BbTextInput.vue.d.ts +2 -2
- package/dist/validated/BbTextInput.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/validated/BbTextarea.vue.d.ts +2 -2
- package/dist/validated/BbTextarea.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/validated/BbTimePickerInput.vue.d.ts +3 -2
- package/dist/validated/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/validated/useValidatedField.d.ts +43 -2
- package/dist/vite-plugin.d.ts +44 -0
- package/dist/vite.js +177 -104
- package/llms.txt +9 -7
- package/package.json +32 -13
- package/scripts/lib/eslint-plugin-recommended.node.test.mjs +87 -0
- package/scripts/lib/eslint-plugin-slots.node.test.mjs +271 -0
- package/scripts/lib/eslint-plugin.mjs +422 -5
- package/scripts/lib/eslint-plugin.node.test.mjs +32 -0
- package/scripts/lib/validate-bb-markup.mjs +69 -2
- package/dist/ai/guides/migration/components/bb-off-canvas.md +0 -25
package/README.md
CHANGED
|
@@ -70,7 +70,7 @@ For most **Base\*** and **Bb\*** components, the package exports matching **prop
|
|
|
70
70
|
|
|
71
71
|
The same knowledge base the npm package ships is served publicly over a CDN, so
|
|
72
72
|
an agent can read it before anything is installed. `@alpha` tracks the latest
|
|
73
|
-
v3 prerelease; pin an exact version (`bitboss-ui@3.0.0-alpha.
|
|
73
|
+
v3 prerelease; pin an exact version (`bitboss-ui@3.0.0-alpha.4`) for stable
|
|
74
74
|
links.
|
|
75
75
|
|
|
76
76
|
- [Core knowledge base](https://cdn.jsdelivr.net/npm/bitboss-ui@alpha/dist/llms-medium.txt) (~74 KB) — **start here if you can only fetch one file.** Hard rules, setup, component picker, design language, and the full component catalogue.
|
|
@@ -94,18 +94,25 @@ This package is developed and maintained by [BitBoss](https://www.bitboss.it/),
|
|
|
94
94
|
|
|
95
95
|
## Installation
|
|
96
96
|
|
|
97
|
+
**v3 is a prerelease: the `@alpha` tag is required.** A bare
|
|
98
|
+
`npm install bitboss-ui` resolves to the v2 line, which has no build plugin and
|
|
99
|
+
no `dist/ai` knowledge base — if you are following the v3 docs, that install
|
|
100
|
+
will not work.
|
|
101
|
+
|
|
97
102
|
```bash
|
|
98
|
-
npm install bitboss-ui
|
|
103
|
+
npm install bitboss-ui@alpha
|
|
99
104
|
```
|
|
100
105
|
|
|
101
106
|
```bash
|
|
102
|
-
pnpm add bitboss-ui
|
|
107
|
+
pnpm add bitboss-ui@alpha
|
|
103
108
|
```
|
|
104
109
|
|
|
105
110
|
```bash
|
|
106
|
-
yarn add bitboss-ui
|
|
111
|
+
yarn add bitboss-ui@alpha
|
|
107
112
|
```
|
|
108
113
|
|
|
114
|
+
Verify with `npm ls bitboss-ui` — it must report `3.0.0-alpha.*`.
|
|
115
|
+
|
|
109
116
|
---
|
|
110
117
|
|
|
111
118
|
## Quick start
|
|
@@ -236,13 +243,33 @@ manifest checks as `bitboss-ui check`, so editor, CLI, and CI agree. It reuses
|
|
|
236
243
|
your existing `vue-eslint-parser` setup (from `eslint-plugin-vue`) and no-ops on
|
|
237
244
|
non-Vue files.
|
|
238
245
|
|
|
246
|
+
**Needs the TypeScript parser wired for `.ts` and `.vue`.** This library is
|
|
247
|
+
TS-first — recipes ship `<script setup lang="ts">`, some with `generic="T"` —
|
|
248
|
+
and without the two blocks below, `vue-eslint-parser` throws a `Parsing error`
|
|
249
|
+
on those files. A parsing error means **no rule runs on that file at all**,
|
|
250
|
+
`no-unknown-attributes` included, so the safety net silently goes dark on
|
|
251
|
+
exactly the files it matters most for.
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
npm i -D @typescript-eslint/parser
|
|
255
|
+
```
|
|
256
|
+
|
|
239
257
|
```js
|
|
240
258
|
// eslint.config.js (flat config)
|
|
241
259
|
import vue from 'eslint-plugin-vue';
|
|
260
|
+
import tsParser from '@typescript-eslint/parser';
|
|
242
261
|
import bitbossUi from 'bitboss-ui/eslint-plugin';
|
|
243
262
|
|
|
244
263
|
export default [
|
|
245
264
|
...vue.configs['flat/recommended'],
|
|
265
|
+
{
|
|
266
|
+
files: ['**/*.ts'],
|
|
267
|
+
languageOptions: { parser: tsParser },
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
files: ['**/*.vue'],
|
|
271
|
+
languageOptions: { parserOptions: { parser: tsParser } },
|
|
272
|
+
},
|
|
246
273
|
...bitbossUi.configs.recommended, // enables no-unknown-attributes on **/*.vue
|
|
247
274
|
];
|
|
248
275
|
```
|
package/bin/bitboss-ui-mcp.mjs
CHANGED
|
@@ -81,7 +81,8 @@ function searchComponents({ query, limit, includeReferenceOnly } = {}) {
|
|
|
81
81
|
const needle = String(query ?? '')
|
|
82
82
|
.toLowerCase()
|
|
83
83
|
.trim();
|
|
84
|
-
const max =
|
|
84
|
+
const max =
|
|
85
|
+
Number.isFinite(limit) && limit > 0 ? limit : SEARCH_DEFAULT_LIMIT;
|
|
85
86
|
|
|
86
87
|
// Consumer-first: reference-only internals are excluded unless explicitly
|
|
87
88
|
// requested — recommending them is an agent-contract violation.
|
|
@@ -198,13 +199,83 @@ function getComponent({ name, maxChars } = {}) {
|
|
|
198
199
|
/** Shipped stylesheet that carries every resolved `--bb-*` theme token. */
|
|
199
200
|
const STYLES_CSS = join(PACKAGE_ROOT, 'dist', 'styles.css');
|
|
200
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Selectors that carry a THEME value rather than a component-local rebind:
|
|
204
|
+
* the root scopes a consumer themes on. A selector list qualifies only when
|
|
205
|
+
* every comma-part is built solely from these — `:root`, `.light`, `:root.dark`
|
|
206
|
+
* and `html.dark` are theme roots; `.bb-tooltip .bb-common-popover__bubble` is
|
|
207
|
+
* not, however many `--bb-*` it redeclares.
|
|
208
|
+
*/
|
|
209
|
+
const THEME_ROOT_PART = /^(?::root|html|body|\.light|\.dark)+$/;
|
|
210
|
+
function isThemeSelector(selector) {
|
|
211
|
+
return selector
|
|
212
|
+
.split(',')
|
|
213
|
+
.every((part) =>
|
|
214
|
+
THEME_ROOT_PART.test(part.replace(/[\s>+~]+/g, '').trim())
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Walk a stylesheet and yield every `--bb-*` declaration WITH the selector that
|
|
220
|
+
* owns it. A flat regex cannot do this: it sees a declaration but not its
|
|
221
|
+
* scope, so a component that locally rebinds a theme token is indistinguishable
|
|
222
|
+
* from the dark theme redefining it. Brace-depth scanning (quote-aware, and
|
|
223
|
+
* tolerant of the missing final semicolon that minified CSS emits) is the
|
|
224
|
+
* cheapest way to keep the scope — and this file ships in the package, so it
|
|
225
|
+
* may not reach for postcss the way the dev-only `check:tokens` script does.
|
|
226
|
+
*/
|
|
227
|
+
function* eachTokenDeclaration(css) {
|
|
228
|
+
const stack = [];
|
|
229
|
+
let buffer = '';
|
|
230
|
+
let quote = null;
|
|
231
|
+
const declaration = () => {
|
|
232
|
+
const m = buffer.match(/(--bb-[a-z0-9-]+)\s*:\s*([\s\S]+)/);
|
|
233
|
+
buffer = '';
|
|
234
|
+
return m ? { name: m[1], value: m[2].trim() } : null;
|
|
235
|
+
};
|
|
236
|
+
for (const char of css) {
|
|
237
|
+
if (quote) {
|
|
238
|
+
buffer += char;
|
|
239
|
+
if (char === quote) quote = null;
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (char === '"' || char === "'") {
|
|
243
|
+
quote = char;
|
|
244
|
+
buffer += char;
|
|
245
|
+
} else if (char === '{') {
|
|
246
|
+
stack.push(buffer.trim());
|
|
247
|
+
buffer = '';
|
|
248
|
+
} else if (char === '}' || char === ';') {
|
|
249
|
+
const decl = declaration();
|
|
250
|
+
if (decl) yield { ...decl, selector: stack[stack.length - 1] ?? '' };
|
|
251
|
+
if (char === '}') stack.pop();
|
|
252
|
+
} else {
|
|
253
|
+
buffer += char;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
201
258
|
/**
|
|
202
259
|
* `list_tokens({ filter })` — the `--bb-*` design tokens with their values,
|
|
203
|
-
* read from the shipped stylesheet (the same
|
|
260
|
+
* read from the shipped stylesheet (the same 89 `check:tokens` counts).
|
|
261
|
+
*
|
|
262
|
+
* WHY ONLY `--bb-*` — and why there is no opt-in for the unprefixed ones, even
|
|
263
|
+
* though `search_components` has `includeReferenceOnly`. The two tiers are not
|
|
264
|
+
* the same kind of thing. `--bb-*` is a flat, global, consumer-settable
|
|
265
|
+
* contract. Unprefixed component tokens are *sealed to the file that consumes
|
|
266
|
+
* them* (`check:tokens` rule 3), so the same name means different things in
|
|
267
|
+
* different components and is only meaningful inside that component's scope.
|
|
268
|
+
* Serving them as one flat list would invite exactly the wrong move — an agent
|
|
269
|
+
* writing `:root { --gap: … }` and wondering why nothing changed. They are
|
|
270
|
+
* documented per component, which `get_component` already serves.
|
|
271
|
+
*
|
|
272
|
+
* WHY `dist/styles.css` AND NOT `src/assets/css/variables.css`: `src/` is not
|
|
273
|
+
* in the published package, so the source file does not exist for the consumer
|
|
274
|
+
* this server runs inside. The shipped sheet also carries *resolved* values.
|
|
204
275
|
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
276
|
+
* There is no `limit`/`maxChars` here by design: the whole set is ~9 KB, and a
|
|
277
|
+
* half-list of tokens is the same failure as a half-list of props — it makes an
|
|
278
|
+
* agent invent the missing ones.
|
|
208
279
|
*/
|
|
209
280
|
function listTokens({ filter } = {}) {
|
|
210
281
|
if (!existsSync(STYLES_CSS)) {
|
|
@@ -216,12 +287,18 @@ function listTokens({ filter } = {}) {
|
|
|
216
287
|
}
|
|
217
288
|
const css = readFileSync(STYLES_CSS, 'utf-8');
|
|
218
289
|
const byName = new Map();
|
|
219
|
-
for (const
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
290
|
+
for (const { name, value, selector } of eachTokenDeclaration(css)) {
|
|
291
|
+
const entry = byName.get(name) ?? { theme: [], local: [] };
|
|
292
|
+
if (isThemeSelector(selector)) {
|
|
293
|
+
// Light first, dark after: report both rather than let one win.
|
|
294
|
+
if (!entry.theme.includes(value)) entry.theme.push(value);
|
|
295
|
+
} else if (!entry.local.some((r) => r.selector === selector)) {
|
|
296
|
+
// A component rebinding a theme token for its own subtree. Reporting
|
|
297
|
+
// this as a `themeOverride` is a lie an agent acts on — it reads
|
|
298
|
+
// `--bb-arrow: 0` as "the dark theme hides arrows".
|
|
299
|
+
entry.local.push({ selector, value });
|
|
300
|
+
}
|
|
301
|
+
byName.set(name, entry);
|
|
225
302
|
}
|
|
226
303
|
const needle = String(filter ?? '')
|
|
227
304
|
.toLowerCase()
|
|
@@ -229,16 +306,20 @@ function listTokens({ filter } = {}) {
|
|
|
229
306
|
const tokens = [...byName.entries()]
|
|
230
307
|
.filter(([name]) => !needle || name.toLowerCase().includes(needle))
|
|
231
308
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
232
|
-
.map(([name,
|
|
309
|
+
.map(([name, { theme, local }]) => ({
|
|
233
310
|
name,
|
|
234
|
-
value:
|
|
235
|
-
...(
|
|
311
|
+
value: theme[0],
|
|
312
|
+
...(theme.length > 1 ? { themeOverrides: theme.slice(1) } : {}),
|
|
313
|
+
...(local.length > 0 ? { localRebinds: local } : {}),
|
|
236
314
|
}));
|
|
237
315
|
return {
|
|
238
316
|
count: tokens.length,
|
|
239
317
|
...(needle ? { filter: needle } : { total: byName.size }),
|
|
240
318
|
tokens,
|
|
241
|
-
hint:
|
|
319
|
+
hint:
|
|
320
|
+
needle && tokens.length === 0
|
|
321
|
+
? `No token name contains '${needle}'. Call list_tokens with no filter for all ${byName.size} — the names are semantic (primary/danger/panel/text/border/radius/…), not literal colours.`
|
|
322
|
+
: 'Theme tokens are set by the consumer app (e.g. on :root / .dark); `themeOverrides` is the dark-theme value. `localRebinds` is a component rebinding the token inside its own subtree — not something to copy. Component-level unprefixed tokens are documented per component; see the design-tokens guide via get_guide.',
|
|
242
323
|
};
|
|
243
324
|
}
|
|
244
325
|
|
|
@@ -248,7 +329,8 @@ function collectGuidePaths(dir, prefix = '') {
|
|
|
248
329
|
if (!existsSync(dir)) return out;
|
|
249
330
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
250
331
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
251
|
-
if (entry.isDirectory())
|
|
332
|
+
if (entry.isDirectory())
|
|
333
|
+
out.push(...collectGuidePaths(join(dir, entry.name), rel));
|
|
252
334
|
else if (entry.name.endsWith('.md')) out.push(rel);
|
|
253
335
|
}
|
|
254
336
|
return out;
|
|
@@ -269,7 +351,11 @@ function getGuide({ name, maxChars } = {}) {
|
|
|
269
351
|
const rel = String(name ?? '').replace(/^\/+/, '');
|
|
270
352
|
// Contain reads to the guides dir — no traversal out of the knowledge base.
|
|
271
353
|
if (!rel || rel.includes('..')) {
|
|
272
|
-
return {
|
|
354
|
+
return {
|
|
355
|
+
found: false,
|
|
356
|
+
error: `Invalid guide name '${name}'.`,
|
|
357
|
+
hint: 'Call list_guides for the available names.',
|
|
358
|
+
};
|
|
273
359
|
}
|
|
274
360
|
const fileName = rel.endsWith('.md') ? rel : `${rel}.md`;
|
|
275
361
|
const guidesDir = join(AI_ROOT, 'guides');
|
|
@@ -384,7 +470,7 @@ function buildServer() {
|
|
|
384
470
|
'search_components',
|
|
385
471
|
{
|
|
386
472
|
description:
|
|
387
|
-
|
|
473
|
+
'Search the bitboss-ui component manifest by name and description, ranked by relevance (exact/prefix name matches first, description matches last). Returns consumer-API components only by default. Use this to find the right Bb* component before writing usage code.',
|
|
388
474
|
inputSchema: {
|
|
389
475
|
query: z
|
|
390
476
|
.string()
|
|
@@ -550,6 +636,25 @@ export async function main() {
|
|
|
550
636
|
|
|
551
637
|
export const start = main;
|
|
552
638
|
|
|
639
|
+
/**
|
|
640
|
+
* The knowledge-base half, exported for in-process callers that want the same
|
|
641
|
+
* answers an MCP client gets without paying for a subprocess and a handshake —
|
|
642
|
+
* today, `scripts/run-eval-agent.mjs`, which hands these to a model as tools so
|
|
643
|
+
* the benchmark measures the knowledge base this server actually serves. Pure
|
|
644
|
+
* functions of the installed `dist/`: no transport, no state, safe to call
|
|
645
|
+
* concurrently. Importing this module does not start a server.
|
|
646
|
+
*/
|
|
647
|
+
export {
|
|
648
|
+
searchComponents,
|
|
649
|
+
getComponent,
|
|
650
|
+
listTokens,
|
|
651
|
+
listGuides,
|
|
652
|
+
getGuide,
|
|
653
|
+
listRecipes,
|
|
654
|
+
getRecipe,
|
|
655
|
+
validateCode,
|
|
656
|
+
};
|
|
657
|
+
|
|
553
658
|
const isDirectRun =
|
|
554
659
|
process.argv[1] && import.meta.url === `file://${process.argv[1]}`;
|
|
555
660
|
if (isDirectRun) {
|
package/bin/bitboss-ui.mjs
CHANGED
|
@@ -370,33 +370,79 @@ export default ${localeObjectLiteral(template)} satisfies LocaleOverrides;
|
|
|
370
370
|
console.log(` ${dayjsHint}`);
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
-
|
|
373
|
+
// SNT-007: a bare-segment skip list of `node_modules`/`dist`/`.git` let a
|
|
374
|
+
// default (no-glob) `check` sweep straight through a Laravel-style consumer's
|
|
375
|
+
// `vendor/`, `storage/`, and `public/` trees — hundreds of vendored
|
|
376
|
+
// `README.md`s outnumbering the app's own `.vue`/`.md` files 20:1. These are
|
|
377
|
+
// all directories no project authors `Bb*` markup into, so they're safe
|
|
378
|
+
// blanket exclusions; framework build caches (`.nuxt`, `.output`) get the
|
|
379
|
+
// same treatment.
|
|
380
|
+
const CHECK_SKIP_DIRS = new Set([
|
|
381
|
+
'node_modules',
|
|
382
|
+
'dist',
|
|
383
|
+
'.git',
|
|
384
|
+
'vendor',
|
|
385
|
+
'storage',
|
|
386
|
+
'public',
|
|
387
|
+
'.output',
|
|
388
|
+
'.nuxt',
|
|
389
|
+
]);
|
|
390
|
+
// Composite (multi-segment) skips: too narrow to earn a bare-segment entry —
|
|
391
|
+
// skipping all of `bootstrap/` would also hide a project's own
|
|
392
|
+
// `bootstrap/*.md` — but `bootstrap/cache` specifically is Laravel's compiled
|
|
393
|
+
// config/routes cache, never hand-authored.
|
|
394
|
+
const CHECK_SKIP_SUBPATHS = ['bootstrap/cache'];
|
|
374
395
|
const CHECK_EXTENSIONS = ['.vue', '.md'];
|
|
375
396
|
|
|
376
|
-
/** True when
|
|
397
|
+
/** True when a path segment (by itself) is a directory `check` never descends into. */
|
|
398
|
+
function isSkippedSegment(name) {
|
|
399
|
+
return CHECK_SKIP_DIRS.has(name);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** True when the relative path IS, or falls under, a skipped multi-segment subpath. */
|
|
403
|
+
function isSkippedSubpath(relPath) {
|
|
404
|
+
const normalized = relPath.split(/[\\/]/).join('/');
|
|
405
|
+
return CHECK_SKIP_SUBPATHS.some(
|
|
406
|
+
(sub) => normalized === sub || normalized.startsWith(`${sub}/`)
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** True when any path segment (or composite subpath) is skipped. */
|
|
377
411
|
function inSkippedDir(relPath) {
|
|
378
|
-
return
|
|
412
|
+
return (
|
|
413
|
+
relPath.split(/[\\/]/).some((segment) => isSkippedSegment(segment)) ||
|
|
414
|
+
isSkippedSubpath(relPath)
|
|
415
|
+
);
|
|
379
416
|
}
|
|
380
417
|
|
|
381
418
|
/**
|
|
382
|
-
* Every `.vue`/`.md` file under `dir`, excluding
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
419
|
+
* Every `.vue`/`.md` file under `dir`, excluding the skip list (see
|
|
420
|
+
* `CHECK_SKIP_DIRS`/`CHECK_SKIP_SUBPATHS`) at any depth. A hand-rolled
|
|
421
|
+
* recursive walk rather than `globSync` because glob's `**` never traverses
|
|
422
|
+
* dot-directories (and there is no `dot` option) — the sweep must keep
|
|
423
|
+
* matching files like `.github/copilot-instructions.md`. Pruning skipped
|
|
424
|
+
* directories BEFORE descending (rather than filtering after a flat
|
|
425
|
+
* `recursive: true` readdir) is what keeps a multi-thousand-file `vendor/`
|
|
426
|
+
* tree from being walked at all.
|
|
386
427
|
*/
|
|
387
|
-
function collectCheckFiles(dir) {
|
|
428
|
+
function collectCheckFiles(dir, relBase = dir) {
|
|
388
429
|
let entries;
|
|
389
430
|
try {
|
|
390
|
-
entries = readdirSync(dir, {
|
|
431
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
391
432
|
} catch {
|
|
392
433
|
return [];
|
|
393
434
|
}
|
|
394
435
|
const out = [];
|
|
395
436
|
for (const entry of entries) {
|
|
437
|
+
const full = join(dir, entry.name);
|
|
438
|
+
if (entry.isDirectory()) {
|
|
439
|
+
if (isSkippedSegment(entry.name)) continue;
|
|
440
|
+
if (isSkippedSubpath(relative(relBase, full))) continue;
|
|
441
|
+
out.push(...collectCheckFiles(full, relBase));
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
396
444
|
if (!entry.isFile()) continue;
|
|
397
445
|
if (!CHECK_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) continue;
|
|
398
|
-
const full = join(entry.parentPath, entry.name);
|
|
399
|
-
if (inSkippedDir(relative(dir, full))) continue;
|
|
400
446
|
out.push(full);
|
|
401
447
|
}
|
|
402
448
|
return out;
|
|
@@ -404,10 +450,16 @@ function collectCheckFiles(dir) {
|
|
|
404
450
|
|
|
405
451
|
/**
|
|
406
452
|
* Resolve the file list for `check`: explicit globs/paths if given, otherwise
|
|
407
|
-
* every `.vue`/`.md` file under `cwd` (excluding
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
*
|
|
453
|
+
* every `.vue`/`.md` file under `cwd` (excluding `CHECK_SKIP_DIRS`/
|
|
454
|
+
* `CHECK_SKIP_SUBPATHS` — node_modules, dist, .git, vendor, storage, public,
|
|
455
|
+
* .output, .nuxt, bootstrap/cache). Literal paths resolve directly: a literal
|
|
456
|
+
* FILE is always included (even one that lives inside a skipped dir — asking
|
|
457
|
+
* for it by name is the widen-the-scan escape hatch), a literal DIRECTORY is
|
|
458
|
+
* swept recursively and only its descendants are checked against the skip
|
|
459
|
+
* list (so `check vendor/some-pkg` still works even though a bare sweep would
|
|
460
|
+
* never enter `vendor/` on its own). Glob patterns (`*`, `**`, `?`, `{a,b}`)
|
|
461
|
+
* go through `node:fs` globSync, restricted to `.vue`/`.md` outside the
|
|
462
|
+
* skipped dirs.
|
|
411
463
|
*/
|
|
412
464
|
function resolveCheckFiles(cwd, patterns) {
|
|
413
465
|
if (patterns.length === 0) return collectCheckFiles(cwd).sort();
|
|
@@ -450,6 +502,36 @@ function resolveCheckFiles(cwd, patterns) {
|
|
|
450
502
|
return [...matched].sort();
|
|
451
503
|
}
|
|
452
504
|
|
|
505
|
+
/**
|
|
506
|
+
* `4 .vue + 8 .md` — a plain file count on its own ("715 file(s)") reads as
|
|
507
|
+
* "715 files carefully checked" when SNT-007 showed it can just as easily be
|
|
508
|
+
* "701 vendored READMEs + 14 real files"; splitting by extension makes the
|
|
509
|
+
* number honest about what was actually covered. `.vue`/`.md` sort first
|
|
510
|
+
* (the extensions `check` targets by default); any other extension a literal
|
|
511
|
+
* path argument pulled in — see `resolveCheckFiles` — sorts after, A-Z.
|
|
512
|
+
*/
|
|
513
|
+
function summarizeFileCounts(files) {
|
|
514
|
+
const counts = new Map();
|
|
515
|
+
for (const file of files) {
|
|
516
|
+
const base = file.split(/[\\/]/).pop() ?? file;
|
|
517
|
+
const dot = base.lastIndexOf('.');
|
|
518
|
+
const ext = dot === -1 ? '(no extension)' : base.slice(dot);
|
|
519
|
+
counts.set(ext, (counts.get(ext) ?? 0) + 1);
|
|
520
|
+
}
|
|
521
|
+
const priority = ['.vue', '.md'];
|
|
522
|
+
const exts = [...counts.keys()].sort((a, b) => {
|
|
523
|
+
const pa = priority.indexOf(a);
|
|
524
|
+
const pb = priority.indexOf(b);
|
|
525
|
+
if (pa !== -1 || pb !== -1) {
|
|
526
|
+
return (
|
|
527
|
+
(pa === -1 ? priority.length : pa) - (pb === -1 ? priority.length : pb)
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
return a.localeCompare(b);
|
|
531
|
+
});
|
|
532
|
+
return exts.map((ext) => `${counts.get(ext)} ${ext}`).join(' + ');
|
|
533
|
+
}
|
|
534
|
+
|
|
453
535
|
/**
|
|
454
536
|
* `npx bitboss-ui check [glob…] [--json]` — validate `Bb*` markup in `.vue`
|
|
455
537
|
* and `.md` files against the installed components.json manifest.
|
|
@@ -494,7 +576,7 @@ function checkCommand(globs, jsonMode) {
|
|
|
494
576
|
|
|
495
577
|
if (findings.length === 0) {
|
|
496
578
|
console.log(
|
|
497
|
-
`[bitboss-ui] check OK — ${files
|
|
579
|
+
`[bitboss-ui] check OK — ${summarizeFileCounts(files)} file(s), zero unknown Bb* props/v-models.`
|
|
498
580
|
);
|
|
499
581
|
return;
|
|
500
582
|
}
|
|
@@ -543,7 +625,9 @@ Commands:
|
|
|
543
625
|
Validate \`Bb*\` markup in .vue/.md files against the
|
|
544
626
|
installed components.json manifest (unknown/removed props,
|
|
545
627
|
bad v-models). Defaults to every .vue/.md file under the
|
|
546
|
-
current directory (node_modules
|
|
628
|
+
current directory (node_modules, dist, .git, vendor,
|
|
629
|
+
storage, public, .output, .nuxt, bootstrap/cache
|
|
630
|
+
excluded — pass an explicit glob/path to widen the scan).
|
|
547
631
|
Exits 1 on findings; \`--json\` prints \`{ findings: [...] }\`.
|
|
548
632
|
mcp Start a stdio MCP server exposing the dist/ai knowledge
|
|
549
633
|
base (search_components, get_component, list_recipes,
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `npx bitboss-ui check` integration tests.
|
|
3
|
+
*
|
|
4
|
+
* The CLI entrypoint (`bitboss-ui.mjs`) runs its command dispatch as a
|
|
5
|
+
* top-level side effect keyed off `process.argv` — importing it directly
|
|
6
|
+
* would execute the dispatcher against the TEST RUNNER's own argv. So this
|
|
7
|
+
* spawns the real binary as a subprocess against a scratch directory, which
|
|
8
|
+
* also happens to be the most faithful reproduction of SNT-007: a Laravel-
|
|
9
|
+
* shaped consumer tree where `check` used to report on `vendor/**` READMEs
|
|
10
|
+
* as if they were the project's own markup.
|
|
11
|
+
*/
|
|
12
|
+
import { execFileSync } from 'node:child_process';
|
|
13
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
14
|
+
import { tmpdir } from 'node:os';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
18
|
+
|
|
19
|
+
const BIN = fileURLToPath(new URL('./bitboss-ui.mjs', import.meta.url));
|
|
20
|
+
|
|
21
|
+
let scratch;
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
if (scratch) rmSync(scratch, { recursive: true, force: true });
|
|
25
|
+
scratch = undefined;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/** Build a temp Laravel-shaped consumer tree: vendored noise + real markup. */
|
|
29
|
+
function makeLaravelLikeFixture() {
|
|
30
|
+
const dir = mkdtempSync(join(tmpdir(), 'bitboss-ui-check-'));
|
|
31
|
+
|
|
32
|
+
// Noise a default sweep must now skip.
|
|
33
|
+
mkdirSync(join(dir, 'vendor', 'some', 'package'), { recursive: true });
|
|
34
|
+
writeFileSync(
|
|
35
|
+
join(dir, 'vendor', 'some', 'package', 'README.md'),
|
|
36
|
+
'# Vendored package\n'
|
|
37
|
+
);
|
|
38
|
+
mkdirSync(join(dir, 'storage', 'logs'), { recursive: true });
|
|
39
|
+
writeFileSync(join(dir, 'storage', 'logs', 'notes.md'), '# log notes\n');
|
|
40
|
+
mkdirSync(join(dir, 'public', 'build'), { recursive: true });
|
|
41
|
+
writeFileSync(join(dir, 'public', 'build', 'manifest.md'), '# build\n');
|
|
42
|
+
mkdirSync(join(dir, 'bootstrap', 'cache'), { recursive: true });
|
|
43
|
+
writeFileSync(
|
|
44
|
+
join(dir, 'bootstrap', 'cache', 'config.md'),
|
|
45
|
+
'# compiled config\n'
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// A hand-authored doc that happens to live next to (not inside) the
|
|
49
|
+
// skipped `bootstrap/cache` dir — must still be counted.
|
|
50
|
+
writeFileSync(join(dir, 'bootstrap', 'README.md'), '# real bootstrap doc\n');
|
|
51
|
+
|
|
52
|
+
// Real app markup: one .vue, one .md.
|
|
53
|
+
mkdirSync(join(dir, 'resources', 'js', 'components'), { recursive: true });
|
|
54
|
+
writeFileSync(
|
|
55
|
+
join(dir, 'resources', 'js', 'components', 'Widget.vue'),
|
|
56
|
+
'<template><div>hi</div></template>\n'
|
|
57
|
+
);
|
|
58
|
+
writeFileSync(join(dir, 'GUIDE.md'), '# guide\n');
|
|
59
|
+
|
|
60
|
+
return dir;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function runCheck(cwd, args = []) {
|
|
64
|
+
try {
|
|
65
|
+
const stdout = execFileSync(process.execPath, [BIN, 'check', ...args], {
|
|
66
|
+
cwd,
|
|
67
|
+
encoding: 'utf-8',
|
|
68
|
+
});
|
|
69
|
+
return { status: 0, stdout };
|
|
70
|
+
} catch (error) {
|
|
71
|
+
return {
|
|
72
|
+
status: error.status,
|
|
73
|
+
stdout: error.stdout ?? '',
|
|
74
|
+
stderr: error.stderr ?? '',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
describe('bitboss-ui check — default sweep skip list (SNT-007)', () => {
|
|
80
|
+
it('skips vendor/storage/public/bootstrap-cache and splits the summary by extension', () => {
|
|
81
|
+
scratch = makeLaravelLikeFixture();
|
|
82
|
+
const { status, stdout } = runCheck(scratch);
|
|
83
|
+
|
|
84
|
+
expect(status).toBe(0);
|
|
85
|
+
// Exactly the two real files: Widget.vue + (GUIDE.md + bootstrap/README.md).
|
|
86
|
+
expect(stdout).toMatch(
|
|
87
|
+
/\[bitboss-ui\] check OK — 1 \.vue \+ 2 \.md file\(s\), zero unknown Bb\* props\/v-models\./
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('still reports findings when a real file has an unknown prop', () => {
|
|
92
|
+
scratch = makeLaravelLikeFixture();
|
|
93
|
+
writeFileSync(
|
|
94
|
+
join(scratch, 'resources', 'js', 'components', 'Bad.vue'),
|
|
95
|
+
'<template><BbButton totallyBogusProp="x" /></template>\n'
|
|
96
|
+
);
|
|
97
|
+
const { status, stdout, stderr } = runCheck(scratch);
|
|
98
|
+
|
|
99
|
+
expect(status).toBe(1);
|
|
100
|
+
expect(stdout + stderr).toMatch(/check FAILED/);
|
|
101
|
+
expect(stdout + stderr).toMatch(/totallyBogusProp|totallybogusprop/i);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('an explicit path still widens the scan into a normally-skipped dir', () => {
|
|
105
|
+
scratch = makeLaravelLikeFixture();
|
|
106
|
+
const { status, stdout } = runCheck(scratch, [
|
|
107
|
+
join('vendor', 'some', 'package', 'README.md'),
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
expect(status).toBe(0);
|
|
111
|
+
expect(stdout).toMatch(/check OK — 1 \.md file\(s\)/);
|
|
112
|
+
});
|
|
113
|
+
});
|
package/dist/ai/BbAccordion.md
CHANGED
|
@@ -69,7 +69,7 @@ collapsed state and strips padding/borders you put on the panel itself.
|
|
|
69
69
|
</div>
|
|
70
70
|
</template>
|
|
71
71
|
|
|
72
|
-
<p class="px-3 pb-2.5 text-sm text-
|
|
72
|
+
<p class="px-3 pb-2.5 text-sm text-[color:var(--bb-text-muted)]">
|
|
73
73
|
{{ faq.answer }}
|
|
74
74
|
</p>
|
|
75
75
|
</BbAccordion>
|
|
@@ -145,7 +145,9 @@ on the row, badge included, toggles the panel.
|
|
|
145
145
|
</template>
|
|
146
146
|
|
|
147
147
|
<div class="flex flex-col gap-1.5 px-3 pb-2.5">
|
|
148
|
-
<p class="text-xs text-
|
|
148
|
+
<p class="text-xs text-[color:var(--bb-text-muted)]">
|
|
149
|
+
{{ endpoint.summary }}
|
|
150
|
+
</p>
|
|
149
151
|
<dl class="flex flex-col gap-1 text-xs">
|
|
150
152
|
<div
|
|
151
153
|
v-for="param in endpoint.params"
|
|
@@ -153,7 +155,7 @@ on the row, badge included, toggles the panel.
|
|
|
153
155
|
class="flex items-baseline gap-2"
|
|
154
156
|
>
|
|
155
157
|
<dt class="shrink-0 font-mono">{{ param.name }}</dt>
|
|
156
|
-
<dd class="text-
|
|
158
|
+
<dd class="text-[color:var(--bb-text-muted)]">
|
|
157
159
|
{{ param.type }} · {{ param.description }}
|
|
158
160
|
</dd>
|
|
159
161
|
</div>
|
|
@@ -279,7 +281,7 @@ Both slots — `header` and the default (body) slot — receive the same scope,
|
|
|
279
281
|
</template>
|
|
280
282
|
<template #default="{ toggle }">
|
|
281
283
|
<div class="flex flex-col items-start gap-1.5 px-3 pb-2.5">
|
|
282
|
-
<p class="text-sm text-
|
|
284
|
+
<p class="text-sm text-[color:var(--bb-text-muted)]">
|
|
283
285
|
Dropdown keyboard navigation, smoother select popovers, and a new
|
|
284
286
|
color picker.
|
|
285
287
|
</p>
|
|
@@ -329,7 +331,9 @@ to `null`). Prefer a stable key over an index when the list can reorder.
|
|
|
329
331
|
class="flex w-full items-center justify-between gap-2 px-3 py-2 text-left text-sm"
|
|
330
332
|
>
|
|
331
333
|
<span class="font-medium">{{ plan.name }}</span>
|
|
332
|
-
<span
|
|
334
|
+
<span
|
|
335
|
+
class="flex items-center gap-1.5 text-[color:var(--bb-text-muted)]"
|
|
336
|
+
>
|
|
333
337
|
{{ plan.price }}
|
|
334
338
|
<span
|
|
335
339
|
class="shrink-0 transition-transform duration-200"
|
|
@@ -341,7 +345,9 @@ to `null`). Prefer a stable key over an index when the list can reorder.
|
|
|
341
345
|
</div>
|
|
342
346
|
</template>
|
|
343
347
|
|
|
344
|
-
<ul
|
|
348
|
+
<ul
|
|
349
|
+
class="flex flex-col gap-1 px-3 pb-2.5 text-sm text-[color:var(--bb-text-muted)]"
|
|
350
|
+
>
|
|
345
351
|
<li v-for="feature in plan.features" :key="feature">{{ feature }}</li>
|
|
346
352
|
</ul>
|
|
347
353
|
</BbAccordion>
|
|
@@ -410,7 +416,7 @@ padding on the nested body content.
|
|
|
410
416
|
<BbAccordion v-model="advanced">
|
|
411
417
|
<template #header="{ value }">
|
|
412
418
|
<div
|
|
413
|
-
class="flex w-full items-center justify-between gap-2 py-1 text-left text-sm text-
|
|
419
|
+
class="flex w-full items-center justify-between gap-2 py-1 text-left text-sm text-[color:var(--bb-text-muted)]"
|
|
414
420
|
>
|
|
415
421
|
<span>Advanced</span>
|
|
416
422
|
<span
|
|
@@ -525,7 +531,7 @@ is generated for you.
|
|
|
525
531
|
| --- | --- | --- | --- | --- |
|
|
526
532
|
| `eager` | `boolean \| undefined` | | | Prevents rendering content before it's made visible. |
|
|
527
533
|
| `id` | `string \| undefined` | | | The identifier of the component. |
|
|
528
|
-
| `modelValue` | `boolean \| undefined` | `false` | | Used by v-model to trigger opening / closing the collapsible. |
|
|
534
|
+
| `modelValue` | `boolean \| undefined` | `false` | | Used by v-model to trigger opening / closing the collapsible. An accordion with no `v-model` starts closed. |
|
|
529
535
|
| `transitionDuration` | `number \| undefined` | `transitions.medium` | | How long the transition has to last in milliseconds |
|
|
530
536
|
|
|
531
537
|
## Events
|