Full Code of wobsoriano/solid-zustand for AI

main c2bc4fb48eb1 cached
27 files
24.4 KB
7.6k tokens
14 symbols
1 requests
Download .txt
Repository: wobsoriano/solid-zustand
Branch: main
Commit: c2bc4fb48eb1
Files: 27
Total size: 24.4 KB

Directory structure:
gitextract_tc6bjkld/

├── .changeset/
│   ├── README.md
│   └── config.json
├── .editorconfig
├── .github/
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── dev/
│   ├── App.tsx
│   ├── index.html
│   ├── index.tsx
│   ├── store.ts
│   ├── styles.css
│   ├── tsconfig.json
│   └── vite.config.ts
├── env.d.ts
├── eslint.config.js
├── package.json
├── src/
│   ├── index.ts
│   ├── shared.ts
│   ├── signal.ts
│   └── store.ts
├── tests/
│   └── index.spec.tsx
├── tsconfig.json
├── tsdown.config.ts
└── vitest.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .changeset/README.md
================================================
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)


================================================
FILE: .changeset/config.json
================================================
{
  "$schema": "https://unpkg.com/@changesets/config@3.1.2/schema.json",
  "changelog": "@changesets/cli/changelog",
  "commit": false,
  "fixed": [],
  "linked": [],
  "access": "public",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": []
}


================================================
FILE: .editorconfig
================================================
# editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        node: [22.x]
        os: [ubuntu-latest, windows-latest, macos-latest]
      fail-fast: false

    steps:
      - name: Checkout Repo
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with:
          fetch-depth: 0
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
        with:
          version: 10.25.0

      - name: Set up Node.js ${{ matrix.node }}
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: ${{ matrix.node }}
          cache: pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Lint
        run: pnpm lint

      - name: Typecheck
        run: pnpm typecheck

      - name: Build
        run: pnpm build

      - name: Test
        run: pnpm test
  provenance:
    name: Provenance
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with:
          fetch-depth: 0
      - name: Check Provenance
        uses: danielroe/provenance-action@41bcc969e579d9e29af08ba44fcbfdf95cee6e6c # v0.1.1
        with:
          fail-on-downgrade: true


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    branches:
      - main

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  release:
    permissions:
      contents: write # to create release (changesets/action)
      pull-requests: write # to create pull request (changesets/action)
      id-token: write # allows GitHub Actions to generate OIDC tokens
    name: Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
        with:
          # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
          fetch-depth: 0
      - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
        with:
          version: 10.25.0

      - name: Setup Node.js
        uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
        with:
          node-version: '24'
          cache: pnpm
          registry-url: https://registry.npmjs.org

      - name: Install dependencies
        run: pnpm install

      - name: Create Release Pull Request or Publish to npm
        id: changesets
        uses: changesets/action@e0145edc7d9d8679003495b11f87bd8ef63c0cba # v1.5.3
        with:
          publish: pnpm release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .gitignore
================================================
node_modules
.DS_Store
dist
*.local
.vscode

================================================
FILE: CHANGELOG.md
================================================
# Changelog

## 2.0.0

### Major Changes

- 9d58ece: ## Breaking Changes

  ### New Unified API

  The library now uses a unified `create` function with subpath exports instead of separate `createWithSignal` and `createWithStore` functions.

  **Before:**

  ```ts
  import { createWithSignal } from "solid-zustand"; // signal-based
  import { createWithStore } from "solid-zustand"; // store-based
  ```

  **After:**

  ```ts
  import { create } from "solid-zustand"; // signal-based (default)
  import { create } from "solid-zustand/store"; // store-based
  ```

  ### Requirements

  ⚠️ **Requires zustand v5** or higher.

  ## Migration Guide

  ### Using `createWithSignal`:

  ```diff
  - import { createWithSignal } from 'solid-zustand'
  + import { create } from 'solid-zustand'

  - const useStore = createWithSignal((set) => ({ ... }))
  + const useStore = create((set) => ({ ... }))
  ```

  ### Using `createWithStore`:

  ```diff
  - import { createWithStore } from 'solid-zustand'
  + import { create } from 'solid-zustand/store'

  - const useStore = createWithStore((set) => ({ ... }))
  + const useStore = create((set) => ({ ... }))
  ```

  ### Using default export:

  ```diff
  - import create from 'solid-zustand'
  + import { create } from 'solid-zustand'

  - const useStore = create((set) => ({ ... }))
  + const useStore = create((set) => ({ ... }))
  ```

  ## Deprecated APIs

  The following exports are deprecated but still work:

  - `createWithSignal` → Use `import { create } from 'solid-zustand'`
  - `createWithStore` → Use `import { create } from 'solid-zustand/store'`

  These will be removed in a future major version.

