ksk-design-system 1.64.0 → 1.65.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/README.md CHANGED
@@ -308,6 +308,9 @@ DS を import して委譲するだけの薄いラッパー(段階移行の型
308
308
  <!-- docs-drift-ignore: PrimaryButton AppTextInput BottomSheet CandidateOverflowMenu CrisisBanner AvatarView -->
309
309
  さらに、`contracts/components.json` と完全一致しない名前でも、DS 部品を連想させる命名パターン(`PrimaryButton` → `Button` / `AppTextInput` → `Input` / `BottomSheet` → `Sheet` / `CandidateOverflowMenu` → `DropdownMenu` / `CrisisBanner` → `Banner` / `AvatarView` → `Avatar` 等)は「重複の疑い」として `⚠` 付きで warn 表示されます。これは名前一致のみによる推測(AST は使いません)のため確度は下がり、`--strict` でも exit code には影響しません。誤検知の場合は無視して構いませんが、恒常的に抑制したい場合はそのファイル内のコメントに `ksk-ds-local-fallback` を含めてください。
310
310
 
311
+ <!-- docs-drift-ignore: CandidateOverflowMenu -->
312
+ ただし、ファイルが `ksk-design-system`(`/native` 等のサブパス含む)から named import し、その import した識別子を JSX またはコールとして実際に使っている場合は、名前が DS と異なっていても「DS 委譲ラッパー」とみなし疑い検出の対象から除外します(例: `CandidateOverflowMenu` が `DropdownMenu` を import して `<DropdownMenu>` として使うケース)。DS を import しているだけで実際には使っていない場合はこの除外の対象外です。
313
+
311
314
  ### Media overlay utilities
312
315
 
313
316
  動画・写真の上に文字や操作を置く場合は、`--Text-on-Media` と `.text-on-media` / `.text-on-media-secondary`、上下の `.media-scrim-top` / `.media-scrim-bottom` を使います。TikTok / Reels 型の操作群は `MediaActionCluster` が glass ボタン、ラベル、safe-area anchor、idle auto-hide をまとめて扱います。
@@ -174,6 +174,34 @@ function collectDsImportSourceNames(source) {
174
174
  return names
175
175
  }
176
176
 
177
+ // このファイルが ksk-design-system から named import している要素の
178
+ // ローカル名(alias 込み)の集合。DS 委譲ラッパー判定(実使用チェック)に使う。
179
+ function collectDsImportLocalNames(source) {
180
+ const names = new Set()
181
+ const importPattern = /import\s*\{([^}]*)\}\s*from\s*["']([^"']+)["']/g
182
+
183
+ for (const match of source.matchAll(importPattern)) {
184
+ const [, specifierList, moduleSpecifier] = match
185
+ if (!isDsModuleSpecifier(moduleSpecifier)) continue
186
+ for (const { localName } of parseSpecifierList(specifierList)) {
187
+ names.add(localName)
188
+ }
189
+ }
190
+
191
+ return names
192
+ }
193
+
194
+ // import した DS のローカル名が、JSX(`<Name`)または関数呼び出し(`Name(`)として
195
+ // 実際に使われているか。import しているだけで使っていないケース(不要 import 等)は
196
+ // 「実際に委譲している」とは言えないため対象外にする。
197
+ function usesAnyIdentifierAsJsxOrCall(source, localNames) {
198
+ for (const localName of localNames) {
199
+ const usagePattern = new RegExp(`<${localName}[\\s/>]|\\b${localName}\\s*\\(`)
200
+ if (usagePattern.test(source)) return true
201
+ }
202
+ return false
203
+ }
204
+
177
205
  // `export { X as Y } from 'ksk-design-system/...'` のような re-export 形式。
178
206
  // これは常に DS の実装をそのまま右から左へ渡すだけなので、localName が
179
207
  // registry と一致する場合は無条件でラッパー(除外対象)として扱う。
