Skip to content

Commit eb81454

Browse files
committed
feat: width, max-w-screen
1 parent e53f7cc commit eb81454

File tree

4 files changed

+163
-0
lines changed

4 files changed

+163
-0
lines changed

src/tokens/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ export * from './provide-color'
88
export * from './provide-elevation'
99
export * from './provide-motion'
1010
export * from './provide-shape'
11+
export * from './provide-sizing'
1112
export * from './provide-typography'
1213

1314
export * from './internal/border'
1415
export * from './internal/color'
1516
export * from './internal/elevation'
1617
export * from './internal/motion'
1718
export * from './internal/shape'
19+
export * from './internal/sizing'
1820
export * from './internal/typography'
1921

src/tokens/internal/sizing.ts

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import plugin from "tailwindcss/plugin";
2+
import type { IProvider } from "../../declaration/provider.interface";
3+
import type { IWindowSizing } from "../../declaration/window-sizing.interface";
4+
import { Strings } from "../../utils/strings";
5+
import { Validates } from "../../utils/validates";
6+
7+
export type TSizingProviderConstructorParams = {
8+
9+
/**
10+
* @description
11+
* tokens' prefix.
12+
*
13+
* @default 'md-sys-sizing'
14+
*
15+
* @example If the value of prefix is 'your-prefix'.
16+
* ```css
17+
* .w-compact {
18+
* width: var(--your-prefix-width-compact, 600px);
19+
* }
20+
* ```
21+
*/
22+
readonly prefix: string
23+
24+
/**
25+
* @description
26+
* When set to true, each token contains a default value.
27+
*
28+
* @default true
29+
*
30+
* @example
31+
* ```typescript
32+
* const color = provideSizing({
33+
* // .w-compact { width: var(--md-sys-sizing-width-compact, 600px); }
34+
* hardcodeDefaultValue: true,
35+
*
36+
* // .w-compact { width: var(--md-sys-sizing-width-compact, ); }
37+
* hardcodeDefaultValue: false,
38+
* })
39+
* ```
40+
*/
41+
readonly hardcodeDefaultValue: boolean
42+
43+
/**
44+
* @description
45+
* This option can customize the CSS value corresponding to certain tokens.
46+
* Note that this option ignores [hardcodeDefaultValue] and [prefix].
47+
*
48+
* @default []
49+
*
50+
* @example
51+
* ```typescript
52+
* const color = provideSizing({
53+
* customTokens: {
54+
* // .w-compact { var(--md-sys-sizing-width-compact, 100px); }
55+
* 'compact': '100px'
56+
* },
57+
* })
58+
* ```
59+
*/
60+
readonly customTokens: Omit<IWindowSizing, 'extraLarge'> | Record<string, string>
61+
62+
/**
63+
* @description
64+
* Exclude some unnecessary tokens.
65+
*
66+
* @default []
67+
*
68+
* @example
69+
* ```typescript
70+
* const color = provideSizing({
71+
* excludedTokens: [
72+
* // remove .w-compact and .max-w-screen-compact
73+
* 'compact',
74+
* ],
75+
* })
76+
* ```
77+
*/
78+
readonly excludedTokens: Array<keyof (Omit<IWindowSizing, 'extraLarge'>) | {}>
79+
}
80+
81+
abstract class DefaultWindowSizing implements IWindowSizing {
82+
compact = '600px'
83+
medium = '840px'
84+
expanded = '1200px'
85+
large = '1600px'
86+
87+
/**
88+
* extraLarge: width >= 1600px
89+
* @deprecated
90+
*/
91+
extraLarge = '1600px'
92+
}
93+
94+
class DefaultSizingTokens extends DefaultWindowSizing {
95+
public get defaultTokensRecord() {
96+
return {
97+
compact: this.compact,
98+
medium: this.medium,
99+
expanded: this.expanded,
100+
large: this.large
101+
}
102+
}
103+
}
104+
105+
export class SizingProvider extends DefaultSizingTokens implements IProvider {
106+
public prefix
107+
public tokens
108+
public hardcodeDefaultValue
109+
public excludedTokens
110+
public customTokens
111+
112+
constructor(params: Partial<TSizingProviderConstructorParams>) {
113+
super()
114+
this.prefix = params.prefix ?? 'md-sys-sizing'
115+
this.hardcodeDefaultValue = params.hardcodeDefaultValue ?? true
116+
this.excludedTokens = params.excludedTokens ?? []
117+
this.customTokens = params.customTokens ?? {}
118+
this.tokens = this.validate([this.customTokens, this.defaultTokensRecord, this.excludedTokens])
119+
}
120+
121+
private validate(params: Parameters<typeof Validates.validate>) {
122+
return Validates.validate(...params)
123+
}
124+
125+
protected transformTokensToCssRuleObject(prefix: string, tokens: Record<string, string>, hardcodeDefaultValue: boolean) {
126+
const cssPropertyComputed = (name: string, value: string) => !Object.hasOwn(this.customTokens, name) ? `var(--${prefix}-width-${Strings.toKebabCase(name)}, ${hardcodeDefaultValue ? value : ''})` : `${value}`
127+
128+
const width = Validates.transformTokenRecordToCssRuleObject(
129+
tokens,
130+
(name) => `.w-${Strings.toKebabCase(name)}`,
131+
(name, value) => ({
132+
'width': cssPropertyComputed(name, value)
133+
})
134+
)
135+
const maxWidthScreen = Validates.transformTokenRecordToCssRuleObject(
136+
tokens,
137+
(name) => `.max-w-screen-${Strings.toKebabCase(name)}`,
138+
(name, value) => ({
139+
'max-width': cssPropertyComputed(name, value)
140+
})
141+
)
142+
return Object.assign({}, width, maxWidthScreen)
143+
}
144+
145+
getPlugin() {
146+
const tokens = this.transformTokensToCssRuleObject(this.prefix, this.tokens, this.hardcodeDefaultValue)
147+
console.log(tokens);
148+
149+
return plugin(({ addUtilities }) => {
150+
addUtilities(tokens)
151+
})
152+
}
153+
154+
}

