Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

- [x] Component decorator `Styled`
- [x] Theming with `Theme`
- [ ] Theme switching (dark/light mode)
- [x] Server Side Rendering with Angular Universal
- [ ] Critical CSS

## Table of Contents

Expand Down Expand Up @@ -107,6 +109,45 @@ export class AppComponent {

## Config options

```ts
import { create, Jss } from 'jss';
import extend from 'jss-plugin-extend';
import propsSort from 'jss-plugin-props-sort';
import { JssOptions } from '@design4pro/angular-jss';

const jss: Jss = create({
// additional JSS plugins @see https://cssinjs.org/plugins?v=v10.9.0
plugins: [
extend(),
propsSort()
],
});

const jssOptions: JssOptions = {
jss: jss,
normalize: false // disable normalizing (normalize.css)
};

const theme: Theme = {
palette: {
primary: {
main: '#00bcd4' // use in decorator `theme.palette?.primary?.main`
},
secondary: {
main: '#f50057'
}
}
};

@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AngularJssModule.forRoot(jssOptions, theme)],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
```

## License

[MIT](https://github.com/design4pro/angular-jss/blob/master/LICENSE.md) © DESIGN4 ᴾ ᴿ ᴼ
Empty file.
15 changes: 12 additions & 3 deletions apps/webpage/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
<div [ngClass]="classes.root"></div>

<button (click)="click()">Change color</button>
<!--The content below is only a placeholder and can be replaced.-->
<div [ngClass]="classes?.root">
<h1 [ngClass]="classes?.title">
Welcome to {{ title }}!
</h1>
<p [ngClass]="classes?.hint">Hover the logo</p>
<img width="300"
alt="Angular Logo"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' id='Layer_1' x='0' y='0' viewBox='0 0 250 250' style='enable-background:new 0 0 250 250' xml:space='preserve'%3E%3Cstyle type='text/css' id='style833'%3E.st2%7Bfill:%23fff%7D%3C/style%3E%3Cg id='g841'%3E%3Cpath id='polygon835' style='fill:%23f7df1e;fill-opacity:1' d='M125 30 31.9 63.2l14.2 123.1L125 230l78.9-43.7 14.2-123.1z'/%3E%3Cpath id='polygon837' style='fill:%23ceb828;fill-opacity:1' d='M125 30v22.2-.1V230l78.9-43.7 14.2-123.1L125 30z'/%3E%3Cg id='g867' transform='matrix(.98438 0 0 1 65.938 65)'%3E%3Cpath fill='transparent' d='M0 13h95v94H0Z' id='path850' style='fill:none'/%3E%3Cpath fill='%23eee' d='M96 107.5H0v-95h96Zm-94.197-1.795h92.393v-91.41H1.803Z' id='path852' style='fill:%23eee;fill-opacity:1'/%3E%3Cpath fill='%23fff' d='M64.294 86.574c1.903 3.108 4.379 5.392 8.759 5.392 3.679 0 6.029-1.839 6.029-4.379 0-3.044-2.414-4.123-6.464-5.894l-2.219-.952c-6.407-2.729-10.663-6.149-10.663-13.378 0-6.659 5.073-11.728 13.003-11.728 5.645 0 9.704 1.965 12.628 7.109l-6.914 4.439c-1.522-2.73-3.164-3.805-5.714-3.805-2.601 0-4.249 1.65-4.249 3.805 0 2.663 1.65 3.742 5.459 5.392l2.22.951c7.544 3.235 11.803 6.533 11.803 13.948 0 7.993-6.279 12.373-14.713 12.373-8.246 0-13.573-3.929-16.18-9.079 0-.002 7.215-4.194 7.215-4.194zm32.029 0c1.903 3.108 4.379 5.392 8.759 5.392 3.679 0 6.029-1.839 6.029-4.379 0-3.044-2.414-4.123-6.464-5.894l-2.219-.952c-6.407-2.729-10.663-6.149-10.663-13.378 0-6.659 5.073-11.728 13.003-11.728 5.645 0 9.704 1.965 12.628 7.109l-6.914 4.439c-1.522-2.73-3.164-3.805-5.714-3.805-2.601 0-4.249 1.65-4.249 3.805 0 2.663 1.65 3.742 5.459 5.392l2.22.951C115.741 76.76 120 80.058 120 87.473c0 7.993-6.279 12.373-14.713 12.373-8.246 0-13.573-3.929-16.18-9.079zm-63.393.77c1.395 2.475 2.664 4.567 5.714 4.567 2.917 0 4.757-1.141 4.757-5.579V56.141h8.878v30.31c0 9.193-5.39 13.378-13.258 13.378-7.109 0-11.226-3.679-13.32-8.11l7.229-4.375c0-.001 0 0 0 0z' id='path854'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"
(mouseenter)="onMouseEvent()"
(mouseleave)="onMouseEvent()" />
</div>
18 changes: 11 additions & 7 deletions apps/webpage/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Component } from '@angular/core';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Styled, StyledProp, Theme } from '@design4pro/angular-jss';

