@cntrl-site/sdk-nextjs 1.8.40 → 1.9.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/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/modules.xml +8 -0
- package/.idea/sdk-nextjs.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/lib/components/items/FileItem/ImageItem.js +49 -22
- package/lib/components/items/FileItem/VideoItem.js +48 -21
- package/lib/components/items/FileItem/useFileItem.js +12 -5
- package/lib/components/items/RectangleItem/RectangleItem.js +78 -22
- package/lib/components/items/RectangleItem/useRectangleItem.js +15 -8
- package/lib/interactions/CSSPropertyNameMap.js +18 -18
- package/lib/utils/Animator/Animator.js +171 -19
- package/lib/utils/areFillsVisible/areFillsVisible.js +23 -0
- package/lib/utils/getFill.js +43 -0
- package/package.json +2 -2
- package/src/components/items/CodeEmbedItem/CodeEmbedItem.tsx +1 -1
- package/src/components/items/ComponentItem/ComponentItem.tsx +1 -1
- package/src/components/items/CompoundItem/CompoundChild.tsx +2 -2
- package/src/components/items/CompoundItem/CompoundItem.tsx +1 -1
- package/src/components/items/CustomItem/CustomItem.tsx +1 -1
- package/src/components/items/EmbedVideoItem/VimeoEmbed.tsx +2 -2
- package/src/components/items/EmbedVideoItem/YoutubeEmbed.tsx +2 -2
- package/src/components/items/FileItem/ImageItem.tsx +63 -10
- package/src/components/items/FileItem/VideoItem.tsx +64 -11
- package/src/components/items/FileItem/useFileItem.ts +14 -6
- package/src/components/items/GroupItem/GroupItem.tsx +1 -1
- package/src/components/items/Item.tsx +2 -2
- package/src/components/items/RectangleItem/RectangleItem.tsx +126 -24
- package/src/components/items/RectangleItem/useRectangleItem.ts +17 -10
- package/src/components/items/RichTextItem/RichTextItem.tsx +5 -5
- package/src/interactions/CSSPropertyNameMap.ts +18 -19
- package/src/interactions/ItemInteractionCtrl.ts +4 -4
- package/src/interactions/types.ts +7 -7
- package/src/utils/Animator/Animator.ts +227 -27
- package/src/utils/areFillsVisible/areFillsVisible.test.ts +63 -0
- package/src/utils/areFillsVisible/areFillsVisible.ts +37 -0
- package/src/utils/getFill.ts +46 -0
- package/src/utils/getStyleFromItemStateAndParams.ts +2 -2
- package/src/provider/InteractionsContext.old.tsx +0 -66
- package/src/provider/InteractionsContext.test.tsx +0 -97
|
@@ -69,35 +69,27 @@ class Animator {
|
|
|
69
69
|
top: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.top, end.value.top, true)
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
const keyframes = this.keyframesMap[sdk_1.KeyframeType.
|
|
72
|
+
getBorderFill(values, pos) {
|
|
73
|
+
const keyframes = this.keyframesMap[sdk_1.KeyframeType.BorderFill];
|
|
74
74
|
if (!keyframes || !keyframes.length)
|
|
75
75
|
return values;
|
|
76
76
|
if (keyframes.length === 1) {
|
|
77
77
|
const [keyframe] = keyframes;
|
|
78
|
-
return
|
|
79
|
-
color: keyframe.value.color
|
|
80
|
-
};
|
|
78
|
+
return keyframe.value;
|
|
81
79
|
}
|
|
82
80
|
const { start, end } = this.getStartEnd(pos, keyframes);
|
|
83
|
-
return
|
|
84
|
-
color: this.getRangeColor(start, end, pos)
|
|
85
|
-
};
|
|
81
|
+
return this.getRangeGradient(start, end, pos);
|
|
86
82
|
}
|
|
87
|
-
|
|
88
|
-
const keyframes = this.keyframesMap[sdk_1.KeyframeType.
|
|
83
|
+
getFill(values, pos) {
|
|
84
|
+
const keyframes = this.keyframesMap[sdk_1.KeyframeType.Fill];
|
|
89
85
|
if (!keyframes || !keyframes.length)
|
|
90
86
|
return values;
|
|
91
87
|
if (keyframes.length === 1) {
|
|
92
88
|
const [keyframe] = keyframes;
|
|
93
|
-
return
|
|
94
|
-
color: keyframe.value.color
|
|
95
|
-
};
|
|
89
|
+
return keyframe.value;
|
|
96
90
|
}
|
|
97
91
|
const { start, end } = this.getStartEnd(pos, keyframes);
|
|
98
|
-
return
|
|
99
|
-
color: this.getRangeColor(start, end, pos)
|
|
100
|
-
};
|
|
92
|
+
return this.getRangeGradient(start, end, pos);
|
|
101
93
|
}
|
|
102
94
|
getRadius(values, pos) {
|
|
103
95
|
const keyframes = this.keyframesMap[sdk_1.KeyframeType.BorderRadius];
|
|
@@ -268,6 +260,166 @@ class Animator {
|
|
|
268
260
|
const mixedColor = startColor.mix(endColor, rangeAmount);
|
|
269
261
|
return mixedColor.fmt('oklch');
|
|
270
262
|
}
|
|
263
|
+
getRangeGradient(start, end, position) {
|
|
264
|
+
const rangeAmount = (0, rangeMap_1.rangeMap)(position, start.position, end.position, 0, 1, true);
|
|
265
|
+
const allLayerIds = new Set([
|
|
266
|
+
...start.value.map(layer => layer.id),
|
|
267
|
+
...end.value.map(layer => layer.id)
|
|
268
|
+
]);
|
|
269
|
+
const result = [];
|
|
270
|
+
for (const layerId of allLayerIds) {
|
|
271
|
+
const startLayers = start.value.find(layer => layer.id === layerId);
|
|
272
|
+
const endLayers = end.value.find(layer => layer.id === layerId);
|
|
273
|
+
const startLayersArray = Array.isArray(startLayers) ? startLayers : startLayers ? [startLayers] : [];
|
|
274
|
+
const endLayersArray = Array.isArray(endLayers) ? endLayers : endLayers ? [endLayers] : [];
|
|
275
|
+
if (startLayersArray.length > 0 && endLayersArray.length === 0) {
|
|
276
|
+
result.push(...startLayersArray);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (startLayersArray.length === 0 && endLayersArray.length > 0) {
|
|
280
|
+
result.push(...endLayersArray);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (startLayersArray.length > 0 && endLayersArray.length > 0) {
|
|
284
|
+
result.push(...this.interpolateFillLayerArray(startLayersArray, endLayersArray, rangeAmount));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
interpolateFillLayerArray(startLayers, endLayers, rangeAmount) {
|
|
290
|
+
const startLayerMap = new Map(startLayers.map(layer => [layer.id, layer]));
|
|
291
|
+
const endLayerMap = new Map(endLayers.map(layer => [layer.id, layer]));
|
|
292
|
+
const allLayerIds = new Set([
|
|
293
|
+
...startLayers.map(layer => layer.id),
|
|
294
|
+
...endLayers.map(layer => layer.id)
|
|
295
|
+
]);
|
|
296
|
+
const interpolatedLayers = [];
|
|
297
|
+
for (const layerId of allLayerIds) {
|
|
298
|
+
const startLayer = startLayerMap.get(layerId);
|
|
299
|
+
const endLayer = endLayerMap.get(layerId);
|
|
300
|
+
if (startLayer && !endLayer) {
|
|
301
|
+
interpolatedLayers.push(startLayer);
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
if (!startLayer && endLayer) {
|
|
305
|
+
interpolatedLayers.push(endLayer);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (startLayer && endLayer) {
|
|
309
|
+
interpolatedLayers.push(this.interpolateFillLayer(startLayer, endLayer, rangeAmount));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const result = [];
|
|
313
|
+
for (const startLayer of startLayers) {
|
|
314
|
+
const interpolatedLayer = interpolatedLayers.find(layer => layer.id === startLayer.id);
|
|
315
|
+
if (interpolatedLayer) {
|
|
316
|
+
result.push(interpolatedLayer);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
for (const endLayer of endLayers) {
|
|
320
|
+
if (!startLayerMap.has(endLayer.id)) {
|
|
321
|
+
const interpolatedLayer = interpolatedLayers.find(layer => layer.id === endLayer.id);
|
|
322
|
+
if (interpolatedLayer) {
|
|
323
|
+
result.push(interpolatedLayer);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return result;
|
|
328
|
+
}
|
|
329
|
+
interpolateFillLayer(startLayer, endLayer, rangeAmount) {
|
|
330
|
+
if (startLayer.type !== endLayer.type) {
|
|
331
|
+
return startLayer;
|
|
332
|
+
}
|
|
333
|
+
switch (startLayer.type) {
|
|
334
|
+
case 'solid': {
|
|
335
|
+
const endSolidLayer = endLayer;
|
|
336
|
+
const startColor = color_1.CntrlColor.parse(startLayer.value);
|
|
337
|
+
const endColor = color_1.CntrlColor.parse(endSolidLayer.value);
|
|
338
|
+
const mixedColor = startColor.mix(endColor, rangeAmount);
|
|
339
|
+
return Object.assign(Object.assign({}, startLayer), { value: mixedColor.fmt('oklch') });
|
|
340
|
+
}
|
|
341
|
+
case 'linear-gradient': {
|
|
342
|
+
const endLinearLayer = endLayer;
|
|
343
|
+
const interpolatedColors = this.interpolateColorStops(startLayer.colors, endLinearLayer.colors, rangeAmount);
|
|
344
|
+
const angle = startLayer.angle + (endLinearLayer.angle - startLayer.angle) * rangeAmount;
|
|
345
|
+
const startPoint = [
|
|
346
|
+
startLayer.start[0] + (endLinearLayer.start[0] - startLayer.start[0]) * rangeAmount,
|
|
347
|
+
startLayer.start[1] + (endLinearLayer.start[1] - startLayer.start[1]) * rangeAmount
|
|
348
|
+
];
|
|
349
|
+
const endPoint = [
|
|
350
|
+
startLayer.end[0] + (endLinearLayer.end[0] - startLayer.end[0]) * rangeAmount,
|
|
351
|
+
startLayer.end[1] + (endLinearLayer.end[1] - startLayer.end[1]) * rangeAmount
|
|
352
|
+
];
|
|
353
|
+
return Object.assign(Object.assign({}, startLayer), { colors: interpolatedColors, angle, start: startPoint, end: endPoint });
|
|
354
|
+
}
|
|
355
|
+
case 'radial-gradient': {
|
|
356
|
+
const endRadialLayer = endLayer;
|
|
357
|
+
const interpolatedColors = this.interpolateColorStops(startLayer.colors, endRadialLayer.colors, rangeAmount);
|
|
358
|
+
const angle = startLayer.angle + (endRadialLayer.angle - startLayer.angle) * rangeAmount;
|
|
359
|
+
const center = [
|
|
360
|
+
startLayer.center[0] + (endRadialLayer.center[0] - startLayer.center[0]) * rangeAmount,
|
|
361
|
+
startLayer.center[1] + (endRadialLayer.center[1] - startLayer.center[1]) * rangeAmount
|
|
362
|
+
];
|
|
363
|
+
const diameter = startLayer.diameter + (endRadialLayer.diameter - startLayer.diameter) * rangeAmount;
|
|
364
|
+
return Object.assign(Object.assign({}, startLayer), { colors: interpolatedColors, angle,
|
|
365
|
+
center,
|
|
366
|
+
diameter });
|
|
367
|
+
}
|
|
368
|
+
case 'conic-gradient': {
|
|
369
|
+
const endConicLayer = endLayer;
|
|
370
|
+
const interpolatedColors = this.interpolateColorStops(startLayer.colors, endConicLayer.colors, rangeAmount);
|
|
371
|
+
const angle = startLayer.angle + (endConicLayer.angle - startLayer.angle) * rangeAmount;
|
|
372
|
+
const center = [
|
|
373
|
+
startLayer.center[0] + (endConicLayer.center[0] - startLayer.center[0]) * rangeAmount,
|
|
374
|
+
startLayer.center[1] + (endConicLayer.center[1] - startLayer.center[1]) * rangeAmount
|
|
375
|
+
];
|
|
376
|
+
return Object.assign(Object.assign({}, startLayer), { colors: interpolatedColors, angle,
|
|
377
|
+
center });
|
|
378
|
+
}
|
|
379
|
+
case 'image': {
|
|
380
|
+
const endImageLayer = endLayer;
|
|
381
|
+
const opacity = startLayer.opacity + (endImageLayer.opacity - startLayer.opacity) * rangeAmount;
|
|
382
|
+
const backgroundSize = startLayer.backgroundSize + (endImageLayer.backgroundSize - startLayer.backgroundSize) * rangeAmount;
|
|
383
|
+
return Object.assign(Object.assign({}, startLayer), { opacity,
|
|
384
|
+
backgroundSize });
|
|
385
|
+
}
|
|
386
|
+
default:
|
|
387
|
+
return startLayer;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
interpolateColorStops(startColors, endColors, rangeAmount) {
|
|
391
|
+
const startColorMap = new Map(startColors.map(stop => [stop.id, stop]));
|
|
392
|
+
const endColorMap = new Map(endColors.map(stop => [stop.id, stop]));
|
|
393
|
+
const allStopIds = new Set([
|
|
394
|
+
...startColors.map(stop => stop.id),
|
|
395
|
+
...endColors.map(stop => stop.id)
|
|
396
|
+
]);
|
|
397
|
+
const interpolatedStops = [];
|
|
398
|
+
for (const stopId of allStopIds) {
|
|
399
|
+
const startStop = startColorMap.get(stopId);
|
|
400
|
+
const endStop = endColorMap.get(stopId);
|
|
401
|
+
if (startStop && !endStop) {
|
|
402
|
+
interpolatedStops.push(startStop);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (!startStop && endStop) {
|
|
406
|
+
interpolatedStops.push(endStop);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
if (startStop && endStop) {
|
|
410
|
+
const startColor = color_1.CntrlColor.parse(startStop.value);
|
|
411
|
+
const endColor = color_1.CntrlColor.parse(endStop.value);
|
|
412
|
+
const mixedColor = startColor.mix(endColor, rangeAmount);
|
|
413
|
+
const position = startStop.position + (endStop.position - startStop.position) * rangeAmount;
|
|
414
|
+
interpolatedStops.push({
|
|
415
|
+
id: stopId,
|
|
416
|
+
value: mixedColor.fmt('oklch'),
|
|
417
|
+
position
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return interpolatedStops.sort((a, b) => a.position - b.position);
|
|
422
|
+
}
|
|
271
423
|
}
|
|
272
424
|
exports.Animator = Animator;
|
|
273
425
|
function createKeyframesMap() {
|
|
@@ -276,9 +428,8 @@ function createKeyframesMap() {
|
|
|
276
428
|
[sdk_1.KeyframeType.Position]: [],
|
|
277
429
|
[sdk_1.KeyframeType.BorderWidth]: [],
|
|
278
430
|
[sdk_1.KeyframeType.BorderRadius]: [],
|
|
279
|
-
[sdk_1.KeyframeType.Color]: [],
|
|
280
431
|
[sdk_1.KeyframeType.Rotation]: [],
|
|
281
|
-
[sdk_1.KeyframeType.
|
|
432
|
+
[sdk_1.KeyframeType.BorderFill]: [],
|
|
282
433
|
[sdk_1.KeyframeType.Opacity]: [],
|
|
283
434
|
[sdk_1.KeyframeType.Scale]: [],
|
|
284
435
|
[sdk_1.KeyframeType.Blur]: [],
|
|
@@ -286,6 +437,7 @@ function createKeyframesMap() {
|
|
|
286
437
|
[sdk_1.KeyframeType.LetterSpacing]: [],
|
|
287
438
|
[sdk_1.KeyframeType.WordSpacing]: [],
|
|
288
439
|
[sdk_1.KeyframeType.TextColor]: [],
|
|
289
|
-
[sdk_1.KeyframeType.FXParams]: []
|
|
440
|
+
[sdk_1.KeyframeType.FXParams]: [],
|
|
441
|
+
[sdk_1.KeyframeType.Fill]: []
|
|
290
442
|
};
|
|
291
443
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.areFillsVisible = void 0;
|
|
4
|
+
const color_1 = require("@cntrl-site/color");
|
|
5
|
+
function areFillsVisible(fills) {
|
|
6
|
+
return fills.some(fill => {
|
|
7
|
+
switch (fill.type) {
|
|
8
|
+
case 'solid':
|
|
9
|
+
return color_1.CntrlColor.parse(fill.value).getAlpha() !== 0;
|
|
10
|
+
case 'linear-gradient':
|
|
11
|
+
return fill.colors.some(color => color_1.CntrlColor.parse(color.value).getAlpha() !== 0);
|
|
12
|
+
case 'radial-gradient':
|
|
13
|
+
return fill.colors.some(color => color_1.CntrlColor.parse(color.value).getAlpha() !== 0);
|
|
14
|
+
case 'conic-gradient':
|
|
15
|
+
return fill.colors.some(color => color_1.CntrlColor.parse(color.value).getAlpha() !== 0);
|
|
16
|
+
case 'image':
|
|
17
|
+
return fill.opacity !== 0;
|
|
18
|
+
default:
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
exports.areFillsVisible = areFillsVisible;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFill = void 0;
|
|
4
|
+
function getFill(fill) {
|
|
5
|
+
var _a;
|
|
6
|
+
if (fill.type === 'linear-gradient' && Array.isArray(fill.colors)) {
|
|
7
|
+
return `linear-gradient(${fill.angle}deg, ${fill.colors
|
|
8
|
+
.map(c => `${c.value} ${c.position}%`)
|
|
9
|
+
.join(', ')})`;
|
|
10
|
+
}
|
|
11
|
+
if (fill.type === 'radial-gradient' && Array.isArray(fill.colors)) {
|
|
12
|
+
const center = fill.center
|
|
13
|
+
? `${fill.center[0] * 100}% ${fill.center[1] * 100}%`
|
|
14
|
+
: '50% 50%';
|
|
15
|
+
const diameter = fill.diameter;
|
|
16
|
+
return `radial-gradient(circle ${diameter * 100} at ${center}, ${fill.colors
|
|
17
|
+
.map(c => `${c.value} ${c.position}%`)
|
|
18
|
+
.join(', ')})`;
|
|
19
|
+
}
|
|
20
|
+
if (fill.type === 'conic-gradient' && Array.isArray(fill.colors)) {
|
|
21
|
+
const center = fill.center
|
|
22
|
+
? `${fill.center[0] * 100}% ${fill.center[1] * 100}%`
|
|
23
|
+
: '50% 50%';
|
|
24
|
+
const angle = ((_a = fill.angle) !== null && _a !== void 0 ? _a : 0);
|
|
25
|
+
const hasMultipleStops = fill.colors.length > 1;
|
|
26
|
+
const lastStop = fill.colors[fill.colors.length - 1];
|
|
27
|
+
const shouldAppendWrapStop = hasMultipleStops && typeof lastStop.position === 'number' && lastStop.position < 100;
|
|
28
|
+
const colorsWithWrap = shouldAppendWrapStop
|
|
29
|
+
? [...fill.colors, { value: fill.colors[0].value, position: 100 }]
|
|
30
|
+
: fill.colors;
|
|
31
|
+
return `conic-gradient(from ${angle + 90}deg at ${center}, ${colorsWithWrap
|
|
32
|
+
.map(c => `${c.value} ${c.position}%`)
|
|
33
|
+
.join(', ')})`;
|
|
34
|
+
}
|
|
35
|
+
if (fill.type === 'image' && fill.src) {
|
|
36
|
+
return `url(${fill.src})`;
|
|
37
|
+
}
|
|
38
|
+
if (fill.type === 'solid') {
|
|
39
|
+
return fill.value;
|
|
40
|
+
}
|
|
41
|
+
return 'transparent';
|
|
42
|
+
}
|
|
43
|
+
exports.getFill = getFill;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cntrl-site/sdk-nextjs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "SDK for Next.js",
|
|
5
5
|
"author": "arsen@momdesign.nyc",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@antfu/eslint-config": "^3.8.0",
|
|
32
32
|
"@cntrl-site/color": "^1.0.0",
|
|
33
33
|
"@cntrl-site/effects": "^1.4.0",
|
|
34
|
-
"@cntrl-site/sdk": "^1.
|
|
34
|
+
"@cntrl-site/sdk": "^1.24.0",
|
|
35
35
|
"@types/vimeo__player": "^2.18.0",
|
|
36
36
|
"@vimeo/player": "^2.25.0",
|
|
37
37
|
"html-react-parser": "^3.0.1",
|
|
@@ -33,7 +33,7 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
33
33
|
useRegisterResize(ref, onResize);
|
|
34
34
|
const pos = stylesMap[anchor];
|
|
35
35
|
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams];
|
|
36
|
-
const stateParams = interactionCtrl?.getState(['angle', 'blur', 'opacity']);
|
|
36
|
+
const stateParams = interactionCtrl?.getState<number>(['angle', 'blur', 'opacity']);
|
|
37
37
|
const blur = (stateParams?.styles?.blur ?? itemBlur) as number;
|
|
38
38
|
const opacity = stateParams?.styles?.opacity ?? itemOpacity;
|
|
39
39
|
const angle = stateParams?.styles?.angle ?? itemAngle;
|
|
@@ -19,7 +19,7 @@ export const ComponentItem: FC<ItemProps<TComponentItem>> = ({ item, sectionId,
|
|
|
19
19
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
20
20
|
const { opacity: itemOpacity, blur: itemBlur } = useComponentItem(item, sectionId);
|
|
21
21
|
useRegisterResize(ref, onResize);
|
|
22
|
-
const stateParams = interactionCtrl?.getState(['opacity', 'angle', 'blur']);
|
|
22
|
+
const stateParams = interactionCtrl?.getState<number>(['opacity', 'angle', 'blur']);
|
|
23
23
|
const angle = getStyleFromItemStateAndParams(stateParams?.styles?.angle, itemAngle);
|
|
24
24
|
const opacity = getStyleFromItemStateAndParams(stateParams?.styles?.opacity, itemOpacity);
|
|
25
25
|
const blur = getStyleFromItemStateAndParams(stateParams?.styles?.blur, itemBlur);
|
|
@@ -47,8 +47,8 @@ export const CompoundChild: FC<ChildItemProps> = ({ item, sectionId, isParentVis
|
|
|
47
47
|
const itemScale = useItemScale(item, sectionId);
|
|
48
48
|
const interactionCtrl = useItemInteractionCtrl(item.id);
|
|
49
49
|
const triggers = useItemTriggers(interactionCtrl);
|
|
50
|
-
const wrapperStateProps = interactionCtrl?.getState(['top', 'left', 'width', 'height']);
|
|
51
|
-
const innerStateProps = interactionCtrl?.getState(['scale']);
|
|
50
|
+
const wrapperStateProps = interactionCtrl?.getState<number>(['top', 'left', 'width', 'height']);
|
|
51
|
+
const innerStateProps = interactionCtrl?.getState<number>(['scale']);
|
|
52
52
|
const compoundSettings = layout && item.compoundSettings ? item.compoundSettings[layout] : undefined;
|
|
53
53
|
const { width, height, top, left } = useItemArea(item, sectionId, {
|
|
54
54
|
top: wrapperStateProps?.styles?.top as number,
|
|
@@ -19,7 +19,7 @@ export const CompoundItem: FC<ItemProps<TCompoundItem>> = ({ item, sectionId, on
|
|
|
19
19
|
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams];
|
|
20
20
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
21
21
|
useRegisterResize(ref, onResize);
|
|
22
|
-
const stateParams = interactionCtrl?.getState(['opacity', 'angle']);
|
|
22
|
+
const stateParams = interactionCtrl?.getState<number>(['opacity', 'angle']);
|
|
23
23
|
const angle = getStyleFromItemStateAndParams(stateParams?.styles?.angle, itemAngle);
|
|
24
24
|
const opacity = getStyleFromItemStateAndParams(stateParams?.styles?.opacity, itemOpacity);
|
|
25
25
|
const isInteractive = opacity !== 0 && opacity !== undefined;
|
|
@@ -14,7 +14,7 @@ export const CustomItem: FC<ItemProps<TCustomItem>> = ({ item, onResize, section
|
|
|
14
14
|
const layoutValues: Record<string, any>[] = [item.area];
|
|
15
15
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
16
16
|
useRegisterResize(ref, onResize);
|
|
17
|
-
const stateParams = interactionCtrl?.getState(['angle']);
|
|
17
|
+
const stateParams = interactionCtrl?.getState<number>(['angle']);
|
|
18
18
|
const angle = stateParams?.styles?.angle ?? itemAngle;
|
|
19
19
|
if (!component) return null;
|
|
20
20
|
return (
|
|
@@ -31,8 +31,8 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
31
31
|
const [imgRef, setImgRef] = useState<HTMLImageElement | null>(null);
|
|
32
32
|
const [isCoverVisible, setIsCoverVisible] = useState(false);
|
|
33
33
|
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams];
|
|
34
|
-
const wrapperStateParams = interactionCtrl?.getState(['angle', 'blur', 'opacity']);
|
|
35
|
-
const frameStateParams = interactionCtrl?.getState(['radius']);
|
|
34
|
+
const wrapperStateParams = interactionCtrl?.getState<number>(['angle', 'blur', 'opacity']);
|
|
35
|
+
const frameStateParams = interactionCtrl?.getState<number>(['radius']);
|
|
36
36
|
const angle = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.angle, itemAngle);
|
|
37
37
|
const blur = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.blur, itemBlur);
|
|
38
38
|
const opacity = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.opacity, itemOpacity);
|
|
@@ -27,8 +27,8 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
27
27
|
const [isCoverVisible, setIsCoverVisible] = useState(false);
|
|
28
28
|
const [imgRef, setImgRef] = useState<HTMLImageElement | null>(null);
|
|
29
29
|
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams];
|
|
30
|
-
const wrapperStateParams = interactionCtrl?.getState(['angle', 'blur', 'opacity']);
|
|
31
|
-
const frameStateParams = interactionCtrl?.getState(['radius']);
|
|
30
|
+
const wrapperStateParams = interactionCtrl?.getState<number>(['angle', 'blur', 'opacity']);
|
|
31
|
+
const frameStateParams = interactionCtrl?.getState<number>(['radius']);
|
|
32
32
|
const angle = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.angle, itemAngle);
|
|
33
33
|
const blur = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.blur, itemBlur);
|
|
34
34
|
const opacity = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.opacity, itemOpacity);
|
|
@@ -13,6 +13,8 @@ import { useElementRect } from '../../../utils/useElementRect';
|
|
|
13
13
|
import { useLayoutContext } from '../../useLayoutContext';
|
|
14
14
|
import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams';
|
|
15
15
|
import { useItemFXData } from '../../../common/useItemFXData';
|
|
16
|
+
import { getFill } from '../../../utils/getFill';
|
|
17
|
+
import { FillLayer } from '@cntrl-site/sdk/dist/types/article/Item';
|
|
16
18
|
|
|
17
19
|
export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
|
|
18
20
|
const id = useId();
|
|
@@ -22,7 +24,7 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
22
24
|
radius: itemRadius,
|
|
23
25
|
strokeWidth: itemStrokeWidth,
|
|
24
26
|
opacity: itemOpacity,
|
|
25
|
-
|
|
27
|
+
strokeFill: itemStrokeFill,
|
|
26
28
|
blur: itemBlur
|
|
27
29
|
} = useFileItem(item, sectionId);
|
|
28
30
|
const itemAngle = useItemAngle(item, sectionId);
|
|
@@ -38,8 +40,11 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
38
40
|
const exemplary = layouts?.find(l => l.id === layoutId)?.exemplary;
|
|
39
41
|
const width = area && exemplary ? area.width * exemplary : 0;
|
|
40
42
|
const height = area && exemplary ? area.height * exemplary : 0;
|
|
41
|
-
const wrapperStateParams = interactionCtrl?.getState(['angle', 'opacity', 'blur']);
|
|
42
|
-
const imgStateParams = interactionCtrl?.getState(['strokeWidth', 'radius'
|
|
43
|
+
const wrapperStateParams = interactionCtrl?.getState<number>(['angle', 'opacity', 'blur']);
|
|
44
|
+
const imgStateParams = interactionCtrl?.getState<number>(['strokeWidth', 'radius']);
|
|
45
|
+
const stateStrokeFillParams = interactionCtrl?.getState<FillLayer[]>(['strokeFill']);
|
|
46
|
+
const stateStrokeFillLayers = stateStrokeFillParams?.styles?.strokeFill;
|
|
47
|
+
const strokeSolidTransition = stateStrokeFillParams?.transition ?? 'none';
|
|
43
48
|
|
|
44
49
|
useEffect(() => {
|
|
45
50
|
isInitialRef.current = false;
|
|
@@ -58,17 +63,19 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
58
63
|
const rect = useElementRect(wrapperRef);
|
|
59
64
|
const rectWidth = Math.floor(rect?.width ?? 0);
|
|
60
65
|
const rectHeight = Math.floor(rect?.height ?? 0);
|
|
61
|
-
const borderColor = useMemo(() => {
|
|
62
|
-
const borderColor = getStyleFromItemStateAndParams(imgStateParams?.styles?.strokeColor, itemStrokeColor);
|
|
63
|
-
return borderColor ? CntrlColor.parse(borderColor) : undefined;
|
|
64
|
-
}, [itemStrokeColor, imgStateParams?.styles?.strokeColor]);
|
|
65
66
|
const radius = getStyleFromItemStateAndParams(imgStateParams?.styles?.radius, itemRadius);
|
|
66
67
|
const strokeWidth = getStyleFromItemStateAndParams(imgStateParams?.styles?.strokeWidth, itemStrokeWidth);
|
|
67
68
|
const angle = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.angle, itemAngle);
|
|
68
69
|
const opacity = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.opacity, itemOpacity);
|
|
69
70
|
const blur = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.blur, itemBlur);
|
|
71
|
+
|
|
72
|
+
const strokeValue = stateStrokeFillLayers
|
|
73
|
+
? getStyleFromItemStateAndParams<FillLayer>(stateStrokeFillLayers[0], itemStrokeFill?.[0])
|
|
74
|
+
: itemStrokeFill?.[0];
|
|
75
|
+
const stroke = strokeValue
|
|
76
|
+
? getFill(strokeValue) ?? 'transparent'
|
|
77
|
+
: 'transparent';
|
|
70
78
|
const inlineStyles = {
|
|
71
|
-
...(borderColor ? { borderColor: `${borderColor.fmt('rgba')}` } : {}),
|
|
72
79
|
...(radius !== undefined ? { borderRadius: `${radius * 100}vw` } : {}),
|
|
73
80
|
...(strokeWidth !== undefined ? { borderWidth: `${strokeWidth * 100}vw` } : {}),
|
|
74
81
|
transition: imgStateParams?.transition ?? 'none'
|
|
@@ -87,6 +94,14 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
87
94
|
...(opacity !== undefined ? { opacity } : {}),
|
|
88
95
|
...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}),
|
|
89
96
|
...(blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {}),
|
|
97
|
+
...(strokeValue ? {
|
|
98
|
+
'--stroke-background': stroke,
|
|
99
|
+
...(strokeValue.type === 'image' ? {
|
|
100
|
+
'--stroke-background-position': 'center',
|
|
101
|
+
'--stroke-background-size': strokeValue.behavior === 'repeat' ? `${strokeValue.backgroundSize}%` : strokeValue.behavior,
|
|
102
|
+
'--stroke-background-repeat': strokeValue.behavior === 'repeat' ? 'repeat' : 'no-repeat'
|
|
103
|
+
} : {})
|
|
104
|
+
} : {}),
|
|
90
105
|
willChange: blur !== 0 && blur !== undefined ? 'transform' : 'unset',
|
|
91
106
|
transition: wrapperStateParams?.transition ?? 'none'
|
|
92
107
|
}}
|
|
@@ -109,6 +124,31 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
109
124
|
src={item.commonParams.url}
|
|
110
125
|
/>
|
|
111
126
|
)}
|
|
127
|
+
<div
|
|
128
|
+
className={`image-border-${item.id}`}
|
|
129
|
+
style={{
|
|
130
|
+
position: 'absolute',
|
|
131
|
+
inset: 0,
|
|
132
|
+
borderRadius: 'inherit',
|
|
133
|
+
pointerEvents: 'none',
|
|
134
|
+
zIndex: 2,
|
|
135
|
+
WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
|
|
136
|
+
WebkitMaskComposite: 'xor',
|
|
137
|
+
maskComposite: 'exclude',
|
|
138
|
+
...(strokeWidth !== 0 && strokeValue ? {
|
|
139
|
+
...(strokeWidth ? { padding: `${strokeWidth * 100}vw` } : {}),
|
|
140
|
+
...(strokeValue.type === 'solid' ? { transition: strokeSolidTransition, background: stroke } : {}),
|
|
141
|
+
...(strokeValue.type === 'image' ? {
|
|
142
|
+
backgroundPosition: 'center',
|
|
143
|
+
backgroundSize: strokeValue.behavior === 'repeat' ? `${strokeValue.backgroundSize}%` : strokeValue.behavior,
|
|
144
|
+
backgroundRepeat: strokeValue.behavior === 'repeat' ? 'repeat' : 'no-repeat'
|
|
145
|
+
} : {
|
|
146
|
+
background: stroke,
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
} : { background: stroke }),
|
|
150
|
+
}}
|
|
151
|
+
/>
|
|
112
152
|
</div>
|
|
113
153
|
<JSXStyle id={id}>{`
|
|
114
154
|
.image-wrapper-${item.id} {
|
|
@@ -145,9 +185,22 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
145
185
|
${layoutParams.blur !== 0 ? 'will-change: transform;' : ''}
|
|
146
186
|
}
|
|
147
187
|
.image-${item.id} {
|
|
148
|
-
border
|
|
149
|
-
border-
|
|
188
|
+
border: solid;
|
|
189
|
+
border-color: transparent;
|
|
150
190
|
border-width: ${layoutParams.strokeWidth * 100}vw;
|
|
191
|
+
border-radius: ${layoutParams.radius * 100}vw;
|
|
192
|
+
}
|
|
193
|
+
.image-border-${item.id} {
|
|
194
|
+
position: absolute;
|
|
195
|
+
inset: 0;
|
|
196
|
+
border-radius: inherit;
|
|
197
|
+
pointer-events: none;
|
|
198
|
+
z-index: 2;
|
|
199
|
+
-webkit-mask:
|
|
200
|
+
linear-gradient(#fff 0 0) content-box,
|
|
201
|
+
linear-gradient(#fff 0 0);
|
|
202
|
+
-webkit-mask-composite: xor;
|
|
203
|
+
mask-composite: exclude;
|
|
151
204
|
}
|
|
152
205
|
`);
|
|
153
206
|
})}
|
|
@@ -14,6 +14,8 @@ import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemS
|
|
|
14
14
|
import { useVideoFx } from '../../../utils/effects/useVideoFx';
|
|
15
15
|
import { useElementRect } from '../../../utils/useElementRect';
|
|
16
16
|
import { useItemFXData } from '../../../common/useItemFXData';
|
|
17
|
+
import { getFill } from '../../../utils/getFill';
|
|
18
|
+
import { FillLayer } from '@cntrl-site/sdk/dist/types/article/Item';
|
|
17
19
|
|
|
18
20
|
export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
|
|
19
21
|
const id = useId();
|
|
@@ -22,7 +24,7 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
22
24
|
const {
|
|
23
25
|
radius: itemRadius,
|
|
24
26
|
strokeWidth: itemStrokeWidth,
|
|
25
|
-
|
|
27
|
+
strokeFill: itemStrokeFill,
|
|
26
28
|
opacity: itemOpacity,
|
|
27
29
|
blur: itemBlur
|
|
28
30
|
} = useFileItem(item, sectionId);
|
|
@@ -48,17 +50,23 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
48
50
|
const scrollPlayback = layoutParams ? layoutParams.scrollPlayback : null;
|
|
49
51
|
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams];
|
|
50
52
|
const hasScrollPlayback = scrollPlayback !== null;
|
|
51
|
-
const wrapperStateParams = interactionCtrl?.getState(['angle', 'opacity', 'blur']);
|
|
52
|
-
const videoStateParams = interactionCtrl?.getState(['strokeWidth', 'radius'
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}, [videoStateParams?.styles?.color, itemStrokeColor]);
|
|
53
|
+
const wrapperStateParams = interactionCtrl?.getState<number>(['angle', 'opacity', 'blur']);
|
|
54
|
+
const videoStateParams = interactionCtrl?.getState<number>(['strokeWidth', 'radius']);
|
|
55
|
+
const stateStrokeFillParams = interactionCtrl?.getState<FillLayer[]>(['strokeFill']);
|
|
56
|
+
const stateStrokeFillLayers = stateStrokeFillParams?.styles?.strokeFill;
|
|
57
|
+
const strokeSolidTransition = stateStrokeFillParams?.transition ?? 'none';
|
|
57
58
|
const angle = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.angle, itemAngle);
|
|
58
59
|
const opacity = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.opacity, itemOpacity);
|
|
59
60
|
const blur = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.blur, itemBlur);
|
|
60
61
|
const strokeWidth = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.strokeWidth, itemStrokeWidth);
|
|
61
62
|
const radius = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.radius, itemRadius);
|
|
63
|
+
|
|
64
|
+
const strokeValue = stateStrokeFillLayers
|
|
65
|
+
? getStyleFromItemStateAndParams<FillLayer>(stateStrokeFillLayers[0], itemStrokeFill?.[0])
|
|
66
|
+
: itemStrokeFill?.[0];
|
|
67
|
+
const stroke = strokeValue
|
|
68
|
+
? getFill(strokeValue) ?? 'transparent'
|
|
69
|
+
: 'transparent';
|
|
62
70
|
useEffect(() => {
|
|
63
71
|
isInitialRef.current = false;
|
|
64
72
|
}, []);
|
|
@@ -77,7 +85,6 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
77
85
|
const inlineStyles = {
|
|
78
86
|
...(radius !== undefined ? { borderRadius: `${radius * 100}vw` } : {}),
|
|
79
87
|
...(strokeWidth !== undefined ? { borderWidth: `${strokeWidth * 100}vw` } : {}),
|
|
80
|
-
...(borderColor ? { borderColor: `${borderColor.toCss()}` } : {}),
|
|
81
88
|
transition: videoStateParams?.transition ?? 'none'
|
|
82
89
|
};
|
|
83
90
|
const isInteractive = opacity !== 0;
|
|
@@ -112,6 +119,14 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
112
119
|
...(opacity !== undefined ? { opacity } : {}),
|
|
113
120
|
...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}),
|
|
114
121
|
...(blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {}),
|
|
122
|
+
...(strokeValue ? {
|
|
123
|
+
'--stroke-background': stroke,
|
|
124
|
+
...(strokeValue.type === 'image' ? {
|
|
125
|
+
'--stroke-background-position': 'center',
|
|
126
|
+
'--stroke-background-size': strokeValue.behavior === 'repeat' ? `${strokeValue.backgroundSize}%` : strokeValue.behavior,
|
|
127
|
+
'--stroke-background-repeat': strokeValue.behavior === 'repeat' ? 'repeat' : 'no-repeat'
|
|
128
|
+
} : {})
|
|
129
|
+
} : {}),
|
|
115
130
|
willChange: blur !== 0 && blur !== undefined ? 'transform' : 'unset',
|
|
116
131
|
transition: wrapperStateParams?.transition ?? 'none'
|
|
117
132
|
}}
|
|
@@ -203,6 +218,31 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
203
218
|
))}
|
|
204
219
|
</>
|
|
205
220
|
)}
|
|
221
|
+
<div
|
|
222
|
+
className={`video-border-${item.id}`}
|
|
223
|
+
style={{
|
|
224
|
+
position: 'absolute',
|
|
225
|
+
inset: 0,
|
|
226
|
+
borderRadius: 'inherit',
|
|
227
|
+
pointerEvents: 'none',
|
|
228
|
+
zIndex: 2,
|
|
229
|
+
WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
|
|
230
|
+
WebkitMaskComposite: 'xor',
|
|
231
|
+
maskComposite: 'exclude',
|
|
232
|
+
...(strokeWidth !== 0 && strokeValue ? {
|
|
233
|
+
...(strokeWidth ? { padding: `${strokeWidth * 100}vw` } : {}),
|
|
234
|
+
...(strokeValue.type === 'solid' ? { transition: strokeSolidTransition, background: stroke } : {}),
|
|
235
|
+
...(strokeValue.type === 'image' ? {
|
|
236
|
+
backgroundPosition: 'center',
|
|
237
|
+
backgroundSize: strokeValue.behavior === 'repeat' ? `${strokeValue.backgroundSize}%` : strokeValue.behavior,
|
|
238
|
+
backgroundRepeat: strokeValue.behavior === 'repeat' ? 'repeat' : 'no-repeat'
|
|
239
|
+
} : {
|
|
240
|
+
background: stroke,
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
} : { background: stroke }),
|
|
244
|
+
}}
|
|
245
|
+
/>
|
|
206
246
|
</div>
|
|
207
247
|
<JSXStyle id={id}>{`
|
|
208
248
|
.video-wrapper-${item.id} {
|
|
@@ -240,7 +280,7 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
240
280
|
border-style: solid;
|
|
241
281
|
}
|
|
242
282
|
.video-${item.id} {
|
|
243
|
-
border-
|
|
283
|
+
border-radius: ${radius !== undefined ? `${radius * 100}vw` : '0'};
|
|
244
284
|
}
|
|
245
285
|
.video-playback-wrapper {
|
|
246
286
|
display: flex;
|
|
@@ -263,9 +303,22 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
263
303
|
${layoutParams.blur !== 0 ? 'will-change: transform;' : ''}
|
|
264
304
|
}
|
|
265
305
|
.video-${item.id} {
|
|
266
|
-
border
|
|
267
|
-
border-
|
|
306
|
+
border: solid;
|
|
307
|
+
border-color: transparent;
|
|
268
308
|
border-width: ${layoutParams.strokeWidth * 100}vw;
|
|
309
|
+
border-radius: ${layoutParams.radius * 100}vw;
|
|
310
|
+
}
|
|
311
|
+
.video-border-${item.id} {
|
|
312
|
+
position: absolute;
|
|
313
|
+
inset: 0;
|
|
314
|
+
border-radius: inherit;
|
|
315
|
+
pointer-events: none;
|
|
316
|
+
z-index: 2;
|
|
317
|
+
-webkit-mask:
|
|
318
|
+
linear-gradient(#fff 0 0) content-box,
|
|
319
|
+
linear-gradient(#fff 0 0);
|
|
320
|
+
-webkit-mask-composite: xor;
|
|
321
|
+
mask-composite: exclude;
|
|
269
322
|
}
|
|
270
323
|
`);
|
|
271
324
|
})}
|