diff --git a/.changeset/config.json b/.changeset/config.json index ab848d1a..f7e8ad09 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,11 +1,11 @@ { - "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", + "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", "changelog": "@changesets/cli/changelog", - "commit": false, + "commit": ["@changesets/cli/commit", { "skipCI": false }], "fixed": [], "linked": [], - "access": "restricted", + "access": "public", "baseBranch": "main", "updateInternalDependencies": "patch", - "ignore": [] + "ignore": ["@example/*"] } diff --git a/.deepsource.toml b/.deepsource.toml index 0af08500..c3cbc5b2 100644 --- a/.deepsource.toml +++ b/.deepsource.toml @@ -1,12 +1,12 @@ version = 1 -test_patterns = [ - "test/**/*.*", +test_patterns = ["**/*.test.*"] + +exclude_patterns = [ + "docs/**", "**/*.test.*" ] -exclude_patterns = ["docs/**"] - [[analyzers]] name = "javascript" diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 95f5d426..5ef5e42c 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: [mayank1513] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +github: [react18-tools, mayank1513] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] polar: mayank1513 patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8c2a6b39..2d5697aa 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -10,7 +10,6 @@ jobs: if: github.event.repository.owner.login == 'react18-tools' runs-on: ubuntu-latest permissions: - packages: write contents: write steps: - uses: actions/checkout@v4 @@ -21,13 +20,20 @@ jobs: with: registry-url: https://registry.npmjs.org node-version: 20 + - name: Setup Git + run: | + git config --global user.name "mayank1513" + git config --global user.email "mayank.srmu@gmail.com" + git fetch + git checkout main + git pull - run: npm i -g pnpm && pnpm i name: Install dependencies - name: Test run: npm test - - run: git status && git clean -f -d && git status + - run: git stash --include-untracked name: clean up working directory - - run: npx @turbo/codemod update . && pnpm update --latest -w + - run: npx @turbo/codemod update . && pnpm update --latest -r name: Update dependencies - run: pnpm build name: Build all apps to make sure it is not broken due to dependency upgrades @@ -35,11 +41,5 @@ jobs: run: pnpm test - name: Generate/update docs run: pnpm doc - - name: Setup Git - run: | - git config --global user.name "react18-tools" - git config --global user.email "mayank.srmu@gmail.com" - git fetch - git checkout main - name: Save upgraded packages back to repo run: git add . && git commit -m "upgrade deps && docs" && git push origin main diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/manual-publish.yml new file mode 100644 index 00000000..624397c5 --- /dev/null +++ b/.github/workflows/manual-publish.yml @@ -0,0 +1,44 @@ +name: Manually publish to NPM - Apply changeset in the workflow. + +# publish only when package json has changed - assuming version upgrade +on: + workflow_dispatch: + +jobs: + publish: + if: github.event.repository.owner.login == 'react18-tools' + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: https://registry.npmjs.org + - name: Setup Git + run: | + git config --global user.name "mayank1513" + git config --global user.email "mayank.srmu@gmail.com" + - run: npm i -g pnpm && pnpm i + name: Install dependencies + # fail and not publish if any of the unit tests are failing + - name: Test + run: pnpm test + - name: clean up working directory + run: git status && git clean -f -d && git status + - name: Copy Readme file + run: cp ./README.md ./lib # todo: uncomment this line while rebranding + - name: Apply changesets, publish and create release, branches and tags + run: node ./scripts/manual-publish.js + env: + BRANCH: ${{ github.ref_name }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 07973245..cfb637bc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,26 +2,20 @@ name: Publish to NPM # publish only when package json has changed - assuming version upgrade on: - workflow_dispatch: push: branches: [main] - paths: "lib/r18gs/package.json" + paths: "lib/package.json" jobs: publish: # Don't run just after creating repo from template # Also avoid running after merging set-up PR - if: github.event.repository.owner.login == 'react18-tools' + if: github.run_number > 2 && github.event.repository.owner.login == 'react18-tools' runs-on: ubuntu-latest permissions: - packages: write contents: write id-token: write - defaults: - run: - working-directory: ./lib/r18gs - steps: - uses: actions/checkout@v4 with: @@ -31,46 +25,22 @@ jobs: with: node-version: 20 registry-url: https://registry.npmjs.org + - name: Setup Git + run: | + git config --global user.name "mayank1513" + git config --global user.email "mayank.srmu@gmail.com" - run: npm i -g pnpm && pnpm i name: Install dependencies # fail and not publish if any of the unit tests are failing - name: Test run: pnpm test - - name: publish to NPM - run: pnpm build && pnpm publish-package - continue-on-error: true + - name: Copy Readme file + run: cp ./README.md ./lib # will be uncommented while rebranding + - name: Apply changesets, publish and create release, branches and tags + run: node ./scripts/publish.js env: + BRANCH: ${{ github.ref_name }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - TOKEN: ${{ secrets.GITHUB_TOKEN }} - OWNER: ${{ github.event.repository.owner.login }} - REPO: ${{ github.event.repository.name }} - - - name: Create GitHub release - run: | - v=$(node -p -e "require('./package.json').version") - gh release create $v --generate-notes --latest -n "$(sed '1,/^## /d;/^## /,$d' CHANGELOG.md)" --title "Release $v" - env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Publish canonical packages - continue-on-error: true - run: | - sed -i -e "s/.*name.*/\t\"name\": \"@mayank1513\/r18gs\",/" package.json - npm publish --provenance --access public - sed -i -e "s/.*name.*/\t\"name\": \"react18-global-store\",/" package.json - npm publish --provenance --access public - sed -i -e "s/.*name.*/\t\"name\": \"react18-store\",/" package.json - npm publish --provenance --access public - sed -i -e "s/.*name.*/\t\"name\": \"react19-global-store\",/" package.json - npm publish --provenance --access public - sed -i -e "s/.*name.*/\t\"name\": \"react19-store\",/" package.json - npm publish --provenance --access public - sed -i -e "s/.*name.*/\t\"name\": \"r19gs\",/" package.json - npm publish --provenance --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - - - name: Mark scoped package as deprecated - run: npm deprecate @mayank1513/r18gs "Please use https://www.npmjs.com/package/r18gs instead. We initially created scoped packages to have similarities with the GitHub Public Repository (which requires packages to be scoped). We are no longer using GPR and thus deprecating all scoped packages for which corresponding un-scoped packages exist." - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 15e4a2ba..47cca655 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,9 +7,8 @@ on: - cron: "5 */8 * * *" jobs: test: + if: github.run_number != 1 runs-on: ubuntu-latest - permissions: - contents: write steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -23,12 +22,11 @@ jobs: continue-on-error: true uses: codecov/codecov-action@v4 with: - directory: ./lib/r18gs + directory: ./lib token: ${{ secrets.CODECOV_TOKEN }} - flags: r18gs - uses: paambaati/codeclimate-action@v5.0.0 continue-on-error: true env: CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} with: - coverageLocations: ./lib/r18gs/coverage/*.xml:clover + coverageLocations: ./lib/coverage/*.xml:clover diff --git a/.gitignore b/.gitignore index 3e6eed46..544fb870 100644 --- a/.gitignore +++ b/.gitignore @@ -1,39 +1,16 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -node_modules -.pnp -.pnp.js - -# testing -coverage - -# next.js -.next/ -out/ -build - -# misc .DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env -.env.local -.env.development.local -.env.test.local -.env.production.local - -# turbo +node_modules .turbo +*.log +.next +dist +dist-ssr +*.local +.env +.cache -# vercel -.vercel +# test coverage +coverage -# lock files -*lock* +# temporary files +tsup.config.bundled* diff --git a/.prettierignore b/.prettierignore index a8d4ec13..e58c2191 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,4 @@ # ignore hbs files as prettier removes all spaces and makes it ugly *hbs docs +.vscode diff --git a/.prettierrc b/.prettierrc index 25fc6e9d..0b48ac1a 100644 --- a/.prettierrc +++ b/.prettierrc @@ -4,6 +4,5 @@ "tabWidth": 2, "arrowParens": "avoid", "jsxBracketSameLine": true, - "bracketSameLine": true, - "useTabs": true + "bracketSameLine": true } diff --git a/.tkb b/.tkb index 15ff7bec..8e0c6c8e 100644 --- a/.tkb +++ b/.tkb @@ -1,19 +1,11 @@ { "scope": "Workspace", - "tasks": { - "task-oQKhoVOKYhYaRYGvlDMj5": { - "id": "task-oQKhoVOKYhYaRYGvlDMj5", - "description": "Add support for persist and sync", - "columnId": "column-todo" - } - }, + "tasks": {}, "columns": [ { "id": "column-todo", "title": "To do", - "tasksIds": [ - "task-oQKhoVOKYhYaRYGvlDMj5" - ] + "tasksIds": [] }, { "id": "column-doing", diff --git a/.vscode/settings.json b/.vscode/settings.json index 20d656cd..36db13c4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,28 +1,13 @@ { // Formatting using Prettier by default for all languages "editor.defaultFormatter": "esbenp.prettier-vscode", - // Formatting using Prettier for JavaScript, overrides VSCode default. - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, // Ensure enough terminal history is preserved when running tests. "terminal.integrated.scrollback": 10000, - // Configure todo-tree to exclude node_modules, dist, and compiled. - "todo-tree.filtering.excludeGlobs": ["**/node_modules", "**/dist", "**/compiled"], - // Match TODO-APP in addition to other TODOs. - "todo-tree.general.tags": ["BUG", "HACK", "FIXME", "TODO", "XXX", "[ ]", "[x]", "TODO-APP"], - // Disable TypeScript surveys. "typescript.surveys.enabled": false, - "grammarly.selectors": [ - { - "language": "markdown", - "scheme": "file" - } - ], "editor.tabSize": 2, "editor.wordWrap": "on", "editor.formatOnSave": true, diff --git a/FEATURED.md b/FEATURED.md new file mode 100644 index 00000000..97909ff2 --- /dev/null +++ b/FEATURED.md @@ -0,0 +1,11 @@ +# Featured packages built with this template. + +> This file is automatically generated. Please refrain from editing it directly. To add your package, update `scripts/featured.json` in alphabetical order. + +- [esbuild-plugin-react18](https://github.com/react18-tools/esbuild-plugin-react18) - An esbuild plugin for compiling libraries compatible with React 18 server and client component, Nextjs13, and Nextjs14 +- [esbuild-plugin-react18-css](https://github.com/react18-tools/esbuild-plugin-react18-css) - ESBuild plugin to handle CSS/SCSS modules, autoprefixer, etc. +- [Nextjs-Themes](https://github.com/react18-tools/nextjs-themes) - 🤟 👉 Theme with confidence and Unleash the Power of React Server Components +- [Persist-And-Sync](https://github.com/react18-tools/persist-and-sync) - Zustand middleware to easily persist and sync Zustand state between tabs / windows / iframes (Same Origin) +- [React 18 Themes](https://github.com/react18-tools/react18-themes) - 🤟 👉 Unleash the Power of React Server Components +- [React18 Global Store](https://github.com/react18-tools/react18-global-store) - A simple yet elegant, light weight, react18 global store to replace Zustand for better tree shaking. +- [Zustand Sync Tabs](https://github.com/react18-tools/zustand-sync-tabs) - Zustand middleware to easily sync Zustand state between tabs / windows / iframes (Same Origin) diff --git a/README.md b/README.md index ddb13a72..d009ad25 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# React18GlobalStore +# React18GlobalStore [![test](https://github.com/react18-tools/react18-global-store/actions/workflows/test.yml/badge.svg)](https://github.com/react18-tools/react18-global-store/actions/workflows/test.yml) [![Maintainability](https://api.codeclimate.com/v1/badges/ec3140063acd8df82481/maintainability)](https://codeclimate.com/github/react18-tools/react18-global-store/maintainability) [![codecov](https://codecov.io/gh/react18-tools/react18-global-store/graph/badge.svg)](https://codecov.io/gh/react18-tools/react18-global-store) [![Version](https://img.shields.io/npm/v/r18gs.svg?colorB=green)](https://www.npmjs.com/package/r18gs) [![Downloads](https://img.jsdelivr.com/img.shields.io/npm/d18m/r18gs.svg)](https://www.npmjs.com/package/r18gs) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/r18gs) [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/from-referrer/) @@ -68,7 +68,9 @@ Interested in hands-on courses for getting started with Turborepo? Check out [Re ## License -Licensed under the MPL 2.0 open source license. +This library is licensed under the MPL-2.0 open-source license. + +> Please consider enrolling in [our courses](https://mayank-chaudhari.vercel.app/courses) or [sponsoring](https://github.com/sponsors/mayank1513) our work.
with 💖 by Mayank Kumar Chaudhari
diff --git a/contributing.md b/contributing.md index 87045151..f13085b9 100644 --- a/contributing.md +++ b/contributing.md @@ -1,36 +1,67 @@ -# Contributing to r18gs +# Contribution Guidelines -## Contribute +## Overview -Once you have cloned the repo. `cd` to the repo directory and use following commands. +### Included Utilities + +This template is equipped with pre-configured tools to streamline your development process: + +- Monorepo setup powered by TurboRepo + - TurboRepo is renowned for its efficient builds and caching mechanisms, minimizing unnecessary builds. +- [TypeScript](https://www.typescriptlang.org/) for static type checking +- [ESLint](https://eslint.org/) for code linting +- [Prettier](https://prettier.io) for code formatting +- Plop-based code generator for effortlessly scaffolding new components +- Automatic rebranding functionality for this template +- Workflows facilitating testing, documentation, dependency updates, and deployment of your docs and packages +- Build setup capable of creating appropriate CJS and ESM builds to support React 18 server and client component exports from the same library +- Out-of-the-box support for SCSS modules for `lib` and `packages/shared` + +### Apps and Packages + +This TurboRepo comprises the following packages/examples, all written in [TypeScript](https://www.typescriptlang.org/): + +- `@example/nextjs`: a [Next.js](https://nextjs.org/) app +- `@example/vite`: a [Vite.js](https://vitest.dev) app +- `@example/remix`: a Remix app +- `@repo/eslint-config`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) +- `@repo/typescript-config`: `tsconfig.json`s used throughout the monorepo +- `@repo/jest-presets`: Jest presets for unit testing +- `@repo/logger`: A configurable shared logger utility +- `@repo/shared`: An internal library of components utilized by the examples +- `react18-loaders`: a React component library (The core package published to NPM) + +## Automated File Generation + +Simply execute `yarn turbo gen` and follow the prompts to automatically generate your new component along with a test file and dependency linking, adhering to best practices. ### Build -To build all apps and packages, run the following command: +To build all apps and packages, execute the following command: ```bash pnpm build ``` -### Develop +### Development -To develop all apps and packages, run the following command: +For development of all apps and packages, run: ```bash pnpm dev ``` -### Run unit tests +### Running Unit Tests -To run unit tests, run the following command: +To execute unit tests, use: ```bash pnpm test ``` -### Linting and formating +### Linting and Formatting -Before creating PR make sure lint is passing and also run formatter to properly format the code. +Before creating a PR, ensure that linting passes and format the code properly with: ```bash pnpm lint @@ -42,55 +73,12 @@ and pnpm format ``` -You can also contribute by - -1. Sponsoring -2. Check out discussion for providing any feedback or sugestions. -3. Report any issues or feature requests in issues tab - -## What's inside? - -### Utilities - -This Turborepo has some additional tools already setup for you: - -- [TypeScript](https://www.typescriptlang.org/) for static type checking -- [ESLint](https://eslint.org/) for code linting -- [Prettier](https://prettier.io) for code formatting - -### Library, Examples and Packages - -This Turborepo includes the following packages/examples: - -#### React18 Global Store library - -You will find the core library code inside lib/r18gs - -#### Examples (/examples) - -- `nextjs`: a [Next.js](https://nextjs.org/) app -- `vite`: a [Vite.js](https://vitest.dev) app -- `remix`: a [Remix](https://remix.run/) app +## Useful Resources -#### Packages (/packages) - -- `eslint-config-custom`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) -- `tsconfig`: `tsconfig.json`s used throughout the monorepo -- `shared-ui`: An internal UI package for shared UI code - -Each package/example is 100% [TypeScript](https://www.typescriptlang.org/). - -## Automatic file generation - -- just run `yarn turbo gen` and follow the propts to auto generate your new component with test file and dependency linking -- follow best practices automatically - -## Useful Links - -Learn more about Turborepo and Next.js: +Explore more about TurboRepo and Next.js through the following links: - [React and Next.js with TypeScript](https://www.udemy.com/course/react-and-next-js-with-typescript/?referralCode=7202184A1E57C3DCA8B2) - an interactive Next.js course. -- [The Game of Chess with Next.js, React and TypeScrypt](https://www.udemy.com/course/game-of-chess-with-nextjs-react-and-typescrypt/?referralCode=851A28F10B254A8523FE) +- [The Game of Chess with Next.js, React, and TypeScript](https://www.udemy.com/course/game-of-chess-with-nextjs-react-and-typescrypt/?referralCode=851A28F10B254A8523FE) - [Tasks](https://turbo.build/repo/docs/core-concepts/monorepos/running-tasks) - [Caching](https://turbo.build/repo/docs/core-concepts/caching) - [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) @@ -98,10 +86,10 @@ Learn more about Turborepo and Next.js: - [Configuration Options](https://turbo.build/repo/docs/reference/configuration) - [CLI Usage](https://turbo.build/repo/docs/reference/command-line-reference) -> A quick tip: Delete all stale branches `git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d` +> Quick tip: Remove all stale branches with `git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d` -with 💖 by Mayank Kumar Chaudhari
diff --git a/devcontainer.json b/devcontainer.json new file mode 100644 index 00000000..bf721a6c --- /dev/null +++ b/devcontainer.json @@ -0,0 +1,18 @@ +{ + "image": "mcr.microsoft.com/vscode/devcontainers/javascript-node:20", + "hostRequirements": { + "memory": "8gb" + }, + "waitFor": "onCreateCommand", + "updateContentCommand": "", + "postCreateCommand": "", + "postAttachCommand": "", + "customizations": { + "codespaces": { + "openFiles": ["TODO.md", "scripts/rebrand.config.json"] + }, + "vscode": { + "extensions": ["mayank1513.trello-kanban-task-board", "esbenp.prettier-vscode"] + } + } +} diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css deleted file mode 100644 index f544099d..00000000 --- a/docs/assets/highlight.css +++ /dev/null @@ -1,120 +0,0 @@ -:root { - --light-hl-0: #0000FF; - --dark-hl-0: #569CD6; - --light-hl-1: #000000; - --dark-hl-1: #D4D4D4; - --light-hl-2: #0070C1; - --dark-hl-2: #4FC1FF; - --light-hl-3: #795E26; - --dark-hl-3: #DCDCAA; - --light-hl-4: #267F99; - --dark-hl-4: #4EC9B0; - --light-hl-5: #A31515; - --dark-hl-5: #CE9178; - --light-hl-6: #098658; - --dark-hl-6: #B5CEA8; - --light-hl-7: #008000; - --dark-hl-7: #6A9955; - --light-hl-8: #AF00DB; - --dark-hl-8: #C586C0; - --light-hl-9: #001080; - --dark-hl-9: #9CDCFE; - --light-hl-10: #800000; - --dark-hl-10: #808080; - --light-hl-11: #800000; - --dark-hl-11: #569CD6; - --light-hl-12: #E50000; - --dark-hl-12: #9CDCFE; - --light-hl-13: #000000FF; - --dark-hl-13: #D4D4D4; - --light-code-background: #FFFFFF; - --dark-code-background: #1E1E1E; -} - -@media (prefers-color-scheme: light) { :root { - --hl-0: var(--light-hl-0); - --hl-1: var(--light-hl-1); - --hl-2: var(--light-hl-2); - --hl-3: var(--light-hl-3); - --hl-4: var(--light-hl-4); - --hl-5: var(--light-hl-5); - --hl-6: var(--light-hl-6); - --hl-7: var(--light-hl-7); - --hl-8: var(--light-hl-8); - --hl-9: var(--light-hl-9); - --hl-10: var(--light-hl-10); - --hl-11: var(--light-hl-11); - --hl-12: var(--light-hl-12); - --hl-13: var(--light-hl-13); - --code-background: var(--light-code-background); -} } - -@media (prefers-color-scheme: dark) { :root { - --hl-0: var(--dark-hl-0); - --hl-1: var(--dark-hl-1); - --hl-2: var(--dark-hl-2); - --hl-3: var(--dark-hl-3); - --hl-4: var(--dark-hl-4); - --hl-5: var(--dark-hl-5); - --hl-6: var(--dark-hl-6); - --hl-7: var(--dark-hl-7); - --hl-8: var(--dark-hl-8); - --hl-9: var(--dark-hl-9); - --hl-10: var(--dark-hl-10); - --hl-11: var(--dark-hl-11); - --hl-12: var(--dark-hl-12); - --hl-13: var(--dark-hl-13); - --code-background: var(--dark-code-background); -} } - -:root[data-theme='light'] { - --hl-0: var(--light-hl-0); - --hl-1: var(--light-hl-1); - --hl-2: var(--light-hl-2); - --hl-3: var(--light-hl-3); - --hl-4: var(--light-hl-4); - --hl-5: var(--light-hl-5); - --hl-6: var(--light-hl-6); - --hl-7: var(--light-hl-7); - --hl-8: var(--light-hl-8); - --hl-9: var(--light-hl-9); - --hl-10: var(--light-hl-10); - --hl-11: var(--light-hl-11); - --hl-12: var(--light-hl-12); - --hl-13: var(--light-hl-13); - --code-background: var(--light-code-background); -} - -:root[data-theme='dark'] { - --hl-0: var(--dark-hl-0); - --hl-1: var(--dark-hl-1); - --hl-2: var(--dark-hl-2); - --hl-3: var(--dark-hl-3); - --hl-4: var(--dark-hl-4); - --hl-5: var(--dark-hl-5); - --hl-6: var(--dark-hl-6); - --hl-7: var(--dark-hl-7); - --hl-8: var(--dark-hl-8); - --hl-9: var(--dark-hl-9); - --hl-10: var(--dark-hl-10); - --hl-11: var(--dark-hl-11); - --hl-12: var(--dark-hl-12); - --hl-13: var(--dark-hl-13); - --code-background: var(--dark-code-background); -} - -.hl-0 { color: var(--hl-0); } -.hl-1 { color: var(--hl-1); } -.hl-2 { color: var(--hl-2); } -.hl-3 { color: var(--hl-3); } -.hl-4 { color: var(--hl-4); } -.hl-5 { color: var(--hl-5); } -.hl-6 { color: var(--hl-6); } -.hl-7 { color: var(--hl-7); } -.hl-8 { color: var(--hl-8); } -.hl-9 { color: var(--hl-9); } -.hl-10 { color: var(--hl-10); } -.hl-11 { color: var(--hl-11); } -.hl-12 { color: var(--hl-12); } -.hl-13 { color: var(--hl-13); } -pre, code { background: var(--code-background); } diff --git a/docs/assets/icons.js b/docs/assets/icons.js deleted file mode 100644 index b79c9e89..00000000 --- a/docs/assets/icons.js +++ /dev/null @@ -1,15 +0,0 @@ -(function(svg) { - svg.innerHTML = `const [state, setState] = useRGS<number>("counter", 1);
-
-Extract coomon create hook logic to utils
-setter function to set the state.
-craete subscriber function to subscribe to the store.
-Use this hook similar to useState
hook.
-The difference is that you need to pass a
-unique key - unique across the app to make
-this state accessible to all client components.
Unique key to identify the store.
-Optional
value: ValueType<T>Initial value of the store.
-Optional
plugins: Plugin<T>[]Plugins to be applied to the store.
-Do not initialize the store. Useful when you want to initialize the store later. Note that the setter function is not available until the store is initialized.
-const [state, setState] = useRGS<number>("counter", 1);
-
-Creates a store with plugins.
-// in hook file, e.g., store.ts
export const useMyRGS = create<type>(key, value, plugins);
// in component file
const [state, setState] = useMyRGS();
-
-Creates a hook similar to useRGS, but with plugins to be applied on first invocation.
-A hook that automatically initializes the store (if not already initialized) with the given plugins.
-Optional
value: UOptional
doNotInit: booleanI've developed fantastic libraries leveraging React18 features using Zustand, and they performed admirably. However, when attempting to import from specific folders for better tree-shaking, the libraries encountered issues. Each import resulted in a separate Zustand store being created, leading to increased package size.
-As a solution, I set out to create a lightweight, bare minimum store that facilitates shared state even when importing components from separate files, optimizing tree-shaking.
-✅ Full TypeScript Support
-✅ Unleash the full power of React18 Server components
-✅ Compatible with all build systems/tools/frameworks for React18
-✅ Documented with Typedoc (Docs)
-✅ Examples for Next.js, Vite, and Remix
-Utilize this hook similarly to the useState
hook. However, ensure to pass a unique key, unique across the app, to identify and make this state accessible to all client components.
const [state, setState] = useRGS<number>("counter", 1);
-
-or
-const [state, setState] = useRGS<number>("counter", () => 1);
-
---For detailed instructions, see Getting Started
-
Enhance the functionality of the store by leveraging either the create
function, withPlugins
function, or the useRGSWithPlugins
hook from r18gs/dist/with-plugins
, enabling features such as storing to local storage, among others.
// store.ts
import { create } from "r18gs/dist/with-plugins";
import { persist } from "r18gs/dist/plugins"; /** You can create your own plugin or import third-party plugins */
export const useMyPersistentCounterStore = create<number>("persistent-counter", 0, [persist()]);
-
-Now, you can utilize useMyPersistentCounterStore
similarly to useState
without specifying an initial value.
const [persistedCount, setPersistedCount] = useMyPersistentCounterStore();
-
---For detailed instructions, see Leveraging Plugins
-
See contributing.md
-Interested in hands-on courses for getting started with Turborepo? Check out React and Next.js with TypeScript and The Game of Chess with Next.js, React and TypeScript
- -Licensed under the MPL 2.0 open source license.
-with 💖 by Mayank Kumar Chaudhari
Const
Welcome to the quick guide for using this library.
-To get started, you can install the package via your preferred package manager. Here are a few examples:
-$ pnpm add r18gs
-
-or
-$ npm install r18gs
-
-or
-$ yarn add r18gs
-
-Utilize this hook similarly to the useState
hook. However, ensure to pass a unique key, unique across the app, to identify and make this state accessible to all client components.
const [state, setState] = useRGS<number>("counter", 1);
-
-You can access the same state across all client-side components using a unique key.
---It's advisable to store your keys in a separate file to prevent typos and unnecessary conflicts.
-
// constants/global-states.ts
export const COUNTER = "counter";
-
-// components/display.tsx
"use client";
import useRGS from "r18gs";
import { COUNTER } from "../constants/global-states";
export default function Display() {
const [count] = useRGS<number>(COUNTER);
return (
<div>
<h2>Client Component 2</h2>
<b>{count}</b>
</div>
);
}
-
-// components/counter.tsx
"use client";
import useRGS from "r18gs";
import { COUNTER } from "../constants/global-states";
export default function Counter() {
const [count, setCount] = useRGS(COUNTER, 0);
return (
<div>
<h2>Client Component 1</h2>
<input
onChange={e => {
setCount(parseInt(e.target.value.trim()));
}}
type="number"
value={count}
/>
</div>
);
}
-
-Const
Enhance your store's functionality by utilizing either the create
function, withPlugins
function, or the useRGSWithPlugins
hook from r18gs/dist/with-plugins
. This enables features such as storing to local storage, among others.
create
Function// store.ts
import { create } from "r18gs/dist/with-plugins";
import { persist } from "r18gs/dist/plugins"; // You can create your own plugin or import third-party plugins
export const useMyPersistentCounterStore = create<number>("persistent-counter", 0, [persist()]);
-
-Now you can utilize useMyPersistentCounterStore
similar to useState
without specifying an initial value.
// inside your component
const [persistedCount, setPersistedCount] = useMyPersistentCounterStore();
-
-useRGSWithPlugins
HookThis function is beneficial if your requirements dictate that your key
and/or initial value will depend on some props, etc. Or for some other reason you want to initialize the store from within a component (You need to use some variables available inside the component).
import { useRGSWithPlugins } from "r18gs/dist/with-plugin";
export function MyComponent(props: MyComponentProps) {
const [state, setState] = useRGSWithPlugins(
props.key,
props.initialVal,
props.plugins,
props.doNotInit,
);
// ...
}
-
-doNotInit
In some cases, you may not want to initialize the store immediately. In such cases, you can pass the fourth argument (doNotInit
) as true
. The default value is false.
true
, the store is created, but the setter function is set to null. Thus, you can access the initial value set by the first component that triggered this hook. However, it cannot be modified until the store is initialized, i.e., the hook is invoked by a component setting doNotInit
to false (or skipping this argument).Use case*: When you need that the store be used in many components, however, it should be initialized in a particular component only.
-withPlugins
Higher-Order FunctionThis is a utility function that will be very helpful when you want to use the useRGSWithPlugins
hook with the same plugins in multiple components.
// custom hook file, e.g., store.ts
export const useMyRGS = withPlugins([plugin1, plugin2, ...]);
-
-export function MyComponent(props: MyComponentProps) {
const [state, setState] = useMyRGS(props.key, props.initialVal, props.doNotInit);
// ...
}
-
-You can also create your own plugins. Refer to Creating Plugins.
-with 💖 by Mayank Kumar Chaudhari
diff --git a/examples/nextjs/app/favicon.ico b/examples/nextjs/app/favicon.ico deleted file mode 100644 index 71e4bd71..00000000 Binary files a/examples/nextjs/app/favicon.ico and /dev/null differ diff --git a/examples/nextjs/app/layout.tsx b/examples/nextjs/app/layout.tsx deleted file mode 100644 index 5e45229a..00000000 --- a/examples/nextjs/app/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { ServerTarget } from "nthul-lite/server"; -import { Inter } from "next/font/google"; -import { SharedRootLayout } from "shared-ui"; - -const inter = Inter({ subsets: ["latin"] }); - -export default function RootLayout({ children }: { children: React.ReactNode }): JSX.Element { - return ( - - -with 💖 by Mayank Kumar Chaudhari
diff --git a/examples/vite/index.html b/examples/vite/index.html index ef80c79b..978f2d53 100644 --- a/examples/vite/index.html +++ b/examples/vite/index.html @@ -1,13 +1,12 @@ - - - - -with 💖 by Mayank Kumar Chaudhari
diff --git a/lib/package.json b/lib/package.json new file mode 100644 index 00000000..1c7a3651 --- /dev/null +++ b/lib/package.json @@ -0,0 +1,95 @@ +{ + "name": "r18gs", + "author": "Mayank Kumar Chaudhariwith 💖 by Mayank Kumar Chaudhari
diff --git a/lib/r18gs/package.json b/lib/r18gs/package.json deleted file mode 100644 index cc9f74a9..00000000 --- a/lib/r18gs/package.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "r18gs", - "author": "Mayank Kumar Chaudhari{description}
- - ); -} diff --git a/packages/shared-ui/src/cards/cards.module.css b/packages/shared-ui/src/cards/cards.module.css deleted file mode 100644 index 050430d1..00000000 --- a/packages/shared-ui/src/cards/cards.module.css +++ /dev/null @@ -1,75 +0,0 @@ -.cards { - display: flex; - justify-content: space-evenly; - flex-wrap: wrap; - gap: 25px; - width: var(--max-width); - max-width: 95vw; -} - -.card { - all: unset; - display: flex; - flex-direction: column; - padding: 1rem 1.2rem; - border-radius: var(--border-radius); - background: rgba(var(--card-rgb), 0); - border: 1px solid rgba(var(--card-border-rgb), 0.1); - cursor: pointer; - transition: - background 200ms, - border 200ms; -} - -.card span { - display: inline-block; - transition: transform 200ms; -} - -.card h2 { - font-weight: 600; - margin-top: 0; - text-align: start; -} - -.card p { - margin: 0; - opacity: 0.6; - font-size: 0.9rem; - line-height: 1.5; - width: 34ch; - text-align: start; -} - -.card nav { - display: flex; - gap: 15px; - padding-top: 10px; -} - -.card nav select { - flex-grow: 1; -} - -/* Enable hover only on non-touch devices */ -@media (hover: hover) and (pointer: fine) { - .card:hover { - background: rgba(var(--card-rgb), 0.1); - border: 1px solid rgba(var(--card-border-rgb), 0.15); - } - - .card:hover span { - transform: translateX(4px); - } -} - -/* Mobile and Tablet */ -@media (max-width: 1023px) { - .card { - padding: 1rem 2.5rem; - } - - .card h2 { - margin-bottom: 0.5rem; - } -} diff --git a/packages/shared-ui/src/cards/index.tsx b/packages/shared-ui/src/cards/index.tsx deleted file mode 100644 index c2a91604..00000000 --- a/packages/shared-ui/src/cards/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import styles from "./cards.module.css"; -import { StarMeCard } from "./star-me-card"; -import { Card } from "./card"; - -const cards = [ - { - href: "https://react18-tools.github.io/r18gs/", - title: "Docs", - description: "Explore the official docs.", - }, - { - href: "https://github.com/react18-tools/r18gs", - title: "More Examples", - description: "Explore more examples on official GitHub Repo.", - }, -]; - -export function Cards() { - return ( -Star this repo for your new library!
-r18gs
;
-}
diff --git a/packages/shared-ui/src/common/select.tsx b/packages/shared-ui/src/common/select.tsx
deleted file mode 100644
index bbacd8fb..00000000
--- a/packages/shared-ui/src/common/select.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import type { HTMLProps, ReactNode } from "react";
-
-export interface SelectOptionsProps {
- value: string;
- children: ReactNode;
-}
-
-interface SelectProps extends HTMLProps
-
- Unleash the power of React Server Components! No wrapper required.
-
Supports tree shakable libraries.
-
Sharing state between client components without any wrapper or provider.
-Persistant counter - Also synced with multiple tabs
-Duplicate this tab to see state sharing between tabs in action
- -All components below share the same state without any wrapper.
++ +
+{description}
+ + ); +} diff --git a/packages/shared/src/server/cards/cards.module.scss b/packages/shared/src/server/cards/cards.module.scss new file mode 100644 index 00000000..5a19cfb8 --- /dev/null +++ b/packages/shared/src/server/cards/cards.module.scss @@ -0,0 +1,76 @@ +.cards { + display: flex; + justify-content: space-evenly; + flex-wrap: wrap; + gap: 25px; + width: var(--max-width); + max-width: 95vw; + margin: auto; +} + +.card { + all: unset; + display: flex; + flex-direction: column; + padding: 1rem 1.2rem; + border-radius: var(--border-radius); + background: rgba(var(--card-rgb), 0); + border: 1px solid rgba(var(--card-border-rgb), 0.1); + cursor: pointer; + transition: + background 200ms, + border 200ms; +} + +.card span { + display: inline-block; + transition: transform 200ms; +} + +.card h2 { + font-weight: 600; + margin-top: 0; + text-align: start; +} + +.card p { + margin: 0; + opacity: 0.6; + font-size: 0.9rem; + line-height: 1.5; + width: 34ch; + text-align: justify; +} + +.card nav { + display: flex; + gap: 15px; + padding-top: 10px; +} + +.card nav select { + flex-grow: 1; +} + +/* Enable hover only on non-touch devices */ +@media (hover: hover) and (pointer: fine) { + .card:hover { + background: rgba(var(--card-rgb), 0.1); + border: 1px solid rgba(var(--card-border-rgb), 0.15); + } + + .card:hover span { + transform: translateX(4px); + } +} + +/* Mobile and Tablet */ +@media (max-width: 1023px) { + .card { + padding: 1rem 2.5rem; + } + + .card h2 { + margin-bottom: 0.5rem; + } +} diff --git a/packages/shared/src/server/cards/cards.test.tsx b/packages/shared/src/server/cards/cards.test.tsx new file mode 100644 index 00000000..45532c5b --- /dev/null +++ b/packages/shared/src/server/cards/cards.test.tsx @@ -0,0 +1,11 @@ +import { cleanup, render } from "@testing-library/react"; +import { afterEach, describe, test } from "vitest"; +import { Cards } from "./cards"; + +describe.concurrent("cards", () => { + afterEach(cleanup); + + test("check if renders without errors", () => { + render(
Use this hook similar to
-useState
hook. -The difference is that you need to pass a -unique key - unique across the app to make -this state accessible to all client components.