ksk-design-system 2.0.1 → 2.1.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/AGENTS.md +34 -0
- package/CLAUDE.md +34 -0
- package/UPDATING.md +17 -0
- package/contracts/components.json +1 -1
- package/contracts/product-theme-overrides.json +15 -4
- package/contracts/token-hex-cache.json +1 -1
- package/dist/index.js +52 -49
- package/dist/types/components/patterns/commerce/bottom-tab-bar.d.ts +31 -1
- package/dist/types/components/patterns/commerce/mobile-tab-bar.d.ts +6 -1
- package/package.json +10 -7
- package/src/components/COMPONENT_LOOKUP.md +1 -1
- package/src/styles/bottom-nav.css +45 -1
package/AGENTS.md
CHANGED
|
@@ -279,6 +279,9 @@ npm run lint:design
|
|
|
279
279
|
# 非推奨 API 台帳の整合検査(台帳 ⇔ 実ソースの @deprecated JSDoc)
|
|
280
280
|
npm run lint:deprecations
|
|
281
281
|
|
|
282
|
+
# `Closes #N` 誤リンク監査(gh 必須。npm run check には入っていない)
|
|
283
|
+
npm run audit:issue-links -- --recent 60
|
|
284
|
+
|
|
282
285
|
# MIGRATION.md の「非推奨 API 一覧」節を台帳から再生成
|
|
283
286
|
npm run generate:migration-doc
|
|
284
287
|
|
|
@@ -293,8 +296,25 @@ npm run test:interaction
|
|
|
293
296
|
|
|
294
297
|
# a11y 機械検証(axe-core。全ストーリー対象。issue #261)
|
|
295
298
|
npm run test:a11y
|
|
299
|
+
|
|
300
|
+
# 旧 Radix 固定の回帰テスト(consumer が古い Radix を掴む条件を再現。issue #516)
|
|
301
|
+
npm run test:legacy-radix
|
|
296
302
|
```
|
|
297
303
|
|
|
304
|
+
**`Closes #N` 誤リンク監査について(issue #486 が由来):**
|
|
305
|
+
|
|
306
|
+
- PR 本文の `Closes #N` が**別 issue を閉じてしまう**事故を検出する。実例:
|
|
307
|
+
PR #488 が `Closes #486` を書きながら実装したのは ResponsiveOverlayFrame で、
|
|
308
|
+
issue #486(BottomTabBar pill の面)は**未実装のまま自動クローズ**され、
|
|
309
|
+
消費側がリリースされない要望を待ち続けていた。
|
|
310
|
+
- 判定は `contracts/components.json` のコンポーネント名を語彙にして、
|
|
311
|
+
「PR が触った / 言及したコンポーネント」と「issue が指すコンポーネント」に
|
|
312
|
+
共通要素が 1 つも無ければ疑う。どちらかが空(インフラ・トークン系)なら
|
|
313
|
+
判定材料なしとして黙って飛ばす — **見逃してでも誤検知を出さない**方針。
|
|
314
|
+
- `gh` CLI(ネットワーク)が要るため `npm run check` には**含めない**。
|
|
315
|
+
リリース前の棚卸しと、疑わしい PR を見つけたときに手で回す。
|
|
316
|
+
- 単発検査は `npm run audit:issue-links -- --pr 488`。
|
|
317
|
+
|
|
298
318
|
**interaction テストについて(issue #256):**
|
|
299
319
|
|
|
300
320
|
- 実体は Storybook の play 関数。`@storybook/addon-vitest` + vitest browser mode(playwright chromium)で
|
|
@@ -325,6 +345,20 @@ npm run test:a11y
|
|
|
325
345
|
`eslint/icon-button-aria-label.js`(`ksk-a11y/icon-button-aria-label`)で lint 時に検出する
|
|
326
346
|
(`.stories.tsx` は対象外)。
|
|
327
347
|
|
|
348
|
+
**旧 Radix 回帰テストについて(issue #516):**
|
|
349
|
+
|
|
350
|
+
- DS の node_modules は ref churn 修正済みの Radix を解決するため、`npm test` では
|
|
351
|
+
「consumer が古い Radix を掴んだときだけ落ちる」種類の回帰を**原理的に再現できない**
|
|
352
|
+
(#516 は belle-todo で初めて表面化した)。
|
|
353
|
+
- `npm run test:legacy-radix` は当時 belle-todo が解決していた radix-ui@1.4.3 を
|
|
354
|
+
`node_modules/.ksk-legacy-radix` へ install し、`vitest.legacy-radix.config.ts` の
|
|
355
|
+
alias でそちらを掴ませて `test/legacy-radix/` を回す。CI では常時実行。
|
|
356
|
+
- 併せて `package.json` の `radix-ui` / `@radix-ui/react-slot` の下限を安全版へ固定して
|
|
357
|
+
いる(`scripts/check-radix-floor.mjs` が `npm run check` で検査。正本データと版ごとの
|
|
358
|
+
差分は `scripts/radix-ref-churn.mjs`)。
|
|
359
|
+
- **オーバーレイ系(Dialog / Sheet / ResponsiveOverlayFrame)や `useComposedRef` を
|
|
360
|
+
触ったら `npm run test:legacy-radix` を回すこと。**
|
|
361
|
+
|
|
328
362
|
---
|
|
329
363
|
|
|
330
364
|
## カラートークン体系(3層構造)
|
package/CLAUDE.md
CHANGED
|
@@ -279,6 +279,9 @@ npm run lint:design
|
|
|
279
279
|
# 非推奨 API 台帳の整合検査(台帳 ⇔ 実ソースの @deprecated JSDoc)
|
|
280
280
|
npm run lint:deprecations
|
|
281
281
|
|
|
282
|
+
# `Closes #N` 誤リンク監査(gh 必須。npm run check には入っていない)
|
|
283
|
+
npm run audit:issue-links -- --recent 60
|
|
284
|
+
|
|
282
285
|
# MIGRATION.md の「非推奨 API 一覧」節を台帳から再生成
|
|
283
286
|
npm run generate:migration-doc
|
|
284
287
|
|
|
@@ -293,8 +296,25 @@ npm run test:interaction
|
|
|
293
296
|
|
|
294
297
|
# a11y 機械検証(axe-core。全ストーリー対象。issue #261)
|
|
295
298
|
npm run test:a11y
|
|
299
|
+
|
|
300
|
+
# 旧 Radix 固定の回帰テスト(consumer が古い Radix を掴む条件を再現。issue #516)
|
|
301
|
+
npm run test:legacy-radix
|
|
296
302
|
```
|
|
297
303
|
|
|
304
|
+
**`Closes #N` 誤リンク監査について(issue #486 が由来):**
|
|
305
|
+
|
|
306
|
+
- PR 本文の `Closes #N` が**別 issue を閉じてしまう**事故を検出する。実例:
|
|
307
|
+
PR #488 が `Closes #486` を書きながら実装したのは ResponsiveOverlayFrame で、
|
|
308
|
+
issue #486(BottomTabBar pill の面)は**未実装のまま自動クローズ**され、
|
|
309
|
+
消費側がリリースされない要望を待ち続けていた。
|
|
310
|
+
- 判定は `contracts/components.json` のコンポーネント名を語彙にして、
|
|
311
|
+
「PR が触った / 言及したコンポーネント」と「issue が指すコンポーネント」に
|
|
312
|
+
共通要素が 1 つも無ければ疑う。どちらかが空(インフラ・トークン系)なら
|
|
313
|
+
判定材料なしとして黙って飛ばす — **見逃してでも誤検知を出さない**方針。
|
|
314
|
+
- `gh` CLI(ネットワーク)が要るため `npm run check` には**含めない**。
|
|
315
|
+
リリース前の棚卸しと、疑わしい PR を見つけたときに手で回す。
|
|
316
|
+
- 単発検査は `npm run audit:issue-links -- --pr 488`。
|
|
317
|
+
|
|
298
318
|
**interaction テストについて(issue #256):**
|
|
299
319
|
|
|
300
320
|
- 実体は Storybook の play 関数。`@storybook/addon-vitest` + vitest browser mode(playwright chromium)で
|
|
@@ -325,6 +345,20 @@ npm run test:a11y
|
|
|
325
345
|
`eslint/icon-button-aria-label.js`(`ksk-a11y/icon-button-aria-label`)で lint 時に検出する
|
|
326
346
|
(`.stories.tsx` は対象外)。
|
|
327
347
|
|
|
348
|
+
**旧 Radix 回帰テストについて(issue #516):**
|
|
349
|
+
|
|
350
|
+
- DS の node_modules は ref churn 修正済みの Radix を解決するため、`npm test` では
|
|
351
|
+
「consumer が古い Radix を掴んだときだけ落ちる」種類の回帰を**原理的に再現できない**
|
|
352
|
+
(#516 は belle-todo で初めて表面化した)。
|
|
353
|
+
- `npm run test:legacy-radix` は当時 belle-todo が解決していた radix-ui@1.4.3 を
|
|
354
|
+
`node_modules/.ksk-legacy-radix` へ install し、`vitest.legacy-radix.config.ts` の
|
|
355
|
+
alias でそちらを掴ませて `test/legacy-radix/` を回す。CI では常時実行。
|
|
356
|
+
- 併せて `package.json` の `radix-ui` / `@radix-ui/react-slot` の下限を安全版へ固定して
|
|
357
|
+
いる(`scripts/check-radix-floor.mjs` が `npm run check` で検査。正本データと版ごとの
|
|
358
|
+
差分は `scripts/radix-ref-churn.mjs`)。
|
|
359
|
+
- **オーバーレイ系(Dialog / Sheet / ResponsiveOverlayFrame)や `useComposedRef` を
|
|
360
|
+
触ったら `npm run test:legacy-radix` を回すこと。**
|
|
361
|
+
|
|
328
362
|
---
|
|
329
363
|
|
|
330
364
|
## カラートークン体系(3層構造)
|
package/UPDATING.md
CHANGED
|
@@ -202,6 +202,23 @@ publish 直後は registry への反映に数分かかることがあるため
|
|
|
202
202
|
`package.json#peerDependencies` の範囲を確認し、警告の対象パッケージ自体を先に更新してから
|
|
203
203
|
`ksk-design-system` を上げる。警告を `--force` / `--legacy-peer-deps` で握りつぶして進めない。
|
|
204
204
|
|
|
205
|
+
### Radix の版が古いまま固定されている(`Maximum update depth exceeded`)
|
|
206
|
+
|
|
207
|
+
DS の依存 `radix-ui` は **`^1.6.1`**(#516 対応以降)。1.6.1 未満の Radix は
|
|
208
|
+
合成 ref(`composeRefs`)を毎 render 作り直すため、DS のオーバーレイ面(Dialog / Sheet /
|
|
209
|
+
ResponsiveOverlayFrame)が再描画を無限に誘発することがある(issue #516。belle-todo が
|
|
210
|
+
radix-ui@1.4.3 を解決していて踏んだ)。
|
|
211
|
+
|
|
212
|
+
症状が出たら、消費リポで実際に解決されている版を確認する:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
npm ls radix-ui @radix-ui/react-focus-scope @radix-ui/react-presence
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`radix-ui@1.6.1` 未満が出る場合は lockfile が古い版を固定している。`npm install` で
|
|
219
|
+
DS の下限に追随させる(`overrides` で Radix を固定しているなら、その固定を外すか
|
|
220
|
+
1.6.1 以上へ上げる)。
|
|
221
|
+
|
|
205
222
|
### Issue 起票先
|
|
206
223
|
|
|
207
224
|
DS 本体のバグ・想定外の破壊変更に遭遇した場合は、
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"statusPaletteNote": "statusPalette は「消費側が DS の primitive を自分の Tailwind alias(--color-sun-800 等)の実体として使っている」ケース向けの公開段(issue #384)。@theme inline の alias は生成ユーティリティに var(--Primitive-*) が直接展開されるため、alias 側を dark で差し替えても効かず、primitive を上書きする以外の経路が無い。公開しているのは status の tint 段(-50 × 4色)と、依頼のあったアクセント段(Red-600 / Green-700)だけ。-50 は DS の .dark ブロックが一切参照していない(dark の Surface-Caution/Success/Warning/Info は -900 と実値)ので、dark 内での上書きは DS コンポーネントに対して無害。light では --Surface-Caution / --Surface-Success / --Surface-Warning / --Surface-Info を駆動するので上書きは効く。アクセント段は light / dark の両方で DS semantic を駆動するため、パレット全段ではなく依頼ベースで1段ずつ開ける。",
|
|
24
24
|
"statusPaletteSideEffects": "--Primitive-Red-600 は --Caution-Base(light / dark 共通)と、dark の --Active-Destructive-Button を駆動する。dark で Red-600 を Red-500(#EF4444) より明るい値に差し替えると、destructive ボタンの active が hover より明るくなり押下の階調が反転する。差し替えるなら --Hover-Destructive-Button との明度関係を実測すること。--Primitive-Green-700 は light の --Text-Success / --Success-Base のみを駆動する(dark は Green-400 なので影響なし)。",
|
|
25
25
|
"contrastResponsibility": "neutralPalette(--Primitive-Gray-* / White / Black)を差し替えたら、本文×背景のコントラストは消費プロダクト側の責任になる。Gray は --Text-High-Emphasis(本文色)・--Text-Medium-Emphasis・--Surface-Secondary・--Border-Low-Emphasis など semantic.css の 33 箇所を駆動しているため、差し替え後に本文テキスト×各 Surface が WCAG AA(4.5:1、大きい文字は 3:1)を満たすか必ず実測すること。DS 側の scripts/check-contrast.mjs は DS 既定パレット向けの検査で、消費側の差し替えは見ていない。light / dark の両方を確認する。",
|
|
26
|
-
"navSurfaceNote": "--Nav-Center-Action-Surface / -Border / -Shadow と --Nav-Selected-Surface / -Shadow は例外的に :root へ既定値を置いていない(issue #471)。DS 既定は tone=\"inverse\" / dark で出し分ける素材(.glass-accent・ガラスの選択プラッター)で、単一の :root 値に畳めないため。src/styles/bottom-nav.css が var(--Nav-*, <DS 既定>) の形で持ち、消費側が宣言したときだけ上書きされる。宣言しなければレンダリングは 1px も変わらない。"
|
|
26
|
+
"navSurfaceNote": "--Nav-Center-Action-Surface / -Border / -Shadow と --Nav-Selected-Surface / -Shadow は例外的に :root へ既定値を置いていない(issue #471)。DS 既定は tone=\"inverse\" / dark で出し分ける素材(.glass-accent・ガラスの選択プラッター)で、単一の :root 値に畳めないため。src/styles/bottom-nav.css が var(--Nav-*, <DS 既定>) の形で持ち、消費側が宣言したときだけ上書きされる。宣言しなければレンダリングは 1px も変わらない。 --Nav-Pill-Surface / -Backdrop / -Border / -Shadow / -Specular も同じ扱い(issue #486)。pill 本体の DS 既定は Liquid Glass(.glass / tone=\"inverse\" は .glass-dark)で、背後コンテンツの可読性を優先して不透明面にしたい消費側のための口。フォールバックは .glass 自身の内部変数そのものなので、宣言しなければレンダリングは 1px も変わらない。ぼかしを完全に切るなら --Nav-Pill-Backdrop: none、ガラスのスペキュラ / 屈折リムまで消すなら --Nav-Pill-Specular: none(擬似要素の content を none にして生成させない)を併せて宣言する。"
|
|
27
27
|
},
|
|
28
28
|
"allowedVariables": {
|
|
29
29
|
"brandColor": [
|
|
@@ -165,6 +165,11 @@
|
|
|
165
165
|
"--Nav-Pill-Padding-X",
|
|
166
166
|
"--Nav-Pill-Padding-Y",
|
|
167
167
|
"--Nav-Pill-Gap",
|
|
168
|
+
"--Nav-Pill-Surface",
|
|
169
|
+
"--Nav-Pill-Backdrop",
|
|
170
|
+
"--Nav-Pill-Border",
|
|
171
|
+
"--Nav-Pill-Shadow",
|
|
172
|
+
"--Nav-Pill-Specular",
|
|
168
173
|
"--Nav-Item-Min-Height",
|
|
169
174
|
"--Nav-Item-Gap",
|
|
170
175
|
"--Nav-Center-Action-Size",
|
|
@@ -267,9 +272,15 @@
|
|
|
267
272
|
"--Nav-Center-Action-*",
|
|
268
273
|
"--Nav-Selected-*"
|
|
269
274
|
],
|
|
270
|
-
"ResponsiveDialog": [
|
|
271
|
-
|
|
272
|
-
|
|
275
|
+
"ResponsiveDialog": [
|
|
276
|
+
"--Overlay-Desktop-Breakpoint"
|
|
277
|
+
],
|
|
278
|
+
"ResponsiveOverlayFrame": [
|
|
279
|
+
"--Overlay-Desktop-Breakpoint"
|
|
280
|
+
],
|
|
281
|
+
"Toast": [
|
|
282
|
+
"--Toast-Viewport-Offset-Bottom"
|
|
283
|
+
]
|
|
273
284
|
},
|
|
274
285
|
"aiGuidance": [
|
|
275
286
|
"プロダクト差分は、まずこの契約の CSS 変数上書きで表現する。className での個別上書きを何十箇所にも散らさない。",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"name": "KSK Design System — Semantic Token Hex Cache",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.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",
|
package/dist/index.js
CHANGED
|
@@ -13089,8 +13089,8 @@ function Ef(e) {
|
|
|
13089
13089
|
liftInset: e === "lift" ? t : 0
|
|
13090
13090
|
};
|
|
13091
13091
|
}
|
|
13092
|
-
function Df({ className: e, items: t, centerAction: n, showLabels: r, tone: i = "default", maxWidth: a, variant: o = "default", pillPosition: s = "fixed", floatingPosition: c = "center", keyboardBehavior: l = "stay", scrollEdge: u = !1, navLabel: d = "メインナビゲーション",
|
|
13093
|
-
let
|
|
13092
|
+
function Df({ className: e, items: t, centerAction: n, showLabels: r, tone: i = "default", maxWidth: a, variant: o = "default", pillPosition: s = "fixed", floatingPosition: c = "center", keyboardBehavior: l = "stay", scrollEdge: u = !1, navLabel: d = "メインナビゲーション", showOnDesktop: f = !1, ...p }) {
|
|
13093
|
+
let m = Ef(l);
|
|
13094
13094
|
return o === "pill" ? /* @__PURE__ */ B(kf, {
|
|
13095
13095
|
className: e,
|
|
13096
13096
|
items: t,
|
|
@@ -13101,29 +13101,31 @@ function Df({ className: e, items: t, centerAction: n, showLabels: r, tone: i =
|
|
|
13101
13101
|
pillPosition: s,
|
|
13102
13102
|
floatingPosition: c,
|
|
13103
13103
|
scrollEdge: u,
|
|
13104
|
-
keyboardState:
|
|
13104
|
+
keyboardState: m,
|
|
13105
13105
|
navLabel: d,
|
|
13106
|
-
|
|
13106
|
+
showOnDesktop: f,
|
|
13107
|
+
...p
|
|
13107
13108
|
}) : /* @__PURE__ */ B(Of, {
|
|
13108
13109
|
className: e,
|
|
13109
13110
|
items: t,
|
|
13110
|
-
keyboardState:
|
|
13111
|
+
keyboardState: m,
|
|
13111
13112
|
navLabel: d,
|
|
13112
|
-
|
|
13113
|
+
showOnDesktop: f,
|
|
13114
|
+
...p
|
|
13113
13115
|
});
|
|
13114
13116
|
}
|
|
13115
|
-
function Of({ className: e, items: t, keyboardState: n, style: r, navLabel: i = "メインナビゲーション",
|
|
13117
|
+
function Of({ className: e, items: t, keyboardState: n, style: r, navLabel: i = "メインナビゲーション", showOnDesktop: a = !1, ...o }) {
|
|
13116
13118
|
return /* @__PURE__ */ B("nav", {
|
|
13117
13119
|
"data-slot": "bottom-tab-bar",
|
|
13118
13120
|
"data-keyboard-behavior": n.keyboardBehavior,
|
|
13119
13121
|
"data-keyboard-open": n.isKeyboardOpen || void 0,
|
|
13120
13122
|
"aria-label": i,
|
|
13121
|
-
className: G("fixed inset-x-0 z-[var(--Z-Nav)] transition-all duration-[var(--Motion-Duration-Base)]", n.keyboardBehavior === "lift" ? "bottom-[var(--ksk-bottom-tab-bar-keyboard-inset)]" : "bottom-0", "border-t border-[var(--Border-Low-Emphasis)] bg-[var(--Surface-Primary)]", "pb-[env(safe-area-inset-bottom)] lg:hidden", n.shouldHide && "translate-y-2 opacity-0 pointer-events-none invisible", e),
|
|
13123
|
+
className: G("fixed inset-x-0 z-[var(--Z-Nav)] transition-all duration-[var(--Motion-Duration-Base)]", n.keyboardBehavior === "lift" ? "bottom-[var(--ksk-bottom-tab-bar-keyboard-inset)]" : "bottom-0", "border-t border-[var(--Border-Low-Emphasis)] bg-[var(--Surface-Primary)]", "pb-[env(safe-area-inset-bottom)]", a ? "lg:block" : "lg:hidden", n.shouldHide && "translate-y-2 opacity-0 pointer-events-none invisible", e),
|
|
13122
13124
|
style: {
|
|
13123
13125
|
"--ksk-bottom-tab-bar-keyboard-inset": `${n.liftInset}px`,
|
|
13124
13126
|
...r
|
|
13125
13127
|
},
|
|
13126
|
-
...
|
|
13128
|
+
...o,
|
|
13127
13129
|
children: /* @__PURE__ */ B("div", {
|
|
13128
13130
|
className: "flex h-14 items-center justify-around px-1",
|
|
13129
13131
|
children: t.map((e) => /* @__PURE__ */ B(Af, {
|
|
@@ -13133,17 +13135,17 @@ function Of({ className: e, items: t, keyboardState: n, style: r, navLabel: i =
|
|
|
13133
13135
|
})
|
|
13134
13136
|
});
|
|
13135
13137
|
}
|
|
13136
|
-
function kf({ className: e, items: t, centerAction: n, showLabels: r, tone: i = "default", maxWidth: a = 430, pillPosition: o = "fixed", floatingPosition: s = "center", scrollEdge: c = !1, keyboardState: l, style: d, navLabel: f = "メインナビゲーション",
|
|
13137
|
-
let
|
|
13138
|
-
let e =
|
|
13138
|
+
function kf({ className: e, items: t, centerAction: n, showLabels: r, tone: i = "default", maxWidth: a = 430, pillPosition: o = "fixed", floatingPosition: s = "center", scrollEdge: c = !1, keyboardState: l, style: d, navLabel: f = "メインナビゲーション", showOnDesktop: p = !1, ...m }) {
|
|
13139
|
+
let h = !!n || r === !0, g = r ?? !!n, _ = n ? Math.ceil(t.length / 2) : t.length, v = t.slice(0, _), y = t.slice(_), b = u.useRef(null), [x, S] = u.useState(null), [C, w] = u.useState(!1), T = u.useCallback(() => {
|
|
13140
|
+
let e = b.current;
|
|
13139
13141
|
if (!e) return;
|
|
13140
13142
|
let t = e.querySelector("[data-platter-anchor]");
|
|
13141
13143
|
if (!t) {
|
|
13142
|
-
|
|
13144
|
+
S(null);
|
|
13143
13145
|
return;
|
|
13144
13146
|
}
|
|
13145
13147
|
let n = e.getBoundingClientRect(), r = t.getBoundingClientRect();
|
|
13146
|
-
|
|
13148
|
+
S((e) => {
|
|
13147
13149
|
let t = {
|
|
13148
13150
|
x: r.left - n.left,
|
|
13149
13151
|
y: r.top - n.top,
|
|
@@ -13153,66 +13155,66 @@ function kf({ className: e, items: t, centerAction: n, showLabels: r, tone: i =
|
|
|
13153
13155
|
return e && Math.abs(e.x - t.x) < .5 && Math.abs(e.y - t.y) < .5 && Math.abs(e.w - t.w) < .5 && Math.abs(e.h - t.h) < .5 ? e : t;
|
|
13154
13156
|
});
|
|
13155
13157
|
}, []);
|
|
13156
|
-
Tf(
|
|
13157
|
-
if (
|
|
13158
|
-
let e = requestAnimationFrame(() =>
|
|
13158
|
+
Tf(T), u.useEffect(() => {
|
|
13159
|
+
if (x && !C) {
|
|
13160
|
+
let e = requestAnimationFrame(() => w(!0));
|
|
13159
13161
|
return () => cancelAnimationFrame(e);
|
|
13160
13162
|
}
|
|
13161
|
-
}, [
|
|
13162
|
-
let e =
|
|
13163
|
+
}, [x, C]), u.useEffect(() => {
|
|
13164
|
+
let e = b.current;
|
|
13163
13165
|
if (!e || typeof ResizeObserver > "u") return;
|
|
13164
|
-
let t = new ResizeObserver(
|
|
13166
|
+
let t = new ResizeObserver(T);
|
|
13165
13167
|
return t.observe(e), () => t.disconnect();
|
|
13166
|
-
}, [
|
|
13167
|
-
let
|
|
13168
|
+
}, [T]);
|
|
13169
|
+
let E = s === "left" || s === "right", D = {
|
|
13168
13170
|
"--ksk-bottom-tab-bar-keyboard-inset": `${l.liftInset}px`,
|
|
13169
|
-
...
|
|
13171
|
+
...h && !E ? {
|
|
13170
13172
|
width: "calc(100vw - 24px)",
|
|
13171
13173
|
maxWidth: a
|
|
13172
13174
|
} : {},
|
|
13173
|
-
...
|
|
13175
|
+
...E ? { maxWidth: "calc(100vw - 92px)" } : {},
|
|
13174
13176
|
...d
|
|
13175
13177
|
};
|
|
13176
13178
|
return /* @__PURE__ */ V(z, { children: [c && /* @__PURE__ */ B("div", {
|
|
13177
13179
|
"aria-hidden": "true",
|
|
13178
|
-
className: G("inset-x-0 bottom-0 z-[var(--Z-Sticky)] h-28 lg:hidden", "glass-scroll-edge-bottom", "transition-opacity duration-[var(--Motion-Duration-Base)]", o === "fixed" ? "fixed" : "absolute", l.shouldHide && "opacity-0")
|
|
13180
|
+
className: G("inset-x-0 bottom-0 z-[var(--Z-Sticky)] h-28", p ? "lg:block" : "lg:hidden", "glass-scroll-edge-bottom", "transition-opacity duration-[var(--Motion-Duration-Base)]", o === "fixed" ? "fixed" : "absolute", l.shouldHide && "opacity-0")
|
|
13179
13181
|
}), /* @__PURE__ */ V("nav", {
|
|
13180
13182
|
"data-slot": "bottom-nav-pill",
|
|
13181
13183
|
"data-tone": i,
|
|
13182
13184
|
"data-keyboard-behavior": l.keyboardBehavior,
|
|
13183
13185
|
"data-keyboard-open": l.isKeyboardOpen || void 0,
|
|
13184
13186
|
"aria-label": f,
|
|
13185
|
-
className: G("z-[var(--Z-Nav)]
|
|
13186
|
-
style:
|
|
13187
|
-
...
|
|
13188
|
-
ref:
|
|
13187
|
+
className: G("z-[var(--Z-Nav)] transition-all duration-[var(--Motion-Duration-Base)]", p ? "lg:flex" : "lg:hidden", o === "fixed" ? "fixed" : "absolute", l.keyboardBehavior === "lift" ? "bottom-[calc(env(safe-area-inset-bottom)_+_12px_+_var(--ksk-bottom-tab-bar-keyboard-inset))]" : "bottom-[calc(env(safe-area-inset-bottom)_+_12px)]", s === "left" && "left-3 right-20", s === "right" && "right-3 left-20", s === "center" && "left-1/2 -translate-x-1/2", "flex items-center rounded-full glass-specular", i === "inverse" ? "glass-dark" : "glass", h ? "min-h-[var(--Nav-Pill-Min-Height)] gap-[var(--Nav-Pill-Gap)] px-[var(--Nav-Pill-Padding-X)] py-[var(--Nav-Pill-Padding-Y)]" : "h-[58px] gap-0 px-3", l.shouldHide && "translate-y-2 opacity-0 pointer-events-none invisible", e),
|
|
13188
|
+
style: D,
|
|
13189
|
+
...m,
|
|
13190
|
+
ref: b,
|
|
13189
13191
|
children: [
|
|
13190
|
-
|
|
13192
|
+
x && /* @__PURE__ */ B("span", {
|
|
13191
13193
|
"aria-hidden": "true",
|
|
13192
13194
|
"data-slot": wf,
|
|
13193
13195
|
"data-nav-platter": !0,
|
|
13194
|
-
className: G("absolute left-0 top-0 rounded-full pointer-events-none",
|
|
13196
|
+
className: G("absolute left-0 top-0 rounded-full pointer-events-none", C && "transition-[transform,width,height] duration-[var(--Motion-Duration-Base)] ease-[var(--Motion-Easing-Standard)] motion-reduce:transition-none"),
|
|
13195
13197
|
style: {
|
|
13196
|
-
width:
|
|
13197
|
-
height:
|
|
13198
|
-
transform: `translate3d(${
|
|
13198
|
+
width: x.w,
|
|
13199
|
+
height: x.h,
|
|
13200
|
+
transform: `translate3d(${x.x}px, ${x.y}px, 0)`
|
|
13199
13201
|
}
|
|
13200
13202
|
}),
|
|
13201
|
-
|
|
13203
|
+
v.map((e, t) => /* @__PURE__ */ B(Af, {
|
|
13202
13204
|
item: e,
|
|
13203
13205
|
compact: !0,
|
|
13204
|
-
showLabel:
|
|
13206
|
+
showLabel: g,
|
|
13205
13207
|
tone: i,
|
|
13206
|
-
suppressPlatter:
|
|
13208
|
+
suppressPlatter: x !== null
|
|
13207
13209
|
}, `${e.href ?? e.label}-${t}`)),
|
|
13208
13210
|
n ? /* @__PURE__ */ B(jf, { item: n }) : null,
|
|
13209
|
-
|
|
13211
|
+
y.map((e, t) => /* @__PURE__ */ B(Af, {
|
|
13210
13212
|
item: e,
|
|
13211
13213
|
compact: !0,
|
|
13212
|
-
showLabel:
|
|
13214
|
+
showLabel: g,
|
|
13213
13215
|
tone: i,
|
|
13214
|
-
suppressPlatter:
|
|
13215
|
-
}, `${e.href ?? e.label}-${t +
|
|
13216
|
+
suppressPlatter: x !== null
|
|
13217
|
+
}, `${e.href ?? e.label}-${t + _}`))
|
|
13216
13218
|
]
|
|
13217
13219
|
})] });
|
|
13218
13220
|
}
|
|
@@ -13282,11 +13284,11 @@ function Mf() {
|
|
|
13282
13284
|
})
|
|
13283
13285
|
});
|
|
13284
13286
|
}
|
|
13285
|
-
function Nf({ tabs: e, activeTab: t, onSelect: n, addAction: r, floatingPosition: i = "center",
|
|
13286
|
-
let
|
|
13287
|
+
function Nf({ tabs: e, activeTab: t, onSelect: n, addAction: r, floatingPosition: i = "center", showOnDesktop: a = !1, className: o }) {
|
|
13288
|
+
let s = u.useCallback((e) => {
|
|
13287
13289
|
let t = e.target;
|
|
13288
13290
|
t instanceof Element && t.closest("button, a")?.blur();
|
|
13289
|
-
}, []),
|
|
13291
|
+
}, []), c = e.map((e) => {
|
|
13290
13292
|
let r = e.key === t, i = e.Icon;
|
|
13291
13293
|
return {
|
|
13292
13294
|
label: e.label,
|
|
@@ -13302,7 +13304,7 @@ function Nf({ tabs: e, activeTab: t, onSelect: n, addAction: r, floatingPosition
|
|
|
13302
13304
|
onClick: () => n(e.key),
|
|
13303
13305
|
tabKey: e.key
|
|
13304
13306
|
};
|
|
13305
|
-
}),
|
|
13307
|
+
}), l = r ? {
|
|
13306
13308
|
label: "",
|
|
13307
13309
|
ariaLabel: r.ariaLabel ?? r.label,
|
|
13308
13310
|
icon: /* @__PURE__ */ B(Mf, {}),
|
|
@@ -13310,15 +13312,16 @@ function Nf({ tabs: e, activeTab: t, onSelect: n, addAction: r, floatingPosition
|
|
|
13310
13312
|
onClick: r.onClick
|
|
13311
13313
|
} : void 0;
|
|
13312
13314
|
return /* @__PURE__ */ B(Df, {
|
|
13313
|
-
className: a ? `lg:hidden ${
|
|
13315
|
+
className: a ? o : o ? `lg:hidden ${o}` : "lg:hidden",
|
|
13314
13316
|
variant: "pill",
|
|
13315
13317
|
pillPosition: "fixed",
|
|
13316
13318
|
floatingPosition: i,
|
|
13317
13319
|
showLabels: !0,
|
|
13318
13320
|
keyboardBehavior: "hide",
|
|
13319
|
-
onPointerUpCapture:
|
|
13320
|
-
items:
|
|
13321
|
-
centerAction:
|
|
13321
|
+
onPointerUpCapture: s,
|
|
13322
|
+
items: c,
|
|
13323
|
+
centerAction: l,
|
|
13324
|
+
showOnDesktop: a
|
|
13322
13325
|
});
|
|
13323
13326
|
}
|
|
13324
13327
|
//#endregion
|
|
@@ -76,6 +76,20 @@ interface BottomTabBarProps extends React.ComponentProps<"nav"> {
|
|
|
76
76
|
scrollEdge?: boolean;
|
|
77
77
|
/** nav 要素の aria-label。@default "メインナビゲーション" */
|
|
78
78
|
navLabel?: string;
|
|
79
|
+
/**
|
|
80
|
+
* デスクトップ幅(`lg` = 1024px 以上)でもナビを表示するか(issue #486)。
|
|
81
|
+
*
|
|
82
|
+
* DS の既定はモバイル専用(`lg:hidden`)。PC ではサイドナビや
|
|
83
|
+
* ヘッダーナビへ切り替えるアプリを想定しているため。
|
|
84
|
+
* **デスクトップ用シェルを持たず、全幅でこのナビを出し続けたいアプリ**
|
|
85
|
+
* (消費側でこれを `className="lg:flex"` で毎回打ち消していた)は
|
|
86
|
+
* `showOnDesktop` を渡す。
|
|
87
|
+
*
|
|
88
|
+
* `variant="pill"` では scroll edge の装飾帯も一緒に追従する。
|
|
89
|
+
*
|
|
90
|
+
* @default false(従来どおり lg 以上で非表示)
|
|
91
|
+
*/
|
|
92
|
+
showOnDesktop?: boolean;
|
|
79
93
|
}
|
|
80
94
|
/**
|
|
81
95
|
* BottomTabBar — モバイルのグローバルナビゲーション。
|
|
@@ -112,6 +126,22 @@ interface BottomTabBarProps extends React.ComponentProps<"nav"> {
|
|
|
112
126
|
* `--Nav-Selected-Surface` / `-Shadow` は**宣言したときだけ** DS 既定
|
|
113
127
|
* (`.glass-accent` / ガラスの選択プラッター)を置き換える。未宣言なら
|
|
114
128
|
* tone / dark の出し分けは従来どおり DS 側が持つ。
|
|
129
|
+
* - `--Nav-Pill-Surface` / `-Backdrop` / `-Border` / `-Shadow` / `-Specular`
|
|
130
|
+
* … pill 本体の面(issue #486)。DS 既定は Liquid Glass(`.glass`、
|
|
131
|
+
* `tone="inverse"` は `.glass-dark`)で、これも**宣言したときだけ**効く。
|
|
132
|
+
* 背後コンテンツの可読性を優先して不透明なナビにしたい場合に使う:
|
|
133
|
+
*
|
|
134
|
+
* ```css
|
|
135
|
+
* :root {
|
|
136
|
+
* --Nav-Pill-Surface: var(--Surface-Primary);
|
|
137
|
+
* --Nav-Pill-Backdrop: none; (ガラスのぼかしを切る)
|
|
138
|
+
* --Nav-Pill-Specular: none; (スペキュラ / 屈折リムも消す)
|
|
139
|
+
* --Nav-Pill-Shadow: 0 4px 16px rgb(0 0 0 / 0.12);
|
|
140
|
+
* }
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* `className` で `.glass` を打ち消すことはできない(Tailwind ユーティリティ
|
|
144
|
+
* ではないため tailwind-merge が落とせない)ので、面の変更は必ずこの変数で行う。
|
|
115
145
|
* - 寸法系が効くのは prominent レイアウト(`showLabels` か `centerAction` が
|
|
116
146
|
* ある pill)。アイコンのみの compact pill は契約外で固定。
|
|
117
147
|
*
|
|
@@ -142,6 +172,6 @@ interface BottomTabBarProps extends React.ComponentProps<"nav"> {
|
|
|
142
172
|
*
|
|
143
173
|
* いずれも呼び出し側の義務にしていない(明示値があればそちらが優先)。
|
|
144
174
|
*/
|
|
145
|
-
declare function BottomTabBar({ className, items, centerAction, showLabels, tone, maxWidth, variant, pillPosition, floatingPosition, keyboardBehavior, scrollEdge, navLabel, ...props }: BottomTabBarProps): React.JSX.Element;
|
|
175
|
+
declare function BottomTabBar({ className, items, centerAction, showLabels, tone, maxWidth, variant, pillPosition, floatingPosition, keyboardBehavior, scrollEdge, navLabel, showOnDesktop, ...props }: BottomTabBarProps): React.JSX.Element;
|
|
146
176
|
export { BottomTabBar };
|
|
147
177
|
export type { BottomTabBarAction, BottomTabBarFloatingPosition, BottomTabBarItem, BottomTabBarKeyboardBehavior, BottomTabBarProps, };
|
|
@@ -22,6 +22,11 @@ interface MobileTabBarProps<T extends string> {
|
|
|
22
22
|
* addAction と併用しない片側フロート + FAB 併置レイアウトで使う。
|
|
23
23
|
*/
|
|
24
24
|
floatingPosition?: BottomTabBarFloatingPosition;
|
|
25
|
+
/**
|
|
26
|
+
* デスクトップ幅(`lg` = 1024px 以上)でもナビを表示するか(issue #486)。
|
|
27
|
+
* BottomTabBar へそのままパススルーする。@default false
|
|
28
|
+
*/
|
|
29
|
+
showOnDesktop?: boolean;
|
|
25
30
|
className?: string;
|
|
26
31
|
}
|
|
27
32
|
/**
|
|
@@ -34,6 +39,6 @@ interface MobileTabBarProps<T extends string> {
|
|
|
34
39
|
* - 内部は BottomTabBar(variant="pill", pillPosition="fixed", showLabels,
|
|
35
40
|
* keyboardBehavior="hide")の薄いラッパー。floatingPosition はパススルー。
|
|
36
41
|
*/
|
|
37
|
-
declare function MobileTabBar<T extends string>({ tabs, activeTab, onSelect, addAction, floatingPosition, className, }: MobileTabBarProps<T>): React.JSX.Element;
|
|
42
|
+
declare function MobileTabBar<T extends string>({ tabs, activeTab, onSelect, addAction, floatingPosition, showOnDesktop, className, }: MobileTabBarProps<T>): React.JSX.Element;
|
|
38
43
|
export { MobileTabBar };
|
|
39
44
|
export type { MobileTabBarAddAction, MobileTabBarProps, MobileTabItem };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ksk-design-system",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "KSK Design System — フリーランス向けマルチテーマ対応デザインシステム",
|
|
6
6
|
"license": "MIT",
|
|
@@ -164,6 +164,7 @@
|
|
|
164
164
|
"lint:prefix-order": "node scripts/check-prefix-order.mjs",
|
|
165
165
|
"lint:screen-contracts": "node scripts/check-screen-contracts.mjs",
|
|
166
166
|
"lint:deprecations": "node scripts/check-deprecations.mjs",
|
|
167
|
+
"audit:issue-links": "node scripts/check-issue-close-links.mjs",
|
|
167
168
|
"lint:migration-doc": "node scripts/generate-migration-doc.mjs --check",
|
|
168
169
|
"generate:migration-doc": "node scripts/generate-migration-doc.mjs",
|
|
169
170
|
"metrics": "node scripts/download-metrics.mjs",
|
|
@@ -178,6 +179,7 @@
|
|
|
178
179
|
"check:native-parity": "node scripts/check-native-parity.mjs",
|
|
179
180
|
"check:native-lookup": "node scripts/generate-native-component-lookup.mjs --check",
|
|
180
181
|
"test": "vitest run",
|
|
182
|
+
"test:legacy-radix": "node scripts/test-legacy-radix.mjs",
|
|
181
183
|
"test:consumer:web": "npm run build:lib && node scripts/test-packed-web-consumer.mjs",
|
|
182
184
|
"test:consumer:native": "npm run build:lib && node scripts/test-packed-native-consumer.mjs",
|
|
183
185
|
"test:consumer:cli": "node scripts/test-packed-cli-consumer.mjs",
|
|
@@ -185,18 +187,18 @@
|
|
|
185
187
|
"test:watch": "vitest",
|
|
186
188
|
"test:interaction": "vitest run --config vitest.storybook.config.ts",
|
|
187
189
|
"test:a11y": "vitest run --config vitest.a11y.config.ts",
|
|
188
|
-
"check": "tsc -p tsconfig.app.json --noEmit && tsc -p tsconfig.type-tests.json --noEmit && bash scripts/lint-scratch.sh && bash scripts/check-deps.sh && node scripts/check-published-deps.mjs && node scripts/check-css-setup.mjs && bash scripts/check-drift.sh && node scripts/check-screen-contracts.mjs && node scripts/check-docs-drift.mjs && node scripts/check-agents-docs-sync.mjs && node scripts/check-contrast.mjs && node scripts/check-design-md.mjs && node scripts/check-tailwind-v4.mjs && node scripts/check-prefix-order.mjs && node scripts/check-flex-shrink.mjs && node scripts/check-deprecations.mjs && node scripts/check-rules-contract.mjs && node scripts/sync-version.mjs --check && node scripts/generate-migration-doc.mjs --check && bash scripts/check-responsive.sh && node scripts/generate-component-lookup.mjs --check && node scripts/generate-platform-tokens.mjs --check && node scripts/generate-token-hex-cache.mjs --check && node scripts/generate-source-safelist.mjs --check && tsc -p tsconfig.native.json --noEmit && node scripts/check-native-parity.mjs && node scripts/generate-native-component-lookup.mjs --check",
|
|
190
|
+
"check": "tsc -p tsconfig.app.json --noEmit && tsc -p tsconfig.type-tests.json --noEmit && bash scripts/lint-scratch.sh && bash scripts/check-deps.sh && node scripts/check-published-deps.mjs && node scripts/check-radix-floor.mjs && node scripts/check-css-setup.mjs && bash scripts/check-drift.sh && node scripts/check-screen-contracts.mjs && node scripts/check-docs-drift.mjs && node scripts/check-agents-docs-sync.mjs && node scripts/check-contrast.mjs && node scripts/check-design-md.mjs && node scripts/check-tailwind-v4.mjs && node scripts/check-prefix-order.mjs && node scripts/check-flex-shrink.mjs && node scripts/check-deprecations.mjs && node scripts/check-rules-contract.mjs && node scripts/sync-version.mjs --check && node scripts/generate-migration-doc.mjs --check && bash scripts/check-responsive.sh && node scripts/generate-component-lookup.mjs --check && node scripts/generate-platform-tokens.mjs --check && node scripts/generate-token-hex-cache.mjs --check && node scripts/generate-source-safelist.mjs --check && tsc -p tsconfig.native.json --noEmit && node scripts/check-native-parity.mjs && node scripts/generate-native-component-lookup.mjs --check",
|
|
189
191
|
"check:agent": "npm run lint && npm run check && npm test && npm run lint:story-reuse",
|
|
190
192
|
"version": "node scripts/sync-version.mjs",
|
|
191
193
|
"mcp:build": "cd mcp-server && npm install && npm run build",
|
|
192
194
|
"mcp:start": "node mcp-server/dist/index.js"
|
|
193
195
|
},
|
|
194
196
|
"dependencies": {
|
|
195
|
-
"@radix-ui/react-slot": "^1.
|
|
197
|
+
"@radix-ui/react-slot": "^1.3.0",
|
|
196
198
|
"class-variance-authority": "^0.7.1",
|
|
197
199
|
"clsx": "^2.1.1",
|
|
198
200
|
"iconsax-reactjs": "^0.0.8",
|
|
199
|
-
"radix-ui": "^1.
|
|
201
|
+
"radix-ui": "^1.6.1",
|
|
200
202
|
"react-day-picker": "^10.0.1",
|
|
201
203
|
"react-hook-form": "^7.75.0",
|
|
202
204
|
"tailwind-merge": "^3.5.0"
|
|
@@ -260,18 +262,19 @@
|
|
|
260
262
|
"iconsax-reactjs": "^0.0.8",
|
|
261
263
|
"jsdom": "^25.0.1",
|
|
262
264
|
"playwright": "^1.62.0",
|
|
263
|
-
"radix-ui": "^1.
|
|
265
|
+
"radix-ui": "^1.6.1",
|
|
264
266
|
"react": "^19.2.0",
|
|
265
267
|
"react-dom": "^19.2.0",
|
|
266
268
|
"react-native": "^0.86.0",
|
|
267
269
|
"react-native-web": "^0.21.2",
|
|
270
|
+
"semver": "^7.8.5",
|
|
268
271
|
"storybook": "^10.4.6",
|
|
269
272
|
"tailwindcss": "^4.2.1",
|
|
270
273
|
"tw-animate-css": "^1.4.0",
|
|
274
|
+
"typescript": "^6.0.3",
|
|
271
275
|
"typescript-eslint": "^8.48.0",
|
|
272
276
|
"vite": "^8.1.3",
|
|
273
277
|
"vitest": "^4.1.7",
|
|
274
|
-
"zod": "^4.4.2"
|
|
275
|
-
"typescript": "^6.0.3"
|
|
278
|
+
"zod": "^4.4.2"
|
|
276
279
|
}
|
|
277
280
|
}
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
|
|
169
169
|
| Component | Import | Variants | Stories |
|
|
170
170
|
|-----------|--------|----------|---------|
|
|
171
|
-
| BottomTabBar | `@/components/patterns/commerce/bottom-tab-bar` | — | Default, Pill — iOS 26 Liquid Glass, Pill — on light background, Liquid Glass — center action, Liquid Glass — labels visible, Liquid Glass — 5 items, Liquid Glass — over dark photo/gradient, Liquid Glass — light fallback, Liquid Glass — sliding selection (interactive), Liquid Glass — scroll edge effect, Floating position — left + FAB, Floating position — right + FAB, Keyboard behavior — hide |
|
|
171
|
+
| BottomTabBar | `@/components/patterns/commerce/bottom-tab-bar` | — | Default, Pill — iOS 26 Liquid Glass, Pill — on light background, Liquid Glass — center action, Liquid Glass — labels visible, Liquid Glass — 5 items, Liquid Glass — over dark photo/gradient, Liquid Glass — light fallback, Liquid Glass — sliding selection (interactive), Liquid Glass — scroll edge effect, Floating position — left + FAB, Floating position — right + FAB, Keyboard behavior — hide, Pill の面を不透明にする(--Nav-Pill-*), デスクトップ幅でも表示する(showOnDesktop) |
|
|
172
172
|
| FilterBar | `@/components/patterns/commerce/filter-bar` | — | Default, Interactive |
|
|
173
173
|
| ImageCarousel | `@/components/patterns/commerce/image-carousel` | — | Banner, Square, Video, AutoPlay |
|
|
174
174
|
| MobileTabBar | `@/components/patterns/commerce/mobile-tab-bar` | — | Default, With addAction (center CTA), floatingPosition=, ProductCustomization |
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
(belle-todo)が壊れ、`!important` の山が残った事故が由来。
|
|
9
9
|
|
|
10
10
|
── 寸法は product-theme.css の --Nav-* が担当(:root に既定値あり)。
|
|
11
|
-
──
|
|
11
|
+
── 面(背景・backdrop・境界・影)はここが担当し、**既定値を :root に置かない**。
|
|
12
12
|
var(--Nav-*, <DS 既定>) の形で書き、消費側が宣言したときだけ上書きされる。
|
|
13
13
|
宣言しなければ tone="inverse" / dark の出し分けは従来どおり DS が持つ。
|
|
14
14
|
|
|
@@ -28,6 +28,50 @@
|
|
|
28
28
|
SSR / 計測前に面を兼ねるタブ本体・アイコン領域)に当たる。
|
|
29
29
|
============================================================= */
|
|
30
30
|
|
|
31
|
+
/* ─── pill 本体の面(issue #486)───
|
|
32
|
+
DS 既定は Liquid Glass(`.glass` / tone="inverse" は `.glass-dark`)。
|
|
33
|
+
背後コンテンツの可読性を優先して**不透明な面**にしたい消費側が、
|
|
34
|
+
内部クラスに触らず面だけ差し替えられるようにする。
|
|
35
|
+
|
|
36
|
+
`.glass` / `.glass-dark` と同じ詳細度(0,1,0)だが、glass.css より後に
|
|
37
|
+
読み込まれるこのファイルが勝つ(中央アクションと同じ手口)。
|
|
38
|
+
フォールバックは `.glass` 自身が使う内部変数そのものなので、
|
|
39
|
+
未宣言時のレンダリングは 1px も変わらない。
|
|
40
|
+
|
|
41
|
+
backdrop-filter は `none` を宣言すればガラスのぼかしを完全に切れる。
|
|
42
|
+
-webkit- を先・標準形を後に書く(消費側 minifier の dedupe 対策)。 */
|
|
43
|
+
[data-slot="bottom-nav-pill"] {
|
|
44
|
+
background: var(--Nav-Pill-Surface, var(--glass-bg));
|
|
45
|
+
-webkit-backdrop-filter: var(--Nav-Pill-Backdrop, var(--glass-blur));
|
|
46
|
+
backdrop-filter: var(--Nav-Pill-Backdrop, var(--glass-blur));
|
|
47
|
+
border: var(--Nav-Pill-Border, 0.5px solid var(--glass-border));
|
|
48
|
+
box-shadow: var(--Nav-Pill-Shadow, var(--glass-highlight), var(--glass-shadow));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
[data-slot="bottom-nav-pill"][data-tone="inverse"] {
|
|
52
|
+
background: var(--Nav-Pill-Surface, var(--glass-bg-dark));
|
|
53
|
+
-webkit-backdrop-filter: var(--Nav-Pill-Backdrop, var(--glass-blur-media-dark));
|
|
54
|
+
backdrop-filter: var(--Nav-Pill-Backdrop, var(--glass-blur-media-dark));
|
|
55
|
+
border: var(--Nav-Pill-Border, 0.5px solid var(--glass-border-dark));
|
|
56
|
+
box-shadow: var(
|
|
57
|
+
--Nav-Pill-Shadow,
|
|
58
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.12),
|
|
59
|
+
0 8px 32px rgba(0, 0, 0, 0.28)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* ─── pill のスペキュラ / 屈折リム(issue #486)───
|
|
64
|
+
`.glass-specular` の ::before(レンズ上面)と ::after(エッジの屈折リム)は
|
|
65
|
+
面を不透明にしても残るため、ガラスを切りたい消費側にはノイズになる。
|
|
66
|
+
|
|
67
|
+
既定は `.glass-specular` 自身と同じ `content: ""` なので**未宣言なら何も変わらない**。
|
|
68
|
+
`--Nav-Pill-Specular: none` を宣言すると擬似要素そのものが生成されなくなり、
|
|
69
|
+
リムとスペキュラが消える。 */
|
|
70
|
+
[data-slot="bottom-nav-pill"]::before,
|
|
71
|
+
[data-slot="bottom-nav-pill"]::after {
|
|
72
|
+
content: var(--Nav-Pill-Specular, "");
|
|
73
|
+
}
|
|
74
|
+
|
|
31
75
|
/* ─── 中央アクションの面 ───
|
|
32
76
|
.glass-accent と同じ詳細度(0,1,0)なので、glass.css より後に読み込まれる
|
|
33
77
|
このファイルが勝つ。フォールバックは .glass-accent 自身が同じ要素に載せる
|