@animus-ui/theming 0.0.1-alpha.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/LICENSE +21 -0
- package/README.md +162 -0
- package/babel.config.js +5 -0
- package/dist/core/ThemeBuilder.d.ts +34 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +1 -0
- package/dist/utils/createTheme.d.ts +53 -0
- package/dist/utils/flattenScale.d.ts +20 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/serializeTokens.d.ts +18 -0
- package/dist/utils/types.d.ts +41 -0
- package/package.json +36 -0
- package/rollup.config.js +3 -0
- package/tsconfig.json +9 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Aaron Robb
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# `@animus-ui/theming`
|
|
2
|
+
|
|
3
|
+
In order to use animus with your custom theme you must redeclare the emotion global `Theme`.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { theme } from './theme';
|
|
7
|
+
|
|
8
|
+
export type ThemeShape = typeof theme;
|
|
9
|
+
|
|
10
|
+
declare module '@emotion/react' {
|
|
11
|
+
export interface Theme extends ThemeShape {}
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
To help you create this strongly typed theme we've provided a few helpers to make it easier to progressively create a strongly typed and dynamic theme that will adhere to the correct types.
|
|
16
|
+
|
|
17
|
+
## `createTheme()`
|
|
18
|
+
|
|
19
|
+
This method is a set of chainable methods that will progressively add tokens, relationships, and core features to a theme object.
|
|
20
|
+
|
|
21
|
+
While many frameworks restrict theme scales to very specific sets we leave many of the particulars up to the user to define as the only key that we require for baseline functionality is `breakpoints`.
|
|
22
|
+
|
|
23
|
+
We do however offer optional but opinionated handling of both `colors` + `colorModes`.
|
|
24
|
+
|
|
25
|
+
### Usage
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { ThemeProvider, Global, css } from '@emotion/react';
|
|
29
|
+
|
|
30
|
+
export const theme = createTheme({
|
|
31
|
+
breakpoints: {
|
|
32
|
+
xs: '@media screen and (min-width: 480px)',
|
|
33
|
+
sm: '@media screen and (min-width: 768px)',
|
|
34
|
+
md: '@media screen and (min-width: 1024px)',
|
|
35
|
+
lg: '@media screen and (min-width: 1200px)',
|
|
36
|
+
xl: '@media screen and (min-width: 1440px)',
|
|
37
|
+
},
|
|
38
|
+
spacing: {
|
|
39
|
+
4: '0.25rem',
|
|
40
|
+
8: '0.5rem',
|
|
41
|
+
12: '0.75rem',
|
|
42
|
+
16: '1rem',
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
.addColors({
|
|
46
|
+
white: '#ffffff',
|
|
47
|
+
hyper: '3A10E5',
|
|
48
|
+
navy: '#10162f',
|
|
49
|
+
yellow: '#FFD300',
|
|
50
|
+
})
|
|
51
|
+
.createColorModes('light', {
|
|
52
|
+
light: {
|
|
53
|
+
primary: 'hyper',
|
|
54
|
+
secondary: 'navy',
|
|
55
|
+
text: 'navy',
|
|
56
|
+
background: 'white',
|
|
57
|
+
},
|
|
58
|
+
dark: {
|
|
59
|
+
primary: 'yellow',
|
|
60
|
+
secondary: 'white',
|
|
61
|
+
text: 'white',
|
|
62
|
+
background: 'navy',
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
.addVariables('spacing')
|
|
66
|
+
.build();
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* To use your new theme you must do 3 things.
|
|
70
|
+
* 1. Declare your theme shape as the emotion theme.
|
|
71
|
+
* 2. Wrap your application in a ThemeProvider
|
|
72
|
+
* 3. And add your variables to the global styles.
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
export type ThemeShape = typeof theme;
|
|
76
|
+
|
|
77
|
+
declare module '@emotion/react' {
|
|
78
|
+
export interface Theme extends ThemeShape {}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const App = () => {
|
|
82
|
+
return (
|
|
83
|
+
<ThemeProvider theme={theme}>
|
|
84
|
+
<Global styles={css({ ':root': root })} />
|
|
85
|
+
<Global styles={css({ ':root': colorMode })} />
|
|
86
|
+
<Component />
|
|
87
|
+
</ThemeProvider>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Methods
|
|
93
|
+
|
|
94
|
+
A theme creator method that progressively build and decorate a type safe theme object. This allows us to create a build separate themes that will be compatible with animus props. The raw theme must have a valid breakpoint scale to ensure breakpoint variable serialization.
|
|
95
|
+
|
|
96
|
+
**Standard Methods** - These are the core methods to add scales and variables to the theme object
|
|
97
|
+
|
|
98
|
+
- `addScale(scaleKey, updateFunction)` - Adds a set of tokens to the theme on the provided scale key. The current theme can be used as reference for this new scale for shared value reference.
|
|
99
|
+
- `updateScale(scaleKey, updateFunction)` - Updates an existing scale with new or computed value without them being explicitly declared. This can also be used to update or extend a theme for a different context (restrictions or expansions).
|
|
100
|
+
- `createScaleVariables(scaleKey)` - Takes a top level key of the current theme and serialized them as CSS variables. The theme will include references to CSS Variables and adds the actual token values to the root scope of our variable object.
|
|
101
|
+
|
|
102
|
+
**Special Methods** - these have specific behavior that is non standard, these are both required for all features to work
|
|
103
|
+
|
|
104
|
+
- `addColors(tokens)` - Adds color tokens to the theme and creates root color variables by default. Calling this method required to access `getColorValue` and `addColorModes`. You will not be able to add colors through `addScale` and be able to build color modes as they have different internal behaviors. However if you do not want either features you may use it without any issue.
|
|
105
|
+
- `addColorModes(initialMode, colorModes)` - This method takes a configuration of color aliases that have semantic meaning between contexts such as `light` and `dark` modes. This will take a map of modes and an initial mode.
|
|
106
|
+
- Colors must exist on the theme for this to work, call this method after `addColors` to ensure this works correctly.
|
|
107
|
+
- This creates CSS variables for the initial color mode and adds them to the specific bucket at the root scope and ensures that nested color variable references behave correctly (if variables change these will too).
|
|
108
|
+
|
|
109
|
+
**Finalization**
|
|
110
|
+
|
|
111
|
+
- `build()` - Called when all mutations are finished and we get the finalized and fully typed design system objects.
|
|
112
|
+
|
|
113
|
+
# Other Utilities
|
|
114
|
+
|
|
115
|
+
These are some under the hood utilities that you can use outside of root theme creation. `createTheme` may use some of these internally but they can also be used independently.
|
|
116
|
+
|
|
117
|
+
## `serializeTokens()`
|
|
118
|
+
|
|
119
|
+
### Arguments
|
|
120
|
+
|
|
121
|
+
- `tokens` any set of tokens.
|
|
122
|
+
- `prefix` a string to prefix any tokens
|
|
123
|
+
- `theme` to reference existing tokens specifically for breakpoints.
|
|
124
|
+
|
|
125
|
+
This method predictably maps token literal values to CSS variables. We use this to store relational or contextual information in a single reference.
|
|
126
|
+
|
|
127
|
+
### Usage
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
const { tokens, variables } = serializeTokens({
|
|
131
|
+
black: '#000000',
|
|
132
|
+
white: '#FFFFFF'
|
|
133
|
+
}, 'color', {});
|
|
134
|
+
|
|
135
|
+
// tokens
|
|
136
|
+
{ black: 'var(--color-black)', white: 'var(--color-white)' }
|
|
137
|
+
|
|
138
|
+
// variables
|
|
139
|
+
{ '--color-black': '#000000', '--color-white': '#FFFFFF' };
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
This will also work with possible nested selectors like breakpoints:
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
const {
|
|
146
|
+
tokens, //An object of the same keys as the first argument but with values that point to variable references
|
|
147
|
+
variables // Valid CSS variables that are prefixed with the same keys.
|
|
148
|
+
} = serializeTokens({
|
|
149
|
+
height: { _: '4rem', lg: '5rem' },
|
|
150
|
+
}, 'header', theme);
|
|
151
|
+
|
|
152
|
+
// tokens
|
|
153
|
+
{ height: 'var(--header-height)' }
|
|
154
|
+
|
|
155
|
+
// variables
|
|
156
|
+
{
|
|
157
|
+
'--header-height': '4rem',
|
|
158
|
+
'@media screen and (min-width: 1024px)': {
|
|
159
|
+
'--header-height': '5rem',
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
package/babel.config.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Breakpoints } from '@animus-ui/core';
|
|
2
|
+
/**
|
|
3
|
+
* 1. Breakpoints
|
|
4
|
+
* 2. Scales
|
|
5
|
+
* 3. Tokens
|
|
6
|
+
* 4. Variables
|
|
7
|
+
* 5. Colors
|
|
8
|
+
* 6. Color Modes
|
|
9
|
+
*/
|
|
10
|
+
export declare class ThemeWithAll<Bps, Scales, Tokens, Vars> {
|
|
11
|
+
breakpoints: Bps;
|
|
12
|
+
scales: Scales;
|
|
13
|
+
tokens: Tokens;
|
|
14
|
+
variables: Vars;
|
|
15
|
+
constructor(breakpoints: Bps, scales: Scales, tokens: Tokens, vars: Vars);
|
|
16
|
+
addScale(): ThemeWithAll<Bps, Scales, Tokens, Vars>;
|
|
17
|
+
build(): {
|
|
18
|
+
breakpoints: Bps;
|
|
19
|
+
} & Scales & {
|
|
20
|
+
_tokens: Tokens;
|
|
21
|
+
_variables: Vars;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export declare class ThemeWithRawColors<Bps extends Breakpoints, Scales, Tokens, Vars> extends ThemeWithAll<Bps, Scales, Tokens, Vars> {
|
|
25
|
+
constructor(breakpoints: Bps, scales: Scales, tokens: Tokens, vars: Vars);
|
|
26
|
+
addColorModes(): ThemeWithAll<Bps, Scales, Tokens, Vars>;
|
|
27
|
+
}
|
|
28
|
+
export declare class ThemeWithBreakpoints<Bps extends Breakpoints> extends ThemeWithAll<Bps, {}, {}, {}> {
|
|
29
|
+
constructor(breakpoints: Bps);
|
|
30
|
+
addColors(): ThemeWithRawColors<Bps, {}, {}, {}>;
|
|
31
|
+
}
|
|
32
|
+
export declare class ThemeUnitialized {
|
|
33
|
+
addBreakpoints<Bps extends Breakpoints>(breakpoints: Bps): ThemeWithBreakpoints<Bps>;
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("lodash");function t(s,r){return Object.keys(s).reduce(((o,h)=>{const i=r?`${r}${"_"===h?"":`-${h}`}`:h,a=s[h];return e.isObject(a)?{...o,...t(a,i)}:{...o,[i]:s[h]}}),{})}const s=(t,s,r)=>{const o={},h={};return Object.keys(t).forEach((i=>{const a=`--${s}-${i}`;o[i]=`var(${a})`,e.merge(h,((t,s,r)=>{if(e.isObject(t)){const{_:e,base:o,...h}=t,i={[s]:e??o};if(r){const{breakpoints:e}=r;Object.keys(e).forEach((t=>{i[e[t]]={[s]:h[t]}}))}return i}return{[s]:t}})(t[i],a,r))})),{tokens:o,variables:h}};class r{#e={};constructor(e){this.#e=e}createScaleVariables(t){const{variables:r,tokens:o}=s(this.#e[t],t,this.#e);return this.#e=e.merge({},this.#e,{[t]:o,_variables:{root:r},_tokens:{[t]:this.#e[t]}}),this}addColors(r){const o=t(r),{variables:h,tokens:i}=s(o,"color",this.#e);return this.#e=e.merge({},this.#e,{colors:i,_variables:{root:h},_tokens:{colors:o}}),this}addColorModes(r,o){const h=e.mapValues(o,(e=>t(e))),{tokens:i,variables:a}=s(e.mapValues(e.merge({},this.#e.modes?.[r],h[r]),(e=>this.#e.colors[e])),"color",this.#e),m=e=>this.#e._tokens?.colors?.[e];return this.#e=e.merge({},this.#e,{colors:i,modes:h,mode:r,_getColorValue:m,_variables:{mode:a},_tokens:{modes:e.mapValues(h,(t=>e.mapValues(t,m)))}}),this}addScale(s,r){return this.#e=e.merge({},this.#e,{[s]:t(r(this.#e))}),this}updateScale(t,s){return this.#e=e.merge({},this.#e,{[t]:s(this.#e[t])}),this}build(){return e.merge({},this.#e,{_variables:{},_tokens:{}})}}exports.ThemeBuilder=r,exports.createTheme=function(e){return new r(e)},exports.flattenScale=t,exports.serializeTokens=s;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isObject as e,merge as t,mapValues as s}from"lodash";function o(t,s){return Object.keys(t).reduce(((r,h)=>{const i=s?`${s}${"_"===h?"":`-${h}`}`:h,n=t[h];return e(n)?{...r,...o(n,i)}:{...r,[i]:t[h]}}),{})}const r=(s,o,r)=>{const h={},i={};return Object.keys(s).forEach((n=>{const a=`--${o}-${n}`;h[n]=`var(${a})`,t(i,((t,s,o)=>{if(e(t)){const{_:e,base:r,...h}=t,i={[s]:e??r};if(o){const{breakpoints:e}=o;Object.keys(e).forEach((t=>{i[e[t]]={[s]:h[t]}}))}return i}return{[s]:t}})(s[n],a,r))})),{tokens:h,variables:i}};class h{#e={};constructor(e){this.#e=e}createScaleVariables(e){const{variables:s,tokens:o}=r(this.#e[e],e,this.#e);return this.#e=t({},this.#e,{[e]:o,_variables:{root:s},_tokens:{[e]:this.#e[e]}}),this}addColors(e){const s=o(e),{variables:h,tokens:i}=r(s,"color",this.#e);return this.#e=t({},this.#e,{colors:i,_variables:{root:h},_tokens:{colors:s}}),this}addColorModes(e,h){const i=s(h,(e=>o(e))),{tokens:n,variables:a}=r(s(t({},this.#e.modes?.[e],i[e]),(e=>this.#e.colors[e])),"color",this.#e),c=e=>this.#e._tokens?.colors?.[e];return this.#e=t({},this.#e,{colors:n,modes:i,mode:e,_getColorValue:c,_variables:{mode:a},_tokens:{modes:s(i,(e=>s(e,c)))}}),this}addScale(e,s){return this.#e=t({},this.#e,{[e]:o(s(this.#e))}),this}updateScale(e,s){return this.#e=t({},this.#e,{[e]:s(this.#e[e])}),this}build(){return t({},this.#e,{_variables:{},_tokens:{}})}}function i(e){return new h(e)}export{h as ThemeBuilder,i as createTheme,o as flattenScale,r as serializeTokens};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { CSSObject, AbstractTheme } from '@animus-ui/core';
|
|
2
|
+
import { LiteralPaths } from './flattenScale';
|
|
3
|
+
import { KeyAsVariable } from './serializeTokens';
|
|
4
|
+
import { ColorModeConfig, Merge, MergeTheme, PrivateThemeKeys } from './types';
|
|
5
|
+
export declare class ThemeBuilder<T extends AbstractTheme> {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(baseTheme: T);
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param key A key of the current theme to transform into CSS Variables and Variable References
|
|
11
|
+
* @example .createScaleVariables('fontSize')
|
|
12
|
+
*/
|
|
13
|
+
createScaleVariables<Key extends keyof Omit<T, 'breakpoints'> & string>(key: Key): ThemeBuilder<MergeTheme<T, PrivateThemeKeys, Record<Key, Record<Key, KeyAsVariable<T[Key], Key>>>>>;
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @param colors A map of color tokens to add to the theme. These tokens are immediately converted to CSS Variables `--color-${key}`.
|
|
17
|
+
* @example .addColors({ navy: 'navy', hyper: 'purple' })
|
|
18
|
+
*/
|
|
19
|
+
addColors<Colors extends Record<string, string | number | CSSObject>, NextColors extends LiteralPaths<Colors, '-'>>(colors: Colors): ThemeBuilder<MergeTheme<T & PrivateThemeKeys, Record<'colors', KeyAsVariable<NextColors, 'color'>>>>;
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @param initialMode A key of the object passed for modes. This sets the default state for the theme and transforms the correct variables.
|
|
23
|
+
* @param modes A map of color modes with keys of each possible mode with a value of alias to color keys. This must be called after `addColors`
|
|
24
|
+
* @example .addColorModes('light', { light: { primary: 'hyper' }, { dark: { primary: 'navy' } } })
|
|
25
|
+
*/
|
|
26
|
+
addColorModes<Modes extends string, InitialMode extends keyof Config, Colors extends keyof T['colors'], ModeColors extends ColorModeConfig<Colors>, Config extends Record<Modes, ModeColors>, ColorAliases extends {
|
|
27
|
+
[K in keyof Config]: LiteralPaths<Config[K], '-', '_'>;
|
|
28
|
+
}>(initialMode: InitialMode, modeConfig: Config): ThemeBuilder<MergeTheme<T & PrivateThemeKeys, {
|
|
29
|
+
colors: KeyAsVariable<LiteralPaths<Config[keyof Config], '-', '_'>, 'colors'> & T['colors'];
|
|
30
|
+
modes: Merge<T['modes'], ColorAliases>;
|
|
31
|
+
mode: keyof Config;
|
|
32
|
+
_getColorValue: (color: keyof T['colors']) => string;
|
|
33
|
+
}>>;
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param key A new key of theme
|
|
37
|
+
* @param createScale A function that accepts the current theme and returns a new object of scale values.
|
|
38
|
+
* @example .addScale('fonts', () => ({ basic: 'Gotham', cool: 'Wingdings' }))
|
|
39
|
+
*/
|
|
40
|
+
addScale<Key extends string, Fn extends (theme: T) => Record<string | number, string | number | Record<string, string | number>>, NewScale extends LiteralPaths<ReturnType<Fn>, '-'>>(key: Key, createScale: Fn): ThemeBuilder<MergeTheme<T, Record<Key, NewScale>>>;
|
|
41
|
+
/**
|
|
42
|
+
*
|
|
43
|
+
* @param key A current key of theme to be updated with new or computed values
|
|
44
|
+
* @param updateFn A function that accepts an argument of the current values at the specified keys an returns a map of new values to merge.
|
|
45
|
+
* @example .updateScale('fonts', ({ basic }) => ({ basicFallback: `{basic}, Montserrat` }))
|
|
46
|
+
*/
|
|
47
|
+
updateScale<Key extends keyof T, Fn extends (tokens: T[Key]) => Record<string | number, unknown>>(key: Key, updateFn: Fn): ThemeBuilder<T & Record<Key, T[Key] & ReturnType<Fn>>>;
|
|
48
|
+
/**
|
|
49
|
+
* This finalizes the theme build and returns the final theme and variables to be provided.
|
|
50
|
+
*/
|
|
51
|
+
build(): T & PrivateThemeKeys;
|
|
52
|
+
}
|
|
53
|
+
export declare function createTheme<T extends AbstractTheme>(base: T): ThemeBuilder<T>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns an exhaustive list of all possible paths of an object T for keys K.
|
|
3
|
+
* Possibilities are returned as `k1.k2.k3`.
|
|
4
|
+
*/
|
|
5
|
+
export declare type FindPath<T, K extends keyof T, D extends string = '.'> = K extends string | number ? T[K] extends Record<string | number, any> ? T[K] extends ArrayLike<any> ? K | `${K}${D}${FindPath<T[K], Exclude<keyof T[K], keyof any[]>, D>}` : K | `${K}${D}${FindPath<T[K], keyof T[K], D>}` : K : never;
|
|
6
|
+
/** Returns valid paths of object T */
|
|
7
|
+
export declare type Path<T, D extends string = '.'> = FindPath<T, keyof T, D> | keyof T;
|
|
8
|
+
/** Returns the value of a valid path P `k1.k2.k3` in object T */
|
|
9
|
+
export declare type PathValue<T, P extends Path<T, D>, D extends string = '.'> = P extends `${infer K}${D}${infer Rest}` ? K extends keyof T ? Rest extends Path<T[K], D> ? PathValue<T[K], Rest, D> : never : never : P extends keyof T ? T[P] : never;
|
|
10
|
+
/** Check if path has a primitive end value and return only the union of end paths */
|
|
11
|
+
export declare type PathToLiteral<T, K extends Path<T, D>, D extends string = '.', Base extends string = ''> = PathValue<T, K, D> extends string | number ? K extends string | number ? K extends `${infer BasePath}${D}${Base}` ? BasePath : K : never : never;
|
|
12
|
+
/**
|
|
13
|
+
* Reduce all paths to a single map of paths with primitive values removing all extra non stateful paths
|
|
14
|
+
* { path: { sub: 1 } } => { 'path-sub': 1 }
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
export declare type LiteralPaths<T extends Record<string | number, any>, D extends string = '.', Base extends string = ''> = {
|
|
18
|
+
[K in Path<T, D> as PathToLiteral<T, K, D, Base>]: PathValue<T, PathToLiteral<T, K, D>, D>;
|
|
19
|
+
};
|
|
20
|
+
export declare function flattenScale<T extends Record<string | number, any>, P extends string>(object: T, path?: P): LiteralPaths<T, '-', '_'>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Theme } from '@emotion/react';
|
|
2
|
+
import { CSSObject } from '@animus-ui/core';
|
|
3
|
+
/**
|
|
4
|
+
* Returns an type of any object with { key: 'var(--key) }
|
|
5
|
+
*/
|
|
6
|
+
export declare type KeyAsVariable<T extends Record<string, any>, Prefix extends string> = {
|
|
7
|
+
[V in keyof T]: `var(--${Prefix}-${Extract<V, string>})`;
|
|
8
|
+
};
|
|
9
|
+
declare type SerializedTokensInput = Record<string, string | number | CSSObject | SerializedTokensInputRecursive>;
|
|
10
|
+
interface SerializedTokensInputRecursive {
|
|
11
|
+
[i: number]: SerializedTokensInput;
|
|
12
|
+
[i: string]: SerializedTokensInput;
|
|
13
|
+
}
|
|
14
|
+
export declare const serializeTokens: <T extends SerializedTokensInput, Prefix extends string>(tokens: T, prefix: Prefix, theme: Theme | undefined) => {
|
|
15
|
+
tokens: KeyAsVariable<T, Prefix>;
|
|
16
|
+
variables: CSSObject;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AbstractTheme, CSSObject } from '@animus-ui/core';
|
|
2
|
+
/**
|
|
3
|
+
* This is a custom generic that ensures the safety of adding additional values to a theme object without accidentally wiping out
|
|
4
|
+
* required keys like `breakpoints`. It works by creating a new mapped type and merging the values of the union of Base & Next:
|
|
5
|
+
* 1. If the key exists on both Base and Next return the intersection of both values
|
|
6
|
+
* 2. If the key exists on next use the value on next.
|
|
7
|
+
* 3. If the key exists on base but nothing else use the value on base.
|
|
8
|
+
*
|
|
9
|
+
* The resulting type is then rejoined with keys that cannot be mutated (breakpoints) as the next version of Theme
|
|
10
|
+
*/
|
|
11
|
+
export declare type MergeTheme<Base extends AbstractTheme, Next, Unmergable = Record<'breakpoints', Base['breakpoints']>> = Unmergable & Merge<Base, Next>;
|
|
12
|
+
/** This merges at 2 levels of depth */
|
|
13
|
+
export declare type Merge<A, B> = {
|
|
14
|
+
[K in keyof (A & B)]: K extends keyof B ? K extends keyof A ? AssignValueIfUnmergable<A[K], B[K]> : B[K] : K extends keyof A ? A[K] : never;
|
|
15
|
+
};
|
|
16
|
+
/** Extract mergable objects */
|
|
17
|
+
export declare type Mergable<T> = Exclude<T, ((...args: any) => any) | string | boolean | symbol | number | any[]>;
|
|
18
|
+
/** Return B if either A or B is unmergable */
|
|
19
|
+
export declare type AssignValueIfUnmergable<A, B> = Mergable<A> extends never ? B : Mergable<B> extends never ? B : Assign<A, B>;
|
|
20
|
+
/** Prefer all values from B */
|
|
21
|
+
export declare type Assign<A, B> = {
|
|
22
|
+
[K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never;
|
|
23
|
+
};
|
|
24
|
+
/** These are keys that are consistent for all theme builds - they are loosely typed as they are not meant to be accessed directly */
|
|
25
|
+
export declare type PrivateThemeKeys = {
|
|
26
|
+
_variables: Record<string, CSSObject>;
|
|
27
|
+
_tokens: Record<string | number, any>;
|
|
28
|
+
};
|
|
29
|
+
/** This allows 3 layers of color aliases to be constructed when adding colorModes
|
|
30
|
+
* @example
|
|
31
|
+
* {
|
|
32
|
+
* button: {
|
|
33
|
+
* bg: {
|
|
34
|
+
* hover: 'someAlias'
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* `button-bg-hover`
|
|
40
|
+
* */
|
|
41
|
+
export declare type ColorModeConfig<Colors> = Record<string, Colors | Record<string, Colors> | Record<string, Colors | Record<string, Colors>>>;
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@animus-ui/theming",
|
|
3
|
+
"version": "0.0.1-alpha.0+5f19171",
|
|
4
|
+
"description": "> TODO: description",
|
|
5
|
+
"author": "Aaron Robb <airrobb@gmail.com>",
|
|
6
|
+
"homepage": "https://github.com/codecaaron/animus#readme",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"main": "dist/index.cjs.js",
|
|
9
|
+
"module": "dist/index.esm.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/codecaaron/animus.git"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build:clean": "rm -rf ./dist",
|
|
20
|
+
"build": "yarn build:clean && rollup -c",
|
|
21
|
+
"lernaBuildTask": "yarn build"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/codecaaron/animus/issues"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@animus-ui/core": "^0.0.1-alpha.0+5f19171"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@emotion/react": ">=11.0.0",
|
|
31
|
+
"@emotion/styled": ">=11.0.0",
|
|
32
|
+
"lodash": "*",
|
|
33
|
+
"typescript": ">=4.3.5"
|
|
34
|
+
},
|
|
35
|
+
"gitHead": "5f191713f482153b8dd1948e4d0f9f6b56a2e9fc"
|
|
36
|
+
}
|
package/rollup.config.js
ADDED
package/tsconfig.json
ADDED