diff --git a/.husky/.gitignore b/.husky/.gitignore deleted file mode 100644 index 31354ec13..000000000 --- a/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ diff --git a/.husky/pre-commit b/.husky/pre-commit index fab6428a1..cb2c84d5c 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - pnpm lint-staged diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 000000000..1f4f89584 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "MD013": false, + "MD033":false +} \ No newline at end of file diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ba01c71a5..69b9cf69c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,4 +1,4 @@ { - "packages/bootstrap-vue-next": "0.25.15", - "packages/nuxt": "0.25.15" + "packages/bootstrap-vue-next": "0.26.0", + "packages/nuxt": "0.26.0" } diff --git a/.vscode/extensions.json b/.vscode/extensions.json index a7cea0b06..a06a8c699 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,9 @@ { - "recommendations": ["Vue.volar"] + "recommendations": [ + "Vue.volar", + "vitest.explorer", + "dbaeumer.vscode-eslint", + "EditorConfig.EditorConfig", + "esbenp.prettier-vscode" + ] } diff --git a/apps/docs/.eslintrc.cjs b/apps/docs/.eslintrc.cjs deleted file mode 100644 index 14669553e..000000000 --- a/apps/docs/.eslintrc.cjs +++ /dev/null @@ -1,84 +0,0 @@ -/* eslint-env node */ -require('@rushstack/eslint-patch/modern-module-resolution') - -const {defineConfig} = require('eslint-define-config') - -module.exports = defineConfig({ - root: true, - extends: [ - 'eslint:recommended', - 'plugin:vue/vue3-recommended', - '@vue/eslint-config-typescript/recommended', - '@vue/eslint-config-prettier', - ], - parserOptions: { - ecmaVersion: 'latest', - }, - rules: { - 'prettier/prettier': [ - 'warn', - { - endOfLine: 'auto', - }, - ], - 'no-alert': 'warn', - 'no-console': 'warn', - 'no-debugger': 'warn', - 'arrow-body-style': 'warn', - 'arrow-parens': 'warn', - 'eqeqeq': 'error', - 'generator-star-spacing': 'warn', - 'grouped-accessor-pairs': 'warn', - 'no-caller': 'error', - 'no-duplicate-imports': 'error', - 'no-else-return': 'warn', - 'no-eval': 'error', - 'no-extra-bind': 'warn', - 'no-implied-eval': 'error', - 'no-labels': 'warn', - 'no-lone-blocks': 'warn', - 'no-new-func': 'error', - 'no-new-wrappers': 'error', - 'no-return-await': 'warn', - 'no-template-curly-in-string': 'warn', - 'no-throw-literal': 'error', - 'no-undef-init': 'warn', - 'no-useless-call': 'warn', - 'no-useless-constructor': 'warn', - 'no-useless-rename': 'warn', - 'no-useless-return': 'warn', - 'no-var': 'error', - 'object-shorthand': 'warn', - 'prefer-const': 'warn', - 'prefer-destructuring': 'warn', - 'prefer-numeric-literals': 'warn', - 'prefer-rest-params': 'warn', - 'prefer-spread': 'warn', - 'prefer-template': 'warn', - 'require-atomic-updates': 'warn', - 'rest-spread-spacing': 'warn', - 'sort-imports': [ - 'warn', - { - ignoreCase: true, - ignoreDeclarationSort: true, - }, - ], - 'template-curly-spacing': 'warn', - 'yield-star-spacing': 'warn', - 'yoda': 'warn', - 'vue/html-self-closing': [ - 'error', - { - html: { - void: 'always', - normal: 'always', - component: 'always', - }, - svg: 'always', - math: 'always', - }, - ], - 'vue/eqeqeq': 'error', - }, -}) diff --git a/apps/docs/eslint.config.mjs b/apps/docs/eslint.config.mjs new file mode 100644 index 000000000..f49475024 --- /dev/null +++ b/apps/docs/eslint.config.mjs @@ -0,0 +1,91 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' +import pluginVitest from '@vitest/eslint-plugin' +import skipFormatting from '@vue/eslint-config-prettier' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue}'], + }, + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + ...pluginVue.configs['flat/recommended'], + ...vueTsEslintConfig(), + { + ...pluginVitest.configs.recommended, + files: ['src/**/*.spec.*', 'src/**/*.test.*'], + }, + skipFormatting, + { + rules: { + 'prettier/prettier': [ + 'warn', + { + endOfLine: 'auto', + }, + ], + 'no-alert': 'warn', + 'no-console': 'warn', + 'no-debugger': 'warn', + 'arrow-body-style': 'warn', + 'arrow-parens': 'warn', + 'eqeqeq': 'error', + 'generator-star-spacing': 'warn', + 'grouped-accessor-pairs': 'warn', + 'no-caller': 'error', + 'no-duplicate-imports': 'error', + 'no-else-return': 'warn', + 'no-eval': 'error', + 'no-extra-bind': 'warn', + 'no-implied-eval': 'error', + 'no-labels': 'warn', + 'no-lone-blocks': 'warn', + 'no-new-func': 'error', + 'no-new-wrappers': 'error', + 'no-return-await': 'warn', + 'no-template-curly-in-string': 'warn', + 'no-throw-literal': 'error', + 'no-undef-init': 'warn', + 'no-useless-call': 'warn', + 'no-useless-constructor': 'warn', + 'no-useless-rename': 'warn', + 'no-useless-return': 'warn', + 'no-var': 'error', + 'object-shorthand': 'warn', + 'prefer-const': 'warn', + 'prefer-destructuring': 'warn', + 'prefer-numeric-literals': 'warn', + 'prefer-rest-params': 'warn', + 'prefer-spread': 'warn', + 'prefer-template': 'warn', + 'require-atomic-updates': 'warn', + 'rest-spread-spacing': 'warn', + 'sort-imports': [ + 'warn', + { + ignoreCase: true, + ignoreDeclarationSort: true, + }, + ], + 'template-curly-spacing': 'warn', + 'yield-star-spacing': 'warn', + 'yoda': 'warn', + 'vue/html-self-closing': [ + 'error', + { + html: { + void: 'always', + normal: 'always', + component: 'always', + }, + svg: 'always', + math: 'always', + }, + ], + 'vue/eqeqeq': 'error', + }, + }, +] diff --git a/apps/docs/package.json b/apps/docs/package.json index f3db7e10a..ff8db363b 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -7,33 +7,33 @@ "dev": "vitepress dev --port 8000", "build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vitepress build", "preview": "vitepress preview", - "lint": "eslint --ext .js,.ts,.vue --ignore-path ../../.gitignore --fix src", - "test:lint": "eslint --ext .js,.ts,.vue --ignore-path ../../.gitignore src", + "lint": "eslint --fix src", + "test:lint": "eslint src", "test": "pnpm run test:lint" }, "devDependencies": { - "@iconify-json/bi": "^1.2.0", - "@iconify-json/simple-icons": "^1.2.2", + "@iconify-json/bi": "^1.2.1", + "@iconify-json/simple-icons": "^1.2.11", "@rushstack/eslint-patch": "^1.10.4", "@toycode/markdown-it-class": "^1.2.4", - "@tsconfig/node20": "^20.1.4", - "@types/node": "^22.5.4", - "@vue/eslint-config-prettier": "^9.0.0", - "@vue/eslint-config-typescript": "^13.0.0", - "@vue/tsconfig": "^0.5.1", - "@vueuse/core": "^11.0.3", + "@tsconfig/node22": "^22.0.0", + "@types/node": "^22.9.0", + "@vue/eslint-config-prettier": "^10.1.0", + "@vue/eslint-config-typescript": "^14.1.3", + "@vue/tsconfig": "^0.6.0", + "@vueuse/core": "^11.2.0", "bootstrap": "^5.3.3", "bootstrap-vue-next": "workspace:^", "cross-env": "^7.0.3", - "eslint": "^8.57.0", + "eslint": "^9.15.0", "eslint-define-config": "^2.1.0", - "eslint-plugin-vue": "^9.28.0", + "eslint-plugin-vue": "^9.31.0", "prettier": "^3.3.3", - "typescript": "^5.6.2", - "unplugin-icons": "^0.19.3", + "typescript": "^5.6.3", + "unplugin-icons": "^0.20.1", "unplugin-vue-components": "^0.27.4", - "vitepress": "1.3.4", - "vue": "^3.5.3" + "vitepress": "1.5.0", + "vue": "^3.5.13" }, "lint-staged": { "*.{js,ts,vue}": "eslint --cache --fix", diff --git a/apps/docs/src/data/components/accordion.data.ts b/apps/docs/src/data/components/accordion.data.ts index 0a4b6aefa..40d3186f0 100644 --- a/apps/docs/src/data/components/accordion.data.ts +++ b/apps/docs/src/data/components/accordion.data.ts @@ -26,6 +26,31 @@ export default { description: 'The Id of the accordion item that is currently open (not compatible with the `free===true`)', }, + lazy: { + type: 'boolean', + default: false, + description: 'When set, the content will not be mounted until opened', + }, + unmountLazy: { + type: 'boolean', + default: false, + description: 'When set and `lazy` is true, the content will be unmounted when closed', + }, + // transProps: { + // type: 'TransitionProps', + // default: undefined, + // description: 'Transition properties', + // }, + // noAnimation: { + // type: 'boolean', + // default: false, + // description: 'When set, disables the animation', + // }, + // noFade: { + // type: 'boolean', + // default: false, + // description: 'Alias for `noAnimation`', + // }, ...pick( buildCommonProps({ id: { @@ -125,17 +150,42 @@ export default { description: 'Text to place in the header of the AccordionItem (title slot takes precedence)', }, - toggle: { + show: { type: 'boolean', - default: undefined, + default: false, description: - 'When true, will toggle the visibility of the AccordionItem (including animation) when the component is mounted', + "When set, and prop 'visible' is false on mount, will animate from closed to open on initial mount", }, visible: { type: 'boolean', default: false, - description: 'When true, the AccordionItem will be visible', + description: "When 'true', open without animation", + }, + lazy: { + type: 'boolean', + default: false, + description: 'When set, the content will not be mounted until opened', + }, + unmountLazy: { + type: 'boolean', + default: false, + description: 'When set and `lazy` is true, the content will be unmounted when closed', }, + // transProps: { + // type: 'TransitionProps', + // default: undefined, + // description: 'Transition properties', + // }, + // noAnimation: { + // type: 'boolean', + // default: false, + // description: 'When set, disables the animation', + // }, + // noFade: { + // type: 'boolean', + // default: false, + // description: 'Alias for `noAnimation`', + // }, ...pick( buildCommonProps({ id: { diff --git a/apps/docs/src/data/components/card.data.ts b/apps/docs/src/data/components/card.data.ts index 14d0451d7..304e85d31 100644 --- a/apps/docs/src/data/components/card.data.ts +++ b/apps/docs/src/data/components/card.data.ts @@ -70,7 +70,6 @@ export default { 'footerBgVariant', 'footerBorderVariant', 'footerClass', - 'footerHtml', 'footerTag', 'footerTextVariant', 'footerVariant', @@ -78,7 +77,6 @@ export default { 'headerBgVariant', 'headerBorderVariant', 'headerClass', - 'headerHtml', 'headerTag', 'headerTextVariant', 'headerVariant', @@ -163,12 +161,6 @@ export default { emits: [], props: { '': { - html: { - type: 'string', - default: undefined, - description: - 'HTML content to place in the card footer, takes precednce over text prop and default slot', - }, text: { type: 'string', default: undefined, @@ -222,12 +214,6 @@ export default { emits: [], props: { '': { - html: { - type: 'string', - default: undefined, - description: - 'HTML content to place in the card header, takes precednce over text prop and default slot', - }, text: { type: 'string', default: undefined, diff --git a/apps/docs/src/data/components/carousel.data.ts b/apps/docs/src/data/components/carousel.data.ts index 99de92cc6..39aee37cf 100644 --- a/apps/docs/src/data/components/carousel.data.ts +++ b/apps/docs/src/data/components/carousel.data.ts @@ -186,11 +186,6 @@ export default { default: undefined, description: 'Text content to place in the caption', }, - captionHtml: { - type: 'string', - default: undefined, - description: 'HTML string content to place in the caption', - }, captionTag: { type: 'string', default: 'h3', @@ -253,11 +248,6 @@ export default { default: undefined, description: 'Text content to place in the text of the slide', }, - textHtml: { - type: 'string', - default: undefined, - description: 'HTML string content to place in the text of the slide', - }, textTag: { type: 'string', default: 'p', diff --git a/apps/docs/src/data/components/collapse.data.ts b/apps/docs/src/data/components/collapse.data.ts index 1cc94dd37..1218ce4c6 100644 --- a/apps/docs/src/data/components/collapse.data.ts +++ b/apps/docs/src/data/components/collapse.data.ts @@ -1,6 +1,6 @@ import type {BvnComponentProps} from 'bootstrap-vue-next' import type {ComponentReference, PropertyReference, SlotScopeReference} from '../../types' -import {buildCommonProps, pick} from '../../utils' +import {buildCommonProps, pick, showHideProps} from '../../utils' const sharedSlots: SlotScopeReference[] = [ { @@ -47,27 +47,7 @@ export default { description: 'When set, signifies that the collapse is part of a navbar, enabling certain features for navbar support', }, - modelValue: { - type: 'boolean', - default: false, - description: 'Controls the visibility of the collapse', - }, - skipAnimation: { - type: 'boolean', - default: false, - description: 'When set, disables the animation', - }, - toggle: { - type: 'boolean', - default: false, - description: - "When set, and prop 'visible' is false on mount, will animate from closed to open on initial mount", - }, - visible: { - type: 'boolean', - default: false, - description: "When 'true', expands the collapse", - }, + ...showHideProps, ...pick(buildCommonProps(), ['id', 'tag']), } satisfies Record, }, diff --git a/apps/docs/src/data/components/form.data.ts b/apps/docs/src/data/components/form.data.ts index 16f5d436b..829f3381f 100644 --- a/apps/docs/src/data/components/form.data.ts +++ b/apps/docs/src/data/components/form.data.ts @@ -45,7 +45,7 @@ export default { 'Array of items to render in the component. Note that BFormDatalist only supports Options, not OptionsGroups', }, }), - ['disabledField', 'htmlField', 'id', 'options', 'textField', 'valueField'] + ['disabledField', 'id', 'options', 'textField', 'valueField'] ), } satisfies Record, }, diff --git a/apps/docs/src/data/components/formCheckbox.data.ts b/apps/docs/src/data/components/formCheckbox.data.ts index 464e048cd..b7dfb391a 100644 --- a/apps/docs/src/data/components/formCheckbox.data.ts +++ b/apps/docs/src/data/components/formCheckbox.data.ts @@ -18,7 +18,7 @@ export default { type: 'boolean', default: false, description: - "When set, renders the checkbox as part of a button group (it doesn't enclose the checkbox and label with a div). It is not necessary to set this to true if this is part of a RadioGroup as it is handled internally", + "When set, renders the checkbox as part of a button group (it doesn't enclose the checkbox and label with a div). It is not necessary to set this to true if this is part of a CheckboxGroup as it is handled internally", }, buttonVariant: { type: 'ButtonVariant | null', @@ -170,7 +170,6 @@ export default { 'disabled', 'disabledField', 'form', - 'htmlField', 'id', 'name', 'plain', @@ -208,6 +207,28 @@ export default { 'Slot to place for checkboxes so that they appear before checks generated from options prop', scope: [], }, + { + name: 'option', + description: + 'Use this slot to have finer control over the content render inside each checkbox button.', + scope: [ + { + prop: 'value', + type: 'string | number | undefined', + description: 'The value of the checkbox button', + }, + { + prop: 'disabled', + type: 'boolean | undefined', + description: 'Whether the checkbox button is disabled', + }, + { + prop: 'text', + type: 'string | undefined', + description: 'The text to display for the checkbox button', + }, + ], + }, ], }, ], diff --git a/apps/docs/src/data/components/formRadio.data.ts b/apps/docs/src/data/components/formRadio.data.ts index bd2654412..df0918a55 100644 --- a/apps/docs/src/data/components/formRadio.data.ts +++ b/apps/docs/src/data/components/formRadio.data.ts @@ -126,7 +126,6 @@ export default { 'disabled', 'disabledField', 'form', - 'htmlField', 'id', 'name', 'options', @@ -165,6 +164,28 @@ export default { 'Slot to place for radio buttons so that they appear before radios generated from options prop', scope: [], }, + { + name: 'option', + description: + 'Use this slot to have finer control over the content render inside each radio button', + scope: [ + { + prop: 'value', + type: 'string | number | undefined', + description: 'The value of the radio button', + }, + { + prop: 'disabled', + type: 'boolean | undefined', + description: 'Whether the radio button is disabled', + }, + { + prop: 'text', + type: 'string | undefined', + description: 'The text to display for the radio button', + }, + ], + }, ], }, ], diff --git a/apps/docs/src/data/components/formSelect.data.ts b/apps/docs/src/data/components/formSelect.data.ts index 74909575e..d62c75b54 100644 --- a/apps/docs/src/data/components/formSelect.data.ts +++ b/apps/docs/src/data/components/formSelect.data.ts @@ -45,7 +45,6 @@ export default { 'disabled', 'disabledField', 'form', - 'htmlField', 'id', 'name', 'options', @@ -124,7 +123,7 @@ export default { buildCommonProps({ options: {type: 'readonly (unknown | Record)[]'}, }), - ['disabledField', 'htmlField', 'options', 'textField', 'valueField'] + ['disabledField', 'options', 'textField', 'valueField'] ), } satisfies Record, }, diff --git a/apps/docs/src/data/components/inputGroup.data.ts b/apps/docs/src/data/components/inputGroup.data.ts index 732da3520..dc2869f4b 100644 --- a/apps/docs/src/data/components/inputGroup.data.ts +++ b/apps/docs/src/data/components/inputGroup.data.ts @@ -14,23 +14,11 @@ export default { default: undefined, description: 'Text to append to the input group', }, - appendHtml: { - type: 'string', - default: undefined, - description: - "HTML string to append to the input group. Has precedence over 'append' prop", - }, prepend: { type: 'string', default: undefined, description: 'Text to prepend to the input group', }, - prependHtml: { - type: 'string', - default: undefined, - description: - "HTML string to prepend to the input group. Has precedence over 'prepend' prop", - }, ...pick(buildCommonProps(buildCommonProps()), ['id', 'size', 'tag']), } satisfies Record, }, diff --git a/apps/docs/src/data/components/modal.data.ts b/apps/docs/src/data/components/modal.data.ts index 8d9d7df6f..8e7ed0094 100644 --- a/apps/docs/src/data/components/modal.data.ts +++ b/apps/docs/src/data/components/modal.data.ts @@ -1,5 +1,6 @@ import type {BvnComponentProps} from 'bootstrap-vue-next' import type {ComponentReference, PropertyReference, SlotScopeReference} from '../../types' +import {showHideProps} from '../../utils' const sharedSlots: SlotScopeReference[] = [ { @@ -52,6 +53,12 @@ export default { description: "Specify which built-in button to focus once the modal opens: 'ok', 'cancel', or 'close'", }, + backdropFirst: { + type: 'boolean', + default: false, + description: + 'Animate the backdrop before the modal, and on leave animate the modal before the backdrop', + }, body: { type: 'string', default: undefined, @@ -202,22 +209,22 @@ export default { description: 'Applies one of the Bootstrap theme color variants to the header (this takes priority over headerBgVariant and headerTextVariant)', }, - hideBackdrop: { + noBackdrop: { type: 'boolean', default: false, description: 'Disables rendering of the modal backdrop', }, - hideFooter: { + noFooter: { type: 'boolean', default: false, description: 'Disables rendering of the modal footer', }, - hideHeader: { + noHeader: { type: 'boolean', default: false, description: 'Disables rendering of the modal header', }, - hideHeaderClose: { + noHeaderClose: { type: 'boolean', default: false, description: 'Disables rendering of the modal header close button', @@ -228,21 +235,11 @@ export default { description: "Used to set the 'id' attribute on the rendered content, and used as the base to generate any additional element IDs as needed", }, - lazy: { - type: 'boolean', - default: false, - description: 'Renders the modal content lazily', - }, modalClass: { type: 'ClassValue', default: undefined, description: "CSS class (or classes) to apply to the '.modal' wrapper element", }, - modelValue: { - type: 'boolean', - default: false, - description: 'Controls the visibility state of the modal', - }, noCloseOnBackdrop: { type: 'boolean', default: false, @@ -254,12 +251,6 @@ export default { default: false, description: 'Disables the ability to close the modal by pressing the ESC key', }, - noFade: { - type: 'boolean', - default: false, - description: - "When set to 'true', disables the fade animation/transition on the component", - }, noStacking: { type: 'boolean', default: false, @@ -329,10 +320,7 @@ export default { default: 'h5', description: 'Specify the HTML tag to render instead of the default tag for the title', }, - transProps: { - type: 'Readonly', - default: undefined, - }, + ...showHideProps, } satisfies Record, }, emits: [ diff --git a/apps/docs/src/data/components/navbar.data.ts b/apps/docs/src/data/components/navbar.data.ts index be33b1ca2..7c2df0f63 100644 --- a/apps/docs/src/data/components/navbar.data.ts +++ b/apps/docs/src/data/components/navbar.data.ts @@ -1,5 +1,7 @@ import type {BvnComponentProps} from 'bootstrap-vue-next' import type {ComponentReference, PropertyReference} from '../../types' +import {buildCommonProps, omit, pick} from '../../utils' +import {linkProps, linkTo} from '../../utils/link-props' export default { load: (): ComponentReference[] => [ @@ -8,46 +10,50 @@ export default { sourcePath: '/BNavbar/BNavbar.vue', props: { '': { - autoClose: { - type: 'boolean', - default: true, - }, container: { type: "boolean | 'fluid' | Breakpoint", default: 'fluid', + description: + "Use the container option to change the layout of the navbar. By default, the navbar is a fluid container. Use 'fluid' for a full width navbar, or a responsive breakpoint for a container width navbar.", }, fixed: { type: "'top' | 'bottom'", default: undefined, + description: + "Set to 'top' for fixed to the top of the viewport, or 'bottom' for fixed to the bottom of the viewport", }, print: { type: 'boolean', default: false, + description: + 'Navbars are hidden by default when printing. When this prop is set it will be printed', }, sticky: { type: "'top' | 'bottom'", default: undefined, - }, - tag: { - type: 'string', - default: 'nav', + description: + "Set to true to make the navbar stick to the top of the viewport (or parent container that has 'position: relative' set) when scrolled", }, toggleable: { type: 'boolean | Breakpoint', default: false, - }, - variant: { - type: 'ColorVariant | null', - default: null, - }, + description: + "Set to 'true' for an always collapsed navbar, or to a specific breakpoint at which point the navbar will be expanded: 'sm', 'md', 'lg', 'xl', or 'xxl'", + }, + ...pick( + buildCommonProps({ + tag: { + default: 'nav', + }, + }), + ['autoClose', 'tag', 'variant'] + ), } satisfies Record, }, - emits: [], slots: [ { - description: '', name: 'default', - scope: [], + description: 'Content to place in the navbar', }, ], }, @@ -56,102 +62,29 @@ export default { sourcePath: '/BNavbar/BNavbarBrand.vue', props: { '': { - active: { - type: 'boolean', - default: undefined, - }, - activeClass: { - type: 'string', - default: undefined, - }, - disabled: { - type: 'boolean', - default: undefined, - }, - exactActiveClass: { - type: 'string', - default: undefined, - }, - href: { - type: 'string', - default: undefined, - }, - icon: { - type: 'boolean', - default: undefined, - }, - opacity: { - type: "10 | 25 | 50 | 75 | 100 | '10' | '25' | '50' | '75' | '100'", - default: undefined, - }, - opacityHover: { - type: "10 | 25 | 50 | 75 | 100 | '10' | '25' | '50' | '75' | '100'", - default: undefined, - }, - rel: { - type: 'string', - default: undefined, - }, - replace: { - type: 'boolean', - default: undefined, - }, - routerComponentName: { - type: 'string', - default: undefined, - }, - stretched: { - type: 'boolean', - default: false, - }, - tag: { - type: 'string', - default: 'div', - }, - target: { - type: 'LinkTarget', - default: undefined, - }, - to: { - type: 'RouteLocationRaw', - default: undefined, - }, - underlineOffset: { - type: "1 | 2 | 3 | '1' | '2' | '3'", - default: undefined, - }, - underlineOffsetHover: { - type: "1 | 2 | 3 | '1' | '2' | '3'", - default: undefined, - }, - underlineOpacity: { - type: "0 | 10 | 25 | 50 | 75 | 100 | '0' | '10' | '25' | '50' | '75' | '100'", - default: undefined, - }, - underlineOpacityHover: { - type: "0 | 10 | 25 | 50 | 75 | 100 | '0' | '10' | '25' | '50' | '75' | '100'", - default: undefined, - }, - underlineVariant: { - type: 'ColorVariant | null', - default: undefined, - }, - variant: { - type: 'ColorVariant | null', - default: undefined, - }, - noPrefetch: {}, - noRel: {}, - prefetch: {}, - prefetchedClass: {}, - } satisfies Record, + ...pick( + buildCommonProps({ + tag: { + default: 'ul', + }, + }), + ['tag'] + ), + } satisfies Record< + Exclude, + PropertyReference + >, + 'BLink props': { + _linkTo: { + type: linkTo, + }, + ...omit(linkProps, ['routerTag']), + }, }, - emits: [], slots: [ { name: 'default', - description: '', - scope: [], + description: 'Content to place in the navbar brand', }, ], }, @@ -163,31 +96,40 @@ export default { align: { type: 'AlignmentJustifyContent', default: undefined, + description: + "Align the nav items in the nav: 'start', 'end', 'center', 'between', 'around', or 'evenly'", }, fill: { type: 'boolean', default: false, + description: + 'Proportionately fills all horizontal space with nav items. All horizontal space is occupied, but not every nav item has the same width', }, justified: { type: 'boolean', default: false, + description: + "Fills all horizontal space with nav items, but unlike 'fill', every nav item will be the same width", }, small: { type: 'boolean', default: false, - }, - tag: { - type: 'string', - default: 'ul', - }, + description: 'Makes the nav smaller', + }, + ...pick( + buildCommonProps({ + tag: { + default: 'ul', + }, + }), + ['tag'] + ), } satisfies Record, }, - emits: [], slots: [ { - description: '', name: 'default', - scope: [], + description: 'Content to place in the navbar nav', }, ], }, @@ -196,38 +138,52 @@ export default { sourcePath: '/BNavbar/BNavbarToggle.vue', props: { '': { - disabled: { - type: 'boolean', - default: false, - }, label: { type: 'string', default: 'Toggle navigation', + description: "String to place in the toggle's 'aria-label' attribute", }, target: { - type: 'string | string[]', - default: undefined, - }, + type: 'string | readonly string[]', + default: undefined, + description: + 'ID (or array of IDs) of the collapse/sidebar components that should be toggled', + }, + ...pick( + buildCommonProps({ + tag: { + default: 'ul', + }, + }), + ['disabled'] + ), } satisfies Record, }, emits: [ { + event: 'click', + description: 'Emitted when the toggle is clicked', args: [ { arg: 'click', - description: '', + description: 'Native mouse event object', type: 'MouseEvent', }, ], - description: '', - event: 'click', }, ], slots: [ { - description: '', name: 'default', - scope: [], + description: 'Alternate content to replace the default Bootstrap hamburger', + scope: [ + { + prop: 'expanded', + type: 'boolean', + description: '`true` if the collapse is expanded, `false` otherwise', + notYetImplemented: true, + }, + ], }, ], }, diff --git a/apps/docs/src/data/components/offcanvas.data.ts b/apps/docs/src/data/components/offcanvas.data.ts index cf2ad5563..46c54876c 100644 --- a/apps/docs/src/data/components/offcanvas.data.ts +++ b/apps/docs/src/data/components/offcanvas.data.ts @@ -1,5 +1,6 @@ import type {BvnComponentProps} from 'bootstrap-vue-next' import type {ComponentReference, PropertyReference} from '../../types' +import {showHideProps} from '../../utils' export default { load: (): ComponentReference[] => [ @@ -8,6 +9,12 @@ export default { sourcePath: '/BOffcanvas/BOffcanvas.vue', props: { '': { + backdropFirst: { + type: 'boolean', + default: false, + description: + 'Animate the backdrop before the offcanvas, and on leave animate the offcanvas before the backdrop', + }, bodyAttrs: { type: 'Readonly', default: undefined, @@ -40,7 +47,7 @@ export default { type: 'ButtonVariant | null', default: 'secondary', }, - hideBackdrop: { + noBackdrop: { type: 'boolean', default: false, }, @@ -48,14 +55,6 @@ export default { type: 'string', default: undefined, }, - lazy: { - type: 'boolean', - default: false, - }, - modelValue: { - type: 'boolean', - default: false, - }, noCloseOnBackdrop: { type: 'boolean', default: false, @@ -108,6 +107,7 @@ export default { type: 'string', default: undefined, }, + ...showHideProps, } satisfies Record, }, emits: [ diff --git a/apps/docs/src/data/components/pagination.data.ts b/apps/docs/src/data/components/pagination.data.ts index c049dcd9c..717818b89 100644 --- a/apps/docs/src/data/components/pagination.data.ts +++ b/apps/docs/src/data/components/pagination.data.ts @@ -57,12 +57,12 @@ export default { default: '\u00AB', description: 'Content to place in the go to first page button', }, - hideEllipsis: { + noEllipsis: { type: 'boolean', default: false, description: 'Do not show ellipsis buttons', }, - hideGotoEndButtons: { + noGotoEndButtons: { type: 'boolean', default: false, description: 'Hides the go to first and go to last page buttons', diff --git a/apps/docs/src/data/components/placeholder.data.ts b/apps/docs/src/data/components/placeholder.data.ts index 5583f19aa..6dae87957 100644 --- a/apps/docs/src/data/components/placeholder.data.ts +++ b/apps/docs/src/data/components/placeholder.data.ts @@ -232,7 +232,7 @@ export default { type: 'ColorVariant | null', default: undefined, }, - hideHeader: { + noHeader: { type: 'boolean', default: false, }, diff --git a/apps/docs/src/data/components/popover.data.ts b/apps/docs/src/data/components/popover.data.ts index 9329a64da..7ec4daae4 100644 --- a/apps/docs/src/data/components/popover.data.ts +++ b/apps/docs/src/data/components/popover.data.ts @@ -1,5 +1,6 @@ import type {BvnComponentProps} from 'bootstrap-vue-next' import type {ComponentReference, PropertyReference} from '../../types' +import {showHideProps} from '../../utils' export default { load: (): ComponentReference[] => [ @@ -36,10 +37,6 @@ export default { type: 'Middleware[]', default: undefined, }, - html: { - type: 'boolean', - default: false, - }, id: { type: 'string', default: undefined, @@ -52,18 +49,10 @@ export default { type: 'boolean', default: false, }, - modelValue: { - type: 'boolean', - default: false, - }, noAutoClose: { type: 'boolean', default: false, }, - noFade: { - type: 'boolean', - default: false, - }, noFlip: { type: 'boolean', default: false, @@ -88,10 +77,6 @@ export default { type: 'Numberish | null', default: null, }, - persistent: { - type: 'boolean', - default: false, - }, placement: { type: 'PopoverPlacement', default: 'top', @@ -133,6 +118,13 @@ export default { default: null, }, closeOnHide: {}, + hideMargin: { + type: 'number', + default: 0, + description: + 'The margin to apply when hiding the popover on pointer leave (how far the pointer can move off the target before hiding the popover)', + }, + ...showHideProps, } satisfies Record, }, emits: [ @@ -212,14 +204,14 @@ export default { }, { prop: 'hide', - type: '(e: Event) => void', + type: '(trigger: string) => void', }, { prop: 'toggle', - type: '(e: Event) => void', + type: '() => void', }, { - prop: 'showState', + prop: 'visible', type: 'boolean', }, ], diff --git a/apps/docs/src/data/components/progress.data.ts b/apps/docs/src/data/components/progress.data.ts index 2b7c6ec61..4cf7a8f47 100644 --- a/apps/docs/src/data/components/progress.data.ts +++ b/apps/docs/src/data/components/progress.data.ts @@ -80,10 +80,6 @@ export default { type: 'string', default: undefined, }, - labelHtml: { - type: 'string', - default: undefined, - }, max: { type: 'Numberish', default: undefined, diff --git a/apps/docs/src/data/components/table.data.ts b/apps/docs/src/data/components/table.data.ts index 427b8a7e8..d1c4d3304 100644 --- a/apps/docs/src/data/components/table.data.ts +++ b/apps/docs/src/data/components/table.data.ts @@ -93,10 +93,6 @@ export default { type: 'string', default: undefined, }, - captionHtml: { - type: 'string', - default: undefined, - }, detailsTdClass: { type: 'ClassValue', default: undefined, diff --git a/apps/docs/src/data/components/toast.data.ts b/apps/docs/src/data/components/toast.data.ts index e2bf5fe88..b072393ea 100644 --- a/apps/docs/src/data/components/toast.data.ts +++ b/apps/docs/src/data/components/toast.data.ts @@ -1,6 +1,6 @@ import type {BvnComponentProps} from 'bootstrap-vue-next' import type {ComponentReference, PropertyReference} from '../../types' -import {buildCommonProps, pick} from '../../utils' +import {buildCommonProps, omit, pick, showHideProps} from '../../utils' export default { load: (): ComponentReference[] => [ @@ -85,12 +85,6 @@ export default { default: false, description: 'When set, hides the close button in the toast header', }, - noFade: { - type: 'boolean', - default: false, - description: - 'When set to `true`, disables the fade animation/transition on the component', - }, opacity: { type: "10 | 25 | 50 | 75 | 100 | '10' | '25' | '50' | '75' | '100'", default: undefined, @@ -100,7 +94,7 @@ export default { default: undefined, }, progressProps: { - type: "Omit", + type: "Omit", default: undefined, description: 'The properties to define the progress bar in the toast. No progress will be shown if left undefined', @@ -154,11 +148,6 @@ export default { default: undefined, description: 'CSS class (or classes) to add to the toast wrapper element', }, - transProps: { - type: 'BTransitionProps', - default: undefined, - description: 'Props to pass to the BTransition wrapper', - }, underlineOffset: { type: "1 | 2 | 3 | '1' | '2' | '3'", default: undefined, @@ -183,10 +172,12 @@ export default { type: 'ColorVariant | null', default: undefined, }, - noPrefetch: {}, + // noPrefetch: {}, noRel: {}, - prefetch: {}, - prefetchedClass: {}, + // prefetch: {}, + // prefetchedClass: {}, + ...omit(showHideProps, ['modelValue']), + ...pick(buildCommonProps(), ['noHoverPause', 'noResumeOnHoverLeave']), } satisfies Record, }, diff --git a/apps/docs/src/docs/components/collapse.md b/apps/docs/src/docs/components/collapse.md index 7ac49f8b2..4f51ca07a 100644 --- a/apps/docs/src/docs/components/collapse.md +++ b/apps/docs/src/docs/components/collapse.md @@ -40,7 +40,7 @@ directive). In this example we **must control the attributes ourselves** for pro support. By default, an initially visible collapse will not animate on mount. To enable the collapse expanding animation on mount, -set the `toggle` prop on `` and leave the `visible` prop as false. +set the `initial-animation` prop on `` and leave the `visible` prop as false. <<< DEMO ./demo/CollapseModel.vue diff --git a/apps/docs/src/docs/components/demo/CarouselCaptions.vue b/apps/docs/src/docs/components/demo/CarouselCaptions.vue index 0b315a0c8..ded3b58c8 100644 --- a/apps/docs/src/docs/components/demo/CarouselCaptions.vue +++ b/apps/docs/src/docs/components/demo/CarouselCaptions.vue @@ -2,12 +2,8 @@ - - + diff --git a/apps/docs/src/docs/components/demo/NavRouter.js b/apps/docs/src/docs/components/demo/NavRouter.js index 3d36e8f6b..4ba24f196 100644 --- a/apps/docs/src/docs/components/demo/NavRouter.js +++ b/apps/docs/src/docs/components/demo/NavRouter.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ const routes = [ { path: '/some/route', diff --git a/apps/docs/src/docs/components/demo/NavbarBrandHeading.vue b/apps/docs/src/docs/components/demo/NavbarBrandHeading.vue new file mode 100644 index 000000000..9a532e01e --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarBrandHeading.vue @@ -0,0 +1,8 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarBrandImage.vue b/apps/docs/src/docs/components/demo/NavbarBrandImage.vue new file mode 100644 index 000000000..121bc8bb3 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarBrandImage.vue @@ -0,0 +1,10 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarBrandImageText.vue b/apps/docs/src/docs/components/demo/NavbarBrandImageText.vue new file mode 100644 index 000000000..592a477e1 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarBrandImageText.vue @@ -0,0 +1,15 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarBrandLink.vue b/apps/docs/src/docs/components/demo/NavbarBrandLink.vue new file mode 100644 index 000000000..f60b9d971 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarBrandLink.vue @@ -0,0 +1,8 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarColorMode.vue b/apps/docs/src/docs/components/demo/NavbarColorMode.vue new file mode 100644 index 000000000..ee3d746c9 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarColorMode.vue @@ -0,0 +1,7 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarForm.vue b/apps/docs/src/docs/components/demo/NavbarForm.vue new file mode 100644 index 000000000..97977a140 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarForm.vue @@ -0,0 +1,10 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarInlineGroup.vue b/apps/docs/src/docs/components/demo/NavbarInlineGroup.vue new file mode 100644 index 000000000..c63a0fd1b --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarInlineGroup.vue @@ -0,0 +1,11 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarItemDropdown.vue b/apps/docs/src/docs/components/demo/NavbarItemDropdown.vue new file mode 100644 index 000000000..45624b364 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarItemDropdown.vue @@ -0,0 +1,19 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarOffcanvas.vue b/apps/docs/src/docs/components/demo/NavbarOffcanvas.vue new file mode 100644 index 000000000..2bd97c649 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarOffcanvas.vue @@ -0,0 +1,35 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarOverview.vue b/apps/docs/src/docs/components/demo/NavbarOverview.vue new file mode 100644 index 000000000..9e0d126a3 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarOverview.vue @@ -0,0 +1,35 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarScroll.vue b/apps/docs/src/docs/components/demo/NavbarScroll.vue new file mode 100644 index 000000000..d4b321c75 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarScroll.vue @@ -0,0 +1,35 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarText.vue b/apps/docs/src/docs/components/demo/NavbarText.vue new file mode 100644 index 000000000..58aa1014b --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarText.vue @@ -0,0 +1,13 @@ + diff --git a/apps/docs/src/docs/components/demo/NavbarToggle.vue b/apps/docs/src/docs/components/demo/NavbarToggle.vue new file mode 100644 index 000000000..7534b0618 --- /dev/null +++ b/apps/docs/src/docs/components/demo/NavbarToggle.vue @@ -0,0 +1,23 @@ + + + diff --git a/apps/docs/src/docs/components/form-group.md b/apps/docs/src/docs/components/form-group.md index ae20333dd..44ed435ca 100644 --- a/apps/docs/src/docs/components/form-group.md +++ b/apps/docs/src/docs/components/form-group.md @@ -78,6 +78,30 @@ You can also apply additional classes to the label via the `label-class` prop, s padding and text alignment utility classes. The `label-class` prop accepts either a string or array of strings. +### Automatic Inheriting of id + +The `BFormGroup` component automatically inherits the id of its child input components, such as BFormInput and BFormTextarea. This functionality ensures that the label element's for attribute is correctly set to match the id of the input component, providing proper association between the label and the input field. + + + + + + + + + ### Horizontal layout By default, the label appears above the input element(s), but you may optionally render horizontal diff --git a/apps/docs/src/docs/components/modal.md b/apps/docs/src/docs/components/modal.md index 37ebe92c3..e05d6bf59 100644 --- a/apps/docs/src/docs/components/modal.md +++ b/apps/docs/src/docs/components/modal.md @@ -49,9 +49,9 @@ It is possible to prevent showing/closing modals. You can prevent hiding on the Toggle modal - + Foobar? - Force leave + Prevent close