@charcoal-ui/theme 5.0.0-beta.3 → 5.0.0-beta.5

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["light: CharcoalTheme","dark: CharcoalTheme"],"sources":["../src/default.ts"],"sourcesContent":["import rgba from 'polished/lib/color/rgba'\nimport { CharcoalTheme } from './theme'\nimport {\n BORDER_RADIUS,\n BREAKPOINT,\n COLUMN_UNIT,\n GUTTER_UNIT,\n SPACING,\n TYPOGRAPHY_SIZE,\n} from '@charcoal-ui/foundation'\nimport { applyEffect } from '@charcoal-ui/utils'\n\nconst outlineEffect = {\n type: 'opacity',\n opacity: 0.32,\n} as const\n\nconst assertive = '#ff2b00'\nconst brand = '#0096fa'\nconst borderForLight = rgba('#000000', 0.08)\nconst borderForDark = rgba('#ffffff', 0.12)\n\nconst common = {\n typography: {\n size: TYPOGRAPHY_SIZE,\n },\n spacing: SPACING,\n grid: {\n unit: {\n column: COLUMN_UNIT,\n gutter: GUTTER_UNIT,\n },\n },\n borderRadius: BORDER_RADIUS,\n transition: {\n default: {\n duration: 0.2,\n },\n },\n breakpoint: {\n screen1: BREAKPOINT[6],\n screen2: BREAKPOINT[8],\n screen3: BREAKPOINT[10],\n screen4: BREAKPOINT[12],\n },\n gradientColor: {\n surface5: [\n { color: rgba('#000000', 0.32), ratio: 0 },\n { color: rgba('#000000', 0), ratio: 100 },\n ],\n callToAction: [\n { color: '#d1ff1a', ratio: 0 },\n { color: '#1ad1ff', ratio: 100 },\n ],\n },\n outline: {\n default: {\n color: applyEffect(brand, outlineEffect),\n weight: 4,\n },\n assertive: {\n color: applyEffect(assertive, outlineEffect),\n weight: 4,\n },\n },\n elementEffect: {\n disabled: {\n type: 'opacity',\n opacity: 0.32,\n },\n },\n} as const\n\nexport const light: CharcoalTheme = {\n ...common,\n effect: {\n hover: {\n type: 'alpha',\n color: rgba('#000000', 0.04), // surface3\n },\n press: {\n type: 'alpha',\n color: rgba('#000000', 0.16), // surface10\n },\n },\n color: {\n // TODO: colors should be picked from foundation color palette\n transparent: rgba('#000000', 0),\n background1: '#ffffff',\n background2: '#f5f5f5',\n icon6: rgba('#ffffff', 0.28),\n link1: '#3d7699',\n link2: rgba('#ffffff', 0.36),\n surface1: '#ffffff',\n surface2: rgba('#000000', 0.02),\n surface3: rgba('#000000', 0.04),\n surface4: rgba('#000000', 0.32),\n surface6: rgba('#000000', 0.88),\n surface7: rgba('#000000', 0.02),\n surface8: rgba('#000000', 0.88),\n surface9: '#ffffff',\n surface10: rgba('#000000', 0.16),\n text1: '#1f1f1f',\n text2: '#474747',\n text3: '#858585',\n text4: '#adadad',\n text5: '#ffffff',\n brand,\n assertive,\n warning: '#ffaf0f',\n success: '#b1cc29',\n updatedItem: rgba(0, 150, 250, 0.04),\n border: borderForLight,\n },\n border: {\n default: {\n color: borderForLight,\n },\n },\n}\n\nexport const dark: CharcoalTheme = {\n ...common,\n effect: {\n hover: {\n type: 'alpha',\n color: rgba('#ffffff', 0.12), // surface3\n },\n press: {\n type: 'alpha',\n color: rgba('#ffffff', 0.2), // surface10\n },\n },\n color: {\n transparent: rgba('#000000', 0),\n background1: '#1f1f1f',\n background2: '#000000',\n icon6: light.color.icon6,\n link1: '#669FC2',\n link2: light.color.link2,\n surface1: '#1f1f1f',\n surface2: rgba('#000000', 0.16),\n surface3: rgba('#ffffff', 0.12),\n surface4: light.color.surface4,\n surface6: rgba('#ffffff', 0.12),\n surface7: rgba('#000000', 0),\n surface8: light.color.surface8,\n surface9: '#333333',\n surface10: rgba('#ffffff', 0.2),\n text1: '#f5f5f5',\n text2: '#d6d6d6',\n text3: '#858585',\n text4: '#5c5c5c',\n text5: '#f5f5f5',\n brand,\n assertive,\n warning: light.color.warning,\n success: light.color.success,\n updatedItem: rgba(0, 150, 250, 0.12),\n border: borderForDark,\n },\n border: {\n default: {\n color: borderForDark,\n },\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["light: CharcoalTheme","dark: CharcoalTheme"],"sources":["../src/default.ts"],"sourcesContent":["/** This file is auto generated. DO NOT EDIT BY HAND. */\nimport { CharcoalTheme } from './theme'\n\nconst common = {\n borderRadius: {\n '4': 4,\n '8': 8,\n '16': 16,\n '24': 24,\n none: 0,\n oval: 999999,\n },\n breakpoint: {\n screen1: 744,\n screen2: 952,\n screen3: 1160,\n screen4: 1368,\n },\n elementEffect: {\n disabled: {\n opacity: 0.32,\n type: 'opacity',\n },\n },\n gradientColor: {\n callToAction: [\n {\n color: '#d1ff1a',\n ratio: 0,\n },\n {\n color: '#1ad1ff',\n ratio: 100,\n },\n ],\n surface5: [\n {\n color: 'rgba(0,0,0,0.32)',\n ratio: 0,\n },\n {\n color: 'rgba(0,0,0,0)',\n ratio: 100,\n },\n ],\n },\n grid: {\n unit: {\n column: 80,\n gutter: 24,\n },\n },\n outline: {\n assertive: {\n color: 'rgba(255,43,0,0.32)',\n weight: 4,\n },\n default: {\n color: 'rgba(0,150,250,0.32)',\n weight: 4,\n },\n },\n spacing: {\n '0': 0,\n '4': 4,\n '8': 8,\n '16': 16,\n '24': 24,\n '40': 40,\n '64': 64,\n '104': 104,\n '168': 168,\n '272': 272,\n '440': 440,\n },\n transition: {\n default: {\n duration: 0.2,\n },\n },\n typography: {\n size: {\n '12': {\n fontSize: 12,\n lineHeight: 20,\n },\n '14': {\n fontSize: 14,\n lineHeight: 22,\n },\n '16': {\n fontSize: 16,\n lineHeight: 24,\n },\n '20': {\n fontSize: 20,\n lineHeight: 28,\n },\n '32': {\n fontSize: 32,\n lineHeight: 40,\n },\n },\n },\n} as const\n\nexport const light: CharcoalTheme = {\n ...common,\n ...{\n border: {\n default: {\n color: 'rgba(0,0,0,0.08)',\n },\n },\n color: {\n assertive: '#ff2b00',\n background1: '#ffffff',\n background2: '#f5f5f5',\n border: 'rgba(0,0,0,0.08)',\n brand: '#0096fa',\n icon6: 'rgba(255,255,255,0.28)',\n link1: '#3d7699',\n link2: 'rgba(255,255,255,0.36)',\n success: '#b1cc29',\n surface1: '#ffffff',\n surface10: 'rgba(0,0,0,0.16)',\n surface2: 'rgba(0,0,0,0.02)',\n surface3: 'rgba(0,0,0,0.04)',\n surface4: 'rgba(0,0,0,0.32)',\n surface6: 'rgba(0,0,0,0.88)',\n surface7: 'rgba(0,0,0,0.02)',\n surface8: 'rgba(0,0,0,0.88)',\n surface9: '#ffffff',\n text1: '#1f1f1f',\n text2: '#474747',\n text3: '#858585',\n text4: '#adadad',\n text5: '#ffffff',\n transparent: 'rgba(0,0,0,0)',\n updatedItem: 'rgba(0,150,250,0.04)',\n warning: '#ffaf0f',\n },\n effect: {\n hover: {\n color: 'rgba(0,0,0,0.04)',\n type: 'alpha',\n },\n press: {\n color: 'rgba(0,0,0,0.16)',\n type: 'alpha',\n },\n },\n },\n}\n\nexport const dark: CharcoalTheme = {\n ...common,\n ...{\n border: {\n default: {\n color: 'rgba(255,255,255,0.12)',\n },\n },\n color: {\n assertive: '#ff2b00',\n background1: '#1f1f1f',\n background2: '#000000',\n border: 'rgba(255,255,255,0.12)',\n brand: '#0096fa',\n icon6: 'rgba(255,255,255,0.28)',\n link1: '#669FC2',\n link2: 'rgba(255,255,255,0.36)',\n success: '#b1cc29',\n surface1: '#1f1f1f',\n surface10: 'rgba(255,255,255,0.2)',\n surface2: 'rgba(0,0,0,0.16)',\n surface3: 'rgba(255,255,255,0.12)',\n surface4: 'rgba(0,0,0,0.32)',\n surface6: 'rgba(255,255,255,0.12)',\n surface7: 'rgba(0,0,0,0)',\n surface8: 'rgba(0,0,0,0.88)',\n surface9: '#333333',\n text1: '#f5f5f5',\n text2: '#d6d6d6',\n text3: '#858585',\n text4: '#5c5c5c',\n text5: '#f5f5f5',\n transparent: 'rgba(0,0,0,0)',\n updatedItem: 'rgba(0,150,250,0.12)',\n warning: '#ffaf0f',\n },\n effect: {\n hover: {\n color: 'rgba(255,255,255,0.12)',\n type: 'alpha',\n },\n press: {\n color: 'rgba(255,255,255,0.2)',\n type: 'alpha',\n },\n },\n },\n}\n"],"mappings":";AAGA,MAAM,SAAS;CACb,cAAc;EACZ,KAAK;EACL,KAAK;EACL,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACP;CACD,YAAY;EACV,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACV;CACD,eAAe,EACb,UAAU;EACR,SAAS;EACT,MAAM;EACP,EACF;CACD,eAAe;EACb,cAAc,CACZ;GACE,OAAO;GACP,OAAO;GACR,EACD;GACE,OAAO;GACP,OAAO;GACR,CACF;EACD,UAAU,CACR;GACE,OAAO;GACP,OAAO;GACR,EACD;GACE,OAAO;GACP,OAAO;GACR,CACF;EACF;CACD,MAAM,EACJ,MAAM;EACJ,QAAQ;EACR,QAAQ;EACT,EACF;CACD,SAAS;EACP,WAAW;GACT,OAAO;GACP,QAAQ;GACT;EACD,SAAS;GACP,OAAO;GACP,QAAQ;GACT;EACF;CACD,SAAS;EACP,KAAK;EACL,KAAK;EACL,KAAK;EACL,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACR;CACD,YAAY,EACV,SAAS,EACP,UAAU,IACX,EACF;CACD,YAAY,EACV,MAAM;EACJ,MAAM;GACJ,UAAU;GACV,YAAY;GACb;EACD,MAAM;GACJ,UAAU;GACV,YAAY;GACb;EACD,MAAM;GACJ,UAAU;GACV,YAAY;GACb;EACD,MAAM;GACJ,UAAU;GACV,YAAY;GACb;EACD,MAAM;GACJ,UAAU;GACV,YAAY;GACb;EACF,EACF;CACF;AAED,MAAaA,QAAuB;CAClC,GAAG;CAED,QAAQ,EACN,SAAS,EACP,OAAO,oBACR,EACF;CACD,OAAO;EACL,WAAW;EACX,aAAa;EACb,aAAa;EACb,QAAQ;EACR,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,SAAS;EACT,UAAU;EACV,WAAW;EACX,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,aAAa;EACb,aAAa;EACb,SAAS;EACV;CACD,QAAQ;EACN,OAAO;GACL,OAAO;GACP,MAAM;GACP;EACD,OAAO;GACL,OAAO;GACP,MAAM;GACP;EACF;CAEJ;AAED,MAAaC,OAAsB;CACjC,GAAG;CAED,QAAQ,EACN,SAAS,EACP,OAAO,0BACR,EACF;CACD,OAAO;EACL,WAAW;EACX,aAAa;EACb,aAAa;EACb,QAAQ;EACR,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,SAAS;EACT,UAAU;EACV,WAAW;EACX,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,aAAa;EACb,aAAa;EACb,SAAS;EACV;CACD,QAAQ;EACN,OAAO;GACL,OAAO;GACP,MAAM;GACP;EACD,OAAO;GACL,OAAO;GACP,MAAM;GACP;EACF;CAEJ"}
@@ -1,8 +1,30 @@
1
- const require_chunk = require('../chunk-CUT6urMc.cjs');
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
2
24
  let deepmerge = require("deepmerge");
3
- deepmerge = require_chunk.__toESM(deepmerge);
25
+ deepmerge = __toESM(deepmerge);
4
26
  let change_case_all = require("change-case-all");
5
- change_case_all = require_chunk.__toESM(change_case_all);
27
+ change_case_all = __toESM(change_case_all);
6
28
 
7
29
  //#region src/unstable-token-object/reference-token.ts
8
30
  const isReferenceToken = (value) => value.startsWith("{") && value.endsWith("}");
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["value"],"sources":["../../src/unstable-token-object/reference-token.ts","../../src/unstable-token-object/helpers/is-empty-array.ts","../../src/unstable-token-object/helpers/nest-object.ts","../../src/unstable-token-object/to-token-object.ts","../../src/unstable-token-object/helpers/changecase-keys.ts","../../src/unstable-token-object/index.ts"],"sourcesContent":["import { TokenDictionary, Tokens } from './types'\n\nexport type ReferenceToken = `{${string}}`\n\nconst isReferenceToken = (value: string): value is ReferenceToken =>\n value.startsWith('{') && value.endsWith('}')\n\nconst parseReferenceToken = (\n value: ReferenceToken\n): [category: string, key: string] => {\n const [category, key] = value.slice(1, -1).split('.')\n\n return [category, key]\n}\n\nexport const createReferenceTokenResolver = <T extends TokenDictionary>(\n tokenDictionary: T,\n baseTokenDictionary: TokenDictionary\n): ((value: string) => string) => {\n const resolver = (value: string): string => {\n if (!isReferenceToken(value)) return value\n\n const [category, tokenKey] = parseReferenceToken(value)\n const baseTokens = baseTokenDictionary[category] as Tokens | undefined\n\n return resolver(\n (baseTokens?.[tokenKey] ?? tokenDictionary[category][tokenKey]).value\n )\n }\n\n return resolver\n}\n","export const isNonEmptyArray = <T>(arr: T[]): arr is [T, ...T[]] =>\n arr.length > 0\n","import { isNonEmptyArray } from './is-empty-array'\n\ntype MakeNestObject<P extends readonly string[], T> = P extends [\n infer Head,\n ...infer Tail\n]\n ? Head extends string\n ? Tail extends string[]\n ? {\n [K in Head]: MakeNestObject<Tail, T>\n }\n : { [K in Head]: T }\n : T\n : T\n\nexport const nestObject = <P extends [string, ...string[]], T>(\n path: P,\n value: T\n): MakeNestObject<P, T> => {\n if (!isNonEmptyArray(path)) throw new Error('Path must be a non-empty array')\n\n const [key, ...rest] = path\n if (!isNonEmptyArray(rest)) return { [key]: value } as MakeNestObject<P, T>\n\n return {\n [key]: nestObject(rest, value),\n } as MakeNestObject<P, T>\n}\n","import deepmerge from 'deepmerge'\nimport { isNonEmptyArray } from './helpers/is-empty-array'\nimport { nestObject } from './helpers/nest-object'\nimport { Tokens, TokenObject } from './types'\n\nexport const toTokenObject = <T extends Tokens>(tokens: T): TokenObject<T> => {\n let result = {}\n for (const key in tokens) {\n const { value } = tokens[key]\n const splitted = key.split('/')\n if (!isNonEmptyArray(splitted)) continue\n\n const v = nestObject(splitted, value)\n result = deepmerge(result, v)\n }\n\n return result as TokenObject<T>\n}\n","import { camelCase } from 'change-case-all'\n\nconst isObject = (value: unknown): value is Record<string, unknown> => {\n if (value instanceof RegExp) return false\n if (value instanceof Date) return false\n if (value instanceof Error) return false\n\n return typeof value === 'object' && value !== null\n}\n\ntype CamelCase<\n T extends string,\n D extends string = '-'\n> = T extends `${infer A}${D}${infer B}`\n ? `${Lowercase<A>}${Capitalize<CamelCase<B, D>>}`\n : T\n\ntype CamelCaseKeys<\n T extends Record<string, unknown>,\n D extends string = '-'\n> = {\n [K in keyof T as CamelCase<K & string, D>]: T[K] extends Record<\n string,\n unknown\n >\n ? CamelCaseKeys<T[K], D>\n : T[K]\n}\n\nexport const camelCaseKeys = <\n T extends Record<string, unknown>,\n Delimiter extends string = '-'\n>(\n obj: T\n): CamelCaseKeys<T, Delimiter> => {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => [\n camelCase(key),\n isObject(value) ? camelCaseKeys(value) : value,\n ])\n ) as CamelCaseKeys<T, Delimiter>\n}\n","import { createReferenceTokenResolver } from './reference-token'\nimport { toTokenObject } from './to-token-object'\nimport type { TokenObject, TokenDictionary, TokenValue } from './types'\n\nimport { kebabCase } from 'change-case-all'\nexport { camelCaseKeys } from './helpers/changecase-keys'\n\nexport const createTokenObject = <T extends TokenDictionary>(\n tokenDictionary: T,\n baseTokenDictionary: TokenDictionary\n): { [K in keyof T]: TokenObject<T[K]> } => {\n const result = {} as { [K in keyof T]: TokenObject<T[K]> }\n const referenceTokenResolver = createReferenceTokenResolver(\n tokenDictionary,\n baseTokenDictionary\n )\n\n for (const category in tokenDictionary) {\n const value = tokenDictionary[category]\n\n // category ごとに template を展開していく\n const resolvedTokens = Object.fromEntries(\n Object.entries(value).map(([key, value]) => [\n key,\n { value: referenceTokenResolver(value.value) } satisfies TokenValue,\n ])\n ) as typeof value\n\n result[category] = toTokenObject(resolvedTokens)\n }\n\n return result\n}\n\nexport const createCSSTokenObject = <T extends TokenDictionary>(\n tokenDictionary: T,\n format: (value: string) => string = (value) => value\n): { [K in keyof T]: TokenObject<T[K]> } => {\n const result = {} as { [K in keyof T]: TokenObject<T[K]> }\n\n for (const category in tokenDictionary) {\n const value = tokenDictionary[category]\n\n // category ごとに template を展開していく\n const resolvedTokens = Object.fromEntries(\n Object.entries(value).map(([key]) => [\n key,\n {\n value: `var(--${format(\n [category, ...key.split('/')].map((x) => kebabCase(x)).join('-')\n )})`,\n } satisfies TokenValue,\n ])\n ) as typeof value\n\n result[category] = toTokenObject(resolvedTokens)\n }\n\n return result\n}\n"],"mappings":";;;;;;;AAIA,MAAM,oBAAoB,UACxB,MAAM,WAAW,IAAI,IAAI,MAAM,SAAS,IAAI;AAE9C,MAAM,uBACJ,UACoC;CACpC,MAAM,CAAC,UAAU,OAAO,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI;AAErD,QAAO,CAAC,UAAU,IAAI;;AAGxB,MAAa,gCACX,iBACA,wBACgC;CAChC,MAAM,YAAY,UAA0B;AAC1C,MAAI,CAAC,iBAAiB,MAAM,CAAE,QAAO;EAErC,MAAM,CAAC,UAAU,YAAY,oBAAoB,MAAM;EACvD,MAAM,aAAa,oBAAoB;AAEvC,SAAO,UACJ,aAAa,aAAa,gBAAgB,UAAU,WAAW,MACjE;;AAGH,QAAO;;;;;AC9BT,MAAa,mBAAsB,QACjC,IAAI,SAAS;;;;ACcf,MAAa,cACX,MACA,UACyB;AACzB,KAAI,CAAC,gBAAgB,KAAK,CAAE,OAAM,IAAI,MAAM,iCAAiC;CAE7E,MAAM,CAAC,KAAK,GAAG,QAAQ;AACvB,KAAI,CAAC,gBAAgB,KAAK,CAAE,QAAO,GAAG,MAAM,OAAO;AAEnD,QAAO,GACJ,MAAM,WAAW,MAAM,MAAM,EAC/B;;;;;ACrBH,MAAa,iBAAmC,WAA8B;CAC5E,IAAI,SAAS,EAAE;AACf,MAAK,MAAM,OAAO,QAAQ;EACxB,MAAM,EAAE,UAAU,OAAO;EACzB,MAAM,WAAW,IAAI,MAAM,IAAI;AAC/B,MAAI,CAAC,gBAAgB,SAAS,CAAE;EAEhC,MAAM,IAAI,WAAW,UAAU,MAAM;AACrC,kCAAmB,QAAQ,EAAE;;AAG/B,QAAO;;;;;ACdT,MAAM,YAAY,UAAqD;AACrE,KAAI,iBAAiB,OAAQ,QAAO;AACpC,KAAI,iBAAiB,KAAM,QAAO;AAClC,KAAI,iBAAiB,MAAO,QAAO;AAEnC,QAAO,OAAO,UAAU,YAAY,UAAU;;AAsBhD,MAAa,iBAIX,QACgC;AAChC,QAAO,OAAO,YACZ,OAAO,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,WAAW,gCAC9B,IAAI,EACd,SAAS,MAAM,GAAG,cAAc,MAAM,GAAG,MAC1C,CAAC,CACH;;;;;ACjCH,MAAa,qBACX,iBACA,wBAC0C;CAC1C,MAAM,SAAS,EAAE;CACjB,MAAM,yBAAyB,6BAC7B,iBACA,oBACD;AAED,MAAK,MAAM,YAAY,iBAAiB;EACtC,MAAM,QAAQ,gBAAgB;AAU9B,SAAO,YAAY,cAPI,OAAO,YAC5B,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAKA,aAAW,CAC1C,KACA,EAAE,OAAO,uBAAuBA,QAAM,MAAM,EAAE,CAC/C,CAAC,CACH,CAE+C;;AAGlD,QAAO;;AAGT,MAAa,wBACX,iBACA,UAAqC,UAAU,UACL;CAC1C,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,YAAY,iBAAiB;EACtC,MAAM,QAAQ,gBAAgB;AAc9B,SAAO,YAAY,cAXI,OAAO,YAC5B,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,SAAS,CACnC,KACA,EACE,OAAO,SAAS,OACd,CAAC,UAAU,GAAG,IAAI,MAAM,IAAI,CAAC,CAAC,KAAK,qCAAgB,EAAE,CAAC,CAAC,KAAK,IAAI,CACjE,CAAC,IACH,CACF,CAAC,CACH,CAE+C;;AAGlD,QAAO"}
1
+ {"version":3,"file":"index.cjs","names":["value"],"sources":["../../src/unstable-token-object/reference-token.ts","../../src/unstable-token-object/helpers/is-empty-array.ts","../../src/unstable-token-object/helpers/nest-object.ts","../../src/unstable-token-object/to-token-object.ts","../../src/unstable-token-object/helpers/changecase-keys.ts","../../src/unstable-token-object/index.ts"],"sourcesContent":["import { TokenDictionary, Tokens } from './types'\n\nexport type ReferenceToken = `{${string}}`\n\nconst isReferenceToken = (value: string): value is ReferenceToken =>\n value.startsWith('{') && value.endsWith('}')\n\nconst parseReferenceToken = (\n value: ReferenceToken\n): [category: string, key: string] => {\n const [category, key] = value.slice(1, -1).split('.')\n\n return [category, key]\n}\n\nexport const createReferenceTokenResolver = <T extends TokenDictionary>(\n tokenDictionary: T,\n baseTokenDictionary: TokenDictionary\n): ((value: string) => string) => {\n const resolver = (value: string): string => {\n if (!isReferenceToken(value)) return value\n\n const [category, tokenKey] = parseReferenceToken(value)\n const baseTokens = baseTokenDictionary[category] as Tokens | undefined\n\n return resolver(\n (baseTokens?.[tokenKey] ?? tokenDictionary[category][tokenKey]).value\n )\n }\n\n return resolver\n}\n","export const isNonEmptyArray = <T>(arr: T[]): arr is [T, ...T[]] =>\n arr.length > 0\n","import { isNonEmptyArray } from './is-empty-array'\n\ntype MakeNestObject<P extends readonly string[], T> = P extends [\n infer Head,\n ...infer Tail\n]\n ? Head extends string\n ? Tail extends string[]\n ? {\n [K in Head]: MakeNestObject<Tail, T>\n }\n : { [K in Head]: T }\n : T\n : T\n\nexport const nestObject = <P extends [string, ...string[]], T>(\n path: P,\n value: T\n): MakeNestObject<P, T> => {\n if (!isNonEmptyArray(path)) throw new Error('Path must be a non-empty array')\n\n const [key, ...rest] = path\n if (!isNonEmptyArray(rest)) return { [key]: value } as MakeNestObject<P, T>\n\n return {\n [key]: nestObject(rest, value),\n } as MakeNestObject<P, T>\n}\n","import deepmerge from 'deepmerge'\nimport { isNonEmptyArray } from './helpers/is-empty-array'\nimport { nestObject } from './helpers/nest-object'\nimport { Tokens, TokenObject } from './types'\n\nexport const toTokenObject = <T extends Tokens>(tokens: T): TokenObject<T> => {\n let result = {}\n for (const key in tokens) {\n const { value } = tokens[key]\n const splitted = key.split('/')\n if (!isNonEmptyArray(splitted)) continue\n\n const v = nestObject(splitted, value)\n result = deepmerge(result, v)\n }\n\n return result as TokenObject<T>\n}\n","import { camelCase } from 'change-case-all'\n\nconst isObject = (value: unknown): value is Record<string, unknown> => {\n if (value instanceof RegExp) return false\n if (value instanceof Date) return false\n if (value instanceof Error) return false\n\n return typeof value === 'object' && value !== null\n}\n\ntype CamelCase<\n T extends string,\n D extends string = '-'\n> = T extends `${infer A}${D}${infer B}`\n ? `${Lowercase<A>}${Capitalize<CamelCase<B, D>>}`\n : T\n\ntype CamelCaseKeys<\n T extends Record<string, unknown>,\n D extends string = '-'\n> = {\n [K in keyof T as CamelCase<K & string, D>]: T[K] extends Record<\n string,\n unknown\n >\n ? CamelCaseKeys<T[K], D>\n : T[K]\n}\n\nexport const camelCaseKeys = <\n T extends Record<string, unknown>,\n Delimiter extends string = '-'\n>(\n obj: T\n): CamelCaseKeys<T, Delimiter> => {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => [\n camelCase(key),\n isObject(value) ? camelCaseKeys(value) : value,\n ])\n ) as CamelCaseKeys<T, Delimiter>\n}\n","import { createReferenceTokenResolver } from './reference-token'\nimport { toTokenObject } from './to-token-object'\nimport type { TokenObject, TokenDictionary, TokenValue } from './types'\n\nimport { kebabCase } from 'change-case-all'\nexport { camelCaseKeys } from './helpers/changecase-keys'\n\nexport const createTokenObject = <T extends TokenDictionary>(\n tokenDictionary: T,\n baseTokenDictionary: TokenDictionary\n): { [K in keyof T]: TokenObject<T[K]> } => {\n const result = {} as { [K in keyof T]: TokenObject<T[K]> }\n const referenceTokenResolver = createReferenceTokenResolver(\n tokenDictionary,\n baseTokenDictionary\n )\n\n for (const category in tokenDictionary) {\n const value = tokenDictionary[category]\n\n // category ごとに template を展開していく\n const resolvedTokens = Object.fromEntries(\n Object.entries(value).map(([key, value]) => [\n key,\n { value: referenceTokenResolver(value.value) } satisfies TokenValue,\n ])\n ) as typeof value\n\n result[category] = toTokenObject(resolvedTokens)\n }\n\n return result\n}\n\nexport const createCSSTokenObject = <T extends TokenDictionary>(\n tokenDictionary: T,\n format: (value: string) => string = (value) => value\n): { [K in keyof T]: TokenObject<T[K]> } => {\n const result = {} as { [K in keyof T]: TokenObject<T[K]> }\n\n for (const category in tokenDictionary) {\n const value = tokenDictionary[category]\n\n // category ごとに template を展開していく\n const resolvedTokens = Object.fromEntries(\n Object.entries(value).map(([key]) => [\n key,\n {\n value: `var(--${format(\n [category, ...key.split('/')].map((x) => kebabCase(x)).join('-')\n )})`,\n } satisfies TokenValue,\n ])\n ) as typeof value\n\n result[category] = toTokenObject(resolvedTokens)\n }\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,oBAAoB,UACxB,MAAM,WAAW,IAAI,IAAI,MAAM,SAAS,IAAI;AAE9C,MAAM,uBACJ,UACoC;CACpC,MAAM,CAAC,UAAU,OAAO,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI;AAErD,QAAO,CAAC,UAAU,IAAI;;AAGxB,MAAa,gCACX,iBACA,wBACgC;CAChC,MAAM,YAAY,UAA0B;AAC1C,MAAI,CAAC,iBAAiB,MAAM,CAAE,QAAO;EAErC,MAAM,CAAC,UAAU,YAAY,oBAAoB,MAAM;EACvD,MAAM,aAAa,oBAAoB;AAEvC,SAAO,UACJ,aAAa,aAAa,gBAAgB,UAAU,WAAW,MACjE;;AAGH,QAAO;;;;;AC9BT,MAAa,mBAAsB,QACjC,IAAI,SAAS;;;;ACcf,MAAa,cACX,MACA,UACyB;AACzB,KAAI,CAAC,gBAAgB,KAAK,CAAE,OAAM,IAAI,MAAM,iCAAiC;CAE7E,MAAM,CAAC,KAAK,GAAG,QAAQ;AACvB,KAAI,CAAC,gBAAgB,KAAK,CAAE,QAAO,GAAG,MAAM,OAAO;AAEnD,QAAO,GACJ,MAAM,WAAW,MAAM,MAAM,EAC/B;;;;;ACrBH,MAAa,iBAAmC,WAA8B;CAC5E,IAAI,SAAS,EAAE;AACf,MAAK,MAAM,OAAO,QAAQ;EACxB,MAAM,EAAE,UAAU,OAAO;EACzB,MAAM,WAAW,IAAI,MAAM,IAAI;AAC/B,MAAI,CAAC,gBAAgB,SAAS,CAAE;EAEhC,MAAM,IAAI,WAAW,UAAU,MAAM;AACrC,kCAAmB,QAAQ,EAAE;;AAG/B,QAAO;;;;;ACdT,MAAM,YAAY,UAAqD;AACrE,KAAI,iBAAiB,OAAQ,QAAO;AACpC,KAAI,iBAAiB,KAAM,QAAO;AAClC,KAAI,iBAAiB,MAAO,QAAO;AAEnC,QAAO,OAAO,UAAU,YAAY,UAAU;;AAsBhD,MAAa,iBAIX,QACgC;AAChC,QAAO,OAAO,YACZ,OAAO,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,WAAW,gCAC9B,IAAI,EACd,SAAS,MAAM,GAAG,cAAc,MAAM,GAAG,MAC1C,CAAC,CACH;;;;;ACjCH,MAAa,qBACX,iBACA,wBAC0C;CAC1C,MAAM,SAAS,EAAE;CACjB,MAAM,yBAAyB,6BAC7B,iBACA,oBACD;AAED,MAAK,MAAM,YAAY,iBAAiB;EACtC,MAAM,QAAQ,gBAAgB;AAU9B,SAAO,YAAY,cAPI,OAAO,YAC5B,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAKA,aAAW,CAC1C,KACA,EAAE,OAAO,uBAAuBA,QAAM,MAAM,EAAE,CAC/C,CAAC,CACH,CAE+C;;AAGlD,QAAO;;AAGT,MAAa,wBACX,iBACA,UAAqC,UAAU,UACL;CAC1C,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,YAAY,iBAAiB;EACtC,MAAM,QAAQ,gBAAgB;AAc9B,SAAO,YAAY,cAXI,OAAO,YAC5B,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,SAAS,CACnC,KACA,EACE,OAAO,SAAS,OACd,CAAC,UAAU,GAAG,IAAI,MAAM,IAAI,CAAC,CAAC,KAAK,qCAAgB,EAAE,CAAC,CAAC,KAAK,IAAI,CACjE,CAAC,IACH,CACF,CAAC,CACH,CAE+C;;AAGlD,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@charcoal-ui/theme",
3
- "version": "5.0.0-beta.3",
3
+ "version": "5.0.0-beta.5",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -40,14 +40,14 @@
40
40
  ],
41
41
  "devDependencies": {
42
42
  "@types/css": "^0.0.38",
43
- "css": "^3.0.0"
43
+ "css": "^3.0.0",
44
+ "polished": "^4.1.4"
44
45
  },
45
46
  "dependencies": {
46
47
  "change-case-all": "^2.1.0",
47
48
  "deepmerge": "^4.3.1",
48
- "polished": "^4.1.4",
49
- "@charcoal-ui/utils": "5.0.0-beta.3",
50
- "@charcoal-ui/foundation": "5.0.0-beta.3"
49
+ "@charcoal-ui/foundation": "5.0.0-beta.5",
50
+ "@charcoal-ui/utils": "5.0.0-beta.5"
51
51
  },
52
52
  "files": [
53
53
  "src",
@@ -0,0 +1,211 @@
1
+ import { rgba } from 'polished'
2
+ import prettier from 'prettier'
3
+ import { CharcoalTheme } from './theme'
4
+ import {
5
+ BORDER_RADIUS,
6
+ BREAKPOINT,
7
+ COLUMN_UNIT,
8
+ GUTTER_UNIT,
9
+ SPACING,
10
+ TYPOGRAPHY_SIZE,
11
+ } from '@charcoal-ui/foundation'
12
+ import { applyEffect } from '@charcoal-ui/utils'
13
+
14
+ const outlineEffect = {
15
+ type: 'opacity',
16
+ opacity: 0.32,
17
+ } as const
18
+
19
+ const assertive = '#ff2b00'
20
+ const brand = '#0096fa'
21
+ const borderForLight = rgba('#000000', 0.08)
22
+ const borderForDark = rgba('#ffffff', 0.12)
23
+
24
+ const common = {
25
+ typography: {
26
+ size: TYPOGRAPHY_SIZE,
27
+ },
28
+ spacing: SPACING,
29
+ grid: {
30
+ unit: {
31
+ column: COLUMN_UNIT,
32
+ gutter: GUTTER_UNIT,
33
+ },
34
+ },
35
+ borderRadius: BORDER_RADIUS,
36
+ transition: {
37
+ default: {
38
+ duration: 0.2,
39
+ },
40
+ },
41
+ breakpoint: {
42
+ screen1: BREAKPOINT[6],
43
+ screen2: BREAKPOINT[8],
44
+ screen3: BREAKPOINT[10],
45
+ screen4: BREAKPOINT[12],
46
+ },
47
+ gradientColor: {
48
+ surface5: [
49
+ { color: rgba('#000000', 0.32), ratio: 0 },
50
+ { color: rgba('#000000', 0), ratio: 100 },
51
+ ],
52
+ callToAction: [
53
+ { color: '#d1ff1a', ratio: 0 },
54
+ { color: '#1ad1ff', ratio: 100 },
55
+ ],
56
+ },
57
+ outline: {
58
+ default: {
59
+ color: applyEffect(brand, outlineEffect),
60
+ weight: 4,
61
+ },
62
+ assertive: {
63
+ color: applyEffect(assertive, outlineEffect),
64
+ weight: 4,
65
+ },
66
+ },
67
+ elementEffect: {
68
+ disabled: {
69
+ type: 'opacity',
70
+ opacity: 0.32,
71
+ },
72
+ },
73
+ } as const
74
+
75
+ const light: Omit<CharcoalTheme, keyof typeof common> = {
76
+ effect: {
77
+ hover: {
78
+ type: 'alpha',
79
+ color: rgba('#000000', 0.04), // surface3
80
+ },
81
+ press: {
82
+ type: 'alpha',
83
+ color: rgba('#000000', 0.16), // surface10
84
+ },
85
+ },
86
+ color: {
87
+ // TODO: colors should be picked from foundation color palette
88
+ transparent: rgba('#000000', 0),
89
+ background1: '#ffffff',
90
+ background2: '#f5f5f5',
91
+ icon6: rgba('#ffffff', 0.28),
92
+ link1: '#3d7699',
93
+ link2: rgba('#ffffff', 0.36),
94
+ surface1: '#ffffff',
95
+ surface2: rgba('#000000', 0.02),
96
+ surface3: rgba('#000000', 0.04),
97
+ surface4: rgba('#000000', 0.32),
98
+ surface6: rgba('#000000', 0.88),
99
+ surface7: rgba('#000000', 0.02),
100
+ surface8: rgba('#000000', 0.88),
101
+ surface9: '#ffffff',
102
+ surface10: rgba('#000000', 0.16),
103
+ text1: '#1f1f1f',
104
+ text2: '#474747',
105
+ text3: '#858585',
106
+ text4: '#adadad',
107
+ text5: '#ffffff',
108
+ brand,
109
+ assertive,
110
+ warning: '#ffaf0f',
111
+ success: '#b1cc29',
112
+ updatedItem: rgba(0, 150, 250, 0.04),
113
+ border: borderForLight,
114
+ },
115
+ border: {
116
+ default: {
117
+ color: borderForLight,
118
+ },
119
+ },
120
+ }
121
+
122
+ const dark: Omit<CharcoalTheme, keyof typeof common> = {
123
+ effect: {
124
+ hover: {
125
+ type: 'alpha',
126
+ color: rgba('#ffffff', 0.12), // surface3
127
+ },
128
+ press: {
129
+ type: 'alpha',
130
+ color: rgba('#ffffff', 0.2), // surface10
131
+ },
132
+ },
133
+ color: {
134
+ transparent: rgba('#000000', 0),
135
+ background1: '#1f1f1f',
136
+ background2: '#000000',
137
+ icon6: light.color.icon6,
138
+ link1: '#669FC2',
139
+ link2: light.color.link2,
140
+ surface1: '#1f1f1f',
141
+ surface2: rgba('#000000', 0.16),
142
+ surface3: rgba('#ffffff', 0.12),
143
+ surface4: light.color.surface4,
144
+ surface6: rgba('#ffffff', 0.12),
145
+ surface7: rgba('#000000', 0),
146
+ surface8: light.color.surface8,
147
+ surface9: '#333333',
148
+ surface10: rgba('#ffffff', 0.2),
149
+ text1: '#f5f5f5',
150
+ text2: '#d6d6d6',
151
+ text3: '#858585',
152
+ text4: '#5c5c5c',
153
+ text5: '#f5f5f5',
154
+ brand,
155
+ assertive,
156
+ warning: light.color.warning,
157
+ success: light.color.success,
158
+ updatedItem: rgba(0, 150, 250, 0.12),
159
+ border: borderForDark,
160
+ },
161
+ border: {
162
+ default: {
163
+ color: borderForDark,
164
+ },
165
+ },
166
+ }
167
+
168
+ // The MIT License (MIT)
169
+ // Copyright (c) 2023-present Fabio Spampinato
170
+ // https://github.com/fabiospampinato/json-sorted-stringify/blob/b4b87427d471ec4e5972489638dbba100d47ef18/src/index.ts
171
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
+ const sortReplacer = (_: string, value: any): any => {
173
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
174
+ const keys = Object.keys(value).sort()
175
+ const clone: Record<string, unknown> = {}
176
+
177
+ for (let i = 0, l = keys.length; i < l; i++) {
178
+ const key = keys[i]
179
+
180
+ clone[key] = value[key]
181
+ }
182
+
183
+ return clone
184
+ }
185
+
186
+ return value
187
+ }
188
+
189
+ it('writes default.ts', () => {
190
+ const code = `
191
+ /** This file is auto generated. DO NOT EDIT BY HAND. */
192
+ import { CharcoalTheme } from './theme'
193
+
194
+ const common = ${JSON.stringify(common, sortReplacer, 2)} as const;
195
+
196
+ export const light: CharcoalTheme = {
197
+ ...common,
198
+ ...${JSON.stringify(light, sortReplacer, 2)}
199
+ };
200
+
201
+ export const dark: CharcoalTheme = {
202
+ ...common,
203
+ ...${JSON.stringify(dark, sortReplacer, 2)}
204
+ }`
205
+ const fmt = prettier.format(code, {
206
+ parser: 'typescript',
207
+ singleQuote: true,
208
+ semi: false,
209
+ })
210
+ expect(fmt).toMatchFileSnapshot('./default.ts')
211
+ })