@tanstack/lit-query 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +125 -43
  3. package/dist/QueryClientProvider.d.ts +85 -0
  4. package/dist/QueryClientProvider.d.ts.map +1 -0
  5. package/dist/QueryClientProvider.js +137 -0
  6. package/dist/QueryClientProvider.js.map +1 -0
  7. package/dist/accessor.d.ts +32 -0
  8. package/dist/accessor.d.ts.map +1 -0
  9. package/dist/accessor.js +12 -0
  10. package/dist/accessor.js.map +1 -0
  11. package/dist/context.d.ts +59 -0
  12. package/dist/context.d.ts.map +1 -0
  13. package/dist/context.js +100 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/controllers/BaseController.d.ts +38 -0
  16. package/dist/controllers/BaseController.d.ts.map +1 -0
  17. package/dist/controllers/BaseController.js +204 -0
  18. package/dist/controllers/BaseController.js.map +1 -0
  19. package/dist/createInfiniteQueryController.d.ts +76 -0
  20. package/dist/createInfiniteQueryController.d.ts.map +1 -0
  21. package/dist/createInfiniteQueryController.js +221 -0
  22. package/dist/createInfiniteQueryController.js.map +1 -0
  23. package/dist/createMutationController.d.ts +79 -0
  24. package/dist/createMutationController.d.ts.map +1 -0
  25. package/dist/createMutationController.js +193 -0
  26. package/dist/createMutationController.js.map +1 -0
  27. package/dist/createQueriesController.d.ts +145 -0
  28. package/dist/createQueriesController.d.ts.map +1 -0
  29. package/dist/createQueriesController.js +302 -0
  30. package/dist/createQueriesController.js.map +1 -0
  31. package/dist/createQueryController.d.ts +67 -0
  32. package/dist/createQueryController.d.ts.map +1 -0
  33. package/dist/createQueryController.js +211 -0
  34. package/dist/createQueryController.js.map +1 -0
  35. package/dist/index.d.ts +24 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +15 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/infiniteQueryOptions.d.ts +21 -0
  40. package/dist/infiniteQueryOptions.d.ts.map +1 -0
  41. package/dist/infiniteQueryOptions.js +22 -0
  42. package/dist/infiniteQueryOptions.js.map +1 -0
  43. package/dist/mutationOptions.d.ts +19 -0
  44. package/dist/mutationOptions.d.ts.map +1 -0
  45. package/dist/mutationOptions.js +20 -0
  46. package/dist/mutationOptions.js.map +1 -0
  47. package/dist/queryOptions.d.ts +62 -0
  48. package/dist/queryOptions.d.ts.map +1 -0
  49. package/dist/queryOptions.js +4 -0
  50. package/dist/queryOptions.js.map +1 -0
  51. package/dist/types.d.ts +31 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +2 -0
  54. package/dist/types.js.map +1 -0
  55. package/dist/useIsFetching.d.ts +45 -0
  56. package/dist/useIsFetching.d.ts.map +1 -0
  57. package/dist/useIsFetching.js +116 -0
  58. package/dist/useIsFetching.js.map +1 -0
  59. package/dist/useIsMutating.d.ts +45 -0
  60. package/dist/useIsMutating.d.ts.map +1 -0
  61. package/dist/useIsMutating.js +116 -0
  62. package/dist/useIsMutating.js.map +1 -0
  63. package/dist/useMutationState.d.ts +57 -0
  64. package/dist/useMutationState.d.ts.map +1 -0
  65. package/dist/useMutationState.js +132 -0
  66. package/dist/useMutationState.js.map +1 -0
  67. package/dist-cjs/QueryClientProvider.d.cts +84 -0
  68. package/dist-cjs/QueryClientProvider.js +141 -0
  69. package/dist-cjs/QueryClientProvider.js.map +1 -0
  70. package/dist-cjs/accessor.d.cts +31 -0
  71. package/dist-cjs/accessor.js +16 -0
  72. package/dist-cjs/accessor.js.map +1 -0
  73. package/dist-cjs/context.d.cts +58 -0
  74. package/dist-cjs/context.js +109 -0
  75. package/dist-cjs/context.js.map +1 -0
  76. package/dist-cjs/controllers/BaseController.d.cts +37 -0
  77. package/dist-cjs/controllers/BaseController.js +208 -0
  78. package/dist-cjs/controllers/BaseController.js.map +1 -0
  79. package/dist-cjs/createInfiniteQueryController.d.cts +75 -0
  80. package/dist-cjs/createInfiniteQueryController.js +224 -0
  81. package/dist-cjs/createInfiniteQueryController.js.map +1 -0
  82. package/dist-cjs/createMutationController.d.cts +78 -0
  83. package/dist-cjs/createMutationController.js +196 -0
  84. package/dist-cjs/createMutationController.js.map +1 -0
  85. package/dist-cjs/createQueriesController.d.cts +144 -0
  86. package/dist-cjs/createQueriesController.js +305 -0
  87. package/dist-cjs/createQueriesController.js.map +1 -0
  88. package/dist-cjs/createQueryController.d.cts +66 -0
  89. package/dist-cjs/createQueryController.js +214 -0
  90. package/dist-cjs/createQueryController.js.map +1 -0
  91. package/dist-cjs/index.d.cts +23 -0
  92. package/dist-cjs/index.js +49 -0
  93. package/dist-cjs/index.js.map +1 -0
  94. package/dist-cjs/infiniteQueryOptions.d.cts +20 -0
  95. package/dist-cjs/infiniteQueryOptions.js +25 -0
  96. package/dist-cjs/infiniteQueryOptions.js.map +1 -0
  97. package/dist-cjs/mutationOptions.d.cts +18 -0
  98. package/dist-cjs/mutationOptions.js +23 -0
  99. package/dist-cjs/mutationOptions.js.map +1 -0
  100. package/dist-cjs/package.json +3 -0
  101. package/dist-cjs/queryOptions.d.cts +61 -0
  102. package/dist-cjs/queryOptions.js +7 -0
  103. package/dist-cjs/queryOptions.js.map +1 -0
  104. package/dist-cjs/types.d.cts +30 -0
  105. package/dist-cjs/types.js +3 -0
  106. package/dist-cjs/types.js.map +1 -0
  107. package/dist-cjs/useIsFetching.d.cts +44 -0
  108. package/dist-cjs/useIsFetching.js +119 -0
  109. package/dist-cjs/useIsFetching.js.map +1 -0
  110. package/dist-cjs/useIsMutating.d.cts +44 -0
  111. package/dist-cjs/useIsMutating.js +119 -0
  112. package/dist-cjs/useIsMutating.js.map +1 -0
  113. package/dist-cjs/useMutationState.d.cts +56 -0
  114. package/dist-cjs/useMutationState.js +135 -0
  115. package/dist-cjs/useMutationState.js.map +1 -0
  116. package/package.json +73 -8
  117. package/src/QueryClientProvider.ts +174 -0
  118. package/src/accessor.ts +43 -0
  119. package/src/context.ts +120 -0
  120. package/src/controllers/BaseController.ts +284 -0
  121. package/src/createInfiniteQueryController.ts +394 -0
  122. package/src/createMutationController.ts +361 -0
  123. package/src/createQueriesController.ts +633 -0
  124. package/src/createQueryController.ts +342 -0
  125. package/src/index.ts +72 -0
  126. package/src/infiniteQueryOptions.ts +48 -0
  127. package/src/mutationOptions.ts +31 -0
  128. package/src/queryOptions.ts +143 -0
  129. package/src/types.ts +77 -0
  130. package/src/useIsFetching.ts +159 -0
  131. package/src/useIsMutating.ts +159 -0
  132. package/src/useMutationState.ts +201 -0
