@riebeckite/plugin-map 0.0.31 → 0.0.33
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 +12 -1
- package/README_ja.md +20 -9
- package/dist/client.js +13 -3
- package/dist/index.d.ts +0 -2
- package/dist/index.js +25 -51
- package/dist/src/hast.d.ts +6 -6
- package/dist/src/init.d.ts +7 -1
- package/dist/src/options.d.ts +0 -22
- package/dist/src/types.d.ts +4 -3
- package/package.json +3 -2
- package/style.css +0 -20
package/README.md
CHANGED
|
@@ -77,6 +77,17 @@ map:
|
|
|
77
77
|
`lat`/`lng` also accept `latitude`/`longitude`, `coordinates: [lat, lng]` or
|
|
78
78
|
`coordinates: "lat, lng"`, and `label` also accepts `title`/`place`/`name`.
|
|
79
79
|
|
|
80
|
+
## Live example
|
|
81
|
+
|
|
82
|
+
~~~map
|
|
83
|
+
center: 35.6812, 139.7671
|
|
84
|
+
zoom: 13
|
|
85
|
+
label: Tokyo Station
|
|
86
|
+
markers:
|
|
87
|
+
- 35.6812, 139.7671 | Tokyo Station
|
|
88
|
+
- 35.6586, 139.7454 | Tokyo Tower
|
|
89
|
+
~~~
|
|
90
|
+
|
|
80
91
|
## How it renders
|
|
81
92
|
|
|
82
93
|
A block or frontmatter map becomes a `figure.rr-map`:
|
|
@@ -156,7 +167,7 @@ to inject a fake Leaflet).
|
|
|
156
167
|
|
|
157
168
|
## Main exports
|
|
158
169
|
|
|
159
|
-
- `map(options?)`: create the plugin (`
|
|
170
|
+
- `map(options?)`: create the plugin (`map` is an alias)
|
|
160
171
|
- `initMap`: initialize client-side maps
|
|
161
172
|
- `parseMapSource`: parse a fenced block into `MapData`
|
|
162
173
|
- `normalizeMapInput`: normalize frontmatter into `MapData`
|
package/README_ja.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[English](./README.md)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 使い方
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
12
|
import { defineConfig } from "@riebeckite/core";
|
|
@@ -33,7 +33,7 @@ export default defineConfig({
|
|
|
33
33
|
|
|
34
34
|
### コードブロック
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
ブロック本文は簡単なキーと値の形式です。`markers:` の後に `-` でマーカーを並べ、`lat, lng` だけの行は暗黙のマーカーになります。
|
|
37
37
|
|
|
38
38
|
````markdown
|
|
39
39
|
```map
|
|
@@ -70,7 +70,18 @@ map:
|
|
|
70
70
|
|
|
71
71
|
`lat`/`lng` は `latitude`/`longitude`、`coordinates: [lat, lng]` または `coordinates: "lat, lng"` も受け付けます。`label` は `title`/`place`/`name` も使えます。
|
|
72
72
|
|
|
73
|
-
##
|
|
73
|
+
## 実行例
|
|
74
|
+
|
|
75
|
+
~~~map
|
|
76
|
+
center: 35.6812, 139.7671
|
|
77
|
+
zoom: 13
|
|
78
|
+
label: Tokyo Station
|
|
79
|
+
markers:
|
|
80
|
+
- 35.6812, 139.7671 | Tokyo Station
|
|
81
|
+
- 35.6586, 139.7454 | Tokyo Tower
|
|
82
|
+
~~~
|
|
83
|
+
|
|
84
|
+
## 描画の仕組み
|
|
74
85
|
|
|
75
86
|
コードブロックまたは frontmatter の地図は `figure.rr-map` になります。
|
|
76
87
|
|
|
@@ -80,7 +91,7 @@ map:
|
|
|
80
91
|
- `div.rr-map__static`: 常に利用できるフォールバック。`p.rr-map__place`、`ul.rr-map__markers` → `a.rr-map__link`(OpenStreetMap リンク)、任意の `img.rr-map__image`、`p.rr-map__attribution` を含みます
|
|
81
92
|
- `details.rr-map__fallback`: 元のブロック本文を折りたたんで表示
|
|
82
93
|
|
|
83
|
-
`initMap` は `[data-rr-map="pending"]` を探し、Leaflet
|
|
94
|
+
`initMap` は `[data-rr-map="pending"]` を探し、Leaflet を遅延読み込みします。タイルレイヤーとマーカーを描画して `data-rr-map="rendered"` にします(このとき静的フォールバックは非表示になります)。失敗した場合は `data-rr-map="error"` になり、`details` を開き、静的フォールバックは表示されたままになります。
|
|
84
95
|
|
|
85
96
|
座標も `center` もないブロックは置き換えず、通常のコードブロックのまま残し、`source: "@riebeckite/plugin-map"` を持つ診断を出します。
|
|
86
97
|
|
|
@@ -103,7 +114,7 @@ map:
|
|
|
103
114
|
|
|
104
115
|
## タイルと帰属表示
|
|
105
116
|
|
|
106
|
-
既定はキー不要の [OpenStreetMap 標準タイル](https://tile.openstreetmap.org/) です。小規模なサイトには十分ですが、OpenStreetMap の[タイル利用ポリシー](https://operations.osmfoundation.org/policies/tiles/)
|
|
117
|
+
既定はキー不要の [OpenStreetMap 標準タイル](https://tile.openstreetmap.org/) です。小規模なサイトには十分ですが、OpenStreetMap の[タイル利用ポリシー](https://operations.osmfoundation.org/policies/tiles/)は、識別可能なリファラーを前提とし、一括取得や高負荷な利用を禁じています。一定のトラフィックがあるサイトは `tileUrl` を自前のタイルサーバーや商用プロバイダに向けてください。
|
|
107
118
|
|
|
108
119
|
帰属表示は省略できません。`attribution` は Leaflet に渡され、静的フォールバックにも(プレーンテキストで)描画されます。プロバイダが要求するクレジットを常に表示してください。
|
|
109
120
|
|
|
@@ -111,11 +122,11 @@ map:
|
|
|
111
122
|
|
|
112
123
|
## クライアント側の描画
|
|
113
124
|
|
|
114
|
-
`[data-rr-map="pending"]` の figure が 1 つ以上あるときだけ取得します。取得元は jsDelivr
|
|
125
|
+
`[data-rr-map="pending"]` の figure が 1 つ以上あるときだけ取得します。取得元は jsDelivr の Leaflet(`leaflet.js` と `leaflet.css`)です。遅延読み込みなので、地図のないページに負担はかかりません。地図のあるページでも、JavaScript が無効だったり CDN に到達できなかったりすれば、静的フォールバックが表示されます。
|
|
115
126
|
|
|
116
|
-
`initMap(options?)` が受け取るオプションは次のとおりです。`tileUrl`、`attribution`、`minZoom`、`maxZoom`、`leafletScriptUrl`、`leafletStyleUrl`。さらに、事前読み込み済みの `runtime`
|
|
127
|
+
`initMap(options?)` が受け取るオプションは次のとおりです。`tileUrl`、`attribution`、`minZoom`、`maxZoom`、`leafletScriptUrl`、`leafletStyleUrl`。さらに、事前読み込み済みの `runtime` も指定できます(テストでモックの Leaflet を注入する用途)。
|
|
117
128
|
|
|
118
|
-
##
|
|
129
|
+
## 出力フック
|
|
119
130
|
|
|
120
131
|
- `figure[data-rr-map]`: 状態(`pending` / `rendered` / `error`)
|
|
121
132
|
- `figure[data-rr-map-payload]`: 解決済みの地図データ JSON
|
|
@@ -125,7 +136,7 @@ map:
|
|
|
125
136
|
|
|
126
137
|
## 主なエクスポート
|
|
127
138
|
|
|
128
|
-
- `map(options?)`: プラグインを作成する(`
|
|
139
|
+
- `map(options?)`: プラグインを作成する(`map` は別名)
|
|
129
140
|
- `initMap`: クライアント側の地図を初期化する
|
|
130
141
|
- `parseMapSource`: コードブロックを `MapData` に変換する
|
|
131
142
|
- `normalizeMapInput`: frontmatter を `MapData` に正規化する
|
package/dist/client.js
CHANGED
|
@@ -4,19 +4,28 @@ var DEFAULT_LEAFLET_STYLE_URL = "https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist
|
|
|
4
4
|
var DEFAULT_TILE_URL = "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
|
|
5
5
|
var DEFAULT_ATTRIBUTION = '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
|
|
6
6
|
var leafletPromise = null;
|
|
7
|
-
async function initMap(
|
|
7
|
+
async function initMap(context = {}) {
|
|
8
|
+
const options = context.config ?? {};
|
|
9
|
+
const root = context.root ?? document;
|
|
8
10
|
const figures = Array.from(
|
|
9
|
-
|
|
11
|
+
root.querySelectorAll('[data-rr-map="pending"]')
|
|
10
12
|
);
|
|
11
13
|
if (figures.length === 0) return;
|
|
12
14
|
const runtime = options.runtime ?? await loadLeaflet(options);
|
|
15
|
+
if (context.signal?.aborted) return;
|
|
13
16
|
if (!runtime) {
|
|
14
17
|
for (const figure of figures) setError(figure);
|
|
15
18
|
return;
|
|
16
19
|
}
|
|
20
|
+
const maps = [];
|
|
17
21
|
for (const figure of figures) {
|
|
18
|
-
|
|
22
|
+
if (context.signal?.aborted || !figure.isConnected) break;
|
|
23
|
+
const map = renderMap(runtime, figure, options);
|
|
24
|
+
if (map) maps.push(map);
|
|
19
25
|
}
|
|
26
|
+
return () => {
|
|
27
|
+
for (const map of maps) map.remove();
|
|
28
|
+
};
|
|
20
29
|
}
|
|
21
30
|
function renderMap(runtime, figure, options) {
|
|
22
31
|
const canvas = figure.querySelector("[data-rr-map-canvas]");
|
|
@@ -57,6 +66,7 @@ function renderMap(runtime, figure, options) {
|
|
|
57
66
|
map.setView([payload.center.lat, payload.center.lng], payload.zoom);
|
|
58
67
|
}
|
|
59
68
|
figure.dataset.rrMap = "rendered";
|
|
69
|
+
return map;
|
|
60
70
|
} catch {
|
|
61
71
|
setError(figure);
|
|
62
72
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,5 +13,3 @@ export declare const MAP_PLUGIN_NAME = "map";
|
|
|
13
13
|
* map is present and upgrades each figure to an interactive map.
|
|
14
14
|
*/
|
|
15
15
|
export declare function map(options?: MapOptions): import("@riebeckite/core").RiebeckitePlugin<MapOptions>;
|
|
16
|
-
/** Alias matching the `*Plugin` suffix used by other plugin factories. */
|
|
17
|
-
export declare const mapPlugin: typeof map;
|
package/dist/index.js
CHANGED
|
@@ -56,50 +56,20 @@ function clampZoom(value, minimum = 1) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// src/hast.ts
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
function text(value) {
|
|
74
|
-
return { type: "text", value };
|
|
75
|
-
}
|
|
76
|
-
function getTextContent(node) {
|
|
77
|
-
if (node.type === "text" && "value" in node && typeof node.value === "string") {
|
|
78
|
-
return node.value;
|
|
79
|
-
}
|
|
80
|
-
return getChildren(node).map(getTextContent).join("");
|
|
81
|
-
}
|
|
82
|
-
function getStringProperty(node, key) {
|
|
83
|
-
const value = node.properties?.[key];
|
|
84
|
-
if (typeof value === "string") return value;
|
|
85
|
-
if (Array.isArray(value)) return value.join(" ");
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
function hasClass(node, className) {
|
|
89
|
-
const value = node.properties?.className;
|
|
90
|
-
const classes = Array.isArray(value) ? value.map(String) : typeof value === "string" ? value.split(/\s+/) : [];
|
|
91
|
-
return classes.includes(className);
|
|
92
|
-
}
|
|
93
|
-
function isElementNode(node) {
|
|
94
|
-
return node.type === "element";
|
|
95
|
-
}
|
|
96
|
-
function hasChildren(node) {
|
|
97
|
-
return Array.isArray(node.children);
|
|
98
|
-
}
|
|
99
|
-
function getChildren(node) {
|
|
100
|
-
const children = node.children;
|
|
101
|
-
return Array.isArray(children) ? children : [];
|
|
102
|
-
}
|
|
59
|
+
import {
|
|
60
|
+
element as sharedElement,
|
|
61
|
+
getStringProperty as sharedGetStringProperty,
|
|
62
|
+
getTextContent as sharedGetTextContent,
|
|
63
|
+
hasClass as sharedHasClass,
|
|
64
|
+
text as sharedText,
|
|
65
|
+
visitElements as sharedVisitElements
|
|
66
|
+
} from "@riebeckite/diagram";
|
|
67
|
+
var element = sharedElement;
|
|
68
|
+
var text = sharedText;
|
|
69
|
+
var getTextContent = sharedGetTextContent;
|
|
70
|
+
var getStringProperty = sharedGetStringProperty;
|
|
71
|
+
var hasClass = sharedHasClass;
|
|
72
|
+
var visitElements = sharedVisitElements;
|
|
103
73
|
|
|
104
74
|
// src/parse.ts
|
|
105
75
|
var KEY_VALUE = /^([A-Za-z][\w-]*)\s*:\s*(.*)$/;
|
|
@@ -422,10 +392,14 @@ function buildFigure(input) {
|
|
|
422
392
|
}
|
|
423
393
|
if (options.fallback && input.source) {
|
|
424
394
|
children.push(
|
|
425
|
-
element(
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
395
|
+
element(
|
|
396
|
+
"details",
|
|
397
|
+
{ className: `${options.className}__fallback rb-source-fallback` },
|
|
398
|
+
[
|
|
399
|
+
element("summary", {}, [text("Map source")]),
|
|
400
|
+
element("pre", {}, [element("code", {}, [text(input.source)])])
|
|
401
|
+
]
|
|
402
|
+
)
|
|
429
403
|
);
|
|
430
404
|
}
|
|
431
405
|
return element(
|
|
@@ -578,12 +552,13 @@ function map(options = {}) {
|
|
|
578
552
|
attribution: resolved.attribution,
|
|
579
553
|
minZoom: resolved.minZoom,
|
|
580
554
|
maxZoom: resolved.maxZoom
|
|
581
|
-
}
|
|
555
|
+
},
|
|
556
|
+
void 0,
|
|
557
|
+
"context"
|
|
582
558
|
)
|
|
583
559
|
]
|
|
584
560
|
});
|
|
585
561
|
}
|
|
586
|
-
var mapPlugin = map;
|
|
587
562
|
function validateMapOptions(options) {
|
|
588
563
|
if (!options) return [];
|
|
589
564
|
const issues = [];
|
|
@@ -630,7 +605,6 @@ export {
|
|
|
630
605
|
describeMap,
|
|
631
606
|
formatCoordinates,
|
|
632
607
|
map,
|
|
633
|
-
mapPlugin,
|
|
634
608
|
normalizeMapInput,
|
|
635
609
|
openStreetMapUrl,
|
|
636
610
|
parseMapSource,
|
package/dist/src/hast.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ElementNode, HastNode, ParentNode, TextNode } from "./types.js";
|
|
2
|
-
export declare
|
|
3
|
-
export declare
|
|
4
|
-
export declare
|
|
5
|
-
export declare
|
|
6
|
-
export declare
|
|
7
|
-
export declare
|
|
2
|
+
export declare const element: (tagName: string, properties?: Record<string, unknown>, children?: HastNode[]) => ElementNode;
|
|
3
|
+
export declare const text: (value: string) => TextNode;
|
|
4
|
+
export declare const getTextContent: (node: HastNode) => string;
|
|
5
|
+
export declare const getStringProperty: (node: ElementNode, key: string) => string | null;
|
|
6
|
+
export declare const hasClass: (node: ElementNode, className: string) => boolean;
|
|
7
|
+
export declare const visitElements: (node: HastNode, visitor: (node: ElementNode, parent?: ParentNode, index?: number) => void, parent?: ParentNode, index?: number) => void;
|
package/dist/src/init.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { MapClientOptions } from "./types.js";
|
|
2
|
+
type ClientContext = {
|
|
3
|
+
root?: ParentNode;
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
config?: MapClientOptions;
|
|
6
|
+
};
|
|
2
7
|
/**
|
|
3
8
|
* Upgrades every server-emitted `[data-rr-map="pending"]` figure to an
|
|
4
9
|
* interactive Leaflet map.
|
|
@@ -8,4 +13,5 @@ import type { MapClientOptions } from "./types.js";
|
|
|
8
13
|
* `data-rr-map-payload`, which means the page still renders its static
|
|
9
14
|
* fallback when JavaScript is disabled or the CDN is unreachable.
|
|
10
15
|
*/
|
|
11
|
-
export declare function initMap(
|
|
16
|
+
export declare function initMap(context?: ClientContext): Promise<undefined | (() => void)>;
|
|
17
|
+
export {};
|
package/dist/src/options.d.ts
CHANGED
|
@@ -1,26 +1,4 @@
|
|
|
1
1
|
import type { MapOptions, ResolvedMapOptions } from "./types.js";
|
|
2
|
-
/** Default base class for the generated figure. */
|
|
3
|
-
export declare const DEFAULT_MAP_CLASS_NAME = "rr-map";
|
|
4
|
-
/** Default map height in pixels. */
|
|
5
|
-
export declare const DEFAULT_MAP_HEIGHT = 320;
|
|
6
|
-
/** Default fenced-code language. */
|
|
7
|
-
export declare const DEFAULT_MAP_LANGUAGE = "map";
|
|
8
|
-
/** Default zoom level. */
|
|
9
|
-
export declare const DEFAULT_MAP_ZOOM = 13;
|
|
10
|
-
/** Default minimum zoom level. */
|
|
11
|
-
export declare const DEFAULT_MAP_MIN_ZOOM = 1;
|
|
12
|
-
/** Default maximum zoom level (OpenStreetMap's standard maximum). */
|
|
13
|
-
export declare const DEFAULT_MAP_MAX_ZOOM = 19;
|
|
14
|
-
/** Frontmatter property read for coordinates by default. */
|
|
15
|
-
export declare const DEFAULT_MAP_FRONTMATTER_KEY = "map";
|
|
16
|
-
/**
|
|
17
|
-
* Default OpenStreetMap tile template. It is keyless and safe to expose to the
|
|
18
|
-
* browser, but sites with meaningful traffic should follow the tile usage
|
|
19
|
-
* policy or point `tileUrl` at their own tile server.
|
|
20
|
-
*/
|
|
21
|
-
export declare const DEFAULT_MAP_TILE_URL = "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
|
|
22
|
-
/** Attribution required by the default tile provider. */
|
|
23
|
-
export declare const DEFAULT_MAP_ATTRIBUTION = "© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors";
|
|
24
2
|
/**
|
|
25
3
|
* Applies defaults to the user-provided options.
|
|
26
4
|
*
|
package/dist/src/types.d.ts
CHANGED
|
@@ -121,11 +121,11 @@ export type MapClientOptions = {
|
|
|
121
121
|
runtime?: MapRuntime;
|
|
122
122
|
};
|
|
123
123
|
/** The subset of the Leaflet API the initializer uses. */
|
|
124
|
-
|
|
124
|
+
type LeafletLayer = {
|
|
125
125
|
addTo(map: LeafletMap): LeafletLayer;
|
|
126
126
|
bindPopup?(content: string): LeafletLayer;
|
|
127
127
|
};
|
|
128
|
-
|
|
128
|
+
type LeafletMap = {
|
|
129
129
|
setView(center: [number, number], zoom: number): LeafletMap;
|
|
130
130
|
fitBounds(bounds: unknown, options?: Record<string, unknown>): LeafletMap;
|
|
131
131
|
remove(): void;
|
|
@@ -149,7 +149,7 @@ export type TextNode = {
|
|
|
149
149
|
type: "text";
|
|
150
150
|
value: string;
|
|
151
151
|
};
|
|
152
|
-
|
|
152
|
+
type RawNode = {
|
|
153
153
|
type: "raw";
|
|
154
154
|
value: string;
|
|
155
155
|
};
|
|
@@ -157,3 +157,4 @@ export type HastNode = ElementNode | TextNode | RawNode | {
|
|
|
157
157
|
type: string;
|
|
158
158
|
[key: string]: unknown;
|
|
159
159
|
};
|
|
160
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/plugin-map",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.33",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"./style.css": "./style.css"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@riebeckite/core": "0.0.
|
|
24
|
+
"@riebeckite/core": "0.0.33",
|
|
25
|
+
"@riebeckite/diagram": "0.0.33"
|
|
25
26
|
},
|
|
26
27
|
"publishConfig": {
|
|
27
28
|
"access": "public"
|
package/style.css
CHANGED
|
@@ -75,26 +75,6 @@
|
|
|
75
75
|
font-size: 0.75rem;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
.rr-map__fallback {
|
|
79
|
-
border-top: 1px solid var(--rr-map-rule);
|
|
80
|
-
color: var(--rr-map-muted);
|
|
81
|
-
font-size: 0.8125rem;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.rr-map__fallback summary {
|
|
85
|
-
cursor: pointer;
|
|
86
|
-
padding: 0.5rem 0.75rem;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.rr-map__fallback pre {
|
|
90
|
-
overflow: auto;
|
|
91
|
-
margin: 0 1rem;
|
|
92
|
-
padding: 0.75rem;
|
|
93
|
-
border-top: 1px solid var(--rr-map-rule);
|
|
94
|
-
color: var(--rr-map-ink);
|
|
95
|
-
background: color-mix(in srgb, var(--rr-map-ink) 6%, transparent);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
78
|
.rr-map[data-rr-map="error"] .rr-map__static::before {
|
|
99
79
|
content: "The interactive map could not be loaded. ";
|
|
100
80
|
color: var(--rr-map-muted);
|