@hjmds/design-contracts 1.3.4 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,23 +51,23 @@ export declare const authProviderPalettes: {
51
51
  readonly kakao: {
52
52
  readonly light: {
53
53
  readonly background: "#FEE500";
54
- readonly content: "rgba(0, 0, 0, 0.85)";
54
+ readonly content: "#191919";
55
55
  readonly border: null;
56
56
  };
57
57
  readonly dark: {
58
58
  readonly background: "#FEE500";
59
- readonly content: "rgba(0, 0, 0, 0.85)";
59
+ readonly content: "#191919";
60
60
  readonly border: null;
61
61
  };
62
62
  };
63
63
  readonly naver: {
64
64
  readonly light: {
65
- readonly background: "#03C75A";
65
+ readonly background: "#03A94D";
66
66
  readonly content: "#FFFFFF";
67
67
  readonly border: null;
68
68
  };
69
69
  readonly dark: {
70
- readonly background: "#03C75A";
70
+ readonly background: "#03A94D";
71
71
  readonly content: "#FFFFFF";
72
72
  readonly border: null;
73
73
  };
@@ -1 +1 @@
1
- {"version":3,"file":"provider-button.d.ts","sourceRoot":"","sources":["../src/provider-button.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAEpE,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,KAAK,EAAE,mBAAmB,CAAC;IAC3B;;;OAGG;IACH,IAAI,EAAE,mBAAmB,CAAC;CAC3B,CAAC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsByC,CAAC;AAE3E,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,QAAQ,EAAE,cAAc,CAAC;IACzB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC,CAAC;AAEH,wBAAgB,oCAAoC,CAClD,UAAU,EAAE,4BAA4B,GACvC,IAAI,CAUN;AAED,qDAAqD;AACrD,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,OAAO,GAAG,MAAM,GACtB,mBAAmB,CAErB;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;IAUnC,sCAAsC;;CAE9B,CAAC;AAEX,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;CAmBF,CAAC"}
1
+ {"version":3,"file":"provider-button.d.ts","sourceRoot":"","sources":["../src/provider-button.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAEpE,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,KAAK,EAAE,mBAAmB,CAAC;IAC3B;;;OAGG;IACH,IAAI,EAAE,mBAAmB,CAAC;CAC3B,CAAC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4ByC,CAAC;AAE3E,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,QAAQ,EAAE,cAAc,CAAC;IACzB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC,CAAC;AAEH,wBAAgB,oCAAoC,CAClD,UAAU,EAAE,4BAA4B,GACvC,IAAI,CAUN;AAED,qDAAqD;AACrD,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,OAAO,GAAG,MAAM,GACtB,mBAAmB,CAErB;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;IAUnC,sCAAsC;;CAE9B,CAAC;AAEX,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;CAmBF,CAAC"}
@@ -12,15 +12,21 @@ export const authProviderPalettes = {
12
12
  light: { background: "#FFFFFF", content: "#1F1F1F", border: "#747775" },
13
13
  dark: { background: "#131314", content: "#E3E3E3", border: "#8E918F" },
14
14
  },
15
- // Kakao 로그인: 배경 #FEE500 고정, 글자는 검정 85% 불투명도.
15
+ // Kakao 로그인: 배경 #FEE500 고정, 글자 #191919.
16
+ // 예전 값은 `rgba(0, 0, 0, 0.85)`였다. 흔히 인용되는 "검정 85%"인데, 노란 배경 위에서
17
+ // 실제로 합성하면 (38, 34, 0)이라 카카오가 배포하는 버튼 이미지의 글자색과 다르다.
18
+ // 공식 자산(kakao_login.zip의 ko/kakao_login_large_wide.png)에서 픽셀을 뽑아 대조했다.
16
19
  kakao: {
17
- light: { background: "#FEE500", content: "rgba(0, 0, 0, 0.85)", border: null },
18
- dark: { background: "#FEE500", content: "rgba(0, 0, 0, 0.85)", border: null },
20
+ light: { background: "#FEE500", content: "#191919", border: null },
21
+ dark: { background: "#FEE500", content: "#191919", border: null },
19
22
  },
20
- // 네이버 로그인: 배경 #03C75A 고정, 글자 흰색.
23
+ // 네이버 로그인: 배경 #03A94D 고정, 글자 흰색.
24
+ // 예전 값 #03C75A는 구 BI다. 네이버 로그인 BI 가이드가 "배경 컬러가 더 뚜렷하게
25
+ // 바뀌었어요. 반드시 지정된 녹색을 사용해 주세요. 컬러 #03A94D, RGB 3/169/77"로 못박고,
26
+ // 배포 중인 버튼 자산(NAVER_login_KR.zip)의 픽셀도 (3, 169, 77)이다(2026-09-19 확인).
21
27
  naver: {
22
- light: { background: "#03C75A", content: "#FFFFFF", border: null },
23
- dark: { background: "#03C75A", content: "#FFFFFF", border: null },
28
+ light: { background: "#03A94D", content: "#FFFFFF", border: null },
29
+ dark: { background: "#03A94D", content: "#FFFFFF", border: null },
24
30
  },
25
31
  // Sign in with Apple: 검정 버튼이 기본, 밝은 배경 위에서는 흰 버튼 + 검은 테두리.
26
32
  apple: {
@@ -1 +1 @@
1
- {"version":3,"file":"provider-button.js","sourceRoot":"","sources":["../src/provider-button.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport { buttonRecipe } from \"./base-recipes.js\";\nimport { control, radius, spacing, typography } from \"./foundations.js\";\n\n/**\n * 소셜 로그인 버튼이다. Button의 tone 하나로 풀 수 없어서 별도 계약으로 둔다.\n *\n * HJM의 tone은 **의미**(primary/secondary/danger)이고 팔레트가 테마를 따라 움직인다.\n * 제공자 버튼의 색은 의미가 아니라 **남의 브랜드 자산**이다 — Google·Kakao·Naver·Apple이\n * 각자 로그인 버튼의 배경·글자·테두리·최소 크기를 브랜드 가이드라인으로 규정하고, 심사에서\n * 그대로 쓰기를 요구한다. 그래서 이 색들은 semantic token이 아니고 테마가 다시 칠하지\n * 않는다. 제품이 `.hjm-button.bt-provider-google` 같은 CSS로 덮어 오던 자리를 계약으로\n * 올리되, 값의 출처가 HJM이 아니라는 사실을 타입으로 드러낸다.\n *\n * **HJM이 소유하는 것**: 높이·radius·터치 타깃·포커스 링·로고와 라벨의 배치·큰 글자 대응.\n * **제공자가 소유하는 것**: 색과 로고 모양.\n * **제품이 소유하는 것**: 로고 자산(재배포하지 않으므로 슬롯으로 받는다)과 현지화된 문구\n * (\"Google로 계속하기\"의 정확한 표현은 제공자 가이드라인과 언어에 따라 다르다).\n */\nexport type AuthProviderId = \"google\" | \"kakao\" | \"naver\" | \"apple\";\n\nexport type AuthProviderSurface = Readonly<{\n /** 제공자 가이드라인이 지정한 배경색. HJM 팔레트가 아니다. */\n background: string;\n /** 같은 가이드라인의 글자/로고 색. */\n content: string;\n /** 배경이 캔버스와 구분되지 않을 때만 가이드라인이 요구하는 테두리. */\n border: string | null;\n}>;\n\nexport type AuthProviderPalette = Readonly<{\n light: AuthProviderSurface;\n /**\n * 제공자가 다크 변형을 따로 규정한 경우에만 다르다. 브랜드색 자체가 정체성인\n * Kakao·Naver는 다크에서도 같은 색을 쓰라고 명시하므로 light와 동일하다.\n */\n dark: AuthProviderSurface;\n}>;\n\n/**\n * 값의 출처는 각 제공자의 공개 브랜드 가이드라인이다(2026-09 확인).\n * 로고 이미지는 포함하지 않는다 — 배포 조건이 제공자마다 다르고, HJM이 재배포할 권리가\n * 없다. 가이드라인이 바뀌면 이 표를 고치는 것이 유일한 변경 지점이다.\n */\nexport const authProviderPalettes = {\n // Google Identity: 흰 버튼 #FFFFFF / 글자 #1F1F1F / 테두리 #747775,\n // 어두운 변형 #131314 / #E3E3E3 / #8E918F.\n google: {\n light: { background: \"#FFFFFF\", content: \"#1F1F1F\", border: \"#747775\" },\n dark: { background: \"#131314\", content: \"#E3E3E3\", border: \"#8E918F\" },\n },\n // Kakao 로그인: 배경 #FEE500 고정, 글자는 검정 85% 불투명도.\n kakao: {\n light: { background: \"#FEE500\", content: \"rgba(0, 0, 0, 0.85)\", border: null },\n dark: { background: \"#FEE500\", content: \"rgba(0, 0, 0, 0.85)\", border: null },\n },\n // 네이버 로그인: 배경 #03C75A 고정, 글자 흰색.\n naver: {\n light: { background: \"#03C75A\", content: \"#FFFFFF\", border: null },\n dark: { background: \"#03C75A\", content: \"#FFFFFF\", border: null },\n },\n // Sign in with Apple: 검정 버튼이 기본, 밝은 배경 위에서는 흰 버튼 + 검은 테두리.\n apple: {\n light: { background: \"#000000\", content: \"#FFFFFF\", border: null },\n dark: { background: \"#FFFFFF\", content: \"#000000\", border: \"#000000\" },\n },\n} as const satisfies Readonly<Record<AuthProviderId, AuthProviderPalette>>;\n\nexport type AuthProviderButtonDescriptor = Readonly<{\n provider: AuthProviderId;\n /** 제공자 가이드라인과 언어에 맞춘 문구. renderer가 만들지 않는다. */\n label: string;\n /** 진행 중 표시. 라벨을 지우지 않고 버튼 폭도 유지한다. */\n busy?: boolean;\n disabled?: boolean;\n}>;\n\nexport function validateAuthProviderButtonDescriptor(\n descriptor: AuthProviderButtonDescriptor,\n): void {\n if (descriptor === null || typeof descriptor !== \"object\") {\n throw new TypeError(\"AuthProviderButton descriptor must be an object\");\n }\n if (!Object.prototype.hasOwnProperty.call(authProviderPalettes, descriptor.provider)) {\n throw new TypeError(`Unsupported auth provider: ${String(descriptor.provider)}`);\n }\n if (typeof descriptor.label !== \"string\" || descriptor.label.trim().length === 0) {\n throw new TypeError(\"AuthProviderButton label must not be empty\");\n }\n}\n\n/** 해석된 테마에 맞는 제공자 표면. 테마는 *변형 선택*만 하고 색을 만들지 않는다. */\nexport function resolveAuthProviderSurface(\n provider: AuthProviderId,\n theme: \"light\" | \"dark\",\n): AuthProviderSurface {\n return authProviderPalettes[provider][theme];\n}\n\n/**\n * 크기는 HJM 것이다 — 한 화면에 네 개가 세로로 쌓이므로 높이·radius·간격이 서로 다르면\n * 목록이 무너진다. `buttonRecipe`의 medium 높이와 같은 값을 쓰고, 최소 터치 타깃도 공유한다.\n */\nexport const authProviderButtonRecipe = {\n slots: [\"root\", \"logo\", \"label\", \"spinner\"] as const,\n minHeight: buttonRecipe.sizes.medium.height,\n minTouchTarget: control.minTouchTarget,\n radius: radius.md,\n paddingHorizontal: spacing.md,\n gap: spacing.sm,\n logoSize: 20,\n label: typography.body,\n borderWidth: 1,\n /** 제공자 색 위에서도 보이도록 포커스 링은 바깥에 그린다. */\n focusOutlineOffset: 2,\n} as const;\n\nexport const authProviderButtonBehavior = {\n controlled: [],\n inputs: [\"provider\", \"label\", \"busy\", \"disabled\"],\n events: [\"onPress\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\", \"busy\"],\n interaction: [\"idle\", \"hover\", \"focusVisible\", \"pressed\"],\n },\n web: { roles: [\"button\"], keyboard: [\"Enter\", \"Space\"], focus: \"native\" },\n native: { roles: [\"button\"], states: [\"disabled\", \"busy\"], actions: [\"press\"] },\n scenarios: [\n \"provider-colors-come-from-the-provider-guideline-and-the-theme-never-recolors-them\",\n \"the-theme-only-picks-between-the-providers-own-light-and-dark-variants\",\n \"the-logo-asset-is-a-product-supplied-slot-never-bundled-by-the-design-system\",\n \"the-label-is-product-copy-because-the-required-wording-differs-per-provider-and-language\",\n \"height-radius-and-touch-target-stay-hjm-so-a-stack-of-providers-lines-up\",\n \"busy-keeps-the-label-and-the-button-width-instead-of-collapsing-to-a-spinner\",\n \"the-focus-ring-is-drawn-outside-the-brand-fill-so-it-survives-every-provider-color\",\n ],\n} as const satisfies BehaviorContract;\n"]}
1
+ {"version":3,"file":"provider-button.js","sourceRoot":"","sources":["../src/provider-button.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport { buttonRecipe } from \"./base-recipes.js\";\nimport { control, radius, spacing, typography } from \"./foundations.js\";\n\n/**\n * 소셜 로그인 버튼이다. Button의 tone 하나로 풀 수 없어서 별도 계약으로 둔다.\n *\n * HJM의 tone은 **의미**(primary/secondary/danger)이고 팔레트가 테마를 따라 움직인다.\n * 제공자 버튼의 색은 의미가 아니라 **남의 브랜드 자산**이다 — Google·Kakao·Naver·Apple이\n * 각자 로그인 버튼의 배경·글자·테두리·최소 크기를 브랜드 가이드라인으로 규정하고, 심사에서\n * 그대로 쓰기를 요구한다. 그래서 이 색들은 semantic token이 아니고 테마가 다시 칠하지\n * 않는다. 제품이 `.hjm-button.bt-provider-google` 같은 CSS로 덮어 오던 자리를 계약으로\n * 올리되, 값의 출처가 HJM이 아니라는 사실을 타입으로 드러낸다.\n *\n * **HJM이 소유하는 것**: 높이·radius·터치 타깃·포커스 링·로고와 라벨의 배치·큰 글자 대응.\n * **제공자가 소유하는 것**: 색과 로고 모양.\n * **제품이 소유하는 것**: 로고 자산(재배포하지 않으므로 슬롯으로 받는다)과 현지화된 문구\n * (\"Google로 계속하기\"의 정확한 표현은 제공자 가이드라인과 언어에 따라 다르다).\n */\nexport type AuthProviderId = \"google\" | \"kakao\" | \"naver\" | \"apple\";\n\nexport type AuthProviderSurface = Readonly<{\n /** 제공자 가이드라인이 지정한 배경색. HJM 팔레트가 아니다. */\n background: string;\n /** 같은 가이드라인의 글자/로고 색. */\n content: string;\n /** 배경이 캔버스와 구분되지 않을 때만 가이드라인이 요구하는 테두리. */\n border: string | null;\n}>;\n\nexport type AuthProviderPalette = Readonly<{\n light: AuthProviderSurface;\n /**\n * 제공자가 다크 변형을 따로 규정한 경우에만 다르다. 브랜드색 자체가 정체성인\n * Kakao·Naver는 다크에서도 같은 색을 쓰라고 명시하므로 light와 동일하다.\n */\n dark: AuthProviderSurface;\n}>;\n\n/**\n * 값의 출처는 각 제공자의 공개 브랜드 가이드라인이다(2026-09 확인).\n * 로고 이미지는 포함하지 않는다 — 배포 조건이 제공자마다 다르고, HJM이 재배포할 권리가\n * 없다. 가이드라인이 바뀌면 이 표를 고치는 것이 유일한 변경 지점이다.\n */\nexport const authProviderPalettes = {\n // Google Identity: 흰 버튼 #FFFFFF / 글자 #1F1F1F / 테두리 #747775,\n // 어두운 변형 #131314 / #E3E3E3 / #8E918F.\n google: {\n light: { background: \"#FFFFFF\", content: \"#1F1F1F\", border: \"#747775\" },\n dark: { background: \"#131314\", content: \"#E3E3E3\", border: \"#8E918F\" },\n },\n // Kakao 로그인: 배경 #FEE500 고정, 글자 #191919.\n // 예전 값은 `rgba(0, 0, 0, 0.85)`였다. 흔히 인용되는 \"검정 85%\"인데, 노란 배경 위에서\n // 실제로 합성하면 (38, 34, 0)이라 카카오가 배포하는 버튼 이미지의 글자색과 다르다.\n // 공식 자산(kakao_login.zip의 ko/kakao_login_large_wide.png)에서 픽셀을 뽑아 대조했다.\n kakao: {\n light: { background: \"#FEE500\", content: \"#191919\", border: null },\n dark: { background: \"#FEE500\", content: \"#191919\", border: null },\n },\n // 네이버 로그인: 배경 #03A94D 고정, 글자 흰색.\n // 예전 값 #03C75A는 구 BI다. 네이버 로그인 BI 가이드가 \"배경 컬러가 더 뚜렷하게\n // 바뀌었어요. 반드시 지정된 녹색을 사용해 주세요. 컬러 #03A94D, RGB 3/169/77\"로 못박고,\n // 배포 중인 버튼 자산(NAVER_login_KR.zip)의 픽셀도 (3, 169, 77)이다(2026-09-19 확인).\n naver: {\n light: { background: \"#03A94D\", content: \"#FFFFFF\", border: null },\n dark: { background: \"#03A94D\", content: \"#FFFFFF\", border: null },\n },\n // Sign in with Apple: 검정 버튼이 기본, 밝은 배경 위에서는 흰 버튼 + 검은 테두리.\n apple: {\n light: { background: \"#000000\", content: \"#FFFFFF\", border: null },\n dark: { background: \"#FFFFFF\", content: \"#000000\", border: \"#000000\" },\n },\n} as const satisfies Readonly<Record<AuthProviderId, AuthProviderPalette>>;\n\nexport type AuthProviderButtonDescriptor = Readonly<{\n provider: AuthProviderId;\n /** 제공자 가이드라인과 언어에 맞춘 문구. renderer가 만들지 않는다. */\n label: string;\n /** 진행 중 표시. 라벨을 지우지 않고 버튼 폭도 유지한다. */\n busy?: boolean;\n disabled?: boolean;\n}>;\n\nexport function validateAuthProviderButtonDescriptor(\n descriptor: AuthProviderButtonDescriptor,\n): void {\n if (descriptor === null || typeof descriptor !== \"object\") {\n throw new TypeError(\"AuthProviderButton descriptor must be an object\");\n }\n if (!Object.prototype.hasOwnProperty.call(authProviderPalettes, descriptor.provider)) {\n throw new TypeError(`Unsupported auth provider: ${String(descriptor.provider)}`);\n }\n if (typeof descriptor.label !== \"string\" || descriptor.label.trim().length === 0) {\n throw new TypeError(\"AuthProviderButton label must not be empty\");\n }\n}\n\n/** 해석된 테마에 맞는 제공자 표면. 테마는 *변형 선택*만 하고 색을 만들지 않는다. */\nexport function resolveAuthProviderSurface(\n provider: AuthProviderId,\n theme: \"light\" | \"dark\",\n): AuthProviderSurface {\n return authProviderPalettes[provider][theme];\n}\n\n/**\n * 크기는 HJM 것이다 — 한 화면에 네 개가 세로로 쌓이므로 높이·radius·간격이 서로 다르면\n * 목록이 무너진다. `buttonRecipe`의 medium 높이와 같은 값을 쓰고, 최소 터치 타깃도 공유한다.\n */\nexport const authProviderButtonRecipe = {\n slots: [\"root\", \"logo\", \"label\", \"spinner\"] as const,\n minHeight: buttonRecipe.sizes.medium.height,\n minTouchTarget: control.minTouchTarget,\n radius: radius.md,\n paddingHorizontal: spacing.md,\n gap: spacing.sm,\n logoSize: 20,\n label: typography.body,\n borderWidth: 1,\n /** 제공자 색 위에서도 보이도록 포커스 링은 바깥에 그린다. */\n focusOutlineOffset: 2,\n} as const;\n\nexport const authProviderButtonBehavior = {\n controlled: [],\n inputs: [\"provider\", \"label\", \"busy\", \"disabled\"],\n events: [\"onPress\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\", \"busy\"],\n interaction: [\"idle\", \"hover\", \"focusVisible\", \"pressed\"],\n },\n web: { roles: [\"button\"], keyboard: [\"Enter\", \"Space\"], focus: \"native\" },\n native: { roles: [\"button\"], states: [\"disabled\", \"busy\"], actions: [\"press\"] },\n scenarios: [\n \"provider-colors-come-from-the-provider-guideline-and-the-theme-never-recolors-them\",\n \"the-theme-only-picks-between-the-providers-own-light-and-dark-variants\",\n \"the-logo-asset-is-a-product-supplied-slot-never-bundled-by-the-design-system\",\n \"the-label-is-product-copy-because-the-required-wording-differs-per-provider-and-language\",\n \"height-radius-and-touch-target-stay-hjm-so-a-stack-of-providers-lines-up\",\n \"busy-keeps-the-label-and-the-button-width-instead-of-collapsing-to-a-spinner\",\n \"the-focus-ring-is-drawn-outside-the-brand-fill-so-it-survives-every-provider-color\",\n ],\n} as const satisfies BehaviorContract;\n"]}
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Package release shown by documentation surfaces. Kept in sync by a test. */
2
- export declare const designSystemVersion: "1.3.4";
2
+ export declare const designSystemVersion: "1.3.5";
3
3
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Package release shown by documentation surfaces. Kept in sync by a test. */
2
- export const designSystemVersion = "1.3.4";
2
+ export const designSystemVersion = "1.3.5";
3
3
  //# sourceMappingURL=version.js.map
@@ -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.3.4\" as const;\n"]}
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.3.5\" as const;\n"]}
@@ -1,6 +1,6 @@
1
1
  # Component maturity and evidence manifest
2
2
 
3
- > Generated from `@hjmds/design-contracts` 1.3.4. Do not edit this file directly; run `pnpm contracts:sync`.
3
+ > Generated from `@hjmds/design-contracts` 1.3.5. 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.4",
3
+ "designSystemVersion": "1.3.5",
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.3.4",
8
+ "packageVersion": "1.3.5",
9
9
  "activeComponents": 96,
10
10
  "claimedComponents": 96,
11
11
  "completeScenarioComponents": 33,
@@ -4508,7 +4508,7 @@
4508
4508
  },
