0.6.2 • Published 1 year ago

svelte-micro-components v0.6.2

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year ago

svelte-micro-components

svelte-micro-components is a JavaScript library for creating small Svelte components that don't deserve their own file.

Currently supports:

  • Text props (e.g. <h1>Hello ${'name'}!</h1>)
  • Attribute props (<input class={name} />)
    • Note: not class="your-class {propClass}"
  • Event forwarding (optionally under an alias)
    • <button ${on`${'click'}`} />
    • <button ${on`${'click'}=${'otherClick'}`} />
  • Slots
    • Default: <div class="wrapper">${slot()}</div>
    • Named: <div class="wrapper">${slot('slotName')}</div>
  • Actions, including:
    • with events: <div ${use`${outclick}`} /> (the component will emit a fully typed outclick event when the user clicks outside of the element)
    • with props: <div ${use`${longclick}=${'duration'}`} />
  • Nested components
    • <div class="wrapper">${component`<${Nested} />`}</div>
    • with props: <div class="wrapper">${component`<${Nested} prop=${'nested_prop'} />`}</div> (Nested will be passed the prop nested_prop)
    • events are not currently supported

Usage

<script>
	import m from 'svelte-micro-components';
	const Greeting = m`<h1>Hello ${'name'}!</h1>`;

	let name = '';
</script>

<Greeting {name} />
<input class={name} bind:value={name} />
  • Micro component props are typesafe, so trying <Greeting propThatIsntName="world" /> will throw an error.
  • They also support SSR, so you can use them easily in your SvelteKit app.
  • Also note that for attributes, you have to do class={your-class ${propClass}} instead of class="your-class {propClass}", and that there can't be spaces padding the equals sign.

Examples

Basic text interpolation: Link to REPL: REPL

<script lang="ts">
	import m from 'svelte-micro-components';

	const Greeting = m`<h1>Hello ${'name'}</h1>`;
</script>

<Greeting name="world" />

Dynamic attributes: REPL

<script lang="ts">
	import m from 'svelte-micro-components';

	const src = 'https://svelte.dev/tutorial/image.gif';
	const name = 'Rick Astley';

	const Image = m`<img src=${'src'} alt=${'alt'}>`;
</script>

<Image {src} alt="{name} dancing" />

Nested components: REPL

<script lang="ts">
	import m, { component } from 'svelte-micro-components';
	import Nested from './Nested.svelte';

	const Wrapper = m`<div class="wrapper">${component`<${Nested} />`}</div>`;
</script>

<Wrapper />

DOM events: REPL

<script lang="ts">
	let pos = { x: 0, y: 0 };

	function handleMousemove(event: MouseEvent) {
		pos.x = event.clientX;
		pos.y = event.clientY;
	}

	import m, { on } from 'svelte-micro-components';

	const Tracker = m`
		<div ${on`${'mousemove'}`}>
			The mouse position is ${'x'} x ${'y'}
		</div>
	`;
</script>

<Tracker x={pos.x} y={pos.y} on:mousemove={handleMousemove} />

Event forwarding: REPL

<script lang="ts">
	let pos = { x: 0, y: 0 };

	function handleMousemove(event: MouseEvent) {
		pos.x = event.clientX;
		pos.y = event.clientY;
	}

	import m, { on } from 'svelte-micro-components';

	const Tracker = m`
		<div ${on`${'mousemove'}=${'moved'}`}>
			The mouse position is ${'x'} x ${'y'}
		</div>
	`;
</script>

<Tracker x={pos.x} y={pos.y} on:moved={handleMousemove} />

Basic action: REPL

<script context="module" lang="ts">
	import type { Action } from 'svelte/action';

	const changeColor: Action<HTMLElement, string> = (node, param = 'red') => {
		node.style.color = param;

		return {
			update(parameter) {
				node.style.color = parameter;
			}
		};
	};
</script>

<script lang="ts">
	import m, { on, use } from 'svelte-micro-components';

	const Box = m`
		<div ${use`${changeColor}=${'color'}`} ${on`${'click'}`}>
			I start off as red, but when you click me I turn green.
		</div>
	`;

	let color = 'rgb(255, 0, 0)';
</script>

<Box on:click={() => (color = 'rgb(0, 255, 0)')} {color} />

Parameterized action (longpress from this official example): REPL

<script context="module" lang="ts">
	import type { Action } from 'svelte/action';

	declare const longpress: Action<
		HTMLElement,
		number,
		{ 'on:longpress': (e: CustomEvent) => void }
	>;
</script>

<script lang="ts">
	import m, { on, use } from 'svelte-micro-components';

	let pressed = false;
	let duration = 2000;

	const Button = m`
        <button
            ${use`${longpress}=${'duration'}`}
            ${on`${'longpress'}`}
            ${on`${'mouseenter'}`}
        >
            press and hold
        </button>
    `;

	const Message = m`<p>congratulations, you pressed and held for ${'duration'}ms</p>`;
