@gitlab/ui 115.10.0 → 116.0.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/dist/components/base/filtered_search/filtered_search_suggestion.js +11 -5
- package/dist/components/dashboards/dashboard_layout/grid_layout/grid_layout.js +2 -2
- package/dist/components/dashboards/dashboard_panel/dashboard_panel.js +45 -3
- package/dist/components/index.js +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/tailwind.css +1 -1
- package/dist/tailwind.css.map +1 -1
- package/dist/tokens/common_story_options.js +1 -6
- package/dist/tokens/tokens_story.js +3 -16
- package/package.json +5 -5
- package/src/components/base/button/button.scss +8 -0
- package/src/components/base/filtered_search/filtered_search_suggestion.vue +32 -14
- package/src/components/dashboards/dashboard_layout/grid_layout/grid_layout.vue +2 -2
- package/src/components/dashboards/dashboard_panel/dashboard_panel.md +61 -13
- package/src/components/dashboards/dashboard_panel/dashboard_panel.vue +46 -3
- package/src/components/index.js +1 -1
- package/src/tokens/common_story_options.js +1 -9
- package/src/tokens/tokens_story.vue +2 -22
- package/src/components/base/form/form.md +0 -2
- package/src/components/base/form/form_character_count/form_character_count.md +0 -53
- package/src/components/base/form/form_combobox/form_combobox.md +0 -52
- package/src/components/base/form/form_date/form_date.md +0 -26
- package/src/components/base/form/form_fields/form_fields.md +0 -41
- package/src/components/base/form/form_group/form_group.md +0 -1
- package/src/components/base/form/form_input_group/form_input_group.md +0 -67
- package/src/components/base/form/input_group_text/input_group_text.md +0 -1
- package/src/components/charts/bar/bar.md +0 -3
- package/src/components/charts/chart/chart.md +0 -19
- package/src/components/charts/gauge/gauge.md +0 -8
- package/src/components/charts/heatmap/heatmap.md +0 -7
- package/src/components/charts/legend/legend.md +0 -16
- package/src/components/charts/line/line.md +0 -7
- package/src/components/charts/series_label/series_label.md +0 -1
- package/src/components/charts/shared/tooltip/tooltip.md +0 -3
- package/src/components/charts/single_stat/single_stat.md +0 -8
- package/src/components/charts/sparkline/sparkline.md +0 -8
- package/src/components/charts/stacked_column/stacked_column.md +0 -10
- package/src/components/regions/empty_state/empty_state.md +0 -4
- package/src/components/utilities/animated_number/animated_number.md +0 -6
- package/src/components/utilities/friendly_wrap/friendly_wrap.md +0 -66
- package/src/components/utilities/intersection_observer/intersection_observer.md +0 -16
- package/src/components/utilities/intersperse/intersperse.md +0 -90
- package/src/components/utilities/sprintf/sprintf.md +0 -243
- package/src/components/utilities/truncate/truncate.md +0 -14
- package/src/components/utilities/truncate_text/truncate_text.md +0 -26
- package/src/directives/hover_load/hover_load.md +0 -22
- package/src/directives/outside/outside.md +0 -140
- package/src/directives/resize_observer/resize_observer.md +0 -54
- package/src/directives/safe_html/safe_html.md +0 -58
- package/src/directives/safe_link/safe_link.md +0 -37
- package/src/internal/color_contrast/color_contrast.md +0 -8
- package/src/internal/color_contrast/color_contrast.vue +0 -52
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
## Overview
|
|
2
|
-
|
|
3
|
-
The `GlSprintf` component lets you do `sprintf`-style string interpolation with
|
|
4
|
-
child components. Each placeholder in the translated string, provided via the
|
|
5
|
-
`message` prop, becomes a slot that you can use to insert any components or
|
|
6
|
-
markup in the rendered output.
|
|
7
|
-
|
|
8
|
-
> NOTE: `gl-sprintf` does not translate the message for you; you must provide
|
|
9
|
-
> it already translated. In the following examples, it is assumed that
|
|
10
|
-
> a `gettext`-style `__` translation function is available in your Vue
|
|
11
|
-
> templates.
|
|
12
|
-
|
|
13
|
-
## Displaying messages with text between placeholders (e.g., links, buttons)
|
|
14
|
-
|
|
15
|
-
Sentences should not be split up into different messages, otherwise they may
|
|
16
|
-
not be translatable into certain languages. To help with this, `GlSprintf`
|
|
17
|
-
interprets placeholders suffixed with `Start` and `End` to indicate the
|
|
18
|
-
boundaries of a component to display within the message. Any text between
|
|
19
|
-
them is passed, via the `content` scoped slot property, to the slot name common
|
|
20
|
-
to the placeholders.
|
|
21
|
-
|
|
22
|
-
For example, using `linkStart` and `linkEnd` placeholders in a message defines
|
|
23
|
-
a `link` scoped slot:
|
|
24
|
-
|
|
25
|
-
```html
|
|
26
|
-
<div>
|
|
27
|
-
<gl-sprintf :message="__('Learn more about %{linkStart}zones%{linkEnd}')">
|
|
28
|
-
<template #link="{ content }">
|
|
29
|
-
<gl-link
|
|
30
|
-
href="https://cloud.google.com/compute/docs/regions-zones/regions-zones"
|
|
31
|
-
target="_blank"
|
|
32
|
-
>{{ content }}</gl-link>
|
|
33
|
-
</template>
|
|
34
|
-
</gl-sprintf>
|
|
35
|
-
</div>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
will render as:
|
|
39
|
-
|
|
40
|
-
```html
|
|
41
|
-
<div>
|
|
42
|
-
Learn more about
|
|
43
|
-
<a
|
|
44
|
-
href="https://cloud.google.com/compute/docs/regions-zones/regions-zones"
|
|
45
|
-
target="_blank"
|
|
46
|
-
rel="noopener noreferrer"
|
|
47
|
-
>zones</a>
|
|
48
|
-
</div>
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Note that _any_ arbitrary HTML tags or Vue component(s) can be used within
|
|
52
|
-
a scoped slot, and that the content passed to it can be used in any way at all;
|
|
53
|
-
for instance, as regular text, or in component attributes or slots.
|
|
54
|
-
|
|
55
|
-
Here's a more complex example, which `<gl-sprintf>` lets you do in a breeze:
|
|
56
|
-
|
|
57
|
-
```html
|
|
58
|
-
<div>
|
|
59
|
-
<gl-sprintf :message="__('Written by %{authorStart}someone%{authorEnd}')">
|
|
60
|
-
<template #author="{ content }">
|
|
61
|
-
<my-vue-component v-gl-tooltip="content" @event="handleEvent(content)">
|
|
62
|
-
{{ content }}
|
|
63
|
-
</my-vue-component>
|
|
64
|
-
<p>
|
|
65
|
-
{{ content }}
|
|
66
|
-
<div>{{ content }}</div>
|
|
67
|
-
</p>
|
|
68
|
-
</template>
|
|
69
|
-
</gl-sprintf>
|
|
70
|
-
</div>
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
This is not feasible in a JS-only solution, since arbitrary Vue components
|
|
74
|
-
cannot easily be used. In addition, a JS-only solution is more likely to be
|
|
75
|
-
prone to XSS attacks, as the Vue compiler isn't available to help protect
|
|
76
|
-
against them.
|
|
77
|
-
|
|
78
|
-
### Customizing start/end placeholders
|
|
79
|
-
|
|
80
|
-
You can customize the start and end placeholders that `GlSprintf` looks for
|
|
81
|
-
using the `placeholders` prop. For instance:
|
|
82
|
-
|
|
83
|
-
```html
|
|
84
|
-
<div>
|
|
85
|
-
<gl-sprintf
|
|
86
|
-
:message="__('Learn more about %{my_custom_start}zones%{my_custom_end}')"
|
|
87
|
-
:placeholders="{ link: ['my_custom_start', 'my_custom_end'] }"
|
|
88
|
-
>
|
|
89
|
-
<template #link="{ content }">
|
|
90
|
-
<gl-link
|
|
91
|
-
href="https://cloud.google.com/compute/docs/regions-zones/regions-zones"
|
|
92
|
-
target="_blank"
|
|
93
|
-
>{{ content }}</gl-link>
|
|
94
|
-
</template>
|
|
95
|
-
</gl-sprintf>
|
|
96
|
-
</div>
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
This can be useful if you are migrating an existing string to `GlSprintf` that
|
|
100
|
-
uses different placeholder naming conventions, and don't want invalidate
|
|
101
|
-
existing translations.
|
|
102
|
-
|
|
103
|
-
## Displaying components within a message
|
|
104
|
-
|
|
105
|
-
Use slots to replace placeholders in the message with the slots' contents.
|
|
106
|
-
There is a slot for every placeholder in the message. For example, the `author`
|
|
107
|
-
slot name can be used when there is an `%{author}` placeholder in the message:
|
|
108
|
-
|
|
109
|
-
```html
|
|
110
|
-
<script>
|
|
111
|
-
export default {
|
|
112
|
-
data() {
|
|
113
|
-
return {
|
|
114
|
-
authorName: 'Some author',
|
|
115
|
-
};
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
</script>
|
|
119
|
-
|
|
120
|
-
<template>
|
|
121
|
-
<div>
|
|
122
|
-
<gl-sprintf :message="__('Written by %{author}')">
|
|
123
|
-
<template #author>
|
|
124
|
-
<span>{{ authorName }}</span>
|
|
125
|
-
</template>
|
|
126
|
-
</gl-sprintf>
|
|
127
|
-
</div>
|
|
128
|
-
</template>
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
The example above renders to this HTML:
|
|
132
|
-
|
|
133
|
-
```html
|
|
134
|
-
<div>Written by <span>Some author</span></div>
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Usage caveats
|
|
138
|
-
|
|
139
|
-
### White space
|
|
140
|
-
|
|
141
|
-
`GlSprintf` does not handle white space in scoped slots specially; it is passed
|
|
142
|
-
through and rendered just like regular text. This means that white space in the
|
|
143
|
-
scoped slot templates _themselves_, including newlines and indentation, are
|
|
144
|
-
passed through untouched (assuming the template compiler you're using doesn't
|
|
145
|
-
trim text nodes at compile time; `vue-template-compiler` preserves white space
|
|
146
|
-
by default, for instance).
|
|
147
|
-
|
|
148
|
-
Most of the time you don't need to worry about this, since
|
|
149
|
-
[browsers normalize white space][1] automatically, but here's an example, using
|
|
150
|
-
punctuation, where you might want to be conscious of the white space in the
|
|
151
|
-
template:
|
|
152
|
-
|
|
153
|
-
```html
|
|
154
|
-
<div>
|
|
155
|
-
<gl-sprintf :message="__('Foo %{boldStart}bar%{boldEnd}!')">
|
|
156
|
-
<template #bold="{ content }">
|
|
157
|
-
<b>
|
|
158
|
-
{{ content }}
|
|
159
|
-
</b>
|
|
160
|
-
</template>
|
|
161
|
-
</gl-sprintf>
|
|
162
|
-
</div>
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
As written, the literal markup rendered would be:
|
|
166
|
-
|
|
167
|
-
```html
|
|
168
|
-
<div> Foo <b>
|
|
169
|
-
bar
|
|
170
|
-
</b>!
|
|
171
|
-
</div>
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
where the white space (including newlines) before and after `bar` is exactly
|
|
175
|
-
the newlines and indentation in the source template. The browser will render
|
|
176
|
-
this as:
|
|
177
|
-
|
|
178
|
-
<div> Foo <b>
|
|
179
|
-
bar
|
|
180
|
-
</b>!
|
|
181
|
-
</div>
|
|
182
|
-
|
|
183
|
-
Note the single space between `bar` and `!`. To avoid that, remove the
|
|
184
|
-
white space in the template, or use `v-text`:
|
|
185
|
-
|
|
186
|
-
```html
|
|
187
|
-
<div>
|
|
188
|
-
<gl-sprintf :message="__('Foo %{boldStart}bar%{boldEnd}!')">
|
|
189
|
-
<template #bold="{ content }">
|
|
190
|
-
<b>{{ content }}</b>
|
|
191
|
-
<!-- OR -->
|
|
192
|
-
<b v-text="content" />
|
|
193
|
-
</template>
|
|
194
|
-
</gl-sprintf>
|
|
195
|
-
</div>
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### Miscellaneous
|
|
199
|
-
|
|
200
|
-
While there are a lot of caveats here, you don't need to worry about reading
|
|
201
|
-
them _unless_ you find `GlSprintf` isn't rendering what you'd expect.
|
|
202
|
-
|
|
203
|
-
- Since `GlSprintf` typically renders multiple elements, it can't be used as
|
|
204
|
-
a component's root, it must be wrapped with at least one other root element,
|
|
205
|
-
otherwise Vue will throw a `Multiple root nodes returned from render
|
|
206
|
-
function` error.
|
|
207
|
-
- If a slot for a given placeholder _isn't_ provided, the placeholder
|
|
208
|
-
will be rendered as-is, e.g., literally `Written by %{author}` if the
|
|
209
|
-
`author` slot _isn't_ provided, or literally `%{linkStart}foo%{linkEnd}` if
|
|
210
|
-
the `link` slot isn't provided.
|
|
211
|
-
- Content between `Start` and `End` placeholders is effectively thrown away if
|
|
212
|
-
the scoped slot of the correct name doesn't consume the `content` property in
|
|
213
|
-
some way, though the slot's components should still be rendered.
|
|
214
|
-
- If there's no placeholder in the message for a provided named slot, the
|
|
215
|
-
content of that slot is silently thrown away.
|
|
216
|
-
- If only one of the `Start` or `End` placeholders is in the message, or they
|
|
217
|
-
are in the wrong order, they are treated as plain slots, i.e., it is assumed
|
|
218
|
-
there is no text to extract and pass to the scoped slot. This allows you to
|
|
219
|
-
use plain slots whose names end in `Start` or `End`, e.g., `backEnd`, or
|
|
220
|
-
`fromStart` in isolation, without their `Start`/`End` counterparts.
|
|
221
|
-
- Text extraction between `Start` and `End` placeholders is only done one level
|
|
222
|
-
deep. This is intentional, so as to avoid building complex sprintf messages
|
|
223
|
-
that would better be implemented in components. As an example,
|
|
224
|
-
`${linkStart}test%{icon}%{linkEnd}`, if provided both the `link` and `icon`
|
|
225
|
-
slots, would pass `test%{icon}` as a literal string as content to the `link`
|
|
226
|
-
scoped slot.
|
|
227
|
-
- For more examples and edge cases, please see the test suite for `GlSprintf`.
|
|
228
|
-
- To be successfully used in `GlSprintf`, slot names should:
|
|
229
|
-
- start with a letter (`[A-Za-z]`)
|
|
230
|
-
- only contain alpha-numeric characters (`[A-Za-z0-9]`), underscore (`_`) and
|
|
231
|
-
dash (`-`),
|
|
232
|
-
- should not end with underscore (`_`) or dash (`-`) So for example:
|
|
233
|
-
`%{author}`, `%{author_name}`, `%{authorName}` or `%{author-name-100}` are
|
|
234
|
-
all valid placeholders.
|
|
235
|
-
|
|
236
|
-
## Internet Explorer 11
|
|
237
|
-
|
|
238
|
-
This component uses [`String.prototype.startsWith()`] and [`String.prototype.endsWith()`] under the
|
|
239
|
-
hood. Make sure those methods are polyfilled if you plan on using the component on IE11.
|
|
240
|
-
|
|
241
|
-
[1]: https://www.w3.org/TR/css-text-3/#white-space-phase-1
|
|
242
|
-
[`String.prototype.startsWith()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
|
|
243
|
-
[`String.prototype.endsWith()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
The `GlTruncate` component lets you truncate the long texts with ellipsis.
|
|
2
|
-
|
|
3
|
-
> **Tip:** Try resizing the side panel for truncation.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```html
|
|
8
|
-
<gl-truncate :text="text" :position="position" />
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
By default, the ellipsis position is at the `end`.
|
|
12
|
-
|
|
13
|
-
Pro Tip: Truncating long filepaths from the `middle` / `start` can help preventing the important
|
|
14
|
-
information in the end, i.e. filenames.
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
The `GlTruncateText` component lets you truncate a large text by number of lines.
|
|
2
|
-
The last line ends with an ellipsis if the text is truncated.
|
|
3
|
-
Truncation can be toggled by a 'Show more' / 'Show less' button.
|
|
4
|
-
The button will not be shown when no truncation is necessary.
|
|
5
|
-
There is a separate property to set the number of lines initially shown on small screens.
|
|
6
|
-
Use the `showMoreText` and `showLessText` properties to provide translated strings.
|
|
7
|
-
|
|
8
|
-
> **Tip:** Try resizing the side panel to see the truncated number of lines change.
|
|
9
|
-
|
|
10
|
-
## Usage
|
|
11
|
-
|
|
12
|
-
```html
|
|
13
|
-
<gl-truncate-text :show-more-text="__('Show more')" :show-less-text="__('Show less')" :lines="3" :mobile-lines="10">
|
|
14
|
-
{{ largeText }}
|
|
15
|
-
</gl-truncate-text>
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Usage caveats
|
|
19
|
-
|
|
20
|
-
When the size of the window is large,
|
|
21
|
-
and the text is displayed on a number of lines greater than the value of the `lines` property,
|
|
22
|
-
but smaller than the value of the `mobileLines` property,
|
|
23
|
-
and the `Show more` button has been clicked to show the entire content of the text,
|
|
24
|
-
and the window is resized to a small size,
|
|
25
|
-
then instead of disappearing,
|
|
26
|
-
the `Show less` button will remain visible and will do nothing when clicked.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
A Vue Directive to help with preloading resources when hovering over an element.
|
|
2
|
-
|
|
3
|
-
## Usage
|
|
4
|
-
|
|
5
|
-
```html
|
|
6
|
-
<script>
|
|
7
|
-
import { GlHoverLoadDirective } from '@gitlab/ui';
|
|
8
|
-
|
|
9
|
-
export default {
|
|
10
|
-
directives: { GlHoverLoadDirective },
|
|
11
|
-
methods: {
|
|
12
|
-
handlePreload() {
|
|
13
|
-
fetch('some/endpoint');
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
</script>
|
|
18
|
-
|
|
19
|
-
<template>
|
|
20
|
-
<div v-gl-hover-load="handlePreload">Hover me to preload</div>
|
|
21
|
-
</template>
|
|
22
|
-
```
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
A Vue Directive to call a callback when a supported event type occurs *outside* of the element
|
|
2
|
-
the directive is bound to. Any events on the element or any descendant elements are ignored.
|
|
3
|
-
The directive supports the event types `click` and `focusin` and can be configured in several ways.
|
|
4
|
-
If no event type is set, `click` is the default.
|
|
5
|
-
|
|
6
|
-
## Usage
|
|
7
|
-
|
|
8
|
-
### Default
|
|
9
|
-
|
|
10
|
-
The following example listens for click events outside the specified element:
|
|
11
|
-
|
|
12
|
-
```html
|
|
13
|
-
<script>
|
|
14
|
-
import { GlOutsideDirective as Outside } from '@gitlab/ui';
|
|
15
|
-
|
|
16
|
-
export default {
|
|
17
|
-
directives: { Outside },
|
|
18
|
-
methods: {
|
|
19
|
-
onClick(event) {
|
|
20
|
-
console.log('User clicked somewhere outside of this component', event);
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
</script>
|
|
25
|
-
|
|
26
|
-
<template>
|
|
27
|
-
<div v-outside="onClick">Click anywhere but here</div>
|
|
28
|
-
</template>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### When binding another event type than `click`
|
|
32
|
-
|
|
33
|
-
You can specify event types as modifiers. The following example listens for `focusin` events,
|
|
34
|
-
but not for `click`. With this implementation:
|
|
35
|
-
|
|
36
|
-
```html
|
|
37
|
-
<script>
|
|
38
|
-
export default {
|
|
39
|
-
methods: {
|
|
40
|
-
onFocusin(event) {
|
|
41
|
-
console.log('User set the focus somewhere outside of this component', event);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
</script>
|
|
46
|
-
|
|
47
|
-
<template>
|
|
48
|
-
<div v-outside.focusin="onFocusin">...</div>
|
|
49
|
-
</template>
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### When binding multiple event types
|
|
53
|
-
|
|
54
|
-
You can specify multiple event types by providing multiple modifiers. The following example
|
|
55
|
-
listens for `click` and `focusin` events:
|
|
56
|
-
|
|
57
|
-
```html
|
|
58
|
-
<script>
|
|
59
|
-
export default {
|
|
60
|
-
methods: {
|
|
61
|
-
onEvent(event) {
|
|
62
|
-
console.log('Event occurred outside the element:', event);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
</script>
|
|
67
|
-
|
|
68
|
-
<template>
|
|
69
|
-
<div v-outside.click.focusin="onEvent">...</div>
|
|
70
|
-
</template>
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
💡 The callback function receives the `event` as a parameter. You can use the `event.type`
|
|
74
|
-
property to execute different code paths depending on which event triggered the callback.
|
|
75
|
-
|
|
76
|
-
### When handler expects arguments
|
|
77
|
-
|
|
78
|
-
In case a click handler expects an arument to be passed, simple `v-outside="onClick('foo')"` will
|
|
79
|
-
invoke the handler instantly when mounting the component and the directive won't be active. The
|
|
80
|
-
simplest solution to pass the arguments to the directive is to wrap the handler into an anonumous
|
|
81
|
-
function.
|
|
82
|
-
|
|
83
|
-
```html
|
|
84
|
-
<script>
|
|
85
|
-
import { GlOutsideDirective as Outside } from '@gitlab/ui';
|
|
86
|
-
|
|
87
|
-
export default {
|
|
88
|
-
directives: { Outside },
|
|
89
|
-
methods: {
|
|
90
|
-
onClick(event, foo) {
|
|
91
|
-
console.log('Event occurred outside the element:', event);
|
|
92
|
-
console.log('An argument was passed along:', foo);
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
</script>
|
|
97
|
-
|
|
98
|
-
<template>
|
|
99
|
-
<div v-outside="(event) => onClick(event, 'foo')">Click anywhere but here</div>
|
|
100
|
-
</template>
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Caveats
|
|
104
|
-
|
|
105
|
-
* Clicks cannot be detected across document boundaries (e.g., across an
|
|
106
|
-
`iframe` boundary), in either direction.
|
|
107
|
-
* Clicks on focusable elements, such as buttons or input fields, will fire both
|
|
108
|
-
`click` and `focusin` events. When both event types are registered,
|
|
109
|
-
the callback will be executed twice. To prevent executing the same code twice
|
|
110
|
-
after only one user interaction, use a flag in the callback to stop its
|
|
111
|
-
execution. Example:
|
|
112
|
-
|
|
113
|
-
```html
|
|
114
|
-
<script>
|
|
115
|
-
export default {
|
|
116
|
-
data: () => ({
|
|
117
|
-
isOpen: false,
|
|
118
|
-
}),
|
|
119
|
-
methods: {
|
|
120
|
-
openDropdown() {
|
|
121
|
-
this.isOpen = true;
|
|
122
|
-
},
|
|
123
|
-
closeDropdown() {
|
|
124
|
-
if(!this.isOpen) {
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// more code
|
|
129
|
-
|
|
130
|
-
this.isOpen = false;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
</script>
|
|
135
|
-
|
|
136
|
-
<template>
|
|
137
|
-
<button type="button" @click="openDropdown">Open</button>
|
|
138
|
-
<div v-outside.click.focusin="closeDropdown">...</div>
|
|
139
|
-
</template>
|
|
140
|
-
```
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
This directive can be used to get notified whenever a given element's size (width or height) changes
|
|
2
|
-
and to retrieve the updated dimensions.
|
|
3
|
-
|
|
4
|
-
Under the hood, it leverages the [Resize Observer API](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).
|
|
5
|
-
If you use GitLab UI in an older browser which doesn't support the Resize Observer API,
|
|
6
|
-
you can use a [polyfill](https://github.com/que-etc/resize-observer-polyfill).
|
|
7
|
-
|
|
8
|
-
The directive accepts a callback as a value and passes on the received
|
|
9
|
-
[contentRect](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentRect)
|
|
10
|
-
and the target element whenever a resize event gets triggered.
|
|
11
|
-
|
|
12
|
-
```html
|
|
13
|
-
<script>
|
|
14
|
-
export default {
|
|
15
|
-
data() {
|
|
16
|
-
return {
|
|
17
|
-
width: 0,
|
|
18
|
-
height: 0,
|
|
19
|
-
};
|
|
20
|
-
},
|
|
21
|
-
methods: {
|
|
22
|
-
handleResize({ contentRect: { width, height } }) {
|
|
23
|
-
this.width = width;
|
|
24
|
-
this.height = height;
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
</script>
|
|
29
|
-
<template>
|
|
30
|
-
<div v-gl-resize-observer-directive="handleResize">
|
|
31
|
-
<p>{{ width }} x {{ height }}</p>
|
|
32
|
-
</div>
|
|
33
|
-
</template>
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
The observer can be toggled on or off by passing a boolean argument to the directive:
|
|
37
|
-
|
|
38
|
-
```html
|
|
39
|
-
<script>
|
|
40
|
-
export default {
|
|
41
|
-
data() {
|
|
42
|
-
return {
|
|
43
|
-
shouldObserve: true,
|
|
44
|
-
};
|
|
45
|
-
},
|
|
46
|
-
methods: {
|
|
47
|
-
handleResize() {},
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
</script>
|
|
51
|
-
<template>
|
|
52
|
-
<div v-gl-resize-observer-directive[shouldObserve]="handleResize"></div>
|
|
53
|
-
</template>
|
|
54
|
-
```
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
A Vue Directive to sanitize HTML to avoid any XSS vulnerabilities.
|
|
2
|
-
|
|
3
|
-
## Usage
|
|
4
|
-
|
|
5
|
-
This directive can be used to sanitize HTML code which may contain user input, to prevent cross-site
|
|
6
|
-
scripting (XSS) vulnerabilities.
|
|
7
|
-
|
|
8
|
-
Under the hood, it uses [DOMPurify](https://github.com/cure53/DOMPurify) to sanitize the provided HTML.
|
|
9
|
-
|
|
10
|
-
DOMPurify will strip out dangerous HTML and will keep the safe HTML. You can refer complete list of
|
|
11
|
-
[tags][1] and [attributes][2] allowed by DOMPurify.
|
|
12
|
-
|
|
13
|
-
[1]: https://github.com/cure53/DOMPurify/blob/main/src/tags.js
|
|
14
|
-
[2]: https://github.com/cure53/DOMPurify/blob/main/src/attrs.js
|
|
15
|
-
|
|
16
|
-
## Example
|
|
17
|
-
|
|
18
|
-
```html
|
|
19
|
-
<script>
|
|
20
|
-
import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
|
|
21
|
-
|
|
22
|
-
export default {
|
|
23
|
-
directives: {
|
|
24
|
-
SafeHtml,
|
|
25
|
-
},
|
|
26
|
-
data() {
|
|
27
|
-
return {
|
|
28
|
-
rawHtml: "Hello! <script>alert('XSS')</script>",
|
|
29
|
-
};
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
</script>
|
|
33
|
-
|
|
34
|
-
<template>
|
|
35
|
-
<div v-safe-html="rawHtml"></div>
|
|
36
|
-
</template>
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Advanced configuration
|
|
40
|
-
|
|
41
|
-
```js
|
|
42
|
-
// It allows only <b> tags
|
|
43
|
-
const config = { ALLOWED_TAGS: ['b'] };
|
|
44
|
-
|
|
45
|
-
// It doesn't allow any html tags
|
|
46
|
-
const config = { ALLOWED_TAGS: [] };
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
```html
|
|
50
|
-
<div v-safe-html:[config]="rawHtml"></div>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
For advanced configuration options, please refer to [DOMPurify's documentation](https://github.com/cure53/DOMPurify#can-i-configure-dompurify).
|
|
54
|
-
|
|
55
|
-
### Notes
|
|
56
|
-
|
|
57
|
-
1. `target` attribute is not allowed by default - See <https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1427>.
|
|
58
|
-
1. To know more about other tips & caveats - See <https://gitlab.com/groups/gitlab-org/-/epics/4273#caveats>.
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
A Vue directive to make the hyperlinks secure by default.
|
|
2
|
-
|
|
3
|
-
## Security measures
|
|
4
|
-
|
|
5
|
-
### rel
|
|
6
|
-
|
|
7
|
-
When setting target to `_blank`, the rel attribute gets set automatically to `noopener noreferrer`,
|
|
8
|
-
this is done to avoid the `window.opener` [API exploit]. If you set the `rel` attribute manually,
|
|
9
|
-
this will overwrite the aforementioned logic.
|
|
10
|
-
|
|
11
|
-
### href
|
|
12
|
-
|
|
13
|
-
This directive enforces "safe" URLs. What this means is that, if the provided `href`
|
|
14
|
-
doesn't point to a safe protocol (one of `http:`, `https:`, `mailto:` or `ftp:`), then it is
|
|
15
|
-
replaced with `about:blank` to prevent [URL injections].
|
|
16
|
-
|
|
17
|
-
```html
|
|
18
|
-
<script>
|
|
19
|
-
import { GlSafeLinkDirective as SafeLink } from '@gitlab/ui';
|
|
20
|
-
|
|
21
|
-
export default {
|
|
22
|
-
data() {
|
|
23
|
-
return {
|
|
24
|
-
url: 'javascript:alert(1)',
|
|
25
|
-
};
|
|
26
|
-
},
|
|
27
|
-
directives: { SafeLink },
|
|
28
|
-
};
|
|
29
|
-
</script>
|
|
30
|
-
<template>
|
|
31
|
-
<a v-safe-link href="url" target="_blank">Click</a>
|
|
32
|
-
<!-- Renders to: <a href="about:blank" target="_blank">Click</a> -->
|
|
33
|
-
</template>
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
[API exploit]: https://www.jitbit.com/alexblog/256-targetblank---the-most-underestimated-vulnerability-ever/
|
|
37
|
-
[URL injections]: https://vuejs.org/v2/guide/security.html#Injecting-URLs
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
## Usage
|
|
2
|
-
|
|
3
|
-
`GlColorContrast` is an **internal** component to display color contrast
|
|
4
|
-
scores and levels for design token stories.
|
|
5
|
-
|
|
6
|
-
`GlColorContrast` accepts `foreground` and `background` color props to
|
|
7
|
-
calculate a contrast score (e.g. `4.5`) and level (e.g. `AA`) consistent
|
|
8
|
-
with [WCAG 2.1 1.4.3: Contrast (Minimum) level](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html).
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import { HEX_REGEX } from '../../utils/constants';
|
|
3
|
-
import { getColorContrast } from '../../utils/utils';
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
name: 'GlColorContrast',
|
|
7
|
-
props: {
|
|
8
|
-
foreground: {
|
|
9
|
-
type: String,
|
|
10
|
-
required: true,
|
|
11
|
-
validator: (value) => HEX_REGEX.test(value),
|
|
12
|
-
},
|
|
13
|
-
background: {
|
|
14
|
-
type: String,
|
|
15
|
-
required: true,
|
|
16
|
-
validator: (value) => HEX_REGEX.test(value),
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
computed: {
|
|
20
|
-
isValidColorCombination() {
|
|
21
|
-
return HEX_REGEX.test(this.foreground) && HEX_REGEX.test(this.background);
|
|
22
|
-
},
|
|
23
|
-
classes() {
|
|
24
|
-
if (!this.isValidColorCombination) return 'gl-text-neutral-950';
|
|
25
|
-
const { grade } = this.contrast.level;
|
|
26
|
-
const isFail = grade === 'F';
|
|
27
|
-
const contrastScore = getColorContrast('#fff', this.background).score > 4.5;
|
|
28
|
-
const textClass = contrastScore ? 'gl-text-neutral-0' : 'gl-text-neutral-950';
|
|
29
|
-
const failClasses = contrastScore
|
|
30
|
-
? 'gl-shadow-inner-1-red-300 gl-text-red-300'
|
|
31
|
-
: 'gl-shadow-inner-1-red-500 gl-text-red-500';
|
|
32
|
-
return [isFail ? failClasses : textClass];
|
|
33
|
-
},
|
|
34
|
-
contrast() {
|
|
35
|
-
return getColorContrast(this.foreground, this.background);
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
</script>
|
|
40
|
-
|
|
41
|
-
<template>
|
|
42
|
-
<code
|
|
43
|
-
class="gl-w-10 gl-rounded-base gl-p-2 gl-text-center gl-text-xs"
|
|
44
|
-
:class="classes"
|
|
45
|
-
:style="{ backgroundColor: background }"
|
|
46
|
-
>
|
|
47
|
-
<template v-if="isValidColorCombination">
|
|
48
|
-
{{ contrast.level.grade }} {{ contrast.score }}
|
|
49
|
-
</template>
|
|
50
|
-
<template v-else>???</template>
|
|
51
|
-
</code>
|
|
52
|
-
</template>
|