From 0e7ef6718038e45089d784ff293f2e0741a11255 Mon Sep 17 00:00:00 2001 From: krulod Date: Sat, 18 Nov 2023 16:32:23 +0200 Subject: [PATCH 1/4] docs: improve readme and setup --- README.md | 295 ++--------- docs/.astro/types.d.ts | 486 ++++++++++++++++++ .../what-is-a-state-manager.md} | 0 .../src/content/docs/getting-started/setup.md | 102 +--- docs/src/content/docs/index.md | 295 ++--------- package.json | 1 - 6 files changed, 597 insertions(+), 582 deletions(-) create mode 100644 docs/.astro/types.d.ts rename docs/src/content/docs/{blog/what-is-state-manager.md => fundamentals/what-is-a-state-manager.md} (100%) diff --git a/README.md b/README.md index dd8173c4..8cf72bd2 100644 --- a/README.md +++ b/README.md @@ -1,279 +1,80 @@ -**Reatom is a ultimate logic and state manager for small widgets and huge SPAs.** +# Reatom -## Key features - -- **simple** and powerful abstractions. - There are only three main primitives: `ctx`, `atom`, `action`, all other features and packages works on top of that. -- **immutable** and reliable. - All pure computations processed with atomicity guaranties. -- **explicit reactivity** without proxies. - To archive [maximum](#how-performant-reatom-is) performance we have [atomization](https://www.reatom.dev/recipes/atomization) pattern. -- perfect **effects management**. - Advanced [async package](https://www.reatom.dev/package/async) allows you to describe complex async flows with caching, retrying and automatic cancellation with native `await` and `AbortController`. -- nice **debugging** experience. - Each atom and action update stores [immutable cause (call) stack](https://www.reatom.dev/getting-started/debugging/) which is super helpful for debugging complex async flows. To simplify this we have [logger package](https://www.reatom.dev/package/logger). -- implicit **DI**. - To run tests and SSR 100% safety you need an isolation layer, which `ctx` is! We have the extra [testing package](https://www.reatom.dev/package/testing) with pack of helpers for a mocking. -- actor-like **lifecycle hooks** - To archive a trhtully modularity you have ability to describe [self-sufficient models](https://www.reatom.dev/handbook#lifecycle) -- **smallest bundle** size: [2 KB](https://bundlejs.com/?q=%40reatom%2Fcore) gzipped - Because of the power of the base primitives all ecosystem with A LOT of enterprize-grade helpers took only [~15KB](https://bundlejs.com/?q=%40reatom%2Fframework%2C%40reatom%2Fnpm-react%2C%40reatom%2Fpersist-web-storage%2C%40reatom%2Fundo%2C%40reatom%2Fform-web&config=%7B%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22use-sync-external-store%22%5D%7D%7D) - insane! -- **best TypeScript** experience - [Automatic type inference](https://www.reatom.dev/recipes/typescript/) is one of the main priority of Reatom developement. - -[The core package](https://www.reatom.dev/core) includes most these features and you may use it anywhere, from huge apps to even small libs, as the overhead is tiny. Also, you could reuse our carefully written [helper tools](https://www.reatom.dev/package/framework) to solve complex tasks in a couple lines of code. We are trying to build a stable and balanced ecosystem for perfect DX and predictable maintains even for years ahead. - -## Simple example - -Let's define input state and compute a greeting from it. - -### Install - -```sh -npm i @reatom/core -``` - -[vanilla codesandbox](https://codesandbox.io/s/reatom-vanila-hello-world-6oo36v?file=/src/index.ts) - -[react codesandbox](https://codesandbox.io/s/reatom-react-hello-world-fgt6jn?file=/src/model.ts) - -### Simple example model - -The concept is _dumb_ - if you want to make a variable reactive, wrap the init state in `atom`, you will alow to change the state by calling it as a function. Need reactive computed? - wrap it to `atom`! - -`action`s needed to separate logic and batch atom updates. - -All data processing should be immutable, all side-effects should be wrapped to `ctx.schedule`. - -What is `ctx`? It is the most powerful feature of Reatom. It flows as the first argument across all Reatom functions, bringing you enterprise-grade features with only three extra symbols! - -```ts -import { action, atom } from '@reatom/core' - -const initState = localStorage.getItem('name') ?? '' -export const inputAtom = atom(initState) - -export const greetingAtom = atom((ctx) => { - // `spy` dynamically reads the atom and subscribes to it - const input = ctx.spy(inputAtom) - return input ? `Hello, ${input}!` : '' -}) - -export const onSubmit = action((ctx) => { - const input = ctx.get(inputAtom) - ctx.schedule(() => { - localStorage.setItem('name', input) - }) -}) -``` - -### Simple example context - -The context set up once for the whole app, or multiple times if you need isolation in SSR or tests. - -```ts -import { createCtx } from '@reatom/core' - -const ctx = createCtx() -``` - -### Simple example view - -```ts -import { inputAtom, greetingAtom, onSubmit } from './model' - -ctx.subscribe(greetingAtom, (greeting) => { - document.getElementById('greeting')!.innerText = greeting -}) - -document.getElementById('name').addEventListener('input', (event) => { - inputAtom(ctx, event.currentTarget.value) -}) -document.getElementById('save').addEventListener('click', () => { - onSubmit(ctx) -}) -``` - -Check out [@reatom/core docs](https://www.reatom.dev/core) for detailed explanation of key principles and features. - -Do you use React.js? Check out [npm-react](https://www.reatom.dev/package/npm-react) package! +The ultimate state manager for any kinds of applications. -## Advanced example - -The core package is already profitable and you could use only it as a most simple and featured solution for your state and logic management. If you want to solve common system logic with advanced libraries to care more optimizations and UX tasks - continue and check this small guide out. - -This example is close to real life and shows the complexity of interactive UI. It is a simple search input with debouncing and autocomplete. It uses [GitHub API](https://docs.github.com/en/rest/reference/search#search-issues-and-pull-requests) to fetch issues by query. The limitations of this API are described in [GitHub docs](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). We need to reduce the number of requests and retry them if we hit the limit. Also, we need to cancel all previous requests if a new one is created, to prevent race conditions - when the previous request resolves after the new one. - -### Install framework - -```sh -npm i @reatom/framework @reatom/npm-react -``` - -[codesandbox](https://codesandbox.io/s/reatom-react-search-component-l4pe8q?file=/src/App.tsx) - -### Advanced example description - -We will use [@reatom/core](https://www.reatom.dev/core), [@reatom/async](https://www.reatom.dev/package/async) and [@reatom/hooks](https://www.reatom.dev/package/hooks) packages in this example by importing it from the meta package [@reatom/framework](https://www.reatom.dev/package/framework) - it simplifies imports and dependencies management. - -`reatomAsync` is a simple decorator which wraps your async function and adds extra actions and atoms to track creating promise statuses. - -`withDataAtom` adds property `dataAtom` which saves the last effect result and allow you to subscribe to it. `withCache` enable function middleware which prevent it's extra calls based on passed arguments identity - classic cache. `withAbort` allows to define concurrent requests abort strategy, by using `ctx.controller` ([AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)) from `reatomAsync`. `withRetry` and `onReject` handler help to handle temporal rate limit. - -Simple `sleep` helper (for debounce) gotten from [utils package](https://www.reatom.dev/package/utils) - it is a built-in microscopic lodash alternative for most popular and tiny helpers. - -`onUpdate` is a [hook](https://www.reatom.dev/package/hooks) which link to the atom and calls passed callback on every update. - -### Advanced example model - -```ts -import { atom, reatomAsync, withAbort, withDataAtom, withRetry, onUpdate, sleep, withCache } from "@reatom/framework"; // prettier-ignore -import * as api from './api' - -const searchAtom = atom('', 'searchAtom') - -const fetchIssues = reatomAsync(async (ctx, query: string) => { - await sleep(350) // debounce - const { items } = await api.fetchIssues(query, ctx.controller) - return items -}, 'fetchIssues').pipe( - withAbort({ strategy: 'last-in-win' }), - withDataAtom([]), - withCache({ length: 50, swr: false, paramsLength: 1 }), - withRetry({ - onReject(ctx, error: any, retries) { - // return delay in ms or -1 to prevent retries - return error?.message.includes('rate limit') - ? 100 * Math.min(500, retries ** 2) - : -1 - }, - }), -) - -// run fetchIssues on every searchAtom update -onUpdate(searchAtom, fetchIssues) -``` - -### Advanced example view - -```tsx -import { useAtom } from '@reatom/npm-react' - -export const Search = () => { - const [search, setSearch] = useAtom(searchAtom) - const [issues] = useAtom(fetchIssues.dataAtom) - // you could pass a callback to `useAtom` to create a computed atom - const [isLoading] = useAtom( - (ctx) => - // even if there are no pending requests, we need to wait for retries - // let do not show the limit error to make him think that everything is fine for a better UX - ctx.spy(fetchIssues.pendingAtom) + ctx.spy(fetchIssues.retriesAtom) > 0, - ) - - return ( -
- setSearch(e.currentTarget.value)} - placeholder="Search" - /> - {isLoading && 'Loading...'} - -
- ) -} -``` - -The whole logic definition is only about 15 LoC and it is not coupled to React and could be tested easily. What would the lines count be in a different library? The most impressive thing is that the overhead is [less than 4KB (gzip)](https://bundlejs.com/?q=%28import%29%40reatom%2Fframework%2C%28import%29%40reatom%2Fnpm-react&treeshake=%5B%7B%0A++atom%2CcreateCtx%2ConUpdate%2CreatomAsync%2Csleep%2CwithAbort%2CwithDataAtom%2CwithRetry%2C%7D%5D%2C%5B%7B+useAtom+%7D%5D&share=MYewdgzgLgBBCmBDATsAFgQSiAtjAvDItjgBQBE5ANDOQiulruQJQDcAUKJLAGbxR0ASQgQArvAgEYyJCQwQAnmGClESlTFLAoADxoBHCckUAuOFGQBLMAHMWBAHwwA3hxhEA7oiuwIAG3h4AAdSACYAVgAGdhgAejiYABN4ACMQMRV4dxhuaFcYX3gcKQBfaURvXyJgqwA6fkE0EXFJUiN4ExodXTruSxB-QOR2HNkoMWQwQqhiiE5SmnJG4VEJCFY62uD4UhzPXzQAEWJEJjIAbQBdFip9w4x05ChSFwtkYnhbM1p-dSgALQ2AEHMDkGClW73KBoABKAhMrxyHnA8IAVvAdNo9DROsgQMhzIgwIoaONrJIHG4PDT4olxpNpik-opCtMSjACTAAQBGGDYGDBWQAN3gYFg5KskmRNIZUxgeIJAH46jhJBBELZ4HUbMB-GIUhAKB9ZjB-FYcL5WDLaUqYDyolEYAAqGAAWWIaFVNlI0SiZIRUqkztdYRYNpp5l5nFpixykLuowSMkyMBWzTWkk503gopMcCQqEwJBgYmCSU%2BHHAAFVy59SPQi%2BcaOmWutRlxZJ8AMJ6UijMQIc6kVuZiB1CtQM4kFhAA&config=%7B%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22use-sync-external-store%22%5D%7D%7D) could you imagine?! And you are not limited to network cache, Reatom is powerful and expressive enough for describing any kind of state. +## Key features -To get maximum of Reatom and the ecosystem just go to [tutorial](https://www.reatom.dev/getting-started/setup/). If you need something tiny - check out [the core package docs](https://www.reatom.dev/core). Also, we have a [package for testing](https://www.reatom.dev/package/testing)! +- efficient and reliable reactive runtime +- minimal but powerful primitives +- advanced primitives to abstract away the complexity of asynchronous interactions +- rich official ecosystem with lots of high-quality helpers and integrations +- tiny bundle size starting from 2KB +- full TypeScript support +- [nice debugging experience](https://reatom.dev/package/logger) +- builtin DI for straightforward testing and SSR +- lifecycle hooks for describing focused and self-sufficient models -## Roadmap +## Getting started -- Finish [forms package](https://www.reatom.dev/package/form) -- Finish ~~[persist](https://www.reatom.dev/package/persist)~~, improve [url](https://www.reatom.dev/package/url/) packages -- Add adapters for most popular ui frameworks: ~~[react](https://www.reatom.dev/package/npm-react)~~, angular, vue, ~~[svelte](https://www.reatom.dev/package/npm-svelte)~~, ~~[solid](https://www.reatom.dev/package/npm-solid-js/)~~. -- Port some components logic from reakit.io, to made it fast, light and portable. -- Add ability to made async transaction and elaborate optimistic-ui patterns and helpers / package. +[Read the docs](https://reatom.dev/getting-started/setup) or [see examples](https://www.reatom.dev/examples/). ## FAQ -### Why not X? - -**Redux** is awesome and Reatom is heavy inspired by it. Immutability, separation of computations and effects are good architecture designs principles. But there are a lot of missing features, when you trying to build something huge, or want to describe something small. Some of them is just impossible to fix, like [batching](https://www.reatom.dev/core#ctxget-batch-api), [O(n) complexity](https://www.reatom.dev/recipes/atomization/#reducing-computational-complexity) or that selectors is not inspectable and breaks [the atomicy](https://www.reatom.dev/general/what-is-state-manager#state). Others is really [hard to improve](https://github.com/reduxjs/reselect/discussions/491). And boilerplate, yeah, [the difference is a huge](https://github.com/artalar/RTK-entities-basic-example/pull/1/files#diff-43162f68100a9b5eb2e58684c7b9a5dc7b004ba28fd8a4eb6461402ec3a3a6c6). -Reatom solves all this problems and bring much more features by the almost same size. +### Comparison -**MobX** brings too big bundle to use it in a small widgets, Reatom is more universal in this case. Also, MobX has mutability and implicit reactivity, which is usefull for simple cases, but could be not obvious and hard to debug in complex cases. There is no separate thing like action / event / effect to describe some dependent effects sequences (FRP-way). [There is not atomicy too](https://github.com/artalar/state-management-specification/blob/master/src/index.test.js#L60). +**Redux**: Reatom was heavily inspired by Redux and does share many design principles with it. But it has many flaws that are hard or impossible to fix. Absence of action batching, non-atomic selectors and linear state update complexity, to name a few. Reatom solves all of them, implements much more features and [reduces the amount of boilerplate code](https://github.com/artalar/RTK-entities-basic-example/pull/1/files#diff-43162f68100a9b5eb2e58684c7b9a5dc7b004ba28fd8a4eb6461402ec3a3a6c6) a lot. -**Effector** is too opinionated. There is **no** first-class support for **lazy** reactive computations and all connections are [hot](https://luukgruijs.medium.com/understanding-hot-vs-cold-observables-62d04cf92e03) everytime, which is could be more predictable, but defenetly is not optimal. Effector is not friendly for fabric creation (because of it hotness), which disallow us to use [atomization](https://www.reatom.dev/recipes/atomization/) patterns, needed to handle immutability efficient. [The bundle size is 2-3 times larger](https://bundlejs.com/?q=effector&treeshake=%5B%7BcraeteStore%2CcreateEvent%2Ccombine%7D%5D) and [performance is lower](https://github.com/artalar/reactive-computed-bench). +**MobX**: MobX bundle size is too huge to use it in small embedded widgets, it uses getters/Proxies for change detections and has mutable nature, which eventually leads to confusing debugging sessions. [It has no atomicity as well](https://github.com/artalar/state-management-specification/blob/master/src/index.test.js#L60). -[Zustand](https://github.com/pmndrs/zustand), [nanostores](https://github.com/nanostores/nanostores), [xstate](https://xstate.js.org) and [many other](https://gist.github.com/artalar/e5e8a7274dfdfbe9d36c9e5ec22fc650) state managers have no so great combination of type inference, features, bundle size and performance, as Reatom have. +**Effector:** Effector encourages the description of sequential procedures through custom operators like `sample`, making the code really confusing. It also lacks the laziness of reactive computations, automatic dependency tracking, and is less performant compared to Reatom. -### Why immutability? +Solutions like **zustand**, **jotai**, **nanostores**, **xstate**, [and many others](https://gist.github.com/artalar/e5e8a7274dfdfbe9d36c9e5ec22fc650), are either less efficient than Reatom, or are not that feature-rich. -Immutable data is much predictable and better for debug, than mutable states and wrapers around that. Reatom specialy designed with focus on [simple debug of async chains](https://www.reatom.dev/getting-started/debugging/) and [have a patterns](https://www.reatom.dev/recipes/atomization/) to handle [greate performance](#how-performant-reatom-is). +### What LTS policy is used and what about the bus factor? -### What LTS policy is used and what about bus factor? +Reatom is always developed for continous usage. LTS versions are released once a year since [December 2019](https://github.com/artalar/reatom/releases/tag/v1.0) and have [compatibility layers](https://www.reatom.dev/compat/core-v1) with the most recent version of the core package. We hope it proves our approach to maintainance to be responsible. -Reatom always developed for long time usage. Our first LTS (Long Time Support) version (v1) [was released in December 2019](https://github.com/artalar/reatom/releases/tag/v1.0) and in 2022 we provided breaking changes less [Migration guide](https://www.reatom.dev/compat/core-v1#migration-guide) to the new LTS (v3) version. 3 years of successful maintains is not ended, but continued in [adapter package](https://www.reatom.dev/compat/core-v1). We hope it shows and prove our responsibility. +Our team currently consists of 4 people: [@artalar](https://github.com/artalar) and [@krulod](https://github.com/krulod) develop and maintain the core features, while [@BANOnotIT](https://github.com/BANOnotIT) and [@Akiyamka](https://github.com/Akiyamka) help with documentation and issue management. [Many other people also took part in the development of the library](https://github.com/artalar/reatom/graphs/contributors). -Currently, there are four people in the development team: [@artalar](https://github.com/artalar) and [@krulod](https://github.com/krulod) are managing the core features, while [@BANOnotIT](https://github.com/BANOnotIT) and [@Akiyamka](https://github.com/Akiyamka) help with documentation and issue management. [A lot of people](https://github.com/artalar/reatom/graphs/contributors) contributes to different packages. +### What about build targets and browser support? -### What build target and browser support? +All packages are configured based on [Browserslist's "last 1 year" query](https://browsersl.ist/#q=last+1+year). If you need to support older environments, you should handle transpilation by yourself. -All packages are configured based on [Browserslist's "last 1 year" query](https://browsersl.ist/#q=last+1+year). If you need to support older environments, you should handle transpilation yourself. - -All builds have two types of output formats: CJS (`exports.require`, `main`) and ESM (`exports.default`, `module`). You can check `package.json` for more details. +Packages include CommonJS and ESM entrypoints. See `package.json` files for more details. ### How performant Reatom is? -[Here is the benchmark](https://github.com/artalar/reactive-computed-bench) of complex computations for different state managers. Note that Reatom by default uses immutable data structures, works in a separate context (DI-like) and keeps [atomicity](https://www.reatom.dev/general/what-is-state-manager#state), which means the Reatom test checks more features, than other state manager tests. Anyway, for the middle numbers Reatom faster than MobX which is pretty impressive. - -Also, check out [atomization guide](https://www.reatom.dev/recipes/atomization). - -### Limitations - -Of course there are no software without limitations. Reatom is trying to be a silver bullet but we still have some cases which you should know about. - -- Immutable data always have an additional performance impact and in critical cases you should think well about your structures and how you could handle it better. The good news is that you [don't have to use normalization](https://www.reatom.dev/recipes/atomization). -- Laziness could be not obvious in some cases and will cause some updates missing. But it easy to debug a missing update, which is more explicit, than memory leaks and performance issues of hot observables. Anyway, we have [hooks](https://www.reatom.dev/package/hooks) for hot linking. -- Currently, there is no way to subscribe on error of any dependency, but we are working on it. In [reatomAsync](https://www.reatom.dev/package/async) passed effects wraps to an error handler and allow you to handle errors, but again - you should wrap it explicit. -- Currently, there is no asynchronous transactions support, but we are working on it. It is important feature for simplify building of optimistic UI and we really think it will improve UX a lot. -- We have a lot of utils and the ecosystem is growing all the time, but the target of that is have a set of well done logic primitives, and there is no architecture framework or codestyle / declarative framework to fit you in one strict flow. Reatom trying to be in the middle of a library and a framework. We love procedural programming with minimum extra API and semantic overhead. Our defaults are good already to help to you to write a better code: immutability and lazyness, transactions and separation of pure computations and effects, `ctx` and connections and processes virtualizations. +[Here is the benchmark](https://github.com/artalar/reactive-computed-bench) of complex computations for different state managers. Although Reatom features introduce more overhead, it appears to be more performant than MobX, which is pretty impressive. -### Media +### Limitations? -- [en twitter](https://twitter.com/ReatomJS) -- [en discord](https://discord.gg/EPAKK5SNFh) -- [en github discussion](https://github.com/artalar/reatom/discussions) -- [ru telegram](https://t.me/reatom_ru) -- [ru youtube](https://www.youtube.com/playlist?list=PLXObawgXpIfxERCN8Lqd89wdsXeUHm9XU) +No software is free from limitations, and Reatom is no exception. -### How to support the project? +- Immutable data introduces some overhead and encourages you to optimize your data structures. +- Lazy nature of Reatom may be unobvious and cause some problems like missing updates, but we find it much easier to bear with than the flaws of hot observables. +- Currently, there is no way to subscribe to errors of reactive computations, but we are working on it. +- Currently, there is no asynchronous transactions support, but we are working on it. +- We already have lots of utils and the ecosystem is growing all the time, but at the moment we don't have a strict architectural framework like `mobx-state-tree` that makes the development exceptionally straightforward. -https://www.patreon.com/artalar_dev +## Media -## Zen +- [X (EN)](https://twitter.com/ReatomJS) +- [Telegram (RU)](https://t.me/reatom_ru) +- [YouTube (RU)](https://www.youtube.com/playlist?list=PLXObawgXpIfxERCN8Lqd89wdsXeUHm9XU) -- **Good primitive is more than a framework** -- Composition beats configuration - +- [Patreon](https://www.patreon.com/artalar_dev) +- [Boosty](https://boosty.to/artalar) ## Credits -Software development in 202X is hard and we really appreciate all [contributors](https://github.com/artalar/reatom/graphs/contributors) and free software maintainers, who make our life easier. Special thanks to: +We really appreciate all [contributors](https://github.com/artalar/reatom/graphs/contributors) and free software maintainers. Shout-outs to the people behind the projects that helped us: -- [React](https://reactjs.org), [Redux](https://redux.js.org), [Effector](https://effector.dev/) and [$mol](https://github.com/hyoo-ru/mam_mol) for inspiration -- [microbundle](https://github.com/developit/microbundle) for handling all bundling complexity -- [Quokka](https://wallabyjs.com/oss/) and [uvu](https://github.com/lukeed/uvu) for incredible testing experience -- [TURBO](https://turbo.build) for simple monorepo management -- [Astro](https://astro.build) for best in class combine of performance and developer experience -- [Vercel](https://vercel.com/) for free hosting and perfect CI/CD (preview branches are <3) +- [React](https://reactjs.org), [Redux](https://redux.js.org), [Effector](https://effector.dev/) and [$mol](https://mol.hyoo.ru) — for inspiration +- [microbundle](https://github.com/developit/microbundle) +- [Quokka](https://wallabyjs.com/oss/) +- [uvu](https://github.com/lukeed/uvu) +- [Turborepo](https://turbo.build/repo) +- [Astro](https://astro.build) +- [Vercel](https://vercel.com/) diff --git a/docs/.astro/types.d.ts b/docs/.astro/types.d.ts new file mode 100644 index 00000000..75068925 --- /dev/null +++ b/docs/.astro/types.d.ts @@ -0,0 +1,486 @@ +declare module 'astro:content' { + interface Render { + '.mdx': Promise<{ + Content: import('astro').MarkdownInstance<{}>['Content']; + headings: import('astro').MarkdownHeading[]; + remarkPluginFrontmatter: Record; + }>; + } +} + +declare module 'astro:content' { + interface Render { + '.md': Promise<{ + Content: import('astro').MarkdownInstance<{}>['Content']; + headings: import('astro').MarkdownHeading[]; + remarkPluginFrontmatter: Record; + }>; + } +} + +declare module 'astro:content' { + export { z } from 'astro/zod'; + + type Flatten = T extends { [K: string]: infer U } ? U : never; + + export type CollectionKey = keyof AnyEntryMap; + export type CollectionEntry = Flatten; + + export type ContentCollectionKey = keyof ContentEntryMap; + export type DataCollectionKey = keyof DataEntryMap; + + // This needs to be in sync with ImageMetadata + export type ImageFunction = () => import('astro/zod').ZodObject<{ + src: import('astro/zod').ZodString; + width: import('astro/zod').ZodNumber; + height: import('astro/zod').ZodNumber; + format: import('astro/zod').ZodUnion< + [ + import('astro/zod').ZodLiteral<'png'>, + import('astro/zod').ZodLiteral<'jpg'>, + import('astro/zod').ZodLiteral<'jpeg'>, + import('astro/zod').ZodLiteral<'tiff'>, + import('astro/zod').ZodLiteral<'webp'>, + import('astro/zod').ZodLiteral<'gif'>, + import('astro/zod').ZodLiteral<'svg'>, + import('astro/zod').ZodLiteral<'avif'>, + ] + >; + }>; + + type BaseSchemaWithoutEffects = + | import('astro/zod').AnyZodObject + | import('astro/zod').ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]> + | import('astro/zod').ZodDiscriminatedUnion + | import('astro/zod').ZodIntersection; + + type BaseSchema = + | BaseSchemaWithoutEffects + | import('astro/zod').ZodEffects; + + export type SchemaContext = { image: ImageFunction }; + + type DataCollectionConfig = { + type: 'data'; + schema?: S | ((context: SchemaContext) => S); + }; + + type ContentCollectionConfig = { + type?: 'content'; + schema?: S | ((context: SchemaContext) => S); + }; + + type CollectionConfig = ContentCollectionConfig | DataCollectionConfig; + + export function defineCollection( + input: CollectionConfig + ): CollectionConfig; + + type AllValuesOf = T extends any ? T[keyof T] : never; + type ValidContentEntrySlug = AllValuesOf< + ContentEntryMap[C] + >['slug']; + + export function getEntryBySlug< + C extends keyof ContentEntryMap, + E extends ValidContentEntrySlug | (string & {}), + >( + collection: C, + // Note that this has to accept a regular string too, for SSR + entrySlug: E + ): E extends ValidContentEntrySlug + ? Promise> + : Promise | undefined>; + + export function getDataEntryById( + collection: C, + entryId: E + ): Promise>; + + export function getCollection>( + collection: C, + filter?: (entry: CollectionEntry) => entry is E + ): Promise; + export function getCollection( + collection: C, + filter?: (entry: CollectionEntry) => unknown + ): Promise[]>; + + export function getEntry< + C extends keyof ContentEntryMap, + E extends ValidContentEntrySlug | (string & {}), + >(entry: { + collection: C; + slug: E; + }): E extends ValidContentEntrySlug + ? Promise> + : Promise | undefined>; + export function getEntry< + C extends keyof DataEntryMap, + E extends keyof DataEntryMap[C] | (string & {}), + >(entry: { + collection: C; + id: E; + }): E extends keyof DataEntryMap[C] + ? Promise + : Promise | undefined>; + export function getEntry< + C extends keyof ContentEntryMap, + E extends ValidContentEntrySlug | (string & {}), + >( + collection: C, + slug: E + ): E extends ValidContentEntrySlug + ? Promise> + : Promise | undefined>; + export function getEntry< + C extends keyof DataEntryMap, + E extends keyof DataEntryMap[C] | (string & {}), + >( + collection: C, + id: E + ): E extends keyof DataEntryMap[C] + ? Promise + : Promise | undefined>; + + /** Resolve an array of entry references from the same collection */ + export function getEntries( + entries: { + collection: C; + slug: ValidContentEntrySlug; + }[] + ): Promise[]>; + export function getEntries( + entries: { + collection: C; + id: keyof DataEntryMap[C]; + }[] + ): Promise[]>; + + export function reference( + collection: C + ): import('astro/zod').ZodEffects< + import('astro/zod').ZodString, + C extends keyof ContentEntryMap + ? { + collection: C; + slug: ValidContentEntrySlug; + } + : { + collection: C; + id: keyof DataEntryMap[C]; + } + >; + // Allow generic `string` to avoid excessive type errors in the config + // if `dev` is not running to update as you edit. + // Invalid collection names will be caught at build time. + export function reference( + collection: C + ): import('astro/zod').ZodEffects; + + type ReturnTypeOrOriginal = T extends (...args: any[]) => infer R ? R : T; + type InferEntrySchema = import('astro/zod').infer< + ReturnTypeOrOriginal['schema']> + >; + + type ContentEntryMap = { + "docs": { +"compat/core-v1.md": { + id: "compat/core-v1.md"; + slug: "compat/core-v1"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"compat/core-v2.md": { + id: "compat/core-v2.md"; + slug: "compat/core-v2"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"compat/react-v1.md": { + id: "compat/react-v1.md"; + slug: "compat/react-v1"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"compat/react-v2.md": { + id: "compat/react-v2.md"; + slug: "compat/react-v2"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"contributing.md": { + id: "contributing.md"; + slug: "contributing"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"examples.md": { + id: "examples.md"; + slug: "examples"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"fundamentals/what-is-a-state-manager.md": { + id: "fundamentals/what-is-a-state-manager.md"; + slug: "fundamentals/what-is-a-state-manager"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"getting-started/debugging.md": { + id: "getting-started/debugging.md"; + slug: "getting-started/debugging"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"getting-started/learning.md": { + id: "getting-started/learning.md"; + slug: "getting-started/learning"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"getting-started/setup.md": { + id: "getting-started/setup.md"; + slug: "getting-started/setup"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"getting-started/testing.md": { + id: "getting-started/testing.md"; + slug: "getting-started/testing"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"handbook.md": { + id: "handbook.md"; + slug: "handbook"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"index.md": { + id: "index.md"; + slug: "index"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/async.md": { + id: "package/async.md"; + slug: "package/async"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/core.md": { + id: "package/core.md"; + slug: "package/core"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/effects.md": { + id: "package/effects.md"; + slug: "package/effects"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/eslint-plugin.md": { + id: "package/eslint-plugin.md"; + slug: "package/eslint-plugin"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/form.md": { + id: "package/form.md"; + slug: "package/form"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/framework.md": { + id: "package/framework.md"; + slug: "package/framework"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/hooks.md": { + id: "package/hooks.md"; + slug: "package/hooks"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/jsx.md": { + id: "package/jsx.md"; + slug: "package/jsx"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/lens.md": { + id: "package/lens.md"; + slug: "package/lens"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/logger.md": { + id: "package/logger.md"; + slug: "package/logger"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/npm-cookie-baker.md": { + id: "package/npm-cookie-baker.md"; + slug: "package/npm-cookie-baker"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/npm-history.md": { + id: "package/npm-history.md"; + slug: "package/npm-history"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/npm-react.md": { + id: "package/npm-react.md"; + slug: "package/npm-react"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/npm-solid-js.md": { + id: "package/npm-solid-js.md"; + slug: "package/npm-solid-js"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/npm-svelte.md": { + id: "package/npm-svelte.md"; + slug: "package/npm-svelte"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/persist-web-storage.md": { + id: "package/persist-web-storage.md"; + slug: "package/persist-web-storage"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/persist.md": { + id: "package/persist.md"; + slug: "package/persist"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/primitives.md": { + id: "package/primitives.md"; + slug: "package/primitives"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/testing.md": { + id: "package/testing.md"; + slug: "package/testing"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/timer.md": { + id: "package/timer.md"; + slug: "package/timer"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/undo.md": { + id: "package/undo.md"; + slug: "package/undo"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/url.md": { + id: "package/url.md"; + slug: "package/url"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/utils.md": { + id: "package/utils.md"; + slug: "package/utils"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"package/web.md": { + id: "package/web.md"; + slug: "package/web"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"recipes/atomization.md": { + id: "recipes/atomization.md"; + slug: "recipes/atomization"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"recipes/custom-operator.md": { + id: "recipes/custom-operator.md"; + slug: "recipes/custom-operator"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"recipes/typescript.md": { + id: "recipes/typescript.md"; + slug: "recipes/typescript"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".md"] }; +"repl.mdx": { + id: "repl.mdx"; + slug: "repl"; + body: string; + collection: "docs"; + data: InferEntrySchema<"docs"> +} & { render(): Render[".mdx"] }; +}; + + }; + + type DataEntryMap = { + + }; + + type AnyEntryMap = ContentEntryMap & DataEntryMap; + + type ContentConfig = typeof import("../src/content/config"); +} diff --git a/docs/src/content/docs/blog/what-is-state-manager.md b/docs/src/content/docs/fundamentals/what-is-a-state-manager.md similarity index 100% rename from docs/src/content/docs/blog/what-is-state-manager.md rename to docs/src/content/docs/fundamentals/what-is-a-state-manager.md diff --git a/docs/src/content/docs/getting-started/setup.md b/docs/src/content/docs/getting-started/setup.md index ac16b314..9b457c95 100644 --- a/docs/src/content/docs/getting-started/setup.md +++ b/docs/src/content/docs/getting-started/setup.md @@ -5,107 +5,35 @@ sidebar: order: 1 --- -Reatom is a framework-agnostic state manager, and you can use it with various adapters for different frameworks. This guide provides a common usage with React.js, as it is the most commonly used view library currently. +## Start from React template -## Create new project from template +Here is a minimal project template with TypeScript, Vite, React and Reatom: [`reatom-react-ts`](https://artalar/reatom-react-ts/). -The base template project includes Vite, TypeScript, React and Reatom ecosystem: https://github.com/artalar/reatom-react-ts - -You could try it online: [codesandbox](https://codesandbox.io/p/sandbox/github/artalar/reatom-react-ts/tree/main), [stackblitz](https://githubblitz.com/artalar/reatom-react-ts), [gitpod](https://gitpod.io/#https://github.com/artalar/reatom-react-ts) - -To setup it in your machine you can use [degit](https://github.com/Rich-Harris/degit) package. +You can use [`degit`](https://github.com/rich-harris/degit) to quickly download it: ```sh -npx degit github:artalar/reatom-react-ts PROJECT-NAME -cd PROJECT-NAME - +npx degit github:artalar/reatom-react-ts new-reatom-app +cd new-reatom-app npm install npm run dev ``` -## Add to existing project - -```sh -npm i @reatom/core -``` +## Add Reatom to an existing project -### With React - -#### Installation +Install [`@reatom/core`](https://www.reatom.dev/package/core/) if you are looking for a minimal and framework-agnostic state manager: ```sh -npm i @reatom/npm-react +npm install @reatom/core ``` -You need to set up the main context and put it into the provider at the top of your application. - -```jsx -import { createCtx } from '@reatom/core' -import { reatomContext } from '@reatom/npm-react' -import { Main } from './path/to/an/Main' - -const ctx = createCtx() - -export const App = () => ( - -
- -) -``` +Or use [`@reatom/framework`](https://www.reatom.dev/package/framework/) which includes most of the Reatom ecosystem and is recommended for most applications. -#### Usage - -The `useAtom` function allows you to have an experience similar to `useState`, but with shared atom state. - -```jsx -const nameAtom = atom('Joe') -const greetingAtom = atom((ctx) => `Hello, ${ctx.spy(nameAtom)}!`) - -const Greeting = () => { - const [name, setName] = useAtom(nameAtom) - const [greeting] = useAtom(greetingAtom) - - return ( - <> - -

Hello {greeting}!

- - ) -} -``` - -Also, you can create computed atoms (kind of selectors) right inside `useAtom`. - -```jsx -const nameAtom = atom('Joe') - -const Greeting = () => { - const t = useTranslation() - const [name, setName] = useAtom(nameAtom) - const [greeting] = useAtom( - (ctx) => `${t('common:GREETING')} ${ctx.spy(nameAtom)}!`, - [t], - ) - - return ( - <> - -

{greeting}!

- - ) -} -``` +For a guide on integration with a supported view framework, see the relevant adapter's docs: -This is very basic functionality of reatom-react bindings, see more in [@reatom/npm-react](/package/npm-react/) package documentation +- [React](https://reatom.dev/package/npm-react) +- [Svelte](https://reatom.dev/package/npm-svelte) +- [SolidJS](https://reatom.dev/package/npm-solid-js) - +If you are using ESLint, see [`@reatom/eslint-plugin`](https://www.reatom.dev/package/eslint-plugin/) for a set of Reatom-specific rules. diff --git a/docs/src/content/docs/index.md b/docs/src/content/docs/index.md index 128d71ed..b7d707c9 100644 --- a/docs/src/content/docs/index.md +++ b/docs/src/content/docs/index.md @@ -7,282 +7,83 @@ description: Reatom - tiny and powerful reactive system with immutable nature -**Reatom is a ultimate logic and state manager for small widgets and huge SPAs.** +# Reatom -## Key features - -- **simple** and powerful abstractions. - There are only three main primitives: `ctx`, `atom`, `action`, all other features and packages works on top of that. -- **immutable** and reliable. - All pure computations processed with atomicity guaranties. -- **explicit reactivity** without proxies. - To archive [maximum](#how-performant-reatom-is) performance we have [atomization](/recipes/atomization) pattern. -- perfect **effects management**. - Advanced [async package](/package/async) allows you to describe complex async flows with caching, retrying and automatic cancellation with native `await` and `AbortController`. -- nice **debugging** experience. - Each atom and action update stores [immutable cause (call) stack](/getting-started/debugging/) which is super helpful for debugging complex async flows. To simplify this we have [logger package](/package/logger). -- implicit **DI**. - To run tests and SSR 100% safety you need an isolation layer, which `ctx` is! We have the extra [testing package](/package/testing) with pack of helpers for a mocking. -- actor-like **lifecycle hooks** - To archive a trhtully modularity you have ability to describe [self-sufficient models](/handbook#lifecycle) -- **smallest bundle** size: [2 KB](https://bundlejs.com/?q=%40reatom%2Fcore) gzipped - Because of the power of the base primitives all ecosystem with A LOT of enterprize-grade helpers took only [~15KB](https://bundlejs.com/?q=%40reatom%2Fframework%2C%40reatom%2Fnpm-react%2C%40reatom%2Fpersist-web-storage%2C%40reatom%2Fundo%2C%40reatom%2Fform-web&config=%7B%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22use-sync-external-store%22%5D%7D%7D) - insane! -- **best TypeScript** experience - [Automatic type inference](/recipes/typescript/) is one of the main priority of Reatom developement. - -[The core package](/core) includes most these features and you may use it anywhere, from huge apps to even small libs, as the overhead is tiny. Also, you could reuse our carefully written [helper tools](/package/framework) to solve complex tasks in a couple lines of code. We are trying to build a stable and balanced ecosystem for perfect DX and predictable maintains even for years ahead. - -## Simple example - -Let's define input state and compute a greeting from it. - -### Install - -```sh -npm i @reatom/core -``` - -[vanilla codesandbox](https://codesandbox.io/s/reatom-vanila-hello-world-6oo36v?file=/src/index.ts) - -[react codesandbox](https://codesandbox.io/s/reatom-react-hello-world-fgt6jn?file=/src/model.ts) - -### Simple example model - -The concept is _dumb_ - if you want to make a variable reactive, wrap the init state in `atom`, you will alow to change the state by calling it as a function. Need reactive computed? - wrap it to `atom`! - -`action`s needed to separate logic and batch atom updates. - -All data processing should be immutable, all side-effects should be wrapped to `ctx.schedule`. - -What is `ctx`? It is the most powerful feature of Reatom. It flows as the first argument across all Reatom functions, bringing you enterprise-grade features with only three extra symbols! - -```ts -import { action, atom } from '@reatom/core' - -const initState = localStorage.getItem('name') ?? '' -export const inputAtom = atom(initState) - -export const greetingAtom = atom((ctx) => { - // `spy` dynamically reads the atom and subscribes to it - const input = ctx.spy(inputAtom) - return input ? `Hello, ${input}!` : '' -}) - -export const onSubmit = action((ctx) => { - const input = ctx.get(inputAtom) - ctx.schedule(() => { - localStorage.setItem('name', input) - }) -}) -``` - -### Simple example context - -The context set up once for the whole app, or multiple times if you need isolation in SSR or tests. - -```ts -import { createCtx } from '@reatom/core' - -const ctx = createCtx() -``` - -### Simple example view - -```ts -import { inputAtom, greetingAtom, onSubmit } from './model' - -ctx.subscribe(greetingAtom, (greeting) => { - document.getElementById('greeting')!.innerText = greeting -}) - -document.getElementById('name').addEventListener('input', (event) => { - inputAtom(ctx, event.currentTarget.value) -}) -document.getElementById('save').addEventListener('click', () => { - onSubmit(ctx) -}) -``` - -Check out [@reatom/core docs](/core) for detailed explanation of key principles and features. - -Do you use React.js? Check out [npm-react](/package/npm-react) package! +The ultimate state manager for any kinds of applications. -## Advanced example - -The core package is already profitable and you could use only it as a most simple and featured solution for your state and logic management. If you want to solve common system logic with advanced libraries to care more optimizations and UX tasks - continue and check this small guide out. - -This example is close to real life and shows the complexity of interactive UI. It is a simple search input with debouncing and autocomplete. It uses [GitHub API](https://docs.github.com/en/rest/reference/search#search-issues-and-pull-requests) to fetch issues by query. The limitations of this API are described in [GitHub docs](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). We need to reduce the number of requests and retry them if we hit the limit. Also, we need to cancel all previous requests if a new one is created, to prevent race conditions - when the previous request resolves after the new one. - -### Install framework - -```sh -npm i @reatom/framework @reatom/npm-react -``` - -[codesandbox](https://codesandbox.io/s/reatom-react-search-component-l4pe8q?file=/src/App.tsx) - -### Advanced example description - -We will use [@reatom/core](/core), [@reatom/async](/package/async) and [@reatom/hooks](/package/hooks) packages in this example by importing it from the meta package [@reatom/framework](/package/framework) - it simplifies imports and dependencies management. - -`reatomAsync` is a simple decorator which wraps your async function and adds extra actions and atoms to track creating promise statuses. - -`withDataAtom` adds property `dataAtom` which saves the last effect result and allow you to subscribe to it. `withCache` enable function middleware which prevent it's extra calls based on passed arguments identity - classic cache. `withAbort` allows to define concurrent requests abort strategy, by using `ctx.controller` ([AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)) from `reatomAsync`. `withRetry` and `onReject` handler help to handle temporal rate limit. - -Simple `sleep` helper (for debounce) gotten from [utils package](/package/utils) - it is a built-in microscopic lodash alternative for most popular and tiny helpers. - -`onUpdate` is a [hook](/package/hooks) which link to the atom and calls passed callback on every update. - -### Advanced example model - -```ts -import { atom, reatomAsync, withAbort, withDataAtom, withRetry, onUpdate, sleep, withCache } from "@reatom/framework"; // prettier-ignore -import * as api from './api' - -const searchAtom = atom('', 'searchAtom') - -const fetchIssues = reatomAsync(async (ctx, query: string) => { - await sleep(350) // debounce - const { items } = await api.fetchIssues(query, ctx.controller) - return items -}, 'fetchIssues').pipe( - withAbort({ strategy: 'last-in-win' }), - withDataAtom([]), - withCache({ length: 50, swr: false, paramsLength: 1 }), - withRetry({ - onReject(ctx, error: any, retries) { - // return delay in ms or -1 to prevent retries - return error?.message.includes('rate limit') - ? 100 * Math.min(500, retries ** 2) - : -1 - }, - }), -) - -// run fetchIssues on every searchAtom update -onUpdate(searchAtom, fetchIssues) -``` - -### Advanced example view - -```tsx -import { useAtom } from '@reatom/npm-react' - -export const Search = () => { - const [search, setSearch] = useAtom(searchAtom) - const [issues] = useAtom(fetchIssues.dataAtom) - // you could pass a callback to `useAtom` to create a computed atom - const [isLoading] = useAtom( - (ctx) => - // even if there are no pending requests, we need to wait for retries - // let do not show the limit error to make him think that everything is fine for a better UX - ctx.spy(fetchIssues.pendingAtom) + ctx.spy(fetchIssues.retriesAtom) > 0, - ) - - return ( -
- setSearch(e.currentTarget.value)} - placeholder="Search" - /> - {isLoading && 'Loading...'} -
    - {issues.map(({ title }, i) => ( -
  • {title}
  • - ))} -
-
- ) -} -``` - -The whole logic definition is only about 15 LoC and it is not coupled to React and could be tested easily. What would the lines count be in a different library? The most impressive thing is that the overhead is [less than 4KB (gzip)](https://bundlejs.com/?q=%28import%29%40reatom%2Fframework%2C%28import%29%40reatom%2Fnpm-react&treeshake=%5B%7B%0A++atom%2CcreateCtx%2ConUpdate%2CreatomAsync%2Csleep%2CwithAbort%2CwithDataAtom%2CwithRetry%2C%7D%5D%2C%5B%7B+useAtom+%7D%5D&share=MYewdgzgLgBBCmBDATsAFgQSiAtjAvDItjgBQBE5ANDOQiulruQJQDcAUKJLAGbxR0ASQgQArvAgEYyJCQwQAnmGClESlTFLAoADxoBHCckUAuOFGQBLMAHMWBAHwwA3hxhEA7oiuwIAG3h4AAdSACYAVgAGdhgAejiYABN4ACMQMRV4dxhuaFcYX3gcKQBfaURvXyJgqwA6fkE0EXFJUiN4ExodXTruSxB-QOR2HNkoMWQwQqhiiE5SmnJG4VEJCFY62uD4UhzPXzQAEWJEJjIAbQBdFip9w4x05ChSFwtkYnhbM1p-dSgALQ2AEHMDkGClW73KBoABKAhMrxyHnA8IAVvAdNo9DROsgQMhzIgwIoaONrJIHG4PDT4olxpNpik-opCtMSjACTAAQBGGDYGDBWQAN3gYFg5KskmRNIZUxgeIJAH46jhJBBELZ4HUbMB-GIUhAKB9ZjB-FYcL5WDLaUqYDyolEYAAqGAAWWIaFVNlI0SiZIRUqkztdYRYNpp5l5nFpixykLuowSMkyMBWzTWkk503gopMcCQqEwJBgYmCSU%2BHHAAFVy59SPQi%2BcaOmWutRlxZJ8AMJ6UijMQIc6kVuZiB1CtQM4kFhAA&config=%7B%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22use-sync-external-store%22%5D%7D%7D) could you imagine?! And you are not limited to network cache, Reatom is powerful and expressive enough for describing any kind of state. +## Key features -To get maximum of Reatom and the ecosystem just go to [tutorial](/getting-started/setup/). If you need something tiny - check out [the core package docs](/core). Also, we have a [package for testing](/package/testing)! +- efficient and reliable reactive runtime +- minimal but powerful primitives +- advanced primitives to abstract away the complexity of asynchronous interactions +- rich official ecosystem with lots of high-quality helpers and integrations +- tiny bundle size starting from 2KB +- full TypeScript support +- [nice debugging experience](https://reatom.dev/package/logger) +- builtin DI for straightforward testing and SSR +- lifecycle hooks for describing focused and self-sufficient models -## Roadmap +## Getting started -- Finish [forms package](/package/form) -- Finish ~~[persist](/package/persist)~~, improve [url](/package/url/) packages -- Add adapters for most popular ui frameworks: ~~[react](/package/npm-react)~~, angular, vue, ~~[svelte](/package/npm-svelte)~~, ~~[solid](/package/npm-solid-js/)~~. -- Port some components logic from reakit.io, to made it fast, light and portable. -- Add ability to made async transaction and elaborate optimistic-ui patterns and helpers / package. +[Read the docs](https://reatom.dev/getting-started/setup) or [see examples](/examples/). ## FAQ -### Why not X? - -**Redux** is awesome and Reatom is heavy inspired by it. Immutability, separation of computations and effects are good architecture designs principles. But there are a lot of missing features, when you trying to build something huge, or want to describe something small. Some of them is just impossible to fix, like [batching](/core#ctxget-batch-api), [O(n) complexity](/recipes/atomization/#reducing-computational-complexity) or that selectors is not inspectable and breaks [the atomicy](/general/what-is-state-manager#state). Others is really [hard to improve](https://github.com/reduxjs/reselect/discussions/491). And boilerplate, yeah, [the difference is a huge](https://github.com/artalar/RTK-entities-basic-example/pull/1/files#diff-43162f68100a9b5eb2e58684c7b9a5dc7b004ba28fd8a4eb6461402ec3a3a6c6). -Reatom solves all this problems and bring much more features by the almost same size. +### Comparison -**MobX** brings too big bundle to use it in a small widgets, Reatom is more universal in this case. Also, MobX has mutability and implicit reactivity, which is usefull for simple cases, but could be not obvious and hard to debug in complex cases. There is no separate thing like action / event / effect to describe some dependent effects sequences (FRP-way). [There is not atomicy too](https://github.com/artalar/state-management-specification/blob/master/src/index.test.js#L60). +**Redux**: Reatom was heavily inspired by Redux and does share many design principles with it. But it has many flaws that are hard or impossible to fix. Absence of action batching, non-atomic selectors and linear state update complexity, to name a few. Reatom solves all of them, implements much more features and [reduces the amount of boilerplate code](https://github.com/artalar/RTK-entities-basic-example/pull/1/files#diff-43162f68100a9b5eb2e58684c7b9a5dc7b004ba28fd8a4eb6461402ec3a3a6c6) a lot. -**Effector** is too opinionated. There is **no** first-class support for **lazy** reactive computations and all connections are [hot](https://luukgruijs.medium.com/understanding-hot-vs-cold-observables-62d04cf92e03) everytime, which is could be more predictable, but defenetly is not optimal. Effector is not friendly for fabric creation (because of it hotness), which disallow us to use [atomization](/recipes/atomization/) patterns, needed to handle immutability efficient. [The bundle size is 2-3 times larger](https://bundlejs.com/?q=effector&treeshake=%5B%7BcraeteStore%2CcreateEvent%2Ccombine%7D%5D) and [performance is lower](https://github.com/artalar/reactive-computed-bench). +**MobX**: MobX bundle size is too huge to use it in small embedded widgets, it uses getters/Proxies for change detections and has mutable nature, which eventually leads to confusing debugging sessions. [It has no atomicity as well](https://github.com/artalar/state-management-specification/blob/master/src/index.test.js#L60). -[Zustand](https://github.com/pmndrs/zustand), [nanostores](https://github.com/nanostores/nanostores), [xstate](https://xstate.js.org) and [many other](https://gist.github.com/artalar/e5e8a7274dfdfbe9d36c9e5ec22fc650) state managers have no so great combination of type inference, features, bundle size and performance, as Reatom have. +**Effector:** Effector encourages the description of sequential procedures through custom operators like `sample`, making the code really confusing. It also lacks the laziness of reactive computations, automatic dependency tracking, and is less performant compared to Reatom. -### Why immutability? +Solutions like **zustand**, **jotai**, **nanostores**, **xstate**, [and many others](https://gist.github.com/artalar/e5e8a7274dfdfbe9d36c9e5ec22fc650), are either less efficient than Reatom, or are not that feature-rich. -Immutable data is much predictable and better for debug, than mutable states and wrapers around that. Reatom specialy designed with focus on [simple debug of async chains](/getting-started/debugging/) and [have a patterns](/recipes/atomization/) to handle [greate performance](#how-performant-reatom-is). +### What LTS policy is used and what about the bus factor? -### What LTS policy is used and what about bus factor? +Reatom is always developed for continous usage. LTS versions are released once a year since [December 2019](https://github.com/artalar/reatom/releases/tag/v1.0) and have [compatibility layers](/compat/core-v1) with the most recent version of the core package. We hope it proves our approach to maintainance to be responsible. -Reatom always developed for long time usage. Our first LTS (Long Time Support) version (v1) [was released in December 2019](https://github.com/artalar/reatom/releases/tag/v1.0) and in 2022 we provided breaking changes less [Migration guide](/compat/core-v1#migration-guide) to the new LTS (v3) version. 3 years of successful maintains is not ended, but continued in [adapter package](/compat/core-v1). We hope it shows and prove our responsibility. +Our team currently consists of 4 people: [@artalar](https://github.com/artalar) and [@krulod](https://github.com/krulod) develop and maintain the core features, while [@BANOnotIT](https://github.com/BANOnotIT) and [@Akiyamka](https://github.com/Akiyamka) help with documentation and issue management. [Many other people also took part in the development of the library](https://github.com/artalar/reatom/graphs/contributors). -Currently, there are four people in the development team: [@artalar](https://github.com/artalar) and [@krulod](https://github.com/krulod) are managing the core features, while [@BANOnotIT](https://github.com/BANOnotIT) and [@Akiyamka](https://github.com/Akiyamka) help with documentation and issue management. [A lot of people](https://github.com/artalar/reatom/graphs/contributors) contributes to different packages. +### What about build targets and browser support? -### What build target and browser support? +All packages are configured based on [Browserslist's "last 1 year" query](https://browsersl.ist/#q=last+1+year). If you need to support older environments, you should handle transpilation by yourself. -All packages are configured based on [Browserslist's "last 1 year" query](https://browsersl.ist/#q=last+1+year). If you need to support older environments, you should handle transpilation yourself. - -All builds have two types of output formats: CJS (`exports.require`, `main`) and ESM (`exports.default`, `module`). You can check `package.json` for more details. +Packages include CommonJS and ESM entrypoints. See `package.json` files for more details. ### How performant Reatom is? -[Here is the benchmark](https://github.com/artalar/reactive-computed-bench) of complex computations for different state managers. Note that Reatom by default uses immutable data structures, works in a separate context (DI-like) and keeps [atomicity](/general/what-is-state-manager#state), which means the Reatom test checks more features, than other state manager tests. Anyway, for the middle numbers Reatom faster than MobX which is pretty impressive. - -Also, check out [atomization guide](/recipes/atomization). - -### Limitations - -Of course there are no software without limitations. Reatom is trying to be a silver bullet but we still have some cases which you should know about. - -- Immutable data always have an additional performance impact and in critical cases you should think well about your structures and how you could handle it better. The good news is that you [don't have to use normalization](/recipes/atomization). -- Laziness could be not obvious in some cases and will cause some updates missing. But it easy to debug a missing update, which is more explicit, than memory leaks and performance issues of hot observables. Anyway, we have [hooks](/package/hooks) for hot linking. -- Currently, there is no way to subscribe on error of any dependency, but we are working on it. In [reatomAsync](/package/async) passed effects wraps to an error handler and allow you to handle errors, but again - you should wrap it explicit. -- Currently, there is no asynchronous transactions support, but we are working on it. It is important feature for simplify building of optimistic UI and we really think it will improve UX a lot. -- We have a lot of utils and the ecosystem is growing all the time, but the target of that is have a set of well done logic primitives, and there is no architecture framework or codestyle / declarative framework to fit you in one strict flow. Reatom trying to be in the middle of a library and a framework. We love procedural programming with minimum extra API and semantic overhead. Our defaults are good already to help to you to write a better code: immutability and lazyness, transactions and separation of pure computations and effects, `ctx` and connections and processes virtualizations. +[Here is the benchmark](https://github.com/artalar/reactive-computed-bench) of complex computations for different state managers. Although Reatom features introduce more overhead, it appears to be more performant than MobX, which is pretty impressive. -### Media +### Limitations? -- [en twitter](https://twitter.com/ReatomJS) -- [en discord](https://discord.gg/EPAKK5SNFh) -- [en github discussion](https://github.com/artalar/reatom/discussions) -- [ru telegram](https://t.me/reatom_ru) -- [ru youtube](https://www.youtube.com/playlist?list=PLXObawgXpIfxERCN8Lqd89wdsXeUHm9XU) +No software is free from limitations, and Reatom is no exception. -### How to support the project? +- Immutable data introduces some overhead and encourages you to optimize your data structures. +- Lazy nature of Reatom may be unobvious and cause some problems like missing updates, but we find it much easier to bear with than the flaws of hot observables. +- Currently, there is no way to subscribe to errors of reactive computations, but we are working on it. +- Currently, there is no asynchronous transactions support, but we are working on it. +- We already have lots of utils and the ecosystem is growing all the time, but at the moment we don't have a strict architectural framework like `mobx-state-tree` that makes the development exceptionally straightforward. -https://www.patreon.com/artalar_dev +## Media -## Zen +- [X (EN)](https://twitter.com/ReatomJS) +- [Telegram (RU)](https://t.me/reatom_ru) +- [YouTube (RU)](https://www.youtube.com/playlist?list=PLXObawgXpIfxERCN8Lqd89wdsXeUHm9XU) -- **Good primitive is more than a framework** -- Composition beats configuration - +- [Patreon](https://www.patreon.com/artalar_dev) +- [Boosty](https://boosty.to/artalar) ## Credits -Software development in 202X is hard and we really appreciate all [contributors](https://github.com/artalar/reatom/graphs/contributors) and free software maintainers, who make our life easier. Special thanks to: +We really appreciate all [contributors](https://github.com/artalar/reatom/graphs/contributors) and free software maintainers. Shout-outs to the people behind the projects that helped us: -- [React](https://reactjs.org), [Redux](https://redux.js.org), [Effector](https://effector.dev/) and [$mol](https://github.com/hyoo-ru/mam_mol) for inspiration -- [microbundle](https://github.com/developit/microbundle) for handling all bundling complexity -- [Quokka](https://wallabyjs.com/oss/) and [uvu](https://github.com/lukeed/uvu) for incredible testing experience -- [TURBO](https://turbo.build) for simple monorepo management -- [Astro](https://astro.build) for best in class combine of performance and developer experience -- [Vercel](https://vercel.com/) for free hosting and perfect CI/CD (preview branches are <3) +- [React](https://reactjs.org), [Redux](https://redux.js.org), [Effector](https://effector.dev/) and [$mol](https://mol.hyoo.ru) — for inspiration +- [microbundle](https://github.com/developit/microbundle) +- [Quokka](https://wallabyjs.com/oss/) +- [uvu](https://github.com/lukeed/uvu) +- [Turborepo](https://turbo.build/repo) +- [Astro](https://astro.build) +- [Vercel](https://vercel.com/) diff --git a/package.json b/package.json index a79ddbcb..f4769a47 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "name": "reatom", "private": true, - "description": "Expressive and deterministic state manager", "scripts": { "release": "npx tsx ./tools/publish.ts", "postinstall": "turbo run build --filter=core --filter=framework --filter=testing", From 9c74fe9ab01ac5937f7d097ef26dbce5254517b7 Mon Sep 17 00:00:00 2001 From: krulod Date: Tue, 5 Dec 2023 01:19:08 +0200 Subject: [PATCH 2/4] docs: npm-lit docs draft --- examples/_lit/.gitignore | 24 + examples/_lit/README.md | 5 + examples/_lit/index.html | 13 + examples/_lit/package-lock.json | 1499 ++++++++++++++++++++++++++++++ examples/_lit/package.json | 22 + examples/_lit/public/vite.svg | 1 + examples/_lit/src/main.ts | 32 + examples/_lit/src/vite-env.d.ts | 1 + examples/_lit/tsconfig.json | 23 + examples/_lit/tsconfig.node.json | 10 + examples/_lit/vite.config.ts | 4 + packages/npm-lit/README.md | 56 +- 12 files changed, 1661 insertions(+), 29 deletions(-) create mode 100644 examples/_lit/.gitignore create mode 100644 examples/_lit/README.md create mode 100644 examples/_lit/index.html create mode 100644 examples/_lit/package-lock.json create mode 100644 examples/_lit/package.json create mode 100644 examples/_lit/public/vite.svg create mode 100644 examples/_lit/src/main.ts create mode 100644 examples/_lit/src/vite-env.d.ts create mode 100644 examples/_lit/tsconfig.json create mode 100644 examples/_lit/tsconfig.node.json create mode 100644 examples/_lit/vite.config.ts diff --git a/examples/_lit/.gitignore b/examples/_lit/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/examples/_lit/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/_lit/README.md b/examples/_lit/README.md new file mode 100644 index 00000000..d5da0084 --- /dev/null +++ b/examples/_lit/README.md @@ -0,0 +1,5 @@ +# Reatom atomization example + +An example showing how to use the [atomization](https://www.reatom.dev/recipes/atomization/) pattern in Reatom. + +[Open in StackBlitz](https://stackblitz.com/github/artalar/reatom/tree/v3/examples/react-atomization) diff --git a/examples/_lit/index.html b/examples/_lit/index.html new file mode 100644 index 00000000..06e67d9b --- /dev/null +++ b/examples/_lit/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/examples/_lit/package-lock.json b/examples/_lit/package-lock.json new file mode 100644 index 00000000..7210f2b6 --- /dev/null +++ b/examples/_lit/package-lock.json @@ -0,0 +1,1499 @@ +{ + "name": "reatom-lit", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "reatom-lit", + "version": "0.0.0", + "dependencies": { + "@reatom/framework": "^3.4.24", + "lit": "^3.1.0" + }, + "devDependencies": { + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@vitejs/plugin-react": "^4.0.3", + "typescript": "^5.0.2", + "vite": "^4.4.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", + "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", + "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz", + "integrity": "sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==" + }, + "node_modules/@lit/reactive-element": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.2.tgz", + "integrity": "sha512-SVOwLAWUQg3Ji1egtOt1UiFe4zdDpnWHyc5qctSceJ5XIu0Uc76YmGpIjZgx9YJ0XtdW0Jm507sDvjOu+HnB8w==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.2" + } + }, + "node_modules/@reatom/async": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@reatom/async/-/async-3.11.0.tgz", + "integrity": "sha512-Prp74LKozdDa1aXqzvJIjOY13zwhoAn2b6Vm5AQBWpH7glnFjnxMqeh0Q0ZuxdyPz6DbnA5LqemfQA50DYuVDw==", + "dependencies": { + "@reatom/core": "^3.5.0", + "@reatom/effects": "^3.5.0", + "@reatom/hooks": "^3.2.0", + "@reatom/primitives": "^3.1.0", + "@reatom/utils": "^3.4.0" + } + }, + "node_modules/@reatom/core": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@reatom/core/-/core-3.6.2.tgz", + "integrity": "sha512-CdKFz2jmoBTLjCnIvJcbSqkSy3fRyjsZeU8mIZEmYqYG78TMdtVnbCGqtsE99zWC/ivRTqGLJYgagp9X5RpSbg==" + }, + "node_modules/@reatom/effects": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@reatom/effects/-/effects-3.6.0.tgz", + "integrity": "sha512-aygpgLPrRwe/OQvSViDZwZHI2VF8CKd6BXKjeXglTH313tjCylItlDphzPvRx3vS4fDBZpf3MIDyGTJELnVRHA==", + "dependencies": { + "@reatom/core": "^3.2.0", + "@reatom/utils": "^3.5.0" + } + }, + "node_modules/@reatom/framework": { + "version": "3.4.24", + "resolved": "https://registry.npmjs.org/@reatom/framework/-/framework-3.4.24.tgz", + "integrity": "sha512-BlTUGYzb864HB0yA6+JRtdo4aqOk2KJqhbyEGqGDFv5D7okYeKlrJmm3VcbVxQLK2Ko4TcSyCt13lJ6kA4qs1Q==", + "dependencies": { + "@reatom/async": "^3.11.0", + "@reatom/core": "^3.6.2", + "@reatom/effects": "^3.6.0", + "@reatom/hooks": "^3.5.0", + "@reatom/lens": "^3.8.0", + "@reatom/logger": "^3.6.0", + "@reatom/primitives": "^3.2.1", + "@reatom/utils": "^3.7.0" + } + }, + "node_modules/@reatom/hooks": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@reatom/hooks/-/hooks-3.5.0.tgz", + "integrity": "sha512-m7QYzoWT7rHNT758nSyrSgFJFx/nxpIaWUWHZji5RH30Rm86ruIh5JHbgyoZPFnHY4BcPIRdOc0PmG76WuZCQA==", + "dependencies": { + "@reatom/core": "^3.2.0", + "@reatom/utils": "^3.3.0" + } + }, + "node_modules/@reatom/jsx": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@reatom/jsx/-/jsx-3.6.0.tgz", + "integrity": "sha512-CnvZycKWCLFrzn8uvY5UOf/k345vJYO4nD6jjvfg5Vjp+Vd+Pe5m6sSWJiXA6IJPHf5eZ7wxmzcPrZ43kRmJQw==", + "dependencies": { + "@reatom/core": ">=3.5.0", + "@reatom/lens": "^3.6.2", + "@reatom/utils": "^3.5.0", + "csstype": "^3.1.2" + } + }, + "node_modules/@reatom/lens": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@reatom/lens/-/lens-3.8.0.tgz", + "integrity": "sha512-UTt0ZkRFuyVLHKIuWYrw86Z0WWefi1zwrqZvkD0pAybYmYgf2B3AH6nOothrZkzjnDj/CKK2KMUjOChv4nklIg==", + "dependencies": { + "@reatom/core": "^3.4.0", + "@reatom/effects": "^3.2.0", + "@reatom/hooks": "^3.3.1", + "@reatom/utils": "^3.1.0" + } + }, + "node_modules/@reatom/logger": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@reatom/logger/-/logger-3.6.0.tgz", + "integrity": "sha512-UgYivXasJN+U8vUn8wbCx+bGlyVb6PZgJynmNrPwfSulG1oaoF/oi99ahDSXdQapu+GXkeyUXwoyOlrIY5wLQg==", + "dependencies": { + "@reatom/core": "^3.1.0", + "@reatom/jsx": "^3.4.0", + "stylerun": "^1.0.0" + } + }, + "node_modules/@reatom/primitives": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@reatom/primitives/-/primitives-3.2.1.tgz", + "integrity": "sha512-INZqbPbNG0bqRrlZ0LgaRCT8+q3g1ySjKOcpugHCFK0aCRlSK/jbPYQHIg2NYkB5PCamRdJJxaJeBrI8op6Miw==", + "dependencies": { + "@reatom/core": "^3.1.1", + "@reatom/utils": "^3.1.1" + } + }, + "node_modules/@reatom/utils": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@reatom/utils/-/utils-3.7.0.tgz", + "integrity": "sha512-P2uJATSneh1eIprZtv5BzQ4AERk1mWYwE6ZSyfpXPw7IrS+2cTymdt0NPPae+Ly7r+ncoAMBP3GqLgF2Xe+R+g==" + }, + "node_modules/@types/babel__core": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", + "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.6.tgz", + "integrity": "sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.3.tgz", + "integrity": "sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.3.tgz", + "integrity": "sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.9", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz", + "integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.2.33", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.33.tgz", + "integrity": "sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.14", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.14.tgz", + "integrity": "sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.5.tgz", + "integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==", + "dev": true + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz", + "integrity": "sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.22.20", + "@babel/plugin-transform-react-jsx-self": "^7.22.5", + "@babel/plugin-transform-react-jsx-source": "^7.22.5", + "@types/babel__core": "^7.20.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001559", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001559.tgz", + "integrity": "sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.572", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.572.tgz", + "integrity": "sha512-RlFobl4D3ieetbnR+2EpxdzFl9h0RAJkPK3pfiwMug2nhBin2ZCsGIAJWdpNniLz43sgXam/CgipOmvTA+rUiA==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", + "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", + "dependencies": { + "@lit/reactive-element": "^2.0.0", + "lit-element": "^4.0.0", + "lit-html": "^3.1.0" + } + }, + "node_modules/lit-element": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.2.tgz", + "integrity": "sha512-/W6WQZUa5VEXwC7H9tbtDMdSs9aWil3Ou8hU6z2cOKWbsm/tXPAcsoaHVEtrDo0zcOIE5GF6QgU55tlGL2Nihg==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.2", + "@lit/reactive-element": "^2.0.0", + "lit-html": "^3.1.0" + } + }, + "node_modules/lit-html": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.0.tgz", + "integrity": "sha512-FwAjq3iNsaO6SOZXEIpeROlJLUlrbyMkn4iuv4f4u1H40Jw8wkeR/OUXZUHUoiYabGk8Y4Y0F/rgq+R4MrOLmA==", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylerun": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stylerun/-/stylerun-1.0.0.tgz", + "integrity": "sha512-dP6GZ+iUAsV50/YwLVP0VMc2iIZ33jydFgP8AWzmTUjoKLy/bgHDGEuEt+5oomtU4iQ0rMrZGHiMVsi/FzjQvw==", + "engines": { + "node": ">=18" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } +} diff --git a/examples/_lit/package.json b/examples/_lit/package.json new file mode 100644 index 00000000..0d981858 --- /dev/null +++ b/examples/_lit/package.json @@ -0,0 +1,22 @@ +{ + "name": "reatom-lit", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@reatom/framework": "^3.4.24", + "lit": "^3.1.0" + }, + "devDependencies": { + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@vitejs/plugin-react": "^4.0.3", + "typescript": "^5.0.2", + "vite": "^4.4.5" + } +} diff --git a/examples/_lit/public/vite.svg b/examples/_lit/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/examples/_lit/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/_lit/src/main.ts b/examples/_lit/src/main.ts new file mode 100644 index 00000000..6d017df6 --- /dev/null +++ b/examples/_lit/src/main.ts @@ -0,0 +1,32 @@ +import { setupCtx, withReatom } from '@reatom/npm-lit' +import { atom, action, createCtx } from '@reatom/core' +import { onConnect } from '@reatom/hooks' +import { LitElement, html } from 'lit' + +const ctx = createCtx() +setupCtx(ctx) + +const count = atom(0, 'count') +const countText = atom((ctx) => `Current count: ${ctx.spy(count)}`, 'countText') +const increment = action((ctx) => { + count(ctx, (v) => v + 1) +}, 'increment') +onConnect(count, (ctx) => { + const timer = setInterval(() => increment(ctx), 1000) + return () => clearInterval(timer) +}) + +const text = atom('Empty', 'text') + +export class AppElement extends withReatom(LitElement) { + render() { + return html`
+ +

