@gitlab/ui 137.3.1 → 138.1.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 (95) hide show
  1. package/README.md +3 -12
  2. package/dist/components/base/alert/alert.js +0 -1
  3. package/dist/components/base/drawer/drawer.js +0 -1
  4. package/dist/components/base/filtered_search/filtered_search_suggestion_list.js +1 -1
  5. package/dist/components/base/filtered_search/filtered_search_token_segment.js +0 -1
  6. package/dist/components/base/form/form_group/form_group.js +0 -1
  7. package/dist/components/base/form/form_select/form_select.js +322 -6
  8. package/dist/components/base/modal/modal.js +1 -5
  9. package/dist/components/base/new_dropdowns/base_dropdown/dropdown_container.js +1 -1
  10. package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown.js +1 -3
  11. package/dist/components/base/toast/index.js +1 -1
  12. package/dist/components/base/toggle/toggle.js +0 -1
  13. package/dist/components/mixins/tooltip_mixin.js +1 -1
  14. package/dist/index.css +2 -2
  15. package/dist/index.css.map +1 -1
  16. package/dist/tailwind.css +1 -1
  17. package/dist/tailwind.css.map +1 -1
  18. package/dist/tokens/build/js/tokens.dark.js +299 -299
  19. package/dist/tokens/build/js/tokens.js +302 -302
  20. package/dist/utils/confetti/confetti.js +189 -0
  21. package/dist/utils/confetti/constants.js +36 -0
  22. package/dist/utils/confetti/field.js +114 -0
  23. package/dist/utils/confetti/palette.js +6 -0
  24. package/dist/utils/confetti/particles.js +92 -0
  25. package/dist/utils/matrix/columns.js +54 -0
  26. package/dist/utils/matrix/constants.js +19 -0
  27. package/dist/utils/matrix/matrix.js +157 -0
  28. package/dist/utils/matrix/palette.js +9 -0
  29. package/dist/utils.js +2 -0
  30. package/dist/vendor/bootstrap-vue/src/components/popover/helpers/bv-popover-template.js +4 -2
  31. package/dist/vendor/bootstrap-vue/src/components/tooltip/helpers/bv-tooltip-template.js +3 -1
  32. package/dist/vendor/bootstrap-vue/src/constants/components.js +1 -4
  33. package/package.json +4 -11
  34. package/src/components/base/alert/alert.vue +0 -1
  35. package/src/components/base/drawer/drawer.vue +0 -1
  36. package/src/components/base/filtered_search/filtered_search_suggestion_list.vue +2 -1
  37. package/src/components/base/filtered_search/filtered_search_token_segment.vue +0 -1
  38. package/src/components/base/form/form_group/form_group.vue +0 -2
  39. package/src/components/base/form/form_select/form_select.vue +389 -10
  40. package/src/components/base/modal/modal.vue +0 -3
  41. package/src/components/base/new_dropdowns/base_dropdown/dropdown_container.js +1 -1
  42. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.vue +0 -1
  43. package/src/components/base/tabs/tabs/scrollable_tabs.vue +0 -1
  44. package/src/components/base/tabs/tabs/tabs.vue +0 -1
  45. package/src/components/base/toast/index.js +1 -1
  46. package/src/components/base/toggle/toggle.vue +0 -1
  47. package/src/components/charts/heatmap/index.js +1 -1
  48. package/src/components/mixins/tooltip_mixin.js +1 -1
  49. package/src/tokens/build/css/tokens.css +74 -74
  50. package/src/tokens/build/css/tokens.dark.css +70 -70
  51. package/src/tokens/build/docs/tokens-tailwind-docs.dark.json +303 -303
  52. package/src/tokens/build/docs/tokens-tailwind-docs.json +323 -323
  53. package/src/tokens/build/figma/constants.dark.json +207 -207
  54. package/src/tokens/build/figma/constants.json +207 -207
  55. package/src/tokens/build/figma/mode.dark.json +37 -37
  56. package/src/tokens/build/figma/mode.json +35 -35
  57. package/src/tokens/build/js/tokens.dark.js +299 -300
  58. package/src/tokens/build/js/tokens.js +302 -303
  59. package/src/tokens/build/json/tokens.dark.json +369 -369
  60. package/src/tokens/build/json/tokens.json +376 -376
  61. package/src/tokens/build/scss/_tokens.dark.scss +70 -70
  62. package/src/tokens/build/scss/_tokens.scss +74 -74
  63. package/src/tokens/constant/color.blue.tokens.json +39 -39
  64. package/src/tokens/constant/color.green.tokens.json +41 -41
  65. package/src/tokens/constant/color.orange.tokens.json +43 -43
  66. package/src/tokens/constant/color.purple.tokens.json +40 -40
  67. package/src/tokens/constant/color.red.tokens.json +44 -44
  68. package/src/tokens/contextual/avatar.tokens.json +13 -13
  69. package/src/tokens/contextual/button.tokens.json +22 -22
  70. package/src/tokens/contextual/chart.tokens.json +3 -3
  71. package/src/tokens/semantic/action.tokens.json +18 -18
  72. package/src/utils/confetti/confetti.js +191 -0
  73. package/src/utils/confetti/constants.js +42 -0
  74. package/src/utils/confetti/field.js +134 -0
  75. package/src/utils/confetti/palette.js +15 -0
  76. package/src/utils/confetti/particles.js +98 -0
  77. package/src/utils/matrix/columns.js +53 -0
  78. package/src/utils/matrix/constants.js +19 -0
  79. package/src/utils/matrix/matrix.js +185 -0
  80. package/src/utils/matrix/palette.js +18 -0
  81. package/src/utils.js +2 -0
  82. package/src/vendor/bootstrap-vue/src/components/popover/helpers/bv-popover-template.js +7 -2
  83. package/src/vendor/bootstrap-vue/src/components/tooltip/helpers/bv-tooltip-template.js +2 -1
  84. package/src/vendor/bootstrap-vue/src/constants/components.js +0 -3
  85. package/translations.js +1 -1
  86. package/dist/vendor/bootstrap-vue/src/components/form-select/form-select-option-group.js +0 -51
  87. package/dist/vendor/bootstrap-vue/src/components/form-select/form-select-option.js +0 -41
  88. package/dist/vendor/bootstrap-vue/src/components/form-select/form-select.js +0 -153
  89. package/dist/vendor/bootstrap-vue/src/components/form-select/helpers/mixin-options.js +0 -63
  90. package/dist/vendor/bootstrap-vue/src/components/form-select/index.js +0 -3
  91. package/src/vendor/bootstrap-vue/src/components/form-select/form-select-option-group.js +0 -46
  92. package/src/vendor/bootstrap-vue/src/components/form-select/form-select-option.js +0 -35
  93. package/src/vendor/bootstrap-vue/src/components/form-select/form-select.js +0 -156
  94. package/src/vendor/bootstrap-vue/src/components/form-select/helpers/mixin-options.js +0 -60
  95. package/src/vendor/bootstrap-vue/src/components/form-select/index.js +0 -5
