ice-web-components 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -23
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/types/components/ICETileMap.d.ts +12 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/model/ICEChip8Model.d.ts +86 -0
- package/dist/types/model/ICEHistoryModel.d.ts +45 -0
- package/dist/types/model/ICEPixelModel.d.ts +89 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -27,31 +27,24 @@ rings and shadows) is drawn by the engine.
|
|
|
27
27
|
- **Bootstrap 5 token theme** (plus a dark theme) — swap with one call.
|
|
28
28
|
- **No name collisions with the engine** — the package’s runtime exports are
|
|
29
29
|
disjoint from `ice-render`’s (there is a regression test for it).
|
|
30
|
-
- **Actually tested** —
|
|
30
|
+
- **Actually tested** — 749 unit tests (101 suites: form validation, overlay
|
|
31
31
|
positioning, keyboard navigation, sort/hover/focus edge cases, the Minesweeper,
|
|
32
|
-
Tetris and
|
|
33
|
-
`qa:
|
|
32
|
+
Tetris, Snake, 2048 and CHIP-8 rule/machine models, the pixel canvas and the undo
|
|
33
|
+
stack) plus six browser QA suites (`qa:admin`, `qa:gallery`, `qa:workbench`, `qa:xp`,
|
|
34
|
+
`qa:arcade`, `qa:pixel` — 232 assertions) that drive the demo pages with
|
|
34
35
|
real mouse and keyboard events and fail on any console error.
|
|
35
36
|
|
|
36
37
|
## Quick start
|
|
37
38
|
|
|
38
|
-
> **Install**:
|
|
39
|
-
>
|
|
39
|
+
> **Install**: both packages are on npm now — `npm install ice-web-components` (it pulls
|
|
40
|
+
> `ice-render` as a dependency). `1.0.0` is the first published release; from a checkout you
|
|
41
|
+
> can also `npm install /path/to/ice-web-components` or `npm install git+https://github.com/ice-render/ice-web-components.git`.
|
|
40
42
|
|
|
41
43
|
```bash
|
|
42
|
-
|
|
43
|
-
npm install /path/to/ice-web-components
|
|
44
|
-
|
|
45
|
-
# ② straight from git
|
|
46
|
-
npm install git+https://github.com/ice-render/ice-web-components.git
|
|
47
|
-
|
|
48
|
-
# ③ pack it, then install the tarball
|
|
49
|
-
(cd /path/to/ice-web-components && npm pack) # produces ice-web-components-0.0.1.tgz
|
|
50
|
-
npm install /path/to/ice-web-components-0.0.1.tgz
|
|
44
|
+
npm install ice-web-components # + ice-render, pulled automatically
|
|
51
45
|
```
|
|
52
46
|
|
|
53
|
-
|
|
54
|
-
contains `dist/` only (cjs + esm + umd + type declarations).
|
|
47
|
+
The published tarball contains `dist/` only (cjs + esm + umd + type declarations).
|
|
55
48
|
|
|
56
49
|
```ts
|
|
57
50
|
import { ICE } from 'ice-render';
|
|
@@ -224,8 +217,8 @@ that window is active; closing the window stops its step timer.
|
|
|
224
217
|
|
|
225
218
|
Not a web page but a **handheld console**: the shell, the screen bezel, the HUD cards,
|
|
226
219
|
the buttons and the sound switch are all ICE components, and there is not a single
|
|
227
|
-
bitmap asset in the picture.
|
|
228
|
-
the top switches between them (a
|
|
220
|
+
bitmap asset in the picture. Four cartridges are plugged in, and the cartridge row at
|
|
221
|
+
the top switches between them (a fifth slot, Chinese chess, is disabled for now).
|
|
229
222
|
|
|
230
223
|
| | |
|
|
231
224
|
|---|---|
|
|
@@ -256,10 +249,32 @@ weight and text colour, so a 4×4 board with 16 numbers is still one node.
|
|
|
256
249
|
|
|
257
250
|

|
|
258
251
|
|
|
259
|
-
|
|
252
|
+
**Cartridge 4 — CHIP-8** (`ICEChip8Model`, 19 unit tests). The odd one out: instead of
|
|
253
|
+
“the rules of a game” it is **an actual virtual machine** — 4 KB of memory, `V0`–`VF`,
|
|
254
|
+
the 16-bit `I` register, a 64×32 monochrome framebuffer, two 60 Hz timers and a 16-key
|
|
255
|
+
keypad. 35 opcodes are implemented (`00E0` / `1NNN` / `2NNN` / `DXYN` / `EX9E` / `FX0A` /
|
|
256
|
+
`FX29` / `FX33` / `FX55` …), including `DXYN`’s XOR drawing with the classic
|
|
257
|
+
`VF = collision` flag and `FX0A` blocking key waits.
|
|
258
|
+
|
|
259
|
+
The console ships a **self-written demo ROM** (no external ROM, no copyright questions):
|
|
260
|
+
it clears the screen, draws an 8×8 smiley, moves it, flips its velocity when a wall is
|
|
261
|
+
reached, and loops — which exercises conditional skips and two’s-complement arithmetic
|
|
262
|
+
as well as drawing. Both the 2048-cell framebuffer and the 4×4 machine keypad are single
|
|
263
|
+
`ICETileMap` nodes; the keys light up while pressed, which makes the `keydown` / `keyup`
|
|
264
|
+
path visible. On that cartridge the machine owns its 16 keys (`1 2 3 4 / Q W E R / A S D F
|
|
265
|
+
/ Z X C V`), so the console hands even `R` to the ROM and keeps `P` for pause.
|
|
266
|
+
|
|
267
|
+

|
|
268
|
+
|
|
269
|
+
All four games are pure models that never touch the canvas; the page only reads the model
|
|
260
270
|
and paints cells. Switching a cartridge tears the old board down, builds the new one
|
|
261
|
-
and re-captions the HUD, so
|
|
262
|
-
Switching away from the tab pauses whatever is running
|
|
271
|
+
and re-captions the HUD, so another game is a registry entry plus a `mount()`.
|
|
272
|
+
Switching away from the tab pauses whatever is running (CHIP-8 also drops its pressed
|
|
273
|
+
keys, otherwise a lost `keyup` would leave `FX0A` waiting forever).
|
|
274
|
+
|
|
275
|
+
| Pause overlay (`已暂停`) |
|
|
276
|
+
|---|
|
|
277
|
+
|  |
|
|
263
278
|
|
|
264
279
|
Under the hood this page is where the engine work happens:
|
|
265
280
|
|
|
@@ -279,6 +294,10 @@ Under the hood this page is where the engine work happens:
|
|
|
279
294
|
- Toasts are **replaced, not stacked**: a console only needs one status line, and the QA
|
|
280
295
|
caught a stack of three toasts covering the cartridge row (the click never reached the
|
|
281
296
|
button). `ICEMessage` still supports stacking for pages that want it.
|
|
297
|
+
- CHIP-8 also drove two engine fixes: an offscreen-cache bug where a bitmap baked the
|
|
298
|
+
*ancestor’s* opacity (so the pause plate faded in but its “已暂停” text never appeared —
|
|
299
|
+
translucent subtrees are no longer cached, and stale bitmaps are dropped), and
|
|
300
|
+
keyboard routing that lets a cartridge declare the keys it owns.
|
|
282
301
|
|
|
283
302
|
| Leaderboard (`ICEModal` + `ICETable` + `ICEScrollPane`) |
|
|
284
303
|
|---|
|
|
@@ -289,6 +308,52 @@ Under the hood this page is where the engine work happens:
|
|
|
289
308
|
> A game page keeps the keyboard for itself; mouse hover still goes through
|
|
290
309
|
> `ICEHoverManager`.
|
|
291
310
|
|
|
311
|
+
### `pixel-editor.html` — ICE Pixel Studio (a real pixel editor)
|
|
312
|
+
|
|
313
|
+
The other direction: instead of “draw a business screen”, this page is a **tool**.
|
|
314
|
+
The canvas, tool palette, colour swatches and status bar are all components — only the
|
|
315
|
+
pixels themselves are self-drawn, as a single `ICETileMap` node. Pencil, eraser, line,
|
|
316
|
+
rectangle and flood fill, undo/redo, and PNG + SVG export.
|
|
317
|
+
|
|
318
|
+

|
|
319
|
+
|
|
320
|
+
Two pure models carry it (no canvas involved):
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
import { ICEPixelModel, ICEHistoryModel } from 'ice-web-components';
|
|
324
|
+
|
|
325
|
+
const model = new ICEPixelModel({ rows: 32, cols: 32, palette: PALETTE, background: 0 });
|
|
326
|
+
model.setPixel(4, 4, 1); // live change; returns whether it really changed
|
|
327
|
+
model.drawLine(0, 0, 0, 7, 2); // Bresenham
|
|
328
|
+
model.fill(3, 3, 5); // 4-neighbour flood fill (iterative, no recursion)
|
|
329
|
+
model.commit(); // one commit = one undo step
|
|
330
|
+
model.toSVG({ cellSize: 16 }); // run-length merged SVG string
|
|
331
|
+
model.toRGBA(16); // feed it straight into ImageData for PNG export
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
The three decisions worth stealing:
|
|
335
|
+
|
|
336
|
+
1. **History is per *operation*, not per pixel** — a 20-cell drag pushes exactly one
|
|
337
|
+
snapshot (`mousedown` paints, `mouseup` commits). Otherwise undo would need 20
|
|
338
|
+
presses to walk one stroke back, which decides whether a 1024-cell editor is usable.
|
|
339
|
+
`ICEHistoryModel` itself is a plain generic stack (push clears redo, trims to a limit,
|
|
340
|
+
notifies with a reason) — reusable for kanban or table editing too.
|
|
341
|
+
2. **Preview via the highlight layer, not “draw then undo”** — dragging a line or a
|
|
342
|
+
rectangle lights up `ICETileMap.setHighlights()` from `getLineCells()` /
|
|
343
|
+
`getRectCells()`, and only `mouseup` commits. Preview and painting share the same
|
|
344
|
+
coordinate API, so the preview is exactly what you get (a unit test paints both and
|
|
345
|
+
compares cell by cell).
|
|
346
|
+
3. **Export is pure** — `toSVG()` merges horizontal runs into single `<rect>`s (the
|
|
347
|
+
32×32 smiley emits 20 elements, not 1024), and `toRGBA(scale)` hands the page an
|
|
348
|
+
`ImageData` buffer; only the page touches `canvas.toDataURL()`. The QA asserts on the
|
|
349
|
+
data: the PNG check decodes the **IHDR** chunk to prove the bitmap is 512×512.
|
|
350
|
+
|
|
351
|
+
> A component gap this page closed: `ICETileMap` cached `rows`/`cols`/`cellSize` in
|
|
352
|
+
> instance fields, so resizing with only `setState({ rows, cols })` left the internals
|
|
353
|
+
> stale and the next `setTiles` threw (“expected 1024 cells, got 256”). There is now a
|
|
354
|
+
> proper `setSize(rows, cols, cellSize?)` that updates the internals, the state and the
|
|
355
|
+
> default width/height in one go, and clears the old cell data.
|
|
356
|
+
|
|
292
357
|
## Components
|
|
293
358
|
|
|
294
359
|
| Group | Components |
|
|
@@ -300,12 +365,12 @@ Under the hood this page is where the engine work happens:
|
|
|
300
365
|
| Feedback & status | `ICEAlert` `ICEModal` `ICEDrawer` `ICEMessage` `ICENotification` `ICETooltip` `ICEPopover` `ICEPopconfirm` `ICETour` `ICEFloatButton` `ICEEmpty` `ICESkeleton` `ICESpin` `ICEResult` `ICESteps` `ICEOverlayManager` |
|
|
301
366
|
| Navigation | `ICEMenu` `ICEBreadcrumb` `ICEAnchor` `ICEBackTop` `ICEDropdown` `ICEPagination` `ICETabs` |
|
|
302
367
|
| Layout & core | `ICEWidget` `ICEContainer` `ICEHoverManager` `ICEFocusManager` `ICEMessageManager` `ICEManager` (`ICEPainter` / `ICELayoutManager` are types) |
|
|
303
|
-
| Models | `ICEButtonModel` `ICEToggleModel` `ICEBoundedRangeModel` `ICESelectionModel` `ICEFormModel` |
|
|
368
|
+
| Models | `ICEButtonModel` `ICEToggleModel` `ICEBoundedRangeModel` `ICESelectionModel` `ICEFormModel` `ICEHistoryModel` `ICEPixelModel` `ICETetrisModel` `ICESnakeModel` `ICE2048Model` `ICEChip8Model` `ICEMinesweeperModel` `ICEHighScoreModel` |
|
|
304
369
|
|
|
305
370
|
Helper functions: `attachTooltip` `attachPopover` `attachPopconfirm` `attachDropdown`
|
|
306
371
|
`openModal` `openDrawer` `getICEOverlayManager` `getICEFocusManager` `getICEMessageManager`
|
|
307
372
|
`formatStatisticValue` `formatCountdown` `truncateTextLines` `buildMonthGrid` `formatCalendarDate`
|
|
308
|
-
`openImagePreview` `tween` `fadeIn` `fadeOut` `slideIn` `scaleIn` and friends.
|
|
373
|
+
`openImagePreview` `icePixelParseColor` `tween` `fadeIn` `fadeOut` `slideIn` `scaleIn` and friends.
|
|
309
374
|
|
|
310
375
|
## Theme
|
|
311
376
|
|
|
@@ -440,6 +505,11 @@ npm run qa:xp
|
|
|
440
505
|
# real clicks on the HUD
|
|
441
506
|
npm run qa:arcade
|
|
442
507
|
|
|
508
|
+
# browser QA for examples/pixel-editor.html: drawing with a real mouse (pencil drag,
|
|
509
|
+
# line/rect preview, flood fill, eraser), undo/redo via buttons and Ctrl+Z/Y, and the
|
|
510
|
+
# PNG (IHDR-checked) / SVG exports
|
|
511
|
+
npm run qa:pixel
|
|
512
|
+
|
|
443
513
|
# docs: regenerate the API reference and check relative links
|
|
444
514
|
npm run docs
|
|
445
515
|
```
|