Skip to content

Commit 26dba29

Browse files
committed
chore: wrap <a> in Anchor helper component
1 parent 8459546 commit 26dba29

File tree

4 files changed

+94
-65
lines changed

4 files changed

+94
-65
lines changed

src/lib/marks/Area.svelte

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import { maybeCurve } from '$lib/helpers/curves.js';
3030
import { isValid } from '$lib/helpers/index.js';
3131
import AreaCanvas from './helpers/AreaCanvas.svelte';
32+
import Anchor from './helpers/Anchor.svelte';
3233
3334
import type {
3435
CurveName,
@@ -37,7 +38,6 @@
3738
BaseMarkProps,
3839
ConstantAccessor,
3940
ChannelAccessor,
40-
FacetContext,
4141
ScaledDataRecord,
4242
LinkableMarkProps
4343
} from '../types.js';
@@ -113,32 +113,24 @@
113113
{:else}
114114
<GroupMultiple length={grouped.length}>
115115
{#each grouped as areaData, i (i)}
116-
{#snippet el(datum: ScaledDataRecord)}
117-
{@const title = resolveProp(options.title, datum.datum, '')}
118-
{@const [style, styleClass] = resolveStyles(
119-
plot,
120-
datum,
121-
options,
122-
'fill',
123-
usedScales
124-
)}
125-
<path
126-
class={['svelteplot-area', className, styleClass]}
127-
clip-path={options.clipPath}
128-
d={areaPath(areaData)}
129-
{style}
130-
>{#if title}<title>{title}</title>{/if}</path>
131-
{/snippet}
116+
{@const datum = areaData[0]}
132117
{#if areaData.length > 0}
133-
{#if options.href}
134-
<a
135-
href={resolveProp(options.href, areaData[0].datum, '')}
136-
target={resolveProp(options.target, areaData[0].datum, '_self')}>
137-
{@render el(areaData[0])}
138-
</a>
139-
{:else}
140-
{@render el(areaData[0])}
141-
{/if}
118+
<Anchor {options} {datum}>
119+
{@const title = resolveProp(options.title, datum.datum, '')}
120+
{@const [style, styleClass] = resolveStyles(
121+
plot,
122+
datum,
123+
options,
124+
'fill',
125+
usedScales
126+
)}
127+
<path
128+
class={['svelteplot-area', className, styleClass]}
129+
clip-path={options.clipPath}
130+
d={areaPath(areaData)}
131+
{style}
132+
>{#if title}<title>{title}</title>{/if}</path>
133+
</Anchor>
142134
{/if}
143135
{/each}
144136
</GroupMultiple>

src/lib/marks/Geo.svelte

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
geoType?: 'sphere' | 'graticule';
88
dragRotate: boolean;
99
canvas: boolean;
10-
href: ConstantAccessor<string>;
11-
target: ConstantAccessor<string>;
10+
/**
11+
* simple browser tooltip to be displayed on mouseover
12+
*/
13+
title: ConstantAccessor<string>;
1214
} & BaseMarkProps &
1315
LinkableMarkProps;
1416
</script>
@@ -31,6 +33,7 @@
3133
import GeoCanvas from './helpers/GeoCanvas.svelte';
3234
import { recordize } from '$lib/transforms/recordize.js';
3335
import { GEOJSON_PREFER_STROKE } from '$lib/helpers/index.js';
36+
import Anchor from './helpers/Anchor.svelte';
3437
3538
const { getPlotState } = getContext<PlotContext>('svelteplot');
3639
const plot = $derived(getPlotState());
@@ -68,28 +71,6 @@
6871
channels={['fill', 'stroke', 'opacity', 'fillOpacity', 'strokeOpacity', 'r']}
6972
{...args}>
7073
{#snippet children({ mark, scaledData, usedScales })}
71-
{#snippet el(d)}
72-
{@const title = resolveProp(args.title, d.datum, '')}
73-
{@const geometry = resolveProp(args.geometry, d.datum, d.datum)}
74-
{@const [style, styleClass] = resolveStyles(
75-
plot,
76-
d,
77-
args,
78-
GEOJSON_PREFER_STROKE.has(geometry.type) ? 'stroke' : 'fill',
79-
usedScales
80-
)}
81-
<path
82-
d={path(geometry)}
83-
{style}
84-
class={[styleClass]}
85-
use:addEventHandlers={{
86-
getPlotState,
87-
options: args,
88-
datum: d.datum
89-
}}>
90-
{#if title}<title>{title}</title>{/if}
91-
</path>
92-
{/snippet}
9374
<g
9475
aria-label="geo"
9576
class={['geo', geoType && `geo-${geoType}`, className]}
@@ -99,15 +80,28 @@
9980
{:else}
10081
{#each scaledData as d, i (i)}
10182
{#if d.valid}
102-
{#if options.href}
103-
<a
104-
href={resolveProp(args.href, d.datum, '')}
105-
target={resolveProp(args.target, d.datum, '_self')}>
106-
{@render el(d)}
107-
</a>
108-
{:else}
109-
{@render el(d)}
110-
{/if}
83+
<Anchor {options} datum={d.datum}>
84+
{@const title = resolveProp(args.title, d.datum, '')}
85+
{@const geometry = resolveProp(args.geometry, d.datum, d.datum)}
86+
{@const [style, styleClass] = resolveStyles(
87+
plot,
88+
d,
89+
args,
90+
GEOJSON_PREFER_STROKE.has(geometry.type) ? 'stroke' : 'fill',
91+
usedScales
92+
)}
93+
<path
94+
d={path(geometry)}
95+
{style}
96+
class={[styleClass]}
97+
use:addEventHandlers={{
98+
getPlotState,
99+
options: args,
100+
datum: d.datum
101+
}}>
102+
{#if title}<title>{title}</title>{/if}
103+
</path>
104+
</Anchor>
111105
{/if}
112106
{/each}
113107
{/if}

src/lib/marks/helpers/Anchor.svelte

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script>
2+
import { resolveProp } from '$lib/helpers/resolve';
3+
4+
let { datum = {}, options = {}, children } = $props();
5+
6+
const href = $derived(resolveProp(options.href, datum, null));
7+
const target = $derived(resolveProp(options.target, datum, null));
8+
const rel = $derived(resolveProp(options.rel, datum, null));
9+
const type = $derived(resolveProp(options.type, datum, null));
10+
const download = $derived(resolveProp(options.download, datum, null));
11+
</script>
12+
13+
{#if href}
14+
<!-- we can't use <a> directly here because Svelte confuses it with the
15+
HTMLAElement which breaks the rendering -->
16+
<svelte:element
17+
this={'a'}
18+
{href}
19+
{target}
20+
{rel}
21+
{type}
22+
{download}
23+
aria-label="link"
24+
xmlns="http://www.w3.org/2000/svg">
25+
{@render children?.()}
26+
</svelte:element>
27+
{:else}
28+
{@render children?.()}
29+
{/if}

src/lib/types.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -634,15 +634,29 @@ export type FacetContext = {
634634

635635
export type LinkableMarkProps = {
636636
/**
637-
* simple browser tooltip to be displayed on mouseover
637+
* if set, the mark element will be wrapped in a <a> link element
638638
*/
639-
title: ConstantAccessor<string>;
639+
href: ConstantAccessor<string>;
640640
/**
641-
* if set, the mark element will be wrapped in a <a> link
642-
* element
641+
* the relationship of the target object to the link object (e.g. "noopener")
642+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a#rel
643643
*/
644-
href: ConstantAccessor<string>;
645-
target: ConstantAccessor<'_self' | '_blank' | string>;
644+
rel: ConstantAccessor<string>;
645+
/**
646+
* the link target mime type, e.g. "text/csv"
647+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a#type
648+
*/
649+
type: ConstantAccessor<string>;
650+
/**
651+
* the target of the link, e.g. "_blank" or "_self"
652+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a#target
653+
*/
654+
target: ConstantAccessor<'_self' | '_blank' | '_parent' | '_top' | string>;
655+
/**
656+
* if set to true, the link will be downloaded instead of navigating to it
657+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download
658+
*/
659+
download: ConstantAccessor<boolean>;
646660
};
647661

648662
export type BaseMarkProps = Partial<{

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy