@ubie/vitals-ui-business 0.5.0 → 0.6.1

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/DESIGN.md +39 -35
  3. package/dist/index.cjs +198 -9
  4. package/dist/index.d.cts +19 -2
  5. package/dist/index.d.cts.map +1 -1
  6. package/dist/index.d.mts +20 -3
  7. package/dist/index.d.mts.map +1 -1
  8. package/dist/index.mjs +175 -10
  9. package/dist/index.mjs.map +1 -1
  10. package/docs/components/chat.md +2 -2
  11. package/docs/components/drawer.md +5 -4
  12. package/docs/components/icon.md +2 -2
  13. package/docs/components/layout.md +3 -1
  14. package/docs/components/modal.md +1 -1
  15. package/docs/components/statistic.md +4 -4
  16. package/docs/components/table.md +41 -17
  17. package/docs/patterns/chart.md +4 -4
  18. package/docs/patterns/disclosure.md +6 -3
  19. package/docs/patterns/empty-state.md +3 -3
  20. package/docs/patterns/link.md +53 -0
  21. package/docs/patterns/list-detail.md +12 -11
  22. package/docs/patterns/print.md +6 -6
  23. package/docs/patterns/region-state.md +6 -5
  24. package/docs/patterns/skeleton.md +6 -6
  25. package/docs/principles/README.md +45 -10
  26. package/docs/principles/information-design.md +7 -7
  27. package/docs/principles/runtime-environment.md +53 -0
  28. package/docs/principles/ux-checklist-items.md +199 -0
  29. package/docs/principles/ux-checklist.md +94 -0
  30. package/docs/principles/ux-principles.md +152 -43
  31. package/package.json +15 -5
  32. package/src/UbieConfigProvider.tsx +97 -3
  33. package/src/components/Table/index.tsx +65 -14
  34. package/src/index.ts +10 -0
  35. package/src/ownedStyle.ts +20 -0
  36. package/src/reference/hardcodedStyle.ts +117 -0
  37. package/src/reference/hardcodedStyleKnown.ts +41 -0
  38. package/src/stories/business/Table.stories.tsx +110 -0
  39. package/src/stories/patterns/Link.stories.tsx +91 -0
  40. package/src/theme/businessLinkInteraction.ts +28 -0
  41. package/src/theme/businessTheme.ts +12 -0
  42. package/docs/principles/scorecard.md +0 -56
package/CHANGELOG.md CHANGED
@@ -1,5 +1,178 @@
1
1
  # @ubie/vitals-ui-business
2
2
 