src/tokens/provide-all.ts

+4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import type { TColorProviderConstructorParams } from "./internal/color";
33
import type { TElevationProviderConstructorParams } from "./internal/elevation";
44
import type { TMotionProviderConstructorParams } from "./internal/motion";
55
import type { TShapeProviderConstructorParams } from "./internal/shape";
6+
import type { TSizingProviderConstructorParams } from "./internal/sizing";
67
import type { TTypographyProviderConstructorParams } from "./internal/typography";
78
import { provideBorder } from "./provide-border";
89
import { provideColor } from "./provide-color";
910
import { provideElevation } from "./provide-elevation";
1011
import { provideMotion } from "./provide-motion";
1112
import { provideShape } from "./provide-shape";
13+
import { provideSizing } from "./provide-sizing";
1214
import { provideTypography } from "./provide-typography";
1315

1416
export function provideAll(params: {
@@ -18,6 +20,7 @@ export function provideAll(params: {
1820
shape?: TShapeProviderConstructorParams,
1921
typography?: TTypographyProviderConstructorParams,
2022
border?: Partial<TBorderProviderConstructorParams>,
23+
sizing?: Partial<TSizingProviderConstructorParams>,
2124
}) {
2225
return ({
2326
color: provideColor(params.color),
@@ -26,6 +29,7 @@ export function provideAll(params: {
2629
shape: provideShape(params.shape),
2730
typography: provideTypography(params.typography),
2831
border: provideBorder(params.border),
32+
sizing: provideSizing(params.sizing),
2933
allPlugins() {
3034
return ([
3135
this.color.getPlugin(),

src/tokens/provide-sizing.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { SizingProvider, type TSizingProviderConstructorParams } from "./internal/sizing";
2+
3+
export const provideSizing = (params?: Partial<TSizingProviderConstructorParams>) => new SizingProvider(params ?? {})

0 commit comments

Comments
 (0)