packing-bingo 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -85
- package/dist/{chunk-WGZKPODU.js → chunk-Z34GMJW2.js} +190 -108
- package/dist/core.cjs +191 -108
- package/dist/core.d.cts +46 -10
- package/dist/core.d.ts +46 -10
- package/dist/core.js +3 -1
- package/dist/index.cjs +191 -108
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -1
- package/dist/packing-bingo.global.js +37 -33
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
# 持ちものビンゴ(Packing Bingo)
|
|
2
2
|
|
|
3
|
-
**修学旅行の持ち物チェックリストを、4×4
|
|
3
|
+
**修学旅行の持ち物チェックリストを、4×4(3×3や5×5などにも変えられます)のビンゴにするReactコンポーネントです。持ち物をかばんに入れるたびにマスをタップしてスタンプを押し、タテ・ヨコ・ナナメがそろうと、コンボ・ファンファーレ・花火で盛り上がります。進み具合は各自のブラウザに自動で保存されます。**
|
|
4
4
|
|
|
5
|
+
[](https://jin-hiroo.github.io/packing-bingo/)
|
|
5
6
|
[](https://www.npmjs.com/package/packing-bingo)
|
|
6
7
|
[](LICENSE)
|
|
7
8
|
[](#概要)
|
|
8
9
|
[](#api)
|
|
9
10
|
[](#単体のページ)
|
|
10
11
|
|
|
11
|
-
[クイックスタート](#クイックスタート) · [使い方の例](#使い方の例) · [API](#api) · [組み込むときの注意](#組み込むときの注意) · [Reactなしで使う](#reactなしで使う) · [English](#english) · [変更履歴](CHANGELOG.md)
|
|
12
|
+
[デモサイト](https://jin-hiroo.github.io/packing-bingo/) · [クイックスタート](#クイックスタート) · [デモコード](#デモ) · [使い方の例](#使い方の例) · [API](#api) · [組み込むときの注意](#組み込むときの注意) · [Reactなしで使う](#reactなしで使う) · [English](#english) · [変更履歴](CHANGELOG.md)
|
|
12
13
|
|
|
13
14
|
<p align="center">
|
|
14
|
-
<a href="docs/images/bingo-desktop.png"><img src="docs/images/bingo-desktop.png" alt="持ち物が並んだ4×4
|
|
15
|
+
<a href="docs/images/bingo-desktop.png"><img src="docs/images/bingo-desktop.png" alt="持ち物が並んだ4×4のビンゴカード。一番上の列に続いて、左上からのナナメの列がそろった瞬間で、大きなBINGO!の文字、「2 ライン目!」、+100の得点、紙吹雪が出ている。上の欄には8/16、2ライン、290点、2 COMBOと表示されている。" width="560"></a>
|
|
15
16
|
</p>
|
|
16
17
|
|
|
17
18
|
_2コンボで2列目がそろったところ。列に線が引かれ、BINGO!と+100が出て、紙吹雪が舞います。_
|
|
18
19
|
|
|
19
20
|
<p>
|
|
20
|
-
<a href="docs/images/phone-reach.png"><img src="docs/images/phone-reach.png" alt="
|
|
21
|
-
<a href="docs/images/phone-combo.png"><img src="docs/images/phone-combo.png" alt="スマホの画面。3回続けてタップしたところで、+20と+30、2 COMBO!と3 COMBO
|
|
21
|
+
<a href="docs/images/phone-reach.png"><img src="docs/images/phone-reach.png" alt="スマホの画面。一番上の列がそろっていて、ナナメの列を完成させる最後のマス(日焼け止め)が点線で囲まれ、リーチの札が付いて点滅している。下の1行には「リーチ! あと「日焼け止め」でビンゴ」と出ている。" height="320"></a>
|
|
22
|
+
<a href="docs/images/phone-combo.png"><img src="docs/images/phone-combo.png" alt="スマホの画面。3回続けてタップしたところで、+20と+30、2 COMBO!と3 COMBO!の表示、減っていくコンボのゲージ、新しく出た2つのリーチ!が見える。" height="320"></a>
|
|
22
23
|
<a href="docs/images/phone-perfect.png"><img src="docs/images/phone-perfect.png" alt="スマホの画面。16個すべてにスタンプを押したあと。準備完了のスタンプと、得点3,410、最大コンボ×10、10ラインのパーフェクト画面に、紙吹雪と持ち物の絵文字が降っている。" height="320"></a>
|
|
23
24
|
</p>
|
|
24
25
|
|
|
@@ -30,7 +31,8 @@ _スマホでの表示。左から、1列そろって次の列にリーチがか
|
|
|
30
31
|
|
|
31
32
|
- **タップするたびに反応があります。** スタンプ、波紋、火花、少しずつ高くなる音。2.5秒以内に続けてタップすると、コンボになります。
|
|
32
33
|
- **次の目標がいつも見えます。** あと1つで列がそろうマスは、リーチの札を付けて点滅し、下の1行にその持ち物の名前が出ます。
|
|
33
|
-
- **列がそろうたびにお祝いします。**
|
|
34
|
+
- **列がそろうたびにお祝いします。** タテ・ヨコ・ナナメの列(4×4なら10列)のどれかがそろうと、BINGO!の文字と紙吹雪が出ます。すべてそろうと、花火とスコアカードのフィナーレになります。
|
|
35
|
+
- **マスの数を選べます。** 3×3や5×5など、2×2から10×10までの正方形にできます。奇数のときは、真ん中をはじめからスタンプ済みのFREEマスにできます。[マスの数を変える](#マスの数を変える)を見てください。
|
|
34
36
|
- **得点は、そろえることへのごほうびです。** 付けたり外したりしても増えません。[得点のルール](#得点のルール)を見てください。
|
|
35
37
|
- **進み具合は自動で保存されます。** 各自のブラウザ(localStorage)に保存されるので、ページを閉じても続きから始められます。サーバーには何も送りません。
|
|
36
38
|
- **だれでも使えるように配慮しています。** マスは本物のチェックボックスなので、キーボードで操作できます。`prefers-reduced-motion`(動きを減らす設定)に従います。音は合成した音(音声ファイルなし)で、消すこともできます。
|
|
@@ -41,7 +43,7 @@ _スマホでの表示。左から、1列そろって次の列にリーチがか
|
|
|
41
43
|
| --- | --- |
|
|
42
44
|
| インストール | `npm install packing-bingo`。ESMとCommonJSの両方、TypeScriptの型付き |
|
|
43
45
|
| 必要なもの | React 18以上と `react-dom`。ほかに依存するパッケージはありません。CSSの読み込みもProviderも不要です |
|
|
44
|
-
| サイズ | 約
|
|
46
|
+
| サイズ | 約14 kB(minify・gzip後、CSS込み、Reactは含まず) |
|
|
45
47
|
| サーバー側での表示 | `"use client"` 付きで配布しています。サーバー側では空の `<div>` を出し、ブラウザでカードを作ります |
|
|
46
48
|
| 見た目 | `<head>` に `<style>` を1つ追加します。クラス名はすべて `pkb-` で始まります。CSS変数で配色を変えられ、置いた場所の幅に合わせて自動で大きさが変わります |
|
|
47
49
|
| 通信 | Google Fontsからフォントを2つ読み込みます(`fonts={false}` で止められます) |
|
|
@@ -60,68 +62,66 @@ npm install packing-bingo
|
|
|
60
62
|
|
|
61
63
|
pnpmなら `pnpm add packing-bingo`、yarnなら `yarn add packing-bingo` です。
|
|
62
64
|
|
|
63
|
-
### 2.
|
|
65
|
+
### 2. 表示したい場所に置く
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
表示したいページやコンポーネントで読み込み、置きたい場所に `<PackingBingo />` と書きます。一般的な修学旅行の持ち物16個が、4×4のカードに並びます。
|
|
66
68
|
|
|
67
69
|
```tsx
|
|
68
|
-
import { PackingBingo
|
|
69
|
-
|
|
70
|
-
// 沖縄の修学旅行の持ち物。ちょうど16個、左上から横に4つずつ並びます。
|
|
71
|
-
const items: BingoItem[] = [
|
|
72
|
-
{ emoji: "📖", label: "旅のしおり" },
|
|
73
|
-
{ emoji: "🪪", label: "生徒手帳" },
|
|
74
|
-
{ emoji: "🏥", label: "保険証コピー" },
|
|
75
|
-
{ emoji: "👛", label: "おこづかい" },
|
|
76
|
-
{ emoji: "👕", label: "着替え" },
|
|
77
|
-
{ emoji: "🩱", label: "水着" },
|
|
78
|
-
{ emoji: "🧴", label: "日焼け止め" },
|
|
79
|
-
{ emoji: "🧢", label: "帽子" },
|
|
80
|
-
{ emoji: "🕶️", label: "サングラス" },
|
|
81
|
-
{ emoji: "🩴", label: "ビーチサンダル" },
|
|
82
|
-
{ emoji: "🪥", label: "洗面用具" },
|
|
83
|
-
{ emoji: "🛁", label: "タオル" },
|
|
84
|
-
{ emoji: "💊", label: "常備薬・酔い止め" },
|
|
85
|
-
{ emoji: "☂️", label: "折りたたみ傘" },
|
|
86
|
-
{ emoji: "🛍️", label: "ビニール袋" },
|
|
87
|
-
{ emoji: "📱", label: "スマホ・充電器" },
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
export function OkinawaPackingBingo() {
|
|
91
|
-
return <PackingBingo items={items} tag="沖縄修学旅行" />;
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### 3. 表示したい場所に置く
|
|
96
|
-
|
|
97
|
-
表示したいページやコンポーネントで読み込み、置きたい場所に `<OkinawaPackingBingo />` と書きます。`import` のパスは、ファイルを置いた場所に合わせてください。
|
|
98
|
-
|
|
99
|
-
```tsx
|
|
100
|
-
import { OkinawaPackingBingo } from "./components/OkinawaPackingBingo";
|
|
70
|
+
import { PackingBingo } from "packing-bingo";
|
|
101
71
|
|
|
102
72
|
// JSXの中の、表示したい場所に
|
|
103
|
-
<
|
|
73
|
+
<PackingBingo />
|
|
104
74
|
```
|
|
105
75
|
|
|
106
76
|
Next.js(App Router)で専用のページを作るなら、`app/packing/page.tsx` を作って次を貼り付けます。`/packing` を開くと表示されます。
|
|
107
77
|
|
|
108
78
|
```tsx
|
|
109
|
-
import {
|
|
79
|
+
import { PackingBingo } from "packing-bingo";
|
|
110
80
|
|
|
111
81
|
export default function PackingPage() {
|
|
112
82
|
return (
|
|
113
83
|
<main style={{ padding: 16 }}>
|
|
114
|
-
<
|
|
84
|
+
<PackingBingo />
|
|
115
85
|
</main>
|
|
116
86
|
);
|
|
117
87
|
}
|
|
118
88
|
```
|
|
119
89
|
|
|
120
|
-
|
|
90
|
+
カードは置いた場所の幅いっぱい(最大720 px)に広がり、狭い場所ではスマホ向けの配置に自動で切り替わります。
|
|
91
|
+
|
|
92
|
+
Next.jsのServer Componentのページからでも、そのまま使えます。ただし、`onBingo` などの関数(コールバック)はServer Componentから渡せず、「Event handlers cannot be passed to Client Component props」というエラーでビルドが止まります。コールバックを使うときは、1行目に `"use client";` を書いたファイル(client component)の中に `<PackingBingo>` を置いてください。
|
|
121
93
|
|
|
122
|
-
|
|
94
|
+
### 3. 持ち物を変える
|
|
123
95
|
|
|
124
|
-
|
|
96
|
+
`items` に、持ち物を左上から横に1行ずつ並べて渡します。16個なら4×4、9個なら3×3、25個なら5×5になります([マスの数を変える](#マスの数を変える))。次のリストを書き換えて使ってください。
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { PackingBingo, type BingoItem } from "packing-bingo";
|
|
100
|
+
|
|
101
|
+
// 持ち物。16個なら、左上から横に4つずつ並びます。
|
|
102
|
+
// \u200B は「狭い画面ではここで改行してよい」という目印です(画面には出ません)。
|
|
103
|
+
const items: BingoItem[] = [
|
|
104
|
+
{ emoji: "👛", label: "財布" },
|
|
105
|
+
{ emoji: "📱", label: "スマホ" },
|
|
106
|
+
{ emoji: "🔋", label: "モバイル\u200B充電器" },
|
|
107
|
+
{ emoji: "📋", label: "健康調査票" },
|
|
108
|
+
{ emoji: "🪪", label: "マイナカード\u200Bまたは保険証" },
|
|
109
|
+
{ emoji: "📖", label: "しおり" },
|
|
110
|
+
{ emoji: "😷", label: "マスク" },
|
|
111
|
+
{ emoji: "🤧", label: "ハンカチ" },
|
|
112
|
+
{ emoji: "💊", label: "常備薬" },
|
|
113
|
+
{ emoji: "🛍️", label: "ビニール袋" },
|
|
114
|
+
{ emoji: "🧤", label: "軍手(学校支給)" },
|
|
115
|
+
{ emoji: "🔦", label: "ヘッドライト" },
|
|
116
|
+
{ emoji: "👕", label: "ジャージ" },
|
|
117
|
+
{ emoji: "☔", label: "雨具" },
|
|
118
|
+
{ emoji: "🛁", label: "タオル" },
|
|
119
|
+
{ emoji: "🧴", label: "日焼け止め" },
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
// JSXの中の、表示したい場所に
|
|
123
|
+
<PackingBingo items={items} />
|
|
124
|
+
```
|
|
125
125
|
|
|
126
126
|
### Reactを使っていないページに置く場合
|
|
127
127
|
|
|
@@ -129,24 +129,35 @@ HTMLの好きな場所に、次をそのまま貼り付けます。インスト
|
|
|
129
129
|
|
|
130
130
|
```html
|
|
131
131
|
<div id="packing-bingo"></div>
|
|
132
|
-
<script src="https://cdn.jsdelivr.net/npm/packing-bingo@0.
|
|
132
|
+
<script src="https://cdn.jsdelivr.net/npm/packing-bingo@0.3/dist/packing-bingo.global.js"></script>
|
|
133
133
|
<script>
|
|
134
134
|
PackingBingo.createPackingBingo(document.getElementById("packing-bingo"), {
|
|
135
|
-
tag: "沖縄修学旅行",
|
|
136
135
|
items: [
|
|
137
|
-
{ emoji: "
|
|
138
|
-
{ emoji: "
|
|
139
|
-
{ emoji: "
|
|
140
|
-
{ emoji: "
|
|
141
|
-
{ emoji: "
|
|
142
|
-
{ emoji: "
|
|
143
|
-
{ emoji: "
|
|
144
|
-
{ emoji: "
|
|
136
|
+
{ emoji: "👛", label: "財布" }, { emoji: "📱", label: "スマホ" },
|
|
137
|
+
{ emoji: "🔋", label: "モバイル\u200B充電器" }, { emoji: "📋", label: "健康調査票" },
|
|
138
|
+
{ emoji: "🪪", label: "マイナカード\u200Bまたは保険証" }, { emoji: "📖", label: "しおり" },
|
|
139
|
+
{ emoji: "😷", label: "マスク" }, { emoji: "🤧", label: "ハンカチ" },
|
|
140
|
+
{ emoji: "💊", label: "常備薬" }, { emoji: "🛍️", label: "ビニール袋" },
|
|
141
|
+
{ emoji: "🧤", label: "軍手(学校支給)" }, { emoji: "🔦", label: "ヘッドライト" },
|
|
142
|
+
{ emoji: "👕", label: "ジャージ" }, { emoji: "☔", label: "雨具" },
|
|
143
|
+
{ emoji: "🛁", label: "タオル" }, { emoji: "🧴", label: "日焼け止め" },
|
|
145
144
|
],
|
|
146
145
|
});
|
|
147
146
|
</script>
|
|
148
147
|
```
|
|
149
148
|
|
|
149
|
+
## デモ
|
|
150
|
+
|
|
151
|
+
- **デモサイト:** https://jin-hiroo.github.io/packing-bingo/
|
|
152
|
+
その場でタップして試せます。演出だけを自動で再生するカードと、組み込み用のコード(このREADMEのクイックスタートと同じもの)も載っています。
|
|
153
|
+
- **デモコード:** [`examples/`](examples/) に、そのまま動かせるプロジェクトがあります。フォルダごとコピーして、自分のサイトの土台にもできます。
|
|
154
|
+
|
|
155
|
+
| フォルダ | 内容 | 動かし方 |
|
|
156
|
+
| --- | --- | --- |
|
|
157
|
+
| [`examples/nextjs`](examples/nextjs) | Next.js(App Router)。クイックスタートそのままのページと、ビンゴの瞬間を受け取るページ | `npm install` → `npm run dev` |
|
|
158
|
+
| [`examples/vite-react`](examples/vite-react) | Vite + React。ふつうのReactアプリのページに置く例 | `npm install` → `npm run dev` |
|
|
159
|
+
| [`examples/html`](examples/html) | HTMLだけ。Reactもインストールも使わない例 | `index.html` をブラウザで開く |
|
|
160
|
+
|
|
150
161
|
## 使い方の例
|
|
151
162
|
|
|
152
163
|
### 持ち物と文言を変える
|
|
@@ -155,17 +166,43 @@ HTMLの好きな場所に、次をそのまま貼り付けます。インスト
|
|
|
155
166
|
import { PackingBingo, en, type BingoItem } from "packing-bingo";
|
|
156
167
|
|
|
157
168
|
const items: BingoItem[] = [
|
|
158
|
-
{ emoji: "
|
|
159
|
-
{ emoji: "
|
|
160
|
-
// …
|
|
169
|
+
{ emoji: "👛", label: "Wallet" },
|
|
170
|
+
{ emoji: "📱", label: "Phone" },
|
|
171
|
+
// … 4×4なら16個、左上から横に1行ずつ
|
|
161
172
|
];
|
|
162
173
|
|
|
163
|
-
<PackingBingo items={items} messages={en} title="
|
|
174
|
+
<PackingBingo items={items} messages={en} title="School Trip" tag="Class 2-B" />;
|
|
164
175
|
```
|
|
165
176
|
|
|
166
|
-
- `items`
|
|
177
|
+
- `items` の数で、カードの大きさが決まります。16個なら4×4、9個なら3×3、25個なら5×5です。正方形にならない数だと、`[packing-bingo] "items" must have a square number of entries` で始まるエラーになります。くわしくは[マスの数を変える](#マスの数を変える)を見てください。
|
|
167
178
|
- `messages` は日本語の既定値の上に重なるので、`messages={{ reset: "やり直す" }}` のように一部の文言だけを変えられます。`en` は英語の文言一式です。キーの一覧は[文言のキー](#文言のキー)にあります。
|
|
168
|
-
- 狭いカードでは、ラベルは `・` の後ろで折り返します。`常備薬・酔い止め` は「常備薬・」と「酔い止め」の2
|
|
179
|
+
- 狭いカードでは、ラベルは `・` の後ろで折り返します。`常備薬・酔い止め` は「常備薬・」と「酔い止め」の2行になります。`・` を入れたくない長いラベルは、`\u200B`(画面には出ない改行位置の目印)を入れた場所で折り返します。`"モバイル\u200B充電器"` は「モバイル」と「充電器」の2行になります。スマホの幅では、1行に入るのは6文字ほどです。
|
|
180
|
+
|
|
181
|
+
### マスの数を変える
|
|
182
|
+
|
|
183
|
+
`size` で1辺のマスの数を、`free` で真ん中のFREEマスを決めます。
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
// 3×3。items を渡さなければ、既定の持ち物の最初の9個を使います
|
|
187
|
+
<PackingBingo size={3} />
|
|
188
|
+
|
|
189
|
+
// 5×5で、真ん中がFREEマス。items は 5×5 − 1 = 24個
|
|
190
|
+
<PackingBingo size={5} free items={items} />
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
<p>
|
|
194
|
+
<a href="docs/images/phone-5x5-free.png"><img src="docs/images/phone-5x5-free.png" alt="スマホの画面。5×5のカードで、真ん中が赤い丸のFREEマス。左上からのナナメの列がFREEマスを通ってそろい、線が引かれている。真ん中のヨコの列は、残りの「雨具」にリーチの札が付いている。上の欄は9/24、1ライン。" height="320"></a>
|
|
195
|
+
</p>
|
|
196
|
+
|
|
197
|
+
_5×5で真ん中がFREEのカード。FREEマスを通るナナメの列は、残りの4個でそろいます。_
|
|
198
|
+
|
|
199
|
+
- `size` は2〜10です。省略すると、`items` の数から決まります(9個なら3×3、16個なら4×4、25個なら5×5。`free` のときは8個で3×3、24個で5×5)。
|
|
200
|
+
- `items` は `size` × `size` 個、`free` のときはそれより1個少なくします。左上から横に1行ずつ並び、FREEマスは飛ばします。数が合わないと、必要な数を書いたエラーになります。
|
|
201
|
+
- `items` を渡さないときに使う既定の持ち物は16個です。3×3までは最初の何個かを使いますが、5×5以上では `items` が必要です。
|
|
202
|
+
- `free` は `size` が奇数のときだけ使えます。FREEマスは最初からスタンプ済みで、タップできず、持ち物の数にも入りません。FREEマスを通る列(真ん中のタテとヨコ、2本のナナメ)は、残りの `size` − 1 個でそろいます。マスの文字は `messages` の `free` で変えられます(既定は `FREE`)。
|
|
203
|
+
- `checked`・`defaultChecked`・`onChange` の配列は、持ち物の数(FREEマスを除く)と同じ長さです。
|
|
204
|
+
- 文字やすき間は、マスの大きさに合わせて変わります。スマホの幅で読みやすいのは5×5くらいまでです。それより大きいと、ラベルが細かく折り返してマスが縦に伸びます。
|
|
205
|
+
- 持ち物リストから決まる保存のキーは、実際に並ぶ持ち物から決まります。`size={3}` だけのカードと、ふつうの4×4のカードは、別々に保存されます。
|
|
169
206
|
|
|
170
207
|
### 保存のしかたを変える
|
|
171
208
|
|
|
@@ -213,13 +250,13 @@ export function PackingCard({ studentId }: { studentId: string }) {
|
|
|
213
250
|
}
|
|
214
251
|
```
|
|
215
252
|
|
|
216
|
-
生徒のタップは通信より速いので、この例では保存を順番に送り、`studentId`
|
|
253
|
+
生徒のタップは通信より速いので、この例では保存を順番に送り、`studentId` が変わったあとに届いた読み込みは捨てています。保存のたびにすべての持ち物の状態を送るので、最後の保存がいつも最新の状態になります。
|
|
217
254
|
|
|
218
255
|
controlledのカードの動き:
|
|
219
256
|
|
|
220
|
-
-
|
|
257
|
+
- タップしただけでは、カードは変わりません。ユーザーが求めた状態(持ち物の数だけの配列)で `onChange` が呼ばれ、`checked` が変わるとカードがそれに合わせます。`checked` を変えなければ、タップは取り消されます。
|
|
221
258
|
- `checked` がちょうど1個だけ変わったときは、タップと同じように演出します(スタンプ、音、ビンゴやフィナーレ)。サーバーからデータが届いたときのように一度に何個も変わったときは、演出なしで静かに反映し、同時にそろった列のボーナスも付けません。
|
|
222
|
-
-
|
|
259
|
+
- リセットボタンを押すと、すべて `false` の配列で `onChange` が呼ばれます。
|
|
223
260
|
- `storageKey` は使われません。
|
|
224
261
|
|
|
225
262
|
### ビンゴの瞬間を受け取る
|
|
@@ -281,28 +318,30 @@ function PackingPage() {
|
|
|
281
318
|
|
|
282
319
|
| prop | 型 | 既定値 | 内容 |
|
|
283
320
|
| --- | --- | --- | --- |
|
|
284
|
-
| `items` | `readonly BingoItem[]
|
|
321
|
+
| `items` | `readonly BingoItem[]`(`size` × `size` 個。`free` のときは1個少なく) | `DEFAULT_ITEMS`(一般的な修学旅行の持ち物16個) | マスの中身。左上から横に1行ずつ、FREEマスは飛ばす:`{ emoji, label }` |
|
|
322
|
+
| `size` | `number`(2〜10) | `items` の数から決まる(既定の持ち物なら4) | 1辺のマスの数。[マスの数を変える](#マスの数を変える)を見てください |
|
|
323
|
+
| `free` | `boolean` | `false` | 真ん中をFREEマスにする。`size` が奇数のときだけ |
|
|
285
324
|
| `messages` | `Partial<Messages>` | `ja` | 画面の文言。日本語の既定値の上に重なります。英語の `en` も入っています |
|
|
286
|
-
| `title`・`tag`・`subtitle` | `string` | `messages` の値 | 見出し、その上の小さなラベル、その下の1
|
|
325
|
+
| `title`・`tag`・`subtitle` | `string` | `messages` の値 | 見出し、その上の小さなラベル、その下の1行。`subtitle` は既定では空で、表示しません |
|
|
287
326
|
| `storageKey` | `string \| null` | 持ち物から自動で決まる | 進み具合を保存するlocalStorageのキー。`null` で保存しません。controlledのときは使われません |
|
|
288
|
-
| `defaultChecked` | `readonly boolean[]
|
|
289
|
-
| `checked` | `readonly boolean[]
|
|
327
|
+
| `defaultChecked` | `readonly boolean[]`(持ち物と同じ数) | すべて `false` | uncontrolledのカードの最初の状態。保存された進み具合があれば、そちらが優先です |
|
|
328
|
+
| `checked` | `readonly boolean[]`(持ち物と同じ数) | なし | 指定するとcontrolledになります。[自分のサーバーに保存する](#自分のサーバーに保存する)を見てください |
|
|
290
329
|
| `onChange` | `(checked: boolean[]) => void` | なし | ユーザーがタップかリセットをした。controlledのときは、求められた状態 |
|
|
291
330
|
| `onBingo` | `(event: BingoEvent) => void` | なし | タップで1列以上そろった |
|
|
292
331
|
| `onPerfect` | `(event: PerfectEvent) => void` | なし | タップでカード全体がそろった |
|
|
293
332
|
| `sound` | `boolean` | `true` | 音の最初の設定。ユーザーが🔊ボタンで選ぶまで使われます |
|
|
294
333
|
| `fonts` | `boolean` | `true` | Dela Gothic OneとM PLUS Rounded 1cをGoogle Fontsから読み込む |
|
|
295
|
-
| `demo` | `boolean` | `false` | デモ用のボタンを出します。保存された進み具合も `defaultChecked`
|
|
334
|
+
| `demo` | `boolean` | `false` | デモ用のボタンを出します。保存された進み具合も `defaultChecked` もなければ、一番上の列と、左上からのナナメの途中までが埋まった状態(4×4なら6マス)から始めます。`storageKey` を指定しない限り保存しません |
|
|
296
335
|
| `className`・`style` | | なし | 外側の `<div>` に付きます |
|
|
297
336
|
| `ref` | `Ref<PackingBingoHandle>` | なし | [ref](#ref) を見てください |
|
|
298
337
|
|
|
299
|
-
propsは中身で比べるので、配列やオブジェクトをその場で書いても構いません。`items`・`title`・`tag`・`subtitle`・`storageKey`・`sound`・`fonts`・`demo`、または `messages` の文字列が変わると、カードを作り直します。保存先のキーが変わらなければ、チェックはそのまま残ります。キーが変わったとき(`items` を変えて自動のキーが変わったときも含む)は、新しいキーに保存された進み具合を読み込みます。得点は[得点のルール](#得点のルール)のとおり計算し直します。`messages` の関数はpropsやstateを使っても構いません。`messages` が変わると、作り直さずに下の1行だけを描き直します。
|
|
338
|
+
propsは中身で比べるので、配列やオブジェクトをその場で書いても構いません。`items`・`size`・`free`・`title`・`tag`・`subtitle`・`storageKey`・`sound`・`fonts`・`demo`、または `messages` の文字列が変わると、カードを作り直します。保存先のキーが変わらなければ、チェックはそのまま残ります。キーが変わったとき(`items` を変えて自動のキーが変わったときも含む)は、新しいキーに保存された進み具合を読み込みます。得点は[得点のルール](#得点のルール)のとおり計算し直します。`messages` の関数はpropsやstateを使っても構いません。`messages` が変わると、作り直さずに下の1行だけを描き直します。
|
|
300
339
|
|
|
301
340
|
### イベント
|
|
302
341
|
|
|
303
342
|
```ts
|
|
304
343
|
interface BingoEvent {
|
|
305
|
-
newLines: number[]; // このタップでそろった列(LINES
|
|
344
|
+
newLines: number[]; // このタップでそろった列(bingoLines(size, free) の番号。4×4ならLINESと同じ)
|
|
306
345
|
totalLines: number; // これまでにそろった列の数
|
|
307
346
|
score: number; // このタップのあとの得点
|
|
308
347
|
}
|
|
@@ -326,15 +365,17 @@ interface PackingBingoHandle {
|
|
|
326
365
|
}
|
|
327
366
|
|
|
328
367
|
interface PackingBingoState {
|
|
329
|
-
checked: boolean[]; //
|
|
330
|
-
lines: number[]; // そろった列(
|
|
368
|
+
checked: boolean[]; // 持ち物ごと、左上から横に1行ずつ(FREEマスは含まない)
|
|
369
|
+
lines: number[]; // そろった列(bingoLines(size, free) の番号)
|
|
331
370
|
score: number;
|
|
332
371
|
maxCombo: number;
|
|
333
|
-
complete: boolean; //
|
|
372
|
+
complete: boolean; // すべての持ち物にチェックが付いている
|
|
373
|
+
size: number; // 1辺のマスの数
|
|
374
|
+
free: boolean; // 真ん中がFREEマスか
|
|
334
375
|
}
|
|
335
376
|
```
|
|
336
377
|
|
|
337
|
-
`LINES` もexportしています。0〜3がヨコの列、4〜7がタテの列、8が左上からのナナメ、9
|
|
378
|
+
`LINES` もexportしています。4×4のカードの列で、0〜3がヨコの列、4〜7がタテの列、8が左上からのナナメ、9が右上からのナナメです。ほかの大きさの列は `bingoLines(size, free)` で取れます。並び方は同じで、ヨコの列、タテの列、左上からのナナメ、右上からのナナメの順です。中身は `checked` と同じ持ち物の番号なので、`free` のときは真ん中を通る列だけ `size` − 1 個になります。
|
|
338
379
|
|
|
339
380
|
### 得点のルール
|
|
340
381
|
|
|
@@ -348,12 +389,14 @@ interface PackingBingoState {
|
|
|
348
389
|
|
|
349
390
|
`messages` には、次のキーを好きなだけ指定できます。日本語と英語の一式は、[`src/messages.ts`](src/messages.ts) の `ja` と `en` です。
|
|
350
391
|
|
|
351
|
-
- **文字列:** `title`、`tag`、`subtitle`、`packed`、`bingo`、`score`、`reset`、`soundOn`、`soundOff`、`stamp`、`reachBadge`、`reachPop`、`bannerSingle`、`bannerDouble`、`bannerTriple`、`statusDone`、`perfectTag`、`perfectStamp`、`perfectTitle`、`perfectBody`、`statScore`、`statCombo`、`statLines`、`close`、`demoLabel`、`demoBingo`、`demoPerfect`、`demoRestore`。`perfectStamp` と `perfectBody` では、`\n` で改行します。
|
|
392
|
+
- **文字列:** `title`、`tag`、`subtitle`、`packed`、`bingo`、`score`、`reset`、`soundOn`、`soundOff`、`stamp`、`free`、`reachBadge`、`reachPop`、`bannerSingle`、`bannerDouble`、`bannerTriple`、`statusDone`、`perfectTag`、`perfectStamp`、`perfectTitle`、`perfectBody`、`statScore`、`statCombo`、`statLines`、`close`、`demoLabel`、`demoBingo`、`demoPerfect`、`demoRestore`。`perfectStamp` と `perfectBody` では、`\n` で改行します。
|
|
352
393
|
- **関数(どれも文字列を返します):** `combo(n)`、`comboPop(n)`、`bannerNth(totalLines)`、`bannerMulti(newLines)`、`statusStart(left)`、`statusLines(lines, left)`、`statusReach(labels)`、`perfectBonus(points)`。
|
|
394
|
+
- `perfectBody` は、文字列のほかに、持ち物の数を受け取る関数 `perfectBody(total)` にもできます。`ja` と `en` では関数で、「16こ ぜんぶそろった!」の数がカードに合わせて変わります。
|
|
395
|
+
- `subtitle`(見出しの下の1行)と `statusStart(left)`(1列もそろう前の下の1行)は、`ja` と `en` のどちらでも空なので、表示しません。出したいときは `subtitle="タップでスタンプ。タテ・ヨコ・ナナメでビンゴ!"` や `` messages={{ statusStart: (left) => `のこり ${left} こ` }} `` のように指定します。
|
|
353
396
|
|
|
354
397
|
### export
|
|
355
398
|
|
|
356
|
-
- `packing-bingo`:`PackingBingo`、`createPackingBingo`、`LINES`、`DEFAULT_ITEMS`、`ja`、`en`。型は `PackingBingoProps`、`PackingBingoHandle`、`PackingBingoState`、`BingoItem`、`BingoEvent`、`PerfectEvent`、`Messages`、`PackingBingoOptions`、`PackingBingoInstance`。
|
|
399
|
+
- `packing-bingo`:`PackingBingo`、`createPackingBingo`、`LINES`、`bingoLines`、`DEFAULT_ITEMS`、`ja`、`en`。型は `PackingBingoProps`、`PackingBingoHandle`、`PackingBingoState`、`BingoItem`、`BingoEvent`、`PerfectEvent`、`Messages`、`PackingBingoOptions`、`PackingBingoInstance`。
|
|
357
400
|
- `packing-bingo/core`:Reactのコンポーネントとその型(`PackingBingoProps`、`PackingBingoHandle`)を除いた残り。Reactを読み込みません。
|
|
358
401
|
|
|
359
402
|
## 組み込むときの注意
|
|
@@ -378,7 +421,7 @@ Dela Gothic OneとM PLUS Rounded 1cを使います。`fonts={false}` にする
|
|
|
378
421
|
|
|
379
422
|
### 保存されるデータ
|
|
380
423
|
|
|
381
|
-
|
|
424
|
+
チェックは、持ち物の数(4×4なら16個。FREEマスは含みません)だけの真偽値のJSON配列として、localStorageに保存されます。キーは `storageKey`、指定しなければ `packing-bingo:` で始まる、持ち物リストから決まるキーです。得点は保存しません。保存された進み具合は `defaultChecked` より優先されます。プライベートブラウズなどで保存できない環境では、保存せずにそのまま動きます。
|
|
382
425
|
|
|
383
426
|
### アクセシビリティ
|
|
384
427
|
|
|
@@ -407,7 +450,7 @@ CSSのコンテナクエリ(Chrome・Edge 105以上、Safari 16以上、Firefo
|
|
|
407
450
|
import { createPackingBingo } from "packing-bingo/core";
|
|
408
451
|
|
|
409
452
|
const card = createPackingBingo(document.getElementById("bingo")!, {
|
|
410
|
-
tag: "
|
|
453
|
+
tag: "2年B組",
|
|
411
454
|
onBingo: (e) => console.log(e),
|
|
412
455
|
});
|
|
413
456
|
// card.reset()、card.getState()、card.setChecked(next, { animate: true })、card.destroy()
|
|
@@ -427,7 +470,7 @@ cd packing-bingo
|
|
|
427
470
|
open index.html # macOSの場合。ほかのOSでは、ファイルをブラウザで開いてください
|
|
428
471
|
```
|
|
429
472
|
|
|
430
|
-
URLの末尾に `?demo` を付けると、途中まで埋まった状態から始まり、デモ用のボタンが出ます。「▶ ビンゴを見る」でビンゴを、「▶ コンボ →
|
|
473
|
+
URLの末尾に `?demo` を付けると、途中まで埋まった状態から始まり、デモ用のボタンが出ます。「▶ ビンゴを見る」でビンゴを、「▶ コンボ → パーフェクト」でコンボからパーフェクトまでを再生します。デモサイトの [standalone.html](https://jin-hiroo.github.io/packing-bingo/standalone.html) でも同じページを公開しています。
|
|
431
474
|
|
|
432
475
|
ページの中身を変えるときは、最後の `<script>` にある `PackingBingo.createPackingBingo(…)` のオプションを書き換えます。どのビルドでも使われる既定値を変えるときは、`src/items.ts` か `src/messages.ts` を編集して `npm run build` を実行します。
|
|
433
476
|
|
|
@@ -441,9 +484,11 @@ npm run typecheck
|
|
|
441
484
|
|
|
442
485
|
`index.html` は `scripts/build-standalone.mjs` が `src/` から作るので、直接編集しないでください。
|
|
443
486
|
|
|
487
|
+
デモサイトは `site/index.html` です。`node scripts/build-site.mjs` を実行すると、`_site/` にデモサイトができます。そのとき、組み込み用のコードはこのREADMEのクイックスタートから差し込まれるので、READMEとデモサイトのコードはいつも同じになります。`main` に変更が入ると、GitHub Actions(`.github/workflows/pages.yml`)がビルドしてGitHub Pagesに公開し直します。
|
|
488
|
+
|
|
444
489
|
## English
|
|
445
490
|
|
|
446
|
-
Packing Bingo is a React component that turns a school-trip packing checklist into a
|
|
491
|
+
Packing Bingo is a React component that turns a school-trip packing checklist into a bingo card, with combos, fanfares and fireworks. Cards are 4×4 by default; `size` makes them anything from 2×2 to 10×10, and `free` puts a FREE square in the center of an odd-sized card. Progress is saved in each student's browser automatically. It has no runtime dependencies and is safe to render on the server (it ships with `"use client"`).
|
|
447
492
|
|
|
448
493
|
```sh
|
|
449
494
|
npm install packing-bingo
|
|
@@ -455,7 +500,7 @@ import { PackingBingo, en } from "packing-bingo";
|
|
|
455
500
|
<PackingBingo messages={en} />;
|
|
456
501
|
```
|
|
457
502
|
|
|
458
|
-
The default UI text is Japanese; `en` is a complete English set. Pass
|
|
503
|
+
Try it on the [demo site](https://jin-hiroo.github.io/packing-bingo/); runnable example projects (Next.js, Vite + React, plain HTML) are in [`examples/`](examples/). The default UI text is Japanese; `en` is a complete English set. Pass your own `items` (`{ emoji, label }`, row by row): 16 for 4×4, size² in general, or size² − 1 with `free` (the FREE square is skipped, also in `checked`). Without `size`, the number of items sets it. `bingoLines(size, free)` gives the winning lines as item indices. The sections above cover the props, events and integration notes; the code snippets and type names can be read as they are.
|
|
459
504
|
|
|
460
505
|
## ライセンス
|
|
461
506
|
|