@charcoal-ui/styled 2.3.0 → 2.5.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/dist/builders/border.d.ts +10 -0
- package/dist/builders/border.d.ts.map +1 -0
- package/dist/builders/borderRadius.d.ts +7 -0
- package/dist/builders/borderRadius.d.ts.map +1 -0
- package/dist/builders/colors.d.ts +13 -0
- package/dist/builders/colors.d.ts.map +1 -0
- package/dist/builders/elementEffect.d.ts +7 -0
- package/dist/builders/elementEffect.d.ts.map +1 -0
- package/dist/builders/o.d.ts +115 -0
- package/dist/builders/o.d.ts.map +1 -0
- package/dist/builders/outline.d.ts +10 -0
- package/dist/builders/outline.d.ts.map +1 -0
- package/dist/builders/size.d.ts +23 -0
- package/dist/builders/size.d.ts.map +1 -0
- package/dist/builders/spacing.d.ts +15 -0
- package/dist/builders/spacing.d.ts.map +1 -0
- package/dist/builders/transition.d.ts +7 -0
- package/dist/builders/transition.d.ts.map +1 -0
- package/dist/builders/typography.d.ts +11 -0
- package/dist/builders/typography.d.ts.map +1 -0
- package/dist/{lib.d.ts → factories/lib.d.ts} +13 -14
- package/dist/factories/lib.d.ts.map +1 -0
- package/dist/index.cjs +765 -643
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +91 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.modern.js +555 -393
- package/dist/index.modern.js.map +1 -1
- package/dist/index.module.js +765 -643
- package/dist/index.module.js.map +1 -1
- package/dist/index.story.d.ts +1 -0
- package/dist/index.story.d.ts.map +1 -1
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/internals/index.d.ts +42 -0
- package/dist/internals/index.d.ts.map +1 -0
- package/dist/util.d.ts +36 -2
- package/dist/util.d.ts.map +1 -1
- package/package.json +8 -5
- package/src/__snapshots__/index.test.tsx.snap +768 -0
- package/src/builders/border.ts +63 -0
- package/src/builders/borderRadius.ts +32 -0
- package/src/builders/colors.ts +198 -0
- package/src/builders/elementEffect.ts +54 -0
- package/src/builders/o.ts +43 -0
- package/src/builders/outline.ts +79 -0
- package/src/builders/size.ts +61 -0
- package/src/builders/spacing.ts +113 -0
- package/src/builders/transition.ts +32 -0
- package/src/builders/typography.ts +97 -0
- package/src/{lib.ts → factories/lib.ts} +30 -25
- package/src/index.story.tsx +2 -2
- package/src/index.test.tsx +24 -0
- package/src/index.ts +47 -696
- package/src/internals/index.ts +84 -0
- package/src/util.ts +46 -3
- package/dist/lib.d.ts.map +0 -1
package/dist/index.modern.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { filterObject, flatMapObject, customPropertyToken, applyEffect, notDisabledSelector, disabledSelector, px, dur, gradient, applyEffectToGradient, halfLeading } from '@charcoal-ui/utils';
|
|
1
2
|
import warning from 'warning';
|
|
2
|
-
import { filterObject, flatMapObject, customPropertyToken, applyEffect, notDisabledSelector, disabledSelector, px, halfLeading, dur, applyEffectToGradient, gradient } from '@charcoal-ui/utils';
|
|
3
3
|
import { columnSystem } from '@charcoal-ui/foundation';
|
|
4
4
|
import React, { useEffect, useState, useMemo } from 'react';
|
|
5
5
|
import { createGlobalStyle, css } from 'styled-components';
|
|
6
6
|
|
|
7
7
|
function _extends() {
|
|
8
|
-
_extends = Object.assign
|
|
8
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
9
9
|
for (var i = 1; i < arguments.length; i++) {
|
|
10
10
|
var source = arguments[i];
|
|
11
11
|
|
|
@@ -18,7 +18,6 @@ function _extends() {
|
|
|
18
18
|
|
|
19
19
|
return target;
|
|
20
20
|
};
|
|
21
|
-
|
|
22
21
|
return _extends.apply(this, arguments);
|
|
23
22
|
}
|
|
24
23
|
|
|
@@ -36,9 +35,27 @@ const isPresent = value => value != null; // eslint-disable-next-line @typescrip
|
|
|
36
35
|
function objectAssign(...sources) {
|
|
37
36
|
return Object.assign({}, ...sources);
|
|
38
37
|
}
|
|
39
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Object.keys の返り値の型を厳しめにしてくれるやつ。
|
|
40
|
+
*
|
|
41
|
+
* ジェネリクスは基本的に明示して使うことを推奨。
|
|
42
|
+
*
|
|
43
|
+
* このライブラリでは Theme オブジェクトのジェネリクスを引き回すケースが多く、
|
|
44
|
+
* ジェネリクスを省略するといつのまにか keys の返り値が `string | number | symbol` になりがちなので
|
|
45
|
+
*
|
|
46
|
+
* @param obj - キーを取りたいオブジェクト。ジェネリクスを省略したとき `never[]` のような使えない型が返って欲しい
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
function keyof(obj) {
|
|
40
50
|
return Object.keys(obj);
|
|
41
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* 配列じゃなかったら配列にする
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
function wrapArray(value) {
|
|
57
|
+
return Array.isArray(value) ? value : [value];
|
|
58
|
+
}
|
|
42
59
|
const noThemeProvider = new Error('`theme` is invalid. `<ThemeProvider>` is not likely mounted.');
|
|
43
60
|
/**
|
|
44
61
|
* 子孫要素で使われるカラーテーマの CSS Variables を上書きする
|
|
@@ -68,6 +85,80 @@ function defineThemeVariables(colorParams, effectParams) {
|
|
|
68
85
|
return flatMapObject(colors, (colorKey, color) => [[customPropertyToken(colorKey), color], ...effects.map(([effectKey, effect]) => [customPropertyToken(colorKey, [effectKey]), applyEffect(color, [effect])])]);
|
|
69
86
|
};
|
|
70
87
|
}
|
|
88
|
+
function isSupportedEffect(effect) {
|
|
89
|
+
return ['hover', 'press', 'disabled'].includes(effect);
|
|
90
|
+
}
|
|
91
|
+
const variable = value => `var(${value})`;
|
|
92
|
+
function onEffectPseudo(effect, css) {
|
|
93
|
+
return effect === 'hover' ? {
|
|
94
|
+
'&:hover': {
|
|
95
|
+
[notDisabledSelector]: css
|
|
96
|
+
}
|
|
97
|
+
} : effect === 'press' ? {
|
|
98
|
+
'&:active': {
|
|
99
|
+
[notDisabledSelector]: css
|
|
100
|
+
}
|
|
101
|
+
} : // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
102
|
+
effect === 'disabled' ? {
|
|
103
|
+
[disabledSelector]: css
|
|
104
|
+
} : unreachable(effect);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 絶対にこれを export してはいけない
|
|
109
|
+
*
|
|
110
|
+
* さもないと `o.bg[internalSym]` みたいな叩き方が可能になってしまう(補完にも意図せず出てしまう)
|
|
111
|
+
*/
|
|
112
|
+
const internalSym = Symbol('internal');
|
|
113
|
+
/**
|
|
114
|
+
* CSSObject に変換可能なオブジェクトを作成する
|
|
115
|
+
*
|
|
116
|
+
* 実際に CSSObject に変換するには外部から `__DO_NOT_USE_GET_INTERNAL__` を使わなければならない
|
|
117
|
+
*
|
|
118
|
+
* これ以降メソッドチェーンが続いてもいいし、続かなくても良い
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
function createInternal({
|
|
122
|
+
toCSS,
|
|
123
|
+
context = {}
|
|
124
|
+
}) {
|
|
125
|
+
return {
|
|
126
|
+
[internalSym]: {
|
|
127
|
+
toCSS,
|
|
128
|
+
context
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function __DO_NOT_USE_ACCESS_PRIVATE_PROPERTY__(internal) {
|
|
134
|
+
return internal[internalSym];
|
|
135
|
+
} // half-leadingをキャンセルするとき && 垂直方向のpaddingが無い時
|
|
136
|
+
// -> before/afterを入れる
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
const shouldCancelHalfLeading = ({
|
|
140
|
+
cancelHalfLeadingPx,
|
|
141
|
+
hasVerticalPadding: _hasVerticalPadding = false
|
|
142
|
+
}) => cancelHalfLeadingPx !== undefined && !_hasVerticalPadding;
|
|
143
|
+
/**
|
|
144
|
+
* 個別の Internal( o.〇〇 の返り値 )が提出した context の中身を1つの context にまとめる
|
|
145
|
+
*/
|
|
146
|
+
|
|
147
|
+
function getContext(internals) {
|
|
148
|
+
return internals.reduce((context, internal) => _extends({}, context, __DO_NOT_USE_ACCESS_PRIVATE_PROPERTY__(internal).context), {});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 全ユーザー定義からコンテキスト生成し、styled-components 向けに CSSObject を構築
|
|
152
|
+
*/
|
|
153
|
+
|
|
154
|
+
function toCSSObjects(internals) {
|
|
155
|
+
// 1パス目
|
|
156
|
+
// 全ユーザー定義を舐めて相互に影響し合う定義をチェックし、その結果(コンテキスト)を取得
|
|
157
|
+
const context = getContext(internals); // 2パス目
|
|
158
|
+
// コンテキストを見ながら最適化されたCSSを構築
|
|
159
|
+
|
|
160
|
+
return internals.map(v => __DO_NOT_USE_ACCESS_PRIVATE_PROPERTY__(v).toCSS(context));
|
|
161
|
+
}
|
|
71
162
|
|
|
72
163
|
/**
|
|
73
164
|
* 配列で指定したプロパティを動的に生やす
|
|
@@ -85,7 +176,7 @@ function defineThemeVariables(colorParams, effectParams) {
|
|
|
85
176
|
* console.log(o.red) //=> #ff0000
|
|
86
177
|
*/
|
|
87
178
|
|
|
88
|
-
const
|
|
179
|
+
const defineProperties = (source, member, chain) => Object.defineProperties(source, Object.fromEntries(member.map(key => [key, {
|
|
89
180
|
get: () => chain(key),
|
|
90
181
|
enumerable: true,
|
|
91
182
|
configurable: true
|
|
@@ -99,14 +190,14 @@ const factory = (source, member, chain) => Object.defineProperties(source, Objec
|
|
|
99
190
|
*
|
|
100
191
|
* @example
|
|
101
192
|
*
|
|
102
|
-
* const o =
|
|
193
|
+
* const o = defineMethods({}, ['red', 'blue'],
|
|
103
194
|
* (color, alpha: number) => hex(color, alpha)
|
|
104
195
|
* )
|
|
105
196
|
*
|
|
106
197
|
* console.log(o.red(0.5)) //=> #ff000077
|
|
107
198
|
*/
|
|
108
199
|
|
|
109
|
-
const
|
|
200
|
+
const defineMethods = (source, member, chain) => Object.defineProperties(source, Object.fromEntries(member.map(key => [key, {
|
|
110
201
|
value: (...args) => chain(key, ...args),
|
|
111
202
|
enumerable: true,
|
|
112
203
|
configurable: true
|
|
@@ -119,7 +210,7 @@ const argumentedFactory = (source, member, chain) => Object.defineProperties(sou
|
|
|
119
210
|
*
|
|
120
211
|
* @example
|
|
121
212
|
*
|
|
122
|
-
* const o =
|
|
213
|
+
* const o = defineConstantProperties({}, {
|
|
123
214
|
* red: '#f00',
|
|
124
215
|
* blue: '#00f',
|
|
125
216
|
* })
|
|
@@ -127,7 +218,7 @@ const argumentedFactory = (source, member, chain) => Object.defineProperties(sou
|
|
|
127
218
|
* console.log(o.red) //=> #f00
|
|
128
219
|
*/
|
|
129
220
|
|
|
130
|
-
const
|
|
221
|
+
const defineConstantProperties = (source, def) => defineProperties(source, Object.keys(def), key => def[key]);
|
|
131
222
|
/**
|
|
132
223
|
* 配列で指定したモディファイア(プロパティ)をチェーン可能な再帰オブジェクトを動的に生やす
|
|
133
224
|
*
|
|
@@ -136,16 +227,16 @@ const constFactory = (source, def) => factory(source, Object.keys(def), key => d
|
|
|
136
227
|
*
|
|
137
228
|
* @example
|
|
138
229
|
*
|
|
139
|
-
* const o =
|
|
230
|
+
* const o = definePropertyChains(['red', 'blue'],
|
|
140
231
|
* modifiers => modifiers.map(color => hex(color)).join(',')
|
|
141
232
|
* )
|
|
142
233
|
*
|
|
143
234
|
* console.log(o.red.blue) => #f00,#00f
|
|
144
235
|
*/
|
|
145
236
|
|
|
146
|
-
const
|
|
237
|
+
const definePropertyChains = (modifiers, source) => function definePropertiesRecursively(applied) {
|
|
147
238
|
const notApplied = modifiers.filter(v => !applied.includes(v));
|
|
148
|
-
return
|
|
239
|
+
return defineProperties(source(applied), notApplied, modifier => notApplied.length === 0 ? unreachable() : definePropertiesRecursively([...applied, modifier]));
|
|
149
240
|
}([]);
|
|
150
241
|
/**
|
|
151
242
|
* 配列で指定したモディファイア(メソッド)をチェーン可能な再帰オブジェクトを動的に生やす
|
|
@@ -156,18 +247,424 @@ const modifiedFactory = (modifiers, source) => function recursiveModifiedFactory
|
|
|
156
247
|
*
|
|
157
248
|
* @example
|
|
158
249
|
*
|
|
159
|
-
* const o =
|
|
250
|
+
* const o = defineMethodChains(['red', 'blue'],
|
|
160
251
|
* modifiers => modifiers.map(([color, alpha]) => hex(color, alpha)).join(',')
|
|
161
252
|
* , {} as [number])
|
|
162
253
|
*
|
|
163
|
-
* console.log(o.red(0.5).blue(1)) => #ff000077,#0000ffff
|
|
254
|
+
* console.log(o.red(0.5).blue(1)) => #ff000077,#0000ffff
|
|
255
|
+
*/
|
|
256
|
+
|
|
257
|
+
const defineMethodChains = (modifiers, source, ..._inferPhantom) => function defineMethodsRecursively(applied) {
|
|
258
|
+
const notApplied = modifiers.filter(v => !applied.map(([w]) => w).includes(v));
|
|
259
|
+
return defineMethods(source(applied), notApplied, (modifier, ...args) => notApplied.length === 0 ? unreachable() : defineMethodsRecursively([...applied, [modifier, ...args]]));
|
|
260
|
+
}([]);
|
|
261
|
+
|
|
262
|
+
const borderDirections = ['top', 'right', 'bottom', 'left'];
|
|
263
|
+
|
|
264
|
+
function borderProperty(direction) {
|
|
265
|
+
return `border-${direction}`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function borderShorthand(color) {
|
|
269
|
+
return `solid 1px ${color}`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const createBorderCss = theme => (variant, directions) => {
|
|
273
|
+
const all = directions.length === 0;
|
|
274
|
+
const value = borderShorthand(theme.border[variant].color);
|
|
275
|
+
return createInternal({
|
|
276
|
+
toCSS() {
|
|
277
|
+
return _extends({}, all ? {
|
|
278
|
+
border: value
|
|
279
|
+
} : directions.reduce((acc, direction) => _extends({}, acc, {
|
|
280
|
+
[borderProperty(direction)]: value
|
|
281
|
+
}), {}));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
function border(theme) {
|
|
287
|
+
const borderTypes = keyof(theme.border);
|
|
288
|
+
const borderCss = createBorderCss(theme);
|
|
289
|
+
const borderObject = defineConstantProperties({}, {
|
|
290
|
+
border: defineProperties({}, borderTypes, variant => definePropertyChains(borderDirections, modifiers => borderCss(variant, modifiers)))
|
|
291
|
+
});
|
|
292
|
+
return borderObject;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const createBorderRadiusCss = theme => size => {
|
|
296
|
+
return createInternal({
|
|
297
|
+
toCSS() {
|
|
298
|
+
return {
|
|
299
|
+
borderRadius: px(theme.borderRadius[size])
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
function borderRadius(theme) {
|
|
306
|
+
// 角丸
|
|
307
|
+
const borderRadiusCss = createBorderRadiusCss(theme);
|
|
308
|
+
const borderRadiusObject = defineConstantProperties({}, {
|
|
309
|
+
borderRadius: radius => borderRadiusCss(radius)
|
|
310
|
+
});
|
|
311
|
+
return borderRadiusObject;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const TRANSITION_DURATION = 0.2;
|
|
315
|
+
/**
|
|
316
|
+
* context の状態を元に transition を追加する。必ず一番最後に呼ぶ
|
|
317
|
+
*/
|
|
318
|
+
|
|
319
|
+
function transition(_theme) {
|
|
320
|
+
const duration = dur(TRANSITION_DURATION);
|
|
321
|
+
|
|
322
|
+
const transition = property => ({
|
|
323
|
+
transition: property.map(v => `${duration} ${v}`).join(', ')
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
function toCSS({
|
|
327
|
+
colorTransition = false,
|
|
328
|
+
backgroundColorTransition = false,
|
|
329
|
+
boxShadowTransition = false
|
|
330
|
+
}) {
|
|
331
|
+
return transition([colorTransition ? 'color' : null, backgroundColorTransition ? 'background-color' : null, boxShadowTransition ? 'box-shadow' : null].filter(isPresent));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return createInternal({
|
|
335
|
+
toCSS
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function targetProperty(target) {
|
|
340
|
+
return target === 'bg' ? 'background-color' : 'color';
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const createColorCss = _theme => (target, color, effects = []) => {
|
|
344
|
+
function toCSS() {
|
|
345
|
+
return _extends({
|
|
346
|
+
[targetProperty(target)]: variable(customPropertyToken(color.toString()))
|
|
347
|
+
}, effects.filter(isSupportedEffect).reduce((acc, effect) => _extends({}, acc, onEffectPseudo(effect, {
|
|
348
|
+
[targetProperty(target)]: variable(customPropertyToken(color.toString(), [effect]))
|
|
349
|
+
})), {}));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return createInternal({
|
|
353
|
+
toCSS,
|
|
354
|
+
context: effects.length > 0 ? target === 'font' ? {
|
|
355
|
+
colorTransition: true
|
|
356
|
+
} : {
|
|
357
|
+
backgroundColorTransition: true
|
|
358
|
+
} : {}
|
|
359
|
+
});
|
|
360
|
+
};
|
|
361
|
+
const createGradientColorCss = theme => (color, effects = [], direction) => {
|
|
362
|
+
const toLinearGradient = gradient(direction);
|
|
363
|
+
|
|
364
|
+
function toCSS(context) {
|
|
365
|
+
const optimized = !shouldCancelHalfLeading(context);
|
|
366
|
+
const duration = dur(TRANSITION_DURATION);
|
|
367
|
+
|
|
368
|
+
if (optimized && effects.length > 0) {
|
|
369
|
+
return _extends({
|
|
370
|
+
position: 'relative',
|
|
371
|
+
zIndex: 0,
|
|
372
|
+
overflow: 'hidden'
|
|
373
|
+
}, effects.filter(isSupportedEffect).reduce((acc, effect) => {
|
|
374
|
+
var _theme$effect$effect;
|
|
375
|
+
|
|
376
|
+
return _extends({}, acc, {
|
|
377
|
+
'&::before': _extends({
|
|
378
|
+
zIndex: -1
|
|
379
|
+
}, overlayElement, {
|
|
380
|
+
transition: `${duration} background-color`
|
|
381
|
+
}),
|
|
382
|
+
'&::after': _extends({
|
|
383
|
+
zIndex: -2
|
|
384
|
+
}, overlayElement, toLinearGradient(theme.gradientColor[color]))
|
|
385
|
+
}, onEffectPseudo(effect, {
|
|
386
|
+
'&::before': {
|
|
387
|
+
backgroundColor: applyEffect(null, (_theme$effect$effect = theme.effect[effect]) != null ? _theme$effect$effect : [])
|
|
388
|
+
}
|
|
389
|
+
}));
|
|
390
|
+
}, {}));
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
warning(effects.length === 0, // eslint-disable-next-line max-len
|
|
394
|
+
`'Transition' will not be applied. You can get around this by specifying 'preserveHalfLeading' or both 'padding' and 'typograpy'.`);
|
|
395
|
+
return _extends({}, toLinearGradient(theme.gradientColor[color]), effects.filter(isSupportedEffect).reduce((acc, effect) => {
|
|
396
|
+
var _theme$effect$effect2;
|
|
397
|
+
|
|
398
|
+
return _extends({}, acc, onEffectPseudo(effect, _extends({}, toLinearGradient(applyEffectToGradient((_theme$effect$effect2 = theme.effect[effect]) != null ? _theme$effect$effect2 : [])(theme.gradientColor[color])))));
|
|
399
|
+
}, {}));
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return createInternal({
|
|
403
|
+
toCSS
|
|
404
|
+
});
|
|
405
|
+
};
|
|
406
|
+
const overlayElement = {
|
|
407
|
+
content: "''",
|
|
408
|
+
display: 'block',
|
|
409
|
+
position: 'absolute',
|
|
410
|
+
width: '100%',
|
|
411
|
+
height: '100%',
|
|
412
|
+
top: 0,
|
|
413
|
+
left: 0
|
|
414
|
+
};
|
|
415
|
+
function colors(theme) {
|
|
416
|
+
const colors = keyof(theme.color);
|
|
417
|
+
const effects = keyof(theme.effect); // 色
|
|
418
|
+
|
|
419
|
+
const gradientColors = keyof(theme.gradientColor);
|
|
420
|
+
const colorCss = createColorCss();
|
|
421
|
+
const gradientColorCss = createGradientColorCss(theme);
|
|
422
|
+
const colorObject = defineConstantProperties({}, {
|
|
423
|
+
bg: objectAssign(defineProperties({}, colors, color => definePropertyChains(effects, modifiers => colorCss('bg', color, modifiers))), defineProperties({}, gradientColors, color => direction => definePropertyChains(effects, modifiers => gradientColorCss(color, modifiers, direction)))),
|
|
424
|
+
font: defineProperties({}, colors, color => definePropertyChains(effects, modifiers => colorCss('font', color, modifiers)))
|
|
425
|
+
});
|
|
426
|
+
return colorObject;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const createElementEffectCss = theme => (effects = []) => createInternal({
|
|
430
|
+
toCSS() {
|
|
431
|
+
return effects.filter(isSupportedEffect).reduce((acc, effect) => {
|
|
432
|
+
var _theme$elementEffect$, _theme$elementEffect$2;
|
|
433
|
+
|
|
434
|
+
return _extends({}, acc, onEffectPseudo(effect, {
|
|
435
|
+
opacity: !Array.isArray(theme.elementEffect[effect]) && ((_theme$elementEffect$ = theme.elementEffect[effect]) == null ? void 0 : _theme$elementEffect$.type) === 'opacity' ? (_theme$elementEffect$2 = theme.elementEffect[effect]) == null ? void 0 : _theme$elementEffect$2.opacity : unreachable()
|
|
436
|
+
}));
|
|
437
|
+
}, {});
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
});
|
|
441
|
+
function elementEffect(theme) {
|
|
442
|
+
const effectTypes = keyof(theme.elementEffect); // 要素へのエフェクト (etc: 透過)
|
|
443
|
+
|
|
444
|
+
const elementEffectCss = createElementEffectCss(theme);
|
|
445
|
+
const elementEffectObject = definePropertyChains(effectTypes, modifiers => elementEffectCss(modifiers));
|
|
446
|
+
return elementEffectObject;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const outlineType = ['focus'];
|
|
450
|
+
|
|
451
|
+
const outlineCss = (weight, color) => ({
|
|
452
|
+
boxShadow: `0 0 0 ${px(weight)} ${color}`
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
const createOutlineColorCss = theme => (variant, modifiers) => {
|
|
456
|
+
const weight = theme.outline[variant].weight;
|
|
457
|
+
const color = theme.outline[variant].color;
|
|
458
|
+
return createInternal({
|
|
459
|
+
toCSS() {
|
|
460
|
+
return modifiers.includes('focus') ? onFocus(outlineCss(weight, color)) : {
|
|
461
|
+
'&&': {
|
|
462
|
+
[notDisabledSelector]: outlineCss(weight, color)
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
},
|
|
466
|
+
|
|
467
|
+
context: {
|
|
468
|
+
boxShadowTransition: true
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
};
|
|
472
|
+
/**
|
|
473
|
+
* @see https://developer.mozilla.org/ja/docs/Web/CSS/:focus-visible#selectively_showing_the_focus_indicator
|
|
474
|
+
*/
|
|
475
|
+
|
|
476
|
+
const onFocus = css => ({
|
|
477
|
+
[notDisabledSelector]: {
|
|
478
|
+
'&:focus, &:active': _extends({
|
|
479
|
+
outline: 'none'
|
|
480
|
+
}, css),
|
|
481
|
+
'&:focus:not(:focus-visible), &:active:not(:focus-visible)': {
|
|
482
|
+
outline: 'none'
|
|
483
|
+
},
|
|
484
|
+
'&:focus-visible': _extends({
|
|
485
|
+
outline: 'none'
|
|
486
|
+
}, css)
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
function outline(theme) {
|
|
491
|
+
const outlineCss = createOutlineColorCss(theme);
|
|
492
|
+
const outlineObject = defineConstantProperties({}, {
|
|
493
|
+
outline: defineProperties({}, keyof(theme.outline), variant => definePropertyChains(outlineType, modifiers => outlineCss(variant, modifiers)))
|
|
494
|
+
});
|
|
495
|
+
return outlineObject;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const fixedProperties = ['width', 'height'];
|
|
499
|
+
const createFixedPxCss = theme => (property, size) => createInternal({
|
|
500
|
+
toCSS() {
|
|
501
|
+
return {
|
|
502
|
+
[property]: size === 'auto' ? 'auto' : px(theme.spacing[size])
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
});
|
|
507
|
+
const createFixedRelativeCss = _theme => (property, amount) => createInternal({
|
|
508
|
+
toCSS() {
|
|
509
|
+
return {
|
|
510
|
+
[property]: amount
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
});
|
|
515
|
+
const createFixedColumnCss = theme => (property, span) => createInternal({
|
|
516
|
+
toCSS() {
|
|
517
|
+
return {
|
|
518
|
+
[property]: px(columnSystem(span, theme.grid.unit.column, theme.grid.unit.gutter))
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
});
|
|
523
|
+
function size(theme) {
|
|
524
|
+
const fixedPxCss = createFixedPxCss(theme);
|
|
525
|
+
const fixedColumnCss = createFixedColumnCss(theme);
|
|
526
|
+
const fixedRelativeCss = createFixedRelativeCss();
|
|
527
|
+
const fixedObject = defineProperties({}, fixedProperties, property => defineConstantProperties({}, {
|
|
528
|
+
px: size => fixedPxCss(property, size),
|
|
529
|
+
column: span => fixedColumnCss(property, span),
|
|
530
|
+
auto: fixedRelativeCss(property, 'auto'),
|
|
531
|
+
full: fixedRelativeCss(property, '100%')
|
|
532
|
+
}));
|
|
533
|
+
return fixedObject;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const spacingProperties = ['margin', 'padding'];
|
|
537
|
+
const spacingDirections = ['top', 'right', 'bottom', 'left', 'vertical', 'horizontal', 'all'];
|
|
538
|
+
|
|
539
|
+
function spacingProperty(property, direction) {
|
|
540
|
+
return `${property}-${direction}`;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const createSpacingCss = theme => (property, modifiers) => {
|
|
544
|
+
const {
|
|
545
|
+
top,
|
|
546
|
+
right,
|
|
547
|
+
bottom,
|
|
548
|
+
left
|
|
549
|
+
} = modifiers.reduce((acc, [direction, size]) => {
|
|
550
|
+
if (direction === 'all') {
|
|
551
|
+
acc.top = size;
|
|
552
|
+
acc.right = size;
|
|
553
|
+
acc.bottom = size;
|
|
554
|
+
acc.left = size;
|
|
555
|
+
} else if (direction === 'vertical') {
|
|
556
|
+
acc.top = size;
|
|
557
|
+
acc.bottom = size;
|
|
558
|
+
} else if (direction === 'horizontal') {
|
|
559
|
+
acc.right = size;
|
|
560
|
+
acc.left = size;
|
|
561
|
+
} else {
|
|
562
|
+
acc[direction] = size;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return acc;
|
|
566
|
+
}, {});
|
|
567
|
+
const hasVerticalPadding = property === 'padding' && top !== undefined && bottom !== undefined && top !== 'auto' && bottom !== 'auto';
|
|
568
|
+
|
|
569
|
+
function toCSS({
|
|
570
|
+
cancelHalfLeadingPx = 0
|
|
571
|
+
}) {
|
|
572
|
+
return _extends({}, top !== undefined && {
|
|
573
|
+
[spacingProperty(property, 'top')]: top === 'auto' ? 'auto' : px(theme.spacing[top] + (hasVerticalPadding ? cancelHalfLeadingPx : 0))
|
|
574
|
+
}, bottom !== undefined && {
|
|
575
|
+
[spacingProperty(property, 'bottom')]: bottom === 'auto' ? 'auto' : px(theme.spacing[bottom] + (hasVerticalPadding ? cancelHalfLeadingPx : 0))
|
|
576
|
+
}, right !== undefined && {
|
|
577
|
+
[spacingProperty(property, 'right')]: right === 'auto' ? 'auto' : px(theme.spacing[right])
|
|
578
|
+
}, left !== undefined && {
|
|
579
|
+
[spacingProperty(property, 'left')]: left === 'auto' ? 'auto' : px(theme.spacing[left])
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return createInternal({
|
|
584
|
+
toCSS,
|
|
585
|
+
context: hasVerticalPadding ? {
|
|
586
|
+
hasVerticalPadding: true
|
|
587
|
+
} : {}
|
|
588
|
+
});
|
|
589
|
+
};
|
|
590
|
+
function spacing(theme) {
|
|
591
|
+
const spacingCss = createSpacingCss(theme);
|
|
592
|
+
const spacingObject = defineProperties({}, spacingProperties, spacingProperty => defineMethodChains(spacingDirections, modifiers => spacingCss(spacingProperty, modifiers), {} // 推論のためのメタタイプ
|
|
593
|
+
));
|
|
594
|
+
return spacingObject;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
const createTypographyCss = theme => (size, options = {}) => {
|
|
598
|
+
const {
|
|
599
|
+
preserveHalfLeading = false,
|
|
600
|
+
monospace = false,
|
|
601
|
+
bold = false
|
|
602
|
+
} = options;
|
|
603
|
+
const descriptor = theme.typography.size[size];
|
|
604
|
+
const margin = -halfLeading(descriptor);
|
|
605
|
+
|
|
606
|
+
function toCSS(context) {
|
|
607
|
+
return _extends({
|
|
608
|
+
fontSize: px(descriptor.fontSize),
|
|
609
|
+
lineHeight: px(descriptor.lineHeight)
|
|
610
|
+
}, monospace && {
|
|
611
|
+
fontFamily: 'monospace'
|
|
612
|
+
}, bold && {
|
|
613
|
+
fontWeight: 'bold'
|
|
614
|
+
}, shouldCancelHalfLeading(context) && {
|
|
615
|
+
// prevent margin collapsing
|
|
616
|
+
display: 'flow-root',
|
|
617
|
+
// cancel half-leading with negative margin
|
|
618
|
+
'&::before': _extends({}, leadingCancel, {
|
|
619
|
+
marginTop: px(margin)
|
|
620
|
+
}),
|
|
621
|
+
'&::after': _extends({}, leadingCancel, {
|
|
622
|
+
marginBottom: px(margin)
|
|
623
|
+
})
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
return createInternal({
|
|
628
|
+
toCSS,
|
|
629
|
+
context: !preserveHalfLeading ? {
|
|
630
|
+
cancelHalfLeadingPx: margin
|
|
631
|
+
} : {}
|
|
632
|
+
});
|
|
633
|
+
};
|
|
634
|
+
const leadingCancel = {
|
|
635
|
+
display: 'block',
|
|
636
|
+
width: 0,
|
|
637
|
+
height: 0,
|
|
638
|
+
content: `''`
|
|
639
|
+
}; // タイポグラフィ
|
|
640
|
+
|
|
641
|
+
const typographyModifiers = [// TODO
|
|
642
|
+
'monospace', 'bold', 'preserveHalfLeading'];
|
|
643
|
+
function typography(theme) {
|
|
644
|
+
const typographyCss = createTypographyCss(theme);
|
|
645
|
+
const typographyObject = defineProperties({}, ['typography'], _ => size => definePropertyChains(typographyModifiers, modifiers => typographyCss(size, {
|
|
646
|
+
preserveHalfLeading: modifiers.includes('preserveHalfLeading'),
|
|
647
|
+
monospace: modifiers.includes('monospace'),
|
|
648
|
+
bold: modifiers.includes('bold')
|
|
649
|
+
})));
|
|
650
|
+
return typographyObject;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* `theme(o => [...])` の `o` の部分を構築する
|
|
655
|
+
*
|
|
656
|
+
* @param theme テーマオブジェクト
|
|
657
|
+
* @param DO_NOTHING_IT_IS_JUST_CALLED_FOR_TYPE_INFERENCE 型推論のためだけに使う場合にランタイムコストをゼロにするフラグ
|
|
164
658
|
*/
|
|
165
659
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
660
|
+
function createO(theme, DO_NOTHING_IT_IS_JUST_CALLED_FOR_TYPE_INFERENCE = false) {
|
|
661
|
+
if (DO_NOTHING_IT_IS_JUST_CALLED_FOR_TYPE_INFERENCE) {
|
|
662
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
663
|
+
return {};
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return objectAssign(colors(theme), typography(theme), spacing(theme), size(theme), elementEffect(theme), border(theme), borderRadius(theme), outline(theme));
|
|
667
|
+
}
|
|
171
668
|
|
|
172
669
|
let _ = t => t,
|
|
173
670
|
_t,
|
|
@@ -428,358 +925,11 @@ const defaultProps = {
|
|
|
428
925
|
};
|
|
429
926
|
SetThemeScript.defaultProps = defaultProps;
|
|
430
927
|
|
|
431
|
-
const spacingProperties = ['margin', 'padding'];
|
|
432
|
-
const spacingDirections = ['top', 'right', 'bottom', 'left', 'vertical', 'horizontal', 'all'];
|
|
433
|
-
const fixedProperties = ['width', 'height'];
|
|
434
|
-
const borderDirections = ['top', 'right', 'bottom', 'left'];
|
|
435
|
-
const outlineType = ['focus'];
|
|
436
|
-
/**
|
|
437
|
-
* `theme(o => [...])` の `o` の部分を構築する
|
|
438
|
-
*
|
|
439
|
-
* @param theme テーマオブジェクト
|
|
440
|
-
* @param isPhantom 型推論のためだけに使う場合にランタイムコストをゼロにするフラグ
|
|
441
|
-
*/
|
|
442
|
-
|
|
443
|
-
function builder(theme, isPhantom = false) {
|
|
444
|
-
if (isPhantom) {
|
|
445
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
446
|
-
return {};
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
const colors = objectKeys(theme.color);
|
|
450
|
-
const effects = objectKeys(theme.effect); // 色
|
|
451
|
-
|
|
452
|
-
const gradientColors = objectKeys(theme.gradientColor);
|
|
453
|
-
const colorCss = createColorCss();
|
|
454
|
-
const gradientColorCss = createGradientColorCss(theme);
|
|
455
|
-
const colorObject = constFactory({}, {
|
|
456
|
-
bg: objectAssign(factory({}, colors, color => modifiedFactory(effects, modifiers => colorCss('bg', color, modifiers))), factory({}, gradientColors, color => direction => modifiedFactory(effects, modifiers => gradientColorCss(color, modifiers, direction)))),
|
|
457
|
-
font: factory({}, colors, color => modifiedFactory(effects, modifiers => colorCss('font', color, modifiers)))
|
|
458
|
-
}); // タイポグラフィ
|
|
459
|
-
|
|
460
|
-
const typographyModifiers = [// TODO
|
|
461
|
-
'monospace', 'bold', 'preserveHalfLeading'];
|
|
462
|
-
const typographyCss = createTypographyCss(theme);
|
|
463
|
-
const typographyObject = factory({}, ['typography'], _ => size => modifiedFactory(typographyModifiers, modifiers => typographyCss(size, {
|
|
464
|
-
preserveHalfLeading: modifiers.includes('preserveHalfLeading'),
|
|
465
|
-
monospace: modifiers.includes('monospace'),
|
|
466
|
-
bold: modifiers.includes('bold')
|
|
467
|
-
}))); // スペーシング
|
|
468
|
-
|
|
469
|
-
const spacingCss = createSpacingCss(theme);
|
|
470
|
-
const spacingObject = factory({}, spacingProperties, spacingProperty => modifiedArgumentedFactory(spacingDirections, modifiers => spacingCss(spacingProperty, modifiers), {} // 推論のためのメタタイプ
|
|
471
|
-
)); // 大きさ
|
|
472
|
-
|
|
473
|
-
const fixedPxCss = createFixedPxCss(theme);
|
|
474
|
-
const fixedColumnCss = createFixedColumnCss(theme);
|
|
475
|
-
const fixedRelativeCss = createFixedRelativeCss();
|
|
476
|
-
const fixedObject = factory({}, fixedProperties, property => constFactory({}, {
|
|
477
|
-
px: size => fixedPxCss(property, size),
|
|
478
|
-
column: span => fixedColumnCss(property, span),
|
|
479
|
-
auto: fixedRelativeCss(property, 'auto'),
|
|
480
|
-
full: fixedRelativeCss(property, '100%')
|
|
481
|
-
})); // 要素へのエフェクト (etc: 透過)
|
|
482
|
-
|
|
483
|
-
const elementEffectCss = createElementEffectCss(theme);
|
|
484
|
-
const elementEffectObject = modifiedFactory(objectKeys(theme.elementEffect), modifiers => elementEffectCss(modifiers)); // ボーダー
|
|
485
|
-
|
|
486
|
-
const borderCss = createBorderCss(theme);
|
|
487
|
-
const borderObject = constFactory({}, {
|
|
488
|
-
border: factory({}, objectKeys(theme.border), variant => modifiedFactory(borderDirections, modifiers => borderCss(variant, modifiers)))
|
|
489
|
-
}); // 角丸
|
|
490
|
-
|
|
491
|
-
const borderRadiusCss = createBorderRadiusCss(theme);
|
|
492
|
-
const borderRadiusObject = constFactory({}, {
|
|
493
|
-
borderRadius: radius => borderRadiusCss(radius)
|
|
494
|
-
}); // アウトライン
|
|
495
|
-
|
|
496
|
-
const outlineCss = createOutlineColorCss(theme);
|
|
497
|
-
const outlineObject = constFactory({}, {
|
|
498
|
-
outline: factory({}, objectKeys(theme.outline), variant => modifiedFactory(outlineType, modifiers => outlineCss(variant, modifiers)))
|
|
499
|
-
});
|
|
500
|
-
return objectAssign(colorObject, typographyObject, spacingObject, fixedObject, elementEffectObject, borderObject, borderRadiusObject, outlineObject);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
function targetProperty(target) {
|
|
504
|
-
return target === 'bg' ? 'background-color' : 'color';
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
function isSupportedEffect(effect) {
|
|
508
|
-
return ['hover', 'press', 'disabled'].includes(effect);
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
function onEffectPseudo(effect, css) {
|
|
512
|
-
return effect === 'hover' ? {
|
|
513
|
-
'&:hover': {
|
|
514
|
-
[notDisabledSelector]: css
|
|
515
|
-
}
|
|
516
|
-
} : effect === 'press' ? {
|
|
517
|
-
'&:active': {
|
|
518
|
-
[notDisabledSelector]: css
|
|
519
|
-
}
|
|
520
|
-
} : // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
521
|
-
effect === 'disabled' ? {
|
|
522
|
-
[disabledSelector]: css
|
|
523
|
-
} : unreachable(effect);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
const createColorCss = _theme => (target, color, effects = []) => internal(() => _extends({
|
|
527
|
-
[targetProperty(target)]: variable(customPropertyToken(color.toString()))
|
|
528
|
-
}, effects.filter(isSupportedEffect).reduce((acc, effect) => _extends({}, acc, onEffectPseudo(effect, {
|
|
529
|
-
[targetProperty(target)]: variable(customPropertyToken(color.toString(), [effect]))
|
|
530
|
-
})), {})), effects.length > 0 ? target === 'font' ? {
|
|
531
|
-
colorTransition: true
|
|
532
|
-
} : {
|
|
533
|
-
backgroundColorTransition: true
|
|
534
|
-
} : {}); // TODO: deprecate
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
const TRANSITION_DURATION = 0.2;
|
|
538
|
-
|
|
539
|
-
const createGradientColorCss = theme => (color, effects = [], direction) => {
|
|
540
|
-
const toLinearGradient = gradient(direction);
|
|
541
|
-
return internal(context => {
|
|
542
|
-
const optimized = !useHalfLeadingCanceller(context);
|
|
543
|
-
const duration = dur(TRANSITION_DURATION);
|
|
544
|
-
|
|
545
|
-
if (optimized && effects.length > 0) {
|
|
546
|
-
return _extends({
|
|
547
|
-
position: 'relative',
|
|
548
|
-
zIndex: 0,
|
|
549
|
-
overflow: 'hidden'
|
|
550
|
-
}, effects.filter(isSupportedEffect).reduce((acc, effect) => {
|
|
551
|
-
var _theme$effect$effect;
|
|
552
|
-
|
|
553
|
-
return _extends({}, acc, {
|
|
554
|
-
'&::before': _extends({
|
|
555
|
-
zIndex: -1
|
|
556
|
-
}, overlayElement, {
|
|
557
|
-
transition: `${duration} background-color`
|
|
558
|
-
}),
|
|
559
|
-
'&::after': _extends({
|
|
560
|
-
zIndex: -2
|
|
561
|
-
}, overlayElement, toLinearGradient(theme.gradientColor[color]))
|
|
562
|
-
}, onEffectPseudo(effect, {
|
|
563
|
-
'&::before': {
|
|
564
|
-
backgroundColor: applyEffect(null, (_theme$effect$effect = theme.effect[effect]) != null ? _theme$effect$effect : [])
|
|
565
|
-
}
|
|
566
|
-
}));
|
|
567
|
-
}, {}));
|
|
568
|
-
} else {
|
|
569
|
-
warning(effects.length === 0, // eslint-disable-next-line max-len
|
|
570
|
-
`'Transition' will not be applied. You can get around this by specifying 'preserveHalfLeading' or both 'padding' and 'typograpy'.`);
|
|
571
|
-
return _extends({}, toLinearGradient(theme.gradientColor[color]), effects.filter(isSupportedEffect).reduce((acc, effect) => {
|
|
572
|
-
var _theme$effect$effect2;
|
|
573
|
-
|
|
574
|
-
return _extends({}, acc, onEffectPseudo(effect, _extends({}, toLinearGradient(applyEffectToGradient((_theme$effect$effect2 = theme.effect[effect]) != null ? _theme$effect$effect2 : [])(theme.gradientColor[color])))));
|
|
575
|
-
}, {}));
|
|
576
|
-
}
|
|
577
|
-
});
|
|
578
|
-
};
|
|
579
|
-
/**
|
|
580
|
-
* @see https://developer.mozilla.org/ja/docs/Web/CSS/:focus-visible#selectively_showing_the_focus_indicator
|
|
581
|
-
*/
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
const onFocus = css => ({
|
|
585
|
-
[notDisabledSelector]: {
|
|
586
|
-
'&:focus, &:active': _extends({
|
|
587
|
-
outline: 'none'
|
|
588
|
-
}, css),
|
|
589
|
-
'&:focus:not(:focus-visible), &:active:not(:focus-visible)': {
|
|
590
|
-
outline: 'none'
|
|
591
|
-
},
|
|
592
|
-
'&:focus-visible': _extends({
|
|
593
|
-
outline: 'none'
|
|
594
|
-
}, css)
|
|
595
|
-
}
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
const outlineCss = (weight, color) => ({
|
|
599
|
-
boxShadow: `0 0 0 ${px(weight)} ${color}`
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
const createOutlineColorCss = theme => (variant, modifiers) => {
|
|
603
|
-
const weight = theme.outline[variant].weight;
|
|
604
|
-
const color = theme.outline[variant].color;
|
|
605
|
-
return internal(() => modifiers.includes('focus') ? onFocus(outlineCss(weight, color)) : {
|
|
606
|
-
'&&': {
|
|
607
|
-
[notDisabledSelector]: outlineCss(weight, color)
|
|
608
|
-
}
|
|
609
|
-
}, {
|
|
610
|
-
boxShadowTransition: true
|
|
611
|
-
});
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
const overlayElement = {
|
|
615
|
-
content: "''",
|
|
616
|
-
display: 'block',
|
|
617
|
-
position: 'absolute',
|
|
618
|
-
width: '100%',
|
|
619
|
-
height: '100%',
|
|
620
|
-
top: 0,
|
|
621
|
-
left: 0
|
|
622
|
-
}; // half-leadingをキャンセルするとき && 垂直方向のpaddingが無い時
|
|
623
|
-
// -> before/afterを入れる
|
|
624
|
-
|
|
625
|
-
const useHalfLeadingCanceller = ({
|
|
626
|
-
cancelHalfLeadingPx,
|
|
627
|
-
hasVerticalPadding: _hasVerticalPadding = false
|
|
628
|
-
}) => cancelHalfLeadingPx !== undefined && !_hasVerticalPadding;
|
|
629
|
-
|
|
630
|
-
const createTypographyCss = theme => (size, options = {}) => {
|
|
631
|
-
const {
|
|
632
|
-
preserveHalfLeading = false,
|
|
633
|
-
monospace = false,
|
|
634
|
-
bold = false
|
|
635
|
-
} = options;
|
|
636
|
-
const descriptor = theme.typography.size[size];
|
|
637
|
-
const margin = -halfLeading(descriptor);
|
|
638
|
-
return internal(context => _extends({
|
|
639
|
-
fontSize: px(descriptor.fontSize),
|
|
640
|
-
lineHeight: px(descriptor.lineHeight)
|
|
641
|
-
}, monospace && {
|
|
642
|
-
fontFamily: 'monospace'
|
|
643
|
-
}, bold && {
|
|
644
|
-
fontWeight: 'bold'
|
|
645
|
-
}, useHalfLeadingCanceller(context) && {
|
|
646
|
-
// prevent margin collapsing
|
|
647
|
-
display: 'flow-root',
|
|
648
|
-
// cancel half-leading with negative margin
|
|
649
|
-
'&::before': _extends({}, leadingCancel, {
|
|
650
|
-
marginTop: px(margin)
|
|
651
|
-
}),
|
|
652
|
-
'&::after': _extends({}, leadingCancel, {
|
|
653
|
-
marginBottom: px(margin)
|
|
654
|
-
})
|
|
655
|
-
}), !preserveHalfLeading ? {
|
|
656
|
-
cancelHalfLeadingPx: margin
|
|
657
|
-
} : {});
|
|
658
|
-
};
|
|
659
|
-
|
|
660
|
-
const leadingCancel = {
|
|
661
|
-
display: 'block',
|
|
662
|
-
width: 0,
|
|
663
|
-
height: 0,
|
|
664
|
-
content: `''`
|
|
665
|
-
};
|
|
666
|
-
|
|
667
|
-
function spacingProperty(property, direction) {
|
|
668
|
-
return `${property}-${direction}`;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
const createSpacingCss = theme => (property, modifiers) => {
|
|
672
|
-
const {
|
|
673
|
-
top,
|
|
674
|
-
right,
|
|
675
|
-
bottom,
|
|
676
|
-
left
|
|
677
|
-
} = modifiers.reduce((acc, [direction, size]) => {
|
|
678
|
-
if (direction === 'all') {
|
|
679
|
-
acc.top = size;
|
|
680
|
-
acc.right = size;
|
|
681
|
-
acc.bottom = size;
|
|
682
|
-
acc.left = size;
|
|
683
|
-
} else if (direction === 'vertical') {
|
|
684
|
-
acc.top = size;
|
|
685
|
-
acc.bottom = size;
|
|
686
|
-
} else if (direction === 'horizontal') {
|
|
687
|
-
acc.right = size;
|
|
688
|
-
acc.left = size;
|
|
689
|
-
} else {
|
|
690
|
-
acc[direction] = size;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
return acc;
|
|
694
|
-
}, {});
|
|
695
|
-
const hasVerticalPadding = property === 'padding' && top !== undefined && bottom !== undefined && top !== 'auto' && bottom !== 'auto';
|
|
696
|
-
return internal(({
|
|
697
|
-
cancelHalfLeadingPx: _cancelHalfLeadingPx = 0
|
|
698
|
-
}) => _extends({}, top !== undefined && {
|
|
699
|
-
[spacingProperty(property, 'top')]: top === 'auto' ? 'auto' : px(theme.spacing[top] + (hasVerticalPadding ? _cancelHalfLeadingPx : 0))
|
|
700
|
-
}, bottom !== undefined && {
|
|
701
|
-
[spacingProperty(property, 'bottom')]: bottom === 'auto' ? 'auto' : px(theme.spacing[bottom] + (hasVerticalPadding ? _cancelHalfLeadingPx : 0))
|
|
702
|
-
}, right !== undefined && {
|
|
703
|
-
[spacingProperty(property, 'right')]: right === 'auto' ? 'auto' : px(theme.spacing[right])
|
|
704
|
-
}, left !== undefined && {
|
|
705
|
-
[spacingProperty(property, 'left')]: left === 'auto' ? 'auto' : px(theme.spacing[left])
|
|
706
|
-
}), hasVerticalPadding ? {
|
|
707
|
-
hasVerticalPadding: true
|
|
708
|
-
} : {});
|
|
709
|
-
};
|
|
710
|
-
|
|
711
|
-
const createFixedPxCss = theme => (property, size) => internal(() => ({
|
|
712
|
-
[property]: size === 'auto' ? 'auto' : px(theme.spacing[size])
|
|
713
|
-
}));
|
|
714
|
-
|
|
715
|
-
const createFixedRelativeCss = _theme => (property, amount) => internal(() => ({
|
|
716
|
-
[property]: amount
|
|
717
|
-
}));
|
|
718
|
-
|
|
719
|
-
const createFixedColumnCss = theme => (property, span) => internal(() => ({
|
|
720
|
-
[property]: px(columnSystem(span, theme.grid.unit.column, theme.grid.unit.gutter))
|
|
721
|
-
}));
|
|
722
|
-
|
|
723
|
-
const createElementEffectCss = theme => (effects = []) => internal(() => effects.filter(isSupportedEffect).reduce((acc, effect) => {
|
|
724
|
-
var _theme$elementEffect$, _theme$elementEffect$2;
|
|
725
|
-
|
|
726
|
-
return _extends({}, acc, onEffectPseudo(effect, {
|
|
727
|
-
opacity: !Array.isArray(theme.elementEffect[effect]) && ((_theme$elementEffect$ = theme.elementEffect[effect]) == null ? void 0 : _theme$elementEffect$.type) === 'opacity' ? (_theme$elementEffect$2 = theme.elementEffect[effect]) == null ? void 0 : _theme$elementEffect$2.opacity : unreachable()
|
|
728
|
-
}));
|
|
729
|
-
}, {}));
|
|
730
|
-
|
|
731
|
-
function borderProperty(direction) {
|
|
732
|
-
return `border-${direction}`;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
function borderShorthand(color) {
|
|
736
|
-
return `solid 1px ${color}`;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
const createBorderCss = theme => (variant, directions) => {
|
|
740
|
-
const all = directions.length === 0;
|
|
741
|
-
const value = borderShorthand(theme.border[variant].color);
|
|
742
|
-
return internal(() => _extends({}, all ? {
|
|
743
|
-
border: value
|
|
744
|
-
} : directions.reduce((acc, direction) => _extends({}, acc, {
|
|
745
|
-
[borderProperty(direction)]: value
|
|
746
|
-
}), {})));
|
|
747
|
-
};
|
|
748
|
-
|
|
749
|
-
const createBorderRadiusCss = theme => size => internal(() => ({
|
|
750
|
-
borderRadius: px(theme.borderRadius[size])
|
|
751
|
-
}));
|
|
752
|
-
|
|
753
|
-
const commonSpec = _theme => {
|
|
754
|
-
const duration = dur(TRANSITION_DURATION);
|
|
755
|
-
|
|
756
|
-
const transition = property => ({
|
|
757
|
-
transition: property.map(v => `${duration} ${v}`).join(', ')
|
|
758
|
-
});
|
|
759
|
-
|
|
760
|
-
return internal(({
|
|
761
|
-
colorTransition: _colorTransition = false,
|
|
762
|
-
backgroundColorTransition: _backgroundColorTransition = false,
|
|
763
|
-
boxShadowTransition: _boxShadowTransition = false
|
|
764
|
-
}) => transition([_colorTransition ? 'color' : null, _backgroundColorTransition ? 'background-color' : null, _boxShadowTransition ? 'box-shadow' : null].filter(isPresent)));
|
|
765
|
-
};
|
|
766
|
-
|
|
767
|
-
const internalSym = Symbol('internal');
|
|
768
|
-
|
|
769
|
-
function internal(operation, context = {}) {
|
|
770
|
-
return {
|
|
771
|
-
[internalSym]: {
|
|
772
|
-
operation,
|
|
773
|
-
context
|
|
774
|
-
}
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
|
|
778
928
|
const nonBlank = value => isPresent(value) && value !== false;
|
|
779
929
|
/**
|
|
780
930
|
* `theme(o => [...])` の `theme` ユーティリティを構築する
|
|
781
931
|
*
|
|
782
|
-
* @param _styled styled-componnets の `styled`
|
|
932
|
+
* @param _styled - DEPRECATED: styled-componnets の `styled` そのものを渡すとそれを元に型推論ができる。が、型引数を渡す方が型推論が高速になりやすい
|
|
783
933
|
*
|
|
784
934
|
* @example
|
|
785
935
|
*
|
|
@@ -793,33 +943,45 @@ const nonBlank = value => isPresent(value) && value !== false;
|
|
|
793
943
|
|
|
794
944
|
|
|
795
945
|
function createTheme(_styled) {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
const specDescriptor = [...(Array.isArray(rawSpecDescriptor) ? rawSpecDescriptor : [rawSpecDescriptor]), commonSpec()].filter(nonBlank); // 1パス目
|
|
817
|
-
// 全ユーザー定義を舐めて相互に影響し合う定義をチェックし、その結果(コンテキスト)を取得
|
|
818
|
-
|
|
819
|
-
const context = specDescriptor.reduce((acc, v) => _extends({}, acc, v[internalSym].context), {}); // 2パス目
|
|
820
|
-
// コンテキストを見ながら最適化されたCSSを構築
|
|
946
|
+
/**
|
|
947
|
+
* 本当は `type Builder = ReturnType<createO<T>>` みたいな型を作って、それを o の型にしたい。
|
|
948
|
+
* が、styled がつくられた時点の TypeScript ではこういうジェネリクスの使い方ができなかった
|
|
949
|
+
* なので代わりに特に意味のない `createO` の呼び出しをやっている
|
|
950
|
+
*/
|
|
951
|
+
createO( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
952
|
+
{},
|
|
953
|
+
/** DO_NOTHING_IT_IS_JUST_CALLED_FOR_TYPE_INFERENCE = */
|
|
954
|
+
true); // ランタイムの `theme(o => [...])` のインターフェースを構築する
|
|
955
|
+
|
|
956
|
+
return function theme(specFn) {
|
|
957
|
+
// styled-components のテンプレートに埋め込める関数
|
|
958
|
+
return function interpolate({
|
|
959
|
+
theme
|
|
960
|
+
}) {
|
|
961
|
+
if (!isPresent(theme)) {
|
|
962
|
+
// テーマが入っていない場合は復旧不可能なのでエラーにする
|
|
963
|
+
throw noThemeProvider;
|
|
964
|
+
}
|
|
821
965
|
|
|
822
|
-
|
|
966
|
+
const internals = [// ユーザーが定義したルール
|
|
967
|
+
...wrapArray(
|
|
968
|
+
/**
|
|
969
|
+
* こう書いてはいけない
|
|
970
|
+
*
|
|
971
|
+
* ❌
|
|
972
|
+
* ```ts
|
|
973
|
+
* const o = createO(theme)
|
|
974
|
+
* const declaration = spec(o)
|
|
975
|
+
* ```
|
|
976
|
+
*
|
|
977
|
+
* `o` を一時変数に入れてしまうと型 `T` の具象化が行われるので関数内に書く
|
|
978
|
+
*/
|
|
979
|
+
specFn(
|
|
980
|
+
/** o = */
|
|
981
|
+
createO(theme))), // 必ず挿入される共通のルール
|
|
982
|
+
transition()].filter(nonBlank);
|
|
983
|
+
return toCSSObjects(internals);
|
|
984
|
+
};
|
|
823
985
|
};
|
|
824
986
|
}
|
|
825
987
|
|