@hidemikimura/chit-ui 0.2.0 → 0.3.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.
- package/CHANGELOG.md +59 -0
- package/README.md +148 -3
- package/dist/chit-ui.iife.min.js +218 -99
- package/dist/chit-ui.iife.min.js.map +1 -1
- package/dist/chit-ui.min.js +209 -90
- package/dist/chit-ui.min.js.map +1 -1
- package/dist/types/chit-ui.d.ts +64 -4
- package/dist/types/controllers/composer-controller.d.ts +4 -0
- package/dist/types/controllers/drag-controller.d.ts +118 -0
- package/dist/types/controllers/scroll-lock-controller.d.ts +37 -0
- package/dist/types/controllers/viewport-controller.d.ts +38 -0
- package/dist/types/events.d.ts +1 -0
- package/dist/types/global.d.ts +7 -1
- package/dist/types/i18n/labels.d.ts +8 -0
- package/dist/types/index.d.ts +162 -0
- package/dist/types/render/message-list.d.ts +0 -1
- package/dist/types/theme/default-theme.d.ts +8 -0
- package/dist/types/types.d.ts +40 -0
- package/package.json +1 -1
- package/src/chit-ui.js +261 -4
- package/src/controllers/composer-controller.js +2 -0
- package/src/controllers/drag-controller.js +319 -0
- package/src/controllers/scroll-controller.js +21 -1
- package/src/controllers/scroll-lock-controller.js +185 -0
- package/src/controllers/viewport-controller.js +102 -0
- package/src/events.js +1 -0
- package/src/global.d.ts +7 -1
- package/src/i18n/labels.js +6 -0
- package/src/index.js +34 -0
- package/src/render/launcher.js +9 -1
- package/src/render/message-list.js +40 -10
- package/src/render/panel.js +17 -1
- package/src/styles/composer.css.js +18 -0
- package/src/styles/launcher.css.js +13 -0
- package/src/styles/message.css.js +60 -15
- package/src/styles/panel.css.js +30 -3
- package/src/theme/default-theme.js +16 -0
- package/src/types.js +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,65 @@
|
|
|
4
4
|
バージョンは [Semantic Versioning](https://semver.org/lang/ja/) に従いますが、0.x の間は
|
|
5
5
|
マイナー更新に破壊的変更が入ることがあります。
|
|
6
6
|
|
|
7
|
+
## 0.3.1 — 2026-09-20
|
|
8
|
+
|
|
9
|
+
### 追加
|
|
10
|
+
|
|
11
|
+
- 公開している型をパッケージのルートからも読めるようにしました。
|
|
12
|
+
`import type { Message, Theme } from '@hidemikimura/chit-ui'` のように書けます
|
|
13
|
+
(これまでは `dist/types/` を直接指す必要がありました)。
|
|
14
|
+
|
|
15
|
+
### 修正
|
|
16
|
+
|
|
17
|
+
- **スマホで入力欄にフォーカスしても画面が拡大されなくなりました。** iOS Safari は
|
|
18
|
+
16px 未満の入力欄にフォーカスするとページを拡大し、離れても元に戻しません。タッチ端末
|
|
19
|
+
(`pointer: coarse`)では入力欄を 16px 以上にして、拡大そのものが起きないようにしました。
|
|
20
|
+
ウィジェット全体の文字サイズは変わりません。テーマの文字が 16px より大きい場合はそちらが
|
|
21
|
+
優先されます。
|
|
22
|
+
- **キーボードが出ている間、全画面のパネルが見えている範囲に収まるようになりました。**
|
|
23
|
+
`visualViewport` を見て、パネルの上端と高さを実際に見えている箱に合わせます。入力欄と
|
|
24
|
+
直前の発言がキーボードの下に隠れなくなり、送信したあともそのまま見えています。
|
|
25
|
+
ピンチで拡大しているときは何もしません(拡大は読み手のものなので、勝手に組み直さない)。
|
|
26
|
+
- **パネルの上をなぞっても後ろのページが動かなくなりました。** 会話が画面に収まっていて
|
|
27
|
+
発言一覧がスクロールしないとき、タイトルバーや入力欄をなぞったときに、指の動きがそのまま
|
|
28
|
+
ページに渡っていました(iPhone で顕著)。`overscroll-behavior: contain` が効くのは
|
|
29
|
+
スクロールできる箱を端まで引っぱったときだけで、そもそも箱になっていない場合は素通しに
|
|
30
|
+
なるためです。パネルの中に進める入れ子があるかを見て、なければその指の動きを取り消します。
|
|
31
|
+
ピンチ(2 本指)はそのままなので、拡大は変わりません。
|
|
32
|
+
|
|
33
|
+
## 0.3.0 — 2026-09-20
|
|
34
|
+
|
|
35
|
+
### 追加
|
|
36
|
+
|
|
37
|
+
- **応答待ちのローディング**。`loading` プロパティで、送信から返事までの間の表示を出せます。
|
|
38
|
+
見た目は `open.loading.style`(`'spinner'`(既定)/ `'dots'` / `'text'`)と `text` で
|
|
39
|
+
決められます。
|
|
40
|
+
相手が機械のとき「入力中」は実態と違うため、スピナーや文言を選べるようにしました。
|
|
41
|
+
- `open.loading.auto` を `true` にすると、`chat-submit` から相手側の発言が届くまで自動で
|
|
42
|
+
表示します。`timeout` を過ぎたら自分で引っ込みます。
|
|
43
|
+
- CSS パーツ `loading` `loading-text`、ラベル `loading`(ja / en)。`loading` は属性にも
|
|
44
|
+
反映されるので、ページ側の CSS から `chit-ui[loading]` で拾えます。
|
|
45
|
+
- **ドラッグで動かせるようになりました**。`closed.draggable` でランチャーを、
|
|
46
|
+
`open.draggable` でパネル(取っ手はタイトルバー)を動かせます。どちらも既定は無効です。
|
|
47
|
+
矢印キー(Shift で大きく)でも動かせ、画面の外には出られません。
|
|
48
|
+
- 閉じた状態と開いた状態は一緒に動きます。ドラッグが動かすのは位置そのものではなく
|
|
49
|
+
「テーマの位置からのずれ」で、これをウィジェット全体でひとつだけ持つためです。ランチャーを
|
|
50
|
+
動かしてから開けばパネルも同じだけずれ、その逆も同じです。
|
|
51
|
+
- 動かすと `chat-move`(`detail: { target, position, offset, displacement }`)が出ます。
|
|
52
|
+
ずれは `dragOffset` プロパティで読み書きでき、保存しておけば代入するだけで復元できます。
|
|
53
|
+
`resetPosition()` でテーマの位置に戻ります。ラベル `move`(ja / en)。
|
|
54
|
+
|
|
55
|
+
### 変更
|
|
56
|
+
|
|
57
|
+
- `loading` と `typing` を排他にしました。片方を `true` にすると、もう片方が `false` に
|
|
58
|
+
なります。どちらも会話の同じ「間」を指しているので、2 つ並べないためです。
|
|
59
|
+
- パネルの最大サイズをオフセットの 2 倍からの引き算ではなく、角から反対側の端までの余白で
|
|
60
|
+
計算するようにしました。以前の式は左右(上下)の余白が等しい前提だったため、ドラッグで
|
|
61
|
+
動かすとパネルが縮んでいきました。画面内に収める判定も、実測の大きさではなくテーマが
|
|
62
|
+
指定した大きさで行うようにしています(実測だと、縮んだ分だけさらに押し込めてしまうため)。
|
|
63
|
+
- 入力中インジケーターの行の高さをフォント任せ(`normal`)ではなく `1.5` と明示しました。
|
|
64
|
+
ローディングと同じ大きさに揃えるためで、環境によって 1〜2px 変わります。
|
|
65
|
+
|
|
7
66
|
## 0.2.0 — 2026-09-19
|
|
8
67
|
|
|
9
68
|
### 追加
|
package/README.md
CHANGED
|
@@ -69,6 +69,17 @@ customElements.define('my-chat', ChitUI);
|
|
|
69
69
|
`window.ChitUI` を作る IIFE 版(`dist/chit-ui.iife.min.js`)もあります。npm 版と
|
|
70
70
|
単一バンドル版を同じページで混ぜると Lit が二重に読み込まれるので、どちらか一方にしてください。
|
|
71
71
|
|
|
72
|
+
### TypeScript
|
|
73
|
+
|
|
74
|
+
型はパッケージのルートから読めます。
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import type { Message, Theme, Position } from '@hidemikimura/chit-ui';
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`chit-ui` 要素と `chat-*` イベントの型も一緒に入るので、`document.querySelector('chit-ui')`
|
|
81
|
+
の戻り値や `addEventListener('chat-submit', ...)` の `detail` に型が付きます。
|
|
82
|
+
|
|
72
83
|
## 発言の中身
|
|
73
84
|
|
|
74
85
|
1 つの発言には、次の 5 つのうち **ちょうど 1 つ** を指定します。
|
|
@@ -310,6 +321,107 @@ chat.addEventListener('chat-home', (event) => {
|
|
|
310
321
|
自前のボタンを置いてください(その場合 `home: false` のままで構いません)。読み上げ名は
|
|
311
322
|
ロケールに応じて「最初に戻る」/「Back to the start」になります。
|
|
312
323
|
|
|
324
|
+
### ドラッグで動かす
|
|
325
|
+
|
|
326
|
+
ランチャー(閉じた状態)と、開いた状態のパネルを、読み手が動かせるようにできます。
|
|
327
|
+
どちらも既定は無効です。
|
|
328
|
+
|
|
329
|
+
```js
|
|
330
|
+
chat.theme = {
|
|
331
|
+
closed: { draggable: true }, // ランチャーをドラッグ
|
|
332
|
+
open: { draggable: true }, // パネルをタイトルバーでドラッグ
|
|
333
|
+
};
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
パネルの取っ手はタイトルバーです。バーの中のボタン(閉じる・ホーム)を押したときはドラッグに
|
|
337
|
+
なりません。タイトルバーを消している(`header.visible: false`)ときは掴む場所がないので
|
|
338
|
+
動かせません。スマホ幅ではパネルは全画面なので、パネルのドラッグは自動的に無効になります
|
|
339
|
+
(ランチャーは動かせます)。
|
|
340
|
+
|
|
341
|
+
矢印キーでも動かせます。ランチャーかタイトルバーにフォーカスして、矢印キーで 8px、
|
|
342
|
+
Shift と一緒なら 32px ずつです。ポインタが使えない人でも同じことができるようにするためで、
|
|
343
|
+
そのためタイトルバーは `draggable` のときだけフォーカスを受けます。
|
|
344
|
+
|
|
345
|
+
画面の外には出られません。端から 8px のところで止まります。ウィンドウの大きさが変わったときも
|
|
346
|
+
中に収まるように置き直します。
|
|
347
|
+
|
|
348
|
+
#### 閉じた状態と開いた状態は一緒に動きます
|
|
349
|
+
|
|
350
|
+
ドラッグが動かすのは「位置」ではなく「テーマの位置からどれだけずらしたか」(画面上の px)で、
|
|
351
|
+
このずれをウィジェット全体でひとつだけ持っています。そのため、
|
|
352
|
+
|
|
353
|
+
- ランチャーを動かしてから開くと、パネルも同じだけずれた位置に出ます
|
|
354
|
+
- パネルを動かしてから閉じると、ランチャーも同じだけずれた位置に戻ります
|
|
355
|
+
|
|
356
|
+
ランチャーとパネルは同じウィジェットの 2 つの姿なので、片方だけ元の場所に残るほうが不自然だと
|
|
357
|
+
考えてこうしています。それぞれの角(`closed.position` / `open.position`)や余白の違いは
|
|
358
|
+
そのまま保たれ、ずれだけが共有されます。
|
|
359
|
+
|
|
360
|
+
#### 動かした位置を覚える
|
|
361
|
+
|
|
362
|
+
ずれは `dragOffset` で読み書きできます。ページを開いている間だけ保持され、離したときに
|
|
363
|
+
`chat-move` が出ます。保存と復元は利用者側の仕事です(`localStorage` に入れるかどうかは
|
|
364
|
+
サイトの方針なので、ライブラリは決めません)。
|
|
365
|
+
|
|
366
|
+
```js
|
|
367
|
+
chat.addEventListener('chat-move', (event) => {
|
|
368
|
+
const { target, position, offset, displacement } = event.detail;
|
|
369
|
+
localStorage.setItem('chit-position', JSON.stringify(displacement));
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// 復元はずれを戻すだけ(閉じた状態・開いた状態の両方に効きます)
|
|
373
|
+
chat.dragOffset = JSON.parse(localStorage.getItem('chit-position') ?? 'null');
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
`displacement` が共有しているずれ、`offset` は実際に落ち着いた位置で、テーマと同じ意味
|
|
377
|
+
(`position` が指す角からの距離)です。`target` はどちらを掴んで動かしたかです。
|
|
378
|
+
`chat.resetPosition()`(= `chat.dragOffset = null`)でテーマの位置に戻ります。
|
|
379
|
+
|
|
380
|
+
動かしている間の位置は要素のインラインスタイルとして書かれるので、テーマよりもページ側の CSS
|
|
381
|
+
よりも優先されます。読み手が自分で動かした結果が、いちばん具体的な指定だからです。
|
|
382
|
+
|
|
383
|
+
### 応答待ちのローディング
|
|
384
|
+
|
|
385
|
+
送信してから返事が届くまでの間に出す表示です。`loading` プロパティで切り替えます。
|
|
386
|
+
|
|
387
|
+
```js
|
|
388
|
+
chat.loading = true;
|
|
389
|
+
// …サーバーとやり取り…
|
|
390
|
+
chat.loading = false;
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
`open.loading` で見た目を決めます。既定はスピナーです。入力中インジケーターと同じ三点ドットだと
|
|
394
|
+
「誰かが書いている」という意味になってしまい、サーバーの応答待ちとは違うためです。相手が人間の
|
|
395
|
+
オペレーターなら `'dots'` を選べます。
|
|
396
|
+
|
|
397
|
+
```js
|
|
398
|
+
chat.theme = {
|
|
399
|
+
open: {
|
|
400
|
+
loading: {
|
|
401
|
+
auto: true, // 送信から次の発言まで自動で出す(既定 false)
|
|
402
|
+
style: 'spinner', // 'spinner'(既定)/ 'dots' / 'text'
|
|
403
|
+
text: '回答を作成しています', // 省略すると読み上げ名だけに使われます
|
|
404
|
+
timeout: 8000, // ms。0(既定)なら自分で消します
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
};
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`auto: true` にすると、`chat-submit` が出た時点で表示し、相手側(`assistant` か `system`)の
|
|
411
|
+
発言が `messages` に増えた時点で消します。自分の発言を積んでも消えません。ストリーミングの
|
|
412
|
+
場合は空の吹き出しが現れた時点で消えます。送信をキャンセル(`preventDefault`)したときは
|
|
413
|
+
そもそも出ません。`timeout` を過ぎたら黙って引っ込むので、通信が返ってこないまま残り続ける
|
|
414
|
+
ことはありません。`chat.loading = false` でいつでも手で消せます。
|
|
415
|
+
|
|
416
|
+
入力中インジケーター(`typing`)と同じ位置に出ます。**この 2 つは同時には立ちません。**
|
|
417
|
+
`loading` を `true` にすると `typing` は `false` になり、その逆も同じです。どちらも会話の
|
|
418
|
+
同じ「間」を指していて(片方は人が書いている、もう片方はサーバーがまだ答えていない)、
|
|
419
|
+
2 つ並ぶと読み手に違いを考えさせてしまうためです。片方を `false` にしてももう片方は
|
|
420
|
+
そのままです。同じタイミングで両方に `true` を入れた場合は、後から書いたほうが残ります。
|
|
421
|
+
|
|
422
|
+
入力欄をロックするかどうかは別の話なので、必要なら `busy` も合わせて立ててください。
|
|
423
|
+
`loading` は属性にも反映されるので、ページ側の CSS から `chit-ui[loading]` で拾えます。
|
|
424
|
+
|
|
313
425
|
### 添付ボタン
|
|
314
426
|
|
|
315
427
|
`open.input.attach` を `true` にすると、入力欄の左に添付ボタンが出ます。押すとファイル選択が
|
|
@@ -450,6 +562,31 @@ chat.theme = { open: { animation: { scroll: 'instant' } } };
|
|
|
450
562
|
スクロール位置が「最下部にいない」と読めてしまい、追従そのものが止まるためです。
|
|
451
563
|
`prefers-reduced-motion` が有効な環境でも即時になります。
|
|
452
564
|
|
|
565
|
+
### スマホのキーボードと拡大
|
|
566
|
+
|
|
567
|
+
入力欄の文字は、タッチ端末では 16px を下回りません。iOS Safari はそれより小さい欄に
|
|
568
|
+
フォーカスするとページを拡大し、離れても元に戻さないためです。ウィジェット全体の文字サイズ
|
|
569
|
+
(`--chit-font-size`)は変わりません。テーマの文字が 16px より大きければそちらが使われます。
|
|
570
|
+
|
|
571
|
+
全画面表示のとき、キーボードが出ている間はパネルが見えている範囲(`visualViewport`)に
|
|
572
|
+
収まります。入力欄と直前の発言がキーボードの下に隠れず、送信後もそのまま見えます。
|
|
573
|
+
`100dvh` はブラウザの上下のバーが縮むぶんは見てくれますが、キーボードのことは知りません。
|
|
574
|
+
|
|
575
|
+
ピンチで拡大しているときは何もしません。拡大は読み手のものなので、そこで組み直して
|
|
576
|
+
文字を元の大きさに戻してしまうのは余計なお世話です。
|
|
577
|
+
|
|
578
|
+
### 後ろのページは動きません
|
|
579
|
+
|
|
580
|
+
パネルの上を指でなぞっても、後ろのページはスクロールしません。会話が画面に収まっていて
|
|
581
|
+
スクロールするものが何もないときも、タイトルバーや入力欄をなぞったときも同じです。
|
|
582
|
+
スクロールできるものがパネルの中にあれば、そちらは普段どおり動きます。
|
|
583
|
+
|
|
584
|
+
`overscroll-behavior: contain` だけでは足りません。あれが効くのは「スクロールできる箱を
|
|
585
|
+
端まで引っぱったとき」で、会話が短くて発言一覧がそもそもスクロールしない場合は箱ですらなく、
|
|
586
|
+
指の動きはそのままページに渡ってしまいます。iPhone で「チャットの後ろが動く」のはこれです。
|
|
587
|
+
そこで、指が最初に動いた向きに進める入れ子がパネルの中にあるかを見て、なければその指の動きを
|
|
588
|
+
取り消しています。2 本指(ピンチ)はそのままで、拡大は読み手のものです。
|
|
589
|
+
|
|
453
590
|
テーマの値は CSS カスタムプロパティになるので、ページ側の CSS からも上書きできます。
|
|
454
591
|
こちらが優先されます。
|
|
455
592
|
|
|
@@ -492,7 +629,8 @@ chit-ui {
|
|
|
492
629
|
| `state` | `'closed' \| 'open' \| 'hidden'` | `'closed'` | 現在の状態 |
|
|
493
630
|
| `theme` | `Theme` | `{}` | テーマ(部分指定可) |
|
|
494
631
|
| `messages` | `Message[]` | `[]` | 描画する発言 |
|
|
495
|
-
| `typing` | `boolean \| { html }` | `false` |
|
|
632
|
+
| `typing` | `boolean \| { html }` | `false` | 相手が入力中の表示。`loading` とは排他です |
|
|
633
|
+
| `loading` | `boolean` | `false` | 応答待ちの表示。`typing` とは排他で、`open.loading.auto` なら自動で切り替わります |
|
|
496
634
|
| `busy` | `boolean` | `false` | 送信中。入力をロックします |
|
|
497
635
|
| `inputDisabled` / `inputHidden` | `boolean` | `false` | 入力欄の無効化 / 非表示 |
|
|
498
636
|
| `value` | `string` | `''` | 入力欄の内容 |
|
|
@@ -506,6 +644,8 @@ chit-ui {
|
|
|
506
644
|
| `locale` | `string` | `<html lang>` | ラベルと時刻の言語 |
|
|
507
645
|
| `labels` | `Partial<Labels>` | なし | UI 文字列の上書き |
|
|
508
646
|
|
|
647
|
+
`dragOffset`(`{ x, y } | null`)はドラッグで生じたずれです。読み書きできます。
|
|
648
|
+
|
|
509
649
|
読み取り専用: `renderedState`、`device`(`'pc' \| 'mobile'`)、`hasUnseen`、`canSend`、
|
|
510
650
|
`currentTheme`、`currentLabels`、`resolvedLocale`。
|
|
511
651
|
|
|
@@ -520,6 +660,7 @@ chit-ui {
|
|
|
520
660
|
| `getMessageElement(id)` | その発言のコンテナ DOM(未描画なら `null`) |
|
|
521
661
|
| `home()` | `chat-home` を発火します(ホームボタンと同じ合図) |
|
|
522
662
|
| `openAttach()` | 添付のファイル選択を開きます(添付ボタンと同じ) |
|
|
663
|
+
| `resetPosition()` | ドラッグで動かした位置を忘れ、テーマの位置に戻します |
|
|
523
664
|
|
|
524
665
|
## イベント
|
|
525
666
|
|
|
@@ -540,6 +681,7 @@ chit-ui {
|
|
|
540
681
|
| `chat-breakpoint-change` | PC / スマホの判定が変わった | `{ device }` | |
|
|
541
682
|
| `chat-home` | ホームボタンが押された(または `home()`) | `{ trigger }` | |
|
|
542
683
|
| `chat-attach` | 添付ファイルが選ばれた | `{ files }`(`File[]`) | |
|
|
684
|
+
| `chat-move` | ドラッグまたは矢印キーで動かされた | `{ target, position, offset, displacement }` | |
|
|
543
685
|
|
|
544
686
|
`trigger` は `'user'`(クリックや Esc)か `'api'`(メソッドやプロパティ代入)です。
|
|
545
687
|
|
|
@@ -576,7 +718,7 @@ chat.addEventListener('chat-message-click', (event) => {
|
|
|
576
718
|
`home-button` `attach-button` `attach-input`
|
|
577
719
|
`header-actions` `close-button` `messages` `messages-inner` `message` `message-user`
|
|
578
720
|
`message-assistant` `message-system` `bubble` `message-content` `avatar` `name` `meta` `time`
|
|
579
|
-
`status` `cursor` `typing` `to-latest` `composer` `input` `counter` `send-button` `spinner`
|
|
721
|
+
`status` `cursor` `typing` `loading` `loading-text` `to-latest` `composer` `input` `counter` `send-button` `spinner`
|
|
580
722
|
|
|
581
723
|
パーツ名・プロパティ名・イベント名・スロット名・CSS カスタムプロパティ名は公開 API として
|
|
582
724
|
扱い、変更はメジャーバージョンでのみ行います。
|
|
@@ -615,7 +757,10 @@ npm run check # 上記をまとめて
|
|
|
615
757
|
IME の実挙動は合成イベントでは再現しきれないため、リリース前に実機で確認します。
|
|
616
758
|
|
|
617
759
|
- macOS Safari + 日本語 IME: 変換確定の Enter で誤送信しないこと
|
|
618
|
-
- iOS Safari:
|
|
760
|
+
- iOS Safari: パネルが全画面になり、キーボード表示中も入力欄が隠れないこと。
|
|
761
|
+
入力欄にフォーカスしてもページが拡大しないこと(送信後も拡大したままにならないこと)
|
|
762
|
+
- iOS Safari: パネルの上を指でなぞっても後ろのページが動かないこと。会話が短くて
|
|
763
|
+
スクロールするものが無いときも同じであること
|
|
619
764
|
- Android Chrome: 変換中の Enter で誤送信しないこと
|
|
620
765
|
- iOS Safari / Android Chrome: 添付ボタンからカメラとフォトライブラリが開けること
|
|
621
766
|
(`accept` はブラウザによって扱いが違うため)
|