diff --git a/examples/lorem-ipsum/build/diez-lorem-ipsum-web/package.json b/examples/lorem-ipsum/build/diez-lorem-ipsum-web/package.json
index 81f0e5aad..f52270b79 100644
--- a/examples/lorem-ipsum/build/diez-lorem-ipsum-web/package.json
+++ b/examples/lorem-ipsum/build/diez-lorem-ipsum-web/package.json
@@ -3,7 +3,7 @@
"version": "0.1.0",
"license": "MIT",
"dependencies": {
- "@diez/web-sdk-common": "^10.0.0-beta.2",
+ "@diez/web-sdk-common": "^10.0.0-beta.3",
"lottie-web": "^5.5.2"
}
}
diff --git a/examples/lorem-ipsum/examples/ios/LoremIpsum/ViewController.swift b/examples/lorem-ipsum/examples/ios/LoremIpsum/ViewController.swift
index b37483c3c..bcbda2654 100644
--- a/examples/lorem-ipsum/examples/ios/LoremIpsum/ViewController.swift
+++ b/examples/lorem-ipsum/examples/ios/LoremIpsum/ViewController.swift
@@ -35,6 +35,7 @@ class ViewController: UIViewController {
}
view.iconView.image = designSystem.images.logo.uiImage
+ view.iconView.layer.apply(designSystem.shadows.logo)
view.contentBackgroundView.backgroundColor = designSystem.palette.contentBackground.uiColor
let margin = designSystem.layoutValues.contentMargin
diff --git a/examples/lorem-ipsum/examples/web/src/App.module.scss b/examples/lorem-ipsum/examples/web/src/App.module.scss
index a85feb22f..210d3d953 100644
--- a/examples/lorem-ipsum/examples/web/src/App.module.scss
+++ b/examples/lorem-ipsum/examples/web/src/App.module.scss
@@ -64,6 +64,7 @@
.icon {
@include images-logo-background-image();
+ @include shadows-logo-filter();
transform: translate(0, -50%);
position: absolute;
margin-left: $layout-values-spacing-medium-px;
diff --git a/examples/lorem-ipsum/src/DesignSystem.ts b/examples/lorem-ipsum/src/DesignSystem.ts
index 5e68e45fb..4740f197d 100644
--- a/examples/lorem-ipsum/src/DesignSystem.ts
+++ b/examples/lorem-ipsum/src/DesignSystem.ts
@@ -1,4 +1,4 @@
-import {Color, Image, Lottie, Toward, Typograph, Font, LinearGradient} from '@diez/prefabs';
+import {Color, DropShadow, Image, Lottie, Toward, Typograph, Font, LinearGradient, Point2D} from '@diez/prefabs';
import {Margin} from './components/Margin';
/**
@@ -106,6 +106,14 @@ class Strings {
helper = 'Modify the contents of “src/DesignSystem.ts” (relative to the root of the Diez project) to see changes to the design system in real time.';
}
+class Shadows {
+ logo = new DropShadow({
+ offset: Point2D.make(0, 1),
+ radius: 16,
+ color: colors.black.fade(0.59),
+ });
+}
+
/**
* Note how this component is exported from `index.ts`. Diez compiles these
* exported components for your apps' codebases.
@@ -128,4 +136,5 @@ export class DesignSystem {
layoutValues = new LayoutValues();
strings = new Strings();
loadingAnimation = Lottie.fromJson('assets/loadingAnimation.json', false);
+ shadows = new Shadows();
}
diff --git a/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard.png b/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard.png
index b3e579eea..d670c6ccb 100644
Binary files a/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard.png and b/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard.png differ
diff --git a/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@2x.png b/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@2x.png
index f939e63f9..6d74eb70e 100644
Binary files a/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@2x.png and b/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@2x.png differ
diff --git a/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@3x.png b/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@3x.png
index bbb314922..f32e7b949 100644
Binary files a/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@3x.png and b/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@3x.png differ
diff --git a/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@4x.png b/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@4x.png
index 8909225f5..d953a6d96 100644
Binary files a/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@4x.png and b/examples/poodle-surf/assets/PoodleSurf.sketch.contents/slices/Artboard@4x.png differ
diff --git a/examples/poodle-surf/build/diez-poodle-surf-web/package.json b/examples/poodle-surf/build/diez-poodle-surf-web/package.json
index d28d88670..06650f177 100644
--- a/examples/poodle-surf/build/diez-poodle-surf-web/package.json
+++ b/examples/poodle-surf/build/diez-poodle-surf-web/package.json
@@ -3,7 +3,7 @@
"version": "0.1.0",
"license": "MIT",
"dependencies": {
- "@diez/web-sdk-common": "^10.0.0-beta.2",
+ "@diez/web-sdk-common": "^10.0.0-beta.3",
"lottie-web": "^5.5.2"
}
}
diff --git a/examples/poodle-surf/designs/PoodleSurf.sketch b/examples/poodle-surf/designs/PoodleSurf.sketch
index 681a45eba..513828349 100644
Binary files a/examples/poodle-surf/designs/PoodleSurf.sketch and b/examples/poodle-surf/designs/PoodleSurf.sketch differ
diff --git a/examples/poodle-surf/examples/ios-objc/PoodleSurfObjC/ViewController.m b/examples/poodle-surf/examples/ios-objc/PoodleSurfObjC/ViewController.m
index 29304c76e..de6bb2c95 100644
--- a/examples/poodle-surf/examples/ios-objc/PoodleSurfObjC/ViewController.m
+++ b/examples/poodle-surf/examples/ios-objc/PoodleSurfObjC/ViewController.m
@@ -87,6 +87,8 @@ - (void)viewDidLoad {
imageView.image = component.designs.navigationTitle.icon.uiImage;
+ [imageView.layer dez_applyDropShadow:component.designs.report.wind.shared.dropShadow];
+
[gradientView.gradientLayer dez_applyLinearGradient:component.designs.report.waterTemperature.shared.gradient];
[animationView dez_loadLottie:component.designs.loading.animation completion:nil];
diff --git a/examples/poodle-surf/examples/ios/PoodleSurf/Report/ReportViewController+Diez.swift b/examples/poodle-surf/examples/ios/PoodleSurf/Report/ReportViewController+Diez.swift
index 606db5c40..aff62a50f 100644
--- a/examples/poodle-surf/examples/ios/PoodleSurf/Report/ReportViewController+Diez.swift
+++ b/examples/poodle-surf/examples/ios/PoodleSurf/Report/ReportViewController+Diez.swift
@@ -76,8 +76,9 @@ extension ReportViewController {
view.titleLabel.attributedText = design.titleTypograph.attributedString(decorating: design.title)
view.titleContentSpacing = design.titleContentSpacing
view.layoutMargins = UIEdgeInsets(design.layoutMargins)
- view.cornerRadius = design.cornerRadius
view.backgroundView.gradientLayer.apply(design.gradient)
+ view.backgroundView.cornerRadius = design.cornerRadius
+ view.layer.apply(design.dropShadow)
}
private func apply(_ design: DayPartDesign, to view: DayPartView) {
diff --git a/examples/poodle-surf/examples/web/src/App.tsx b/examples/poodle-surf/examples/web/src/App.tsx
index c9738c288..c139d214c 100644
--- a/examples/poodle-surf/examples/web/src/App.tsx
+++ b/examples/poodle-surf/examples/web/src/App.tsx
@@ -31,8 +31,10 @@ class App extends React.PureComponent<{}, {ds: DesignSystem, mocks: ModelMocks}>
/>
}}
>
-
+
diff --git a/examples/poodle-surf/examples/web/src/components/Card.tsx b/examples/poodle-surf/examples/web/src/components/Card.tsx
index e5e357ffe..b1f445ad0 100644
--- a/examples/poodle-surf/examples/web/src/components/Card.tsx
+++ b/examples/poodle-surf/examples/web/src/components/Card.tsx
@@ -14,6 +14,7 @@ export default class Card extends React.PureComponent {
return (
{
paddingRight: ds.layoutMargins.right,
borderRadius: ds.cornerRadius,
marginBottom: ds.layoutMargins.bottom,
- breakInside: 'avoid',
+ boxShadow: ds.dropShadow.boxShadow,
display: 'flex',
flexWrap: 'wrap',
flexDirection: 'column',
+ width: '42%',
}}
>
{ds.title}
diff --git a/examples/poodle-surf/examples/web/src/components/ForecastCard.tsx b/examples/poodle-surf/examples/web/src/components/ForecastCard.tsx
index ec29e8bd0..a62830960 100644
--- a/examples/poodle-surf/examples/web/src/components/ForecastCard.tsx
+++ b/examples/poodle-surf/examples/web/src/components/ForecastCard.tsx
@@ -19,15 +19,12 @@ export default class ForecastCard extends React.PureComponent
{Object.values(mocks).map((dayPart: WindDayPartMock) => (
() {
@@ -45,7 +46,8 @@ class SharedCardDesign extends prefab() {
left: LayoutValues.DefaultMargin,
right: LayoutValues.DefaultMargin,
}),
- cornerRadius: 5,
+ cornerRadius: 8,
+ dropShadow: shadows.card,
};
}
diff --git a/examples/poodle-surf/src/designs/constants.ts b/examples/poodle-surf/src/designs/constants.ts
index 957f5e539..f395de954 100644
--- a/examples/poodle-surf/src/designs/constants.ts
+++ b/examples/poodle-surf/src/designs/constants.ts
@@ -17,6 +17,12 @@ class Palette {
*/
export const palette = new Palette();
+class Shadows {
+ card = poodleSurfTokens.shadows.cardStyleDropShadow;
+}
+
+export const shadows = new Shadows();
+
/**
* A registry of all of the design's fonts.
*/
diff --git a/packages/generation/src/api.ts b/packages/generation/src/api.ts
index 1f20ad823..8089390af 100644
--- a/packages/generation/src/api.ts
+++ b/packages/generation/src/api.ts
@@ -53,6 +53,7 @@ export interface CodegenDesignSystem {
projectRoot: string;
colors: CodegenEntity[];
gradients: CodegenEntity[];
+ shadows: CodegenEntity[];
typographs: CodegenEntity[];
fonts: GeneratedFonts;
assets: GeneratedAssets;
diff --git a/packages/generation/src/constants.ts b/packages/generation/src/constants.ts
new file mode 100644
index 000000000..59183de89
--- /dev/null
+++ b/packages/generation/src/constants.ts
@@ -0,0 +1,6 @@
+/**
+ * The precision to use when rounding numbers to a reasonable float value.
+ *
+ * @ignore
+ */
+export const floatPrecision = 6;
diff --git a/packages/generation/src/drop-shadow.ts b/packages/generation/src/drop-shadow.ts
new file mode 100644
index 000000000..1bebc2ede
--- /dev/null
+++ b/packages/generation/src/drop-shadow.ts
@@ -0,0 +1,16 @@
+import {floatPrecision} from './constants';
+import {GeneratedPoint2D, getPoint2DInitializer} from './point2d';
+
+interface GeneratedDropShadow {
+ colorInitializer: string;
+ offset: GeneratedPoint2D;
+ radius: number;
+}
+
+/**
+ * Returns a drop shadow initializer.
+ * @ignore
+ */
+export const getDropShadowInitializer = (shadow: GeneratedDropShadow) => {
+ return `new DropShadow({offset: ${getPoint2DInitializer(shadow.offset)}, radius: ${shadow.radius.toFixed(floatPrecision)}, color: ${shadow.colorInitializer}})`;
+};
diff --git a/packages/generation/src/index.ts b/packages/generation/src/index.ts
index fcff1dfbf..8d034f664 100644
--- a/packages/generation/src/index.ts
+++ b/packages/generation/src/index.ts
@@ -1,5 +1,7 @@
export * from './api';
export * from './color';
+export * from './drop-shadow';
export * from './linear-gradient';
+export * from './point2d';
export * from './typography';
export * from './utils';
diff --git a/packages/generation/src/linear-gradient.ts b/packages/generation/src/linear-gradient.ts
index 1600d7a92..b49976bbe 100644
--- a/packages/generation/src/linear-gradient.ts
+++ b/packages/generation/src/linear-gradient.ts
@@ -1,25 +1,22 @@
-interface GeneratedPoint2D {
- x: number;
- y: number;
-}
+import {floatPrecision} from './constants';
+import {GeneratedPoint2D, getPoint2DInitializer} from './point2d';
interface GeneratedGradientStop {
position: number;
colorInitializer: string;
}
-const FloatPrecision = 6;
-
-const getPoint2DInitializer = (point: GeneratedPoint2D) =>
- `Point2D.make(${point.x.toFixed(FloatPrecision)}, ${point.y.toFixed(FloatPrecision)})`;
-
/**
* Returns a linear gradient initializer.
* @ignore
*/
-export const getLinearGradientInitializer = (stops: GeneratedGradientStop[], start: GeneratedPoint2D, end: GeneratedPoint2D) => {
+export const getLinearGradientInitializer = (
+ stops: GeneratedGradientStop[],
+ start: GeneratedPoint2D,
+ end: GeneratedPoint2D,
+) => {
const colorStopInitializers = stops.map((stop) => {
- return `GradientStop.make(${stop.position.toFixed(FloatPrecision)}, ${stop.colorInitializer})`;
+ return `GradientStop.make(${stop.position.toFixed(floatPrecision)}, ${stop.colorInitializer})`;
});
const colorStopInitializer = `[${colorStopInitializers.join(', ')}]`;
return `new LinearGradient({stops: ${colorStopInitializer}, start: ${getPoint2DInitializer(start)}, end: ${getPoint2DInitializer(end)}})`;
diff --git a/packages/generation/src/point2d.ts b/packages/generation/src/point2d.ts
new file mode 100644
index 000000000..52738c484
--- /dev/null
+++ b/packages/generation/src/point2d.ts
@@ -0,0 +1,17 @@
+import {floatPrecision} from './constants';
+
+/**
+ * A 2D point.
+ * @ignore
+ */
+export interface GeneratedPoint2D {
+ x: number;
+ y: number;
+}
+
+/**
+ * Returns a 2D point initializer.
+ * @ignore
+ */
+export const getPoint2DInitializer = (point: GeneratedPoint2D) =>
+ `Point2D.make(${point.x.toFixed(floatPrecision)}, ${point.y.toFixed(floatPrecision)})`;
diff --git a/packages/generation/src/utils.ts b/packages/generation/src/utils.ts
index 867420faa..0fd1c7c9d 100644
--- a/packages/generation/src/utils.ts
+++ b/packages/generation/src/utils.ts
@@ -67,6 +67,7 @@ export const createDesignSystemSpec = (
projectRoot,
colors: [],
gradients: [],
+ shadows: [],
typographs: [],
fonts: new Map(),
assets: new Map(),
@@ -157,10 +158,12 @@ export const codegenDesignSystem = async (spec: CodegenDesignSystem) => {
const designSystemImports = new Set();
const colorsName = localResolver.getComponentName(`${designSystemName} Colors`);
const gradientsName = localResolver.getComponentName(`${designSystemName} Gradients`);
+ const shadowsName = localResolver.getComponentName(`${designSystemName} Shadows`);
const typographsName = localResolver.getComponentName(`${designSystemName} Typographs`);
const hasColors = spec.colors.length > 0;
const hasGradients = spec.gradients.length > 0;
+ const hasShadows = spec.shadows.length > 0;
const hasTypographs = spec.typographs.length > 0;
if (hasColors) {
@@ -194,6 +197,22 @@ export const codegenDesignSystem = async (spec: CodegenDesignSystem) => {
});
}
+ if (hasShadows) {
+ designSystemImports.add('Color');
+ designSystemImports.add('Point2D');
+ designSystemImports.add('DropShadow');
+ sourceFile.addClass({
+ name: shadowsName,
+ properties: spec.shadows.map(({name, initializer}) => {
+ const shadowName = localResolver.getPropertyName(name || 'Untitled Shadow', shadowsName);
+ return {
+ initializer,
+ name: shadowName,
+ };
+ }),
+ });
+ }
+
if (hasTypographs) {
designSystemImports.add('Color');
designSystemImports.add('Typograph');
@@ -304,6 +323,13 @@ export const codegenDesignSystem = async (spec: CodegenDesignSystem) => {
});
}
+ if (hasShadows) {
+ exportedClassDeclaration.addProperty({
+ name: 'shadows',
+ initializer: `new ${shadowsName}()`,
+ });
+ }
+
if (hasTypographs) {
designSystemImports.add('Font');
exportedClassDeclaration.addProperty({
diff --git a/packages/generation/test/codegen.e2e.test.ts b/packages/generation/test/codegen.e2e.test.ts
index c7da498d0..f333ac578 100644
--- a/packages/generation/test/codegen.e2e.test.ts
+++ b/packages/generation/test/codegen.e2e.test.ts
@@ -120,6 +120,17 @@ describe('codegen.e2e', () => {
},
);
+ spec.shadows.push(
+ {
+ name: '',
+ initializer: '6',
+ },
+ {
+ name: 'Some Shadow',
+ initializer: '7',
+ },
+ );
+
registerAsset(
{
src: 'assets/blah/Foobar.png',
diff --git a/packages/generation/test/drop-shadow.test.ts b/packages/generation/test/drop-shadow.test.ts
new file mode 100644
index 000000000..4b38a5024
--- /dev/null
+++ b/packages/generation/test/drop-shadow.test.ts
@@ -0,0 +1,17 @@
+import {getDropShadowInitializer} from '../src/drop-shadow';
+import {getPoint2DInitializer} from '../src/point2d';
+
+describe('drop-shadow', () => {
+ test('initializer', () => {
+ const offset = {
+ x: 0.1234567890,
+ y: 0.1234567890,
+ };
+ const initializer = getDropShadowInitializer({
+ offset,
+ radius: 0.1234567890,
+ colorInitializer: 'init',
+ });
+ expect(initializer).toBe(`new DropShadow({offset: ${getPoint2DInitializer(offset)}, radius: 0.123457, color: init})`);
+ });
+});
diff --git a/packages/generation/test/goldens/codegennable/src/index.ts b/packages/generation/test/goldens/codegennable/src/index.ts
index 8f0ecb188..f4c0ffd77 100644
--- a/packages/generation/test/goldens/codegennable/src/index.ts
+++ b/packages/generation/test/goldens/codegennable/src/index.ts
@@ -1,4 +1,4 @@
-import { Color, File, Font, GradientStop, Image, LinearGradient, Point2D, Typograph } from "@diez/prefabs";
+import { Color, DropShadow, File, Font, GradientStop, Image, LinearGradient, Point2D, Typograph } from "@diez/prefabs";
class MyDesignSystemColors {
untitledColor = 2;
@@ -10,6 +10,11 @@ class MyDesignSystemGradients {
someGradient = 5;
}
+class MyDesignSystemShadows {
+ untitledShadow = 6;
+ someShadow = 7;
+}
+
class MyDesignSystemTypographs {
untitledTypograph = 0;
someTypograph = 1;
@@ -41,6 +46,7 @@ export const MyDesignSystemFonts = {
export class MyDesignSystemTokens {
colors = new MyDesignSystemColors();
gradients = new MyDesignSystemGradients();
+ shadows = new MyDesignSystemShadows();
typographs = new MyDesignSystemTypographs();
}
diff --git a/packages/generation/test/linear-gradient.test.ts b/packages/generation/test/linear-gradient.test.ts
index 4af38c34e..388b4920d 100644
--- a/packages/generation/test/linear-gradient.test.ts
+++ b/packages/generation/test/linear-gradient.test.ts
@@ -1,7 +1,7 @@
import {getLinearGradientInitializer} from '../src/linear-gradient';
describe('linear-gradient', () => {
- test('initializers', () => {
+ test('initializer', () => {
const start = {x: 0.1234567890, y: 0.1234567890};
const end = {x: 1.1234567890, y: 1.1234567890};
const stops = [
diff --git a/packages/generation/test/point2d.test.ts b/packages/generation/test/point2d.test.ts
new file mode 100644
index 000000000..31af0f999
--- /dev/null
+++ b/packages/generation/test/point2d.test.ts
@@ -0,0 +1,9 @@
+import {getPoint2DInitializer} from '../src/point2d';
+
+describe('point2d', () => {
+ test('initializer', () => {
+ const point = {x: 0.1234567890, y: 0.1234567890};
+ const initializer = getPoint2DInitializer(point);
+ expect(initializer).toBe('Point2D.make(0.123457, 0.123457)');
+ });
+});
diff --git a/packages/prefabs/src/drop-shadow.ts b/packages/prefabs/src/drop-shadow.ts
new file mode 100644
index 000000000..de5551f53
--- /dev/null
+++ b/packages/prefabs/src/drop-shadow.ts
@@ -0,0 +1,40 @@
+import {prefab} from '@diez/engine';
+import {Color} from './color';
+import {Point2D} from './point2d';
+
+/**
+ * DropShadow data.
+ */
+export interface DropShadowData {
+ /**
+ * The offset of the drop shadow.
+ *
+ * This is defined in a coordinate space where x+ is right and y+ is down.
+ */
+ offset: Point2D;
+ /**
+ * The blur radius of the drop shadow.
+ *
+ * This value assumes a Guassian blur and equals double the Guassian blur's standard deviation value.
+ *
+ * @see {@link https://drafts.csswg.org/css-backgrounds-3/#shadow-blur}
+ */
+ radius: number;
+ /**
+ * The color of the drop shadow.
+ */
+ color: Color;
+}
+
+/**
+ * Provides a drop shadow.
+ *
+ * @noinheritdoc
+ */
+export class DropShadow extends prefab() {
+ defaults = {
+ offset: Point2D.make(0, 0),
+ radius: 0,
+ color: Color.rgb(0, 0, 0),
+ };
+}
diff --git a/packages/prefabs/src/index.ts b/packages/prefabs/src/index.ts
index bce600b83..8492662db 100644
--- a/packages/prefabs/src/index.ts
+++ b/packages/prefabs/src/index.ts
@@ -1,4 +1,5 @@
export * from './color';
+export * from './drop-shadow';
export * from './file';
export * from './image';
export * from './linear-gradient';
diff --git a/packages/prefabs/test/drop-shadow.test.ts b/packages/prefabs/test/drop-shadow.test.ts
new file mode 100644
index 000000000..0800be73d
--- /dev/null
+++ b/packages/prefabs/test/drop-shadow.test.ts
@@ -0,0 +1,28 @@
+import {Color} from '../src/color';
+import {DropShadow} from '../src/drop-shadow';
+import {Point2D} from '../src/point2d';
+
+describe('DropShadow', () => {
+ test('basic functionality', () => {
+ const color = Color.hsla(0, 0.25, 0.5, 0.75);
+ const point = Point2D.make(1, 2);
+ const shadow = new DropShadow({
+ color,
+ offset: point,
+ radius: 3,
+ });
+ expect(shadow.serialize()).toEqual({
+ color: {
+ h: 0,
+ s: 0.25,
+ l: 0.5,
+ a: 0.75,
+ },
+ offset: {
+ x: 1,
+ y: 2,
+ },
+ radius: 3,
+ });
+ });
+});
diff --git a/packages/sources/src/exporters/figma.ts b/packages/sources/src/exporters/figma.ts
index ddf04979c..a6cd06dad 100644
--- a/packages/sources/src/exporters/figma.ts
+++ b/packages/sources/src/exporters/figma.ts
@@ -4,6 +4,7 @@ import {
codegenDesignSystem,
CodegenDesignSystem,
createDesignSystemSpec,
+ getDropShadowInitializer,
getLinearGradientInitializer,
getTypographInitializer,
locateFont,
@@ -55,7 +56,7 @@ const folders = new Map([
* Describes a Figma paint type retrieved from the Figma API.
* @ignore
*/
-export const enum FigmaPaintType {
+const enum FigmaPaintType {
Solid = 'SOLID',
GradientLinear = 'GRADIENT_LINEAR',
}
@@ -67,6 +68,11 @@ interface FigmaColor {
a: number;
}
+interface FigmaColorStop {
+ position: number;
+ color: FigmaColor;
+}
+
interface FigmaLinearGradient {
type: FigmaPaintType.GradientLinear;
gradientHandlePositions: FigmaVector[];
@@ -88,16 +94,32 @@ const isFigmaSolid = (paint: FigmaPaint): paint is FigmaSolid => {
return paint.type === FigmaPaintType.Solid;
};
+/**
+ * Describes a Figma effect type retrieved from the Figma API.
+ * @ignore
+ */
+const enum FigmaEffectType {
+ DropShadow = 'DROP_SHADOW',
+}
+
interface FigmaVector {
x: number;
y: number;
}
-interface FigmaColorStop {
- position: number;
+interface FigmaDropShadow {
+ type: FigmaEffectType.DropShadow;
color: FigmaColor;
+ offset: FigmaVector;
+ radius: number;
}
+type FigmaEffect = FigmaDropShadow | {type: unknown};
+
+const isFigmaDropShadow = (effect: FigmaEffect): effect is FigmaDropShadow => {
+ return effect.type === FigmaEffectType.DropShadow;
+};
+
interface FigmaTextStyle {
fontFamily: string;
fontPostScriptName: string;
@@ -114,9 +136,11 @@ interface FigmaNode {
name: string;
children?: FigmaNode[];
absoluteBoundingBox?: FigmaDimensions;
+ effects?: FigmaEffect[];
fills?: FigmaPaint[];
style?: FigmaTextStyle;
styles?: {
+ effect?: string;
fill?: string;
text?: string;
};
@@ -134,7 +158,7 @@ export interface FigmaFile {
styles?: {
[id: string]: {
name: string;
- styleType: 'FILL' | 'TEXT';
+ styleType: 'FILL' | 'TEXT' | 'EFFECT';
};
};
components?: {
@@ -233,30 +257,29 @@ const downloadAssets = async (
return Promise.all(streams);
};
-const populateInitializerForFigmaPaint = (paint: FigmaPaint, name: string, spec: CodegenDesignSystem) => {
- if (isFigmaSolid(paint)) {
- spec.colors.push({
- name,
- initializer: getSolidInitializerFromFigma(paint),
- });
- return;
- }
+const getDropShadowInitializerFromFigma = (shadow: FigmaDropShadow) =>
+ getDropShadowInitializer({
+ offset: shadow.offset,
+ radius: shadow.radius,
+ colorInitializer: getColorInitializerFromFigma(shadow.color),
+ });
- if (isFigmaLinearGradient(paint)) {
- spec.gradients.push({
+const populateInitializerForFigmaEffect = (effect: FigmaEffect, name: string, spec: CodegenDesignSystem) => {
+ if (isFigmaDropShadow(effect)) {
+ spec.shadows.push({
name,
- initializer: getLinearGradientInitializerFromFigma(paint),
+ initializer: getDropShadowInitializerFromFigma(effect),
});
return;
}
};
-const getSolidInitializerFromFigma = (solid: FigmaSolid) =>
- getColorInitializerFromFigma(solid.color);
-
const getColorInitializerFromFigma = ({r, g, b, a}: FigmaColor) =>
`Color.rgba(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(b * 255)}, ${a})`;
+const getSolidInitializerFromFigma = (solid: FigmaSolid) =>
+ getColorInitializerFromFigma(solid.color);
+
const getLinearGradientInitializerFromFigma = (gradient: FigmaLinearGradient) => {
const stops = gradient.gradientStops.map((stop) => {
return {
@@ -267,6 +290,24 @@ const getLinearGradientInitializerFromFigma = (gradient: FigmaLinearGradient) =>
return getLinearGradientInitializer(stops, gradient.gradientHandlePositions[0], gradient.gradientHandlePositions[1]);
};
+const populateInitializerForFigmaPaint = (paint: FigmaPaint, name: string, spec: CodegenDesignSystem) => {
+ if (isFigmaSolid(paint)) {
+ spec.colors.push({
+ name,
+ initializer: getSolidInitializerFromFigma(paint),
+ });
+ return;
+ }
+
+ if (isFigmaLinearGradient(paint)) {
+ spec.gradients.push({
+ name,
+ initializer: getLinearGradientInitializerFromFigma(paint),
+ });
+ return;
+ }
+};
+
const getInitializerForTypographColorFromFigma = (node: FigmaNode) => {
const fill = node.fills && node.fills[0];
if (!fill) {
@@ -288,17 +329,23 @@ const getInitializerForTypographColorFromFigma = (node: FigmaNode) => {
const processFigmaNode = async (
spec: CodegenDesignSystem,
+ effects: Map,
fills: Map,
typographs: Map,
components: Set,
componentDimensions: Map,
node: FigmaNode,
) => {
- if (!fills.size && !typographs.size && !components.size) {
+ if (!fills.size && !effects.size && !typographs.size && !components.size) {
return;
}
if (node.styles) {
+ if (effects.size && node.styles.effect && effects.has(node.styles.effect) && node.effects && node.effects.length) {
+ populateInitializerForFigmaEffect(node.effects[0], effects.get(node.styles.effect)!, spec);
+ effects.delete(node.styles.effect);
+ }
+
if (fills.size && node.styles.fill && fills.has(node.styles.fill) && node.fills && node.fills.length) {
populateInitializerForFigmaPaint(node.fills[0], fills.get(node.styles.fill)!, spec);
fills.delete(node.styles.fill);
@@ -336,7 +383,7 @@ const processFigmaNode = async (
if (node.children) {
for (const childNode of node.children) {
- await processFigmaNode(spec, fills, typographs, components, componentDimensions, childNode);
+ await processFigmaNode(spec, effects, fills, typographs, components, componentDimensions, childNode);
}
}
};
@@ -352,12 +399,14 @@ const parseFigmaFile = async (
const styles = Object.entries(file.styles || {});
const fills = new Map(styles.filter(
([_, {styleType}]) => styleType === 'FILL').map(([id, {name}]) => [id, name]));
+ const effects = new Map(styles.filter(
+ ([_, {styleType}]) => styleType === 'EFFECT').map(([id, {name}]) => [id, name]));
const typographs = new Map(styles.filter(
([_, {styleType}]) => styleType === 'TEXT').map(([id, {name}]) => [id, name]));
const components = new Set(filenameMap.keys());
const componentDimensions = new Map();
for (const node of file.document.children) {
- await processFigmaNode(spec, fills, typographs, components, componentDimensions, node);
+ await processFigmaNode(spec, effects, fills, typographs, components, componentDimensions, node);
}
for (const [id, filename] of filenameMap) {
diff --git a/packages/sources/src/exporters/sketch.ts b/packages/sources/src/exporters/sketch.ts
index 441ffff2d..88eee9023 100644
--- a/packages/sources/src/exporters/sketch.ts
+++ b/packages/sources/src/exporters/sketch.ts
@@ -1,11 +1,12 @@
import {execAsync, isMacOS, Log} from '@diez/cli-core';
import {
AssetFolder,
- CodegenDesignSystem,
codegenDesignSystem,
+ CodegenDesignSystem,
createDesignSystemSpec,
GeneratedAssets,
getColorInitializer,
+ getDropShadowInitializer,
getLinearGradientInitializer,
getTypographInitializer,
locateFont,
@@ -99,6 +100,20 @@ interface SketchSharedTypograph {
};
}
+interface SketchDropShadow {
+ offsetX: number;
+ offsetY: number;
+ blurRadius: number;
+ color: SketchColor;
+}
+
+interface SketchSharedLayerStyle {
+ name: string;
+ value: {
+ shadows: SketchDropShadow[];
+ };
+}
+
interface SketchLayer {
['']: string;
exportOptions: {
@@ -117,6 +132,9 @@ interface SketchDump {
layerTextStyles: {
objects: SketchSharedTypograph[];
};
+ layerStyles: {
+ objects: SketchSharedLayerStyle[];
+ };
pages: SketchLayer[];
}
@@ -143,16 +161,6 @@ const populateAssets = (assetsDirectory: string, layers: SketchLayer[], extracte
}
};
-const populateInitializerForSketchGradient = (gradient: SketchGradient, name: string, spec: CodegenDesignSystem) => {
- if (isSketchLinearGradient(gradient)) {
- spec.gradients.push({
- name,
- initializer: getLinearGradientInitializerForSketchGradient(gradient),
- });
- return;
- }
-};
-
const getLinearGradientInitializerForSketchGradient = (gradient: SketchLinearGradient) => {
const stops = gradient.stops.map((stop) => {
return {
@@ -163,6 +171,16 @@ const getLinearGradientInitializerForSketchGradient = (gradient: SketchLinearGra
return getLinearGradientInitializer(stops, gradient.from, gradient.to);
};
+const populateInitializerForSketchGradient = (gradient: SketchGradient, name: string, spec: CodegenDesignSystem) => {
+ if (isSketchLinearGradient(gradient)) {
+ spec.gradients.push({
+ name,
+ initializer: getLinearGradientInitializerForSketchGradient(gradient),
+ });
+ return;
+ }
+};
+
class SketchExporterImplementation implements Exporter {
/**
* ExporterFactory interface method.
@@ -236,6 +254,22 @@ class SketchExporterImplementation implements Exporter {
populateInitializerForSketchGradient(gradient.gradient, gradient.name, codegenSpec);
}
+ for (const style of dump.layerStyles.objects.filter((object) => object.value.shadows.length)) {
+ const shadow = style.value.shadows[0]!;
+ const initializer = getDropShadowInitializer({
+ colorInitializer: getColorInitializer(shadow.color.value),
+ offset: {
+ x: shadow.offsetX,
+ y: shadow.offsetY,
+ },
+ radius: shadow.blurRadius,
+ });
+ codegenSpec.shadows.push({
+ initializer,
+ name: `${style.name} Drop Shadow`,
+ });
+ }
+
for (const {name, value: {textStyle}} of dump.layerTextStyles.objects) {
const fontSize = textStyle.NSFont.attributes.NSFontSizeAttribute;
const candidateFont = await locateFont(
diff --git a/packages/sources/test/exporters/figma.test.ts b/packages/sources/test/exporters/figma.test.ts
index 1598b029a..4c776a77a 100644
--- a/packages/sources/test/exporters/figma.test.ts
+++ b/packages/sources/test/exporters/figma.test.ts
@@ -19,7 +19,7 @@ jest.doMock('@diez/storage', () => ({
}));
import {Readable} from 'stream';
-import {FigmaExporter, FigmaFile, FigmaPaintType} from '../../src/exporters/figma';
+import {FigmaExporter, FigmaFile} from '../../src/exporters/figma';
const figma = FigmaExporter.create('mock-token');
@@ -50,7 +50,7 @@ const mockFullResponse: FigmaFile = {
id: '',
name: '',
fills: [{
- type: FigmaPaintType.Solid,
+ type: 'SOLID',
color: {
r: 0.03921568627451,
g: 0.03921568627451,
@@ -66,7 +66,7 @@ const mockFullResponse: FigmaFile = {
id: '',
name: '',
fills: [{
- type: FigmaPaintType.Solid,
+ type: 'SOLID',
color: {
r: 0.392156862745098,
g: 0.392156862745098,
@@ -87,7 +87,7 @@ const mockFullResponse: FigmaFile = {
id: '',
name: '',
fills: [{
- type: FigmaPaintType.GradientLinear,
+ type: 'GRADIENT_LINEAR',
gradientHandlePositions: [
{
x: 2.220446049250313e-16,
@@ -138,7 +138,7 @@ const mockFullResponse: FigmaFile = {
id: '',
name: '',
fills: [{
- type: FigmaPaintType.GradientLinear,
+ type: 'GRADIENT_LINEAR',
gradientHandlePositions: [
{
x: 2.220446049250313e-16,
@@ -174,7 +174,22 @@ const mockFullResponse: FigmaFile = {
},
],
}],
+ effects: [{
+ type: 'DROP_SHADOW',
+ color: {
+ r: 0,
+ g: 0,
+ b: 0.062745101749897,
+ a: 0.4099999964237213,
+ },
+ offset: {
+ x: 0,
+ y: 1,
+ },
+ radius: 16,
+ }],
styles: {
+ effect: 'dropShadow',
fill: 'linearGradient',
},
},
@@ -201,6 +216,10 @@ const mockFullResponse: FigmaFile = {
name: 'Diez Black',
styleType: 'FILL',
},
+ dropShadow: {
+ name: 'Diez Drop Shadow',
+ styleType: 'EFFECT',
+ },
linearGradient: {
name: 'Diez Red To Purple',
styleType: 'FILL',
@@ -377,6 +396,12 @@ describe('Figma', () => {
new Map([['BoldItalic', {name: 'Foobar-BoldItalic', path: '/path/to/Foobar-BoldItalic.ttf'}]]),
]]),
projectRoot: '.',
+ shadows: [
+ {
+ initializer: 'new DropShadow({offset: Point2D.make(0.000000, 1.000000), radius: 16.000000, color: Color.rgba(0, 0, 16, 0.4099999964237213)})',
+ name: 'Diez Drop Shadow',
+ },
+ ],
typographs: [
{
name: 'Foobar Typograph',
diff --git a/packages/sources/test/exporters/invision.test.ts b/packages/sources/test/exporters/invision.test.ts
index 917e9ed22..b013dc078 100644
--- a/packages/sources/test/exporters/invision.test.ts
+++ b/packages/sources/test/exporters/invision.test.ts
@@ -76,6 +76,7 @@ describe('InvisionExporter', () => {
assetsDirectory: 'out/Test.invision.contents',
colors: [{initializer: 'Color.rgba(255, 0, 0, 1)', name: 'Red'}],
gradients: [],
+ shadows: [],
designSystemName: 'Test',
filename: 'src/Test.invision.ts',
fonts: new Map([['Foobar', new Map([['Italic', {name: 'Foobar-Italic', path: '/path/to/Foobar-Italic.ttf'}]])]]),
diff --git a/packages/sources/test/exporters/sketch.test.ts b/packages/sources/test/exporters/sketch.test.ts
index a2c366005..4fea52b0a 100644
--- a/packages/sources/test/exporters/sketch.test.ts
+++ b/packages/sources/test/exporters/sketch.test.ts
@@ -75,6 +75,26 @@ beforeEach(() => {
],
imageCollection: [],
},
+ layerStyles: {
+ objects: [
+ {
+ name: 'Card Style',
+ value: {
+ shadows: [
+ {
+ blurRadius: 30,
+ color: {
+ value: 'rgba(255,63,112,0.70)',
+ },
+ isEnabled: 1,
+ offsetX: 0,
+ offsetY: 2,
+ },
+ ],
+ },
+ },
+ ],
+ },
layerTextStyles: {
objects: [
{
@@ -202,6 +222,12 @@ describe('Sketch', () => {
name: 'Pink To Orange',
initializer: 'new LinearGradient({stops: [GradientStop.make(0.000000, Color.rgba(255, 63, 112, 1)), GradientStop.make(1.000000, Color.rgba(255, 154, 58, 1))], start: Point2D.make(0.256905, -0.052988), end: Point2D.make(0.912005, 1.039424)})',
}],
+ shadows: [
+ {
+ name: 'Card Style Drop Shadow',
+ initializer: 'new DropShadow({offset: Point2D.make(0.000000, 2.000000), radius: 30.000000, color: Color.rgba(255, 63, 112, 0.7)})',
+ },
+ ],
designSystemName: 'Test',
filename: 'src/Test.sketch.ts',
fonts: new Map([['Foobar', new Map([['BoldItalic', {name: 'Foobar-BoldItalic', path: '/path/to/Foobar-BoldItalic.ttf'}]])]]),
diff --git a/packages/targets/.diezrc b/packages/targets/.diezrc
index e11872905..4fea2719e 100644
--- a/packages/targets/.diezrc
+++ b/packages/targets/.diezrc
@@ -15,6 +15,11 @@
"android": "./lib/bindings/Color/android",
"web": "./lib/bindings/Color/web"
},
+ "@diez/prefabs:DropShadow": {
+ "ios": "./lib/bindings/DropShadow/ios",
+ "android": "./lib/bindings/DropShadow/android",
+ "web": "./lib/bindings/DropShadow/web"
+ },
"@diez/prefabs:File": {
"ios": "./lib/bindings/File/ios",
"android": "./lib/bindings/File/android",
diff --git a/packages/targets/sources/ios/bindings/DropShadow+Binding.swift b/packages/targets/sources/ios/bindings/DropShadow+Binding.swift
new file mode 100644
index 000000000..a8fd12d86
--- /dev/null
+++ b/packages/targets/sources/ios/bindings/DropShadow+Binding.swift
@@ -0,0 +1,15 @@
+import Foundation
+import UIKit
+
+extension CALayer {
+ @objc(dez_applyDropShadow:)
+ public func apply(_ shadow: DropShadow) {
+ masksToBounds = false
+ shadowOpacity = 1
+ shadowOffset = CGSize(width: shadow.offset.cgPoint.x, height: shadow.offset.cgPoint.y)
+ // `DropShadow`'s `radius` value is equal to twice the desired Guassian blur standard deviation.
+ // `shadowRadius` expects the standard deviation value so the value must be cut in half.
+ shadowRadius = shadow.radius / 2
+ shadowColor = shadow.color.uiColor.cgColor
+ }
+}
diff --git a/packages/targets/sources/web/bindings/DropShadow.d.ts b/packages/targets/sources/web/bindings/DropShadow.d.ts
new file mode 100644
index 000000000..beda2ea86
--- /dev/null
+++ b/packages/targets/sources/web/bindings/DropShadow.d.ts
@@ -0,0 +1,32 @@
+export declare class DropShadow {
+ /**
+ * The CSS box-shadow representation of the `DropShadow`.
+ * @example
+ * 0px 1px 16px rgba(0, 0, 16, .4)
+ */
+ boxShadow: string;
+ /**
+ * The CSS text-shadow representation of the `DropShadow`.
+ * @example
+ * 0px 1px 16px rgba(0, 0, 16, .4)
+ */
+ textShadow: string;
+ /**
+ * The CSS filter representation of the `DropShadow`.
+ * @example
+ * drop-shadow(0px 1px 16px rgba(0, 0, 16, .4))
+ */
+ filter: string;
+ /**
+ * CSS declarations for the `box-shadow` CSS property.
+ */
+ boxShadowStyle: {boxShadow: string};
+ /**
+ * CSS declarations for the `text-shadow` CSS property.
+ */
+ textShadowStyle: {textShadow: string};
+ /**
+ * CSS declarations for the `filter` CSS property.
+ */
+ filterStyle: {filter: string};
+}
diff --git a/packages/targets/sources/web/bindings/DropShadow.js b/packages/targets/sources/web/bindings/DropShadow.js
new file mode 100644
index 000000000..c85bead41
--- /dev/null
+++ b/packages/targets/sources/web/bindings/DropShadow.js
@@ -0,0 +1,40 @@
+const {dropShadowToCss, dropShadowToFilterCss} = require('@diez/web-sdk-common');
+
+Object.defineProperties(DropShadow.prototype, {
+ boxShadow: {
+ get () {
+ return dropShadowToCss(this);
+ },
+ },
+ textShadow: {
+ get () {
+ return dropShadowToCss(this);
+ },
+ },
+ filter: {
+ get () {
+ return dropShadowToFilterCss(this);
+ },
+ },
+ boxShadowStyle: {
+ get () {
+ return {
+ boxShadow: this.boxShadow,
+ };
+ },
+ },
+ textShadowStyle: {
+ get () {
+ return {
+ textShadow: this.textShadow,
+ };
+ },
+ },
+ filterStyle: {
+ get () {
+ return {
+ filter: this.filter,
+ };
+ },
+ },
+});
diff --git a/packages/targets/sources/web/bindings/LinearGradient.d.ts b/packages/targets/sources/web/bindings/LinearGradient.d.ts
index 2a006ac89..3eeedba2f 100644
--- a/packages/targets/sources/web/bindings/LinearGradient.d.ts
+++ b/packages/targets/sources/web/bindings/LinearGradient.d.ts
@@ -1,6 +1,6 @@
export declare class LinearGradient {
/**
- * The CSS linear-gradient represntation of the `LinearGradient`.
+ * The CSS linear-gradient representation of the `LinearGradient`.
* @example
* linear-gradient(45deg, hsla(0, 0%, 100%, 1) 0%, hsla(0, 0%, 0%, 1) 100%)
*/
diff --git a/packages/targets/src/bindings/Color/web.ts b/packages/targets/src/bindings/Color/web.ts
index 4c1ef4f30..e25140f54 100644
--- a/packages/targets/src/bindings/Color/web.ts
+++ b/packages/targets/src/bindings/Color/web.ts
@@ -8,7 +8,7 @@ const binding: WebBinding = {
declarations: [join(sourcesPath, 'web', 'bindings', 'Color.d.ts')],
assetsBinder: async (instance, program, output, spec, property) => {
// TODO: this shouldn't be necessary with a good and general design for "resource boundaries".
- if (property.parentType === 'Typograph') {
+ if (property.parentType === 'Typograph' || property.parentType === 'DropShadow') {
return;
}
diff --git a/packages/targets/src/bindings/DropShadow/android.ts b/packages/targets/src/bindings/DropShadow/android.ts
new file mode 100644
index 000000000..3cc9ff697
--- /dev/null
+++ b/packages/targets/src/bindings/DropShadow/android.ts
@@ -0,0 +1,10 @@
+import {DropShadow} from '@diez/prefabs';
+import {AndroidBinding} from '../../targets/android.api';
+
+const binding: AndroidBinding = {
+ // TODO: Remove the need to provide an empty binding on prefabs without any binding overrides.
+ // Provide an empty array to prevent this prefab from being treated as a singleton.
+ sources: [],
+};
+
+export = binding;
diff --git a/packages/targets/src/bindings/DropShadow/ios.ts b/packages/targets/src/bindings/DropShadow/ios.ts
new file mode 100644
index 000000000..40bd2126c
--- /dev/null
+++ b/packages/targets/src/bindings/DropShadow/ios.ts
@@ -0,0 +1,12 @@
+import {DropShadow} from '@diez/prefabs';
+import {join} from 'path';
+import {IosBinding} from '../../targets/ios.api';
+import {sourcesPath} from '../../utils';
+
+const binding: IosBinding = {
+ sources: [
+ join(sourcesPath, 'ios', 'bindings', 'DropShadow+Binding.swift'),
+ ],
+};
+
+export = binding;
diff --git a/packages/targets/src/bindings/DropShadow/web.ts b/packages/targets/src/bindings/DropShadow/web.ts
new file mode 100644
index 000000000..4210f6af7
--- /dev/null
+++ b/packages/targets/src/bindings/DropShadow/web.ts
@@ -0,0 +1,48 @@
+import {diezVersion} from '@diez/cli-core';
+import {DropShadow} from '@diez/prefabs';
+import {dropShadowToCss, dropShadowToFilterCss} from '@diez/web-sdk-common';
+import {join} from 'path';
+import {WebBinding} from '../../targets/web.api';
+import {joinToKebabCase, sourcesPath} from '../../utils';
+
+const binding: WebBinding = {
+ sources: [join(sourcesPath, 'web', 'bindings', 'DropShadow.js')],
+ declarations: [join(sourcesPath, 'web', 'bindings', 'DropShadow.d.ts')],
+ assetsBinder: async (instance, program, output, spec, property) => {
+ const name = joinToKebabCase(property.parentType, property.name);
+ const value = dropShadowToCss(instance);
+ const filterValue = dropShadowToFilterCss(instance);
+
+ output.styleSheet.styles.insertRule({
+ selector: `${name}-box-shadow`,
+ declaration: {
+ 'box-shadow': value,
+ },
+ });
+
+ output.styleSheet.styles.insertRule({
+ selector: `${name}-text-shadow`,
+ declaration: {
+ 'text-shadow': value,
+ },
+ });
+
+ output.styleSheet.styles.insertRule({
+ selector: `${name}-filter`,
+ declaration: {
+ filter: filterValue,
+ },
+ });
+
+ output.styleSheet.variables.set(name, value);
+ output.styleSheet.variables.set(`${name}-filter`, filterValue);
+ },
+ dependencies: [{
+ packageJson: {
+ name: '@diez/web-sdk-common',
+ versionConstraint: `^${diezVersion}`,
+ },
+ }],
+};
+
+export = binding;
diff --git a/packages/targets/src/bindings/Point2D/web.ts b/packages/targets/src/bindings/Point2D/web.ts
index 3526037e5..0340b4741 100644
--- a/packages/targets/src/bindings/Point2D/web.ts
+++ b/packages/targets/src/bindings/Point2D/web.ts
@@ -8,7 +8,7 @@ const binding: WebBinding = {
sources: [],
assetsBinder: async (instance, program, output, spec, property) => {
// TODO: this shouldn't be necessary with a good and general design for "resource boundaries".
- if (property.parentType !== 'LinearGradient') {
+ if (property.parentType !== 'LinearGradient' && property.parentType !== 'DropShadow') {
const name = joinToKebabCase(property.parentType, property.name);
output.styleSheet.variables.set(`${name}-x-px`, `${instance.x}px`);
output.styleSheet.variables.set(`${name}-x-rem`, `${instance.x}rem`);
diff --git a/packages/targets/test/fixtures/Bindings/Bindings.ts b/packages/targets/test/fixtures/Bindings/Bindings.ts
index 37a9d199e..0b3ba018f 100644
--- a/packages/targets/test/fixtures/Bindings/Bindings.ts
+++ b/packages/targets/test/fixtures/Bindings/Bindings.ts
@@ -1,5 +1,6 @@
import {
Color,
+ DropShadow,
File,
FileType,
Font,
@@ -9,7 +10,7 @@ import {
Point2D,
Size2D,
Toward,
- Typograph
+ Typograph,
} from '@diez/prefabs';
export class Bindings {
@@ -33,4 +34,10 @@ export class Bindings {
point = Point2D.make(0.5, 0.5);
size = Size2D.make(400, 300);
+
+ shadow = new DropShadow({
+ offset: Point2D.make(1, 2),
+ radius: 3,
+ color: Color.rgba(0, 255, 0, 0.5),
+ });
}
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Bindings.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Bindings.kt
similarity index 85%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Bindings.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Bindings.kt
index 63babac2c..c77418cea 100644
--- a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Bindings.kt
+++ b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Bindings.kt
@@ -6,7 +6,8 @@ data class Bindings(
val typograph: Typograph = Typograph(Font(File("assets/SomeFont.ttf", "font"), "SomeFont"), 50F, Color(0.16666666666666666F, 1F, 0.5F, 1F)),
val linearGradient: LinearGradient = LinearGradient(arrayOf(GradientStop(0F, Color(0F, 1F, 0.5F, 1F)), GradientStop(1F, Color(0.6666666666666666F, 1F, 0.5F, 1F))), Point2D(0F, 0.5F), Point2D(1F, 0.5F)),
val point: Point2D = Point2D(0.5F, 0.5F),
- val size: Size2D = Size2D(400F, 300F)
+ val size: Size2D = Size2D(400F, 300F),
+ val shadow: DropShadow = DropShadow(Point2D(1F, 2F), 3F, Color(0.3333333333333333F, 1F, 0.5F, 0.5F))
) : StateBag {
companion object {}
override val name = "Bindings"
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Color.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Color.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Color.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Color.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Diez.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Diez.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Diez.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Diez.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/DropShadow.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/DropShadow.kt
new file mode 100644
index 000000000..86b079879
--- /dev/null
+++ b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/DropShadow.kt
@@ -0,0 +1,9 @@
+package org.diez.stub
+
+data class DropShadow(
+ val offset: Point2D,
+ val radius: Float,
+ val color: Color
+) {
+ companion object {}
+}
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Environment.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Environment.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Environment.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Environment.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/File.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/File.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/File.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/File.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Font.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Font.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Font.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Font.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/GradientStop.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/GradientStop.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/GradientStop.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/GradientStop.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Image.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Image.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Image.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Image.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/LinearGradient.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/LinearGradient.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/LinearGradient.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/LinearGradient.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Lottie.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Lottie.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Lottie.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Lottie.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Point2D.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Point2D.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Point2D.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Point2D.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Size2D.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Size2D.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Size2D.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Size2D.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Typograph.kt b/packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Typograph.kt
similarity index 100%
rename from packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/Stub/Typograph.kt
rename to packages/targets/test/goldens/Bindings/diez-stub-android/src/main/java/org/diez/stub/Typograph.kt
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.xcodeproj/project.pbxproj b/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.xcodeproj/project.pbxproj
index 046eb4781..1e1d50ec5 100644
--- a/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.xcodeproj/project.pbxproj
+++ b/packages/targets/test/goldens/Bindings/diez-stub-ios/DiezStub.xcodeproj/project.pbxproj
@@ -17,6 +17,7 @@
30D8DCC71661D0ECFB778AA59754131A /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8778BD519B243F8B2E2F9E6B58B6660F /* Environment.swift */; };
31D405B5F5E3947ED5EC505C44F4868D /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6639302602D066191557EE67F2F3A8BB /* File.swift */; };
35C4CB5F2F0A994E4D65F1145C6CBCCC /* Bundle+Static.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A2033D197C87132619563FDCBF3076E /* Bundle+Static.swift */; };
+ 3769622C01C56887C932DC6D84D79C94 /* DropShadow+Binding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 888C24B260614F9427FA14F4E1CB36CE /* DropShadow+Binding.swift */; };
43F025A40CF48D48F83C7F712D32F9BE /* Lottie+Binding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BEA91049CF649A1AE50E700DB149E5 /* Lottie+Binding.swift */; };
48154B23C778B69B9B7892F5EE62A1D5 /* Size2D.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FFBF4FBE0FC8626F48B4AD710A00CDE /* Size2D.swift */; };
48EEAB321103D62DCD14567E8777BBD2 /* Typograph+Binding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1134BF4AC055DADAD76630D14C02E8A2 /* Typograph+Binding.swift */; };
@@ -34,6 +35,7 @@
BA3861C33773396382B30BD9AB6F0D3B /* Lottie.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9A0B8DEBE9CB8D94DACCED192B2D4E6 /* Lottie.framework */; };
BA503BB9F3C1F14E9E0521FB0144E94D /* Image+Binding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DC81DA6485DC5CEADF4FB56A15C36F3 /* Image+Binding.swift */; };
C2EE21012304852D84A336CE164EB6DF /* GradientStop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CBE006ECEAF9C243C561883C13A8CE /* GradientStop.swift */; };
+ C435F8C907683050CB21BCFBDC2D054A /* DropShadow.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0D2FA722CA1E02A23081718A4FD4D8 /* DropShadow.swift */; };
CB77CEDF8462794317E629439E5483D6 /* Color+Binding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A67FEB60DD6033589048DEE59E4C2A8 /* Color+Binding.swift */; };
D60BA4F9FF449FB834140D4F4E27E1F8 /* Size2D+Binding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A5BEEA9D863F4BE188359CB877C2E3 /* Size2D+Binding.swift */; };
EE60578FFB630A1C71BFD87CBD693839 /* File+Binding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 532372957C7BF2D47B40B9DD6C61D279 /* File+Binding.swift */; };
@@ -68,6 +70,7 @@
813812AEFCC1BB5B22C557244A1BE5F5 /* LinearGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinearGradient.swift; sourceTree = ""; };
853B0CBAF15611244D045E7999114C8A /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = ""; };
8778BD519B243F8B2E2F9E6B58B6660F /* Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; };
+ 888C24B260614F9427FA14F4E1CB36CE /* DropShadow+Binding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DropShadow+Binding.swift"; sourceTree = ""; };
8DC81DA6485DC5CEADF4FB56A15C36F3 /* Image+Binding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Image+Binding.swift"; sourceTree = ""; };
9BE97E7A473C2D663F9221BBCFB0D6E5 /* Bundle+Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Environment.swift"; sourceTree = ""; };
9FFBF4FBE0FC8626F48B4AD710A00CDE /* Size2D.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Size2D.swift; sourceTree = ""; };
@@ -81,6 +84,7 @@
D80839BA9666C276FD55637472736C1A /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = assets; path = Sources/Static/assets; sourceTree = SOURCE_ROOT; };
D81C57324B94295575E3676C0F32C8D0 /* Bundle+File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+File.swift"; sourceTree = ""; };
DBA378500CBA8DF7D7D2779A86A54AAD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ ED0D2FA722CA1E02A23081718A4FD4D8 /* DropShadow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadow.swift; sourceTree = ""; };
EDE20D5466E834322461A7693EB8C949 /* Point2D.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Point2D.swift; sourceTree = ""; };
/* End PBXFileReference section */
@@ -137,6 +141,7 @@
children = (
D81C57324B94295575E3676C0F32C8D0 /* Bundle+File.swift */,
2A67FEB60DD6033589048DEE59E4C2A8 /* Color+Binding.swift */,
+ 888C24B260614F9427FA14F4E1CB36CE /* DropShadow+Binding.swift */,
532372957C7BF2D47B40B9DD6C61D279 /* File+Binding.swift */,
8DC81DA6485DC5CEADF4FB56A15C36F3 /* Image+Binding.swift */,
A6C61241B372972554AA1D66DF18F052 /* LinearGradient+Binding.swift */,
@@ -175,6 +180,7 @@
children = (
123F5E73C868209F9A884D6D03B826D6 /* Bindings.swift */,
C3079B1384BD06EE8EBB48505985BAC9 /* Color.swift */,
+ ED0D2FA722CA1E02A23081718A4FD4D8 /* DropShadow.swift */,
6639302602D066191557EE67F2F3A8BB /* File.swift */,
CF6D6468DECE18204492CA00282CCC8F /* Font.swift */,
70CBE006ECEAF9C243C561883C13A8CE /* GradientStop.swift */,
@@ -310,6 +316,8 @@
CB77CEDF8462794317E629439E5483D6 /* Color+Binding.swift in Sources */,
64623CF1B84B7964CC33E272B5165330 /* Color.swift in Sources */,
1B0A959296A666217D7A0B4C315371A9 /* Diez.swift in Sources */,
+ 3769622C01C56887C932DC6D84D79C94 /* DropShadow+Binding.swift in Sources */,
+ C435F8C907683050CB21BCFBDC2D054A /* DropShadow.swift in Sources */,
30D8DCC71661D0ECFB778AA59754131A /* Environment.swift in Sources */,
EE60578FFB630A1C71BFD87CBD693839 /* File+Binding.swift in Sources */,
31D405B5F5E3947ED5EC505C44F4868D /* File.swift in Sources */,
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Bindings/DropShadow+Binding.swift b/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Bindings/DropShadow+Binding.swift
new file mode 100644
index 000000000..a8fd12d86
--- /dev/null
+++ b/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Bindings/DropShadow+Binding.swift
@@ -0,0 +1,15 @@
+import Foundation
+import UIKit
+
+extension CALayer {
+ @objc(dez_applyDropShadow:)
+ public func apply(_ shadow: DropShadow) {
+ masksToBounds = false
+ shadowOpacity = 1
+ shadowOffset = CGSize(width: shadow.offset.cgPoint.x, height: shadow.offset.cgPoint.y)
+ // `DropShadow`'s `radius` value is equal to twice the desired Guassian blur standard deviation.
+ // `shadowRadius` expects the standard deviation value so the value must be cut in half.
+ shadowRadius = shadow.radius / 2
+ shadowColor = shadow.color.uiColor.cgColor
+ }
+}
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Components/Bindings.swift b/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Components/Bindings.swift
index 6b3dba984..9daa9c709 100644
--- a/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Components/Bindings.swift
+++ b/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Components/Bindings.swift
@@ -9,6 +9,7 @@ public final class Bindings: NSObject, StateBag {
@objc public internal(set) var linearGradient: LinearGradient
@objc public internal(set) var point: Point2D
@objc public internal(set) var size: Size2D
+ @objc public internal(set) var shadow: DropShadow
convenience public override init() {
self.init(
@@ -17,7 +18,8 @@ public final class Bindings: NSObject, StateBag {
typograph: Typograph(font: Font(file: File(src: "assets/SomeFont.ttf", type: "font"), name: "SomeFont"), fontSize: 50, color: Color(h: 0.16666666666666666, s: 1, l: 0.5, a: 1)),
linearGradient: LinearGradient(stops: [GradientStop(position: 0, color: Color(h: 0, s: 1, l: 0.5, a: 1)), GradientStop(position: 1, color: Color(h: 0.6666666666666666, s: 1, l: 0.5, a: 1))], start: Point2D(x: 0, y: 0.5), end: Point2D(x: 1, y: 0.5)),
point: Point2D(x: 0.5, y: 0.5),
- size: Size2D(width: 400, height: 300)
+ size: Size2D(width: 400, height: 300),
+ shadow: DropShadow(offset: Point2D(x: 1, y: 2), radius: 3, color: Color(h: 0.3333333333333333, s: 1, l: 0.5, a: 0.5))
)
}
@@ -27,7 +29,8 @@ public final class Bindings: NSObject, StateBag {
typograph: Typograph,
linearGradient: LinearGradient,
point: Point2D,
- size: Size2D
+ size: Size2D,
+ shadow: DropShadow
) {
self.image = image
self.lottie = lottie
@@ -35,6 +38,7 @@ public final class Bindings: NSObject, StateBag {
self.linearGradient = linearGradient
self.point = point
self.size = size
+ self.shadow = shadow
}
public static let name = "Bindings"
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Components/DropShadow.swift b/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Components/DropShadow.swift
new file mode 100644
index 000000000..dc30f97d4
--- /dev/null
+++ b/packages/targets/test/goldens/Bindings/diez-stub-ios/Sources/DiezStub/Components/DropShadow.swift
@@ -0,0 +1,25 @@
+import Foundation
+import CoreGraphics
+
+@objc(DEZDropShadow)
+public final class DropShadow: NSObject, Decodable {
+ @objc public internal(set) var offset: Point2D
+ @objc public internal(set) var radius: CGFloat
+ @objc public internal(set) var color: Color
+
+ init(
+ offset: Point2D,
+ radius: CGFloat,
+ color: Color
+ ) {
+ self.offset = offset
+ self.radius = radius
+ self.color = color
+ }
+}
+
+extension DropShadow: ReflectedCustomStringConvertible {
+ public override var description: String {
+ return reflectedDescription
+ }
+}
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-web/index.d.ts b/packages/targets/test/goldens/Bindings/diez-stub-web/index.d.ts
index b28d6a5fa..81ae11f73 100644
--- a/packages/targets/test/goldens/Bindings/diez-stub-web/index.d.ts
+++ b/packages/targets/test/goldens/Bindings/diez-stub-web/index.d.ts
@@ -148,7 +148,7 @@ export declare class Point2D {
export declare class LinearGradient {
/**
- * The CSS linear-gradient represntation of the `LinearGradient`.
+ * The CSS linear-gradient representation of the `LinearGradient`.
* @example
* linear-gradient(45deg, hsla(0, 0%, 100%, 1) 0%, hsla(0, 0%, 0%, 1) 100%)
*/
@@ -163,6 +163,39 @@ export declare class LinearGradient {
backgroundStyle: {background: string};
}
+export declare class DropShadow {
+ /**
+ * The CSS box-shadow representation of the `DropShadow`.
+ * @example
+ * 0px 1px 16px rgba(0, 0, 16, .4)
+ */
+ boxShadow: string;
+ /**
+ * The CSS text-shadow representation of the `DropShadow`.
+ * @example
+ * 0px 1px 16px rgba(0, 0, 16, .4)
+ */
+ textShadow: string;
+ /**
+ * The CSS filter representation of the `DropShadow`.
+ * @example
+ * drop-shadow(0px 1px 16px rgba(0, 0, 16, .4))
+ */
+ filter: string;
+ /**
+ * CSS declarations for the `box-shadow` CSS property.
+ */
+ boxShadowStyle: {boxShadow: string};
+ /**
+ * CSS declarations for the `text-shadow` CSS property.
+ */
+ textShadowStyle: {textShadow: string};
+ /**
+ * CSS declarations for the `filter` CSS property.
+ */
+ filterStyle: {filter: string};
+}
+
export declare class Bindings extends StateBag {
image: Image;
lottie: Lottie;
@@ -170,5 +203,6 @@ export declare class Bindings extends StateBag {
linearGradient: LinearGradient;
point: Point2D;
size: Size2D;
+ shadow: DropShadow;
}
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-web/index.js b/packages/targets/test/goldens/Bindings/diez-stub-web/index.js
index 2794db4a0..0bbc97624 100644
--- a/packages/targets/test/goldens/Bindings/diez-stub-web/index.js
+++ b/packages/targets/test/goldens/Bindings/diez-stub-web/index.js
@@ -407,6 +407,62 @@ Object.defineProperties(LinearGradient.prototype, {
},
});
+class DropShadow {
+ constructor({
+ offset,
+ radius,
+ color
+ }) {
+ this.offset = new Point2D(offset);
+ this.radius = radius;
+ this.color = new Color(color);
+ }
+}
+
+
+module.exports.DropShadow = DropShadow;
+
+const {dropShadowToCss, dropShadowToFilterCss} = require('@diez/web-sdk-common');
+
+Object.defineProperties(DropShadow.prototype, {
+ boxShadow: {
+ get () {
+ return dropShadowToCss(this);
+ },
+ },
+ textShadow: {
+ get () {
+ return dropShadowToCss(this);
+ },
+ },
+ filter: {
+ get () {
+ return dropShadowToFilterCss(this);
+ },
+ },
+ boxShadowStyle: {
+ get () {
+ return {
+ boxShadow: this.boxShadow,
+ };
+ },
+ },
+ textShadowStyle: {
+ get () {
+ return {
+ textShadow: this.textShadow,
+ };
+ },
+ },
+ filterStyle: {
+ get () {
+ return {
+ filter: this.filter,
+ };
+ },
+ },
+});
+
class Bindings {
constructor({
image = {file: {src: "assets/image%20with%20spaces.jpg", type: "image"}, file2x: {src: "assets/image%20with%20spaces@2x.jpg", type: "image"}, file3x: {src: "assets/image%20with%20spaces@3x.jpg", type: "image"}, size: {width: 246, height: 246}},
@@ -414,7 +470,8 @@ class Bindings {
typograph = {font: {file: {src: "assets/SomeFont.ttf", type: "font"}, name: "SomeFont", fallbacks: ["Verdana", "serif"], weight: 700, style: "normal"}, fontSize: 50, color: {h: 0.16666666666666666, s: 1, l: 0.5, a: 1}},
linearGradient = {stops: [{position: 0, color: {h: 0, s: 1, l: 0.5, a: 1}}, {position: 1, color: {h: 0.6666666666666666, s: 1, l: 0.5, a: 1}}], start: {x: 0, y: 0.5}, end: {x: 1, y: 0.5}},
point = {x: 0.5, y: 0.5},
- size = {width: 400, height: 300}
+ size = {width: 400, height: 300},
+ shadow = {offset: {x: 1, y: 2}, radius: 3, color: {h: 0.3333333333333333, s: 1, l: 0.5, a: 0.5}}
} = {}) {
this.image = new Image(image);
this.lottie = new Lottie(lottie);
@@ -422,6 +479,7 @@ class Bindings {
this.linearGradient = new LinearGradient(linearGradient);
this.point = new Point2D(point);
this.size = new Size2D(size);
+ this.shadow = new DropShadow(shadow);
}
}
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-web/static/styles.css b/packages/targets/test/goldens/Bindings/diez-stub-web/static/styles.css
index 186ca4409..14249f210 100644
--- a/packages/targets/test/goldens/Bindings/diez-stub-web/static/styles.css
+++ b/packages/targets/test/goldens/Bindings/diez-stub-web/static/styles.css
@@ -22,6 +22,8 @@
--bindings-size-width-rem: 400rem;
--bindings-size-height-px: 300px;
--bindings-size-height-rem: 300rem;
+ --bindings-shadow: 1px 2px 3px hsla(120, 100%, 50%, 0.5);
+ --bindings-shadow-filter: drop-shadow(1px 2px 1.5px hsla(120, 100%, 50%, 0.5));
}
.bindings-image-background-image {
@@ -67,3 +69,15 @@
background-image: linear-gradient(90deg, hsla(0, 100%, 50%, 1) 0%, hsla(240, 100%, 50%, 1) 100%);
}
+.bindings-shadow-box-shadow {
+ box-shadow: 1px 2px 3px hsla(120, 100%, 50%, 0.5);
+}
+
+.bindings-shadow-text-shadow {
+ text-shadow: 1px 2px 3px hsla(120, 100%, 50%, 0.5);
+}
+
+.bindings-shadow-filter {
+ filter: drop-shadow(1px 2px 1.5px hsla(120, 100%, 50%, 0.5));
+}
+
diff --git a/packages/targets/test/goldens/Bindings/diez-stub-web/static/styles.scss b/packages/targets/test/goldens/Bindings/diez-stub-web/static/styles.scss
index 4f94244ee..9a8062653 100644
--- a/packages/targets/test/goldens/Bindings/diez-stub-web/static/styles.scss
+++ b/packages/targets/test/goldens/Bindings/diez-stub-web/static/styles.scss
@@ -21,6 +21,8 @@ $bindings-size-width-px: 400px;
$bindings-size-width-rem: 400rem;
$bindings-size-height-px: 300px;
$bindings-size-height-rem: 300rem;
+$bindings-shadow: 1px 2px 3px hsla(120, 100%, 50%, 0.5);
+$bindings-shadow-filter: drop-shadow(1px 2px 1.5px hsla(120, 100%, 50%, 0.5));
@mixin bindings-image-background-image {
background-image: url("/diez/assets/image with spaces.jpg");
@@ -61,3 +63,15 @@ $bindings-size-height-rem: 300rem;
background-image: linear-gradient(90deg, hsla(0, 100%, 50%, 1) 0%, hsla(240, 100%, 50%, 1) 100%);
}
+@mixin bindings-shadow-box-shadow {
+ box-shadow: 1px 2px 3px hsla(120, 100%, 50%, 0.5);
+}
+
+@mixin bindings-shadow-text-shadow {
+ text-shadow: 1px 2px 3px hsla(120, 100%, 50%, 0.5);
+}
+
+@mixin bindings-shadow-filter {
+ filter: drop-shadow(1px 2px 1.5px hsla(120, 100%, 50%, 0.5));
+}
+
diff --git a/packages/web-sdk-common/src/css-drop-shadow.ts b/packages/web-sdk-common/src/css-drop-shadow.ts
new file mode 100644
index 000000000..45c5d5dcb
--- /dev/null
+++ b/packages/web-sdk-common/src/css-drop-shadow.ts
@@ -0,0 +1,27 @@
+import {DropShadowData} from '@diez/prefabs';
+
+/**
+ * Returns a string containing a valid CSS value for and/or from a [[Shadow]] prefab
+ * instance.
+ */
+export const dropShadowToCss = (shadow: DropShadowData) => {
+ // TODO: Use `colorToCss` once it's moved into this package.
+ const {h, s, l, a} = shadow.color;
+ const color = `hsla(${h * 360}, ${s * 100}%, ${l * 100}%, ${a})`;
+ return `${shadow.offset.x}px ${shadow.offset.y}px ${shadow.radius}px ${color}`;
+};
+
+/**
+ * Returns a string containing a valid CSS value from a [[Shadow]] prefab instance.
+ */
+export const dropShadowToFilterCss = (shadow: DropShadowData) => {
+ // TODO: Use `colorToCss` once it's moved into this package.
+ const {h, s, l, a} = shadow.color;
+ const color = `hsla(${h * 360}, ${s * 100}%, ${l * 100}%, ${a})`;
+
+ // Since the `DropShadowData`'s radius value represents double the standard deviation of the desired Guassian blur,
+ // and `drop-shadow` expects the standard deviation, the value must be cut in half.
+ // See https://css-tricks.com/breaking-css-box-shadow-vs-drop-shadow/#comment-1612592
+ const radius = shadow.radius / 2;
+ return `drop-shadow(${shadow.offset.x}px ${shadow.offset.y}px ${radius}px ${color})`;
+};
diff --git a/packages/web-sdk-common/src/index.ts b/packages/web-sdk-common/src/index.ts
index b3846a0c8..e14d83bc3 100644
--- a/packages/web-sdk-common/src/index.ts
+++ b/packages/web-sdk-common/src/index.ts
@@ -1 +1,2 @@
export * from './css-linear-gradient';
+export * from './css-drop-shadow';
diff --git a/packages/web-sdk-common/test/css-drop-shadow.test.ts b/packages/web-sdk-common/test/css-drop-shadow.test.ts
new file mode 100644
index 000000000..bec21e038
--- /dev/null
+++ b/packages/web-sdk-common/test/css-drop-shadow.test.ts
@@ -0,0 +1,27 @@
+
+import {Color, DropShadow, Point2D} from '@diez/prefabs';
+import {dropShadowToCss, dropShadowToFilterCss} from '../src/css-drop-shadow';
+
+describe('dropShadowToCss', () => {
+ test('simple shadow', () => {
+ const shadow = new DropShadow({
+ offset: Point2D.make(1, 2),
+ radius: 3,
+ color: Color.hsla(0.5, 0.25, 0.75, 0.9),
+ });
+ expect(dropShadowToCss(shadow))
+ .toBe('1px 2px 3px hsla(180, 25%, 75%, 0.9)');
+ });
+});
+
+describe('dropShadowToFilterCss', () => {
+ test('simple shadow', () => {
+ const shadow = new DropShadow({
+ offset: Point2D.make(1, 2),
+ radius: 6,
+ color: Color.hsla(0.5, 0.25, 0.75, 0.9),
+ });
+ expect(dropShadowToFilterCss(shadow))
+ .toBe('drop-shadow(1px 2px 3px hsla(180, 25%, 75%, 0.9))');
+ });
+});