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