Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/lit/simple/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": []
}
27 changes: 27 additions & 0 deletions examples/lit/simple/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

pnpm-lock.yaml
yarn.lock
package-lock.json

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
6 changes: 6 additions & 0 deletions examples/lit/simple/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Example

To run this example:

- `npm install`
- `npm run dev`
16 changes: 16 additions & 0 deletions examples/lit/simple/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/emblem-light.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />

<title>TanStack Query Lit Simple Example App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.ts"></script>
</body>
</html>
19 changes: 19 additions & 0 deletions examples/lit/simple/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@tanstack/query-example-lit-simple",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@tanstack/query-core": "workspace:*",
"@tanstack/lit-query": "workspace:*",
"lit": "3.1.4"
},
"devDependencies": {
"typescript": "5.3.3",
"vite": "^5.2.11"
}
}
13 changes: 13 additions & 0 deletions examples/lit/simple/public/emblem-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 47 additions & 0 deletions examples/lit/simple/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { QueryClient } from '@tanstack/query-core'
import { LitElement, html, render } from 'lit'
import { QueryController, setQueryClient } from '@tanstack/lit-query'
import { customElement } from 'lit/decorators.js'

const queryClient = new QueryClient()
setQueryClient(queryClient)

export default function App() {
return html` <example-app></example-app> `
}

@customElement('example-app')
export class ExampleAppElement extends LitElement {
private todoQuery = new QueryController(this, () => ({
queryKey: ['repoData'],
queryFn: async () => {
const response = await fetch(
'https://api.github.com/repos/TanStack/query',
)

return await response.json()
},
}))

render() {
const { isPending, error, data, isFetching } = this.todoQuery.result

if (isPending) return 'Loading...'

if (error) return 'An error has occurred: ' + error.message

return html`
<div>
<h1>${data.full_name}</h1>
<p>${data.description}</p>
<strong>👀 ${data.subscribers_count}</strong>${' '}
<strong>✨ ${data.stargazers_count}</strong>${' '}
<strong>🍴 ${data.forks_count}</strong>
<div>${isFetching ? 'Updating...' : ''}</div>
</div>
`
}
}

const rootElement = document.getElementById('root') as HTMLElement
render(App(), rootElement)
26 changes: 26 additions & 0 deletions examples/lit/simple/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "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,

/* Lit */
"useDefineForClassFields": false,
"experimentalDecorators": true
},
"include": ["src", "eslint.config.js"]
}
5 changes: 5 additions & 0 deletions examples/lit/simple/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from 'vite'

export default defineConfig({
plugins: [],
})
30 changes: 22 additions & 8 deletions packages/lit-query/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,35 @@
"url": "https://github.com/sponsors/tannerlinsley"
},
"scripts": {
"clean": "rimraf ./dist && rimraf ./coverage",
"clean": "rimraf ./build && rimraf ./coverage",
"test:eslint": "eslint ./src",
"test:lib": "vitest",
"test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"",
"test:types:ts49": "node ../../node_modules/typescript49/lib/tsc.js -p tsconfig.legacy.json",
"test:types:ts50": "node ../../node_modules/typescript50/lib/tsc.js -p tsconfig.legacy.json",
"test:types:ts51": "node ../../node_modules/typescript51/lib/tsc.js -p tsconfig.legacy.json",
"test:types:ts52": "node ../../node_modules/typescript52/lib/tsc.js -p tsconfig.legacy.json",
"test:types:ts53": "tsc",
"test:lib": "vitest --retry=3",
"test:lib:dev": "pnpm run test:lib --watch",
"test:build": "publint --strict && attw --pack",
"build": "svelte-package --input ./src --output ./dist"
"build": "tsup",
"build:watch": "tsup --watch"
},
"type": "module",
"types": "dist/index.d.ts",
"module": "dist/index.js",
"main": "./build/index.cjs",
"module": "./build/index.js",
"types": "./build/index.d.ts",
"browser": {},
"exports": {
".": {
"types": "./dist/index.d.ts",
"svelte": "./dist/index.js",
"import": "./dist/index.js"
"import": {
"types": "./build/modern/index.d.ts",
"default": "./build/modern/index.js"
},
"require": {
"types": "./build/modern/index.d.cts",
"default": "./build/modern/index.cjs"
}
},
"./package.json": "./package.json"
},
Expand Down
118 changes: 118 additions & 0 deletions packages/lit-query/src/MutationController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { MutationObserver } from '@tanstack/query-core'
import { getQueryClient } from './queryClientHelper'
import type {
DefaultError,
MutationObserverOptions,
MutationObserverResult,
} from '@tanstack/query-core'
import type { ReactiveController, ReactiveControllerHost } from 'lit'

