@charcoal-ui/tailwind-config 4.0.0-beta.8 → 4.0.0-rc.1
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/README.md +1 -1
- package/dist/_lib/TailwindBuild.d.ts.map +1 -1
- package/dist/colors/plugin.d.ts +3 -2
- package/dist/colors/plugin.d.ts.map +1 -1
- package/dist/colors/pluginTokenV1.d.ts +32 -0
- package/dist/colors/pluginTokenV1.d.ts.map +1 -0
- package/dist/index.cjs.js +194 -45
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +187 -33
- package/dist/index.esm.js.map +1 -1
- package/dist/tokenV2.d.ts +3 -0
- package/dist/tokenV2.d.ts.map +1 -0
- package/dist/tokenV2.test.d.ts +2 -0
- package/dist/tokenV2.test.d.ts.map +1 -0
- package/dist/util.d.ts +4 -0
- package/dist/util.d.ts.map +1 -1
- package/package.json +10 -7
- package/src/Custom.mdx +122 -0
- package/src/README.mdx +61 -0
- package/src/__snapshots__/index.test.ts.snap +373 -5
- package/src/__snapshots__/tokenV2.test.ts.snap +6082 -0
- package/src/_lib/TailwindBuild.ts +3 -4
- package/src/colors/plugin.ts +17 -6
- package/src/colors/pluginTokenV1.ts +99 -0
- package/src/docs/colors/__snapshots__/TextBgColor.story.storyshot +1 -1
- package/src/index.test.ts +4 -0
- package/src/index.ts +47 -8
- package/src/tokenV2.test.ts +21 -0
- package/src/tokenV2.ts +72 -0
- package/src/util.ts +29 -0
|
@@ -49,7 +49,6 @@ export class TailwindBuild {
|
|
|
49
49
|
const plugin = tailwindcss({
|
|
50
50
|
...config,
|
|
51
51
|
|
|
52
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
53
52
|
// @ts-expect-error safelist が @types/tailwindcss に生えてない
|
|
54
53
|
safelist: [
|
|
55
54
|
{
|
|
@@ -90,9 +89,9 @@ export class TailwindBuild {
|
|
|
90
89
|
const cssVariables = new Set<string>()
|
|
91
90
|
|
|
92
91
|
/**
|
|
93
|
-
* 独自に生成する CSS 変数は必ず --tailwind で始まるはず
|
|
92
|
+
* 独自に生成する CSS 変数は必ず --(tailwind|charcoal) で始まるはず
|
|
94
93
|
*/
|
|
95
|
-
this.result.root.walkDecls(/^--tailwind/u, (decl) => {
|
|
94
|
+
this.result.root.walkDecls(/^--(tailwind|charcoal)/u, (decl) => {
|
|
96
95
|
cssVariables.add(decl.prop)
|
|
97
96
|
})
|
|
98
97
|
|
|
@@ -102,7 +101,7 @@ export class TailwindBuild {
|
|
|
102
101
|
getCssVariable(varName: `--${string}`) {
|
|
103
102
|
const values: string[] = []
|
|
104
103
|
|
|
105
|
-
this.result.root.walkDecls(/^--tailwind/u, (decl) => {
|
|
104
|
+
this.result.root.walkDecls(/^--(tailwind|charcoal)/u, (decl) => {
|
|
106
105
|
if (decl.prop === varName) {
|
|
107
106
|
values.push(decl.value)
|
|
108
107
|
}
|
package/src/colors/plugin.ts
CHANGED
|
@@ -10,19 +10,30 @@ import plugin, { TailwindPlugin } from 'tailwindcss/plugin'
|
|
|
10
10
|
import { mergeEffect } from '../foundation'
|
|
11
11
|
import { CSSVariableName, CSSVariables, Definition, ThemeMap } from '../types'
|
|
12
12
|
import { COLOR_PREFIX, isSingleColor } from './utils'
|
|
13
|
+
import { defineCssVariablesV1 } from './pluginTokenV1'
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
+
* --tailwind-* また --charcoal-* を生成する
|
|
17
|
+
* TODO: --tailwindをやめる
|
|
16
18
|
*/
|
|
17
|
-
export default function cssVariableColorPlugin(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
export default function cssVariableColorPlugin(
|
|
20
|
+
themeMap: ThemeMap,
|
|
21
|
+
cssVariablesV1: boolean
|
|
22
|
+
): TailwindPlugin {
|
|
23
|
+
// `:root` 以外のケースで各 CSS Variable がどういう値を取るかを定義する
|
|
24
|
+
const { ':root': _defaultTheme, ...otherThemes } = themeMap
|
|
25
|
+
const definitions = defineCssVariables(otherThemes)
|
|
22
26
|
|
|
23
27
|
return plugin(({ addBase }) => {
|
|
24
28
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
25
29
|
addBase(definitions)
|
|
30
|
+
|
|
31
|
+
// styledのTokenInjector移植(background処理除く)
|
|
32
|
+
if (cssVariablesV1) {
|
|
33
|
+
const cssVariablesV1 = defineCssVariablesV1(themeMap)
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
35
|
+
addBase(cssVariablesV1)
|
|
36
|
+
}
|
|
26
37
|
})
|
|
27
38
|
}
|
|
28
39
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applyEffect,
|
|
3
|
+
customPropertyToken,
|
|
4
|
+
filterObject,
|
|
5
|
+
flatMapObject,
|
|
6
|
+
mapObject,
|
|
7
|
+
} from '@charcoal-ui/utils'
|
|
8
|
+
import { ThemeMap } from '../types'
|
|
9
|
+
import {
|
|
10
|
+
CharcoalAbstractTheme,
|
|
11
|
+
EffectType,
|
|
12
|
+
Key,
|
|
13
|
+
CharcoalTheme as Theme,
|
|
14
|
+
} from '@charcoal-ui/theme'
|
|
15
|
+
|
|
16
|
+
export function defineCssVariablesV1(themeMap: ThemeMap) {
|
|
17
|
+
// @ts-expect-error FIXME
|
|
18
|
+
return mapObject(themeMap, (key, theme) => {
|
|
19
|
+
if (key.startsWith('@media')) {
|
|
20
|
+
return [
|
|
21
|
+
key,
|
|
22
|
+
{
|
|
23
|
+
':root': defineColorVariableCSS(theme),
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
} else {
|
|
27
|
+
return [key, defineColorVariableCSS(theme)]
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const defineColorVariableCSS = (theme: Theme) => {
|
|
33
|
+
const borders = mapObject(theme.border, (name, { color }) => [
|
|
34
|
+
// REVIEW: もしtheme.colorにたまたまborder-〇〇で始まる色名がいたら被りうる
|
|
35
|
+
withPrefixes('border', name),
|
|
36
|
+
color,
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
const colors = defineThemeVariables({ ...theme.color, ...borders })({ theme })
|
|
40
|
+
return colors
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check whether a value is non-null and non-undefined
|
|
45
|
+
*
|
|
46
|
+
* @param value nullable
|
|
47
|
+
*/
|
|
48
|
+
export const isPresent = <T>(value: T): value is NonNullable<T> => value != null
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 子孫要素で使われるカラーテーマの CSS Variables を上書きする
|
|
52
|
+
*
|
|
53
|
+
* @params colorParams - 上書きしたい色の定義( `theme.color` の一部だけ書けば良い )
|
|
54
|
+
* @params effectParams - effect の定義を上書きしたい場合は渡す(必須ではない)
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```tsx
|
|
58
|
+
* const LocalTheme = styled.div`
|
|
59
|
+
* ${defineThemeVariables({ text1: '#ff0000' })}
|
|
60
|
+
* // `text1` is now defined as red
|
|
61
|
+
* ${theme((o) => [o.font.text1])}
|
|
62
|
+
* `
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export function defineThemeVariables(
|
|
66
|
+
colorParams: Partial<CharcoalAbstractTheme['color']>,
|
|
67
|
+
effectParams?: Partial<CharcoalAbstractTheme['effect']>
|
|
68
|
+
) {
|
|
69
|
+
return function toCssObject(props: {
|
|
70
|
+
theme: Pick<CharcoalAbstractTheme, 'effect'>
|
|
71
|
+
}) {
|
|
72
|
+
const colors = filterObject(colorParams, isPresent)
|
|
73
|
+
|
|
74
|
+
// flatMapObject の中で毎回 Object.entries を呼ぶのは無駄なので外で呼ぶ
|
|
75
|
+
const effects = Object.entries({
|
|
76
|
+
...props.theme.effect,
|
|
77
|
+
...effectParams,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
return flatMapObject(colors, (colorKey, color) => [
|
|
81
|
+
[customPropertyToken(colorKey), color],
|
|
82
|
+
|
|
83
|
+
...effects.map<[string, string]>(([effectKey, effect]) => [
|
|
84
|
+
customPropertyToken(colorKey, [effectKey]),
|
|
85
|
+
applyEffect(color, [effect]),
|
|
86
|
+
]),
|
|
87
|
+
])
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function isSupportedEffect(effect: Key): effect is EffectType {
|
|
92
|
+
return ['hover', 'press', 'disabled'].includes(effect as string)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const variable = (value: string) => `var(${value})`
|
|
96
|
+
|
|
97
|
+
export function withPrefixes(...parts: string[]) {
|
|
98
|
+
return parts.join('-')
|
|
99
|
+
}
|
package/src/index.test.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GRID_COUNT, mergeEffect } from './foundation'
|
|
2
2
|
|
|
3
|
-
import type { TailwindConfig } from 'tailwindcss/tailwind-config'
|
|
3
|
+
import type { TailwindConfig, TailwindTheme } from 'tailwindcss/tailwind-config'
|
|
4
4
|
import { TailwindVersion, ThemeMap } from './types'
|
|
5
5
|
|
|
6
6
|
import {
|
|
@@ -21,15 +21,21 @@ import { colorsToTailwindConfig } from './colors/toTailwindConfig'
|
|
|
21
21
|
import cssVariableColorPlugin from './colors/plugin'
|
|
22
22
|
import cssVariableGradientPlugin from './gradient/plugin'
|
|
23
23
|
import typographyPlugin from './typography/plugin'
|
|
24
|
+
import { unstable_createTailwindConfigTokenV2 } from './tokenV2'
|
|
25
|
+
export { unstable_createTailwindConfigTokenV2 }
|
|
24
26
|
|
|
25
27
|
interface Options {
|
|
26
28
|
version?: TailwindVersion
|
|
27
29
|
theme?: ThemeMap
|
|
30
|
+
cssVariablesV1?: boolean
|
|
31
|
+
unstableTokenV2?: boolean
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
export function createTailwindConfig({
|
|
31
35
|
theme = { ':root': light },
|
|
32
36
|
version = 'v3',
|
|
37
|
+
cssVariablesV1 = true,
|
|
38
|
+
unstableTokenV2 = false,
|
|
33
39
|
}: Options): TailwindConfig {
|
|
34
40
|
assertAllThemeHaveSameKeys(theme)
|
|
35
41
|
|
|
@@ -37,6 +43,20 @@ export function createTailwindConfig({
|
|
|
37
43
|
const effects = mergeEffect(defaultTheme)
|
|
38
44
|
const DEFAULT = getDefaultKeyName(version)
|
|
39
45
|
|
|
46
|
+
const {
|
|
47
|
+
borderWidth: borderWidthV2,
|
|
48
|
+
borderRadius: borderRadiusV2,
|
|
49
|
+
borderColor: borderColorV2,
|
|
50
|
+
colors: colorsV2,
|
|
51
|
+
fontSize: fontSizeV2,
|
|
52
|
+
fontWeight: fontWeightV2,
|
|
53
|
+
spacing: spacingV2,
|
|
54
|
+
gap: gapV2,
|
|
55
|
+
width: widthV2,
|
|
56
|
+
}: Partial<TailwindTheme> = unstableTokenV2
|
|
57
|
+
? unstable_createTailwindConfigTokenV2().theme
|
|
58
|
+
: {}
|
|
59
|
+
|
|
40
60
|
return {
|
|
41
61
|
theme: {
|
|
42
62
|
screens: {
|
|
@@ -56,6 +76,7 @@ export function createTailwindConfig({
|
|
|
56
76
|
transparent: 'transparent',
|
|
57
77
|
current: 'currentColor',
|
|
58
78
|
...colorsToTailwindConfig(version, defaultTheme.color, effects),
|
|
79
|
+
...colorsV2,
|
|
59
80
|
},
|
|
60
81
|
borderColor: {
|
|
61
82
|
...colorsToTailwindConfig(
|
|
@@ -63,8 +84,15 @@ export function createTailwindConfig({
|
|
|
63
84
|
mapObject(defaultTheme.border, (k, v) => [k, v.color]),
|
|
64
85
|
effects
|
|
65
86
|
),
|
|
87
|
+
...borderColorV2,
|
|
88
|
+
},
|
|
89
|
+
spacing: {
|
|
90
|
+
...mapObject(
|
|
91
|
+
SPACING,
|
|
92
|
+
(name, pixel) => [name, px(pixel)] as [string, string]
|
|
93
|
+
),
|
|
94
|
+
...spacingV2,
|
|
66
95
|
},
|
|
67
|
-
spacing: mapObject(SPACING, (name, pixel) => [name, px(pixel)]),
|
|
68
96
|
width: {
|
|
69
97
|
full: '100%',
|
|
70
98
|
screen: '100vw',
|
|
@@ -92,29 +120,40 @@ export function createTailwindConfig({
|
|
|
92
120
|
}),
|
|
93
121
|
{}
|
|
94
122
|
),
|
|
123
|
+
...widthV2,
|
|
95
124
|
},
|
|
96
125
|
gap: {
|
|
97
126
|
fixed: px(GUTTER_UNIT),
|
|
127
|
+
...gapV2,
|
|
128
|
+
},
|
|
129
|
+
borderRadius: {
|
|
130
|
+
...mapObject(
|
|
131
|
+
BORDER_RADIUS,
|
|
132
|
+
(name, value) => [name, px(value)] as [string, string]
|
|
133
|
+
),
|
|
134
|
+
...borderRadiusV2,
|
|
98
135
|
},
|
|
99
|
-
borderRadius: mapObject(BORDER_RADIUS, (name, value) => [
|
|
100
|
-
name,
|
|
101
|
-
px(value),
|
|
102
|
-
]),
|
|
103
136
|
transitionDuration: {
|
|
104
137
|
[DEFAULT]: '0.2s',
|
|
105
138
|
},
|
|
139
|
+
...(unstableTokenV2
|
|
140
|
+
? {
|
|
141
|
+
borderWidth: borderWidthV2,
|
|
142
|
+
fontSize: fontSizeV2,
|
|
143
|
+
fontWeight: fontWeightV2,
|
|
144
|
+
}
|
|
145
|
+
: {}),
|
|
106
146
|
},
|
|
107
147
|
|
|
108
148
|
...getVariantOption(version),
|
|
109
149
|
|
|
110
150
|
corePlugins: {
|
|
111
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
112
151
|
// @ts-expect-error 配列にしろと言ってくるが、たぶん @types が間違っている
|
|
113
152
|
lineHeight: false,
|
|
114
153
|
},
|
|
115
154
|
plugins: [
|
|
116
155
|
typographyPlugin,
|
|
117
|
-
cssVariableColorPlugin(theme),
|
|
156
|
+
cssVariableColorPlugin(theme, Boolean(cssVariablesV1)),
|
|
118
157
|
|
|
119
158
|
...Object.entries(theme).map(([selectorOrMediaQuery, theme]) =>
|
|
120
159
|
cssVariableGradientPlugin(
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TailwindBuild } from './_lib/TailwindBuild'
|
|
2
|
+
import { unstable_createTailwindConfigTokenV2 } from './tokenV2'
|
|
3
|
+
|
|
4
|
+
describe('unstable_createTailwindConfigTokenV2', async () => {
|
|
5
|
+
const config = unstable_createTailwindConfigTokenV2()
|
|
6
|
+
const result = await TailwindBuild.run(
|
|
7
|
+
config,
|
|
8
|
+
`
|
|
9
|
+
@import 'tailwindcss/base';
|
|
10
|
+
@import 'tailwindcss/utilities';
|
|
11
|
+
@import 'tailwindcss/components';
|
|
12
|
+
`
|
|
13
|
+
)
|
|
14
|
+
test('config object', () => {
|
|
15
|
+
expect(config).toMatchSnapshot()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('list of classes', () => {
|
|
19
|
+
expect(result.classNames).toMatchSnapshot()
|
|
20
|
+
})
|
|
21
|
+
})
|
package/src/tokenV2.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
3
|
+
import light from '@charcoal-ui/theme/unstable-tokens/css-variables.json'
|
|
4
|
+
import {
|
|
5
|
+
TailwindConfig,
|
|
6
|
+
TailwindThemeFontSizes,
|
|
7
|
+
} from 'tailwindcss/tailwind-config'
|
|
8
|
+
import {
|
|
9
|
+
flattenKey as flattenKeys,
|
|
10
|
+
mapDefaultKey as mapDefaultKeys,
|
|
11
|
+
} from './util'
|
|
12
|
+
|
|
13
|
+
export function unstable_createTailwindConfigTokenV2() {
|
|
14
|
+
const fontSize = Object.fromEntries(
|
|
15
|
+
Object.entries(light.text['font-size']).flatMap(([k, v]) => {
|
|
16
|
+
// text.fontSize.paragraph + text.lineHeight.paragraph -> text-paragraph
|
|
17
|
+
if (typeof v === 'string') {
|
|
18
|
+
return [
|
|
19
|
+
[
|
|
20
|
+
k,
|
|
21
|
+
[
|
|
22
|
+
v,
|
|
23
|
+
// @ts-expect-error k is keyof line-height
|
|
24
|
+
{ lineHeight: light.text['line-height'][k] },
|
|
25
|
+
],
|
|
26
|
+
],
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// text.fontSize.heading.s + text.lineHeight.heading.s -> text-heading-s
|
|
31
|
+
return Object.entries(v as Record<string, string>).map(([kk, vv]) => {
|
|
32
|
+
return [
|
|
33
|
+
[k, kk].join('-'),
|
|
34
|
+
[
|
|
35
|
+
vv,
|
|
36
|
+
// @ts-expect-error k is keyof line-height
|
|
37
|
+
{ lineHeight: light.text['line-height'][k][kk] },
|
|
38
|
+
],
|
|
39
|
+
]
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
) as TailwindThemeFontSizes
|
|
43
|
+
|
|
44
|
+
// space.target.s -> p-target-s
|
|
45
|
+
// space.gap.gapButtons -> p-gap-buttons
|
|
46
|
+
const spacing = flattenKeys(light.space, (key) => !/(gap|padding)/.test(key))
|
|
47
|
+
// color.container.default -> bg-container
|
|
48
|
+
// color.container.hover -> bg-container-hover
|
|
49
|
+
const colors = mapDefaultKeys(light.color)
|
|
50
|
+
|
|
51
|
+
const config: TailwindConfig = {
|
|
52
|
+
darkMode: 'media',
|
|
53
|
+
theme: {
|
|
54
|
+
// borderWidth.m -> border-m
|
|
55
|
+
// borderWidth.focus.1 -> border-focus-1
|
|
56
|
+
borderWidth: flattenKeys(light['border-width']),
|
|
57
|
+
borderRadius: light.radius,
|
|
58
|
+
borderColor: flattenKeys(colors.border),
|
|
59
|
+
|
|
60
|
+
colors,
|
|
61
|
+
|
|
62
|
+
fontSize,
|
|
63
|
+
fontWeight: light.text['font-weight'],
|
|
64
|
+
|
|
65
|
+
spacing: spacing,
|
|
66
|
+
gap: spacing,
|
|
67
|
+
width: light['paragraph-width'],
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return config
|
|
72
|
+
}
|
package/src/util.ts
CHANGED
|
@@ -71,3 +71,32 @@ export function camelToKebab(value: string) {
|
|
|
71
71
|
.replace(/(?<small>[\da-z]|(?=[A-Z]))(?<capital>[A-Z])/gu, '$1-$2')
|
|
72
72
|
.toLowerCase()
|
|
73
73
|
}
|
|
74
|
+
|
|
75
|
+
export const mapDefaultKey = <O extends object>(o: O) => {
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
77
|
+
return JSON.parse(JSON.stringify(o), function reviver(k: string, v: string) {
|
|
78
|
+
if (k === 'default') {
|
|
79
|
+
const DefaultKey = getDefaultKeyName('v3')
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
81
|
+
this[DefaultKey] = v
|
|
82
|
+
return undefined
|
|
83
|
+
}
|
|
84
|
+
return v
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const flattenKey = <O extends object>(
|
|
89
|
+
o: O,
|
|
90
|
+
join?: (key: string) => boolean
|
|
91
|
+
) => {
|
|
92
|
+
return Object.fromEntries(
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
Object.entries(o).flatMap(([key, v]) => {
|
|
96
|
+
if (typeof v === 'string') return [[key, v]]
|
|
97
|
+
return Object.entries(v as object).map(([kk, vv]) => {
|
|
98
|
+
return [join?.(key) ?? true ? [key, kk].join('-') : kk, vv]
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
)
|
|
102
|
+
}
|