3
+ ## 0.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 2a0f701: test(ui-business): トークンを通さない色・角丸・文字サイズの直書きを数える検査を足す
8
+
9
+ 利用側の API と見た目は変えていない。`src/` の直書き(hex・`rgb()`・角丸と文字サイズの数値)を数え、今ある分(すべて story)を固定した。増えたら CI が落ちる。
10
+
11
+ - 53848d2: fix: 見た目の回帰検査の基準画像を配布物から外し、8 原則の旧番号から 11 原則への対応表を足す
12
+
13
+ - `package.json` の `files` に `!src/**/__screenshots__` を足した。直前の版では、Storybook の見た目の回帰検査に使う基準画像 322 枚(約 3 MB)が配布物に入るところだった。利用側はこの画像を使わない
14
+ - `docs/principles/README.md` に「0.6.0 までの番号(8 原則)」を足した。0.6.0 まで原則は P1〜P8 の 8 個で、11 原則とは同じ番号が別の原則を指す。0.6.0 までの番号で書かれた参照は、次の表で読み替える
15
+
16
+ | 0.6.0 までの ID | 11 原則での行き先 |
17
+ | --------------------------------------------------------------------- | ---------------------------- |
18
+ | P1 間違いを防ぐことを最優先する | `P5`・`P6`・`P7`・`P8`・`P9` |
19
+ | P2 業務の性質で機能の形を決める | `P1` |
20
+ | P3 文脈を引き継ぎ、同じことを二度言わせない | `P11`・`P6`・`P10` |
21
+ | P4 結果は終点ではなく、次の行動の起点として出す | `P10`・`P5` |
22
+ | P5 システムが代わりに動くときは、先に見せ、途中で止められ、後で戻せる | `P6` |
23
+ | P6 今の判断に要る情報だけを、段階的に開示する | `P4`・`P3`・`P2` |
24
+ | P7 システムが何をどこまで確かに知っているかを正直に示す | `P5`・`P2` |
25
+ | P8 繰り返しと修正を無駄にしない | `P11` |
26
+
27
+ - e773a29: docs(principles): PR に貼る `## UX レビュー` の確認項目を「ID +元の原則の名前」に(UX チェックリスト v1.4.1)
28
+
29
+ - `ux-checklist.md` §6: 確認項目の欄は `C8 誰の・誰が(患者の切り替え)` のように、ID のあとに元の原則の名前を書く。C1〜C11 の名前を一覧にした
30
+ - 集計は先頭の ID だけを読む。名前の無い `C3`(v1.4.0)や数字だけの `3`(v1.3.2 まで)も `C3` として数える
31
+ - 版を v1.4.1 に上げた(`ux-checklist.md` の見出しと §6 の例、`ux-checklist-items.md` の参照)。確認項目の追加・削除・リネームはない
32
+
33
+ - 46984b2: docs(principles): UX チェックリストに「見る範囲」を足し、並びと流れで起きる見落としを拾う(UX チェックリスト v1.5.0)
34
+
35
+ - `ux-checklist.md` §2 に「見る範囲」を足した。変えた部分 → 同じ画面に並ぶ既存の操作 → 流れ(④ を選んだとき・画面の行き来が変わるとき)の順に広げて当てる。流れは、作業を始める画面から目的を果たして戻るまでをたどる
36
+ - C1 に「違う操作は見分けがつく」を足した(同じ行に同じアイコンだけの別の操作を並べない。似た操作は「〇〇をコピー」のように対象を書く)。確かめ方を「差分+画面」にした
37
+ - §3: 画面写真は切り抜きでなく画面全体。流れを見るときは、録画から通る画面ごとに切り出した「流れの静止画」も貼る(評価役の AI は動画を読めない)。どちらも証拠の種類は「画面写真」
38
+ - 流れを見るときは、選んだ行に無くても C1〜C4 を答える。流れの 4 つの問いは、書き先の確認項目を 1 対 1 で決めた(次に何をすれば → C4 / 目に入る → C2 / 目的に近づく → C1 / 進んだと分かる → C3)。§4 の C1〜C4 の本文にも、流れを見るときの問いを 1 文ずつ足した(本文だけ読んでも同じ答えになるように)
39
+ - ボタンなどの操作する部品を足す、またはその見た目や言葉を変えるときは、選んだ行に無くても C1 を足す(並ぶ操作との見分けを見るため。⑤・⑦ だけを選ぶ変更でも当たる)
40
+ - 見る範囲の 2・3 で見つかった問題も、この変更で起きたなら「いいえ(この変更で入った)」
41
+ - 冒頭の「目安は 5 分」に、流れを見るときは長くなる、と添えた
42
+ - `ux-checklist-items.md` に P3.16(並ぶ違う操作は見分けがつく)を足し、C1 に対応させた。`ux-principles.md` の P3 の Don't に例を足した
43
+ - §5: 「画面で未確認」は、貼られた画面写真・流れの静止画では確かめられないとき(動きを録画で見ていないとき)にも使える
44
+ - 節の番号(§1〜§7)と確認項目の ID・数は変えていない
45
+
46
+ - 4a8df1f: docs(principles): 体験設計原則を 11 原則にし、UX チェックリストを追加する
47
+
48
+ - `docs/principles/ux-principles.md`: 8 原則(P1〜P8)を 11 原則(共通 8・医療の拡張 3)に置き換え
49
+ - `docs/principles/ux-checklist.md`(追加): 画面に出る変更の PR を確かめる確認項目 11 と、PR に貼る `## UX レビュー` の固定書式
50
+ - `docs/principles/ux-checklist-items.md`(追加): 原則ごとの詳しい確認項目 80
51
+ - `docs/principles/scorecard.md`(削除): レビューは `ux-checklist.md` を使う
52
+ - `docs/patterns/`・`docs/components/` の原則の参照を、旧番号(P1〜P8)から 11 原則の番号に付け替え
53
+
54
+ - 5713aea: docs(principles): 原則と確認項目に消えない ID を振る(UX チェックリスト v1.4.0)
55
+
56
+ - 原則は `P1`〜`P11`、チェックリストの確認項目は `C1`〜`C11`、詳しい確認項目は `P3.9` の形にした。消しても番号を詰めない決まりを `docs/principles/README.md` に書いた
57
+ - `ux-checklist.md`: 版を v1.4.0 に上げた。PR に貼る `## UX レビュー` の表は、確認項目の欄に `C3` のように ID を書く(v1.3.2 までの数字だけの `3` は `C3` と同じもの)
58
+ - `ux-checklist.md`: 「1 本あたり確認項目は 10 以下」を、「確認項目は 11 個。1 本の PR で見るのは選んだ行の分だけ」に直した
59
+ - `ux-principles.md`: P3 の詳しい確認項目の範囲を `P3.1〜P3.15` に直した(`3.13` までと書いていた)
60
+ - `docs/components/*.md`・`docs/patterns/*.md`・`information-design.md`・`runtime-environment.md`: 「原則 5」などの参照を `P5` にそろえた
61
+
62
+ ## 0.6.0
63
+
64
+ ### Minor Changes
65
+
66
+ - a1a7302: リンクの hover とフォーカスを、色の薄化ではなく下線で示すようにした。
67
+
68
+ `<a>`・`Typography.Link`・`Typography` の操作(コピー・編集・展開)・`Button variant="link"` の
69
+ 4 つが同じ体裁で揃う。hover の色は平常時と同じリンク色を保ち、押下中だけ濃い色になる。
70
+
71
+ 変更前は antd の既定で hover に自動生成の明色(`#8aa4e6`)が当たり、白背景でのコントラストが
72
+ 2.46:1 と WCAG AA の 4.5:1 どころか非テキストの 3:1 も割っていた。変更後はどの状態でも 6.04:1 を保つ。
73
+
74
+ **テーマのトークン**(`businessTheme` に含まれる。個別の指定は不要)
75
+
76
+ - `colorLinkHover`: 自動生成の明色 → `colorLink` と同値
77
+ - `linkHoverDecoration`: `none` → `underline`
78
+ - `linkFocusDecoration`: `none` → `underline`
79
+ - `linkDecoration`(平常時): `none` のまま
80
+
81
+ **配る CSS が増える**
82
+
83
+ `Button variant="link"` は text-decoration 系のトークンを読まないため、`UbieConfigProvider` が
84
+ hover / focus / 押下中の下線を CSS で配る。あわせて、無効なリンク(`Typography.Link disabled` と
85
+ `href` 付きの無効な Button link。どちらも `<a>` として描かれ `disabled` 属性を持たない)からは
86
+ 下線を戻すルールも配る。antd の無効時のルールは色しか戻さないため、これが無いと押せないリンクにも
87
+ 下線が出る。
88
+
89
+ `UbieConfigProvider` を使わず `ConfigProvider` に `businessTheme` を直接渡す構成では当たらない。
90
+
91
+ **利用側で要る対応**
92
+
93
+ 画面側の CSS で `:hover { text-decoration: ... }` や hover の色を個別に指定している箇所は、
94
+ specificity でこの既定より勝つため体裁が揃わない。削除して既定に寄せる。
95
+ 規約は `docs/patterns/link.md`、判断の背景は ADR 0007。
96
+
97
+ トークンの追加・削除・リネームは無し。
98
+
99
+ - 5824e7e: `Table` のセルの中に置いた `Typography` にセルの文字サイズ(`cellFontSize` = 14px)を継がせる
100
+
101
+ - **修正**: これまでセルの中の `Typography.Text` / `Paragraph` / `Link` は、セル(14px)ではなく
102
+ グローバルの本文サイズ(`businessTypography` の 16px)で描かれていた。表のセルはほぼ必ず中身を
103
+ `Typography` で包むため、`cellFontSize` の存在意義(一覧の密度、日時列を折り返させない)が
104
+ 既定では成立していなかった。`Table` が「セルの中の `Typography`(見出し以外)は `font-size: inherit`」
105
+ という 1 本の CSS ルールを配るようにした。**利用側の変更は不要**
106
+ - **挙動の変化**: セルの中の `Typography.Text` / `Paragraph` / `Link` が 16px → 14px になる。
107
+ 既に `style={{ fontSize: "inherit" }}` を当てていた箇所はそのままでよい(inline が勝ち、値は同じ)。
108
+ セルの中で本文サイズを保ちたい箇所があれば `style={{ fontSize: token.fontSize }}` を明示する
109
+ - **対象外**: `Typography.Title`(見出しトークンが正)、`Tag`(`fontSizeSM` を自前で持つ)、
110
+ および `Button` / `Input` / `Select` などのコントロール。コントロールは文字サイズが高さ・余白の算出に
111
+ 噛んでいるため `Table` 側では触らない。表の文字サイズに合わせたいときは従来どおり
112
+ `style={{ fontSize: "inherit" }}` を当てる(`size="small"` にしても文字は縮まない)
113
+ - **追加**: `Table` が描く表の `rootClassName` に `ubie-vitals-table` が付く。上のルールを
114
+ この `Table` が描いた表だけに閉じるための目印で、同じページの他の antd Table には影響しない。
115
+ 利用側が渡した `rootClassName` はそのまま残る
116
+ - **文書**: `docs/components/table.md` に「セルの中の文字サイズ」を新設し、継ぐもの・継がないものと
117
+ 上書きの仕方を書いた。旧記述(`cellFontSize` が効かないのは `Button` だけ)は不正確だったので訂正した。
118
+ 機構・代替案・実測は
119
+ https://github.com/ubie-inc/ubie-vitals/blob/main/docs/adr/0005-cell-font-size-inheritance-in-table.md
120
+ - **古いブラウザ**: セレクタを解釈できないブラウザではルールごと捨てられ、この修正前の挙動
121
+ (セルの中身が本文サイズ)に戻るだけ。レイアウトが壊れる方向の失敗は無い
122
+
123
+ - 69add7f: 対応ブラウザの下限(Chrome 85 / Edge 92 / Firefox 109 / Safari 15 / iOS Safari 15.1)を UI Business 側で保証する
124
+
125
+ 下限の正本は [aimon-genius-fe の `.browserslistrc`](https://github.com/ubie-inc/aimon-genius-fe/blob/main/.browserslistrc)
126
+ (各病院での利用実績で決まっている)。antd 6 が出す CSS はこの下限を 2 点で割っていたので、
127
+ UI Business 側で引き受けた。**`UbieConfigProvider` をアプリの最上位に置いていれば、利用側の変更は不要。**
128
+
129
+ - **修正**: `UbieConfigProvider` が論理プロパティ(`padding-inline` / `inset-inline-start` …)を
130
+ 物理プロパティに落とすようになった。Chrome 85〜88 ではこれらの宣言が丸ごと無視され、
131
+ **余白と位置が崩れていた**。aimon-genius-fe の `AntdCompatProvider` 相当をパッケージ側に移した形で、
132
+ 利用側が既に置いている transformer(`px2rem` など)は落とさない
133
+ - **挙動の変化**: `businessTheme` が `hashed: false` を持ち、antd が出すセレクタが
134
+ `:where(.css-<hash>).ant-x{…}` から `.ant-x{…}` になる。**ハッシュクラスが DOM から消える**ので、
135
+ これを選択子にしているコードや E2E があれば直す。specificity(0-1-0)と挿入順は変わらないため、
136
+ CSS module のクラスや `style` での上書きの効き方はこれまでと同じ
137
+ - **追加**: `StyleProvider` / `legacyLogicalPropertiesTransformer` / `px2remTransformer` / `extractStyle` を
138
+ 再 export した。antd は `@ant-design/cssinjs` を再エクスポートしないため、`ConfigProvider` に
139
+ `businessTheme` を直接渡す構成や SSR のスタイル抽出で必要になる
140
+ - **依存**: `@ant-design/cssinjs`(`^2.1.2`、antd 6.5.1 と同じ範囲)を直接依存に足した
141
+
142
+ **注意が 2 つある。**
143
+
144
+ - `ConfigProvider` に `businessTheme` を直接渡す構成では論理プロパティの変換が当たらない。
145
+ その場合は再 export した `StyleProvider` / `legacyLogicalPropertiesTransformer` を利用側で置く:
146
+ `<StyleProvider transformers={[legacyLogicalPropertiesTransformer]}>`
147
+ - cssinjs のスタイルキャッシュは transformer を鍵に含めない。同一ページで変換あり・なしの
148
+ `StyleProvider` が混在すると**先に生成された CSS が両方で使われる**ので、変換はアプリの root で
149
+ 一度だけ当てる
150
+
151
+ **残る劣化。** `:has()` と `:focus-visible` が Chrome 85 / Safari 15〜15.3 で効かず、
152
+ フォーカス表示が出ない。`:focus` へのフォールバックは対応ブラウザでマウス操作時にも枠が出る
153
+ 別の劣化を招くため入れていない。その他は見た目の劣化にとどまる。
154
+ 一覧と理由は `browserSupport.test.tsx` の `KNOWN_GAPS`、判断の経緯は
155
+ https://github.com/ubie-inc/ubie-vitals/blob/main/docs/adr/0006-browser-support-floor-in-ui-business.md
156
+
157
+ ### Patch Changes
158
+
159
+ - c4a7179: 参照層に「実行環境の前提(ブラウザのナビゲーションとブックマーク)」(`docs/principles/runtime-environment.md`)を追加する。
160
+
161
+ 業務プロダクトは、戻る・進む・リロード・アドレスバー・ブックマークバーが画面に無い状態で使われることがある(基幹システムの起動ボタンから起動オプション付きでブラウザを開く構成、キオスク端末、別アプリへの埋め込み)。実際に報告されている 2 つの事象(ナビゲーションが表示されない / ブックマークが永続しない)を前提として記録し、戻る・再試行・再訪の手段をアプリ内に持たせる帰結を 4 つ挙げた。**導入先すべてではなく、割合も原因も分かっていない**という限定条件は原則の文面に残している。
162
+
163
+ 参照層の判断軸そのものは消していない。「URL 共有・ブックマークしたいか」を Drawer と別ページの分岐軸にする判断はそのまま残し、それがブラウザのナビゲーションが使える環境を前提にしていることの注記と読み替えを足した。一方で「直リンクで配信したい」は、外からの入口の要件でナビゲーションの有無とは独立に効くため、URL 共有・ブックマークと同じ扱いから分離した(Drawer は直リンクで開けないので別ページを選ぶ。ただし唯一の入口にしない)。
164
+
165
+ | 文書 | 追記 |
166
+ | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
167
+ | `docs/patterns/disclosure.md` | 別ページ遷移の分岐点と「URL 共有・ブックマークしたい」が前提にしていること。「直リンクで配信したい」は環境に依らず効く軸として区別した |
168
+ | `docs/patterns/list-detail.md` | 絞り込みの URL 復元を、戻る操作を唯一の手段にしない形に |
169
+ | `docs/patterns/skeleton.md` | モーダルドロワーの開閉を URL に載せる判断の読み替え |
170
+ | `docs/patterns/region-state.md` | 復帰を「ページを再読み込みしてください」に任せない |
171
+ | `docs/components/drawer.md` | 「URL 共有・ブックマーク → 別ページ」の前提と、直リンク配信を独立の行に分離 |
172
+ | `docs/components/layout.md` | 上位階層へ戻る導線の置き場を骨格の中に決めておく Do |
173
+
174
+ 8 原則(`docs/principles/ux-principles.md`)と採点の枠(`docs/principles/scorecard.md`)は変えていない。新しい原則は P3 / P8 に紐づく。
175
+
3
176
  ## 0.5.0
4
177
 
5
178
  ### Minor Changes
package/DESIGN.md CHANGED
@@ -9,19 +9,21 @@ antd と Ant Design X の公開 API をそのまま再 export し、共通のテ
9
9
  - `antd` から直接ではなく `@ubie/vitals-ui-business` から import する
10
10
  - アイコンは `@ant-design/icons` の `*Outlined` から選ぶ。`@ant-design/icons` を直接 import しない。塗りが要るときと、antd に絵柄が無いとき(`@ubie/vitals-icon`)の落とし方は `docs/components/icon.md`
11
11
  - 色・寸法の値をプロダクトのコードに書かない。正本はトークンとテーマにある(`docs/tokens.md`)
12
+ - `UbieConfigProvider` はアプリの最上位に置く。antd が対応ブラウザの下限を割るぶんの調整がここに入っている
12
13
  - アプリ固有の逸脱は、そのプロダクトのリポジトリに書く
13
14
 
14
15
  ## 何をするときに何を読むか
15
16
 
16
- | したいこと | 読むもの |
17
- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
18
- | プロダクトを立ち上げる | 下の「立ち上げ」 |
19
- | 画面を 1 枚足す | 骨格と区画は `docs/patterns/skeleton.md` → 一覧と詳細の関係は `docs/patterns/list-detail.md` → 情報の出し方は `docs/patterns/disclosure.md` |
20
- | 部品の使い方を確かめる | `docs/components/`(Table / Layout / Modal / Drawer / Statistic / チャット / アイコン) |
21
- | アイコンを選ぶ | `docs/components/icon.md` |
22
- | 色・寸法を決める | `docs/tokens.md` |
23
- | グラフを置く | `docs/patterns/chart.md`。系列色は `chartSeriesColors` |
24
- | 設計や実装を見直す・採点する | `docs/principles/` |
17
+ | したいこと | 読むもの |
18
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
19
+ | プロダクトを立ち上げる | 下の「立ち上げ」 |
20
+ | 画面を 1 枚足す | 骨格と区画は `docs/patterns/skeleton.md` → 一覧と詳細の関係は `docs/patterns/list-detail.md` → 情報の出し方は `docs/patterns/disclosure.md` |
21
+ | 部品の使い方を確かめる | `docs/components/`(Table / Layout / Modal / Drawer / Statistic / チャット / アイコン) |
22
+ | アイコンを選ぶ | `docs/components/icon.md` |
23
+ | 色・寸法を決める | `docs/tokens.md` |
24
+ | グラフを置く | `docs/patterns/chart.md`。系列色は `chartSeriesColors` |
25
+ | 戻る・再試行・再訪の導線を決める | `docs/principles/runtime-environment.md` |
26
+ | 設計や実装を見直す・レビューする | `docs/principles/` |
25
27
 
26
28
  ## 索引
27
29
 
@@ -38,33 +40,35 @@ antd と Ant Design X の公開 API をそのまま再 export し、共通のテ
38
40
 
39
41
  antd の同名コンポーネントに既定を足したもの、および antd に対応物がない部品。
40
42
 
41
- | 名前 | 場所 | antd との差分 | カード |
42
- | ------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------- | -------------------------- |
43
- | `Table` | `src/components/Table/index.tsx` | `rowActions` / `revealOnHover` / `disableHoverEffect`、`size="small"` 既定 | `docs/components/table.md` |
44
- | `ChatBubble` | `src/components/ChatBubble/index.tsx` | `evidence` / `timestamp` / `timestampFormat` / `onRetry` / `retryLabel` を `footer` / `extra` に合成 | `docs/components/chat.md` |
45
- | `ChatConversations` | `src/components/ChatConversations/index.tsx` | `emptyState`(未指定なら antd の `Empty`) | `docs/components/chat.md` |
43
+ | 名前 | 場所 | antd との差分 | カード |
44
+ | ------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------- |
45
+ | `Table` | `src/components/Table/index.tsx` | `rowActions` / `revealOnHover` / `disableHoverEffect`、`size="small"` 既定、セル内 `Typography` の文字サイズ継承 | `docs/components/table.md` |
46
+ | `ChatBubble` | `src/components/ChatBubble/index.tsx` | `evidence` / `timestamp` / `timestampFormat` / `onRetry` / `retryLabel` を `footer` / `extra` に合成 | `docs/components/chat.md` |
47
+ | `ChatConversations` | `src/components/ChatConversations/index.tsx` | `emptyState`(未指定なら antd の `Empty`) | `docs/components/chat.md` |
46
48
 
47
49
  ### 文書
48
50
 
49
- | 文書 | 場所 |
50
- | ---------------------------- | --------------------------------------- |
51
- | 体験設計の 8 原則と採点の枠 | `docs/principles/README.md` |
52
- | 情報設計の原則 | `docs/principles/information-design.md` |
53
- | トークンの優先順位 | `docs/tokens.md` |
54
- | Table カード | `docs/components/table.md` |
55
- | 画面骨格 5 型と区画 | `docs/patterns/skeleton.md` |
56
- | 情報の開示パターン | `docs/patterns/disclosure.md` |
57
- | 一覧と詳細 | `docs/patterns/list-detail.md` |
58
- | グラフ | `docs/patterns/chart.md` |
59
- | 区画の状態(読み込み・失敗) | `docs/patterns/region-state.md` |
60
- | 空状態 | `docs/patterns/empty-state.md` |
61
- | 印刷様式 | `docs/patterns/print.md` |
62
- | Statistic カード | `docs/components/statistic.md` |
63
- | Layout カード | `docs/components/layout.md` |
64
- | Modal カード | `docs/components/modal.md` |
65
- | Drawer カード | `docs/components/drawer.md` |
66
- | チャット | `docs/components/chat.md` |
67
- | Icon カード | `docs/components/icon.md` |
51
+ | 文書 | 場所 |
52
+ | ---------------------------------- | ---------------------------------------- |
53
+ | 体験設計の 11 原則とチェックリスト | `docs/principles/README.md` |
54
+ | 情報設計の原則 | `docs/principles/information-design.md` |
55
+ | 実行環境の前提 | `docs/principles/runtime-environment.md` |
56
+ | トークンの優先順位 | `docs/tokens.md` |
57
+ | Table カード | `docs/components/table.md` |
58
+ | 画面骨格 5 型と区画 | `docs/patterns/skeleton.md` |
59
+ | 情報の開示パターン | `docs/patterns/disclosure.md` |
60
+ | 一覧と詳細 | `docs/patterns/list-detail.md` |
61
+ | グラフ | `docs/patterns/chart.md` |
62
+ | 区画の状態(読み込み・失敗) | `docs/patterns/region-state.md` |
63
+ | 空状態 | `docs/patterns/empty-state.md` |
64
+ | 印刷様式 | `docs/patterns/print.md` |
65
+ | リンクの体裁 | `docs/patterns/link.md` |
66
+ | Statistic カード | `docs/components/statistic.md` |
67
+ | Layout カード | `docs/components/layout.md` |
68
+ | Modal カード | `docs/components/modal.md` |
69
+ | Drawer カード | `docs/components/drawer.md` |
70
+ | チャット | `docs/components/chat.md` |
71
+ | Icon カード | `docs/components/icon.md` |
68
72
 
69
73
  ### 描画カタログ
70
74
 
@@ -72,7 +76,7 @@ Storybook: https://ubie-inc.github.io/ubie-vitals/ui-business (main への pus
72
76
  コンポーネントは Storybook の "Business/" グループ、パターンの実演は "Patterns/" グループにある。
73
77
 
74
78
  - コンポーネント: `src/stories/business/Table.stories.tsx`・`src/stories/business/Chat.stories.tsx`・`src/stories/business/Icon.stories.tsx`
75
- - パターンの実演: `src/stories/patterns/Skeleton.stories.tsx`・`src/stories/patterns/Section.stories.tsx`・`src/stories/patterns/Disclosure.stories.tsx`・`src/stories/patterns/ListDetail.stories.tsx`・`src/stories/patterns/Chart.stories.tsx`
79
+ - パターンの実演: `src/stories/patterns/Skeleton.stories.tsx`・`src/stories/patterns/Section.stories.tsx`・`src/stories/patterns/Disclosure.stories.tsx`・`src/stories/patterns/ListDetail.stories.tsx`・`src/stories/patterns/Chart.stories.tsx`・`src/stories/patterns/Link.stories.tsx`
76
80
 
77
81
  ## 立ち上げ
78
82
 
@@ -80,5 +84,5 @@ Storybook: https://ubie-inc.github.io/ubie-vitals/ui-business (main への pus
80
84
  2. アプリの最上位を `UbieConfigProvider` で包み、`locale={jaJP}` を渡す。`jaJP` も `UbieConfigProvider` も `@ubie/vitals-ui-business` から import する(`antd/locale/*` を直接 import しない)
81
85
  3. アプリ固有のテーマ差分(ヘッダー高さなど)は `UbieConfigProvider` の `theme` に差分だけ渡す。書き方は `docs/tokens.md`
82
86
  4. 骨格は `docs/patterns/skeleton.md` の 5 型から選ぶ。一覧と詳細の組み立ては `docs/patterns/list-detail.md`、情報の出し方は `docs/patterns/disclosure.md`、部品の用法は `docs/components/` にある
83
- 5. CSS module から antd の値を参照するときは CSS 変数(`--ant-*`)をそのまま使う。`UbieConfigProvider` を通した時点で出ているので `cssVar` の指定は要らない。スタイルの挿入順を変える `StyleProvider` が要るときだけ、antd と同じ major の `@ant-design/cssinjs` を依存に足して直接 import する(再 export していない)
87
+ 5. CSS module から antd の値を参照するときは CSS 変数(`--ant-*`)をそのまま使う。`UbieConfigProvider` を通した時点で出ているので `cssVar` の指定は要らない。スタイルの挿入順や変換を触る `StyleProvider` が要るときは `@ubie/vitals-ui-business` から import する(`@ant-design/cssinjs` を直接依存に足さない)。対応ブラウザのための変換は `UbieConfigProvider` が既に通しているので、アプリの root で 1 度だけ当てる
84
88
  6. Storybook で描くときは decorator で `UbieConfigProvider` → `App` → `Layout` > `Layout.Content` の順に包む。`Layout` が無いと `Layout.bodyBg` が当たらず、面の外側が白いまま描かれる(`docs/components/layout.md`)
package/dist/index.cjs CHANGED
@@ -27,9 +27,29 @@ let _ant_design_x = require("@ant-design/x");
27
27
  let antd = require("antd");
28
28
  let antd_locale_ja_JP_js = require("antd/locale/ja_JP.js");
29
29
  antd_locale_ja_JP_js = __toESM(antd_locale_ja_JP_js);
30
+ let _ant_design_cssinjs = require("@ant-design/cssinjs");
31
+ let react = require("react");
30
32
  let _ubie_vitals_antd_theme = require("@ubie/vitals-antd-theme");
31
33
  let react_jsx_runtime = require("react/jsx-runtime");
32
- let react = require("react");
34
+ //#region src/ownedStyle.ts
35
+ /**
36
+ * ui-business 自身が配る `<style>` の目印。
37
+ *
38
+ * 対応ブラウザの下限の検査(`browserSupport.test.tsx`)は「ui-business が配るルールには既知の
39
+ * ギャップも許さない」を見るため、どの `<style>` が自分のものかを判別できる必要がある。
40
+ * CSS 本文に含まれる文字列で見分けると、スコープクラスを持てないルールを取りこぼす
41
+ * (`UbieConfigProvider` は DOM 要素を描かないので、クラスを付ける先が無い)。属性で印を付ける。
42
+ */
43
+ const ownedStyleAttribute = "data-ubie-vitals";
44
+ /**
45
+ * `<style>` に渡す目印。`scope` は用途がわかる名前を入れる(読む人と DevTools のためで、
46
+ * 検査は属性の有無だけを見る)。
47
+ */
48
+ function ownedStyleProps(scope) {
49
+ return { [ownedStyleAttribute]: scope };
50
+ }
51
+ `${ownedStyleAttribute}`;
52
+ //#endregion
33
53
  //#region ../token/dist/js/tokens.js
34
54
  /**
35
55
  * Do not edit directly, this file was auto-generated.
@@ -57,6 +77,34 @@ const ColorSurfaceContainer = "#ffffffff";
57
77
  const ColorOnSurface = "#0a0b0eff";
58
78
  const ColorOnSurfaceVariant = "#63666bff";
59
79
  //#endregion
80
+ //#region src/theme/businessLinkInteraction.ts
81
+ /**
82
+ * リンクの状態表現。色の濃淡ではなく下線で hover / focus を示す。
83
+ *
84
+ * antd は `colorLink` からパレットを生成し、hover にはその明色(index 3)を当てる。
85
+ * business の `colorLink`(ubie-blue-600)から生成される明色は、白背景で 2.46:1 まで落ちる。
86
+ * WCAG AA の 4.5:1 どころか非テキストの 3:1 も割る。状態を色の濃淡で示す方法そのものが成立していない
87
+ * (実測値は `docs/adr/0007-link-hover-underline.md`)。
88
+ *
89
+ * そこで hover では色を変えず(`colorLink` と同値)、下線で状態を示す。値をコピーせず
90
+ * `antdTheme.token.colorLink` を参照するので、リンク色を変えても hover は自動で追従する。
91
+ *
92
+ * focus も同じ扱いにする。antd の `<a>` は `:focus` に `outline: 0` を当てるため、下線が無いと
93
+ * キーボードのフォーカスがどこにも出ない。代償として、クリック後にフォーカスが残っている間は
94
+ * 下線が出たままになる(2026-09-16 決定。挙動を 1 つに揃えることを優先した)。
95
+ *
96
+ * 平常時の `linkDecoration` は antd 既定の "none" のまま。常時下線にすると業務画面の情報密度が
97
+ * 変わるため、状態が変わったときだけ出す。
98
+ *
99
+ * `Button variant="link"` はこれらを読まない(色の 3 つしか見ない)。Button 側の下線は
100
+ * `UbieConfigProvider` が配る CSS が受け持つ。
101
+ */
102
+ const businessLinkInteraction = {
103
+ colorLinkHover: _ubie_vitals_antd_theme.antdTheme.token.colorLink,
104
+ linkHoverDecoration: "underline",
105
+ linkFocusDecoration: "underline"
106
+ };
107
+ //#endregion
60
108
  //#region src/theme/businessTypography.ts
61
109
  /**
62
110
  * ToB プロダクト共通の書体スタック。
@@ -161,9 +209,20 @@ const businessComponentMetrics = { Table: {
161
209
  */
162
210
  const businessTheme = {
163
211
  ..._ubie_vitals_antd_theme.antdTheme,
212
+ /**
213
+ * 体積削減ではなく**対応ブラウザの下限のために要る**。既定(`true`)では antd が全ルールを
214
+ * `:where(.css-<hash>).ant-x{…}` の形で出すが、`:where()` は Chrome 88 からで、下限は Chrome 85。
215
+ * **戻すと下限のブラウザで antd の CSS が 1 本も当たらず、画面が素の HTML になる。**
216
+ *
217
+ * 失うのは複数バージョン・複数テーマの分離。**antd を 2 バージョン同時に載せる構成にするなら
218
+ * 見直す。** 判断の根拠と代替案は `docs/adr/0006-browser-support-floor-in-ui-business.md`、
219
+ * 前提(テーマが違ってもルール本文が同一)の検査は `browserSupport.test.tsx`。
220
+ */
221
+ hashed: false,
164
222
  token: {
165
223
  ..._ubie_vitals_antd_theme.antdTheme.token,
166
- ...businessTypography
224
+ ...businessTypography,
225
+ ...businessLinkInteraction
167
226
  },
168
227
  components: {
169
228
  Layout: {
@@ -179,15 +238,86 @@ const businessTheme = {
179
238
  //#endregion
180
239
  //#region src/UbieConfigProvider.tsx
181
240
  /**
241
+ * 論理プロパティ(`padding-inline` / `inset-inline-start` …)を物理プロパティに落とす transformer。
242
+ *
243
+ * antd 6 がこれらを多用する一方、対応は Chrome 89 から。対応ブラウザの下限は Chrome 85 なので、
244
+ * **外すと Chrome 85〜88 で余白と位置が崩れる**(`browserSupport.test.tsx` が検査する)。
245
+ * 代償として RTL では左右が反転しなくなる。ToB は日本語の LTR だけなので採る。
246
+ */
247
+ function useMergedTransformers() {
248
+ const { transformers } = (0, react.useContext)(_ant_design_cssinjs.StyleContext);
249
+ return (0, react.useMemo)(() => {
250
+ const inherited = transformers ?? [];
251
+ return inherited.includes(_ant_design_cssinjs.legacyLogicalPropertiesTransformer) ? inherited : [...inherited, _ant_design_cssinjs.legacyLogicalPropertiesTransformer];
252
+ }, [transformers]);
253
+ }
254
+ /**
255
+ * リンクの下線を、トークンで届かないぶんだけ補う CSS。
256
+ *
257
+ * 足す側: `Button variant="link"` は色の 3 つ(base / hover / active)しか読まず、
258
+ * `linkHoverDecoration` を参照しない(antd 6 の `button/style/variant.js`)。
259
+ *
260
+ * 戻す側: `linkHoverDecoration` を `underline` にすると、antd のグローバルな `a:hover` と
261
+ * `.ant-typography-link:hover` にも一律で乗る。一方 antd の無効時のルールは **色しか戻さない**
262
+ * (`typography/style/mixins.js` の disabled は `color` と `cursor` だけ)。そのままだと押せない
263
+ * リンクにまで下線が出る。無効なものは `:not(:disabled)` では届かない——無効な `Typography.Link` は
264
+ * `<a class="…-typography-disabled">`、無効な Button link に `href` を渡したものは
265
+ * `<a class="…-btn-disabled">` で、どちらも `disabled` 属性を持たないため。クラスで名指しして戻す。
266
+ *
267
+ * 判断の背景は `docs/adr/0007-link-hover-underline.md`。
268
+ *
269
+ * セレクタで意図的にやっていること:
270
+ * - セレクタリスト(`,`)を使わず 1 ルール 1 セレクタで並べる。`:not(a, b)` も `:where()` も
271
+ * 対応ブラウザの下限を割る(`browserSupport.test.tsx` が検査する)
272
+ * - 戻す側は特異度を antd のルールより高くする。`.ant-typography.ant-typography-link:hover` に
273
+ * クラス 1 つぶん勝たせるため、`-typography` と `-link` と `-disabled` を重ねる
274
+ */
275
+ function linkUnderlineCss(buttonPrefixCls, typographyPrefixCls) {
276
+ const enabledLinkButton = `.${buttonPrefixCls}-variant-link:not(:disabled):not(.${buttonPrefixCls}-disabled)`;
277
+ const disabledLink = `.${typographyPrefixCls}.${typographyPrefixCls}-link.${typographyPrefixCls}-disabled`;
278
+ return [
279
+ `${enabledLinkButton}:hover{text-decoration:underline}`,
280
+ `${enabledLinkButton}:focus{text-decoration:underline}`,
281
+ `${enabledLinkButton}:active{text-decoration:underline}`,
282
+ `.${buttonPrefixCls}-disabled:hover{text-decoration:none}`,
283
+ `${disabledLink}:hover{text-decoration:none}`
284
+ ].join("");
285
+ }
286
+ /**
287
+ * 上の CSS を配る。`prefixCls` は利用側が差し替えられるので、`ConfigProvider` の内側で解決する。
288
+ *
289
+ * React 19 は `href` をキーに `<head>` へ巻き上げて重複を畳むため、`UbieConfigProvider` が
290
+ * 何段ネストしても同じ prefix なら 1 枚に畳まれる。React 18 ではこの位置にそのまま出るが、
291
+ * `style` は UA スタイルシートで display:none なのでレイアウトには影響しない(ADR 0005 と同じ扱い)。
292
+ */
293
+ function LinkUnderlineStyle() {
294
+ const { getPrefixCls } = (0, react.useContext)(antd.ConfigProvider.ConfigContext);
295
+ const buttonPrefixCls = getPrefixCls("btn");
296
+ const typographyPrefixCls = getPrefixCls("typography");
297
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", {
298
+ ...ownedStyleProps("link-underline"),
299
+ href: `ubie-vitals-link-underline-${buttonPrefixCls}-${typographyPrefixCls}`,
300
+ precedence: "ubie-vitals",
301
+ children: linkUnderlineCss(buttonPrefixCls, typographyPrefixCls)
302
+ });
303
+ }
304
+ /**
182
305
  * ToB プロダクト共通のテーマ(businessTheme)を適用したうえで、利用側の ConfigProvider 設定を重ねる。
183
306
  * 外側で businessTheme を当て、内側で利用側 props を渡すため、利用側の `theme` は差分として上書きされる。
307
+ *
308
+ * さらに、対応ブラウザの下限を満たすための `StyleProvider`(論理プロパティの変換)を内側に持つ。
309
+ * `UbieConfigProvider` を使わず `ConfigProvider` に `businessTheme` を直接渡す構成では当たらないため、
310
+ * その場合は再 export した `StyleProvider` / `legacyLogicalPropertiesTransformer` を利用側で置く。
184
311
  */
185
312
  function UbieConfigProvider({ children, ...configProviderProps }) {
186
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.ConfigProvider, {
187
- theme: businessTheme,
313
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ant_design_cssinjs.StyleProvider, {
314
+ transformers: useMergedTransformers(),
188
315
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.ConfigProvider, {
189
- ...configProviderProps,
190
- children
316
+ theme: businessTheme,
317
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(antd.ConfigProvider, {
318
+ ...configProviderProps,
319
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkUnderlineStyle, {}), children]
320
+ })
191
321
  })
192
322
  });
193
323
  }
