|
6 | 6 |
|
7 | 7 | # [Docs](https://alanscodelog.github.io/metamorphosis)
|
8 | 8 |
|
9 |
| -Metamorphosis is a css variable management library that helps create and organize variables into easily configurable groups and themes. |
| 9 | +Metamorphosis is a css variable management library that helps create and organize variables into easily configurable themes. |
10 | 10 |
|
11 |
| -Establish a few control variables and convert them into an easy to use design system. |
| 11 | +Establish a few control variables and easily create interpolated variables with multiple stops. |
12 | 12 |
|
13 |
| -Unlike other css libraries, it's designed to be managed from the js side to allow for easy, consistent user theming. All variables are also strongly typed with typescript. |
| 13 | +It can be used by itself or as a compliment to other css libraries (e.g. tailwind). It's also easy to integrate other interpolators such as colorsjs.io. |
| 14 | + |
| 15 | +It's designed to allow management from the js side to allow for easy, consistent user theming in apps (though it can be used to statically generate css variables as well). |
| 16 | + |
| 17 | +All variables are strongly typed with typescript. |
14 | 18 |
|
15 | 19 | # Usage
|
16 | 20 |
|
17 | 21 | A quick example:
|
18 | 22 |
|
19 | 23 | ```ts
|
20 |
| -import { Format, InterpolatedVars, Theme, Unit, Var, VarGroup } from "metamorphosis" |
21 |
| - |
22 |
| -// create the base color variables |
23 |
| -const white = new Var("white", Unit.rgb, { r: 255, g: 255, b: 255 }, { |
24 |
| - format: Format.rgb, |
25 |
| -}) |
26 |
| -const black = new Var("black", Unit.rgb, { r: 0, g: 0, b: 0 }, { |
27 |
| - format: Format.rgb, |
28 |
| -}) |
29 |
| - |
30 |
| -// create interpolated variables based on them |
31 |
| -const grays = new InterpolatedVars("gray", Unit.rgb, { |
32 |
| - start: white, |
33 |
| - end: black, |
34 |
| - steps: 10, |
35 |
| - format: Format.rgb |
36 |
| -}) |
37 |
| - |
38 |
| -// further group/select certain variables |
39 |
| -const colors = new VarGroup("color", { |
40 |
| - text: [grays, "8"] |
41 |
| -}) |
42 |
| - |
43 |
| -// create a theme |
44 |
| -const theme = new Theme("mainTheme", { |
| 24 | +const paddingMin = new ControlVar(Units.px, 0) |
| 25 | +const paddingMax = new ControlVar(Units.px, 200) |
| 26 | + |
| 27 | + |
| 28 | +const padding = new InterpolatedVars("padding", |
| 29 | + Units.px, |
| 30 | + [paddingMin, paddingMax], |
| 31 | +/* { steps: 10 } i.e. 0-9 */ |
| 32 | +) |
| 33 | + |
| 34 | +const white = new ControlVar(Units.rgb, { r: 255, g: 255, b: 255 }) |
| 35 | +const black = new ControlVar(Units.rgb, { r: 0, g: 0, b: 0 }) |
| 36 | + |
| 37 | +const grays = new InterpolatedVars("gray", Units.rgb, [white, black], |
| 38 | + { |
| 39 | + // custom percentages |
| 40 | + steps: [0, 0.2, 0.8, 1], |
| 41 | + keyName: paddedKeyNamer(1000), // gray-000 |
| 42 | + }) |
| 43 | + |
| 44 | +const lightRed = new ControlVar(Units.rgb, { r: 255, g: 0, b: 0 }) |
| 45 | +const saturatedMiddleRed = new ControlVar(Units.rgb, { r: 255, g: 170, b: 170 }) |
| 46 | +const darkRed = new ControlVar(Units.rgb, { r: 50, g: 0, b: 0 }) |
| 47 | + |
| 48 | +// interpolated along multiple values |
| 49 | +const red = new InterpolatedVars("red", Units.rgb, [ |
| 50 | + lightRed, |
| 51 | + saturatedMiddleRed, |
| 52 | + darkRed, |
| 53 | +]) |
| 54 | + |
| 55 | +// with custom stops |
| 56 | +const reds = new InterpolatedVars("red", Units.rgb, [ |
| 57 | + [0, lightRed], |
| 58 | + [0.25, saturatedMiddleRed], |
| 59 | + [0.75, darkRed], |
| 60 | +]) |
| 61 | + |
| 62 | + |
| 63 | +const theme = new Theme({ |
45 | 64 | grays,
|
46 |
| - colors |
| 65 | + padding, |
47 | 66 | })
|
48 | 67 |
|
49 |
| -// view theme |
50 |
| -// by default dependencies are hidden, white and black won't show |
51 |
| -console.log(theme.css()) |
| 68 | +// theme.css |
52 | 69 | // :root {
|
53 |
| -// gray-0: rgb(255, 255, 255); |
54 |
| -// ... |
55 |
| -// gray-10: rgb(0, 0, 0); |
56 |
| -// color-text: rgb(51, 51, 51); |
| 70 | +// --gray-000: rgb(255, 255, 255); |
| 71 | +// --gray-250: rgb(204, 204, 204); |
| 72 | +// --gray-500: rgb(51, 51, 51); |
| 73 | +// --gray-750: rgb(0, 0, 0); |
| 74 | +// --padding-0: 0px; |
| 75 | +// ... |
| 76 | +// --padding-9: 200px; |
57 | 77 | // }
|
58 | 78 |
|
59 | 79 | // change a control variable
|
60 | 80 | white.set({ r: 200, g: 200, b: 200 })
|
61 | 81 |
|
62 | 82 | // all variables that depend on it update
|
63 |
| -console.log(theme.css()) |
| 83 | +// theme.css |
64 | 84 | // :root {
|
65 |
| -// gray-0: rgb(200, 200, 200); |
| 85 | +// --gray-000: rgb(200, 200, 200); |
66 | 86 | // ...
|
67 |
| -// gray-10: rgb(0, 0, 0); |
68 |
| -// color-text: rgb(40, 40, 40); |
| 87 | +// --gray-750: rgb(0, 0, 0); |
69 | 88 | // }
|
70 | 89 |
|
71 |
| -// attach or detach a theme from an element, if none given, attaches to document.documentElement |
| 90 | +// attach or detach a theme from an element |
| 91 | +// if none given attaches to document.documentElement |
72 | 92 | // attaching will set the css variables on the element and keep them updated
|
73 | 93 | theme.attach(/* el */)
|
74 | 94 | theme.detach(/* el */)
|
75 |
| -``` |
76 | 95 |
|
77 |
| -Usage of each class is detailed in the docs. |
| 96 | +// add/remove variables |
| 97 | +theme.add({ reds }) |
| 98 | +theme.add({ lightRed }) |
| 99 | +theme.remove("lightRed") |
| 100 | + |
| 101 | +// ADVANCED |
| 102 | + |
| 103 | +// custom unit creation |
| 104 | +// the function argument is used as the unit definition |
| 105 | +const fancyRem = Units.createSimpleUnit("fancy-rem") // same as ({ _ }: { _: number }) => `${_}fancy-rem` |
| 106 | +const fancyUnit = ( |
| 107 | + { some, fancy, unit }: |
| 108 | + { some: number, fancy: "string", unit: boolean } |
| 109 | +) => `${some}px ${fancy} ${unit}` |
| 110 | + |
| 111 | +// so long as the control vars take the same arguments |
| 112 | +// you can use unit functions as custom formatters: |
| 113 | +const customRgbFormatter = ({ r, g, b, a = 0 }: Units.Rgb) => `R:${r} G:${g} B:${b} ${a ? `A:${a}` : ""}` |
| 114 | +const grays3 = new InterpolatedVars("gray", customRgbFormatter, [white, black]) |
| 115 | + |
| 116 | +// custom interpolation, for example, using colorjs.io |
| 117 | + |
| 118 | +// import Color from "colorjs.io" |
| 119 | + |
| 120 | +const grays4 = new InterpolatedVars("gray", Units.rgb, [white, black], { |
| 121 | + interpolator: ({ percent, state, start, end }) => { |
| 122 | + const key = start.css + end.css |
| 123 | + // re/create state if at start or if key switched (due to |
| 124 | + // multiple stops) |
| 125 | + if (state.key !== key) { |
| 126 | + state.range = new Color(start.css).range(new Color(end.css), { space: "srgb" }) |
| 127 | + state.key = key |
| 128 | + } |
| 129 | + |
| 130 | + const val = state.range(percent).coords |
| 131 | + return { r: val[0] * 255, g: val[1] * 255, b: val[0] * 255 } |
| 132 | + }, |
| 133 | +}) |
| 134 | + |
| 135 | +// we can also be a bit more flexible at the cost of strict typing and |
| 136 | +// use colorjs.io's parsing abilities to pass the colors as strings in any format |
| 137 | + |
| 138 | +const white2 = new ControlVar(Units.str, `rgb(255, 255, 255)`) |
| 139 | +const black2 = new ControlVar(Units.str, `#000000`) |
| 140 | + |
| 141 | +const grays5 = new InterpolatedVars("gray", Units.str, [white2, black2], { |
| 142 | + interpolator: ({ percent, state, start, end }) => { |
| 143 | + const key = start.css + end.css |
| 144 | + if (state.key !== key) { |
| 145 | + state.range = new Color(start.css).range(new Color(end.css), { space: "srgb" }) |
| 146 | + state.key = key |
| 147 | + } |
| 148 | + /* ... */ |
| 149 | + return state.range(percent) |
| 150 | + .to("srgb") // our preferred output space |
| 151 | + .toString({ format: "srgb" }) |
| 152 | + }, |
| 153 | +}) |
| 154 | +``` |
78 | 155 |
|
79 |
| -For an example of more advanced usage, see [the example base theme](https://github.com/AlansCodeLog/metamorphosis/blob/master/src/BaseTheme/BaseTheme.ts) . |
| 156 | +For an example of more advanced usage, see [the example base theme](https://github.com/AlansCodeLog/metamorphosis/blob/master/src/BaseTheme.ts). |
80 | 157 |
|
| 158 | +The library has optional peer dependencies for tailwind and colorjs.io. colorjs.io is only needed if importing the base theme from `metamorphosis/BaseTheme`. And tailwind is only needed if importing from `metamorphosis/tailwind`. |
0 commit comments