@reuters-graphics/graphics-components 3.0.27 → 3.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.
@@ -6,7 +6,7 @@ https://www.fluid-type-scale.com/calculate?minFontSize=18&minWidth=320&minRatio=
6
6
  export default {
7
7
  font: {
8
8
  family: {
9
- serif: 'FreightText, serif',
9
+ serif: '"Newsreader Text", serif',
10
10
  'sans-serif': 'Knowledge, sans-serif',
11
11
  monospace:
12
12
  '"Droid Sans Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
@@ -0,0 +1,199 @@
1
+ <!-- @component `Map` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-graphics-map--docs) -->
2
+ <script lang="ts" module>
3
+ import { Protocol } from 'pmtiles';
4
+ import maplibregl from 'maplibre-gl';
5
+
6
+ // Track if PMTiles protocol has been registered (only do this once per page)
7
+ let pmtilesProtocolRegistered = false;
8
+
9
+ function ensurePMTilesProtocol() {
10
+ if (!pmtilesProtocolRegistered) {
11
+ const protocol = new Protocol();
12
+ maplibregl.addProtocol('pmtiles', protocol.tile);
13
+ pmtilesProtocolRegistered = true;
14
+ }
15
+ }
16
+ </script>
17
+
18
+ <script lang="ts">
19
+ import { onMount, onDestroy, setContext, type Snippet } from 'svelte';
20
+ import { writable } from 'svelte/store';
21
+ import GraphicBlock from '../GraphicBlock/GraphicBlock.svelte';
22
+ import type { ContainerWidth } from '../@types/global';
23
+ import type { ProjectionSpecification } from 'maplibre-gl';
24
+ import 'maplibre-gl/dist/maplibre-gl.css';
25
+
26
+ interface Props {
27
+ /** Title of the map as a string or a custom snippet. */
28
+ title?: string | Snippet;
29
+ /** Description of the map, passed in as a markdown string. */
30
+ description?: string;
31
+ /**
32
+ * Notes to the map, passed in as a markdown string or a custom snippet.
33
+ */
34
+ notes?: string | Snippet;
35
+ /**
36
+ * Map container id
37
+ */
38
+ id?: string;
39
+ /**
40
+ * Map center coordinates [longitude, latitude]
41
+ */
42
+ center?: [number, number];
43
+ /**
44
+ * Initial zoom level
45
+ */
46
+ zoom?: number;
47
+ /**
48
+ * Minimum zoom level
49
+ */
50
+ minZoom?: number;
51
+ /**
52
+ * Maximum zoom level
53
+ */
54
+ maxZoom?: number;
55
+ /**
56
+ * Map projection. Use 'globe' for 3D globe view.
57
+ * See https://maplibre.org/maplibre-style-spec/types/#projectiondefinition
58
+ */
59
+ projection?: ProjectionSpecification;
60
+ /**
61
+ * Enable interactive controls (zoom, pan, etc.)
62
+ */
63
+ interactive?: boolean;
64
+ /**
65
+ * Map style URL
66
+ */
67
+ styleUrl?: string;
68
+ /**
69
+ * Map height (default: '500px')
70
+ */
71
+ height?: string;
72
+ /** Width of the map within the text well. */
73
+ width?: ContainerWidth;
74
+ /**
75
+ * Set a different width for the text within the text well, for example,
76
+ * "normal" to keep the title, description and notes inline with the rest
77
+ * of the text well. Can't ever be wider than `width`.
78
+ */
79
+ textWidth?: ContainerWidth;
80
+ /** Callback function that receives the map instance when ready */
81
+ onMapReady?: (map: maplibregl.Map) => void;
82
+ /** Child components (e.g., TileMapLayer) */
83
+ children?: Snippet;
84
+ }
85
+
86
+ let {
87
+ title,
88
+ description,
89
+ notes,
90
+ id = `map-${Math.random().toString(36).substring(2, 9)}`,
91
+ center = [0, 0],
92
+ zoom = 2,
93
+ minZoom = 0,
94
+ maxZoom = 22,
95
+ projection,
96
+ interactive = true,
97
+ styleUrl = 'https://graphics.thomsonreuters.com/reuters-protomaps/style.json',
98
+ height = '500px',
99
+ width = 'normal',
100
+ textWidth = 'normal',
101
+ onMapReady,
102
+ children,
103
+ }: Props = $props();
104
+
105
+ let mapContainer: HTMLDivElement;
106
+ let map: maplibregl.Map | null = null;
107
+
108
+ // Create a writable store for the map instance
109
+ const mapStore = writable<maplibregl.Map | null>(null);
110
+
111
+ // Set context with the store immediately (not in onMount)
112
+ setContext('map', mapStore);
113
+
114
+ onMount(() => {
115
+ if (typeof window !== 'undefined' && mapContainer) {
116
+ // Set up PMTiles protocol (only once per page)
117
+ ensurePMTilesProtocol();
118
+
119
+ // Set the map options
120
+ const mapOptions: maplibregl.MapOptions = {
121
+ container: mapContainer,
122
+ style: styleUrl,
123
+ center,
124
+ zoom,
125
+ minZoom,
126
+ maxZoom,
127
+ attributionControl: false,
128
+ scrollZoom: false, // Always disabled for consistency
129
+ doubleClickZoom: interactive,
130
+ dragPan: interactive,
131
+ touchPitch: false, // Disabled to prevent unwanted tilting
132
+ touchZoomRotate: interactive,
133
+ boxZoom: interactive,
134
+ keyboard: interactive,
135
+ };
136
+
137
+ const mapInstance = new maplibregl.Map(mapOptions);
138
+
139
+ map = mapInstance;
140
+
141
+ // Update the store with the map instance
142
+ mapStore.set(mapInstance);
143
+
144
+ // Initialize controls only if interactive
145
+ if (interactive) {
146
+ map.addControl(
147
+ new maplibregl.NavigationControl({ showCompass: false })
148
+ );
149
+ }
150
+
151
+ // Call the callback when map is ready
152
+ map.on('load', () => {
153
+ if (!map) return;
154
+
155
+ // Set projection after map loads if specified
156
+ if (projection) {
157
+ map.setProjection(projection);
158
+ }
159
+
160
+ if (onMapReady) {
161
+ onMapReady(map);
162
+ }
163
+ });
164
+ }
165
+ });
166
+
167
+ onDestroy(() => {
168
+ if (map) {
169
+ map.remove();
170
+ map = null;
171
+ mapStore.set(null);
172
+ }
173
+ });
174
+ </script>
175
+
176
+ <GraphicBlock {width} {textWidth} {title} {description} {notes}>
177
+ <div class="map" {id}>
178
+ <div
179
+ bind:this={mapContainer}
180
+ class="map-container"
181
+ style="height: {height}"
182
+ ></div>
183
+ {#if children}
184
+ {@render children()}
185
+ {/if}
186
+ </div>
187
+ </GraphicBlock>
188
+
189
+ <style>
190
+ .map {
191
+ width: 100%;
192
+ position: relative;
193
+ }
194
+
195
+ .map-container {
196
+ width: 100%;
197
+ position: relative;
198
+ }
199
+ </style>
@@ -0,0 +1,68 @@
1
+ import maplibregl from 'maplibre-gl';
2
+ import { type Snippet } from 'svelte';
3
+ import type { ContainerWidth } from '../@types/global';
4
+ import type { ProjectionSpecification } from 'maplibre-gl';
5
+ import 'maplibre-gl/dist/maplibre-gl.css';
6
+ interface Props {
7
+ /** Title of the map as a string or a custom snippet. */
8
+ title?: string | Snippet;
9
+ /** Description of the map, passed in as a markdown string. */
10
+ description?: string;
11
+ /**
12
+ * Notes to the map, passed in as a markdown string or a custom snippet.
13
+ */
14
+ notes?: string | Snippet;
15
+ /**
16
+ * Map container id
17
+ */
18
+ id?: string;
19
+ /**
20
+ * Map center coordinates [longitude, latitude]
21
+ */
22
+ center?: [number, number];
23
+ /**
24
+ * Initial zoom level
25
+ */
26
+ zoom?: number;
27
+ /**
28
+ * Minimum zoom level
29
+ */
30
+ minZoom?: number;
31
+ /**
32
+ * Maximum zoom level
33
+ */
34
+ maxZoom?: number;
35
+ /**
36
+ * Map projection. Use 'globe' for 3D globe view.
37
+ * See https://maplibre.org/maplibre-style-spec/types/#projectiondefinition
38
+ */
39
+ projection?: ProjectionSpecification;
40
+ /**
41
+ * Enable interactive controls (zoom, pan, etc.)
42
+ */
43
+ interactive?: boolean;
44
+ /**
45
+ * Map style URL
46
+ */
47
+ styleUrl?: string;
48
+ /**
49
+ * Map height (default: '500px')
50
+ */
51
+ height?: string;
52
+ /** Width of the map within the text well. */
53
+ width?: ContainerWidth;
54
+ /**
55
+ * Set a different width for the text within the text well, for example,
56
+ * "normal" to keep the title, description and notes inline with the rest
57
+ * of the text well. Can't ever be wider than `width`.
58
+ */
59
+ textWidth?: ContainerWidth;
60
+ /** Callback function that receives the map instance when ready */
61
+ onMapReady?: (map: maplibregl.Map) => void;
62
+ /** Child components (e.g., TileMapLayer) */
63
+ children?: Snippet;
64
+ }
65
+ /** `Map` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-graphics-map--docs) */
66
+ declare const TileMap: import("svelte").Component<Props, {}, "">;
67
+ type TileMap = ReturnType<typeof TileMap>;
68
+ export default TileMap;
@@ -0,0 +1,211 @@
1
+ <!-- @component `TileMapLayer` - Add GeoJSON layers to a TileMap component -->
2
+ <script lang="ts">
3
+ import { getContext, onMount } from 'svelte';
4
+ import type { Map as MaplibreMap, GeoJSONSource } from 'maplibre-gl';
5
+ import type { Writable } from 'svelte/store';
6
+ import type { GeoJSON } from 'geojson';
7
+
8
+ interface Props {
9
+ /**
10
+ * Unique ID for this layer
11
+ */
12
+ id: string;
13
+ /**
14
+ * GeoJSON data to display (FeatureCollection, Feature, Geometry, or URL string to fetch from)
15
+ */
16
+ data: GeoJSON | string;
17
+ /**
18
+ * Layer type: 'fill', 'line', 'circle', 'symbol', etc.
19
+ */
20
+ type?:
21
+ | 'fill'
22
+ | 'line'
23
+ | 'circle'
24
+ | 'symbol'
25
+ | 'fill-extrusion'
26
+ | 'raster'
27
+ | 'background'
28
+ | 'heatmap'
29
+ | 'hillshade';
30
+ /**
31
+ * Paint properties for the layer
32
+ */
33
+ paint?: Record<string, unknown>;
34
+ /**
35
+ * Layout properties for the layer
36
+ */
37
+ layout?: Record<string, unknown>;
38
+ /**
39
+ * Layer to insert before (for layer ordering)
40
+ */
41
+ beforeId?: string;
42
+ /**
43
+ * Minimum zoom level to display layer
44
+ */
45
+ minZoom?: number;
46
+ /**
47
+ * Maximum zoom level to display layer
48
+ */
49
+ maxZoom?: number;
50
+ /**
51
+ * Filter expression for the layer
52
+ */
53
+ filter?: unknown[];
54
+ }
55
+
56
+ let {
57
+ id,
58
+ data,
59
+ type = 'fill',
60
+ paint = {},
61
+ layout = {},
62
+ beforeId,
63
+ minZoom,
64
+ maxZoom,
65
+ filter,
66
+ }: Props = $props();
67
+
68
+ const mapStore = getContext<Writable<MaplibreMap | null>>('map');
69
+
70
+ if (!mapStore) {
71
+ throw new Error('TileMapLayer must be used inside a TileMap component');
72
+ }
73
+
74
+ const sourceId = `${id}-source`;
75
+ let isInitialized = $state(false);
76
+ let fetchedData = $state<GeoJSON | null>(null);
77
+ let isLoading = $state(false);
78
+
79
+ // Fetch GeoJSON if data is a URL string
80
+ $effect(() => {
81
+ if (
82
+ typeof data === 'string' &&
83
+ (data.startsWith('http://') || data.startsWith('https://'))
84
+ ) {
85
+ isLoading = true;
86
+ fetchedData = null; // Reset while fetching
87
+ fetch(data)
88
+ .then((response) => {
89
+ if (!response.ok) {
90
+ throw new Error(`Failed to fetch GeoJSON: ${response.statusText}`);
91
+ }
92
+ return response.json();
93
+ })
94
+ .then((json) => {
95
+ fetchedData = json;
96
+ isLoading = false;
97
+ })
98
+ .catch((error) => {
99
+ console.error(`Error fetching GeoJSON from ${data}:`, error);
100
+ isLoading = false;
101
+ });
102
+ } else {
103
+ fetchedData = null;
104
+ isLoading = false;
105
+ }
106
+ });
107
+
108
+ // Get the actual data to use (fetched or passed directly)
109
+ // Only use data directly if it's not a URL string
110
+ const isUrlString = $derived(
111
+ typeof data === 'string' &&
112
+ (data.startsWith('http://') || data.startsWith('https://'))
113
+ );
114
+ const actualData = $derived(fetchedData || (isUrlString ? null : data));
115
+
116
+ // Subscribe to map store and initialize when map is available
117
+ $effect(() => {
118
+ const map = $mapStore;
119
+ const currentData = actualData; // Track actualData explicitly
120
+ const loading = isLoading; // Track isLoading explicitly
121
+
122
+ if (!map || isInitialized || loading || !currentData) return;
123
+
124
+ const initializeLayer = () => {
125
+ if (isInitialized) return;
126
+
127
+ // Add source
128
+ if (!map.getSource(sourceId)) {
129
+ map.addSource(sourceId, {
130
+ type: 'geojson',
131
+ data: currentData,
132
+ });
133
+ }
134
+
135
+ // Add layer
136
+ if (!map.getLayer(id)) {
137
+ const layerConfig: Record<string, unknown> = {
138
+ id,
139
+ type,
140
+ source: sourceId,
141
+ paint,
142
+ layout,
143
+ };
144
+
145
+ if (minZoom !== undefined) layerConfig.minzoom = minZoom;
146
+ if (maxZoom !== undefined) layerConfig.maxzoom = maxZoom;
147
+ if (filter) layerConfig.filter = filter;
148
+
149
+ map.addLayer(layerConfig as never, beforeId);
150
+ }
151
+
152
+ isInitialized = true;
153
+ };
154
+
155
+ // Wait for map to be loaded
156
+ if (!map.loaded()) {
157
+ map.once('load', initializeLayer);
158
+ } else {
159
+ initializeLayer();
160
+ }
161
+ });
162
+
163
+ // Update data reactively
164
+ $effect(() => {
165
+ const map = $mapStore;
166
+ const currentData = actualData; // Track actualData explicitly
167
+ const loading = isLoading; // Track isLoading explicitly
168
+
169
+ if (!map || !isInitialized || loading || !currentData) return;
170
+
171
+ const source = map.getSource(sourceId);
172
+ if (source && (source as GeoJSONSource).setData) {
173
+ (source as GeoJSONSource).setData(currentData);
174
+ }
175
+ });
176
+
177
+ // Update paint properties reactively
178
+ $effect(() => {
179
+ const map = $mapStore;
180
+ if (!map || !isInitialized || !paint) return;
181
+
182
+ Object.entries(paint).forEach(([property, value]) => {
183
+ map.setPaintProperty(id, property, value);
184
+ });
185
+ });
186
+
187
+ // Update layout properties reactively
188
+ $effect(() => {
189
+ const map = $mapStore;
190
+ if (!map || !isInitialized || !layout) return;
191
+
192
+ Object.entries(layout).forEach(([property, value]) => {
193
+ map.setLayoutProperty(id, property, value);
194
+ });
195
+ });
196
+
197
+ // Cleanup
198
+ onMount(() => {
199
+ return () => {
200
+ const map = $mapStore;
201
+ if (map && isInitialized) {
202
+ if (map.getLayer(id)) {
203
+ map.removeLayer(id);
204
+ }
205
+ if (map.getSource(sourceId)) {
206
+ map.removeSource(sourceId);
207
+ }
208
+ }
209
+ };
210
+ });
211
+ </script>
@@ -0,0 +1,43 @@
1
+ import type { GeoJSON } from 'geojson';
2
+ interface Props {
3
+ /**
4
+ * Unique ID for this layer
5
+ */
6
+ id: string;
7
+ /**
8
+ * GeoJSON data to display (FeatureCollection, Feature, Geometry, or URL string to fetch from)
9
+ */
10
+ data: GeoJSON | string;
11
+ /**
12
+ * Layer type: 'fill', 'line', 'circle', 'symbol', etc.
13
+ */
14
+ type?: 'fill' | 'line' | 'circle' | 'symbol' | 'fill-extrusion' | 'raster' | 'background' | 'heatmap' | 'hillshade';
15
+ /**
16
+ * Paint properties for the layer
17
+ */
18
+ paint?: Record<string, unknown>;
19
+ /**
20
+ * Layout properties for the layer
21
+ */
22
+ layout?: Record<string, unknown>;
23
+ /**
24
+ * Layer to insert before (for layer ordering)
25
+ */
26
+ beforeId?: string;
27
+ /**
28
+ * Minimum zoom level to display layer
29
+ */
30
+ minZoom?: number;
31
+ /**
32
+ * Maximum zoom level to display layer
33
+ */
34
+ maxZoom?: number;
35
+ /**
36
+ * Filter expression for the layer
37
+ */
38
+ filter?: unknown[];
39
+ }
40
+ /** `TileMapLayer` - Add GeoJSON layers to a TileMap component */
41
+ declare const TileMapLayer: import("svelte").Component<Props, {}, "">;
42
+ type TileMapLayer = ReturnType<typeof TileMapLayer>;
43
+ export default TileMapLayer;
package/dist/index.d.ts CHANGED
@@ -22,6 +22,8 @@ export { default as EndNotes } from './components/EndNotes/EndNotes.svelte';
22
22
  export { default as InfoBox } from './components/InfoBox/InfoBox.svelte';
23
23
  export { default as InlineAd } from './components/AdSlot/InlineAd.svelte';
24
24
  export { default as LeaderboardAd } from './components/AdSlot/LeaderboardAd.svelte';
25
+ export { default as TileMap } from './components/TileMap/TileMap.svelte';
26
+ export { default as TileMapLayer } from './components/TileMap/TileMapLayer.svelte';
25
27
  export { default as PaddingReset } from './components/PaddingReset/PaddingReset.svelte';
26
28
  export { default as PhotoPack } from './components/PhotoPack/PhotoPack.svelte';
27
29
  export { default as PymChild } from './components/PymChild/PymChild.svelte';
package/dist/index.js CHANGED
@@ -25,6 +25,8 @@ export { default as EndNotes } from './components/EndNotes/EndNotes.svelte';
25
25
  export { default as InfoBox } from './components/InfoBox/InfoBox.svelte';
26
26
  export { default as InlineAd } from './components/AdSlot/InlineAd.svelte';
27
27
  export { default as LeaderboardAd } from './components/AdSlot/LeaderboardAd.svelte';
28
+ export { default as TileMap } from './components/TileMap/TileMap.svelte';
29
+ export { default as TileMapLayer } from './components/TileMap/TileMapLayer.svelte';
28
30
  export { default as PaddingReset } from './components/PaddingReset/PaddingReset.svelte';
29
31
  export { default as PhotoPack } from './components/PhotoPack/PhotoPack.svelte';
30
32
  export { default as PymChild } from './components/PymChild/PymChild.svelte';
@@ -169,13 +169,13 @@
169
169
  font-display: swap;
170
170
  }
171
171
 
172
- /* FREIGHT TEXT */
172
+ /* NEWSREADER TEXT */
173
173
  @font-face {
174
- font-family: 'FreightText';
174
+ font-family: 'Newsreader Text';
175
175
  src:
176
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextBold.woff2')
176
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Bold.woff2')
177
177
  format('woff2'),
178
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextBold.woff')
178
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Bold.woff')
179
179
  format('woff');
180
180
  font-weight: bold;
181
181
  font-style: normal;
@@ -183,49 +183,157 @@
183
183
  }
184
184
 
185
185
  @font-face {
186
- font-family: 'FreightText';
186
+ font-family: 'Newsreader Text';
187
187
  src:
188
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextBook.woff2')
188
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-ExtraBoldItalic.woff2')
189
189
  format('woff2'),
190
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextBook.woff')
190
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-ExtraBoldItalic.woff')
191
191
  format('woff');
192
- font-weight: normal;
193
- font-style: normal;
192
+ font-weight: bold;
193
+ font-style: italic;
194
194
  font-display: swap;
195
195
  }
196
196
 
197
197
  @font-face {
198
- font-family: 'FreightText';
198
+ font-family: 'Newsreader Text';
199
199
  src:
200
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextBookItalic.woff2')
200
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-BoldItalic.woff2')
201
201
  format('woff2'),
202
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextBookItalic.woff')
202
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-BoldItalic.woff')
203
203
  format('woff');
204
- font-weight: normal;
204
+ font-weight: bold;
205
205
  font-style: italic;
206
206
  font-display: swap;
207
207
  }
208
208
 
209
209
  @font-face {
210
- font-family: 'FreightText';
210
+ font-family: 'Newsreader Text';
211
+ src:
212
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-ExtraBold.woff2')
213
+ format('woff2'),
214
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-ExtraBold.woff')
215
+ format('woff');
216
+ font-weight: bold;
217
+ font-style: normal;
218
+ font-display: swap;
219
+ }
220
+
221
+ @font-face {
222
+ font-family: 'Newsreader Text';
211
223
  src:
212
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextLight.woff2')
224
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-LightItalic.woff2')
213
225
  format('woff2'),
214
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextLight.woff')
226
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-LightItalic.woff')
215
227
  format('woff');
216
228
  font-weight: 300;
229
+ font-style: italic;
230
+ font-display: swap;
231
+ }
232
+
233
+ @font-face {
234
+ font-family: 'Newsreader Text';
235
+ src:
236
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-SemiBoldItalic.woff2')
237
+ format('woff2'),
238
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-SemiBoldItalic.woff')
239
+ format('woff');
240
+ font-weight: 600;
241
+ font-style: italic;
242
+ font-display: swap;
243
+ }
244
+
245
+ @font-face {
246
+ font-family: 'Newsreader Text';
247
+ src:
248
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Medium.woff2')
249
+ format('woff2'),
250
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Medium.woff')
251
+ format('woff');
252
+ font-weight: 500;
217
253
  font-style: normal;
218
254
  font-display: swap;
219
255
  }
220
256
 
221
257
  @font-face {
222
- font-family: 'FreightText';
258
+ font-family: 'Newsreader Text';
223
259
  src:
224
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextMedium.woff2')
260
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-MediumItalic.woff2')
225
261
  format('woff2'),
226
- url('//graphics.thomsonreuters.com/style-assets/fonts/v1/FreightTextMedium.woff')
262
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-MediumItalic.woff')
227
263
  format('woff');
228
264
  font-weight: 500;
265
+ font-style: italic;
266
+ font-display: swap;
267
+ }
268
+
269
+ @font-face {
270
+ font-family: 'Newsreader Text';
271
+ src:
272
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-SemiBold.woff2')
273
+ format('woff2'),
274
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-SemiBold.woff')
275
+ format('woff');
276
+ font-weight: 600;
277
+ font-style: normal;
278
+ font-display: swap;
279
+ }
280
+
281
+ @font-face {
282
+ font-family: 'Newsreader Text';
283
+ src:
284
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-ExtraLightItalic.woff2')
285
+ format('woff2'),
286
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-ExtraLightItalic.woff')
287
+ format('woff');
288
+ font-weight: 200;
289
+ font-style: italic;
290
+ font-display: swap;
291
+ }
292
+
293
+ @font-face {
294
+ font-family: 'Newsreader Text';
295
+ src:
296
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Italic.woff2')
297
+ format('woff2'),
298
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Italic.woff')
299
+ format('woff');
300
+ font-weight: normal;
301
+ font-style: italic;
302
+ font-display: swap;
303
+ }
304
+
305
+ @font-face {
306
+ font-family: 'Newsreader Text';
307
+ src:
308
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Regular.woff2')
309
+ format('woff2'),
310
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Regular.woff')
311
+ format('woff');
312
+ font-weight: normal;
313
+ font-style: normal;
314
+ font-display: swap;
315
+ }
316
+
317
+ @font-face {
318
+ font-family: 'Newsreader Text';
319
+ src:
320
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-ExtraLight.woff2')
321
+ format('woff2'),
322
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-ExtraLight.woff')
323
+ format('woff');
324
+ font-weight: 200;
325
+ font-style: normal;
326
+ font-display: swap;
327
+ }
328
+
329
+ @font-face {
330
+ font-family: 'Newsreader Text';
331
+ src:
332
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Light.woff2')
333
+ format('woff2'),
334
+ url('//graphics.thomsonreuters.com/style-assets/fonts/v1/NewsreaderText-Light.woff')
335
+ format('woff');
336
+ font-weight: 300;
229
337
  font-style: normal;
230
338
  font-display: swap;
231
339
  }
@@ -27,8 +27,8 @@
27
27
  .font-knowledge {
28
28
  @include font-knowledge;
29
29
  }
30
- .font-freight-text {
31
- @include font-freight-text;
30
+ .font-newsreader-text {
31
+ @include font-newsreader-text;
32
32
  }
33
33
  .font-noto-sans-jp {
34
34
  @include font-noto-sans-jp;
@@ -60,8 +60,8 @@
60
60
  .\!font-knowledge {
61
61
  @include \!font-knowledge;
62
62
  }
63
- .\!font-freight-text {
64
- @include \!font-freight-text;
63
+ .\!font-newsreader-text {
64
+ @include \!font-newsreader-text;
65
65
  }
66
66
  .\!font-noto-sans-jp {
67
67
  @include \!font-noto-sans-jp;
@@ -25,8 +25,8 @@
25
25
  @mixin font-knowledge {
26
26
  font-family: 'Knowledge', 'Source Sans Pro', Arial, Helvetica, sans-serif;
27
27
  }
28
- @mixin font-freight-text {
29
- font-family: 'FreightText', serif;
28
+ @mixin font-newsreader-text {
29
+ font-family: 'Newsreader Text', serif;
30
30
  }
31
31
  @mixin font-noto-sans-jp {
32
32
  font-family: 'Noto Sans JP';
@@ -59,8 +59,8 @@
59
59
  font-family:
60
60
  'Knowledge', 'Source Sans Pro', Arial, Helvetica, sans-serif !important;
61
61
  }
62
- @mixin \!font-freight-text {
63
- font-family: 'FreightText', serif !important;
62
+ @mixin \!font-newsreader-text {
63
+ font-family: 'Newsreader Text', serif !important;
64
64
  }
65
65
  @mixin \!font-noto-sans-jp {
66
66
  font-family: 'Noto Sans JP' !important;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reuters-graphics/graphics-components",
3
- "version": "3.0.27",
3
+ "version": "3.2.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "homepage": "https://reuters-graphics.github.io/graphics-components",
@@ -96,10 +96,13 @@
96
96
  "@lottiefiles/dotlottie-web": "^0.52.2",
97
97
  "@reuters-graphics/svelte-markdown": "^0.0.3",
98
98
  "@sveltejs/kit": "^2.0.0",
99
+ "@types/geojson": "^7946.0.16",
99
100
  "dayjs": "^1.11.13",
100
101
  "es-toolkit": "^1.35.0",
101
102
  "journalize": "^2.6.0",
103
+ "maplibre-gl": "^5.15.0",
102
104
  "mp4box": "^0.5.4",
105
+ "pmtiles": "^4.3.2",
103
106
  "proper-url-join": "^2.1.2",
104
107
  "pym.js": "^1.3.2",
105
108
  "slugify": "^1.6.6",