4509
4509
  "native": {
4510
4510
  "packageName": "@hjmds/react-native",
4511
- "packageVersion": "1.3.4",
4511
+ "packageVersion": "1.3.5",
4512
4512
  "activeComponents": 79,
4513
4513
  "claimedComponents": 79,
4514
4514
  "completeScenarioComponents": 32,
@@ -1,6 +1,6 @@
1
1
  # Renderer evidence coverage
2
2
 
3
- > Generated for HJM 1.3.4. Do not edit directly; run `pnpm evidence:sync`.
3
+ > Generated for HJM 1.3.5. Do not edit directly; run `pnpm evidence:sync`.
4
4
 
5
5
  This projection joins the canonical surface maturity manifest with first-party renderer claims. Missing scenarios are explicit beta promotion debt; stable surfaces are blocked by CI until none remain.
6
6
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "designSystemVersion": "1.3.4",
3
+ "designSystemVersion": "1.3.5",
4
4
  "packageName": "@hjmds/design-contracts",
5
5
  "components": [
6
6
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hjmds/design-contracts",
3
- "version": "1.3.4",
3
+ "version": "1.3.5",
4
4
  "description": "Renderer-neutral design contracts, tokens, recipes, and behaviors shared by HJM products.",
5
5
  "license": "MIT",
6
6
  "repository": {