bitboss-ui 2.1.134 → 3.0.0-alpha.1
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/LICENSE +21 -0
- package/README.md +244 -21
- package/bin/bitboss-ui-mcp.mjs +557 -0
- package/bin/bitboss-ui.mjs +626 -0
- package/dist/ai/BbAccordion.md +522 -113
- package/dist/ai/BbAlert.md +377 -197
- package/dist/ai/BbAsterisk.md +46 -0
- package/dist/ai/BbAvatar.md +454 -178
- package/dist/ai/BbBadge.md +695 -225
- package/dist/ai/BbBadgeButton.md +54 -0
- package/dist/ai/BbBaseButton.md +489 -0
- package/dist/ai/BbBaseCheckbox.md +49 -0
- package/dist/ai/BbBaseCheckboxGroup.md +64 -0
- package/dist/ai/BbBaseCheckboxIcon.md +174 -0
- package/dist/ai/BbBaseColorInput.md +64 -0
- package/dist/ai/BbBaseColorPalette.md +39 -0
- package/dist/ai/BbBaseDatePicker.md +42 -0
- package/dist/ai/BbBaseDatePickerInput.md +73 -0
- package/dist/ai/BbBaseInputContainer.md +48 -0
- package/dist/ai/BbBaseNumberInput.md +71 -0
- package/dist/ai/BbBaseRadio.md +46 -0
- package/dist/ai/BbBaseRadioGroup.md +63 -0
- package/dist/ai/BbBaseRadioIcon.md +187 -0
- package/dist/ai/BbBaseRating.md +51 -0
- package/dist/ai/BbBaseSelect.md +88 -0
- package/dist/ai/BbBaseSlider.md +56 -0
- package/dist/ai/BbBaseSwitch.md +49 -0
- package/dist/ai/BbBaseSwitchGroup.md +64 -0
- package/dist/ai/BbBaseSwitchIcon.md +184 -0
- package/dist/ai/BbBaseTag.md +68 -0
- package/dist/ai/BbBaseTextInput.md +75 -0
- package/dist/ai/BbBaseTextarea.md +62 -0
- package/dist/ai/BbBaseTimePickerInput.md +62 -0
- package/dist/ai/BbBreadcrumbs.md +542 -503
- package/dist/ai/BbButton.md +767 -636
- package/dist/ai/BbCheckbox.md +572 -254
- package/dist/ai/BbCheckboxGroup.md +561 -361
- package/dist/ai/BbCollapsible.md +419 -103
- package/dist/ai/BbColorInput.md +529 -323
- package/dist/ai/BbColorPalette.md +565 -330
- package/dist/ai/BbConfirm.md +612 -136
- package/dist/ai/BbConfirmPortal.md +28 -0
- package/dist/ai/BbDatePicker.md +244 -0
- package/dist/ai/BbDatePickerInput.md +706 -388
- package/dist/ai/BbDialog.md +770 -99
- package/dist/ai/BbDropdown.md +1054 -763
- package/dist/ai/BbDropdownButton.md +511 -615
- package/dist/ai/BbDropdownGroup.md +34 -0
- package/dist/ai/BbDropzone.md +1148 -436
- package/dist/ai/BbForm.md +239 -0
- package/dist/ai/BbIcon.md +379 -212
- package/dist/ai/BbIndicator.md +283 -0
- package/dist/ai/BbNumberInput.md +713 -355
- package/dist/ai/BbOffCanvas.md +875 -498
- package/dist/ai/BbPagination.md +483 -535
- package/dist/ai/BbPopover.md +583 -546
- package/dist/ai/BbProgress.md +456 -69
- package/dist/ai/BbRadio.md +343 -229
- package/dist/ai/BbRadioGroup.md +426 -353
- package/dist/ai/BbRating.md +361 -226
- package/dist/ai/BbSelect.md +1380 -536
- package/dist/ai/BbSelectPopover.md +1240 -1579
- package/dist/ai/BbSlider.md +478 -257
- package/dist/ai/BbSmoothHeight.md +472 -139
- package/dist/ai/BbSpinner.md +718 -131
- package/dist/ai/BbSwitch.md +549 -119
- package/dist/ai/BbSwitchGroup.md +503 -214
- package/dist/ai/BbTable.md +1956 -2358
- package/dist/ai/BbTabs.md +1113 -0
- package/dist/ai/BbTabsList.md +29 -0
- package/dist/ai/BbTabsPanes.md +27 -0
- package/dist/ai/BbTabsRoot.md +57 -0
- package/dist/ai/BbTag.md +393 -292
- package/dist/ai/BbTextInput.md +852 -333
- package/dist/ai/BbTextarea.md +836 -255
- package/dist/ai/BbTimePicker.md +231 -0
- package/dist/ai/BbTimePickerInput.md +196 -0
- package/dist/ai/BbToast.md +624 -196
- package/dist/ai/BbToastPortal.md +28 -0
- package/dist/ai/BbTooltip.md +443 -346
- package/dist/ai/BbTree.md +984 -235
- package/dist/ai/ChipsBox.md +27 -199
- package/dist/ai/ClearableButton.md +21 -55
- package/dist/ai/CommaBox.md +25 -200
- package/dist/ai/CommonInputWrapper.md +42 -0
- package/dist/ai/CommonPopover.md +30 -510
- package/dist/ai/ErrorIcon.md +19 -56
- package/dist/ai/FlatListBox.md +35 -379
- package/dist/ai/GroupedListBox.md +37 -535
- package/dist/ai/GuidesComponent.md +21 -0
- package/dist/ai/ListBox.md +38 -231
- package/dist/ai/OptionsContainer.md +34 -253
- package/dist/ai/WarningIcon.md +21 -0
- package/dist/ai/components.json +15883 -0
- package/dist/ai/composables/useBbConfig.md +80 -0
- package/dist/ai/composables/useBbFormContext.md +110 -0
- package/dist/ai/composables/useBbTableContext.md +164 -0
- package/dist/ai/composables/useBbTabsContext.md +118 -0
- package/dist/ai/composables/useBroadcastChannelInstance.md +97 -0
- package/dist/ai/composables/useConfirm.md +306 -0
- package/dist/ai/composables/useCountdown.md +84 -0
- package/dist/ai/composables/useId.md +60 -0
- package/dist/ai/composables/useMobile.md +85 -0
- package/dist/ai/composables/useToast.md +230 -0
- package/dist/ai/guides/agent-contract.md +108 -0
- package/dist/ai/guides/ai-router.md +111 -0
- package/dist/ai/guides/app-layout.md +295 -0
- package/dist/ai/guides/coherence-playbook.md +136 -0
- package/dist/ai/guides/component-picker.md +195 -0
- package/dist/ai/guides/design-language.md +461 -0
- package/dist/ai/guides/design-tokens.md +424 -0
- package/dist/ai/guides/fetch-items-playbook.md +161 -0
- package/dist/ai/guides/floating-bottom-panel.md +191 -0
- package/dist/ai/guides/icons-policy.md +257 -0
- package/dist/ai/guides/inertia-helpers.md +1394 -0
- package/dist/ai/guides/inline-edit-playbook.md +258 -0
- package/dist/ai/guides/installation-and-plugin-setup.md +377 -0
- package/dist/ai/guides/migration/components/bb-alert.md +37 -0
- package/dist/ai/guides/migration/components/bb-avatar.md +24 -0
- package/dist/ai/guides/migration/components/bb-badge.md +110 -0
- package/dist/ai/guides/migration/components/bb-breadcrumbs.md +26 -0
- package/dist/ai/guides/migration/components/bb-button.md +55 -0
- package/dist/ai/guides/migration/components/bb-checkbox-group.md +54 -0
- package/dist/ai/guides/migration/components/bb-checkbox.md +45 -0
- package/dist/ai/guides/migration/components/bb-chip.md +35 -0
- package/dist/ai/guides/migration/components/bb-collapsible.md +26 -0
- package/dist/ai/guides/migration/components/bb-color-input.md +23 -0
- package/dist/ai/guides/migration/components/bb-color-palette.md +31 -0
- package/dist/ai/guides/migration/components/bb-date-picker-input.md +84 -0
- package/dist/ai/guides/migration/components/bb-dialog.md +46 -0
- package/dist/ai/guides/migration/components/bb-dropdown-button.md +31 -0
- package/dist/ai/guides/migration/components/bb-dropdown.md +36 -0
- package/dist/ai/guides/migration/components/bb-dropzone.md +27 -0
- package/dist/ai/guides/migration/components/bb-icon.md +27 -0
- package/dist/ai/guides/migration/components/bb-off-canvas.md +25 -0
- package/dist/ai/guides/migration/components/bb-offcanvas.md +54 -0
- package/dist/ai/guides/migration/components/bb-pagination.md +24 -0
- package/dist/ai/guides/migration/components/bb-popover.md +52 -0
- package/dist/ai/guides/migration/components/bb-rating.md +24 -0
- package/dist/ai/guides/migration/components/bb-select-popover.md +58 -0
- package/dist/ai/guides/migration/components/bb-select.md +68 -0
- package/dist/ai/guides/migration/components/bb-slider.md +25 -0
- package/dist/ai/guides/migration/components/bb-smooth-height.md +45 -0
- package/dist/ai/guides/migration/components/bb-spinner.md +23 -0
- package/dist/ai/guides/migration/components/bb-table.md +66 -0
- package/dist/ai/guides/migration/components/bb-tabs.md +47 -0
- package/dist/ai/guides/migration/components/bb-tag.md +29 -0
- package/dist/ai/guides/migration/components/bb-text-input.md +37 -0
- package/dist/ai/guides/migration/components/bb-toast.md +47 -0
- package/dist/ai/guides/migration/components/bb-tooltip.md +34 -0
- package/dist/ai/guides/migration/components/bb-tree.md +77 -0
- package/dist/ai/guides/migration/components/use-confirm.md +46 -0
- package/dist/ai/guides/migration/v2-to-v3.md +649 -0
- package/dist/ai/guides/options-items-playbook.md +222 -0
- package/dist/ai/guides/page-shell.md +314 -0
- package/dist/ai/guides/validated-forms.md +177 -0
- package/dist/ai/index.md +156 -32
- package/dist/ai/recipes/inertia/approvals-inbox.md +1598 -0
- package/dist/ai/recipes/inertia/inline-edit-workspace.md +1733 -0
- package/dist/ai/recipes/inertia/onboarding.md +1765 -0
- package/dist/ai/recipes/inertia/ownership-atlas.md +1281 -0
- package/dist/ai/recipes/inertia/record-form.md +1442 -0
- package/dist/ai/recipes/inertia/records-workspace.md +1328 -0
- package/dist/ai/recipes/inertia/upload-center.md +1926 -0
- package/dist/ai/recipes/inertia/wizard-form.md +1477 -0
- package/dist/ai/recipes/nuxt/approvals-inbox.md +1561 -0
- package/dist/ai/recipes/nuxt/inline-edit-workspace.md +1690 -0
- package/dist/ai/recipes/nuxt/onboarding.md +1698 -0
- package/dist/ai/recipes/nuxt/record-form.md +1456 -0
- package/dist/ai/recipes/nuxt/records-workspace.md +1314 -0
- package/dist/ai/recipes/nuxt/upload-center.md +1847 -0
- package/dist/ai/recipes/nuxt/wizard-form.md +1486 -0
- package/dist/ai/recipes/vue/approvals-inbox.md +1479 -0
- package/dist/ai/recipes/vue/inline-edit-workspace.md +1581 -0
- package/dist/ai/recipes/vue/onboarding.md +1653 -0
- package/dist/ai/recipes/vue/record-form.md +1540 -0
- package/dist/ai/recipes/vue/records-workspace.md +1230 -0
- package/dist/ai/recipes/vue/upload-center.md +1806 -0
- package/dist/ai/recipes/vue/wizard-form.md +1418 -0
- package/dist/ai/source/BbAccordion.md +122 -0
- package/dist/ai/source/BbAlert.md +396 -0
- package/dist/ai/source/BbAsterisk.md +32 -0
- package/dist/ai/source/BbAvatar.md +256 -0
- package/dist/ai/source/BbBadge.md +560 -0
- package/dist/ai/source/BbBadgeButton.md +490 -0
- package/dist/ai/source/BbBaseButton.md +682 -0
- package/dist/ai/source/BbBaseCheckbox.md +459 -0
- package/dist/ai/source/BbBaseCheckboxGroup.md +554 -0
- package/dist/ai/source/BbBaseCheckboxIcon.md +201 -0
- package/dist/ai/source/BbBaseColorInput.md +413 -0
- package/dist/ai/source/BbBaseColorPalette.md +934 -0
- package/dist/ai/source/BbBaseDatePicker.md +1001 -0
- package/dist/ai/source/BbBaseDatePickerInput.md +1781 -0
- package/dist/ai/source/BbBaseInputContainer.md +1148 -0
- package/dist/ai/source/BbBaseNumberInput.md +615 -0
- package/dist/ai/source/BbBaseRadio.md +377 -0
- package/dist/ai/source/BbBaseRadioGroup.md +499 -0
- package/dist/ai/source/BbBaseRadioIcon.md +153 -0
- package/dist/ai/source/BbBaseRating.md +573 -0
- package/dist/ai/source/BbBaseSelect.md +895 -0
- package/dist/ai/source/BbBaseSlider.md +1085 -0
- package/dist/ai/source/BbBaseSwitch.md +246 -0
- package/dist/ai/source/BbBaseSwitchGroup.md +302 -0
- package/dist/ai/source/BbBaseSwitchIcon.md +206 -0
- package/dist/ai/source/BbBaseTag.md +688 -0
- package/dist/ai/source/BbBaseTextInput.md +511 -0
- package/dist/ai/source/BbBaseTextarea.md +480 -0
- package/dist/ai/source/BbBaseTimePickerInput.md +1013 -0
- package/dist/ai/source/BbBreadcrumbs.md +811 -0
- package/dist/ai/source/BbButton.md +990 -0
- package/dist/ai/source/BbCheckbox.md +319 -0
- package/dist/ai/source/BbCheckboxGroup.md +412 -0
- package/dist/ai/source/BbCollapsible.md +133 -0
- package/dist/ai/source/BbColorInput.md +315 -0
- package/dist/ai/source/BbColorPalette.md +361 -0
- package/dist/ai/source/BbConfirm.md +173 -0
- package/dist/ai/source/BbConfirmPortal.md +74 -0
- package/dist/ai/source/BbDatePicker.md +725 -0
- package/dist/ai/source/BbDatePickerInput.md +518 -0
- package/dist/ai/source/BbDialog.md +812 -0
- package/dist/ai/source/BbDropdown.md +2369 -0
- package/dist/ai/source/BbDropdownButton.md +313 -0
- package/dist/ai/source/BbDropdownGroup.md +1249 -0
- package/dist/ai/source/BbDropzone.md +749 -0
- package/dist/ai/source/BbForm.md +100 -0
- package/dist/ai/source/BbIcon.md +212 -0
- package/dist/ai/source/BbIndicator.md +298 -0
- package/dist/ai/source/BbNumberInput.md +365 -0
- package/dist/ai/source/BbOffCanvas.md +1260 -0
- package/dist/ai/source/BbPagination.md +829 -0
- package/dist/ai/source/BbPopover.md +853 -0
- package/dist/ai/source/BbProgress.md +140 -0
- package/dist/ai/source/BbRadio.md +294 -0
- package/dist/ai/source/BbRadioGroup.md +401 -0
- package/dist/ai/source/BbRating.md +362 -0
- package/dist/ai/source/BbSelect.md +681 -0
- package/dist/ai/source/BbSelectPopover.md +2209 -0
- package/dist/ai/source/BbSlider.md +371 -0
- package/dist/ai/source/BbSmoothHeight.md +261 -0
- package/dist/ai/source/BbSpinner.md +127 -0
- package/dist/ai/source/BbSwitch.md +175 -0
- package/dist/ai/source/BbSwitchGroup.md +240 -0
- package/dist/ai/source/BbTable.md +3348 -0
- package/dist/ai/source/BbTabs.md +403 -0
- package/dist/ai/source/BbTabsList.md +578 -0
- package/dist/ai/source/BbTabsPanes.md +368 -0
- package/dist/ai/source/BbTabsRoot.md +372 -0
- package/dist/ai/source/BbTag.md +383 -0
- package/dist/ai/source/BbTextInput.md +345 -0
- package/dist/ai/source/BbTextarea.md +330 -0
- package/dist/ai/source/BbTimePicker.md +591 -0
- package/dist/ai/source/BbTimePickerInput.md +367 -0
- package/dist/ai/source/BbToast.md +524 -0
- package/dist/ai/source/BbToastPortal.md +482 -0
- package/dist/ai/source/BbTooltip.md +508 -0
- package/dist/ai/source/BbTree.md +319 -0
- package/dist/ai/source/ChipsBox.md +201 -0
- package/dist/ai/source/ClearableButton.md +70 -0
- package/dist/ai/source/CommaBox.md +202 -0
- package/dist/ai/source/CommonInputWrapper.md +554 -0
- package/dist/ai/source/CommonPopover.md +606 -0
- package/dist/ai/source/ErrorIcon.md +43 -0
- package/dist/ai/source/FlatListBox.md +396 -0
- package/dist/ai/source/GroupedListBox.md +540 -0
- package/dist/ai/source/GuidesComponent.md +383 -0
- package/dist/ai/source/ListBox.md +238 -0
- package/dist/ai/source/OptionsContainer.md +191 -0
- package/dist/ai/source/WarningIcon.md +47 -0
- package/dist/alert-variants.d.ts +12 -0
- package/dist/assets/css/reset.css_inline.js +4 -0
- package/dist/assets/svgs/alert.svg_raw.js +4 -0
- package/dist/assets/svgs/calendar.svg_raw.js +4 -0
- package/dist/assets/svgs/check_stroke.svg_raw.js +4 -0
- package/dist/assets/svgs/chevron_down.svg_raw.js +4 -0
- package/dist/assets/svgs/chevron_right.svg_raw.js +4 -0
- package/dist/assets/svgs/clear.svg_raw.js +4 -0
- package/dist/assets/svgs/clock.svg_raw.js +4 -0
- package/dist/assets/svgs/error.svg_raw.js +4 -0
- package/dist/assets/svgs/search.svg_raw.js +4 -0
- package/dist/assets/svgs/sort.svg_raw.js +4 -0
- package/dist/assets/svgs/spinner.svg_raw.js +4 -0
- package/dist/assets/svgs/user.svg_raw.js +4 -0
- package/dist/badge-variants.d.ts +18 -0
- package/dist/button-variants.d.ts +15 -0
- package/dist/components/BbAccordion/BbAccordion.vue.d.ts +9 -3
- package/dist/components/BbAccordion/BbAccordion.vue.js +6 -0
- package/dist/components/BbAccordion/BbAccordion.vue_vue_type_script_setup_true_lang.js +66 -0
- package/dist/components/BbAccordion/types.d.ts +10 -7
- package/dist/components/BbAlert/BbAlert.vue.d.ts +12 -3
- package/dist/components/BbAlert/BbAlert.vue.js +6 -0
- package/dist/components/BbAlert/BbAlert.vue_vue_type_script_setup_true_lang.js +65 -0
- package/dist/components/BbAlert/types.d.ts +51 -12
- package/dist/components/BbAsterisk/BbAsterisk.vue.d.ts +3 -0
- package/dist/components/BbAsterisk/BbAsterisk.vue.js +6 -0
- package/dist/components/BbAsterisk/BbAsterisk.vue_vue_type_script_setup_true_lang.js +13 -0
- package/dist/components/BbAvatar/BbAvatar.vue.d.ts +5 -0
- package/dist/components/BbAvatar/BbAvatar.vue.js +6 -0
- package/dist/components/BbAvatar/BbAvatar.vue_vue_type_script_setup_true_lang.js +78 -0
- package/dist/components/BbAvatar/types.d.ts +4 -5
- package/dist/components/BbBadge/BadgeAppendIcon.vue.d.ts +3 -0
- package/dist/components/BbBadge/BadgeAppendIcon.vue.js +5 -0
- package/dist/components/BbBadge/BadgeAppendIcon.vue_vue_type_script_setup_true_lang.js +22 -0
- package/dist/components/BbBadge/BadgeBodyContent.vue.d.ts +15 -0
- package/dist/components/BbBadge/BadgeBodyContent.vue.js +5 -0
- package/dist/components/BbBadge/BadgeBodyContent.vue_vue_type_script_setup_true_lang.js +34 -0
- package/dist/components/BbBadge/BbBadge.vue.d.ts +8 -1
- package/dist/components/BbBadge/BbBadge.vue.js +6 -0
- package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +83 -0
- package/dist/components/BbBadge/BbBadgeButton.vue.d.ts +12 -0
- package/dist/components/BbBadge/BbBadgeButton.vue.js +5 -0
- package/dist/components/BbBadge/BbBadgeButton.vue_vue_type_script_setup_true_lang.js +54 -0
- package/dist/components/BbBadge/badgeButtonContext.d.ts +27 -0
- package/dist/components/BbBadge/badgeButtonContext.js +5 -0
- package/dist/components/BbBadge/types.d.ts +61 -16
- package/dist/components/BbBaseButton/BbBaseButton.vue.d.ts +13 -0
- package/dist/components/BbBaseButton/BbBaseButton.vue.js +6 -0
- package/dist/components/BbBaseButton/BbBaseButton.vue_vue_type_script_setup_true_lang.js +171 -0
- package/dist/components/BbBaseButton/RouterComponent.vue.js +5 -0
- package/dist/components/BbBaseButton/RouterComponent.vue_vue_type_script_setup_true_lang.js +28 -0
- package/dist/components/BbBaseButton/types.d.ts +191 -0
- package/dist/components/BbBaseButton/types.js +33 -0
- package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue.d.ts +40 -0
- package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue.js +6 -0
- package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue_vue_type_script_setup_true_lang.js +145 -0
- package/dist/components/BbBaseCheckbox/types.d.ts +222 -0
- package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue.d.ts +19 -0
- package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue.js +6 -0
- package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue_vue_type_script_setup_true_lang.js +190 -0
- package/dist/components/BbBaseCheckboxGroup/types.d.ts +257 -0
- package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue.d.ts +4 -0
- package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue.js +6 -0
- package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue_vue_type_script_setup_true_lang.js +43 -0
- package/dist/components/BbBaseCheckboxIcon/types.d.ts +47 -0
- package/dist/components/BbBaseColorInput/BbBaseColorInput.vue.d.ts +42 -0
- package/dist/components/BbBaseColorInput/BbBaseColorInput.vue.js +6 -0
- package/dist/components/BbBaseColorInput/BbBaseColorInput.vue_vue_type_script_setup_true_lang.js +178 -0
- package/dist/components/BbBaseColorInput/types.d.ts +207 -0
- package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue.d.ts +13 -0
- package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue.js +6 -0
- package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue_vue_type_script_setup_true_lang.js +395 -0
- package/dist/components/BbBaseColorPalette/types.d.ts +40 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue.js +6 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue_vue_type_script_setup_true_lang.js +300 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue.d.ts +44 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue.js +5 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue_vue_type_script_setup_true_lang.js +310 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue.d.ts +5 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue.js +5 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue_vue_type_script_setup_true_lang.js +63 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue.d.ts +5 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue.js +5 -0
- package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue_vue_type_script_setup_true_lang.js +75 -0
- package/dist/components/BbBaseDatePicker/typeahead.d.ts +112 -0
- package/dist/components/BbBaseDatePicker/typeahead.js +37 -0
- package/dist/components/BbBaseDatePicker/types.d.ts +97 -0
- package/dist/components/BbBaseDatePicker/useDatePickerContext.d.ts +58 -0
- package/dist/components/BbBaseDatePicker/useDatePickerContext.js +11 -0
- package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue.d.ts +30 -0
- package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue.js +6 -0
- package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue_vue_type_script_setup_true_lang.js +713 -0
- package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue.d.ts +30 -0
- package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue.js +6 -0
- package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue_vue_type_script_setup_true_lang.js +204 -0
- package/dist/components/BbBaseDatePickerInput/types.d.ts +309 -0
- package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.d.ts +17 -0
- package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.js +6 -0
- package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue_vue_type_script_setup_true_lang.js +184 -0
- package/dist/components/BbBaseInputContainer/types.d.ts +185 -0
- package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue.d.ts +52 -0
- package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue.js +6 -0
- package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue_vue_type_script_setup_true_lang.js +211 -0
- package/dist/components/BbBaseNumberInput/types.d.ts +211 -0
- package/dist/components/BbBaseRadio/BbBaseRadio.vue.d.ts +33 -0
- package/dist/components/BbBaseRadio/BbBaseRadio.vue.js +6 -0
- package/dist/components/BbBaseRadio/BbBaseRadio.vue_vue_type_script_setup_true_lang.js +114 -0
- package/dist/components/BbBaseRadio/types.d.ts +179 -0
- package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue.d.ts +19 -0
- package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue.js +6 -0
- package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue_vue_type_script_setup_true_lang.js +172 -0
- package/dist/components/BbBaseRadioGroup/types.d.ts +215 -0
- package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue.d.ts +4 -0
- package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue.js +6 -0
- package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue_vue_type_script_setup_true_lang.js +28 -0
- package/dist/components/BbBaseRadioIcon/types.d.ts +41 -0
- package/dist/components/BbBaseRating/BbBaseRating.vue.d.ts +38 -0
- package/dist/components/BbBaseRating/BbBaseRating.vue.js +6 -0
- package/dist/components/BbBaseRating/BbBaseRating.vue_vue_type_script_setup_true_lang.js +184 -0
- package/dist/components/BbBaseRating/types.d.ts +168 -0
- package/dist/components/BbBaseSelect/BbBaseSelect.vue.d.ts +19 -0
- package/dist/components/BbBaseSelect/BbBaseSelect.vue.js +6 -0
- package/dist/components/BbBaseSelect/BbBaseSelect.vue_vue_type_script_setup_true_lang.js +307 -0
- package/dist/components/BbBaseSelect/types.d.ts +294 -0
- package/dist/components/BbBaseSlider/BbBaseSlider.vue.d.ts +35 -0
- package/dist/components/BbBaseSlider/BbBaseSlider.vue.js +6 -0
- package/dist/components/BbBaseSlider/BbBaseSlider.vue_vue_type_script_setup_true_lang.js +324 -0
- package/dist/components/BbBaseSlider/types.d.ts +200 -0
- package/dist/components/BbBaseSwitch/BbBaseSwitch.vue.d.ts +35 -0
- package/dist/components/BbBaseSwitch/BbBaseSwitch.vue.js +6 -0
- package/dist/components/BbBaseSwitch/BbBaseSwitch.vue_vue_type_script_setup_true_lang.js +146 -0
- package/dist/components/BbBaseSwitch/types.d.ts +10 -0
- package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue.d.ts +19 -0
- package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue.js +6 -0
- package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue_vue_type_script_setup_true_lang.js +190 -0
- package/dist/components/BbBaseSwitchGroup/types.d.ts +8 -0
- package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue.d.ts +4 -0
- package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue.js +6 -0
- package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue_vue_type_script_setup_true_lang.js +30 -0
- package/dist/components/BbBaseSwitchIcon/types.d.ts +48 -0
- package/dist/components/BbBaseTag/BbBaseTag.vue.d.ts +50 -0
- package/dist/components/BbBaseTag/BbBaseTag.vue.js +6 -0
- package/dist/components/BbBaseTag/BbBaseTag.vue_vue_type_script_setup_true_lang.js +266 -0
- package/dist/components/BbBaseTag/types.d.ts +160 -0
- package/dist/components/BbBaseTextInput/BbBaseTextInput.vue.d.ts +45 -0
- package/dist/components/BbBaseTextInput/BbBaseTextInput.vue.js +6 -0
- package/dist/components/BbBaseTextInput/BbBaseTextInput.vue_vue_type_script_setup_true_lang.js +200 -0
- package/dist/components/BbBaseTextInput/types.d.ts +209 -0
- package/dist/components/BbBaseTextarea/BbBaseTextarea.vue.d.ts +39 -0
- package/dist/components/BbBaseTextarea/BbBaseTextarea.vue.js +6 -0
- package/dist/components/BbBaseTextarea/BbBaseTextarea.vue_vue_type_script_setup_true_lang.js +175 -0
- package/dist/components/BbBaseTextarea/types.d.ts +170 -0
- package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue.d.ts +27 -0
- package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue.js +6 -0
- package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue_vue_type_script_setup_true_lang.js +517 -0
- package/dist/components/BbBaseTimePickerInput/types.d.ts +151 -0
- package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue.d.ts +0 -1
- package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue.js +6 -0
- package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +224 -0
- package/dist/components/BbBreadcrumbs/estimateBreadcrumbItemWidth.js +47 -0
- package/dist/components/BbBreadcrumbs/types.d.ts +33 -22
- package/dist/components/BbButton/BbButton.vue.d.ts +6 -5
- package/dist/components/BbButton/BbButton.vue.js +6 -0
- package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +177 -0
- package/dist/components/BbButton/types.d.ts +48 -47
- package/dist/components/BbCheckbox/BbCheckbox.vue.d.ts +4 -3
- package/dist/components/BbCheckbox/BbCheckbox.vue.js +6 -0
- package/dist/components/BbCheckbox/BbCheckbox.vue_vue_type_script_setup_true_lang.js +146 -0
- package/dist/components/BbCheckbox/types.d.ts +24 -10
- package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue.d.ts +2 -13
- package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue.js +6 -0
- package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +190 -0
- package/dist/components/BbCheckboxGroup/types.d.ts +44 -23
- package/dist/components/BbCollapsible/BbCollapsible.vue.d.ts +2 -1
- package/dist/components/BbCollapsible/BbCollapsible.vue.js +6 -0
- package/dist/components/BbCollapsible/BbCollapsible.vue_vue_type_script_setup_true_lang.js +31 -0
- package/dist/components/BbCollapsible/types.d.ts +10 -9
- package/dist/components/BbColorInput/BbColorInput.vue.d.ts +10 -1
- package/dist/components/BbColorInput/BbColorInput.vue.js +6 -0
- package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +177 -0
- package/dist/components/BbColorInput/types.d.ts +37 -11
- package/dist/components/BbColorPalette/BbColorPalette.vue.d.ts +5 -8
- package/dist/components/BbColorPalette/BbColorPalette.vue.js +5 -0
- package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +125 -0
- package/dist/components/BbColorPalette/types.d.ts +66 -53
- package/dist/components/BbConfirm/BbConfirm.vue.js +6 -0
- package/dist/components/BbConfirm/BbConfirm.vue_vue_type_script_setup_true_lang.js +130 -0
- package/dist/components/BbConfirm/BbConfirmPortal.vue.d.ts +5 -6
- package/dist/components/BbConfirm/BbConfirmPortal.vue.js +5 -0
- package/dist/components/BbConfirm/BbConfirmPortal.vue_vue_type_script_setup_true_lang.js +19 -0
- package/dist/components/BbDatePicker/BbDatePicker.vue.d.ts +37 -0
- package/dist/components/BbDatePicker/BbDatePicker.vue.js +6 -0
- package/dist/components/BbDatePicker/BbDatePicker.vue_vue_type_script_setup_true_lang.js +319 -0
- package/dist/components/BbDatePicker/types.d.ts +155 -0
- package/dist/components/BbDatePickerInput/BbDatePickerInput.vue.d.ts +3 -1
- package/dist/components/BbDatePickerInput/BbDatePickerInput.vue.js +6 -0
- package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +179 -0
- package/dist/components/BbDatePickerInput/types.d.ts +127 -16
- package/dist/components/BbDialog/BbDialog.vue.d.ts +8 -6
- package/dist/components/BbDialog/BbDialog.vue.js +6 -0
- package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +214 -0
- package/dist/components/BbDialog/types.d.ts +146 -1
- package/dist/components/BbDialog/useDialogStack.d.ts +5 -0
- package/dist/components/BbDialog/useDialogStack.js +20 -0
- package/dist/components/BbDropdown/AdaptiveDropdown.vue.d.ts +18 -0
- package/dist/components/BbDropdown/AdaptiveDropdown.vue.js +6 -0
- package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +116 -0
- package/dist/components/BbDropdown/BbDropdown.vue.d.ts +14 -7
- package/dist/components/BbDropdown/BbDropdown.vue.js +6 -0
- package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +560 -0
- package/dist/components/BbDropdown/BbDropdownGroup.vue.d.ts +44 -0
- package/dist/components/BbDropdown/BbDropdownGroup.vue.js +5 -0
- package/dist/components/BbDropdown/BbDropdownGroup.vue_vue_type_script_setup_true_lang.js +36 -0
- package/dist/components/BbDropdown/BbDropdownList.vue.d.ts +27 -0
- package/dist/components/BbDropdown/BbDropdownList.vue.js +6 -0
- package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +464 -0
- package/dist/components/BbDropdown/DropdownPipelineResolver.vue.d.ts +16 -0
- package/dist/components/BbDropdown/DropdownPipelineResolver.vue.js +5 -0
- package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +168 -0
- package/dist/components/BbDropdown/normalizeGroups.d.ts +18 -0
- package/dist/components/BbDropdown/normalizeGroups.js +46 -0
- package/dist/components/BbDropdown/types.d.ts +457 -45
- package/dist/components/BbDropdown/types.js +4 -0
- package/dist/components/BbDropdown/useDropdownContext.d.ts +89 -0
- package/dist/components/BbDropdown/useDropdownContext.js +9 -0
- package/dist/components/BbDropdown/useDropdownGroupRegistry.d.ts +108 -0
- package/dist/components/BbDropdown/useDropdownGroupRegistry.js +5 -0
- package/dist/components/BbDropdownButton/BbDropdownButton.vue.d.ts +3 -3
- package/dist/components/BbDropdownButton/BbDropdownButton.vue.js +6 -0
- package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +119 -0
- package/dist/components/BbDropdownButton/types.d.ts +45 -52
- package/dist/components/BbDropzone/BbDropzone.vue.d.ts +5 -4
- package/dist/components/BbDropzone/BbDropzone.vue.js +6 -0
- package/dist/components/BbDropzone/BbDropzone.vue_vue_type_script_setup_true_lang.js +284 -0
- package/dist/components/BbDropzone/types.d.ts +55 -7
- package/dist/components/BbIcon/BbIcon.vue.d.ts +3 -2
- package/dist/components/BbIcon/BbIcon.vue.js +6 -0
- package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +65 -0
- package/dist/components/BbIcon/types.d.ts +6 -19
- package/dist/components/BbIndicator/BbIndicator.vue.d.ts +14 -0
- package/dist/components/BbIndicator/BbIndicator.vue.js +6 -0
- package/dist/components/BbIndicator/BbIndicator.vue_vue_type_script_setup_true_lang.js +56 -0
- package/dist/components/BbIndicator/types.d.ts +49 -0
- package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +12 -6
- package/dist/components/BbNumberInput/BbNumberInput.vue.js +6 -0
- package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +194 -0
- package/dist/components/BbNumberInput/types.d.ts +31 -4
- package/dist/components/BbOffCanvas/BbOffCanvas.vue.d.ts +10 -10
- package/dist/components/BbOffCanvas/BbOffCanvas.vue.js +6 -0
- package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +284 -0
- package/dist/components/BbOffCanvas/types.d.ts +71 -39
- package/dist/components/BbOffCanvas/useOffCanvasStack.d.ts +25 -0
- package/dist/components/BbOffCanvas/useOffCanvasStack.js +68 -0
- package/dist/components/BbPagination/BbPagination.vue.d.ts +3 -4
- package/dist/components/BbPagination/BbPagination.vue.js +6 -0
- package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +244 -0
- package/dist/components/BbPagination/paginationFit.d.ts +38 -0
- package/dist/components/BbPagination/paginationFit.js +13 -0
- package/dist/components/BbPagination/types.d.ts +51 -16
- package/dist/components/BbPopover/BbPopover.vue.d.ts +10 -15
- package/dist/components/BbPopover/BbPopover.vue.js +6 -0
- package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +310 -0
- package/dist/components/BbPopover/escapeStack.d.ts +6 -0
- package/dist/components/BbPopover/escapeStack.js +10 -0
- package/dist/components/BbPopover/types.d.ts +84 -31
- package/dist/components/BbProgress/BbProgress.vue.d.ts +1 -0
- package/dist/components/BbProgress/BbProgress.vue.js +6 -0
- package/dist/components/BbProgress/BbProgress.vue_vue_type_script_setup_true_lang.js +36 -0
- package/dist/components/BbProgress/types.d.ts +15 -1
- package/dist/components/BbRadio/BbRadio.vue.d.ts +5 -3
- package/dist/components/BbRadio/BbRadio.vue.js +6 -0
- package/dist/components/BbRadio/BbRadio.vue_vue_type_script_setup_true_lang.js +133 -0
- package/dist/components/BbRadio/types.d.ts +23 -9
- package/dist/components/BbRadioGroup/BbRadioGroup.vue.d.ts +4 -14
- package/dist/components/BbRadioGroup/BbRadioGroup.vue.js +6 -0
- package/dist/components/BbRadioGroup/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +184 -0
- package/dist/components/BbRadioGroup/types.d.ts +41 -22
- package/dist/components/BbRating/BbRating.vue.d.ts +4 -1
- package/dist/components/BbRating/BbRating.vue.js +6 -0
- package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +150 -0
- package/dist/components/BbRating/types.d.ts +37 -10
- package/dist/components/BbSelect/BbSelect.vue.d.ts +2 -11
- package/dist/components/BbSelect/BbSelect.vue.js +6 -0
- package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +241 -0
- package/dist/components/BbSelect/types.d.ts +105 -59
- package/dist/components/BbSelectPopover/BbSelectPopover.vue.d.ts +1 -10
- package/dist/components/BbSelectPopover/BbSelectPopover.vue.js +6 -0
- package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +637 -0
- package/dist/components/BbSelectPopover/types.d.ts +189 -102
- package/dist/components/BbSlider/BbSlider.vue.d.ts +3 -6
- package/dist/components/BbSlider/BbSlider.vue.js +6 -0
- package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +166 -0
- package/dist/components/BbSlider/types.d.ts +37 -13
- package/dist/components/BbSmoothHeight/BbSmoothHeight.vue.d.ts +3 -1
- package/dist/components/BbSmoothHeight/BbSmoothHeight.vue.js +6 -0
- package/dist/components/BbSmoothHeight/BbSmoothHeight.vue_vue_type_script_setup_true_lang.js +79 -0
- package/dist/components/BbSmoothHeight/types.d.ts +13 -2
- package/dist/components/BbSpinner/BbSpinner.vue.d.ts +1 -1
- package/dist/components/BbSpinner/BbSpinner.vue.js +6 -0
- package/dist/components/BbSpinner/BbSpinner.vue_vue_type_script_setup_true_lang.js +30 -0
- package/dist/components/BbSpinner/types.d.ts +10 -3
- package/dist/components/BbSwitch/BbSwitch.vue.d.ts +5 -3
- package/dist/components/BbSwitch/BbSwitch.vue.js +6 -0
- package/dist/components/BbSwitch/BbSwitch.vue_vue_type_script_setup_true_lang.js +142 -0
- package/dist/components/BbSwitch/types.d.ts +3 -1
- package/dist/components/BbSwitchGroup/BbSwitchGroup.vue.d.ts +4 -14
- package/dist/components/BbSwitchGroup/BbSwitchGroup.vue.js +6 -0
- package/dist/components/BbSwitchGroup/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +190 -0
- package/dist/components/BbSwitchGroup/types.d.ts +3 -22
- package/dist/components/BbTable/BbTable.vue.d.ts +53 -31
- package/dist/components/BbTable/BbTable.vue.js +6 -0
- package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +889 -0
- package/dist/components/BbTable/types.d.ts +176 -37
- package/dist/components/BbTable/utils.d.ts +9 -1
- package/dist/components/BbTable/utils.js +53 -0
- package/dist/components/BbTabs/BbTabs.vue.d.ts +20 -0
- package/dist/components/BbTabs/BbTabs.vue.js +6 -0
- package/dist/components/BbTabs/BbTabs.vue_vue_type_script_setup_true_lang.js +64 -0
- package/dist/components/BbTabs/BbTabsList.vue.d.ts +19 -0
- package/dist/components/BbTabs/BbTabsList.vue.js +6 -0
- package/dist/components/BbTabs/BbTabsList.vue_vue_type_script_setup_true_lang.js +123 -0
- package/dist/components/BbTabs/BbTabsPanes.vue.d.ts +16 -0
- package/dist/components/BbTabs/BbTabsPanes.vue.js +6 -0
- package/dist/components/BbTabs/BbTabsPanes.vue_vue_type_script_setup_true_lang.js +35 -0
- package/dist/components/BbTabs/BbTabsRoot.vue.d.ts +20 -0
- package/dist/components/BbTabs/BbTabsRoot.vue.js +5 -0
- package/dist/components/BbTabs/BbTabsRoot.vue_vue_type_script_setup_true_lang.js +55 -0
- package/dist/components/BbTabs/types.d.ts +264 -0
- package/dist/components/BbTag/BbTag.vue.d.ts +19 -6
- package/dist/components/BbTag/BbTag.vue.js +6 -0
- package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +187 -0
- package/dist/components/BbTag/types.d.ts +48 -17
- package/dist/components/BbTextInput/BbTextInput.vue.d.ts +10 -1
- package/dist/components/BbTextInput/BbTextInput.vue.js +6 -0
- package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +195 -0
- package/dist/components/BbTextInput/types.d.ts +24 -4
- package/dist/components/BbTextarea/BbTextarea.vue.d.ts +10 -1
- package/dist/components/BbTextarea/BbTextarea.vue.js +6 -0
- package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +178 -0
- package/dist/components/BbTextarea/types.d.ts +26 -2
- package/dist/components/BbTimePicker/BbTimePicker.vue.d.ts +33 -0
- package/dist/components/BbTimePicker/BbTimePicker.vue.js +6 -0
- package/dist/components/BbTimePicker/BbTimePicker.vue_vue_type_script_setup_true_lang.js +244 -0
- package/dist/components/BbTimePicker/types.d.ts +129 -0
- package/dist/components/BbTimePickerInput/BbTimePickerInput.vue.d.ts +25 -0
- package/dist/components/BbTimePickerInput/BbTimePickerInput.vue.js +6 -0
- package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +157 -0
- package/dist/components/BbTimePickerInput/types.d.ts +165 -0
- package/dist/components/BbToast/BbToast.vue.d.ts +2 -3
- package/dist/components/BbToast/BbToast.vue.js +6 -0
- package/dist/components/BbToast/BbToast.vue_vue_type_script_setup_true_lang.js +35 -0
- package/dist/components/BbToast/BbToastMessage.vue.d.ts +17 -8
- package/dist/components/BbToast/BbToastMessage.vue.js +5 -0
- package/dist/components/BbToast/BbToastMessage.vue_vue_type_script_setup_true_lang.js +170 -0
- package/dist/components/BbToast/BbToastPortal.vue.d.ts +30 -0
- package/dist/components/BbToast/BbToastPortal.vue.js +5 -0
- package/dist/components/BbToast/BbToastPortal.vue_vue_type_script_setup_true_lang.js +19 -0
- package/dist/components/BbToast/BbToastRegion.vue.d.ts +8 -0
- package/dist/components/BbToast/BbToastRegion.vue.js +5 -0
- package/dist/components/BbToast/BbToastRegion.vue_vue_type_script_setup_true_lang.js +100 -0
- package/dist/components/BbToast/types.d.ts +69 -5
- package/dist/components/BbTooltip/BbTooltip.vue.d.ts +4 -3
- package/dist/components/BbTooltip/BbTooltip.vue.js +6 -0
- package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +160 -0
- package/dist/components/BbTooltip/types.d.ts +61 -11
- package/dist/components/BbTree/BbTree.vue.d.ts +26 -13
- package/dist/components/BbTree/BbTree.vue.js +6 -0
- package/dist/components/BbTree/BbTree.vue_vue_type_script_setup_true_lang.js +55 -0
- package/dist/components/BbTree/BbTreeLevel.vue.d.ts +19 -0
- package/dist/components/BbTree/BbTreeLevel.vue.js +5 -0
- package/dist/components/BbTree/BbTreeLevel.vue_vue_type_script_setup_true_lang.js +94 -0
- package/dist/components/BbTree/context.d.ts +17 -0
- package/dist/components/BbTree/context.js +4 -0
- package/dist/components/BbTree/types.d.ts +93 -42
- package/dist/components/ChipsBox/ChipsBox.vue.d.ts +2 -1
- package/dist/components/ChipsBox/ChipsBox.vue.js +5 -0
- package/dist/components/ChipsBox/ChipsBox.vue_vue_type_script_setup_true_lang.js +98 -0
- package/dist/components/ChipsBox/types.d.ts +12 -5
- package/dist/components/ClearableButton/ClearableButton.vue.d.ts +2 -1
- package/dist/components/ClearableButton/ClearableButton.vue.js +6 -0
- package/dist/components/ClearableButton/ClearableButton.vue_vue_type_script_setup_true_lang.js +19 -0
- package/dist/components/ClearableButton/types.d.ts +7 -1
- package/dist/components/CloseIcon/CloseButton.vue.d.ts +5 -0
- package/dist/components/CloseIcon/CloseButton.vue.js +7 -0
- package/dist/components/CloseIcon/CloseButton.vue_vue_type_script_setup_true_lang.js +23 -0
- package/dist/components/CloseIcon/types.d.ts +2 -0
- package/dist/components/CommaBox/CommaBox.vue.d.ts +2 -1
- package/dist/components/CommaBox/CommaBox.vue.js +6 -0
- package/dist/components/CommaBox/CommaBox.vue_vue_type_script_setup_true_lang.js +81 -0
- package/dist/components/CommaBox/types.d.ts +6 -7
- package/dist/components/CommonInputWrapper/CommonInputWrapper.vue.d.ts +19 -0
- package/dist/components/CommonInputWrapper/CommonInputWrapper.vue.js +6 -0
- package/dist/components/CommonInputWrapper/CommonInputWrapper.vue_vue_type_script_setup_true_lang.js +107 -0
- package/dist/components/CommonInputWrapper/types.d.ts +96 -0
- package/dist/components/CommonPopover/CommonPopover.vue.d.ts +3 -3
- package/dist/components/CommonPopover/CommonPopover.vue.js +6 -0
- package/dist/components/CommonPopover/CommonPopover.vue_vue_type_script_setup_true_lang.js +160 -0
- package/dist/components/CommonPopover/types.d.ts +61 -16
- package/dist/components/ErrorIcon/ErrorIcon.vue.d.ts +2 -0
- package/dist/components/ErrorIcon/ErrorIcon.vue.js +6 -0
- package/dist/components/ErrorIcon/ErrorIcon.vue_vue_type_script_setup_true_lang.js +16 -0
- package/dist/components/FlatListBox/FlatListBox.vue.d.ts +2 -5
- package/dist/components/FlatListBox/FlatListBox.vue.js +5 -0
- package/dist/components/FlatListBox/FlatListBox.vue_vue_type_script_setup_true_lang.js +167 -0
- package/dist/components/FlatListBox/types.d.ts +1 -1
- package/dist/components/GroupedListBox/GroupedListBox.vue.d.ts +2 -5
- package/dist/components/GroupedListBox/GroupedListBox.vue.js +5 -0
- package/dist/components/GroupedListBox/GroupedListBox.vue_vue_type_script_setup_true_lang.js +218 -0
- package/dist/components/ListBox/ListBox.vue.d.ts +3 -6
- package/dist/components/ListBox/ListBox.vue.js +5 -0
- package/dist/components/ListBox/ListBox.vue_vue_type_script_setup_true_lang.js +112 -0
- package/dist/components/ListBox/types.d.ts +1 -1
- package/dist/components/OptionsContainer/OptionsContainer.vue.d.ts +1 -0
- package/dist/components/OptionsContainer/OptionsContainer.vue.js +5 -0
- package/dist/components/OptionsContainer/OptionsContainer.vue_vue_type_script_setup_true_lang.js +52 -0
- package/dist/components/OptionsContainer/types.d.ts +14 -24
- package/dist/components/Transitions/ScaleFade.vue.js +5 -0
- package/dist/components/Transitions/ScaleFade.vue_vue_type_script_setup_true_lang.js +47 -0
- package/dist/components/Transitions/Slide.vue.js +7 -0
- package/dist/components/Transitions/Slide.vue_vue_type_script_setup_true_lang.js +28 -0
- package/dist/components/WarningIcon/WarningIcon.vue.d.ts +5 -0
- package/dist/components/WarningIcon/WarningIcon.vue.js +6 -0
- package/dist/components/WarningIcon/WarningIcon.vue_vue_type_script_setup_true_lang.js +16 -0
- package/dist/components/WarningIcon/types.d.ts +3 -0
- package/dist/composables/__testResets.d.ts +1 -0
- package/dist/composables/useActiveInactiveState.d.ts +4 -0
- package/dist/composables/useActiveInactiveState.js +21 -0
- package/dist/composables/useBaseOptions.d.ts +3 -3
- package/dist/composables/useBaseOptions.js +31 -0
- package/dist/composables/useBbConfig.d.ts +8 -37
- package/dist/composables/useBbConfig.js +5 -0
- package/dist/composables/useBbDropdownContext.d.ts +89 -0
- package/dist/composables/useBbDropdownContext.js +46 -0
- package/dist/composables/useBbFormContext.d.ts +90 -0
- package/dist/composables/useBbFormContext.js +69 -0
- package/dist/composables/useBbTableContext.d.ts +195 -0
- package/dist/composables/useBbTableContext.js +208 -0
- package/dist/composables/useBbTabsContext.d.ts +111 -0
- package/dist/composables/useBbTabsContext.js +219 -0
- package/dist/composables/useBreakpoint.d.ts +13 -0
- package/dist/composables/useBreakpoint.js +39 -0
- package/dist/composables/useBroadcastChannelInstance.d.ts +1 -3
- package/dist/composables/useBroadcastChannelInstance.js +39 -0
- package/dist/composables/useCancelableFunction.js +37 -0
- package/dist/composables/useCoherence.js +16 -0
- package/dist/composables/useConfirm.d.ts +257 -67
- package/dist/composables/useConfirm.js +122 -0
- package/dist/composables/useCountdown.js +42 -0
- package/dist/composables/useHashedWatcher.d.ts +17 -0
- package/dist/composables/useHashedWatcher.js +14 -0
- package/dist/composables/useId.d.ts +3 -2
- package/dist/composables/useIndexById.js +16 -0
- package/dist/composables/useInertiaPage.d.ts +10 -0
- package/dist/composables/useInertiaPage.js +8 -0
- package/dist/composables/useItemText.js +17 -0
- package/dist/composables/useItemValue.js +9 -0
- package/dist/composables/useItemsGetter.d.ts +1 -1
- package/dist/composables/useItemsGetter.js +30 -0
- package/dist/composables/useListboxFocus.js +66 -0
- package/dist/composables/useLocale.d.ts +1 -1
- package/dist/composables/useLocale.js +11 -0
- package/dist/composables/useLogger.d.ts +1 -1
- package/dist/composables/useLogger.js +10 -0
- package/dist/composables/useMinimalQueue.d.ts +1 -1
- package/dist/composables/useMobile.js +7 -0
- package/dist/composables/useOnFalsy.d.ts +2 -0
- package/dist/composables/useOnFalsy.js +9 -0
- package/dist/composables/useOnTruthy.d.ts +7 -0
- package/dist/composables/useOnTruthy.js +9 -0
- package/dist/composables/usePrefill.d.ts +2 -1
- package/dist/composables/usePrefill.js +24 -0
- package/dist/composables/useQuery.d.ts +15 -3
- package/dist/composables/useQuery.js +42 -0
- package/dist/composables/useRoute.js +11 -0
- package/dist/composables/useRouter.js +8 -0
- package/dist/composables/useSafeArea.d.ts +51 -0
- package/dist/composables/useSafeArea.js +16 -0
- package/dist/composables/useSegmentedFields.d.ts +103 -0
- package/dist/composables/useSegmentedFields.js +152 -0
- package/dist/composables/useTableWidthContext.d.ts +5 -0
- package/dist/composables/useTableWidthContext.js +42 -0
- package/dist/composables/useToast.d.ts +17 -73
- package/dist/composables/useToast.js +49 -0
- package/dist/composables/useTopLayer.d.ts +9 -0
- package/dist/composables/useTopLayer.js +7 -0
- package/dist/composables/useUntil.js +13 -0
- package/dist/composables/useViewportWidth.d.ts +17 -0
- package/dist/composables/useViewportWidth.js +6 -0
- package/dist/confirm-variants.d.ts +10 -0
- package/dist/deprecation/ai-deprecations.json.d.ts +784 -0
- package/dist/deprecation/ai-deprecations.json.js +4 -0
- package/dist/deprecation/removedProps.d.ts +3 -0
- package/dist/deprecation/removedProps.js +13 -0
- package/dist/directives/bbColor.d.ts +65 -0
- package/dist/directives/bbColor.js +24 -0
- package/dist/directives/bbDate.d.ts +66 -0
- package/dist/directives/bbDate.js +24 -0
- package/dist/directives/bbDropdown.d.ts +15 -11
- package/dist/directives/bbDropdown.js +23 -0
- package/dist/directives/bbTime.d.ts +64 -0
- package/dist/directives/bbTime.js +24 -0
- package/dist/directives/bbTooltip.d.ts +16 -11
- package/dist/directives/bbTooltip.js +24 -0
- package/dist/dropdown-item-variants.d.ts +10 -0
- package/dist/i18n/index.d.ts +51 -3
- package/dist/i18n/index.js +27 -0
- package/dist/i18n/locales/cs.json +115 -0
- package/dist/i18n/locales/da.json +115 -0
- package/dist/i18n/locales/de.json +115 -0
- package/dist/i18n/locales/el.json +115 -0
- package/dist/i18n/locales/en.json +115 -0
- package/dist/i18n/locales/es.json +115 -0
- package/dist/i18n/locales/fi.json +115 -0
- package/dist/i18n/locales/fr.json +115 -0
- package/dist/i18n/locales/hu.json +115 -0
- package/dist/i18n/locales/it.json +115 -0
- package/dist/i18n/locales/ja.json +115 -0
- package/dist/i18n/locales/ko.json +115 -0
- package/dist/i18n/locales/nb.json +115 -0
- package/dist/i18n/locales/nl.json +115 -0
- package/dist/i18n/locales/pl.json +115 -0
- package/dist/i18n/locales/pt.json +115 -0
- package/dist/i18n/locales/ro.json +115 -0
- package/dist/i18n/locales/ru.json +115 -0
- package/dist/i18n/locales/sv.json +115 -0
- package/dist/i18n/locales/tr.json +115 -0
- package/dist/i18n/locales/uk.json +115 -0
- package/dist/i18n/locales/zh-cn.json +115 -0
- package/dist/icons-whitelist.d.ts +8 -0
- package/dist/index.d.ts +94 -79
- package/dist/index.js +76 -82
- package/dist/indicator-variants.d.ts +13 -0
- package/dist/llms-full.txt +77073 -0
- package/dist/llms-medium.txt +1334 -0
- package/dist/llms.txt +103 -0
- package/dist/locale-blueprint.json +141 -0
- package/dist/nuxt-module.d.ts +3 -0
- package/dist/nuxt.js +19 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.js +22 -0
- package/dist/reset.css +1 -0
- package/dist/reset.d.ts +0 -0
- package/dist/runtime/nuxt-plugin.d.ts +2 -0
- package/dist/runtime/nuxt-plugin.js +24 -0
- package/dist/styles.css +2 -0
- package/dist/styles.d.ts +0 -0
- package/dist/toast-variants.d.ts +13 -0
- package/dist/tooltip-variants.d.ts +10 -0
- package/dist/types/ActionButton.d.ts +32 -0
- package/dist/types/AlertVariant.d.ts +16 -0
- package/dist/types/BadgeVariant.d.ts +16 -0
- package/dist/types/ButtonVariant.d.ts +17 -0
- package/dist/types/Classes.d.ts +1 -1
- package/dist/types/ColumnName.d.ts +1 -1
- package/dist/types/CommonProps.d.ts +66 -279
- package/dist/types/Config.d.ts +84 -0
- package/dist/types/ConfirmVariant.d.ts +15 -0
- package/dist/types/DropdownItemVariant.d.ts +18 -0
- package/dist/types/Icon.d.ts +5 -7
- package/dist/types/IndicatorVariant.d.ts +16 -0
- package/dist/types/InputDirection.d.ts +15 -0
- package/dist/types/ItemAccessor.d.ts +21 -0
- package/dist/types/Placement.d.ts +6 -0
- package/dist/types/ResponsiveSize.d.ts +20 -0
- package/dist/types/SizeScale.d.ts +8 -0
- package/dist/types/ToastVariant.d.ts +17 -0
- package/dist/types/TooltipVariant.d.ts +18 -0
- package/dist/utilities/functions/bytesToUnit.d.ts +2 -0
- package/dist/utilities/functions/bytesToUnit.js +18 -0
- package/dist/utilities/functions/clampPrecision.js +10 -0
- package/dist/utilities/functions/convertDateValue.d.ts +23 -10
- package/dist/utilities/functions/convertDateValue.js +12 -0
- package/dist/utilities/functions/deburr.js +5 -0
- package/dist/utilities/functions/empty.js +5 -0
- package/dist/utilities/functions/flattenTree.d.ts +1 -1
- package/dist/utilities/functions/hash.js +5 -0
- package/dist/utilities/functions/isDateDisabled.d.ts +1 -0
- package/dist/utilities/functions/isDateDisabled.js +20 -0
- package/dist/utilities/functions/isEqual.js +5 -0
- package/dist/utilities/functions/isNotEmpty.js +5 -0
- package/dist/utilities/functions/matchAnyKey.d.ts +1 -1
- package/dist/utilities/functions/matchAnyKey.js +15 -0
- package/dist/utilities/functions/parseSize.d.ts +1 -1
- package/dist/utilities/functions/parseSize.js +15 -0
- package/dist/utilities/functions/percentage.js +11 -0
- package/dist/utilities/functions/pipe.d.ts +1 -1
- package/dist/utilities/functions/reject.d.ts +25 -0
- package/dist/utilities/functions/reject.js +28 -0
- package/dist/utilities/functions/resolveEnumProp.d.ts +19 -0
- package/dist/utilities/functions/resolveEnumProp.js +5 -0
- package/dist/utilities/functions/slotKey.d.ts +13 -0
- package/dist/utilities/functions/slotKey.js +4 -0
- package/dist/utilities/functions/sort.d.ts +2 -2
- package/dist/utilities/functions/sort.js +19 -0
- package/dist/utilities/functions/throttle.js +5 -0
- package/dist/utilities/functions/waitFor.d.ts +9 -2
- package/dist/utilities/functions/waitFor.js +14 -0
- package/dist/utilities/functions/warnRemovedAttrs.d.ts +11 -0
- package/dist/utilities/functions/warnRemovedAttrs.js +20 -0
- package/dist/utilities/functions/when.js +5 -0
- package/dist/utilities/misc/iconsInjectionKey.d.ts +15 -0
- package/dist/utilities/misc/iconsInjectionKey.js +4 -0
- package/dist/utilities/misc/transitions.d.ts +5 -0
- package/dist/utilities/misc/transitions.js +8 -0
- package/dist/utils/injectLibraryStyles.d.ts +6 -0
- package/dist/utils/injectLibraryStyles.js +38 -0
- package/dist/validated/BbCheckbox.vue.d.ts +29 -0
- package/dist/validated/BbCheckbox.vue.js +5 -0
- package/dist/validated/BbCheckbox.vue_vue_type_script_setup_true_lang.js +75 -0
- package/dist/validated/BbCheckboxGroup.vue.d.ts +34 -0
- package/dist/validated/BbCheckboxGroup.vue.js +5 -0
- package/dist/validated/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +76 -0
- package/dist/validated/BbColorInput.vue.d.ts +36 -0
- package/dist/validated/BbColorInput.vue.js +5 -0
- package/dist/validated/BbColorInput.vue_vue_type_script_setup_true_lang.js +71 -0
- package/dist/validated/BbDatePickerInput.vue.d.ts +40 -0
- package/dist/validated/BbDatePickerInput.vue.js +5 -0
- package/dist/validated/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +87 -0
- package/dist/validated/BbDropzone.vue.d.ts +24 -0
- package/dist/validated/BbDropzone.vue.js +5 -0
- package/dist/validated/BbDropzone.vue_vue_type_script_setup_true_lang.js +45 -0
- package/dist/validated/BbForm.vue.d.ts +28 -0
- package/dist/validated/BbForm.vue.js +5 -0
- package/dist/validated/BbForm.vue_vue_type_script_setup_true_lang.js +42 -0
- package/dist/validated/BbNumberInput.vue.d.ts +36 -0
- package/dist/validated/BbNumberInput.vue.js +5 -0
- package/dist/validated/BbNumberInput.vue_vue_type_script_setup_true_lang.js +72 -0
- package/dist/validated/BbRadioGroup.vue.d.ts +34 -0
- package/dist/validated/BbRadioGroup.vue.js +5 -0
- package/dist/validated/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +75 -0
- package/dist/validated/BbRating.vue.d.ts +30 -0
- package/dist/validated/BbRating.vue.js +5 -0
- package/dist/validated/BbRating.vue_vue_type_script_setup_true_lang.js +63 -0
- package/dist/validated/BbSelect.vue.d.ts +46 -0
- package/dist/validated/BbSelect.vue.js +5 -0
- package/dist/validated/BbSelect.vue_vue_type_script_setup_true_lang.js +100 -0
- package/dist/validated/BbSlider.vue.d.ts +36 -0
- package/dist/validated/BbSlider.vue.js +5 -0
- package/dist/validated/BbSlider.vue_vue_type_script_setup_true_lang.js +69 -0
- package/dist/validated/BbSwitch.vue.d.ts +29 -0
- package/dist/validated/BbSwitch.vue.js +5 -0
- package/dist/validated/BbSwitch.vue_vue_type_script_setup_true_lang.js +75 -0
- package/dist/validated/BbSwitchGroup.vue.d.ts +34 -0
- package/dist/validated/BbSwitchGroup.vue.js +5 -0
- package/dist/validated/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +76 -0
- package/dist/validated/BbTag.vue.d.ts +36 -0
- package/dist/validated/BbTag.vue.js +5 -0
- package/dist/validated/BbTag.vue_vue_type_script_setup_true_lang.js +72 -0
- package/dist/validated/BbTextInput.vue.d.ts +36 -0
- package/dist/validated/BbTextInput.vue.js +5 -0
- package/dist/validated/BbTextInput.vue_vue_type_script_setup_true_lang.js +72 -0
- package/dist/validated/BbTextarea.vue.d.ts +36 -0
- package/dist/validated/BbTextarea.vue.js +5 -0
- package/dist/validated/BbTextarea.vue_vue_type_script_setup_true_lang.js +70 -0
- package/dist/validated/BbTimePickerInput.vue.d.ts +36 -0
- package/dist/validated/BbTimePickerInput.vue.js +5 -0
- package/dist/validated/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +78 -0
- package/dist/validated/index.d.ts +29 -0
- package/dist/validated/useValidatedField.d.ts +52 -0
- package/dist/validated/useValidatedField.js +51 -0
- package/dist/validated.js +21 -0
- package/dist/vite-plugin.d.ts +217 -0
- package/dist/vite.js +530 -0
- package/llms.txt +105 -0
- package/package.json +161 -59
- package/scripts/lib/__fixtures__/validated-manifest.json +65 -0
- package/scripts/lib/ensure-manifest.mjs +39 -0
- package/scripts/lib/eslint-plugin-autofix.node.test.mjs +109 -0
- package/scripts/lib/eslint-plugin.mjs +285 -0
- package/scripts/lib/eslint-plugin.node.test.mjs +161 -0
- package/scripts/lib/html-attributes.mjs +191 -0
- package/scripts/lib/mcp-config.mjs +126 -0
- package/scripts/lib/migrate-fix.mjs +115 -0
- package/scripts/lib/validate-bb-markup.mjs +421 -0
- package/dist/ai/BaseButton.md +0 -449
- package/dist/ai/BaseCheckbox.md +0 -512
- package/dist/ai/BaseCheckboxGroup.md +0 -597
- package/dist/ai/BaseColorInput.md +0 -461
- package/dist/ai/BaseDatePicker.md +0 -739
- package/dist/ai/BaseDatePickerInput.md +0 -1517
- package/dist/ai/BaseDialog.md +0 -610
- package/dist/ai/BaseInputContainer.md +0 -570
- package/dist/ai/BaseNumberInput.md +0 -509
- package/dist/ai/BaseRadio.md +0 -405
- package/dist/ai/BaseRadioGroup.md +0 -535
- package/dist/ai/BaseRating.md +0 -489
- package/dist/ai/BaseSelect.md +0 -1742
- package/dist/ai/BaseSlider.md +0 -871
- package/dist/ai/BaseSwitch.md +0 -322
- package/dist/ai/BaseSwitchGroup.md +0 -298
- package/dist/ai/BaseTag.md +0 -623
- package/dist/ai/BaseTextInput.md +0 -392
- package/dist/ai/BaseTextarea.md +0 -398
- package/dist/ai/BbChip.md +0 -147
- package/dist/ai/BbIntersection.md +0 -120
- package/dist/ai/BbRatio.md +0 -61
- package/dist/ai/BbRows.md +0 -307
- package/dist/ai/BbTab.md +0 -950
- package/dist/ai/CommonInputInnerContainer.md +0 -414
- package/dist/ai/CommonInputOuterContainer.md +0 -55
- package/dist/components/BaseButton/BaseButton.vue.d.ts +0 -14
- package/dist/components/BaseButton/types.d.ts +0 -159
- package/dist/components/BaseCheckbox/BaseCheckbox.vue.d.ts +0 -39
- package/dist/components/BaseCheckbox/types.d.ts +0 -213
- package/dist/components/BaseCheckboxGroup/BaseCheckboxGroup.vue.d.ts +0 -30
- package/dist/components/BaseCheckboxGroup/types.d.ts +0 -282
- package/dist/components/BaseColorInput/BaseColorInput.vue.d.ts +0 -35
- package/dist/components/BaseColorInput/ColorPalette.vue.d.ts +0 -13
- package/dist/components/BaseColorInput/types.d.ts +0 -233
- package/dist/components/BaseDatePicker/BaseDatePickerHeader.vue.d.ts +0 -15
- package/dist/components/BaseDatePicker/BaseDatePickerInputDaySelector.vue.d.ts +0 -58
- package/dist/components/BaseDatePicker/BaseDatePickerMonthSelector.vue.d.ts +0 -12
- package/dist/components/BaseDatePicker/BaseDatePickerYearSelector.vue.d.ts +0 -12
- package/dist/components/BaseDatePicker/types.d.ts +0 -100
- package/dist/components/BaseDatePickerInput/BaseDatePickerInput.vue.d.ts +0 -26
- package/dist/components/BaseDatePickerInput/types.d.ts +0 -206
- package/dist/components/BaseDialog/BaseDialog.vue.d.ts +0 -37
- package/dist/components/BaseDialog/types.d.ts +0 -180
- package/dist/components/BaseInputContainer/BaseInputContainer.vue.d.ts +0 -18
- package/dist/components/BaseInputContainer/types.d.ts +0 -126
- package/dist/components/BaseNumberInput/BaseNumberInput.vue.d.ts +0 -46
- package/dist/components/BaseNumberInput/types.d.ts +0 -191
- package/dist/components/BaseRadio/BaseRadio.vue.d.ts +0 -31
- package/dist/components/BaseRadio/types.d.ts +0 -173
- package/dist/components/BaseRadioGroup/BaseRadioGroup.vue.d.ts +0 -30
- package/dist/components/BaseRadioGroup/types.d.ts +0 -240
- package/dist/components/BaseRating/BaseRating.vue.d.ts +0 -35
- package/dist/components/BaseRating/types.d.ts +0 -144
- package/dist/components/BaseSelect/BaseSelect.vue.d.ts +0 -28
- package/dist/components/BaseSelect/types.d.ts +0 -470
- package/dist/components/BaseSlider/BaseSlider.vue.d.ts +0 -38
- package/dist/components/BaseSlider/types.d.ts +0 -201
- package/dist/components/BaseSwitch/BaseSwitch.vue.d.ts +0 -34
- package/dist/components/BaseSwitch/types.d.ts +0 -25
- package/dist/components/BaseSwitchGroup/BaseSwitchGroup.vue.d.ts +0 -30
- package/dist/components/BaseSwitchGroup/types.d.ts +0 -8
- package/dist/components/BaseTag/BaseTag.vue.d.ts +0 -37
- package/dist/components/BaseTag/types.d.ts +0 -136
- package/dist/components/BaseTextInput/BaseTextInput.vue.d.ts +0 -33
- package/dist/components/BaseTextInput/types.d.ts +0 -166
- package/dist/components/BaseTextarea/BaseTextarea.vue.d.ts +0 -31
- package/dist/components/BaseTextarea/types.d.ts +0 -151
- package/dist/components/BbChip/BbChip.vue.d.ts +0 -17
- package/dist/components/BbChip/types.d.ts +0 -23
- package/dist/components/BbIntersection/BbIntersection.vue.d.ts +0 -23
- package/dist/components/BbIntersection/types.d.ts +0 -36
- package/dist/components/BbRatio/BbRatio.vue.d.ts +0 -14
- package/dist/components/BbRatio/types.d.ts +0 -15
- package/dist/components/BbRows/BbRows.vue.d.ts +0 -62
- package/dist/components/BbRows/types.d.ts +0 -21
- package/dist/components/BbTab/BbTab.vue.d.ts +0 -27
- package/dist/components/BbTab/types.d.ts +0 -186
- package/dist/components/CommonInputInnerContainer/CommonInputInnerContainer.vue.d.ts +0 -15
- package/dist/components/CommonInputInnerContainer/types.d.ts +0 -47
- package/dist/components/CommonInputOuterContainer/CommonInputOuterContainer.vue.d.ts +0 -11
- package/dist/components/CommonInputOuterContainer/types.d.ts +0 -16
- package/dist/composables/useModalsState.d.ts +0 -5
- package/dist/composables/useQueue.d.ts +0 -58
- package/dist/composables/useWizard.d.ts +0 -85
- package/dist/i18n/en.d.ts +0 -67
- package/dist/i18n/it.d.ts +0 -67
- package/dist/index.css +0 -2
- package/dist/index100.js +0 -6
- package/dist/index101.js +0 -300
- package/dist/index102.js +0 -16
- package/dist/index103.js +0 -16
- package/dist/index104.js +0 -27
- package/dist/index109.js +0 -19
- package/dist/index11.js +0 -42
- package/dist/index110.js +0 -12
- package/dist/index111.js +0 -19
- package/dist/index112.js +0 -25
- package/dist/index114.js +0 -7
- package/dist/index115.js +0 -241
- package/dist/index116.js +0 -5
- package/dist/index117.js +0 -42
- package/dist/index118.js +0 -5
- package/dist/index119.js +0 -53
- package/dist/index120.js +0 -5
- package/dist/index121.js +0 -32
- package/dist/index122.js +0 -5
- package/dist/index124.js +0 -52
- package/dist/index125.js +0 -5
- package/dist/index126.js +0 -223
- package/dist/index128.js +0 -6
- package/dist/index129.js +0 -162
- package/dist/index13.js +0 -92
- package/dist/index130.js +0 -25
- package/dist/index131.js +0 -51
- package/dist/index132.js +0 -5
- package/dist/index133.js +0 -607
- package/dist/index135.js +0 -6
- package/dist/index136.js +0 -14
- package/dist/index137.js +0 -153
- package/dist/index139.js +0 -6
- package/dist/index14.js +0 -306
- package/dist/index140.js +0 -224
- package/dist/index141.js +0 -5
- package/dist/index143.js +0 -128
- package/dist/index145.js +0 -6
- package/dist/index146.js +0 -8
- package/dist/index147.js +0 -182
- package/dist/index149.js +0 -6
- package/dist/index15.js +0 -10
- package/dist/index151.js +0 -4
- package/dist/index152.js +0 -95
- package/dist/index154.js +0 -6
- package/dist/index155.js +0 -168
- package/dist/index157.js +0 -6
- package/dist/index158.js +0 -145
- package/dist/index16.js +0 -59
- package/dist/index160.js +0 -6
- package/dist/index161.js +0 -53
- package/dist/index163.js +0 -6
- package/dist/index164.js +0 -16
- package/dist/index166.js +0 -35
- package/dist/index168.js +0 -6
- package/dist/index169.js +0 -89
- package/dist/index171.js +0 -6
- package/dist/index172.js +0 -82
- package/dist/index174.js +0 -6
- package/dist/index175.js +0 -38
- package/dist/index176.js +0 -461
- package/dist/index177.js +0 -28
- package/dist/index178.js +0 -66
- package/dist/index18.js +0 -35
- package/dist/index180.js +0 -162
- package/dist/index181.js +0 -5
- package/dist/index182.js +0 -217
- package/dist/index183.js +0 -5
- package/dist/index184.js +0 -112
- package/dist/index185.js +0 -5
- package/dist/index186.js +0 -459
- package/dist/index188.js +0 -6
- package/dist/index19.js +0 -4
- package/dist/index192.js +0 -268
- package/dist/index194.js +0 -6
- package/dist/index195.js +0 -124
- package/dist/index197.js +0 -6
- package/dist/index198.js +0 -174
- package/dist/index2.js +0 -20
- package/dist/index20.js +0 -9
- package/dist/index200.js +0 -6
- package/dist/index201.js +0 -224
- package/dist/index203.js +0 -6
- package/dist/index204.js +0 -135
- package/dist/index206.js +0 -6
- package/dist/index207.js +0 -5
- package/dist/index208.js +0 -170
- package/dist/index21.js +0 -35
- package/dist/index210.js +0 -6
- package/dist/index211.js +0 -37
- package/dist/index213.js +0 -6
- package/dist/index214.js +0 -63
- package/dist/index216.js +0 -6
- package/dist/index217.js +0 -74
- package/dist/index219.js +0 -6
- package/dist/index22.js +0 -6
- package/dist/index220.js +0 -65
- package/dist/index222.js +0 -6
- package/dist/index223.js +0 -67
- package/dist/index225.js +0 -6
- package/dist/index226.js +0 -41
- package/dist/index228.js +0 -6
- package/dist/index229.js +0 -10
- package/dist/index23.js +0 -7
- package/dist/index230.js +0 -22
- package/dist/index232.js +0 -8
- package/dist/index233.js +0 -297
- package/dist/index235.js +0 -6
- package/dist/index236.js +0 -47
- package/dist/index237.js +0 -165
- package/dist/index239.js +0 -6
- package/dist/index24.js +0 -9
- package/dist/index241.js +0 -159
- package/dist/index243.js +0 -6
- package/dist/index244.js +0 -134
- package/dist/index246.js +0 -6
- package/dist/index247.js +0 -167
- package/dist/index249.js +0 -6
- package/dist/index25.js +0 -24
- package/dist/index250.js +0 -147
- package/dist/index252.js +0 -6
- package/dist/index253.js +0 -35
- package/dist/index255.js +0 -6
- package/dist/index256.js +0 -65
- package/dist/index258.js +0 -6
- package/dist/index259.js +0 -19
- package/dist/index260.js +0 -5
- package/dist/index261.js +0 -160
- package/dist/index263.js +0 -6
- package/dist/index264.js +0 -60
- package/dist/index266.js +0 -6
- package/dist/index267.js +0 -134
- package/dist/index269.js +0 -6
- package/dist/index27.js +0 -4
- package/dist/index271.js +0 -206
- package/dist/index273.js +0 -6
- package/dist/index274.js +0 -85
- package/dist/index275.js +0 -5
- package/dist/index276.js +0 -55
- package/dist/index277.js +0 -5
- package/dist/index278.js +0 -164
- package/dist/index28.js +0 -8
- package/dist/index280.js +0 -6
- package/dist/index281.js +0 -145
- package/dist/index283.js +0 -6
- package/dist/index284.js +0 -11
- package/dist/index285.js +0 -200
- package/dist/index287.js +0 -6
- package/dist/index288.js +0 -241
- package/dist/index29.js +0 -7
- package/dist/index290.js +0 -6
- package/dist/index291.js +0 -21
- package/dist/index293.js +0 -6
- package/dist/index294.js +0 -125
- package/dist/index296.js +0 -6
- package/dist/index297.js +0 -161
- package/dist/index299.js +0 -6
- package/dist/index30.js +0 -118
- package/dist/index300.js +0 -127
- package/dist/index302.js +0 -6
- package/dist/index303.js +0 -20
- package/dist/index305.js +0 -6
- package/dist/index306.js +0 -116
- package/dist/index307.js +0 -5
- package/dist/index308.js +0 -507
- package/dist/index31.js +0 -10
- package/dist/index310.js +0 -6
- package/dist/index311.js +0 -196
- package/dist/index313.js +0 -6
- package/dist/index314.js +0 -142
- package/dist/index316.js +0 -6
- package/dist/index317.js +0 -134
- package/dist/index319.js +0 -6
- package/dist/index32.js +0 -28
- package/dist/index320.js +0 -162
- package/dist/index322.js +0 -6
- package/dist/index323.js +0 -319
- package/dist/index325.js +0 -6
- package/dist/index326.js +0 -40
- package/dist/index327.js +0 -43
- package/dist/index328.js +0 -665
- package/dist/index33.js +0 -5
- package/dist/index330.js +0 -6
- package/dist/index331.js +0 -155
- package/dist/index333.js +0 -6
- package/dist/index334.js +0 -142
- package/dist/index336.js +0 -6
- package/dist/index337.js +0 -155
- package/dist/index339.js +0 -6
- package/dist/index34.js +0 -112
- package/dist/index340.js +0 -58
- package/dist/index341.js +0 -5
- package/dist/index342.js +0 -20
- package/dist/index344.js +0 -6
- package/dist/index345.js +0 -142
- package/dist/index347.js +0 -6
- package/dist/index349.js +0 -109
- package/dist/index351.js +0 -6
- package/dist/index353.js +0 -24
- package/dist/index354.js +0 -23
- package/dist/index355.js +0 -839
- package/dist/index356.js +0 -474
- package/dist/index357.js +0 -52
- package/dist/index358.js +0 -7
- package/dist/index36.js +0 -6
- package/dist/index38.js +0 -63
- package/dist/index39.js +0 -63
- package/dist/index40.js +0 -9
- package/dist/index42.js +0 -8
- package/dist/index43.js +0 -179
- package/dist/index44.js +0 -21
- package/dist/index46.js +0 -385
- package/dist/index48.js +0 -6
- package/dist/index49.js +0 -33
- package/dist/index5.js +0 -34
- package/dist/index50.js +0 -12
- package/dist/index51.js +0 -8
- package/dist/index52.js +0 -106
- package/dist/index53.js +0 -330
- package/dist/index54.js +0 -97
- package/dist/index55.js +0 -328
- package/dist/index56.js +0 -28
- package/dist/index57.js +0 -102
- package/dist/index58.js +0 -157
- package/dist/index6.js +0 -38
- package/dist/index60.js +0 -6
- package/dist/index61.js +0 -131
- package/dist/index62.js +0 -5
- package/dist/index65.js +0 -35
- package/dist/index66.js +0 -26
- package/dist/index68.js +0 -6
- package/dist/index69.js +0 -54
- package/dist/index7.js +0 -58
- package/dist/index71.js +0 -6
- package/dist/index72.js +0 -14
- package/dist/index74.js +0 -6
- package/dist/index75.js +0 -159
- package/dist/index77.js +0 -6
- package/dist/index78.js +0 -4
- package/dist/index79.js +0 -4
- package/dist/index80.js +0 -54
- package/dist/index81.js +0 -5
- package/dist/index82.js +0 -5
- package/dist/index83.js +0 -141
- package/dist/index85.js +0 -6
- package/dist/index86.js +0 -65
- package/dist/index88.js +0 -6
- package/dist/index89.js +0 -30
- package/dist/index9.js +0 -11
- package/dist/index90.js +0 -19
- package/dist/index91.js +0 -17
- package/dist/index92.js +0 -9
- package/dist/index93.js +0 -34
- package/dist/index95.js +0 -16
- package/dist/index96.js +0 -10
- package/dist/index97.js +0 -18
- package/dist/index98.js +0 -189
- package/dist/types/VoidHtmlElements.d.ts +0 -1
- package/dist/utilities/functions/add.d.ts +0 -1
- package/dist/utilities/functions/booleanishToBoolean.d.ts +0 -6
- package/dist/utilities/functions/capitalize.d.ts +0 -4
- package/dist/utilities/functions/cloneDeep.d.ts +0 -1
- package/dist/utilities/functions/debounce.d.ts +0 -1
- package/dist/utilities/functions/drop.d.ts +0 -1
- package/dist/utilities/functions/exceedsPrecision.d.ts +0 -1
- package/dist/utilities/functions/findRight.d.ts +0 -4
- package/dist/utilities/functions/findRightIndex.d.ts +0 -4
- package/dist/utilities/functions/flow.d.ts +0 -1
- package/dist/utilities/functions/getHueFromRGB.d.ts +0 -9
- package/dist/utilities/functions/groupBy.d.ts +0 -6
- package/dist/utilities/functions/gt.d.ts +0 -7
- package/dist/utilities/functions/hexToRGB.d.ts +0 -7
- package/dist/utilities/functions/hslToHex.d.ts +0 -1
- package/dist/utilities/functions/includes.d.ts +0 -1
- package/dist/utilities/functions/initial.d.ts +0 -1
- package/dist/utilities/functions/isCssColor.d.ts +0 -5
- package/dist/utilities/functions/lt.d.ts +0 -7
- package/dist/utilities/functions/makeUrl.d.ts +0 -1
- package/dist/utilities/functions/mapKeys.d.ts +0 -5
- package/dist/utilities/functions/mapValues.d.ts +0 -1
- package/dist/utilities/functions/matchesPropertyInsensitive.d.ts +0 -1
- package/dist/utilities/functions/max.d.ts +0 -2
- package/dist/utilities/functions/mean.d.ts +0 -4
- package/dist/utilities/functions/merge.d.ts +0 -11
- package/dist/utilities/functions/millisecondsTo.d.ts +0 -1
- package/dist/utilities/functions/negate.d.ts +0 -4
- package/dist/utilities/functions/normalizeItemGroups.d.ts +0 -13
- package/dist/utilities/functions/omit.d.ts +0 -2
- package/dist/utilities/functions/overEvery.d.ts +0 -4
- package/dist/utilities/functions/pick.d.ts +0 -1
- package/dist/utilities/functions/replace.d.ts +0 -1
- package/dist/utilities/functions/replaceInTree.d.ts +0 -4
- package/dist/utilities/functions/retry.d.ts +0 -5
- package/dist/utilities/functions/roundToTheNearest.d.ts +0 -8
- package/dist/utilities/functions/set.d.ts +0 -15
- package/dist/utilities/functions/stub.d.ts +0 -6
- package/dist/utilities/functions/transposePercent.d.ts +0 -9
- package/dist/utilities/functions/tryTo.d.ts +0 -2
- package/dist/utilities/functions/uniqBy.d.ts +0 -1
- /package/dist/{index64.js → _virtual/_plugin-vue_export-helper.js} +0 -0
- /package/dist/components/{BaseButton → BbBaseButton}/RouterComponent.vue.d.ts +0 -0
- /package/dist/components/{BaseDatePicker/BaseDatePicker.vue.d.ts → BbBaseDatePicker/BbBaseDatePicker.vue.d.ts} +0 -0
- /package/dist/{index165.js → composables/useArray.js} +0 -0
- /package/dist/{index17.js → composables/useFrameworkDetection.js} +0 -0
- /package/dist/{index12.js → composables/useId.js} +0 -0
- /package/dist/{index352.js → directives/createPopoverDirective.js} +0 -0
- /package/dist/{index107.js → utilities/functions/chunk.js} +0 -0
- /package/dist/{index8.js → utilities/functions/clamp.js} +0 -0
- /package/dist/{index150.js → utilities/functions/curry.js} +0 -0
- /package/dist/{index45.js → utilities/functions/extractDomContainer.js} +0 -0
- /package/dist/{index270.js → utilities/functions/findInTree.js} +0 -0
- /package/dist/{index348.js → utilities/functions/flattenTree.js} +0 -0
- /package/dist/{index41.js → utilities/functions/get.js} +0 -0
- /package/dist/{index189.js → utilities/functions/head.js} +0 -0
- /package/dist/{index108.js → utilities/functions/identity.js} +0 -0
- /package/dist/{index179.js → utilities/functions/indexBy.js} +0 -0
- /package/dist/{index37.js → utilities/functions/isHex.js} +0 -0
- /package/dist/{index94.js → utilities/functions/isNil.js} +0 -0
- /package/dist/{index26.js → utilities/functions/isNotNil.js} +0 -0
- /package/dist/{index105.js → utilities/functions/last.js} +0 -0
- /package/dist/{index142.js → utilities/functions/noop.js} +0 -0
- /package/dist/{index231.js → utilities/functions/parseWidthString.js} +0 -0
- /package/dist/{index240.js → utilities/functions/pickBy.js} +0 -0
- /package/dist/{index123.js → utilities/functions/range.js} +0 -0
- /package/dist/{index190.js → utilities/functions/snapToStep.js} +0 -0
- /package/dist/{index191.js → utilities/functions/transpose.js} +0 -0
- /package/dist/{index106.js → utilities/functions/validateDateFormat.js} +0 -0
- /package/dist/{index10.js → utilities/functions/wait.js} +0 -0
|
@@ -0,0 +1,1690 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Inline-Edit Workspace (Nuxt)
|
|
3
|
+
summary: Linear-style sprint backlog for Nuxt where every cell autosaves — optimistic per-field overlay with rollback, commit-on-blur text cells, spinner-in-the-chevron badge pickers, an async assignee search, bulk bar and peek workbench, filters URL-synced and data fetched with useAsyncData (the overlay retires in its transform), all through one coopting page context.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Recipe: Inline-Edit Workspace (Nuxt)
|
|
7
|
+
|
|
8
|
+
The flagship of pattern **§6.8 — autosave cells**, adapted for **Nuxt**: a
|
|
9
|
+
Linear-grade sprint backlog where **every cell persists itself and the page
|
|
10
|
+
has no Save button anywhere**. Change a status, retype a title, clear an
|
|
11
|
+
estimate — it is already saved, or it has already rolled back and told you.
|
|
12
|
+
Filters and the active tab live in the URL, the list loads through
|
|
13
|
+
`useAsyncData` watching `route.query`, and the optimistic overlay retires in
|
|
14
|
+
that fetch's `transform`; every mutation ends in `refresh()`. Anatomy,
|
|
15
|
+
components, the context shape, copy and data are identical to the Vue
|
|
16
|
+
recipe; only the data/URL/mutation layer changes.
|
|
17
|
+
|
|
18
|
+
Domain: **Sprint 24** of a product team — fourteen issues (`BB-227` …
|
|
19
|
+
`BB-241`), four statuses, three priorities, a six-member team (Sofia Reyes,
|
|
20
|
+
Jonah Weiss, Priya Natarajan, Tom Okafor, Elif Demir, Marco Bianchi).
|
|
21
|
+
Deliberately distinct from the invoices/members/expenses of the sibling
|
|
22
|
+
recipes.
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
Components: [BbTable](../../BbTable.md) ·
|
|
27
|
+
[BbSelectPopover](../../BbSelectPopover.md) (§ One popover per table row is
|
|
28
|
+
load-bearing here) · [BbBadge](../../BbBadge.md) (the `loading` /
|
|
29
|
+
`append:icon` interplay).
|
|
30
|
+
|
|
31
|
+
Guides: [Inline Edit Playbook](../../guides/inline-edit-playbook.md) (who owns
|
|
32
|
+
the edit — this page is the autosave answer) ·
|
|
33
|
+
[Design language](../../guides/design-language.md) (§ Using color, § Badges
|
|
34
|
+
label state) · [Page Shell](../../guides/page-shell.md) ·
|
|
35
|
+
[Floating Bottom Panel](../../guides/floating-bottom-panel.md).
|
|
36
|
+
|
|
37
|
+
Siblings: [vue](../vue/inline-edit-workspace.md) ·
|
|
38
|
+
[inertia](../inertia/inline-edit-workspace.md).
|
|
39
|
+
|
|
40
|
+
Platform assumptions: `<BbConfirm />` and `<BbToast />` mounted once in
|
|
41
|
+
`app.vue`; the layout chrome from the guides copied into
|
|
42
|
+
`src/components/layout/`. Server routes: `GET /api/issues` (accepts
|
|
43
|
+
`search`, `status[]`, `priority[]`, `assignee`, `tab`, `page`, `perPage`;
|
|
44
|
+
returns `{ data, total, tabCounts }`); `GET /api/members` (`search`; the
|
|
45
|
+
team directory) and `GET /api/members/:id`; plus the mutation routes
|
|
46
|
+
referenced below (`PATCH /api/issues/:id`, `POST /api/issues/:id/duplicate`,
|
|
47
|
+
`POST /api/issues/move-to-next-sprint`, `PATCH /api/issues/bulk`,
|
|
48
|
+
`DELETE /api/issues/:id`).
|
|
49
|
+
|
|
50
|
+
## Key ideas
|
|
51
|
+
|
|
52
|
+
- **No Save button anywhere.** Every cell commits itself through one context
|
|
53
|
+
action, `persistField(issue, key, value)` — optimistic write, single-field
|
|
54
|
+
PATCH, refetch; failure rolls back just that field and toasts. Nothing on
|
|
55
|
+
the page is ever "changed but unsaved", so there is no dirty ring and no
|
|
56
|
+
dirty-gated button — the only transient state is _saving_, and the spinner
|
|
57
|
+
carries it.
|
|
58
|
+
- **The optimistic overlay is page state, not cell state.** `pending` maps
|
|
59
|
+
`issue.id → { field: value }` on **rung 3** of the state ladder: the grid
|
|
60
|
+
cells, the peek workbench _and the fetch itself_ all read it. This is the
|
|
61
|
+
deliberate contrast with the one-shot §6.1 status cell (see
|
|
62
|
+
`records-workspace`), whose `saving` flag is a rung-1 local ref — in an
|
|
63
|
+
autosave grid the fetch must also know what is in flight, so the flag
|
|
64
|
+
cannot live inside a cell.
|
|
65
|
+
- **The overlay is retired in the fetch's `transform`, never when a save
|
|
66
|
+
resolves** — and only for fields the response actually confirms. Retiring
|
|
67
|
+
on save-resolve makes the cell flash new → old → new for the whole reload,
|
|
68
|
+
because the table still holds the stale row until the refetch lands.
|
|
69
|
+
- **Typed inputs commit on `@change` (blur/Enter), never `v-model`.** A
|
|
70
|
+
`v-model` autosave is one request per keystroke. Pickers commit on pick —
|
|
71
|
+
the click already _is_ the commit.
|
|
72
|
+
- **One coopting page context.** `provideBacklogWorkspace()` joins the
|
|
73
|
+
page-shell stack and the table context once, owns filters/tab/overlay, and
|
|
74
|
+
exposes complete actions. Eleven components share everything through one
|
|
75
|
+
`useBacklogWorkspace()` call — zero prop drilling.
|
|
76
|
+
- **Filters and tab live in the URL, not in local-only refs.** They are
|
|
77
|
+
seeded from `route.query` at setup and every change mirrors back through
|
|
78
|
+
`navigateTo` (debounced for free text); `useAsyncData('issues', …)`
|
|
79
|
+
watching `route.query` is the single refetch trigger, and its own
|
|
80
|
+
`refresh()` is the one imperative reload every mutation calls. The page is
|
|
81
|
+
bookmarkable mid-triage and survives reload.
|
|
82
|
+
- **Options resolve once, at page level.** Status and priority are static
|
|
83
|
+
module-level catalogs (fifty rows, zero requests); the assignee picker
|
|
84
|
+
shares **one** query provider across every row, so unopened rows cost
|
|
85
|
+
nothing.
|
|
86
|
+
- **Status is color, per the soft palette.** The registered `soft-*` badge
|
|
87
|
+
variants label the closed status/priority sets; the internal trailing
|
|
88
|
+
chevron says "clickable", and the badge's `loading` swaps the spinner into
|
|
89
|
+
the chevron's place while that one field saves.
|
|
90
|
+
- **Buttons are `md` by default**; `sm` appears only in row actions, the
|
|
91
|
+
filter pills, the peek footer and the bulk bar. Internal navigation
|
|
92
|
+
(`New issue`, the peek's `Open full page`) uses `to`, Nuxt's Vue Router
|
|
93
|
+
prop, instead of a raw `href`.
|
|
94
|
+
|
|
95
|
+
## Page anatomy
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
BacklogWorkspace/
|
|
99
|
+
Index.vue ← assembly: PageShell slots, table, tabs, pagination
|
|
100
|
+
context.ts ← coopts shell + table ctx; owns URL-synced filters + the pending overlay + persistField
|
|
101
|
+
FilterRail.vue ← status / priority / assignee filter pills + clear-all
|
|
102
|
+
EditableTitleCell.vue ← commit-on-blur text (@change, never v-model)
|
|
103
|
+
EstimateCell.vue ← commit-on-change number cell
|
|
104
|
+
StatusCell.vue ← editable soft badge (chevron at rest, spinner in flight)
|
|
105
|
+
PriorityCell.vue ← same grammar, its own leaf (§6.3: never one EditableCell with a type prop)
|
|
106
|
+
AssigneeCell.vue ← provider-backed people picker badge (ONE shared query fn)
|
|
107
|
+
RowActions.vue ← … dropdown: duplicate, move to next sprint, delete (confirm)
|
|
108
|
+
SelectionBar.vue ← bulk status / bulk assign / bulk move (floating bottom panel)
|
|
109
|
+
IssuePeek.vue ← peek workbench reusing the SAME Status/Priority/Assignee cells
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Chrome assumed from the guides: `AppLayout` (left nav + fat footer),
|
|
113
|
+
`PageShell`, `FloatingBottomPanel`. Note what is _missing_ compared to the
|
|
114
|
+
records workspace: there is no dialog component and the shell's `#dialogs`
|
|
115
|
+
slot stays empty — on an autosave page the grid _is_ the form, so nothing
|
|
116
|
+
needs a modal to edit.
|
|
117
|
+
|
|
118
|
+
## Action inventory
|
|
119
|
+
|
|
120
|
+
| # | Action | Trigger | Mechanism |
|
|
121
|
+
| --- | ------------------------ | ---------------------------------- | ---------------------------------------------------- |
|
|
122
|
+
| 1 | New issue | topbar, the page's one `primary` | navigation (`to="/issues/new"`) |
|
|
123
|
+
| 2 | Page search | topbar right | `filters.search` → URL → `useAsyncData` refetch |
|
|
124
|
+
| 3 | Switch sprint tab | href tabs with live counts | URL + `useAsyncData` refetch |
|
|
125
|
+
| 4 | Filter by status | rail pill | `BbSelectPopover` multiple over the static catalog |
|
|
126
|
+
| 5 | Filter by priority | rail pill | `BbSelectPopover` multiple over the static catalog |
|
|
127
|
+
| 6 | Filter by assignee | rail pill | the shared people provider, single select |
|
|
128
|
+
| 7 | Clear filters | rail right (only when active) | context `clearFilters()` |
|
|
129
|
+
| 8 | Rename issue | title cell (grid) | commit-on-blur `@change` → `persistField('title')` |
|
|
130
|
+
| 9 | Re-estimate | estimate cell (grid) | commit-on-change number → `persistField('estimate')` |
|
|
131
|
+
| 10 | Change status | status badge (grid **and** peek) | pick = commit; spinner in the chevron (§6.8) |
|
|
132
|
+
| 11 | Change priority | priority badge (grid **and** peek) | same grammar, its own leaf |
|
|
133
|
+
| 12 | Reassign | assignee badge (grid **and** peek) | async people search; one shared provider |
|
|
134
|
+
| 13 | Peek issue | issue ref cell | `peekIssue(id)` → shell stack |
|
|
135
|
+
| 14 | Duplicate | row `…` dropdown | context action + toast |
|
|
136
|
+
| 15 | Move to next sprint | row `…` **and** bulk bar | `moveToNextSprint` / `bulkMoveToNextSprint` |
|
|
137
|
+
| 16 | Delete | row `…`, peek footer | destructive behind `useConfirm` |
|
|
138
|
+
| 17 | Bulk set status | bottom panel picker | `bulkStatus` on `table.selected` |
|
|
139
|
+
| 18 | Bulk assign | bottom panel picker | `bulkAssign` on `table.selected` |
|
|
140
|
+
| 19 | Select rows / select all | table checkboxes | table context |
|
|
141
|
+
| 20 | Open full issue | peek footer | navigation (`to="/issues/:id"`) |
|
|
142
|
+
| 21 | Close peek | shell chrome | shell stack close |
|
|
143
|
+
|
|
144
|
+
Rows 8–12 are the recipe's reason to exist: five editable fields of three
|
|
145
|
+
different control kinds, each persisting itself, two of them able to be in
|
|
146
|
+
flight **on the same row at the same time**.
|
|
147
|
+
|
|
148
|
+
## The code
|
|
149
|
+
|
|
150
|
+
### Project setup — the soft status palette
|
|
151
|
+
|
|
152
|
+
Status and priority are small closed sets — the textbook case for the soft
|
|
153
|
+
semantic accents. The names are registered in the Nuxt module (that makes
|
|
154
|
+
them type-check as `BbBadge` variants); the CSS is the project's own,
|
|
155
|
+
kept in a stylesheet separate from the library defaults:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
// nuxt.config.ts — the names; the library ships no CSS for them.
|
|
159
|
+
export default defineNuxtConfig({
|
|
160
|
+
modules: ['bitboss-ui/nuxt'],
|
|
161
|
+
css: ['~/assets/css/badge-variants.css'],
|
|
162
|
+
bitboss: {
|
|
163
|
+
iconDir: './assets/icons',
|
|
164
|
+
badgeVariants: [
|
|
165
|
+
'soft-gray',
|
|
166
|
+
'soft-blue',
|
|
167
|
+
'soft-green',
|
|
168
|
+
'soft-amber',
|
|
169
|
+
'soft-red',
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```css
|
|
176
|
+
/* assets/css/badge-variants.css — trimmed. Canonical palette + the full
|
|
177
|
+
recipe (why the selectors are doubled, why the hue lives in a local
|
|
178
|
+
--accent): design-language.md § Using color. */
|
|
179
|
+
.bb-badge.bb-badge--soft-gray {
|
|
180
|
+
--accent: #64748b;
|
|
181
|
+
}
|
|
182
|
+
.bb-badge.bb-badge--soft-blue {
|
|
183
|
+
--accent: #2563eb;
|
|
184
|
+
}
|
|
185
|
+
.bb-badge.bb-badge--soft-green {
|
|
186
|
+
--accent: #16a34a;
|
|
187
|
+
}
|
|
188
|
+
.bb-badge.bb-badge--soft-amber {
|
|
189
|
+
--accent: #d97706;
|
|
190
|
+
}
|
|
191
|
+
.bb-badge.bb-badge--soft-red {
|
|
192
|
+
--accent: #dc2626;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.bb-badge.bb-badge--soft-gray,
|
|
196
|
+
.bb-badge.bb-badge--soft-blue,
|
|
197
|
+
.bb-badge.bb-badge--soft-green,
|
|
198
|
+
.bb-badge.bb-badge--soft-amber,
|
|
199
|
+
.bb-badge.bb-badge--soft-red {
|
|
200
|
+
--bg: color-mix(in oklab, var(--accent) 15%, var(--bb-panel));
|
|
201
|
+
--color: color-mix(in oklab, var(--accent) 80%, var(--bb-text));
|
|
202
|
+
--border-width: 1px;
|
|
203
|
+
--border-color: color-mix(in oklab, var(--accent) 25%, var(--bb-panel));
|
|
204
|
+
--ring: color-mix(in oklab, var(--accent) 45%, transparent);
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### context.ts
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// BacklogWorkspace/context.ts
|
|
212
|
+
import {
|
|
213
|
+
computed,
|
|
214
|
+
inject,
|
|
215
|
+
provide,
|
|
216
|
+
reactive,
|
|
217
|
+
ref,
|
|
218
|
+
watch,
|
|
219
|
+
type ComputedRef,
|
|
220
|
+
type InjectionKey,
|
|
221
|
+
type Ref,
|
|
222
|
+
} from 'vue';
|
|
223
|
+
import {
|
|
224
|
+
useBbTableContext,
|
|
225
|
+
useConfirm,
|
|
226
|
+
useToast,
|
|
227
|
+
type BadgeVariantType,
|
|
228
|
+
type BbTableContext,
|
|
229
|
+
} from 'bitboss-ui';
|
|
230
|
+
import {
|
|
231
|
+
usePageShellContext,
|
|
232
|
+
type PageShellContext,
|
|
233
|
+
} from '@/components/layout/usePageShellContext';
|
|
234
|
+
import { watchDebounced } from '@vueuse/core';
|
|
235
|
+
import type { Issue, IssuePriority, IssueStatus, Member } from '@/types';
|
|
236
|
+
|
|
237
|
+
/** What the peek sidebar can show. Clicking an issue ref pushes one of these. */
|
|
238
|
+
export type PeekItem = { type: 'issue'; id: string };
|
|
239
|
+
|
|
240
|
+
export type SprintTab = 'backlog' | 'current' | 'done';
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Exactly what a save can carry: the subset of Issue the user edits inline.
|
|
244
|
+
* Five fields of three control kinds on purpose — the pattern only proves
|
|
245
|
+
* itself once a row can be PARTIALLY in flight (title saving while the same
|
|
246
|
+
* row's status saves), once a field is backed by a search (assignee), and
|
|
247
|
+
* once a field changes on every keystroke (title, estimate).
|
|
248
|
+
*/
|
|
249
|
+
export type IssuePatch = Partial<
|
|
250
|
+
Pick<Issue, 'title' | 'estimate' | 'status' | 'priority' | 'assignee'>
|
|
251
|
+
>;
|
|
252
|
+
export type EditableKey = keyof IssuePatch;
|
|
253
|
+
|
|
254
|
+
export interface BacklogFilters {
|
|
255
|
+
search: string;
|
|
256
|
+
status: IssueStatus[];
|
|
257
|
+
priority: IssuePriority[];
|
|
258
|
+
/** The whole member, not an id — the pill labels itself with zero fetches. */
|
|
259
|
+
assignee: Member | null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
type IssueListResponse = {
|
|
263
|
+
data: Issue[];
|
|
264
|
+
total: number;
|
|
265
|
+
tabCounts: Record<SprintTab, number>;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// -- Option catalogs: resolved once, at module level, for the whole page. ----
|
|
269
|
+
// Static arrays cost fifty rows zero requests; a per-row provider would cost
|
|
270
|
+
// one request per opened row (BbSelectPopover § One popover per table row).
|
|
271
|
+
export const STATUS_OPTIONS: { value: IssueStatus; label: string }[] = [
|
|
272
|
+
{ value: 'open', label: 'Open' },
|
|
273
|
+
{ value: 'in-progress', label: 'In progress' },
|
|
274
|
+
{ value: 'blocked', label: 'Blocked' },
|
|
275
|
+
{ value: 'done', label: 'Done' },
|
|
276
|
+
];
|
|
277
|
+
export const PRIORITY_OPTIONS: { value: IssuePriority; label: string }[] = [
|
|
278
|
+
{ value: 'high', label: 'High' },
|
|
279
|
+
{ value: 'normal', label: 'Normal' },
|
|
280
|
+
{ value: 'low', label: 'Low' },
|
|
281
|
+
];
|
|
282
|
+
|
|
283
|
+
// Status/priority are small closed sets — the textbook case for the soft
|
|
284
|
+
// accents (design-language.md § Using color). Registered in nuxt.config.ts.
|
|
285
|
+
export const STATUS_VARIANT: Record<IssueStatus, BadgeVariantType> = {
|
|
286
|
+
open: 'soft-gray',
|
|
287
|
+
'in-progress': 'soft-blue',
|
|
288
|
+
blocked: 'soft-red',
|
|
289
|
+
done: 'soft-green',
|
|
290
|
+
};
|
|
291
|
+
export const PRIORITY_VARIANT: Record<IssuePriority, BadgeVariantType> = {
|
|
292
|
+
high: 'soft-amber',
|
|
293
|
+
normal: 'secondary',
|
|
294
|
+
low: 'outline',
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* `id: null` is the real "Unassigned" option, not an absence. The assignee is
|
|
299
|
+
* stored on the row as the whole member, so a row's badge always labels
|
|
300
|
+
* itself from its own data — no client-side directory cache, and the trigger
|
|
301
|
+
* never depends on the picker having loaded.
|
|
302
|
+
*/
|
|
303
|
+
export const UNASSIGNED: Member = { id: null, name: 'Unassigned' };
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* ONE query provider shared by every assignee picker on the page — each
|
|
307
|
+
* row's cell, the peek's cell, the rail pill and the bulk-assign picker.
|
|
308
|
+
* Providers are lazy, so a row nobody opens costs nothing. Contract
|
|
309
|
+
* (fetch-items-playbook): component-initiated calls (`prefill === true`) and
|
|
310
|
+
* an empty query return the whole team — six people, one cheap request — so
|
|
311
|
+
* the current selection always stays resolvable; typed queries search.
|
|
312
|
+
*/
|
|
313
|
+
export const searchMembers = async (
|
|
314
|
+
query: string,
|
|
315
|
+
prefill: boolean
|
|
316
|
+
): Promise<Member[]> => {
|
|
317
|
+
const q = query.trim();
|
|
318
|
+
const members = await $fetch<Member[]>('/api/members', {
|
|
319
|
+
query: prefill || !q ? {} : { search: q },
|
|
320
|
+
});
|
|
321
|
+
return [UNASSIGNED, ...members];
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
export interface BacklogWorkspaceContext {
|
|
325
|
+
// -- Coopted contexts ------------------------------------------------------
|
|
326
|
+
shell: PageShellContext<PeekItem>;
|
|
327
|
+
table: BbTableContext;
|
|
328
|
+
// -- Page-owned state (URL-synced) -------------------------------------------
|
|
329
|
+
filters: BacklogFilters;
|
|
330
|
+
hasActiveFilters: ComputedRef<boolean>;
|
|
331
|
+
tab: Ref<SprintTab>;
|
|
332
|
+
tabCounts: ComputedRef<Record<SprintTab, number>>;
|
|
333
|
+
// -- The autosave overlay (§6.8) --------------------------------------------
|
|
334
|
+
/**
|
|
335
|
+
* Optimistic values per row PER FIELD, held until the server's own data
|
|
336
|
+
* carries them. Reactive. Rung 3 on purpose: the cells, the peek and
|
|
337
|
+
* the fetch's transform all read it. Cells never touch it directly —
|
|
338
|
+
* they go through `valueOf` / `isSaving`.
|
|
339
|
+
*/
|
|
340
|
+
pending: Record<string, IssuePatch>;
|
|
341
|
+
/** Fields whose last save failed, keyed `${id}:${field}`. */
|
|
342
|
+
failed: Readonly<Ref<Set<string>>>;
|
|
343
|
+
/** Read-through: the overlay wins, the row is the fallback. */
|
|
344
|
+
valueOf: <K extends EditableKey>(issue: Issue, key: K) => Issue[K];
|
|
345
|
+
/** Whether THIS field of THIS row has a save in flight. */
|
|
346
|
+
isSaving: (issue: Issue, key: EditableKey) => boolean;
|
|
347
|
+
/** The one write path every cell commits through. */
|
|
348
|
+
persistField: <K extends EditableKey>(
|
|
349
|
+
issue: Issue,
|
|
350
|
+
key: K,
|
|
351
|
+
value: Issue[K]
|
|
352
|
+
) => Promise<void>;
|
|
353
|
+
// -- Data (URL-driven; the fetch's transform retires the overlay) ------------
|
|
354
|
+
issues: ComputedRef<Issue[]>;
|
|
355
|
+
issuesPending: Ref<boolean>;
|
|
356
|
+
// -- Peek ------------------------------------------------------------------
|
|
357
|
+
peekIssue: (id: string) => void;
|
|
358
|
+
// -- Actions (complete: API + refresh + toast) ------------------------------
|
|
359
|
+
clearFilters: () => void;
|
|
360
|
+
duplicateIssue: (issue: Issue) => Promise<void>;
|
|
361
|
+
moveToNextSprint: (issue: Issue) => Promise<void>;
|
|
362
|
+
deleteIssue: (issue: Issue) => Promise<void>;
|
|
363
|
+
bulkStatus: (status: IssueStatus) => Promise<void>;
|
|
364
|
+
bulkAssign: (assignee: Member) => Promise<void>;
|
|
365
|
+
bulkMoveToNextSprint: () => Promise<void>;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const key: InjectionKey<BacklogWorkspaceContext> = Symbol('backlog-workspace');
|
|
369
|
+
|
|
370
|
+
/** Comma-joined query value → string[] (or null when absent). */
|
|
371
|
+
const toArray = (value: unknown): string[] | null => {
|
|
372
|
+
if (value == null || value === '') return null;
|
|
373
|
+
return Array.isArray(value) ? value.map(String) : String(value).split(',');
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
export function provideBacklogWorkspace(): BacklogWorkspaceContext {
|
|
377
|
+
const { toast } = useToast();
|
|
378
|
+
const { confirm } = useConfirm();
|
|
379
|
+
const route = useRoute();
|
|
380
|
+
|
|
381
|
+
// -- Coopt the specific contexts: once, here, for the whole page. ----------
|
|
382
|
+
const shell = usePageShellContext<PeekItem>();
|
|
383
|
+
const table = useBbTableContext('backlog-table', { perPage: 25 });
|
|
384
|
+
|
|
385
|
+
// -- Filters + tab: seeded from the URL, the single source of truth. -------
|
|
386
|
+
const filters = reactive<BacklogFilters>({
|
|
387
|
+
search: (route.query.search as string) ?? '',
|
|
388
|
+
status: (toArray(route.query.status) ?? []) as IssueStatus[],
|
|
389
|
+
priority: (toArray(route.query.priority) ?? []) as IssuePriority[],
|
|
390
|
+
assignee: null, // resolved from the URL just below
|
|
391
|
+
});
|
|
392
|
+
const tab = ref<SprintTab>((route.query.tab as SprintTab) ?? 'current');
|
|
393
|
+
|
|
394
|
+
// The URL carries the assignee as an id (`none` = the real Unassigned
|
|
395
|
+
// option, whose id is null). Rows store the whole member, so this one-time
|
|
396
|
+
// resolution exists only so a deep link into a filtered view can label the
|
|
397
|
+
// pill — nothing else on the page ever resolves an id to a name.
|
|
398
|
+
if (route.query.assignee === 'none') {
|
|
399
|
+
filters.assignee = UNASSIGNED;
|
|
400
|
+
} else if (route.query.assignee) {
|
|
401
|
+
$fetch<Member>(`/api/members/${route.query.assignee}`).then((member) => {
|
|
402
|
+
filters.assignee = member;
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const hasActiveFilters = computed(
|
|
407
|
+
() =>
|
|
408
|
+
filters.search !== '' ||
|
|
409
|
+
filters.status.length > 0 ||
|
|
410
|
+
filters.priority.length > 0 ||
|
|
411
|
+
filters.assignee !== null
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
const clearFilters = () => {
|
|
415
|
+
filters.search = '';
|
|
416
|
+
filters.status = [];
|
|
417
|
+
filters.priority = [];
|
|
418
|
+
filters.assignee = null;
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
// Every filter/tab change mirrors into the query string; `useAsyncData`
|
|
422
|
+
// below watches `route.query`, so this is the whole refetch trigger.
|
|
423
|
+
const syncQuery = () =>
|
|
424
|
+
navigateTo({
|
|
425
|
+
query: {
|
|
426
|
+
search: filters.search || undefined,
|
|
427
|
+
status: filters.status.length ? filters.status.join(',') : undefined,
|
|
428
|
+
priority: filters.priority.length
|
|
429
|
+
? filters.priority.join(',')
|
|
430
|
+
: undefined,
|
|
431
|
+
assignee:
|
|
432
|
+
filters.assignee === null
|
|
433
|
+
? undefined
|
|
434
|
+
: (filters.assignee.id ?? 'none'),
|
|
435
|
+
tab: tab.value,
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
watchDebounced(filters, syncQuery, { deep: true, debounce: 300 });
|
|
439
|
+
watch(tab, () => {
|
|
440
|
+
table.page.value = 1;
|
|
441
|
+
syncQuery();
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// -- The autosave overlay -----------------------------------------------------
|
|
445
|
+
const pending = reactive<Record<string, IssuePatch>>({});
|
|
446
|
+
const failed = ref(new Set<string>());
|
|
447
|
+
|
|
448
|
+
const valueOf = <K extends EditableKey>(issue: Issue, key: K): Issue[K] => {
|
|
449
|
+
const patch = pending[issue.id];
|
|
450
|
+
// `key in patch`, not `patch[key] ?? issue[key]`: null is a legitimate
|
|
451
|
+
// committed value here (a cleared estimate), and `??` would drop that
|
|
452
|
+
// overlay and show the stale row value while the save runs.
|
|
453
|
+
return patch && key in patch ? (patch[key] as Issue[K]) : issue[key];
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const isSaving = (issue: Issue, key: EditableKey): boolean => {
|
|
457
|
+
const patch = pending[issue.id];
|
|
458
|
+
return patch !== undefined && key in patch;
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// -- Data ---------------------------------------------------------------------
|
|
462
|
+
// The one place the list loads. `route.query` is the single watch source —
|
|
463
|
+
// filters, tab and page changes all funnel through the URL first. The
|
|
464
|
+
// overlay owns the name `pending` on this page, so the fetch's own flag
|
|
465
|
+
// lands as `issuesPending`.
|
|
466
|
+
const {
|
|
467
|
+
data,
|
|
468
|
+
pending: issuesPending,
|
|
469
|
+
refresh,
|
|
470
|
+
} = useAsyncData<IssueListResponse>(
|
|
471
|
+
'issues',
|
|
472
|
+
() =>
|
|
473
|
+
$fetch<IssueListResponse>('/api/issues', {
|
|
474
|
+
query: {
|
|
475
|
+
search: filters.search || undefined,
|
|
476
|
+
status: filters.status,
|
|
477
|
+
priority: filters.priority,
|
|
478
|
+
assignee:
|
|
479
|
+
filters.assignee === null
|
|
480
|
+
? undefined
|
|
481
|
+
: (filters.assignee.id ?? 'none'),
|
|
482
|
+
tab: tab.value,
|
|
483
|
+
page: table.page.value,
|
|
484
|
+
perPage: table.perPage.value,
|
|
485
|
+
},
|
|
486
|
+
}),
|
|
487
|
+
{
|
|
488
|
+
watch: [() => route.query, table.page],
|
|
489
|
+
// Retire the overlay HERE — in the transform, where the fresh rows
|
|
490
|
+
// materialize — not when a save resolves, and only the fields this
|
|
491
|
+
// response actually CONFIRMS. Between a save landing and this
|
|
492
|
+
// reload arriving, the table still holds the OLD row; clearing the
|
|
493
|
+
// overlay early makes the cell revert to the stale value for the
|
|
494
|
+
// whole reload — visibly, new → old → new. A field still in flight
|
|
495
|
+
// (the response doesn't carry its value yet) is left alone.
|
|
496
|
+
transform: (response: IssueListResponse) => {
|
|
497
|
+
for (const issue of response.data) {
|
|
498
|
+
const patch = pending[issue.id];
|
|
499
|
+
if (!patch) continue;
|
|
500
|
+
for (const field of Object.keys(patch) as EditableKey[]) {
|
|
501
|
+
if (JSON.stringify(patch[field]) === JSON.stringify(issue[field])) {
|
|
502
|
+
delete patch[field]; // the server's own data carries it now
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
if (!Object.keys(patch).length) delete pending[issue.id];
|
|
506
|
+
}
|
|
507
|
+
return response;
|
|
508
|
+
},
|
|
509
|
+
}
|
|
510
|
+
);
|
|
511
|
+
const issues = computed(() => data.value?.data ?? []);
|
|
512
|
+
const tabCounts = computed(
|
|
513
|
+
() => data.value?.tabCounts ?? { backlog: 0, current: 0, done: 0 }
|
|
514
|
+
);
|
|
515
|
+
// Paging totals come back on every fetch and land in the table context.
|
|
516
|
+
watch(
|
|
517
|
+
data,
|
|
518
|
+
(response) => {
|
|
519
|
+
if (response) table.total.value = response.total;
|
|
520
|
+
},
|
|
521
|
+
{ immediate: true }
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* The complete autosave action, one per commit, for every control kind:
|
|
526
|
+
* no-op guard → optimistic set → single-field PATCH → refetch. On failure
|
|
527
|
+
* it deletes JUST this field from the overlay (the cell snaps back to the
|
|
528
|
+
* row's value — a second field of the same row still in flight is
|
|
529
|
+
* untouched) and toasts destructive. Success does NOT toast: a page where
|
|
530
|
+
* every blur saves would toast constantly — the spinner resolving is the
|
|
531
|
+
* confirmation, failure is the exception worth announcing.
|
|
532
|
+
*/
|
|
533
|
+
const persistField = async <K extends EditableKey>(
|
|
534
|
+
issue: Issue,
|
|
535
|
+
key: K,
|
|
536
|
+
value: Issue[K]
|
|
537
|
+
): Promise<void> => {
|
|
538
|
+
// No-op-commit guard — against what the user SEES (the overlay when one
|
|
539
|
+
// is in flight, the row otherwise): a blur without a change, or
|
|
540
|
+
// re-picking the on-screen value, must not fire a request.
|
|
541
|
+
if (JSON.stringify(value) === JSON.stringify(valueOf(issue, key))) return;
|
|
542
|
+
|
|
543
|
+
const flag = `${issue.id}:${key}`;
|
|
544
|
+
(pending[issue.id] ??= {})[key] = value; // optimistic: the UI moves NOW
|
|
545
|
+
failed.value.delete(flag);
|
|
546
|
+
try {
|
|
547
|
+
await $fetch(`/api/issues/${issue.id}`, {
|
|
548
|
+
method: 'PATCH',
|
|
549
|
+
body: { [key]: value } as IssuePatch,
|
|
550
|
+
});
|
|
551
|
+
// Reload — but do NOT retire the overlay here. The useAsyncData
|
|
552
|
+
// transform drops it once the server's own data carries the value
|
|
553
|
+
// (see above).
|
|
554
|
+
await refresh();
|
|
555
|
+
} catch {
|
|
556
|
+
// Rollback: drop just this field.
|
|
557
|
+
const patch = pending[issue.id];
|
|
558
|
+
if (patch) {
|
|
559
|
+
delete patch[key];
|
|
560
|
+
if (!Object.keys(patch).length) delete pending[issue.id];
|
|
561
|
+
}
|
|
562
|
+
failed.value.add(flag);
|
|
563
|
+
toast({
|
|
564
|
+
title: `Couldn't save the ${key} of ${issue.ref} — reverted.`,
|
|
565
|
+
variant: 'destructive',
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
// -- Peek ------------------------------------------------------------------------
|
|
571
|
+
// One record type on this page, so the grammar is one verb: fresh stack.
|
|
572
|
+
const peekIssue = (id: string) => shell.push({ type: 'issue', id }, true);
|
|
573
|
+
|
|
574
|
+
// -- Discrete actions (row `…`, bulk bar) -------------------------------------
|
|
575
|
+
// These are ordinary complete actions, records-workspace style: they
|
|
576
|
+
// mutate whole rows, not single fields, so they bypass the overlay and
|
|
577
|
+
// simply `refresh()` — and being discrete (not a blur), they DO toast
|
|
578
|
+
// success.
|
|
579
|
+
const duplicateIssue = async (issue: Issue) => {
|
|
580
|
+
const copy = await $fetch<Issue>(`/api/issues/${issue.id}/duplicate`, {
|
|
581
|
+
method: 'POST',
|
|
582
|
+
});
|
|
583
|
+
await refresh();
|
|
584
|
+
toast({ title: `Duplicated as ${copy.ref}.`, variant: 'success' });
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
const moveToNextSprint = async (issue: Issue) => {
|
|
588
|
+
await $fetch('/api/issues/move-to-next-sprint', {
|
|
589
|
+
method: 'POST',
|
|
590
|
+
body: { ids: [issue.id] },
|
|
591
|
+
});
|
|
592
|
+
await refresh();
|
|
593
|
+
toast({ title: `${issue.ref} moved to Sprint 25.`, variant: 'success' });
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
const deleteIssue = async (issue: Issue) => {
|
|
597
|
+
const ok = await confirm({
|
|
598
|
+
variant: 'destructive',
|
|
599
|
+
title: 'Delete issue',
|
|
600
|
+
text: `Delete ${issue.ref} — “${issue.title}”? This cannot be undone.`,
|
|
601
|
+
yes: 'Delete',
|
|
602
|
+
no: 'Cancel',
|
|
603
|
+
});
|
|
604
|
+
if (!ok) return;
|
|
605
|
+
await $fetch(`/api/issues/${issue.id}`, { method: 'DELETE' });
|
|
606
|
+
await refresh();
|
|
607
|
+
toast({ title: `${issue.ref} deleted.`, variant: 'success' });
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
// Bulk actions read and clear the coopted table context themselves.
|
|
611
|
+
const bulkIds = (): string[] => table.selected.value;
|
|
612
|
+
const clearSelection = () => {
|
|
613
|
+
table.selected.value = [];
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const bulkStatus = async (status: IssueStatus) => {
|
|
617
|
+
const ids = bulkIds();
|
|
618
|
+
await $fetch('/api/issues/bulk', {
|
|
619
|
+
method: 'PATCH',
|
|
620
|
+
body: { ids, patch: { status } },
|
|
621
|
+
});
|
|
622
|
+
clearSelection();
|
|
623
|
+
await refresh();
|
|
624
|
+
const label = STATUS_OPTIONS.find((o) => o.value === status)?.label;
|
|
625
|
+
toast({
|
|
626
|
+
title: `${ids.length} issues moved to ${label}.`,
|
|
627
|
+
variant: 'success',
|
|
628
|
+
});
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
const bulkAssign = async (assignee: Member) => {
|
|
632
|
+
const ids = bulkIds();
|
|
633
|
+
await $fetch('/api/issues/bulk', {
|
|
634
|
+
method: 'PATCH',
|
|
635
|
+
body: { ids, patch: { assignee } },
|
|
636
|
+
});
|
|
637
|
+
clearSelection();
|
|
638
|
+
await refresh();
|
|
639
|
+
toast({
|
|
640
|
+
title: `${ids.length} issues assigned to ${assignee.name}.`,
|
|
641
|
+
variant: 'success',
|
|
642
|
+
});
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
const bulkMoveToNextSprint = async () => {
|
|
646
|
+
const ids = bulkIds();
|
|
647
|
+
await $fetch('/api/issues/move-to-next-sprint', {
|
|
648
|
+
method: 'POST',
|
|
649
|
+
body: { ids },
|
|
650
|
+
});
|
|
651
|
+
clearSelection();
|
|
652
|
+
await refresh();
|
|
653
|
+
toast({
|
|
654
|
+
title: `${ids.length} issues moved to Sprint 25.`,
|
|
655
|
+
variant: 'success',
|
|
656
|
+
});
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
const ctx: BacklogWorkspaceContext = {
|
|
660
|
+
shell,
|
|
661
|
+
table,
|
|
662
|
+
filters,
|
|
663
|
+
hasActiveFilters,
|
|
664
|
+
tab,
|
|
665
|
+
tabCounts,
|
|
666
|
+
pending,
|
|
667
|
+
failed,
|
|
668
|
+
valueOf,
|
|
669
|
+
isSaving,
|
|
670
|
+
persistField,
|
|
671
|
+
issues,
|
|
672
|
+
issuesPending,
|
|
673
|
+
peekIssue,
|
|
674
|
+
clearFilters,
|
|
675
|
+
duplicateIssue,
|
|
676
|
+
moveToNextSprint,
|
|
677
|
+
deleteIssue,
|
|
678
|
+
bulkStatus,
|
|
679
|
+
bulkAssign,
|
|
680
|
+
bulkMoveToNextSprint,
|
|
681
|
+
};
|
|
682
|
+
provide(key, ctx);
|
|
683
|
+
return ctx;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
export function useBacklogWorkspace(): BacklogWorkspaceContext {
|
|
687
|
+
const ctx = inject(key);
|
|
688
|
+
if (!ctx)
|
|
689
|
+
throw new Error('useBacklogWorkspace() called outside BacklogWorkspace');
|
|
690
|
+
return ctx;
|
|
691
|
+
}
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
### Index.vue — the assembly
|
|
695
|
+
|
|
696
|
+
```vue
|
|
697
|
+
<!-- BacklogWorkspace/Index.vue -->
|
|
698
|
+
<template>
|
|
699
|
+
<PageShell>
|
|
700
|
+
<!-- Topbar: breadcrumbs left, page search + primary action right. -->
|
|
701
|
+
<template #topbar>
|
|
702
|
+
<div class="flex items-center justify-between gap-4 border-b px-4 py-2">
|
|
703
|
+
<!-- Breadcrumbs take the row's slack on a stable basis (min-w-0 flex-auto);
|
|
704
|
+
without it their overflow recompute fights the flex layout every frame. -->
|
|
705
|
+
<BbBreadcrumbs
|
|
706
|
+
class="min-w-0 flex-auto"
|
|
707
|
+
:items="[
|
|
708
|
+
{ key: 'product', text: 'Product', to: '/product' },
|
|
709
|
+
{ key: 'sprints', text: 'Sprints', to: '/sprints' },
|
|
710
|
+
{ key: 'sprint-24', text: 'Sprint 24' },
|
|
711
|
+
]"
|
|
712
|
+
/>
|
|
713
|
+
<div class="flex shrink-0 items-center gap-2">
|
|
714
|
+
<!-- `label` is required across the input family; `hide-label`
|
|
715
|
+
keeps the accessible name while hiding it visually. -->
|
|
716
|
+
<BbTextInput
|
|
717
|
+
v-model="ctx.filters.search"
|
|
718
|
+
clearable
|
|
719
|
+
compact
|
|
720
|
+
hide-label
|
|
721
|
+
label="Search issues"
|
|
722
|
+
placeholder="Search ref or title…"
|
|
723
|
+
prepend:icon="lucide:search"
|
|
724
|
+
/>
|
|
725
|
+
<BbButton
|
|
726
|
+
prepend:icon="lucide:plus"
|
|
727
|
+
to="/issues/new"
|
|
728
|
+
variant="primary"
|
|
729
|
+
>
|
|
730
|
+
New issue
|
|
731
|
+
</BbButton>
|
|
732
|
+
</div>
|
|
733
|
+
</div>
|
|
734
|
+
</template>
|
|
735
|
+
|
|
736
|
+
<div class="flex flex-col gap-3 p-4">
|
|
737
|
+
<FilterRail />
|
|
738
|
+
|
|
739
|
+
<!-- Tabs as URL filters: href updates the query, the key feeds the
|
|
740
|
+
fetch. Counts come back from the server on every fetch. -->
|
|
741
|
+
<BbTabs
|
|
742
|
+
v-model="ctx.tab.value"
|
|
743
|
+
compact
|
|
744
|
+
:items="[
|
|
745
|
+
{
|
|
746
|
+
key: 'backlog',
|
|
747
|
+
label: `Backlog · ${ctx.tabCounts.value.backlog}`,
|
|
748
|
+
href: '?tab=backlog',
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
key: 'current',
|
|
752
|
+
label: `Current sprint · ${ctx.tabCounts.value.current}`,
|
|
753
|
+
href: '?tab=current',
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
key: 'done',
|
|
757
|
+
label: `Done · ${ctx.tabCounts.value.done}`,
|
|
758
|
+
href: '?tab=done',
|
|
759
|
+
},
|
|
760
|
+
]"
|
|
761
|
+
/>
|
|
762
|
+
|
|
763
|
+
<BbTable
|
|
764
|
+
id="backlog-table"
|
|
765
|
+
v-model:highlighted="highlightedIssue"
|
|
766
|
+
actions
|
|
767
|
+
caption="Sprint 24 backlog"
|
|
768
|
+
:columns="columns"
|
|
769
|
+
compact
|
|
770
|
+
item-value="id"
|
|
771
|
+
:items="ctx.issues.value"
|
|
772
|
+
legend="Sprint 24 backlog issues"
|
|
773
|
+
:loading="ctx.issuesPending.value"
|
|
774
|
+
loading-text="Loading issues…"
|
|
775
|
+
:row-class="rowClass"
|
|
776
|
+
selectable
|
|
777
|
+
>
|
|
778
|
+
<!-- The ref is the peek handle — the title can't be, it's an input.
|
|
779
|
+
`.plain-link` is the project-owned inline-link helper
|
|
780
|
+
(design-language.md § Guide helper), not a BbButton variant. -->
|
|
781
|
+
<template #ref="{ item, content }">
|
|
782
|
+
<BbBaseButton
|
|
783
|
+
class="plain-link font-semibold"
|
|
784
|
+
@click="() => ctx.peekIssue(item.id)"
|
|
785
|
+
>
|
|
786
|
+
{{ content }}
|
|
787
|
+
</BbBaseButton>
|
|
788
|
+
</template>
|
|
789
|
+
|
|
790
|
+
<!-- Five self-persisting cells, three control kinds, one leaf each. -->
|
|
791
|
+
<template #title="{ item }">
|
|
792
|
+
<EditableTitleCell :issue="item" />
|
|
793
|
+
</template>
|
|
794
|
+
|
|
795
|
+
<template #estimate="{ item }">
|
|
796
|
+
<EstimateCell :issue="item" />
|
|
797
|
+
</template>
|
|
798
|
+
|
|
799
|
+
<template #status="{ item }">
|
|
800
|
+
<StatusCell :issue="item" />
|
|
801
|
+
</template>
|
|
802
|
+
|
|
803
|
+
<template #priority="{ item }">
|
|
804
|
+
<PriorityCell :issue="item" />
|
|
805
|
+
</template>
|
|
806
|
+
|
|
807
|
+
<template #assignee="{ item }">
|
|
808
|
+
<AssigneeCell :issue="item" />
|
|
809
|
+
</template>
|
|
810
|
+
|
|
811
|
+
<template #actions="{ item }">
|
|
812
|
+
<RowActions :issue="item" />
|
|
813
|
+
</template>
|
|
814
|
+
|
|
815
|
+
<template #no-data>
|
|
816
|
+
<div class="flex flex-col items-center gap-2 p-6 text-center">
|
|
817
|
+
<p class="text-sm text-gray-500">
|
|
818
|
+
No issues match
|
|
819
|
+
{{
|
|
820
|
+
ctx.hasActiveFilters.value ? 'the current filters' : 'this tab'
|
|
821
|
+
}}.
|
|
822
|
+
</p>
|
|
823
|
+
<BbButton
|
|
824
|
+
v-if="ctx.hasActiveFilters.value"
|
|
825
|
+
variant="ghost"
|
|
826
|
+
@click="ctx.clearFilters"
|
|
827
|
+
>
|
|
828
|
+
Clear filters
|
|
829
|
+
</BbButton>
|
|
830
|
+
</div>
|
|
831
|
+
</template>
|
|
832
|
+
</BbTable>
|
|
833
|
+
|
|
834
|
+
<!-- Joins the table context by id: no page/totalPages wiring at all. -->
|
|
835
|
+
<BbPagination table-id="backlog-table" />
|
|
836
|
+
</div>
|
|
837
|
+
|
|
838
|
+
<SelectionBar />
|
|
839
|
+
|
|
840
|
+
<!-- Peek sidebar: the shell owns close; we render by type. -->
|
|
841
|
+
<template #sidebar>
|
|
842
|
+
<IssuePeek
|
|
843
|
+
v-if="ctx.shell.current.value?.type === 'issue'"
|
|
844
|
+
:issue-id="ctx.shell.current.value.id"
|
|
845
|
+
/>
|
|
846
|
+
</template>
|
|
847
|
+
|
|
848
|
+
<!-- Deliberately no #dialogs content: every mutation on this page is
|
|
849
|
+
inline. The grid is the form. -->
|
|
850
|
+
</PageShell>
|
|
851
|
+
</template>
|
|
852
|
+
|
|
853
|
+
<script setup lang="ts">
|
|
854
|
+
import { computed } from 'vue';
|
|
855
|
+
import {
|
|
856
|
+
BbBaseButton,
|
|
857
|
+
BbBreadcrumbs,
|
|
858
|
+
BbButton,
|
|
859
|
+
BbPagination,
|
|
860
|
+
BbTable,
|
|
861
|
+
BbTabs,
|
|
862
|
+
BbTextInput,
|
|
863
|
+
} from 'bitboss-ui';
|
|
864
|
+
import PageShell from '@/components/layout/PageShell.vue';
|
|
865
|
+
import { provideBacklogWorkspace } from './context';
|
|
866
|
+
import AssigneeCell from './AssigneeCell.vue';
|
|
867
|
+
import EditableTitleCell from './EditableTitleCell.vue';
|
|
868
|
+
import EstimateCell from './EstimateCell.vue';
|
|
869
|
+
import FilterRail from './FilterRail.vue';
|
|
870
|
+
import IssuePeek from './IssuePeek.vue';
|
|
871
|
+
import PriorityCell from './PriorityCell.vue';
|
|
872
|
+
import RowActions from './RowActions.vue';
|
|
873
|
+
import SelectionBar from './SelectionBar.vue';
|
|
874
|
+
import StatusCell from './StatusCell.vue';
|
|
875
|
+
import type { Issue } from '@/types';
|
|
876
|
+
|
|
877
|
+
const ctx = provideBacklogWorkspace();
|
|
878
|
+
|
|
879
|
+
// Row highlight tracks the open peek — the peeked row stays marked, and
|
|
880
|
+
// highlighting a row opens its peek; clearing the highlight closes it.
|
|
881
|
+
const highlightedIssue = computed<string | null>({
|
|
882
|
+
get: () =>
|
|
883
|
+
ctx.shell.current.value?.type === 'issue'
|
|
884
|
+
? ctx.shell.current.value.id
|
|
885
|
+
: null,
|
|
886
|
+
set: (id) => {
|
|
887
|
+
if (id == null) ctx.shell.close();
|
|
888
|
+
else ctx.peekIssue(id);
|
|
889
|
+
},
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
const columns = [
|
|
893
|
+
{ key: 'ref', label: 'Ref', width: 90 },
|
|
894
|
+
{ key: 'title', label: 'Title' },
|
|
895
|
+
{ key: 'estimate', label: 'Est.', width: 90 },
|
|
896
|
+
{ key: 'status', label: 'Status', width: 170 },
|
|
897
|
+
{ key: 'priority', label: 'Priority', width: 140 },
|
|
898
|
+
{ key: 'assignee', label: 'Assignee', width: 200 },
|
|
899
|
+
];
|
|
900
|
+
|
|
901
|
+
// Blocked rows get a tinted background — public row-class API, no internals.
|
|
902
|
+
// Even the tint reads THROUGH the overlay: unblock an issue and the row
|
|
903
|
+
// clears the moment the pick commits, not when the refetch lands.
|
|
904
|
+
const rowClass = (item: Issue) =>
|
|
905
|
+
ctx.valueOf(item, 'status') === 'blocked'
|
|
906
|
+
? 'bg-red-50 dark:bg-red-950/20'
|
|
907
|
+
: undefined;
|
|
908
|
+
</script>
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
### FilterRail.vue
|
|
912
|
+
|
|
913
|
+
```vue
|
|
914
|
+
<!-- BacklogWorkspace/FilterRail.vue -->
|
|
915
|
+
<template>
|
|
916
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
917
|
+
<!-- Status: multi-select pill over the same static catalog the cells use.
|
|
918
|
+
`disable-writing` means there's no search field to host an in-popover
|
|
919
|
+
clear, so these tiny fixed-list filters clear from a rail-level chip
|
|
920
|
+
(×) instead — the searchable filter below clears from inside the
|
|
921
|
+
popover. -->
|
|
922
|
+
<div class="inline-flex items-center gap-1">
|
|
923
|
+
<BbSelectPopover
|
|
924
|
+
v-model="ctx.filters.status"
|
|
925
|
+
disable-writing
|
|
926
|
+
item-text="label"
|
|
927
|
+
item-value="value"
|
|
928
|
+
:items="STATUS_OPTIONS"
|
|
929
|
+
multiple
|
|
930
|
+
>
|
|
931
|
+
<template #activator="{ props }">
|
|
932
|
+
<BbButton
|
|
933
|
+
v-bind="props"
|
|
934
|
+
append:icon="lucide:chevron-down"
|
|
935
|
+
size="sm"
|
|
936
|
+
variant="outline"
|
|
937
|
+
>
|
|
938
|
+
Status{{
|
|
939
|
+
ctx.filters.status.length ? ` · ${ctx.filters.status.length}` : ''
|
|
940
|
+
}}
|
|
941
|
+
</BbButton>
|
|
942
|
+
</template>
|
|
943
|
+
</BbSelectPopover>
|
|
944
|
+
<BbButton
|
|
945
|
+
v-if="ctx.filters.status.length"
|
|
946
|
+
aria-label="Clear status filter"
|
|
947
|
+
prepend:icon="lucide:x"
|
|
948
|
+
size="sm"
|
|
949
|
+
variant="ghost"
|
|
950
|
+
@click="ctx.filters.status = []"
|
|
951
|
+
/>
|
|
952
|
+
</div>
|
|
953
|
+
|
|
954
|
+
<!-- Priority: same shape, three options. -->
|
|
955
|
+
<div class="inline-flex items-center gap-1">
|
|
956
|
+
<BbSelectPopover
|
|
957
|
+
v-model="ctx.filters.priority"
|
|
958
|
+
disable-writing
|
|
959
|
+
item-text="label"
|
|
960
|
+
item-value="value"
|
|
961
|
+
:items="PRIORITY_OPTIONS"
|
|
962
|
+
multiple
|
|
963
|
+
>
|
|
964
|
+
<template #activator="{ props }">
|
|
965
|
+
<BbButton
|
|
966
|
+
v-bind="props"
|
|
967
|
+
append:icon="lucide:chevron-down"
|
|
968
|
+
size="sm"
|
|
969
|
+
variant="outline"
|
|
970
|
+
>
|
|
971
|
+
Priority{{
|
|
972
|
+
ctx.filters.priority.length
|
|
973
|
+
? ` · ${ctx.filters.priority.length}`
|
|
974
|
+
: ''
|
|
975
|
+
}}
|
|
976
|
+
</BbButton>
|
|
977
|
+
</template>
|
|
978
|
+
</BbSelectPopover>
|
|
979
|
+
<BbButton
|
|
980
|
+
v-if="ctx.filters.priority.length"
|
|
981
|
+
aria-label="Clear priority filter"
|
|
982
|
+
prepend:icon="lucide:x"
|
|
983
|
+
size="sm"
|
|
984
|
+
variant="ghost"
|
|
985
|
+
@click="ctx.filters.priority = []"
|
|
986
|
+
/>
|
|
987
|
+
</div>
|
|
988
|
+
|
|
989
|
+
<!-- Assignee: the SAME shared provider as every assignee cell. The whole
|
|
990
|
+
member is the value, so the pill labels itself from page state with
|
|
991
|
+
zero fetches — no watchEffect-to-resolve-a-name here. Query-aware
|
|
992
|
+
(searchable), so the filter clears from inside the popover search. -->
|
|
993
|
+
<BbSelectPopover
|
|
994
|
+
v-model="ctx.filters.assignee"
|
|
995
|
+
clearable
|
|
996
|
+
item-text="name"
|
|
997
|
+
:items="searchMembers"
|
|
998
|
+
>
|
|
999
|
+
<template #activator="{ props }">
|
|
1000
|
+
<BbButton
|
|
1001
|
+
v-bind="props"
|
|
1002
|
+
append:icon="lucide:chevron-down"
|
|
1003
|
+
size="sm"
|
|
1004
|
+
variant="outline"
|
|
1005
|
+
>
|
|
1006
|
+
{{ ctx.filters.assignee?.name ?? 'Assignee' }}
|
|
1007
|
+
</BbButton>
|
|
1008
|
+
</template>
|
|
1009
|
+
</BbSelectPopover>
|
|
1010
|
+
|
|
1011
|
+
<!-- Clear-all renders only while something is active. -->
|
|
1012
|
+
<BbButton
|
|
1013
|
+
v-if="ctx.hasActiveFilters.value"
|
|
1014
|
+
class="ml-auto"
|
|
1015
|
+
prepend:icon="lucide:x"
|
|
1016
|
+
size="sm"
|
|
1017
|
+
variant="ghost"
|
|
1018
|
+
@click="ctx.clearFilters"
|
|
1019
|
+
>
|
|
1020
|
+
Clear filters
|
|
1021
|
+
</BbButton>
|
|
1022
|
+
</div>
|
|
1023
|
+
</template>
|
|
1024
|
+
|
|
1025
|
+
<script setup lang="ts">
|
|
1026
|
+
import { BbButton, BbSelectPopover } from 'bitboss-ui';
|
|
1027
|
+
import {
|
|
1028
|
+
PRIORITY_OPTIONS,
|
|
1029
|
+
STATUS_OPTIONS,
|
|
1030
|
+
searchMembers,
|
|
1031
|
+
useBacklogWorkspace,
|
|
1032
|
+
} from './context';
|
|
1033
|
+
|
|
1034
|
+
const ctx = useBacklogWorkspace();
|
|
1035
|
+
</script>
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
### EditableTitleCell.vue
|
|
1039
|
+
|
|
1040
|
+
```vue
|
|
1041
|
+
<!-- BacklogWorkspace/EditableTitleCell.vue -->
|
|
1042
|
+
<template>
|
|
1043
|
+
<!-- Commit on @change (blur/Enter), NEVER v-model: a v-model autosave is
|
|
1044
|
+
one request per keystroke. `:model-value` binds the read-through value
|
|
1045
|
+
down; the user's in-progress typing lives in the DOM until blur commits
|
|
1046
|
+
it. A failed save marks the field until the next commit attempt. -->
|
|
1047
|
+
<BbTextInput
|
|
1048
|
+
compact
|
|
1049
|
+
:has-errors="ctx.failed.value.has(`${issue.id}:title`)"
|
|
1050
|
+
hide-label
|
|
1051
|
+
label="Issue title"
|
|
1052
|
+
:loading="ctx.isSaving(issue, 'title')"
|
|
1053
|
+
:model-value="ctx.valueOf(issue, 'title')"
|
|
1054
|
+
@change="commit"
|
|
1055
|
+
/>
|
|
1056
|
+
</template>
|
|
1057
|
+
|
|
1058
|
+
<script setup lang="ts">
|
|
1059
|
+
import { BbTextInput } from 'bitboss-ui';
|
|
1060
|
+
import { useBacklogWorkspace } from './context';
|
|
1061
|
+
import type { Issue } from '@/types';
|
|
1062
|
+
|
|
1063
|
+
const props = defineProps<{ issue: Issue }>();
|
|
1064
|
+
|
|
1065
|
+
const ctx = useBacklogWorkspace();
|
|
1066
|
+
|
|
1067
|
+
// `@change` is the native event; the committed text is on the target.
|
|
1068
|
+
const commit = (event: Event) =>
|
|
1069
|
+
ctx.persistField(
|
|
1070
|
+
props.issue,
|
|
1071
|
+
'title',
|
|
1072
|
+
(event.target as HTMLInputElement).value
|
|
1073
|
+
);
|
|
1074
|
+
</script>
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
### EstimateCell.vue
|
|
1078
|
+
|
|
1079
|
+
```vue
|
|
1080
|
+
<!-- BacklogWorkspace/EstimateCell.vue -->
|
|
1081
|
+
<template>
|
|
1082
|
+
<BbNumberInput
|
|
1083
|
+
compact
|
|
1084
|
+
:has-errors="ctx.failed.value.has(`${issue.id}:estimate`)"
|
|
1085
|
+
hide-label
|
|
1086
|
+
label="Estimate"
|
|
1087
|
+
:loading="ctx.isSaving(issue, 'estimate')"
|
|
1088
|
+
:min="0"
|
|
1089
|
+
:model-value="ctx.valueOf(issue, 'estimate')"
|
|
1090
|
+
placeholder="—"
|
|
1091
|
+
@change="commit"
|
|
1092
|
+
/>
|
|
1093
|
+
</template>
|
|
1094
|
+
|
|
1095
|
+
<script setup lang="ts">
|
|
1096
|
+
import { BbNumberInput } from 'bitboss-ui';
|
|
1097
|
+
import { useBacklogWorkspace } from './context';
|
|
1098
|
+
import type { Issue } from '@/types';
|
|
1099
|
+
|
|
1100
|
+
const props = defineProps<{ issue: Issue }>();
|
|
1101
|
+
|
|
1102
|
+
const ctx = useBacklogWorkspace();
|
|
1103
|
+
|
|
1104
|
+
// A number input's `change` carries the RAW STRING; '' means cleared. A
|
|
1105
|
+
// cleared estimate is a real commit (estimate: null), not a no-op — which is
|
|
1106
|
+
// exactly why the context's valueOf checks `key in patch` instead of `??`.
|
|
1107
|
+
const commit = (event: Event) => {
|
|
1108
|
+
const raw = (event.target as HTMLInputElement).value;
|
|
1109
|
+
ctx.persistField(props.issue, 'estimate', raw === '' ? null : Number(raw));
|
|
1110
|
+
};
|
|
1111
|
+
</script>
|
|
1112
|
+
```
|
|
1113
|
+
|
|
1114
|
+
### StatusCell.vue
|
|
1115
|
+
|
|
1116
|
+
```vue
|
|
1117
|
+
<!-- BacklogWorkspace/StatusCell.vue -->
|
|
1118
|
+
<template>
|
|
1119
|
+
<BbSelectPopover
|
|
1120
|
+
compact
|
|
1121
|
+
disable-writing
|
|
1122
|
+
item-text="label"
|
|
1123
|
+
item-value="value"
|
|
1124
|
+
:items="STATUS_OPTIONS"
|
|
1125
|
+
:model-value="status"
|
|
1126
|
+
width="180px"
|
|
1127
|
+
@update:model-value="
|
|
1128
|
+
(next) => ctx.persistField(issue, 'status', next as IssueStatus)
|
|
1129
|
+
"
|
|
1130
|
+
>
|
|
1131
|
+
<template #activator="{ props: activatorProps, shown }">
|
|
1132
|
+
<!-- The badge IS the trigger: BbBadgeButton turns the badge's own
|
|
1133
|
+
body into the button, so the pill is the hit target and draws its own
|
|
1134
|
+
focus ring — no wrapper element, no chrome class. The internal
|
|
1135
|
+
trailing chevron says "this can change" and sits inside the button
|
|
1136
|
+
with the label; while THIS field's save runs the badge's `loading`
|
|
1137
|
+
swaps the spinner into the chevron's place — same size, nothing
|
|
1138
|
+
shifts. Unlike the one-shot §6.1 cell there is no local `saving` ref:
|
|
1139
|
+
the flag comes from the context overlay, because in an autosave grid
|
|
1140
|
+
the fetch must also know what's in flight. -->
|
|
1141
|
+
<BbBadge
|
|
1142
|
+
append:icon="lucide:chevron-down"
|
|
1143
|
+
:class="{ 'status-cell--open': shown }"
|
|
1144
|
+
:loading="ctx.isSaving(issue, 'status')"
|
|
1145
|
+
:variant="STATUS_VARIANT[status]"
|
|
1146
|
+
>
|
|
1147
|
+
<BbBadgeButton v-bind="activatorProps">{{ label }}</BbBadgeButton>
|
|
1148
|
+
</BbBadge>
|
|
1149
|
+
</template>
|
|
1150
|
+
</BbSelectPopover>
|
|
1151
|
+
</template>
|
|
1152
|
+
|
|
1153
|
+
<script setup lang="ts">
|
|
1154
|
+
import { computed } from 'vue';
|
|
1155
|
+
import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
|
|
1156
|
+
import { STATUS_OPTIONS, STATUS_VARIANT, useBacklogWorkspace } from './context';
|
|
1157
|
+
import type { Issue, IssueStatus } from '@/types';
|
|
1158
|
+
|
|
1159
|
+
const props = defineProps<{ issue: Issue }>();
|
|
1160
|
+
|
|
1161
|
+
const ctx = useBacklogWorkspace();
|
|
1162
|
+
|
|
1163
|
+
// Read through the overlay, so the badge moves the instant a pick commits —
|
|
1164
|
+
// color and label both.
|
|
1165
|
+
const status = computed(() => ctx.valueOf(props.issue, 'status'));
|
|
1166
|
+
const label = computed(
|
|
1167
|
+
() =>
|
|
1168
|
+
STATUS_OPTIONS.find((option) => option.value === status.value)?.label ??
|
|
1169
|
+
status.value
|
|
1170
|
+
);
|
|
1171
|
+
</script>
|
|
1172
|
+
|
|
1173
|
+
<style scoped>
|
|
1174
|
+
/* Open = the badge's own hue, deepened, plus its variant ring — derived from
|
|
1175
|
+
the badge's --color/--ring tokens so every status keeps its identity
|
|
1176
|
+
instead of washing out to a neutral. */
|
|
1177
|
+
.status-cell--open {
|
|
1178
|
+
--bg: color-mix(in oklab, var(--color) 24%, var(--bb-panel));
|
|
1179
|
+
--border-color: color-mix(in oklab, var(--color) 45%, var(--bb-panel));
|
|
1180
|
+
box-shadow: 0 0 0 var(--bb-ring-size) var(--ring);
|
|
1181
|
+
}
|
|
1182
|
+
</style>
|
|
1183
|
+
```
|
|
1184
|
+
|
|
1185
|
+
### PriorityCell.vue
|
|
1186
|
+
|
|
1187
|
+
```vue
|
|
1188
|
+
<!-- BacklogWorkspace/PriorityCell.vue -->
|
|
1189
|
+
<template>
|
|
1190
|
+
<!-- Same grammar as StatusCell, its OWN leaf (§6.3): one `EditableCell`
|
|
1191
|
+
with a `type` prop growing a renderer switch is the API-monster seed. The
|
|
1192
|
+
sixty percent that repeats is cheaper than the prop that accumulates. -->
|
|
1193
|
+
<BbSelectPopover
|
|
1194
|
+
compact
|
|
1195
|
+
disable-writing
|
|
1196
|
+
item-text="label"
|
|
1197
|
+
item-value="value"
|
|
1198
|
+
:items="PRIORITY_OPTIONS"
|
|
1199
|
+
:model-value="priority"
|
|
1200
|
+
width="160px"
|
|
1201
|
+
@update:model-value="
|
|
1202
|
+
(next) => ctx.persistField(issue, 'priority', next as IssuePriority)
|
|
1203
|
+
"
|
|
1204
|
+
>
|
|
1205
|
+
<template #activator="{ props: activatorProps, shown }">
|
|
1206
|
+
<BbBadge
|
|
1207
|
+
append:icon="lucide:chevron-down"
|
|
1208
|
+
:class="{ 'priority-cell--open': shown }"
|
|
1209
|
+
:loading="ctx.isSaving(issue, 'priority')"
|
|
1210
|
+
:variant="PRIORITY_VARIANT[priority]"
|
|
1211
|
+
>
|
|
1212
|
+
<BbBadgeButton v-bind="activatorProps">{{ label }}</BbBadgeButton>
|
|
1213
|
+
</BbBadge>
|
|
1214
|
+
</template>
|
|
1215
|
+
</BbSelectPopover>
|
|
1216
|
+
</template>
|
|
1217
|
+
|
|
1218
|
+
<script setup lang="ts">
|
|
1219
|
+
import { computed } from 'vue';
|
|
1220
|
+
import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
|
|
1221
|
+
import {
|
|
1222
|
+
PRIORITY_OPTIONS,
|
|
1223
|
+
PRIORITY_VARIANT,
|
|
1224
|
+
useBacklogWorkspace,
|
|
1225
|
+
} from './context';
|
|
1226
|
+
import type { Issue, IssuePriority } from '@/types';
|
|
1227
|
+
|
|
1228
|
+
const props = defineProps<{ issue: Issue }>();
|
|
1229
|
+
|
|
1230
|
+
const ctx = useBacklogWorkspace();
|
|
1231
|
+
|
|
1232
|
+
const priority = computed(() => ctx.valueOf(props.issue, 'priority'));
|
|
1233
|
+
const label = computed(
|
|
1234
|
+
() =>
|
|
1235
|
+
PRIORITY_OPTIONS.find((option) => option.value === priority.value)?.label ??
|
|
1236
|
+
priority.value
|
|
1237
|
+
);
|
|
1238
|
+
</script>
|
|
1239
|
+
|
|
1240
|
+
<style scoped>
|
|
1241
|
+
/* Open = the badge's own hue, deepened, plus its variant ring (see
|
|
1242
|
+
StatusCell). */
|
|
1243
|
+
.priority-cell--open {
|
|
1244
|
+
--bg: color-mix(in oklab, var(--color) 24%, var(--bb-panel));
|
|
1245
|
+
--border-color: color-mix(in oklab, var(--color) 45%, var(--bb-panel));
|
|
1246
|
+
box-shadow: 0 0 0 var(--bb-ring-size) var(--ring);
|
|
1247
|
+
}
|
|
1248
|
+
</style>
|
|
1249
|
+
```
|
|
1250
|
+
|
|
1251
|
+
### AssigneeCell.vue
|
|
1252
|
+
|
|
1253
|
+
```vue
|
|
1254
|
+
<!-- BacklogWorkspace/AssigneeCell.vue -->
|
|
1255
|
+
<template>
|
|
1256
|
+
<!-- Provider-backed people picker. The provider is the ONE shared
|
|
1257
|
+
`searchMembers` — lazy per instance, so a row nobody opens never fetches.
|
|
1258
|
+
The whole member is the value (no item-value), matching how the row
|
|
1259
|
+
stores it. -->
|
|
1260
|
+
<BbSelectPopover
|
|
1261
|
+
compact
|
|
1262
|
+
item-text="name"
|
|
1263
|
+
:items="searchMembers"
|
|
1264
|
+
:model-value="assignee"
|
|
1265
|
+
width="220px"
|
|
1266
|
+
@update:model-value="
|
|
1267
|
+
(next) => ctx.persistField(issue, 'assignee', next as Member)
|
|
1268
|
+
"
|
|
1269
|
+
>
|
|
1270
|
+
<template #activator="{ props: activatorProps, shown }">
|
|
1271
|
+
<!-- Labelled from the ROW (through the overlay), never from the
|
|
1272
|
+
popover's `text`: a lazy provider has no items until first open, so
|
|
1273
|
+
`text` is empty — and the rows nobody opens must still read right on
|
|
1274
|
+
first paint. An assignee is a person, not a semantic status, so the
|
|
1275
|
+
badge stays neutral (`secondary`), no soft accent. -->
|
|
1276
|
+
<BbBadge
|
|
1277
|
+
append:icon="lucide:chevron-down"
|
|
1278
|
+
:class="{ 'assignee-cell--open': shown }"
|
|
1279
|
+
:loading="ctx.isSaving(issue, 'assignee')"
|
|
1280
|
+
variant="secondary"
|
|
1281
|
+
>
|
|
1282
|
+
<BbBadgeButton v-bind="activatorProps">{{
|
|
1283
|
+
assignee.name
|
|
1284
|
+
}}</BbBadgeButton>
|
|
1285
|
+
</BbBadge>
|
|
1286
|
+
</template>
|
|
1287
|
+
</BbSelectPopover>
|
|
1288
|
+
</template>
|
|
1289
|
+
|
|
1290
|
+
<script setup lang="ts">
|
|
1291
|
+
import { computed } from 'vue';
|
|
1292
|
+
import { BbBadge, BbBadgeButton, BbSelectPopover } from 'bitboss-ui';
|
|
1293
|
+
import { searchMembers, useBacklogWorkspace } from './context';
|
|
1294
|
+
import type { Issue, Member } from '@/types';
|
|
1295
|
+
|
|
1296
|
+
const props = defineProps<{ issue: Issue }>();
|
|
1297
|
+
|
|
1298
|
+
const ctx = useBacklogWorkspace();
|
|
1299
|
+
|
|
1300
|
+
const assignee = computed(() => ctx.valueOf(props.issue, 'assignee'));
|
|
1301
|
+
</script>
|
|
1302
|
+
|
|
1303
|
+
<style scoped>
|
|
1304
|
+
/* Open = the badge's own hue, deepened, plus its variant ring (see
|
|
1305
|
+
StatusCell). */
|
|
1306
|
+
.assignee-cell--open {
|
|
1307
|
+
--bg: color-mix(in oklab, var(--color) 24%, var(--bb-panel));
|
|
1308
|
+
--border-color: color-mix(in oklab, var(--color) 45%, var(--bb-panel));
|
|
1309
|
+
box-shadow: 0 0 0 var(--bb-ring-size) var(--ring);
|
|
1310
|
+
}
|
|
1311
|
+
</style>
|
|
1312
|
+
```
|
|
1313
|
+
|
|
1314
|
+
### RowActions.vue
|
|
1315
|
+
|
|
1316
|
+
```vue
|
|
1317
|
+
<!-- BacklogWorkspace/RowActions.vue -->
|
|
1318
|
+
<template>
|
|
1319
|
+
<BbDropdown
|
|
1320
|
+
:items="[
|
|
1321
|
+
{
|
|
1322
|
+
key: 'duplicate',
|
|
1323
|
+
text: 'Duplicate',
|
|
1324
|
+
'prepend:icon': 'lucide:copy',
|
|
1325
|
+
onClick: () => ctx.duplicateIssue(issue),
|
|
1326
|
+
},
|
|
1327
|
+
{
|
|
1328
|
+
key: 'next-sprint',
|
|
1329
|
+
text: 'Move to next sprint',
|
|
1330
|
+
'prepend:icon': 'lucide:arrow-right',
|
|
1331
|
+
onClick: () => ctx.moveToNextSprint(issue),
|
|
1332
|
+
},
|
|
1333
|
+
{
|
|
1334
|
+
key: 'delete',
|
|
1335
|
+
text: 'Delete',
|
|
1336
|
+
'prepend:icon': 'lucide:trash-2',
|
|
1337
|
+
variant: 'destructive',
|
|
1338
|
+
onClick: () => ctx.deleteIssue(issue),
|
|
1339
|
+
},
|
|
1340
|
+
]"
|
|
1341
|
+
>
|
|
1342
|
+
<template #activator="{ props }">
|
|
1343
|
+
<BbButton v-bind="props" icon="lucide:ellipsis" size="sm" variant="ghost">
|
|
1344
|
+
Issue actions
|
|
1345
|
+
</BbButton>
|
|
1346
|
+
</template>
|
|
1347
|
+
</BbDropdown>
|
|
1348
|
+
</template>
|
|
1349
|
+
|
|
1350
|
+
<script setup lang="ts">
|
|
1351
|
+
import { BbButton, BbDropdown } from 'bitboss-ui';
|
|
1352
|
+
import { useBacklogWorkspace } from './context';
|
|
1353
|
+
import type { Issue } from '@/types';
|
|
1354
|
+
|
|
1355
|
+
defineProps<{ issue: Issue }>();
|
|
1356
|
+
|
|
1357
|
+
const ctx = useBacklogWorkspace();
|
|
1358
|
+
</script>
|
|
1359
|
+
```
|
|
1360
|
+
|
|
1361
|
+
### SelectionBar.vue
|
|
1362
|
+
|
|
1363
|
+
```vue
|
|
1364
|
+
<!-- BacklogWorkspace/SelectionBar.vue -->
|
|
1365
|
+
<template>
|
|
1366
|
+
<FloatingBottomPanel :open="selectedCount > 0">
|
|
1367
|
+
<span class="px-2 text-sm">{{ selectedCount }} selected</span>
|
|
1368
|
+
|
|
1369
|
+
<!-- Bulk pickers are DISPATCHERS, not fields: model stays null, every
|
|
1370
|
+
pick fires the bulk action and the popover closes. The bar holds no
|
|
1371
|
+
state of its own. `placement="top"` because the bar hugs the viewport
|
|
1372
|
+
bottom — open upward instead of flipping — with an 8px `offset` so the
|
|
1373
|
+
menu clears the bar. -->
|
|
1374
|
+
<BbSelectPopover
|
|
1375
|
+
disable-writing
|
|
1376
|
+
item-text="label"
|
|
1377
|
+
item-value="value"
|
|
1378
|
+
:items="STATUS_OPTIONS"
|
|
1379
|
+
:model-value="null"
|
|
1380
|
+
:offset="8"
|
|
1381
|
+
placement="top"
|
|
1382
|
+
width="180px"
|
|
1383
|
+
@update:model-value="(next) => ctx.bulkStatus(next as IssueStatus)"
|
|
1384
|
+
>
|
|
1385
|
+
<template #activator="{ props }">
|
|
1386
|
+
<BbButton
|
|
1387
|
+
v-bind="props"
|
|
1388
|
+
append:icon="lucide:chevron-up"
|
|
1389
|
+
size="sm"
|
|
1390
|
+
variant="ghost"
|
|
1391
|
+
>
|
|
1392
|
+
Set status
|
|
1393
|
+
</BbButton>
|
|
1394
|
+
</template>
|
|
1395
|
+
</BbSelectPopover>
|
|
1396
|
+
|
|
1397
|
+
<BbSelectPopover
|
|
1398
|
+
item-text="name"
|
|
1399
|
+
:items="searchMembers"
|
|
1400
|
+
:model-value="null"
|
|
1401
|
+
:offset="8"
|
|
1402
|
+
placement="top"
|
|
1403
|
+
width="220px"
|
|
1404
|
+
@update:model-value="(next) => ctx.bulkAssign(next as Member)"
|
|
1405
|
+
>
|
|
1406
|
+
<template #activator="{ props }">
|
|
1407
|
+
<BbButton
|
|
1408
|
+
v-bind="props"
|
|
1409
|
+
append:icon="lucide:chevron-up"
|
|
1410
|
+
size="sm"
|
|
1411
|
+
variant="ghost"
|
|
1412
|
+
>
|
|
1413
|
+
Assign
|
|
1414
|
+
</BbButton>
|
|
1415
|
+
</template>
|
|
1416
|
+
</BbSelectPopover>
|
|
1417
|
+
|
|
1418
|
+
<BbButton
|
|
1419
|
+
prepend:icon="lucide:arrow-right"
|
|
1420
|
+
size="sm"
|
|
1421
|
+
variant="ghost"
|
|
1422
|
+
@click="ctx.bulkMoveToNextSprint"
|
|
1423
|
+
>
|
|
1424
|
+
Next sprint
|
|
1425
|
+
</BbButton>
|
|
1426
|
+
|
|
1427
|
+
<div class="floating-bottom-panel__right flex items-center gap-1">
|
|
1428
|
+
<BbButton
|
|
1429
|
+
aria-label="Clear selection"
|
|
1430
|
+
icon="lucide:x"
|
|
1431
|
+
size="sm"
|
|
1432
|
+
variant="ghost"
|
|
1433
|
+
@click="clearSelection"
|
|
1434
|
+
/>
|
|
1435
|
+
</div>
|
|
1436
|
+
</FloatingBottomPanel>
|
|
1437
|
+
</template>
|
|
1438
|
+
|
|
1439
|
+
<script setup lang="ts">
|
|
1440
|
+
import { computed } from 'vue';
|
|
1441
|
+
import { BbButton, BbSelectPopover } from 'bitboss-ui';
|
|
1442
|
+
import FloatingBottomPanel from '@/components/layout/FloatingBottomPanel.vue';
|
|
1443
|
+
import { STATUS_OPTIONS, searchMembers, useBacklogWorkspace } from './context';
|
|
1444
|
+
import type { IssueStatus, Member } from '@/types';
|
|
1445
|
+
|
|
1446
|
+
const ctx = useBacklogWorkspace();
|
|
1447
|
+
|
|
1448
|
+
const selectedCount = computed(() => ctx.table.selected.value?.length ?? 0);
|
|
1449
|
+
const clearSelection = () => {
|
|
1450
|
+
ctx.table.selected.value = [];
|
|
1451
|
+
};
|
|
1452
|
+
</script>
|
|
1453
|
+
```
|
|
1454
|
+
|
|
1455
|
+
### IssuePeek.vue
|
|
1456
|
+
|
|
1457
|
+
```vue
|
|
1458
|
+
<!-- BacklogWorkspace/IssuePeek.vue -->
|
|
1459
|
+
<template>
|
|
1460
|
+
<div v-if="issue" class="flex flex-col gap-4 text-sm">
|
|
1461
|
+
<!-- Identity header. -->
|
|
1462
|
+
<header class="flex flex-col gap-1">
|
|
1463
|
+
<p class="text-xs font-medium text-gray-500">{{ issue.ref }}</p>
|
|
1464
|
+
<h2 class="text-base font-semibold">{{ issue.title }}</h2>
|
|
1465
|
+
</header>
|
|
1466
|
+
|
|
1467
|
+
<!-- Properties: the SAME editable cells as the grid — one leaf, two
|
|
1468
|
+
call sites. Change the status here and the grid's badge (and even the
|
|
1469
|
+
blocked-row tint) moves in the same tick, because both surfaces read
|
|
1470
|
+
the same overlay; the spinner shows in both places at once. -->
|
|
1471
|
+
<dl class="grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2">
|
|
1472
|
+
<dt class="text-gray-500">Status</dt>
|
|
1473
|
+
<dd><StatusCell :issue="issue" /></dd>
|
|
1474
|
+
<dt class="text-gray-500">Priority</dt>
|
|
1475
|
+
<dd><PriorityCell :issue="issue" /></dd>
|
|
1476
|
+
<dt class="text-gray-500">Assignee</dt>
|
|
1477
|
+
<dd><AssigneeCell :issue="issue" /></dd>
|
|
1478
|
+
<dt class="text-gray-500">Estimate</dt>
|
|
1479
|
+
<dd>
|
|
1480
|
+
{{
|
|
1481
|
+
ctx.valueOf(issue, 'estimate') === null
|
|
1482
|
+
? 'Unestimated'
|
|
1483
|
+
: `${ctx.valueOf(issue, 'estimate')} points`
|
|
1484
|
+
}}
|
|
1485
|
+
</dd>
|
|
1486
|
+
<dt class="text-gray-500">Sprint</dt>
|
|
1487
|
+
<dd>{{ issue.sprint }}</dd>
|
|
1488
|
+
</dl>
|
|
1489
|
+
|
|
1490
|
+
<!-- Description. -->
|
|
1491
|
+
<section class="flex flex-col gap-1.5">
|
|
1492
|
+
<h3 class="text-xs font-semibold uppercase tracking-wide text-gray-500">
|
|
1493
|
+
Description
|
|
1494
|
+
</h3>
|
|
1495
|
+
<p class="whitespace-pre-line text-gray-700 dark:text-gray-300">
|
|
1496
|
+
{{ issue.description }}
|
|
1497
|
+
</p>
|
|
1498
|
+
</section>
|
|
1499
|
+
|
|
1500
|
+
<!-- Activity feed. -->
|
|
1501
|
+
<section class="flex flex-col gap-1.5">
|
|
1502
|
+
<h3 class="text-xs font-semibold uppercase tracking-wide text-gray-500">
|
|
1503
|
+
Activity
|
|
1504
|
+
</h3>
|
|
1505
|
+
<ul class="flex flex-col gap-2">
|
|
1506
|
+
<li v-for="entry in issue.activity" :key="entry.id" class="flex gap-2">
|
|
1507
|
+
<BbIcon
|
|
1508
|
+
class="mt-0.5 shrink-0 text-gray-400"
|
|
1509
|
+
:icon="entry.icon"
|
|
1510
|
+
size="14"
|
|
1511
|
+
/>
|
|
1512
|
+
<div class="flex flex-col">
|
|
1513
|
+
<span>{{ entry.text }}</span>
|
|
1514
|
+
<span class="text-xs text-gray-500"
|
|
1515
|
+
>{{ entry.actor }} · {{ longDate(entry.at) }}</span
|
|
1516
|
+
>
|
|
1517
|
+
</div>
|
|
1518
|
+
</li>
|
|
1519
|
+
</ul>
|
|
1520
|
+
</section>
|
|
1521
|
+
|
|
1522
|
+
<!-- Peek is a workbench: act here, or leave for the full page. -->
|
|
1523
|
+
<footer class="mt-2 flex items-center gap-2 border-t pt-3">
|
|
1524
|
+
<BbButton
|
|
1525
|
+
prepend:icon="lucide:arrow-right"
|
|
1526
|
+
size="sm"
|
|
1527
|
+
variant="secondary"
|
|
1528
|
+
@click="() => ctx.moveToNextSprint(issue!)"
|
|
1529
|
+
>
|
|
1530
|
+
Next sprint
|
|
1531
|
+
</BbButton>
|
|
1532
|
+
<BbButton
|
|
1533
|
+
size="sm"
|
|
1534
|
+
variant="destructive"
|
|
1535
|
+
@click="() => ctx.deleteIssue(issue!)"
|
|
1536
|
+
>
|
|
1537
|
+
Delete
|
|
1538
|
+
</BbButton>
|
|
1539
|
+
<BbButton
|
|
1540
|
+
append:icon="lucide:arrow-up-right"
|
|
1541
|
+
size="sm"
|
|
1542
|
+
:to="`/issues/${issue.id}`"
|
|
1543
|
+
variant="ghost"
|
|
1544
|
+
>
|
|
1545
|
+
Open full page
|
|
1546
|
+
</BbButton>
|
|
1547
|
+
</footer>
|
|
1548
|
+
</div>
|
|
1549
|
+
|
|
1550
|
+
<div v-else class="flex justify-center p-8">
|
|
1551
|
+
<BbSpinner />
|
|
1552
|
+
</div>
|
|
1553
|
+
</template>
|
|
1554
|
+
|
|
1555
|
+
<script setup lang="ts">
|
|
1556
|
+
import { ref, watchEffect } from 'vue';
|
|
1557
|
+
import { BbButton, BbIcon, BbSpinner } from 'bitboss-ui';
|
|
1558
|
+
import AssigneeCell from './AssigneeCell.vue';
|
|
1559
|
+
import PriorityCell from './PriorityCell.vue';
|
|
1560
|
+
import StatusCell from './StatusCell.vue';
|
|
1561
|
+
import { useBacklogWorkspace } from './context';
|
|
1562
|
+
import type { IssueDetail } from '@/types';
|
|
1563
|
+
|
|
1564
|
+
const props = defineProps<{ issueId: string }>();
|
|
1565
|
+
|
|
1566
|
+
const ctx = useBacklogWorkspace();
|
|
1567
|
+
|
|
1568
|
+
// Re-fetches whenever the stack shows a different issue; reading `ctx.issues`
|
|
1569
|
+
// makes every commit (from the grid OR from this panel) — each of which ends
|
|
1570
|
+
// in the list's `refresh()` — reflect here immediately. The cells inside
|
|
1571
|
+
// don't flash across that reload either — they read the overlay, and the
|
|
1572
|
+
// overlay only retires when the fresh data confirms it.
|
|
1573
|
+
const issue = ref<IssueDetail | null>(null);
|
|
1574
|
+
watchEffect(async () => {
|
|
1575
|
+
void ctx.issues.value;
|
|
1576
|
+
issue.value = await $fetch<IssueDetail>(`/api/issues/${props.issueId}`);
|
|
1577
|
+
});
|
|
1578
|
+
|
|
1579
|
+
const longDate = (value: string) =>
|
|
1580
|
+
new Date(value).toLocaleDateString('en-US', {
|
|
1581
|
+
month: 'short',
|
|
1582
|
+
day: 'numeric',
|
|
1583
|
+
year: 'numeric',
|
|
1584
|
+
});
|
|
1585
|
+
</script>
|
|
1586
|
+
```
|
|
1587
|
+
|
|
1588
|
+
## Why it is built this way
|
|
1589
|
+
|
|
1590
|
+
- **`pending` sits on rung 3, and the recipe's whole shape follows from
|
|
1591
|
+
that.** Three consumers force it up the ladder: the cells read it to render
|
|
1592
|
+
optimistically, the peek reads it so the second call site of every cell
|
|
1593
|
+
agrees with the first, and the `useAsyncData` transform reads it to retire
|
|
1594
|
+
confirmed fields. Contrast the records workspace's §6.1 status cell, where
|
|
1595
|
+
`saving` is a rung-1 local `ref` around one awaited action — correct
|
|
1596
|
+
**there** because nothing but that one cell ever cares. Here the fetch must
|
|
1597
|
+
know what's in flight, so a local flag physically cannot work; that is why
|
|
1598
|
+
the picker cells bind `:loading="ctx.isSaving(issue, 'status')"` instead of
|
|
1599
|
+
owning a `saving` ref.
|
|
1600
|
+
- **`persistField` is one complete action for every control kind.** Text,
|
|
1601
|
+
number, and three pickers all commit through the same guard → optimistic
|
|
1602
|
+
set → PATCH → refetch pipeline, so the failure story (drop one field,
|
|
1603
|
+
destructive toast) and the no-op story (blur without change costs nothing)
|
|
1604
|
+
are written once. The guard compares against `valueOf`, not the raw row —
|
|
1605
|
+
what the user _sees_ is the value they are re-committing.
|
|
1606
|
+
- **Retirement lives in the fetch's `transform` because that is when the
|
|
1607
|
+
truth changes.** A resolved PATCH proves the server accepted the value, not
|
|
1608
|
+
that the table shows it — the rows in memory are still old until the
|
|
1609
|
+
refetch lands. Retiring per-field (only values the response confirms) means
|
|
1610
|
+
a slow title save survives a fast status save's reload untouched. The
|
|
1611
|
+
comment on the `transform` ships with the recipe on purpose: this is the
|
|
1612
|
+
§6.8 bug everyone writes once.
|
|
1613
|
+
- **The URL is the filter store, `useAsyncData` is the fetch.** Filters and
|
|
1614
|
+
tab are seeded from `route.query` once at setup, mirrored back with
|
|
1615
|
+
`navigateTo` on every change (debounced for free text), and
|
|
1616
|
+
`useAsyncData('issues', …, { watch: [() => route.query, table.page] })` is
|
|
1617
|
+
the single refetch trigger — there is exactly one place data loads, which
|
|
1618
|
+
is also the only place the overlay retires. The assignee pill is the one
|
|
1619
|
+
URL nuance: rows store the whole member, but a deep link carries only an
|
|
1620
|
+
id, so the context resolves it to a member once at setup.
|
|
1621
|
+
- **`valueOf` checks `key in patch`, not `??`.** A cleared estimate commits
|
|
1622
|
+
`null`, and `null ?? row.estimate` would silently un-render the overlay
|
|
1623
|
+
while the save runs. The one-line comment in the context is load-bearing.
|
|
1624
|
+
- **No dirty ring anywhere, no success toasts for cell commits.** Autosave
|
|
1625
|
+
has no "changed but unsaved" state, so the ring (the draft-map pattern's
|
|
1626
|
+
grammar) would lie; and a page where every blur saves would toast
|
|
1627
|
+
constantly. The spinner in the chevron's place is the feedback; failure is
|
|
1628
|
+
the exception worth announcing (destructive toast + `has-errors` on the
|
|
1629
|
+
text/number cells via the `failed` set; badge cells announce by visibly
|
|
1630
|
+
snapping back). Discrete actions — duplicate, move, delete, bulk — _do_
|
|
1631
|
+
toast success: they are events, not keystrokes.
|
|
1632
|
+
- **Five cells, five leaves.** `EditableTitleCell`, `EstimateCell`,
|
|
1633
|
+
`StatusCell`, `PriorityCell`, `AssigneeCell` — never one `EditableCell`
|
|
1634
|
+
with a `type` prop growing a renderer switch (§6.3/§4). Each takes exactly
|
|
1635
|
+
one data prop (`issue`) and gets its behavior from the context.
|
|
1636
|
+
- **Typed inputs commit on `@change`; pickers commit on pick.** The text and
|
|
1637
|
+
number cells bind `:model-value` down and read the committed value from the
|
|
1638
|
+
native event (`event.target`); the number cell's change carries the raw
|
|
1639
|
+
string where `''` means cleared. No debounce machinery — blur/Enter and
|
|
1640
|
+
pick are natural commit points, so the request count equals the commit
|
|
1641
|
+
count.
|
|
1642
|
+
- **Options resolve once.** Status and priority are module-level catalogs
|
|
1643
|
+
shared by the cells, the rail pills and the bulk picker — zero requests.
|
|
1644
|
+
The assignee is genuinely query-driven, so it gets the one exception: a
|
|
1645
|
+
**single** shared provider (`searchMembers`), lazy per instance, keeping
|
|
1646
|
+
unopened rows free; prefill calls return the whole six-person team so the
|
|
1647
|
+
current selection always resolves. Rows store the whole member, so every
|
|
1648
|
+
badge and the filter pill label themselves from data they already hold —
|
|
1649
|
+
no `watchEffect`-to-resolve-a-name anywhere on this page; the only
|
|
1650
|
+
directory lookup is the one-time deep-link resolution of `?assignee=` at
|
|
1651
|
+
setup.
|
|
1652
|
+
- **Internal links use `to`, not `href`.** `to` renders a real Vue Router
|
|
1653
|
+
link (client-side navigation); a raw `href` would force a full page reload.
|
|
1654
|
+
The `New issue` primary and the peek's `Open full page` link use `to`; the
|
|
1655
|
+
tabs keep `href` (`?tab=…`) because their client-side pushState is what
|
|
1656
|
+
keeps `route.query.tab` in sync — the URL-filter grammar itself.
|
|
1657
|
+
- **The ref cell is the peek handle** because the title — the "name" of an
|
|
1658
|
+
issue — is an input here, and a click that sometimes edits and sometimes
|
|
1659
|
+
navigates is a broken affordance. One record type also collapses the stack
|
|
1660
|
+
grammar to a single verb (`peekIssue`, fresh stack).
|
|
1661
|
+
- **The peek reuses the grid's cells verbatim** — one leaf, two call sites.
|
|
1662
|
+
Both read the same overlay, so a status change made in the panel updates
|
|
1663
|
+
the grid row (badge, tint, spinner) in the same tick, and vice versa.
|
|
1664
|
+
- **Sizing:** topbar follows `md`-first (`compact` inputs at 28px flush
|
|
1665
|
+
beside the default buttons); `sm` appears exactly where the doctrine
|
|
1666
|
+
allows — rail pills, row actions, the bulk bar, the peek footer. Cell
|
|
1667
|
+
inputs are `compact`.
|
|
1668
|
+
- **One `variant="primary"`** (New issue). The only irreversible action
|
|
1669
|
+
(delete — row menu and peek footer) rides `useConfirm`; moving between
|
|
1670
|
+
sprints is reversible, so it deliberately does not.
|
|
1671
|
+
|
|
1672
|
+
## Variations
|
|
1673
|
+
|
|
1674
|
+
- **Keyboard triage**: add `keyboard-navigation` to the table —
|
|
1675
|
+
`v-model:highlighted` already drives the peek — the approvals-inbox recipe
|
|
1676
|
+
is the full treatment; the overlay needs no changes, since it never cared
|
|
1677
|
+
how a commit was triggered.
|
|
1678
|
+
- **Review-before-save domains**: if the product wants a batch the user
|
|
1679
|
+
confirms (accounting lines, permissions), swap the overlay for the
|
|
1680
|
+
draft-map pattern — dirty ring, dirty-gated Save — per the
|
|
1681
|
+
[Inline Edit Playbook](../../guides/inline-edit-playbook.md); the
|
|
1682
|
+
record-form recipe's line-item editor assembles it. Never mix both
|
|
1683
|
+
grammars on one table.
|
|
1684
|
+
- **Undo instead of confirm**: for softer destructive-ish moves (Done →
|
|
1685
|
+
reopened), a success toast with an Undo action that PATCHes the old value
|
|
1686
|
+
back is more Linear than a confirm dialog.
|
|
1687
|
+
- **Live board**: because refetches retire the overlay per confirmed field,
|
|
1688
|
+
a polling `refresh()` call (or a websocket-triggered one) is safe — a
|
|
1689
|
+
poll landing mid-save cannot destroy an in-flight edit, which is exactly
|
|
1690
|
+
the property the write-back anti-pattern lacks.
|