</script>

<label>
	<input type="range" bind:value={duration} max={2000} step={100} />
	{duration}ms
</label>

<Button {duration} on:longpress={() => (pressed = true)} on:mouseenter={() => (pressed = false)} />

{#if pressed}
	<Message {duration} />
{/if}

Complex action: REPL

<script lang="ts" context="module">
	import type { Action } from 'svelte/action';
	declare const pannable: Action<
		HTMLElement,
		null,
		{
			'on:panstart': CustomEvent<{ x: number; y: number }>;
			'on:panmove': CustomEvent<{ x: number; y: number; dx: number; dy: number }>;
			'on:panend': CustomEvent<{ x: number; y: number }>;
		}
	>;
</script>

<script lang="ts">
	import { spring } from 'svelte/motion';

	const coords = spring({ x: 0, y: 0 }, { stiffness: 0.2, damping: 0.4 });

	function handlePanStart() {
		coords.stiffness = coords.damping = 1;
	}

	function handlePanMove(event: CustomEvent<{ x: number; y: number; dx: number; dy: number }>) {
		coords.update(($coords) => ({
			x: $coords.x + event.detail.dx,
			y: $coords.y + event.detail.dy
		}));
	}

	function handlePanEnd() {
		coords.stiffness = 0.2;
		coords.damping = 0.4;
		coords.set({ x: 0, y: 0 });
	}

	import m, { on, use } from 'svelte-micro-components';

	const Box = m`
		<div class="box"
			${use`${pannable}`}
			${on`${'panstart'}`}
			${on`${'panmove'}`}
			${on`${'panend'}`}
			style=${'style'}
		></div>
	`;
</script>

<Box
	on:panstart={handlePanStart}
	on:panmove={handlePanMove}
	on:panend={handlePanEnd}
	style="transform:
		translate({$coords.x}px,{$coords.y}px)
		rotate({$coords.x * 0.2}deg)"
/>

Slots: REPL

<script>
	import m, { slot } from 'svelte-micro-components';

	const Box = m`
		<div class="box">
			${slot()}
		</div>
	`;
</script>

<Box>
	<h2>Hello!</h2>
	<p>This is a box. It can contain anything.</p>
</Box>

Named slots: REPL

<script>
	import m, { slot } from 'svelte-micro-components';

	const ContactCard = m`
        <article class="contact-card">
            <h2>
                ${slot('name')}
            </h2>

            <div class="address">
                ${slot('address')}
            </div>

            <div class="email">
                ${slot('email')}
            </div>
        </article>
    `;
</script>

<ContactCard>
	<span slot="name"> P. Sherman </span>

	<span slot="address">
		42 Wallaby Way<br />
		Sydney
	</span>
</ContactCard>

Modal: REPL

<script>
    let showModal = false;
    
    function dialogShow(node) {
        return {
            update(showModal) {
                if (showModal) node.showModal();
                else node.close();
            }
        }
    }
    
    import m, { slot, on, use } from "svelte-micro-components";
    
    const Modal = m`
        <dialog
            ${on`${"close"}`}
            ${on`${"click"}`}
            ${use`${dialogShow}=${"showmodal"}`}
        >
            <div ${on`${"click"}=${'divClick'}`}>
                ${slot("header")}
                <hr />
                ${slot()}
                <hr />
                <!-- svelte-ignore a11y-autofocus -->
                <button autofocus ${on`${"click"}`}>close modal</button>
            </div>
        </dialog>
    `;
    
    function hide() { showModal = false }
    function show() { showModal = true }
    function stopPropagation(e) { e.stopPropagation(); }
</script>

<button on:click={show}>
    show modal
</button>

<Modal on:close={hide} on:click={hide} on:divClick={stopPropagation} showmodal={showModal}>
    <h2 slot="header">
        modal
        <small><em>adjective</em> mod·al \ˈmō-dəl\</small>
    </h2>

    <ol class="definition-list">
        <li>of or relating to modality in logic</li>
        <li>
            containing provisions as to the mode of procedure or the manner of taking effect —used of a contract or legacy
        </li>
        <li>of or relating to a musical mode</li>
        <li>of or relating to structure as opposed to substance</li>
        <li>of, relating to, or constituting a grammatical form or category characteristically indicating predication</li>
        <li>of or relating to a statistical mode</li>
    </ol>

    <a href="https://www.merriam-webster.com/dictionary/modal">merriam-webster.com</a>
</Modal>
0.6.2

1 year ago

0.6.1

1 year ago

0.6.0

1 year ago

0.5.3

1 year ago

0.5.2

1 year ago

0.5.1

1 year ago

0.5.0

1 year ago

0.4.1

1 year ago

0.3.0

1 year ago

0.2.1

1 year ago

0.2.0

1 year ago

0.1.1

1 year ago

0.1.0

1 year ago

0.0.1

1 year ago