@hjmds/design-contracts 1.36.0 → 1.37.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/catalog.d.ts +27 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/chart.d.ts +10 -0
- package/dist/chart.d.ts.map +1 -1
- package/dist/component-recipes.d.ts +17 -0
- package/dist/component-recipes.d.ts.map +1 -1
- package/dist/component-recipes.js +9 -2
- package/dist/component-recipes.js.map +1 -1
- package/dist/dataviz.d.ts +10 -0
- package/dist/dataviz.d.ts.map +1 -1
- package/dist/dataviz.js +3 -0
- package/dist/dataviz.js.map +1 -1
- package/dist/design-system-provider.d.ts +3 -0
- package/dist/design-system-provider.d.ts.map +1 -1
- package/dist/design-system-provider.js +7 -0
- package/dist/design-system-provider.js.map +1 -1
- package/dist/palette-contrast.d.ts +4 -2
- package/dist/palette-contrast.d.ts.map +1 -1
- package/dist/palette-contrast.js +9 -2
- package/dist/palette-contrast.js.map +1 -1
- package/dist/semantic-colors.d.ts.map +1 -1
- package/dist/semantic-colors.js +21 -19
- package/dist/semantic-colors.js.map +1 -1
- package/dist/theme-studio.d.ts +1 -1
- package/dist/theme-studio.js +2 -2
- package/dist/theme-studio.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/brand-boundary.md +6 -3
- package/docs/design-profile.md +1 -1
- package/docs/generated/component-maturity.md +1 -1
- package/docs/generated/renderer-evidence.json +3 -3
- package/docs/generated/renderer-evidence.md +1 -1
- package/docs/generated/showcase-manifest.json +1 -1
- package/docs/usage/README.md +5 -4
- package/docs/usage/components/bottom-cta.md +2 -0
- package/docs/usage/components/card.md +1 -1
- package/docs/usage/components/chart.md +4 -0
- package/docs/usage/components/combobox.md +7 -5
- package/docs/usage/components/composition-layout.md +2 -1
- package/docs/usage/components/design-system-provider.md +2 -2
- package/docs/usage/components/empty-state.md +2 -0
- package/docs/usage/components/notice.md +4 -0
- package/docs/usage/components/segmented-control.md +2 -0
- package/docs/usage/components/select.md +9 -7
- package/docs/usage/components/sheet.md +5 -1
- package/docs/usage/components/time-picker.md +1 -1
- package/docs/usage/components/toast.md +3 -0
- package/docs/usage/compositions/save-feedback.md +93 -0
- package/docs/usage/compositions/shortcut-rail.md +5 -5
- package/docs/usage/tokens/color.md +11 -5
- package/package.json +1 -1
package/dist/dataviz.d.ts
CHANGED
|
@@ -62,6 +62,16 @@ export declare const datavizChromeTokens: {
|
|
|
62
62
|
key: "textBody";
|
|
63
63
|
alpha?: number;
|
|
64
64
|
}>;
|
|
65
|
+
readonly labelSurface: Readonly<{
|
|
66
|
+
source: "theme";
|
|
67
|
+
key: "bg";
|
|
68
|
+
alpha?: number;
|
|
69
|
+
}>;
|
|
70
|
+
readonly labelContent: Readonly<{
|
|
71
|
+
source: "theme";
|
|
72
|
+
key: "text";
|
|
73
|
+
alpha?: number;
|
|
74
|
+
}>;
|
|
65
75
|
readonly lineWidth: 1;
|
|
66
76
|
readonly gridWidth: 1;
|
|
67
77
|
readonly labelVariant: "caption";
|
package/dist/dataviz.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataviz.d.ts","sourceRoot":"","sources":["../src/dataviz.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB;;;CAGsC,CAAC;AAExE,eAAO,MAAM,kBAAkB,GAAoC,CAAC;AAEpE;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMrF;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB
|
|
1
|
+
{"version":3,"file":"dataviz.d.ts","sourceRoot":"","sources":["../src/dataviz.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB;;;CAGsC,CAAC;AAExE,eAAO,MAAM,kBAAkB,GAAoC,CAAC;AAEpE;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMrF;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B9B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,yBAAyB,oDAAqD,CAAC;AAC5F,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElF,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,SAAS,wBAAwB,EAAE,GAC7C,IAAI,CAMN"}
|
package/dist/dataviz.js
CHANGED
|
@@ -41,6 +41,9 @@ export const datavizChromeTokens = {
|
|
|
41
41
|
tooltipSurface: themeColor("surface"),
|
|
42
42
|
tooltipBorder: themeColor("border"),
|
|
43
43
|
tooltipContent: themeColor("textBody"),
|
|
44
|
+
// An opaque label plate owns contrast even for arbitrary product series colors and faded slices.
|
|
45
|
+
labelSurface: themeColor("bg"),
|
|
46
|
+
labelContent: themeColor("text"),
|
|
44
47
|
lineWidth: stroke.default,
|
|
45
48
|
gridWidth: stroke.subtle,
|
|
46
49
|
labelVariant: "caption",
|
package/dist/dataviz.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataviz.js","sourceRoot":"","sources":["../src/dataviz.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAuB,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,KAAK,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;IAC/F,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;CACzB,CAAC;AAExE,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC,KAAK,CAAC,MAAM,CAAC;AAEpE;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAoB,EAAE,KAAa;IAC3E,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,UAAU,CAAC,qDAAqD,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC5C,OAAO,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAE,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC;IAC9B,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC;IAClC,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC;IACnC,WAAW,EAAE,UAAU,CAAC,UAAU,CAAC;IACnC,cAAc,EAAE,UAAU,CAAC,SAAS,CAAC;IACrC,aAAa,EAAE,UAAU,CAAC,QAAQ,CAAC;IACnC,cAAc,EAAE,UAAU,CAAC,UAAU,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC,OAAO;IACzB,SAAS,EAAE,MAAM,CAAC,MAAM;IACxB,YAAY,EAAE,SAAS;IACvB,aAAa,EAAE,OAAO;
|
|
1
|
+
{"version":3,"file":"dataviz.js","sourceRoot":"","sources":["../src/dataviz.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAuB,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,KAAK,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;IAC/F,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;CACzB,CAAC;AAExE,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC,KAAK,CAAC,MAAM,CAAC;AAEpE;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAoB,EAAE,KAAa;IAC3E,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,UAAU,CAAC,qDAAqD,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC5C,OAAO,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAE,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC;IAC9B,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC;IAClC,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC;IACnC,WAAW,EAAE,UAAU,CAAC,UAAU,CAAC;IACnC,cAAc,EAAE,UAAU,CAAC,SAAS,CAAC;IACrC,aAAa,EAAE,UAAU,CAAC,QAAQ,CAAC;IACnC,cAAc,EAAE,UAAU,CAAC,UAAU,CAAC;IACtC,iGAAiG;IACjG,YAAY,EAAE,UAAU,CAAC,IAAI,CAAC;IAC9B,YAAY,EAAE,UAAU,CAAC,MAAM,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC,OAAO;IACzB,SAAS,EAAE,MAAM,CAAC,MAAM;IACxB,YAAY,EAAE,SAAS;IACvB,aAAa,EAAE,OAAO;CAetB,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,aAAa,EAAE,SAAS,EAAE,aAAa,CAAU,CAAC;AAG5F,MAAM,UAAU,uBAAuB,CACrC,SAA8C;IAE9C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,UAAU,CAClB,8FAA8F,CAC/F,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import type { ResolvedTheme } from \"./colors.js\";\nimport { themeColor, type ColorReference } from \"./color-references.js\";\nimport { stroke, typography } from \"./foundations.js\";\n\n/**\n * 차트의 **색·축·격자·범례 토큰 계약**이다. 그리기는 `src/chart.ts`와 두 renderer가 맡는다.\n *\n * 2026-10-14 번복: 처음에는 렌더러를 만들지 않고 그리기를 제품 라이브러리(Recharts·\n * victory-native·d3)에 맡겼다. 실제로는 제품(Yajalal)이 같은 스크럽 선 차트·막대·정렬 표를\n * 직접 다시 만들었고, 사용자가 차트·표 라이브러리 흡수를 요청해 그리기를 HJM으로 옮겼다.\n * 색이 제각각이던 문제(Spint 열지도·Yajalal 통계)를 막는 이 토큰의 값과 규칙은 그대로이며,\n * HJM 차트와 계약 밖 종류를 그리는 제품 라이브러리가 함께 소비한다. 이전 결정과 번복의\n * 근거는 docs/chart.md다.\n *\n * 상태색(info/success/warning/attention)을 계열색으로 쓰지 않는다. 상태색은 뜻을 가진\n * 색이라 \"3번 계열\"에 쓰면 사용자가 경고로 읽는다.\n */\nexport const datavizSeriesPalette = {\n light: [\"#2563eb\", \"#db2777\", \"#0d9488\", \"#b45309\", \"#7c3aed\", \"#0369a1\", \"#9d174d\", \"#4d7c0f\"],\n dark: [\"#60a5fa\", \"#f472b6\", \"#2dd4bf\", \"#fbbf24\", \"#a78bfa\", \"#38bdf8\", \"#fb7185\", \"#a3e635\"],\n} as const satisfies Readonly<Record<ResolvedTheme, readonly string[]>>;\n\nexport const datavizSeriesCount = datavizSeriesPalette.light.length;\n\n/**\n * 계열 수가 팔레트보다 많으면 **순환**한다. 색을 자동으로 더 만들지 않는다 — 생성한 색은\n * 대비를 보장할 수 없고, 9번째 계열이 필요한 화면은 대개 차트가 아니라 표가 맞다.\n */\nexport function resolveDatavizSeriesColor(theme: ResolvedTheme, index: number): string {\n if (!Number.isInteger(index) || index < 0) {\n throw new RangeError(\"Dataviz series index must be a non-negative integer\");\n }\n const palette = datavizSeriesPalette[theme];\n return palette[index % palette.length]!;\n}\n\n/**\n * 축·격자·범례는 차트가 아니라 **화면의 부속**이라 본문 토큰을 그대로 쓴다. 차트 전용\n * 회색을 따로 두면 같은 화면의 표·캡션과 어긋난다.\n */\nexport const datavizChromeTokens = {\n axisLine: themeColor(\"border\"),\n axisLabel: themeColor(\"textMuted\"),\n gridLine: themeColor(\"border\", 0.6),\n legendLabel: themeColor(\"textBody\"),\n tooltipSurface: themeColor(\"surface\"),\n tooltipBorder: themeColor(\"border\"),\n tooltipContent: themeColor(\"textBody\"),\n // An opaque label plate owns contrast even for arbitrary product series colors and faded slices.\n labelSurface: themeColor(\"bg\"),\n labelContent: themeColor(\"text\"),\n lineWidth: stroke.default,\n gridWidth: stroke.subtle,\n labelVariant: \"caption\",\n legendVariant: \"label\",\n} as const satisfies Readonly<{\n axisLine: ColorReference;\n axisLabel: ColorReference;\n gridLine: ColorReference;\n legendLabel: ColorReference;\n tooltipSurface: ColorReference;\n tooltipBorder: ColorReference;\n tooltipContent: ColorReference;\n labelSurface: ColorReference;\n labelContent: ColorReference;\n lineWidth: number;\n gridWidth: number;\n labelVariant: keyof typeof typography;\n legendVariant: keyof typeof typography;\n}>;\n\n/**\n * 색만으로 계열을 구분하지 않는다(WCAG 1.4.1). 제품이 쓰는 라이브러리가 무엇이든 이\n * 셋 중 하나를 색과 **함께** 붙여야 한다 — 색각 이상과 흑백 인쇄에서 차트가 남는 조건이다.\n */\nexport const datavizRedundantEncodings = [\"directLabel\", \"pattern\", \"markerShape\"] as const;\nexport type DatavizRedundantEncoding = (typeof datavizRedundantEncodings)[number];\n\nexport function validateDatavizEncoding(\n encodings: readonly DatavizRedundantEncoding[],\n): void {\n if (encodings.length === 0) {\n throw new RangeError(\n \"A dataviz series needs at least one non-color encoding: directLabel, pattern, or markerShape\",\n );\n }\n}\n"]}
|
|
@@ -113,6 +113,9 @@ export type DesignSystemProviderValue = Readonly<{
|
|
|
113
113
|
/** Optional to preserve existing pre-resolved provider values. */
|
|
114
114
|
designProfile?: HjmDesignProfile;
|
|
115
115
|
}>;
|
|
116
|
+
/** A resolved-value bridge still owns its current color scope. Preserve it for nested
|
|
117
|
+
* providers. An explicit brandPalette still replaces the inherited overrides (scope reset contract). */
|
|
118
|
+
export declare function resolveProviderBrandPalette(inherited: ResolveDesignSystemEnvironmentOptions["brandPalette"], supplied: ResolveDesignSystemEnvironmentOptions["brandPalette"], value?: DesignSystemProviderValue): ResolveDesignSystemEnvironmentOptions["brandPalette"];
|
|
116
119
|
/**
|
|
117
120
|
* Runtime boundary for the resolved palette a renderer receives, including one
|
|
118
121
|
* merged from a partial `brandPalette`: after merging, every semantic role a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"design-system-provider.d.ts","sourceRoot":"","sources":["../src/design-system-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEnE,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,KAAK,CAAC;AAElD;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,qBAAqB,GAAG,OAAO,CAE1E;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,OAAO,GAC3B,MAAM,CAER;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG,SAAS,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,SAAS,MAAM,EAAE,OAAO,SAAS,MAAM,EACtF,OAAO,EAAE,mBAAmB,EAC5B,UAAU,EAAE,QAAQ,CAAC;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,GACnE,WAAW,GAAG,OAAO,CAEvB;AAED,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,yEAAyE;IACzE,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B,CAAC,CAAC;AAEH,eAAO,MAAM,+BAA+B;;;;;;;CAc1C,CAAC;AAEH,MAAM,MAAM,+BAA+B,GAAG,QAAQ,CAAC;IACrD,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,qBAAqB,CAAC;IACjC,SAAS,EAAE,qBAAqB,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC,CAAC;AAEH,MAAM,MAAM,qCAAqC,GAAG,QAAQ,CAAC;IAC3D;;;;;OAKG;IACH,WAAW,EAAE,aAAa,CAAC;IAC3B,2FAA2F;IAC3F,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF;6FACyF;IACzF,aAAa,CAAC,EAAE,gBAAgB,CAAC;IACjC,4FAA4F;IAC5F,MAAM,CAAC,EAAE,+BAA+B,CAAC;CAC1C,CAAC,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,WAAW,EAAE,+BAA+B,CAAC;IAC7C,4DAA4D;IAC5D,OAAO,EAAE,qBAAqB,CAAC;IAC/B,kEAAkE;IAClE,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"design-system-provider.d.ts","sourceRoot":"","sources":["../src/design-system-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,6 +37,13 @@ export const designSystemEnvironmentDefaults = {
|
|
|
37
37
|
minimumVisualTarget: false,
|
|
38
38
|
density: "comfortable",
|
|
39
39
|
};
|
|
40
|
+
/** A resolved-value bridge still owns its current color scope. Preserve it for nested
|
|
41
|
+
* providers. An explicit brandPalette still replaces the inherited overrides (scope reset contract). */
|
|
42
|
+
export function resolveProviderBrandPalette(inherited, supplied, value) {
|
|
43
|
+
if (value !== undefined)
|
|
44
|
+
return { ...inherited, [value.environment.theme]: value.palette.theme };
|
|
45
|
+
return supplied ?? inherited;
|
|
46
|
+
}
|
|
40
47
|
const themeColorKeys = Object.keys(THEMES.light);
|
|
41
48
|
const accentColorKeys = Object.keys(ACCENTS.light);
|
|
42
49
|
const sixDigitHexColor = /^#[0-9a-f]{6}$/i;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"design-system-provider.js","sourceRoot":"","sources":["../src/design-system-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import type { HjmDesignProfile } from \"./design-profile.js\";\nimport type { ColorReferencePalette } from \"./color-references.js\";\nimport { control, largeTextThreshold } from \"./foundations.js\";\nimport {\n ACCENTS,\n THEMES,\n accentFill,\n isThemePreference,\n type ResolvedTheme,\n type ThemeColors,\n type ThemePreference,\n} from \"./colors.js\";\n\n/**\n * Canonical logical direction. Existing public component-specific names stay\n * source-compatible as aliases of this type instead of redeclaring the union.\n */\nexport type DesignSystemDirection = \"ltr\" | \"rtl\";\n\n/**\n * A continuous OS/user font-scale multiplier (iOS Dynamic Type, Android font\n * size, browser zoom) — not `ShowcaseTextScale`'s closed `1 | 1.5 | 2`, which\n * only names Showcase's five fixture stories, or `description-list.ts`'s\n * local layout clamp. This is the single upstream signal both now consume.\n */\nexport type DesignSystemTextScale = number;\n\n/**\n * Whether a resolved `textScale` has crossed into large-text layout. A\n * stylesheet cannot compare numbers, so the provider resolves the axis once and\n * publishes the result for surfaces that can only match a flag (#20).\n */\nexport function isLargeTextScale(textScale: DesignSystemTextScale): boolean {\n return Number.isFinite(textScale) && textScale >= largeTextThreshold;\n}\n\n/**\n * Visible height a compact control paints under a product's target-size policy.\n *\n * The compact recipes stay at 36 and reach the 44pt target through hit slop,\n * which satisfies WCAG 2.5.8 but not the stricter iOS/Android guidance some\n * products commit to. `minimumVisualTarget` turns that commitment into one\n * resolved axis, so both renderers compute the same geometry instead of each\n * consumer re-adding `minHeight` in product styles. It lives beside the axis\n * rather than in `foundations` because it is a policy over a token, not a token.\n */\nexport function visibleControlHeight(\n recipeHeight: number,\n minimumVisualTarget: boolean,\n): number {\n return minimumVisualTarget ? Math.max(recipeHeight, control.minTouchTarget) : recipeHeight;\n}\n\n/**\n * 한 화면 안에서 목록·메뉴·표가 각각 다른 밀도로 그려지던 문제를 하나의 축으로 모은다.\n * 지금까지는 `ListRow density`, `Menu density`, DataTable의 행 높이가 서로 모르는 값이라\n * 제품이 세 군데를 따로 맞췄다. 컴포넌트의 명시적 prop이 언제나 이 축을 이긴다 —\n * 전역값은 기본이지 강제가 아니다.\n *\n * OS 신호가 없다. 밀도는 제품의 입장(같은 화면에 얼마나 담을 것인가)이지 사용자 설정이\n * 아니라서 `system*` 짝을 두지 않았다. 반대로 큰 글자 설정은 사용자 설정이므로\n * `textScale`이 큰 상태에서 `compact`를 쓰는 것은 제품이 스스로 막아야 한다.\n */\nexport type DesignSystemDensity = \"comfortable\" | \"compact\";\n\n/**\n * 전역 밀도를 컴포넌트마다 다른 밀도 어휘로 옮긴다. 컴포넌트의 명시적 prop이 언제나\n * 이긴다 — 전역값은 기본이지 강제가 아니다. 어휘를 하나로 통일하지 않은 이유: 목록의\n * `relaxed`와 표의 `regular`는 같은 말이 아니고, 억지로 합치면 둘 중 하나가 거짓말을 한다.\n */\nexport function resolveDensityDefault<Comfortable extends string, Compact extends string>(\n density: DesignSystemDensity,\n vocabulary: Readonly<{ comfortable: Comfortable; compact: Compact }>,\n): Comfortable | Compact {\n return density === \"compact\" ? vocabulary.compact : vocabulary.comfortable;\n}\n\nexport type DesignSystemEnvironmentInput = Readonly<{\n theme?: ThemePreference;\n direction?: DesignSystemDirection;\n textScale?: DesignSystemTextScale;\n reducedMotion?: boolean;\n /**\n * Paint the minimum touch target as visible control geometry instead of\n * reaching it with hit slop. This is a product accessibility stance, not an\n * OS signal, so it has no `system*` counterpart.\n */\n minimumVisualTarget?: boolean;\n /** Default row/menu/table density for everything below this provider. */\n density?: DesignSystemDensity;\n}>;\n\nexport const designSystemEnvironmentDefaults = {\n theme: \"system\",\n direction: \"ltr\",\n textScale: 1,\n reducedMotion: false,\n minimumVisualTarget: false,\n density: \"comfortable\",\n} as const satisfies Readonly<{\n theme: ThemePreference;\n direction: DesignSystemDirection;\n textScale: DesignSystemTextScale;\n reducedMotion: boolean;\n minimumVisualTarget: boolean;\n density: DesignSystemDensity;\n}>;\n\nexport type ResolvedDesignSystemEnvironment = Readonly<{\n theme: ResolvedTheme;\n direction: DesignSystemDirection;\n textScale: DesignSystemTextScale;\n reducedMotion: boolean;\n minimumVisualTarget: boolean;\n density: DesignSystemDensity;\n}>;\n\nexport type ResolveDesignSystemEnvironmentOptions = Readonly<{\n /**\n * The platform's current OS-level scheme, consulted only when `theme`\n * resolves to `\"system\"`. Renderers detect this themselves\n * (`Appearance.getColorScheme()`, `matchMedia('(prefers-color-scheme)')`)\n * — this package never queries the OS.\n */\n systemTheme: ResolvedTheme;\n /** Optional OS/renderer signals used when neither input nor a parent supplies the axis. */\n systemDirection?: DesignSystemDirection;\n systemTextScale?: DesignSystemTextScale;\n systemReducedMotion?: boolean;\n /**\n * Product brand colors layered over the HJM semantic keys. The key set is\n * unchanged, so recipes and contrast rules keep applying. Without this entry\n * point a consumer has to build its own token layer and override the CSS\n * variables, which is a copy of the canonical palette. Only the supplied\n * keys are replaced; the rest keep the HJM defaults.\n */\n brandPalette?: Readonly<Partial<Record<ResolvedTheme, Readonly<Partial<ThemeColors>>>>>;\n /** Use defineHjmDesignProfile once at the product boundary; importing its registry\n * here at runtime would force every granular component to bundle all reference packs. */\n designProfile?: HjmDesignProfile;\n /** A nested renderer inherits the already-resolved parent before consulting OS defaults. */\n parent?: ResolvedDesignSystemEnvironment;\n}>;\n\nexport type DesignSystemProviderValue = Readonly<{\n environment: ResolvedDesignSystemEnvironment;\n /** Palette consumed directly by `resolveColorReference`. */\n palette: ColorReferencePalette;\n /** Optional to preserve existing pre-resolved provider values. */\n designProfile?: HjmDesignProfile;\n}>;\n\nconst themeColorKeys = Object.keys(THEMES.light) as readonly (keyof typeof THEMES.light)[];\nconst accentColorKeys = Object.keys(ACCENTS.light) as readonly (keyof typeof ACCENTS.light)[];\nconst sixDigitHexColor = /^#[0-9a-f]{6}$/i;\n\nfunction assertColorRecord(\n value: unknown,\n keys: readonly string[],\n field: string,\n): asserts value is Readonly<Record<string, string>> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new TypeError(`DesignSystemProviderValue ${field} must be a color record`);\n }\n const record = value as Readonly<Record<string, unknown>>;\n for (const key of keys) {\n const color = record[key];\n if (typeof color !== \"string\" || !sixDigitHexColor.test(color)) {\n throw new TypeError(\n `DesignSystemProviderValue ${field}.${key} must be a six-digit hex color`,\n );\n }\n }\n}\n\n/**\n * Runtime boundary for the resolved palette a renderer receives, including one\n * merged from a partial `brandPalette`: after merging, every semantic role a\n * recipe reads must be present, and alpha composition requires six-digit hex.\n * Brand rules: docs/brand-boundary.md.\n */\nexport function validateDesignSystemProviderValue(\n value: DesignSystemProviderValue,\n): void {\n if (value === null || typeof value !== \"object\") {\n throw new TypeError(\"DesignSystemProviderValue must be an object\");\n }\n if (value.environment === null || typeof value.environment !== \"object\") {\n throw new TypeError(\"DesignSystemProviderValue environment must be an object\");\n }\n validateResolvedDesignSystemEnvironment(value.environment);\n const palette = value.palette;\n if (palette === null || typeof palette !== \"object\") {\n throw new TypeError(\"DesignSystemProviderValue palette must be an object\");\n }\n assertColorRecord(palette.theme, themeColorKeys, \"palette.theme\");\n assertColorRecord(\n palette.statusAccents,\n accentColorKeys,\n \"palette.statusAccents\",\n );\n assertColorRecord(\n palette.statusAccentFills,\n accentColorKeys,\n \"palette.statusAccentFills\",\n );\n}\n\nfunction assertBoolean(value: boolean, field: string): void {\n if (typeof value !== \"boolean\") {\n throw new TypeError(`DesignSystemEnvironment ${field} must be a boolean`);\n }\n}\n\nfunction assertDirection(value: DesignSystemDirection, field: string): void {\n if (value !== \"ltr\" && value !== \"rtl\") {\n throw new TypeError(`Unsupported DesignSystemEnvironment ${field}: ${String(value)}`);\n }\n}\n\nfunction assertTextScale(value: DesignSystemTextScale, field: string): void {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n throw new RangeError(\n `DesignSystemEnvironment ${field} must be a finite number greater than 0`,\n );\n }\n}\n\nfunction assertDensity(value: unknown, field: string): asserts value is DesignSystemDensity {\n if (value !== \"comfortable\" && value !== \"compact\") {\n throw new TypeError(`Unsupported DesignSystemEnvironment ${field}: ${String(value)}`);\n }\n}\n\nexport function validateDesignSystemEnvironmentInput(\n input: DesignSystemEnvironmentInput,\n): void {\n if (input.theme !== undefined && !isThemePreference(input.theme)) {\n throw new TypeError(`Unsupported DesignSystemEnvironment theme: ${String(input.theme)}`);\n }\n if (\n input.direction !== undefined &&\n input.direction !== \"ltr\" &&\n input.direction !== \"rtl\"\n ) {\n throw new TypeError(\n `Unsupported DesignSystemEnvironment direction: ${String(input.direction)}`,\n );\n }\n if (input.textScale !== undefined) {\n assertTextScale(input.textScale, \"textScale\");\n }\n if (input.reducedMotion !== undefined) {\n assertBoolean(input.reducedMotion, \"reducedMotion\");\n }\n if (input.minimumVisualTarget !== undefined) {\n assertBoolean(input.minimumVisualTarget, \"minimumVisualTarget\");\n }\n if (input.density !== undefined) {\n assertDensity(input.density, \"density\");\n }\n}\n\n/**\n * A parent has already crossed the system-preference boundary. Unlike the\n * partial input validator, this rejects `\"system\"`, missing axes, and every\n * malformed resolved value instead of silently resolving them again.\n */\nexport function validateResolvedDesignSystemEnvironment(\n environment: ResolvedDesignSystemEnvironment,\n): void {\n if (environment.theme !== \"light\" && environment.theme !== \"dark\") {\n throw new TypeError(\n `Unsupported ResolvedDesignSystemEnvironment theme: ${String(environment.theme)}`,\n );\n }\n assertDirection(environment.direction, \"parent direction\");\n assertTextScale(environment.textScale, \"parent textScale\");\n assertBoolean(environment.reducedMotion, \"parent reducedMotion\");\n assertBoolean(environment.minimumVisualTarget, \"parent minimumVisualTarget\");\n assertDensity(environment.density, \"parent density\");\n}\n\n/**\n * Merges partial signals with safe defaults and resolves `\"system\"` against\n * the renderer-supplied `systemTheme`. This — not a React/RN context, which\n * this package cannot own — is the entire portable contract behind antd\n * `ConfigProvider`: see docs/design-system-provider.md for what was\n * deliberately left to the renderer.\n */\nexport function resolveDesignSystemEnvironment(\n input: DesignSystemEnvironmentInput,\n options: ResolveDesignSystemEnvironmentOptions,\n): ResolvedDesignSystemEnvironment {\n validateDesignSystemEnvironmentInput(input);\n if (options.systemTheme !== \"light\" && options.systemTheme !== \"dark\") {\n throw new TypeError(`Unsupported DesignSystemEnvironment systemTheme: ${String(options.systemTheme)}`);\n }\n if (options.systemDirection !== undefined) {\n assertDirection(options.systemDirection, \"systemDirection\");\n }\n if (options.systemTextScale !== undefined) {\n assertTextScale(options.systemTextScale, \"systemTextScale\");\n }\n if (options.systemReducedMotion !== undefined) {\n assertBoolean(options.systemReducedMotion, \"systemReducedMotion\");\n }\n if (options.parent !== undefined) {\n validateResolvedDesignSystemEnvironment(options.parent);\n }\n\n const theme =\n input.theme ?? options.parent?.theme ?? designSystemEnvironmentDefaults.theme;\n return {\n theme: theme === \"system\" ? options.systemTheme : theme,\n direction:\n input.direction ??\n options.parent?.direction ??\n options.systemDirection ??\n designSystemEnvironmentDefaults.direction,\n textScale:\n input.textScale ??\n options.parent?.textScale ??\n options.systemTextScale ??\n designSystemEnvironmentDefaults.textScale,\n reducedMotion:\n input.reducedMotion ??\n options.parent?.reducedMotion ??\n options.systemReducedMotion ??\n designSystemEnvironmentDefaults.reducedMotion,\n minimumVisualTarget:\n input.minimumVisualTarget ??\n options.parent?.minimumVisualTarget ??\n designSystemEnvironmentDefaults.minimumVisualTarget,\n density:\n input.density ??\n options.parent?.density ??\n designSystemEnvironmentDefaults.density,\n };\n}\n\n/**\n * Resolves the portable Provider value without owning React/RN Context. A\n * renderer stores this object in its own context and feeds `palette` directly\n * to recipe color resolution.\n */\nexport function resolveDesignSystemProviderValue(\n input: DesignSystemEnvironmentInput,\n options: ResolveDesignSystemEnvironmentOptions,\n): DesignSystemProviderValue {\n const environment = resolveDesignSystemEnvironment(input, options);\n const brandOverride = options.brandPalette?.[environment.theme];\n const basePalette = options.designProfile?.palette[environment.theme] ?? THEMES[environment.theme];\n const value = {\n environment,\n ...(options.designProfile === undefined ? {} : { designProfile: options.designProfile }),\n palette: {\n theme: brandOverride === undefined\n ? basePalette\n : { ...basePalette, ...brandOverride },\n statusAccents: ACCENTS[environment.theme],\n statusAccentFills: accentFill,\n },\n };\n validateDesignSystemProviderValue(value);\n return value;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"design-system-provider.js","sourceRoot":"","sources":["../src/design-system-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACL,OAAO,EACP,MAAM,EACN,UAAU,EACV,iBAAiB,GAIlB,MAAM,aAAa,CAAC;AAgBrB;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAgC;IAC/D,OAAO,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,kBAAkB,CAAC;AACvE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAClC,YAAoB,EACpB,mBAA4B;IAE5B,OAAO,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;AAC7F,CAAC;AAcD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAA4B,EAC5B,UAAoE;IAEpE,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC;AAC7E,CAAC;AAiBD,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC7C,KAAK,EAAE,QAAQ;IACf,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,CAAC;IACZ,aAAa,EAAE,KAAK;IACpB,mBAAmB,EAAE,KAAK;IAC1B,OAAO,EAAE,aAAa;CAQtB,CAAC;AA8CH;wGACwG;AACxG,MAAM,UAAU,2BAA2B,CACzC,SAAgE,EAChE,QAA+D,EAC/D,KAAiC;IAEjC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,GAAG,SAAS,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACjG,OAAO,QAAQ,IAAI,SAAS,CAAC;AAC/B,CAAC;AAED,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAA2C,CAAC;AAC3F,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAA4C,CAAC;AAC9F,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAE3C,SAAS,iBAAiB,CACxB,KAAc,EACd,IAAuB,EACvB,KAAa;IAEb,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,SAAS,CAAC,6BAA6B,KAAK,yBAAyB,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,MAAM,GAAG,KAA0C,CAAC;IAC1D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,SAAS,CACjB,6BAA6B,KAAK,IAAI,GAAG,gCAAgC,CAC1E,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iCAAiC,CAC/C,KAAgC;IAEhC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;QACxE,MAAM,IAAI,SAAS,CAAC,yDAAyD,CAAC,CAAC;IACjF,CAAC;IACD,uCAAuC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACpD,MAAM,IAAI,SAAS,CAAC,qDAAqD,CAAC,CAAC;IAC7E,CAAC;IACD,iBAAiB,CAAC,OAAO,CAAC,KAAK,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC;IAClE,iBAAiB,CACf,OAAO,CAAC,aAAa,EACrB,eAAe,EACf,uBAAuB,CACxB,CAAC;IACF,iBAAiB,CACf,OAAO,CAAC,iBAAiB,EACzB,eAAe,EACf,2BAA2B,CAC5B,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,KAAa;IAClD,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,SAAS,CAAC,2BAA2B,KAAK,oBAAoB,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAA4B,EAAE,KAAa;IAClE,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QACvC,MAAM,IAAI,SAAS,CAAC,uCAAuC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAA4B,EAAE,KAAa;IAClE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,UAAU,CAClB,2BAA2B,KAAK,yCAAyC,CAC1E,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,KAAa;IAClD,IAAI,KAAK,KAAK,aAAa,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACnD,MAAM,IAAI,SAAS,CAAC,uCAAuC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oCAAoC,CAClD,KAAmC;IAEnC,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,SAAS,CAAC,8CAA8C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,IACE,KAAK,CAAC,SAAS,KAAK,SAAS;QAC7B,KAAK,CAAC,SAAS,KAAK,KAAK;QACzB,KAAK,CAAC,SAAS,KAAK,KAAK,EACzB,CAAC;QACD,MAAM,IAAI,SAAS,CACjB,kDAAkD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAC5E,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAClC,eAAe,CAAC,KAAK,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACtC,aAAa,CAAC,KAAK,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,KAAK,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;QAC5C,aAAa,CAAC,KAAK,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAChC,aAAa,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uCAAuC,CACrD,WAA4C;IAE5C,IAAI,WAAW,CAAC,KAAK,KAAK,OAAO,IAAI,WAAW,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;QAClE,MAAM,IAAI,SAAS,CACjB,sDAAsD,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAClF,CAAC;IACJ,CAAC;IACD,eAAe,CAAC,WAAW,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;IAC3D,eAAe,CAAC,WAAW,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;IAC3D,aAAa,CAAC,WAAW,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC;IACjE,aAAa,CAAC,WAAW,CAAC,mBAAmB,EAAE,4BAA4B,CAAC,CAAC;IAC7E,aAAa,CAAC,WAAW,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,8BAA8B,CAC5C,KAAmC,EACnC,OAA8C;IAE9C,oCAAoC,CAAC,KAAK,CAAC,CAAC;IAC5C,IAAI,OAAO,CAAC,WAAW,KAAK,OAAO,IAAI,OAAO,CAAC,WAAW,KAAK,MAAM,EAAE,CAAC;QACtE,MAAM,IAAI,SAAS,CAAC,oDAAoD,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACzG,CAAC;IACD,IAAI,OAAO,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QAC1C,eAAe,CAAC,OAAO,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,OAAO,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QAC1C,eAAe,CAAC,OAAO,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,OAAO,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;QAC9C,aAAa,CAAC,OAAO,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,uCAAuC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,KAAK,GACT,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,+BAA+B,CAAC,KAAK,CAAC;IAChF,OAAO;QACL,KAAK,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK;QACvD,SAAS,EACP,KAAK,CAAC,SAAS;YACf,OAAO,CAAC,MAAM,EAAE,SAAS;YACzB,OAAO,CAAC,eAAe;YACvB,+BAA+B,CAAC,SAAS;QAC3C,SAAS,EACP,KAAK,CAAC,SAAS;YACf,OAAO,CAAC,MAAM,EAAE,SAAS;YACzB,OAAO,CAAC,eAAe;YACvB,+BAA+B,CAAC,SAAS;QAC3C,aAAa,EACX,KAAK,CAAC,aAAa;YACnB,OAAO,CAAC,MAAM,EAAE,aAAa;YAC7B,OAAO,CAAC,mBAAmB;YAC3B,+BAA+B,CAAC,aAAa;QAC/C,mBAAmB,EACjB,KAAK,CAAC,mBAAmB;YACzB,OAAO,CAAC,MAAM,EAAE,mBAAmB;YACnC,+BAA+B,CAAC,mBAAmB;QACrD,OAAO,EACL,KAAK,CAAC,OAAO;YACb,OAAO,CAAC,MAAM,EAAE,OAAO;YACvB,+BAA+B,CAAC,OAAO;KAC1C,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAC9C,KAAmC,EACnC,OAA8C;IAE9C,MAAM,WAAW,GAAG,8BAA8B,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACnE,MAAM,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAChE,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACnG,MAAM,KAAK,GAAG;QACZ,WAAW;QACX,GAAG,CAAC,OAAO,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC;QACxF,OAAO,EAAE;YACP,KAAK,EAAE,aAAa,KAAK,SAAS;gBAChC,CAAC,CAAC,WAAW;gBACb,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,GAAG,aAAa,EAAE;YACxC,aAAa,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC;YACzC,iBAAiB,EAAE,UAAU;SAC9B;KACF,CAAC;IACF,iCAAiC,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { HjmDesignProfile } from \"./design-profile.js\";\nimport type { ColorReferencePalette } from \"./color-references.js\";\nimport { control, largeTextThreshold } from \"./foundations.js\";\nimport {\n ACCENTS,\n THEMES,\n accentFill,\n isThemePreference,\n type ResolvedTheme,\n type ThemeColors,\n type ThemePreference,\n} from \"./colors.js\";\n\n/**\n * Canonical logical direction. Existing public component-specific names stay\n * source-compatible as aliases of this type instead of redeclaring the union.\n */\nexport type DesignSystemDirection = \"ltr\" | \"rtl\";\n\n/**\n * A continuous OS/user font-scale multiplier (iOS Dynamic Type, Android font\n * size, browser zoom) — not `ShowcaseTextScale`'s closed `1 | 1.5 | 2`, which\n * only names Showcase's five fixture stories, or `description-list.ts`'s\n * local layout clamp. This is the single upstream signal both now consume.\n */\nexport type DesignSystemTextScale = number;\n\n/**\n * Whether a resolved `textScale` has crossed into large-text layout. A\n * stylesheet cannot compare numbers, so the provider resolves the axis once and\n * publishes the result for surfaces that can only match a flag (#20).\n */\nexport function isLargeTextScale(textScale: DesignSystemTextScale): boolean {\n return Number.isFinite(textScale) && textScale >= largeTextThreshold;\n}\n\n/**\n * Visible height a compact control paints under a product's target-size policy.\n *\n * The compact recipes stay at 36 and reach the 44pt target through hit slop,\n * which satisfies WCAG 2.5.8 but not the stricter iOS/Android guidance some\n * products commit to. `minimumVisualTarget` turns that commitment into one\n * resolved axis, so both renderers compute the same geometry instead of each\n * consumer re-adding `minHeight` in product styles. It lives beside the axis\n * rather than in `foundations` because it is a policy over a token, not a token.\n */\nexport function visibleControlHeight(\n recipeHeight: number,\n minimumVisualTarget: boolean,\n): number {\n return minimumVisualTarget ? Math.max(recipeHeight, control.minTouchTarget) : recipeHeight;\n}\n\n/**\n * 한 화면 안에서 목록·메뉴·표가 각각 다른 밀도로 그려지던 문제를 하나의 축으로 모은다.\n * 지금까지는 `ListRow density`, `Menu density`, DataTable의 행 높이가 서로 모르는 값이라\n * 제품이 세 군데를 따로 맞췄다. 컴포넌트의 명시적 prop이 언제나 이 축을 이긴다 —\n * 전역값은 기본이지 강제가 아니다.\n *\n * OS 신호가 없다. 밀도는 제품의 입장(같은 화면에 얼마나 담을 것인가)이지 사용자 설정이\n * 아니라서 `system*` 짝을 두지 않았다. 반대로 큰 글자 설정은 사용자 설정이므로\n * `textScale`이 큰 상태에서 `compact`를 쓰는 것은 제품이 스스로 막아야 한다.\n */\nexport type DesignSystemDensity = \"comfortable\" | \"compact\";\n\n/**\n * 전역 밀도를 컴포넌트마다 다른 밀도 어휘로 옮긴다. 컴포넌트의 명시적 prop이 언제나\n * 이긴다 — 전역값은 기본이지 강제가 아니다. 어휘를 하나로 통일하지 않은 이유: 목록의\n * `relaxed`와 표의 `regular`는 같은 말이 아니고, 억지로 합치면 둘 중 하나가 거짓말을 한다.\n */\nexport function resolveDensityDefault<Comfortable extends string, Compact extends string>(\n density: DesignSystemDensity,\n vocabulary: Readonly<{ comfortable: Comfortable; compact: Compact }>,\n): Comfortable | Compact {\n return density === \"compact\" ? vocabulary.compact : vocabulary.comfortable;\n}\n\nexport type DesignSystemEnvironmentInput = Readonly<{\n theme?: ThemePreference;\n direction?: DesignSystemDirection;\n textScale?: DesignSystemTextScale;\n reducedMotion?: boolean;\n /**\n * Paint the minimum touch target as visible control geometry instead of\n * reaching it with hit slop. This is a product accessibility stance, not an\n * OS signal, so it has no `system*` counterpart.\n */\n minimumVisualTarget?: boolean;\n /** Default row/menu/table density for everything below this provider. */\n density?: DesignSystemDensity;\n}>;\n\nexport const designSystemEnvironmentDefaults = {\n theme: \"system\",\n direction: \"ltr\",\n textScale: 1,\n reducedMotion: false,\n minimumVisualTarget: false,\n density: \"comfortable\",\n} as const satisfies Readonly<{\n theme: ThemePreference;\n direction: DesignSystemDirection;\n textScale: DesignSystemTextScale;\n reducedMotion: boolean;\n minimumVisualTarget: boolean;\n density: DesignSystemDensity;\n}>;\n\nexport type ResolvedDesignSystemEnvironment = Readonly<{\n theme: ResolvedTheme;\n direction: DesignSystemDirection;\n textScale: DesignSystemTextScale;\n reducedMotion: boolean;\n minimumVisualTarget: boolean;\n density: DesignSystemDensity;\n}>;\n\nexport type ResolveDesignSystemEnvironmentOptions = Readonly<{\n /**\n * The platform's current OS-level scheme, consulted only when `theme`\n * resolves to `\"system\"`. Renderers detect this themselves\n * (`Appearance.getColorScheme()`, `matchMedia('(prefers-color-scheme)')`)\n * — this package never queries the OS.\n */\n systemTheme: ResolvedTheme;\n /** Optional OS/renderer signals used when neither input nor a parent supplies the axis. */\n systemDirection?: DesignSystemDirection;\n systemTextScale?: DesignSystemTextScale;\n systemReducedMotion?: boolean;\n /**\n * Product brand colors layered over the HJM semantic keys. The key set is\n * unchanged, so recipes and contrast rules keep applying. Without this entry\n * point a consumer has to build its own token layer and override the CSS\n * variables, which is a copy of the canonical palette. Only the supplied\n * keys are replaced; the rest keep the HJM defaults.\n */\n brandPalette?: Readonly<Partial<Record<ResolvedTheme, Readonly<Partial<ThemeColors>>>>>;\n /** Use defineHjmDesignProfile once at the product boundary; importing its registry\n * here at runtime would force every granular component to bundle all reference packs. */\n designProfile?: HjmDesignProfile;\n /** A nested renderer inherits the already-resolved parent before consulting OS defaults. */\n parent?: ResolvedDesignSystemEnvironment;\n}>;\n\nexport type DesignSystemProviderValue = Readonly<{\n environment: ResolvedDesignSystemEnvironment;\n /** Palette consumed directly by `resolveColorReference`. */\n palette: ColorReferencePalette;\n /** Optional to preserve existing pre-resolved provider values. */\n designProfile?: HjmDesignProfile;\n}>;\n\n/** A resolved-value bridge still owns its current color scope. Preserve it for nested\n * providers. An explicit brandPalette still replaces the inherited overrides (scope reset contract). */\nexport function resolveProviderBrandPalette(\n inherited: ResolveDesignSystemEnvironmentOptions[\"brandPalette\"],\n supplied: ResolveDesignSystemEnvironmentOptions[\"brandPalette\"],\n value?: DesignSystemProviderValue,\n): ResolveDesignSystemEnvironmentOptions[\"brandPalette\"] {\n if (value !== undefined) return { ...inherited, [value.environment.theme]: value.palette.theme };\n return supplied ?? inherited;\n}\n\nconst themeColorKeys = Object.keys(THEMES.light) as readonly (keyof typeof THEMES.light)[];\nconst accentColorKeys = Object.keys(ACCENTS.light) as readonly (keyof typeof ACCENTS.light)[];\nconst sixDigitHexColor = /^#[0-9a-f]{6}$/i;\n\nfunction assertColorRecord(\n value: unknown,\n keys: readonly string[],\n field: string,\n): asserts value is Readonly<Record<string, string>> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new TypeError(`DesignSystemProviderValue ${field} must be a color record`);\n }\n const record = value as Readonly<Record<string, unknown>>;\n for (const key of keys) {\n const color = record[key];\n if (typeof color !== \"string\" || !sixDigitHexColor.test(color)) {\n throw new TypeError(\n `DesignSystemProviderValue ${field}.${key} must be a six-digit hex color`,\n );\n }\n }\n}\n\n/**\n * Runtime boundary for the resolved palette a renderer receives, including one\n * merged from a partial `brandPalette`: after merging, every semantic role a\n * recipe reads must be present, and alpha composition requires six-digit hex.\n * Brand rules: docs/brand-boundary.md.\n */\nexport function validateDesignSystemProviderValue(\n value: DesignSystemProviderValue,\n): void {\n if (value === null || typeof value !== \"object\") {\n throw new TypeError(\"DesignSystemProviderValue must be an object\");\n }\n if (value.environment === null || typeof value.environment !== \"object\") {\n throw new TypeError(\"DesignSystemProviderValue environment must be an object\");\n }\n validateResolvedDesignSystemEnvironment(value.environment);\n const palette = value.palette;\n if (palette === null || typeof palette !== \"object\") {\n throw new TypeError(\"DesignSystemProviderValue palette must be an object\");\n }\n assertColorRecord(palette.theme, themeColorKeys, \"palette.theme\");\n assertColorRecord(\n palette.statusAccents,\n accentColorKeys,\n \"palette.statusAccents\",\n );\n assertColorRecord(\n palette.statusAccentFills,\n accentColorKeys,\n \"palette.statusAccentFills\",\n );\n}\n\nfunction assertBoolean(value: boolean, field: string): void {\n if (typeof value !== \"boolean\") {\n throw new TypeError(`DesignSystemEnvironment ${field} must be a boolean`);\n }\n}\n\nfunction assertDirection(value: DesignSystemDirection, field: string): void {\n if (value !== \"ltr\" && value !== \"rtl\") {\n throw new TypeError(`Unsupported DesignSystemEnvironment ${field}: ${String(value)}`);\n }\n}\n\nfunction assertTextScale(value: DesignSystemTextScale, field: string): void {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n throw new RangeError(\n `DesignSystemEnvironment ${field} must be a finite number greater than 0`,\n );\n }\n}\n\nfunction assertDensity(value: unknown, field: string): asserts value is DesignSystemDensity {\n if (value !== \"comfortable\" && value !== \"compact\") {\n throw new TypeError(`Unsupported DesignSystemEnvironment ${field}: ${String(value)}`);\n }\n}\n\nexport function validateDesignSystemEnvironmentInput(\n input: DesignSystemEnvironmentInput,\n): void {\n if (input.theme !== undefined && !isThemePreference(input.theme)) {\n throw new TypeError(`Unsupported DesignSystemEnvironment theme: ${String(input.theme)}`);\n }\n if (\n input.direction !== undefined &&\n input.direction !== \"ltr\" &&\n input.direction !== \"rtl\"\n ) {\n throw new TypeError(\n `Unsupported DesignSystemEnvironment direction: ${String(input.direction)}`,\n );\n }\n if (input.textScale !== undefined) {\n assertTextScale(input.textScale, \"textScale\");\n }\n if (input.reducedMotion !== undefined) {\n assertBoolean(input.reducedMotion, \"reducedMotion\");\n }\n if (input.minimumVisualTarget !== undefined) {\n assertBoolean(input.minimumVisualTarget, \"minimumVisualTarget\");\n }\n if (input.density !== undefined) {\n assertDensity(input.density, \"density\");\n }\n}\n\n/**\n * A parent has already crossed the system-preference boundary. Unlike the\n * partial input validator, this rejects `\"system\"`, missing axes, and every\n * malformed resolved value instead of silently resolving them again.\n */\nexport function validateResolvedDesignSystemEnvironment(\n environment: ResolvedDesignSystemEnvironment,\n): void {\n if (environment.theme !== \"light\" && environment.theme !== \"dark\") {\n throw new TypeError(\n `Unsupported ResolvedDesignSystemEnvironment theme: ${String(environment.theme)}`,\n );\n }\n assertDirection(environment.direction, \"parent direction\");\n assertTextScale(environment.textScale, \"parent textScale\");\n assertBoolean(environment.reducedMotion, \"parent reducedMotion\");\n assertBoolean(environment.minimumVisualTarget, \"parent minimumVisualTarget\");\n assertDensity(environment.density, \"parent density\");\n}\n\n/**\n * Merges partial signals with safe defaults and resolves `\"system\"` against\n * the renderer-supplied `systemTheme`. This — not a React/RN context, which\n * this package cannot own — is the entire portable contract behind antd\n * `ConfigProvider`: see docs/design-system-provider.md for what was\n * deliberately left to the renderer.\n */\nexport function resolveDesignSystemEnvironment(\n input: DesignSystemEnvironmentInput,\n options: ResolveDesignSystemEnvironmentOptions,\n): ResolvedDesignSystemEnvironment {\n validateDesignSystemEnvironmentInput(input);\n if (options.systemTheme !== \"light\" && options.systemTheme !== \"dark\") {\n throw new TypeError(`Unsupported DesignSystemEnvironment systemTheme: ${String(options.systemTheme)}`);\n }\n if (options.systemDirection !== undefined) {\n assertDirection(options.systemDirection, \"systemDirection\");\n }\n if (options.systemTextScale !== undefined) {\n assertTextScale(options.systemTextScale, \"systemTextScale\");\n }\n if (options.systemReducedMotion !== undefined) {\n assertBoolean(options.systemReducedMotion, \"systemReducedMotion\");\n }\n if (options.parent !== undefined) {\n validateResolvedDesignSystemEnvironment(options.parent);\n }\n\n const theme =\n input.theme ?? options.parent?.theme ?? designSystemEnvironmentDefaults.theme;\n return {\n theme: theme === \"system\" ? options.systemTheme : theme,\n direction:\n input.direction ??\n options.parent?.direction ??\n options.systemDirection ??\n designSystemEnvironmentDefaults.direction,\n textScale:\n input.textScale ??\n options.parent?.textScale ??\n options.systemTextScale ??\n designSystemEnvironmentDefaults.textScale,\n reducedMotion:\n input.reducedMotion ??\n options.parent?.reducedMotion ??\n options.systemReducedMotion ??\n designSystemEnvironmentDefaults.reducedMotion,\n minimumVisualTarget:\n input.minimumVisualTarget ??\n options.parent?.minimumVisualTarget ??\n designSystemEnvironmentDefaults.minimumVisualTarget,\n density:\n input.density ??\n options.parent?.density ??\n designSystemEnvironmentDefaults.density,\n };\n}\n\n/**\n * Resolves the portable Provider value without owning React/RN Context. A\n * renderer stores this object in its own context and feeds `palette` directly\n * to recipe color resolution.\n */\nexport function resolveDesignSystemProviderValue(\n input: DesignSystemEnvironmentInput,\n options: ResolveDesignSystemEnvironmentOptions,\n): DesignSystemProviderValue {\n const environment = resolveDesignSystemEnvironment(input, options);\n const brandOverride = options.brandPalette?.[environment.theme];\n const basePalette = options.designProfile?.palette[environment.theme] ?? THEMES[environment.theme];\n const value = {\n environment,\n ...(options.designProfile === undefined ? {} : { designProfile: options.designProfile }),\n palette: {\n theme: brandOverride === undefined\n ? basePalette\n : { ...basePalette, ...brandOverride },\n statusAccents: ACCENTS[environment.theme],\n statusAccentFills: accentFill,\n },\n };\n validateDesignSystemProviderValue(value);\n return value;\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type ResolvedTheme, type ThemeColors } from "./colors.js";
|
|
1
|
+
import { type AccentTone, type ResolvedTheme, type ThemeColors } from "./colors.js";
|
|
2
2
|
/** Pair thresholds and their rationale: docs/brand-boundary.md. */
|
|
3
3
|
export type PaletteContrastRule = Readonly<{
|
|
4
4
|
foreground: keyof ThemeColors;
|
|
5
|
-
background: keyof ThemeColors
|
|
5
|
+
background: keyof ThemeColors | `accentFill.${AccentTone}`;
|
|
6
6
|
minimum: number;
|
|
7
7
|
kind: "text" | "non-text";
|
|
8
8
|
}>;
|
|
@@ -12,6 +12,8 @@ export type PaletteContrastFinding = PaletteContrastRule & Readonly<{
|
|
|
12
12
|
export declare const paletteContrastRules: readonly PaletteContrastRule[];
|
|
13
13
|
/** WCAG 2.x contrast ratio between two six-digit hex colors. */
|
|
14
14
|
export declare function contrastRatio(foreground: string, background: string): number;
|
|
15
|
+
/** Fixed status fills remain outside the product palette, but participate in the same report. */
|
|
16
|
+
export declare function resolveContrastBackground(palette: Readonly<ThemeColors>, key: PaletteContrastRule["background"]): string;
|
|
15
17
|
/** Pairs of a resolved theme palette that fall below their threshold; empty means it passes. */
|
|
16
18
|
export declare function checkPaletteContrast(palette: Readonly<ThemeColors>): readonly PaletteContrastFinding[];
|
|
17
19
|
/** Checks a `brandPalette` the way the Provider applies it: each theme merged over the HJM defaults. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"palette-contrast.d.ts","sourceRoot":"","sources":["../src/palette-contrast.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"palette-contrast.d.ts","sourceRoot":"","sources":["../src/palette-contrast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAExG,mEAAmE;AACnE,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,UAAU,EAAE,MAAM,WAAW,CAAC;IAC9B,UAAU,EAAE,MAAM,WAAW,GAAG,cAAc,UAAU,EAAE,CAAC;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;CAC3B,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,mBAAmB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAKvF,eAAO,MAAM,oBAAoB,EAAE,SAAS,mBAAmB,EAe9D,CAAC;AAaF,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAI5E;AAED,iGAAiG;AACjG,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,mBAAmB,CAAC,YAAY,CAAC,GAAG,MAAM,CAExH;AAED,gGAAgG;AAChG,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAC7B,SAAS,sBAAsB,EAAE,CAOnC;AAED,wGAAwG;AACxG,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GACrF,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,SAAS,sBAAsB,EAAE,CAAC,CAAC,CAKpE;AAED;;;;oFAIoF;AACpF,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,CASnG"}
|
package/dist/palette-contrast.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { THEMES } from "./colors.js";
|
|
1
|
+
import { THEMES, accentFill } from "./colors.js";
|
|
2
2
|
const readable = ["text", "textBody", "textMuted", "textSub", "contentBrand", "danger"];
|
|
3
3
|
const surfaces = ["bg", "surface"];
|
|
4
4
|
export const paletteContrastRules = [
|
|
5
5
|
...readable.flatMap((foreground) => surfaces.map((background) => ({ foreground, background, minimum: 4.5, kind: "text" }))),
|
|
6
6
|
{ foreground: "onPrimary", background: "primary", minimum: 4.5, kind: "text" },
|
|
7
7
|
{ foreground: "onDanger", background: "dangerFill", minimum: 4.5, kind: "text" },
|
|
8
|
+
// Filled badges use a separate ink/fill pair, independent of primary buttons.
|
|
9
|
+
...["neutralFill", "strongFill"].map(background => ({ foreground: "onStatusFill", background, minimum: 4.5, kind: "text" })),
|
|
10
|
+
...Object.keys(accentFill).map(tone => ({ foreground: "onStatusFill", background: `accentFill.${tone}`, minimum: 4.5, kind: "text" })),
|
|
8
11
|
...["primary", "borderControl"].flatMap((foreground) => surfaces.map((background) => ({ foreground, background, minimum: 3, kind: "non-text" }))),
|
|
9
12
|
// textWeak is the disabled/decorative/placeholder tier, exempt from text AA;
|
|
10
13
|
// it also paints border.strong on canvas, which must stay a visible boundary.
|
|
@@ -26,11 +29,15 @@ export function contrastRatio(foreground, background) {
|
|
|
26
29
|
const b = luminance(background);
|
|
27
30
|
return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
|
|
28
31
|
}
|
|
32
|
+
/** Fixed status fills remain outside the product palette, but participate in the same report. */
|
|
33
|
+
export function resolveContrastBackground(palette, key) {
|
|
34
|
+
return key.startsWith("accentFill.") ? accentFill[key.slice("accentFill.".length)] : palette[key];
|
|
35
|
+
}
|
|
29
36
|
/** Pairs of a resolved theme palette that fall below their threshold; empty means it passes. */
|
|
30
37
|
export function checkPaletteContrast(palette) {
|
|
31
38
|
const findings = [];
|
|
32
39
|
for (const rule of paletteContrastRules) {
|
|
33
|
-
const ratio = contrastRatio(palette[rule.foreground], palette
|
|
40
|
+
const ratio = contrastRatio(palette[rule.foreground], resolveContrastBackground(palette, rule.background));
|
|
34
41
|
if (ratio < rule.minimum)
|
|
35
42
|
findings.push({ ...rule, ratio: Math.round(ratio * 100) / 100 });
|
|
36
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"palette-contrast.js","sourceRoot":"","sources":["../src/palette-contrast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"palette-contrast.js","sourceRoot":"","sources":["../src/palette-contrast.ts"],"names":[],"mappings":"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","sourcesContent":["import { THEMES, accentFill, type AccentTone, type ResolvedTheme, type ThemeColors } from \"./colors.js\";\n\n/** Pair thresholds and their rationale: docs/brand-boundary.md. */\nexport type PaletteContrastRule = Readonly<{\n foreground: keyof ThemeColors;\n background: keyof ThemeColors | `accentFill.${AccentTone}`;\n minimum: number;\n kind: \"text\" | \"non-text\";\n}>;\n\nexport type PaletteContrastFinding = PaletteContrastRule & Readonly<{ ratio: number }>;\n\nconst readable = [\"text\", \"textBody\", \"textMuted\", \"textSub\", \"contentBrand\", \"danger\"] as const;\nconst surfaces = [\"bg\", \"surface\"] as const;\n\nexport const paletteContrastRules: readonly PaletteContrastRule[] = [\n ...readable.flatMap((foreground) =>\n surfaces.map((background) => ({ foreground, background, minimum: 4.5, kind: \"text\" as const })),\n ),\n { foreground: \"onPrimary\", background: \"primary\", minimum: 4.5, kind: \"text\" },\n { foreground: \"onDanger\", background: \"dangerFill\", minimum: 4.5, kind: \"text\" },\n // Filled badges use a separate ink/fill pair, independent of primary buttons.\n ...([\"neutralFill\", \"strongFill\"] as const).map(background => ({ foreground: \"onStatusFill\" as const, background, minimum: 4.5, kind: \"text\" as const })),\n ...(Object.keys(accentFill) as AccentTone[]).map(tone => ({ foreground: \"onStatusFill\" as const, background: `accentFill.${tone}` as const, minimum: 4.5, kind: \"text\" as const })),\n ...([\"primary\", \"borderControl\"] as const).flatMap((foreground) =>\n surfaces.map((background) => ({ foreground, background, minimum: 3, kind: \"non-text\" as const })),\n ),\n // textWeak is the disabled/decorative/placeholder tier, exempt from text AA;\n // it also paints border.strong on canvas, which must stay a visible boundary.\n { foreground: \"textWeak\", background: \"bg\", minimum: 3, kind: \"non-text\" },\n];\n\nconst sixDigitHex = /^#[0-9a-f]{6}$/i;\n\nfunction luminance(hex: string): number {\n if (!sixDigitHex.test(hex)) throw new TypeError(`Expected a six-digit hex color, got ${hex}`);\n const [r, g, b] = [1, 3, 5].map((offset) => {\n const channel = Number.parseInt(hex.slice(offset, offset + 2), 16) / 255;\n return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;\n }) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG 2.x contrast ratio between two six-digit hex colors. */\nexport function contrastRatio(foreground: string, background: string): number {\n const a = luminance(foreground);\n const b = luminance(background);\n return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);\n}\n\n/** Fixed status fills remain outside the product palette, but participate in the same report. */\nexport function resolveContrastBackground(palette: Readonly<ThemeColors>, key: PaletteContrastRule[\"background\"]): string {\n return key.startsWith(\"accentFill.\") ? accentFill[key.slice(\"accentFill.\".length) as AccentTone] : palette[key as keyof ThemeColors];\n}\n\n/** Pairs of a resolved theme palette that fall below their threshold; empty means it passes. */\nexport function checkPaletteContrast(\n palette: Readonly<ThemeColors>,\n): readonly PaletteContrastFinding[] {\n const findings: PaletteContrastFinding[] = [];\n for (const rule of paletteContrastRules) {\n const ratio = contrastRatio(palette[rule.foreground], resolveContrastBackground(palette, rule.background));\n if (ratio < rule.minimum) findings.push({ ...rule, ratio: Math.round(ratio * 100) / 100 });\n }\n return findings;\n}\n\n/** Checks a `brandPalette` the way the Provider applies it: each theme merged over the HJM defaults. */\nexport function checkBrandPaletteContrast(\n brandPalette: Readonly<Partial<Record<ResolvedTheme, Readonly<Partial<ThemeColors>>>>>,\n): Readonly<Record<ResolvedTheme, readonly PaletteContrastFinding[]>> {\n return {\n light: checkPaletteContrast({ ...THEMES.light, ...brandPalette.light }),\n dark: checkPaletteContrast({ ...THEMES.dark, ...brandPalette.dark }),\n };\n}\n\n/** Shared whole-surface fill adaptation. This palette-only entry keeps ordinary\n * renderer imports independent of the optional preset registry/effect descriptors.\n * The supported 0.85..1 interval keeps readable foregrounds outside the backdrop\n * luminance interval; testing its black/white endpoints bounds any opaque backdrop.\n * See docs/design-profile.md for why a reference card's low alpha is not copied. */\nexport function resolveSurfaceFillOpacity(requested: number, palette: Readonly<ThemeColors>): number {\n if (!Number.isFinite(requested) || requested < 0.85 || requested > 1) throw new RangeError(\"Surface fill opacity must be between 0.85 and 1\");\n const channels = [1, 3, 5].map(offset => Number.parseInt(palette.bg.slice(offset, offset + 2), 16));\n const rules = paletteContrastRules.filter(rule => rule.background === \"bg\");\n for (let opacity = requested; opacity < 1; opacity = Math.min(1, opacity + 0.01)) {\n const endpoints = [0, 255].map(backdrop => \"#\" + channels.map(channel => Math.round(channel * opacity + backdrop * (1 - opacity)).toString(16).padStart(2, \"0\")).join(\"\"));\n if (endpoints.every(color => rules.every(rule => contrastRatio(palette[rule.foreground], color) >= rule.minimum))) return opacity;\n }\n return 1;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic-colors.d.ts","sourceRoot":"","sources":["../src/semantic-colors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"semantic-colors.d.ts","sourceRoot":"","sources":["../src/semantic-colors.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;QAOvB;;;;WAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAkBH,iDAAiD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA4DjD;;;WAGG;;;;;;;CAGG,CAAC"}
|
package/dist/semantic-colors.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { stateLayer } from "./foundations.js";
|
|
2
|
+
import { accentTint } from "./colors.js";
|
|
1
3
|
import { accentColor, themeColor } from "./color-references.js";
|
|
2
4
|
/**
|
|
3
5
|
* Stable role aliases above the legacy ThemeColors key set. New recipes should
|
|
@@ -58,40 +60,40 @@ export const semanticColors = {
|
|
|
58
60
|
feedback: {
|
|
59
61
|
info: {
|
|
60
62
|
foreground: accentColor("info"),
|
|
61
|
-
background: accentColor("info",
|
|
62
|
-
badgeBackground: accentColor("info",
|
|
63
|
-
border: accentColor("info",
|
|
63
|
+
background: accentColor("info", accentTint.weak),
|
|
64
|
+
badgeBackground: accentColor("info", accentTint.weak),
|
|
65
|
+
border: accentColor("info", accentTint.border),
|
|
64
66
|
},
|
|
65
67
|
success: {
|
|
66
68
|
foreground: accentColor("success"),
|
|
67
|
-
background: accentColor("success",
|
|
68
|
-
badgeBackground: accentColor("success",
|
|
69
|
-
border: accentColor("success",
|
|
69
|
+
background: accentColor("success", accentTint.weak),
|
|
70
|
+
badgeBackground: accentColor("success", accentTint.weak),
|
|
71
|
+
border: accentColor("success", accentTint.border),
|
|
70
72
|
},
|
|
71
73
|
warning: {
|
|
72
74
|
foreground: accentColor("warning"),
|
|
73
|
-
background: accentColor("warning",
|
|
74
|
-
badgeBackground: accentColor("warning",
|
|
75
|
-
border: accentColor("warning",
|
|
75
|
+
background: accentColor("warning", accentTint.weak),
|
|
76
|
+
badgeBackground: accentColor("warning", accentTint.weak),
|
|
77
|
+
border: accentColor("warning", accentTint.border),
|
|
76
78
|
},
|
|
77
79
|
attention: {
|
|
78
80
|
foreground: accentColor("attention"),
|
|
79
|
-
background: accentColor("attention",
|
|
80
|
-
badgeBackground: accentColor("attention",
|
|
81
|
-
border: accentColor("attention",
|
|
81
|
+
background: accentColor("attention", accentTint.weak),
|
|
82
|
+
badgeBackground: accentColor("attention", accentTint.weak),
|
|
83
|
+
border: accentColor("attention", accentTint.border),
|
|
82
84
|
},
|
|
83
85
|
danger: {
|
|
84
86
|
foreground: themeColor("danger"),
|
|
85
|
-
background: themeColor("danger",
|
|
86
|
-
badgeBackground: themeColor("danger",
|
|
87
|
-
border: themeColor("danger",
|
|
87
|
+
background: themeColor("danger", accentTint.weak),
|
|
88
|
+
badgeBackground: themeColor("danger", accentTint.weak),
|
|
89
|
+
border: themeColor("danger", accentTint.border),
|
|
88
90
|
},
|
|
89
91
|
},
|
|
90
92
|
interaction: {
|
|
91
|
-
hover: themeColor("text",
|
|
92
|
-
focus: themeColor("contentBrand",
|
|
93
|
-
pressed: themeColor("text",
|
|
94
|
-
selected: themeColor("primary",
|
|
93
|
+
hover: themeColor("text", stateLayer.hover),
|
|
94
|
+
focus: themeColor("contentBrand", stateLayer.focus),
|
|
95
|
+
pressed: themeColor("text", stateLayer.pressed),
|
|
96
|
+
selected: themeColor("primary", stateLayer.selected),
|
|
95
97
|
/**
|
|
96
98
|
* Lower edge of a raised object, composited over its own fill so one shade
|
|
97
99
|
* darkens any brand color (BottomNavigation raised tile, Spint 2026-10-13).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic-colors.js","sourceRoot":"","sources":["../src/semantic-colors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC;IACxB,OAAO,EAAE;QACP,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC;QAC9B,MAAM,EAAE,UAAU,CAAC,YAAY,CAAC;QAChC,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC;QACxB,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC;QAClC;;;;WAIG;QACH,WAAW,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC;KACtC;IACD,OAAO,EAAE;QACP,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC;QAC3B,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC;QAC5B,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC;QAClC,QAAQ,EAAE,UAAU,CAAC,SAAS,CAAC;QAC/B,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC;QAClC,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC;QACjC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC;QAC5B,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC;QAChC,4EAA4E;QAC5E,aAAa,EAAE,UAAU,CAAC,cAAc,CAAC;KAC1C;IACD,MAAM,EAAE;QACN,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC;QACjC,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC;QAC7B,iDAAiD;QACjD,OAAO,EAAE,UAAU,CAAC,eAAe,CAAC;QACpC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC;QAC9B,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC;QACjC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC;KAC7B;IACD,MAAM,EAAE;QACN,KAAK,EAAE;YACL,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC;YACjC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC;SACjC;QACD,OAAO,EAAE;YACP,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC;YAC5B,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC;YAC3B,uEAAuE;YACvE,2DAA2D;YAC3D,MAAM,EAAE,UAAU,CAAC,eAAe,CAAC;SACpC;QACD,MAAM,EAAE;YACN,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC;YACpC,OAAO,EAAE,UAAU,CAAC,UAAU,CAAC;SAChC;KACF;IACD,QAAQ,EAAE;QACR,IAAI,EAAE;YACJ,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC;YAC/B,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"semantic-colors.js","sourceRoot":"","sources":["../src/semantic-colors.ts"],"names":[],"mappings":"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","sourcesContent":["import { stateLayer } from \"./foundations.js\";\nimport { accentTint } from \"./colors.js\";\nimport { accentColor, themeColor } from \"./color-references.js\";\n\n/**\n * Stable role aliases above the legacy ThemeColors key set. New recipes should\n * prefer these roles so the underlying theme shape can evolve independently.\n */\nexport const semanticColors = {\n canvas: themeColor(\"bg\"),\n surface: {\n default: themeColor(\"surface\"),\n sunken: themeColor(\"surfaceAlt\"),\n raised: themeColor(\"bg\"),\n brand: themeColor(\"surfaceAccent\"),\n /**\n * Loading placeholder fill (Skeleton, ListRow `loading`). A translucent text tint instead of an opaque\n * neutral: it darkens/lightens whatever it sits on, so it stays visible on canvas, Card surfaces and\n * profile palettes whose `surfaceAlt` is as light as `bg` (2026-10-17 Skeleton review, skeleton.md 근거).\n */\n placeholder: themeColor(\"text\", 0.12),\n },\n content: {\n primary: themeColor(\"text\"),\n body: themeColor(\"textBody\"),\n secondary: themeColor(\"textMuted\"),\n tertiary: themeColor(\"textSub\"),\n decorative: themeColor(\"textWeak\"),\n brand: themeColor(\"contentBrand\"),\n danger: themeColor(\"danger\"),\n inverse: themeColor(\"onPrimary\"),\n // Status fills are independent of a product's primary button contrast pair.\n statusInverse: themeColor(\"onStatusFill\"),\n },\n border: {\n subtle: themeColor(\"border\", 0.7),\n default: themeColor(\"border\"),\n /** Resting outline of an interactive control. */\n control: themeColor(\"borderControl\"),\n strong: themeColor(\"textWeak\"),\n focus: themeColor(\"contentBrand\"),\n danger: themeColor(\"danger\"),\n },\n action: {\n brand: {\n background: themeColor(\"primary\"),\n content: themeColor(\"onPrimary\"),\n },\n neutral: {\n background: themeColor(\"bg\"),\n content: themeColor(\"text\"),\n // A control outline is a border role. `textSub` made a resting neutral\n // action read heavier than the selected control beside it.\n border: themeColor(\"borderControl\"),\n },\n danger: {\n background: themeColor(\"dangerFill\"),\n content: themeColor(\"onDanger\"),\n },\n },\n feedback: {\n info: {\n foreground: accentColor(\"info\"),\n background: accentColor(\"info\", accentTint.weak),\n badgeBackground: accentColor(\"info\", accentTint.weak),\n border: accentColor(\"info\", accentTint.border),\n },\n success: {\n foreground: accentColor(\"success\"),\n background: accentColor(\"success\", accentTint.weak),\n badgeBackground: accentColor(\"success\", accentTint.weak),\n border: accentColor(\"success\", accentTint.border),\n },\n warning: {\n foreground: accentColor(\"warning\"),\n background: accentColor(\"warning\", accentTint.weak),\n badgeBackground: accentColor(\"warning\", accentTint.weak),\n border: accentColor(\"warning\", accentTint.border),\n },\n attention: {\n foreground: accentColor(\"attention\"),\n background: accentColor(\"attention\", accentTint.weak),\n badgeBackground: accentColor(\"attention\", accentTint.weak),\n border: accentColor(\"attention\", accentTint.border),\n },\n danger: {\n foreground: themeColor(\"danger\"),\n background: themeColor(\"danger\", accentTint.weak),\n badgeBackground: themeColor(\"danger\", accentTint.weak),\n border: themeColor(\"danger\", accentTint.border),\n },\n },\n interaction: {\n hover: themeColor(\"text\", stateLayer.hover),\n focus: themeColor(\"contentBrand\", stateLayer.focus),\n pressed: themeColor(\"text\", stateLayer.pressed),\n selected: themeColor(\"primary\", stateLayer.selected),\n /**\n * Lower edge of a raised object, composited over its own fill so one shade\n * darkens any brand color (BottomNavigation raised tile, Spint 2026-10-13).\n */\n depth: themeColor(\"text\", 0.45),\n },\n} as const;\n"]}
|
package/dist/theme-studio.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare function studioReport(palette: StudioPalette, theme: ResolvedThem
|
|
|
6
6
|
ratio: number;
|
|
7
7
|
pass: boolean;
|
|
8
8
|
foreground: keyof ThemeColors;
|
|
9
|
-
background: keyof ThemeColors
|
|
9
|
+
background: keyof ThemeColors | `accentFill.${import("./colors.js").AccentTone}`;
|
|
10
10
|
minimum: number;
|
|
11
11
|
kind: "text" | "non-text";
|
|
12
12
|
}[];
|
package/dist/theme-studio.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { THEMES } from "./colors.js";
|
|
2
|
-
import { contrastRatio, paletteContrastRules } from "./palette-contrast.js";
|
|
2
|
+
import { contrastRatio, paletteContrastRules, resolveContrastBackground } from "./palette-contrast.js";
|
|
3
3
|
export function applyStudioColor(palette, theme, role, color) {
|
|
4
4
|
if (!/^#[0-9a-f]{6}$/i.test(color.trim()))
|
|
5
5
|
throw new TypeError("Expected a six-digit hex color");
|
|
@@ -7,7 +7,7 @@ export function applyStudioColor(palette, theme, role, color) {
|
|
|
7
7
|
}
|
|
8
8
|
export function studioReport(palette, theme) {
|
|
9
9
|
const resolved = { ...THEMES[theme], ...palette[theme] };
|
|
10
|
-
return paletteContrastRules.map(rule => ({ ...rule, ratio: contrastRatio(resolved[rule.foreground], resolved
|
|
10
|
+
return paletteContrastRules.map(rule => ({ ...rule, ratio: contrastRatio(resolved[rule.foreground], resolveContrastBackground(resolved, rule.background)), pass: contrastRatio(resolved[rule.foreground], resolveContrastBackground(resolved, rule.background)) >= rule.minimum }));
|
|
11
11
|
}
|
|
12
12
|
export function exportStudioPalette(palette) {
|
|
13
13
|
// Export the actual provider overrides, not invented derived hues or product defaults.
|
package/dist/theme-studio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-studio.js","sourceRoot":"","sources":["../src/theme-studio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAwC,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"theme-studio.js","sourceRoot":"","sources":["../src/theme-studio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAwC,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAGvG,MAAM,UAAU,gBAAgB,CAAC,OAAqB,EAAE,KAAmB,EAAE,IAAoB,EAAE,KAAY;IAC9G,IAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAAC,MAAM,IAAI,SAAS,CAAC,gCAAgC,CAAC,CAAC;IAC/F,OAAO,EAAC,GAAG,OAAO,EAAC,CAAC,KAAK,CAAC,EAAC,EAAC,GAAG,OAAO,CAAC,KAAK,CAAC,EAAC,CAAC,IAAI,CAAC,EAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAC,EAAC,CAAC;AACnF,CAAC;AACD,MAAM,UAAU,YAAY,CAAC,OAAqB,EAAC,KAAmB;IACrE,MAAM,QAAQ,GAAC,EAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAC,GAAG,OAAO,CAAC,KAAK,CAAC,EAAC,CAAC;IACpD,OAAO,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAA,EAAE,CAAA,CAAC,EAAC,GAAG,IAAI,EAAC,KAAK,EAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,EAAC,IAAI,EAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,IAAE,IAAI,CAAC,OAAO,EAAC,CAAC,CAAC,CAAC;AACzQ,CAAC;AACD,MAAM,UAAU,mBAAmB,CAAC,OAAqB;IACxD,uFAAuF;IACvF,OAAO,IAAI,CAAC,SAAS,CAAC,EAAC,YAAY,EAAC,OAAO,EAAC,EAAC,IAAI,EAAC,CAAC,CAAC,CAAC;AACtD,CAAC","sourcesContent":["import { THEMES, type ResolvedTheme, type ThemeColors } from \"./colors.js\";\nimport { contrastRatio, paletteContrastRules, resolveContrastBackground } from \"./palette-contrast.js\";\nexport type StudioPalette = Partial<Record<ResolvedTheme, Partial<ThemeColors>>>;\nexport type StudioColorRole = \"primary\" | \"onPrimary\" | \"contentBrand\";\nexport function applyStudioColor(palette:StudioPalette, theme:ResolvedTheme, role:StudioColorRole, color:string):StudioPalette {\n if(!/^#[0-9a-f]{6}$/i.test(color.trim()))throw new TypeError(\"Expected a six-digit hex color\");\n return {...palette,[theme]:{...palette[theme],[role]:color.trim().toLowerCase()}};\n}\nexport function studioReport(palette:StudioPalette,theme:ResolvedTheme){\n const resolved={...THEMES[theme],...palette[theme]};\n return paletteContrastRules.map(rule=>({...rule,ratio:contrastRatio(resolved[rule.foreground],resolveContrastBackground(resolved, rule.background)),pass:contrastRatio(resolved[rule.foreground],resolveContrastBackground(resolved, rule.background))>=rule.minimum}));\n}\nexport function exportStudioPalette(palette:StudioPalette){\n // Export the actual provider overrides, not invented derived hues or product defaults.\n return JSON.stringify({brandPalette:palette},null,2);\n}\n"]}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAiB,CAAC","sourcesContent":["/** Package release shown by documentation surfaces. Kept in sync by a test. */\nexport const designSystemVersion = \"1.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAiB,CAAC","sourcesContent":["/** Package release shown by documentation surfaces. Kept in sync by a test. */\nexport const designSystemVersion = \"1.37.0\" as const;\n"]}
|
package/docs/brand-boundary.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 브랜드 경계 — 제품이 바꿀 수 있는 것과 그 경로
|
|
2
2
|
|
|
3
|
-
상태: 규범 · 검토일: 2026-10-
|
|
3
|
+
상태: 규범 · 검토일: 2026-10-20 · 이 문서가 브랜드·테마 주입 규칙의 단일 원본이다.
|
|
4
4
|
[theming.md](./theming.md)는 사용법 예시, [consumer-policy.md](./consumer-policy.md)는 채택 정책,
|
|
5
5
|
[design-system-provider.md](./design-system-provider.md)는 환경 축 설계를 다루며 브랜드 규칙은 여기로 링크한다.
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ CSS 변수 재정의, 제품 자체 토큰 생성기)였고, 문서 세 개가
|
|
|
12
12
|
## 1. 지원하는 제품 설정 경로
|
|
13
13
|
|
|
14
14
|
- 색만 바꾸는 제품 브랜드는 Provider의 `brandPalette` prop으로 넣는다(`<HjmProvider brandPalette={…}>`,
|
|
15
|
-
`<HjmNativeProvider brandPalette={…}>`, 1.5.0). theme별로
|
|
15
|
+
`<HjmNativeProvider brandPalette={…}>`, 1.5.0). theme별로 20개 `ThemeColors` key 중 필요한 것만 넘기고,
|
|
16
16
|
나머지는 선택된 프로필 또는 HJM 기본값을 쓴다(부분 병합). Provider는 계속 OS theme·글자 크기·모션 설정을 따르고,
|
|
17
17
|
중첩 Provider는 가장 가까운 상위의 `brandPalette`를 물려받는다.
|
|
18
18
|
- 상태 강조색(`statusAccents`·`statusAccentFills`)은 덮을 수 없다. "오류·성공"과 "브랜드"가 같은 색이 되는
|
|
@@ -22,7 +22,7 @@ CSS 변수 재정의, 제품 자체 토큰 생성기)였고, 문서 세 개가
|
|
|
22
22
|
motion을 직접 구독해야 했다. 이 우회를 쓰는 제품은 prop으로 옮긴다.
|
|
23
23
|
- **전체 `value`를 손으로 조립하는 것**(resolver 결과의 `palette.theme`을 통째로 바꾸는 것 포함)은 테스트·임베딩용이지
|
|
24
24
|
브랜드 경로가 아니다. 부분 병합으로 표현할 수 없는 요구는 계약 공백이므로 이슈로 올린다.
|
|
25
|
-
|
|
25
|
+
20개 key를 모두 채운 `brandPalette`는 허용되지만 아래 대비 검사를 반드시 통과해야 한다.
|
|
26
26
|
|
|
27
27
|
2026-10-07 사용자 요청으로 색뿐 아니라 질감·컴포넌트 기본 전환·구성·화면 배치를 한 번 선택하는
|
|
28
28
|
[디자인 프로필](./design-profile.md)을 제공한다. 제공 버전과 지원 축은 해당 계약을 따른다. `defineHjmDesignProfile`로 정규화한
|
|
@@ -30,6 +30,8 @@ CSS 변수 재정의, 제품 자체 토큰 생성기)였고, 문서 세 개가
|
|
|
30
30
|
허용하지 않는다. `brandPalette`는 프로필의 해당 light/dark 팔레트 위에 병합된다. 글꼴 자산·로고·문구·데이터는
|
|
31
31
|
제품 소유이며 현재 연결 범위와 미지원 표현은 프로필 계약에 명시한다.
|
|
32
32
|
|
|
33
|
+
안전 영역 등 환경을 연결하는 `value={resolvedValue}` 중첩 Provider도 현재 모드의 해석된 브랜드 팔레트를 하위 Provider에 전달한다. 명시적으로 새 `brandPalette`를 지정하면 기존처럼 그 범위를 대체한다. 이 구분은 환경 bridge 뒤의 일반 Provider가 브랜드색을 기본값으로 되돌리던 문제를 막는다.
|
|
34
|
+
|
|
33
35
|
## 2. 모든 브랜드 팔레트는 대비 검사를 통과해야 한다
|
|
34
36
|
|
|
35
37
|
`@hjmds/design-contracts/palette-contrast`의 `checkBrandPaletteContrast(brandPalette)`가 Provider와 같은 방식으로
|
|
@@ -44,6 +46,7 @@ theme별 병합 결과를 검사하고, theme별 기준 미달 쌍을 돌려준
|
|
|
44
46
|
| `text`·`textBody`·`textMuted`·`textSub` on `bg`·`surface` | 4.5 | WCAG 1.4.3 본문. `textSub`는 `Text tone="subtle"`의 실제 글자색이다 |
|
|
45
47
|
| `contentBrand`·`danger` on `bg`·`surface` | 4.5 | 링크·현재 위치·오류 문구는 글자로 읽힌다 |
|
|
46
48
|
| `onPrimary` on `primary`, `onDanger` on `dangerFill` | 4.5 | 채운 버튼의 라벨 |
|
|
49
|
+
| `onStatusFill` on `neutralFill`·`strongFill`·고정 `accentFill.<tone>` | 4.5 | 채운 Badge의 실제 라벨·바탕 쌍 |
|
|
47
50
|
| `primary`·`borderControl` vs `bg`·`surface` | 3 | WCAG 1.4.11. 채운 컨트롤과 쉬고 있는 컨트롤 윤곽선은 형태로 식별돼야 한다 |
|
|
48
51
|
| `textWeak` vs `bg` | 3 | 아래 참조 |
|
|
49
52
|
|
package/docs/design-profile.md
CHANGED
|
@@ -38,7 +38,7 @@ export const productDesign = defineHjmDesignProfile({
|
|
|
38
38
|
|
|
39
39
|
| 축 | 중립 기본값 | 참고 프리셋의 차이 |
|
|
40
40
|
| --- | --- | --- |
|
|
41
|
-
| palette | 현재 HJM light/dark
|
|
41
|
+
| palette | 현재 HJM light/dark 20 semantic roles | 레트로의 잉크/황갈색, 종이의 따뜻한 중립색, 숲의 녹색 |
|
|
42
42
|
| tokens | 기존 radius/fontFamily/typography/heading/shadow | 모서리·글자 크기/행간/강조·그림자와 일반 monospace fallback; 폰트 자산은 번들하지 않음 |
|
|
43
43
|
| material | canvas/card/surface 모두 null | 레트로 noise, 종이 grain+ruled, 숲 mesh+glow; 오로라만 active=true, 나머지는 정적 |
|
|
44
44
|
| interactions | contentTransition=fade, selectionMotion=none | 레트로 slide, 종이 fade, 숲 rise와 slide 선택 배경 |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Component maturity and evidence manifest
|
|
2
2
|
|
|
3
|
-
> Generated from `@hjmds/design-contracts` 1.
|
|
3
|
+
> Generated from `@hjmds/design-contracts` 1.37.0. Do not edit this file directly; run `pnpm contracts:sync`.
|
|
4
4
|
|
|
5
5
|
This document is the human-readable projection of the same catalog and Showcase manifest consumed by product CI.
|
|
6
6
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"designSystemVersion": "1.
|
|
3
|
+
"designSystemVersion": "1.37.0",
|
|
4
4
|
"source": "packages/design-contracts/docs/generated/showcase-manifest.json",
|
|
5
5
|
"surfaces": {
|
|
6
6
|
"web": {
|
|
7
7
|
"packageName": "@hjmds/react",
|
|
8
|
-
"packageVersion": "1.
|
|
8
|
+
"packageVersion": "1.37.0",
|
|
9
9
|
"activeComponents": 131,
|
|
10
10
|
"claimedComponents": 131,
|
|
11
11
|
"completeScenarioComponents": 130,
|
|
@@ -7062,7 +7062,7 @@
|
|
|
7062
7062
|
},
|
|
7063
7063
|
"native": {
|
|
7064
7064
|
"packageName": "@hjmds/react-native",
|
|
7065
|
-
"packageVersion": "1.
|
|
7065
|
+
"packageVersion": "1.37.0",
|
|
7066
7066
|
"activeComponents": 113,
|
|
7067
7067
|
"claimedComponents": 113,
|
|
7068
7068
|
"completeScenarioComponents": 110,
|