@hjmds/design-contracts 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog.d.ts +39 -47
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +13 -13
- package/dist/catalog.js.map +1 -1
- package/dist/colors.js +1 -1
- package/dist/colors.js.map +1 -1
- package/dist/design-system-provider.d.ts +4 -3
- package/dist/design-system-provider.d.ts.map +1 -1
- package/dist/design-system-provider.js +4 -3
- package/dist/design-system-provider.js.map +1 -1
- package/dist/palette-contrast.d.ts +19 -0
- package/dist/palette-contrast.d.ts.map +1 -0
- package/dist/palette-contrast.js +46 -0
- package/dist/palette-contrast.js.map +1 -0
- package/dist/showcase.d.ts.map +1 -1
- package/dist/showcase.js +3 -1
- package/dist/showcase.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 +89 -0
- package/docs/catalog-freeze.json +120 -0
- package/docs/consumer-policy.md +17 -13
- package/docs/design-system-provider.md +4 -4
- package/docs/generated/component-maturity.md +18 -18
- package/docs/generated/renderer-evidence.json +2275 -1342
- package/docs/generated/renderer-evidence.md +178 -178
- package/docs/generated/showcase-manifest.json +40 -50
- package/docs/stable-core.md +18 -1
- package/docs/tag.md +7 -8
- package/docs/theme-palette.md +12 -0
- package/docs/theming.md +17 -22
- package/package.json +7 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { THEMES } from "./colors.js";
|
|
2
|
+
const readable = ["text", "textBody", "textMuted", "textSub", "contentBrand", "danger"];
|
|
3
|
+
const surfaces = ["bg", "surface"];
|
|
4
|
+
export const paletteContrastRules = [
|
|
5
|
+
...readable.flatMap((foreground) => surfaces.map((background) => ({ foreground, background, minimum: 4.5, kind: "text" }))),
|
|
6
|
+
{ foreground: "onPrimary", background: "primary", minimum: 4.5, kind: "text" },
|
|
7
|
+
{ foreground: "onDanger", background: "dangerFill", minimum: 4.5, kind: "text" },
|
|
8
|
+
...["primary", "borderControl"].flatMap((foreground) => surfaces.map((background) => ({ foreground, background, minimum: 3, kind: "non-text" }))),
|
|
9
|
+
// textWeak is the disabled/decorative/placeholder tier, exempt from text AA;
|
|
10
|
+
// it also paints border.strong on canvas, which must stay a visible boundary.
|
|
11
|
+
{ foreground: "textWeak", background: "bg", minimum: 3, kind: "non-text" },
|
|
12
|
+
];
|
|
13
|
+
const sixDigitHex = /^#[0-9a-f]{6}$/i;
|
|
14
|
+
function luminance(hex) {
|
|
15
|
+
if (!sixDigitHex.test(hex))
|
|
16
|
+
throw new TypeError(`Expected a six-digit hex color, got ${hex}`);
|
|
17
|
+
const [r, g, b] = [1, 3, 5].map((offset) => {
|
|
18
|
+
const channel = Number.parseInt(hex.slice(offset, offset + 2), 16) / 255;
|
|
19
|
+
return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
|
|
20
|
+
});
|
|
21
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
22
|
+
}
|
|
23
|
+
/** WCAG 2.x contrast ratio between two six-digit hex colors. */
|
|
24
|
+
export function contrastRatio(foreground, background) {
|
|
25
|
+
const a = luminance(foreground);
|
|
26
|
+
const b = luminance(background);
|
|
27
|
+
return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
|
|
28
|
+
}
|
|
29
|
+
/** Pairs of a resolved theme palette that fall below their threshold; empty means it passes. */
|
|
30
|
+
export function checkPaletteContrast(palette) {
|
|
31
|
+
const findings = [];
|
|
32
|
+
for (const rule of paletteContrastRules) {
|
|
33
|
+
const ratio = contrastRatio(palette[rule.foreground], palette[rule.background]);
|
|
34
|
+
if (ratio < rule.minimum)
|
|
35
|
+
findings.push({ ...rule, ratio: Math.round(ratio * 100) / 100 });
|
|
36
|
+
}
|
|
37
|
+
return findings;
|
|
38
|
+
}
|
|
39
|
+
/** Checks a `brandPalette` the way the Provider applies it: each theme merged over the HJM defaults. */
|
|
40
|
+
export function checkBrandPaletteContrast(brandPalette) {
|
|
41
|
+
return {
|
|
42
|
+
light: checkPaletteContrast({ ...THEMES.light, ...brandPalette.light }),
|
|
43
|
+
dark: checkPaletteContrast({ ...THEMES.dark, ...brandPalette.dark }),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=palette-contrast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"palette-contrast.js","sourceRoot":"","sources":["../src/palette-contrast.ts"],"names":[],"mappings":"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","sourcesContent":["import { THEMES, 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;\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 ...([\"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/** 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], 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"]}
|
package/dist/showcase.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"showcase.d.ts","sourceRoot":"","sources":["../src/showcase.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"showcase.d.ts","sourceRoot":"","sources":["../src/showcase.ts"],"names":[],"mappings":"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"}
|
package/dist/showcase.js
CHANGED
|
@@ -134,8 +134,10 @@ export function getRequiredShowcaseScenarios(entry) {
|
|
|
134
134
|
function isRendererMaturity(status) {
|
|
135
135
|
return status === "stable" || status === "beta";
|
|
136
136
|
}
|
|
137
|
+
// 글자 슬롯이 없어 long-copy를 증명할 수 없는 컴포넌트. 근거: docs/stable-core.md 1.5.0.
|
|
138
|
+
const textlessComponentNames = new Set(["Icon", "IconButton", "Skeleton", "Spinner", "Divider"]);
|
|
137
139
|
function getRendererShowcaseScenarios(entry, activeSurfaces) {
|
|
138
|
-
const requirements =
|
|
140
|
+
const requirements = rendererRequirements.filter((scenario) => scenario !== "long-copy" || !textlessComponentNames.has(entry.name));
|
|
139
141
|
if (entry.behavior) {
|
|
140
142
|
requirements.push("keyboard");
|
|
141
143
|
}
|
package/dist/showcase.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"showcase.js","sourceRoot":"","sources":["../src/showcase.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n componentCatalog,\n getComponentSurfaceStatus,\n type ComponentCatalogEntry,\n type ComponentStatus,\n type ComponentSurface,\n type ComponentSurfaceMaturity,\n type ComponentSurfaceStatus,\n} from \"./catalog.js\";\nimport type { ResolvedTheme } from \"./colors.js\";\nimport type {\n DesignSystemDirection,\n DesignSystemEnvironmentInput,\n DesignSystemTextScale,\n} from \"./design-system-provider.js\";\n\nexport type ShowcaseTheme = ResolvedTheme;\nexport type ShowcaseDirection = DesignSystemDirection;\n/** Closed fixture subset of the Provider's continuous text-scale signal. */\nexport type ShowcaseTextScale = 1 | 1.5 | 2;\nexport type ShowcaseMotionPreference = \"full\" | \"reduced\";\n\nexport type ShowcaseEnvironment = Readonly<{\n id: \"default\" | \"dark\" | \"large-text\" | \"rtl\" | \"reduced-motion\";\n label: string;\n theme: ShowcaseTheme;\n direction: ShowcaseDirection;\n textScale: ShowcaseTextScale;\n motion: ShowcaseMotionPreference;\n}>;\n\n/**\n * A small, deliberate environment matrix catches the high-risk differences\n * without multiplying every story into an unreadable Cartesian product.\n */\nexport const showcaseEnvironmentMatrix = [\n {\n id: \"default\",\n label: \"Light · LTR · 100%\",\n theme: \"light\",\n direction: \"ltr\",\n textScale: 1,\n motion: \"full\",\n },\n {\n id: \"dark\",\n label: \"Dark · LTR · 100%\",\n theme: \"dark\",\n direction: \"ltr\",\n textScale: 1,\n motion: \"full\",\n },\n {\n id: \"large-text\",\n label: \"Light · LTR · 200%\",\n theme: \"light\",\n direction: \"ltr\",\n textScale: 2,\n motion: \"full\",\n },\n {\n id: \"rtl\",\n label: \"Light · RTL · 100%\",\n theme: \"light\",\n direction: \"rtl\",\n textScale: 1,\n motion: \"full\",\n },\n {\n id: \"reduced-motion\",\n label: \"Light · LTR · Reduced motion\",\n theme: \"light\",\n direction: \"ltr\",\n textScale: 1,\n motion: \"reduced\",\n },\n] as const satisfies readonly ShowcaseEnvironment[];\n\n/** Bridges documentation fixtures to the same environment contract products consume. */\nexport function getShowcaseEnvironmentInput(\n environment: ShowcaseEnvironment,\n): DesignSystemEnvironmentInput {\n const textScale: DesignSystemTextScale = environment.textScale;\n return {\n theme: environment.theme,\n direction: environment.direction,\n textScale,\n reducedMotion: environment.motion === \"reduced\",\n };\n}\n\nexport type ShowcaseScenarioId =\n | \"contract\"\n | \"default\"\n | \"dark\"\n | \"long-copy\"\n | \"large-text\"\n | \"rtl\"\n | \"reduced-motion\"\n | \"accessibility\"\n | \"keyboard\"\n | \"platform-parity\";\n\nexport type ShowcaseSurface = \"contract\" | \"web\" | \"native\";\n\nexport type ShowcaseScenario = Readonly<{\n id: ShowcaseScenarioId;\n label: string;\n description: string;\n}>;\n\nexport const showcaseScenarios = [\n {\n id: \"contract\",\n label: \"Contract\",\n description: \"Anatomy, defaults, supported axes, platform and maturity are visible.\",\n },\n {\n id: \"default\",\n label: \"Default\",\n description: \"The normal state renders using recipe defaults without product overrides.\",\n },\n {\n id: \"dark\",\n label: \"Dark\",\n description: \"Semantic colors remain legible on the dark theme.\",\n },\n {\n id: \"long-copy\",\n label: \"Long copy\",\n description: \"Long Korean and English copy wraps without clipping or hiding meaning.\",\n },\n {\n id: \"large-text\",\n label: \"200% text\",\n description: \"Text can grow to 200% without truncating required information.\",\n },\n {\n id: \"rtl\",\n label: \"RTL\",\n description: \"Logical start/end layout and directional icons mirror correctly.\",\n },\n {\n id: \"reduced-motion\",\n label: \"Reduced motion\",\n description: \"Motion follows the recipe reduced-motion fallback.\",\n },\n {\n id: \"accessibility\",\n label: \"Accessibility\",\n description: \"Names, states, relationships, contrast and touch targets are inspectable.\",\n },\n {\n id: \"keyboard\",\n label: \"Keyboard\",\n description: \"Focus order and documented keyboard behavior run as interaction tests.\",\n },\n {\n id: \"platform-parity\",\n label: \"Web / Native parity\",\n description: \"Adaptive renderers preserve intent while using platform-native behavior.\",\n },\n] as const satisfies readonly ShowcaseScenario[];\n\nconst plannedRequirements = [\"contract\"] as const satisfies readonly ShowcaseScenarioId[];\nconst rendererRequirements = [\n \"default\",\n \"dark\",\n \"long-copy\",\n \"large-text\",\n \"rtl\",\n \"reduced-motion\",\n \"accessibility\",\n] as const satisfies readonly Exclude<ShowcaseScenarioId, \"contract\">[];\n\nexport type ShowcaseComponentEntry = Readonly<{\n storyId: string;\n component: ComponentCatalogEntry;\n /** Resolved Web/Native renderer maturity, including legacy catalog inputs. */\n surfaceMaturity: ComponentSurfaceMaturity;\n requirements: readonly ShowcaseEvidenceRequirement[];\n requiredScenarios: readonly ShowcaseScenarioId[];\n requiredSurfaces: readonly ShowcaseSurface[];\n}>;\n\nexport type ShowcaseEvidenceRequirement = Readonly<{\n surface: ShowcaseSurface;\n scenarios: readonly ShowcaseScenarioId[];\n}>;\n\nexport type ShowcaseEvidenceEntry = Readonly<{\n storyId: string;\n surface: ShowcaseSurface;\n scenarios: readonly ShowcaseScenarioId[];\n}>;\n\nexport type ShowcaseCoverageEntry = Readonly<{\n storyId: string;\n component: ComponentCatalogEntry;\n missingEvidence: readonly Readonly<{\n surface: ShowcaseSurface;\n scenario: ShowcaseScenarioId;\n }>[];\n missingSurfaces: readonly ShowcaseSurface[];\n missingScenarios: readonly ShowcaseScenarioId[];\n complete: boolean;\n}>;\n\nexport function getShowcaseStoryId(entry: ComponentCatalogEntry): string {\n const slug = entry.name\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/[^a-zA-Z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .toLowerCase();\n return `${entry.category}/${slug}`;\n}\n\nexport function getRequiredShowcaseScenarios(\n entry: ComponentCatalogEntry,\n): readonly ShowcaseScenarioId[] {\n const activeSurfaces = ([\"web\", \"native\"] as const).filter((surface) =>\n isRendererMaturity(getComponentSurfaceStatus(entry, surface)),\n );\n if (activeSurfaces.length === 0) return plannedRequirements;\n\n return [\"contract\", ...getRendererShowcaseScenarios(entry, activeSurfaces)];\n}\n\nfunction isRendererMaturity(\n status: ComponentSurfaceStatus,\n): status is Extract<ComponentStatus, \"stable\" | \"beta\"> {\n return status === \"stable\" || status === \"beta\";\n}\n\nfunction getRendererShowcaseScenarios(\n entry: ComponentCatalogEntry,\n activeSurfaces: readonly ComponentSurface[],\n): readonly Exclude<ShowcaseScenarioId, \"contract\">[] {\n const requirements: Exclude<ShowcaseScenarioId, \"contract\">[] = [...rendererRequirements];\n if (entry.behavior) {\n requirements.push(\"keyboard\");\n }\n if (\n entry.platform === \"adaptive\" &&\n activeSurfaces.includes(\"web\") &&\n activeSurfaces.includes(\"native\")\n ) {\n requirements.push(\"platform-parity\");\n }\n return requirements;\n}\n\nexport function getRequiredShowcaseSurfaces(\n entry: ComponentCatalogEntry,\n): readonly ShowcaseSurface[] {\n return getRequiredShowcaseEvidence(entry).map(({ surface }) => surface);\n}\n\nexport function getRequiredShowcaseEvidence(\n entry: ComponentCatalogEntry,\n): readonly ShowcaseEvidenceRequirement[] {\n const requirements: ShowcaseEvidenceRequirement[] = [\n { surface: \"contract\", scenarios: [\"contract\"] },\n ];\n const activeSurfaces = ([\"web\", \"native\"] as const).filter((surface) =>\n isRendererMaturity(getComponentSurfaceStatus(entry, surface)),\n );\n const rendererScenarios = getRendererShowcaseScenarios(entry, activeSurfaces);\n for (const surface of activeSurfaces) {\n requirements.push({ surface, scenarios: rendererScenarios });\n }\n return requirements;\n}\n\nexport function createShowcaseManifest(\n entries: readonly ComponentCatalogEntry[] = componentCatalog,\n): readonly ShowcaseComponentEntry[] {\n return entries.map((component) => ({\n storyId: getShowcaseStoryId(component),\n component,\n surfaceMaturity: {\n web: getComponentSurfaceStatus(component, \"web\"),\n native: getComponentSurfaceStatus(component, \"native\"),\n },\n requirements: getRequiredShowcaseEvidence(component),\n requiredScenarios: getRequiredShowcaseScenarios(component),\n requiredSurfaces: getRequiredShowcaseSurfaces(component),\n }));\n}\n\nexport const showcaseManifest = createShowcaseManifest();\n\nexport function createShowcaseCoverage(\n evidence: readonly ShowcaseEvidenceEntry[],\n manifest: readonly ShowcaseComponentEntry[] = showcaseManifest,\n): readonly ShowcaseCoverageEntry[] {\n return manifest.map(({ storyId, component, requirements }) => {\n const componentEvidence = evidence.filter((entry) => entry.storyId === storyId);\n const missingEvidence = requirements.flatMap(({ surface, scenarios }) =>\n scenarios\n .filter(\n (scenario) =>\n !componentEvidence.some(\n (entry) => entry.surface === surface && entry.scenarios.includes(scenario),\n ),\n )\n .map((scenario) => ({ surface, scenario })),\n );\n const missingSurfaces = [...new Set(missingEvidence.map(({ surface }) => surface))];\n const missingScenarios = [...new Set(missingEvidence.map(({ scenario }) => scenario))];\n return {\n storyId,\n component,\n missingEvidence,\n missingSurfaces,\n missingScenarios,\n complete: missingSurfaces.length === 0 && missingScenarios.length === 0,\n };\n });\n}\n\nexport function assertShowcaseCoverage(\n evidence: readonly ShowcaseEvidenceEntry[],\n manifest: readonly ShowcaseComponentEntry[] = showcaseManifest,\n): void {\n const missing = createShowcaseCoverage(evidence, manifest).filter(({ complete }) => !complete);\n if (missing.length === 0) return;\n const details = missing\n .map(({ storyId, missingEvidence }) =>\n `${storyId} (${missingEvidence.map(({ surface, scenario }) => `${surface}/${scenario}`).join(\", \") || \"none\"})`,\n )\n .join(\"\\n\");\n throw new Error(`Showcase evidence is incomplete:\\n${details}`);\n}\n\nexport function summarizeShowcaseMaturity(\n entries: readonly ComponentCatalogEntry[] = componentCatalog,\n): Readonly<Record<ComponentStatus, number>> {\n return entries.reduce<Record<ComponentStatus, number>>(\n (summary, entry) => {\n summary[entry.status] += 1;\n return summary;\n },\n { stable: 0, beta: 0, planned: 0, deprecated: 0 },\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"showcase.js","sourceRoot":"","sources":["../src/showcase.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n componentCatalog,\n getComponentSurfaceStatus,\n type ComponentCatalogEntry,\n type ComponentStatus,\n type ComponentSurface,\n type ComponentSurfaceMaturity,\n type ComponentSurfaceStatus,\n} from \"./catalog.js\";\nimport type { ResolvedTheme } from \"./colors.js\";\nimport type {\n DesignSystemDirection,\n DesignSystemEnvironmentInput,\n DesignSystemTextScale,\n} from \"./design-system-provider.js\";\n\nexport type ShowcaseTheme = ResolvedTheme;\nexport type ShowcaseDirection = DesignSystemDirection;\n/** Closed fixture subset of the Provider's continuous text-scale signal. */\nexport type ShowcaseTextScale = 1 | 1.5 | 2;\nexport type ShowcaseMotionPreference = \"full\" | \"reduced\";\n\nexport type ShowcaseEnvironment = Readonly<{\n id: \"default\" | \"dark\" | \"large-text\" | \"rtl\" | \"reduced-motion\";\n label: string;\n theme: ShowcaseTheme;\n direction: ShowcaseDirection;\n textScale: ShowcaseTextScale;\n motion: ShowcaseMotionPreference;\n}>;\n\n/**\n * A small, deliberate environment matrix catches the high-risk differences\n * without multiplying every story into an unreadable Cartesian product.\n */\nexport const showcaseEnvironmentMatrix = [\n {\n id: \"default\",\n label: \"Light · LTR · 100%\",\n theme: \"light\",\n direction: \"ltr\",\n textScale: 1,\n motion: \"full\",\n },\n {\n id: \"dark\",\n label: \"Dark · LTR · 100%\",\n theme: \"dark\",\n direction: \"ltr\",\n textScale: 1,\n motion: \"full\",\n },\n {\n id: \"large-text\",\n label: \"Light · LTR · 200%\",\n theme: \"light\",\n direction: \"ltr\",\n textScale: 2,\n motion: \"full\",\n },\n {\n id: \"rtl\",\n label: \"Light · RTL · 100%\",\n theme: \"light\",\n direction: \"rtl\",\n textScale: 1,\n motion: \"full\",\n },\n {\n id: \"reduced-motion\",\n label: \"Light · LTR · Reduced motion\",\n theme: \"light\",\n direction: \"ltr\",\n textScale: 1,\n motion: \"reduced\",\n },\n] as const satisfies readonly ShowcaseEnvironment[];\n\n/** Bridges documentation fixtures to the same environment contract products consume. */\nexport function getShowcaseEnvironmentInput(\n environment: ShowcaseEnvironment,\n): DesignSystemEnvironmentInput {\n const textScale: DesignSystemTextScale = environment.textScale;\n return {\n theme: environment.theme,\n direction: environment.direction,\n textScale,\n reducedMotion: environment.motion === \"reduced\",\n };\n}\n\nexport type ShowcaseScenarioId =\n | \"contract\"\n | \"default\"\n | \"dark\"\n | \"long-copy\"\n | \"large-text\"\n | \"rtl\"\n | \"reduced-motion\"\n | \"accessibility\"\n | \"keyboard\"\n | \"platform-parity\";\n\nexport type ShowcaseSurface = \"contract\" | \"web\" | \"native\";\n\nexport type ShowcaseScenario = Readonly<{\n id: ShowcaseScenarioId;\n label: string;\n description: string;\n}>;\n\nexport const showcaseScenarios = [\n {\n id: \"contract\",\n label: \"Contract\",\n description: \"Anatomy, defaults, supported axes, platform and maturity are visible.\",\n },\n {\n id: \"default\",\n label: \"Default\",\n description: \"The normal state renders using recipe defaults without product overrides.\",\n },\n {\n id: \"dark\",\n label: \"Dark\",\n description: \"Semantic colors remain legible on the dark theme.\",\n },\n {\n id: \"long-copy\",\n label: \"Long copy\",\n description: \"Long Korean and English copy wraps without clipping or hiding meaning.\",\n },\n {\n id: \"large-text\",\n label: \"200% text\",\n description: \"Text can grow to 200% without truncating required information.\",\n },\n {\n id: \"rtl\",\n label: \"RTL\",\n description: \"Logical start/end layout and directional icons mirror correctly.\",\n },\n {\n id: \"reduced-motion\",\n label: \"Reduced motion\",\n description: \"Motion follows the recipe reduced-motion fallback.\",\n },\n {\n id: \"accessibility\",\n label: \"Accessibility\",\n description: \"Names, states, relationships, contrast and touch targets are inspectable.\",\n },\n {\n id: \"keyboard\",\n label: \"Keyboard\",\n description: \"Focus order and documented keyboard behavior run as interaction tests.\",\n },\n {\n id: \"platform-parity\",\n label: \"Web / Native parity\",\n description: \"Adaptive renderers preserve intent while using platform-native behavior.\",\n },\n] as const satisfies readonly ShowcaseScenario[];\n\nconst plannedRequirements = [\"contract\"] as const satisfies readonly ShowcaseScenarioId[];\nconst rendererRequirements = [\n \"default\",\n \"dark\",\n \"long-copy\",\n \"large-text\",\n \"rtl\",\n \"reduced-motion\",\n \"accessibility\",\n] as const satisfies readonly Exclude<ShowcaseScenarioId, \"contract\">[];\n\nexport type ShowcaseComponentEntry = Readonly<{\n storyId: string;\n component: ComponentCatalogEntry;\n /** Resolved Web/Native renderer maturity, including legacy catalog inputs. */\n surfaceMaturity: ComponentSurfaceMaturity;\n requirements: readonly ShowcaseEvidenceRequirement[];\n requiredScenarios: readonly ShowcaseScenarioId[];\n requiredSurfaces: readonly ShowcaseSurface[];\n}>;\n\nexport type ShowcaseEvidenceRequirement = Readonly<{\n surface: ShowcaseSurface;\n scenarios: readonly ShowcaseScenarioId[];\n}>;\n\nexport type ShowcaseEvidenceEntry = Readonly<{\n storyId: string;\n surface: ShowcaseSurface;\n scenarios: readonly ShowcaseScenarioId[];\n}>;\n\nexport type ShowcaseCoverageEntry = Readonly<{\n storyId: string;\n component: ComponentCatalogEntry;\n missingEvidence: readonly Readonly<{\n surface: ShowcaseSurface;\n scenario: ShowcaseScenarioId;\n }>[];\n missingSurfaces: readonly ShowcaseSurface[];\n missingScenarios: readonly ShowcaseScenarioId[];\n complete: boolean;\n}>;\n\nexport function getShowcaseStoryId(entry: ComponentCatalogEntry): string {\n const slug = entry.name\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/[^a-zA-Z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .toLowerCase();\n return `${entry.category}/${slug}`;\n}\n\nexport function getRequiredShowcaseScenarios(\n entry: ComponentCatalogEntry,\n): readonly ShowcaseScenarioId[] {\n const activeSurfaces = ([\"web\", \"native\"] as const).filter((surface) =>\n isRendererMaturity(getComponentSurfaceStatus(entry, surface)),\n );\n if (activeSurfaces.length === 0) return plannedRequirements;\n\n return [\"contract\", ...getRendererShowcaseScenarios(entry, activeSurfaces)];\n}\n\nfunction isRendererMaturity(\n status: ComponentSurfaceStatus,\n): status is Extract<ComponentStatus, \"stable\" | \"beta\"> {\n return status === \"stable\" || status === \"beta\";\n}\n\n// 글자 슬롯이 없어 long-copy를 증명할 수 없는 컴포넌트. 근거: docs/stable-core.md 1.5.0.\nconst textlessComponentNames: ReadonlySet<string> = new Set([\"Icon\", \"IconButton\", \"Skeleton\", \"Spinner\", \"Divider\"]);\n\nfunction getRendererShowcaseScenarios(\n entry: ComponentCatalogEntry,\n activeSurfaces: readonly ComponentSurface[],\n): readonly Exclude<ShowcaseScenarioId, \"contract\">[] {\n const requirements: Exclude<ShowcaseScenarioId, \"contract\">[] = rendererRequirements.filter(\n (scenario) => scenario !== \"long-copy\" || !textlessComponentNames.has(entry.name),\n );\n if (entry.behavior) {\n requirements.push(\"keyboard\");\n }\n if (\n entry.platform === \"adaptive\" &&\n activeSurfaces.includes(\"web\") &&\n activeSurfaces.includes(\"native\")\n ) {\n requirements.push(\"platform-parity\");\n }\n return requirements;\n}\n\nexport function getRequiredShowcaseSurfaces(\n entry: ComponentCatalogEntry,\n): readonly ShowcaseSurface[] {\n return getRequiredShowcaseEvidence(entry).map(({ surface }) => surface);\n}\n\nexport function getRequiredShowcaseEvidence(\n entry: ComponentCatalogEntry,\n): readonly ShowcaseEvidenceRequirement[] {\n const requirements: ShowcaseEvidenceRequirement[] = [\n { surface: \"contract\", scenarios: [\"contract\"] },\n ];\n const activeSurfaces = ([\"web\", \"native\"] as const).filter((surface) =>\n isRendererMaturity(getComponentSurfaceStatus(entry, surface)),\n );\n const rendererScenarios = getRendererShowcaseScenarios(entry, activeSurfaces);\n for (const surface of activeSurfaces) {\n requirements.push({ surface, scenarios: rendererScenarios });\n }\n return requirements;\n}\n\nexport function createShowcaseManifest(\n entries: readonly ComponentCatalogEntry[] = componentCatalog,\n): readonly ShowcaseComponentEntry[] {\n return entries.map((component) => ({\n storyId: getShowcaseStoryId(component),\n component,\n surfaceMaturity: {\n web: getComponentSurfaceStatus(component, \"web\"),\n native: getComponentSurfaceStatus(component, \"native\"),\n },\n requirements: getRequiredShowcaseEvidence(component),\n requiredScenarios: getRequiredShowcaseScenarios(component),\n requiredSurfaces: getRequiredShowcaseSurfaces(component),\n }));\n}\n\nexport const showcaseManifest = createShowcaseManifest();\n\nexport function createShowcaseCoverage(\n evidence: readonly ShowcaseEvidenceEntry[],\n manifest: readonly ShowcaseComponentEntry[] = showcaseManifest,\n): readonly ShowcaseCoverageEntry[] {\n return manifest.map(({ storyId, component, requirements }) => {\n const componentEvidence = evidence.filter((entry) => entry.storyId === storyId);\n const missingEvidence = requirements.flatMap(({ surface, scenarios }) =>\n scenarios\n .filter(\n (scenario) =>\n !componentEvidence.some(\n (entry) => entry.surface === surface && entry.scenarios.includes(scenario),\n ),\n )\n .map((scenario) => ({ surface, scenario })),\n );\n const missingSurfaces = [...new Set(missingEvidence.map(({ surface }) => surface))];\n const missingScenarios = [...new Set(missingEvidence.map(({ scenario }) => scenario))];\n return {\n storyId,\n component,\n missingEvidence,\n missingSurfaces,\n missingScenarios,\n complete: missingSurfaces.length === 0 && missingScenarios.length === 0,\n };\n });\n}\n\nexport function assertShowcaseCoverage(\n evidence: readonly ShowcaseEvidenceEntry[],\n manifest: readonly ShowcaseComponentEntry[] = showcaseManifest,\n): void {\n const missing = createShowcaseCoverage(evidence, manifest).filter(({ complete }) => !complete);\n if (missing.length === 0) return;\n const details = missing\n .map(({ storyId, missingEvidence }) =>\n `${storyId} (${missingEvidence.map(({ surface, scenario }) => `${surface}/${scenario}`).join(\", \") || \"none\"})`,\n )\n .join(\"\\n\");\n throw new Error(`Showcase evidence is incomplete:\\n${details}`);\n}\n\nexport function summarizeShowcaseMaturity(\n entries: readonly ComponentCatalogEntry[] = componentCatalog,\n): Readonly<Record<ComponentStatus, number>> {\n return entries.reduce<Record<ComponentStatus, number>>(\n (summary, entry) => {\n summary[entry.status] += 1;\n return summary;\n },\n { stable: 0, beta: 0, planned: 0, deprecated: 0 },\n );\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,OAAgB,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,OAAgB,CAAC","sourcesContent":["/** Package release shown by documentation surfaces. Kept in sync by a test. */\nexport const designSystemVersion = \"1.5.0\" as const;\n"]}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# 브랜드 경계 — 제품이 바꿀 수 있는 것과 그 경로
|
|
2
|
+
|
|
3
|
+
상태: 규범 · 2026-09-26 · 이 문서가 브랜드·테마 주입 규칙의 단일 원본이다.
|
|
4
|
+
[theming.md](./theming.md)는 사용법 예시, [consumer-policy.md](./consumer-policy.md)는 채택 정책,
|
|
5
|
+
[design-system-provider.md](./design-system-provider.md)는 환경 축 설계를 다루며 브랜드 규칙은 여기로 링크한다.
|
|
6
|
+
|
|
7
|
+
2026-09-26 설계 점검에서 브랜드가 들어오는 경로가 네 가지(부분 `brandPalette`, 손으로 조립한 전체 `value`,
|
|
8
|
+
CSS 변수 재정의, 제품 자체 토큰 생성기)였고, 문서 세 개가 서로 다른 규칙을 적고 있었다
|
|
9
|
+
(`.hjm-*` 재정의 금지 vs 특이도를 맞추면 허용, 부분 덮어쓰기 배제 vs `brandPalette` 권장). 그리고 제품 팔레트의
|
|
10
|
+
대비를 아무도 검사하지 않았다. 이 문서가 그 셋을 하나로 정한다.
|
|
11
|
+
|
|
12
|
+
## 1. 지원하는 경로는 `brandPalette` 하나다
|
|
13
|
+
|
|
14
|
+
- 제품 브랜드는 Provider의 `brandPalette` prop으로 넣는다(`<HjmProvider brandPalette={…}>`,
|
|
15
|
+
`<HjmNativeProvider brandPalette={…}>`, 1.5.0). theme별로 17개 `ThemeColors` key 중 필요한 것만 넘기고,
|
|
16
|
+
나머지는 HJM 기본값을 쓴다(부분 병합). Provider는 계속 OS theme·글자 크기·모션 설정을 따르고,
|
|
17
|
+
중첩 Provider는 가장 가까운 상위의 `brandPalette`를 물려받는다.
|
|
18
|
+
- 상태 강조색(`statusAccents`·`statusAccentFills`)은 덮을 수 없다. "오류·성공"과 "브랜드"가 같은 색이 되는
|
|
19
|
+
것을 막는다.
|
|
20
|
+
- 1.4까지는 Provider에 이 prop이 없어서 `resolveDesignSystemProviderValue(input, { brandPalette })` 결과를
|
|
21
|
+
`value`로 넘기는 것이 유일한 방법이었다. 그러면 Provider가 OS 설정 관찰을 멈춰 제품이 system theme·reduced
|
|
22
|
+
motion을 직접 구독해야 했다. 이 우회를 쓰는 제품은 prop으로 옮긴다.
|
|
23
|
+
- **전체 `value`를 손으로 조립하는 것**(resolver 결과의 `palette.theme`을 통째로 바꾸는 것 포함)은 테스트·임베딩용이지
|
|
24
|
+
브랜드 경로가 아니다. 부분 병합으로 표현할 수 없는 요구는 계약 공백이므로 이슈로 올린다.
|
|
25
|
+
17개 key를 모두 채운 `brandPalette`는 허용되지만 아래 대비 검사를 반드시 통과해야 한다.
|
|
26
|
+
|
|
27
|
+
## 2. 모든 브랜드 팔레트는 대비 검사를 통과해야 한다
|
|
28
|
+
|
|
29
|
+
`@hjmds/design-contracts/palette-contrast`의 `checkBrandPaletteContrast(brandPalette)`가 Provider와 같은 방식으로
|
|
30
|
+
theme별 병합 결과를 검사하고, 기준 미달 쌍을 돌려준다. 빈 배열이어야 한다(MUST). 제품은 이 호출을
|
|
31
|
+
자기 테스트에 두어 팔레트 변경마다 실행한다. 전체 팔레트는 `checkPaletteContrast(palette)`를 쓴다.
|
|
32
|
+
|
|
33
|
+
| 쌍 | 최소 | 근거 |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| `text`·`textBody`·`textMuted`·`textSub` on `bg`·`surface` | 4.5 | WCAG 1.4.3 본문. `textSub`는 `Text tone="subtle"`의 실제 글자색이다 |
|
|
36
|
+
| `contentBrand`·`danger` on `bg`·`surface` | 4.5 | 링크·현재 위치·오류 문구는 글자로 읽힌다 |
|
|
37
|
+
| `onPrimary` on `primary`, `onDanger` on `dangerFill` | 4.5 | 채운 버튼의 라벨 |
|
|
38
|
+
| `primary`·`borderControl` vs `bg`·`surface` | 3 | WCAG 1.4.11. 채운 컨트롤과 쉬고 있는 컨트롤 윤곽선은 형태로 식별돼야 한다 |
|
|
39
|
+
| `textWeak` vs `bg` | 3 | 아래 참조 |
|
|
40
|
+
|
|
41
|
+
`textWeak`는 비활성 문구·placeholder·장식 표지(`content.decorative`) 등급이라 본문 4.5를 요구하지 않는다.
|
|
42
|
+
비활성 콘텐츠와 장식은 WCAG 대비 요구에서 제외되고, HJM 필드는 보이는 label을 요구하므로 placeholder가 유일한
|
|
43
|
+
정보가 되지 않는다. 다만 같은 key가 canvas 위의 `border.strong`(Toast 표면 테두리, Carousel 비활성 점)도 칠하므로
|
|
44
|
+
`bg` 대비 3:1은 지킨다. 읽혀야 하는 글자에 `textWeak`를 쓰지 않는다.
|
|
45
|
+
|
|
46
|
+
HJM 기본 light·dark 팔레트도 같은 검사를 통과한다(`test/palette-contrast.test.ts`). 2026-09-26 이 검사를 만들면서
|
|
47
|
+
기본 light `textSub`(`#6b7684`)가 `surface`에서 4.19:1로 AA 미달임을 찾아 `#65707d`(4.57:1)로 고쳤다
|
|
48
|
+
([theme-palette.md](./theme-palette.md)).
|
|
49
|
+
|
|
50
|
+
## 3. CSS 재정의는 지원하는 테마 경로가 아니다
|
|
51
|
+
|
|
52
|
+
- `.hjm-*` 클래스를 제품 stylesheet에서 덮거나 `--hjm-*` 변수를 제품 CSS·인라인 style로 재정의하지 않는다(MUST NOT).
|
|
53
|
+
`.hjm-*` 이름과 내부 DOM은 공개 API가 아니며, HJM이 바꿔도 호환성 파괴로 취급하지 않는다. 특이도를 맞추면
|
|
54
|
+
허용한다던 이전 문구(consumer-policy)는 이 문서로 대체한다.
|
|
55
|
+
- 필요한 값이 semantic key나 recipe 축으로 표현되지 않으면 계약 공백이다. 우회하지 말고 이슈로 올린다.
|
|
56
|
+
- 제3자 브랜드 색(소셜 로그인 등)은 테마가 아니라 남의 자산이다. [AuthProviderButton](./provider-button.md)이 소유한다.
|
|
57
|
+
- component `style` escape hatch는 배치(margin·width·flex)에만 쓴다. 색·타이포·radius·높이·상호작용 상태를
|
|
58
|
+
덮는 데 쓰지 않는다([consumer-policy.md §3](./consumer-policy.md#3-코드-경계)).
|
|
59
|
+
|
|
60
|
+
### 기존 재정의는 추적되는 부채다
|
|
61
|
+
|
|
62
|
+
2026-09-26 기준 제품 web stylesheet의 `.hjm-*` 재정의: 다에리 61줄, 번뚝 26줄. 제품은 이 목록을 한 곳에 모으고,
|
|
63
|
+
각 줄을 (1) `brandPalette` key, (2) HJM recipe 축 요청(이슈), (3) 삭제 중 하나로 옮긴다. 새 재정의는 추가하지 않는다.
|
|
64
|
+
|
|
65
|
+
### 이관 경로: 레이어된 stylesheet (opt-in)
|
|
66
|
+
|
|
67
|
+
`@hjmds/react/styles.css`는 기본적으로 **CSS 레이어 밖**에 있다(호환성 유지). 이 때문에 레이어 안에 있는 소비 앱
|
|
68
|
+
유틸리티(Tailwind 4의 `@layer utilities` 등)는 HJM 규칙을 덮지 못하고, 레이어 밖의 제품 규칙은 특이도 싸움으로만 이긴다.
|
|
69
|
+
|
|
70
|
+
같은 내용을 `@layer hjm { … }`로 감싼 `@hjmds/react/styles.layered.css`를 함께 배포한다. 빌드가 `styles.css`에서 생성하므로
|
|
71
|
+
두 파일의 규칙은 항상 같다. 이 파일을 쓰면 **레이어 밖의 모든 제품 CSS가 특이도와 무관하게 HJM을 이긴다** —
|
|
72
|
+
`button { background: none }`, `* { margin: 0 }` 같은 전역 요소 리셋과 CSS 리셋 라이브러리까지 포함해서다.
|
|
73
|
+
그래서 전환 전에 제품은 다음을 확인한다.
|
|
74
|
+
|
|
75
|
+
1. 전역 요소 선택자(`button`, `input`, `a`, `h1`…, `*`)와 리셋 stylesheet를 찾아 HJM 컴포넌트 안에 닿는지 본다.
|
|
76
|
+
닿으면 제품 레이어(예: `@layer reset, hjm, product;` 순서 선언)로 옮기거나 범위를 좁힌다.
|
|
77
|
+
2. 기존 `.hjm-*` 재정의는 레이어 전환 뒤 특이도 없이도 이기므로, 의도하지 않은 재정의가 더 넓게 먹지 않는지 확인한다.
|
|
78
|
+
3. 브라우저에서 light/dark·큰 글자 화면을 실제로 확인한 뒤 전환한다.
|
|
79
|
+
|
|
80
|
+
기본 `styles.css`를 레이어로 바꾸는 것은 위 확인이 모든 web 소비 제품에서 끝난 다음 major에서 결정한다.
|
|
81
|
+
|
|
82
|
+
## 4. HJM과 제품이 소유하는 것
|
|
83
|
+
|
|
84
|
+
HJM: semantic color role과 light/dark 대비, spacing·type scale·radius·motion·touch target, component anatomy·상태·
|
|
85
|
+
키보드·screen-reader 행동, loading·empty·error·disabled·focus 문법.
|
|
86
|
+
|
|
87
|
+
제품: 이름·로고·대표 이미지, `brandPalette`로 표현한 브랜드 색, 도메인 상태 → `AccentTone` 매핑, 콘텐츠 밀도와
|
|
88
|
+
정보 우선순위, copy·i18n·내비게이션 구조. 제품 고유 gradient는 light/dark·on-color 대비와 reduce-motion을 제품 테스트로
|
|
89
|
+
검증한다([consumer-policy.md §4](./consumer-policy.md#4-제품-정체성-경계)).
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "카탈로그 확장 동결. 이 목록에 없는 이름을 catalog.ts에 추가하면 test/catalog-freeze.test.ts가 실패한다.",
|
|
3
|
+
"frozenAt": "2026-09-26",
|
|
4
|
+
"reason": "2026-09-26 설계 점검: 111개 중 stable 4개였고, 세 제품 이상이 쓰는 약 30개가 beta에 묶여 있었다. 1.5.0에서 13개를 실제 증거로 승격했지만 keyboard·platform-parity 증거가 필요한 핵심(Checkbox, Switch, Dialog, Sheet, SegmentedControl, RadioGroup, Link, PasswordField 등)은 아직 beta다. 폭을 넓히기 전에 이것들을 먼저 올린다.",
|
|
5
|
+
"unfreezeWhen": "위 핵심 beta가 stable이 되면 동결을 푼다. 그 전에 추가가 필요하면 이 파일의 exceptions에 이름·날짜·근거(ADR 또는 이슈)를 적는다.",
|
|
6
|
+
"exceptions": [],
|
|
7
|
+
"names": [
|
|
8
|
+
"Accordion",
|
|
9
|
+
"Affix",
|
|
10
|
+
"Agreement",
|
|
11
|
+
"AlertDialog",
|
|
12
|
+
"Anchor",
|
|
13
|
+
"AppProvider",
|
|
14
|
+
"AspectRatio",
|
|
15
|
+
"Asset",
|
|
16
|
+
"AuthProviderButton",
|
|
17
|
+
"AuthScreenLayout",
|
|
18
|
+
"Avatar",
|
|
19
|
+
"Badge",
|
|
20
|
+
"BorderBeam",
|
|
21
|
+
"BottomCTA",
|
|
22
|
+
"BottomInfo",
|
|
23
|
+
"BottomNavigation",
|
|
24
|
+
"Breadcrumb",
|
|
25
|
+
"Button",
|
|
26
|
+
"Calendar",
|
|
27
|
+
"Card",
|
|
28
|
+
"Carousel",
|
|
29
|
+
"Cascader",
|
|
30
|
+
"Chart",
|
|
31
|
+
"Checkbox",
|
|
32
|
+
"CheckboxGroup",
|
|
33
|
+
"Chip",
|
|
34
|
+
"Collapsible",
|
|
35
|
+
"ColorPicker",
|
|
36
|
+
"Combobox",
|
|
37
|
+
"CommandPalette",
|
|
38
|
+
"ConfirmPopover",
|
|
39
|
+
"Container",
|
|
40
|
+
"ContextMenu",
|
|
41
|
+
"CounterBadge",
|
|
42
|
+
"DataTable",
|
|
43
|
+
"DatePicker",
|
|
44
|
+
"DateRangePicker",
|
|
45
|
+
"DescriptionList",
|
|
46
|
+
"DesignSystemProvider",
|
|
47
|
+
"Dialog",
|
|
48
|
+
"Divider",
|
|
49
|
+
"EmptyState",
|
|
50
|
+
"Field",
|
|
51
|
+
"FilePicker",
|
|
52
|
+
"FloatingActionButton",
|
|
53
|
+
"Form",
|
|
54
|
+
"Grid",
|
|
55
|
+
"Heading",
|
|
56
|
+
"Icon",
|
|
57
|
+
"IconButton",
|
|
58
|
+
"Image",
|
|
59
|
+
"Layout",
|
|
60
|
+
"Link",
|
|
61
|
+
"List",
|
|
62
|
+
"ListRow",
|
|
63
|
+
"LoadMore",
|
|
64
|
+
"Masonry",
|
|
65
|
+
"Mentions",
|
|
66
|
+
"Menu",
|
|
67
|
+
"Menubar",
|
|
68
|
+
"Notice",
|
|
69
|
+
"NumberField",
|
|
70
|
+
"OtpField",
|
|
71
|
+
"Pagination",
|
|
72
|
+
"PasswordField",
|
|
73
|
+
"Popover",
|
|
74
|
+
"Progress",
|
|
75
|
+
"QRCode",
|
|
76
|
+
"Radio",
|
|
77
|
+
"RadioGroup",
|
|
78
|
+
"Rating",
|
|
79
|
+
"Result",
|
|
80
|
+
"SearchField",
|
|
81
|
+
"Section",
|
|
82
|
+
"SegmentedControl",
|
|
83
|
+
"Select",
|
|
84
|
+
"Sheet",
|
|
85
|
+
"SidePanel",
|
|
86
|
+
"Sidebar",
|
|
87
|
+
"Skeleton",
|
|
88
|
+
"SkipNav",
|
|
89
|
+
"Slider",
|
|
90
|
+
"Spinner",
|
|
91
|
+
"Splitter",
|
|
92
|
+
"Stack",
|
|
93
|
+
"Statistic",
|
|
94
|
+
"Steps",
|
|
95
|
+
"Surface",
|
|
96
|
+
"Switch",
|
|
97
|
+
"Tabs",
|
|
98
|
+
"Tag",
|
|
99
|
+
"TagsInput",
|
|
100
|
+
"Text",
|
|
101
|
+
"TextArea",
|
|
102
|
+
"TextFormat",
|
|
103
|
+
"TimePicker",
|
|
104
|
+
"Timeline",
|
|
105
|
+
"Toast",
|
|
106
|
+
"ToggleGroup",
|
|
107
|
+
"Tooltip",
|
|
108
|
+
"Top",
|
|
109
|
+
"TopBar",
|
|
110
|
+
"Tour",
|
|
111
|
+
"TransferList",
|
|
112
|
+
"Tree",
|
|
113
|
+
"TreeSelect",
|
|
114
|
+
"UploadItem",
|
|
115
|
+
"Utility",
|
|
116
|
+
"VirtualList",
|
|
117
|
+
"VisuallyHidden",
|
|
118
|
+
"Watermark"
|
|
119
|
+
]
|
|
120
|
+
}
|
package/docs/consumer-policy.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# HJM 소비 앱 정책
|
|
2
2
|
|
|
3
3
|
상태: **Normative**
|
|
4
|
-
정책 버전: **1.
|
|
4
|
+
정책 버전: **1.3.0**
|
|
5
5
|
적용 대상: 신규 HJM Web·React Native 앱과 기존 앱의 새 화면
|
|
6
6
|
|
|
7
7
|
이 정책 원문은 다음 package patch release부터
|
|
@@ -39,11 +39,13 @@
|
|
|
39
39
|
|
|
40
40
|
### 2.1 Stable Core와 필수 foundation bridge
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
`Icon`, `Stack`, `Container`,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
1.5.0부터 Stable Core는 17개 surface입니다. 1.4까지의 `Surface`, `Button`, `Field`, `TextArea`에
|
|
43
|
+
더해, 첫 제품 화면에 필요한 foundation인 `Text`, `Icon`, `Stack`, `Container`,
|
|
44
|
+
`DesignSystemProvider`와 세 제품 이상이 쓰는 `IconButton`, `Badge`, `Card`, `Tag`, `Notice`,
|
|
45
|
+
`Progress`, `Spinner`, `Skeleton`이 stable로 승격됐습니다. 승격 근거는 이름뿐이던 시나리오 증거를
|
|
46
|
+
실제 계산 스타일 검사로 바꾼 뒤 두 renderer에서 요구 시나리오가 모두 통과한 것입니다
|
|
47
|
+
([Stable Core](stable-core.md)). 그 밖의 컴포넌트는 여전히 `beta`이며, beta를 `stable`로
|
|
48
|
+
간주하거나 `betaAdoptions: []`로 기록하는 것은 허용하지 않습니다(MUST NOT).
|
|
47
49
|
|
|
48
50
|
HJM-APP-STANDARD가 versioned `requiredFoundations` 목록을 선언한 경우 다음 bridge를
|
|
49
51
|
적용합니다.
|
|
@@ -58,8 +60,9 @@ HJM-APP-STANDARD가 versioned `requiredFoundations` 목록을 선언한 경우
|
|
|
58
60
|
- foundation이 catalog에서 `stable`로 승격되면 기존 표준의 의미를 조용히 바꾸지 않고
|
|
59
61
|
다음 versioned app profile에서 bridge 목록을 줄입니다(MUST).
|
|
60
62
|
|
|
61
|
-
이 bridge는 성숙도 예외가 아니라 공개된 임시 채택 계약입니다.
|
|
62
|
-
|
|
63
|
+
이 bridge는 성숙도 예외가 아니라 공개된 임시 채택 계약입니다. 1.5.0에서 bridge의 다섯
|
|
64
|
+
foundation이 모두 stable이 됐으므로, 중앙 app profile의 다음 개정에서 `requiredFoundations`
|
|
65
|
+
목록을 비웁니다. 개정 전까지 기존 profile을 쓰는 앱의 evidence 요구는 조용히 바뀌지 않습니다.
|
|
63
66
|
|
|
64
67
|
## 3. 코드 경계
|
|
65
68
|
|
|
@@ -109,7 +112,8 @@ semantic axis로 옮겼습니다. 아래는 그 축과 대체 대상입니다.
|
|
|
109
112
|
|
|
110
113
|
### Web renderer의 캐스케이드
|
|
111
114
|
|
|
112
|
-
`@hjmds/react/styles.css`는 **CSS 레이어 밖**에
|
|
115
|
+
`@hjmds/react/styles.css`는 **CSS 레이어 밖**에 있다(레이어된 opt-in 파일과 전환 조건은
|
|
116
|
+
[brand-boundary.md §3](./brand-boundary.md#3-css-재정의는-지원하는-테마-경로가-아니다)). Tailwind 4를 쓰는 소비 앱의
|
|
113
117
|
유틸리티는 `@layer utilities` 안에 들어가고, 레이어 밖 규칙은 레이어 안 규칙을
|
|
114
118
|
이긴다. 따라서 HJM 컴포넌트에 `px-0`·`rounded-none`·`justify-start` 같은
|
|
115
119
|
유틸리티를 붙여 recipe 값을 덮으려는 시도는 **조용히 아무 일도 하지 않는다.**
|
|
@@ -120,8 +124,8 @@ semantic axis로 옮겼습니다. 아래는 그 축과 대체 대상입니다.
|
|
|
120
124
|
|
|
121
125
|
- 유틸리티로 recipe 값을 덮는 코드는 리뷰에서 걸러야 한다. 필요한 값은 semantic
|
|
122
126
|
axis로 요청한다.
|
|
123
|
-
- HJM이 표현할 수 없는
|
|
124
|
-
|
|
127
|
+
- HJM이 표현할 수 없는 값은 `.hjm-*` 재정의로 우회하지 않는다. 계약 공백으로 올린다. 기존 재정의는
|
|
128
|
+
추적되는 부채이며 이관 경로(opt-in `styles.layered.css`)와 규칙은 [brand-boundary.md](./brand-boundary.md)가 정한다.
|
|
125
129
|
- 인라인 `style`은 모든 규칙을 이기므로 이관 전에는 보이던 값이 이관 후 조용히
|
|
126
130
|
사라질 수 있다. 이관은 브라우저에서 실제 렌더를 확인하며 진행한다.
|
|
127
131
|
|
|
@@ -213,8 +217,8 @@ package로 승격하지 않습니다.
|
|
|
213
217
|
다음 질문에 모두 "예"라고 답할 수 있어야 HJM 채택이 완료된 것입니다.
|
|
214
218
|
|
|
215
219
|
- exact fixed-train dependency와 Provider가 CI에서 검증되는가?
|
|
216
|
-
- Stable은 기본 사용하고 필수
|
|
217
|
-
제품 ADR+evidence로 구분되어 있는가?
|
|
220
|
+
- Stable은 기본 사용하고(1.5.0 이전 profile이면 필수 foundation은 중앙 목록+앱 evidence로),
|
|
221
|
+
optional Beta는 제품 ADR+evidence로 구분되어 있는가?
|
|
218
222
|
- screen 코드가 semantic token·component를 우회하지 않는가?
|
|
219
223
|
- 같은 상태가 Web/RN에서 같은 의미와 자연스러운 플랫폼 행동을 갖는가?
|
|
220
224
|
- 로고를 제거해도 제품의 핵심 콘텐츠와 정보 구조가 다른 제품과 구분되는가?
|
|
@@ -116,10 +116,10 @@ adapter가 자체 병합 로직을 다시 만들 필요가 없다. `parent`에
|
|
|
116
116
|
| `size`(antd ConfigProvider의 컴포넌트 전역 사이즈 프리셋) | **배제** — 측정된 요구가
|
|
117
117
|
없고, 있다 해도 그건 각 recipe의 `sizes`(예: `selectRecipe.sizes`)가 이미 컴포넌트별로
|
|
118
118
|
갖고 있는 축이라 전역 오버라이드를 얹으면 두 곳이 같은 축을 다시 소유하게 된다. |
|
|
119
|
-
| 임의 theme/component token override | **
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
| 임의 theme/component token override | **component token override는 배제**, theme 색은 `brandPalette`
|
|
120
|
+
부분 병합으로만 — 병합 결과는 `checkBrandPaletteContrast`를 통과해야 한다. 규칙 원본은
|
|
121
|
+
[brand-boundary.md](./brand-boundary.md)이며, 이 행의 이전 문구("partial override 배제, 완전한 value만")는
|
|
122
|
+
0.9.x에 `brandPalette`가 생기면서 사실과 달라졌다. |
|
|
123
123
|
|
|
124
124
|
## 제품 adapter 증거
|
|
125
125
|
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
# Component maturity and evidence manifest
|
|
2
2
|
|
|
3
|
-
> Generated from `@hjmds/design-contracts` 1.
|
|
3
|
+
> Generated from `@hjmds/design-contracts` 1.5.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
|
|
|
7
|
-
- Contract: stable
|
|
8
|
-
- Web renderer: stable
|
|
9
|
-
- Native renderer: stable
|
|
7
|
+
- Contract: stable 17 · beta 79 · planned 15
|
|
8
|
+
- Web renderer: stable 17 · beta 79 · planned 15
|
|
9
|
+
- Native renderer: stable 17 · beta 62 · planned 8 · unsupported 24
|
|
10
10
|
|
|
11
11
|
| Component | Canonical story ID | Contract | Web | Native | Documentation | Required evidence |
|
|
12
12
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
13
|
-
| Text | `foundation/text` |
|
|
13
|
+
| Text | `foundation/text` | stable | stable | stable | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
14
14
|
| TextFormat | `foundation/text-format` | beta | beta | unsupported | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard |
|
|
15
15
|
| Heading | `foundation/heading` | beta | beta | beta | [authored](../heading.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard |
|
|
16
|
-
| Icon | `foundation/icon` |
|
|
16
|
+
| Icon | `foundation/icon` | stable | stable | stable | [authored](../icon.md) | contract: contract; web: default, dark, large-text, rtl, reduced-motion, accessibility; native: default, dark, large-text, rtl, reduced-motion, accessibility |
|
|
17
17
|
| Surface | `layout/surface` | stable | stable | stable | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
18
|
-
| Divider | `layout/divider` | beta | beta | beta | generated only | contract: contract; web: default, dark,
|
|
18
|
+
| Divider | `layout/divider` | beta | beta | beta | generated only | contract: contract; web: default, dark, large-text, rtl, reduced-motion, accessibility; native: default, dark, large-text, rtl, reduced-motion, accessibility |
|
|
19
19
|
| Section | `layout/section` | beta | beta | beta | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
20
|
-
| Stack | `layout/stack` |
|
|
21
|
-
| Container | `layout/container` |
|
|
20
|
+
| Stack | `layout/stack` | stable | stable | stable | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
21
|
+
| Container | `layout/container` | stable | stable | stable | [authored](../container.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
22
22
|
| AspectRatio | `layout/aspect-ratio` | beta | beta | beta | [authored](../aspect-ratio.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
23
23
|
| Grid | `layout/grid` | beta | beta | beta | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, platform-parity; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, platform-parity |
|
|
24
24
|
| Layout | `layout/layout` | beta | beta | beta | [authored](../layout.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity |
|
|
@@ -26,7 +26,7 @@ This document is the human-readable projection of the same catalog and Showcase
|
|
|
26
26
|
| Masonry | `layout/masonry` | planned | planned | planned | generated only | contract: contract |
|
|
27
27
|
| Splitter | `layout/splitter` | beta | beta | unsupported | [authored](../splitter.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard |
|
|
28
28
|
| Button | `action/button` | stable | stable | stable | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
29
|
-
| IconButton | `action/icon-button` |
|
|
29
|
+
| IconButton | `action/icon-button` | stable | stable | stable | generated only | contract: contract; web: default, dark, large-text, rtl, reduced-motion, accessibility; native: default, dark, large-text, rtl, reduced-motion, accessibility |
|
|
30
30
|
| Link | `action/link` | beta | beta | beta | [authored](../link.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity |
|
|
31
31
|
| BottomCTA | `action/bottom-cta` | beta | beta | beta | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, platform-parity; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, platform-parity |
|
|
32
32
|
| FloatingActionButton | `action/floating-action-button` | beta | beta | beta | [authored](../floating-action-button.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity |
|
|
@@ -78,9 +78,9 @@ This document is the human-readable projection of the same catalog and Showcase
|
|
|
78
78
|
| Avatar | `data-display/avatar` | beta | beta | beta | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
79
79
|
| Asset | `data-display/asset` | beta | beta | beta | [authored](../asset.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity |
|
|
80
80
|
| Chart | `data-display/chart` | planned | planned | planned | [authored](../chart.md) | contract: contract |
|
|
81
|
-
| Badge | `data-display/badge` |
|
|
81
|
+
| Badge | `data-display/badge` | stable | stable | stable | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
82
82
|
| CounterBadge | `data-display/counter-badge` | beta | beta | beta | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
83
|
-
| Card | `data-display/card` |
|
|
83
|
+
| Card | `data-display/card` | stable | stable | stable | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
84
84
|
| List | `data-display/list` | beta | beta | beta | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
85
85
|
| ListRow | `data-display/list-row` | beta | beta | beta | [authored](../list-row.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
86
86
|
| VirtualList | `data-display/virtual-list` | planned | planned | planned | [authored](../virtual-list.md) | contract: contract |
|
|
@@ -95,13 +95,13 @@ This document is the human-readable projection of the same catalog and Showcase
|
|
|
95
95
|
| DescriptionList | `data-display/description-list` | beta | beta | beta | [authored](../description-list.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
96
96
|
| Image | `data-display/image` | beta | beta | beta | [authored](../image.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
97
97
|
| QRCode | `data-display/qrcode` | planned | planned | planned | [authored](../qr-code.md) | contract: contract |
|
|
98
|
-
| Tag | `data-display/tag` |
|
|
98
|
+
| Tag | `data-display/tag` | stable | stable | stable | [authored](../tag.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
99
99
|
| Tour | `overlay/tour` | beta | beta | unsupported | [authored](../tour.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard |
|
|
100
100
|
| EmptyState | `feedback/empty-state` | beta | beta | beta | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
101
|
-
| Notice | `feedback/notice` |
|
|
102
|
-
| Progress | `feedback/progress` |
|
|
103
|
-
| Spinner | `feedback/spinner` |
|
|
104
|
-
| Skeleton | `feedback/skeleton` |
|
|
101
|
+
| Notice | `feedback/notice` | stable | stable | stable | generated only | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
102
|
+
| Progress | `feedback/progress` | stable | stable | stable | [authored](../progress.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
103
|
+
| Spinner | `feedback/spinner` | stable | stable | stable | generated only | contract: contract; web: default, dark, large-text, rtl, reduced-motion, accessibility; native: default, dark, large-text, rtl, reduced-motion, accessibility |
|
|
104
|
+
| Skeleton | `feedback/skeleton` | stable | stable | stable | generated only | contract: contract; web: default, dark, large-text, rtl, reduced-motion, accessibility; native: default, dark, large-text, rtl, reduced-motion, accessibility |
|
|
105
105
|
| Result | `feedback/result` | beta | beta | beta | [authored](../result.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
106
106
|
| BottomInfo | `feedback/bottom-info` | beta | beta | beta | [authored](../bottom-info.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity |
|
|
107
107
|
| Toast | `feedback/toast` | beta | beta | beta | [authored](../toast.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard, platform-parity |
|
|
@@ -117,7 +117,7 @@ This document is the human-readable projection of the same catalog and Showcase
|
|
|
117
117
|
| Affix | `utility/affix` | planned | planned | unsupported | [authored](../affix.md) | contract: contract |
|
|
118
118
|
| AppProvider | `provider/app-provider` | planned | planned | planned | [authored](../app-provider.md) | contract: contract |
|
|
119
119
|
| BorderBeam | `utility/border-beam` | planned | planned | unsupported | [authored](../border-beam.md) | contract: contract |
|
|
120
|
-
| DesignSystemProvider | `provider/design-system-provider` |
|
|
120
|
+
| DesignSystemProvider | `provider/design-system-provider` | stable | stable | stable | [authored](../design-system-provider.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
121
121
|
| Utility | `utility/utility` | planned | planned | unsupported | [authored](../utility.md) | contract: contract |
|
|
122
122
|
| SkipNav | `utility/skip-nav` | beta | beta | unsupported | [authored](../skip-nav.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard |
|
|
123
123
|
| VisuallyHidden | `utility/visually-hidden` | beta | beta | unsupported | [authored](../visually-hidden.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|