@@ -0,0 +1,42 @@
1
+ export const DEFAULT_COUNT = 168;
2
+ export const MIN_AUTO_COUNT = 36;
3
+ export const AREA_EXPONENT = 0.4;
4
+ export const DEFAULT_DURATION = 3000;
5
+ export const FADE_OUT_DURATION = 600;
6
+ export const CANVAS_Z_INDEX = 9999;
7
+ export const MAX_FRAME_DELTA = 50;
8
+
9
+ export const EDGE_ANGLE = (54 * Math.PI) / 180;
10
+ export const POINT_ANGLE = Math.PI / 2;
11
+ export const POINT_POWER = 0.8;
12
+ export const MIN_REACH = 0.04;
13
+ export const REACH_HEADROOM = 1.3;
14
+
15
+ export const BAYER = [
16
+ [0, 8, 2, 10],
17
+ [12, 4, 14, 6],
18
+ [3, 11, 1, 9],
19
+ [15, 7, 13, 5],
20
+ ];
21
+
22
+ export const CONFIG = {
23
+ burstWindow: 220,
24
+ edgeSpread: 46,
25
+ pointSpread: 75,
26
+ aimJitter: 5,
27
+ drag: 0.0022,
28
+ gravity: 0.0005,
29
+ cell: 10,
30
+ fringeCells: 2,
31
+ blobCells: 1.4,
32
+ blobCellRange: 2,
33
+ stretch: 1.6,
34
+ stretchRange: 1.4,
35
+ peak: 0.55,
36
+ peakRange: 0.45,
37
+ falloff: 1.3,
38
+ decayMin: 0.45,
39
+ pixelFloor: 0.5,
40
+ pixelFade: 0.6,
41
+ pixelMin: 2,
42
+ };
@@ -0,0 +1,134 @@
1
+ import { CONFIG, BAYER } from './constants';
2
+ import { FRINGE_KEYS } from './palette';
3
+
4
+ const SPAN = BAYER.length;
5
+ const LEVELS = SPAN * SPAN;
6
+
7
+ export const createField = ({ ramp, duration }) => {
8
+ const last = ramp.length - 1;
9
+
10
+ let columns = 0;
11
+ let rows = 0;
12
+ let coverage = new Float32Array(0);
13
+ let sizes = new Float32Array(0);
14
+ let fromColumn = 0;
15
+ let toColumn = -1;
16
+ let fromRow = 0;
17
+ let toRow = -1;
18
+
19
+ const valueAt = (column, row) =>
20
+ column < 0 || column >= columns ? 0 : coverage[row * columns + column];
21
+
22
+ const thresholdAt = (column, row) => BAYER[row % SPAN][column % SPAN] / LEVELS;
23
+
24
+ const fringeKey = (column, row, threshold) =>
25
+ (valueAt(column - CONFIG.fringeCells, row) > threshold ? 1 : 0) +
26
+ (valueAt(column, row) > threshold ? 2 : 0) +
27
+ (valueAt(column + CONFIG.fringeCells, row) > threshold ? 4 : 0);
28
+
29
+ const fringeColor = (column, row, threshold) => {
30
+ const index = FRINGE_KEYS[fringeKey(column, row, threshold)];
31
+
32
+ return index === null ? null : ramp[Math.min(last, index)];
33
+ };
34
+
35
+ const coverageColor = (value) => ramp[Math.min(last, Math.floor(value * ramp.length))];
36
+
37
+ const pixelSize = (index) => Math.max(CONFIG.pixelMin, Math.round(CONFIG.cell * sizes[index]));
38
+
39
+ const resize = (stage) => {
40
+ const nextColumns = Math.ceil(stage.width / CONFIG.cell) + 1;
41
+ const nextRows = Math.ceil(stage.height / CONFIG.cell) + 1;
42
+
43
+ if (nextColumns !== columns || nextRows !== rows) {
44
+ columns = nextColumns;
45
+ rows = nextRows;
46
+ coverage = new Float32Array(columns * rows);
47
+ sizes = new Float32Array(columns * rows);
48
+ } else {
49
+ coverage.fill(0);
50
+ }
51
+
52
+ fromColumn = columns;
53
+ toColumn = -1;
54
+ fromRow = rows;
55
+ toRow = -1;
56
+ };
57
+
58
+ const stamp = (piece, elapsed) => {
59
+ const age = (elapsed - piece.delay) / (duration * piece.decayFrom);
60
+ const strength = piece.peak * Math.max(0, 1 - age);
61
+
62
+ if (strength <= 0) {
63
+ return;
64
+ }
65
+
66
+ const fade = 1 - CONFIG.pixelFade * age;
67
+ const near = CONFIG.pixelFloor + piece.depth * (1 - CONFIG.pixelFloor);
68
+ const size = near * fade;
69
+ const radius = piece.radius * fade;
70
+ const { stretch } = piece;
71
+ const centerX = piece.x / CONFIG.cell;
72
+ const centerY = piece.y / CONFIG.cell;
73
+ const speed = Math.hypot(piece.velocityX, piece.velocityY) || 1;
74
+ const alongX = piece.velocityX / speed;
75
+ const alongY = piece.velocityY / speed;
76
+ const reach = radius * stretch;
77
+ const fromX = Math.max(0, Math.ceil(centerX - reach));
78
+ const toX = Math.min(columns - 1, Math.floor(centerX + reach));
79
+ const fromY = Math.max(0, Math.ceil(centerY - reach));
80
+ const toY = Math.min(rows - 1, Math.floor(centerY + reach));
81
+
82
+ fromColumn = Math.min(fromColumn, fromX);
83
+ toColumn = Math.max(toColumn, toX);
84
+ fromRow = Math.min(fromRow, fromY);
85
+ toRow = Math.max(toRow, toY);
86
+
87
+ for (let row = fromY; row <= toY; row += 1) {
88
+ const deltaY = row - centerY;
89
+
90
+ for (let column = fromX; column <= toX; column += 1) {
91
+ const deltaX = column - centerX;
92
+ const along = (deltaX * alongX + deltaY * alongY) / stretch;
93
+ const across = deltaX * alongY - deltaY * alongX;
94
+ const distance = Math.hypot(along, across) / radius;
95
+
96
+ if (distance < 1) {
97
+ const index = row * columns + column;
98
+ const value = strength * (1 - distance) ** CONFIG.falloff;
99
+
100
+ if (value > coverage[index]) {
101
+ coverage[index] = value;
102
+ sizes[index] = size;
103
+ }
104
+ }
105
+ }
106
+ }
107
+ };
108
+
109
+ const paint = (drawBlock) => {
110
+ for (let row = fromRow; row <= toRow; row += 1) {
111
+ for (let column = fromColumn; column <= toColumn; column += 1) {
112
+ const index = row * columns + column;
113
+ const threshold = thresholdAt(column, row);
114
+ const value = coverage[index];
115
+
116
+ if (value <= threshold) {
117
+ continue;
118
+ }
119
+
120
+ const size = pixelSize(index);
121
+ const inset = Math.round((CONFIG.cell - size) / 2);
122
+
123
+ drawBlock({
124
+ x: column * CONFIG.cell + inset,
125
+ y: row * CONFIG.cell + inset,
126
+ size,
127
+ color: fringeColor(column, row, threshold) ?? coverageColor(value),
128
+ });
129
+ }
130
+ }
131
+ };
132
+
133
+ return { resize, stamp, paint };
134
+ };
@@ -0,0 +1,15 @@
1
+ import {
2
+ GL_COLOR_BRAND_PURPLE_02P,
3
+ GL_COLOR_RED_500,
4
+ GL_COLOR_BRAND_ORANGE_02P,
5
+ GL_COLOR_BRAND_ORANGE_01P,
6
+ } from '../../tokens/build/js/tokens';
7
+
8
+ export const COVERAGE_RAMP = [
9
+ GL_COLOR_BRAND_PURPLE_02P,
10
+ GL_COLOR_RED_500,
11
+ GL_COLOR_BRAND_ORANGE_02P,
12
+ GL_COLOR_BRAND_ORANGE_01P,
13
+ ];
14
+
15
+ export const FRINGE_KEYS = [null, null, 0, 1, null, 2, 3, null];
@@ -0,0 +1,98 @@
1
+ import {
2
+ CONFIG,
3
+ DEFAULT_COUNT,
4
+ MIN_AUTO_COUNT,
5
+ AREA_EXPONENT,
6
+ EDGE_ANGLE,
7
+ POINT_ANGLE,
8
+ POINT_POWER,
9
+ MIN_REACH,
10
+ REACH_HEADROOM,
11
+ } from './constants';
12
+
13
+ const randomBetween = (min, max) => min + Math.random() * (max - min);
14
+
15
+ const degrees = (value) => (value * Math.PI) / 180;
16
+
17
+ const aimJitter = () => randomBetween(-degrees(CONFIG.aimJitter), degrees(CONFIG.aimJitter));
18
+
19
+ const countFor = (stage) => {
20
+ const share = (stage.width * stage.height) / (window.innerWidth * window.innerHeight);
21
+
22
+ return Math.round(Math.max(MIN_AUTO_COUNT, DEFAULT_COUNT * share ** AREA_EXPONENT));
23
+ };
24
+
25
+ const launchFromEdges = (stage, index) => {
26
+ const fromLeft = index % 2 === 0;
27
+
28
+ return {
29
+ x: fromLeft ? -10 : stage.width + 10,
30
+ y: stage.height + 10,
31
+ aim: Math.max(EDGE_ANGLE, Math.atan2(stage.height, stage.width)),
32
+ spread: degrees(CONFIG.edgeSpread),
33
+ direction: fromLeft ? 1 : -1,
34
+ power: 1,
35
+ };
36
+ };
37
+
38
+ const launchFromPoint = (origin) => ({
39
+ x: origin.x,
40
+ y: origin.y,
41
+ aim: POINT_ANGLE,
42
+ spread: degrees(CONFIG.pointSpread),
43
+ direction: 1,
44
+ power: POINT_POWER,
45
+ });
46
+
47
+ const createPiece = ({ stage, origin, index, jitter, maxSpeed }) => {
48
+ const launch = origin ? launchFromPoint(origin) : launchFromEdges(stage, index);
49
+ const depth = Math.random();
50
+ const reach = Math.sqrt(randomBetween(MIN_REACH, 1));
51
+ const speed = maxSpeed * launch.power * reach * (0.85 + depth * 0.2);
52
+ const angle = launch.aim + jitter + randomBetween(-launch.spread, launch.spread);
53
+
54
+ return {
55
+ depth,
56
+ x: launch.x,
57
+ y: launch.y,
58
+ delay: randomBetween(0, CONFIG.burstWindow),
59
+ radius: CONFIG.blobCells + depth * CONFIG.blobCellRange,
60
+ stretch: CONFIG.stretch + Math.random() * CONFIG.stretchRange,
61
+ peak: CONFIG.peak + depth * CONFIG.peakRange,
62
+ decayFrom: randomBetween(CONFIG.decayMin, 1),
63
+ velocityX: Math.cos(angle) * speed * launch.direction,
64
+ velocityY: -Math.sin(angle) * speed,
65
+ swayAmplitude: randomBetween(0.02, 0.08) * (1.3 - depth * 0.5),
66
+ swayFrequency: randomBetween(0.001, 0.003),
67
+ swayPhase: Math.random() * Math.PI * 2,
68
+ };
69
+ };
70
+
71
+ export const createPieces = ({ stage, origin, count }) => {
72
+ const travel = Math.max(Math.hypot(stage.width, stage.height), stage.height * REACH_HEADROOM);
73
+ const maxSpeed = travel * CONFIG.drag;
74
+ const jitter = aimJitter();
75
+
76
+ return Array.from({ length: count ?? countFor(stage) }, (value, index) =>
77
+ createPiece({ stage, origin, index, jitter, maxSpeed }),
78
+ );
79
+ };
80
+
81
+ export const advancePiece = (piece, { elapsed, delta }) => {
82
+ if (elapsed < piece.delay) {
83
+ return piece;
84
+ }
85
+
86
+ const drag = Math.exp(-CONFIG.drag * delta);
87
+ const velocityX = piece.velocityX * drag;
88
+ const velocityY = (piece.velocityY + CONFIG.gravity * delta) * drag;
89
+ const sway = Math.sin(piece.swayPhase + elapsed * piece.swayFrequency) * piece.swayAmplitude;
90
+
91
+ return {
92
+ ...piece,
93
+ velocityX,
94
+ velocityY,
95
+ x: piece.x + (velocityX + sway) * delta,
96
+ y: piece.y + velocityY * delta,
97
+ };
98
+ };
@@ -0,0 +1,53 @@
1
+ import { GLYPHS, CONFIG } from './constants';
2
+
3
+ const randomBetween = (min, max) => min + Math.random() * (max - min);
4
+
5
+ const sample = (values) => values[Math.floor(Math.random() * values.length)];
6
+
7
+ export const glyph = () => sample(GLYPHS);
8
+
9
+ export const measureGrid = ({ width, height }) => ({
10
+ across: Math.ceil(width / CONFIG.cell),
11
+ rows: Math.ceil(height / CONFIG.cell),
12
+ });
13
+
14
+ export const createColumns = (stage, colors) => {
15
+ const { across, rows } = measureGrid(stage);
16
+
17
+ return Array.from({ length: across }, (value, column) => ({
18
+ column,
19
+ rows,
20
+ row: -randomBetween(0, CONFIG.startSpread),
21
+ speed: randomBetween(CONFIG.minSpeed, CONFIG.maxSpeed),
22
+ color: sample(colors),
23
+ head: null,
24
+ steps: [],
25
+ })).filter(() => Math.random() < CONFIG.columnShare);
26
+ };
27
+
28
+ export const advanceColumn = (column, delta) => {
29
+ if (column.row > column.rows + CONFIG.restartAfter) {
30
+ return {
31
+ ...column,
32
+ row: -randomBetween(0, CONFIG.restartSpread),
33
+ head: null,
34
+ steps: [],
35
+ };
36
+ }
37
+
38
+ const row = column.row + column.speed * delta;
39
+ const from = Math.max(0, Math.ceil(column.row));
40
+ const to = Math.min(column.rows, Math.floor(row));
41
+ const steps = [];
42
+
43
+ for (let step = from; step <= to; step += 1) {
44
+ steps.push(step);
45
+ }
46
+
47
+ return {
48
+ ...column,
49
+ row,
50
+ head: steps.length ? steps.at(-1) : column.head,
51
+ steps,
52
+ };
53
+ };
@@ -0,0 +1,19 @@
1
+ export const GLYPHS = ['G', 'L'];
2
+ export const FONT = 'ui-monospace, SFMono-Regular, Menlo, monospace';
3
+
4
+ export const DEFAULT_DURATION = 6000;
5
+ export const FADE_OUT_DURATION = 900;
6
+ export const CANVAS_Z_INDEX = 9999;
7
+ export const MAX_FRAME_DELTA = 50;
8
+ export const RUNNING_ATTRIBUTE = 'data-matrix';
9
+
10
+ export const CONFIG = {
11
+ cell: 16,
12
+ trail: 0.0016,
13
+ minSpeed: 0.004,
14
+ maxSpeed: 0.014,
15
+ columnShare: 0.72,
16
+ startSpread: 30,
17
+ restartSpread: 10,
18
+ restartAfter: 3,
19
+ };
@@ -0,0 +1,185 @@
1
+ import { resolveColors } from './palette';
2
+ import { createColumns, advanceColumn, glyph, measureGrid } from './columns';
3
+ import {
4
+ CONFIG,
5
+ FONT,
6
+ DEFAULT_DURATION,
7
+ FADE_OUT_DURATION,
8
+ CANVAS_Z_INDEX,
9
+ MAX_FRAME_DELTA,
10
+ RUNNING_ATTRIBUTE,
11
+ } from './constants';
12
+
13
+ const noop = () => {};
14
+
15
+ const measureStage = (boundary) => {
16
+ const rect =
17
+ boundary instanceof Element
18
+ ? boundary.getBoundingClientRect()
19
+ : { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight };
20
+
21
+ return { x: rect.left, y: rect.top, width: rect.width, height: rect.height };
22
+ };
23
+
24
+ const createCanvas = () => {
25
+ const canvas = document.createElement('canvas');
26
+
27
+ canvas.setAttribute('aria-hidden', 'true');
28
+ canvas.setAttribute(RUNNING_ATTRIBUTE, '');
29
+ Object.assign(canvas.style, {
30
+ position: 'fixed',
31
+ inset: '0',
32
+ width: '100%',
33
+ height: '100%',
34
+ pointerEvents: 'none',
35
+ zIndex: String(CANVAS_Z_INDEX),
36
+ });
37
+
38
+ return canvas;
39
+ };
40
+
41
+ /**
42
+ * Rains `G` and `L` glyphs down the screen, then cleans up after itself.
43
+ *
44
+ * Every option has a default, so `matrix()` on its own rains over the whole viewport. Pass
45
+ * `boundary` to keep the rain inside an element. Each column falls at its own speed in one color
46
+ * from the brand ramp, with a head glyph in the default text color and a trail that fades behind it.
47
+ *
48
+ * Only one run happens at a time: a call made while another is still on screen does nothing and
49
+ * returns a no-op.
50
+ *
51
+ * Does nothing when the user prefers reduced motion, or outside a browser.
52
+ *
53
+ * The canvas is `aria-hidden`, so nobody using a screen reader will know it ran. When the rain is
54
+ * the only sign that something happened, the caller has to convey that in the accessibility tree
55
+ * as well.
56
+ *
57
+ * @param {Object} [options]
58
+ * @param {Number} [options.duration=6000] How long the rain runs, in milliseconds.
59
+ * @param {String[]} [options.colors] CSS colors for the columns, picked at random one per column.
60
+ * Defaults to the brand orange and purple and the red color tokens. The head glyph's text color
61
+ * resolves against `boundary` when given, so a `.gl-dark-scope` ancestor is honored.
62
+ * @param {Element} [options.boundary] Element to confine the rain to. Defaults to the viewport.
63
+ * @example
64
+ * const stop = matrix({ boundary: terminal, duration: 4000 });
65
+ * @returns {Function} Stops the rain and removes the canvas early.
66
+ */
67
+ export const matrix = ({ duration = DEFAULT_DURATION, colors, boundary } = {}) => {
68
+ if (
69
+ typeof window === 'undefined' ||
70
+ window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ||
71
+ document.querySelector(`[${RUNNING_ATTRIBUTE}]`)
72
+ ) {
73
+ return noop;
74
+ }
75
+
76
+ const canvas = createCanvas();
77
+ const context = canvas.getContext('2d');
78
+
79
+ if (!context) {
80
+ return noop;
81
+ }
82
+
83
+ const stage = measureStage(boundary);
84
+
85
+ const resize = () => {
86
+ const ratio = window.devicePixelRatio || 1;
87
+
88
+ canvas.width = window.innerWidth * ratio;
89
+ canvas.height = window.innerHeight * ratio;
90
+ context.setTransform(ratio, 0, 0, ratio, 0, 0);
91
+ };
92
+
93
+ const { head, rain } = resolveColors(
94
+ colors,
95
+ boundary instanceof Element ? boundary : document.documentElement,
96
+ );
97
+ let columns = createColumns(stage, rain);
98
+
99
+ const erase = (delta) => {
100
+ context.globalCompositeOperation = 'destination-out';
101
+ context.fillStyle = `rgba(0, 0, 0, ${1 - Math.exp(-CONFIG.trail * delta)})`;
102
+ context.fillRect(0, 0, stage.width, stage.height);
103
+ context.globalCompositeOperation = 'source-over';
104
+ };
105
+
106
+ const paintColumn = (column, previousHead) => {
107
+ const x = column.column * CONFIG.cell;
108
+
109
+ if (previousHead !== null) {
110
+ context.fillStyle = column.color;
111
+ context.fillText(glyph(), x, previousHead * CONFIG.cell);
112
+ }
113
+
114
+ column.steps.forEach((row, index) => {
115
+ context.fillStyle = index === column.steps.length - 1 ? head : column.color;
116
+ context.fillText(glyph(), x, row * CONFIG.cell);
117
+ });
118
+ };
119
+
120
+ let frame = null;
121
+ let startedAt = null;
122
+ let previousAt = null;
123
+
124
+ const stop = () => {
125
+ if (frame !== null) {
126
+ window.cancelAnimationFrame(frame);
127
+ frame = null;
128
+ }
129
+ window.removeEventListener('resize', resize);
130
+ canvas.remove();
131
+ };
132
+
133
+ const render = (now) => {
134
+ startedAt ??= now;
135
+ const elapsed = now - startedAt;
136
+ const delta = Math.min(now - (previousAt ?? now), MAX_FRAME_DELTA);
137
+ previousAt = now;
138
+
139
+ if (elapsed >= duration) {
140
+ stop();
141
+ return;
142
+ }
143
+
144
+ const grid = measureGrid(stage);
145
+ Object.assign(stage, measureStage(boundary));
146
+ const nextGrid = measureGrid(stage);
147
+
148
+ if (nextGrid.across !== grid.across || nextGrid.rows !== grid.rows) {
149
+ columns = createColumns(stage, rain);
150
+ }
151
+
152
+ canvas.style.opacity = String(Math.min(1, (duration - elapsed) / FADE_OUT_DURATION));
153
+
154
+ context.save();
155
+ context.beginPath();
156
+ context.rect(stage.x, stage.y, stage.width, stage.height);
157
+ context.clip();
158
+ context.translate(stage.x, stage.y);
159
+
160
+ erase(delta);
161
+ context.font = `${CONFIG.cell}px ${FONT}`;
162
+ context.textBaseline = 'top';
163
+
164
+ columns = columns.map((column) => {
165
+ const next = advanceColumn(column, delta);
166
+
167
+ if (next.steps.length) {
168
+ paintColumn(next, column.head);
169
+ }
170
+
171
+ return next;
172
+ });
173
+
174
+ context.restore();
175
+
176
+ frame = window.requestAnimationFrame(render);
177
+ };
178
+
179
+ resize();
180
+ window.addEventListener('resize', resize);
181
+ document.body.append(canvas);
182
+ frame = window.requestAnimationFrame(render);
183
+
184
+ return stop;
185
+ };
@@ -0,0 +1,18 @@
1
+ import {
2
+ GL_COLOR_BRAND_ORANGE_01P,
3
+ GL_COLOR_BRAND_ORANGE_02P,
4
+ GL_COLOR_BRAND_PURPLE_01P,
5
+ GL_COLOR_RED_500,
6
+ } from '../../tokens/build/js/tokens';
7
+
8
+ const MATRIX_COLORS = [
9
+ GL_COLOR_BRAND_ORANGE_02P,
10
+ GL_COLOR_BRAND_ORANGE_01P,
11
+ GL_COLOR_RED_500,
12
+ GL_COLOR_BRAND_PURPLE_01P,
13
+ ];
14
+
15
+ export const resolveColors = (colors, element) => ({
16
+ head: window.getComputedStyle(element).getPropertyValue('--gl-text-color-default').trim(),
17
+ rain: colors?.length ? colors : MATRIX_COLORS,
18
+ });
package/src/utils.js CHANGED
@@ -2,3 +2,5 @@ export { GlBreakpointInstance, breakpoints } from './utils/breakpoints';
2
2
 
