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

feat: box.readonly #17

Merged
merged 7 commits into from
Apr 25, 2024
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/smart-weeks-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"runed": minor
---

Add `box.readonly` utility
16 changes: 15 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"tabWidth": 4,
"singleQuote": false,
"trailingComma": "es5",
"semi": true,
"printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"overrides": [
Expand All @@ -11,7 +12,20 @@
"options": {
"parser": "svelte"
}
}
},
{
"files": "*.md",
"options": {
"parser": "markdown",
"printWidth": 100,
"proseWrap": "always",
"tabWidth": 2,
"useTabs": true,
"semi": true,
"trailingComma": "none",
"bracketSameLine": true
}
}
],
"tailwindConfig": "./sites/docs/tailwind.config.js",
"tailwindFunctions": ["clsx", "cn", "tv"]
Expand Down
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
// Enable the ESlint flat config support
"eslint.experimental.useFlatConfig": true,
"eslint.useFlatConfig": true,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
Expand All @@ -16,7 +17,6 @@
"vue",
"html",
"svelte",
"markdown",
"json",
"jsonc",
"yaml",
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

<!-- /automd -->

Runed provides utilities to power your applications using the magic of [Svelte Runes](https://svelte.dev/blog/runes).
Runed provides utilities to power your applications using the magic of
[Svelte Runes](https://svelte.dev/blog/runes).

## Features

Expand All @@ -30,11 +31,10 @@ This project is supported by the following beautiful people/organizations:

<!-- automd:contributors license=MIT author="huntabyte" -->

Published under the [MIT](https://github.com/svecosystem/runed/blob/main/LICENSE) license.
Made by [@TGlide](https://github.com/tglide), [@huntabyte](https://github.com/huntabyte) and [community](https://github.com/svecosystem/runed/graphs/contributors) 💛
<br><br>
Published under the [MIT](https://github.com/svecosystem/runed/blob/main/LICENSE) license. Made by
[@TGlide](https://github.com/tglide), [@huntabyte](https://github.com/huntabyte) and
[community](https://github.com/svecosystem/runed/graphs/contributors) 💛 <br><br>
<a href="https://github.com/svecosystem/runed/graphs/contributors">
<img src="https://contrib.rocks/image?repo=svecosystem/runed" />
</a>
<img src="https://contrib.rocks/image?repo=svecosystem/runed" /> </a>

<!-- /automd -->
1 change: 0 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const CUSTOM_IGNORES = [
"**/node_modules/**",
"**/.svelte-kit/**",
".svelte-kit/**/*",
"*.md",
];

export default config({
Expand Down
12 changes: 6 additions & 6 deletions packages/runed/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

<!-- /automd -->

Runed provides utilities to power your applications using the magic of [Svelte Runes](https://svelte.dev/blog/runes).
Runed provides utilities to power your applications using the magic of
[Svelte Runes](https://svelte.dev/blog/runes).

## Features

Expand All @@ -22,11 +23,10 @@ Runed will be published to NPM once Svelte 5 is released.

<!-- automd:contributors license=MIT author="huntabyte" -->

Published under the [MIT](https://github.com/svecosystem/runed/blob/main/LICENSE) license.
Made by [@tglide](https://github.com/tglide), [@huntabyte](https://github.com/huntabyte) and [community](https://github.com/svecosystem/runed/graphs/contributors) 💛
<br><br>
Published under the [MIT](https://github.com/svecosystem/runed/blob/main/LICENSE) license. Made by
[@tglide](https://github.com/tglide), [@huntabyte](https://github.com/huntabyte) and
[community](https://github.com/svecosystem/runed/graphs/contributors) 💛 <br><br>
<a href="https://github.com/svecosystem/runed/graphs/contributors">
<img src="https://contrib.rocks/image?repo=svecosystem/runed" />
</a>
<img src="https://contrib.rocks/image?repo=svecosystem/runed" /> </a>

<!-- /automd -->
17 changes: 17 additions & 0 deletions packages/runed/src/lib/functions/box/box.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,25 @@ function boxFlatten<R extends Record<string, unknown>>(boxes: R): BoxFlatten<R>
}, {} as BoxFlatten<R>);
}

/**
* Function that converts a box to a readonly box.
*
* @example
* const count = box(0) // WritableBox<number>
* const countReadonly = box.readonly(count) // ReadableBox<number>
*/
function toReadonlyBox<T>(box: ReadableBox<T>): ReadableBox<T> {
return {
[BoxSymbol]: true,
get value() {
return box.value;
},
};
}

box.from = boxFrom;
box.with = boxWith;
box.flatten = boxFlatten;
box.readonly = toReadonlyBox;
box.isBox = isBox;
box.isWritableBox = isWritableBox;
33 changes: 33 additions & 0 deletions packages/runed/src/lib/functions/box/box.test.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,37 @@ describe("box types", () => {
expectTypeOf(count).toMatchTypeOf<WritableBox<number>>();
}
});

test("box.readonly should return a non-settable box", () => {
const count = box(0);
const readonlyCount = box.readonly(count);
expectTypeOf(readonlyCount).toMatchTypeOf<ReadableBox<number>>();
expectTypeOf(readonlyCount).not.toMatchTypeOf<WritableBox<number>>();
});
});

describe("box.readonly", () => {
test("box.readonly returns a non-settable box", () => {
const count = box(0);
const readonlyCount = box.readonly(count);

function setReadOnlyCount() {
// eslint-disable-next-line ts/no-explicit-any
(readonlyCount as any).value = 1;
}

expect(setReadOnlyCount).toThrow();
});

test("box.readonly returned box should update with original box", () => {
const count = box(0);
const readonlyCount = box.readonly(count);

expect(readonlyCount.value).toBe(0);
count.value = 1;
expect(readonlyCount.value).toBe(1);

count.value = 2;
expect(readonlyCount.value).toBe(2);
});
});
4 changes: 0 additions & 4 deletions pnpm-lock.yaml

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

28 changes: 22 additions & 6 deletions sites/docs/content/functions/box.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { UseActiveElementDemo } from '$lib/components/demos';

## Description

State in runes is based on primitives, which provides a concise syntax. However, when sending these primitives across boundaries, e.g. in function arguments, the state is not reactive, and rather, the static value gets sent.
State in runes is based on primitives, which provides a concise syntax. However, when sending these
primitives across boundaries, e.g. in function arguments, the state is not reactive, and rather, the
static value gets sent.

Box provides several utilities to make sending and receiving reactive values easier.

Expand Down Expand Up @@ -45,7 +47,7 @@ Allows you to use getters and setters to define a box. Useful to pass around sta
count.value++;
},
// We pass a box that doubles the count value
double: box.with(() => count.value * 2),
double: box.with(() => count.value * 2)
};
}

Expand All @@ -67,8 +69,8 @@ Allows you to use getters and setters to define a box. Useful to pass around sta

### `box.from`

Creates a box from an existing box, a getter function, or a static value.
Used in functions to receive props that are optionally reactive.
Creates a box from an existing box, a getter function, or a static value. Used in functions to
receive props that are optionally reactive.

```svelte
<script lang="ts">
Expand All @@ -83,7 +85,7 @@ Used in functions to receive props that are optionally reactive.
count.value++;
},
// We pass a box that doubles the count value
double: box.with(() => count.value * 2),
double: box.with(() => count.value * 2)
};
}

Expand Down Expand Up @@ -123,7 +125,7 @@ const flat = box.flatten({
double: box.with(() => count.value * 2),
increment() {
count.value++;
},
}
});

console.log(flat.count); // 1
Expand All @@ -132,6 +134,20 @@ flat.increment();
console.log(flat.count); // 2
```

### `box.readonly`

Creates a readonly box from a writable box that remains in sync with the original box.

```ts
const count = box(1);
const readonlyCount = box.readonly(count);
console.log(readonlyCount.value); // 1
count.value++;
console.log(readonlyCount.value); // 2

readonlyCount.value = 3; // Error: Cannot assign to read only property 'value' of object
```

### `box.isBox`

Checks if a value is a `Box`.
Expand Down
15 changes: 9 additions & 6 deletions sites/docs/content/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ description: What this project is all about.
<script>
</script>

Runed provides utilities to power your applications using the magic of [Svelte Runes](https://svelte.dev/blog/runes).
Runed provides utilities to power your applications using the magic of
[Svelte Runes](https://svelte.dev/blog/runes).

Here are some tools that are provided:

- Debouncing utilities synced with state
- Element size tracking
- RequestAnimationFrame helpers
- etc.
- Debouncing utilities synced with state
- Element size tracking
- RequestAnimationFrame helpers
- etc.

## Next Steps

Start using Runed in your Svelte app by following the [Getting Started](/docs/getting-started) guide. If you have any questions or need help, feel free to ask in the [Discord](https://discord.gg/hbAGu6akVy)!
Start using Runed in your Svelte app by following the [Getting Started](/docs/getting-started)
guide. If you have any questions or need help, feel free to ask in the
[Discord](https://discord.gg/hbAGu6akVy)!
Loading