export type { MutationObserverOptions }

// TODO: Proper JSDoc descriptions
/**
* MutationController is a class that integrates a mutation-based data fetching system
* into a Lit component as a ReactiveController.
*
* @template TData - ~~The data type returned by the mutation function.~~
* @template TError - ~~The error type for mutation errors.~~
* @template TVariables - ~~The data variables to be used in the component.~~
* @template TContext - ~~The context returned by the mutation (may differ from TData).~~
*/
export class MutationController<
TData = unknown,
TError = DefaultError,
TVariables = void,
TContext = unknown,
> implements ReactiveController
{
/**
* The result of the mutation observer, containing data and error information.
*/
result: MutationObserverResult<TData, TError, TVariables, TContext>

/**
* The internal mutation observer responsible for managing the mutation.
*/
private mutationObserver: MutationObserver<
TData,
TError,
TVariables,
TContext
>

/**
* Creates a new MutationController instance.
*
* @param host - The host component to which this controller is added.
* @param options - A function that provides MutationObserverOptions for the mutation.
* @link [MutationObserverOptions API Docs](). //TODO: Add the correct doc
*/
constructor(
private host: ReactiveControllerHost,
private options: () => MutationObserverOptions<
TData,
TError,
TVariables,
TContext
>,
) {
this.host.addController(this)

// Initialize the MutationObserver with default options.
const mutationClient = getQueryClient()
const defaultOption = this.getDefaultOptions()
this.mutationObserver = new MutationObserver(mutationClient, defaultOption)

// FIXME: does not exist
// Get an optimistic result based on the default options.
this.result = this.mutationObserver.getCurrentResult()
}

/**
* Unsubscribe function to remove the observer when the component disconnects.
*/
private unsubscribe() {
// We set the unsubscribe function when hostConnected is invoked
}

/**
* Invoked when the host component updates.
* Updates the mutation observer options with default options.
*/
hostUpdate() {
const defaultOption = this.getDefaultOptions()
this.mutationObserver.setOptions(defaultOption)
}

/**
* Invoked when the host component is connected.
* Subscribes to the mutation observer and updates the result.
*/
hostConnected() {
this.unsubscribe = this.mutationObserver.subscribe((result) => {
this.result = result
this.host.requestUpdate()
})
}

/**
* Invoked when the host component is disconnected.
* Unsubscribes from the mutation observer to clean up.
*/
hostDisconnected() {
this.unsubscribe()
}

/**
* Retrieves the default mutation options by combining the user-provided options
* with the default options from the mutation client.
*
* @returns The default mutation options.
*/
private getDefaultOptions() {
const mutationClient = getQueryClient()
const defaultOption = mutationClient.defaultMutationOptions(this.options())
return defaultOption
}
}
3 changes: 2 additions & 1 deletion packages/lit-query/src/QueryController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { QueryObserver } from '@tanstack/query-core'
import { getQueryClient } from './queryClientHelper'
import type {
DefaultError,
QueryKey,
QueryObserverOptions,
QueryObserverResult,
Expand All @@ -21,7 +22,7 @@ export type { QueryObserverOptions }
*/
export class QueryController<
TQueryFnData = unknown,
TError = unknown,
TError = DefaultError,
TData = TQueryFnData,
TQueryData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
Expand Down
Loading