Skip to content

Commit 61e55c7

Browse files
authored
Merge pull request #524 from VividLemon/nav
feat: bnav components
2 parents ca8414d + 9e1a1d8 commit 61e55c7

File tree

12 files changed

+324
-16
lines changed

12 files changed

+324
-16
lines changed

packages/bootstrap-vue-3/src/BootstrapVue.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,13 @@ import BLink from './components/BLink/BLink.vue'
6969
import BListGroup from './components/BListGroup/BListGroup.vue'
7070
import BListGroupItem from './components/BListGroup/BListGroupItem.vue'
7171
import BModal from './components/BModal.vue'
72-
import BNav from './components/BNav.vue'
73-
import BNavItem from './components/BNavItem.vue'
74-
import BNavItemDropdown from './components/BNavItemDropdown.vue'
72+
import BNav from './components/BNav/BNav.vue'
73+
import BNavbar from './components/BNav/BNavbar.vue'
74+
import BNavbarBrand from './components/BNav/BNavbarBrand.vue'
75+
import BNavbarNav from './components/BNav/BNavbarNav.vue'
76+
// import BNavbarToggle from './components/BNav/BNavbarToggle.vue'
77+
import BNavItem from './components/BNav/BNavItem.vue'
78+
import BNavItemDropdown from './components/BNav/BNavItemDropdown.vue'
7579
import BOffcanvas from './components/BOffcanvas.vue'
7680
import BOverlay from './components/BOverlay/BOverlay.vue'
7781
import BPagination from './components/BPagination/BPagination.vue'
@@ -181,6 +185,10 @@ export {
181185
BListGroupItem,
182186
BModal,
183187
BNav,
188+
BNavbar,
189+
BNavbarBrand,
190+
BNavbarNav,
191+
// BNavbarToggle,
184192
BNavItem,
185193
BNavItemDropdown,
186194
BOffcanvas,
@@ -304,6 +312,10 @@ declare module '@vue/runtime-core' {
304312
BListGroupItem: typeof BListGroupItem
305313
BModal: typeof BModal
306314
BNav: typeof BNav
315+
BNavbar: typeof BNavbar
316+
BNavbarBrand: typeof BNavbarBrand
317+
BNavbarNav: typeof BNavbarNav
318+
// BNavbarToggle: typeof BNavbarToggle
307319
BNavItem: typeof BNavItem
308320
BNavItemDropdown: typeof BNavItemDropdown
309321
BOffcanvas: typeof BOffcanvas

packages/bootstrap-vue-3/src/components/BCollapse.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
class="collapse"
77
:class="classes"
88
:data-bs-parent="accordion || null"
9+
:is-nav="isNav"
910
>
1011
<slot :visible="modelValue" :close="close" />
1112
</component>
@@ -27,6 +28,7 @@ interface BCollapseProps {
2728
tag?: string
2829
toggle?: boolean
2930
visible?: boolean
31+
isNav?: boolean
3032
}
3133
3234
const props = withDefaults(defineProps<BCollapseProps>(), {
@@ -35,6 +37,7 @@ const props = withDefaults(defineProps<BCollapseProps>(), {
3537
tag: 'div',
3638
toggle: false,
3739
visible: false,
40+
isNav: false,
3841
})
3942
4043
interface BCollapseEmits {
@@ -50,7 +53,8 @@ const emit = defineEmits<BCollapseEmits>()
5053
const element = ref<HTMLElement>()
5154
const instance = ref<Collapse>()
5255
const classes = computed(() => ({
53-
show: props.modelValue,
56+
'show': props.modelValue,
57+
'navbar-collapse': props.isNav,
5458
}))
5559
5660
const close = () => emit('update:modelValue', false)
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
2-
<ul class="nav" :class="classes">
2+
<component :is="tag" class="nav" :class="classes">
33
<slot />
4-
</ul>
4+
</component>
55
</template>
66

77
<script setup lang="ts">
@@ -10,27 +10,36 @@ import {computed} from 'vue'
1010
1111
interface BNavProps {
1212
align?: string
13+
cardHeader?: boolean
1314
fill?: boolean
1415
justified?: boolean
1516
pills?: boolean
17+
small?: boolean
1618
tabs?: boolean
19+
tag?: string
1720
vertical?: boolean
1821
}
1922
2023
const props = withDefaults(defineProps<BNavProps>(), {
24+
cardHeader: false,
2125
fill: false,
2226
justified: false,
2327
pills: false,
28+
small: false,
2429
tabs: false,
30+
tag: 'ul',
2531
vertical: false,
2632
})
2733
2834
const classes = computed(() => ({
29-
'flex-column': props.vertical,
30-
[`justify-content-${props.align}`]: props.align,
3135
'nav-tabs': props.tabs,
32-
'nav-pills': props.pills,
36+
'nav-pills': props.pills && !props.tabs,
37+
'card-header-tabs': !props.vertical && props.cardHeader && props.tabs,
38+
'card-header-pills': !props.vertical && props.cardHeader && !props.tabs,
39+
'flex-column': props.vertical,
3340
'nav-fill': props.fill,
3441
'nav-justified': props.justified,
42+
[`justify-content-${props.align}`]: props.align,
43+
'small': props.small,
3544
}))
3645
</script>

packages/bootstrap-vue-3/src/components/BNavItem.vue renamed to packages/bootstrap-vue-3/src/components/BNav/BNavItem.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
<template>
22
<li class="nav-item" :class="classes">
3-
<a
3+
<b-link
44
:href="href"
5+
:to="to"
56
class="nav-link"
7+
:class="classes"
68
:tabindex="disabled ? -1 : undefined"
79
:aria-disabled="disabled ? true : undefined"
810
>
911
<slot />
10-
</a>
12+
</b-link>
1113
</li>
1214
</template>
1315

1416
<script setup lang="ts">
1517
// import type {BNavItemProps} from '../types/components'
18+
import BLink from '../BLink/BLink.vue'
1619
import {computed} from 'vue'
20+
import type {RouteLocationRaw} from 'vue-router'
1721
1822
interface BNavItemProps {
1923
active?: boolean
2024
disabled?: boolean
2125
href?: string
26+
to?: RouteLocationRaw
2227
}
2328
2429
const props = withDefaults(defineProps<BNavItemProps>(), {

packages/bootstrap-vue-3/src/components/BNavItemDropdown.vue renamed to packages/bootstrap-vue-3/src/components/BNav/BNavItemDropdown.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

1111
<script setup lang="ts">
1212
// import type {BNavItemDropdownProps} from '../types/components'
13-
import type {ButtonVariant, Size} from '../types'
14-
import BDropdown from './BDropdown/BDropdown.vue'
13+
import type {ButtonVariant, Size} from '../../types'
14+
import BDropdown from '../BDropdown/BDropdown.vue'
1515
1616
interface BNavItemDropdownProps {
1717
id?: string
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<template>
2+
<component :is="tag" class="navbar" :class="classes" :role="computedRole">
3+
<slot />
4+
</component>
5+
</template>
6+
7+
<script setup lang="ts">
8+
import {computed} from 'vue'
9+
import type {ColorVariant} from '../../types'
10+
11+
interface Props {
12+
fixed?: string
13+
print?: boolean
14+
sticky?: boolean
15+
tag?: string
16+
toggleable?: false | 'sm' | 'md' | 'lg' | 'xl' // Type Omit<Breakpoint, 'xxl'>
17+
type?: string
18+
variant?: ColorVariant
19+
}
20+
21+
const props = withDefaults(defineProps<Props>(), {
22+
print: false,
23+
sticky: false,
24+
tag: 'nav',
25+
toggleable: false, // navbar never collapses
26+
type: 'light',
27+
})
28+
29+
const computedRole = computed<undefined | 'navigation'>(() =>
30+
props.tag === 'nav' ? undefined : 'navigation'
31+
)
32+
33+
const computedNavbarExpand = computed<undefined | string>(() =>
34+
props.toggleable && typeof props.toggleable === 'string'
35+
? `navbar-expand-${props.toggleable}`
36+
: props.toggleable === false
37+
? 'navbar-expand'
38+
: undefined
39+
)
40+
41+
const classes = computed(() => ({
42+
'd-print': props.print,
43+
'sticky-top': props.sticky,
44+
[`navbar-${props.type}`]: props.type,
45+
[`bg-${props.variant}`]: props.variant,
46+
[`fixed-${props.fixed}`]: props.fixed,
47+
'navbar-expand': props.toggleable === false, // for navbars that never collapse
48+
[computedNavbarExpand.value as string]: computedNavbarExpand.value !== undefined,
49+
}))
50+
</script>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<template>
2+
<component :is="computedTag" v-bind="attrs">
3+
<slot />
4+
</component>
5+
</template>
6+
7+
<script setup lang="ts">
8+
// TODO refactor this to use old setup containing BLINKPROPS and pluckprops utility
9+
import type {LinkTarget} from '../../types'
10+
import {computed} from 'vue'
11+
import type {RouteLocationRaw} from 'vue-router'
12+
// TODO this components is not done
13+
interface Props {
14+
active?: boolean
15+
activeClass?: string
16+
append?: boolean
17+
disabled?: boolean
18+
exact?: boolean
19+
exactActiveClass?: string
20+
exactPath?: boolean
21+
exactPathActiveClass?: string
22+
href?: string
23+
noPrefetch?: boolean
24+
prefetch?: boolean
25+
rel?: string
26+
replace?: boolean
27+
routerComponentName?: string
28+
tag?: string
29+
target?: LinkTarget
30+
to?: RouteLocationRaw
31+
}
32+
33+
const props = withDefaults(defineProps<Props>(), {
34+
active: false,
35+
append: false,
36+
disabled: false,
37+
exact: false,
38+
exactPath: false,
39+
noPrefetch: false,
40+
replace: false,
41+
target: '_self',
42+
tag: 'div',
43+
})
44+
45+
const computedTag = computed<string>(() => (props.to ? 'b-link' : props.href ? 'a' : props.tag))
46+
47+
const attrs = computed(() => ({target: props.target, href: props.href, to: props.to}))
48+
</script>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<template>
2+
<ul class="navbar-nav" :class="classes">
3+
<slot></slot>
4+
</ul>
5+
</template>
6+
7+
<script setup lang="ts">
8+
import {computed} from 'vue'
9+
10+
interface Props {
11+
align?: string
12+
fill?: boolean
13+
justified?: boolean
14+
small?: boolean
15+
tag?: string
16+
}
17+
18+
const props = withDefaults(defineProps<Props>(), {
19+
fill: false,
20+
justified: false,
21+
small: false,
22+
tag: 'ul',
23+
})
24+
25+
const comptuedJustifyContent = computed(() => {
26+
const value = props.align === 'left' ? 'start' : props.align === 'right' ? 'end' : props.align
27+
return `justify-content-${value}`
28+
})
29+
30+
const classes = computed(() => ({
31+
'nav-fill': props.fill,
32+
'nav-justified': props.justified,
33+
[comptuedJustifyContent.value]: props.align !== undefined,
34+
'small': props.small,
35+
}))
36+
</script>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<template>
2+
<button
3+
v-b-toggle=""
4+
class="navbar-toggler"
5+
:class="classes"
6+
type=""
7+
v-bind="attrs"
8+
@click="onClick"
9+
>
10+
<span class="navbar-toggler-icon" />
11+
</button>
12+
</template>
13+
14+
<script setup lang="ts">
15+
import {BToggle as vBToggle} from '../../directives/index'
16+
import {computed} from 'vue'
17+
import {ButtonType} from '../../types'
18+
19+
interface Props {
20+
disabled?: boolean // TODO ensure that if the button is disabled that it doesn't collapse
21+
label?: string
22+
target?: string // TODO target should be required, ignoring the other rules about possibly undefined? It is in B-V
23+
}
24+
25+
const props = withDefaults(defineProps<Props>(), {
26+
label: 'Toggle navigation',
27+
disabled: false,
28+
})
29+
30+
interface Emits {
31+
(e: 'click'): void
32+
}
33+
34+
const emit = defineEmits<Emits>()
35+
36+
const attrs = computed(() => ({
37+
'type': 'button' as ButtonType,
38+
'disabled': props.disabled,
39+
'aria-label': props.label,
40+
}))
41+
42+
const classes = computed(() => ({
43+
'navbar-toggler': true,
44+
'collapsed': true,
45+
}))
46+
47+
const onClick = (): void => {
48+
if (!props.disabled) {
49+
emit('click')
50+
51+
classes.value.collapsed = !classes.value.collapsed
52+
if (props.target !== undefined) {
53+
const el = document.getElementById(props.target)
54+
el?.classList.toggle('show')
55+
}
56+
}
57+
}
58+
</script>

0 commit comments

Comments
 (0)