@inkra/react 0.12.0 → 0.14.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/i18n/catalog.d.ts +1 -1
- package/dist/i18n/catalog.js +1 -0
- package/dist/journey-map/annotations.d.ts +40 -0
- package/dist/journey-map/annotations.js +94 -0
- package/dist/journey-map/index.d.ts +26 -11
- package/dist/journey-map/index.js +318 -56
- package/dist/journey-map/rendering.d.ts +36 -0
- package/dist/journey-map/rendering.js +144 -0
- package/dist/journey-map/terrain.d.ts +4 -1
- package/dist/journey-map/terrain.js +35 -3
- package/dist/journey-map/trackpad.d.ts +3 -0
- package/dist/journey-map/trackpad.js +110 -0
- package/dist/styles/journey-map.css +14 -1
- package/dist/styles/markdown.css +2 -0
- package/dist/styles.css +16 -1
- package/package.json +1 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export function journeyAnimationMs(animate, duration, reducedMotion) {
|
|
2
|
+
if (!animate || reducedMotion)
|
|
3
|
+
return 0;
|
|
4
|
+
return Number.isFinite(duration) ? Math.max(0, Math.min(duration, 5000)) : 420;
|
|
5
|
+
}
|
|
6
|
+
export function journeyFocusZoom(overviewZoom, scale) {
|
|
7
|
+
const ratio = Number.isFinite(scale) && scale >= 1 ? Math.min(scale, 64) : 2;
|
|
8
|
+
return overviewZoom + Math.log2(ratio);
|
|
9
|
+
}
|
|
10
|
+
export function resolveJourneyMapRendering(rendering = 'auto') {
|
|
11
|
+
if (rendering === 'legacy')
|
|
12
|
+
return { boundaryViewport: false, terrainViewport: false, reuseCanvas: false, cacheBase: false };
|
|
13
|
+
const options = typeof rendering === 'object' ? rendering : {};
|
|
14
|
+
return {
|
|
15
|
+
boundaryViewport: options.boundaryViewport ?? true,
|
|
16
|
+
terrainViewport: options.terrainViewport ?? true,
|
|
17
|
+
reuseCanvas: options.reuseCanvas ?? true,
|
|
18
|
+
cacheBase: options.cacheBase ?? true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const MAX_SIDE = 8192;
|
|
22
|
+
const MAX_LAYER_PIXELS = 4 * 1024 * 1024;
|
|
23
|
+
// One base bitmap per map; together with the visible bitmap, at most 6 Mi pixels.
|
|
24
|
+
const MAX_BASE_PIXELS = 3 * 1024 * 1024;
|
|
25
|
+
/** Non-overlapping newly exposed strips after moving an existing base bitmap. */
|
|
26
|
+
export function journeyPanRegions(width, height, dx, dy) {
|
|
27
|
+
if (Math.abs(dx) >= width || Math.abs(dy) >= height)
|
|
28
|
+
return [[0, 0, width, height]];
|
|
29
|
+
const regions = [];
|
|
30
|
+
if (dx)
|
|
31
|
+
regions.push([dx > 0 ? 0 : width + dx, 0, Math.abs(dx), height]);
|
|
32
|
+
if (dy)
|
|
33
|
+
regions.push([Math.max(0, dx), dy > 0 ? 0 : height + dy, width - Math.abs(dx), Math.abs(dy)]);
|
|
34
|
+
return regions;
|
|
35
|
+
}
|
|
36
|
+
/** Pure and SSR safe: browser DPR is supplied by the caller. */
|
|
37
|
+
export function journeyCanvasSize(width, height, requestedDpr) {
|
|
38
|
+
if (![width, height].every(value => Number.isFinite(value) && value > 0))
|
|
39
|
+
return;
|
|
40
|
+
const requested = Number.isFinite(requestedDpr) ? Math.max(1, Math.min(requestedDpr, 2)) : 1;
|
|
41
|
+
const dpr = Math.min(requested, MAX_SIDE / width, MAX_SIDE / height, Math.sqrt(MAX_LAYER_PIXELS / (width * height)));
|
|
42
|
+
if (dpr < 1)
|
|
43
|
+
return;
|
|
44
|
+
const pixelWidth = Math.round(width * dpr), pixelHeight = Math.round(height * dpr);
|
|
45
|
+
// Round-down adjustment prevents rounding the two sides over the pixel budget.
|
|
46
|
+
const boundedDpr = pixelWidth * pixelHeight > MAX_LAYER_PIXELS
|
|
47
|
+
? Math.min(dpr, Math.floor(width * dpr) / width, Math.floor(height * dpr) / height) : dpr;
|
|
48
|
+
return { width, height, pixelWidth: Math.round(width * boundedDpr), pixelHeight: Math.round(height * boundedDpr), dpr: boundedDpr };
|
|
49
|
+
}
|
|
50
|
+
function releaseCanvas(canvas) {
|
|
51
|
+
canvas.width = 0;
|
|
52
|
+
canvas.height = 0;
|
|
53
|
+
}
|
|
54
|
+
export function prepareJourneyCanvas(canvas, size, reuse) {
|
|
55
|
+
const changed = canvas.width !== size.pixelWidth || canvas.height !== size.pixelHeight;
|
|
56
|
+
if (changed)
|
|
57
|
+
releaseCanvas(canvas); // Avoid an oversized intermediate width/height swap.
|
|
58
|
+
if (changed || !reuse) {
|
|
59
|
+
canvas.width = size.pixelWidth;
|
|
60
|
+
canvas.height = size.pixelHeight;
|
|
61
|
+
}
|
|
62
|
+
canvas.style.width = `${size.width}px`;
|
|
63
|
+
canvas.style.height = `${size.height}px`;
|
|
64
|
+
const context = canvas.getContext('2d');
|
|
65
|
+
if (!context || context.isContextLost?.())
|
|
66
|
+
return null;
|
|
67
|
+
// Never accumulate DPR transforms when the backing store is reused.
|
|
68
|
+
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
69
|
+
context.globalAlpha = 1;
|
|
70
|
+
context.globalCompositeOperation = 'source-over';
|
|
71
|
+
context.clearRect(0, 0, size.pixelWidth, size.pixelHeight);
|
|
72
|
+
context.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);
|
|
73
|
+
return context;
|
|
74
|
+
}
|
|
75
|
+
/** Per-map, memory-only, single-entry cache. No DOM or allocation until capture. */
|
|
76
|
+
export class JourneyBaseBitmap {
|
|
77
|
+
constructor() {
|
|
78
|
+
this.invalidate = () => { this.key = undefined; };
|
|
79
|
+
}
|
|
80
|
+
restore(context, key, offset = [0, 0]) {
|
|
81
|
+
if (key !== this.key || !this.canvas)
|
|
82
|
+
return false;
|
|
83
|
+
const cachedContext = this.canvas.getContext('2d');
|
|
84
|
+
if (!cachedContext || cachedContext.isContextLost?.()) {
|
|
85
|
+
this.clear();
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
context.save();
|
|
90
|
+
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
91
|
+
context.drawImage(this.canvas, offset[0], offset[1]);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
this.clear();
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
context.restore();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
capture(source, size, key) {
|
|
103
|
+
if (size.pixelWidth * size.pixelHeight > MAX_BASE_PIXELS) {
|
|
104
|
+
this.clear();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const canvas = this.canvas ?? document.createElement('canvas');
|
|
109
|
+
if (!this.canvas) {
|
|
110
|
+
canvas.addEventListener('contextlost', this.invalidate);
|
|
111
|
+
canvas.addEventListener('contextrestored', this.invalidate);
|
|
112
|
+
this.canvas = canvas;
|
|
113
|
+
}
|
|
114
|
+
this.key = undefined;
|
|
115
|
+
if (canvas.width !== size.pixelWidth || canvas.height !== size.pixelHeight) {
|
|
116
|
+
releaseCanvas(canvas);
|
|
117
|
+
canvas.width = size.pixelWidth;
|
|
118
|
+
canvas.height = size.pixelHeight;
|
|
119
|
+
}
|
|
120
|
+
const context = canvas.getContext('2d');
|
|
121
|
+
if (!context || context.isContextLost?.()) {
|
|
122
|
+
this.clear();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
126
|
+
context.clearRect(0, 0, size.pixelWidth, size.pixelHeight);
|
|
127
|
+
context.drawImage(source, 0, 0);
|
|
128
|
+
this.key = key;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Allocation/copy failures affect optimization, never the already drawn map.
|
|
132
|
+
this.clear();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
clear() {
|
|
136
|
+
this.key = undefined;
|
|
137
|
+
if (!this.canvas)
|
|
138
|
+
return;
|
|
139
|
+
this.canvas.removeEventListener('contextlost', this.invalidate);
|
|
140
|
+
this.canvas.removeEventListener('contextrestored', this.invalidate);
|
|
141
|
+
releaseCanvas(this.canvas);
|
|
142
|
+
this.canvas = undefined;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -3,6 +3,9 @@ import { type PencilPoint } from '../internal/stroke.js';
|
|
|
3
3
|
type Project = (position: Position) => PencilPoint;
|
|
4
4
|
export declare function paintSea(ctx: CanvasRenderingContext2D, width: number, height: number, anchor: PencilPoint): void;
|
|
5
5
|
export declare function mapFeatures(data: GeoJsonObject): Feature[];
|
|
6
|
-
|
|
6
|
+
/** Conservative x bounds of polygon edges inside a horizontal strip.
|
|
7
|
+
* Hole rings may widen the bounds, but never remove visible fill. */
|
|
8
|
+
export declare function terrainRowBounds(rings: readonly (readonly PencilPoint[])[], top: number, bottom: number): readonly [number, number] | undefined;
|
|
9
|
+
export declare function paintTerrain(ctx: CanvasRenderingContext2D, data: GeoJsonObject, project: Project, width: number, height: number, dark: boolean, defaultKind?: string, terrainViewport?: boolean): void;
|
|
7
10
|
export declare function paintStop(ctx: CanvasRenderingContext2D, x: number, y: number, seed: number, color: string, paper: string, selected: boolean): void;
|
|
8
11
|
export {};
|
|
@@ -45,14 +45,38 @@ export function mapFeatures(data) {
|
|
|
45
45
|
return [data];
|
|
46
46
|
return [{ type: 'Feature', properties: {}, geometry: data }];
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
/** Conservative x bounds of polygon edges inside a horizontal strip.
|
|
49
|
+
* Hole rings may widen the bounds, but never remove visible fill. */
|
|
50
|
+
export function terrainRowBounds(rings, top, bottom) {
|
|
51
|
+
let left = Infinity, right = -Infinity;
|
|
52
|
+
for (const ring of rings)
|
|
53
|
+
for (let i = 0; i < ring.length; i++) {
|
|
54
|
+
const [ax, ay] = ring[i], [bx, by] = ring[(i + 1) % ring.length];
|
|
55
|
+
if ((ay < top && by < top) || (ay > bottom && by > bottom))
|
|
56
|
+
continue;
|
|
57
|
+
if (!Number.isFinite(ax) || !Number.isFinite(ay) || !Number.isFinite(bx) || !Number.isFinite(by))
|
|
58
|
+
return [-Infinity, Infinity];
|
|
59
|
+
if (ay === by) {
|
|
60
|
+
left = Math.min(left, ax, bx);
|
|
61
|
+
right = Math.max(right, ax, bx);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const low = Math.max(0, Math.min(1, (top - ay) / (by - ay)));
|
|
65
|
+
const high = Math.max(0, Math.min(1, (bottom - ay) / (by - ay)));
|
|
66
|
+
const x1 = ax + (bx - ax) * low, x2 = ax + (bx - ax) * high;
|
|
67
|
+
left = Math.min(left, x1, x2);
|
|
68
|
+
right = Math.max(right, x1, x2);
|
|
69
|
+
}
|
|
70
|
+
return left <= right ? [left, right] : undefined;
|
|
71
|
+
}
|
|
72
|
+
export function paintTerrain(ctx, data, project, width, height, dark, defaultKind = 'land', terrainViewport = false) {
|
|
49
73
|
for (const [featureIndex, feature] of mapFeatures(data).entries()) {
|
|
50
74
|
const geometry = feature.geometry;
|
|
51
75
|
if (!geometry)
|
|
52
76
|
continue;
|
|
53
77
|
const polygons = geometry.type === 'MultiPolygon' ? geometry.coordinates : geometry.type === 'Polygon' ? [geometry.coordinates] : [];
|
|
54
78
|
const kind = String(feature.properties?.id ?? defaultKind);
|
|
55
|
-
const [fill, ink] = palette[kind] ?? palette.land;
|
|
79
|
+
const [fill, ink] = palette[kind] ?? palette[defaultKind] ?? palette.land;
|
|
56
80
|
for (const [polygonIndex, polygon] of polygons.entries()) {
|
|
57
81
|
const rings = polygon.map(ring => ring.map(project));
|
|
58
82
|
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
@@ -87,7 +111,15 @@ export function paintTerrain(ctx, data, project, width, height, dark, defaultKin
|
|
|
87
111
|
const spacing = kind === 'forest' ? 9 : 13;
|
|
88
112
|
const seed = 21000 + featureIndex * 43 + polygonIndex;
|
|
89
113
|
for (let row = Math.floor((top - origin[1]) / spacing); row <= Math.ceil((bottom - origin[1]) / spacing); row++) {
|
|
90
|
-
|
|
114
|
+
// Jitter, the 44px hatch, category glyphs and pencil bleed all fit this
|
|
115
|
+
// envelope. Keep the original world-grid indices and per-cell seeds.
|
|
116
|
+
const rowY = origin[1] + row * spacing;
|
|
117
|
+
const band = terrainViewport ? terrainRowBounds(rings, rowY - 25, rowY + 20) : [left, right];
|
|
118
|
+
if (!band)
|
|
119
|
+
continue;
|
|
120
|
+
const first = Math.max(Math.floor((left - origin[0]) / 36), terrainViewport ? Math.ceil((band[0] - origin[0] - 68) / 36) : -Infinity);
|
|
121
|
+
const last = Math.min(Math.ceil((right - origin[0]) / 36), terrainViewport ? Math.floor((band[1] - origin[0] + 17) / 36) : Infinity);
|
|
122
|
+
for (let col = first; col <= last; col++) {
|
|
91
123
|
const cell = (seed ^ Math.imul(col, 73856093) ^ Math.imul(row, 19349663)) >>> 0;
|
|
92
124
|
const rng = seededRandom(cell);
|
|
93
125
|
if (rng() < .2)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/** Trackpad pinch is independent of ordinary wheel scrolling and native touch zoom. */
|
|
2
|
+
export function attachJourneyTrackpad(host, map) {
|
|
3
|
+
let frame = 0;
|
|
4
|
+
let pending;
|
|
5
|
+
let gesture;
|
|
6
|
+
let touching = false;
|
|
7
|
+
let remainder = 0;
|
|
8
|
+
let lastWheel = -Infinity;
|
|
9
|
+
const clamp = (zoom) => Math.max(map.getMinZoom(), Math.min(map.getMaxZoom(), zoom));
|
|
10
|
+
const apply = () => {
|
|
11
|
+
frame = 0;
|
|
12
|
+
if (!pending)
|
|
13
|
+
return;
|
|
14
|
+
const { point, zoom } = pending;
|
|
15
|
+
pending = undefined;
|
|
16
|
+
const snap = map.options.zoomSnap ?? 0;
|
|
17
|
+
// Snap before calculating the anchor; Leaflet otherwise snaps only the
|
|
18
|
+
// final view and the coordinate under the pointer can drift.
|
|
19
|
+
const target = snap > 0 ? clamp(Math.round(zoom / snap) * snap) : zoom;
|
|
20
|
+
if (target !== map.getZoom())
|
|
21
|
+
map.setZoomAround(point, target, { animate: false });
|
|
22
|
+
// Preserve sub-snap movement across a wheel burst instead of losing tiny deltas.
|
|
23
|
+
remainder = zoom - map.getZoom();
|
|
24
|
+
};
|
|
25
|
+
const queue = (zoom, point) => {
|
|
26
|
+
pending = { zoom: clamp(zoom), point };
|
|
27
|
+
if (!frame)
|
|
28
|
+
frame = requestAnimationFrame(apply);
|
|
29
|
+
};
|
|
30
|
+
const pointAt = (event) => {
|
|
31
|
+
const size = map.getSize();
|
|
32
|
+
if (Number.isFinite(event.clientX) && Number.isFinite(event.clientY)) {
|
|
33
|
+
const point = map.mouseEventToContainerPoint(event);
|
|
34
|
+
if (point.x >= 0 && point.y >= 0 && point.x <= size.x && point.y <= size.y)
|
|
35
|
+
return point;
|
|
36
|
+
}
|
|
37
|
+
return size.divideBy(2);
|
|
38
|
+
};
|
|
39
|
+
const stop = (event) => { event.preventDefault(); event.stopImmediatePropagation(); };
|
|
40
|
+
const wheel = (event) => {
|
|
41
|
+
if (!event.ctrlKey)
|
|
42
|
+
return; // Plain two-finger scrolling continues to the page.
|
|
43
|
+
if (!Number.isFinite(event.deltaY))
|
|
44
|
+
return;
|
|
45
|
+
stop(event);
|
|
46
|
+
if (gesture || touching || event.deltaY === 0)
|
|
47
|
+
return;
|
|
48
|
+
const now = performance.now();
|
|
49
|
+
if (now - lastWheel > 160)
|
|
50
|
+
remainder = 0;
|
|
51
|
+
lastWheel = now;
|
|
52
|
+
const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? host.clientHeight : 1;
|
|
53
|
+
const pixels = Math.max(-100, Math.min(100, event.deltaY * unit));
|
|
54
|
+
queue((pending?.zoom ?? map.getZoom() + remainder) - pixels / (100 * Math.LN2), pointAt(event));
|
|
55
|
+
};
|
|
56
|
+
const start = (event) => {
|
|
57
|
+
if (touching)
|
|
58
|
+
return; // Leaflet owns physical touchscreen pinch.
|
|
59
|
+
const input = event;
|
|
60
|
+
stop(event);
|
|
61
|
+
map.stop();
|
|
62
|
+
if (frame)
|
|
63
|
+
cancelAnimationFrame(frame);
|
|
64
|
+
frame = 0;
|
|
65
|
+
pending = undefined;
|
|
66
|
+
remainder = 0;
|
|
67
|
+
gesture = { zoom: map.getZoom(), scale: input.scale && input.scale > 0 && Number.isFinite(input.scale) ? input.scale : 1, point: pointAt(input) };
|
|
68
|
+
};
|
|
69
|
+
const change = (event) => {
|
|
70
|
+
if (!gesture || touching)
|
|
71
|
+
return;
|
|
72
|
+
stop(event);
|
|
73
|
+
const scale = event.scale;
|
|
74
|
+
if (scale && scale > 0 && Number.isFinite(scale))
|
|
75
|
+
queue(gesture.zoom + Math.log2(scale / gesture.scale), gesture.point);
|
|
76
|
+
};
|
|
77
|
+
const end = (event) => {
|
|
78
|
+
change(event);
|
|
79
|
+
gesture = undefined;
|
|
80
|
+
};
|
|
81
|
+
const touch = (event) => {
|
|
82
|
+
touching = event.touches.length > 0;
|
|
83
|
+
if (touching && gesture) {
|
|
84
|
+
gesture = undefined;
|
|
85
|
+
pending = undefined;
|
|
86
|
+
if (frame)
|
|
87
|
+
cancelAnimationFrame(frame);
|
|
88
|
+
frame = 0;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
host.addEventListener('wheel', wheel, { capture: true, passive: false });
|
|
92
|
+
host.addEventListener('gesturestart', start, { passive: false });
|
|
93
|
+
host.addEventListener('gesturechange', change, { passive: false });
|
|
94
|
+
host.addEventListener('gestureend', end, { passive: false });
|
|
95
|
+
for (const type of ['touchstart', 'touchend', 'touchcancel'])
|
|
96
|
+
host.addEventListener(type, touch, { capture: true, passive: true });
|
|
97
|
+
const cleanup = () => {
|
|
98
|
+
map.off('unload', cleanup);
|
|
99
|
+
if (frame)
|
|
100
|
+
cancelAnimationFrame(frame);
|
|
101
|
+
host.removeEventListener('wheel', wheel, true);
|
|
102
|
+
host.removeEventListener('gesturestart', start);
|
|
103
|
+
host.removeEventListener('gesturechange', change);
|
|
104
|
+
host.removeEventListener('gestureend', end);
|
|
105
|
+
for (const type of ['touchstart', 'touchend', 'touchcancel'])
|
|
106
|
+
host.removeEventListener(type, touch, true);
|
|
107
|
+
};
|
|
108
|
+
map.on('unload', cleanup);
|
|
109
|
+
return cleanup;
|
|
110
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
.inkra-journey-map { min-width: 0; width: 100%; color: var(--inkra-ink); }
|
|
2
2
|
.inkra-journey-map__viewport { position: relative; overflow: hidden; isolation: isolate; background: var(--inkra-paper); }
|
|
3
3
|
.inkra-journey-map__host { position: absolute; inset: 0; background: transparent; font: inherit; }
|
|
4
|
-
.inkra-journey-map__ink { position: absolute;
|
|
4
|
+
.inkra-journey-map__ink { position: absolute; top: 0; left: 0; pointer-events: none; z-index: 350; }
|
|
5
5
|
.inkra-journey-map__tools { position: absolute; z-index: 600; inset-block-end: 9px; inset-inline-start: 9px; display: grid; gap: 4px; }
|
|
6
6
|
.inkra-journey-map__marker { display: grid; place-items: center; }
|
|
7
|
+
.inkra-journey-map__symbol, .inkra-journey-map__stop { display: block; width: 44px; height: 44px; }
|
|
8
|
+
.inkra-journey-map__stop { pointer-events: none; }
|
|
7
9
|
.inkra-journey-map__pin { position: absolute; top: 37px; left: 50%; transform: translateX(-50%); width: max-content; max-width: 140px; text-align: center; color: var(--inkra-ink); font: 14px/1.4 var(--inkra-font-hand); }
|
|
8
10
|
.inkra-journey-map__marker[aria-pressed="true"] .inkra-journey-map__pin { color: var(--inkra-accent-strong); }
|
|
9
11
|
.inkra-journey-map__orientation { position: absolute; bottom: 18px; right: 18px; z-index: 600; display: flex; align-items: end; gap: 12px; pointer-events: none; }
|
|
@@ -17,3 +19,14 @@
|
|
|
17
19
|
.inkra-journey-map__places button { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 8px; border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; }
|
|
18
20
|
.inkra-journey-map__places button[aria-pressed="true"] { text-decoration: underline; text-underline-offset: 4px; }
|
|
19
21
|
.inkra-journey-map button:focus-visible, .inkra-journey-map__marker:focus-visible { outline: 2px solid var(--inkra-focus); outline-offset: -2px; }
|
|
22
|
+
|
|
23
|
+
.inkra-journey-map__portal-owner { display: contents; }
|
|
24
|
+
.inkra-journey-map__custom-icon { display: grid; place-items: center; width: 44px; height: 44px; color: var(--inkra-accent-strong); }
|
|
25
|
+
.inkra-journey-map__custom-icon[hidden], .inkra-journey-map__stop[hidden] { display: none; }
|
|
26
|
+
.inkra-journey-map__caption { position: absolute; transform: translate(-50%, -50%); width: max-content; max-width: 150px; pointer-events: none; }
|
|
27
|
+
.inkra-journey-map__feature-label { padding: 3px 8px; font-size: 12px; line-height: 1.5; text-align: center; color: var(--inkra-ink); }
|
|
28
|
+
.inkra-journey-map__feature-label[data-selected="true"] { color: var(--inkra-accent-strong); }
|
|
29
|
+
.inkra-journey-map__features { display: flex; flex-wrap: wrap; list-style: none; gap: 8px; padding: 0; margin: 8px 0 0; }
|
|
30
|
+
.inkra-journey-map__features button { min-height: 44px; padding: 8px; border: 0; background: none; color: inherit; font: inherit; cursor: pointer; }
|
|
31
|
+
.inkra-journey-map__features [aria-pressed="true"] { text-decoration: underline; text-underline-offset: 4px; }
|
|
32
|
+
.inkra-journey-map__feature-hit:focus-visible { outline: 2px solid var(--inkra-focus); outline-offset: 2px; }
|
package/dist/styles/markdown.css
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
.inkra-markdown {
|
|
2
|
+
inline-size: 100%;
|
|
2
3
|
color: var(--inkra-ink);
|
|
3
4
|
font-family: var(--inkra-font-body);
|
|
4
5
|
font-size: var(--inkra-text-md);
|
|
@@ -203,6 +204,7 @@
|
|
|
203
204
|
.inkra-markdown__code-text > .inkra-pencil-text__source { font-family: inherit; }
|
|
204
205
|
|
|
205
206
|
.inkra-markdown__code-frame {
|
|
207
|
+
inline-size: 100%;
|
|
206
208
|
margin-block: 0 var(--inkra-space-4);
|
|
207
209
|
max-width: 100%;
|
|
208
210
|
min-width: 0;
|
package/dist/styles.css
CHANGED
|
@@ -8781,6 +8781,7 @@ div.inkra-choice-grid > .inkra-radio-group {
|
|
|
8781
8781
|
}
|
|
8782
8782
|
|
|
8783
8783
|
.inkra-markdown {
|
|
8784
|
+
inline-size: 100%;
|
|
8784
8785
|
color: var(--inkra-ink);
|
|
8785
8786
|
font-family: var(--inkra-font-body);
|
|
8786
8787
|
font-size: var(--inkra-text-md);
|
|
@@ -8985,6 +8986,7 @@ div.inkra-choice-grid > .inkra-radio-group {
|
|
|
8985
8986
|
.inkra-markdown__code-text > .inkra-pencil-text__source { font-family: inherit; }
|
|
8986
8987
|
|
|
8987
8988
|
.inkra-markdown__code-frame {
|
|
8989
|
+
inline-size: 100%;
|
|
8988
8990
|
margin-block: 0 var(--inkra-space-4);
|
|
8989
8991
|
max-width: 100%;
|
|
8990
8992
|
min-width: 0;
|
|
@@ -10018,9 +10020,11 @@ svg.leaflet-image-layer.leaflet-interactive path {
|
|
|
10018
10020
|
.inkra-journey-map { min-width: 0; width: 100%; color: var(--inkra-ink); }
|
|
10019
10021
|
.inkra-journey-map__viewport { position: relative; overflow: hidden; isolation: isolate; background: var(--inkra-paper); }
|
|
10020
10022
|
.inkra-journey-map__host { position: absolute; inset: 0; background: transparent; font: inherit; }
|
|
10021
|
-
.inkra-journey-map__ink { position: absolute;
|
|
10023
|
+
.inkra-journey-map__ink { position: absolute; top: 0; left: 0; pointer-events: none; z-index: 350; }
|
|
10022
10024
|
.inkra-journey-map__tools { position: absolute; z-index: 600; inset-block-end: 9px; inset-inline-start: 9px; display: grid; gap: 4px; }
|
|
10023
10025
|
.inkra-journey-map__marker { display: grid; place-items: center; }
|
|
10026
|
+
.inkra-journey-map__symbol, .inkra-journey-map__stop { display: block; width: 44px; height: 44px; }
|
|
10027
|
+
.inkra-journey-map__stop { pointer-events: none; }
|
|
10024
10028
|
.inkra-journey-map__pin { position: absolute; top: 37px; left: 50%; transform: translateX(-50%); width: max-content; max-width: 140px; text-align: center; color: var(--inkra-ink); font: 14px/1.4 var(--inkra-font-hand); }
|
|
10025
10029
|
.inkra-journey-map__marker[aria-pressed="true"] .inkra-journey-map__pin { color: var(--inkra-accent-strong); }
|
|
10026
10030
|
.inkra-journey-map__orientation { position: absolute; bottom: 18px; right: 18px; z-index: 600; display: flex; align-items: end; gap: 12px; pointer-events: none; }
|
|
@@ -10035,6 +10039,17 @@ svg.leaflet-image-layer.leaflet-interactive path {
|
|
|
10035
10039
|
.inkra-journey-map__places button[aria-pressed="true"] { text-decoration: underline; text-underline-offset: 4px; }
|
|
10036
10040
|
.inkra-journey-map button:focus-visible, .inkra-journey-map__marker:focus-visible { outline: 2px solid var(--inkra-focus); outline-offset: -2px; }
|
|
10037
10041
|
|
|
10042
|
+
.inkra-journey-map__portal-owner { display: contents; }
|
|
10043
|
+
.inkra-journey-map__custom-icon { display: grid; place-items: center; width: 44px; height: 44px; color: var(--inkra-accent-strong); }
|
|
10044
|
+
.inkra-journey-map__custom-icon[hidden], .inkra-journey-map__stop[hidden] { display: none; }
|
|
10045
|
+
.inkra-journey-map__caption { position: absolute; transform: translate(-50%, -50%); width: max-content; max-width: 150px; pointer-events: none; }
|
|
10046
|
+
.inkra-journey-map__feature-label { padding: 3px 8px; font-size: 12px; line-height: 1.5; text-align: center; color: var(--inkra-ink); }
|
|
10047
|
+
.inkra-journey-map__feature-label[data-selected="true"] { color: var(--inkra-accent-strong); }
|
|
10048
|
+
.inkra-journey-map__features { display: flex; flex-wrap: wrap; list-style: none; gap: 8px; padding: 0; margin: 8px 0 0; }
|
|
10049
|
+
.inkra-journey-map__features button { min-height: 44px; padding: 8px; border: 0; background: none; color: inherit; font: inherit; cursor: pointer; }
|
|
10050
|
+
.inkra-journey-map__features [aria-pressed="true"] { text-decoration: underline; text-underline-offset: 4px; }
|
|
10051
|
+
.inkra-journey-map__feature-hit:focus-visible { outline: 2px solid var(--inkra-focus); outline-offset: 2px; }
|
|
10052
|
+
|
|
10038
10053
|
.inkra-toast__theme-anchor { display: none; }
|
|
10039
10054
|
|
|
10040
10055
|
.inkra-toast__viewport {
|