Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add SetValues #731

Merged
merged 1 commit into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/perfect-dryers-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solid-primitives/keyed": minor
---

Add `SetValues` control flow component.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ The goal of Solid Primitives is to wrap client and server side functionality to
|<h4>*Control Flow*</h4>|
|[context](https://github.com/solidjs-community/solid-primitives/tree/main/packages/context#readme)|[![STAGE](https://img.shields.io/endpoint?style=for-the-badge&label=&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolidjs-community%2Fsolid-primitives%2Fmain%2Fassets%2Fbadges%2Fstage-2.json)](https://github.com/solidjs-community/solid-primitives/blob/main/CONTRIBUTING.md#contribution-process)|[createContextProvider](https://github.com/solidjs-community/solid-primitives/tree/main/packages/context#createcontextprovider)<br />[MultiProvider](https://github.com/solidjs-community/solid-primitives/tree/main/packages/context#multiprovider)|[![SIZE](https://img.shields.io/bundlephobia/minzip/@solid-primitives/context?style=for-the-badge&label=)](https://bundlephobia.com/package/@solid-primitives/context)|[![VERSION](https://img.shields.io/npm/v/@solid-primitives/context?style=for-the-badge&label=)](https://www.npmjs.com/package/@solid-primitives/context)|
|[jsx-tokenizer](https://github.com/solidjs-community/solid-primitives/tree/main/packages/jsx-tokenizer#readme)|[![STAGE](https://img.shields.io/endpoint?style=for-the-badge&label=&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolidjs-community%2Fsolid-primitives%2Fmain%2Fassets%2Fbadges%2Fstage-2.json)](https://github.com/solidjs-community/solid-primitives/blob/main/CONTRIBUTING.md#contribution-process)|[createTokenizer](https://github.com/solidjs-community/solid-primitives/tree/main/packages/jsx-tokenizer#createtokenizer)<br />[createToken](https://github.com/solidjs-community/solid-primitives/tree/main/packages/jsx-tokenizer#createtoken)<br />[resolveTokens](https://github.com/solidjs-community/solid-primitives/tree/main/packages/jsx-tokenizer#resolvetokens)<br />[isToken](https://github.com/solidjs-community/solid-primitives/tree/main/packages/jsx-tokenizer#istoken)|[![SIZE](https://img.shields.io/bundlephobia/minzip/@solid-primitives/jsx-tokenizer?style=for-the-badge&label=)](https://bundlephobia.com/package/@solid-primitives/jsx-tokenizer)|[![VERSION](https://img.shields.io/npm/v/@solid-primitives/jsx-tokenizer?style=for-the-badge&label=)](https://www.npmjs.com/package/@solid-primitives/jsx-tokenizer)|
|[keyed](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#readme)|[![STAGE](https://img.shields.io/endpoint?style=for-the-badge&label=&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolidjs-community%2Fsolid-primitives%2Fmain%2Fassets%2Fbadges%2Fstage-3.json)](https://github.com/solidjs-community/solid-primitives/blob/main/CONTRIBUTING.md#contribution-process)|[keyArray](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#keyarray)<br />[Key](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#key)<br />[Entries](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#entries)<br />[MapEntries](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#mapentries)|[![SIZE](https://img.shields.io/bundlephobia/minzip/@solid-primitives/keyed?style=for-the-badge&label=)](https://bundlephobia.com/package/@solid-primitives/keyed)|[![VERSION](https://img.shields.io/npm/v/@solid-primitives/keyed?style=for-the-badge&label=)](https://www.npmjs.com/package/@solid-primitives/keyed)|
|[keyed](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#readme)|[![STAGE](https://img.shields.io/endpoint?style=for-the-badge&label=&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolidjs-community%2Fsolid-primitives%2Fmain%2Fassets%2Fbadges%2Fstage-3.json)](https://github.com/solidjs-community/solid-primitives/blob/main/CONTRIBUTING.md#contribution-process)|[keyArray](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#keyarray)<br />[Key](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#key)<br />[Entries](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#entries)<br />[MapEntries](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#mapentries)<br />[SetValues](https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#setvalues)|[![SIZE](https://img.shields.io/bundlephobia/minzip/@solid-primitives/keyed?style=for-the-badge&label=)](https://bundlephobia.com/package/@solid-primitives/keyed)|[![VERSION](https://img.shields.io/npm/v/@solid-primitives/keyed?style=for-the-badge&label=)](https://www.npmjs.com/package/@solid-primitives/keyed)|
|[list](https://github.com/solidjs-community/solid-primitives/tree/main/packages/list#readme)|[![STAGE](https://img.shields.io/endpoint?style=for-the-badge&label=&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolidjs-community%2Fsolid-primitives%2Fmain%2Fassets%2Fbadges%2Fstage-0.json)](https://github.com/solidjs-community/solid-primitives/blob/main/CONTRIBUTING.md#contribution-process)|[listArray](https://github.com/solidjs-community/solid-primitives/tree/main/packages/list#listarray)<br />[List](https://github.com/solidjs-community/solid-primitives/tree/main/packages/list#list)|[![SIZE](https://img.shields.io/bundlephobia/minzip/@solid-primitives/list?style=for-the-badge&label=)](https://bundlephobia.com/package/@solid-primitives/list)|[![VERSION](https://img.shields.io/npm/v/@solid-primitives/list?style=for-the-badge&label=)](https://www.npmjs.com/package/@solid-primitives/list)|
|[range](https://github.com/solidjs-community/solid-primitives/tree/main/packages/range#readme)|[![STAGE](https://img.shields.io/endpoint?style=for-the-badge&label=&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolidjs-community%2Fsolid-primitives%2Fmain%2Fassets%2Fbadges%2Fstage-1.json)](https://github.com/solidjs-community/solid-primitives/blob/main/CONTRIBUTING.md#contribution-process)|[repeat](https://github.com/solidjs-community/solid-primitives/tree/main/packages/range#repeat)<br />[mapRange](https://github.com/solidjs-community/solid-primitives/tree/main/packages/range#maprange)<br />[indexRange](https://github.com/solidjs-community/solid-primitives/tree/main/packages/range#indexrange)<br />[Repeat](https://github.com/solidjs-community/solid-primitives/tree/main/packages/range#repeat)<br />[Range](https://github.com/solidjs-community/solid-primitives/tree/main/packages/range#range)<br />[IndexRange](https://github.com/solidjs-community/solid-primitives/tree/main/packages/range#indexrange)|[![SIZE](https://img.shields.io/bundlephobia/minzip/@solid-primitives/range?style=for-the-badge&label=)](https://bundlephobia.com/package/@solid-primitives/range)|[![VERSION](https://img.shields.io/npm/v/@solid-primitives/range?style=for-the-badge&label=)](https://www.npmjs.com/package/@solid-primitives/range)|
|[refs](https://github.com/solidjs-community/solid-primitives/tree/main/packages/refs#readme)|[![STAGE](https://img.shields.io/endpoint?style=for-the-badge&label=&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolidjs-community%2Fsolid-primitives%2Fmain%2Fassets%2Fbadges%2Fstage-2.json)](https://github.com/solidjs-community/solid-primitives/blob/main/CONTRIBUTING.md#contribution-process)|[mergeRefs](https://github.com/solidjs-community/solid-primitives/tree/main/packages/refs#mergerefs)<br />[resolveElements](https://github.com/solidjs-community/solid-primitives/tree/main/packages/refs#resolveelements)<br />[resolveFirst](https://github.com/solidjs-community/solid-primitives/tree/main/packages/refs#resolvefirst)<br />[Ref](https://github.com/solidjs-community/solid-primitives/tree/main/packages/refs#ref)<br />[Refs](https://github.com/solidjs-community/solid-primitives/tree/main/packages/refs#refs)|[![SIZE](https://img.shields.io/bundlephobia/minzip/@solid-primitives/refs?style=for-the-badge&label=)](https://bundlephobia.com/package/@solid-primitives/refs)|[![VERSION](https://img.shields.io/npm/v/@solid-primitives/refs?style=for-the-badge&label=)](https://www.npmjs.com/package/@solid-primitives/refs)|
Expand Down
39 changes: 38 additions & 1 deletion packages/keyed/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Control Flow primitives and components that require specifying explicit keys to
- [`Key`](#key) - Creates a list of elements by mapping items by provided key.
- [`Entries`](#entries) - Creates a list of elements by mapping object entries.
- [`MapEntries`](#mapentries) - Creates a list of elements by mapping Map entries.
- [`SetValues`](#setvalues) - Creates a list of elements by mapping Set values.
- [`Rerun`](#rerun) - Causes the children to rerender when the `on` changes.

## Installation
Expand Down Expand Up @@ -177,7 +178,7 @@ const [map, setMap] = createSignal(new Map());

Third argument of the map function is an index signal.

`MapEntries` is using [`Map#key()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys) so the index and resulting JSX will follow the insertion order.
`MapEntries` is using [`Map#keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys) so the index and resulting JSX will follow the insertion order.

```tsx
<MapEntries of={map()} fallback={<div>No items</div>}>
Expand All @@ -189,6 +190,42 @@ Third argument of the map function is an index signal.
</MapEntries>
```

## `<SetValues>`

Creates a list of elements by mapping Set values. Similar to Solid's `<For>` and `<Index>`, but here, render function takes two arguments, the value and the index argument as a signal.

### How to use it

```tsx
import { SetValues } from "@solid-primitives/keyed";

const [set, setSet] = createSignal(new Set());

<SetValues of={set()} fallback={<div>No items</div>}>
{(value) => (
<div>
{value}
</div>
)}
</SetValues>;
```

### Index argument

Second argument of the map function is an index signal.

`SetValues` is using [`Set#values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values) so the index and resulting JSX will follow the insertion order.

```tsx
<SetValues of={set()} fallback={<div>No items</div>}>
{(value, index) => (
<div data-index={index()}>
{value}
</div>
)}
</SetValues>
```

## `<Rerun>`

Causes the children to rerender when the `on` key changes. Equivalent of `v-key` in vue, and `{#key}` in svelte.
Expand Down
5 changes: 5 additions & 0 deletions packages/keyed/dev/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Component } from "solid-js";
import Key from "./key.js";
import Entries from "./entries.js";
import MapEntries from "./mapEntries.js";
import SetValues from "./setValues.js";

const App: Component = () => {
return (
Expand All @@ -19,6 +20,10 @@ const App: Component = () => {
<h4>MapEntries</h4>
<MapEntries />
</div>
<div class="wrapper-v">
<h4>SetValues</h4>
<SetValues />
</div>
</div>
);
};
Expand Down
94 changes: 94 additions & 0 deletions packages/keyed/dev/setValues.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// changes to this file might be applicable to similar files - grep 95DB7339-BB2A-4F06-A34A-25DDF8BF7AF7

import { createEffect, createSignal } from "solid-js";
import { SetValues } from "../src/index.js";
import { TransitionGroup } from "solid-transition-group";

const foods = [
"oatmeal",
"plantains",
"cranberries",
"chickpeas",
"tofu",
"Parmesan cheese",
"amaretto",
"sunflower seeds",
"grapes",
"vegemite",
"pasta",
"cider",
"chicken",
"pinto beans",
"bok choy",
"sweet peppers",
"Cappuccino Latte",
"corn",
"broccoli",
"brussels sprouts",
"bread",
"milk",
"honey",
"chips",
"cookie",
];
const randomIndex = (list: readonly any[]): number => Math.floor(Math.random() * list.length);
const getRandomFood = () => foods[randomIndex(foods)]!;
const randomValue = (map: Set<string>): string => {
const values = Array.from(map.values());
return values[randomIndex(values)]!;
};

export default function App() {
const [set, setSet] = createSignal(new Set(["bread", "milk", "honey", "chips", "cookie"]));

const addRandom = () => {
setSet(p => {
p.add(getRandomFood());
return new Set(p);
});
};
const removeRandom = () =>
setSet(p => {
p.delete(randomValue(p));
return new Set(p);
});
const clone = () => setSet(p => new Set(p));

return (
<>
<div class="wrapper-h">
<button class="btn" onclick={addRandom}>
Add
</button>
<button class="btn" onclick={removeRandom}>
Remove
</button>
<button class="btn" onclick={clone}>
Clone
</button>
</div>
<div class="wrapper-h flex-wrap">
<TransitionGroup name="fade">
<SetValues
of={set()}
fallback={<p class="bg-yellow-500 p-1 transition-all">No items.</p>}
>
{(value, index) => {
createEffect(() => {
console.log("Effect:", value);
});
return (
<div class="node relative transition-all duration-500">
{index()}. {value}
<div class="bg-dark-500 text-light-900 absolute -bottom-2 left-2 px-1 text-[9px]">
{value}
</div>
</div>
);
}}
</SetValues>
</TransitionGroup>
</div>
</>
);
}
3 changes: 2 additions & 1 deletion packages/keyed/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"keyArray",
"Key",
"Entries",
"MapEntries"
"MapEntries",
"SetValues"
],
"category": "Control Flow"
},
Expand Down
31 changes: 31 additions & 0 deletions packages/keyed/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,37 @@ export function MapEntries<K, V>(props: {
) as unknown as JSX.Element;
}

/**
* Creates a list of elements from the values of provided Set
*
* @param props
* @param props.of set to iterate values of (`mySet.values()`)
* @param props.children
* a map render function that receives a Set value and **index signal** and returns a JSX-Element; if the list is empty, an optional fallback is returned:
* ```tsx
* <SetValues of={set()} fallback={<div>No items</div>}>
* {(value, index) => <div data-index={index()}>{value)}</div>}
* </SetValues>
* ```
*
* @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#setvalues
*/
export function SetValues<T>(props: {
of: Set<T> | undefined | null | false;
fallback?: JSX.Element;
children: (value: T, i: Accessor<number>) => JSX.Element;
}): JSX.Element {
// changes to this function may be applicable to similar functions - grep 4A29BECD-767A-4CC0-AEBB-3543D7B444C6
const mapFn = props.children;
return createMemo(
mapArray(
() => props.of && Array.from(props.of.values()),
mapFn.length < 2 ? value => (mapFn as (value: T) => JSX.Element)(value) : mapFn,
"fallback" in props ? { fallback: () => props.fallback } : undefined,
),
) as unknown as JSX.Element;
}

export type RerunChildren<T> = ((input: T, prevInput: T | undefined) => JSX.Element) | JSX.Element;

/**
Expand Down
Loading
Loading