@gitlab/ui 126.3.4 → 126.4.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.
Files changed (90) hide show
  1. package/dist/components/base/alert/alert.js +9 -0
  2. package/dist/components/base/breadcrumb/breadcrumb.js +3 -0
  3. package/dist/components/base/breadcrumb/breadcrumb_item.js +15 -0
  4. package/dist/components/base/datepicker/datepicker.js +54 -0
  5. package/dist/components/base/daterange_picker/daterange_picker.js +70 -1
  6. package/dist/components/base/filtered_search/filtered_search.js +1 -1
  7. package/dist/components/base/form/form_input_group/form_input_group.js +9 -1
  8. package/dist/components/base/path/data.js +1 -1
  9. package/dist/components/base/search_box_by_click/search_box_by_click.js +9 -1
  10. package/dist/components/dashboards/dashboard_panel/dashboard_panel.js +10 -2
  11. package/dist/directives/resize_observer/resize_observer.js +10 -3
  12. package/dist/index.css.map +1 -1
  13. package/dist/tailwind.css +1 -1
  14. package/dist/tailwind.css.map +1 -1
  15. package/dist/vendor/bootstrap-vue/src/components/modal/modal.js +7 -2
  16. package/dist/vendor/bootstrap-vue/src/components/table/helpers/mixin-filtering.js +8 -0
  17. package/dist/vendor/bootstrap-vue/src/components/table/helpers/mixin-items.js +4 -0
  18. package/dist/vendor/bootstrap-vue/src/components/table/helpers/mixin-provider.js +8 -4
  19. package/dist/vendor/bootstrap-vue/src/components/table/helpers/mixin-selectable.js +3 -19
  20. package/dist/vendor/bootstrap-vue/src/components/table/helpers/mixin-sorting.js +1 -16
  21. package/dist/vendor/bootstrap-vue/src/components/table/helpers/mixin-tbody.js +8 -2
  22. package/dist/vendor/bootstrap-vue/src/components/table/helpers/mixin-thead.js +4 -0
  23. package/dist/vendor/bootstrap-vue/src/components/toast/helpers/bv-toast.js +15 -7
  24. package/dist/vendor/bootstrap-vue/src/components/tooltip/helpers/bv-popper.js +15 -13
  25. package/dist/vendor/bootstrap-vue/src/components/tooltip/helpers/bv-tooltip.js +24 -21
  26. package/dist/vendor/bootstrap-vue/src/components/tooltip/tooltip.js +10 -9
  27. package/dist/vendor/bootstrap-vue/src/components/transition/bv-transition.js +3 -0
  28. package/dist/vendor/bootstrap-vue/src/components/transporter/transporter.js +29 -21
  29. package/dist/vendor/bootstrap-vue/src/constants/events.js +1 -5
  30. package/dist/vendor/bootstrap-vue/src/directives/tooltip/tooltip.js +15 -13
  31. package/dist/vendor/bootstrap-vue/src/directives/visible/visible.js +15 -16
  32. package/dist/vendor/bootstrap-vue/src/mixins/attrs.js +1 -18
  33. package/dist/vendor/bootstrap-vue/src/mixins/dropdown.js +8 -3
  34. package/dist/vendor/bootstrap-vue/src/mixins/has-listener.js +1 -1
  35. package/dist/vendor/bootstrap-vue/src/mixins/listeners.js +13 -12
  36. package/dist/vendor/bootstrap-vue/src/utils/cache.js +35 -13
  37. package/dist/vendor/bootstrap-vue/src/utils/config-set.js +16 -11
  38. package/dist/vendor/bootstrap-vue/src/utils/config.js +4 -10
  39. package/dist/vendor/bootstrap-vue/src/utils/create-new-child-component.js +102 -3
  40. package/dist/vendor/bootstrap-vue/src/utils/element-to-vue-instance-registry.js +3 -9
  41. package/dist/vendor/bootstrap-vue/src/utils/get-instance-from-directive.js +1 -3
  42. package/dist/vendor/bootstrap-vue/src/utils/on-instance-destroy.js +22 -0
  43. package/dist/vendor/bootstrap-vue/src/utils/plugins.js +2 -21
  44. package/dist/vendor/bootstrap-vue/src/utils/router.js +15 -1
  45. package/dist/vendor/bootstrap-vue/src/utils/safe-vue-instance.js +1 -1
  46. package/dist/vendor/bootstrap-vue/src/vue.js +16 -81
  47. package/package.json +6 -6
  48. package/src/components/base/alert/alert.vue +9 -0
  49. package/src/components/base/breadcrumb/breadcrumb.vue +3 -0
  50. package/src/components/base/breadcrumb/breadcrumb_item.vue +15 -0
  51. package/src/components/base/datepicker/datepicker.vue +54 -0
  52. package/src/components/base/daterange_picker/daterange_picker.vue +70 -1
  53. package/src/components/base/filtered_search/filtered_search.vue +1 -1
  54. package/src/components/base/form/form_input_group/form_input_group.vue +9 -1
  55. package/src/components/base/path/data.js +1 -1
  56. package/src/components/base/search_box_by_click/search_box_by_click.vue +9 -0
  57. package/src/components/dashboards/dashboard_panel/dashboard_panel.vue +27 -9
  58. package/src/directives/resize_observer/resize_observer.js +6 -0
  59. package/src/vendor/bootstrap-vue/src/components/modal/modal.js +6 -1
  60. package/src/vendor/bootstrap-vue/src/components/table/helpers/mixin-filtering.js +8 -0
  61. package/src/vendor/bootstrap-vue/src/components/table/helpers/mixin-items.js +4 -0
  62. package/src/vendor/bootstrap-vue/src/components/table/helpers/mixin-provider.js +9 -4
  63. package/src/vendor/bootstrap-vue/src/components/table/helpers/mixin-selectable.js +3 -24
  64. package/src/vendor/bootstrap-vue/src/components/table/helpers/mixin-sorting.js +1 -20
  65. package/src/vendor/bootstrap-vue/src/components/table/helpers/mixin-tbody.js +8 -2
  66. package/src/vendor/bootstrap-vue/src/components/table/helpers/mixin-thead.js +4 -0
  67. package/src/vendor/bootstrap-vue/src/components/toast/helpers/bv-toast.js +15 -13
  68. package/src/vendor/bootstrap-vue/src/components/tooltip/helpers/bv-popper.js +14 -13
  69. package/src/vendor/bootstrap-vue/src/components/tooltip/helpers/bv-tooltip.js +16 -23
  70. package/src/vendor/bootstrap-vue/src/components/tooltip/tooltip.js +10 -9
  71. package/src/vendor/bootstrap-vue/src/components/transition/bv-transition.js +4 -0
  72. package/src/vendor/bootstrap-vue/src/components/transporter/transporter.js +36 -26
  73. package/src/vendor/bootstrap-vue/src/constants/events.js +0 -5
  74. package/src/vendor/bootstrap-vue/src/directives/tooltip/tooltip.js +17 -13
  75. package/src/vendor/bootstrap-vue/src/directives/visible/visible.js +13 -9
  76. package/src/vendor/bootstrap-vue/src/mixins/attrs.js +1 -17
  77. package/src/vendor/bootstrap-vue/src/mixins/dropdown.js +8 -3
  78. package/src/vendor/bootstrap-vue/src/mixins/has-listener.js +1 -1
  79. package/src/vendor/bootstrap-vue/src/mixins/listeners.js +14 -14
  80. package/src/vendor/bootstrap-vue/src/utils/cache.js +27 -7
  81. package/src/vendor/bootstrap-vue/src/utils/config-set.js +16 -11
  82. package/src/vendor/bootstrap-vue/src/utils/config.js +4 -10
  83. package/src/vendor/bootstrap-vue/src/utils/create-new-child-component.js +85 -2
  84. package/src/vendor/bootstrap-vue/src/utils/element-to-vue-instance-registry.js +3 -10
  85. package/src/vendor/bootstrap-vue/src/utils/get-instance-from-directive.js +1 -4
  86. package/src/vendor/bootstrap-vue/src/utils/on-instance-destroy.js +21 -0
  87. package/src/vendor/bootstrap-vue/src/utils/plugins.js +1 -26
  88. package/src/vendor/bootstrap-vue/src/utils/router.js +13 -1
  89. package/src/vendor/bootstrap-vue/src/utils/safe-vue-instance.js +1 -1
  90. package/src/vendor/bootstrap-vue/src/vue.js +11 -98