3
3
  export * as formValidators from './components/base/form/form_fields/validators';
4
4
  export * as formMappers from './components/base/form/form_fields/mappers';
5
+ export { matrix } from './utils/matrix/matrix';
6
+ export { confetti } from './utils/confetti/confetti';
@@ -46,11 +46,16 @@ export const BVPopoverTemplate = /*#__PURE__*/ extend({
46
46
  domProps: titleDomProps,
47
47
  attrs: { role: 'presentation' }
48
48
  },
49
- [$title]
49
+ // `innerHTML` overrides children, so avoid passing both — Vue 3 warns otherwise
50
+ titleDomProps.innerHTML ? [] : [$title]
50
51
  ),
51
52
  isUndefinedOrNull($content) || $content === ''
52
53
  ? /* istanbul ignore next */ h()
53
- : h('div', { staticClass: 'popover-body', domProps: contentDomProps }, [$content])
54
+ : h(
55
+ 'div',
56
+ { staticClass: 'popover-body', domProps: contentDomProps },
57
+ contentDomProps.innerHTML ? [] : [$content]
58
+ )
54
59
  ]
55
60
  )
56
61
  }
@@ -130,7 +130,8 @@ export const BVTooltipTemplate = /*#__PURE__*/ extend({
130
130
  staticClass: 'tooltip-inner',
131
131
  domProps
132
132
  },
133
- [$title]
133
+ // `innerHTML` overrides children, so avoid passing both — Vue 3 warns otherwise
134
+ domProps.innerHTML ? [] : [$title]
134
135
  )
