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