@@ -274,6 +404,33 @@ const chartSeriesColors = {
274
404
  //#endregion
275
405
  //#region src/components/Table/index.tsx
276
406
  const ROW_ACTIONS_COLUMN_KEY = "__rowActions";
407
+ /**
408
+ * セル内 Typography の文字サイズ継承を、この Table が描いた表だけに閉じるための目印クラス。
409
+ * `rootClassName` で `.ant-table-wrapper` に付く。
410
+ */
411
+ const CELL_FONT_SIZE_SCOPE_CLASS = "ubie-vitals-table";
412
+ /**
413
+ * セルの中の `Typography`(`Text` / `Paragraph` / `Link`)にセルの文字サイズを継がせる CSS。
414
+ *
415
+ * theme では書けない。理由・対象の線引き・採らなかった案・実測は
416
+ * `docs/adr/0005-cell-font-size-inheritance-in-table.md`。
417
+ *
418
+ * セレクタで意図的にやっていること(いずれも外すと壊れる):
419
+ * - `Title`(h1〜h5 と編集中の `div.ant-typography-h*`)を除外する。除外しないとこのルールが
420
+ * antd の見出し宣言に勝ち、見出しトークンが効かなくなる
421
+ * - `:not()` を連ねる。`:not(a, b)` のセレクタリストも `:where()` も対応ブラウザの下限を割るので
422
+ * 使わない(`browserSupport.test.tsx` が検査する。下限は package.json の `browserslist`)
423
+ */
424
+ function cellFontSizeCss(tablePrefixCls, typographyPrefixCls) {
425
+ return `.${CELL_FONT_SIZE_SCOPE_CLASS} .${tablePrefixCls}-cell .${typographyPrefixCls}${[
426
+ "h1",
427
+ "h2",
428
+ "h3",
429
+ "h4",
430
+ "h5",
431
+ `[class*="${typographyPrefixCls}-h"]`
432
+ ].map((selector) => `:not(${selector})`).join("")}{font-size:inherit}`;
433
+ }
277
434
  function resolveRowKey(rowKey, record, index) {
278
435
  if (typeof rowKey === "function") return rowKey(record, index);
279
436
  const value = record[rowKey ?? "key"];
@@ -284,7 +441,6 @@ function resolveRowKey(rowKey, record, index) {
284
441
  *
285
442
  * - `size` の既定は `small`(`businessTheme` の `Table.cellPaddingBlockSM` と組で一覧画面の密度にする)
286
443
  * - `rowActions` / `revealOnHover` / `disableHoverEffect` を足す。それ以外の props は antd にそのまま渡す
287
- * - hover 状態は React state で持つ(CSS に依存しないので描画テストで検査できる)
288
444
  *
289
445
  * @displayName Table
290
446
  */
@@ -343,14 +499,23 @@ function InternalTable(props) {
343
499
  ]);
344
500
  const columnsProp = mergedColumns === void 0 ? {} : { columns: mergedColumns };
345
501
  const rowKeyProp = rowKey === void 0 ? {} : { rowKey };
346
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Table, {
502
+ const { getPrefixCls } = (0, react.useContext)(antd.ConfigProvider.ConfigContext);
503
+ const tablePrefixCls = getPrefixCls("table", props.prefixCls);
504
+ const typographyPrefixCls = getPrefixCls("typography");
505
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", {
506
+ ...ownedStyleProps("table-cell-font-size"),
507
+ href: `${CELL_FONT_SIZE_SCOPE_CLASS}-cell-font-size-${tablePrefixCls}-${typographyPrefixCls}`,
508
+ precedence: "ubie-vitals",
509
+ children: cellFontSizeCss(tablePrefixCls, typographyPrefixCls)
510
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Table, {
347
511
  ...rest,
348
512
  ...columnsProp,
349
513
  ...rowKeyProp,
350
514
  onRow: mergedOnRow,
351
515
  ref,
516
+ rootClassName: [CELL_FONT_SIZE_SCOPE_CLASS, props.rootClassName].filter(Boolean).join(" "),
352
517
  size
353
- });
518
+ })] });
354
519
  }
