Merge branch 'main' into margins-for-rtl

This commit is contained in:
Prasanta Kumar Dutta 2025-05-13 04:07:33 -07:00 committed by GitHub
commit cfdab01c02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 250 additions and 126 deletions

View file

@ -1,5 +1,28 @@
# @reuters-graphics/graphics-components
## 3.0.3
### Patch Changes
- c074a18: Allows step.background to be undefined
## 3.0.2
### Patch Changes
- 737f2e1: Adds a simple dropdown option to search embeds for Framer
- a032218: Don't fetch referrals on non-dotcom domains
- 2d4a641: Cleans up a spare console log left in
- c91807e: a11y fixes for SiteHeader and SiteFooter
- b13463f: fixes for Ad types that were colliding with their component names and a bug in the Framer Resizer
- a48d333: Ignore hydration mismatch in SEO component ld+json
## 3.0.1
### Patch Changes
- 93a41f3: Exposes bindable props for the Scroller component
## 3.0.0
### Major Changes

View file

@ -1,6 +1,6 @@
{
"name": "@reuters-graphics/graphics-components",
"version": "3.0.0",
"version": "3.0.3",
"type": "module",
"private": false,
"homepage": "https://reuters-graphics.github.io/graphics-components",

View file

@ -31,7 +31,7 @@ export interface ScrollerStep {
/**
* A background component
*/
background: Component;
background: Component | undefined;
/**
* Optional props for background component
*/

View file

@ -1,4 +1,4 @@
export type LeaderboardAd = {
export type LeaderboardAdType = {
mobile: {
adType: 'leaderboard';
placementName: 'reuters_mobile_leaderboard';
@ -8,8 +8,7 @@ export type LeaderboardAd = {
placementName: 'reuters_desktop_leaderboard_atf';
};
};
export type SponsorshipAd = {
export type SponsorshipAdType = {
mobile: {
adType: 'sponsorlogo';
placementName: 'reuters_sponsorlogo';
@ -19,8 +18,7 @@ export type SponsorshipAd = {
placementName: 'reuters_sponsorlogo';
};
};
export type InlineAd = {
export type InlineAdType = {
mobile: {
adType: 'mpu' | 'native' | 'mpu2';
placementName:
@ -36,23 +34,19 @@ export type InlineAd = {
| 'reuters_desktop_native_3';
};
};
export type DesktopPlacementName =
| LeaderboardAd['desktop']['placementName']
| SponsorshipAd['desktop']['placementName']
| InlineAd['desktop']['placementName'];
| LeaderboardAdType['desktop']['placementName']
| SponsorshipAdType['desktop']['placementName']
| InlineAdType['desktop']['placementName'];
export type MobilePlacementName =
| LeaderboardAd['mobile']['placementName']
| SponsorshipAd['mobile']['placementName']
| InlineAd['mobile']['placementName'];
| LeaderboardAdType['mobile']['placementName']
| SponsorshipAdType['mobile']['placementName']
| InlineAdType['mobile']['placementName'];
export type DesktopAdType =
| LeaderboardAd['desktop']['adType']
| SponsorshipAd['desktop']['adType']
| InlineAd['desktop']['adType'];
| LeaderboardAdType['desktop']['adType']
| SponsorshipAdType['desktop']['adType']
| InlineAdType['desktop']['adType'];
export type MobileAdType =
| LeaderboardAd['mobile']['adType']
| SponsorshipAd['mobile']['adType']
| InlineAd['mobile']['adType'];
| LeaderboardAdType['mobile']['adType']
| SponsorshipAdType['mobile']['adType']
| InlineAdType['mobile']['adType'];

View file

@ -2,7 +2,7 @@
<!-- @component `InlineAd` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-ads-analytics-inlinead--docs) -->
<script lang="ts">
import Block from '../Block/Block.svelte';
import type { InlineAd } from './@types/ads';
import type { InlineAdType } from './@types/ads';
import ResponsiveAd from './ResponsiveAd.svelte';
interface Props {
@ -16,7 +16,7 @@
let { id = '', class: cls = 'my-12', n = 1 }: Props = $props();
const desktopPlacementName: InlineAd['desktop']['placementName'] = `reuters_desktop_native_${n}`;
const desktopPlacementName: InlineAdType['desktop']['placementName'] = `reuters_desktop_native_${n}`;
</script>
<Block {id} class="freestar-adslot {cls}">

View file

@ -1,6 +1,6 @@
<!-- @component `LeaderboardAd` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-ads-analytics-leaderboardad--docs) -->
<script lang="ts">
import type { LeaderboardAd } from './@types/ads';
import type { LeaderboardAdType } from './@types/ads';
import ResponsiveAd from './ResponsiveAd.svelte';
import { onMount } from 'svelte';
@ -16,7 +16,7 @@
let windowWidth = $state(1200);
let adSize = $derived(windowWidth < 1024 ? 110 : 275);
const desktopPlacementName: LeaderboardAd['desktop']['placementName'] =
const desktopPlacementName: LeaderboardAdType['desktop']['placementName'] =
'reuters_desktop_leaderboard_atf';
let sticky = $state(false);

View file

@ -2,7 +2,7 @@
<!-- @component `SponsorshipAd` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-ads-analytics-sponsorshipad--docs) -->
<script lang="ts">
import Block from '../Block/Block.svelte';
import type { SponsorshipAd } from './@types/ads';
import type { SponsorshipAdType } from './@types/ads';
import ResponsiveAd from './ResponsiveAd.svelte';
interface Props {
@ -18,7 +18,7 @@
let { id = '', class: cls = 'my-12', adLabel = '' }: Props = $props();
const desktopPlacementName: SponsorshipAd['desktop']['placementName'] =
const desktopPlacementName: SponsorshipAdType['desktop']['placementName'] =
'reuters_sponsorlogo';
</script>

View file

@ -0,0 +1,50 @@
<script lang="ts">
interface Props {
data: {
index: number;
embed: string;
title: string;
}[];
selected: string;
}
let { data = [], selected = $bindable() }: Props = $props();
</script>
<form>
<label for="embed-options">Select an embed</label>
<select id="embed-options" bind:value={selected}>
{#each data as d (d.index)}
<option value={d.embed}>{d.title}</option>
{/each}
</select>
</form>
<style lang="scss">
@use '../../../scss/mixins' as mixins;
label {
margin-bottom: 0.25rem;
display: inline-flex;
font-size: 0.75rem;
color: #aaa;
@include mixins.font-sans;
}
select {
width: 100%;
padding: 0.5rem 0.75rem;
background: none;
font-size: 1rem;
border: 0;
border-radius: 0 !important;
background-color: #fff;
border: 1px solid #ddd;
@include mixins.font-sans;
}
select:focus {
outline: none;
border: 1px solid #ccc;
}
</style>

View file

@ -7,6 +7,7 @@
import { width } from './stores';
import getUniqNames from './uniqNames';
import Typeahead from './Typeahead/index.svelte';
import Dropdown from './Dropdown/index.svelte';
import ReutersGraphicsLogo from '../ReutersGraphicsLogo/ReutersGraphicsLogo.svelte';
interface Props {
@ -14,6 +15,7 @@
breakpoints?: number[];
minFrameWidth?: number;
maxFrameWidth?: number;
searchType?: 'dropdown' | 'typeahead';
}
let {
@ -21,6 +23,7 @@
breakpoints = [330, 510, 660, 930, 1200],
minFrameWidth = 320,
maxFrameWidth = 1200,
searchType = 'dropdown',
}: Props = $props();
const getDefaultEmbed = (embeds: Props['embeds']) => {
@ -71,37 +74,62 @@
<p>No embeds to show.</p>
</div>
{:else}
<div id="typeahead-container">
<div class="embed-link">
<a
rel="external"
target="_blank"
href={activeEmbed}
title={activeEmbed}
>
Live link <Fa icon={faLink} />
</a>
{#if searchType === 'typeahead'}
<div id="typeahead-container">
<div class="embed-link">
<a
rel="external"
target="_blank"
href={activeEmbed}
title={activeEmbed}
>
Live link <Fa icon={faLink} />
</a>
</div>
<Typeahead
label="Select an embed"
value={embedTitles[embeds.indexOf(activeEmbed)] ||
embedTitles[activeEmbedIndex] ||
embedTitles[0]}
extract={(d) => embedTitles[d.index]}
data={embeds.map((embed, index) => ({ index, embed }))}
showDropdownOnFocus={true}
onselect={(detail) => {
if (typeof window !== 'undefined') {
window.localStorage.setItem(
'framer-active-embed',
detail.original.embed
);
}
activeEmbed = detail.original.embed;
// activeEmbedIndex = detail.original.index;
}}
/>
</div>
<Typeahead
label="Select an embed"
value={embedTitles[embeds.indexOf(activeEmbed)] ||
embedTitles[activeEmbedIndex] ||
embedTitles[0]}
extract={(d) => embedTitles[d.index]}
data={embeds.map((embed, index) => ({ index, embed }))}
showDropdownOnFocus={true}
onselect={(detail) => {
if (typeof window !== 'undefined') {
window.localStorage.setItem(
'framer-active-embed',
detail.original.embed
);
}
activeEmbed = detail.original.embed;
// activeEmbedIndex = detail.original.index;
}}
/>
</div>
{:else}
<div id="dropdown-container">
<div>
<div class="embed-link">
<a
rel="external"
target="_blank"
href={activeEmbed}
title={activeEmbed}
>
Live link <Fa icon={faLink} />
</a>
</div>
</div>
<Dropdown
data={embeds.map((embed, index) => ({
index,
embed,
title: embedTitles[index],
}))}
bind:selected={activeEmbed}
/>
</div>
{/if}
<div id="preview-label" style="width:{$width}px;">
<p>Preview</p>
@ -139,26 +167,27 @@
}
}
div#typeahead-container {
div#typeahead-container,
div#dropdown-container {
max-width: 660px;
margin: 0 auto 15px;
position: relative;
}
div#typeahead-container div.embed-link {
position: absolute;
top: 0;
right: 0;
display: inline-block;
z-index: 2;
}
div#typeahead-container div.embed-link a {
font-family: 'Knowledge', 'Source Sans Pro', Arial, sans-serif;
color: #bbb;
font-size: 12px;
text-decoration: none !important;
}
div#typeahead-container div.embed-link a:hover {
color: #666;
div.embed-link {
position: absolute;
top: 0;
right: 0;
display: inline-block;
z-index: 2;
a {
font-family: 'Knowledge', 'Source Sans Pro', Arial, sans-serif;
color: #bbb;
font-size: 12px;
text-decoration: none !important;
&:hover {
color: #666;
}
}
}
}
div#preview-label {

View file

@ -27,8 +27,7 @@
if ($width > maxWidth) width.set(maxWidth);
});
// svelte-ignore state_referenced_locally
let offset = $state(($width - minWidth) / pixelRange);
let offset = $derived(($width - minWidth) / pixelRange);
let sliding = $state(false);
let isFocused = $state(false);
@ -55,7 +54,7 @@
} else if (keyCode === 37) {
offset = Math.max(0, offset - pixelWidth / sliderWidth);
}
width.set(getPx());
$width = getPx();
};
const start = (e: MouseEvent) => {
sliding = true;
@ -77,17 +76,17 @@
.filter((b) => b <= maxWidth)
.filter((b) => b > $width);
if (availableBreakpoints.length === 0) {
width.set(maxWidth);
$width = maxWidth;
} else {
width.set(availableBreakpoints[0]);
$width = availableBreakpoints[0];
}
};
const decrement = () => {
const availableBreakpoints = breakpoints.filter((b) => b < $width);
if (availableBreakpoints.length === 0) {
width.set(minWidth);
$width = minWidth;
} else {
width.set(availableBreakpoints.slice(-1)[0]);
$width = availableBreakpoints.slice(-1)[0];
}
};
</script>

