@udixio/theme 1.0.0-beta.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.mjs +22 -0
- package/CHANGELOG.md +174 -0
- package/README.md +6 -68
- package/dist/API.d.ts +14 -0
- package/dist/API.d.ts.map +1 -0
- package/dist/LICENSE +202 -0
- package/dist/adapter/adapter.abstract.d.ts +10 -0
- package/dist/adapter/adapter.abstract.d.ts.map +1 -0
- package/dist/adapter/config.interface.d.ts +14 -0
- package/dist/adapter/config.interface.d.ts.map +1 -0
- package/dist/adapter/define-config.d.ts +3 -0
- package/dist/adapter/define-config.d.ts.map +1 -0
- package/dist/adapter/file-adapter.mixin.d.ts +18 -0
- package/dist/adapter/file-adapter.mixin.d.ts.map +1 -0
- package/dist/adapter/index.d.ts +4 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapters/index.d.ts +3 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/node.adapter.d.ts +7 -0
- package/dist/adapters/node.adapter.d.ts.map +1 -0
- package/dist/adapters/vite.adapter.d.ts +3 -0
- package/dist/adapters/vite.adapter.d.ts.map +1 -0
- package/dist/app.container.d.ts +5 -5
- package/dist/app.container.d.ts.map +1 -0
- package/dist/app.module.d.ts +1 -0
- package/dist/app.module.d.ts.map +1 -0
- package/dist/bootstrap.d.ts +3 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/color/color.api.d.ts +39 -0
- package/dist/color/color.api.d.ts.map +1 -0
- package/dist/color/color.manager.d.ts +24 -0
- package/dist/color/color.manager.d.ts.map +1 -0
- package/dist/color/color.module.d.ts +1 -0
- package/dist/color/color.module.d.ts.map +1 -0
- package/dist/color/color.utils.d.ts +8 -0
- package/dist/color/color.utils.d.ts.map +1 -0
- package/dist/color/configurable-color.d.ts +31 -0
- package/dist/color/configurable-color.d.ts.map +1 -0
- package/dist/color/default-color.d.ts +3 -0
- package/dist/color/default-color.d.ts.map +1 -0
- package/dist/color/index.d.ts +5 -4
- package/dist/color/index.d.ts.map +1 -0
- package/dist/index.cjs +3215 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3175 -7
- package/dist/material-color-utilities/contrastCurve.d.ts +1 -0
- package/dist/material-color-utilities/contrastCurve.d.ts.map +1 -0
- package/dist/material-color-utilities/dynamic_color.d.ts +89 -76
- package/dist/material-color-utilities/dynamic_color.d.ts.map +1 -0
- package/dist/material-color-utilities/hct_solver.d.ts +131 -0
- package/dist/material-color-utilities/hct_solver.d.ts.map +1 -0
- package/dist/material-color-utilities/htc.d.ts +77 -0
- package/dist/material-color-utilities/htc.d.ts.map +1 -0
- package/dist/material-color-utilities/index.d.ts +1 -0
- package/dist/material-color-utilities/index.d.ts.map +1 -0
- package/dist/material-color-utilities/toneDeltaPair.d.ts +19 -25
- package/dist/material-color-utilities/toneDeltaPair.d.ts.map +1 -0
- package/dist/plugin/index.d.ts +4 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/plugin.abstract.d.ts +19 -5
- package/dist/plugin/plugin.abstract.d.ts.map +1 -0
- package/dist/plugin/plugin.api.d.ts +10 -0
- package/dist/plugin/plugin.api.d.ts.map +1 -0
- package/dist/plugin/plugin.module.d.ts +1 -0
- package/dist/plugin/plugin.module.d.ts.map +1 -0
- package/dist/plugins/font/font.plugin.d.ts +50 -0
- package/dist/plugins/font/font.plugin.d.ts.map +1 -0
- package/dist/plugins/font/index.d.ts +2 -0
- package/dist/plugins/font/index.d.ts.map +1 -0
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/theme/index.d.ts +7 -3
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/scheme.d.ts +20 -0
- package/dist/theme/scheme.d.ts.map +1 -0
- package/dist/theme/scheme.manager.d.ts +31 -0
- package/dist/theme/scheme.manager.d.ts.map +1 -0
- package/dist/theme/theme.api.d.ts +23 -0
- package/dist/theme/theme.api.d.ts.map +1 -0
- package/dist/theme/theme.module.d.ts +1 -0
- package/dist/theme/theme.module.d.ts.map +1 -0
- package/dist/theme/variant.d.ts +36 -0
- package/dist/theme/variant.d.ts.map +1 -0
- package/dist/theme/variant.manager.d.ts +14 -0
- package/dist/theme/variant.manager.d.ts.map +1 -0
- package/dist/theme/variants/expressive.variant.d.ts +3 -0
- package/dist/theme/variants/expressive.variant.d.ts.map +1 -0
- package/dist/theme/variants/index.d.ts +11 -0
- package/dist/theme/variants/index.d.ts.map +1 -0
- package/dist/theme/variants/neutral.variant.d.ts +3 -0
- package/dist/theme/variants/neutral.variant.d.ts.map +1 -0
- package/dist/theme/variants/tonal-spot.variant.d.ts +3 -0
- package/dist/theme/variants/tonal-spot.variant.d.ts.map +1 -0
- package/dist/theme/variants/vibrant.variant.d.ts +3 -0
- package/dist/theme/variants/vibrant.variant.d.ts.map +1 -0
- package/package.json +24 -86
- package/src/API.ts +23 -0
- package/src/adapter/adapter.abstract.ts +64 -0
- package/src/adapter/config.interface.ts +14 -0
- package/src/adapter/define-config.ts +11 -0
- package/src/adapter/file-adapter.mixin.ts +72 -0
- package/src/adapter/index.ts +3 -0
- package/src/adapters/index.ts +2 -0
- package/src/adapters/node.adapter.ts +49 -0
- package/src/adapters/vite.adapter.ts +79 -0
- package/src/app.container.ts +12 -36
- package/src/app.module.ts +2 -2
- package/src/bootstrap.ts +6 -0
- package/src/color/color.api.ts +75 -0
- package/src/color/color.manager.ts +213 -0
- package/src/color/color.module.ts +4 -4
- package/src/color/color.utils.ts +126 -0
- package/src/color/configurable-color.ts +67 -0
- package/src/color/default-color.ts +832 -0
- package/src/color/index.ts +4 -4
- package/src/index.test.ts +5 -0
- package/src/index.ts +6 -4
- package/src/material-color-utilities/dynamic_color.ts +286 -222
- package/src/material-color-utilities/hct_solver.ts +536 -0
- package/src/material-color-utilities/htc.ts +198 -0
- package/src/material-color-utilities/toneDeltaPair.ts +29 -11
- package/src/plugin/index.ts +3 -0
- package/src/plugin/plugin.abstract.ts +45 -4
- package/src/plugin/plugin.api.ts +51 -0
- package/src/plugin/plugin.module.ts +2 -2
- package/src/plugins/font/font.plugin.ts +203 -0
- package/src/plugins/font/index.ts +1 -0
- package/src/plugins/index.ts +1 -0
- package/src/theme/index.ts +6 -3
- package/src/theme/{services/scheme.service.ts → scheme.manager.ts} +39 -19
- package/src/theme/{entities/scheme.entity.ts → scheme.ts} +20 -4
- package/src/theme/{services/theme.service.ts → theme.api.ts} +23 -19
- package/src/theme/theme.module.ts +6 -4
- package/src/theme/variant.manager.ts +58 -0
- package/src/theme/variant.ts +53 -0
- package/src/theme/variants/expressive.variant.ts +81 -0
- package/src/theme/variants/index.ts +16 -0
- package/src/theme/variants/neutral.variant.ts +45 -0
- package/src/theme/variants/tonal-spot.variant.ts +35 -0
- package/src/theme/variants/vibrant.variant.ts +72 -0
- package/tsconfig.json +13 -0
- package/tsconfig.lib.json +33 -0
- package/tsconfig.spec.json +36 -0
- package/vite.config.ts +54 -0
- package/LICENSE +0 -21
- package/dist/app.service.d.ts +0 -13
- package/dist/color/color.interface.d.ts +0 -8
- package/dist/color/entities/color.entity.d.ts +0 -42
- package/dist/color/entities/index.d.ts +0 -1
- package/dist/color/models/default-color.model.d.ts +0 -3
- package/dist/color/models/index.d.ts +0 -1
- package/dist/color/services/color-manager.service.d.ts +0 -18
- package/dist/color/services/color.service.d.ts +0 -21
- package/dist/color/services/index.d.ts +0 -2
- package/dist/config/config.interface.d.ts +0 -14
- package/dist/config/config.module.d.ts +0 -2
- package/dist/config/config.service.d.ts +0 -12
- package/dist/config/index.d.ts +0 -2
- package/dist/main.d.ts +0 -3
- package/dist/plugin/plugin.service.d.ts +0 -9
- package/dist/theme/entities/index.d.ts +0 -2
- package/dist/theme/entities/scheme.entity.d.ts +0 -15
- package/dist/theme/entities/variant.entity.d.ts +0 -7
- package/dist/theme/models/index.d.ts +0 -1
- package/dist/theme/models/variant.model.d.ts +0 -8
- package/dist/theme/services/index.d.ts +0 -3
- package/dist/theme/services/scheme.service.d.ts +0 -17
- package/dist/theme/services/theme.service.d.ts +0 -22
- package/dist/theme/services/variant.service.d.ts +0 -13
- package/dist/theme.cjs.development.js +0 -1975
- package/dist/theme.cjs.development.js.map +0 -1
- package/dist/theme.cjs.production.min.js +0 -2
- package/dist/theme.cjs.production.min.js.map +0 -1
- package/dist/theme.esm.js +0 -1947
- package/dist/theme.esm.js.map +0 -1
- package/src/app.service.spec.ts +0 -15
- package/src/app.service.ts +0 -23
- package/src/color/color.interface.ts +0 -13
- package/src/color/entities/color.entity.ts +0 -71
- package/src/color/entities/index.ts +0 -1
- package/src/color/models/default-color.model.ts +0 -300
- package/src/color/models/index.ts +0 -1
- package/src/color/services/color-manager.service.ts +0 -191
- package/src/color/services/color.service.spec.ts +0 -28
- package/src/color/services/color.service.ts +0 -75
- package/src/color/services/index.ts +0 -2
- package/src/config/config.interface.ts +0 -15
- package/src/config/config.module.ts +0 -7
- package/src/config/config.service.ts +0 -68
- package/src/config/index.ts +0 -2
- package/src/main.ts +0 -14
- package/src/plugin/plugin.service.ts +0 -26
- package/src/theme/entities/index.ts +0 -2
- package/src/theme/entities/variant.entity.ts +0 -39
- package/src/theme/models/index.ts +0 -1
- package/src/theme/models/variant.model.ts +0 -63
- package/src/theme/services/index.ts +0 -3
- package/src/theme/services/variant.service.ts +0 -52
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2021 Google LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A color system built using CAM16 hue and chroma, and L* from
|
|
20
|
+
* L*a*b*.
|
|
21
|
+
*
|
|
22
|
+
* Using L* creates a link between the color system, contrast, and thus
|
|
23
|
+
* accessibility. Contrast ratio depends on relative luminance, or Y in the XYZ
|
|
24
|
+
* color space. L*, or perceptual luminance can be calculated from Y.
|
|
25
|
+
*
|
|
26
|
+
* Unlike Y, L* is linear to human perception, allowing trivial creation of
|
|
27
|
+
* accurate color tones.
|
|
28
|
+
*
|
|
29
|
+
* Unlike contrast ratio, measuring contrast in L* is linear, and simple to
|
|
30
|
+
* calculate. A difference of 40 in HCT tone guarantees a contrast ratio >= 3.0,
|
|
31
|
+
* and a difference of 50 guarantees a contrast ratio >= 4.5.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { Cam16, lstarFromArgb, lstarFromY, ViewingConditions } from '@material/material-color-utilities';
|
|
35
|
+
import { HctSolver } from './hct_solver';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* HCT, hue, chroma, and tone. A color system that provides a perceptually
|
|
39
|
+
* accurate color measurement system that can also accurately render what colors
|
|
40
|
+
* will appear as in different lighting environments.
|
|
41
|
+
*/
|
|
42
|
+
export class Hct {
|
|
43
|
+
/**
|
|
44
|
+
* @param hue 0 <= hue < 360; invalid values are corrected.
|
|
45
|
+
* @param chroma 0 <= chroma < ?; Informally, colorfulness. The color
|
|
46
|
+
* returned may be lower than the requested chroma. Chroma has a different
|
|
47
|
+
* maximum for any given hue and tone.
|
|
48
|
+
* @param tone 0 <= tone <= 100; invalid values are corrected.
|
|
49
|
+
* @return HCT representation of a color in default viewing conditions.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
internalHue: number;
|
|
53
|
+
internalChroma: number;
|
|
54
|
+
internalTone: number;
|
|
55
|
+
|
|
56
|
+
private constructor(private argb: number) {
|
|
57
|
+
const cam = Cam16.fromInt(argb);
|
|
58
|
+
this.internalHue = cam.hue;
|
|
59
|
+
this.internalChroma = cam.chroma;
|
|
60
|
+
this.internalTone = lstarFromArgb(argb);
|
|
61
|
+
this.argb = argb;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* A number, in degrees, representing ex. red, orange, yellow, etc.
|
|
66
|
+
* Ranges from 0 <= hue < 360.
|
|
67
|
+
*/
|
|
68
|
+
get hue(): number {
|
|
69
|
+
return this.internalHue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param newHue 0 <= newHue < 360; invalid values are corrected.
|
|
74
|
+
* Chroma may decrease because chroma has a different maximum for any given
|
|
75
|
+
* hue and tone.
|
|
76
|
+
*/
|
|
77
|
+
set hue(newHue: number) {
|
|
78
|
+
this.setInternalState(
|
|
79
|
+
HctSolver.solveToInt(newHue, this.internalChroma, this.internalTone),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get chroma(): number {
|
|
84
|
+
return this.internalChroma;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param newChroma 0 <= newChroma < ?
|
|
89
|
+
* Chroma may decrease because chroma has a different maximum for any given
|
|
90
|
+
* hue and tone.
|
|
91
|
+
*/
|
|
92
|
+
set chroma(newChroma: number) {
|
|
93
|
+
this.setInternalState(
|
|
94
|
+
HctSolver.solveToInt(this.internalHue, newChroma, this.internalTone),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Lightness. Ranges from 0 to 100. */
|
|
99
|
+
get tone(): number {
|
|
100
|
+
return this.internalTone;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @param newTone 0 <= newTone <= 100; invalid valids are corrected.
|
|
105
|
+
* Chroma may decrease because chroma has a different maximum for any given
|
|
106
|
+
* hue and tone.
|
|
107
|
+
*/
|
|
108
|
+
set tone(newTone: number) {
|
|
109
|
+
this.setInternalState(
|
|
110
|
+
HctSolver.solveToInt(this.internalHue, this.internalChroma, newTone),
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static from(hue: number, chroma: number, tone: number) {
|
|
115
|
+
return new Hct(HctSolver.solveToInt(hue, chroma, tone));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @param argb ARGB representation of a color.
|
|
120
|
+
* @return HCT representation of a color in default viewing conditions
|
|
121
|
+
*/
|
|
122
|
+
static fromInt(argb: number) {
|
|
123
|
+
return new Hct(argb);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static isBlue(hue: number): boolean {
|
|
127
|
+
return hue >= 250 && hue < 270;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static isYellow(hue: number): boolean {
|
|
131
|
+
return hue >= 105 && hue < 125;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static isCyan(hue: number): boolean {
|
|
135
|
+
return hue >= 170 && hue < 207;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
toInt(): number {
|
|
139
|
+
return this.argb;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Sets a property of the Hct object. */
|
|
143
|
+
setValue(propertyName: string, value: number) {
|
|
144
|
+
(this as any)[propertyName] = value;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
toString(): string {
|
|
148
|
+
return `HCT(${this.hue.toFixed(0)}, ${this.chroma.toFixed(0)}, ${this.tone.toFixed(
|
|
149
|
+
0,
|
|
150
|
+
)})`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Translates a color into different [ViewingConditions].
|
|
155
|
+
*
|
|
156
|
+
* Colors change appearance. They look different with lights on versus off,
|
|
157
|
+
* the same color, as in hex code, on white looks different when on black.
|
|
158
|
+
* This is called color relativity, most famously explicated by Josef Albers
|
|
159
|
+
* in Interaction of Color.
|
|
160
|
+
*
|
|
161
|
+
* In color science, color appearance models can account for this and
|
|
162
|
+
* calculate the appearance of a color in different settings. HCT is based on
|
|
163
|
+
* CAM16, a color appearance model, and uses it to make these calculations.
|
|
164
|
+
*
|
|
165
|
+
* See [ViewingConditions.make] for parameters affecting color appearance.
|
|
166
|
+
*/
|
|
167
|
+
inViewingConditions(vc: ViewingConditions): Hct {
|
|
168
|
+
// 1. Use CAM16 to find XYZ coordinates of color in specified VC.
|
|
169
|
+
const cam = Cam16.fromInt(this.toInt());
|
|
170
|
+
const viewedInVc = cam.xyzInViewingConditions(vc);
|
|
171
|
+
|
|
172
|
+
// 2. Create CAM16 of those XYZ coordinates in default VC.
|
|
173
|
+
const recastInVc = Cam16.fromXyzInViewingConditions(
|
|
174
|
+
viewedInVc[0],
|
|
175
|
+
viewedInVc[1],
|
|
176
|
+
viewedInVc[2],
|
|
177
|
+
ViewingConditions.make(),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
// 3. Create HCT from:
|
|
181
|
+
// - CAM16 using default VC with XYZ coordinates in specified VC.
|
|
182
|
+
// - L* converted from Y in XYZ coordinates in specified VC.
|
|
183
|
+
const recastHct = Hct.from(
|
|
184
|
+
recastInVc.hue,
|
|
185
|
+
recastInVc.chroma,
|
|
186
|
+
lstarFromY(viewedInVc[1]),
|
|
187
|
+
);
|
|
188
|
+
return recastHct;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private setInternalState(argb: number) {
|
|
192
|
+
const cam = Cam16.fromInt(argb);
|
|
193
|
+
this.internalHue = cam.hue;
|
|
194
|
+
this.internalChroma = cam.chroma;
|
|
195
|
+
this.internalTone = lstarFromArgb(argb);
|
|
196
|
+
this.argb = argb;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -19,8 +19,21 @@ import { DynamicColor } from './dynamic_color';
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Describes the different in tone between colors.
|
|
22
|
+
*
|
|
23
|
+
* nearer and farther are deprecated. Use DeltaConstraint instead.
|
|
24
|
+
*/
|
|
25
|
+
export type TonePolarity =
|
|
26
|
+
| 'darker'
|
|
27
|
+
| 'lighter'
|
|
28
|
+
| 'nearer'
|
|
29
|
+
| 'farther'
|
|
30
|
+
| 'relative_darker'
|
|
31
|
+
| 'relative_lighter';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Describes how to fulfill a tone delta pair constraint.
|
|
22
35
|
*/
|
|
23
|
-
export type
|
|
36
|
+
export type DeltaConstraint = 'exact' | 'nearer' | 'farther';
|
|
24
37
|
|
|
25
38
|
/**
|
|
26
39
|
* Documents a constraint between two DynamicColors, in which their tones must
|
|
@@ -36,13 +49,14 @@ export class ToneDeltaPair {
|
|
|
36
49
|
*
|
|
37
50
|
* The polarity is an adjective that describes "A", compared to "B".
|
|
38
51
|
*
|
|
39
|
-
* For instance, ToneDeltaPair(A, B, 15, 'darker',
|
|
40
|
-
* A's tone should be
|
|
52
|
+
* For instance, ToneDeltaPair(A, B, 15, 'darker', 'exact') states that
|
|
53
|
+
* A's tone should be exactly 15 darker than B's.
|
|
41
54
|
*
|
|
42
|
-
* '
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
55
|
+
* 'relative_darker' and 'relative_lighter' describes the tone adjustment
|
|
56
|
+
* relative to the surface color trend (white in light mode; black in dark
|
|
57
|
+
* mode). For instance, ToneDeltaPair(A, B, 10, 'relative_lighter',
|
|
58
|
+
* 'farther') states that A should be at least 10 lighter than B in light
|
|
59
|
+
* mode, and at least 10 darker than B in dark mode.
|
|
46
60
|
*
|
|
47
61
|
* @param roleA The first role in a pair.
|
|
48
62
|
* @param roleB The second role in a pair.
|
|
@@ -50,8 +64,9 @@ export class ToneDeltaPair {
|
|
|
50
64
|
* values have undefined behavior.
|
|
51
65
|
* @param polarity The relative relation between tones of roleA and roleB,
|
|
52
66
|
* as described above.
|
|
53
|
-
* @param
|
|
54
|
-
*
|
|
67
|
+
* @param constraint How to fulfill the tone delta pair constraint.
|
|
68
|
+
* @param stayTogether Whether these two roles should stay on the same side
|
|
69
|
+
* of the "awkward zone" (T50-59). This is necessary for certain cases where
|
|
55
70
|
* one role has two backgrounds.
|
|
56
71
|
*/
|
|
57
72
|
constructor(
|
|
@@ -59,6 +74,9 @@ export class ToneDeltaPair {
|
|
|
59
74
|
readonly roleB: DynamicColor,
|
|
60
75
|
readonly delta: number,
|
|
61
76
|
readonly polarity: TonePolarity,
|
|
62
|
-
readonly stayTogether: boolean
|
|
63
|
-
|
|
77
|
+
readonly stayTogether: boolean,
|
|
78
|
+
readonly constraint?: DeltaConstraint,
|
|
79
|
+
) {
|
|
80
|
+
this.constraint = constraint ?? 'exact';
|
|
81
|
+
}
|
|
64
82
|
}
|
|
@@ -1,7 +1,48 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { API } from '../API';
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
|
|
3
|
+
export type PluginConstructor<Plugin extends PluginImplAbstract<any>> = new (
|
|
4
|
+
...args: any
|
|
5
|
+
) => Plugin;
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
export abstract class PluginAbstract<
|
|
8
|
+
Plugin extends PluginImplAbstract<Options>,
|
|
9
|
+
Options extends object,
|
|
10
|
+
> {
|
|
11
|
+
public abstract readonly dependencies: (new (
|
|
12
|
+
...args: any
|
|
13
|
+
) => PluginAbstract<any, any>)[];
|
|
14
|
+
public abstract readonly name: string;
|
|
15
|
+
public options: Options;
|
|
16
|
+
public abstract readonly pluginClass: PluginConstructor<Plugin>;
|
|
17
|
+
protected pluginInstance: Plugin | undefined;
|
|
18
|
+
|
|
19
|
+
constructor(options: Options) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public init(api: API) {
|
|
24
|
+
this.pluginInstance = new this.pluginClass(api, this.options);
|
|
25
|
+
this.pluginInstance.onInit?.();
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public getInstance(): Plugin {
|
|
30
|
+
if (!this.pluginInstance) {
|
|
31
|
+
throw new Error(`Plugin ${this.name} is not initialized`);
|
|
32
|
+
}
|
|
33
|
+
return this.pluginInstance;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export abstract class PluginImplAbstract<Options extends object> {
|
|
38
|
+
constructor(
|
|
39
|
+
protected api: API,
|
|
40
|
+
protected options: Options,
|
|
41
|
+
) {
|
|
42
|
+
this.onInit?.();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
abstract onInit?(): void;
|
|
46
|
+
|
|
47
|
+
abstract onLoad?(): void;
|
|
7
48
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { PluginAbstract } from './plugin.abstract';
|
|
2
|
+
import { API } from '../API';
|
|
3
|
+
|
|
4
|
+
export class PluginApi {
|
|
5
|
+
private plugins = new Map<string, PluginAbstract<any, any>>();
|
|
6
|
+
|
|
7
|
+
public addPlugin(plugin: PluginAbstract<any, any>) {
|
|
8
|
+
this.plugins.set(plugin.name, plugin);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public initPlugins(api: API) {
|
|
12
|
+
const plugins = new Map(this.plugins);
|
|
13
|
+
|
|
14
|
+
let size = 0;
|
|
15
|
+
|
|
16
|
+
this.plugins = new Map();
|
|
17
|
+
|
|
18
|
+
do {
|
|
19
|
+
size = plugins.size;
|
|
20
|
+
plugins.forEach((plugin, key) => {
|
|
21
|
+
const deps = plugin.dependencies.filter(
|
|
22
|
+
(dep) => !this.plugins.has(new dep().name),
|
|
23
|
+
);
|
|
24
|
+
if (deps.length === 0) {
|
|
25
|
+
this.plugins.set(plugin.name, plugin.init(api));
|
|
26
|
+
plugins.delete(key);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
} while (plugins.size != 0 && plugins.size < size);
|
|
30
|
+
|
|
31
|
+
if (plugins.size > 0)
|
|
32
|
+
throw new Error(
|
|
33
|
+
"Some plugins couldn't be loaded due to missing dependencies: " +
|
|
34
|
+
Array.from(plugins.keys()),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public loadPlugins() {
|
|
39
|
+
this.plugins.forEach((plugin) => {
|
|
40
|
+
plugin.getInstance().onLoad?.();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public getPlugin<T extends PluginAbstract<any, any>>(
|
|
45
|
+
plugin: new (...args: any) => T,
|
|
46
|
+
): T {
|
|
47
|
+
const pluginInstance = this.plugins.get(new plugin().name);
|
|
48
|
+
if (!pluginInstance) throw new Error(`Plugin ${plugin.name} not found`);
|
|
49
|
+
return pluginInstance as T;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { asClass } from 'awilix';
|
|
2
2
|
import { Module } from '../app.container';
|
|
3
|
-
import {
|
|
3
|
+
import { PluginApi } from './plugin.api';
|
|
4
4
|
|
|
5
5
|
export const PluginModule: Module = {
|
|
6
|
-
|
|
6
|
+
pluginApi: asClass(PluginApi).singleton(),
|
|
7
7
|
};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { PluginAbstract, PluginImplAbstract } from '../../plugin';
|
|
2
|
+
|
|
3
|
+
export enum FontFamily {
|
|
4
|
+
Expressive = 'expressive',
|
|
5
|
+
Neutral = 'neutral',
|
|
6
|
+
}
|
|
7
|
+
export type FontStyle = {
|
|
8
|
+
fontSize: number;
|
|
9
|
+
lineHeight: number;
|
|
10
|
+
fontWeight: number;
|
|
11
|
+
letterSpacing?: number;
|
|
12
|
+
fontFamily: FontFamily;
|
|
13
|
+
};
|
|
14
|
+
export type FontRole = 'display' | 'headline' | 'title' | 'label' | 'body';
|
|
15
|
+
export type FontSize = 'large' | 'medium' | 'small';
|
|
16
|
+
interface FontPluginOptions {
|
|
17
|
+
fontFamily?: {
|
|
18
|
+
expressive?: string[];
|
|
19
|
+
neutral?: string[];
|
|
20
|
+
};
|
|
21
|
+
fontStyles?: Partial<Record<FontRole, Record<FontSize, Partial<FontStyle>>>>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class FontPlugin extends PluginAbstract<
|
|
25
|
+
FontPluginImpl,
|
|
26
|
+
FontPluginOptions
|
|
27
|
+
> {
|
|
28
|
+
dependencies = [];
|
|
29
|
+
name = 'font';
|
|
30
|
+
pluginClass = FontPluginImpl;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class FontPluginImpl extends PluginImplAbstract<FontPluginOptions> {
|
|
34
|
+
private _fontFamily: { expressive: string[]; neutral: string[] } | undefined;
|
|
35
|
+
|
|
36
|
+
get fontFamily(): { expressive: string[]; neutral: string[] } {
|
|
37
|
+
if (!this._fontFamily) throw new Error('Font family not initialized');
|
|
38
|
+
return this._fontFamily;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
set fontFamily(
|
|
42
|
+
value: { expressive: string[]; neutral: string[] } | undefined
|
|
43
|
+
) {
|
|
44
|
+
this._fontFamily = value;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private _fontStyles:
|
|
48
|
+
| Record<FontRole, Record<FontSize, FontStyle>>
|
|
49
|
+
| undefined;
|
|
50
|
+
|
|
51
|
+
get fontStyles(): Record<FontRole, Record<FontSize, FontStyle>> {
|
|
52
|
+
if (!this._fontStyles) throw new Error('Font styles not initialized');
|
|
53
|
+
return this._fontStyles;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
set fontStyles(
|
|
57
|
+
value: Record<FontRole, Record<FontSize, FontStyle>> | undefined
|
|
58
|
+
) {
|
|
59
|
+
this._fontStyles = value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getFonts() {
|
|
63
|
+
return {
|
|
64
|
+
fontStyles: this.fontStyles,
|
|
65
|
+
fontFamily: this.fontFamily,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onInit(): void {
|
|
70
|
+
this.fontFamily = {
|
|
71
|
+
expressive: this.options?.fontFamily?.expressive ?? [
|
|
72
|
+
'Roboto',
|
|
73
|
+
'sans-serif',
|
|
74
|
+
],
|
|
75
|
+
neutral: this.options?.fontFamily?.neutral ?? ['Roboto', 'sans-serif'],
|
|
76
|
+
};
|
|
77
|
+
this.fontStyles = {
|
|
78
|
+
display: {
|
|
79
|
+
large: {
|
|
80
|
+
fontWeight: 400,
|
|
81
|
+
fontSize: 3.5625,
|
|
82
|
+
lineHeight: 4,
|
|
83
|
+
letterSpacing: -0.015625,
|
|
84
|
+
fontFamily: FontFamily.Expressive,
|
|
85
|
+
},
|
|
86
|
+
medium: {
|
|
87
|
+
fontWeight: 400,
|
|
88
|
+
fontSize: 2.8125,
|
|
89
|
+
lineHeight: 3.25,
|
|
90
|
+
fontFamily: FontFamily.Expressive,
|
|
91
|
+
},
|
|
92
|
+
small: {
|
|
93
|
+
fontWeight: 400,
|
|
94
|
+
fontSize: 2.25,
|
|
95
|
+
lineHeight: 2.75,
|
|
96
|
+
fontFamily: FontFamily.Expressive,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
headline: {
|
|
100
|
+
large: {
|
|
101
|
+
fontWeight: 400,
|
|
102
|
+
fontSize: 2,
|
|
103
|
+
lineHeight: 2.5,
|
|
104
|
+
fontFamily: FontFamily.Expressive,
|
|
105
|
+
},
|
|
106
|
+
medium: {
|
|
107
|
+
fontWeight: 400,
|
|
108
|
+
fontSize: 1.75,
|
|
109
|
+
lineHeight: 2.25,
|
|
110
|
+
fontFamily: FontFamily.Expressive,
|
|
111
|
+
},
|
|
112
|
+
small: {
|
|
113
|
+
fontWeight: 400,
|
|
114
|
+
fontSize: 1.5,
|
|
115
|
+
lineHeight: 2,
|
|
116
|
+
fontFamily: FontFamily.Expressive,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
title: {
|
|
120
|
+
large: {
|
|
121
|
+
fontWeight: 400,
|
|
122
|
+
fontSize: 1.375,
|
|
123
|
+
lineHeight: 1.75,
|
|
124
|
+
fontFamily: FontFamily.Neutral,
|
|
125
|
+
},
|
|
126
|
+
medium: {
|
|
127
|
+
fontWeight: 500,
|
|
128
|
+
fontSize: 1,
|
|
129
|
+
lineHeight: 1.5,
|
|
130
|
+
fontFamily: FontFamily.Neutral,
|
|
131
|
+
letterSpacing: 0.009375,
|
|
132
|
+
},
|
|
133
|
+
small: {
|
|
134
|
+
fontWeight: 500,
|
|
135
|
+
fontSize: 0.875,
|
|
136
|
+
lineHeight: 1.25,
|
|
137
|
+
fontFamily: FontFamily.Neutral,
|
|
138
|
+
letterSpacing: 0.00625,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
label: {
|
|
142
|
+
large: {
|
|
143
|
+
fontWeight: 500,
|
|
144
|
+
fontSize: 0.875,
|
|
145
|
+
lineHeight: 1.25,
|
|
146
|
+
fontFamily: FontFamily.Neutral,
|
|
147
|
+
letterSpacing: 0.00625,
|
|
148
|
+
},
|
|
149
|
+
medium: {
|
|
150
|
+
fontWeight: 500,
|
|
151
|
+
fontSize: 0.75,
|
|
152
|
+
lineHeight: 1,
|
|
153
|
+
fontFamily: FontFamily.Neutral,
|
|
154
|
+
letterSpacing: 0.03125,
|
|
155
|
+
},
|
|
156
|
+
small: {
|
|
157
|
+
fontWeight: 500,
|
|
158
|
+
fontSize: 0.6875,
|
|
159
|
+
lineHeight: 1,
|
|
160
|
+
fontFamily: FontFamily.Neutral,
|
|
161
|
+
letterSpacing: 0.03125,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
body: {
|
|
165
|
+
large: {
|
|
166
|
+
fontWeight: 400,
|
|
167
|
+
fontSize: 1,
|
|
168
|
+
lineHeight: 1.5625,
|
|
169
|
+
fontFamily: FontFamily.Neutral,
|
|
170
|
+
letterSpacing: 0.03125,
|
|
171
|
+
},
|
|
172
|
+
medium: {
|
|
173
|
+
fontWeight: 400,
|
|
174
|
+
fontSize: 0.875,
|
|
175
|
+
lineHeight: 1.25,
|
|
176
|
+
fontFamily: FontFamily.Neutral,
|
|
177
|
+
letterSpacing: 0.015625,
|
|
178
|
+
},
|
|
179
|
+
small: {
|
|
180
|
+
fontWeight: 400,
|
|
181
|
+
fontSize: 0.75,
|
|
182
|
+
lineHeight: 1,
|
|
183
|
+
fontFamily: FontFamily.Neutral,
|
|
184
|
+
letterSpacing: 0.025,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
if (this.options && this.options.fontStyles)
|
|
190
|
+
Object.entries(this.options.fontStyles).forEach(([key, fontParam]) => {
|
|
191
|
+
const fontRole: FontRole = key as FontRole;
|
|
192
|
+
Object.entries(fontParam).forEach(([size, fontStyle]) => {
|
|
193
|
+
const fontSize: FontSize = size as FontSize;
|
|
194
|
+
if (fontStyle) {
|
|
195
|
+
this.fontStyles[fontRole][fontSize] = {
|
|
196
|
+
...this.fontStyles[fontRole][fontSize],
|
|
197
|
+
...fontStyle,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './font.plugin';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './font';
|
package/src/theme/index.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export * from './entities';
|
|
2
|
-
export * from './models';
|
|
3
|
-
export * from './services';
|
|
4
1
|
export * from './theme.module';
|
|
2
|
+
export * from './variants';
|
|
3
|
+
export * from './scheme.manager';
|
|
4
|
+
export * from './scheme';
|
|
5
|
+
export * from './theme.api';
|
|
6
|
+
export * from './variant';
|
|
7
|
+
export * from './variant.manager';
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
Hct,
|
|
5
|
-
TonalPalette,
|
|
6
|
-
} from '@material/material-color-utilities';
|
|
1
|
+
import { Scheme, SchemeOptions } from './scheme';
|
|
2
|
+
import { argbFromHex, TonalPalette } from '@material/material-color-utilities';
|
|
3
|
+
import { Hct } from '../material-color-utilities/htc';
|
|
7
4
|
|
|
8
5
|
export type SchemeServiceOptions = Omit<
|
|
9
6
|
SchemeOptions,
|
|
@@ -12,15 +9,31 @@ export type SchemeServiceOptions = Omit<
|
|
|
12
9
|
sourcesColorHex: Record<string, string> & { primary?: string };
|
|
13
10
|
palettes: Record<
|
|
14
11
|
string,
|
|
15
|
-
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
| {
|
|
13
|
+
sourceColorkey: string;
|
|
14
|
+
tonalPalette: CustomPaletteFunction;
|
|
15
|
+
}
|
|
16
|
+
| {
|
|
17
|
+
sourceColorkey?: never;
|
|
18
|
+
tonalPalette: PaletteFunction;
|
|
19
|
+
}
|
|
19
20
|
>;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
type PaletteFunctionArgs = {
|
|
24
|
+
isDark: boolean;
|
|
25
|
+
sourceColorHct: Hct;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type PaletteFunction = (args: PaletteFunctionArgs) => TonalPalette;
|
|
29
|
+
export type CustomPaletteFunction = (
|
|
30
|
+
args: PaletteFunctionArgs & {
|
|
31
|
+
colorHct: Hct;
|
|
32
|
+
},
|
|
33
|
+
) => TonalPalette;
|
|
34
|
+
|
|
35
|
+
export class SchemeManager {
|
|
36
|
+
private schemeEntity?: Scheme;
|
|
24
37
|
private options?: SchemeServiceOptions;
|
|
25
38
|
|
|
26
39
|
createOrUpdate(options: Partial<SchemeServiceOptions>) {
|
|
@@ -53,25 +66,32 @@ export class SchemeService {
|
|
|
53
66
|
{ sourceColorkey, tonalPalette: paletteFunction },
|
|
54
67
|
] of Object.entries(this.options.palettes)) {
|
|
55
68
|
let palette: TonalPalette;
|
|
56
|
-
if (
|
|
57
|
-
palette = paletteFunction(
|
|
69
|
+
if (typeof sourceColorkey != 'string') {
|
|
70
|
+
palette = paletteFunction({
|
|
71
|
+
sourceColorHct: sourceColorHct,
|
|
72
|
+
isDark: options.isDark ?? false,
|
|
73
|
+
});
|
|
58
74
|
} else {
|
|
59
75
|
const sourceColorArgb = argbFromHex(
|
|
60
|
-
this.options.sourcesColorHex[sourceColorkey]
|
|
76
|
+
this.options.sourcesColorHex[sourceColorkey],
|
|
61
77
|
);
|
|
62
|
-
const
|
|
63
|
-
palette = paletteFunction(
|
|
78
|
+
const colorHct: Hct = Hct.fromInt(sourceColorArgb);
|
|
79
|
+
palette = paletteFunction({
|
|
80
|
+
sourceColorHct: sourceColorHct,
|
|
81
|
+
colorHct: colorHct,
|
|
82
|
+
isDark: options.isDark ?? false,
|
|
83
|
+
});
|
|
64
84
|
}
|
|
65
85
|
palettes.set(key, palette);
|
|
66
86
|
}
|
|
67
|
-
this.schemeEntity = new
|
|
87
|
+
this.schemeEntity = new Scheme({
|
|
68
88
|
...this.options,
|
|
69
89
|
palettes: palettes,
|
|
70
90
|
sourceColorArgb: sourceColorArgb,
|
|
71
91
|
});
|
|
72
92
|
}
|
|
73
93
|
|
|
74
|
-
get():
|
|
94
|
+
get(): Scheme {
|
|
75
95
|
if (!this.schemeEntity) {
|
|
76
96
|
throw new Error('Scheme is not created');
|
|
77
97
|
}
|