355
520
  const Table = Object.assign(InternalTable, {
356
521
  Column: antd.Table.Column,
@@ -459,6 +624,12 @@ Object.defineProperty(exports, "Icon", {
459
624
  return _ant_design_icons.default;
460
625
  }
461
626
  });
627
+ Object.defineProperty(exports, "StyleProvider", {
628
+ enumerable: true,
629
+ get: function() {
630
+ return _ant_design_cssinjs.StyleProvider;
631
+ }
632
+ });
462
633
  exports.Table = Table;
463
634
  exports.UbieConfigProvider = UbieConfigProvider;
464
635
  exports.businessFontFamily = businessFontFamily;
@@ -467,18 +638,36 @@ exports.businessLineHeights = businessLineHeights;
467
638
  exports.businessTheme = businessTheme;
468
639
  exports.businessTypography = businessTypography;
469
640
  exports.chartSeriesColors = chartSeriesColors;
641
+ Object.defineProperty(exports, "extractStyle", {
642
+ enumerable: true,
643
+ get: function() {
644
+ return _ant_design_cssinjs.extractStyle;
645
+ }
646
+ });
470
647
  Object.defineProperty(exports, "jaJP", {
471
648
  enumerable: true,
472
649
  get: function() {
473
650
  return antd_locale_ja_JP_js.default;
474
651
  }
475
652
  });
653
+ Object.defineProperty(exports, "legacyLogicalPropertiesTransformer", {
654
+ enumerable: true,
655
+ get: function() {
656
+ return _ant_design_cssinjs.legacyLogicalPropertiesTransformer;
657
+ }
658
+ });
476
659
  Object.defineProperty(exports, "notification", {
477
660
  enumerable: true,
478
661
  get: function() {
479
662
  return antd.notification;
480
663
  }
481
664
  });
665
+ Object.defineProperty(exports, "px2remTransformer", {
666
+ enumerable: true,
667
+ get: function() {
668
+ return _ant_design_cssinjs.px2remTransformer;
669
+ }
670
+ });
482
671
  Object.defineProperty(exports, "version", {
483
672
  enumerable: true,
484
673
  get: function() {