Skip to content

Commit

Permalink
feat: add labels prop and slot
Browse files Browse the repository at this point in the history
See #1
  • Loading branch information
theetrain committed Jul 22, 2024
1 parent 29be2c1 commit 09cf893
Show file tree
Hide file tree
Showing 13 changed files with 365 additions and 19 deletions.
4 changes: 2 additions & 2 deletions e2e/svelte-4/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion e2e/svelte-4/src/lib/Button.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
<script>
export let size = "medium"
export let variant = "primary"
export let disabled = false
/** @type {{ [key: string]: string }} */
export let definitions = {}
</script>

<button {...$$restProps} class="{variant} {size}">
<button {...$$restProps} {disabled} class="{variant} {size}">
<slot name="left" />
<slot />
{#if definitions}
<dl>
{#each Object.entries(definitions) as [term, definition]}
<dt>{term}</dt>
<dd>{definition}</dd>
{/each}
</dl>
{/if}
<slot name="right" />
</button>

Expand Down
12 changes: 12 additions & 0 deletions e2e/svelte-4/src/lib/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,15 @@ body {
box-sizing: border-box;
margin: 0;
}

h1 {
font-size: 1.75rem;
}
h2 {
font-size: 1.5rem;
}

h1,
h2 {
margin-bottom: 0.75rem;
}
32 changes: 32 additions & 0 deletions e2e/svelte-4/src/routes/labels/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script>
import { Cartesian } from "svelte-cartesian"
import Button from "$lib/Button.svelte"
const props = {
props: {
size: ["small", "medium", "large"],
variant: ["primary", "secondary"],
disabled: [true, false],
definitions: [{ animals: "a holistic group of species" }],
},
Component: Button,
}
</script>

<h1>Labelled Cartesian</h1>

<h2>Short - explicit</h2>

<Cartesian {...props} labels="short">Make popcorn</Cartesian>

<h2>Short - implicit</h2>

<Cartesian {...props} labels>Make popcorn</Cartesian>

<h2>Long</h2>

<Cartesian {...props} labels="long">Make popcorn</Cartesian>

<h2>Long with objects</h2>

<Cartesian {...props} labels="long-with-objects">Make popcorn</Cartesian>
69 changes: 69 additions & 0 deletions e2e/svelte-4/src/routes/labels/custom/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<script>
import { Cartesian } from "svelte-cartesian"
import Button from "$lib/Button.svelte"
const props = {
props: {
size: ["small", "medium", "large"],
variant: ["primary", "secondary"],
disabled: [true, false],
definitions: [{ animals: "a holistic group of species" }],
},
Component: Button,
}
/**
* @param {Record<string, any>} innerProps
*/
function customLabel(innerProps) {
return Object.entries(innerProps)
.map(([key, value]) => {
let refinedValue = value
if (typeof value === "object") {
refinedValue = JSON.stringify(value)
} else if (typeof value !== "string" && typeof value !== "number") {
refinedValue = typeof value
}
return `${key}: ${refinedValue}`
})
.join("\n")
}
</script>

<h2>Custom label, string value</h2>

<Cartesian {...props} labels="long-with-objects">
Make popcorn
<div class="label-container" slot="label" let:label>
<span class="label">Props</span>
<pre class="props">{label}</pre>
</div>
</Cartesian>

<h2>Custom label, object value</h2>

<Cartesian {...props} labels="long-with-objects">
Make popcorn
<div class="label-container" slot="label" let:innerProps>
<span class="label">Props</span>
<pre class="props">{customLabel(innerProps)}</pre>
</div>
</Cartesian>

<style>
.label-container {
border: 1px solid black;
border-radius: 3px;
padding: 0.5rem;
margin-top: 0.5rem;
}
.label {
font-size: 1.25rem;
font-weight: 600;
}
.props {
color: crimson;
}
</style>
12 changes: 12 additions & 0 deletions e2e/svelte-4/src/routes/labels/dark/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script>
import Page from "../+page.svelte"
</script>

<Page />

<style>
:global(body) {
background-color: #000;
color: #fff;
}
</style>
8 changes: 7 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@ const compat = new FlatCompat()
export default [
// standard compatibility
...compat.extends('eslint-config-standard'),
...eslintPluginSvelte.configs['flat/recommended']
...eslintPluginSvelte.configs['flat/recommended'],
{
rules: {
'no-multi-str': 0,
'operator-linebreak': ['error', 'before']
}
}
]
1 change: 1 addition & 0 deletions jsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"sourceMap": true,
"strict": true,
"module": "ESNext",
"lib": ["ESNext"],
"moduleResolution": "Bundler"
},
"exclude": ["e2e/**"]
Expand Down
79 changes: 71 additions & 8 deletions lib/Cartesian.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script>
import { getCartesianProduct } from "./cartesian"
import { createLabel, getCartesianProduct } from "./cartesian"
/** A Svelte component. */
export let Component
Expand All @@ -18,6 +18,19 @@
*/
export let asChild = false
/**
* Generate labels under every iteration.
*
* - **true**: same as `'short'`.
* - **short**: display comma-separated values, skip objects.
* - **long**: display line-separated key-value pairs, represent object values
* as their type name.
* - **long-with-objects**: same as `'long'` but with full object definitions.
* @type {undefined | boolean | 'short' | 'long' | 'long-with-objects'}
* @default undefined
*/
export let labels = undefined
/**
* Disable built-in CSS.
* @type {boolean}
Expand All @@ -33,25 +46,75 @@
const cartesianProps = getCartesianProduct(props)
</script>

<div class:container={!unstyled} {...divAttributes}>
<!--
@component
A single component that helps render prop combinations
(the "Cartesian Product") for visual regression testing.
-->

<div class:sc-container={!unstyled} {...divAttributes}>
{#each cartesianProps as innerProps}
<div>
{@const label = labels && createLabel(innerProps, { verbosity: labels })}
<div class="sc-group">
{#if asChild}
<slot {innerProps} />
<div>
<slot {innerProps} />
</div>
{#if labels}
<div>
<slot name="label" {label} {innerProps}>
<pre class="sc-label">{label}</pre>
</slot>
</div>
{/if}
{:else}
<svelte:component this={Component} {...innerProps}>
<slot />
</svelte:component>
<div>
<svelte:component this={Component} {...innerProps}>
<slot />
</svelte:component>
</div>
{#if labels}
<div>
<slot name="label" {label} {innerProps}>
<pre class="sc-label">{label}</pre>
</slot>
</div>
{/if}
{/if}
</div>
{/each}
</div>

<style>
.container {
:where(.sc-container) {
display: grid;
grid-template-columns: var(--columns, repeat(2, 1fr));
gap: 1rem;
padding: 0.5rem 1rem;
}
:where(.sc-group) {
display: flex;
flex-direction: column;
}
:where(.sc-label) {
display: inline-block;
background-color: #fff;
color: #000;
padding: 0.25rem;
margin: 0.25rem;
border-radius: 3px;
font-family:
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
Oxygen,
Ubuntu,
Cantarell,
"Open Sans",
"Helvetica Neue",
sans-serif;
font-size: var(--label-font-size, 0.875rem);
}
</style>
25 changes: 25 additions & 0 deletions lib/Cartesian.svelte.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ interface Props {
* @default false
*/
asChild?: boolean
/**
* Generate labels under every iteration.
*
* - **true**: same as `'short'`.
* - **short**: display comma-separated values, skip objects.
* - **long**: display line-separated key-value pairs, represent object values
* as their type name.
* - **long-with-objects**: same as `'long'` but with full object definitions.
* @default undefined
*/
labels?: undefined | boolean | 'short' | 'long' | 'long-with-objects'
/**
* Disable built-in CSS.
* @default false
Expand All @@ -26,6 +37,10 @@ interface Props {
divAttributes?: RestProps
}

/**
* A single component that helps render prop combinations
* (the "Cartesian Product") for visual regression testing.
*/
export default class Cartesian extends SvelteComponent<
Props,
{},
Expand All @@ -38,5 +53,15 @@ export default class Cartesian extends SvelteComponent<
*/
innerProps: Record<string, any>
}
label: {
/**
* The generated label. Hint: use `<pre>` to render provided newline characters.
*/
label: string
/**
* A single combination of props.
*/
innerProps: Record<string, any>
}
}
> {}
Loading

0 comments on commit 09cf893

Please sign in to comment.