@Component({
selector: 'angular-jss-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
@Styled(({ css, injectGlobal }) => {
injectGlobal({
Expand All @@ -18,25 +18,29 @@ import { Styled, StyledProp, Theme } from '@design4pro/angular-jss';
return css(
(theme: Theme) => ({
root: {
color: '#fff',
textAlign: 'center',
},
title: {
color: theme.palette?.common?.white,
backgroundColor: 'var(--background-color)',
padding: '20px',
direction: theme.direction,
},
hint: {
color: theme.palette?.common?.black,
},
}),
{ name: 'first' }
);
})
export class AppComponent {
title = 'angular-jss';
title = 'Angular JSS';
classes: any;
name?: string;

@StyledProp()
color = 'red';

click() {
onMouseEvent() {
this.color = this.color === 'red' ? 'green' : 'red';
this.name = this.color;
}
}
45 changes: 45 additions & 0 deletions libs/angular-jss/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@

## Features

- [x] Component decorator `Styled`
- [x] Theming with `Theme`
- [ ] Theme switching (dark/light mode)
- [x] Server Side Rendering with Angular Universal
- [ ] Critical CSS

## Table of Contents

- [Installation](#installation)
Expand Down Expand Up @@ -103,6 +109,45 @@ export class AppComponent {

## Config options

```ts
import { create, Jss } from 'jss';
import extend from 'jss-plugin-extend';
import propsSort from 'jss-plugin-props-sort';
import { JssOptions } from '@design4pro/angular-jss';

const jss: Jss = create({
// additional JSS plugins @see https://cssinjs.org/plugins?v=v10.9.0
plugins: [
extend(),
propsSort()
],
});

const jssOptions: JssOptions = {
jss: jss,
normalize: false // disable normalizing (normalize.css)
};

const theme: Theme = {
palette: {
primary: {
main: '#00bcd4' // use in decorator `theme.palette?.primary?.main`
},
secondary: {
main: '#f50057'
}
}
};

@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AngularJssModule.forRoot(jssOptions, theme)],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
```

## License

[MIT](https://github.com/design4pro/angular-jss/blob/master/LICENSE.md) © DESIGN4 ᴾ ᴿ ᴼ
1 change: 1 addition & 0 deletions libs/angular-jss/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './lib/angular-jss.service';
export * from './lib/angular-jss.types';
export * from './lib/ssr';
export * from './lib/styled';
export * from './lib/theme';
15 changes: 13 additions & 2 deletions libs/angular-jss/src/lib/angular-jss.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { JssOptions } from './jss/types';
import { ColorCommon } from './theme/colors/common';

export interface Options extends JssOptions {
normalize?: boolean;
Expand All @@ -7,8 +8,7 @@ export interface Options extends JssOptions {
export interface Theme {
breakpoints?: ThemeBreakpoints;
direction?: string;
overrides?: object;
props?: object;
palette?: ThemePalette;
}

export interface ThemeBreakpoints {
Expand All @@ -24,3 +24,14 @@ export interface ThemeBreakpoints {
unit?: string;
step?: number;
}

export type ThemeType = string | 'auto' | 'light' | 'dark';

export interface ThemePaletteCommonColor {
[key: string]: ColorCommon;
}

export interface ThemePalette {
mode: ThemeType;
common: typeof ColorCommon;
}
2 changes: 1 addition & 1 deletion libs/angular-jss/src/lib/jss/utils/sheets.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getDynamicStyles, StyleSheet, StyleSheetFactoryOptions } from 'jss';
import { Theme } from '../../angular-jss.types';
import { StyledProps } from '../../styled/styled.interface';
import { StyledProps } from '../../styled/styled.types';
import { ThemeContext } from '../../theme/theme-context';
import { JssContext } from '../context';
import { getManager } from '../managers';
Expand Down
2 changes: 1 addition & 1 deletion libs/angular-jss/src/lib/styled/create-use-styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
updateDynamicRules,
} from '../jss/utils/sheets';
import { ThemeContext } from '../theme/theme-context';
import { StyledProps } from './styled.interface';
import { StyledProps } from './styled.types';

const createUseStyles =
(doCheck: BehaviorSubject<StyledProps>, onDestroy: Subject<void>) =>
Expand Down
2 changes: 1 addition & 1 deletion libs/angular-jss/src/lib/styled/internals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
DirectiveDef,
DirectiveType,
} from './ivy';
import { StyledProps } from './styled.interface';
import { StyledProps } from './styled.types';

/**
* Applied to definitions and informs that class is decorated
Expand Down
2 changes: 1 addition & 1 deletion libs/angular-jss/src/lib/styled/styled.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'reflect-metadata';
import { BehaviorSubject, Subject } from 'rxjs';
import { generateStyles, markAsDecorated, STYLED_PROPS } from './internals';
import { ComponentType, DirectiveType } from './ivy';
import { StyledProps } from './styled.interface';
import { StyledProps } from './styled.types';

// eslint-disable-next-line @typescript-eslint/naming-convention
export function StyledProp<T>(): PropertyDecorator {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HookOptions, Styles } from '../jss/types';
import { Theme } from '../angular-jss.types';
import { HookOptions, Styles } from '../jss/types';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type StyledProps = (context: StyledContext) => any;
Expand Down
6 changes: 6 additions & 0 deletions libs/angular-jss/src/lib/theme/colors/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum ColorCommon {
black = '#000',
white = '#fff',
};

export default ColorCommon;
1 change: 1 addition & 0 deletions libs/angular-jss/src/lib/theme/colors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './common';
21 changes: 21 additions & 0 deletions libs/angular-jss/src/lib/theme/create-palette.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ThemePalette } from '../angular-jss.types';
import deepmerge from '../utils/deepmerge';
import common from './colors/common';

function createPalette(palette: ThemePalette): ThemePalette {
const { mode = 'light', ...other } = palette;

const paletteOutput = deepmerge<ThemePalette>(
{
// A collection of common colors.
common: common,
// The palette mode, can be light or dark.
mode,
},
other
);

return paletteOutput;
}

export default createPalette;
21 changes: 13 additions & 8 deletions libs/angular-jss/src/lib/theme/create-theme.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import { Theme, ThemeBreakpoints } from '../angular-jss.types';
import { Theme, ThemeBreakpoints, ThemePalette } from '../angular-jss.types';
import deepmerge from '../utils/deepmerge';
import createBreakpoints from './create-breakpoints';
import createPalette from './create-palette';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function createTheme(options: Theme = {}, ...args: any): Theme {
const { breakpoints: input = {}, ...other } = options;
const {
breakpoints: breakpointsInput = {},
palette: paletteInput = {},
...other
} = options;

const _breakpoints = createBreakpoints(input as ThemeBreakpoints);
const breakpoints = createBreakpoints(breakpointsInput as ThemeBreakpoints);
const palette = createPalette(paletteInput as ThemePalette);

let theme = deepmerge(
let theme = deepmerge<Theme>(
{
breakpoints: _breakpoints,
breakpoints: breakpoints,
direction: 'ltr',
overrides: {}, // Inject custom styles
props: {}, // Provide default props
palette: palette,
},
other
);

theme = args.reduce(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(acc: Theme, argument: any) => deepmerge(acc, argument),
(acc: Theme, argument: any) => deepmerge<Theme>(acc, argument),
theme
);

Expand Down
3 changes: 3 additions & 0 deletions libs/angular-jss/src/lib/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './colors';
export * from './create-breakpoints';
export * from './create-theme';
7 changes: 2 additions & 5 deletions libs/angular-jss/src/lib/theme/theme-context.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { Injectable } from '@angular/core';
import { ThemeBreakpoints } from '../angular-jss.types';
import { ThemeBreakpoints, ThemePalette } from '../angular-jss.types';
import { Store } from '../utils/store';

export type ThemeType = string | 'auto' | 'light' | 'dark';

export class ThemeContext {
breakpoints?: ThemeBreakpoints;
direction?: string;
overrides?: object;
props?: object;
palette?: ThemePalette;
}

@Injectable()
Expand Down
Loading