135
136
  ]
136
137
  )
@@ -14,9 +14,6 @@ export const NAME_FORM = 'BForm'
14
14
  export const NAME_FORM_GROUP = 'BFormGroup'
15
15
  export const NAME_FORM_INVALID_FEEDBACK = 'BFormInvalidFeedback'
16
16
  export const NAME_FORM_ROW = 'BFormRow'
17
- export const NAME_FORM_SELECT = 'BFormSelect'
18
- export const NAME_FORM_SELECT_OPTION = 'BFormSelectOption'
19
- export const NAME_FORM_SELECT_OPTION_GROUP = 'BFormSelectOptionGroup'
20
17
  export const NAME_FORM_TEXT = 'BFormText'
21
18
  export const NAME_FORM_VALID_FEEDBACK = 'BFormValidFeedback'
22
19
  export const NAME_LINK = 'BLink'
package/translations.js CHANGED
@@ -1,4 +1,4 @@
1
- /* eslint-disable import/no-default-export */
1
+ /* eslint-disable import-x/no-default-export */
2
2
  export default {
3
3
  'ClearIconButton.title': 'Clear',
4
4
  'ClipboardButton.copied': 'Copied',
@@ -1,51 +0,0 @@
1
- import { extend } from '../../vue';
2
- import { NAME_FORM_SELECT_OPTION_GROUP } from '../../constants/components';
3
- import { SLOT_NAME_FIRST } from '../../constants/slots';
4
- import { htmlOrText } from '../../utils/html';
5
- import { sortKeys } from '../../utils/object';
6
- import { props as props$1, formOptionsMixin } from '../../mixins/form-options';
7
- import { normalizeSlotMixin } from '../../mixins/normalize-slot';
8
- import { BFormSelectOption } from './form-select-option';
9
-
10
- // --- Props ---
11
-
12
- const props = sortKeys({
13
- ...props$1,
14
- label: {
15
- type: String,
16
- required: true
17
- }
18
- });
19
-
20
- // --- Main component ---
21
-
22
- // @vue/component
23
- const BFormSelectOptionGroup = /*#__PURE__*/extend({
24
- name: NAME_FORM_SELECT_OPTION_GROUP,
25
- mixins: [normalizeSlotMixin, formOptionsMixin],
26
- props,
27
- render(h) {
28
- const label = this.label;
29
- const $options = this.formOptions.map((option, index) => {
30
- const value = option.value,
31
- text = option.text,
32
- html = option.html,
33
- disabled = option.disabled;
34
- return h(BFormSelectOption, {
35
- attrs: {
36
- value,
37
- disabled
38
- },
39
- domProps: htmlOrText(html, text),
40
- key: `option_${index}`
41
- });
42
- });
43
- return h('optgroup', {
44
- attrs: {
45
- label
46
- }
47
- }, [this.normalizeSlot(SLOT_NAME_FIRST), $options, this.normalizeSlot()]);
48
- }
49
- });
50
-
51
- export { BFormSelectOptionGroup, props };