svelte-put

repository·main·Indexed 21 days ago

https://github.com/vnphanquang/svelte-put

A collection of modular Svelte utilities, components, and actions for common web functionalities. Includes packages for async stack management (@svelte-put/async-stack), avatar rendering (@svelte-put/avatar), click-outside detection (@svelte-put/clickoutside), Cloudflare Turnstile integration (@svelte-put/cloudflare-turnstile), clipboard copying (@svelte-put/copy), drag-to-scroll (@svelte-put/dragscroll), SVG inlining (@svelte-put/inline-svg), and intersection observers (@svelte-put/intersect).

Tokens
67.3K
Snippets
225
Records
267
Agent score
74%

What's inside svelte-put

  1. Overview of @svelte-put packages

    main

    The @svelte-put ecosystem is a collection of specialized Svelte utilities and components designed to add common functionalities to Svelte projects. Each package is self-managed with its own release cycle.

    Important Migration Note: If you are using Svelte 5, it is highly recommended to migrate to Svelte 5 and upgrade to the next major versions of the corresponding svelte-put/* packages to ensure compatibility.

  2. How @svelte-put/toc works

    main

    The @svelte-put/toc package uses a Svelte action strategy to build a Table of Contents. It works by:

    1. Root Observation: The toc.actions.root action marks a container as the root for TOC generation. It assigns a unique data-toc-root ID and sets up observation for headings within that container.
    2. Heading Identification: The package identifies headings and can inject anchor links (e.g., #) into them for better UX. It uses data-toc attributes to mark these elements.
    3. Link Management: The toc.actions.link action is applied to <a> tags. It automatically sets the href to the heading's ID and manages the data-toc-link-current attribute to indicate which heading is currently active in the viewport.
    4. State Management: The Toc class provides a items collection (a Map) containing the heading metadata, allowing you to build custom UI components that react to the document structure.
  3. How `@svelte-put/preprocess-external-link` identifies external links

    main

    The preprocessor determines if a link is external based on two criteria:

    1. Domain matching: If the link's domain is NOT included in the array passed to externalLink(), it is treated as external.
    2. Manual override: Adding the data-external attribute to an <a> tag forces it to be treated as an external link.

    Internal links (those matching your provided domains or relative paths) remain unchanged. External links will have target="_blank" and rel="noreferrer noopener" injected into the output HTML.

    <!-- Input: External link via domain -->
    <a href="https://svelte.dev/">Svelte</a>
    
    <!-- Input: External link via manual attribute -->
    <a href="https://developer.mozilla.org" data-external>MDN</a>
    
    <!-- Output: Both receive attributes -->
    <a href="https://svelte.dev/" target="_blank" rel="noreferrer noopener">Svelte</a>
    <a href="https://developer.mozilla.org" data-external target="_blank" rel="noreferrer noopener">MDN</a>
  4. Quick Start with `@svelte-put/lockscroll`

    main

    The @svelte-put/lockscroll package provides a Svelte action use:lockscroll that allows you to lock the scroll within an HTML element. A common use case is locking the body scroll when a modal or overlay is active.

    To use it, import lockscroll and pass a boolean value to the action. When the value is true, scrolling is locked; when false, scrolling is enabled.

    <script>
    	import { lockscroll } from '@svelte-put/lockscroll';
    
    	let locked = $state(false);
    </script>
    
    <svelte:body use:lockscroll="{locked}" />
    
    <button onclick="{() => locked = !locked}">Toggle lock scroll on body</button>
  5. Quick Start with @svelte-put/toc

    main

    To build a Table of Contents (TOC) in Svelte, use the Toc class and the use:toc action. The Toc class manages the state of the headings, while the toc.actions provide Svelte actions to link the root container and individual links to the headings.

    1. Initialize a new Toc instance. Passing { observe: true } enables observation of heading changes.
    2. Apply use:toc.actions.root to the main container that wraps your content.
    3. Iterate over toc.items to render your list.
    4. Apply use:toc.actions.link to the anchor tags within your list to automatically handle IDs, text content injection, and active state tracking.
    <!-- input.svelte -->
    <script>
    	import { Toc } from '@svelte-put/toc';
    
    	const toc = new Toc({ observe: true });
    </script>
    
    <main use:toc.actions.root>
    	<h1 id="page-heading">Page Heading</h1>
    
    	<section>
    		<h2 id="table-of-contents">Table of Contents</h2>
    		{#if toc.items.size}
    		<ul>
    			{#each toc.items.values() as tocItem (tocItem.id)}
    			<li
    				<!-- svelte-ignore a11y_missing_attribute -->
    				<a use:toc.actions.link="{tocItem}">
    					<!-- textContent injected by toc -->
    				</a>
    			</li>
    			{/each}
    		</ul>
    		{/if}
    	</section>
    
    	<section>
    		<h2 id="section-heading-level-2">Section Heading Level 2</h2>
    		<p>...</p>
    	</section>
    
    	<section>
    		<h3 id="section-heading-level-3">Section Heading Level 3</h3>
    		<p>...</p>
    	</section>
    </main>
  6. Use the `use:copy` action to copy text to clipboard

    main

    The @svelte-put/copy package provides a Svelte action use:copy that allows you to copy text to the clipboard when an element is interacted with.

    When the copy action is triggered, it dispatches a oncopied custom event. You can listen to this event to access the CopyDetail object, which contains the text that was successfully copied.

    To use it, import copy and CopyDetail from @svelte-put/copy and apply the use:copy directive to your target element (e.g., a button).

    <script lang="ts">
    	import { copy, type CopyDetail } from '@svelte-put/copy';
    
    	function handleCopied(e: CustomEvent<CopyDetail>) {
    		console.log('Text copied:', e.detail.text);
    	}
    </script>
    
    <button type="button" use:copy oncopied="{handleCopied}">Click to copy this</button>
  7. Install and configure `@svelte-put/preprocess-external-link`

    main

    Use @svelte-put/preprocess-external-link to automatically add target="_blank" and rel="noreferrer noopener" attributes to anchor tags (<a>) that point to external domains.

    To set it up, add the preprocessor to your svelte.config.js and provide an array of domain strings that should be treated as internal (and thus will not receive the external attributes).

    // svelte.config.js
    import externalLink from '@svelte-put/preprocess-external-link';
    
    /** @type {import('@sveltejs/kit').Config} */
    const config = {
    	preprocess: [
    		externalLink(['your-domain.com', 'your-other-domain.com']),
    		// other preprocessors,
    	],
    };
    export default config;
  8. Quick Start with @svelte-put/popover

    main

    To use the Popover enhancement in Svelte, import the Popover class from @svelte-put/popover. You instantiate it with new Popover() and then apply its properties to two distinct elements:

    1. The Control Element: The element that triggers the popover (e.g., a button). Apply popover.control.attributes using the spread operator and popover.control.actions using the use: directive.
    2. The Target Element: The element that contains the popover content. Apply popover.target.attributes using the spread operator and popover.target.actions using the use: directive.

    This implementation leverages the native browser Popover API.

    <script>
    	import { Popover } from '@svelte-put/popover';
    
    	const popover = new Popover();
    </script>
    
    <button {...popover.control.attributes} use:popover.control.actions>Open me Popover</button>
    
    <div {...popover.target.attributes} use:popover.target.actions>
    	<p>Popover content. Click backdrop to dismiss</p>
    </div
    >
  9. Quick Start with `@svelte-put/intersect`

    main

    The @svelte-put/intersect package provides a Svelte action use:intersect which acts as a wrapper for the browser's IntersectionObserver.

    To use it, import the intersect action and the IntersectDetail type. You can listen for intersection events using the onintersect directive. You can also use the onintersectonce directive if you only want the intersection to trigger once.

    When an intersection occurs, a CustomEvent is dispatched. The event's detail property contains an IntersectDetail object with the following properties:

    • observer: The IntersectionObserver instance.
    • entries: An array of IntersectionObserverEntry objects.
    • direction: The scrolling direction (e.g., when the element enters or leaves the viewport).
    <script lang="ts">
    	import { intersect, type IntersectDetail } from '@svelte-put/intersect';
    
    	function onIntersect(e: CustomEvent<IntersectDetail>) {
    		const { observer, entries, direction } = e.detail;
    		console.log('the observer itself', observer);
    		console.log('scrolling direction:', direction);
    		console.log('intersecting:', entries[0]?.isIntersecting ? 'entering' : 'leaving');
    	}
    </script>
    
    <div use:intersect onintersect="{onIntersect}" onintersectonce></div>
  10. Quick Start with @svelte-put/qr

    main

    The @svelte-put/qr package allows you to render QR codes as either an <img> element or an <svg> element. You can optionally include a logo in the center of the QR code.

    There are two ways to use the package:

    1. As a Svelte Component: Import the component and use it like any other Svelte component.
    2. As a Svelte Action: Import the action and use the use: directive on an existing <img> or <svg> element.
    <script>
    	// as img
    	import { qr as imgQR } from '@svelte-put/qr/img';
    	import ImgQR from '@svelte-put/qr/img/QR.svelte';
    
    	// as svg
    	import { qr as svgQR } from '@svelte-put/qr/svg';
    	import SvgQR from '@svelte-put/qr/svg/QR.svelte';
    
    	const data = 'https://svelte-put.vnphanquang.com/docs/qr';
    	const logo = 'https://svelte-put.vnphanquang.com/images/svelte-put-logo.svg';
    </script>
    
    <!-- svg using component -->
    <SvgQR {data} {logo} />
    
    <!-- svg using action -->
    <svg use:svgQR="{{ data, logo }}" />
    
    <!-- img using component -->
    <ImgQR {data} {logo} />
    
    <!-- img using action -->
    <img use:imgQR="{{ data, logo }}" />
  11. Quick Start with `@svelte-put/shortcut`

    main

    The @svelte-put/shortcut package provides a Svelte action called use:shortcut that allows you to easily add keyboard shortcut event listeners to elements or the window.

    To use it, import the shortcut action and pass a configuration object to the use: directive. A common pattern is to apply it to <svelte:window /> to listen for global shortcuts. The configuration object requires a trigger property which defines the key, optional modifiers, and the callback function to execute when the shortcut is pressed.

    <script lang="ts">
      import { shortcut, type ShortcutEventDetail } from '@svelte-put/shortcut';
    
      function handleK(detail: ShortcutEventDetail) { 
        // detail.node is the element the action is attached to
        console.log('attached node:', detail.node);
        // detail.trigger contains the original configuration
        console.log('original trigger config:', detail.trigger);
      }
    </script>
    
    <svelte:window
      use:shortcut={{
        trigger: {
          key: 'k',
          modifier: ['ctrl', 'meta'],
          callback: handleK,
        },
      }}
    />