@@ -1,10 +1,93 @@
1
+ import { isVue3 } from '../vue'
2
+
3
+ // Regex to detect event handler props: onSomething or onSomethingOnce
4
+ const EVENT_HANDLER_RE = /^on([A-Z][a-zA-Z]*)$/
5
+ const ONCE_SUFFIX = 'Once'
6
+
7
+ /**
8
+ * Converts an event name to a handler prop name.
9
+ * Use as computed property key with event constants: [eventProp(EVENT_NAME_HIDDEN)]
10
+ * @param {string} eventName - The event name (e.g., 'hidden', 'show', 'mouseenter')
11
+ * @param {Object} options - Options object
12
+ * @param {boolean} options.once - If true, returns the "once" variant (e.g., 'onHiddenOnce')
13
+ * @returns {string} The handler prop name (e.g., 'onHidden', 'onHiddenOnce')
14
+ */
15
+ export const eventProp = (eventName, { once = false } = {}) => {
16
+ const capitalized = eventName.charAt(0).toUpperCase() + eventName.slice(1)
17
+ return `on${capitalized}${once ? ONCE_SUFFIX : ''}`
18
+ }
19
+
20
+ /**
21
+ * Parses a handler prop name to extract event name and once flag.
22
+ * Examples:
23
+ * onShow -> { eventName: 'show', once: false }
24
+ * onShowOnce -> { eventName: 'show', once: true }
25
+ * onMouseenter -> { eventName: 'mouseenter', once: false }
26
+ */
27
+ const parseEventHandlerProp = propName => {
28
+ const match = propName.match(EVENT_HANDLER_RE)
29
+ if (!match) return null
30
+
31
+ let eventPart = match[1]
32
+ const once = eventPart.endsWith(ONCE_SUFFIX)
33
+ if (once) eventPart = eventPart.slice(0, -ONCE_SUFFIX.length)
34
+
35
+ const eventName = eventPart.charAt(0).toLowerCase() + eventPart.slice(1)
36
+ return { eventName, once }
37
+ }
38
+
39
+ /**
40
+ * Extracts event handlers from config and separates them from other props.
41
+ * @param {Object} config - The config object with potential event handler props
42
+ * @returns {{ handlers: Array<{eventName: string, handler: Function, once: boolean}>, cleanConfig: Object }}
43
+ */
44
+ const extractEventHandlers = config => {
45
+ const handlers = []
46
+ const cleanConfig = { ...config }
47
+
48
+ if (cleanConfig.propsData) {
49
+ const cleanPropsData = {}
50
+ Object.keys(cleanConfig.propsData).forEach(propName => {
51
+ const parsed = parseEventHandlerProp(propName)
52
+ if (parsed && typeof cleanConfig.propsData[propName] === 'function') {
53
+ handlers.push({ ...parsed, handler: cleanConfig.propsData[propName] })
54
+ } else {
55
+ cleanPropsData[propName] = cleanConfig.propsData[propName]
56
+ }
57
+ })
58
+ cleanConfig.propsData = cleanPropsData
59
+ }
60
+
61
+ return { handlers, cleanConfig }
62
+ }
63
+
1
64
  export const createNewChildComponent = (parent, Component, config = {}) => {
2
65
  const bvEventRoot = parent.$root ? parent.$root.$options.bvEventRoot || parent.$root : null
3
66
 
4
- return new Component({
5
- ...config,
67
+ // Vue 3: pass handlers as props directly (Vue 3 converts onXxx props to listeners)
68
+ if (isVue3(parent)) {
69
+ return new Component({
70
+ ...config,
71
+ parent,
72
+ bvParent: parent,
73
+ bvEventRoot
74
+ })
75
+ }
76
+
77
+ // Vue 2: extract handlers and subscribe manually after creation
78
+ const { handlers, cleanConfig } = extractEventHandlers(config)
79
+
80
+ const instance = new Component({
81
+ ...cleanConfig,
6
82
  parent,
7
83
  bvParent: parent,
8
84
  bvEventRoot
9
85
  })
86
+
87
+ // Subscribe to events using $on/$once
88
+ handlers.forEach(({ eventName, handler, once }) => {
89
+ instance[once ? '$once' : '$on'](eventName, handler)
90
+ })
91
+
92
+ return instance
10
93
  }
@@ -1,12 +1,9 @@
1
1
  import { isVue3 } from '../vue'
2
2
 
3
- let registry = null
4
- if (isVue3) {
5
- registry = new WeakMap()
6
- }
3
+ const registry = new WeakMap()
7
4
 
8
5
  export const registerElementToInstance = (element, instance) => {
9
- if (!isVue3) {
6
+ if (!isVue3(instance)) {
10
7
  return
11
8
  }
12
9
 
@@ -14,15 +11,11 @@ export const registerElementToInstance = (element, instance) => {
14
11
  }
15
12
 
16
13
  export const removeElementToInstance = element => {
17
- if (!isVue3) {
18
- return
19
- }
20
-
21
14
  registry.delete(element)
22
15
  }
23
16
 
24
17
  export const getInstanceFromElement = element => {
25
- if (!isVue3) {
18
+ if (element.__vue__) {
26
19
  return element.__vue__
27
20
  }
28
21
 
@@ -1,4 +1 @@
1
- import { isVue3 } from '../vue'
2
-
3
- export const getInstanceFromDirective = (vnode, bindings) =>
4
- isVue3 ? bindings.instance : vnode.context
1
+ export const getInstanceFromDirective = (vnode, bindings) => bindings.instance || vnode.context
@@ -0,0 +1,21 @@
1
+ import { isVue3 } from '../vue'
2
+
3
+ /**
4
+ * Register a callback to be called when a Vue instance is destroyed/unmounted.
5
+ *
6
+ * For Vue 2: Uses $once with 'hook:destroyed' event
7
+ * For Vue 3: Uses scope.cleanups for proper effect scope cleanup
8
+ *
9
+ * @param {Object} instance - The Vue instance to watch for destruction
10
+ * @param {Function} callback - The callback to run when the instance is destroyed
11
+ */
12
+ export const onInstanceDestroy = (instance, callback) => {
13
+ if (isVue3(instance)) {
14
+ // onScopeDispose is not available on instance and we do
15
+ // not want to import 'vue' in this file
16
+ instance.$.scope.cleanups.push(callback)
17
+ return
18
+ }
19
+
20
+ instance.$once('hook:destroyed', callback)
21
+ }
@@ -1,29 +1,5 @@
1
- import { Vue as OurVue } from '../vue'
2
- import { HAS_WINDOW_SUPPORT, IS_JSDOM } from '../constants/env'
1
+ import { HAS_WINDOW_SUPPORT } from '../constants/env'
3
2
  import { setConfig } from './config-set'
4
- import { warn } from './warn'
5
-
6
- /**
7
- * Checks if there are multiple instances of Vue, and warns (once) about possible issues.
8
- * @param {object} Vue
9
- */
10
- export const checkMultipleVue = (() => {
11
- let checkMultipleVueWarned = false
12
-
13
- const MULTIPLE_VUE_WARNING = [
14
- 'Multiple instances of Vue detected!',
15
- 'You may need to set up an alias for Vue in your bundler config.',
16
- 'See: https://bootstrap-vue.org/docs#using-module-bundlers'
17
- ].join('\n')
18
-
19
- return Vue => {
20
- /* istanbul ignore next */
21
- if (!checkMultipleVueWarned && OurVue !== Vue && !IS_JSDOM) {
22
- warn(MULTIPLE_VUE_WARNING)
23
- }
24
- checkMultipleVueWarned = true
25
- }
26
- })()
27
3
 
28
4
  /**
29
5
  * Plugin install factory function.
@@ -37,7 +13,6 @@ export const installFactory = ({ components, directives, plugins } = {}) => {
37
13
  return
38
14
  }
39
15
  install.installed = true
40
- checkMultipleVue(Vue)
41
16
  setConfig(config, Vue)
42
17
  registerComponents(Vue, components)
43
18
  registerDirectives(Vue, directives)
@@ -1,4 +1,5 @@
1
1
  import { RX_ENCODED_COMMA, RX_ENCODE_REVERSE, RX_PLUS, RX_QUERY_START } from '../constants/regex'
2
+ import { isVue3 } from '../vue'
2
3
  import { isTag } from './dom'
3
4
  import { isArray, isNull, isPlainObject, isString, isUndefined } from './inspect'
4
5
  import { keys } from './object'
@@ -86,6 +87,16 @@ export const parseQuery = query => {
86
87
 
87
88
  export const isLink = props => !!(props.href || props.to)
88
89
 
90
+ const routerLink = {
91
+ functional: true,
92
+ _name: 'router-link',
93
+ render(h, ctx) {
94
+ // $hasNormal is Vue.js 2 legacy way to check if default slot is scoped or not
95
+ // in bootstrap-vue codebase we never use scoped slots router-link rendering
96
+ return h('router-link', ctx.data, { ...ctx.children, $hasNormal: true })
97
+ }
98
+ }
99
+
89
100
  export const isRouterLink = tag => !!(tag && !isTag(tag, 'a'))
90
101
 
91
102
  export const computeTag = ({ to, disabled, routerComponentName }, thisOrParent) => {
@@ -103,7 +114,8 @@ export const computeTag = ({ to, disabled, routerComponentName }, thisOrParent)
103
114
  // exists = names.some(name => !!thisOrParent.$options.components[name])
104
115
  // And may want to cache the result for performance or we just let the render fail
105
116
  // if the component is not registered
106
- return routerComponentName || (hasNuxt ? 'nuxt-link' : 'router-link')
117
+ const actualRouterLink = isVue3(thisOrParent) ? routerLink : 'router-link'
118
+ return routerComponentName || (hasNuxt ? 'nuxt-link' : actualRouterLink)
107
119
  }
108
120
 
109
121
  export const computeRel = ({ target, rel } = {}) =>
@@ -1,7 +1,7 @@
1
1
  import { isVue3 } from '../vue'
2
2
 
3
3
  export function safeVueInstance(target) {
4
- if (!isVue3) {
4
+ if (!isVue3(target)) {
5
5
  return target
6
6
  }
7
7
 
@@ -1,35 +1,14 @@
1
1
  import Vue from 'vue'
2
- import { mergeData } from 'vue-functional-data-merge'
2
+ import { mergeData as originalMergeData } from 'vue-functional-data-merge'
3
3
 
4
4
  // --- Constants ---
5
5
  const COMPONENT_UID_KEY = '_uid'
6
6
 
7
- const isVue3 = Vue.version.startsWith('3')
7
+ const isGlobalVue3 = Vue.version.startsWith('3')
8
8
 
9
- export const REF_FOR_KEY = isVue3 ? 'ref_for' : 'refInFor'
9
+ export const REF_FOR_KEY = isGlobalVue3 ? 'ref_for' : 'refInFor'
10
10
 
11
- const ALLOWED_FIELDS_IN_DATA = [
12
- 'class',
13
- 'staticClass',
14
- 'style',
15
- 'attrs',
16
- 'props',
17
- 'domProps',
18
- 'on',
19
- 'nativeOn',
20
- 'directives',
21
- 'scopedSlots',
22
- 'slot',
23
- 'key',
24
- 'ref',
25
- 'refInFor'
26
- ]
27
-
28
- let extend = Vue.extend.bind(Vue)
29
-
30
- if (isVue3) {
31
- const { extend: originalExtend } = Vue
32
- const KNOWN_COMPONENTS = ['router-link', 'transition', 'transition-group']
11
+ if (isGlobalVue3) {
33
12
  const originalVModelDynamicCreated = Vue.vModelDynamic.created
34
13
  const originalVModelDynamicBeforeUpdate = Vue.vModelDynamic.beforeUpdate
35
14
 
@@ -64,81 +43,15 @@ if (isVue3) {
64
43
  el[assignSymbol] = function() {}
65
44
  }
66
45
  }
67
- extend = function patchedBootstrapVueExtend(definition) {
68
- if (typeof definition === 'object' && definition.render && !definition.__alreadyPatched) {
69
- const originalRender = definition.render
70
- definition.__alreadyPatched = true
71
- definition.render = function(h) {
72
- const patchedH = function(tag, dataObjOrChildren, rawSlots) {
73
- const slots =
74
- rawSlots === undefined
75
- ? []
76
- : [Array.isArray(rawSlots) ? rawSlots.filter(Boolean) : rawSlots]
77
-
78
- const isTag = typeof tag === 'string' && !KNOWN_COMPONENTS.includes(tag)
79
- const isSecondArgumentDataObject =
80
- dataObjOrChildren &&
81
- typeof dataObjOrChildren === 'object' &&
82
- !Array.isArray(dataObjOrChildren)
83
-
84
- if (!isSecondArgumentDataObject) {
85
- return h(tag, dataObjOrChildren, ...slots)
86
- }
87
-
88
- const { attrs, props, ...restData } = dataObjOrChildren
89
- const normalizedData = {
90
- ...restData,
91
- attrs,
92
- props: isTag ? {} : props
93
- }
94
- if (tag === 'router-link' && !normalizedData.slots && !normalizedData.scopedSlots) {
95
- // terrible workaround to fix router-link rendering with compat vue-router
96
- normalizedData.scopedSlots = { $hasNormal: () => {} }
97
- }
98
- return h(tag, normalizedData, ...slots)
99
- }
100
-
101
- if (definition.functional) {
102
- const ctx = arguments[1]
103
- const patchedCtx = { ...ctx }
104
- patchedCtx.data = {
105
- attrs: { ...(ctx.data.attrs || {}) },
106
- props: { ...(ctx.data.props || {}) }
107
- }
108
- Object.keys(ctx.data || {}).forEach(key => {
109
- if (ALLOWED_FIELDS_IN_DATA.includes(key)) {
110
- patchedCtx.data[key] = ctx.data[key]
111
- } else if (key in ctx.props) {
112
- patchedCtx.data.props[key] = ctx.data[key]
113
- } else if (!key.startsWith('on')) {
114
- patchedCtx.data.attrs[key] = ctx.data[key]
115
- }
116
- })
117
-
118
- const IGNORED_CHILDREN_KEYS = ['_ctx']
119
- const children = ctx.children?.default?.() || ctx.children
46
+ }
120
47
 
121
- if (
122
- children &&
123
- Object.keys(patchedCtx.children).filter(k => !IGNORED_CHILDREN_KEYS.includes(k))
124
- .length === 0
125
- ) {
126
- delete patchedCtx.children
127
- } else {
128
- patchedCtx.children = children
129
- }
48
+ const isVue3 = instance => Boolean(instance.$)
130
49
 
131
- patchedCtx.data.on = ctx.listeners
132
- return originalRender.call(this, patchedH, patchedCtx)
133
- }
50
+ const extend = Vue.extend.bind(Vue)
134
51
 
135
- return originalRender.call(this, patchedH)
136
- }
137
- }
138
- return originalExtend.call(this, definition)
139
- }.bind(Vue)
52
+ function mergeData(...data) {
53
+ const result = originalMergeData(...data)
54
+ return { ...result, ...(result.attrs ?? {}), ...(result.props ?? {}) }
140
55
  }
141
56
 
142
- const nextTick = Vue.nextTick
143
-
144
- export { COMPONENT_UID_KEY, Vue, mergeData, isVue3, nextTick, extend }
57
+ export { COMPONENT_UID_KEY, mergeData, isGlobalVue3, isVue3, extend }