@cntrl-site/sdk-nextjs 1.8.39 → 1.8.40-alpha.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 +46 -22
- package/lib/components/items/FileItem/VideoItem.js +45 -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 +60 -11
- package/src/components/items/FileItem/VideoItem.tsx +61 -12
- 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.8.
|
|
3
|
+
"version": "1.8.40-alpha.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.23.
|
|
34
|
+
"@cntrl-site/sdk": "^1.23.1-alpha.1",
|
|
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,19 +63,20 @@ 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
|
-
...(strokeWidth !== undefined ? { borderWidth: `${strokeWidth * 100}vw` } : {}),
|
|
74
80
|
transition: imgStateParams?.transition ?? 'none'
|
|
75
81
|
};
|
|
76
82
|
const isInteractive = opacity !== 0;
|
|
@@ -87,6 +93,14 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
87
93
|
...(opacity !== undefined ? { opacity } : {}),
|
|
88
94
|
...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}),
|
|
89
95
|
...(blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {}),
|
|
96
|
+
...(strokeValue ? {
|
|
97
|
+
'--stroke-background': stroke,
|
|
98
|
+
...(strokeValue.type === 'image' ? {
|
|
99
|
+
'--stroke-background-position': 'center',
|
|
100
|
+
'--stroke-background-size': strokeValue.behavior === 'repeat' ? `${strokeValue.backgroundSize}%` : strokeValue.behavior,
|
|
101
|
+
'--stroke-background-repeat': strokeValue.behavior === 'repeat' ? 'repeat' : 'no-repeat'
|
|
102
|
+
} : {})
|
|
103
|
+
} : {}),
|
|
90
104
|
willChange: blur !== 0 && blur !== undefined ? 'transform' : 'unset',
|
|
91
105
|
transition: wrapperStateParams?.transition ?? 'none'
|
|
92
106
|
}}
|
|
@@ -109,6 +123,31 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
109
123
|
src={item.commonParams.url}
|
|
110
124
|
/>
|
|
111
125
|
)}
|
|
126
|
+
<div
|
|
127
|
+
className={`image-border-${item.id}`}
|
|
128
|
+
style={{
|
|
129
|
+
position: 'absolute',
|
|
130
|
+
inset: 0,
|
|
131
|
+
borderRadius: 'inherit',
|
|
132
|
+
pointerEvents: 'none',
|
|
133
|
+
zIndex: 2,
|
|
134
|
+
WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
|
|
135
|
+
WebkitMaskComposite: 'xor',
|
|
136
|
+
maskComposite: 'exclude',
|
|
137
|
+
...(strokeWidth !== 0 && strokeValue ? {
|
|
138
|
+
...(strokeWidth ? { padding: `${strokeWidth * 100}vw` } : {}),
|
|
139
|
+
...(strokeValue.type === 'solid' ? { transition: strokeSolidTransition, background: stroke } : {}),
|
|
140
|
+
...(strokeValue.type === 'image' ? {
|
|
141
|
+
backgroundPosition: 'center',
|
|
142
|
+
backgroundSize: strokeValue.behavior === 'repeat' ? `${strokeValue.backgroundSize}%` : strokeValue.behavior,
|
|
143
|
+
backgroundRepeat: strokeValue.behavior === 'repeat' ? 'repeat' : 'no-repeat'
|
|
144
|
+
} : {
|
|
145
|
+
background: stroke,
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
} : { background: stroke }),
|
|
149
|
+
}}
|
|
150
|
+
/>
|
|
112
151
|
</div>
|
|
113
152
|
<JSXStyle id={id}>{`
|
|
114
153
|
.image-wrapper-${item.id} {
|
|
@@ -145,9 +184,19 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
145
184
|
${layoutParams.blur !== 0 ? 'will-change: transform;' : ''}
|
|
146
185
|
}
|
|
147
186
|
.image-${item.id} {
|
|
148
|
-
border-color: ${CntrlColor.parse(layoutParams.strokeColor).fmt('rgba')};
|
|
149
187
|
border-radius: ${layoutParams.radius * 100}vw;
|
|
150
|
-
|
|
188
|
+
}
|
|
189
|
+
.image-border-${item.id} {
|
|
190
|
+
position: absolute;
|
|
191
|
+
inset: 0;
|
|
192
|
+
border-radius: inherit;
|
|
193
|
+
pointer-events: none;
|
|
194
|
+
z-index: 2;
|
|
195
|
+
-webkit-mask:
|
|
196
|
+
linear-gradient(#fff 0 0) content-box,
|
|
197
|
+
linear-gradient(#fff 0 0);
|
|
198
|
+
-webkit-mask-composite: xor;
|
|
199
|
+
mask-composite: exclude;
|
|
151
200
|
}
|
|
152
201
|
`);
|
|
153
202
|
})}
|
|
@@ -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
|
}, []);
|
|
@@ -76,8 +84,6 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
76
84
|
useRegisterResize(ref, onResize);
|
|
77
85
|
const inlineStyles = {
|
|
78
86
|
...(radius !== undefined ? { borderRadius: `${radius * 100}vw` } : {}),
|
|
79
|
-
...(strokeWidth !== undefined ? { borderWidth: `${strokeWidth * 100}vw` } : {}),
|
|
80
|
-
...(borderColor ? { borderColor: `${borderColor.toCss()}` } : {}),
|
|
81
87
|
transition: videoStateParams?.transition ?? 'none'
|
|
82
88
|
};
|
|
83
89
|
const isInteractive = opacity !== 0;
|
|
@@ -112,6 +118,14 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
112
118
|
...(opacity !== undefined ? { opacity } : {}),
|
|
113
119
|
...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}),
|
|
114
120
|
...(blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {}),
|
|
121
|
+
...(strokeValue ? {
|
|
122
|
+
'--stroke-background': stroke,
|
|
123
|
+
...(strokeValue.type === 'image' ? {
|
|
124
|
+
'--stroke-background-position': 'center',
|
|
125
|
+
'--stroke-background-size': strokeValue.behavior === 'repeat' ? `${strokeValue.backgroundSize}%` : strokeValue.behavior,
|
|
126
|
+
'--stroke-background-repeat': strokeValue.behavior === 'repeat' ? 'repeat' : 'no-repeat'
|
|
127
|
+
} : {})
|
|
128
|
+
} : {}),
|
|
115
129
|
willChange: blur !== 0 && blur !== undefined ? 'transform' : 'unset',
|
|
116
130
|
transition: wrapperStateParams?.transition ?? 'none'
|
|
117
131
|
}}
|
|
@@ -203,6 +217,31 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
203
217
|
))}
|
|
204
218
|
</>
|
|
205
219
|
)}
|
|
220
|
+
<div
|
|
221
|
+
className={`video-border-${item.id}`}
|
|
222
|
+
style={{
|
|
223
|
+
position: 'absolute',
|
|
224
|
+
inset: 0,
|
|
225
|
+
borderRadius: 'inherit',
|
|
226
|
+
pointerEvents: 'none',
|
|
227
|
+
zIndex: 2,
|
|
228
|
+
WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
|
|
229
|
+
WebkitMaskComposite: 'xor',
|
|
230
|
+
maskComposite: 'exclude',
|
|
231
|
+
...(strokeWidth !== 0 && strokeValue ? {
|
|
232
|
+
...(strokeWidth ? { padding: `${strokeWidth * 100}vw` } : {}),
|
|
233
|
+
...(strokeValue.type === 'solid' ? { transition: strokeSolidTransition, background: stroke } : {}),
|
|
234
|
+
...(strokeValue.type === 'image' ? {
|
|
235
|
+
backgroundPosition: 'center',
|
|
236
|
+
backgroundSize: strokeValue.behavior === 'repeat' ? `${strokeValue.backgroundSize}%` : strokeValue.behavior,
|
|
237
|
+
backgroundRepeat: strokeValue.behavior === 'repeat' ? 'repeat' : 'no-repeat'
|
|
238
|
+
} : {
|
|
239
|
+
background: stroke,
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
} : { background: stroke }),
|
|
243
|
+
}}
|
|
244
|
+
/>
|
|
206
245
|
</div>
|
|
207
246
|
<JSXStyle id={id}>{`
|
|
208
247
|
.video-wrapper-${item.id} {
|
|
@@ -240,7 +279,7 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
240
279
|
border-style: solid;
|
|
241
280
|
}
|
|
242
281
|
.video-${item.id} {
|
|
243
|
-
border-
|
|
282
|
+
border-radius: ${radius !== undefined ? `${radius * 100}vw` : '0'};
|
|
244
283
|
}
|
|
245
284
|
.video-playback-wrapper {
|
|
246
285
|
display: flex;
|
|
@@ -263,9 +302,19 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
263
302
|
${layoutParams.blur !== 0 ? 'will-change: transform;' : ''}
|
|
264
303
|
}
|
|
265
304
|
.video-${item.id} {
|
|
266
|
-
border-color: ${CntrlColor.parse(layoutParams.strokeColor).fmt('rgba')};
|
|
267
305
|
border-radius: ${layoutParams.radius * 100}vw;
|
|
268
|
-
|
|
306
|
+
}
|
|
307
|
+
.video-border-${item.id} {
|
|
308
|
+
position: absolute;
|
|
309
|
+
inset: 0;
|
|
310
|
+
border-radius: inherit;
|
|
311
|
+
pointer-events: none;
|
|
312
|
+
z-index: 2;
|
|
313
|
+
-webkit-mask:
|
|
314
|
+
linear-gradient(#fff 0 0) content-box,
|
|
315
|
+
linear-gradient(#fff 0 0);
|
|
316
|
+
-webkit-mask-composite: xor;
|
|
317
|
+
mask-composite: exclude;
|
|
269
318
|
}
|
|
270
319
|
`);
|
|
271
320
|
})}
|