@gitlab/ui 134.1.1 → 134.1.3

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.
@@ -147,9 +147,20 @@ const useMockIntersectionObserver = () => {
147
147
  const getInstances = () => {
148
148
  return instances;
149
149
  };
150
+ const observersCount = observer => {
151
+ var _observer$$_observers;
152
+ return (observer === null || observer === void 0 ? void 0 : (_observer$$_observers = observer.$_observers) === null || _observer$$_observers === void 0 ? void 0 : _observer$$_observers.length) || 0;
153
+ };
154
+ const observesElement = (observer, element) => (observer === null || observer === void 0 ? void 0 : observer.$_observers.some(_ref8 => {
155
+ let _ref9 = _slicedToArray(_ref8, 1),
156
+ observedElement = _ref9[0];
157
+ return observedElement === element;
158
+ })) || false;
150
159
  return {
151
160
  getInstances,
152
- trigger
161
+ trigger,
162
+ observersCount,
163
+ observesElement
153
164
  };
154
165
  };
155
166
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "134.1.1",
3
+ "version": "134.1.3",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -2,8 +2,8 @@
2
2
  import { uniqueId, isBoolean, toInteger, toString } from 'lodash-es';
3
3
  import { toFloat } from '../../../../utils/number_utils';
4
4
  import { isVisible, stopEvent } from '../../../../utils/utils';
5
- import { VBVisible } from '../../../../vendor/bootstrap-vue/src/directives/visible/visible';
6
5
  import GlFormCharacterCount from '../form_character_count/form_character_count.vue';
6
+ import { GlVisibleDirective } from './visible';
7
7
 