View file

@ -177,7 +177,6 @@
<svelte:window
onclick={({ target }) => {
console.log('HELLO', !comboboxRef?.contains(target as Node));
if (!hideDropdown && !comboboxRef?.contains(target as Node)) {
close();
}

View file

@ -1,11 +0,0 @@
An embed tool for development in the graphics kit.
```svelte
<script>
import { Framer } from '@reuters-graphics/graphics-components';
const embeds = ['/embeds/my-chart/index.html'];
</script>
<Framer embeds="{embeds}" />
```

View file

@ -67,6 +67,9 @@
let referrals: Article[] = $state([]);
const getReferrals = async () => {
if (typeof window === 'undefined') return;
// fetch only reliably works on prod sites
if (window?.location?.hostname !== 'www.reuters.com') return;
const isCollection = Boolean(collection);
const API = isCollection ? COLLECTION_API : SECTION_API;
try {

View file

@ -185,9 +185,11 @@
<meta property="fb:admins" content="625796953" />
<meta property="fb:admins" content="571759798" />
<!-- svelte-ignore hydration_html_changed -->
{@html `<${'script'} type="application/ld+json">${JSON.stringify(
orgLdJson
)}</script>`}
<!-- svelte-ignore hydration_html_changed -->
{@html `<${'script'} type="application/ld+json">${JSON.stringify(
articleLdJson
)}</script>`}

View file

@ -19,6 +19,24 @@
control: 'select',
options: ['fb', 'bf'],
},
index: {
control: false,
table: {
category: 'Bindable states (Read-only)',
},
},
offset: {
control: false,
table: {
category: 'Bindable states (Read-only)',
},
},
progress: {
control: false,
table: {
category: 'Bindable states (Read-only)',
},
},
},
});
</script>