${this.ctx.spy(text)}

+ +

${this.ctx.spy(countText)}

+
` + } +} + +customElements.define('app-element', AppElement) diff --git a/examples/_lit/src/vite-env.d.ts b/examples/_lit/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/examples/_lit/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/_lit/tsconfig.json b/examples/_lit/tsconfig.json new file mode 100644 index 00000000..9302bbb9 --- /dev/null +++ b/examples/_lit/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/examples/_lit/tsconfig.node.json b/examples/_lit/tsconfig.node.json new file mode 100644 index 00000000..42872c59 --- /dev/null +++ b/examples/_lit/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/examples/_lit/vite.config.ts b/examples/_lit/vite.config.ts new file mode 100644 index 00000000..0640f332 --- /dev/null +++ b/examples/_lit/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig({}) diff --git a/packages/npm-lit/README.md b/packages/npm-lit/README.md index 3fac4b24..5b608086 100644 --- a/packages/npm-lit/README.md +++ b/packages/npm-lit/README.md @@ -1,5 +1,7 @@ # What is Lit? +Lit is a library for building web components. It eliminates the boilerplate of native WebComponent APIs and implements a minimal declarative template engine. + Lit is a simple library for building fast, lightweight web components. At Lit's core is a boilerplate-killing component base class that provides reactive state, scoped styles, and a declarative template system that's tiny, fast and expressive @@ -8,46 +10,42 @@ At Lit's core is a boilerplate-killing component base class that provides reacti Package provide 2 functions: -- setupCtx(ctx) - set context -- withReatom(el: LitElement) - mixin for subscribes to atom changes - -```Javascript -withReatom(LitElement) -``` +- `setupCtx(ctx)`: a function to provide integration with a `ctx` object +- `withReatom(el: LitElement)`: a mixin to make your components listen to Reatom state updates ## Example -```Javascript -import { setupCtx, withReatom } from "@reatom/npm-lit"; -import { atom, action, createCtx } from "@reatom/core"; -import { LitElement, html } from "lit"; +```js +import { setupCtx, withReatom } from '@reatom/npm-lit' +import { atom, action, createCtx } from '@reatom/core' +import { onConnect } from '@reatom/hooks' +import { LitElement, html } from 'lit' -const ctx = createCtx(); -setupCtx(ctx); +const ctx = createCtx() +setupCtx(ctx) -const count = atom(0); -const text = atom('Empty'); -const countText = atom((ctx) => `Current count: ${ctx.spy(count)}`); +const count = atom(0, 'count') +const countText = atom((ctx) => `Current count: ${ctx.spy(count)}`, 'countText') const increment = action((ctx) => { - count(ctx, (v) => v + 1); -}); + count(ctx, (v) => v + 1) +}, 'increment') +onConnect(count, (ctx) => { + const timer = setInterval(() => increment(ctx), 1000) + return () => clearInterval(timer) +}) -setTimeout(() => text(ctx, 'Not Empty'), 5000) -setInterval(() => increment(ctx), 1000); +const text = atom('Empty', 'text') - -export class Test extends withReatom(LitElement) { +export class AppElement extends withReatom(LitElement) { render() { return html`
- TextAtom: ${this.ctx.spy(text)}
- Render: ${this.ctx.spy(countText)}
- -
`; + +

${this.ctx.spy(text)}

+ +

${this.ctx.spy(countText)}

+ ` } } -if (!customElements.get("test-element")) { - customElements.define("test-element", Test); -} - +customElements.define('app-element', AppElement) ``` From a1698c201ddded922528a2be7d79dc236e627126 Mon Sep 17 00:00:00 2001 From: krulod Date: Sun, 10 Dec 2023 15:31:43 +0200 Subject: [PATCH 3/4] docs: expand readme --- README.md | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8cf72bd2..5059d8a2 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,21 @@ The ultimate state manager for any kinds of applications. ## Key features -- efficient and reliable reactive runtime +- framework-agnostic, supports multiple UI frameworks - minimal but powerful primitives -- advanced primitives to abstract away the complexity of asynchronous interactions -- rich official ecosystem with lots of high-quality helpers and integrations -- tiny bundle size starting from 2KB +- efficient and reliable reactive runtime +- tiny bundle size + - the core package adds only 2KB to your bundle + - the whole ecosystem weighs ~15KB +- rich official ecosystem with lots of high-quality helpers and integrations + - advanced primitives to abstract away the complexity of asynchronous interactions + - has integrations with [React](https://www.reatom.dev/package/npm-react/), [Svelte](https://www.reatom.dev/package/npm-svelte/), [SolidJS](https://www.reatom.dev/package/npm-solid-js/) - full TypeScript support -- [nice debugging experience](https://reatom.dev/package/logger) -- builtin DI for straightforward testing and SSR -- lifecycle hooks for describing focused and self-sufficient models + - APIs are designed to fully enable type inference +- efficient at any scale + - [includes tools to simplify debugging](https://reatom.dev/package/logger) + - builtin DI for straightforward testing and SSR + - lifecycle hooks for describing focused and self-sufficient models ## Getting started @@ -36,7 +42,7 @@ Reatom is always developed for continous usage. LTS versions are released once a Our team currently consists of 4 people: [@artalar](https://github.com/artalar) and [@krulod](https://github.com/krulod) develop and maintain the core features, while [@BANOnotIT](https://github.com/BANOnotIT) and [@Akiyamka](https://github.com/Akiyamka) help with documentation and issue management. [Many other people also took part in the development of the library](https://github.com/artalar/reatom/graphs/contributors). -### What about build targets and browser support? +### What about build targets and browser support? All packages are configured based on [Browserslist's "last 1 year" query](https://browsersl.ist/#q=last+1+year). If you need to support older environments, you should handle transpilation by yourself. @@ -56,6 +62,12 @@ No software is free from limitations, and Reatom is no exception. - Currently, there is no asynchronous transactions support, but we are working on it. - We already have lots of utils and the ecosystem is growing all the time, but at the moment we don't have a strict architectural framework like `mobx-state-tree` that makes the development exceptionally straightforward. +## Zen + +- Good primitive is better than framework +- Composition beats configuration +- JavaScript features should be reused, not reinvented + ## Media - [X (EN)](https://twitter.com/ReatomJS) @@ -73,7 +85,7 @@ We really appreciate all [contributors](https://github.com/artalar/reatom/graphs - [React](https://reactjs.org), [Redux](https://redux.js.org), [Effector](https://effector.dev/) and [$mol](https://mol.hyoo.ru) — for inspiration - [microbundle](https://github.com/developit/microbundle) -- [Quokka](https://wallabyjs.com/oss/) +- [Quokka](https://wallabyjs.com/oss/) - [uvu](https://github.com/lukeed/uvu) - [Turborepo](https://turbo.build/repo) - [Astro](https://astro.build) From 09948749bde9c50f6064e52c2dc1ac17a56c758a Mon Sep 17 00:00:00 2001 From: krulod Date: Wed, 22 May 2024 09:48:38 +0300 Subject: [PATCH 4/4] docs: more readme improvements --- README.md | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 5059d8a2..48aa916e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -# Reatom - The ultimate state manager for any kinds of applications. ## Key features @@ -12,13 +10,14 @@ The ultimate state manager for any kinds of applications. - the whole ecosystem weighs ~15KB - rich official ecosystem with lots of high-quality helpers and integrations - advanced primitives to abstract away the complexity of asynchronous interactions - - has integrations with [React](https://www.reatom.dev/package/npm-react/), [Svelte](https://www.reatom.dev/package/npm-svelte/), [SolidJS](https://www.reatom.dev/package/npm-solid-js/) + - has adapters for [React](https://www.reatom.dev/package/npm-react/), [Vue](https://www.reatom.dev/package/npm-vue/), [Angular](https://reatom.dev/package/npm-angular), [SolidJS](https://www.reatom.dev/package/npm-solid-js/) and [Svelte](https://www.reatom.dev/package/npm-svelte/) - full TypeScript support - - APIs are designed to fully enable type inference + - all APIs are designed to fully enable type inference - efficient at any scale + - decomposition made easy with factories + - lifecycle hooks for describing focused and self-sufficient models - [includes tools to simplify debugging](https://reatom.dev/package/logger) - builtin DI for straightforward testing and SSR - - lifecycle hooks for describing focused and self-sufficient models ## Getting started @@ -28,49 +27,51 @@ The ultimate state manager for any kinds of applications. ### Comparison -**Redux**: Reatom was heavily inspired by Redux and does share many design principles with it. But it has many flaws that are hard or impossible to fix. Absence of action batching, non-atomic selectors and linear state update complexity, to name a few. Reatom solves all of them, implements much more features and [reduces the amount of boilerplate code](https://github.com/artalar/RTK-entities-basic-example/pull/1/files#diff-43162f68100a9b5eb2e58684c7b9a5dc7b004ba28fd8a4eb6461402ec3a3a6c6) a lot. +**Redux**: Reatom was heavily inspired by Redux and does share many design principles with it. But it has many flaws that are hard or impossible to fix. Absence of action batching, non-atomic selectors and `O(n)` state update complexity, to name a few. Reatom solves all of them, implements much more features and [reduces the amount of boilerplate code](https://github.com/artalar/RTK-entities-basic-example/pull/1/files#diff-43162f68100a9b5eb2e58684c7b9a5dc7b004ba28fd8a4eb6461402ec3a3a6c6) a lot. -**MobX**: MobX bundle size is too huge to use it in small embedded widgets, it uses getters/Proxies for change detections and has mutable nature, which eventually leads to confusing debugging sessions. [It has no atomicity as well](https://github.com/artalar/state-management-specification/blob/master/src/index.test.js#L60). +**MobX**: MobX bundle size is too big, making it a poor choice for small embedded widgets. It also tracks dependencies through getters or Proxies, which eventually leads to confusing debugging sessions. [There is no atomicity as well](https://github.com/artalar/state-management-specification/blob/master/src/index.test.js#L60). -**Effector:** Effector encourages the description of sequential procedures through custom operators like `sample`, making the code really confusing. It also lacks the laziness of reactive computations, automatic dependency tracking, and is less performant compared to Reatom. +**Effector:** Effector encourages the description of procedures through sophisticated primitives like `sample`, making the code really confusing and unaccessible for those unfamiliar with the "DSL". It also lacks the laziness of reactive computations, automatic dependency tracking, and is less performant compared to Reatom. -Solutions like **zustand**, **jotai**, **nanostores**, **xstate**, [and many others](https://gist.github.com/artalar/e5e8a7274dfdfbe9d36c9e5ec22fc650), are either less efficient than Reatom, or are not that feature-rich. +In the modern front-end tooling landscape, there are lots of other solutions including **zustand**, **jotai**, **nanostores**, **xstate** [and many others](https://gist.github.com/artalar/e5e8a7274dfdfbe9d36c9e5ec22fc650), but we find them either less efficient than Reatom, or lacking in features. ### What LTS policy is used and what about the bus factor? -Reatom is always developed for continous usage. LTS versions are released once a year since [December 2019](https://github.com/artalar/reatom/releases/tag/v1.0) and have [compatibility layers](https://www.reatom.dev/compat/core-v1) with the most recent version of the core package. We hope it proves our approach to maintainance to be responsible. +Reatom has always been developed for continous usage. LTS versions are released once a year since [December 2019](https://github.com/artalar/reatom/releases/tag/v1.0) and have [compatibility layers](https://www.reatom.dev/compat/core-v1) with the most recent version of the core package. We hope it proves our approach to maintainance to be responsible. Our team currently consists of 4 people: [@artalar](https://github.com/artalar) and [@krulod](https://github.com/krulod) develop and maintain the core features, while [@BANOnotIT](https://github.com/BANOnotIT) and [@Akiyamka](https://github.com/Akiyamka) help with documentation and issue management. [Many other people also took part in the development of the library](https://github.com/artalar/reatom/graphs/contributors). ### What about build targets and browser support? -All packages are configured based on [Browserslist's "last 1 year" query](https://browsersl.ist/#q=last+1+year). If you need to support older environments, you should handle transpilation by yourself. +Transpilation target of all packages is [Browserslist's "last 1 year" query](https://browsersl.ist/#q=last+1+year). If you need to support older environments, you should transpile applications by yourself. Packages include CommonJS and ESM entrypoints. See `package.json` files for more details. ### How performant Reatom is? -[Here is the benchmark](https://github.com/artalar/reactive-computed-bench) of complex computations for different state managers. Although Reatom features introduce more overhead, it appears to be more performant than MobX, which is pretty impressive. +Performance at design time is one of the main principles behind all Reatom code. Packages are written to be as small and efficient as possble, and all critical code is constantly being optimized pedantically. + +As a proof, [here is a benchmark](https://github.com/artalar/reactive-computed-bench) testing efficiency and memory consumption of various reactive programming libraries. Although the immutable nature of Reatom that makes its features possible does introduce more overhead, it appears to be more performant than MobX, which we believe is a quite decent result. ### Limitations? No software is free from limitations, and Reatom is no exception. -- Immutable data introduces some overhead and encourages you to optimize your data structures. -- Lazy nature of Reatom may be unobvious and cause some problems like missing updates, but we find it much easier to bear with than the flaws of hot observables. -- Currently, there is no way to subscribe to errors of reactive computations, but we are working on it. -- Currently, there is no asynchronous transactions support, but we are working on it. -- We already have lots of utils and the ecosystem is growing all the time, but at the moment we don't have a strict architectural framework like `mobx-state-tree` that makes the development exceptionally straightforward. +- Immutable data introduces some overhead and encourages you to optimize your data structures, but these trade-offs are insignificant compared to pros +- Lazy nature of Reatom may feel unobvious and cause some problems like missing updates, but they are much easier to bear with than the flaws of hot observables +- Currently, there is no way to subscribe to errors of reactive computations, but we are working on it +- Currently, there is no asynchronous transactions support, but we are working on it +- Ecosystem is growing all the time and is already pretty decent, but at the moment we don't have a strict architectural framework like `mobx-state-tree` that makes the development exceptionally straightforward ## Zen -- Good primitive is better than framework +- A good primitive is better than a framework - Composition beats configuration - JavaScript features should be reused, not reinvented ## Media -- [X (EN)](https://twitter.com/ReatomJS) +- [X (EN)](https://x.com/ReatomJS) - [Telegram (RU)](https://t.me/reatom_ru) - [YouTube (RU)](https://www.youtube.com/playlist?list=PLXObawgXpIfxERCN8Lqd89wdsXeUHm9XU)