@@ -0,0 +1,159 @@
1
+ import type { QueryClient, QueryFilters } from '@tanstack/query-core'
2
+ import type { ReactiveControllerHost } from 'lit'
3
+ import {
4
+ createValueAccessor,
5
+ readAccessor,
6
+ type Accessor,
7
+ type ValueAccessor,
8
+ } from './accessor.js'
9
+ import { BaseController } from './controllers/BaseController.js'
10
+
11
+ /**
12
+ * Accessor returned by `useIsFetching`.
13
+ *
14
+ * Call the accessor or read its `current` property to get the number of
15
+ * currently fetching queries that match the filters.
16
+ */
17
+ export type IsFetchingAccessor = ValueAccessor<number> & { destroy: () => void }
18
+
19
+ class IsFetchingController extends BaseController<number> {
20
+ private queryClient: QueryClient | undefined
21
+ private unsubscribe: (() => void) | undefined
22
+
23
+ constructor(
24
+ host: ReactiveControllerHost,
25
+ private readonly filters: Accessor<QueryFilters> = {},
26
+ queryClient?: QueryClient,
27
+ ) {
28
+ super(host, 0, queryClient)
29
+
30
+ if (!queryClient) {
31
+ return
32
+ }
33
+
34
+ this.queryClient = queryClient
35
+ this.result = this.computeValue()
36
+ }
37
+
38
+ protected onConnected(): void {
39
+ if (!this.syncClient()) {
40
+ this.setResult(0)
41
+ return
42
+ }
43
+
44
+ this.subscribe()
45
+ this.setResult(this.computeValue())
46
+ }
47
+
48
+ protected onDisconnected(): void {
49
+ this.unsubscribe?.()
50
+ this.unsubscribe = undefined
51
+ this.syncClient()
52
+ }
53
+
54
+ protected onHostUpdate(): void {
55
+ if (typeof this.filters !== 'function') {
56
+ return
57
+ }
58
+
59
+ this.setResult(this.syncClient() ? this.computeValue() : 0)
60
+ }
61
+
62
+ protected onQueryClientChanged(): void {
63
+ if (!this.syncClient()) {
64
+ this.setResult(0)
65
+ return
66
+ }
67
+
68
+ if (this.connectedState) {
69
+ this.subscribe()
70
+ this.setResult(this.computeValue())
71
+ }
72
+ }
73
+
74
+ private syncClient(): boolean {
75
+ const nextClient = this.tryGetQueryClient()
76
+ if (!nextClient) {
77
+ this.unsubscribe?.()
78
+ this.unsubscribe = undefined
79
+ this.queryClient = undefined
80
+ return false
81
+ }
82
+
83
+ if (nextClient === this.queryClient) {
84
+ return true
85
+ }
86
+
87
+ this.unsubscribe?.()
88
+ this.unsubscribe = undefined
89
+ this.queryClient = nextClient
90
+ return true
91
+ }
92
+
93
+ private subscribe(): void {
94
+ if (!this.queryClient) {
95
+ return
96
+ }
97
+
98
+ if (this.unsubscribe) {
99
+ return
100
+ }
101
+
102
+ this.unsubscribe = this.queryClient.getQueryCache().subscribe(() => {
103
+ this.setResult(this.computeValue())
104
+ })
105
+ }
106
+
107
+ private computeValue(): number {
108
+ if (!this.queryClient) {
109
+ return 0
110
+ }
111
+
112
+ return this.queryClient.isFetching(readAccessor(this.filters))
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Creates a Lit reactive controller that tracks how many matching queries are
118
+ * currently fetching.
119
+ *
120
+ * When `filters` is a function, it is re-read during host updates so the count
121
+ * can follow reactive host state. If `queryClient` is omitted, the controller
122
+ * resolves the client from the nearest connected `QueryClientProvider`.
123
+ *
124
+ * @param host - The Lit reactive controller host that owns the cache
125
+ * subscription.
126
+ * @param filters - Query filters, or a getter that returns query filters.
127
+ * @param queryClient - Optional explicit query client. Provide this for
128
+ * controllers that should not resolve a client from Lit context.
129
+ * @returns An accessor for the current number of matching fetching queries.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * import { LitElement, html } from 'lit'
134
+ * import { useIsFetching } from '@tanstack/lit-query'
135
+ *
136
+ * class TodosStatus extends LitElement {
137
+ * private readonly todosFetching = useIsFetching(this, {
138
+ * queryKey: ['todos'],
139
+ * })
140
+ *
141
+ * render() {
142
+ * return html`<span>${this.todosFetching()} active todo fetches</span>`
143
+ * }
144
+ * }
145
+ * ```
146
+ */
147
+ export function useIsFetching(
148
+ host: ReactiveControllerHost,
149
+ filters: Accessor<QueryFilters> = {},
150
+ queryClient?: QueryClient,
151
+ ): IsFetchingAccessor {
152
+ const controller = new IsFetchingController(host, filters, queryClient)
153
+ return Object.assign(
154
+ createValueAccessor(() => controller.current),
155
+ {
156
+ destroy: () => controller.destroy(),
157
+ },
158
+ )
159
+ }
@@ -0,0 +1,159 @@
1
+ import type { MutationFilters, QueryClient } from '@tanstack/query-core'
2
+ import type { ReactiveControllerHost } from 'lit'
3
+ import {
4
+ createValueAccessor,
5
+ readAccessor,
6
+ type Accessor,
7
+ type ValueAccessor,
8
+ } from './accessor.js'
9
+ import { BaseController } from './controllers/BaseController.js'
10
+
11
+ /**
12
+ * Accessor returned by `useIsMutating`.
13
+ *
14
+ * Call the accessor or read its `current` property to get the number of
15
+ * currently pending mutations that match the filters.
16
+ */
17
+ export type IsMutatingAccessor = ValueAccessor<number> & { destroy: () => void }
18
+
19
+ class IsMutatingController extends BaseController<number> {
20
+ private queryClient: QueryClient | undefined
21
+ private unsubscribe: (() => void) | undefined
22
+
23
+ constructor(
24
+ host: ReactiveControllerHost,
25
+ private readonly filters: Accessor<MutationFilters> = {},
26
+ queryClient?: QueryClient,
27
+ ) {
28
+ super(host, 0, queryClient)
29
+
30
+ if (!queryClient) {
31
+ return
32
+ }
33
+
34
+ this.queryClient = queryClient
35
+ this.result = this.computeValue()
36
+ }
37
+
38
+ protected onConnected(): void {
39
+ if (!this.syncClient()) {
40
+ this.setResult(0)
41
+ return
42
+ }
43
+
44
+ this.subscribe()
45
+ this.setResult(this.computeValue())
46
+ }
47
+
48
+ protected onDisconnected(): void {
49
+ this.unsubscribe?.()
50
+ this.unsubscribe = undefined
51
+ this.syncClient()
52
+ }
53
+
54
+ protected onHostUpdate(): void {
55
+ if (typeof this.filters !== 'function') {
56
+ return
57
+ }
58
+
59
+ this.setResult(this.syncClient() ? this.computeValue() : 0)
60
+ }
61
+
62
+ protected onQueryClientChanged(): void {
63
+ if (!this.syncClient()) {
64
+ this.setResult(0)
65
+ return
66
+ }
67
+
68
+ if (this.connectedState) {
69
+ this.subscribe()
70
+ this.setResult(this.computeValue())
71
+ }
72
+ }
73
+
74
+ private syncClient(): boolean {
75
+ const nextClient = this.tryGetQueryClient()
76
+ if (!nextClient) {
77
+ this.unsubscribe?.()
78
+ this.unsubscribe = undefined
79
+ this.queryClient = undefined
80
+ return false
81
+ }
82
+
83
+ if (nextClient === this.queryClient) {
84
+ return true
85
+ }
86
+
87
+ this.unsubscribe?.()
88
+ this.unsubscribe = undefined
89
+ this.queryClient = nextClient
90
+ return true
91
+ }
92
+
93
+ private subscribe(): void {
94
+ if (!this.queryClient) {
95
+ return
96
+ }
97
+
98
+ if (this.unsubscribe) {
99
+ return
100
+ }
101
+
102
+ this.unsubscribe = this.queryClient.getMutationCache().subscribe(() => {
103
+ this.setResult(this.computeValue())
104
+ })
105
+ }
106
+
107
+ private computeValue(): number {
108
+ if (!this.queryClient) {
109
+ return 0
110
+ }
111
+
112
+ return this.queryClient.isMutating(readAccessor(this.filters))
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Creates a Lit reactive controller that tracks how many matching mutations are
118
+ * currently pending.
119
+ *
120
+ * When `filters` is a function, it is re-read during host updates so the count
121
+ * can follow reactive host state. If `queryClient` is omitted, the controller
122
+ * resolves the client from the nearest connected `QueryClientProvider`.
123
+ *
124
+ * @param host - The Lit reactive controller host that owns the cache
125
+ * subscription.
126
+ * @param filters - Mutation filters, or a getter that returns mutation filters.
127
+ * @param queryClient - Optional explicit query client. Provide this for
128
+ * controllers that should not resolve a client from Lit context.
129
+ * @returns An accessor for the current number of matching pending mutations.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * import { LitElement, html } from 'lit'
134
+ * import { useIsMutating } from '@tanstack/lit-query'
135
+ *
136
+ * class MutationStatus extends LitElement {
137
+ * private readonly savesPending = useIsMutating(this, {
138
+ * mutationKey: ['save-project'],
139
+ * })
140
+ *
141
+ * render() {
142
+ * return html`<span>${this.savesPending()} saves pending</span>`
143
+ * }
144
+ * }
145
+ * ```
146
+ */
147
+ export function useIsMutating(
148
+ host: ReactiveControllerHost,
149
+ filters: Accessor<MutationFilters> = {},
150
+ queryClient?: QueryClient,
151
+ ): IsMutatingAccessor {
152
+ const controller = new IsMutatingController(host, filters, queryClient)
153
+ return Object.assign(
154
+ createValueAccessor(() => controller.current),
155
+ {
156
+ destroy: () => controller.destroy(),
157
+ },
158
+ )
159
+ }
@@ -0,0 +1,201 @@
1
+ import type {
2
+ Mutation,
3
+ MutationFilters,
4
+ MutationState,
5
+ QueryClient,
6
+ } from '@tanstack/query-core'
7
+ import type { ReactiveControllerHost } from 'lit'
8
+ import {
9
+ createValueAccessor,
10
+ readAccessor,
11
+ type Accessor,
12
+ type ValueAccessor,
13
+ } from './accessor.js'
14
+ import { BaseController } from './controllers/BaseController.js'
15
+
16
+ /**
17
+ * Options accepted by `useMutationState`.
18
+ */
19
+ export type MutationStateOptions<TResult> = {
20
+ /** Filters used to select mutations from the mutation cache. */
21
+ filters?: Accessor<MutationFilters>
22
+ /** Maps each matching mutation to the value returned by the accessor. */
23
+ select?: (mutation: Mutation) => TResult
24
+ }
25
+
26
+ /**
27
+ * Accessor returned by `useMutationState`.
28
+ *
29
+ * Call the accessor or read its `current` property to get the selected state for
30
+ * matching mutations.
31
+ */
32
+ export type MutationStateAccessor<TResult> = ValueAccessor<TResult[]> & {
33
+ /** Removes the controller from its Lit host and unsubscribes observers. */
34
+ destroy: () => void
35
+ }
36
+
37
+ class MutationStateController<TResult> extends BaseController<TResult[]> {
38
+ private queryClient: QueryClient | undefined
39
+ private unsubscribe: (() => void) | undefined
40
+
41
+ constructor(
42
+ host: ReactiveControllerHost,
43
+ private readonly options: MutationStateOptions<TResult>,
44
+ queryClient?: QueryClient,
45
+ ) {
46
+ super(host, [], queryClient)
47
+
48
+ if (!queryClient) {
49
+ return
50
+ }
51
+
52
+ this.queryClient = queryClient
53
+ this.result = this.computeState()
54
+ }
55
+
56
+ protected onConnected(): void {
57
+ if (!this.syncClient()) {
58
+ this.setResult([])
59
+ return
60
+ }
61
+
62
+ this.subscribe()
63
+ this.setResult(this.computeState())
64
+ }
65
+
66
+ protected onDisconnected(): void {
67
+ this.unsubscribe?.()
68
+ this.unsubscribe = undefined
69
+ this.syncClient()
70
+ }
71
+
72
+ protected onHostUpdate(): void {
73
+ if (!this.shouldRefreshOnHostUpdate()) {
74
+ return
75
+ }
76
+
77
+ this.setResult(this.syncClient() ? this.computeState() : [])
78
+ }
79
+
80
+ protected onQueryClientChanged(): void {
81
+ if (!this.syncClient()) {
82
+ this.setResult([])
83
+ return
84
+ }
85
+
86
+ if (this.connectedState) {
87
+ this.subscribe()
88
+ this.setResult(this.computeState())
89
+ }
90
+ }
91
+
92
+ private syncClient(): boolean {
93
+ const nextClient = this.tryGetQueryClient()
94
+ if (!nextClient) {
95
+ this.unsubscribe?.()
96
+ this.unsubscribe = undefined
97
+ this.queryClient = undefined
98
+ return false
99
+ }
100
+
101
+ if (nextClient === this.queryClient) {
102
+ return true
103
+ }
104
+
105
+ this.unsubscribe?.()
106
+ this.unsubscribe = undefined
107
+ this.queryClient = nextClient
108
+ return true
109
+ }
110
+
111
+ private subscribe(): void {
112
+ if (!this.queryClient) {
113
+ return
114
+ }
115
+
116
+ if (this.unsubscribe) {
117
+ return
118
+ }
119
+
120
+ this.unsubscribe = this.queryClient.getMutationCache().subscribe(() => {
121
+ this.setResult(this.computeState())
122
+ })
123
+ }
124
+
125
+ private shouldRefreshOnHostUpdate(): boolean {
126
+ return (
127
+ typeof this.options.filters === 'function' ||
128
+ typeof this.options.select === 'function'
129
+ )
130
+ }
131
+
132
+ private computeState(): TResult[] {
133
+ if (!this.queryClient) {
134
+ return []
135
+ }
136
+
137
+ const filters = this.options.filters
138
+ ? readAccessor(this.options.filters)
139
+ : undefined
140
+
141
+ const select = this.options.select
142
+ const mutations = this.queryClient.getMutationCache().findAll(filters)
143
+
144
+ return mutations.map((mutation) => {
145
+ if (select) {
146
+ return select(mutation)
147
+ }
148
+
149
+ return mutation.state as TResult
150
+ })
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Creates a Lit reactive controller that selects state from matching mutations
156
+ * in the mutation cache.
157
+ *
158
+ * When `options.filters` is a function, it is re-read during host updates so
159
+ * the selection can follow reactive host state. If `queryClient` is omitted,
160
+ * the controller resolves the client from the nearest connected
161
+ * `QueryClientProvider`.
162
+ *
163
+ * @param host - The Lit reactive controller host that owns the mutation cache
164
+ * subscription.
165
+ * @param options - Mutation state filters and optional selector.
166
+ * @param queryClient - Optional explicit query client. Provide this for
167
+ * controllers that should not resolve a client from Lit context.
168
+ * @returns An accessor for the selected mutation state array.
169
+ *
170
+ * @example
171
+ * ```ts
172
+ * import { LitElement, html } from 'lit'
173
+ * import { useMutationState } from '@tanstack/lit-query'
174
+ *
175
+ * class PendingUploads extends LitElement {
176
+ * private readonly uploads = useMutationState(this, {
177
+ * filters: { mutationKey: ['upload'], status: 'pending' },
178
+ * select: (mutation) => mutation.state.variables as File,
179
+ * })
180
+ *
181
+ * render() {
182
+ * return html`<span>${this.uploads().length} uploads pending</span>`
183
+ * }
184
+ * }
185
+ * ```
186
+ */
187
+ export function useMutationState<
188
+ TResult = MutationState<unknown, unknown, unknown, unknown>,
189
+ >(
190
+ host: ReactiveControllerHost,
191
+ options: MutationStateOptions<TResult> = {},
192
+ queryClient?: QueryClient,
193
+ ): MutationStateAccessor<TResult> {
194
+ const controller = new MutationStateController(host, options, queryClient)
195
+ return Object.assign(
196
+ createValueAccessor(() => controller.current),
197
+ {
198
+ destroy: () => controller.destroy(),
199
+ },
200
+ )
201
+ }