diff --git a/.changeset/chilled-files-poke.md b/.changeset/chilled-files-poke.md new file mode 100644 index 000000000..d1d07c87c --- /dev/null +++ b/.changeset/chilled-files-poke.md @@ -0,0 +1,5 @@ +--- +'layerchart': patch +--- + +Added hideDelay prop to Tooltip for configurable hide behavior diff --git a/packages/layerchart/package.json b/packages/layerchart/package.json index 9ba92eb33..cb7366f92 100644 --- a/packages/layerchart/package.json +++ b/packages/layerchart/package.json @@ -63,7 +63,7 @@ "rehype-slug": "^6.0.0", "shapefile": "^0.6.6", "solar-calculator": "^0.3.0", - "svelte": "^5.19.9", + "svelte": "5.19.4", "svelte-check": "^4.1.4", "svelte-json-tree": "^2.2.0", "svelte-ux": "^0.90.0", diff --git a/packages/layerchart/src/lib/components/tooltip/TooltipContext.svelte b/packages/layerchart/src/lib/components/tooltip/TooltipContext.svelte index 5ac927f55..9ad6b4a0f 100644 --- a/packages/layerchart/src/lib/components/tooltip/TooltipContext.svelte +++ b/packages/layerchart/src/lib/components/tooltip/TooltipContext.svelte @@ -101,7 +101,7 @@ /** Similar to d3-selection's raise, re-insert the e.target as the last child of its parent, so to be the top-most element */ export let raiseTarget = false; - /** Lock tooltip (keep open, do not update on mouse movement). Allows for kicking on tooltip */ + /** Lock tooltip (keep open, do not update on mouse movement). Allows for clicking on tooltip */ export let locked = false; /** quadtree search radius @@ -124,6 +124,10 @@ }); setTooltipContext(tooltip); + /** Delay in ms before hiding tooltip */ + export let hideDelay = 0; + + let isHoveringTooltip = false; let hideTimeoutId: NodeJS.Timeout; $: bisectX = bisector((d: any) => { @@ -175,7 +179,9 @@ function showTooltip(e: PointerEvent, tooltipData?: any) { // Cancel hiding tooltip if from previous event loop - clearTimeout(hideTimeoutId); + if (hideTimeoutId) { + clearTimeout(hideTimeoutId); + } if (locked) { // Ignore (keep current position / data) @@ -294,9 +300,12 @@ } // Wait an event loop tick in case `showTooltip` is called immediately on another element, to allow tweeneing (ex. moving between bands/bars) + // Additional hideDelay can be configured to extend this delay further hideTimeoutId = setTimeout(() => { - $tooltip = { ...$tooltip, data: null }; - }); + if (!isHoveringTooltip) { + $tooltip = { ...$tooltip, data: null }; + } + }, hideDelay); } let quadtree: Quadtree<[number, number]>; @@ -401,9 +410,19 @@ 'TooltipContext absolute touch-none', debug && triggerPointerEvents && 'bg-danger/10 outline outline-danger' )} - on:pointerenter={triggerPointerEvents ? showTooltip : undefined} + on:pointerenter={(e) => { + isHoveringTooltip = true; + if (triggerPointerEvents) { + showTooltip(e); + } + }} on:pointermove={triggerPointerEvents ? showTooltip : undefined} - on:pointerleave={triggerPointerEvents ? hideTooltip : undefined} + on:pointerleave={(e) => { + isHoveringTooltip = false; + if (triggerPointerEvents) { + hideTooltip(); + } + }} on:click={(e) => { if (triggerPointerEvents) { onclick(e, { data: $tooltip?.data }); diff --git a/packages/layerchart/src/routes/docs/components/AreaChart/+page.svelte b/packages/layerchart/src/routes/docs/components/AreaChart/+page.svelte index 5f94d1798..d39efca8a 100644 --- a/packages/layerchart/src/routes/docs/components/AreaChart/+page.svelte +++ b/packages/layerchart/src/routes/docs/components/AreaChart/+page.svelte @@ -860,6 +860,43 @@ +

Fixed tooltip below chart with hide delay

+ + +
+ + + + + {format(x(data), PeriodType.Day)} + + + + {#each series as s} + {@const valueAccessor = accessor(s.value ?? s.key)} + {@const value = valueAccessor(data)} + + {format(value)} + + {/each} + + + + +
+
+

Brushing

diff --git a/packages/layerchart/src/routes/docs/components/Tooltip/+page.ts b/packages/layerchart/src/routes/docs/components/Tooltip/+page.ts index 517b9e35d..4f53cbfce 100644 --- a/packages/layerchart/src/routes/docs/components/Tooltip/+page.ts +++ b/packages/layerchart/src/routes/docs/components/Tooltip/+page.ts @@ -27,6 +27,7 @@ export async function load() { ], 'Multiple instances', 'Maintain within chart container, window/viewport, or overflow outside', + 'Configurable hide delay to prevent accidental hiding when moving to tooltip', ], related: ['components/TooltipContext', 'components/Highlight'], }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 849700b1e..32dc1718c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -100,7 +100,7 @@ importers: version: 4.1.0 layercake: specifier: ^8.4.2 - version: 8.4.2(svelte@5.19.9)(typescript@5.7.3) + version: 8.4.2(svelte@5.19.4)(typescript@5.7.3) lodash-es: specifier: ^4.17.21 version: 4.17.21 @@ -122,16 +122,16 @@ importers: version: 3.0.5(rollup@2.79.2) '@sveltejs/adapter-cloudflare': specifier: ^5.0.2 - version: 5.0.2(@sveltejs/kit@2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(wrangler@3.107.3(@cloudflare/workers-types@4.20250204.0)) + version: 5.0.2(@sveltejs/kit@2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(wrangler@3.107.3(@cloudflare/workers-types@4.20250204.0)) '@sveltejs/kit': specifier: ^2.17.1 - version: 2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) + version: 2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) '@sveltejs/package': specifier: ^2.3.10 - version: 2.3.10(svelte@5.19.9)(typescript@5.7.3) + version: 2.3.10(svelte@5.19.4)(typescript@5.7.3) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 - version: 5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) + version: 5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) '@svitejs/changesets-changelog-github-compact': specifier: ^1.2.0 version: 1.2.0 @@ -215,7 +215,7 @@ importers: version: 15.0.6 mdsvex: specifier: ^0.12.3 - version: 0.12.3(svelte@5.19.9) + version: 0.12.3(svelte@5.19.4) posthog-js: specifier: ^1.215.5 version: 1.215.5 @@ -224,7 +224,7 @@ importers: version: 3.4.2 prettier-plugin-svelte: specifier: ^3.3.3 - version: 3.3.3(prettier@3.4.2)(svelte@5.19.9) + version: 3.3.3(prettier@3.4.2)(svelte@5.19.4) prism-svelte: specifier: ^0.5.0 version: 0.5.0 @@ -241,20 +241,20 @@ importers: specifier: ^0.3.0 version: 0.3.0 svelte: - specifier: ^5.19.9 - version: 5.19.9 + specifier: 5.19.4 + version: 5.19.4 svelte-check: specifier: ^4.1.4 - version: 4.1.4(picomatch@4.0.2)(svelte@5.19.9)(typescript@5.7.3) + version: 4.1.4(picomatch@4.0.2)(svelte@5.19.4)(typescript@5.7.3) svelte-json-tree: specifier: ^2.2.0 - version: 2.2.0(svelte@5.19.9) + version: 2.2.0(svelte@5.19.4) svelte-ux: specifier: ^0.90.0 - version: 0.90.0(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.4.49)(yaml@2.7.0))(postcss@8.4.49)(svelte@5.19.9) + version: 0.90.0(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.4.49)(yaml@2.7.0))(postcss@8.4.49)(svelte@5.19.4) svelte2tsx: specifier: ^0.7.34 - version: 0.7.34(svelte@5.19.9)(typescript@5.7.3) + version: 0.7.34(svelte@5.19.4)(typescript@5.7.3) tailwindcss: specifier: ^3.4.16 version: 3.4.16 @@ -2398,8 +2398,8 @@ packages: resolution: {integrity: sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==} engines: {node: '>=16'} - svelte@5.19.9: - resolution: {integrity: sha512-860s752/ZZxHIsii31ELkdKBOCeAuDsfb/AGUXJyQyzUVLRSt4oqEw/BV5+2+mNg8mbqmD3OK+vMvwWMPM6f8A==} + svelte@5.19.4: + resolution: {integrity: sha512-pzWvFQdvfEfT4Ll/JriAtcG7qmWjcL+x/NSl9Q+FPje5SXukYNp9kcufZ27ydauLLE/dwYMz9XRC8kiwTZmfDA==} engines: {node: '>=18'} tailwind-merge@2.5.4: @@ -3274,17 +3274,17 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.34.4': optional: true - '@sveltejs/adapter-cloudflare@5.0.2(@sveltejs/kit@2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(wrangler@3.107.3(@cloudflare/workers-types@4.20250204.0))': + '@sveltejs/adapter-cloudflare@5.0.2(@sveltejs/kit@2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(wrangler@3.107.3(@cloudflare/workers-types@4.20250204.0))': dependencies: '@cloudflare/workers-types': 4.20250204.0 - '@sveltejs/kit': 2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) + '@sveltejs/kit': 2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) esbuild: 0.24.2 worktop: 0.8.0-next.18 wrangler: 3.107.3(@cloudflare/workers-types@4.20250204.0) - '@sveltejs/kit@2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0))': + '@sveltejs/kit@2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) '@types/cookie': 0.6.0 cookie: 0.6.0 devalue: 5.1.1 @@ -3296,37 +3296,37 @@ snapshots: sade: 1.8.1 set-cookie-parser: 2.7.1 sirv: 3.0.0 - svelte: 5.19.9 + svelte: 5.19.4 vite: 6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0) - '@sveltejs/package@2.3.10(svelte@5.19.9)(typescript@5.7.3)': + '@sveltejs/package@2.3.10(svelte@5.19.4)(typescript@5.7.3)': dependencies: chokidar: 4.0.3 kleur: 4.1.5 sade: 1.8.1 semver: 7.7.1 - svelte: 5.19.9 - svelte2tsx: 0.7.34(svelte@5.19.9)(typescript@5.7.3) + svelte: 5.19.4 + svelte2tsx: 0.7.34(svelte@5.19.4)(typescript@5.7.3) transitivePeerDependencies: - typescript - '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0))': + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) debug: 4.4.0 - svelte: 5.19.9 + svelte: 5.19.4 vite: 6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0))': + '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.9)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)))(svelte@5.19.4)(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) debug: 4.4.0 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.17 - svelte: 5.19.9 + svelte: 5.19.4 vite: 6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0) vitefu: 1.0.5(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(yaml@2.7.0)) transitivePeerDependencies: @@ -4127,13 +4127,13 @@ snapshots: kleur@4.1.5: {} - layercake@8.4.2(svelte@5.19.9)(typescript@5.7.3): + layercake@8.4.2(svelte@5.19.4)(typescript@5.7.3): dependencies: d3-array: 3.2.4 d3-color: 3.1.0 d3-scale: 4.0.2 d3-shape: 3.2.0 - svelte: 5.19.9 + svelte: 5.19.4 typescript: 5.7.3 lilconfig@3.1.3: {} @@ -4178,12 +4178,12 @@ snapshots: mdn-data@2.0.30: {} - mdsvex@0.12.3(svelte@5.19.9): + mdsvex@0.12.3(svelte@5.19.4): dependencies: '@types/unist': 2.0.11 prism-svelte: 0.4.7 prismjs: 1.29.0 - svelte: 5.19.9 + svelte: 5.19.4 vfile-message: 2.0.4 merge2@1.4.1: {} @@ -4420,10 +4420,10 @@ snapshots: preact@10.25.4: {} - prettier-plugin-svelte@3.3.3(prettier@3.4.2)(svelte@5.19.9): + prettier-plugin-svelte@3.3.3(prettier@3.4.2)(svelte@5.19.4): dependencies: prettier: 3.4.2 - svelte: 5.19.9 + svelte: 5.19.4 prettier@2.8.8: {} @@ -4679,21 +4679,21 @@ snapshots: - stylus - sugarss - svelte-check@4.1.4(picomatch@4.0.2)(svelte@5.19.9)(typescript@5.7.3): + svelte-check@4.1.4(picomatch@4.0.2)(svelte@5.19.4)(typescript@5.7.3): dependencies: '@jridgewell/trace-mapping': 0.3.25 chokidar: 4.0.3 fdir: 6.4.3(picomatch@4.0.2) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.19.9 + svelte: 5.19.4 typescript: 5.7.3 transitivePeerDependencies: - picomatch - svelte-json-tree@2.2.0(svelte@5.19.9): + svelte-json-tree@2.2.0(svelte@5.19.4): dependencies: - svelte: 5.19.9 + svelte: 5.19.4 svelte-preprocess@6.0.3(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.4.49)(yaml@2.7.0))(postcss@8.4.49)(svelte@4.2.19)(typescript@5.7.3): dependencies: @@ -4703,7 +4703,7 @@ snapshots: postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.4.49)(yaml@2.7.0) typescript: 5.7.3 - svelte-ux@0.90.0(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.4.49)(yaml@2.7.0))(postcss@8.4.49)(svelte@5.19.9): + svelte-ux@0.90.0(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.4.49)(yaml@2.7.0))(postcss@8.4.49)(svelte@5.19.4): dependencies: '@floating-ui/dom': 1.6.13 '@fortawesome/fontawesome-common-types': 6.7.2 @@ -4725,7 +4725,7 @@ snapshots: prism-themes: 1.9.0 prismjs: 1.29.0 sveld: 0.22.0(postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.4.49)(yaml@2.7.0))(postcss@8.4.49) - svelte: 5.19.9 + svelte: 5.19.4 tailwind-merge: 2.6.0 zod: 3.24.1 transitivePeerDependencies: @@ -4740,11 +4740,11 @@ snapshots: - sugarss - ts-node - svelte2tsx@0.7.34(svelte@5.19.9)(typescript@5.7.3): + svelte2tsx@0.7.34(svelte@5.19.4)(typescript@5.7.3): dependencies: dedent-js: 1.0.1 pascal-case: 3.1.2 - svelte: 5.19.9 + svelte: 5.19.4 typescript: 5.7.3 svelte@4.2.19: @@ -4764,7 +4764,7 @@ snapshots: magic-string: 0.30.17 periscopic: 3.1.0 - svelte@5.19.9: + svelte@5.19.4: dependencies: '@ampproject/remapping': 2.3.0 '@jridgewell/sourcemap-codec': 1.5.0