@johnmorrisdotca/kumimoji 1.3.0 → 1.4.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/dist/element.js CHANGED
@@ -1,23 +1,12 @@
1
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
- };
6
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
- if (kind === "m") throw new TypeError("Private method is not writable");
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
- };
12
- var _KumimojiTable_instances, _KumimojiTable_table, _KumimojiTable_key, _KumimojiTable_queued, _KumimojiTable_seed, _KumimojiTable_options, _KumimojiTable_revision, _KumimojiTable_widthBefore, _KumimojiTable_widthOwned, _KumimojiTable_labelBefore, _KumimojiTable_write, _KumimojiTable_frame, _KumimojiTable_refresh;
13
- import { embedDay } from "./embed-day.js";
14
- import { KUMIMOJI_STYLE } from "./ui/style.js";
15
1
  import { kumimojiDailySeed } from "./daily.js";
2
+ import { embedDay } from "./embed-day.js";
16
3
  import { KUMIMOJI_HANDS } from "./tiles.constants.js";
4
+ import { isCloth } from "./ui/cloth.js";
17
5
  import { mountKumimoji } from "./ui/mount.js";
6
+ import { KUMIMOJI_STYLE } from "./ui/style.js";
18
7
  const ElementBase = typeof HTMLElement === "undefined" ? class {
19
8
  } : HTMLElement;
20
- const oneOf = (value, allowed) => (allowed.includes(value) ? value : undefined);
9
+ const oneOf = (value, allowed) => allowed.includes(value) ? value : undefined;
21
10
  const isOn = (value, fallback = false) => value === null ? fallback : !["false", "off", "no", "0"].includes(value.trim().toLowerCase());
22
11
  const HANDS = Object.values(KUMIMOJI_HANDS);
23
12
  /**
@@ -53,7 +42,24 @@ const HANDS = Object.values(KUMIMOJI_HANDS);
53
42
  * console.log(KUMIMOJI_EMBED_OPTION_KEYS.includes("saved"));
54
43
  * ```
55
44
  */
56
- export const KUMIMOJI_EMBED_OPTION_KEYS = Object.keys({ language: true, hand: true, level: true, gameLength: true, diagonals: true, seed: true, onFinish: true, onChange: true, locale: true, strings: true, theme: true, keep: true, controls: true, saved: true, onError: true });
45
+ export const KUMIMOJI_EMBED_OPTION_KEYS = Object.keys({
46
+ language: true,
47
+ hand: true,
48
+ level: true,
49
+ gameLength: true,
50
+ diagonals: true,
51
+ seed: true,
52
+ onFinish: true,
53
+ onChange: true,
54
+ locale: true,
55
+ strings: true,
56
+ theme: true,
57
+ cloth: true,
58
+ keep: true,
59
+ controls: true,
60
+ saved: true,
61
+ onError: true,
62
+ });
57
63
  /**
58
64
  * A reflected crossword table with the native table handle and saved-state getter.
59
65
  * @example
@@ -63,187 +69,349 @@ export const KUMIMOJI_EMBED_OPTION_KEYS = Object.keys({ language: true, hand: tr
63
69
  * ```
64
70
  */
65
71
  export class KumimojiTable extends ElementBase {
66
- constructor() {
67
- super(...arguments);
68
- _KumimojiTable_instances.add(this);
69
- _KumimojiTable_table.set(this, null);
70
- _KumimojiTable_key.set(this, "");
71
- _KumimojiTable_queued.set(this, false);
72
- _KumimojiTable_seed.set(this, null);
73
- _KumimojiTable_options.set(this, {});
74
- _KumimojiTable_revision.set(this, 0);
75
- _KumimojiTable_widthBefore.set(this, null);
76
- _KumimojiTable_widthOwned.set(this, false);
77
- _KumimojiTable_labelBefore.set(this, null);
78
- }
72
+ static observedAttributes = [
73
+ "language",
74
+ "hand",
75
+ "level",
76
+ "length",
77
+ "diagonals",
78
+ "seed",
79
+ "lang",
80
+ "keep",
81
+ "daily",
82
+ "controls",
83
+ "theme",
84
+ "size",
85
+ "width",
86
+ "label",
87
+ "cloth",
88
+ ];
89
+ #table = null;
90
+ #key = "";
91
+ #queued = false;
92
+ #seed = null;
93
+ #options = {};
94
+ #revision = 0;
95
+ #widthBefore = null;
96
+ #widthOwned = false;
97
+ #labelBefore = null;
79
98
  /** Native host options. Callback/presentation changes preserve the current game. */
80
- get options() { return __classPrivateFieldGet(this, _KumimojiTable_options, "f"); }
81
- set options(value) { __classPrivateFieldSet(this, _KumimojiTable_options, value ?? {}, "f"); if (this.isConnected)
82
- __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_refresh).call(this); }
99
+ get options() {
100
+ return this.#options;
101
+ }
102
+ set options(value) {
103
+ this.#options = value ?? {};
104
+ if (this.isConnected)
105
+ this.#refresh();
106
+ }
107
+ #write(name, value) {
108
+ if (value === null || value === undefined)
109
+ this.removeAttribute(name);
110
+ else
111
+ this.setAttribute(name, String(value));
112
+ }
83
113
  connectedCallback() {
84
- __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_refresh).call(this);
114
+ this.#refresh();
85
115
  }
86
116
  disconnectedCallback() {
87
- var _a;
88
- __classPrivateFieldSet(this, _KumimojiTable_revision, (_a = __classPrivateFieldGet(this, _KumimojiTable_revision, "f"), ++_a), "f");
89
- __classPrivateFieldGet(this, _KumimojiTable_table, "f")?.destroy();
90
- __classPrivateFieldSet(this, _KumimojiTable_table, null, "f");
91
- __classPrivateFieldSet(this, _KumimojiTable_key, "", "f");
117
+ ++this.#revision;
118
+ this.#table?.destroy();
119
+ this.#table = null;
120
+ this.#key = "";
92
121
  }
93
122
  attributeChangedCallback() {
94
- if (!this.isConnected || __classPrivateFieldGet(this, _KumimojiTable_queued, "f"))
123
+ if (!this.isConnected || this.#queued)
95
124
  return;
96
- __classPrivateFieldSet(this, _KumimojiTable_queued, true, "f");
125
+ this.#queued = true;
97
126
  queueMicrotask(() => {
98
- __classPrivateFieldSet(this, _KumimojiTable_queued, false, "f");
127
+ this.#queued = false;
99
128
  if (this.isConnected)
100
- __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_refresh).call(this);
129
+ this.#refresh();
101
130
  });
102
131
  }
103
132
  /** The mounted table's handle (`mountKumimoji`), or null while the attributes name no table the rules offer. */
104
133
  get table() {
105
- return __classPrivateFieldGet(this, _KumimojiTable_table, "f");
134
+ return this.#table;
106
135
  }
107
136
  /** The game as it would be saved, or null while there is none (or it is still being dealt). */
108
137
  get saved() {
109
- return __classPrivateFieldGet(this, _KumimojiTable_table, "f")?.saved() ?? null;
138
+ return this.#table?.saved() ?? null;
110
139
  }
111
140
  /** A new game at the same table: see `KumimojiTableHandle.newGame`. */
112
141
  newGame(options) {
113
- return __classPrivateFieldGet(this, _KumimojiTable_table, "f")?.newGame(options) ?? Promise.resolve();
142
+ return this.#table?.newGame(options) ?? Promise.resolve();
114
143
  }
115
144
  /** Put a game on the table: see `KumimojiTableHandle.setGame`. */
116
145
  setGame(saved) {
117
- return __classPrivateFieldGet(this, _KumimojiTable_table, "f")?.setGame(saved) ?? Promise.resolve();
146
+ return this.#table?.setGame(saved) ?? Promise.resolve();
118
147
  }
119
148
  /** The `language` attribute, reflected. */
120
- get language() { return this.getAttribute("language"); }
121
- set language(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "language", value); }
149
+ get language() {
150
+ return this.getAttribute("language");
151
+ }
152
+ set language(value) {
153
+ this.#write("language", value);
154
+ }
122
155
  /** The `hand` attribute, reflected. */
123
- get hand() { return this.getAttribute("hand"); }
124
- set hand(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "hand", value); }
156
+ get hand() {
157
+ return this.getAttribute("hand");
158
+ }
159
+ set hand(value) {
160
+ this.#write("hand", value);
161
+ }
125
162
  /** The `level` attribute, reflected. */
