@ntmats/hc-ui 0.6.0 → 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/dist/index.d.ts +34 -2
- package/dist/index.js +54 -10
- package/dist/styles.css +9 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -310,6 +310,7 @@ export interface DialogProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'ti
|
|
|
310
310
|
*/
|
|
311
311
|
export declare const Dialog: ForwardRefExoticComponent<DialogProps & RefAttributes<HTMLDialogElement>>;
|
|
312
312
|
export type SheetPresentation = 'bottom' | 'center' | 'auto';
|
|
313
|
+
export type SheetHeight = 'content' | 'half';
|
|
313
314
|
interface SheetBaseProps extends Omit<DialogProps, 'size' | 'actions' | 'description' | 'closeLabel' | 'title'> {
|
|
314
315
|
/** Slot under the scrolling body, for the buttons (Clear | Done). */
|
|
315
316
|
footer?: ReactNode;
|
|
@@ -321,6 +322,13 @@ interface SheetBaseProps extends Omit<DialogProps, 'size' | 'actions' | 'descrip
|
|
|
321
322
|
presentation?: SheetPresentation;
|
|
322
323
|
/** Maximum width of the centered panel, in px. Default 440. */
|
|
323
324
|
width?: number;
|
|
325
|
+
/**
|
|
326
|
+
* Resting height at the bottom. `content` (default) grows with the content up to almost the
|
|
327
|
+
* whole screen. `half` rests at half the screen, so what is behind stays in sight (dimmed),
|
|
328
|
+
* and the content scrolls inside; a drag up from the grabber or header still goes to full
|
|
329
|
+
* height, and a drag down from there comes back to half. No effect on the centered panel.
|
|
330
|
+
*/
|
|
331
|
+
height?: SheetHeight;
|
|
324
332
|
}
|
|
325
333
|
/**
|
|
326
334
|
* `Sheet` props. By default the sheet has a header with the title (its accessible name) and a
|
|
@@ -346,7 +354,8 @@ export type SheetProps = SheetBaseProps & ({
|
|
|
346
354
|
* Tab trap, Esc, focus return, scroll lock, stacking and controlled `open`/`onClose`.
|
|
347
355
|
* At the bottom it has a grabber, drag to close (past 20% of its height or a quick
|
|
348
356
|
* flick) and drag up from the grabber or header to full height; content that has
|
|
349
|
-
* scrolled down scrolls back before the sheet moves.
|
|
357
|
+
* scrolled down scrolls back before the sheet moves. `height="half"` rests at half the
|
|
358
|
+
* screen instead of growing with the content.
|
|
350
359
|
*/
|
|
351
360
|
export declare const Sheet: ForwardRefExoticComponent<SheetProps & RefAttributes<HTMLDialogElement>>;
|
|
352
361
|
export interface SheetOption<T extends string> {
|
|
@@ -1358,6 +1367,21 @@ export interface HCMapJson {
|
|
|
1358
1367
|
ramps?: JsonRamp[];
|
|
1359
1368
|
ziplines?: JsonWall[];
|
|
1360
1369
|
}
|
|
1370
|
+
/** The grid's line between squares. */
|
|
1371
|
+
export declare const MAP_GRID_COLOR = "#222222";
|
|
1372
|
+
/** `soft` grid: the line between two plain squares (clear, at floor level). */
|
|
1373
|
+
export declare const MAP_GRID_SOFT_COLOR = "#D4D2CC";
|
|
1374
|
+
/** `soft` grid: between two squares of the same terrain, the fill darkened by this fraction. */
|
|
1375
|
+
export declare const MAP_GRID_TERRAIN_SHADE = 0.22;
|
|
1376
|
+
export interface MapDrawOptions {
|
|
1377
|
+
/**
|
|
1378
|
+
* `dark` (default): every square outlined in the dark grid, as printed. `soft`: the line between
|
|
1379
|
+
* two plain squares (clear terrain at floor level) is light gray; between two squares of the same
|
|
1380
|
+
* terrain, a darker tone of that terrain's color; between different kinds and on the map's edge,
|
|
1381
|
+
* the dark grid.
|
|
1382
|
+
*/
|
|
1383
|
+
grid?: 'dark' | 'soft';
|
|
1384
|
+
}
|
|
1361
1385
|
export declare class HCMap {
|
|
1362
1386
|
width: number;
|
|
1363
1387
|
height: number;
|
|
@@ -1368,7 +1392,13 @@ export declare class HCMap {
|
|
|
1368
1392
|
constructor(json: HCMapJson);
|
|
1369
1393
|
private getTile;
|
|
1370
1394
|
private tryAddEdge;
|
|
1371
|
-
|
|
1395
|
+
/**
|
|
1396
|
+
* The `soft` grid's color for the line between two squares: light gray between plain squares
|
|
1397
|
+
* (clear, floor level, no starting zone), a tone of the terrain's own color between two squares
|
|
1398
|
+
* of the same kind, and the dark grid between different kinds or on the map's edge.
|
|
1399
|
+
*/
|
|
1400
|
+
private softGridColor;
|
|
1401
|
+
draw(ctx: CanvasRenderingContext2D, { grid }?: MapDrawOptions): void;
|
|
1372
1402
|
private drawWall;
|
|
1373
1403
|
}
|
|
1374
1404
|
export declare function mapSquare(map: HCMapJson, x: number, y: number): {
|
|
@@ -1584,6 +1614,8 @@ export interface MapBoardViewProps extends Omit<HTMLAttributes<HTMLDivElement>,
|
|
|
1584
1614
|
onLeave?(): void;
|
|
1585
1615
|
/** Drawing failed (a JSON outside the expected format). */
|
|
1586
1616
|
onDrawError?(): void;
|
|
1617
|
+
/** The grid between squares: `dark` (default) or `soft` (light between plain squares). */
|
|
1618
|
+
grid?: MapDrawOptions['grid'];
|
|
1587
1619
|
}
|
|
1588
1620
|
/**
|
|
1589
1621
|
* The map's 2D board: the hcmaps drawing in a canvas and, over it, the inspection's
|
package/dist/index.js
CHANGED
|
@@ -602,7 +602,7 @@ function useSheetDrag(sheet, latest) {
|
|
|
602
602
|
};
|
|
603
603
|
}, [sheet, latest]);
|
|
604
604
|
}
|
|
605
|
-
var Sheet = forwardRef(function Sheet2({ presentation = "auto", width = 440, footer, dismissible = true, header = true, onClose, className, style, ...props }, ref) {
|
|
605
|
+
var Sheet = forwardRef(function Sheet2({ presentation = "auto", width = 440, height = "content", footer, dismissible = true, header = true, onClose, className, style, ...props }, ref) {
|
|
606
606
|
const [node, setNode] = useState(null);
|
|
607
607
|
const setRef = useCallback((element) => {
|
|
608
608
|
setNode(element);
|
|
@@ -626,7 +626,8 @@ var Sheet = forwardRef(function Sheet2({ presentation = "auto", width = 440, foo
|
|
|
626
626
|
headerless: !header,
|
|
627
627
|
className: classes("hc-ui-sheet", className),
|
|
628
628
|
style: sized,
|
|
629
|
-
"data-presentation": presentation
|
|
629
|
+
"data-presentation": presentation,
|
|
630
|
+
"data-height": height === "half" ? "half" : void 0
|
|
630
631
|
}
|
|
631
632
|
);
|
|
632
633
|
});
|
|
@@ -2468,6 +2469,16 @@ var Tile = class {
|
|
|
2468
2469
|
ctx.restore();
|
|
2469
2470
|
}
|
|
2470
2471
|
};
|
|
2472
|
+
var MAP_GRID_COLOR = "#222222";
|
|
2473
|
+
var MAP_GRID_SOFT_COLOR = "#D4D2CC";
|
|
2474
|
+
var MAP_GRID_TERRAIN_SHADE = 0.22;
|
|
2475
|
+
function shadeHex(color, amount) {
|
|
2476
|
+
const m = /^#([0-9a-f]{6})$/i.exec(color);
|
|
2477
|
+
if (!m) return null;
|
|
2478
|
+
const n = parseInt(m[1], 16);
|
|
2479
|
+
const ch = (shift) => Math.round((n >> shift & 255) * (1 - amount)).toString(16).padStart(2, "0");
|
|
2480
|
+
return `#${ch(16)}${ch(8)}${ch(0)}`;
|
|
2481
|
+
}
|
|
2471
2482
|
var HCMap = class {
|
|
2472
2483
|
constructor(json) {
|
|
2473
2484
|
__publicField(this, "width");
|
|
@@ -2537,7 +2548,19 @@ var HCMap = class {
|
|
|
2537
2548
|
t0.addEdge(edgeType, MAP_TERRAIN_EDGE_COLORS[t0.terrain] ?? "#FFFFFF", dashed);
|
|
2538
2549
|
}
|
|
2539
2550
|
}
|
|
2540
|
-
|
|
2551
|
+
/**
|
|
2552
|
+
* The `soft` grid's color for the line between two squares: light gray between plain squares
|
|
2553
|
+
* (clear, floor level, no starting zone), a tone of the terrain's own color between two squares
|
|
2554
|
+
* of the same kind, and the dark grid between different kinds or on the map's edge.
|
|
2555
|
+
*/
|
|
2556
|
+
softGridColor(a, b) {
|
|
2557
|
+
if (!a || !b) return MAP_GRID_COLOR;
|
|
2558
|
+
const same = a.terrain === b.terrain && a.type === b.type && String(a.elevation) === String(b.elevation) && !!a.isStartingZone === !!b.isStartingZone && !!a.isStartingZone4p === !!b.isStartingZone4p && a.fillStyle === b.fillStyle;
|
|
2559
|
+
if (!same) return MAP_GRID_COLOR;
|
|
2560
|
+
if (a.terrain === "clear" && Number(a.elevation) === 1 && !a.isStartingZone && !a.isStartingZone4p) return MAP_GRID_SOFT_COLOR;
|
|
2561
|
+
return shadeHex(a.fillStyle, MAP_GRID_TERRAIN_SHADE) ?? MAP_GRID_COLOR;
|
|
2562
|
+
}
|
|
2563
|
+
draw(ctx, { grid = "dark" } = {}) {
|
|
2541
2564
|
ctx.save();
|
|
2542
2565
|
for (const tile of this.tiles) tile.draw(ctx);
|
|
2543
2566
|
ctx.restore();
|
|
@@ -2545,11 +2568,29 @@ var HCMap = class {
|
|
|
2545
2568
|
for (const tile of this.tiles) tile.drawEdges(ctx);
|
|
2546
2569
|
ctx.restore();
|
|
2547
2570
|
ctx.save();
|
|
2548
|
-
ctx.strokeStyle =
|
|
2571
|
+
ctx.strokeStyle = MAP_GRID_COLOR;
|
|
2549
2572
|
ctx.lineWidth = 1;
|
|
2550
|
-
|
|
2551
|
-
for (let
|
|
2552
|
-
|
|
2573
|
+
if (grid === "dark") {
|
|
2574
|
+
for (let y = 0; y < this.height; y++) {
|
|
2575
|
+
for (let x = 0; x < this.width; x++) {
|
|
2576
|
+
ctx.strokeRect(x * MAP_TILE_SIZE, y * MAP_TILE_SIZE, MAP_TILE_SIZE, MAP_TILE_SIZE);
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
} else {
|
|
2580
|
+
const lines = [];
|
|
2581
|
+
for (let y = 0; y <= this.height; y++) {
|
|
2582
|
+
for (let x = 0; x < this.width; x++) lines.push({ x0: x, y0: y, x1: x + 1, y1: y, color: this.softGridColor(this.getTile(x, y - 1), this.getTile(x, y)) });
|
|
2583
|
+
}
|
|
2584
|
+
for (let x = 0; x <= this.width; x++) {
|
|
2585
|
+
for (let y = 0; y < this.height; y++) lines.push({ x0: x, y0: y, x1: x, y1: y + 1, color: this.softGridColor(this.getTile(x - 1, y), this.getTile(x, y)) });
|
|
2586
|
+
}
|
|
2587
|
+
lines.sort((a, b) => Number(a.color === MAP_GRID_COLOR) - Number(b.color === MAP_GRID_COLOR));
|
|
2588
|
+
for (const l of lines) {
|
|
2589
|
+
ctx.strokeStyle = l.color;
|
|
2590
|
+
ctx.beginPath();
|
|
2591
|
+
ctx.moveTo(l.x0 * MAP_TILE_SIZE, l.y0 * MAP_TILE_SIZE);
|
|
2592
|
+
ctx.lineTo(l.x1 * MAP_TILE_SIZE, l.y1 * MAP_TILE_SIZE);
|
|
2593
|
+
ctx.stroke();
|
|
2553
2594
|
}
|
|
2554
2595
|
}
|
|
2555
2596
|
ctx.restore();
|
|
@@ -3140,7 +3181,7 @@ function renderMapThumbnail(json, height = MAP_THUMBNAIL_HEIGHT) {
|
|
|
3140
3181
|
tctx.drawImage(full, 0, 0, thumb.width, thumb.height);
|
|
3141
3182
|
return thumb.toDataURL("image/png");
|
|
3142
3183
|
}
|
|
3143
|
-
var MapBoardView = forwardRef(function MapBoardView2({ map, canvasLabel, selection, onInspect, onLeave, onDrawError, className, style, ...rest }, ref) {
|
|
3184
|
+
var MapBoardView = forwardRef(function MapBoardView2({ map, canvasLabel, selection, onInspect, onLeave, onDrawError, grid = "dark", className, style, ...rest }, ref) {
|
|
3144
3185
|
const canvasRef = useRef(null);
|
|
3145
3186
|
const failed = useRef(onDrawError);
|
|
3146
3187
|
failed.current = onDrawError;
|
|
@@ -3151,11 +3192,11 @@ var MapBoardView = forwardRef(function MapBoardView2({ map, canvasLabel, selecti
|
|
|
3151
3192
|
if (!ctx) return;
|
|
3152
3193
|
try {
|
|
3153
3194
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
3154
|
-
new HCMap(map).draw(ctx);
|
|
3195
|
+
new HCMap(map).draw(ctx, { grid });
|
|
3155
3196
|
} catch {
|
|
3156
3197
|
failed.current?.();
|
|
3157
3198
|
}
|
|
3158
|
-
}, [map]);
|
|
3199
|
+
}, [map, grid]);
|
|
3159
3200
|
function pointer(event) {
|
|
3160
3201
|
const bounds = event.currentTarget.getBoundingClientRect();
|
|
3161
3202
|
onInspect?.((event.clientX - bounds.left) / bounds.width * map.width, (event.clientY - bounds.top) / bounds.height * map.height, event.clientX, event.clientY);
|
|
@@ -3261,6 +3302,9 @@ export {
|
|
|
3261
3302
|
MAP_DEFAULT_CAMERA,
|
|
3262
3303
|
MAP_ELEVATION_EDGE_COLOR,
|
|
3263
3304
|
MAP_ELEVATION_TILE_COLORS,
|
|
3305
|
+
MAP_GRID_COLOR,
|
|
3306
|
+
MAP_GRID_SOFT_COLOR,
|
|
3307
|
+
MAP_GRID_TERRAIN_SHADE,
|
|
3264
3308
|
MAP_INDOOR_EDGE_COLOR,
|
|
3265
3309
|
MAP_SCENE_BASE_Z,
|
|
3266
3310
|
MAP_SCENE_LEVEL_HEIGHT,
|
package/dist/styles.css
CHANGED
|
@@ -854,6 +854,11 @@
|
|
|
854
854
|
border-radius: 20px 20px 0 0;
|
|
855
855
|
}
|
|
856
856
|
[data-hc-ds] .hc-ui-sheet[data-presentation='bottom'][data-closing] { animation: hc-ui-sheet-down var(--hc-dur-medium) var(--hc-ease-emphasized-accel) forwards; }
|
|
857
|
+
/* height="half": rests at half the screen; the body scrolls. Expanded still wins (full height). */
|
|
858
|
+
[data-hc-ds] .hc-ui-sheet[data-presentation='bottom'][data-height='half']:not([data-expanded]) {
|
|
859
|
+
height: 50dvh;
|
|
860
|
+
max-height: 50dvh;
|
|
861
|
+
}
|
|
857
862
|
|
|
858
863
|
@media (max-width: 959.98px) {
|
|
859
864
|
[data-hc-ds] .hc-ui-sheet[data-presentation='auto'] {
|
|
@@ -888,6 +893,10 @@
|
|
|
888
893
|
border-radius: 20px 20px 0 0;
|
|
889
894
|
}
|
|
890
895
|
[data-hc-ds] .hc-ui-sheet[data-presentation='auto'][data-closing] { animation: hc-ui-sheet-down var(--hc-dur-medium) var(--hc-ease-emphasized-accel) forwards; }
|
|
896
|
+
[data-hc-ds] .hc-ui-sheet[data-presentation='auto'][data-height='half']:not([data-expanded]) {
|
|
897
|
+
height: 50dvh;
|
|
898
|
+
max-height: 50dvh;
|
|
899
|
+
}
|
|
891
900
|
}
|
|
892
901
|
|
|
893
902
|
/* Closing by drag: the backdrop fades with the sheet instead of waiting for the exit. */
|