Skip to content

Commit

Permalink
feat(compiler): add support for plain TypeScript classes without deco…
Browse files Browse the repository at this point in the history
…rators (#215)

- Deprecate `extends Component<T?>` and `@property` semantics required for component authoring. Dangling references remain in `@diez/engine` for legacy projects created before the next release, but they are no longer functional.
- Allow design token components to be built with plain TypeScript classes, punching `public`-scoped instance properties through to transpiled SDKs and leaving everything else out. We are now equipped to easily add support for typed hashmaps, but that should come in a subsequent PR.
- Provide a new, more strongly typed generic factory for prefab base classes. It would have been lovely to do this with just an abstract base class and not a factory, but sadly, TypeScript has a few limitations with regard to typing classes whose constructors mutate the class type to conform to a generic interface whose type is not known statically at compile time. The new syntax is:

```
import {prefab} from '@diez/engine';

interface FooData {
  bar: string;
}

class Foo extends prefab<FooData>() {
  defaults = {
    bar: 'bar',
  };
}
```

With the power of abstract classes, generics, and ES6 proxies, `new Foo()` and `new Foo({bar: string})` satisfy `Prefab<FooData> & FooData` automatically and without the need to carefully register data properties matching the types of the state shape.
- Migrate example projects and documentation to use/refer to this new syntax.
  • Loading branch information
gumptious committed Nov 14, 2019
1 parent b3c7cf7 commit ccad2eb
Show file tree
Hide file tree
Showing 68 changed files with 872 additions and 1,837 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ before_install:
- nvm install 10.15.3
- nvm alias default 10.15.3
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.16.0
- nvm alias default 10.15.3
- nvm use 10.15.3
- export PATH="$HOME/.yarn/bin:$PATH"
- gem install cocoapods -v '1.7.4'
Expand Down
75 changes: 37 additions & 38 deletions examples/lorem-ipsum/src/DesignSystem.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import {Color, Image, Lottie, Toward, Typograph, Font, LinearGradient} from '@diez/prefabs';
import {Component, property} from '@diez/engine';
import {Margin} from './components/Margin';

/**
* You can collect anything inside a Diez component. Design tokens labeled with
* @property will be made available in the SDKs transpiled with Diez. Everything
* You can collect anything inside a Diez component. Design tokens specified as public
* properties will be made available in the SDKs transpiled with Diez. Everything
* else is purely internal.
*/
class Colors extends Component {
class Colors {
private lightener = 0.2;

@property white = Color.hex('#FFFFFF');
@property black = Color.hex('#000010');
@property purple = Color.rgb(86, 35, 238);
@property darkPurple = Color.rgb(22, 11, 54);
@property lightPurple = this.purple.lighten(this.lightener);
white = Color.hex('#FFFFFF');
black = Color.hex('#000010');
purple = Color.rgb(86, 35, 238);
darkPurple = Color.rgb(22, 11, 54);
lightPurple = this.purple.lighten(this.lightener);
}

/**
Expand All @@ -29,12 +28,12 @@ const colors = new Colors();
/**
* You can reference properties from other components.
*/
class Palette extends Component {
@property background = colors.black;
@property contentBackground = colors.white;
@property text = colors.black;
@property caption = colors.purple;
@property headerBackground = LinearGradient.make(Toward.Bottom, colors.darkPurple, colors.black);
class Palette {
background = colors.black;
contentBackground = colors.white;
text = colors.black;
caption = colors.purple;
headerBackground = LinearGradient.make(Toward.Bottom, colors.darkPurple, colors.black);
}

const palette = new Palette();
Expand All @@ -53,20 +52,20 @@ const Fonts = {
* Typographs encapsulate type styles with support for a specific font, font size,
* and color. More typograph properties are coming soon.
*/
class Typography extends Component {
@property heading1 = new Typograph({
class Typography {
heading1 = new Typograph({
font: Fonts.SourceSansPro.Regular,
fontSize: 24,
color: palette.text,
});

@property body = new Typograph({
body = new Typograph({
font: Fonts.SourceSansPro.Regular,
fontSize: 18,
color: palette.text,
});

@property caption = new Typograph({
caption = new Typograph({
font: Fonts.SourceSansPro.Regular,
fontSize: 14,
color: palette.caption,
Expand All @@ -78,19 +77,19 @@ class Typography extends Component {
* design system primitives in components as well — such as images, icons &
* animations.
*/
class Images extends Component {
@property logo = Image.responsive('assets/logo.png', 52, 48);
@property masthead = Image.responsive('assets/masthead.png', 208, 88);
class Images {
logo = Image.responsive('assets/logo.png', 52, 48);
masthead = Image.responsive('assets/masthead.png', 208, 88);
}

/**
* You can even collect your own custom components.
*/
class LayoutValues extends Component {
@property spacingSmall = 5;
@property spacingMedium = 25;
@property spacingLarge = 40;
@property contentMargin = new Margin({
class LayoutValues {
spacingSmall = 5;
spacingMedium = 25;
spacingLarge = 40;
contentMargin = new Margin({
top: this.spacingLarge,
left: this.spacingMedium,
right: this.spacingMedium,
Expand All @@ -101,10 +100,10 @@ class LayoutValues extends Component {
/**
* You can also define strings.
*/
class Strings extends Component {
@property title = 'Diez';
@property caption = 'Keep your designs in sync with code';
@property 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 Strings {
title = 'Diez';
caption = 'Keep your designs in sync with code';
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.';
}

/**
Expand All @@ -122,11 +121,11 @@ class Strings extends Component {
* Look for `MainActivity.kt` inside `examples/android` to see how you can
* use Diez in an Android codebase.
*/
export class DesignSystem extends Component {
@property palette = palette;
@property typography = new Typography();
@property images = new Images();
@property layoutValues = new LayoutValues();
@property strings = new Strings();
@property loadingAnimation = Lottie.fromJson('assets/loadingAnimation.json', false);
export class DesignSystem {
palette = palette;
typography = new Typography();
images = new Images();
layoutValues = new LayoutValues();
strings = new Strings();
loadingAnimation = Lottie.fromJson('assets/loadingAnimation.json', false);
}
18 changes: 10 additions & 8 deletions examples/lorem-ipsum/src/components/Margin.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {Component, property} from '@diez/engine';
import {prefab} from '@diez/engine';

/**
* Defining the interface of your component's state enables you to instantiate your own
* Defining the interface of your component's data enables you to instantiate your own
* reusable components.
*/
interface MarginState {
interface MarginData {
top: number;
bottom: number;
left: number;
Expand All @@ -14,11 +14,13 @@ interface MarginState {
/**
* Here we create a custom reusable component for describing layout margins.
*/
export class Margin extends Component<MarginState> {
@property top = 0;
@property bottom = 0;
@property left = 0;
@property right = 0;
export class Margin extends prefab<MarginData>() {
defaults = {
top: 0,
bottom: 0,
left: 0,
right: 0,
};

/**
* Let's add in a helper method for defining margins (inspired by CSS shorthand).
Expand Down
17 changes: 8 additions & 9 deletions examples/poodle-surf/src/DesignSystem.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import {Component, property} from '@diez/engine';
import {LoadingDesign, NavigationTitleDesign, palette, ReportDesign, typographs} from './designs';

class Designs extends Component {
@property report = new ReportDesign();
@property loading = new LoadingDesign();
@property navigationTitle = new NavigationTitleDesign();
class Designs {
report = new ReportDesign();
loading = new LoadingDesign();
navigationTitle = new NavigationTitleDesign();
}

/**
* The design system for Poodle Surf.
*/
export class DesignSystem extends Component {
@property palette = palette;
@property typographs = typographs;
@property designs = new Designs();
export class DesignSystem {
palette = palette;
typographs = typographs;
designs = new Designs();
}
5 changes: 2 additions & 3 deletions examples/poodle-surf/src/ModelMocks.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import {Component, property} from '@diez/engine';
import {ReportModelMock} from './mocks';

/**
* The model mocks for Poodle Surf.
*/
export class ModelMocks extends Component {
@property report = new ReportModelMock();
export class ModelMocks {
report = new ReportModelMock();
}
7 changes: 3 additions & 4 deletions examples/poodle-surf/src/designs/LoadingDesign.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {Lottie} from '@diez/prefabs';
import {Component, property} from '@diez/engine';
import {palette} from './constants';

enum LottieJsons {
Expand All @@ -11,7 +10,7 @@ enum LottieJsons {
/**
* The loading design.
*/
export class LoadingDesign extends Component {
@property backgroundColor = palette.loadingBackground;
@property animation = Lottie.fromJson(LottieJsons.PoodleSurf);
export class LoadingDesign {
backgroundColor = palette.loadingBackground;
animation = Lottie.fromJson(LottieJsons.PoodleSurf);
}
13 changes: 6 additions & 7 deletions examples/poodle-surf/src/designs/NavigationTitleDesign.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import {PoodleSurfSlices} from './PoodleSurf.sketch';
import {Component, property} from '@diez/engine';
import {LayoutValues, palette, typographs} from './constants';

/**
* The navigation title design.
*/
export class NavigationTitleDesign extends Component {
@property barTintColor = palette.background;
@property icon = PoodleSurfSlices.Icon;
@property title = 'P o o d l e S u r f';
@property typograph = typographs.headerTitle;
@property iconToTitleSpacing = LayoutValues.DefaultSpacing;
export class NavigationTitleDesign {
barTintColor = palette.background;
icon = PoodleSurfSlices.Icon;
title = 'P o o d l e S u r f';
typograph = typographs.headerTitle;
iconToTitleSpacing = LayoutValues.DefaultSpacing;
}
16 changes: 3 additions & 13 deletions examples/poodle-surf/src/designs/PoodleSurf.sketch.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import { Color, File, GradientStop, Image, LinearGradient, Point2D } from "@diez/prefabs";
import { Component, property } from "@diez/engine";

class PoodleSurfColors extends Component {
@property
class PoodleSurfColors {
pink = Color.rgba(255, 63, 112, 1);
@property
orange = Color.rgba(255, 154, 58, 1);
@property
blue = Color.rgba(120, 207, 253, 1);
@property
white = Color.rgba(255, 255, 255, 1);
@property
whiteA40 = Color.rgba(255, 255, 255, 0.4);
@property
black = Color.rgba(0, 0, 0, 1);
}

class PoodleSurfGradients extends Component {
@property
class PoodleSurfGradients {
gradient = 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)});
}

Expand Down Expand Up @@ -72,10 +64,8 @@ export class PoodleSurfSlices {
static Icon = Image.responsive("assets/PoodleSurf.sketch.contents/slices/Icon.png", 29, 26);
}

export class PoodleSurfTokens extends Component {
@property
export class PoodleSurfTokens {
colors = new PoodleSurfColors();
@property
gradients = new PoodleSurfGradients();
}

Expand Down

0 comments on commit ccad2eb

Please sign in to comment.