diff --git a/.changeset/press-feedback.md b/.changeset/press-feedback.md
new file mode 100644
index 000000000..aa7ca5ee5
--- /dev/null
+++ b/.changeset/press-feedback.md
@@ -0,0 +1,10 @@
+---
+'8341-ui': patch
+---
+
+タッチでも押したことが伝わるよう、押している間の見た目(`active:`)を付けました。
+
+- Link・Card(`href`)・Accordion・Checkbox / Radio / Switch(ラベルの文字を押しても出る)・入力欄・NotificationBanner の閉じるボタンに、マウスの hover と同じ見た目を `active:` でも付けた
+- Button の hover と押した見た目を `enabled:` から `not-disabled:` に替えた。`buttonVariants` を `` に当てたとき、hover も押した見た目も出なかった
+- テーマで端末のタップの塗り(`-webkit-tap-highlight-color`)を消した
+- iOS Safari で `:active` を効かせるには、アプリで `document` に `touchstart` の受け手を置く(README)
diff --git a/DESIGN.md b/DESIGN.md
index 9eaa508a5..c74d54d42 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -185,7 +185,7 @@ DTCG では `{"colorSpace": "oklch", "components": [L, C, H], "hex": "#..."}`
- import パスは shadcn 方式: `@/components/ui/{Name}/index`(ディレクトリ名は PascalCase)、`@/lib/{name}`
- 独自のスタイルは `tv()` を `@/lib/tv` から import して書く。`tailwind-variants` の `tv` を直接使わない(独自のテーマ名を登録した `tv` でないと `text-fg text-body-md` の文字色が消える)
- **フォーカスは `focus-ring` クラス**。見た目が 44px 未満の操作対象には `tap-target`
-- コンポーネント自体を作る・直すときの規約(data 属性、`enabled:hover:`、`forced-colors:`、`'use client'` など)は [docs/rulebook/04-components.md](./docs/rulebook/04-components.md)
+- コンポーネント自体を作る・直すときの規約(data 属性、`not-disabled:hover:`、`forced-colors:`、`'use client'` など)は [docs/rulebook/04-components.md](./docs/rulebook/04-components.md)
### Button
diff --git a/README.md b/README.md
index 11b519d63..0592e6490 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,16 @@ npx shadcn@latest add @8341/8341-base @8341/button @8341/form-field @8341/text-f
あとは使うだけです。テーマは `` か `` でダークに切り替わり、どちらも無ければ OS の設定に従います。
テーマ(`styles/8341-ui.css`)はトークンを同梱しています。トークンが更新されたら `npx shadcn@latest add @8341/theme --overwrite` で取り込み直します。
+部品は押している間の見た目(`:active`)でタッチでも押したことを伝えます。iOS Safari は `touchstart` の受け手が無いと `:active` を当てないので、アプリの全画面に共通する枠(レイアウトなど)で一度だけ受け手を置きます。インラインの `ontouchstart` 属性は CSP で止まることがあるので、スクリプトで付けます。
+
+```tsx
+useEffect(() => {
+ const enableActive = () => undefined;
+ document.addEventListener('touchstart', enableActive, { passive: true });
+ return () => document.removeEventListener('touchstart', enableActive);
+}, []);
+```
+
```tsx
import { Button } from '@/components/ui/Button/index';
import { FormField } from '@/components/ui/FormField/index';
diff --git a/docs/improvement/log.md b/docs/improvement/log.md
index 4e8c9fd6a..a71d1c3a1 100644
--- a/docs/improvement/log.md
+++ b/docs/improvement/log.md
@@ -4,6 +4,7 @@
| 日付 | 種別 | 内容 | 再発防止 |
| ---------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
+| 2026-11-07 | 部品 | タッチで押したことが伝わるよう、hover だけだった部品(Link・Card・Accordion・Checkbox / Radio / Switch(ラベルを押しても出る)・入力欄・NotificationBanner の閉じる)に、hover と同じ見た目の `active:` を足した。ボタンの見た目(`buttonVariants`)をリンクに当てると `enabled:` が `` に当たらず hover も押した見た目も出なかったので、Button を `not-disabled:` に替えた。端末のタップの塗りは消した。bouzu(#84・#89)での知見 | クラス監査に `enabled-variant`(enabled: を禁止)と `hover-without-active`(hover: だけで active: が無い部品)を追加。Button・Link のテスト。iOS Safari の touchstart の受け手を README に記載 |
| 2026-11-02 | 保守 | Node.js を 26.13.0(LTS Lithium)に更新。`devEngines` を `>=26.13.0`、`@types/node` を 26 系(`^26.6.6`)に合わせた。他の依存の版は変えていない | ADR-0020。CI は `.tool-versions` の版を使う |
| 2026-10-23 | 保守 | 全体のリファクタリング。古い参照(存在しない make ターゲット・パス・README の節名)を直し、トークンを変えた後の手順を `make generate` に統一。Makefile と重複していた pnpm スクリプト、design-review に混ざっていたコードレビュー・Next.js の項目、使われていない関数と export を削除。DESIGN.md・ルールブック 04・06・CONTRIBUTING・factory.md の重複を正本へのリンクにし、トークンの CSS 化の規則を `packages/tokens/scripts/lib/css.ts` に集めて build.ts とスライドで共有 | 規則を 1 か所にしたので、tokens.css とスライドの値の書き方がずれない。重複していた手順は正本(Makefile・COMPONENT_STRUCTURE.md・06 章・ds-factory)だけに置いた |
| 2026-10-23 | 機能 | 8341-ui を使うプロダクトに、DESIGN.md と design-principles を配るレジストリ item `@8341/design-md` を追加。DESIGN.md はコードから読み取れない考え方(プロダクトの前提・画面領域ごとの方向性・大事にすること・外した必須)と原則の必須の要約だけにし、トークンや部品の一覧は載せない | ADR-0019。原則の要約は `scripts/sync-product-design.ts` が docs/design-principles から生成し、`make check` で鮮度を検査。配布する原則のファイル一覧も registry.json の --check で追従 |
diff --git a/docs/rulebook/02-accessibility.md b/docs/rulebook/02-accessibility.md
index eb0876e7e..e29cf9ed1 100644
--- a/docs/rulebook/02-accessibility.md
+++ b/docs/rulebook/02-accessibility.md
@@ -21,7 +21,7 @@
| A11 | 動的に出す通知だけ `role="status"` / `role="alert"` を付ける | 4.1.3 | NotificationBanner の `live` |
| A12 | `prefers-reduced-motion` で動きを止める | 2.3.3 | theme.css、`motion-reduce:` |
| A13 | 強制カラーモード(Windows ハイコントラスト)で境界とフォーカスが消えない | 1.4.11 | 各コンポーネントの `forced-colors:`、e2e の forced-colors プロジェクト |
-| A14 | hover で文字の太さ・大きさを変えない。無効状態に hover を効かせない(`enabled:hover:`) | — | レビュー(Tailwind v4 の `hover:` は自動で `@media (hover: hover)` に入る) |
+| A14 | hover で文字の太さ・大きさを変えない。無効状態に hover を効かせない(`not-disabled:hover:`)。hover の見た目は `active:` にも付け、タッチでも押したことを伝える | — | クラス監査の `enabled-variant`・`hover-without-active`(Tailwind v4 の `hover:` は自動で `@media (hover: hover)` に入る) |
| A15 | ストーリーはすべて axe の WCAG 2.2 AA ルールで違反ゼロ | — | Storybook addon-a11y(`test: 'error'`)+ addon-vitest |
| A16 | 幅 320px で横スクロールが出ない。文字サイズ 200% で内容が切れない | 1.4.10, 1.4.4 | Playwright の e2e(手動・都度実行) |
diff --git a/docs/rulebook/04-components.md b/docs/rulebook/04-components.md
index f3d5d4279..bc5394d2d 100644
--- a/docs/rulebook/04-components.md
+++ b/docs/rulebook/04-components.md
@@ -37,7 +37,9 @@
- 状態は Base UI の data 属性で装飾する(`data-[checked]:`、`data-[invalid]:`、`data-[disabled]:`、`data-[highlighted]:`、`data-[panel-open]:`、`data-[starting-style]:`)
- **フォーカスは `focus-ring`**(`@/lib/focus` の `focusRing`)。Base UI は `data-focus-visible` を付けないため `:focus-visible` で描く
- 見た目が 44px 未満の操作対象には `tap-target`
-- 無効状態に hover を効かせないよう `enabled:hover:` を使う(Tailwind v4 の `hover:` は自動で `@media (hover: hover)` に入る)
+- 無効状態に hover と押した見た目を効かせないよう `not-disabled:hover:`・`not-disabled:active:` を使う。`enabled:` は `` に当たらず、ボタンの見た目(`buttonVariants`)をリンクに当てたときに何も出なくなる(クラス監査の `enabled-variant`)
+- `hover:` を付けたら、同じ見た目かそれより濃い見た目を `active:` にも付ける。Tailwind v4 の `hover:` は自動で `@media (hover: hover)` に入り、タッチでは出ないので、押したことは `active:` だけが伝える(クラス監査の `hover-without-active`)
+- ラベルの文字を押して操作する部品(Checkbox・Radio・Switch)は、ラベルに `group/*` を付け、`group-active/*:` で四角・丸・トラックにも押した見た目を出す
- 強制カラーモードは `forced-colors:` で補う
- 論理プロパティのクラスを使う(`ps-*`、`ms-*`、`border-s-*`)
- クラス名を動的に組み立てない(`` `text-${size}` `` は Tailwind が検出できない)。variants に列挙する
diff --git a/packages/ui/scripts/audit-classes.ts b/packages/ui/scripts/audit-classes.ts
index ac2b72f58..1b882d507 100644
--- a/packages/ui/scripts/audit-classes.ts
+++ b/packages/ui/scripts/audit-classes.ts
@@ -14,6 +14,8 @@
* bare-read-only … read-only: は button や無効の input にも当たる。[&:read-only:not(:disabled,button)]: を使う
* theme-var-ref … 任意値・手書き CSS からの Tailwind テーマ変数(--color-* / --spacing-* / --text-* など)の参照。
* @theme inline は使われた変数しか出力しないため未定義になりうる。常に存在する --8341-* を参照する
+ * enabled-variant … enabled: は に当たらない。ボタンの見た目をリンクに当てると hover も押した見た目も出ない。not-disabled: を使う
+ * hover-without-active … hover: を書いた部品に active: が無い。タッチでは hover が出ないので、押した見た目は active: で出す
* warning
* numeric-spacing … p-4 / gap-6 など数値の余白。semantic な余白(p-inset-md、gap-stack-md)を検討する
*/
@@ -57,6 +59,17 @@ export function auditClasses(): Finding[] {
message: "フックを使っているのに 'use client' がありません",
});
}
+ const classText = text.replace(/\/\/.*$/gm, '');
+ if (/(? {
const add = (rule: string, severity: Finding['severity'], message: string) =>
findings.push({ file: rel, line: i + 1, rule, severity, message });
@@ -77,6 +90,8 @@ export function auditClasses(): Finding[] {
'error',
'read-only: は button や無効の input にも当たります。[&:read-only:not(:disabled,button)]: を使ってください',
);
+ if (/(? に当たりません。not-disabled: を使ってください');
const palette = line.match(PALETTE);
if (palette)
add('tailwind-palette', 'error', `Tailwind 既定のパレットは使えません: ${palette[0]}(semantic の色を使う)`);
diff --git a/packages/ui/src/components/ui/Accordion/index.tsx b/packages/ui/src/components/ui/Accordion/index.tsx
index 693c65bf4..6fae1f805 100644
--- a/packages/ui/src/components/ui/Accordion/index.tsx
+++ b/packages/ui/src/components/ui/Accordion/index.tsx
@@ -10,7 +10,7 @@ export const accordionVariants = tv({
item: 'border-b border-border',
header: 'm-0 text-body-md font-bold',
trigger: [
- 'group/trigger flex min-h-target-min w-full cursor-pointer items-center rounded-xs border-0 bg-transparent px-inset-sm py-inset-md text-start font-bold text-fg hover:bg-muted',
+ 'group/trigger flex min-h-target-min w-full cursor-pointer items-center rounded-xs border-0 bg-transparent px-inset-sm py-inset-md text-start font-bold text-fg hover:bg-muted active:bg-muted',
focusRing,
],
icon: 'ms-gap-md shrink-0 text-icon-key transition-transform group-data-[panel-open]/trigger:rotate-180',
diff --git a/packages/ui/src/components/ui/Button/index.test.tsx b/packages/ui/src/components/ui/Button/index.test.tsx
index 7b5e82eee..de00a854b 100644
--- a/packages/ui/src/components/ui/Button/index.test.tsx
+++ b/packages/ui/src/components/ui/Button/index.test.tsx
@@ -1,9 +1,20 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, expect, it, vi } from 'vite-plus/test';
-import { Button } from './index';
+import { Button, buttonVariants } from './index';
describe('Button', () => {
+ it('ボタンの見た目をリンクに当てても、押した見た目が出る(:enabled は a に当たらない)', () => {
+ render(
+
+ 申請を始める
+ ,
+ );
+ const link = screen.getByRole('link', { name: '申請を始める' });
+ expect(link).toHaveClass('not-disabled:active:bg-key-active');
+ expect(link.className).not.toMatch(/(? {
render();
expect(screen.getByRole('button')).toHaveAttribute('type', 'button');
diff --git a/packages/ui/src/components/ui/Button/index.tsx b/packages/ui/src/components/ui/Button/index.tsx
index a4560afb2..5facd1b5d 100644
--- a/packages/ui/src/components/ui/Button/index.tsx
+++ b/packages/ui/src/components/ui/Button/index.tsx
@@ -28,16 +28,16 @@ export const buttonVariants = tv({
*/
variant: {
primary: {
- root: 'border-key bg-key text-fg-on-key enabled:hover:border-key-hover enabled:hover:bg-key-hover enabled:active:border-key-active enabled:active:bg-key-active',
+ root: 'border-key bg-key text-fg-on-key not-disabled:hover:border-key-hover not-disabled:hover:bg-key-hover not-disabled:active:border-key-active not-disabled:active:bg-key-active',
},
secondary: {
- root: 'border-border-key bg-surface text-fg-key enabled:hover:bg-key-subtle enabled:active:bg-key-subtle-hover',
+ root: 'border-border-key bg-surface text-fg-key not-disabled:hover:bg-key-subtle not-disabled:active:bg-key-subtle-hover',
},
tertiary: {
- root: 'border-transparent bg-transparent text-fg-key underline underline-offset-[0.2em] enabled:hover:bg-key-subtle enabled:active:bg-key-subtle-hover disabled:border-transparent disabled:bg-transparent',
+ root: 'border-transparent bg-transparent text-fg-key underline underline-offset-[0.2em] not-disabled:hover:bg-key-subtle not-disabled:active:bg-key-subtle-hover disabled:border-transparent disabled:bg-transparent',
},
danger: {
- root: 'border-danger bg-danger text-fg-on-key enabled:hover:border-danger-hover enabled:hover:bg-danger-hover enabled:active:border-danger-active enabled:active:bg-danger-active',
+ root: 'border-danger bg-danger text-fg-on-key not-disabled:hover:border-danger-hover not-disabled:hover:bg-danger-hover not-disabled:active:border-danger-active not-disabled:active:bg-danger-active',
},
},
/** sm は見た目 36px だが、タップ領域は 44px を確保する */
diff --git a/packages/ui/src/components/ui/Card/index.tsx b/packages/ui/src/components/ui/Card/index.tsx
index a1e600bfe..30c4635f7 100644
--- a/packages/ui/src/components/ui/Card/index.tsx
+++ b/packages/ui/src/components/ui/Card/index.tsx
@@ -11,10 +11,11 @@ export const cardVariants = tv({
body: 'flex flex-1 flex-col gap-stack-sm p-inset-xl',
eyebrow: 'm-0 text-body-sm text-fg-subtle',
title: 'm-0 text-heading-xs',
- link: 'text-fg-link underline decoration-1 underline-offset-[0.2em] outline-none after:absolute after:inset-0 after:content-[""] group-hover/card:decoration-(length:--8341-border-width-underline-hover)', // allow-outline-none: フォーカスはカード全体に focus-ring-within で描く
+ link: 'text-fg-link underline decoration-1 underline-offset-[0.2em] outline-none after:absolute after:inset-0 after:content-[""] group-hover/card:decoration-(length:--8341-border-width-underline-hover) group-active/card:decoration-(length:--8341-border-width-underline-hover)', // allow-outline-none: フォーカスはカード全体に focus-ring-within で描く
content: '[&>p]:m-0',
footer: 'flex items-center justify-between gap-gap-sm px-inset-xl pb-inset-xl text-fg-subtle',
- arrow: 'ms-auto text-icon-key transition-transform group-hover/card:translate-x-gap-xs',
+ arrow:
+ 'ms-auto text-icon-key transition-transform group-hover/card:translate-x-gap-xs group-active/card:translate-x-gap-xs',
},
variants: {
variant: {
@@ -22,7 +23,12 @@ export const cardVariants = tv({
filled: { root: 'border-transparent bg-subtle' },
},
interactive: {
- true: { root: [focusRingWithin, 'hover:border-border-key hover:shadow-1'] },
+ true: {
+ root: [
+ focusRingWithin,
+ 'hover:border-border-key hover:shadow-1 active:border-border-key active:bg-subtle active:shadow-1',
+ ],
+ },
},
},
defaultVariants: { variant: 'outlined' },
diff --git a/packages/ui/src/components/ui/Checkbox/index.tsx b/packages/ui/src/components/ui/Checkbox/index.tsx
index 4bbc8c4b1..ce0ce36cd 100644
--- a/packages/ui/src/components/ui/Checkbox/index.tsx
+++ b/packages/ui/src/components/ui/Checkbox/index.tsx
@@ -8,7 +8,7 @@ import { type VariantProps, tv } from '@/lib/tv';
export const choiceVariants = tv({
slots: {
label: [
- 'flex w-fit cursor-pointer items-start gap-gap-sm text-body-md text-fg',
+ 'group/choice flex w-fit cursor-pointer items-start gap-gap-sm text-body-md text-fg',
// 1 行の高さ(16px × 1.7)に上下の余白を足して 44px のタップ領域にする
'min-h-target-min py-[calc((var(--8341-size-target-min)-var(--8341-text-body-md-font-size)*var(--8341-text-body-md-line-height))/2)]',
'has-[[data-disabled]]:cursor-not-allowed has-[[data-disabled]]:text-fg-disabled',
@@ -16,6 +16,8 @@ export const choiceVariants = tv({
control: [
'group/control mt-[calc((var(--8341-text-body-md-font-size)*var(--8341-text-body-md-line-height)-var(--choice-box))/2)] inline-grid size-(--choice-box) shrink-0 place-items-center',
'border-2 border-border-input bg-surface hover:border-border-strong hover:bg-muted',
+ // ラベルの文字を押しても、四角や丸に押した見た目を出す
+ 'group-active/choice:not-data-[disabled]:border-border-strong group-active/choice:not-data-[disabled]:bg-muted',
'data-[invalid]:border-border-danger',
'data-[disabled]:border-border-disabled data-[disabled]:bg-disabled',
focusRing,
diff --git a/packages/ui/src/components/ui/FormField/index.tsx b/packages/ui/src/components/ui/FormField/index.tsx
index f9eaf998d..8551dae30 100644
--- a/packages/ui/src/components/ui/FormField/index.tsx
+++ b/packages/ui/src/components/ui/FormField/index.tsx
@@ -14,7 +14,7 @@ export const controlVariants = tv({
'block w-full rounded-md border border-border-input bg-surface px-inset-md py-inset-sm',
// 16px 未満だと iOS Safari がフォーカス時に拡大するため、文字サイズは固定
'text-body-md leading-(--8341-text-dense-md-line-height) text-fg placeholder:text-fg-subtle',
- 'transition-colors hover:border-border-strong focus-visible:border-border-strong',
+ 'transition-colors hover:border-border-strong active:border-border-strong focus-visible:border-border-strong',
focusRing,
// エラーは色に加えて線を太くし、形でも示す
'data-[invalid]:border-border-danger data-[invalid]:shadow-[inset_0_0_0_1px_var(--8341-color-border-danger)] aria-invalid:border-border-danger aria-invalid:shadow-[inset_0_0_0_1px_var(--8341-color-border-danger)]',
diff --git a/packages/ui/src/components/ui/Link/index.test.tsx b/packages/ui/src/components/ui/Link/index.test.tsx
index 27665831a..eb09073dc 100644
--- a/packages/ui/src/components/ui/Link/index.test.tsx
+++ b/packages/ui/src/components/ui/Link/index.test.tsx
@@ -12,4 +12,13 @@ describe('Link', () => {
const link = screen.getByRole('link', { name: /外部サイト\s?(新しいタブで開きます)/ });
expect(link).toHaveAttribute('rel', expect.stringContaining('noopener'));
});
+
+ it('押している間は、タッチでも見える色と下線の太さに変わる', () => {
+ render(単語帳);
+ const link = screen.getByRole('link', { name: '単語帳' });
+ expect(link).toHaveClass(
+ 'active:text-fg-link-active',
+ 'active:decoration-(length:--8341-border-width-underline-hover)',
+ );
+ });
});
diff --git a/packages/ui/src/components/ui/Link/index.tsx b/packages/ui/src/components/ui/Link/index.tsx
index b53ff6f50..8b07f405f 100644
--- a/packages/ui/src/components/ui/Link/index.tsx
+++ b/packages/ui/src/components/ui/Link/index.tsx
@@ -6,12 +6,13 @@ import { tv } from '@/lib/tv';
* リンクの 5 状態: default / visited / hover / active / focus
* - 下線は常に表示する(色だけで判別させない)
* - hover では下線を太くするだけで、文字の太さ・大きさは変えない(レイアウトがずれないように)
+ * - active(押している間)は橙にし、下線も hover と同じ太さにする。タッチでは hover が出ないので、押したことはこれで伝える
* - focus では背景も黄色にして、文中のリンクでも見失わないようにする
*/
export const linkVariants = tv({
base: [
'rounded-xs text-fg-link underline decoration-1 underline-offset-[0.2em]',
- 'visited:text-fg-link-visited hover:text-fg-link-hover hover:decoration-(length:--8341-border-width-underline-hover) active:text-fg-link-active',
+ 'visited:text-fg-link-visited hover:text-fg-link-hover hover:decoration-(length:--8341-border-width-underline-hover) active:text-fg-link-active active:decoration-(length:--8341-border-width-underline-hover)',
// Tailwind v4 の outline-none は線種を none にするため使わず、:focus-visible で線種から指定する
'focus-visible:bg-focus-ring focus-visible:text-focus-text focus-visible:decoration-1 focus-visible:outline-solid',
'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-outline',
diff --git a/packages/ui/src/components/ui/NotificationBanner/index.tsx b/packages/ui/src/components/ui/NotificationBanner/index.tsx
index e01f37765..dabbc1d76 100644
--- a/packages/ui/src/components/ui/NotificationBanner/index.tsx
+++ b/packages/ui/src/components/ui/NotificationBanner/index.tsx
@@ -18,7 +18,7 @@ export const notificationBannerVariants = tv({
content: '[&>p]:m-0',
actions: 'flex flex-wrap gap-gap-sm',
close: [
- 'tap-target -m-inset-md inline-grid size-target-min shrink-0 cursor-pointer place-items-center rounded-md border-0 bg-transparent p-0 text-icon hover:bg-muted',
+ 'tap-target -m-inset-md inline-grid size-target-min shrink-0 cursor-pointer place-items-center rounded-md border-0 bg-transparent p-0 text-icon hover:bg-muted active:bg-muted',
focusRing,
],
},
diff --git a/packages/ui/src/components/ui/Switch/index.tsx b/packages/ui/src/components/ui/Switch/index.tsx
index 17a464c6c..d8d6eb353 100644
--- a/packages/ui/src/components/ui/Switch/index.tsx
+++ b/packages/ui/src/components/ui/Switch/index.tsx
@@ -11,7 +11,7 @@ import { type VariantProps, tv } from '@/lib/tv';
export const switchVariants = tv({
slots: {
label: [
- 'grid w-fit cursor-pointer grid-cols-[auto_minmax(0,1fr)] items-center gap-x-gap-sm text-fg',
+ 'group/switch-label grid w-fit cursor-pointer grid-cols-[auto_minmax(0,1fr)] items-center gap-x-gap-sm text-fg',
// ラベル全体がタップ領域になる。トラックの見た目は 44px 未満でも行の高さで 44px を確保する
'min-h-target-min',
'has-[[data-disabled]]:cursor-not-allowed has-[[data-disabled]]:text-fg-disabled',
@@ -23,6 +23,9 @@ export const switchVariants = tv({
'hover:not-data-[disabled]:border-border-strong hover:not-data-[disabled]:bg-muted',
'data-[checked]:border-key data-[checked]:bg-key',
'data-[checked]:hover:not-data-[disabled]:border-key-hover data-[checked]:hover:not-data-[disabled]:bg-key-hover',
+ // ラベルの文字を押しても、トラックに押した見た目を出す。色は hover と同じ
+ 'group-active/switch-label:not-data-[disabled]:border-border-strong group-active/switch-label:not-data-[disabled]:bg-muted',
+ 'data-[checked]:group-active/switch-label:not-data-[disabled]:border-key-hover data-[checked]:group-active/switch-label:not-data-[disabled]:bg-key-hover',
'data-[invalid]:border-border-danger',
'data-[disabled]:border-border-disabled data-[disabled]:bg-disabled',
'data-[disabled]:data-[checked]:border-border-disabled data-[disabled]:data-[checked]:bg-disabled',
@@ -31,10 +34,10 @@ export const switchVariants = tv({
],
thumb: [
'grid size-(--switch-thumb) place-items-center rounded-full transition-[translate,background-color]',
- 'bg-(--8341-color-border-input) group-hover/switch:not-data-[disabled]:bg-(--8341-color-border-strong)',
+ 'bg-(--8341-color-border-input) group-hover/switch:not-data-[disabled]:bg-(--8341-color-border-strong) group-active/switch-label:not-data-[disabled]:bg-(--8341-color-border-strong)',
// オンでは白抜きのつまみにチェックを出す(色だけで状態を伝えない)
'data-[checked]:translate-x-(--switch-thumb) rtl:data-[checked]:-translate-x-(--switch-thumb)',
- 'data-[checked]:bg-surface group-hover/switch:data-[checked]:not-data-[disabled]:bg-surface',
+ 'data-[checked]:bg-surface group-hover/switch:data-[checked]:not-data-[disabled]:bg-surface group-active/switch-label:data-[checked]:not-data-[disabled]:bg-surface',
'data-[disabled]:bg-(--8341-color-text-disabled) data-[disabled]:data-[checked]:bg-(--8341-color-text-disabled)',
'forced-colors:bg-[ButtonText] forced-colors:data-[checked]:bg-[Highlight] forced-colors:data-[disabled]:bg-[GrayText]',
],
diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css
index 502a8d827..c864f1a0b 100644
--- a/packages/ui/src/styles/theme.css
+++ b/packages/ui/src/styles/theme.css
@@ -62,6 +62,8 @@
line-height: var(--8341-text-body-md-line-height);
letter-spacing: var(--8341-text-body-md-letter-spacing);
font-feature-settings: normal;
+ /* 押した見た目は各部品の active: で出す。端末の灰色や青のタップの塗りと重ねない */
+ -webkit-tap-highlight-color: transparent;
/* 和文の禁則を厳格に、単語途中の改行を避ける */
line-break: strict;
overflow-wrap: anywhere;