## v1.7.0

[compare changes](https://github.com/wobsoriano/solid-zustand/compare/v1.5.1...v1.7.0)

### 🏡 Chore

- **release:** V2.0.0 ([8d55674](https://github.com/wobsoriano/solid-zustand/commit/8d55674))
- **release:** V1.6.0 ([f78d98b](https://github.com/wobsoriano/solid-zustand/commit/f78d98b))

### ❤️ Contributors

- Wobsoriano ([@wobsoriano](http://github.com/wobsoriano))

## v1.6.0

[compare changes](https://github.com/wobsoriano/solid-zustand/compare/v1.5.1...v1.6.0)

### 🏡 Chore

- **release:** V2.0.0 ([8d55674](https://github.com/wobsoriano/solid-zustand/commit/8d55674))

### ❤️ Contributors

- Wobsoriano ([@wobsoriano](http://github.com/wobsoriano))

## v2.0.0

[compare changes](https://github.com/wobsoriano/solid-zustand/compare/v1.5.1...v2.0.0)

## v1.5.1

[compare changes](https://github.com/wobsoriano/solid-zustand/compare/v1.5.0...v1.5.1)

### 🩹 Fixes

- Update import statements due to deprecation of default exports ([bcc848e](https://github.com/wobsoriano/solid-zustand/commit/bcc848e))

### 🏡 Chore

- Update deps ([d27db70](https://github.com/wobsoriano/solid-zustand/commit/d27db70))
- Update deps ([f2f0dbf](https://github.com/wobsoriano/solid-zustand/commit/f2f0dbf))
- Update zustand ([b949c4e](https://github.com/wobsoriano/solid-zustand/commit/b949c4e))

### ❤️ Contributors

- Jcha0713 ([@jcha0713](http://github.com/jcha0713))
- Wobsoriano ([@wobsoriano](http://github.com/wobsoriano))


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2022 Robert Soriano

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: README.md
================================================
<p>
  <img width="100%" src="https://assets.solidjs.com/banner?type=solid-zustand&background=tiles&project=%20" alt="solid-zustand">
</p>

# solid-zustand

🐻 State management in Solid using [zustand](https://github.com/pmndrs/zustand).

## Install

```sh
pnpm add zustand solid-zustand
```

Demo: https://stackblitz.com/edit/vitejs-vite-tcofpc

## Usage

First create a zustand store (default uses signals)

```tsx
import { create } from 'solid-zustand'

interface BearState {
  bears: number
  increase: () => void
}

const useStore = create<BearState>(set => ({
  bears: 0,
  increase: () => set(state => ({ bears: state.bears + 1 })),
}))
```

Then bind your components, and that's it!

```tsx
function BearCounter() {
  const bears = useStore(state => state.bears)
  return (
    <h1>
      {bears()}
      {' '}
      around here ...
    </h1>
  )
}

function Controls() {
  const increase = useStore(state => state.increase)
  return <button onClick={increase}>one up</button>
}
```

If you prefer the underlying reactivity to use Solid [stores](https://docs.solidjs.com/references/api-reference/stores/using-stores) instead of [signals](https://www.solidjs.com/docs/latest#createsignal), use the `/store` subpath export:

```tsx
import { create } from 'solid-zustand/store'

const useStore = create<BearState>(set => ({
  bears: {
    count: 0,
  },
  increase: () => set(state => ({ bears: state.bears.count + 1 })),
}))

function BearCounter() {
  const bears = useStore(state => state.bears)
  return (
    <h1>
      {bears.count}
      {' '}
      around here ...
    </h1>
  )
}
```

## Recipes

### Fetching everything

```ts
const state = useStore()
```

### Selecting multiple state slices

It detects changes with strict-equality (old === new) by default, this is efficient for atomic state picks.

```ts
const nuts = useStore(state => state.nuts) // nuts()
const honey = useStore(state => state.honey) // honey()
```

If you want to construct a single object with multiple state-picks inside, similar to redux's mapStateToProps, you can tell zustand that you want the object to be diffed shallowly by passing the `shallow` equality function. That function will then be passed to the [`equals`](https://www.solidjs.com/docs/latest/api#options) option of `createSignal` (if using `create`):

```ts
import shallow from 'zustand/shallow'

// Object pick, either state.nuts or state.honey change
const state = useStore(state => ({ nuts: state.nuts, honey: state.honey }), shallow) // state().nuts, state().honey

// Array pick, either state.nuts or state.honey change
const state = useStore(state => [state.nuts, state.honey], shallow) // state()[0], state()[1]
```

## License

MIT


================================================
FILE: dev/App.tsx
================================================
import type { Component } from 'solid-js'
import { useStore } from './store'

const App: Component = () => {
  return (
    <div>
      <BearCounter />
      <Controls />
    </div>
  )
}

function BearCounter() {
  const bears = useStore(state => state.bears)
  return (
    <h1>
      {bears()}
      {' '}
      around here ...
    </h1>
  )
}

function Controls() {
  const increase = useStore(state => state.increase)
  return <button onClick={increase}>one up</button>
}

export default App


================================================
FILE: dev/index.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="theme-color" content="#000000" />
  <title>Solid App</title>
</head>

<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <div id="root"></div>

  <script src="./index.tsx" type="module"></script>
</body>

</html>


================================================
FILE: dev/index.tsx
================================================
import { render } from 'solid-js/web'
import App from './App'

import './styles.css'

render(() => <App />, document.getElementById('root')!)


================================================
FILE: dev/store.ts
================================================
import { createWithSignal } from '../src'

interface BearState {
  bears: number
  increase: () => void
}

export const useStore = createWithSignal<BearState>(set => ({
  bears: 0,
  increase: () => set(state => ({ bears: state.bears + 1 })),
}))


================================================
FILE: dev/styles.css
================================================
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
    'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}


================================================
FILE: dev/tsconfig.json
================================================
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "types": ["vite/client"]
  },
  "exclude": ["node_modules", "dist"]
}


================================================
FILE: dev/vite.config.ts
================================================
import { defineConfig } from 'vite'
import solidPlugin from 'vite-plugin-solid'

export default defineConfig({
  resolve: {
    alias: {
      src: '/src',
    },
  },
  plugins: [
    solidPlugin(),
    {
      name: 'Reaplace env variables',
      transform(code, id) {
        if (id.includes('node_modules')) {
          return code
        }
        return code
          .replace(/process\.env\.SSR/g, 'false')
          .replace(/process\.env\.DEV/g, 'true')
          .replace(/process\.env\.PROD/g, 'false')
          .replace(/process\.env\.NODE_ENV/g, '"development"')
          .replace(/import\.meta\.env\.SSR/g, 'false')
          .replace(/import\.meta\.env\.DEV/g, 'true')
          .replace(/import\.meta\.env\.PROD/g, 'false')
          .replace(/import\.meta\.env\.NODE_ENV/g, '"development"')
      },
    },
  ],
  server: {
    port: 3000,
  },
  build: {
    target: 'esnext',
  },
})


================================================
FILE: env.d.ts
================================================
declare global {
  interface ImportMeta {
    env: {
      NODE_ENV: 'production' | 'development'
      PROD: boolean
      DEV: boolean
    }
  }
  namespace NodeJS {
    interface ProcessEnv {
      NODE_ENV: 'production' | 'development'
      PROD: boolean
      DEV: boolean
    }
  }
}

export {}


================================================
FILE: eslint.config.js
================================================
import antfu from '@antfu/eslint-config'

export default antfu({
  solid: true,
  ignores: ['README.md'],
})


================================================
FILE: package.json
================================================
{
  "name": "solid-zustand",
  "type": "module",
  "version": "2.0.0",
  "packageManager": "pnpm@10.25.0",
  "description": "🐻 State management in Solid using zustand.",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/wobsoriano/solid-zustand.git"
  },
  "keywords": [
    "solid",
    "state",
    "management",
    "store",
    "zustand"
  ],
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    },
    "./store": {
      "types": "./dist/store.d.ts",
      "import": "./dist/store.js"
    }
  },
  "files": [
    "dist"
  ],
  "scripts": {
    "dev": "vite serve dev",
    "build": "tsdown",
    "test": "vitest run",
    "typecheck": "tsc --noEmit",
    "release": "pnpm build && changeset publish",
    "prepublishOnly": "pnpm build",
    "lint": "eslint",
    "lint:fix": "eslint --fix"
  },
  "peerDependencies": {
    "solid-js": "^1.6.0",
    "zustand": "^5.0.0"
  },
  "devDependencies": {
    "@antfu/eslint-config": "^6.5.1",
    "@changesets/cli": "^2.29.8",
    "eslint": "^9.39.1",
    "eslint-plugin-solid": "^0.14.5",
    "jsdom": "^24.1.3",
    "solid-js": "^1.9.10",
    "tsdown": "^0.17.2",
    "typescript": "^5.9.3",
    "vite": "^7.2.7",
    "vite-plugin-solid": "^2.11.10",
    "vitest": "^3.2.4",
    "zustand": "^5.0.9"
  }
}


================================================
FILE: src/index.ts
================================================
import { create } from './signal'
import { create as createStore } from './store'

export { create }

/**
 * @deprecated Use `import { create } from 'solid-zustand'` instead
 */
const createWithSignal = create
export { createWithSignal }

/**
 * @deprecated Use `import { create } from 'solid-zustand/store'` instead
 */
const createWithStore = createStore
export { createWithStore }


================================================
FILE: src/shared.ts
================================================
import type { Accessor } from 'solid-js'
import type { Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla'
import { createStore as createZustandStore } from 'zustand/vanilla'

export type ExtractState<S> = S extends { getState: () => infer T } ? T : never

export type IsFunction<T> = T extends (...args: any[]) => any ? T : never

export type UseBoundStore<S extends StoreApi<unknown>, P extends 'store' | 'signal'> = {
  (): P extends 'store'
    ? ExtractState<S>
    : ExtractState<S> extends IsFunction<ExtractState<S>>
      ? ExtractState<S>
      : Accessor<ExtractState<S>>
  <U>(
    selector: (state: ExtractState<S>) => U,
    equals?: (a: U, b: U) => boolean,
  ): P extends 'store' ? U : U extends IsFunction<U> ? U : Accessor<U>
} & S

export interface Create<P extends 'store' | 'signal'> {
  <T extends object, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
    initializer: StateCreator<T, [], Mos>,
  ): UseBoundStore<Mutate<StoreApi<T>, Mos>, P>
  <T extends object>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(
    initializer: StateCreator<T, [], Mos>,
  ) => UseBoundStore<Mutate<StoreApi<T>, Mos>, P>
  <S extends StoreApi<unknown>>(store: S): UseBoundStore<S, P>
}

export function createFactory<P extends 'store' | 'signal'>(
  useStore: (api: StoreApi<any>, selector?: any, equalityFn?: any) => any,
): Create<P> {
  function createImpl<T extends object>(createState: StateCreator<T, [], []>) {
    const api = typeof createState === 'function' ? createZustandStore(createState) : createState

    const useBoundStore: any = (selector?: any, equalityFn?: any) =>
      useStore(api, selector, equalityFn)

    Object.assign(useBoundStore, api)

    return useBoundStore
  }

  return (<T extends object>(createState: StateCreator<T, [], []> | undefined) =>
    createState ? createImpl(createState) : createImpl) as Create<P>
}


================================================
FILE: src/signal.ts
================================================
import type { Accessor } from 'solid-js'
import type { StoreApi } from 'zustand/vanilla'
import type { ExtractState, IsFunction } from './shared'
import { createSignal, onCleanup } from 'solid-js'
import { createFactory } from './shared'

export function useStore<S extends StoreApi<unknown>>(
  api: S,
): ExtractState<S> extends IsFunction<ExtractState<S>> ? ExtractState<S> : Accessor<ExtractState<S>>

export function useStore<S extends StoreApi<unknown>, U>(
  api: S,
  selector: (state: ExtractState<S>) => U,
  equalityFn?: (a: U, b: U) => boolean,
): U extends IsFunction<U> ? U : Accessor<U>

export function useStore<TState extends object, StateSlice>(
  api: StoreApi<TState>,
  selector: (state: TState) => StateSlice = api.getState as any,
  equalityFn?: (a: StateSlice, b: StateSlice) => boolean,
) {
  const initialValue = selector(api.getState())

  if (typeof initialValue === 'function')
    return initialValue

  const options: Parameters<typeof createSignal>[1] = {}
  if (equalityFn)
    options.equals = equalityFn as any

  const [signal, setSignal] = createSignal(initialValue, options)

  const unsubscribe = api.subscribe((payload) => {
    const nextStateSlice = selector(payload) as any
    setSignal(nextStateSlice)
  })

  onCleanup(() => unsubscribe())

  return signal
}

const create = createFactory<'signal'>(useStore)

export {
  create,
}


================================================
FILE: src/store.ts
================================================
import type { StoreApi } from 'zustand/vanilla'
import type { ExtractState } from './shared'
import { onCleanup } from 'solid-js'
import { createStore, reconcile } from 'solid-js/store'
import { createFactory } from './shared'

export function useStore<S extends StoreApi<unknown>>(api: S): ExtractState<S>

export function useStore<S extends StoreApi<unknown>, U>(
  api: S,
  selector: (state: ExtractState<S>) => U,
  equalityFn?: (a: U, b: U) => boolean,
): U

export function useStore<TState extends object, StateSlice>(
  api: StoreApi<TState>,
  selector: (state: TState) => StateSlice = api.getState as any,
  equalityFn?: (a: StateSlice, b: StateSlice) => boolean,
) {
  const initialValue = selector(api.getState()) as any
  const [state, setState] = createStore(initialValue)

  const listener = (nextState: TState, previousState: TState) => {
    const prevStateSlice = selector(previousState)
    const nextStateSlice = selector(nextState)

    if (equalityFn !== undefined) {
      if (!equalityFn(prevStateSlice, nextStateSlice))
        setState(reconcile(nextStateSlice))
    }
    else {
      setState(reconcile(nextStateSlice))
    }
  }

  const unsubscribe = api.subscribe(listener)
  onCleanup(() => unsubscribe())
  return state
}

const create = createFactory<'store'>(useStore)

export {
  create,
}


================================================
FILE: tests/index.spec.tsx
================================================
import { render } from 'solid-js/web'
import { beforeEach, describe, expect, it } from 'vitest'
import { create } from '../src'
import { create as createWithStore } from '../src/store'

interface BearState {
  bears: number
  bulls: number
  increase: () => void
}

const useSignalStore = create<BearState>(set => ({
  bears: 0,
  bulls: 0,
  increase: () => set(state => ({ bears: state.bears + 1 })),
}))

describe('create', () => {
  beforeEach(() => {
    useSignalStore.setState({ bears: 0, bulls: 0 })
  })

  it('should return default zustand properties', () => {
    expect(typeof useSignalStore.setState).toBe('function')
    expect(typeof useSignalStore.getState).toBe('function')
    expect(typeof useSignalStore.subscribe).toBe('function')
  })

  it('should function correct when rendering in Solid', () => {
    const div = document.createElement('div')
    render(() => {
      const state = useSignalStore()
      const increase = useSignalStore(state => state.increase)
      expect(state().bears).toBe(0)
      increase()
      increase()
      increase()
      return <span>{state().bears}</span>
    }, div)
    expect(div.innerHTML).toBe('<span>3</span>')
  })

  it('should allow multiple state slices', () => {
    const div = document.createElement('div')
    render(() => {
      const state = useSignalStore(state => ({ bears: state.bears, bulls: state.bulls }))
      useSignalStore.setState({ bears: 6, bulls: 9 })
      return (
        <span>
          Bears:
          {state().bears}
          {' '}
          | Bulls:
          {state().bulls}
        </span>
      )
    }, div)
    expect(div.textContent).toBe('Bears:6 | Bulls:9')
  })
})

const useStore = createWithStore<BearState>(set => ({
  bears: 0,
  bulls: 0,
  increase: () => set(state => ({ bears: state.bears + 1 })),
}))

describe('create from /store', () => {
  beforeEach(() => {
    useStore.setState({ bears: 0, bulls: 0 })
  })

  it('should return default zustand properties', () => {
    expect(typeof useStore.setState).toBe('function')
    expect(typeof useStore.getState).toBe('function')
    expect(typeof useStore.subscribe).toBe('function')
  })

  it('should function correct when rendering in Solid', () => {
    const div = document.createElement('div')
    render(() => {
      const state = useStore()
      const increase = useStore(state => state.increase)
      expect(state.bears).toBe(0)
      increase()
      increase()
      increase()
      return <span>{state.bears}</span>
    }, div)
    expect(div.innerHTML).toBe('<span>3</span>')
  })

  it('should allow multiple state slices', () => {
    const div = document.createElement('div')
    render(() => {
      const state = useStore(state => ({ bears: state.bears, bulls: state.bulls }))
      useStore.setState({ bears: 6, bulls: 9 })
      return (
        <span>
          Bears:
          {state.bears}
          {' '}
          | Bulls:
          {state.bulls}
        </span>
      )
    }, div)
    expect(div.textContent).toBe('Bears:6 | Bulls:9')
  })
})

describe('new API - create (signal)', () => {
  const useNewStore = create<BearState>(set => ({
    bears: 0,
    bulls: 0,
    increase: () => set(state => ({ bears: state.bears + 1 })),
  }))

  beforeEach(() => {
    useNewStore.setState({ bears: 0, bulls: 0 })
  })

  it('should work with new create API', () => {
    const div = document.createElement('div')
    render(() => {
      const state = useNewStore()
      const increase = useNewStore(state => state.increase)
      expect(state().bears).toBe(0)
      increase()
      return <span>{state().bears}</span>
    }, div)
    expect(div.innerHTML).toBe('<span>1</span>')
  })
})


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "ES2022",
    "jsx": "preserve",
    "jsxImportSource": "solid-js",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "allowImportingTsExtensions": false,
    "strict": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "declaration": true,
    "declarationMap": true,
    "inlineSources": true,
    "noEmit": false,
    "outDir": "./dist",
    "sourceMap": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "verbatimModuleSyntax": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*", "tests/**/*"],
  "exclude": ["dist", "node_modules", "./dev"]
}


================================================
FILE: tsdown.config.ts
================================================
import { defineConfig } from 'tsdown'
import solid from 'vite-plugin-solid'

export default defineConfig({
  entry: ['src/index.ts', 'src/store.ts'],
  format: 'esm',
  platform: 'browser',
  target: 'es2022',
  plugins: [solid()],
  clean: true,
  external: ['solid-js'],
  dts: {
    build: true,
  },
})


================================================
FILE: vitest.config.ts
================================================
import solid from 'vite-plugin-solid'
import { defineConfig } from 'vitest/config'

export default defineConfig({
  plugins: [solid()],
})
Download .txt
gitextract_tc6bjkld/

├── .changeset/
│   ├── README.md
│   └── config.json
├── .editorconfig
├── .github/
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── dev/
│   ├── App.tsx
│   ├── index.html
│   ├── index.tsx
│   ├── store.ts
│   ├── styles.css
│   ├── tsconfig.json
│   └── vite.config.ts
├── env.d.ts
├── eslint.config.js
├── package.json
├── src/
│   ├── index.ts
│   ├── shared.ts
│   ├── signal.ts
│   └── store.ts
├── tests/
│   └── index.spec.tsx
├── tsconfig.json
├── tsdown.config.ts
└── vitest.config.ts
Download .txt
SYMBOL INDEX (14 symbols across 8 files)

FILE: dev/App.tsx
  function BearCounter (line 13) | function BearCounter() {
  function Controls (line 24) | function Controls() {

FILE: dev/store.ts
  type BearState (line 3) | interface BearState {

FILE: dev/vite.config.ts
  method transform (line 14) | transform(code, id) {

FILE: env.d.ts
  type ImportMeta (line 2) | interface ImportMeta {
  type ProcessEnv (line 10) | interface ProcessEnv {

FILE: src/shared.ts
  type ExtractState (line 5) | type ExtractState<S> = S extends { getState: () => infer T } ? T : never
  type IsFunction (line 7) | type IsFunction<T> = T extends (...args: any[]) => any ? T : never
  type UseBoundStore (line 9) | type UseBoundStore<S extends StoreApi<unknown>, P extends 'store' | 'sig...
  type Create (line 21) | interface Create<P extends 'store' | 'signal'> {
  function createFactory (line 31) | function createFactory<P extends 'store' | 'signal'>(

FILE: src/signal.ts
  function useStore (line 17) | function useStore<TState extends object, StateSlice>(

FILE: src/store.ts
  function useStore (line 15) | function useStore<TState extends object, StateSlice>(

FILE: tests/index.spec.tsx
  type BearState (line 6) | interface BearState {
Condensed preview — 27 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (27K chars).
[
  {
    "path": ".changeset/README.md",
    "chars": 510,
    "preview": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that wo"
  },
  {
    "path": ".changeset/config.json",
    "chars": 271,
    "preview": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@3.1.2/schema.json\",\n  \"changelog\": \"@changesets/cli/changelog\",\n  \""
  },
  {
    "path": ".editorconfig",
    "chars": 166,
    "preview": "# editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1417,
    "preview": "name: CI\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - main\n\njobs:\n  test:\n    runs-on: "
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 1363,
    "preview": "name: Release\n\non:\n  push:\n    branches:\n      - main\n\nconcurrency: ${{ github.workflow }}-${{ github.ref }}\n\njobs:\n  re"
  },
  {
    "path": ".gitignore",
    "chars": 43,
    "preview": "node_modules\n.DS_Store\ndist\n*.local\n.vscode"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 3086,
    "preview": "# Changelog\n\n## 2.0.0\n\n### Major Changes\n\n- 9d58ece: ## Breaking Changes\n\n  ### New Unified API\n\n  The library now uses "
  },
  {
    "path": "LICENSE",
    "chars": 1080,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2022 Robert Soriano\n\nPermission is hereby granted, free of charge, to any person ob"
  },
  {
    "path": "README.md",
    "chars": 2696,
    "preview": "<p>\n  <img width=\"100%\" src=\"https://assets.solidjs.com/banner?type=solid-zustand&background=tiles&project=%20\" alt=\"sol"
  },
  {
    "path": "dev/App.tsx",
    "chars": 497,
    "preview": "import type { Component } from 'solid-js'\nimport { useStore } from './store'\n\nconst App: Component = () => {\n  return (\n"
  },
  {
    "path": "dev/index.html",
    "chars": 396,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width,"
  },
  {
    "path": "dev/index.tsx",
    "chars": 142,
    "preview": "import { render } from 'solid-js/web'\nimport App from './App'\n\nimport './styles.css'\n\nrender(() => <App />, document.get"
  },
  {
    "path": "dev/store.ts",
    "chars": 247,
    "preview": "import { createWithSignal } from '../src'\n\ninterface BearState {\n  bears: number\n  increase: () => void\n}\n\nexport const "
  },
  {
    "path": "dev/styles.css",
    "chars": 358,
    "preview": "body {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n    'Can"
  },
  {
    "path": "dev/tsconfig.json",
    "chars": 132,
    "preview": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"vite/client\"]\n  },\n  \"exclude\": [\"node_modules\""
  },
  {
    "path": "dev/vite.config.ts",
    "chars": 908,
    "preview": "import { defineConfig } from 'vite'\nimport solidPlugin from 'vite-plugin-solid'\n\nexport default defineConfig({\n  resolve"
  },
  {
    "path": "env.d.ts",
    "chars": 302,
    "preview": "declare global {\n  interface ImportMeta {\n    env: {\n      NODE_ENV: 'production' | 'development'\n      PROD: boolean\n  "
  },
  {
    "path": "eslint.config.js",
    "chars": 109,
    "preview": "import antfu from '@antfu/eslint-config'\n\nexport default antfu({\n  solid: true,\n  ignores: ['README.md'],\n})\n"
  },
  {
    "path": "package.json",
    "chars": 1339,
    "preview": "{\n  \"name\": \"solid-zustand\",\n  \"type\": \"module\",\n  \"version\": \"2.0.0\",\n  \"packageManager\": \"pnpm@10.25.0\",\n  \"descriptio"
  },
  {
    "path": "src/index.ts",
    "chars": 384,
    "preview": "import { create } from './signal'\nimport { create as createStore } from './store'\n\nexport { create }\n\n/**\n * @deprecated"
  },
  {
    "path": "src/shared.ts",
    "chars": 1905,
    "preview": "import type { Accessor } from 'solid-js'\nimport type { Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zu"
  },
  {
    "path": "src/signal.ts",
    "chars": 1377,
    "preview": "import type { Accessor } from 'solid-js'\nimport type { StoreApi } from 'zustand/vanilla'\nimport type { ExtractState, IsF"
  },
  {
    "path": "src/store.ts",
    "chars": 1326,
    "preview": "import type { StoreApi } from 'zustand/vanilla'\nimport type { ExtractState } from './shared'\nimport { onCleanup } from '"
  },
  {
    "path": "tests/index.spec.tsx",
    "chars": 3687,
    "preview": "import { render } from 'solid-js/web'\nimport { beforeEach, describe, expect, it } from 'vitest'\nimport { create } from '"
  },
  {
    "path": "tsconfig.json",
    "chars": 806,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"solid-js\",\n    \"lib\": [\""
  },
  {
    "path": "tsdown.config.ts",
    "chars": 307,
    "preview": "import { defineConfig } from 'tsdown'\nimport solid from 'vite-plugin-solid'\n\nexport default defineConfig({\n  entry: ['sr"
  },
  {
    "path": "vitest.config.ts",
    "chars": 139,
    "preview": "import solid from 'vite-plugin-solid'\nimport { defineConfig } from 'vitest/config'\n\nexport default defineConfig({\n  plug"
  }
]

About this extraction

This page contains the full source code of the wobsoriano/solid-zustand GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 27 files (24.4 KB), approximately 7.6k tokens, and a symbol index with 14 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!