@charcoal-ui/styled 2.0.0-alpha.3 → 2.0.0-alpha.4

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.
@@ -1,21 +1,785 @@
1
- import e from"warning";import{columnSystem as t}from"@charcoal-ui/foundation";import{customPropertyToken as o,applyEffect as n,notDisabledSelector as r,disabledSelector as i,px as a,halfLeading as c,dur as l,applyEffectToGradient as u,gradient as s}from"@charcoal-ui/utils";import d,{useEffect as f,useState as g,useMemo as m}from"react";import{createGlobalStyle as h,css as p}from"styled-components";function b(){return b=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var o=arguments[t];for(var n in o)Object.prototype.hasOwnProperty.call(o,n)&&(e[n]=o[n])}return e},b.apply(this,arguments)}function v(e){throw new Error(0===arguments.length?"unreachable":`unreachable (${JSON.stringify(e)})`)}const y=e=>null!=e;function $(...e){return Object.assign({},...e)}function w(e){return Object.keys(e)}const S=(e,t,o)=>Object.defineProperties(e,Object.fromEntries(t.map(e=>[e,{get:()=>o(e),enumerable:!0,configurable:!0}]))),k=(e,t)=>S(e,Object.keys(t),e=>t[e]),E=(e,t)=>function o(n){const r=e.filter(e=>!n.includes(e));return S(t(n),r,e=>0===r.length?v():o([...n,e]))}([]),x=e=>`var(${e})`;let O,j,L,T,A,H=e=>e;const P=h(O||(O=H`
1
+ import warning from 'warning';
2
+ import { columnSystem } from '@charcoal-ui/foundation';
3
+ import { customPropertyToken, applyEffect, notDisabledSelector, disabledSelector, px, halfLeading, dur, applyEffectToGradient, gradient } from '@charcoal-ui/utils';
4
+ import React, { useEffect, useState, useMemo } from 'react';
5
+ import { createGlobalStyle, css } from 'styled-components';
6
+
7
+ function _extends() {
8
+ _extends = Object.assign || function (target) {
9
+ for (var i = 1; i < arguments.length; i++) {
10
+ var source = arguments[i];
11
+
12
+ for (var key in source) {
13
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
14
+ target[key] = source[key];
15
+ }
16
+ }
17
+ }
18
+
19
+ return target;
20
+ };
21
+
22
+ return _extends.apply(this, arguments);
23
+ }
24
+
25
+ function unreachable(value) {
26
+ throw new Error(arguments.length === 0 ? 'unreachable' : `unreachable (${JSON.stringify(value)})`);
27
+ }
28
+ /**
29
+ * Check whether a value is non-null and non-undefined
30
+ *
31
+ * @param value nullable
32
+ */
33
+
34
+ const isPresent = value => value != null; // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
+
36
+ function objectAssign(...sources) {
37
+ return Object.assign({}, ...sources);
38
+ }
39
+ function objectKeys(obj) {
40
+ return Object.keys(obj);
41
+ }
42
+
43
+ /**
44
+ * 配列で指定したプロパティを動的に生やす
45
+ *
46
+ * @param source 拡張するオブジェクト
47
+ * @param member オブジェクトに生やすプロパティ一覧
48
+ * @param chain プロパティに格納される値を生成する関数
49
+ *
50
+ * @example
51
+ *
52
+ * const o = factory({}, ['red', 'blue'],
53
+ * color => hex(color)
54
+ * )
55
+ *
56
+ * console.log(o.red) //=> #ff0000
57
+ */
58
+
59
+ const factory = (source, member, chain) => Object.defineProperties(source, Object.fromEntries(member.map(key => [key, {
60
+ get: () => chain(key),
61
+ enumerable: true,
62
+ configurable: true
63
+ }])));
64
+ /**
65
+ * 配列で指定した名前のメソッドを動的に生やす
66
+ *
67
+ * @param source 拡張するオブジェクト
68
+ * @param member オブジェクトに生やすメソッド名一覧
69
+ * @param chain メソッドの戻り値になる値を生成する関数
70
+ *
71
+ * @example
72
+ *
73
+ * const o = argumentedFactory({}, ['red', 'blue'],
74
+ * (color, alpha: number) => hex(color, alpha)
75
+ * )
76
+ *
77
+ * console.log(o.red(0.5)) //=> #ff000077
78
+ */
79
+
80
+ const argumentedFactory = (source, member, chain) => Object.defineProperties(source, Object.fromEntries(member.map(key => [key, {
81
+ value: (...args) => chain(key, ...args),
82
+ enumerable: true,
83
+ configurable: true
84
+ }])));
85
+ /**
86
+ * オブジェクトで指定したプロパティ名と値を動的に生やす
87
+ *
88
+ * @param source 拡張するオブジェクト
89
+ * @param def オブジェクトに生やす定義(プロパティ名と値)
90
+ *
91
+ * @example
92
+ *
93
+ * const o = constFactory({}, {
94
+ * red: '#f00',
95
+ * blue: '#00f',
96
+ * })
97
+ *
98
+ * console.log(o.red) //=> #f00
99
+ */
100
+
101
+ const constFactory = (source, def) => factory(source, Object.keys(def), key => def[key]);
102
+ /**
103
+ * 配列で指定したモディファイア(プロパティ)をチェーン可能な再帰オブジェクトを動的に生やす
104
+ *
105
+ * @param modifiers オブジェクトに生やすモディファイヤ一覧
106
+ * @param source 指定されたモディファイヤの一覧から値を生成する関数
107
+ *
108
+ * @example
109
+ *
110
+ * const o = modifiedArgumentedFactory(['red', 'blue'],
111
+ * modifiers => modifiers.map(color => hex(color)).join(',')
112
+ * )
113
+ *
114
+ * console.log(o.red.blue) => #f00,#00f
115
+ */
116
+
117
+ const modifiedFactory = (modifiers, source) => function recursiveModifiedFactory(applied) {
118
+ const notApplied = modifiers.filter(v => !applied.includes(v));
119
+ return factory(source(applied), notApplied, modifier => notApplied.length === 0 ? unreachable() : recursiveModifiedFactory([...applied, modifier]));
120
+ }([]);
121
+ /**
122
+ * 配列で指定したモディファイア(メソッド)をチェーン可能な再帰オブジェクトを動的に生やす
123
+ *
124
+ * @param modifiers オブジェクトに生やすモディファイヤ一覧
125
+ * @param source 指定されたモディファイヤの一覧から値を生成する関数
126
+ * @param _inferPhantom 関数形式のモディファイヤの引数型を推論するためのメタタイプ(引数の個数に合わせてタプルで指定する)
127
+ *
128
+ * @example
129
+ *
130
+ * const o = modifiedArgumentedFactory(['red', 'blue'],
131
+ * modifiers => modifiers.map(([color, alpha]) => hex(color, alpha)).join(',')
132
+ * , {} as [number])
133
+ *
134
+ * console.log(o.red(0.5).blue(1)) => #ff000077,#0000ffff
135
+ */
136
+
137
+ const modifiedArgumentedFactory = (modifiers, source, ..._inferPhantom) => function recursiveModifiedFactory(applied) {
138
+ const notApplied = modifiers.filter(v => !applied.map(([w]) => w).includes(v));
139
+ return argumentedFactory(source(applied), notApplied, (modifier, ...args) => notApplied.length === 0 ? unreachable() : recursiveModifiedFactory([...applied, [modifier, ...args]]));
140
+ }([]);
141
+ const variable = value => `var(${value})`;
142
+
143
+ let _ = t => t,
144
+ _t,
145
+ _t2,
146
+ _t3,
147
+ _t4,
148
+ _t5;
149
+ const GlobalStyle = createGlobalStyle(_t || (_t = _`
2
150
  ${0}
3
- `),({themeMap:e,background:t})=>Object.entries(e).map(([e,o])=>e.startsWith("@media")?p(j||(j=H`
151
+ `), ({
152
+ themeMap,
153
+ background
154
+ }) => Object.entries(themeMap).map(([key, theme]) => key.startsWith('@media') ? css(_t2 || (_t2 = _`
4
155
  ${0} {
5
156
  :root {
6
157
  ${0}
7
158
  ${0}
8
159
  }
9
160
  }
10
- `),e,void 0!==t&&p(L||(L=H`
161
+ `), key, background !== undefined && css(_t3 || (_t3 = _`
11
162
  background-color: ${0};
12
- `),o.color[t]),I(o)):p(T||(T=H`
163
+ `), theme.color[background]), customProperties(theme)) : css(_t4 || (_t4 = _`
13
164
  /* stylelint-disable-next-line no-duplicate-selectors */
14
165
  ${0} {
15
166
  ${0}
16
167
  ${0}
17
168
  }
18
- `),e,void 0!==t&&p(A||(A=H`
169
+ `), key, background !== undefined && css(_t5 || (_t5 = _`
19
170
  background-color: ${0};
20
- `),o.color[t]),I(o)))),I=e=>Object.entries(e.color).flatMap(([t,r])=>[z(o(t),r),...Object.entries(e.effect).map(([e,i])=>z(o(t,[e]),n(r,[i])))]).join(";"),z=(e,t)=>`${e}: ${t}`;function C({theme:e,background:t}){/*#__PURE__*/return d.createElement(P,{themeMap:e,background:t})}const K=new RegExp(/^(\w|-)+$/);function M(e){if(!K.test(e))throw new Error(`Unexpected key :${e}, expect: /^(\\w|-)+$/`)}const R=(e="theme")=>t=>{M(e),void 0!==t?document.documentElement.dataset[e]=t:delete document.documentElement.dataset[e]};function J(e,t){return`:root[data-${null!=t?t:"theme"}='${e}']`}function N(e){return`@media (prefers-color-scheme: ${e})`}function V({key:e="charcoal-theme",setter:t=R()}={}){const[o,,n]=_(e);f(()=>{void 0!==o&&t(n?void 0:o)},[t,n,o])}function W(e="charcoal-theme"){return localStorage.getItem(e)}const _=(e="charcoal-theme")=>{M(e);const t=F("(prefers-color-scheme: dark)"),o=void 0!==t?t?"dark":"light":void 0,[n,r,i]=B(e);return[i&&void 0!==o?null!=n?n:o:void 0,r,void 0===n]};function B(e,t){const[o,n]=g(!1),[r,i]=g(),a=m(()=>null==t?void 0:t(),[t]);f(()=>(l(),window.addEventListener("storage",c),()=>{window.removeEventListener("storage",c)}));const c=t=>{t.storageArea===localStorage&&t.key===e&&l()},l=()=>{var t;const o=localStorage.getItem(e);i(null!=(t=null!==o?function(e){try{return JSON.parse(e)}catch(t){return e}}(o):null)?t:a),n(!0)};return[null!=r?r:a,t=>{if(void 0===t)localStorage.removeItem(e);else{const o=function(e){return"string"==typeof e?e:JSON.stringify(e)}(t);localStorage.setItem(e,o)}const o=new StorageEvent("storage",{bubbles:!0,cancelable:!1,key:e,url:location.href,storageArea:localStorage});dispatchEvent(o)},o]}function F(e){const[t,o]=g();return f(()=>{const t=window.matchMedia(e),n=()=>{o(t.matches)};return t.addEventListener("change",n),o(t.matches),()=>{t.removeEventListener("change",n)}},[e]),t}function U(e){return M(e.localStorageKey),M(e.rootAttribute),/*#__PURE__*/d.createElement("script",{dangerouslySetInnerHTML:{__html:`'use strict';\n(function () {\n var localStorageKey = '${e.localStorageKey}'\n var rootAttribute = '${e.rootAttribute}'\n var currentTheme = localStorage.getItem(localStorageKey);\n if (currentTheme) {\n document.documentElement.dataset[rootAttribute] = currentTheme;\n }\n})();\n`}})}U.defaultProps={localStorageKey:"charcoal-theme",rootAttribute:"theme"};const Y=["margin","padding"],q=["top","right","bottom","left","vertical","horizontal","all"],D=["width","height"],G=["top","right","bottom","left"],Q=["focus"];function X(e,t=!1){if(t)return{};const o=w(e.color),n=w(e.effect),r=w(e.gradientColor),i=oe(),a=ne(e),c=k({},{bg:$(S({},o,e=>E(n,t=>i("bg",e,t))),S({},r,e=>t=>E(n,o=>a(e,o,t)))),font:S({},o,e=>E(n,t=>i("font",e,t)))}),l=["monospace","bold","preserveHalfLeading"],u=le(e),s=S({},["typography"],e=>e=>E(l,t=>u(e,{preserveHalfLeading:t.includes("preserveHalfLeading"),monospace:t.includes("monospace"),bold:t.includes("bold")}))),d=de(e),f=S({},Y,e=>{return t=q,o=t=>d(e,t),function e(n){const r=t.filter(e=>!n.map(([e])=>e).includes(e));return((t,o,i)=>Object.defineProperties(t,Object.fromEntries(o.map(t=>[t,{value:(...o)=>((t,...o)=>0===r.length?v():e([...n,[t,...o]]))(t,...o),enumerable:!0,configurable:!0}]))))(o(n),r)}([]);var t,o}),g=fe(e),m=me(e),h=ge(),p=S({},D,e=>k({},{px:t=>g(e,t),column:t=>m(e,t),auto:h(e,"auto"),full:h(e,"100%")})),b=he(e),y=E(w(e.elementEffect),e=>b(e)),x=be(e),O=k({},{border:S({},w(e.border),e=>E(G,t=>x(e,t)))}),j=ve(e),L=k({},{borderRadius:e=>j(e)}),T=ie(e);return $(c,s,f,p,y,O,L,k({},{outline:S({},w(e.outline),e=>E(Q,t=>T(e,t)))}))}function Z(e){return"bg"===e?"background-color":"color"}function ee(e){return["hover","press","disabled"].includes(e)}function te(e,t){return"hover"===e?{"&:hover":{[r]:t}}:"press"===e?{"&:active":{[r]:t}}:"disabled"===e?{[i]:t}:v(e)}const oe=e=>(e,t,n=[])=>we(()=>b({[Z(e)]:x(o(t.toString()))},n.filter(ee).reduce((n,r)=>b({},n,te(r,{[Z(e)]:x(o(t.toString(),[r]))})),{})),n.length>0?"font"===e?{colorTransition:!0}:{backgroundColorTransition:!0}:{}),ne=t=>(o,r=[],i)=>{const a=s(i);return we(i=>{const c=!ce(i),s=l(.2);return c&&r.length>0?b({position:"relative",zIndex:0,overflow:"hidden"},r.filter(ee).reduce((e,r)=>{var i;return b({},e,{"&::before":b({zIndex:-1},ae,{transition:`${s} background-color`}),"&::after":b({zIndex:-2},ae,a(t.gradientColor[o]))},te(r,{"&::before":{backgroundColor:n(null,null!=(i=t.effect[r])?i:[])}}))},{})):(e(0===r.length,"'Transition' will not be applied. You can get around this by specifying 'preserveHalfLeading' or both 'padding' and 'typograpy'."),b({},a(t.gradientColor[o]),r.filter(ee).reduce((e,n)=>{var r;return b({},e,te(n,b({},a(u(null!=(r=t.effect[n])?r:[])(t.gradientColor[o])))))},{})))})},re=(e,t)=>({boxShadow:`0 0 0 ${a(e)} ${t}`}),ie=e=>(t,o)=>{const n=e.outline[t].weight,i=e.outline[t].color;return we(()=>o.includes("focus")?(e=>({[r]:{"&:focus, &:active":b({outline:"none"},e),"&:focus:not(:focus-visible), &:active:not(:focus-visible)":{outline:"none"},"&:focus-visible":b({outline:"none"},e)}}))(re(n,i)):{"&&":{[r]:re(n,i)}},{boxShadowTransition:!0})},ae={content:"''",display:"block",position:"absolute",width:"100%",height:"100%",top:0,left:0},ce=({cancelHalfLeadingPx:e,hasVerticalPadding:t=!1})=>void 0!==e&&!t,le=e=>(t,o={})=>{const{preserveHalfLeading:n=!1,monospace:r=!1,bold:i=!1}=o,l=e.typography.size[t],u=-c(l);return we(e=>b({fontSize:a(l.fontSize),lineHeight:a(l.lineHeight)},r&&{fontFamily:"monospace"},i&&{fontWeight:"bold"},ce(e)&&{display:"flow-root","&::before":b({},ue,{marginTop:a(u)}),"&::after":b({},ue,{marginBottom:a(u)})}),n?{}:{cancelHalfLeadingPx:u})},ue={display:"block",width:0,height:0,content:"''"};function se(e,t){return`${e}-${t}`}const de=e=>(t,o)=>{const{top:n,right:r,bottom:i,left:c}=o.reduce((e,[t,o])=>("all"===t?(e.top=o,e.right=o,e.bottom=o,e.left=o):"vertical"===t?(e.top=o,e.bottom=o):"horizontal"===t?(e.right=o,e.left=o):e[t]=o,e),{}),l="padding"===t&&void 0!==n&&void 0!==i&&"auto"!==n&&"auto"!==i;return we(({cancelHalfLeadingPx:o=0})=>b({},void 0!==n&&{[se(t,"top")]:"auto"===n?"auto":a(e.spacing[n]+(l?o:0))},void 0!==i&&{[se(t,"bottom")]:"auto"===i?"auto":a(e.spacing[i]+(l?o:0))},void 0!==r&&{[se(t,"right")]:"auto"===r?"auto":a(e.spacing[r])},void 0!==c&&{[se(t,"left")]:"auto"===c?"auto":a(e.spacing[c])}),l?{hasVerticalPadding:!0}:{})},fe=e=>(t,o)=>we(()=>({[t]:"auto"===o?"auto":a(e.spacing[o])})),ge=e=>(e,t)=>we(()=>({[e]:t})),me=e=>(o,n)=>we(()=>({[o]:a(t(n,e.grid.unit.column,e.grid.unit.gutter))})),he=e=>(t=[])=>we(()=>t.filter(ee).reduce((t,o)=>{var n,r;return b({},t,te(o,{opacity:Array.isArray(e.elementEffect[o])||"opacity"!==(null==(n=e.elementEffect[o])?void 0:n.type)?v():null==(r=e.elementEffect[o])?void 0:r.opacity}))},{}));function pe(e){return`border-${e}`}const be=e=>(t,o)=>{const n=0===o.length,r=`solid 1px ${e.border[t].color}`;return we(()=>b({},n?{border:r}:o.reduce((e,t)=>b({},e,{[pe(t)]:r}),{})))},ve=e=>t=>we(()=>({borderRadius:a(e.borderRadius[t])})),ye=e=>{const t=l(.2);return we(({colorTransition:e=!1,backgroundColorTransition:o=!1,boxShadowTransition:n=!1})=>({transition:[e?"color":null,o?"background-color":null,n?"box-shadow":null].filter(y).map(e=>`${t} ${e}`).join(", ")}))},$e=Symbol("internal");function we(e,t={}){return{[$e]:{operation:e,context:t}}}const Se=e=>y(e)&&!1!==e;function ke(e){return X({},!0),e=>({theme:t})=>{if(null==t)throw new Error("`theme` is invalid. `<ThemeProvider>` is not likely mounted.");const o=e(X(t)),n=[...Array.isArray(o)?o:[o],ye()].filter(Se),r=n.reduce((e,t)=>b({},e,t[$e].context),{});return n.map(e=>e[$e].operation(r))}}export{U as SetThemeScript,C as TokenInjector,ke as createTheme,W as getThemeSync,N as prefersColorScheme,J as themeSelector,R as themeSetter,B as useLocalStorage,F as useMedia,_ as useTheme,V as useThemeSetter};
171
+ `), theme.color[background]), customProperties(theme))));
172
+
173
+ const customProperties = theme => Object.entries(theme.color).flatMap(([colorKey, color]) => [variableDefinition(customPropertyToken(colorKey), color), ...Object.entries(theme.effect).map(([effectKey, effect]) => variableDefinition(customPropertyToken(colorKey, [effectKey]), applyEffect(color, [effect])))]).join(';');
174
+
175
+ const variableDefinition = (prop, value) => `${prop}: ${value}`;
176
+
177
+ function TokenInjector({
178
+ theme: themeMap,
179
+ background
180
+ }) {
181
+ return /*#__PURE__*/React.createElement(GlobalStyle, {
182
+ themeMap: themeMap,
183
+ background: background
184
+ });
185
+ }
186
+
187
+ const LOCAL_STORAGE_KEY = 'charcoal-theme';
188
+ const DEFAULT_ROOT_ATTRIBUTE = 'theme';
189
+ const keyStringRegExp = new RegExp(/^(\w|-)+$/);
190
+ /**
191
+ * 文字列が英数字_-のみで構成されているか検証する。不正な文字列ならエラーを投げる
192
+ * @param key 検証するキー
193
+ */
194
+
195
+ function assertKeyString(key) {
196
+ if (!keyStringRegExp.test(key)) {
197
+ throw new Error(`Unexpected key :${key}, expect: /^(\\w|-)+$/`);
198
+ }
199
+ }
200
+ /**
201
+ * `<html data-theme="dark">` のような設定を行うデフォルトのセッター
202
+ */
203
+
204
+ const themeSetter = (attr = DEFAULT_ROOT_ATTRIBUTE) => theme => {
205
+ assertKeyString(attr);
206
+
207
+ if (theme !== undefined) {
208
+ document.documentElement.dataset[attr] = theme;
209
+ } else {
210
+ delete document.documentElement.dataset[attr];
211
+ }
212
+ };
213
+ /**
214
+ * `<html data-theme="dark">` にマッチするセレクタを生成する
215
+ */
216
+
217
+ function themeSelector(theme, attr) {
218
+ return `:root[data-${attr != null ? attr : DEFAULT_ROOT_ATTRIBUTE}='${theme}']`;
219
+ }
220
+ /**
221
+ * prefers-color-scheme を利用する media クエリを生成する
222
+ */
223
+
224
+ function prefersColorScheme(theme) {
225
+ return `@media (prefers-color-scheme: ${theme})`;
226
+ }
227
+ /**
228
+ * LocalStorageからテーマの情報を取得して、変化時にテーマをセットするhooks
229
+ */
230
+
231
+ function useThemeSetter({
232
+ key = LOCAL_STORAGE_KEY,
233
+ setter = themeSetter()
234
+ } = {}) {
235
+ const [theme,, system] = useTheme(key);
236
+ useEffect(() => {
237
+ if (theme === undefined) {
238
+ return;
239
+ } // prefers-color-scheme から値を取っている場合にはcssのみで処理したいのでアンセットする
240
+
241
+
242
+ setter(system ? undefined : theme);
243
+ }, [setter, system, theme]);
244
+ }
245
+ /**
246
+ * 同期的にLocalStorageからテーマを取得するヘルパ
247
+ */
248
+
249
+ function getThemeSync(key = LOCAL_STORAGE_KEY) {
250
+ const theme = localStorage.getItem(key);
251
+ return theme;
252
+ }
253
+ /**
254
+ * LocalStorage, prefers-color-scheme からテーマの情報を取得して、現在のテーマを返すhooks
255
+ *
256
+ * `dark` `light` という名前だけは特別扱いされていて、prefers-color-schemeにマッチした場合に返ります
257
+ */
258
+
259
+ const useTheme = (key = LOCAL_STORAGE_KEY) => {
260
+ assertKeyString(key);
261
+ const isDark = useMedia('(prefers-color-scheme: dark)');
262
+ const media = isDark !== undefined ? isDark ? 'dark' : 'light' : undefined;
263
+ const [local, setTheme, ready] = useLocalStorage(key);
264
+ const theme = !ready || media === undefined ? undefined : local != null ? local : media;
265
+ const system = local === undefined;
266
+ return [theme, setTheme, system];
267
+ };
268
+ function useLocalStorage(key, defaultValue) {
269
+ const [ready, setReady] = useState(false);
270
+ const [state, setState] = useState();
271
+ const defaultValueMemo = useMemo(() => defaultValue == null ? void 0 : defaultValue(), [defaultValue]);
272
+ useEffect(() => {
273
+ fetch();
274
+ window.addEventListener('storage', handleStorage);
275
+ return () => {
276
+ window.removeEventListener('storage', handleStorage);
277
+ };
278
+ });
279
+
280
+ const handleStorage = e => {
281
+ if (e.storageArea !== localStorage) {
282
+ return;
283
+ }
284
+
285
+ if (e.key !== key) {
286
+ return;
287
+ }
288
+
289
+ fetch();
290
+ };
291
+
292
+ const fetch = () => {
293
+ var _ref;
294
+
295
+ const raw = localStorage.getItem(key);
296
+ setState((_ref = raw !== null ? deserialize(raw) : null) != null ? _ref : defaultValueMemo);
297
+ setReady(true);
298
+ };
299
+
300
+ const set = value => {
301
+ if (value === undefined) {
302
+ // undefinedがセットされる場合にはkeyごと削除
303
+ localStorage.removeItem(key);
304
+ } else {
305
+ const raw = serialize(value);
306
+ localStorage.setItem(key, raw);
307
+ } // 同一ウィンドウではstorageイベントが発火しないので、手動で発火させる
308
+
309
+
310
+ const event = new StorageEvent('storage', {
311
+ bubbles: true,
312
+ cancelable: false,
313
+ key,
314
+ url: location.href,
315
+ storageArea: localStorage
316
+ });
317
+ dispatchEvent(event);
318
+ };
319
+
320
+ return [state != null ? state : defaultValueMemo, set, ready];
321
+ }
322
+
323
+ function deserialize(raw) {
324
+ try {
325
+ return JSON.parse(raw);
326
+ } catch (_unused) {
327
+ // syntax error はすべて文字列として扱う
328
+ return raw;
329
+ }
330
+ }
331
+
332
+ function serialize(value) {
333
+ if (typeof value === 'string') {
334
+ return value;
335
+ } else {
336
+ return JSON.stringify(value);
337
+ }
338
+ }
339
+
340
+ function useMedia(query) {
341
+ const [match, setState] = useState();
342
+ useEffect(() => {
343
+ const matcher = window.matchMedia(query);
344
+
345
+ const onChange = () => {
346
+ setState(matcher.matches);
347
+ };
348
+
349
+ matcher.addEventListener('change', onChange);
350
+ setState(matcher.matches);
351
+ return () => {
352
+ matcher.removeEventListener('change', onChange);
353
+ };
354
+ }, [query]);
355
+ return match;
356
+ }
357
+
358
+ /**
359
+ * 同期的にテーマをローカルストレージから取得してhtmlの属性に設定するスクリプトタグ
360
+ * @param props localStorageのキー、htmlのdataになる属性のキーを含むオブジェクト
361
+ * @returns
362
+ */
363
+
364
+ function SetThemeScript(props) {
365
+ assertKeyString(props.localStorageKey);
366
+ assertKeyString(props.rootAttribute);
367
+ const src = `'use strict';
368
+ (function () {
369
+ var localStorageKey = '${props.localStorageKey}'
370
+ var rootAttribute = '${props.rootAttribute}'
371
+ var currentTheme = localStorage.getItem(localStorageKey);
372
+ if (currentTheme) {
373
+ document.documentElement.dataset[rootAttribute] = currentTheme;
374
+ }
375
+ })();
376
+ `;
377
+ return /*#__PURE__*/React.createElement("script", {
378
+ dangerouslySetInnerHTML: {
379
+ __html: src
380
+ }
381
+ });
382
+ }
383
+ const defaultProps = {
384
+ localStorageKey: LOCAL_STORAGE_KEY,
385
+ rootAttribute: DEFAULT_ROOT_ATTRIBUTE
386
+ };
387
+ SetThemeScript.defaultProps = defaultProps;
388
+
389
+ const spacingProperties = ['margin', 'padding'];
390
+ const spacingDirections = ['top', 'right', 'bottom', 'left', 'vertical', 'horizontal', 'all'];
391
+ const fixedProperties = ['width', 'height'];
392
+ const borderDirections = ['top', 'right', 'bottom', 'left'];
393
+ const outlineType = ['focus'];
394
+ /**
395
+ * `theme(o => [...])` の `o` の部分を構築する
396
+ *
397
+ * @param theme テーマオブジェクト
398
+ * @param isPhantom 型推論のためだけに使う場合にランタイムコストをゼロにするフラグ
399
+ */
400
+
401
+ function builder(theme, isPhantom = false) {
402
+ if (isPhantom) {
403
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
404
+ return {};
405
+ }
406
+
407
+ const colors = objectKeys(theme.color);
408
+ const effects = objectKeys(theme.effect); // 色
409
+
410
+ const gradientColors = objectKeys(theme.gradientColor);
411
+ const colorCss = createColorCss();
412
+ const gradientColorCss = createGradientColorCss(theme);
413
+ const colorObject = constFactory({}, {
414
+ bg: objectAssign(factory({}, colors, color => modifiedFactory(effects, modifiers => colorCss('bg', color, modifiers))), factory({}, gradientColors, color => direction => modifiedFactory(effects, modifiers => gradientColorCss(color, modifiers, direction)))),
415
+ font: factory({}, colors, color => modifiedFactory(effects, modifiers => colorCss('font', color, modifiers)))
416
+ }); // タイポグラフィ
417
+
418
+ const typographyModifiers = [// TODO
419
+ 'monospace', 'bold', 'preserveHalfLeading'];
420
+ const typographyCss = createTypographyCss(theme);
421
+ const typographyObject = factory({}, ['typography'], _ => size => modifiedFactory(typographyModifiers, modifiers => typographyCss(size, {
422
+ preserveHalfLeading: modifiers.includes('preserveHalfLeading'),
423
+ monospace: modifiers.includes('monospace'),
424
+ bold: modifiers.includes('bold')
425
+ }))); // スペーシング
426
+
427
+ const spacingCss = createSpacingCss(theme);
428
+ const spacingObject = factory({}, spacingProperties, spacingProperty => modifiedArgumentedFactory(spacingDirections, modifiers => spacingCss(spacingProperty, modifiers), {} // 推論のためのメタタイプ
429
+ )); // 大きさ
430
+
431
+ const fixedPxCss = createFixedPxCss(theme);
432
+ const fixedColumnCss = createFixedColumnCss(theme);
433
+ const fixedRelativeCss = createFixedRelativeCss();
434
+ const fixedObject = factory({}, fixedProperties, property => constFactory({}, {
435
+ px: size => fixedPxCss(property, size),
436
+ column: span => fixedColumnCss(property, span),
437
+ auto: fixedRelativeCss(property, 'auto'),
438
+ full: fixedRelativeCss(property, '100%')
439
+ })); // 要素へのエフェクト (etc: 透過)
440
+
441
+ const elementEffectCss = createElementEffectCss(theme);
442
+ const elementEffectObject = modifiedFactory(objectKeys(theme.elementEffect), modifiers => elementEffectCss(modifiers)); // ボーダー
443
+
444
+ const borderCss = createBorderCss(theme);
445
+ const borderObject = constFactory({}, {
446
+ border: factory({}, objectKeys(theme.border), variant => modifiedFactory(borderDirections, modifiers => borderCss(variant, modifiers)))
447
+ }); // 角丸
448
+
449
+ const borderRadiusCss = createBorderRadiusCss(theme);
450
+ const borderRadiusObject = constFactory({}, {
451
+ borderRadius: radius => borderRadiusCss(radius)
452
+ }); // アウトライン
453
+
454
+ const outlineCss = createOutlineColorCss(theme);
455
+ const outlineObject = constFactory({}, {
456
+ outline: factory({}, objectKeys(theme.outline), variant => modifiedFactory(outlineType, modifiers => outlineCss(variant, modifiers)))
457
+ });
458
+ return objectAssign(colorObject, typographyObject, spacingObject, fixedObject, elementEffectObject, borderObject, borderRadiusObject, outlineObject);
459
+ }
460
+
461
+ function targetProperty(target) {
462
+ return target === 'bg' ? 'background-color' : 'color';
463
+ }
464
+
465
+ function isSupportedEffect(effect) {
466
+ return ['hover', 'press', 'disabled'].includes(effect);
467
+ }
468
+
469
+ function onEffectPseudo(effect, css) {
470
+ return effect === 'hover' ? {
471
+ '&:hover': {
472
+ [notDisabledSelector]: css
473
+ }
474
+ } : effect === 'press' ? {
475
+ '&:active': {
476
+ [notDisabledSelector]: css
477
+ }
478
+ } : // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
479
+ effect === 'disabled' ? {
480
+ [disabledSelector]: css
481
+ } : unreachable(effect);
482
+ }
483
+
484
+ const createColorCss = _theme => (target, color, effects = []) => internal(() => _extends({
485
+ [targetProperty(target)]: variable(customPropertyToken(color.toString()))
486
+ }, effects.filter(isSupportedEffect).reduce((acc, effect) => _extends({}, acc, onEffectPseudo(effect, {
487
+ [targetProperty(target)]: variable(customPropertyToken(color.toString(), [effect]))
488
+ })), {})), effects.length > 0 ? target === 'font' ? {
489
+ colorTransition: true
490
+ } : {
491
+ backgroundColorTransition: true
492
+ } : {}); // TODO: deprecate
493
+
494
+
495
+ const TRANSITION_DURATION = 0.2;
496
+
497
+ const createGradientColorCss = theme => (color, effects = [], direction) => {
498
+ const toLinearGradient = gradient(direction);
499
+ return internal(context => {
500
+ const optimized = !useHalfLeadingCanceller(context);
501
+ const duration = dur(TRANSITION_DURATION);
502
+
503
+ if (optimized && effects.length > 0) {
504
+ return _extends({
505
+ position: 'relative',
506
+ zIndex: 0,
507
+ overflow: 'hidden'
508
+ }, effects.filter(isSupportedEffect).reduce((acc, effect) => {
509
+ var _theme$effect$effect;
510
+
511
+ return _extends({}, acc, {
512
+ '&::before': _extends({
513
+ zIndex: -1
514
+ }, overlayElement, {
515
+ transition: `${duration} background-color`
516
+ }),
517
+ '&::after': _extends({
518
+ zIndex: -2
519
+ }, overlayElement, toLinearGradient(theme.gradientColor[color]))
520
+ }, onEffectPseudo(effect, {
521
+ '&::before': {
522
+ backgroundColor: applyEffect(null, (_theme$effect$effect = theme.effect[effect]) != null ? _theme$effect$effect : [])
523
+ }
524
+ }));
525
+ }, {}));
526
+ } else {
527
+ warning(effects.length === 0, // eslint-disable-next-line max-len
528
+ `'Transition' will not be applied. You can get around this by specifying 'preserveHalfLeading' or both 'padding' and 'typograpy'.`);
529
+ return _extends({}, toLinearGradient(theme.gradientColor[color]), effects.filter(isSupportedEffect).reduce((acc, effect) => {
530
+ var _theme$effect$effect2;
531
+
532
+ return _extends({}, acc, onEffectPseudo(effect, _extends({}, toLinearGradient(applyEffectToGradient((_theme$effect$effect2 = theme.effect[effect]) != null ? _theme$effect$effect2 : [])(theme.gradientColor[color])))));
533
+ }, {}));
534
+ }
535
+ });
536
+ };
537
+ /**
538
+ * @see https://developer.mozilla.org/ja/docs/Web/CSS/:focus-visible#selectively_showing_the_focus_indicator
539
+ */
540
+
541
+
542
+ const onFocus = css => ({
543
+ [notDisabledSelector]: {
544
+ '&:focus, &:active': _extends({
545
+ outline: 'none'
546
+ }, css),
547
+ '&:focus:not(:focus-visible), &:active:not(:focus-visible)': {
548
+ outline: 'none'
549
+ },
550
+ '&:focus-visible': _extends({
551
+ outline: 'none'
552
+ }, css)
553
+ }
554
+ });
555
+
556
+ const outlineCss = (weight, color) => ({
557
+ boxShadow: `0 0 0 ${px(weight)} ${color}`
558
+ });
559
+
560
+ const createOutlineColorCss = theme => (variant, modifiers) => {
561
+ const weight = theme.outline[variant].weight;
562
+ const color = theme.outline[variant].color;
563
+ return internal(() => modifiers.includes('focus') ? onFocus(outlineCss(weight, color)) : {
564
+ '&&': {
565
+ [notDisabledSelector]: outlineCss(weight, color)
566
+ }
567
+ }, {
568
+ boxShadowTransition: true
569
+ });
570
+ };
571
+
572
+ const overlayElement = {
573
+ content: "''",
574
+ display: 'block',
575
+ position: 'absolute',
576
+ width: '100%',
577
+ height: '100%',
578
+ top: 0,
579
+ left: 0
580
+ }; // half-leadingをキャンセルするとき && 垂直方向のpaddingが無い時
581
+ // -> before/afterを入れる
582
+
583
+ const useHalfLeadingCanceller = ({
584
+ cancelHalfLeadingPx,
585
+ hasVerticalPadding: _hasVerticalPadding = false
586
+ }) => cancelHalfLeadingPx !== undefined && !_hasVerticalPadding;
587
+
588
+ const createTypographyCss = theme => (size, options = {}) => {
589
+ const {
590
+ preserveHalfLeading = false,
591
+ monospace = false,
592
+ bold = false
593
+ } = options;
594
+ const descriptor = theme.typography.size[size];
595
+ const margin = -halfLeading(descriptor);
596
+ return internal(context => _extends({
597
+ fontSize: px(descriptor.fontSize),
598
+ lineHeight: px(descriptor.lineHeight)
599
+ }, monospace && {
600
+ fontFamily: 'monospace'
601
+ }, bold && {
602
+ fontWeight: 'bold'
603
+ }, useHalfLeadingCanceller(context) && {
604
+ // prevent margin collapsing
605
+ display: 'flow-root',
606
+ // cancel half-leading with negative margin
607
+ '&::before': _extends({}, leadingCancel, {
608
+ marginTop: px(margin)
609
+ }),
610
+ '&::after': _extends({}, leadingCancel, {
611
+ marginBottom: px(margin)
612
+ })
613
+ }), !preserveHalfLeading ? {
614
+ cancelHalfLeadingPx: margin
615
+ } : {});
616
+ };
617
+
618
+ const leadingCancel = {
619
+ display: 'block',
620
+ width: 0,
621
+ height: 0,
622
+ content: `''`
623
+ };
624
+
625
+ function spacingProperty(property, direction) {
626
+ return `${property}-${direction}`;
627
+ }
628
+
629
+ const createSpacingCss = theme => (property, modifiers) => {
630
+ const {
631
+ top,
632
+ right,
633
+ bottom,
634
+ left
635
+ } = modifiers.reduce((acc, [direction, size]) => {
636
+ if (direction === 'all') {
637
+ acc.top = size;
638
+ acc.right = size;
639
+ acc.bottom = size;
640
+ acc.left = size;
641
+ } else if (direction === 'vertical') {
642
+ acc.top = size;
643
+ acc.bottom = size;
644
+ } else if (direction === 'horizontal') {
645
+ acc.right = size;
646
+ acc.left = size;
647
+ } else {
648
+ acc[direction] = size;
649
+ }
650
+
651
+ return acc;
652
+ }, {});
653
+ const hasVerticalPadding = property === 'padding' && top !== undefined && bottom !== undefined && top !== 'auto' && bottom !== 'auto';
654
+ return internal(({
655
+ cancelHalfLeadingPx: _cancelHalfLeadingPx = 0
656
+ }) => _extends({}, top !== undefined && {
657
+ [spacingProperty(property, 'top')]: top === 'auto' ? 'auto' : px(theme.spacing[top] + (hasVerticalPadding ? _cancelHalfLeadingPx : 0))
658
+ }, bottom !== undefined && {
659
+ [spacingProperty(property, 'bottom')]: bottom === 'auto' ? 'auto' : px(theme.spacing[bottom] + (hasVerticalPadding ? _cancelHalfLeadingPx : 0))
660
+ }, right !== undefined && {
661
+ [spacingProperty(property, 'right')]: right === 'auto' ? 'auto' : px(theme.spacing[right])
662
+ }, left !== undefined && {
663
+ [spacingProperty(property, 'left')]: left === 'auto' ? 'auto' : px(theme.spacing[left])
664
+ }), hasVerticalPadding ? {
665
+ hasVerticalPadding: true
666
+ } : {});
667
+ };
668
+
669
+ const createFixedPxCss = theme => (property, size) => internal(() => ({
670
+ [property]: size === 'auto' ? 'auto' : px(theme.spacing[size])
671
+ }));
672
+
673
+ const createFixedRelativeCss = _theme => (property, amount) => internal(() => ({
674
+ [property]: amount
675
+ }));
676
+
677
+ const createFixedColumnCss = theme => (property, span) => internal(() => ({
678
+ [property]: px(columnSystem(span, theme.grid.unit.column, theme.grid.unit.gutter))
679
+ }));
680
+
681
+ const createElementEffectCss = theme => (effects = []) => internal(() => effects.filter(isSupportedEffect).reduce((acc, effect) => {
682
+ var _theme$elementEffect$, _theme$elementEffect$2;
683
+
684
+ return _extends({}, acc, onEffectPseudo(effect, {
685
+ 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()
686
+ }));
687
+ }, {}));
688
+
689
+ function borderProperty(direction) {
690
+ return `border-${direction}`;
691
+ }
692
+
693
+ function borderShorthand(color) {
694
+ return `solid 1px ${color}`;
695
+ }
696
+
697
+ const createBorderCss = theme => (variant, directions) => {
698
+ const all = directions.length === 0;
699
+ const value = borderShorthand(theme.border[variant].color);
700
+ return internal(() => _extends({}, all ? {
701
+ border: value
702
+ } : directions.reduce((acc, direction) => _extends({}, acc, {
703
+ [borderProperty(direction)]: value
704
+ }), {})));
705
+ };
706
+
707
+ const createBorderRadiusCss = theme => size => internal(() => ({
708
+ borderRadius: px(theme.borderRadius[size])
709
+ }));
710
+
711
+ const commonSpec = _theme => {
712
+ const duration = dur(TRANSITION_DURATION);
713
+
714
+ const transition = property => ({
715
+ transition: property.map(v => `${duration} ${v}`).join(', ')
716
+ });
717
+
718
+ return internal(({
719
+ colorTransition: _colorTransition = false,
720
+ backgroundColorTransition: _backgroundColorTransition = false,
721
+ boxShadowTransition: _boxShadowTransition = false
722
+ }) => transition([_colorTransition ? 'color' : null, _backgroundColorTransition ? 'background-color' : null, _boxShadowTransition ? 'box-shadow' : null].filter(isPresent)));
723
+ };
724
+
725
+ const internalSym = Symbol('internal');
726
+
727
+ function internal(operation, context = {}) {
728
+ return {
729
+ [internalSym]: {
730
+ operation,
731
+ context
732
+ }
733
+ };
734
+ }
735
+
736
+ const nonBlank = value => isPresent(value) && value !== false;
737
+ /**
738
+ * `theme(o => [...])` の `theme` ユーティリティを構築する
739
+ *
740
+ * @param _styled styled-componnets の `styled` そのもの (型推論のために用いられる)
741
+ *
742
+ * @example
743
+ *
744
+ * import styled from 'styled-components'
745
+ * const theme = createTheme(styled)
746
+ *
747
+ * @example
748
+ *
749
+ * const theme = createTheme<DefaultTheme>()
750
+ */
751
+
752
+
753
+ function createTheme(_styled) {
754
+ // `theme(o => [...])` の `o` の部分の型推論のためだけに使う意味のない変数
755
+ // Tを型変数のまま渡してcreateThemeが呼ばれるまで型の具象化が行われないようにする
756
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
757
+ builder({}, true); // ランタイムの `theme(o => [...])` のインターフェースを構築する
758
+
759
+
760
+ return ( // ユーザー定義
761
+ spec) => ({
762
+ theme
763
+ }) => {
764
+ if (theme == null) {
765
+ // テーマが入っていない場合は復旧不可能なのでエラーにする
766
+ throw new Error('`theme` is invalid. `<ThemeProvider>` is not likely mounted.');
767
+ } // styled-componentsのランタイムから受け取ったthemeオブジェクトをbuilderに食わせて`o`をつくる
768
+ // さらに、ユーザー定義にbuilderが構築した`o`を食わせる
769
+ // (`o`を一時変数に入れてしまうと型Tの具象化が行われるので関数合成を優先する)
770
+
771
+
772
+ const rawSpecDescriptor = spec(builder(theme)); // ユーザー定義の配列を整形
773
+
774
+ const specDescriptor = [...(Array.isArray(rawSpecDescriptor) ? rawSpecDescriptor : [rawSpecDescriptor]), commonSpec()].filter(nonBlank); // 1パス目
775
+ // 全ユーザー定義を舐めて相互に影響し合う定義をチェックし、その結果(コンテキスト)を取得
776
+
777
+ const context = specDescriptor.reduce((acc, v) => _extends({}, acc, v[internalSym].context), {}); // 2パス目
778
+ // コンテキストを見ながら最適化されたCSSを構築
779
+
780
+ return specDescriptor.map(v => v[internalSym].operation(context));
781
+ };
782
+ }
783
+
784
+ export { SetThemeScript, TokenInjector, createTheme, getThemeSync, prefersColorScheme, themeSelector, themeSetter, useLocalStorage, useMedia, useTheme, useThemeSetter };
21
785
  //# sourceMappingURL=index.modern.js.map