@gitlab/ui 112.1.2 → 112.2.0

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [112.2.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v112.1.2...v112.2.0) (2025-04-04)
2
+
3
+
4
+ ### Features
5
+
6
+ * **GlChartLegend:** Localizes chart legend labels ([d0e3716](https://gitlab.com/gitlab-org/gitlab-ui/commit/d0e3716d49fe3007567bf4914416e06bf4dd0f6f))
7
+
1
8
  ## [112.1.2](https://gitlab.com/gitlab-org/gitlab-ui/compare/v112.1.1...v112.1.2) (2025-04-03)
2
9
 
3
10
 
@@ -1,3 +1,5 @@
1
+ import { translate } from '../i18n';
2
+
1
3
  /**
2
4
  * As of %12.10 all annotations are added as a decorations
3
5
  * by piggybacking a scatter series. The series should
@@ -39,10 +41,10 @@ const LEGEND_LAYOUT_TABLE = 'table';
39
41
  /**
40
42
  * Default values for the chart legend field labels
41
43
  */
42
- const LEGEND_AVERAGE_TEXT = 'Avg';
43
- const LEGEND_CURRENT_TEXT = 'Current';
44
- const LEGEND_MIN_TEXT = 'Min';
45
- const LEGEND_MAX_TEXT = 'Max';
44
+ const LEGEND_AVERAGE_TEXT = () => translate('GlChartLegend.average', 'Avg');
45
+ const LEGEND_CURRENT_TEXT = () => translate('GlChartLegend.current', 'Current');
46
+ const LEGEND_MIN_TEXT = () => translate('GlChartLegend.min', 'Min');
47
+ const LEGEND_MAX_TEXT = () => translate('GlChartLegend.max', 'Max');
46
48
 
47
49
  /**
48
50
  * These arrow symbols are used as markPoints under the annotations lines
@@ -1,3 +1,2 @@
1
1
  export { BNav } from './nav';
2
2
  export { BNavItem } from './nav-item';
3
- export { BNavItemDropdown } from './nav-item-dropdown';
@@ -29,7 +29,6 @@ const NAME_LINK = 'BLink';
29
29
  const NAME_MODAL = 'BModal';
30
30
  const NAME_NAV = 'BNav';
31
31
  const NAME_NAV_ITEM = 'BNavItem';
32
- const NAME_NAV_ITEM_DROPDOWN = 'BNavItemDropdown';
33
32
  const NAME_POPOVER = 'BPopover';
34
33
  const NAME_TAB = 'BTab';
35
34
  const NAME_TABLE = 'BTable';
@@ -61,4 +60,4 @@ const NAME_TRANSITION = 'BVTransition';
61
60
  const NAME_TRANSPORTER = 'BVTransporter';
62
61
  const NAME_TRANSPORTER_TARGET = 'BVTransporterTarget';
63
62
 
64
- export { NAME_BUTTON, NAME_BUTTON_CLOSE, NAME_COL, NAME_COLLAPSE, NAME_COLLAPSE_HELPER, NAME_DROPDOWN, NAME_DROPDOWN_DIVIDER, NAME_DROPDOWN_FORM, NAME_DROPDOWN_GROUP, NAME_DROPDOWN_HEADER, NAME_DROPDOWN_ITEM, NAME_DROPDOWN_ITEM_BUTTON, NAME_DROPDOWN_TEXT, NAME_FORM, NAME_FORM_BUTTON_LABEL_CONTROL, NAME_FORM_CHECKBOX, NAME_FORM_CHECKBOX_GROUP, NAME_FORM_GROUP, NAME_FORM_INVALID_FEEDBACK, NAME_FORM_RADIO, NAME_FORM_RADIO_GROUP, NAME_FORM_RATING_STAR, NAME_FORM_ROW, NAME_FORM_SELECT, NAME_FORM_SELECT_OPTION, NAME_FORM_SELECT_OPTION_GROUP, NAME_FORM_TEXT, NAME_FORM_TEXTAREA, NAME_FORM_VALID_FEEDBACK, NAME_LINK, NAME_MODAL, NAME_NAV, NAME_NAV_ITEM, NAME_NAV_ITEM_DROPDOWN, NAME_POPOVER, NAME_POPOVER_HELPER, NAME_POPOVER_TEMPLATE, NAME_POPPER, NAME_TAB, NAME_TABLE, NAME_TABLE_CELL, NAME_TABLE_LITE, NAME_TABLE_SIMPLE, NAME_TABS, NAME_TAB_BUTTON_HELPER, NAME_TBODY, NAME_TFOOT, NAME_TH, NAME_THEAD, NAME_TOAST, NAME_TOASTER, NAME_TOAST_POP, NAME_TOOLTIP, NAME_TOOLTIP_HELPER, NAME_TOOLTIP_TEMPLATE, NAME_TR, NAME_TRANSITION, NAME_TRANSPORTER, NAME_TRANSPORTER_TARGET };
63
+ export { NAME_BUTTON, NAME_BUTTON_CLOSE, NAME_COL, NAME_COLLAPSE, NAME_COLLAPSE_HELPER, NAME_DROPDOWN, NAME_DROPDOWN_DIVIDER, NAME_DROPDOWN_FORM, NAME_DROPDOWN_GROUP, NAME_DROPDOWN_HEADER, NAME_DROPDOWN_ITEM, NAME_DROPDOWN_ITEM_BUTTON, NAME_DROPDOWN_TEXT, NAME_FORM, NAME_FORM_BUTTON_LABEL_CONTROL, NAME_FORM_CHECKBOX, NAME_FORM_CHECKBOX_GROUP, NAME_FORM_GROUP, NAME_FORM_INVALID_FEEDBACK, NAME_FORM_RADIO, NAME_FORM_RADIO_GROUP, NAME_FORM_RATING_STAR, NAME_FORM_ROW, NAME_FORM_SELECT, NAME_FORM_SELECT_OPTION, NAME_FORM_SELECT_OPTION_GROUP, NAME_FORM_TEXT, NAME_FORM_TEXTAREA, NAME_FORM_VALID_FEEDBACK, NAME_LINK, NAME_MODAL, NAME_NAV, NAME_NAV_ITEM, NAME_POPOVER, NAME_POPOVER_HELPER, NAME_POPOVER_TEMPLATE, NAME_POPPER, NAME_TAB, NAME_TABLE, NAME_TABLE_CELL, NAME_TABLE_LITE, NAME_TABLE_SIMPLE, NAME_TABS, NAME_TAB_BUTTON_HELPER, NAME_TBODY, NAME_TFOOT, NAME_TH, NAME_THEAD, NAME_TOAST, NAME_TOASTER, NAME_TOAST_POP, NAME_TOOLTIP, NAME_TOOLTIP_HELPER, NAME_TOOLTIP_TEMPLATE, NAME_TR, NAME_TRANSITION, NAME_TRANSPORTER, NAME_TRANSPORTER_TARGET };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "112.1.2",
3
+ "version": "112.2.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -12,9 +12,7 @@ $bv-enable-popover-variants: false;
12
12
  @import '../vendor/bootstrap-vue/src/components/form-radio/index.scss';
13
13
  @import '../vendor/bootstrap-vue/src/components/input-group/index.scss';
14
14
  @import '../vendor/bootstrap-vue/src/components/modal/index.scss';
15
- @import '../vendor/bootstrap-vue/src/components/nav/index.scss';
16
15
  @import '../vendor/bootstrap-vue/src/components/popover/index.scss';
17
16
  @import '../vendor/bootstrap-vue/src/components/table/index.scss';
18
17
  @import '../vendor/bootstrap-vue/src/components/toast/index.scss';
19
18
  @import '../vendor/bootstrap-vue/src/components/tooltip/index.scss';
20
-
@@ -1,3 +1,5 @@
1
+ import { translate } from '../i18n';
2
+
1
3
  /**
2
4
  * As of %12.10 all annotations are added as a decorations
3
5
  * by piggybacking a scatter series. The series should
@@ -39,10 +41,10 @@ export const LEGEND_LAYOUT_TABLE = 'table';
39
41
  /**
40
42
  * Default values for the chart legend field labels
41
43
  */
42
- export const LEGEND_AVERAGE_TEXT = 'Avg';
43
- export const LEGEND_CURRENT_TEXT = 'Current';
44
- export const LEGEND_MIN_TEXT = 'Min';
45
- export const LEGEND_MAX_TEXT = 'Max';
44
+ export const LEGEND_AVERAGE_TEXT = () => translate('GlChartLegend.average', 'Avg');
45
+ export const LEGEND_CURRENT_TEXT = () => translate('GlChartLegend.current', 'Current');
46
+ export const LEGEND_MIN_TEXT = () => translate('GlChartLegend.min', 'Min');
47
+ export const LEGEND_MAX_TEXT = () => translate('GlChartLegend.max', 'Max');
46
48
 
47
49
  /**
48
50
  * These arrow symbols are used as markPoints under the annotations lines
@@ -4,7 +4,6 @@
4
4
  @import "form-radio/index";
5
5
  @import "input-group/index";
6
6
  @import "modal/index";
7
- @import "nav/index";
8
7
  @import "popover/index";
9
8
  @import "table/index";
10
9
  @import "toast/index";
@@ -26,7 +26,6 @@ nav.
26
26
  `<b-nav>` supports the following child components:
27
27
 
28
28
  - `<b-nav-item>` for actionable links (or router-links)
29
- - `<b-nav-item-dropdown>` for dropdowns
30
29
  - `<b-nav-text>` for plain text content
31
30
  - `<b-nav-form>` for inline forms
32
31
 
@@ -144,86 +143,6 @@ and `right`.
144
143
  <!-- b-nav-alignment.vue -->
145
144
  ```
146
145
 
147
- ## Dropdown support
148
-
149
- Use `<b-nav-item-dropdown>` to place dropdown items within your nav.
150
-
151
- ```html
152
- <div>
153
- <b-nav pills>
154
- <b-nav-item active>Active</b-nav-item>
155
- <b-nav-item>Link</b-nav-item>
156
- <b-nav-item-dropdown
157
- id="my-nav-dropdown"
158
- text="Dropdown"
159
- toggle-class="nav-link-custom"
160
- right
161
- >
162
- <b-dropdown-item>One</b-dropdown-item>
163
- <b-dropdown-item>Two</b-dropdown-item>
164
- <b-dropdown-divider></b-dropdown-divider>
165
- <b-dropdown-item>Three</b-dropdown-item>
166
- </b-nav-item-dropdown>
167
- </b-nav>
168
- </div>
169
-
170
- <!-- b-nav-item-dropdown.vue -->
171
- ```
172
-
173
- Sometimes you want to add your own class names to the generated dropdown toggle button, that by
174
- default have the classes `nav-link` and `dropdown-toggle`. Use the `toggle-class` prop to add them
175
- (like above) which will render HTML similar to:
176
-
177
- ```html
178
- <li id="my-nav-dropdown" class="nav-item b-nav-dropdown dropdown">
179
- <a
180
- role="button"
181
- href="#my-nav-dropdown"
182
- id="my-nav-dropdown__BV_button_"
183
- aria-haspopup="true"
184
- aria-expanded="false"
185
- class="nav-link dropdown-toggle nav-link-custom"
186
- ></a>
187
- ...
188
- </li>
189
- ```
190
-
191
- Refer to [`<b-dropdown>`](/docs/components/dropdown) for a list of supported sub-components.
192
-
193
- ### Optionally scoped default slot
194
-
195
- The dropdown default slot is optionally scoped with the following scope available:
196
-
197
- | Property or Method | Description |
198
- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
199
- | `hide()` | Can be used to close the dropdown menu. Accepts an optional boolean argument, which if `true` returns focus to the toggle button |
200
-
201
- ### Lazy dropdown
202
-
203
- By default, `<b-nav-item-dropdown>` renders the menu contents in the DOM even when the menu is not
204
- shown. When there are a large number of dropdowns rendered on the same page, performance could be
205
- impacted due to larger overall memory utilization. You can instruct `<b-nav-item-dropdown>` to
206
- render the menu contents only when it is shown by setting the `lazy` prop to true.
207
-
208
- ### Dropdown placement
209
-
210
- Use the dropdown props `right`, `dropup`, `dropright`, `dropleft`, `no-flip`, and `offset` to
211
- control the positioning of `<b-nav-item-dropdown>`.
212
-
213
- Refer to the [`<b-dropdown>` positioning section](/docs/components/dropdown#positioning) for details
214
- on the effects and usage of these props.
215
-
216
- ### Dropdown implementation note
217
-
218
- Note that the toggle button is actually rendered as a link `<a>` tag with `role="button"` for
219
- styling purposes, and typically has the `href` set to `#` unless an ID is provided via the `id`
220
- prop.
221
-
222
- The toggle will prevent scroll-top-top behaviour (via JavaScript) when clicking the toggle link. In
223
- some cases when using SSR, and the user clicks the toggle button _before_ Vue has had a chance to
224
- hydrate the component, the page will scroll to top. In these cases, simply providing a unique ID via
225
- the `id` prop will prevent the unwanted scroll-to-top behaviour.
226
-
227
146
  ## Nav text content
228
147
 
229
148
  Use the `<b-nav-text>` child component to place plain text content into the nav:
@@ -425,10 +344,6 @@ most logical parent container of `<b-nav>`, or wrap a `<nav>` element around `<b
425
344
  add the role to the `<b-nav>` itself, as this would prevent it from being announced as an actual
426
345
  list by assistive technologies.
427
346
 
428
- When using a `<b-nav-item-dropdown>` in your `<b-nav>`, be sure to assign a unique `id` prop value
429
- to the `<b-nav-item-dropdown>` so that the appropriate `aria-*` attributes can be automatically
430
- generated.
431
-
432
347
  ### Tabbed interface accessibility
433
348
 
434
349
  Note that navigation bars, even if visually styled as tabs, should **not** be given
@@ -438,21 +353,9 @@ described in the [WAI ARIA Authoring Practices](https://www.w3.org/TR/wai-aria-p
438
353
  See [`<gl-tabs>`](?path=/docs/base-tabs--docs) for dynamic tabbed interfaces that are compliant with
439
354
  WAI ARIA.
440
355
 
441
- Tabbed interfaces should avoid using dropdown menus, as this causes both usability and accessibility
442
- issues:
443
-
444
- - From a usability perspective, the fact that the currently displayed tab’s trigger element is not
445
- immediately visible (as it’s inside the closed dropdown menu) can cause confusion.
446
- - From an accessibility point of view, there is currently no sensible way to map this sort of
447
- construct to a standard WAI ARIA pattern, meaning that it cannot be easily made understandable to
448
- users of assistive technologies.
449
-
450
356
  ## See also
451
357
 
452
- - [tabs](?path=/docs/base-tabs--docs) to create tabbable panes of local content, even via dropdown
453
- menus.
454
- - [`<b-dropdown>`](/docs/components/dropdown) for sub-components that you can place inside
455
- `<b-nav-item-dropdown>`
358
+ - [tabs](?path=/docs/base-tabs--docs) to create tabbable panes of local content.
456
359
  - [Router Link Support reference](?path=/docs/base-link--docs#router-link-support) for information
457
360
  about router-link specific props available on `<b-nav-item>`
458
361
 
@@ -1,5 +1,4 @@
1
1
  import { BNav } from './nav'
2
2
  import { BNavItem } from './nav-item'
3
- import { BNavItemDropdown } from './nav-item-dropdown'
4
3
 
5
- export { BNav, BNavItem, BNavItemDropdown }
4
+ export { BNav, BNavItem }
@@ -67,123 +67,6 @@
67
67
  "description": "Content to place in the nav item"
68
68
  }
69
69
  ]
70
- },
71
- {
72
- "component": "BNavItemDropdown",
73
- "aliases": [
74
- "BNavItemDd",
75
- "BNavDropdown",
76
- "BNavDd"
77
- ],
78
- "props": [
79
- {
80
- "prop": "boundary",
81
- "version": "2.4.0",
82
- "description": "The boundary constraint of the menu: 'scrollParent', 'window', 'viewport', or a reference to an HTMLElement."
83
- },
84
- {
85
- "prop": "dropleft",
86
- "description": "When set, positions the menu to the left of the button"
87
- },
88
- {
89
- "prop": "dropright",
90
- "description": "When set, positions the menu to the right of the button"
91
- },
92
- {
93
- "prop": "dropup",
94
- "description": "When set, positions the menu on the top of the button"
95
- },
96
- {
97
- "prop": "html",
98
- "description": "HTML string to place in the toggle element (link)",
99
- "xss": true
100
- },
101
- {
102
- "prop": "lazy",
103
- "description": "When set, will only mount the menu content into the DOM when the menu is open"
104
- },
105
- {
106
- "prop": "menuClass",
107
- "description": "CSS class (or classes) to add to the menu container"
108
- },
109
- {
110
- "prop": "noCaret",
111
- "description": "Hide the caret indicator on the toggle element (link)"
112
- },
113
- {
114
- "prop": "noFlip",
115
- "description": "Prevent the menu from auto flipping positions"
116
- },
117
- {
118
- "prop": "popperOpts",
119
- "description": "Additional configuration to pass to Popper.js"
120
- },
121
- {
122
- "prop": "right",
123
- "description": "Align the right edge of the menu with the right of the button"
124
- },
125
- {
126
- "prop": "text",
127
- "description": "Text to place in the toggle element (link)"
128
- },
129
- {
130
- "prop": "toggleClass",
131
- "description": "CSS class (or classes) to add to the toggle element (link)"
132
- }
133
- ],
134
- "events": [
135
- {
136
- "event": "hidden",
137
- "description": "Emitted when dropdown is hidden"
138
- },
139
- {
140
- "event": "hide",
141
- "description": "Emitted just before dropdown is hidden. Cancelable",
142
- "args": [
143
- {
144
- "arg": "bvEvent",
145
- "type": "BvEvent",
146
- "description": "BvEvent object. Call bvEvent.preventDefault() to cancel hide"
147
- }
148
- ]
149
- },
150
- {
151
- "event": "show",
152
- "description": "Emitted just before dropdown is shown. Cancelable",
153
- "args": [
154
- {
155
- "arg": "bvEvent",
156
- "type": "BvEvent",
157
- "description": "BvEvent object. Call bvEvent.preventDefault() to cancel show"
158
- }
159
- ]
160
- },
161
- {
162
- "event": "shown",
163
- "description": "Emitted when dropdown is shown"
164
- },
165
- {
166
- "event": "toggle",
167
- "description": "Emitted when toggle button is clicked"
168
- }
169
- ],
170
- "slots": [
171
- {
172
- "name": "button-content",
173
- "description": "Can be used to implement custom text with icons and more styling"
174
- },
175
- {
176
- "name": "default",
177
- "description": "Optionally scoped default slot for dropdown menu content",
178
- "scope": [
179
- {
180
- "prop": "hide",
181
- "type": "Function",
182
- "description": "Can be used to close the dropdown menu. Accepts an optional boolean argument, which if true returns focus to the toggle button"
183
- }
184
- ]
185
- }
186
- ]
187
70
  }
188
71
  ]
189
72
  }
@@ -29,7 +29,6 @@ export const NAME_LINK = 'BLink'
29
29
  export const NAME_MODAL = 'BModal'
30
30
  export const NAME_NAV = 'BNav'
31
31
  export const NAME_NAV_ITEM = 'BNavItem'
32
- export const NAME_NAV_ITEM_DROPDOWN = 'BNavItemDropdown'
33
32
  export const NAME_POPOVER = 'BPopover'
34
33
  export const NAME_TAB = 'BTab'
35
34
  export const NAME_TABLE = 'BTable'
package/translations.js CHANGED
@@ -6,6 +6,10 @@ export default {
6
6
  'GlBanner.closeButtonTitle': 'Dismiss',
7
7
  'GlBreadcrumb.showMoreLabel': 'Show more breadcrumbs',
8
8
  'GlBroadcastMessage.closeButtonTitle': 'Dismiss',
9
+ 'GlChartLegend.average': 'Avg',
10
+ 'GlChartLegend.current': 'Current',
11
+ 'GlChartLegend.max': 'Max',
12
+ 'GlChartLegend.min': 'Min',
9
13
  'GlCollapsibleListbox.srOnlyResultsLabel': null,
10
14
  'GlDatepicker.monthLabel': 'Month',
11
15
  'GlDatepicker.yearLabel': 'Year',
@@ -1,108 +0,0 @@
1
- import { extend } from '../../vue';
2
- import { NAME_NAV_ITEM_DROPDOWN } from '../../constants/components';
3
- import { SLOT_NAME_BUTTON_CONTENT, SLOT_NAME_TEXT, SLOT_NAME_DEFAULT } from '../../constants/slots';
4
- import { htmlOrText } from '../../utils/html';
5
- import { sortKeys, pick, keys } from '../../utils/object';
6
- import { makePropsConfigurable } from '../../utils/props';
7
- import { props as props$3, dropdownMixin } from '../../mixins/dropdown';
8
- import { props as props$1, idMixin } from '../../mixins/id';
9
- import { normalizeSlotMixin } from '../../mixins/normalize-slot';
10
- import { props as props$2 } from '../dropdown/dropdown';
11
- import { BLink } from '../link/link';
12
-
13
- // --- Props ---
14
-
15
- const props = makePropsConfigurable(sortKeys({
16
- ...props$1,
17
- ...pick(props$2, [...keys(props$3), 'html', 'lazy', 'menuClass', 'noCaret', 'role', 'text', 'toggleClass'])
18
- }), NAME_NAV_ITEM_DROPDOWN);
19
-
20
- // --- Main component ---
21
-
22
- // @vue/component
23
- const BNavItemDropdown = /*#__PURE__*/extend({
24
- name: NAME_NAV_ITEM_DROPDOWN,
25
- mixins: [idMixin, dropdownMixin, normalizeSlotMixin],
26
- props,
27
- computed: {
28
- toggleId() {
29
- return this.safeId('_BV_toggle_');
30
- },
31
- menuId() {
32
- return this.safeId('_BV_toggle_menu_');
33
- },
34
- dropdownClasses() {
35
- return [this.directionClass, this.boundaryClass, {
36
- show: this.visible
37
- }];
38
- },
39
- menuClasses() {
40
- return [this.menuClass, {
41
- 'dropdown-menu-right': this.right,
42
- show: this.visible
43
- }];
44
- },
45
- toggleClasses() {
46
- return [this.toggleClass, {
47
- 'dropdown-toggle-no-caret': this.noCaret
48
- }];
49
- }
50
- },
51
- render(h) {
52
- const {
53
- toggleId,
54
- menuId,
55
- visible,
56
- hide
57
- } = this;
58
- const $toggle = h(BLink, {
59
- staticClass: 'nav-link dropdown-toggle',
60
- class: this.toggleClasses,
61
- props: {
62
- href: `#${this.id || ''}`,
63
- disabled: this.disabled
64
- },
65
- attrs: {
66
- id: toggleId,
67
- role: 'button',
68
- 'aria-haspopup': 'true',
69
- 'aria-expanded': visible ? 'true' : 'false',
70
- 'aria-controls': menuId
71
- },
72
- on: {
73
- mousedown: this.onMousedown,
74
- click: this.toggle,
75
- keydown: this.toggle // Handle ENTER, SPACE and DOWN
76
- },
77
- ref: 'toggle'
78
- }, [
79
- // TODO: The `text` slot is deprecated in favor of the `button-content` slot
80
- this.normalizeSlot([SLOT_NAME_BUTTON_CONTENT, SLOT_NAME_TEXT]) || h('span', {
81
- domProps: htmlOrText(this.html, this.text)
82
- })]);
83
- const $menu = h('ul', {
84
- staticClass: 'dropdown-menu',
85
- class: this.menuClasses,
86
- attrs: {
87
- tabindex: '-1',
88
- 'aria-labelledby': toggleId,
89
- id: menuId
90
- },
91
- on: {
92
- keydown: this.onKeydown // Handle UP, DOWN and ESC
93
- },
94
- ref: 'menu'
95
- }, !this.lazy || visible ? this.normalizeSlot(SLOT_NAME_DEFAULT, {
96
- hide
97
- }) : [h()]);
98
- return h('li', {
99
- staticClass: 'nav-item b-nav-dropdown dropdown',
100
- class: this.dropdownClasses,
101
- attrs: {
102
- id: this.safeId()
103
- }
104
- }, [$toggle, $menu]);
105
- }
106
- });
107
-
108
- export { BNavItemDropdown, props };
@@ -1 +0,0 @@
1
- @import "../dropdown/index";
@@ -1 +0,0 @@
1
- @import "nav-item-dropdown";
@@ -1,123 +0,0 @@
1
- import { extend } from '../../vue'
2
- import { NAME_NAV_ITEM_DROPDOWN } from '../../constants/components'
3
- import { SLOT_NAME_BUTTON_CONTENT, SLOT_NAME_DEFAULT, SLOT_NAME_TEXT } from '../../constants/slots'
4
- import { htmlOrText } from '../../utils/html'
5
- import { keys, pick, sortKeys } from '../../utils/object'
6
- import { makePropsConfigurable } from '../../utils/props'
7
- import { dropdownMixin, props as dropdownProps } from '../../mixins/dropdown'
8
- import { idMixin, props as idProps } from '../../mixins/id'
9
- import { normalizeSlotMixin } from '../../mixins/normalize-slot'
10
- import { props as BDropdownProps } from '../dropdown/dropdown'
11
- import { BLink } from '../link/link'
12
-
13
- // --- Props ---
14
-
15
- export const props = makePropsConfigurable(
16
- sortKeys({
17
- ...idProps,
18
- ...pick(BDropdownProps, [
19
- ...keys(dropdownProps),
20
- 'html',
21
- 'lazy',
22
- 'menuClass',
23
- 'noCaret',
24
- 'role',
25
- 'text',
26
- 'toggleClass'
27
- ])
28
- }),
29
- NAME_NAV_ITEM_DROPDOWN
30
- )
31
-
32
- // --- Main component ---
33
-
34
- // @vue/component
35
- export const BNavItemDropdown = /*#__PURE__*/ extend({
36
- name: NAME_NAV_ITEM_DROPDOWN,
37
- mixins: [idMixin, dropdownMixin, normalizeSlotMixin],
38
- props,
39
- computed: {
40
- toggleId() {
41
- return this.safeId('_BV_toggle_')
42
- },
43
- menuId() {
44
- return this.safeId('_BV_toggle_menu_')
45
- },
46
- dropdownClasses() {
47
- return [this.directionClass, this.boundaryClass, { show: this.visible }]
48
- },
49
- menuClasses() {
50
- return [
51
- this.menuClass,
52
- {
53
- 'dropdown-menu-right': this.right,
54
- show: this.visible
55
- }
56
- ]
57
- },
58
- toggleClasses() {
59
- return [this.toggleClass, { 'dropdown-toggle-no-caret': this.noCaret }]
60
- }
61
- },
62
- render(h) {
63
- const { toggleId, menuId, visible, hide } = this
64
-
65
- const $toggle = h(
66
- BLink,
67
- {
68
- staticClass: 'nav-link dropdown-toggle',
69
- class: this.toggleClasses,
70
- props: {
71
- href: `#${this.id || ''}`,
72
- disabled: this.disabled
73
- },
74
- attrs: {
75
- id: toggleId,
76
- role: 'button',
77
- 'aria-haspopup': 'true',
78
- 'aria-expanded': visible ? 'true' : 'false',
79
- 'aria-controls': menuId
80
- },
81
- on: {
82
- mousedown: this.onMousedown,
83
- click: this.toggle,
84
- keydown: this.toggle // Handle ENTER, SPACE and DOWN
85
- },
86
- ref: 'toggle'
87
- },
88
- [
89
- // TODO: The `text` slot is deprecated in favor of the `button-content` slot
90
- this.normalizeSlot([SLOT_NAME_BUTTON_CONTENT, SLOT_NAME_TEXT]) ||
91
- h('span', { domProps: htmlOrText(this.html, this.text) })
92
- ]
93
- )
94
-
95
- const $menu = h(
96
- 'ul',
97
- {
98
- staticClass: 'dropdown-menu',
99
- class: this.menuClasses,
100
- attrs: {
101
- tabindex: '-1',
102
- 'aria-labelledby': toggleId,
103
- id: menuId
104
- },
105
- on: {
106
- keydown: this.onKeydown // Handle UP, DOWN and ESC
107
- },
108
- ref: 'menu'
109
- },
110
- !this.lazy || visible ? this.normalizeSlot(SLOT_NAME_DEFAULT, { hide }) : [h()]
111
- )
112
-
113
- return h(
114
- 'li',
115
- {
116
- staticClass: 'nav-item b-nav-dropdown dropdown',
117
- class: this.dropdownClasses,
118
- attrs: { id: this.safeId() }
119
- },
120
- [$toggle, $menu]
121
- )
122
- }
123
- })
@@ -1,268 +0,0 @@
1
- import { mount } from '@vue/test-utils'
2
- import { waitNT, waitRAF } from '../../../tests/utils'
3
- import { BNavItemDropdown } from './nav-item-dropdown'
4
-
5
- describe('nav-item-dropdown', () => {
6
- it('has expected default structure', async () => {
7
- const wrapper = mount(BNavItemDropdown)
8
-
9
- expect(wrapper.vm).toBeDefined()
10
- await waitNT(wrapper.vm)
11
-
12
- expect(wrapper.element.tagName).toBe('LI')
13
- expect(wrapper.element.hasAttribute('id')).toBe(true)
14
- expect(wrapper.classes()).toContain('nav-item')
15
- expect(wrapper.classes()).toContain('b-nav-dropdown')
16
- expect(wrapper.classes()).toContain('dropdown')
17
-
18
- const $toggle = wrapper.find('.dropdown-toggle')
19
- expect($toggle.element.tagName).toBe('A')
20
- expect($toggle.element.hasAttribute('id')).toBe(true)
21
- expect($toggle.attributes('role')).toEqual('button')
22
- expect($toggle.attributes('aria-haspopup')).toEqual('true')
23
- expect($toggle.attributes('aria-expanded')).toEqual('false')
24
- expect($toggle.attributes('href')).toEqual('#')
25
- expect($toggle.classes()).toContain('dropdown-toggle')
26
- expect($toggle.classes()).toContain('nav-link')
27
-
28
- const $menu = wrapper.find('.dropdown-menu')
29
- expect($menu.element.tagName).toBe('UL')
30
- expect($menu.attributes('tabindex')).toEqual('-1')
31
- expect($menu.attributes('aria-labelledby')).toEqual($toggle.attributes('id'))
32
- expect($menu.classes()).toContain('dropdown-menu')
33
-
34
- wrapper.destroy()
35
- })
36
-
37
- it('should have custom toggle class when "toggle-class" prop set', async () => {
38
- const wrapper = mount(BNavItemDropdown, {
39
- propsData: {
40
- toggleClass: 'nav-link-custom'
41
- }
42
- })
43
-
44
- expect(wrapper.vm).toBeDefined()
45
- await waitNT(wrapper.vm)
46
-
47
- const $toggle = wrapper.find('.dropdown-toggle')
48
- expect($toggle.classes()).toContain('nav-link-custom')
49
-
50
- wrapper.destroy()
51
- })
52
-
53
- it('should be disabled when "disabled" prop set', async () => {
54
- const wrapper = mount(BNavItemDropdown, {
55
- propsData: {
56
- disabled: true
57
- }
58
- })
59
-
60
- expect(wrapper.vm).toBeDefined()
61
- await waitNT(wrapper.vm)
62
-
63
- const $toggle = wrapper.find('.dropdown-toggle')
64
- expect($toggle.classes()).toContain('disabled')
65
- expect($toggle.attributes('aria-disabled')).toBeDefined()
66
-
67
- wrapper.destroy()
68
- })
69
-
70
- it('should have href with ID when "id" prop set', async () => {
71
- const wrapper = mount(BNavItemDropdown, {
72
- propsData: {
73
- id: 'foo'
74
- }
75
- })
76
-
77
- expect(wrapper.vm).toBeDefined()
78
- await waitNT(wrapper.vm)
79
-
80
- expect(wrapper.element.hasAttribute('id')).toBe(true)
81
- expect(wrapper.attributes('id')).toEqual('foo')
82
-
83
- const $toggle = wrapper.find('.dropdown-toggle')
84
- expect($toggle.attributes('href')).toEqual('#foo')
85
-
86
- wrapper.destroy()
87
- })
88
-
89
- it('should have correct toggle content when "text" prop set [DEPRECATED]', async () => {
90
- const wrapper = mount(BNavItemDropdown, {
91
- propsData: {
92
- text: 'foo'
93
- }
94
- })
95
-
96
- expect(wrapper.vm).toBeDefined()
97
- await waitNT(wrapper.vm)
98
-
99
- const $toggle = wrapper.find('.dropdown-toggle')
100
- expect($toggle.text()).toEqual('foo')
101
-
102
- wrapper.destroy()
103
- })
104
-
105
- it('should have correct toggle content when "html" prop set', async () => {
106
- const wrapper = mount(BNavItemDropdown, {
107
- propsData: {
108
- text: 'foo',
109
- html: '<span>bar</span>'
110
- }
111
- })
112
-
113
- expect(wrapper.vm).toBeDefined()
114
- await waitNT(wrapper.vm)
115
-
116
- const $toggle = wrapper.find('.dropdown-toggle')
117
- expect($toggle.find('span').exists()).toBe(true)
118
- expect($toggle.text()).toEqual('bar')
119
-
120
- wrapper.destroy()
121
- })
122
-
123
- it('should have correct toggle content from "text" slot', async () => {
124
- const wrapper = mount(BNavItemDropdown, {
125
- propsData: {
126
- text: 'foo',
127
- html: '<span>bar</span>'
128
- },
129
- slots: {
130
- text: '<strong>baz</strong>'
131
- }
132
- })
133
-
134
- expect(wrapper.vm).toBeDefined()
135
- await waitNT(wrapper.vm)
136
-
137
- const $toggle = wrapper.find('.dropdown-toggle')
138
- expect($toggle.find('strong').exists()).toBe(true)
139
- expect($toggle.text()).toEqual('baz')
140
-
141
- wrapper.destroy()
142
- })
143
-
144
- it('should have correct toggle content from "button-content" slot', async () => {
145
- const wrapper = mount(BNavItemDropdown, {
146
- propsData: {
147
- text: 'foo',
148
- html: '<span>bar</span>'
149
- },
150
- slots: {
151
- 'button-content': '<article>foobar</article>',
152
- text: '<strong>baz</strong>'
153
- }
154
- })
155
-
156
- expect(wrapper.vm).toBeDefined()
157
- await waitNT(wrapper.vm)
158
-
159
- const $toggle = wrapper.find('.dropdown-toggle')
160
- expect($toggle.find('article').exists()).toBe(true)
161
- expect($toggle.text()).toEqual('foobar')
162
-
163
- wrapper.destroy()
164
- })
165
-
166
- it('should have correct menu content for "default" slot', async () => {
167
- let slotScope = null
168
- const wrapper = mount(BNavItemDropdown, {
169
- scopedSlots: {
170
- default(scope) {
171
- slotScope = scope
172
- return this.$createElement('div', 'foo')
173
- }
174
- }
175
- })
176
-
177
- expect(wrapper.vm).toBeDefined()
178
- await waitNT(wrapper.vm)
179
-
180
- const $menu = wrapper.find('.dropdown-menu')
181
- expect($menu.find('div').exists()).toBe(true)
182
- expect($menu.text()).toEqual('foo')
183
-
184
- expect(slotScope).toBeDefined()
185
- expect(slotScope.hide).toBeDefined()
186
-
187
- wrapper.destroy()
188
- })
189
-
190
- it('should only render menu content when visible when "lazy" prop set', async () => {
191
- const wrapper = mount(BNavItemDropdown, {
192
- propsData: {
193
- lazy: true
194
- },
195
- scopedSlots: {
196
- default() {
197
- return this.$createElement('div', 'bar')
198
- }
199
- }
200
- })
201
-
202
- expect(wrapper.vm).toBeDefined()
203
- expect(wrapper.vm.visible).toBe(false)
204
- await waitNT(wrapper.vm)
205
-
206
- const $menu = wrapper.find('.dropdown-menu')
207
- expect($menu.find('div').exists()).toBe(false)
208
-
209
- wrapper.vm.show()
210
- await waitNT(wrapper.vm)
211
- await waitRAF()
212
- expect(wrapper.vm.visible).toBe(true)
213
- expect($menu.find('div').exists()).toBe(true)
214
- expect($menu.text()).toEqual('bar')
215
-
216
- wrapper.vm.hide()
217
- await waitNT(wrapper.vm)
218
- await waitRAF()
219
- expect(wrapper.vm.visible).toBe(false)
220
- expect($menu.find('div').exists()).toBe(false)
221
-
222
- wrapper.destroy()
223
- })
224
-
225
- it('should open/close on toggle click', async () => {
226
- const wrapper = mount(BNavItemDropdown)
227
-
228
- expect(wrapper.vm).toBeDefined()
229
- await waitNT(wrapper.vm)
230
-
231
- const $toggle = wrapper.find('.dropdown-toggle')
232
- expect(wrapper.vm.visible).toBe(false)
233
- expect($toggle.attributes('aria-expanded')).toEqual('false')
234
-
235
- await $toggle.trigger('click')
236
- await waitRAF()
237
- expect(wrapper.vm.visible).toBe(true)
238
- expect($toggle.attributes('aria-expanded')).toEqual('true')
239
-
240
- await $toggle.trigger('click')
241
- await waitRAF()
242
- expect(wrapper.vm.visible).toBe(false)
243
- expect($toggle.attributes('aria-expanded')).toEqual('false')
244
-
245
- wrapper.destroy()
246
- })
247
-
248
- it('should prevent toggle click', async () => {
249
- const wrapper = mount(BNavItemDropdown, {
250
- propsData: {
251
- text: 'toggle'
252
- }
253
- })
254
-
255
- expect(wrapper.vm).toBeDefined()
256
- await waitNT(wrapper.vm)
257
-
258
- const $toggle = wrapper.find('.dropdown-toggle')
259
-
260
- await $toggle.trigger('click')
261
- expect(wrapper.emitted('toggle')).toBeDefined()
262
- expect(wrapper.emitted('toggle').length).toBe(1)
263
- expect(wrapper.emitted('toggle')[0]).toBeDefined()
264
- expect(wrapper.emitted('toggle')[0][0].defaultPrevented).toBe(true)
265
-
266
- wrapper.destroy()
267
- })
268
- })