@@ -249,7 +277,11 @@ function findDuplicateExports(file, cwd, registry) {
249
277
 
250
278
  const codeForImportScan = stripComments(source)
251
279
  const dsImportSourceNames = collectDsImportSourceNames(codeForImportScan)
280
+ const dsImportLocalNames = collectDsImportLocalNames(codeForImportScan)
252
281
  const dsReExportLocalNames = collectDsReExports(codeForImportScan)
282
+ // issue #451: 名前が DS と違っても、DS を import してそれを JSX/関数呼び出しで
283
+ // 実際に使っていれば「DS 委譲ラッパー」とみなし、名前ヒューリスティックの疑い対象から除外する。
284
+ const isDsDelegatingWrapper = usesAnyIdentifierAsJsxOrCall(codeForImportScan, dsImportLocalNames)
253
285
 
254
286
  const declarationPattern =
255
287
  /^\s*export\s+(?:default\s+)?(?:(?:async|declare)\s+)?(?:function|const)\s+([A-Z][A-Za-z0-9]*)\b/
@@ -265,6 +297,7 @@ function findDuplicateExports(file, cwd, registry) {
265
297
  // DS を import しているファイル(何らかの形で DS を使っている=別部品のラッパー等)
266
298
  // でも疑いは出す。抑制は SUPPRESSION_MARKER コメントのみ。
267
299
  if (suppressSuspicions) continue
300
+ if (isDsDelegatingWrapper) continue
268
301
  const suggested = suggestDsNameForLocalName(name)
269
302
  if (!suggested) continue
270
303
  suspicions.push({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "meta": {
3
3
  "name": "KSK Design System — Component Contracts",
4
- "version": "1.64.0",
4
+ "version": "1.65.0",
5
5
  "description": "全コンポーネントの構造化定義。バリアント・アクセシビリティ要件・使用ルールを機械可読形式で管理。",
6
6
  "counts": {
7
7
  "ui": 68,
@@ -77,6 +77,7 @@
77
77
  "リンクを Button として表示する場合は <Button asChild><a href=... /></Button> を使う",
78
78
  "Icon-only buttons require aria-label",
79
79
  "Native Button supports loading/loadingLabel and leadingIcon/trailingIcon; do not wrap ActivityIndicator in Text",
80
+ "Native Button supports spinnerColor to override the loading ActivityIndicator color; default unchanged (falls back to variant fg color, issue #450)",
80
81
  "variant=glass は背景がグラデーション/写真の場合のみ使用",
81
82
  "variant=glass-inverse は暗い写真・動画・濃色面上の Liquid Glass CTA 専用",
82
83
  "variant=inverse / ghost-inverse は暗背景・ヒーローセクション専用",
@@ -103,7 +104,8 @@
103
104
  "Must use <Input> not <input>",
104
105
  "showCount + maxLength で controlled / uncontrolled / IME 対応の文字数カウンタを表示",
105
106
  "showCount 未指定時は wrapper / counter DOM を追加しない",
106
- "既存の手書き CSS を持つ画面の段階移行では unstyled を使う(showCount / adornment / IME 追従は維持される)"
107
+ "既存の手書き CSS を持つ画面の段階移行では unstyled を使う(showCount / adornment / IME 追従は維持される)",
108
+ "Native Input supports style (outer container View) and inputStyle (inner TextInput) as RN-idiomatic style overrides, merged after DS defaults (issue #447)"
107
109
  ]
108
110
  },
109
111
  {
@@ -344,7 +346,8 @@
344
346
  ],
345
347
  "rules": [
346
348
  "rounded-full only",
347
- "Use DiceBear shapes for placeholder, not pravatar.cc"
349
+ "Use DiceBear shapes for placeholder, not pravatar.cc",
350
+ "native (src/native/components/Avatar.tsx): size はプリセット(sm/md/lg/xl)に加えて pt の数値も可。shape=\"circle\"(既定)|\"rounded\"、rounded の角丸は radius(lg/xl/2xl・既定 xl)。fallback は文字列に加えて ReactNode を受け、独自のフォールバック表示(決定論グラデ+絵文字等)を差し込める。source はリモート URL 文字列も受け取り {uri} に正規化する(issue #449)"
348
351
  ]
349
352
  },
350
353
  {
@@ -408,7 +411,8 @@
408
411
  "autoFocus は first-input / title / ref / false を指定可能",
409
412
  "description prop はRadix管理IDの sr-only description を自動生成する",
410
413
  "SheetTitle は level=\"page\"|\"section\"|\"card\" で見出しの役割を指定する(値は contracts/composition.json の textHierarchy と1対1)。未指定時は BottomSheetFrame preset=\"mobile-full\"|\"mobile-page\" 配下で page 相当、それ以外は従来の typo-heading-lg",
411
- "native (src/native/components/Sheet.tsx): safeArea(既定 true) で side=\"top\" の上端 inset 退避と、画面いっぱいに近い side=\"bottom\" の食い込み分の退避を行う。実測 inset は SafeAreaInsetsProvider から供給し、未供給なら回避量 0(従来どおり)"
414
+ "native (src/native/components/Sheet.tsx): safeArea(既定 true) で side=\"top\" の上端 inset 退避と、画面いっぱいに近い side=\"bottom\" の食い込み分の退避を行う。実測 inset は SafeAreaInsetsProvider から供給し、未供給なら回避量 0(従来どおり)",
415
+ "native (src/native/components/Sheet.tsx): surfaceColor でパネル(および snap モードの footer)の面色を上書きできる。未指定なら theme.surface.primary(従来どおり)。scrim の色は変えない(issue #448)"
412
416
  ],
413
417
  "variants": {
414
418
  "titleLevel": [
@@ -1599,7 +1603,8 @@
1599
1603
  "placement: start / end / center",
1600
1604
  "bottomOffset: none / bottom-nav / bottom-nav-pill / bottom-nav-pill-inline",
1601
1605
  "keyboardBehavior: hide / lift / stay",
1602
- "fullWidth: true / false"
1606
+ "fullWidth: true / false",
1607
+ "bottomOffsetExtra: CSS length(web)/ number pt(native)。bottomOffset プリセット値へ加算する任意の追加オフセット"
1603
1608
  ],
1604
1609
  "accessibility": [
1605
1610
  "label prop is required and used as aria-label"
@@ -1611,7 +1616,8 @@
1611
1616
  "pill BottomTabBar の上に重ねる場合は bottomOffset=bottom-nav-pill、横並びに置く場合は bottomOffset=bottom-nav-pill-inline を使う",
1612
1617
  "keyboard 表示中に入力を邪魔する場合は keyboardBehavior=hide を使う",
1613
1618
  "variant=glass に shadow-* を重ねない(glass-accent が inset 3層 + drop shadow を内包するため二重になる)",
1614
- "下部固定の全幅 CTA は fullWidth を使い、fixed inset-x + Button を手組みしない。fullWidth 時は placement が無視されラベルが常に表示される"
1619
+ "下部固定の全幅 CTA は fullWidth を使い、fixed inset-x + Button を手組みしない。fullWidth 時は placement が無視されラベルが常に表示される",
1620
+ "広告バナー等で動的に持ち上げる必要があるときは、内部変数 --ksk-fab-bottom-offset を直接上書きせず bottomOffsetExtra を使う(issue #453)"
1615
1621
  ]
1616
1622
  },
1617
1623
  {
@@ -2203,7 +2209,8 @@
2203
2209
  ],
2204
2210
  "rules": [
2205
2211
  "長い SheetContent className recipe を consumer 側に重複させず BottomSheetFrame preset を使う",
2206
- "フォーム/詳細の中身は DetailSheetScaffold と KeyboardAwareSheetFooter を使う"
2212
+ "フォーム/詳細の中身は DetailSheetScaffold と KeyboardAwareSheetFooter を使う",
2213
+ "native (src/native/components/BottomSheetFrame.tsx): height=\"preset\"(既定・従来の固定高)|\"fitContent\"(min/max を外して内容量に追従)。maxHeight で上限だけ明示できる。safeArea(既定 false) で bottom inset 分の内側余白、handle(既定 false) で上端のつまみを表示(issue #448)"
2207
2214
  ]
2208
2215
  },
2209
2216
  {
@@ -70,7 +70,7 @@
70
70
  "severity": "error",
71
71
  "category": "component",
72
72
  "appliesTo": ["dom"],
73
- "pattern": "<a href",
73
+ "pattern": "(?<!(?:asChild|<Slot)[\\s\\S]{0,300})<a href",
74
74
  "excludePaths": [".stories."],
75
75
  "excludeDsPaths": ["components/ui/", "components/patterns/"],
76
76
  "excludeLines": ["data-slot", "asChild"],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "meta": {
3
3
  "name": "KSK Design System — Semantic Token Hex Cache",
4
- "version": "1.64.0",
4
+ "version": "1.65.0",
5
5
  "description": "semantic / semanticDark トークン(var(--Primitive-*) 参照)を実 hex に解決したサイドカー生成物。hex はデフォルト(Blue)テーマでの解決値であり、Brand 系(meta.themeDependentKeys に列挙)はテーマ差し替え(orange/green/violet 等)で実色が変わる。テーマ別の完全解決値は `ksk-design-system/native` エクスポート(バンドル済み native トークンモジュール)の themes を参照。tokens.json 本体のスキーマは変更せず、AI がこのファイルだけで実色を把握できるようにし、primitive 値の変更による semantic 実色のドリフトを --check で機械検出する。",
6
6
  "generatedBy": "scripts/generate-token-hex-cache.mjs",
7
7
  "theme": "default",