@abcnews/components-storylab 0.0.1 → 0.0.2
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 +60 -3
- package/dist/index.js +1 -0
- package/dist/mapLibre/MapLibreLoader/MapLibreLoader.stories.svelte +58 -0
- package/dist/mapLibre/MapLibreLoader/MapLibreLoader.stories.svelte.d.ts +27 -0
- package/dist/mapLibre/MapLibreLoader/MapLibreLoader.svelte +48 -0
- package/dist/mapLibre/MapLibreLoader/MapLibreLoader.svelte.d.ts +14 -0
- package/dist/mapLibre/index.d.ts +3 -0
- package/dist/mapLibre/index.js +3 -0
- package/dist/mapLibre/maplibre.d.ts +6 -0
- package/dist/mapLibre/utils.d.ts +20 -0
- package/dist/mapLibre/utils.js +58 -0
- package/package.json +24 -10
package/README.md
CHANGED
|
@@ -2,9 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
A live repo containing reusable components and snippts by Story Lab. This repo is subject to change.
|
|
4
4
|
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
1. Install the package:
|
|
8
|
+
```sh
|
|
9
|
+
npm i @abcnews/components-storylab
|
|
10
|
+
```
|
|
11
|
+
2. Add the package to your `aunty` config's `includedDependencies` array in `package.json` so it gets built properly:
|
|
12
|
+
```js
|
|
13
|
+
"aunty": {
|
|
14
|
+
"type": "svelte",
|
|
15
|
+
"build": {
|
|
16
|
+
"includedDependencies": [
|
|
17
|
+
"@abcnews/components-storylab"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
5
23
|
## Components
|
|
6
24
|
|
|
7
|
-
### initDarkModeIframe
|
|
25
|
+
### 🌃 initDarkModeIframe
|
|
8
26
|
|
|
9
27
|
Initializes dark mode inside an iframe, synchronizing with the parent site or system preferences.
|
|
10
28
|
|
|
@@ -16,8 +34,47 @@ import { initDarkModeIframe } from "@abcnews/components-storylab";
|
|
|
16
34
|
initDarkModeIframe();
|
|
17
35
|
```
|
|
18
36
|
|
|
37
|
+
### 🌏 MapLibre
|
|
38
|
+
|
|
39
|
+
Tools and components for working with MapLibre. The `utils` export gives you the
|
|
40
|
+
tools to do this yourself, whereas the MapLibreLoader component handles it for
|
|
41
|
+
you in Svelte. Import these from `@abcnews/components-storylab/mapLibre`.
|
|
42
|
+
|
|
43
|
+
#### MapLibreLoader
|
|
44
|
+
|
|
45
|
+
Call back when MapLibre is loaded. Passes the `maplibre` namespace and a root
|
|
46
|
+
node for you to use.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import type { maplibregl } from "@abcnews/components-storylab/mapLibre";
|
|
50
|
+
import { MapLibreLoader, utils } from "@abcnews/components-storylab/mapLibre";
|
|
51
|
+
|
|
52
|
+
// Load MapLibre and use it in your component
|
|
53
|
+
const { loadMapLibre, STYLE_BRIGHT, STYLE_LIGHT } = utils;
|
|
54
|
+
|
|
55
|
+
// Example of using MapLibreLoader in a Svelte component
|
|
56
|
+
<MapLibreLoader
|
|
57
|
+
onLoad={({ rootNode, maplibregl }) => {
|
|
58
|
+
const map = new maplibregl.Map({
|
|
59
|
+
container: rootNode,
|
|
60
|
+
style: STYLE_BRIGHT,
|
|
61
|
+
});
|
|
62
|
+
return map;
|
|
63
|
+
}}
|
|
64
|
+
/>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
If you return the Map from `onLoad`, you can componentise your viz and access it
|
|
68
|
+
from child components with:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
let { map } = getContext<Map>("mapInstance");
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This component will attempt to keep the map stable, so you can not change
|
|
75
|
+
props after the fact. If you want to destroy the map and create a new one
|
|
76
|
+
when props change, wrap it in a {#key}{/key} block/
|
|
77
|
+
|
|
19
78
|
## Developing
|
|
20
79
|
|
|
21
80
|
See [DEVELOPMENT.md](DEVELOPMENT.md)
|
|
22
|
-
|
|
23
|
-
Note: I haven't been able to `npm link` svelte components into an Aunty project. If you work this out please let me know.
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script module>
|
|
2
|
+
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
+
import MapLibreLoader from "./MapLibreLoader.svelte";
|
|
4
|
+
|
|
5
|
+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
|
|
6
|
+
const { Story } = defineMeta({
|
|
7
|
+
title: "MapLibre/MapLibreLoader",
|
|
8
|
+
component: MapLibreLoader,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
});
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<Story
|
|
14
|
+
name="Bright style"
|
|
15
|
+
args={{
|
|
16
|
+
rootElStyle: "width:100%;height:calc(100dvh - 2rem);",
|
|
17
|
+
onLoad: async ({ rootNode, maplibregl }) => {
|
|
18
|
+
const map = new maplibregl.Map({
|
|
19
|
+
zoom: 3,
|
|
20
|
+
minZoom: 2,
|
|
21
|
+
maxZoom: 22,
|
|
22
|
+
attributionControl: false,
|
|
23
|
+
dragRotate: false,
|
|
24
|
+
doubleClickZoom: false,
|
|
25
|
+
style:
|
|
26
|
+
"https://www.abc.net.au/res/sites/news-projects/map-vector-style-bright/style.json",
|
|
27
|
+
container: rootNode,
|
|
28
|
+
interactive: true,
|
|
29
|
+
cooperativeGestures: true,
|
|
30
|
+
center: [133.28, -28.15],
|
|
31
|
+
});
|
|
32
|
+
return map;
|
|
33
|
+
},
|
|
34
|
+
}}
|
|
35
|
+
></Story>
|
|
36
|
+
<Story
|
|
37
|
+
name="Light style"
|
|
38
|
+
args={{
|
|
39
|
+
rootElStyle: "width:100%;height:calc(100dvh - 2rem);",
|
|
40
|
+
onLoad: async ({ rootNode, maplibregl }) => {
|
|
41
|
+
const map = new maplibregl.Map({
|
|
42
|
+
zoom: 3,
|
|
43
|
+
minZoom: 2,
|
|
44
|
+
maxZoom: 22,
|
|
45
|
+
attributionControl: false,
|
|
46
|
+
dragRotate: false,
|
|
47
|
+
doubleClickZoom: false,
|
|
48
|
+
style:
|
|
49
|
+
"https://www.abc.net.au/res/sites/news-projects/map-vector-style-light/style.json",
|
|
50
|
+
container: rootNode,
|
|
51
|
+
interactive: true,
|
|
52
|
+
cooperativeGestures: true,
|
|
53
|
+
center: [133.28, -28.15],
|
|
54
|
+
});
|
|
55
|
+
return map;
|
|
56
|
+
},
|
|
57
|
+
}}
|
|
58
|
+
></Story>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export default MapLibreLoader;
|
|
2
|
+
type MapLibreLoader = SvelteComponent<{
|
|
3
|
+
[x: string]: never;
|
|
4
|
+
}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> & {
|
|
7
|
+
$$bindings?: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare const MapLibreLoader: $$__sveltets_2_IsomorphicComponent<{
|
|
10
|
+
[x: string]: never;
|
|
11
|
+
}, {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
}, {}, {}, string>;
|
|
14
|
+
import MapLibreLoader from "./MapLibreLoader.svelte";
|
|
15
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
16
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
17
|
+
$$bindings?: Bindings;
|
|
18
|
+
} & Exports;
|
|
19
|
+
(internal: unknown, props: {
|
|
20
|
+
$$events?: Events;
|
|
21
|
+
$$slots?: Slots;
|
|
22
|
+
}): Exports & {
|
|
23
|
+
$set?: any;
|
|
24
|
+
$on?: any;
|
|
25
|
+
};
|
|
26
|
+
z_$$bindings?: Bindings;
|
|
27
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount, setContext, untrack } from "svelte";
|
|
3
|
+
import { loadMapLibre } from "../utils.js";
|
|
4
|
+
import type { maplibregl } from "../maplibre.d.js";
|
|
5
|
+
import type { Snippet } from "svelte";
|
|
6
|
+
type Props = {
|
|
7
|
+
rootElStyle?: string;
|
|
8
|
+
onLoad: ({}: {
|
|
9
|
+
rootNode: HTMLDivElement;
|
|
10
|
+
maplibregl: typeof maplibregl;
|
|
11
|
+
}) => maplibregl.Map | Promise<maplibregl.Map> | void | Promise<void>;
|
|
12
|
+
onTeardown?: () => void | Promise<void>;
|
|
13
|
+
children?: Snippet;
|
|
14
|
+
};
|
|
15
|
+
const {
|
|
16
|
+
rootElStyle = "width:100%;height:100%;",
|
|
17
|
+
onLoad,
|
|
18
|
+
children,
|
|
19
|
+
}: Props = $props();
|
|
20
|
+
let rootNode = $state<HTMLDivElement>();
|
|
21
|
+
let status = $state<"loading" | "loaded">("loading");
|
|
22
|
+
let mapInstance = $state<{ map: maplibregl.Map | void }>({ map: undefined });
|
|
23
|
+
setContext("mapInstance", mapInstance);
|
|
24
|
+
|
|
25
|
+
onMount(async () => {
|
|
26
|
+
if (!rootNode) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
await loadMapLibre();
|
|
30
|
+
const newMapInstance = await onLoad({
|
|
31
|
+
rootNode,
|
|
32
|
+
maplibregl: window.maplibregl,
|
|
33
|
+
});
|
|
34
|
+
mapInstance.map = newMapInstance;
|
|
35
|
+
status = "loaded";
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<div class="maplibre" bind:this={rootNode} style={rootElStyle}>
|
|
40
|
+
{@render children?.()}
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<style>
|
|
44
|
+
.maplibre {
|
|
45
|
+
width: 100%;
|
|
46
|
+
height: 100%;
|
|
47
|
+
}
|
|
48
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { maplibregl } from "../maplibre.d.ts";
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
type Props = {
|
|
4
|
+
rootElStyle?: string;
|
|
5
|
+
onLoad: ({}: {
|
|
6
|
+
rootNode: HTMLDivElement;
|
|
7
|
+
maplibregl: typeof maplibregl;
|
|
8
|
+
}) => maplibregl.Map | Promise<maplibregl.Map> | void | Promise<void>;
|
|
9
|
+
onTeardown?: () => void | Promise<void>;
|
|
10
|
+
children?: Snippet;
|
|
11
|
+
};
|
|
12
|
+
declare const MapLibreLoader: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type MapLibreLoader = ReturnType<typeof MapLibreLoader>;
|
|
14
|
+
export default MapLibreLoader;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { maplibregl } from "./maplibre.d.ts";
|
|
2
|
+
export declare const MAPLIBRE_JS_URL = "https://www.abc.net.au/res/sites/news-projects/maplibre/v5.x.x-latest/maplibre-gl.js";
|
|
3
|
+
export declare const MAPLIBRE_CSS_URL = "https://www.abc.net.au/res/sites/news-projects/maplibre/v5.x.x-latest/maplibre-gl.css";
|
|
4
|
+
/** Colourful style */
|
|
5
|
+
export declare const STYLE_BRIGHT = "https://www.abc.net.au/res/sites/news-projects/map-vector-style-bright/style.json";
|
|
6
|
+
/** Grey style */
|
|
7
|
+
export declare const STYLE_LIGHT = "https://www.abc.net.au/res/sites/news-projects/map-vector-style-light/style.json";
|
|
8
|
+
/**
|
|
9
|
+
* Load common MapLibre version from news-projects.
|
|
10
|
+
*
|
|
11
|
+
* To keep bundle sizes, deploys, and end user downloads svelte, we can load
|
|
12
|
+
* MapLibre from news-projects. This version is updated only when the major
|
|
13
|
+
* version changes, which should be safe given semver conventions.
|
|
14
|
+
*
|
|
15
|
+
* - Regular visitors should only need to download & parse MapLibre once, ever,
|
|
16
|
+
* no matter how many different deploys or projects they hit.
|
|
17
|
+
* - Build sizes stay small, preventing duplication & deploy size blowouts
|
|
18
|
+
* - Build times are quicker with MapLibre externalised.
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadMapLibre(): Promise<typeof maplibregl>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const MAPLIBRE_JS_URL = "https://www.abc.net.au/res/sites/news-projects/maplibre/v5.x.x-latest/maplibre-gl.js";
|
|
2
|
+
export const MAPLIBRE_CSS_URL = "https://www.abc.net.au/res/sites/news-projects/maplibre/v5.x.x-latest/maplibre-gl.css";
|
|
3
|
+
/** Colourful style */
|
|
4
|
+
export const STYLE_BRIGHT = "https://www.abc.net.au/res/sites/news-projects/map-vector-style-bright/style.json";
|
|
5
|
+
/** Grey style */
|
|
6
|
+
export const STYLE_LIGHT = "https://www.abc.net.au/res/sites/news-projects/map-vector-style-light/style.json";
|
|
7
|
+
const promises = {};
|
|
8
|
+
function importModule(url) {
|
|
9
|
+
const key = "module" + url;
|
|
10
|
+
const promise = promises[key];
|
|
11
|
+
if (promise) {
|
|
12
|
+
return promise;
|
|
13
|
+
}
|
|
14
|
+
const newPromise = new Promise((resolve, reject) => {
|
|
15
|
+
const s = document.createElement("script");
|
|
16
|
+
s.src = url;
|
|
17
|
+
s.type = "module";
|
|
18
|
+
s.addEventListener("load", () => resolve());
|
|
19
|
+
s.addEventListener("error", reject);
|
|
20
|
+
document.head.appendChild(s);
|
|
21
|
+
});
|
|
22
|
+
promises[key] = newPromise;
|
|
23
|
+
return newPromise;
|
|
24
|
+
}
|
|
25
|
+
function loadCss(url) {
|
|
26
|
+
const key = "css" + url;
|
|
27
|
+
const promise = promises[key];
|
|
28
|
+
if (promise) {
|
|
29
|
+
return promise;
|
|
30
|
+
}
|
|
31
|
+
const newPromise = new Promise((resolve, reject) => {
|
|
32
|
+
const s = document.createElement("link");
|
|
33
|
+
s.rel = "stylesheet";
|
|
34
|
+
s.type = "text/css";
|
|
35
|
+
s.href = url;
|
|
36
|
+
s.addEventListener("load", () => resolve());
|
|
37
|
+
s.addEventListener("error", reject);
|
|
38
|
+
document.head.appendChild(s);
|
|
39
|
+
});
|
|
40
|
+
promises[key] = newPromise;
|
|
41
|
+
return newPromise;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Load common MapLibre version from news-projects.
|
|
45
|
+
*
|
|
46
|
+
* To keep bundle sizes, deploys, and end user downloads svelte, we can load
|
|
47
|
+
* MapLibre from news-projects. This version is updated only when the major
|
|
48
|
+
* version changes, which should be safe given semver conventions.
|
|
49
|
+
*
|
|
50
|
+
* - Regular visitors should only need to download & parse MapLibre once, ever,
|
|
51
|
+
* no matter how many different deploys or projects they hit.
|
|
52
|
+
* - Build sizes stay small, preventing duplication & deploy size blowouts
|
|
53
|
+
* - Build times are quicker with MapLibre externalised.
|
|
54
|
+
*/
|
|
55
|
+
export async function loadMapLibre() {
|
|
56
|
+
await Promise.all([importModule(MAPLIBRE_JS_URL), loadCss(MAPLIBRE_CSS_URL)]);
|
|
57
|
+
return window.maplibregl;
|
|
58
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abcnews/components-storylab",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"scripts": {
|
|
5
|
-
"dev": "
|
|
6
|
-
"build": "
|
|
5
|
+
"dev": "npm run storybook",
|
|
6
|
+
"build": "npm run prepack",
|
|
7
7
|
"preview": "vite preview",
|
|
8
8
|
"prepare": "svelte-kit sync || echo ''",
|
|
9
9
|
"prepack": "svelte-kit sync && svelte-package && publint",
|
|
10
10
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
11
|
-
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
|
11
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
12
|
+
"test:unit": "vitest",
|
|
13
|
+
"test": "npm run test:unit -- --run",
|
|
14
|
+
"storybook": "export AUNTY_HOST=${AUNTY_HOST:-localhost} && storybook dev -p 6006 --host $AUNTY_HOST --ci",
|
|
15
|
+
"build-storybook": "storybook build"
|
|
12
16
|
},
|
|
13
17
|
"files": [
|
|
14
18
|
"dist",
|
|
@@ -25,30 +29,40 @@
|
|
|
25
29
|
".": {
|
|
26
30
|
"types": "./dist/index.d.ts",
|
|
27
31
|
"svelte": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./mapLibre": {
|
|
34
|
+
"types": "./dist/mapLibre/index.d.ts",
|
|
35
|
+
"default": "./dist/mapLibre/index.js"
|
|
28
36
|
}
|
|
29
37
|
},
|
|
30
38
|
"peerDependencies": {
|
|
31
39
|
"svelte": "^5.0.0"
|
|
32
40
|
},
|
|
33
41
|
"devDependencies": {
|
|
42
|
+
"@storybook/addon-svelte-csf": "^5.0.10",
|
|
43
|
+
"@storybook/sveltekit": "^10.1.11",
|
|
34
44
|
"@sveltejs/adapter-auto": "^7.0.0",
|
|
35
45
|
"@sveltejs/kit": "^2.49.1",
|
|
36
46
|
"@sveltejs/package": "^2.5.7",
|
|
37
47
|
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
|
48
|
+
"@types/node": "^24",
|
|
49
|
+
"@vitest/browser-playwright": "^4.0.15",
|
|
50
|
+
"maplibre-gl": "^5.16.0",
|
|
51
|
+
"playwright": "^1.57.0",
|
|
38
52
|
"publint": "^0.3.15",
|
|
53
|
+
"sass-embedded": "^1.97.2",
|
|
54
|
+
"storybook": "^10.1.11",
|
|
39
55
|
"svelte": "^5.45.6",
|
|
40
56
|
"svelte-check": "^4.3.4",
|
|
41
57
|
"typescript": "^5.9.3",
|
|
42
|
-
"vite": "^7.2.6"
|
|
58
|
+
"vite": "^7.2.6",
|
|
59
|
+
"vitest": "^4.0.15",
|
|
60
|
+
"vitest-browser-svelte": "^2.0.1"
|
|
43
61
|
},
|
|
44
62
|
"keywords": [
|
|
45
63
|
"svelte"
|
|
46
64
|
],
|
|
47
65
|
"license": "MIT",
|
|
48
66
|
"homepage": "https://github.com/abcnews/components-storylab",
|
|
49
|
-
"repository":
|
|
50
|
-
"type": "git",
|
|
51
|
-
"url": "git+https://github.com/abcnews/components-storylab.git"
|
|
52
|
-
},
|
|
53
|
-
"private": false
|
|
67
|
+
"repository": "github:abcnews/components-storylab"
|
|
54
68
|
}
|