8
8
  export default {
9
9
  name: 'GlFormTextarea',
@@ -11,7 +11,7 @@ export default {
11
11
  GlFormCharacterCount,
12
12
  },
13
13
  directives: {
14
- 'b-visible': VBVisible,
14
+ GlVisible: GlVisibleDirective,
15
15
  },
16
16
  inheritAttrs: false,
17
17
  model: {
@@ -317,7 +317,6 @@ export default {
317
317
  },
318
318
  mounted() {
319
319
  this.handleAutofocus();
320
- this.setHeight();
321
320
  this.$nextTick(() => {
322
321
  this.localId = uniqueId('gl-form-textarea-');
323
322
  });
@@ -444,11 +443,6 @@ export default {
444
443
  this.$emit('submit');
445
444
  }
446
445
  },
447
- visibleCallback(visible) {
448
- if (visible) {
449
- this.$nextTick(this.setHeight);
450
- }
451
- },
452
446
  setHeight() {
453
447
  this.$nextTick(() => {
454
448
  window.requestAnimationFrame(() => {
@@ -513,7 +507,7 @@ export default {
513
507
  <div v-if="showCharacterCount">
514
508
  <textarea
515
509
  ref="input"
516
- v-b-visible.640="visibleCallback"
510
+ v-gl-visible="setHeight"
517
511
  :value="localValue"
518
512
  :class="computedClass"
519
513
  :style="computedStyle"
@@ -560,7 +554,7 @@ export default {
560
554
  <textarea
561
555
  v-else
562
556
  ref="input"
563
- v-b-visible.640="visibleCallback"
557
+ v-gl-visible="setHeight"
564
558
  :value="localValue"
565
559
  :class="computedClass"
566
560
  :style="computedStyle"
@@ -0,0 +1,52 @@
1
+ import { isFunction } from 'lodash-es';
2
+
3
+ // IntersectionObserver-backed visibility directive.
4
+ // Calls the function when the element enters the viewport.
5
+ // The element is expanded by ROOT_MARGIN.
6
+ const ROOT_MARGIN = '640px';
7
+
8
+ let observer = null;
9
+
10
+ // Exported for testing purposes only
11
+ export const resetObserver = () => {
12
+ observer?.disconnect();
13
+ observer = null;
14
+ };
15
+
16
+ const attachObserver = (el, callback) => {
17
+ if (!isFunction(callback)) {
18
+ throw TypeError('directive value must be a function');
19
+ }
20
+
21
+ if (!observer) {
22
+ // the observer instance is shared for performance reasons
23
+ // more information: https://github.com/WICG/ResizeObserver/issues/59
24
+ observer = new IntersectionObserver(
25
+ (entries) => {
26
+ entries.forEach((entry) => {
27
+ if (entry.isIntersecting) {
28
+ entry.target.glVisibleHandler();
29
+ }
30
+ });
31
+ },
32
+ { rootMargin: ROOT_MARGIN },
33
+ );
34
+ }
35
+
36
+ el.glVisibleHandler = callback;
37
+ observer.observe(el);
38
+ };
39
+
40
+ const detachObserver = (el) => {
41
+ if (el.glVisibleHandler) {
42
+ delete el.glVisibleHandler;
43
+ observer?.unobserve(el);
44
+ }
45
+ };
46
+
47
+ export const GlVisibleDirective = {
48
+ bind(el, { value: callback }) {
49
+ attachObserver(el, callback);
50
+ },
51
+ unbind: detachObserver,
52
+ };
@@ -20,6 +20,8 @@
20
20
  }
21
21
 
22
22
  .gl-token-selector-input {
23
- padding-bottom: $gl-spacing-scale-1 + $gl-spacing-scale-2;
24
- padding-top: $gl-spacing-scale-1 + $gl-spacing-scale-2;
23
+ padding-top: $input-padding-y;
24
+ padding-bottom: $input-padding-y;
25
+ padding-left: $input-padding-x-sm;
26
+ padding-right: $input-padding-x-sm;
25
27
  }
@@ -465,7 +465,7 @@ export default {
465
465
  <input
466
466
  ref="textInput"
467
467
  type="text"
468
- class="gl-token-selector-input gl-h-auto gl-w-4/10 gl-grow gl-border-none gl-bg-transparent gl-px-1 gl-font-regular gl-text-base gl-leading-normal gl-text-default gl-outline-none"
468
+ class="gl-token-selector-input gl-h-auto gl-w-4/10 gl-grow gl-border-none gl-bg-transparent gl-font-regular gl-text-base gl-leading-normal gl-text-default gl-outline-none"
469
469
  :value="inputText"
470
470
  :aria-activedescendant="handleAriaActiveDescendent(focusedDropdownItem)"
471
471
  :autocomplete="autocomplete"
@@ -90,5 +90,10 @@ export const useMockIntersectionObserver = () => {
90
90
  return instances;
91
91
  };
92
92
 
93
- return { getInstances, trigger };
93
+ const observersCount = (observer) => observer?.$_observers?.length || 0;
94
+
95
+ const observesElement = (observer, element) =>
96
+ observer?.$_observers.some(([observedElement]) => observedElement === element) || false;
97
+
98
+ return { getInstances, trigger, observersCount, observesElement };
94
99
  };
@@ -1 +0,0 @@
1
- export { VBVisible } from './visible';
@@ -1,183 +0,0 @@
1
- import { RX_DIGITS } from '../../constants/regex';
2
- import { requestAF } from '../../utils/dom';
3
- import { isFunction } from '../../utils/inspect';
4
- import { looseEqual } from '../../utils/loose-equal';
5
- import { keys, clone } from '../../utils/object';
6
- import { getInstanceFromDirective } from '../../utils/get-instance-from-directive';
7
-
8
- // v-b-visible
9
- // Private visibility check directive
10
- // Based on IntersectionObserver
11
- //
12
- // Usage:
13
- // v-b-visibility.<margin>.<once>="<callback>"
14
- //
15
- // Value:
16
- // <callback>: method to be called when visibility state changes, receives one arg:
17
- // true: element is visible
18
- // false: element is not visible
19
- // null: IntersectionObserver not supported
20
- //
21
- // Modifiers:
22
- // <margin>: a positive decimal value of pixels away from viewport edge
23
- // before being considered "visible". default is 0
24
- // <once>: keyword 'once', meaning when the element becomes visible and
25
- // callback is called observation/notification will stop.
26
- //
27
- // When used in a render function:
28
- // export default {
29
- // directives: { 'b-visible': VBVisible },
30
- // render(h) {
31
- // h(
32
- // 'div',
33
- // {
34
- // directives: [
35
- // { name: 'b-visible', value=this.callback, modifiers: { '123':true, 'once':true } }
36
- // ]
37
- // }
38
- // )
39
- // }
40
-
41
- const OBSERVER_PROP_NAME = '__bv__visibility_observer';
42
- class VisibilityObserver {
43
- constructor(el, options, instance) {
44
- this.el = el;
45
- this.callback = options.callback;
46
- this.margin = options.margin || 0;
47
- this.once = options.once || false;
48
- this.observer = null;
49
- this.visible = undefined;
50
- this.doneOnce = false;
51
- this.instance = instance;
52
- // Create the observer instance (if possible)
53
- this.createObserver();
54
- }
55
- createObserver() {
56
- // Remove any previous observer
57
- if (this.observer) {
58
- /* istanbul ignore next */
59
- this.stop();
60
- }
61
-
62
- // Should only be called once and `callback` prop should be a function
63
- if (this.doneOnce || !isFunction(this.callback)) {
64
- /* istanbul ignore next */
65
- return;
66
- }
67
-
68
- // Create the observer instance
69
- try {
70
- // Future: Possibly add in other modifiers for left/right/top/bottom
71
- // offsets, root element reference, and thresholds
72
- this.observer = new IntersectionObserver(this.handler.bind(this), {
73
- // `null` = 'viewport'
74
- root: null,
75
- // Pixels away from view port to consider "visible"
76
- rootMargin: this.margin,
77
- // Intersection ratio of el and root (as a value from 0 to 1)
78
- threshold: 0
79
- });
80
- } catch {
81
- // No IntersectionObserver support, so just stop trying to observe
82
- this.doneOnce = true;
83
- this.observer = undefined;
84
- this.callback(null);
85
- return;
86
- }
87
-
88
- // Start observing in a `$nextTick()` (to allow DOM to complete rendering)
89
- /* istanbul ignore next: IntersectionObserver not supported in JSDOM */
90
- this.instance.$nextTick(() => {
91
- requestAF(() => {
92
- // Placed in an `if` just in case we were destroyed before
93
- // this `requestAnimationFrame` runs
94
- if (this.observer) {
95
- this.observer.observe(this.el);
96
- }
97
- });
98
- });
99
- }
100
-
101
- /* istanbul ignore next */
102
- handler(entries) {
103
- const entry = entries ? entries[0] : {};
104
- const isIntersecting = Boolean(entry.isIntersecting || entry.intersectionRatio > 0.0);
105
- if (isIntersecting !== this.visible) {
106
- this.visible = isIntersecting;
107
- this.callback(isIntersecting);
108
- if (this.once && this.visible) {
109
- this.doneOnce = true;
110
- this.stop();
111
- }
112
- }
113
- }
114
- stop() {
115
- /* istanbul ignore next */
116
- this.observer && this.observer.disconnect();
117
- this.observer = null;
118
- }
119
- }
120
- const destroy = el => {
121
- const observer = el[OBSERVER_PROP_NAME];
122
- if (observer && observer.stop) {
123
- observer.stop();
124
- }
125
- delete el[OBSERVER_PROP_NAME];
126
- };
127
- const bind = (el, bindings, vnode) => {
128
- const value = bindings.value,
129
- modifiers = bindings.modifiers;
130
- // `value` is the callback function
131
- const options = {
132
- margin: '0px',
133
- once: false,
134
- callback: value
135
- };
136
- // Parse modifiers
137
- keys(modifiers).forEach(mod => {
138
- /* istanbul ignore else: Until <b-img-lazy> is switched to use this directive */
139
- if (RX_DIGITS.test(mod)) {
140
- options.margin = `${mod}px`;
141
- } else if (mod.toLowerCase() === 'once') {
142
- options.once = true;
143
- }
144
- });
145
- // Destroy any previous observer
146
- destroy(el);
147
- // Create new observer
148
- const instance = getInstanceFromDirective(vnode, bindings);
149
- el[OBSERVER_PROP_NAME] = new VisibilityObserver(el, options, instance);
150
- // Store the current modifiers on the object (cloned)
151
- el[OBSERVER_PROP_NAME]._prevModifiers = clone(modifiers);
152
- };
153
-
154
- // When the directive options may have been updated (or element)
155
- const componentUpdated = (el, bindings, vnode) => {
156
- const value = bindings.value,
157
- oldValue = bindings.oldValue,
158
- modifiers = bindings.modifiers;
159
- // Compare value/oldValue and modifiers to see if anything has changed
160
- // and if so, destroy old observer and create new observer
161
- /* istanbul ignore next */
162
- const clonedModifiers = clone(modifiers);
163
- /* istanbul ignore next */
164
- if (el && (value !== oldValue || !el[OBSERVER_PROP_NAME] || !looseEqual(clonedModifiers, el[OBSERVER_PROP_NAME]._prevModifiers))) {
165
- // Re-bind on element
166
- bind(el, bindings, vnode);
167
- }
168
- };
169
-
170
- // When directive un-binds from element
171
- const unbind = el => {
172
- // Remove the observer
173
- destroy(el);
174
- };
175
-
176
- // Export the directive
177
- const VBVisible = {
178
- bind,
179
- componentUpdated,
180
- unbind
181
- };
182
-
183
- export { VBVisible };
@@ -1,3 +0,0 @@
1
- import { VBVisible } from './visible'
2
-
3
- export { VBVisible }
@@ -1,188 +0,0 @@
1
- // v-b-visible
2
- // Private visibility check directive
3
- // Based on IntersectionObserver
4
- //
5
- // Usage:
6
- // v-b-visibility.<margin>.<once>="<callback>"
7
- //
8
- // Value:
9
- // <callback>: method to be called when visibility state changes, receives one arg:
10
- // true: element is visible
11
- // false: element is not visible
12
- // null: IntersectionObserver not supported
13
- //
14
- // Modifiers:
15
- // <margin>: a positive decimal value of pixels away from viewport edge
16
- // before being considered "visible". default is 0
17
- // <once>: keyword 'once', meaning when the element becomes visible and
18
- // callback is called observation/notification will stop.
19
- //
20
- // When used in a render function:
21
- // export default {
22
- // directives: { 'b-visible': VBVisible },
23
- // render(h) {
24
- // h(
25
- // 'div',
26
- // {
27
- // directives: [
28
- // { name: 'b-visible', value=this.callback, modifiers: { '123':true, 'once':true } }
29
- // ]
30
- // }
31
- // )
32
- // }
33
-
34
- import { RX_DIGITS } from '../../constants/regex'
35
- import { requestAF } from '../../utils/dom'
36
- import { isFunction } from '../../utils/inspect'
37
- import { looseEqual } from '../../utils/loose-equal'
38
- import { clone, keys } from '../../utils/object'
39
- import { getInstanceFromDirective } from '../../utils/get-instance-from-directive'
40
-
41
- const OBSERVER_PROP_NAME = '__bv__visibility_observer'
42
-
43
- class VisibilityObserver {
44
- constructor(el, options, instance) {
45
- this.el = el
46
- this.callback = options.callback
47
- this.margin = options.margin || 0
48
- this.once = options.once || false
49
- this.observer = null
50
- this.visible = undefined
51
- this.doneOnce = false
52
- this.instance = instance
53
- // Create the observer instance (if possible)
54
- this.createObserver()
55
- }
56
-
57
- createObserver() {
58
- // Remove any previous observer
59
- if (this.observer) {
60
- /* istanbul ignore next */
61
- this.stop()
62
- }
63
-
64
- // Should only be called once and `callback` prop should be a function
65
- if (this.doneOnce || !isFunction(this.callback)) {
66
- /* istanbul ignore next */
67
- return
68
- }
69
-
70
- // Create the observer instance
71
- try {
72
- // Future: Possibly add in other modifiers for left/right/top/bottom
73
- // offsets, root element reference, and thresholds
74
- this.observer = new IntersectionObserver(this.handler.bind(this), {
75
- // `null` = 'viewport'
76
- root: null,
77
- // Pixels away from view port to consider "visible"
78
- rootMargin: this.margin,
79
- // Intersection ratio of el and root (as a value from 0 to 1)
80
- threshold: 0
81
- })
82
- } catch {
83
- // No IntersectionObserver support, so just stop trying to observe
84
- this.doneOnce = true
85
- this.observer = undefined
86
- this.callback(null)
87
- return
88
- }
89
-
90
- // Start observing in a `$nextTick()` (to allow DOM to complete rendering)
91
- /* istanbul ignore next: IntersectionObserver not supported in JSDOM */
92
- this.instance.$nextTick(() => {
93
- requestAF(() => {
94
- // Placed in an `if` just in case we were destroyed before
95
- // this `requestAnimationFrame` runs
96
- if (this.observer) {
97
- this.observer.observe(this.el)
98
- }
99
- })
100
- })
101
- }
102
-
103
- /* istanbul ignore next */
104
- handler(entries) {
105
- const entry = entries ? entries[0] : {}
106
- const isIntersecting = Boolean(entry.isIntersecting || entry.intersectionRatio > 0.0)
107
- if (isIntersecting !== this.visible) {
108
- this.visible = isIntersecting
109
- this.callback(isIntersecting)
110
- if (this.once && this.visible) {
111
- this.doneOnce = true
112
- this.stop()
113
- }
114
- }
115
- }
116
-
117
- stop() {
118
- /* istanbul ignore next */
119
- this.observer && this.observer.disconnect()
120
- this.observer = null
121
- }
122
- }
123
-
124
- const destroy = el => {
125
- const observer = el[OBSERVER_PROP_NAME]
126
- if (observer && observer.stop) {
127
- observer.stop()
128
- }
129
- delete el[OBSERVER_PROP_NAME]
130
- }
131
-
132
- const bind = (el, bindings, vnode) => {
133
- const { value, modifiers } = bindings
134
- // `value` is the callback function
135
- const options = {
136
- margin: '0px',
137
- once: false,
138
- callback: value
139
- }
140
- // Parse modifiers
141
- keys(modifiers).forEach(mod => {
142
- /* istanbul ignore else: Until <b-img-lazy> is switched to use this directive */
143
- if (RX_DIGITS.test(mod)) {
144
- options.margin = `${mod}px`
145
- } else if (mod.toLowerCase() === 'once') {
146
- options.once = true
147
- }
148
- })
149
- // Destroy any previous observer
150
- destroy(el)
151
- // Create new observer
152
- const instance = getInstanceFromDirective(vnode, bindings)
153
- el[OBSERVER_PROP_NAME] = new VisibilityObserver(el, options, instance)
154
- // Store the current modifiers on the object (cloned)
155
- el[OBSERVER_PROP_NAME]._prevModifiers = clone(modifiers)
156
- }
157
-
158
- // When the directive options may have been updated (or element)
159
- const componentUpdated = (el, bindings, vnode) => {
160
- const { value, oldValue, modifiers } = bindings
161
- // Compare value/oldValue and modifiers to see if anything has changed
162
- // and if so, destroy old observer and create new observer
163
- /* istanbul ignore next */
164
- const clonedModifiers = clone(modifiers)
165
- /* istanbul ignore next */
166
- if (
167
- el &&
168
- (value !== oldValue ||
169
- !el[OBSERVER_PROP_NAME] ||
170
- !looseEqual(clonedModifiers, el[OBSERVER_PROP_NAME]._prevModifiers))
171
- ) {
172
- // Re-bind on element
173
- bind(el, bindings, vnode)
174
- }
175
- }
176
-
177
- // When directive un-binds from element
178
- const unbind = el => {
179
- // Remove the observer
180
- destroy(el)
181
- }
182
-
183
- // Export the directive
184
- export const VBVisible = {
185
- bind,
186
- componentUpdated,
187
- unbind
188
- }