126
- get level() { return this.getAttribute("level"); }
127
- set level(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "level", value); }
163
+ get level() {
164
+ return this.getAttribute("level");
165
+ }
166
+ set level(value) {
167
+ this.#write("level", value);
168
+ }
128
169
  /** The `length` attribute, reflected. */
129
- get length() { return this.getAttribute("length"); }
130
- set length(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "length", value); }
170
+ get length() {
171
+ return this.getAttribute("length");
172
+ }
173
+ set length(value) {
174
+ this.#write("length", value);
175
+ }
131
176
  /** The `diagonals` attribute, reflected. */
132
- get diagonals() { return this.getAttribute("diagonals"); }
133
- set diagonals(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "diagonals", value); }
177
+ get diagonals() {
178
+ return this.getAttribute("diagonals");
179
+ }
180
+ set diagonals(value) {
181
+ this.#write("diagonals", value);
182
+ }
134
183
  /** The `seed` attribute, reflected. */
135
- get seed() { return this.getAttribute("seed"); }
136
- set seed(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "seed", value); }
184
+ get seed() {
185
+ return this.getAttribute("seed");
186
+ }
187
+ set seed(value) {
188
+ this.#write("seed", value);
189
+ }
137
190
  /** The `keep` attribute, reflected. */
138
- get keep() { return this.getAttribute("keep"); }
139
- set keep(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "keep", value); }
191
+ get keep() {
192
+ return this.getAttribute("keep");
193
+ }
194
+ set keep(value) {
195
+ this.#write("keep", value);
196
+ }
140
197
  /** The `daily` attribute, reflected. */
141
- get daily() { return this.getAttribute("daily"); }
142
- set daily(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "daily", value); }
198
+ get daily() {
199
+ return this.getAttribute("daily");
200
+ }
201
+ set daily(value) {
202
+ this.#write("daily", value);
203
+ }
143
204
  /** The `controls` attribute, reflected. */
144
- get controls() { return this.getAttribute("controls"); }
145
- set controls(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "controls", value); }
205
+ get controls() {
206
+ return this.getAttribute("controls");
207
+ }
208
+ set controls(value) {
209
+ this.#write("controls", value);
210
+ }
211
+ /** The `cloth` attribute, reflected: green, blue, red, black or wood. */
212
+ get cloth() {
213
+ return this.getAttribute("cloth");
214
+ }
215
+ set cloth(value) {
216
+ this.#write("cloth", value);
217
+ }
146
218
  /** The `theme` attribute, reflected. */
147
- get theme() { return this.getAttribute("theme"); }
148
- set theme(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "theme", value); }
219
+ get theme() {
220
+ return this.getAttribute("theme");
221
+ }
222
+ set theme(value) {
223
+ this.#write("theme", value);
224
+ }
149
225
  /** The `size` attribute, reflected. */
150
- get size() { return this.getAttribute("size"); }
151
- set size(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "size", value); }
226
+ get size() {
227
+ return this.getAttribute("size");
228
+ }
229
+ set size(value) {
230
+ this.#write("size", value);
231
+ }
152
232
  /** The `width` attribute, reflected. */
153
- get width() { return this.getAttribute("width"); }
154
- set width(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "width", value); }
233
+ get width() {
234
+ return this.getAttribute("width");
235
+ }
236
+ set width(value) {
237
+ this.#write("width", value);
238
+ }
155
239
  /** The `label` attribute, reflected. */