View file

@ -74,6 +74,12 @@
id?: string;
/** Set a class to target with SCSS */
class?: string;
/** The currently active section */
index?: number;
/** How far the section has scrolled past the threshold, as a value between 0 and 1 */
offset?: number;
/** How far the foreground has travelled, where 0 is the top of the foreground crossing top, and 1 is the bottom crossing bottom */
progress?: number;
}
let {
@ -90,12 +96,10 @@
bottom = 1,
parallax = false,
class: cls = '',
index = $bindable(0),
offset = $bindable(0),
progress = $bindable(0),
}: Props = $props();
// Bindable variables passed to ScrollerBase
let index = $state(0);
let offset = $state(0);
let progress = $state(0);
</script>
{#if !embedded}

View file

@ -40,24 +40,20 @@ With the graphics kit, you'll likely get your text value from an ArchieML doc.
```yaml
# Archie ML doc
[timeline]
# date object with events
date: May 18
[.events]
title: Mariupol defenders surrender to Russia but their fate is uncertain
context: More than 250 Ukrainian fighters surrendered to Russian forces at the Azovstal steelworks in Mariupol after weeks of desperate resistance, bringing an end to the most devastating siege of Russia's war in Ukraine and allowing President Vladimir Putin to claim a rare victory in his faltering campaign.
titleLink: https://www.reuters.com/world/europe/ukrainian-troops-evacuate-mariupol-ceding-control-russia-2022-05-17/
# More events...
[]
date: May 10
[.events]
title: U.S. House passes $40 bln bill to bolster Ukraine against Russian invasion
context: The U.S. House of Representatives approved more than $40 billion more aid for Ukraine on Tuesday, as Congress races to keep military aid flowing and boost the government in Kyiv as it grapples with the Russian invasion.
titleLink: https://www.reuters.com/world/us-house-vote-40-billion-ukraine-aid-package-tuesday-pelosi-2022-05-10/
[]
type: timeline
# Optional
class: timeline
id: timeline-1
symbolColour: var(--theme-colour-brand-rules, grey)
dateColour: var(--theme-colour-accent, red)
[.dates]
# date object with events
date: May 10
[.events]
title: U.S. House passes $40 bln bill to bolster Ukraine against Russian invasion
context: The U.S. House of Representatives approved more than $40 billion more aid for Ukraine on Tuesday, as Congress races to keep military aid flowing and boost the government in Kyiv as it grapples with the Russian invasion.
titleLink: https://www.reuters.com/world/us-house-vote-40-billion-ukraine-aid-package-tuesday-pelosi-2022-05-10/
[]
# More dates and events...
[]
@ -72,7 +68,13 @@ titleLink: https://www.reuters.com/world/us-house-vote-40-billion-ukraine-aid-pa
import content from '$locales/en/content.json';
</script>
<EndNotes SimpleTimeline={content.timeline} />
<SimpleTimeline
dates={block.dates}
class={block.class}
symbolColour={block.symbolColour}
id={block.id}
dateColour={block.dateColour}
/>
```
<Canvas of={SimpleTimelineStories.Demo} />

View file

@ -25,6 +25,11 @@
}
let { links = {} }: Props = $props();
const normaliseSocialName = (name: string) => {
if (name === 'twitter') return 'X';
return name;
};
</script>
{#if links.social_links}
@ -42,7 +47,10 @@
{@const SvelteComponent =
symbols[link.type as keyof typeof symbols]}
<li class="social-links symbol">
<a href={normalizeUrl(link.url)}>
<a
href={normalizeUrl(link.url)}
aria-label="Visit Reuters on {normaliseSocialName(link.type)}"
>
<div class="button">
<div class="social">
<SvelteComponent />

View file

@ -37,7 +37,11 @@
textColour="var(--nav-primary)"
/>
</div>
<button class="button close-button" onclick={releaseMobileMenu}>
<button
class="button close-button"
aria-label="Close menu"
onclick={releaseMobileMenu}
>
<div class="button-container">
<CloseIcon />
</div>

View file

@ -69,7 +69,7 @@
};
</script>
<div class="dropdown">
<div class="dropdown" data-chromatic="ignore">
<div class="dropdown-container">
<div class="inner">
<div class="submenu">
@ -78,7 +78,7 @@
</div>
</div>
<div class="stories-container">
<div class="inner" data-chromatic="ignore">
<div class="inner">
{#if stories.length > 0}
<span class="latest">{headingText}</span>
<ul class="story-list">

View file

@ -66,7 +66,7 @@
<a href={normalizeUrl(section.url)}>
{section.name}
</a>
<button class="button">
<button class="button" aria-label="{section.name} menu">
<DownArrow rotate={section.id === $activeSection} />
</button>
</div>

View file

@ -58,8 +58,8 @@ updated:
sectionUrl={content.sectionUrl}
hed={content.hed}
authors={content.authors.split(',')}
publishTime={content.published}
updateTime={content.updated}
publishTime={content.publishTime}
updateTime={content.updatTime}
/>
```