@johnmorrisdotca/dougu-sports 0.7.2 → 0.8.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/CHANGELOG.md +26 -0
- package/NOTICE.md +1 -1
- package/README.md +6 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/turn-control.d.ts +24 -5
- package/dist/turn-control.js +67 -23
- package/dist/turn-full.d.ts +15 -0
- package/dist/turn-full.js +19 -0
- package/dist/turn-registry.d.ts +1 -0
- package/dist/turn-registry.js +3 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,32 @@ All notable changes to this project are written here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.8.0] - 2026-10-14
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`bindTurn` takes an emblem object and is light.** `bindTurn(element, TROPHY_HOCKEY_CUP, options)` draws and turns the emblem it is given with its own `frame` and imports neither a drawing nor the registry, so a bundle of `bindTurn` and one cup is about 9.4 kB gzipped (the turning is about 2.5 kB of it), where it was about 81 kB. `test/size.test.ts` holds it to 10 kB, and the other emblems stay tree-shakeable.
|
|
14
|
+
- **`ready`** on the controller `bindTurn` returns: a promise that resolves when the emblem is drawn and bound (already, for an emblem object) and rejects for an id that names nothing.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **`bindTurn` of `./turn` loads the registry only for an id.** An id (`"trophy:tennis-cup"`) is read from the registry, which `bindTurn` now imports on demand (a dynamic import, a chunk of its own in a bundler) instead of at the top. The first id bound is drawn when `ready` resolves, not before; later ones at once. `bindTurn` of the main entry (`@johnmorrisdotca/dougu-sports`) has the registry already and draws an id at once, as before. New modules: `src/turn-registry.ts` (what is loaded) and `src/turn-full.ts` (the main entry's `bindTurn`).
|
|
19
|
+
|
|
20
|
+
## [0.7.3] - 2026-10-14
|
|
21
|
+
|
|
22
|
+
The repository's own tooling is TypeScript. No change to the package: the same files are published, and the pictures are byte for byte the same.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **The scripts, the browser tests, the test helpers and the demo's source are `.ts`.** `scripts/*.ts` (build, gallery, package check, README examples, release notes, contact sheets, the pictures script, the demo's server and page maker), `e2e/*.demo.ts`, `playwright.config.ts` and `test/pieces-gallery.test.ts` were `.mjs` or `.js`. They run with Node's own type stripping, with no `tsx` and no build step, so `package.json`'s scripts call the `.ts` files directly. The shared family files stay as they are, byte for byte: `scripts/family-template.mjs` and `scripts/family-readme.mjs` (plain JavaScript, with the types of the template written by hand in `scripts/family-template.d.mts`) and `scripts/family-backgrounds.ts`.
|
|
27
|
+
- **`pnpm typecheck` checks all of it.** `tsconfig.check.json` covers `src` and `test`, the new `tsconfig.tools.json` covers `scripts`, `e2e` and the Playwright config (with the browser's types, since the tests and the pictures script run code in the page), and the new `tsconfig.demo.json` covers `demo`. The syntax is the erasable kind only (`erasableSyntaxOnly` was already on), with `import type` and `.ts` extensions.
|
|
28
|
+
- **The demo's scripts are `demo/*.ts`, built with esbuild.** A browser cannot run TypeScript, so `scripts/page.ts` builds each one into `demo.js`, `compose.js` and `gallery.js` for the dev server (on each request) and for `pnpm site`. A script imports the package from `../src/index.ts`, so that it is type-checked against the real source; the build changes that one import to `./dist/index.js`, the built package, as before. The page is the same.
|
|
29
|
+
- **Node.** Working on the repository needs Node 22.18 or later (where type stripping is on by default); CI already runs 22 and 24. `engines` stays `>=22`, because the published package is plain JavaScript and needs no more. `CONTRIBUTING.md` says so.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **The belts note counted the two-colour pairs wrong.** `docs/japanese-sports.md` and `docs/japanese-sports.ja.md` said the IJF names "these four pairs" under a table of five. The IJF's page names four (white-yellow, yellow-orange, orange-green, green-blue); blue-brown is drawn for completeness and no source found names it. Both pages now say that.
|
|
34
|
+
|
|
9
35
|
## [0.7.2] - 2026-10-14
|
|
10
36
|
|
|
11
37
|
The docs are one language to a page. No change to the pictures; the only change to the package is one English description.
|
package/NOTICE.md
CHANGED
|
@@ -72,4 +72,4 @@ Facts only: a dimension or a mass is a fact, not a work. The NHL's puck rule was
|
|
|
72
72
|
| What | Made from | Terms |
|
|
73
73
|
| --- | --- | --- |
|
|
74
74
|
| The demo's page | Written for this package, with the family stylesheet `demo/family.css` | MIT |
|
|
75
|
-
| The README's pictures (`docs/images`) | Taken by `scripts/screenshots.
|
|
75
|
+
| The README's pictures (`docs/images`) | Taken by `scripts/screenshots.ts` from the demo, which draws the package's own emblems | MIT |
|
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ The alias is a name in your `package.json` only: the same package, the same code
|
|
|
137
137
|
| --- | --- |
|
|
138
138
|
| `@johnmorrisdotca/dougu-sports` | The full registry: every emblem by id, the functions, and each emblem as a constant |
|
|
139
139
|
| `@johnmorrisdotca/dougu-sports/emblems` | `renderEmblem`, the ids and the types, with no single drawing imported by name |
|
|
140
|
-
| `@johnmorrisdotca/dougu-sports/turn` | `emblemFrame`, `ballFrame` and `bindTurn` |
|
|
140
|
+
| `@johnmorrisdotca/dougu-sports/turn` | `emblemFrame`, `ballFrame` and `bindTurn`; `bindTurn` with an emblem object takes nothing else with it |
|
|
141
141
|
| `@johnmorrisdotca/dougu-sports/<group>/<name>` | One emblem, alone: `trophy/hockey-cup`, `medal/gold`, `crest/shield`, `sport/nhl`, `award/crown`, `ball/soccer`, `pennant/championship`, `gear/<name>` |
|
|
142
142
|
|
|
143
143
|
### One emblem and nothing else
|
|
@@ -379,12 +379,13 @@ Both are one SVG string in the page's text colour, with a title and a descriptio
|
|
|
379
379
|
|
|
380
380
|
```js no-run
|
|
381
381
|
import { bindTurn } from "@johnmorrisdotca/dougu-sports/turn";
|
|
382
|
+
import { TROPHY_TENNIS_CUP } from "@johnmorrisdotca/dougu-sports/trophy/tennis-cup";
|
|
382
383
|
|
|
383
|
-
const turner = bindTurn(document.getElementById("cup"),
|
|
384
|
+
const turner = bindTurn(document.getElementById("cup"), TROPHY_TENNIS_CUP, { size: 160, speed: 36 });
|
|
384
385
|
document.getElementById("spin").onclick = () => turner.togglePlay();
|
|
385
386
|
```
|
|
386
387
|
|
|
387
|
-
A drag turns it, the arrow keys turn it, Space starts and stops an auto-turn, and nothing moves until you ask;
|
|
388
|
+
A drag turns it, the arrow keys turn it, Space starts and stops an auto-turn, and nothing moves until you ask. Pass the emblem itself and the page carries the turning and that one emblem and nothing else (a cup and the turning are about 9 kB gzipped); pass an id, `"trophy:tennis-cup"`, and the registry is loaded when it is needed. See [docs/turning.md](./docs/turning.md).
|
|
388
389
|
|
|
389
390
|
### In React, Vue and the rest
|
|
390
391
|
|
|
@@ -434,7 +435,7 @@ The thirty-eight sports the ball, gear and sport emblems are made for are `SPORT
|
|
|
434
435
|
| `sportIcon(sport, options?)` | The pictogram of a sport, by the names of `SPORT_NAMES`; an unknown sport is an error |
|
|
435
436
|
| `lineup(ids, options?)` | Several balls side by side, at their true relative sizes (or all as large as the largest) |
|
|
436
437
|
| `emblemFrame(ref, options?)` | An emblem turned by `yaw` and `pitch` degrees (and `roll` for a ball) |
|
|
437
|
-
| `bindTurn(element, ref, options?)` | Draws an emblem into an element and lets a drag, the arrow keys, Space or a clock turn it; returns a controller with `angles`, `playing`, `turnable`, `setAngles`, `update`, `play`, `pause`, `togglePlay` and `destroy` |
|
|
438
|
+
| `bindTurn(element, ref, options?)` | Draws an emblem (the emblem itself, or its id) into an element and lets a drag, the arrow keys, Space or a clock turn it; returns a controller with `angles`, `playing`, `turnable`, `ready`, `setAngles`, `update`, `play`, `pause`, `togglePlay` and `destroy` |
|
|
438
439
|
| `emblemDataUri(ref, options?)` | An emblem as a `data:image/svg+xml;utf8,…` address for an `<img>`, a CSS background or a canvas, with the ink made a colour (`color`, or the theme's) |
|
|
439
440
|
| `emblemSprite(ids, options?)` | A hidden sheet of `<symbol>`s with unique ids, and `use(id, { size, class, title })` for the markup of each use |
|
|
440
441
|
| `sportEquipment(sport)` | The ball, gear, trophy and medal of a sport, as ids of the registry |
|
|
@@ -604,7 +605,7 @@ Bug reports and ideas go in the [issues](https://github.com/johnmorrisdotca/doug
|
|
|
604
605
|
|
|
605
606
|
## Changes
|
|
606
607
|
|
|
607
|
-
See [CHANGELOG.md](./CHANGELOG.md). 0.7.2 makes every docs page single-language (a page in Japanese beside each page that had Japanese words in it, and a test that holds them apart), with no change to the pictures; 0.7.1 puts real countries (Canada, Japan) in the crest and puck examples in place of made-up teams, with no change to the code; 0.7.0 gives the national volleyballs layouts that tell them apart (Japan a crimson band, Poland white above and red below, the USA a navy field), strengthens the 2010-style grooved soccer ball, and adds six pictures of how the judo belt is tied, `gear:obi-step-1` to `gear:obi-step-6` (269 emblems: [docs/obi-steps.md](./docs/obi-steps.md)); 0.6.0 gives the judo suit and the karate suit their sleeves (a judogi has no short ones: they reach the wrist) and adds the judogi seen from behind with the IJF-style back number, a family name and a country code on a patch, with a `backnumber` option (269 emblems: [docs/judogi-back.md](./docs/judogi-back.md)); 0.5.1 redraws the judo suit, the belt and the football pictograms and adds the blue and folded suits and the belts of every grade (261 emblems: [docs/japanese-sports.md](./docs/japanese-sports.md)); 0.5.0 adds fifty balls: vintage leather soccer balls, era-style and shop-wall soccer balls, baseballs of other threads and volleyballs in national colours, with a `colors` option (244 emblems: [docs/vintage-balls.md](./docs/vintage-balls.md)); 0.4.0 adds eight printed pucks and a `face` option (194 emblems: [docs/pucks.md](./docs/pucks.md)); 0.3.0 adds nineteen soccer balls (26, 18, 14, 12 and 6 panels, winter orange and high-visibility yellow, futsal and beach soccer: 186 emblems); 0.2.1 draws every ball and implement to the rulebook's proportions; 0.2.0 is 167 emblems, every one drawn here, with the Japanese sports, engraving, a turn for every emblem and the compose helpers; 0.1.0 brought the first full set of 148; 0.0.1 was the first preview.
|
|
608
|
+
See [CHANGELOG.md](./CHANGELOG.md). 0.8.0 makes `bindTurn` light: it takes an emblem object and then needs no registry, so a turnable cup is about 9.4 kB gzipped instead of about 81 kB, and an id loads the registry on demand; 0.7.3 turns the build, docs and picture scripts, the browser tests and the demo's source from JavaScript into TypeScript, with no change to the package; 0.7.2 makes every docs page single-language (a page in Japanese beside each page that had Japanese words in it, and a test that holds them apart), with no change to the pictures; 0.7.1 puts real countries (Canada, Japan) in the crest and puck examples in place of made-up teams, with no change to the code; 0.7.0 gives the national volleyballs layouts that tell them apart (Japan a crimson band, Poland white above and red below, the USA a navy field), strengthens the 2010-style grooved soccer ball, and adds six pictures of how the judo belt is tied, `gear:obi-step-1` to `gear:obi-step-6` (269 emblems: [docs/obi-steps.md](./docs/obi-steps.md)); 0.6.0 gives the judo suit and the karate suit their sleeves (a judogi has no short ones: they reach the wrist) and adds the judogi seen from behind with the IJF-style back number, a family name and a country code on a patch, with a `backnumber` option (269 emblems: [docs/judogi-back.md](./docs/judogi-back.md)); 0.5.1 redraws the judo suit, the belt and the football pictograms and adds the blue and folded suits and the belts of every grade (261 emblems: [docs/japanese-sports.md](./docs/japanese-sports.md)); 0.5.0 adds fifty balls: vintage leather soccer balls, era-style and shop-wall soccer balls, baseballs of other threads and volleyballs in national colours, with a `colors` option (244 emblems: [docs/vintage-balls.md](./docs/vintage-balls.md)); 0.4.0 adds eight printed pucks and a `face` option (194 emblems: [docs/pucks.md](./docs/pucks.md)); 0.3.0 adds nineteen soccer balls (26, 18, 14, 12 and 6 panels, winter orange and high-visibility yellow, futsal and beach soccer: 186 emblems); 0.2.1 draws every ball and implement to the rulebook's proportions; 0.2.0 is 167 emblems, every one drawn here, with the Japanese sports, engraving, a turn for every emblem and the compose helpers; 0.1.0 brought the first full set of 148; 0.0.1 was the first preview.
|
|
608
609
|
|
|
609
610
|
## Credits
|
|
610
611
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "./emblems-entry.ts";
|
|
2
2
|
export { ballFrame, emblemFrame } from "./emblems/emblem.api.ts";
|
|
3
|
-
export { bindTurn } from "./turn-
|
|
3
|
+
export { bindTurn } from "./turn-full.ts";
|
|
4
4
|
export type { TurnAngles, TurnContainer, TurnControlOptions, TurnController, TurnEvent } from "./turn-control.ts";
|
|
5
5
|
export { EMBLEM_TABLE } from "./emblems/emblem.registry.ts";
|
|
6
6
|
export { AWARD_MEDAL } from "./emblems/award/medal.ts";
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// its own module (`@johnmorrisdotca/dougu-sports/trophy/hockey-cup`), and for the functions alone `@johnmorrisdotca/dougu-sports/emblems`.
|
|
3
3
|
export * from "./emblems-entry.js";
|
|
4
4
|
export { ballFrame, emblemFrame } from "./emblems/emblem.api.js";
|
|
5
|
-
export { bindTurn } from "./turn-
|
|
5
|
+
export { bindTurn } from "./turn-full.js";
|
|
6
6
|
export { EMBLEM_TABLE } from "./emblems/emblem.registry.js";
|
|
7
7
|
export { AWARD_MEDAL } from "./emblems/award/medal.js";
|
|
8
8
|
export { AWARD_BADGE } from "./emblems/award/badge.js";
|
package/dist/turn-control.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { FrameOptions } from "./emblems/emblem.core.ts";
|
|
1
|
+
import type { EmblemRef } from "./emblems/emblem.api.ts";
|
|
2
|
+
import type { Emblem, FrameOptions } from "./emblems/emblem.core.ts";
|
|
3
|
+
/** What reading an id needs of the registry: `emblemOf`, `renderEmblem` and `emblemFrame` of `emblem.api`. The main entry hands them to `bindTurn` itself; `./turn` loads them when an id is bound. */
|
|
4
|
+
export interface TurnRegistry {
|
|
5
|
+
emblemOf(ref: EmblemRef): {
|
|
6
|
+
emblem: Emblem;
|
|
7
|
+
};
|
|
8
|
+
renderEmblem(ref: EmblemRef, options?: FrameOptions): string;
|
|
9
|
+
emblemFrame(ref: EmblemRef, options?: FrameOptions): string;
|
|
10
|
+
}
|
|
3
11
|
/** The three angles of a turn, in degrees. */
|
|
4
12
|
export interface TurnAngles {
|
|
5
13
|
/** About the vertical axis, from -180 (excluded) to 180. */
|
|
@@ -37,8 +45,13 @@ export interface TurnController {
|
|
|
37
45
|
readonly angles: TurnAngles;
|
|
38
46
|
/** Whether the auto-turn is running. */
|
|
39
47
|
readonly playing: boolean;
|
|
40
|
-
/** Whether the emblem now drawn can be turned at all (read from the
|
|
48
|
+
/** Whether the emblem now drawn can be turned at all (read from the emblem's own frames, so an emblem that gains a turn is turnable here without a change). `false` until an id has loaded; see `ready`. */
|
|
41
49
|
readonly turnable: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Resolves when the emblem is drawn and bound. At once (already resolved) for an emblem object, and for an id from the main entry or once the registry has loaded; otherwise after the registry's chunk has loaded.
|
|
52
|
+
* Rejects for an id that names no emblem.
|
|
53
|
+
*/
|
|
54
|
+
readonly ready: Promise<void>;
|
|
42
55
|
/** Sets some of the angles (wrapped or clamped as a drag would) and draws. Pauses the auto-turn when `pauseOnInteract` is on. */
|
|
43
56
|
setAngles(angles: Partial<TurnAngles>): void;
|
|
44
57
|
/** Draws another emblem, or the same one with other options, and keeps the angles (unless the options carry some). */
|
|
@@ -86,16 +99,22 @@ export interface TurnContainer {
|
|
|
86
99
|
/** An angle wrapped into -180 (excluded) to 180, as the demo's slider is. */
|
|
87
100
|
export declare function wrapAngle(value: number): number;
|
|
88
101
|
/**
|
|
89
|
-
* Binds an emblem to an element so that it can be turned: it draws `
|
|
102
|
+
* Binds an emblem to an element so that it can be turned: it draws the emblem's `frame` into `container`, and a drag turns it (left and right are yaw, up and down are pitch, and Shift on a ball is roll), the arrow keys turn
|
|
90
103
|
* it, Home or 0 puts it back, and Space starts and stops an auto-turn. An emblem that cannot turn is drawn as it is, and nothing is listened to. Nothing moves by itself: `autoPlay` is off by default and, under
|
|
91
104
|
* `prefers-reduced-motion`, only starts when it is `"force"`. The element gets `touch-action: none`, `user-select: none`, a grab cursor, a tab stop, a role description and a hint; `destroy()` takes them away.
|
|
105
|
+
*
|
|
106
|
+
* Pass the emblem itself (`TROPHY_HOCKEY_CUP`, from its own module) and nothing but the turning and that one emblem is in the bundle. Pass an id (`"trophy:hockey-cup"`) and the registry is loaded on
|
|
107
|
+
* demand: the element is drawn when `ready` resolves, not before. The main entry's `bindTurn` has the registry already and draws an id at once.
|
|
92
108
|
* @example
|
|
93
109
|
* ```ts
|
|
94
110
|
* import { bindTurn } from "@johnmorrisdotca/dougu-sports/turn";
|
|
95
|
-
*
|
|
111
|
+
* import { TROPHY_TENNIS_CUP } from "@johnmorrisdotca/dougu-sports/trophy/tennis-cup";
|
|
112
|
+
* const turner = bindTurn(document.getElementById("cup")!, TROPHY_TENNIS_CUP, { size: 160 });
|
|
96
113
|
* turner.setAngles({ yaw: 40 });
|
|
97
114
|
* console.log(turner.angles.yaw);
|
|
98
115
|
* // 40
|
|
99
116
|
* ```
|
|
100
117
|
*/
|
|
101
118
|
export declare function bindTurn(container: TurnContainer, ref: EmblemRef, options?: TurnControlOptions): TurnController;
|
|
119
|
+
/** `bindTurn` with the registry in hand (or none, to load it when an id is bound): the main entry gives it, so that an id is drawn at once. An emblem object needs neither. */
|
|
120
|
+
export declare function bindTurnWith(registry: TurnRegistry | undefined, container: TurnContainer, ref: EmblemRef, options?: TurnControlOptions): TurnController;
|
package/dist/turn-control.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
// `bindTurn`: an emblem that a pointer, the arrow keys, the Space bar or a clock can turn. It draws `emblemFrame` into an element and listens to that element, and it is a module of its own, so importing an
|
|
2
|
-
// emblem never pulls it in. Nothing here moves by itself: an auto-turn starts only when the caller asks for it, and not at all under `prefers-reduced-motion` unless the caller forces it.
|
|
3
|
-
import { emblemFrame, emblemOf, renderEmblem } from "./emblems/emblem.api.js";
|
|
4
1
|
const WORDS = {
|
|
5
2
|
en: { role: "turnable emblem", hint: "Drag, or use the arrow keys, to turn it. Space starts and stops the turning." },
|
|
6
3
|
ja: { role: "回せるエンブレム", hint: "ドラッグするか矢印キーで回せます。スペースキーで自動回転を始めたり止めたりできます。" },
|
|
@@ -13,7 +10,7 @@ export function wrapAngle(value) {
|
|
|
13
10
|
const finite = (value, fallback) => (typeof value === "number" && Number.isFinite(value) ? value : fallback);
|
|
14
11
|
const clamp = (value, low, high) => Math.max(low, Math.min(high, value));
|
|
15
12
|
const globals = globalThis;
|
|
16
|
-
/** Whether an emblem turns at all, read from the
|
|
13
|
+
/** Whether an emblem turns at all, read from the emblem's own frames: a turned view that differs from the resting one. An emblem may say so itself with a `turnable` flag. */
|
|
17
14
|
const turns = new WeakMap();
|
|
18
15
|
function canTurn(emblem) {
|
|
19
16
|
const flag = emblem.turnable;
|
|
@@ -26,22 +23,41 @@ function canTurn(emblem) {
|
|
|
26
23
|
}
|
|
27
24
|
return known;
|
|
28
25
|
}
|
|
26
|
+
const fromEmblem = (emblem) => ({ emblem, still: (o) => emblem.svg(o), frame: (o) => emblem.frame(o) });
|
|
27
|
+
const fromId = (registry, ref) => ({ emblem: registry.emblemOf(ref).emblem, still: (o) => registry.renderEmblem(ref, o), frame: (o) => registry.emblemFrame(ref, o) });
|
|
28
|
+
/** The registry, once something has loaded it: later ids are bound at once. */
|
|
29
|
+
let loaded;
|
|
30
|
+
let loading;
|
|
31
|
+
const load = () => {
|
|
32
|
+
loading ??= import("./turn-registry.js").then((api) => (loaded = api));
|
|
33
|
+
return loading;
|
|
34
|
+
};
|
|
29
35
|
/**
|
|
30
|
-
* Binds an emblem to an element so that it can be turned: it draws `
|
|
36
|
+
* Binds an emblem to an element so that it can be turned: it draws the emblem's `frame` into `container`, and a drag turns it (left and right are yaw, up and down are pitch, and Shift on a ball is roll), the arrow keys turn
|
|
31
37
|
* it, Home or 0 puts it back, and Space starts and stops an auto-turn. An emblem that cannot turn is drawn as it is, and nothing is listened to. Nothing moves by itself: `autoPlay` is off by default and, under
|
|
32
38
|
* `prefers-reduced-motion`, only starts when it is `"force"`. The element gets `touch-action: none`, `user-select: none`, a grab cursor, a tab stop, a role description and a hint; `destroy()` takes them away.
|
|
39
|
+
*
|
|
40
|
+
* Pass the emblem itself (`TROPHY_HOCKEY_CUP`, from its own module) and nothing but the turning and that one emblem is in the bundle. Pass an id (`"trophy:hockey-cup"`) and the registry is loaded on
|
|
41
|
+
* demand: the element is drawn when `ready` resolves, not before. The main entry's `bindTurn` has the registry already and draws an id at once.
|
|
33
42
|
* @example
|
|
34
43
|
* ```ts
|
|
35
44
|
* import { bindTurn } from "@johnmorrisdotca/dougu-sports/turn";
|
|
36
|
-
*
|
|
45
|
+
* import { TROPHY_TENNIS_CUP } from "@johnmorrisdotca/dougu-sports/trophy/tennis-cup";
|
|
46
|
+
* const turner = bindTurn(document.getElementById("cup")!, TROPHY_TENNIS_CUP, { size: 160 });
|
|
37
47
|
* turner.setAngles({ yaw: 40 });
|
|
38
48
|
* console.log(turner.angles.yaw);
|
|
39
49
|
* // 40
|
|
40
50
|
* ```
|
|
41
51
|
*/
|
|
42
52
|
export function bindTurn(container, ref, options = {}) {
|
|
53
|
+
return bindTurnWith(undefined, container, ref, options);
|
|
54
|
+
}
|
|
55
|
+
/** `bindTurn` with the registry in hand (or none, to load it when an id is bound): the main entry gives it, so that an id is drawn at once. An emblem object needs neither. */
|
|
56
|
+
export function bindTurnWith(registry, container, ref, options = {}) {
|
|
43
57
|
let current = ref;
|
|
44
|
-
let
|
|
58
|
+
let drawer;
|
|
59
|
+
let version = 0;
|
|
60
|
+
let pending;
|
|
45
61
|
let turnable = false;
|
|
46
62
|
let sensitivity = 1.5;
|
|
47
63
|
let range = [-60, 60];
|
|
@@ -95,7 +111,9 @@ export function bindTurn(container, ref, options = {}) {
|
|
|
95
111
|
}
|
|
96
112
|
const at = angles.yaw === 0 && angles.pitch === 0 && angles.roll === 0;
|
|
97
113
|
// The resting view of an emblem that turns is drawn in the box of the turn too, so that the element is the same size at every angle and a drag does not make the emblem jump or zoom at its first step.
|
|
98
|
-
|
|
114
|
+
if (drawer === undefined)
|
|
115
|
+
return;
|
|
116
|
+
container.innerHTML = !turnable ? drawer.still(frame) : at ? drawer.still({ turnBox: true, ...frame }) : drawer.frame({ ...frame, ...angles });
|
|
99
117
|
};
|
|
100
118
|
/** One drawing for any number of changes within a frame. */
|
|
101
119
|
const schedule = () => {
|
|
@@ -178,7 +196,7 @@ export function bindTurn(container, ref, options = {}) {
|
|
|
178
196
|
drag.y = y;
|
|
179
197
|
if (dx === 0 && dy === 0)
|
|
180
198
|
return;
|
|
181
|
-
if (event.shiftKey === true && emblem.kind === "ball")
|
|
199
|
+
if (event.shiftKey === true && drawer?.emblem.kind === "ball")
|
|
182
200
|
place({ roll: angles.roll + dx, pitch: angles.pitch - dy });
|
|
183
201
|
else
|
|
184
202
|
place({ yaw: angles.yaw + dx, pitch: angles.pitch - dy });
|
|
@@ -287,24 +305,46 @@ export function bindTurn(container, ref, options = {}) {
|
|
|
287
305
|
drag = undefined;
|
|
288
306
|
held = false;
|
|
289
307
|
};
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
turnable = canTurn(emblem);
|
|
308
|
+
const adopt = (next) => {
|
|
309
|
+
drawer = next;
|
|
310
|
+
turnable = canTurn(next.emblem);
|
|
311
|
+
detach();
|
|
293
312
|
if (turnable)
|
|
294
313
|
attach();
|
|
295
|
-
else
|
|
296
|
-
detach();
|
|
314
|
+
else
|
|
297
315
|
setPlaying(false);
|
|
298
|
-
}
|
|
299
316
|
};
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
317
|
+
/** Binds what `current` names: at once for an emblem, or for an id when the registry is in hand; otherwise when it has loaded. Gives the wait, if there is one. */
|
|
318
|
+
const settle = (first) => {
|
|
319
|
+
const mine = ++version;
|
|
320
|
+
const now = current;
|
|
321
|
+
if (typeof now !== "string")
|
|
322
|
+
return void adopt(fromEmblem(now));
|
|
323
|
+
const known = registry ?? loaded;
|
|
324
|
+
if (known !== undefined)
|
|
325
|
+
return void adopt(fromId(known, now));
|
|
326
|
+
return load().then((api) => {
|
|
327
|
+
if (mine !== version || destroyed)
|
|
328
|
+
return;
|
|
329
|
+
adopt(fromId(api, now));
|
|
330
|
+
draw();
|
|
331
|
+
if (first)
|
|
332
|
+
autoStart();
|
|
333
|
+
});
|
|
334
|
+
};
|
|
335
|
+
const autoStart = () => {
|
|
336
|
+
if (!turnable || options.autoPlay === undefined || options.autoPlay === false)
|
|
337
|
+
return;
|
|
305
338
|
const reduced = globals.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true;
|
|
306
339
|
if (options.autoPlay === "force" || !reduced)
|
|
307
340
|
setPlaying(true);
|
|
341
|
+
};
|
|
342
|
+
configure(options);
|
|
343
|
+
place({ yaw: options.yaw, pitch: options.pitch, roll: options.roll });
|
|
344
|
+
pending = settle(true);
|
|
345
|
+
if (pending === undefined) {
|
|
346
|
+
draw();
|
|
347
|
+
autoStart();
|
|
308
348
|
}
|
|
309
349
|
return {
|
|
310
350
|
get angles() {
|
|
@@ -316,6 +356,9 @@ export function bindTurn(container, ref, options = {}) {
|
|
|
316
356
|
get turnable() {
|
|
317
357
|
return turnable;
|
|
318
358
|
},
|
|
359
|
+
get ready() {
|
|
360
|
+
return pending ?? Promise.resolve();
|
|
361
|
+
},
|
|
319
362
|
setAngles(partial) {
|
|
320
363
|
if (destroyed)
|
|
321
364
|
return;
|
|
@@ -331,9 +374,9 @@ export function bindTurn(container, ref, options = {}) {
|
|
|
331
374
|
place({ yaw: o.yaw, pitch: o.pitch, roll: o.roll });
|
|
332
375
|
// The pitch the new range allows.
|
|
333
376
|
place({ pitch: angles.pitch });
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
377
|
+
pending = settle(false);
|
|
378
|
+
if (pending === undefined)
|
|
379
|
+
draw();
|
|
337
380
|
},
|
|
338
381
|
play() {
|
|
339
382
|
if (!turnable || destroyed)
|
|
@@ -355,6 +398,7 @@ export function bindTurn(container, ref, options = {}) {
|
|
|
355
398
|
return;
|
|
356
399
|
setPlaying(false);
|
|
357
400
|
destroyed = true;
|
|
401
|
+
version++;
|
|
358
402
|
if (renderId !== undefined)
|
|
359
403
|
globals.cancelAnimationFrame?.(renderId);
|
|
360
404
|
renderId = undefined;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type EmblemRef } from "./emblems/emblem.api.ts";
|
|
2
|
+
import { type TurnContainer, type TurnControlOptions, type TurnController } from "./turn-control.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Binds an emblem to an element so that a drag, the arrow keys, Space or a clock turn it; see `bindTurn` of `@johnmorrisdotca/dougu-sports/turn`, which takes an emblem object and loads nothing else. This one is
|
|
5
|
+
* from the main entry: an id is read from the registry and drawn at once, with no `await`.
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { bindTurn } from "@johnmorrisdotca/dougu-sports";
|
|
9
|
+
* const turner = bindTurn(document.getElementById("cup")!, "trophy:tennis-cup", { size: 160 });
|
|
10
|
+
* turner.setAngles({ yaw: 40 });
|
|
11
|
+
* console.log(turner.angles.yaw);
|
|
12
|
+
* // 40
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function bindTurn(container: TurnContainer, ref: EmblemRef, options?: TurnControlOptions): TurnController;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// `bindTurn` of the main entry: the same as the light one of `./turn`, with the registry already in hand, so an id is drawn at once (as it always was) and an emblem object works too. It is a function of its own, so
|
|
2
|
+
// a page that imports only emblems from the main entry does not pull it in; one that imports `bindTurn` from here has the registry in the bundle anyway.
|
|
3
|
+
import { emblemFrame, emblemOf, renderEmblem } from "./emblems/emblem.api.js";
|
|
4
|
+
import { bindTurnWith } from "./turn-control.js";
|
|
5
|
+
/**
|
|
6
|
+
* Binds an emblem to an element so that a drag, the arrow keys, Space or a clock turn it; see `bindTurn` of `@johnmorrisdotca/dougu-sports/turn`, which takes an emblem object and loads nothing else. This one is
|
|
7
|
+
* from the main entry: an id is read from the registry and drawn at once, with no `await`.
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { bindTurn } from "@johnmorrisdotca/dougu-sports";
|
|
11
|
+
* const turner = bindTurn(document.getElementById("cup")!, "trophy:tennis-cup", { size: 160 });
|
|
12
|
+
* turner.setAngles({ yaw: 40 });
|
|
13
|
+
* console.log(turner.angles.yaw);
|
|
14
|
+
* // 40
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function bindTurn(container, ref, options = {}) {
|
|
18
|
+
return bindTurnWith({ emblemOf, renderEmblem, emblemFrame }, container, ref, options);
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { emblemFrame, emblemOf, renderEmblem } from "./emblems/emblem.api.ts";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// What `bindTurn` loads when it is given an id: the three functions that read the registry. A module of its own, so that the dynamic import has a target no static import of `./turn` shares, and a bundler
|
|
2
|
+
// makes it a chunk of its own.
|
|
3
|
+
export { emblemFrame, emblemOf, renderEmblem } from "./emblems/emblem.api.js";
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.8.0";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
1
|
+
export const VERSION = "0.8.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/dougu-sports",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Dougu Sports 道具, sports emblems as SVG strings: trophies, medals, crests, sport icons, and the ball and gear of every sport, in metal, line or flat colour, with optional 3D turning. Light and dark, accessible, tree-shakeable. Zero dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sports",
|
|
@@ -113,18 +113,18 @@
|
|
|
113
113
|
"scripts": {
|
|
114
114
|
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json",
|
|
115
115
|
"lint": "eslint .",
|
|
116
|
-
"typecheck": "tsc -p tsconfig.check.json",
|
|
117
|
-
"test": "node --test test/*.test.ts
|
|
118
|
-
"test:package": "pnpm build && node scripts/check-package.
|
|
119
|
-
"test:readme": "pnpm build && node scripts/make-gallery.
|
|
120
|
-
"check": "pnpm lint && pnpm typecheck && pnpm test && pnpm build && node scripts/check-package.
|
|
116
|
+
"typecheck": "tsc -p tsconfig.check.json && tsc -p tsconfig.tools.json && tsc -p tsconfig.demo.json",
|
|
117
|
+
"test": "node --test test/*.test.ts",
|
|
118
|
+
"test:package": "pnpm build && node scripts/check-package.ts",
|
|
119
|
+
"test:readme": "pnpm build && node scripts/make-gallery.ts --check && node scripts/check-readme-examples.ts",
|
|
120
|
+
"check": "pnpm lint && pnpm typecheck && pnpm test && pnpm build && node scripts/check-package.ts",
|
|
121
121
|
"prepublishOnly": "pnpm check",
|
|
122
122
|
"family:readme": "node scripts/family-readme.mjs",
|
|
123
|
-
"dev": "pnpm build && node scripts/dev.
|
|
124
|
-
"gallery": "pnpm build && node scripts/make-gallery.
|
|
125
|
-
"site": "pnpm build && node scripts/site.
|
|
123
|
+
"dev": "pnpm build && node scripts/dev.ts",
|
|
124
|
+
"gallery": "pnpm build && node scripts/make-gallery.ts",
|
|
125
|
+
"site": "pnpm build && node scripts/site.ts",
|
|
126
126
|
"test:demo": "pnpm site && playwright test",
|
|
127
|
-
"screenshots": "pnpm site && node scripts/screenshots.
|
|
127
|
+
"screenshots": "pnpm site && node scripts/screenshots.ts"
|
|
128
128
|
},
|
|
129
129
|
"devDependencies": {
|
|
130
130
|
"@eslint/js": "^9.0.0",
|