156
- get label() { return this.getAttribute("label"); }
157
- set label(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "label", value); }
158
- }
159
- _KumimojiTable_table = new WeakMap(), _KumimojiTable_key = new WeakMap(), _KumimojiTable_queued = new WeakMap(), _KumimojiTable_seed = new WeakMap(), _KumimojiTable_options = new WeakMap(), _KumimojiTable_revision = new WeakMap(), _KumimojiTable_widthBefore = new WeakMap(), _KumimojiTable_widthOwned = new WeakMap(), _KumimojiTable_labelBefore = new WeakMap(), _KumimojiTable_instances = new WeakSet(), _KumimojiTable_write = function _KumimojiTable_write(name, value) { if (value === null || value === undefined)
160
- this.removeAttribute(name);
161
- else
162
- this.setAttribute(name, String(value)); }, _KumimojiTable_frame = function _KumimojiTable_frame() {
163
- this.style.display = "block";
164
- this.style.maxWidth = "100%";
165
- const width = Number(this.getAttribute("width")), size = this.getAttribute("size");
166
- const pixels = this.hasAttribute("width") && width > 0 && Number.isFinite(width) ? Math.min(width, 2000) : size === "small" ? 320 : size === "medium" ? 480 : size === "large" ? 640 : null;
167
- if (pixels !== null) {
168
- if (!__classPrivateFieldGet(this, _KumimojiTable_widthOwned, "f"))
169
- __classPrivateFieldSet(this, _KumimojiTable_widthBefore, this.style.width, "f");
170
- __classPrivateFieldSet(this, _KumimojiTable_widthOwned, true, "f");
171
- this.style.width = `${pixels}px`;
172
- }
173
- else if (__classPrivateFieldGet(this, _KumimojiTable_widthOwned, "f")) {
174
- this.style.width = __classPrivateFieldGet(this, _KumimojiTable_widthBefore, "f") ?? "";
175
- __classPrivateFieldSet(this, _KumimojiTable_widthOwned, false, "f");
176
- }
177
- const theme = this.getAttribute("theme");
178
- this.style.colorScheme = theme === "light" || theme === "dark" ? theme : "light dark";
179
- this.setAttribute("data-kumimoji-embed", "");
180
- const root = this.getRootNode(), target = typeof ShadowRoot !== "undefined" && root instanceof ShadowRoot ? root : this.ownerDocument.head;
181
- if (target.querySelector("style[data-kumimoji-embed-style]") === null) {
182
- const style = this.ownerDocument.createElement("style");
183
- style.setAttribute("data-kumimoji-embed-style", "");
184
- const light = KUMIMOJI_STYLE.match(/\.km-root \{([^}]+)\}/)?.[1] ?? "";
185
- const dark = KUMIMOJI_STYLE.match(/@media \(prefers-color-scheme: dark\) \{\s*\.km-root \{([^}]+)\}/)?.[1] ?? "";
186
- style.textContent = `[data-kumimoji-embed][theme="light"] .km-root{${light}}[data-kumimoji-embed][theme="dark"] .km-root{${dark}}[data-kumimoji-embed]>.km-root{background:var(--km-panel);padding:12px;border-radius:12px}[data-kumimoji-embed] .km-controls[hidden]{display:none}`;
187
- target.append(style);
188
- }
189
- if (this.hasAttribute("label")) {
190
- __classPrivateFieldSet(this, _KumimojiTable_labelBefore, __classPrivateFieldGet(this, _KumimojiTable_labelBefore, "f") ?? { role: this.getAttribute("role"), label: this.getAttribute("aria-label") }, "f");
191
- this.setAttribute("role", "group");
192
- this.setAttribute("aria-label", this.getAttribute("label"));
193
- }
194
- else if (__classPrivateFieldGet(this, _KumimojiTable_labelBefore, "f") !== null) {
195
- for (const [name, value] of [["role", __classPrivateFieldGet(this, _KumimojiTable_labelBefore, "f").role], ["aria-label", __classPrivateFieldGet(this, _KumimojiTable_labelBefore, "f").label]]) {
196
- if (value === null)
197
- this.removeAttribute(name);
198
- else
199
- this.setAttribute(name, value);
240
+ get label() {
241
+ return this.getAttribute("label");
242
+ }
243
+ set label(value) {
244
+ this.#write("label", value);
245
+ }
246
+ #frame() {
247
+ this.style.display = "block";
248
+ this.style.maxWidth = "100%";
249
+ const width = Number(this.getAttribute("width"));
250
+ const size = this.getAttribute("size");
251
+ const pixels = this.hasAttribute("width") && width > 0 && Number.isFinite(width)
252
+ ? Math.min(width, 2000)
253
+ : size === "small"
254
+ ? 320
255
+ : size === "medium"
256
+ ? 480
257
+ : size === "large"
258
+ ? 640
259
+ : null;
260
+ if (pixels !== null) {
261
+ if (!this.#widthOwned)
262
+ this.#widthBefore = this.style.width;
263
+ this.#widthOwned = true;
264
+ this.style.width = `${pixels}px`;
200
265
  }
201
- __classPrivateFieldSet(this, _KumimojiTable_labelBefore, null, "f");
202
- }
203
- }, _KumimojiTable_refresh = function _KumimojiTable_refresh() {
204
- var _a;
205
- __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_frame).call(this);
206
- try {
207
- const language = oneOf(this.getAttribute("language"), ["english", "japanese"]) ?? __classPrivateFieldGet(this, _KumimojiTable_options, "f").language;
208
- const hand = this.hasAttribute("hand") ? Number(this.getAttribute("hand")) : __classPrivateFieldGet(this, _KumimojiTable_options, "f").hand;
209
- const level = oneOf(this.getAttribute("level"), ["easy", "medium", "hard"]) ?? __classPrivateFieldGet(this, _KumimojiTable_options, "f").level;
210
- const gameLength = oneOf(this.getAttribute("length"), ["short", "medium", "full"]) ?? __classPrivateFieldGet(this, _KumimojiTable_options, "f").gameLength;
211
- const diagonals = isOn(this.getAttribute("diagonals"), __classPrivateFieldGet(this, _KumimojiTable_options, "f").diagonals ?? false);
212
- const seedAttribute = this.getAttribute("seed"), asked = Number(seedAttribute);
213
- const day = embedDay(this.hasAttribute("daily") ? this.getAttribute("daily") : seedAttribute === "daily" ? "today" : null);
214
- const seed = day !== null ? kumimojiDailySeed(new Date(`${day}T00:00:00Z`)) : seedAttribute !== null && Number.isInteger(asked) && asked >= 0 && asked <= 0xffffffff ? asked : __classPrivateFieldGet(this, _KumimojiTable_options, "f").seed ?? (__classPrivateFieldSet(this, _KumimojiTable_seed, __classPrivateFieldGet(this, _KumimojiTable_seed, "f") ?? Math.floor(Math.random() * 2 ** 31), "f"));
215
- const lang = this.getAttribute("lang"), locale = lang === "en" || lang === "ja" ? lang : __classPrivateFieldGet(this, _KumimojiTable_options, "f").locale ?? (this.ownerDocument.documentElement.lang.toLowerCase().startsWith("ja") ? "ja" : "en");
216
- const keep = isOn(this.getAttribute("keep"), __classPrivateFieldGet(this, _KumimojiTable_options, "f").keep ?? true), controls = isOn(this.getAttribute("controls"), __classPrivateFieldGet(this, _KumimojiTable_options, "f").controls ?? true);
217
- const key = JSON.stringify([language, hand, level, gameLength, diagonals, seed, day, __classPrivateFieldGet(this, _KumimojiTable_options, "f").saved]);
218
- if (key === __classPrivateFieldGet(this, _KumimojiTable_key, "f") && __classPrivateFieldGet(this, _KumimojiTable_table, "f") !== null) {
219
- __classPrivateFieldGet(this, _KumimojiTable_table, "f").set({ locale, strings: __classPrivateFieldGet(this, _KumimojiTable_options, "f").strings, theme: __classPrivateFieldGet(this, _KumimojiTable_options, "f").theme ?? {}, keep, controls });
220
- return;
266
+ else if (this.#widthOwned) {
267
+ this.style.width = this.#widthBefore ?? "";
268
+ this.#widthOwned = false;
269
+ }
270
+ const theme = this.getAttribute("theme");
271
+ this.style.colorScheme = theme === "light" || theme === "dark" ? theme : "light dark";
272
+ this.setAttribute("data-kumimoji-embed", "");
273
+ const root = this.getRootNode();
274
+ const target = typeof ShadowRoot !== "undefined" && root instanceof ShadowRoot ? root : this.ownerDocument.head;
275
+ if (target.querySelector("style[data-kumimoji-embed-style]") === null) {
276
+ const style = this.ownerDocument.createElement("style");
277
+ style.setAttribute("data-kumimoji-embed-style", "");
278
+ const light = KUMIMOJI_STYLE.match(/\.km-root \{([^}]+)\}/)?.[1] ?? "";
279
+ const dark = KUMIMOJI_STYLE.match(/@media \(prefers-color-scheme: dark\) \{\s*\.km-root \{([^}]+)\}/)?.[1] ?? "";
280
+ style.textContent = `[data-kumimoji-embed][theme="light"] .km-root{${light}}[data-kumimoji-embed][theme="dark"] .km-root{${dark}}[data-kumimoji-embed]>.km-root{background:var(--km-panel);padding:12px;border-radius:12px}[data-kumimoji-embed] .km-controls[hidden]{display:none}`;
281
+ target.append(style);
282
+ }
283
+ if (this.hasAttribute("label")) {
284
+ this.#labelBefore ??= { role: this.getAttribute("role"), label: this.getAttribute("aria-label") };
285
+ this.setAttribute("role", "group");
286
+ this.setAttribute("aria-label", this.getAttribute("label"));
287
+ }
288
+ else if (this.#labelBefore !== null) {
289
+ for (const [name, value] of [
290
+ ["role", this.#labelBefore.role],
291
+ ["aria-label", this.#labelBefore.label],
292
+ ]) {
293
+ if (value === null)
294
+ this.removeAttribute(name);
295
+ else
296
+ this.setAttribute(name, value);
297
+ }
298
+ this.#labelBefore = null;
299
+ }
300
+ }
301
+ #refresh() {
302
+ this.#frame();
303
+ try {
304
+ const language = oneOf(this.getAttribute("language"), ["english", "japanese"]) ?? this.#options.language;
305
+ const hand = this.hasAttribute("hand") ? Number(this.getAttribute("hand")) : this.#options.hand;
306
+ const level = oneOf(this.getAttribute("level"), ["easy", "medium", "hard"]) ?? this.#options.level;
307
+ const gameLength = oneOf(this.getAttribute("length"), ["short", "medium", "full"]) ?? this.#options.gameLength;
308
+ const diagonals = isOn(this.getAttribute("diagonals"), this.#options.diagonals ?? false);
309
+ const seedAttribute = this.getAttribute("seed");
310
+ const asked = Number(seedAttribute);
311
+ const day = embedDay(this.hasAttribute("daily") ? this.getAttribute("daily") : seedAttribute === "daily" ? "today" : null);
312
+ let seed;
313
+ if (day !== null)
314
+ seed = kumimojiDailySeed(new Date(`${day}T00:00:00Z`));
315
+ else if (seedAttribute !== null && Number.isInteger(asked) && asked >= 0 && asked <= 0xffffffff)
316
+ seed = asked;
317
+ else if (this.#options.seed !== undefined && this.#options.seed !== null)
318
+ seed = this.#options.seed;
319
+ else {
320
+ let held = this.#seed;
321
+ if (held === null) {
322
+ held = Math.floor(Math.random() * 2 ** 31);
323
+ this.#seed = held;
324
+ }
325
+ seed = held;
326
+ }
327
+ const lang = this.getAttribute("lang");
328
+ const locale = lang === "en" || lang === "ja"
329
+ ? lang
330
+ : (this.#options.locale ??
331
+ (this.ownerDocument.documentElement.lang.toLowerCase().startsWith("ja") ? "ja" : "en"));
332
+ const cloth = isCloth(this.getAttribute("cloth")) ? this.getAttribute("cloth") : this.#options.cloth;
333
+ const keep = isOn(this.getAttribute("keep"), this.#options.keep ?? true);
334
+ const controls = isOn(this.getAttribute("controls"), this.#options.controls ?? true);
335
+ const key = JSON.stringify([language, hand, level, gameLength, diagonals, seed, day, this.#options.saved]);
336
+ if (key === this.#key && this.#table !== null) {
337
+ this.#table.set({
338
+ locale,
339
+ strings: this.#options.strings,
340
+ cloth,
341
+ theme: this.#options.theme ?? {},
342
+ keep,
343
+ controls,
344
+ });
345
+ return;
346
+ }
347
+ if (hand !== undefined && !HANDS.includes(hand))
348
+ throw new RangeError("Choose a hand of 3, 7 or 11 tiles.");
349
+ this.#table?.destroy();
350
+ this.#table = null;
351
+ this.#key = "";
352
+ this.replaceChildren();
353
+ const revision = ++this.#revision;
354
+ const table = mountKumimoji(this, {
355
+ ...this.#options,
356
+ language,
357
+ hand,
358
+ level,
359
+ gameLength,
360
+ diagonals,
361
+ seed,
362
+ locale,
363
+ cloth,
364
+ keep,
365
+ controls,
366
+ onChange: (saved) => {
367
+ this.dispatchEvent(new CustomEvent("kumimoji-change", {
368
+ detail: JSON.parse(JSON.stringify({ saved })),
369
+ bubbles: true,
370
+ composed: true,
371
+ }));
372
+ this.#options.onChange?.(saved);
373
+ },
374
+ onFinish: (result) => {
375
+ this.dispatchEvent(new CustomEvent("kumimoji-finish", {
376
+ detail: JSON.parse(JSON.stringify(result)),
377
+ bubbles: true,
378
+ composed: true,
379
+ }));
380
+ this.#options.onFinish?.(result);
381
+ },
382
+ onError: (error) => {
383
+ this.dispatchEvent(new CustomEvent("kumimoji-error", { detail: { message: error.message }, bubbles: true, composed: true }));
384
+ this.#options.onError?.(error);
385
+ },
386
+ });
387
+ this.#table = table;
388
+ this.#key = key;
389
+ void table.ready
390
+ .then(() => {
391
+ if (this.isConnected && revision === this.#revision && table.saved() !== null)
392
+ this.dispatchEvent(new CustomEvent("kumimoji-load", {
393
+ bubbles: true,
394
+ composed: true,
395
+ detail: { seed: table.saved().deal.seed, day },
396
+ }));
397
+ })
398
+ .catch(() => {
399
+ /* The native ready error handler reports the load failure. */
400
+ });
401
+ }
402
+ catch (error) {
403
+ this.#table?.destroy();
404
+ this.#table = null;
405
+ this.#key = "";
406
+ const message = error instanceof Error ? error.message : String(error);
407
+ const status = this.ownerDocument.createElement("p");
408
+ status.setAttribute("role", "status");
409
+ status.textContent = message;
410
+ this.replaceChildren(status);
411
+ this.dispatchEvent(new CustomEvent("kumimoji-error", { detail: { message }, bubbles: true, composed: true }));
221
412
  }
222
- if (hand !== undefined && !HANDS.includes(hand))
223
- throw new RangeError("Choose a hand of 3, 7 or 11 tiles.");
224
- __classPrivateFieldGet(this, _KumimojiTable_table, "f")?.destroy();
225
- __classPrivateFieldSet(this, _KumimojiTable_table, null, "f");
226
- __classPrivateFieldSet(this, _KumimojiTable_key, "", "f");
227
- this.replaceChildren();
228
- const revision = __classPrivateFieldSet(this, _KumimojiTable_revision, (_a = __classPrivateFieldGet(this, _KumimojiTable_revision, "f"), ++_a), "f");
229
- const table = mountKumimoji(this, { ...__classPrivateFieldGet(this, _KumimojiTable_options, "f"), language, hand, level, gameLength, diagonals, seed, locale, keep, controls, onChange: saved => { this.dispatchEvent(new CustomEvent("kumimoji-change", { detail: JSON.parse(JSON.stringify({ saved })), bubbles: true, composed: true })); __classPrivateFieldGet(this, _KumimojiTable_options, "f").onChange?.(saved); }, onFinish: result => { this.dispatchEvent(new CustomEvent("kumimoji-finish", { detail: JSON.parse(JSON.stringify(result)), bubbles: true, composed: true })); __classPrivateFieldGet(this, _KumimojiTable_options, "f").onFinish?.(result); }, onError: error => { this.dispatchEvent(new CustomEvent("kumimoji-error", { detail: { message: error.message }, bubbles: true, composed: true })); __classPrivateFieldGet(this, _KumimojiTable_options, "f").onError?.(error); } });
230
- __classPrivateFieldSet(this, _KumimojiTable_table, table, "f");
231
- __classPrivateFieldSet(this, _KumimojiTable_key, key, "f");
232
- void table.ready.then(() => { if (this.isConnected && revision === __classPrivateFieldGet(this, _KumimojiTable_revision, "f") && table.saved() !== null)
233
- this.dispatchEvent(new CustomEvent("kumimoji-load", { bubbles: true, composed: true, detail: { seed: table.saved().deal.seed, day } })); }).catch(() => { });
234
- }
235
- catch (error) {
236
- __classPrivateFieldGet(this, _KumimojiTable_table, "f")?.destroy();
237
- __classPrivateFieldSet(this, _KumimojiTable_table, null, "f");
238
- __classPrivateFieldSet(this, _KumimojiTable_key, "", "f");
239
- const message = error instanceof Error ? error.message : String(error), status = this.ownerDocument.createElement("p");
240
- status.setAttribute("role", "status");
241
- status.textContent = message;
242
- this.replaceChildren(status);
243
- this.dispatchEvent(new CustomEvent("kumimoji-error", { detail: { message }, bubbles: true, composed: true }));
244
- }
245
- };
246
- KumimojiTable.observedAttributes = ["language", "hand", "level", "length", "diagonals", "seed", "lang", "keep", "daily", "controls", "theme", "size", "width", "label"];
413
+ }
414
+ }
247
415
  /**
248
416
  * Defines the table or a subclass under a custom tag. Server-safe and idempotent.
249
417
  * @param tagName - The tag name; kumimoji-table by default.
@@ -256,6 +424,8 @@ KumimojiTable.observedAttributes = ["language", "hand", "level", "length", "diag
256
424
  * console.log(typeof defineTable);
257
425
  * ```
258
426
  */
259
- export function defineTable(tagName = "kumimoji-table", registry = typeof customElements === "undefined" ? undefined : customElements) { if (registry !== undefined && registry.get(tagName) === undefined)
260
- registry.define(tagName, tagName === "kumimoji-table" ? KumimojiTable : class extends KumimojiTable {
261
- }); }
427
+ export function defineTable(tagName = "kumimoji-table", registry = typeof customElements === "undefined" ? undefined : customElements) {
428
+ if (registry !== undefined && registry.get(tagName) === undefined)
429
+ registry.define(tagName, tagName === "kumimoji-table" ? KumimojiTable : class extends KumimojiTable {
430
+ });
431
+ }
package/dist/export.js CHANGED
@@ -1,5 +1,5 @@
1
- import { boundsOf, squareAt } from "./grid.js";
2
1
  import { generateKumimoji } from "./generate.js";
2
+ import { boundsOf, squareAt } from "./grid.js";
3
3
  import { judgeWithWords } from "./judge.js";
4
4
  import { decodeTileProgress, encodeTileProgress, isFinished, tilesLeft } from "./play.js";
5
5
  import { KUMIMOJI_STRINGS, kumimojiSay } from "./strings.js";
@@ -145,7 +145,12 @@ export async function kumimojiFromJSON(text) {
145
145
  await loadTileWords(language);
146
146
  let deal;
147
147
  try {
148
- deal = generateKumimoji(size, level, seed, { language, gameLength: gameLength, doubleSet, diagonals });
148
+ deal = generateKumimoji(size, level, seed, {
149
+ language,
150
+ gameLength: gameLength,
151
+ doubleSet,
152
+ diagonals,
153
+ });
149
154
  }
150
155
  catch {
151
156
  return null;
@@ -231,13 +236,21 @@ export function gridToText(tiles, language = "english") {
231
236
  export function kumimojiToText(saved, strings = KUMIMOJI_STRINGS.en) {
232
237
  const { deal, play } = saved;
233
238
  const words = tileWords(deal.language);
234
- const face = (tile) => (tileFace(tile).blank ? "*" : deal.language === "japanese" ? words.glyphOf(tile) : words.glyphOf(tile).toUpperCase());
235
- const lines = [kumimojiSay(strings.textTitle, { language: deal.language === "japanese" ? strings.japanese : strings.english, hand: deal.size, seed: deal.seed })];
239
+ const face = (tile) => tileFace(tile).blank ? "*" : deal.language === "japanese" ? words.glyphOf(tile) : words.glyphOf(tile).toUpperCase();
240
+ const lines = [
241
+ kumimojiSay(strings.textTitle, {
242
+ language: deal.language === "japanese" ? strings.japanese : strings.english,
243
+ hand: deal.size,
244
+ seed: deal.seed,
245
+ }),
246
+ ];
236
247
  lines.push(play.tiles.size === 0 ? strings.textEmpty : gridToText(play.tiles, deal.language));
237
248
  if (isFinished(play, judgeWithWords(play.tiles, words, { diagonals: deal.diagonals === true })))
238
249
  lines.push(strings.textFinished);
239
250
  else {
240
- lines.push(play.hand.length === 0 ? strings.textHandEmpty : kumimojiSay(strings.textHand, { tiles: play.hand.map(face).join(" ") }));
251
+ lines.push(play.hand.length === 0
252
+ ? strings.textHandEmpty
253
+ : kumimojiSay(strings.textHand, { tiles: play.hand.map(face).join(" ") }));
241
254
  lines.push(kumimojiSay(strings.textLeft, { n: tilesLeft(play) }));
242
255
  }
243
256
  lines.push(kumimojiSay(strings.textTime, { time: kumimojiClock(saved.elapsedMs) }));