@figma-vars/hooks 3.0.0 → 3.1.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 (44) hide show
  1. package/README.md +50 -0
  2. package/dist/api/fetcher.d.ts +32 -1
  3. package/dist/api/fetcher.d.ts.map +1 -1
  4. package/dist/api/index.d.ts +2 -0
  5. package/dist/api/index.d.ts.map +1 -1
  6. package/dist/api/mutator.d.ts +27 -1
  7. package/dist/api/mutator.d.ts.map +1 -1
  8. package/dist/contexts/FigmaVarsProvider.d.ts +2 -0
  9. package/dist/contexts/FigmaVarsProvider.d.ts.map +1 -1
  10. package/dist/core.cjs +1 -1
  11. package/dist/core.mjs +1 -1
  12. package/dist/hooks/index.d.ts +45 -0
  13. package/dist/hooks/index.d.ts.map +1 -1
  14. package/dist/hooks/useCollectionById.d.ts +31 -0
  15. package/dist/hooks/useCollectionById.d.ts.map +1 -0
  16. package/dist/hooks/useInvalidateVariables.d.ts +3 -0
  17. package/dist/hooks/useInvalidateVariables.d.ts.map +1 -1
  18. package/dist/hooks/useModesByCollection.d.ts +34 -0
  19. package/dist/hooks/useModesByCollection.d.ts.map +1 -0
  20. package/dist/hooks/usePublishedVariables.d.ts.map +1 -1
  21. package/dist/hooks/useVariableById.d.ts +31 -0
  22. package/dist/hooks/useVariableById.d.ts.map +1 -0
  23. package/dist/hooks/useVariables.d.ts.map +1 -1
  24. package/dist/index-5ZyKWuYv.cjs +1 -0
  25. package/dist/index-ClHLYVvu.js +142 -0
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.mjs +250 -167
  28. package/dist/types/contexts.d.ts +1 -0
  29. package/dist/types/contexts.d.ts.map +1 -1
  30. package/dist/types/figma.d.ts +9 -1
  31. package/dist/types/figma.d.ts.map +1 -1
  32. package/dist/types/mutations.d.ts +14 -0
  33. package/dist/types/mutations.d.ts.map +1 -1
  34. package/dist/utils/errorHelpers.d.ts +46 -0
  35. package/dist/utils/errorHelpers.d.ts.map +1 -1
  36. package/dist/utils/index.d.ts +2 -1
  37. package/dist/utils/index.d.ts.map +1 -1
  38. package/dist/utils/swrKeys.d.ts +24 -0
  39. package/dist/utils/swrKeys.d.ts.map +1 -0
  40. package/dist/utils/typeGuards.d.ts +50 -0
  41. package/dist/utils/typeGuards.d.ts.map +1 -0
  42. package/package.json +1 -1
  43. package/dist/index-BIUpDTdr.cjs +0 -1
  44. package/dist/index-Cd4HQQHO.js +0 -94
package/README.md CHANGED
@@ -254,6 +254,53 @@ function VariableEditor() {
254
254
 
255
255
  ## 🛡️ Error Handling
256
256
 
257
+ ### Error Boundaries (Recommended)
258
+
259
+ Wrap your Figma-connected components with an error boundary to gracefully handle errors:
260
+
261
+ ```tsx
262
+ import { ErrorBoundary } from 'react-error-boundary'
263
+ import { FigmaVarsProvider } from '@figma-vars/hooks'
264
+
265
+ function FigmaErrorFallback({ error }: { error: Error }) {
266
+ return (
267
+ <div role='alert'>
268
+ <h2>Failed to load Figma data</h2>
269
+ <pre>{error.message}</pre>
270
+ </div>
271
+ )
272
+ }
273
+
274
+ function App() {
275
+ return (
276
+ <ErrorBoundary FallbackComponent={FigmaErrorFallback}>
277
+ <FigmaVarsProvider
278
+ token={FIGMA_TOKEN}
279
+ fileKey={FIGMA_FILE_KEY}>
280
+ <YourApp />
281
+ </FigmaVarsProvider>
282
+ </ErrorBoundary>
283
+ )
284
+ }
285
+ ```
286
+
287
+ > **Note:** The provider validates fallback file structure at runtime and logs warnings in development. Invalid fallback data won't crash the app but will result in `undefined` data.
288
+
289
+ ### Runtime Validation
290
+
291
+ Use type guards to validate data at runtime:
292
+
293
+ ```tsx
294
+ import { isLocalVariablesResponse, isPublishedVariablesResponse } from '@figma-vars/hooks'
295
+
296
+ // Validate before using
297
+ if (isLocalVariablesResponse(data)) {
298
+ // Safe to access data.meta.variables
299
+ }
300
+ ```
301
+
302
+ ### Error Utilities
303
+
257
304
  3.0.0 introduces powerful error handling utilities for type-safe error checking:
258
305
 
259
306
  ```tsx
@@ -371,6 +418,7 @@ Customize SWR behavior globally through the provider:
371
418
  ### Hooks
372
419
 
373
420
  - **Queries**: `useVariables` (local), `usePublishedVariables` (library/published), `useVariableCollections`, `useVariableModes`, `useFigmaToken`
421
+ - **Granular Selectors**: `useCollectionById`, `useModesByCollection`, `useVariableById` (optimized selectors for specific entities)
374
422
  - **Mutations**: `useCreateVariable`, `useUpdateVariable`, `useDeleteVariable`, `useBulkUpdateVariables`
375
423
  - **Cache**: `useInvalidateVariables` (invalidate/revalidate cache)
376
424
 
@@ -378,6 +426,8 @@ Customize SWR behavior globally through the provider:
378
426
 
379
427
  - **Filtering**: `filterVariables` (filter by type, name, etc.)
380
428
  - **Error Handling**: `isFigmaApiError`, `getErrorStatus`, `getErrorMessage`, `hasErrorStatus`
429
+ - **Type Guards**: `isLocalVariablesResponse`, `isPublishedVariablesResponse`, `validateFallbackData` (runtime validation)
430
+ - **SWR Keys**: `getVariablesKey`, `getPublishedVariablesKey`, `getInvalidationKeys` (centralized cache key construction)
381
431
  - **Core helpers**: `fetcher`, `mutator`, constants for endpoints and headers
382
432
 
383
433
  ### Types
@@ -1,3 +1,22 @@
1
+ /**
2
+ * Options for configuring fetcher behavior.
3
+ *
4
+ * @public
5
+ */
6
+ export interface FetcherOptions {
7
+ /**
8
+ * Optional AbortSignal to cancel the request.
9
+ */
10
+ signal?: AbortSignal;
11
+ /**
12
+ * Optional timeout in milliseconds. Creates an AbortSignal internally if provided.
13
+ */
14
+ timeout?: number;
15
+ /**
16
+ * Optional fetch implementation override (useful for testing or custom fetch implementations).
17
+ */
18
+ fetch?: typeof fetch;
19
+ }
1
20
  /**
2
21
  * Low-level utility to fetch data from the Figma Variables REST API with authentication.
3
22
  *
@@ -6,13 +25,17 @@
6
25
  * Parses JSON responses and throws detailed errors for failed requests.
7
26
  * Intended for internal use by hooks but can be used directly for custom API interactions.
8
27
  *
28
+ * Supports request cancellation via AbortSignal and timeout handling.
29
+ *
9
30
  * @param url - The full Figma REST API endpoint URL (e.g., 'https://api.figma.com/v1/files/{file_key}/variables').
10
31
  * @param token - Figma Personal Access Token (PAT) for authentication.
32
+ * @param options - Optional configuration for abort signal, timeout, or custom fetch implementation.
11
33
  *
12
34
  * @returns A Promise resolving to the parsed JSON response from the Figma API.
13
35
  *
14
36
  * @throws Throws an Error if the token is not provided.
15
37
  * @throws Throws an Error if the HTTP response is not ok, including the message returned by the Figma API or a default error message.
38
+ * @throws Throws an AbortError if the request is aborted or times out.
16
39
  *
17
40
  * @example
18
41
  * ```ts
@@ -23,7 +46,15 @@
23
46
  * const data = await fetcher(url, token);
24
47
  * return data;
25
48
  * }
49
+ *
50
+ * // With timeout:
51
+ * const data = await fetcher(url, token, { timeout: 5000 });
52
+ *
53
+ * // With abort signal:
54
+ * const controller = new AbortController();
55
+ * const data = await fetcher(url, token, { signal: controller.signal });
56
+ * controller.abort(); // Cancel the request
26
57
  * ```
27
58
  */
28
- export declare function fetcher<TResponse = unknown>(url: string, token: string): Promise<TResponse>;
59
+ export declare function fetcher<TResponse = unknown>(url: string, token: string, options?: FetcherOptions): Promise<TResponse>;
29
60
  //# sourceMappingURL=fetcher.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/api/fetcher.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,OAAO,CAAC,SAAS,GAAG,OAAO,EAC/C,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,SAAS,CAAC,CAyCpB"}
1
+ {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/api/fetcher.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,OAAO,CAAC,SAAS,GAAG,OAAO,EAC/C,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,SAAS,CAAC,CA0FpB"}
@@ -23,4 +23,6 @@
23
23
  */
24
24
  export { fetcher } from './fetcher';
25
25
  export { mutator } from './mutator';
26
+ export type { FetcherOptions } from './fetcher';
27
+ export type { MutatorOptions } from './mutator';
26
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
@@ -1,4 +1,23 @@
1
1
  import { VariableAction, BulkUpdatePayload } from '../types/mutations.js';
2
+ /**
3
+ * Options for configuring mutator behavior.
4
+ *
5
+ * @public
6
+ */
7
+ export interface MutatorOptions {
8
+ /**
9
+ * Optional AbortSignal to cancel the request.
10
+ */
11
+ signal?: AbortSignal;
12
+ /**
13
+ * Optional timeout in milliseconds. Creates an AbortSignal internally if provided.
14
+ */
15
+ timeout?: number;
16
+ /**
17
+ * Optional fetch implementation override (useful for testing or custom fetch implementations).
18
+ */
19
+ fetch?: typeof fetch;
20
+ }
2
21
  /**
3
22
  * Low-level utility to send authenticated POST, PUT, or DELETE requests to the Figma Variables REST API.
4
23
  *
@@ -7,15 +26,19 @@ import { VariableAction, BulkUpdatePayload } from '../types/mutations.js';
7
26
  * It handles JSON serialization of the request body, parses JSON responses, and propagates detailed errors.
8
27
  * Intended primarily for internal use by mutation hooks, but also suitable for direct custom API mutations.
9
28
  *
29
+ * Supports request cancellation via AbortSignal and timeout handling.
30
+ *
10
31
  * @typeParam TResponse - The expected response type returned from the Figma API.
11
32
  * @param url - The full Figma REST API endpoint URL (e.g., 'https://api.figma.com/v1/files/{file_key}/variables').
12
33
  * @param token - Figma Personal Access Token (PAT) used for authentication.
13
34
  * @param action - The action for the mutation: 'CREATE', 'UPDATE', or 'DELETE'.
14
35
  * @param body - Optional request payload. For bulk operations, use BulkUpdatePayload. For individual operations, use objects with `variables` array.
36
+ * @param options - Optional configuration for abort signal, timeout, or custom fetch implementation.
15
37
  *
16
38
  * @returns A Promise resolving to the parsed JSON response from the Figma API.
17
39
  *
18
40
  * @throws Throws a FigmaApiError if the token is not provided or if the HTTP response is unsuccessful.
41
+ * @throws Throws an AbortError if the request is aborted or times out.
19
42
  *
20
43
  * @example
21
44
  * ```ts
@@ -27,9 +50,12 @@ import { VariableAction, BulkUpdatePayload } from '../types/mutations.js';
27
50
  * const result = await mutator(url, token, 'UPDATE', payload);
28
51
  * return result;
29
52
  * }
53
+ *
54
+ * // With timeout:
55
+ * const result = await mutator(url, token, 'UPDATE', payload, { timeout: 5000 });
30
56
  * ```
31
57
  */
32
58
  export declare function mutator<TResponse = unknown>(url: string, token: string, action: VariableAction, body?: BulkUpdatePayload | {
33
59
  variables?: Array<Record<string, unknown>>;
34
- } | Record<string, unknown>): Promise<TResponse>;
60
+ } | Record<string, unknown>, options?: MutatorOptions): Promise<TResponse>;
35
61
  //# sourceMappingURL=mutator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mutator.d.ts","sourceRoot":"","sources":["../../src/api/mutator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,OAAO,CAAC,SAAS,GAAG,OAAO,EAC/C,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EACD,iBAAiB,GACjB;IAAE,SAAS,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAAE,GAC9C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC1B,OAAO,CAAC,SAAS,CAAC,CAwDpB"}
1
+ {"version":3,"file":"mutator.d.ts","sourceRoot":"","sources":["../../src/api/mutator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3E;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,OAAO,CAAC,SAAS,GAAG,OAAO,EAC/C,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EACD,iBAAiB,GACjB;IAAE,SAAS,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAAE,GAC9C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,SAAS,CAAC,CAyGpB"}
@@ -7,6 +7,8 @@ import { FigmaVarsProviderProps } from '../types/contexts';
7
7
  *
8
8
  * This is the central source of truth for Figma authentication and file context within the app.
9
9
  *
10
+ * Fallback JSON files are parsed once during provider initialization to avoid repeated parsing and provide early validation.
11
+ *
10
12
  * @example
11
13
  * ```tsx
12
14
  * import { FigmaVarsProvider } from '@figma-vars/hooks/contexts';
@@ -1 +1 @@
1
- {"version":3,"file":"FigmaVarsProvider.d.ts","sourceRoot":"","sources":["../../src/contexts/FigmaVarsProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,sBAAsB,EACvB,MAAM,gBAAgB,CAAA;AAMvB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,iBAAiB,GAAI,wDAM/B,sBAAsB,4CAsBxB,CAAA"}
1
+ {"version":3,"file":"FigmaVarsProvider.d.ts","sourceRoot":"","sources":["../../src/contexts/FigmaVarsProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,sBAAsB,EACvB,MAAM,gBAAgB,CAAA;AAIvB;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,iBAAiB,GAAI,wDAM/B,sBAAsB,4CAqFxB,CAAA"}
package/dist/core.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("./index-BIUpDTdr.cjs");exports.CONTENT_TYPE_JSON=_.CONTENT_TYPE_JSON;exports.ERROR_MSG_BULK_UPDATE_FAILED=_.ERROR_MSG_BULK_UPDATE_FAILED;exports.ERROR_MSG_CREATE_VARIABLE_FAILED=_.ERROR_MSG_CREATE_VARIABLE_FAILED;exports.ERROR_MSG_DELETE_VARIABLE_FAILED=_.ERROR_MSG_DELETE_VARIABLE_FAILED;exports.ERROR_MSG_FETCH_FIGMA_DATA_FAILED=_.ERROR_MSG_FETCH_FIGMA_DATA_FAILED;exports.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED=_.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED;exports.ERROR_MSG_TOKEN_REQUIRED=_.ERROR_MSG_TOKEN_REQUIRED;exports.ERROR_MSG_UPDATE_VARIABLE_FAILED=_.ERROR_MSG_UPDATE_VARIABLE_FAILED;exports.FIGMA_API_BASE_URL=_.FIGMA_API_BASE_URL;exports.FIGMA_FILES_ENDPOINT=_.FIGMA_FILES_ENDPOINT;exports.FIGMA_FILE_VARIABLES_PATH=_.FIGMA_FILE_VARIABLES_PATH;exports.FIGMA_LOCAL_VARIABLES_ENDPOINT=_.FIGMA_LOCAL_VARIABLES_ENDPOINT;exports.FIGMA_PUBLISHED_VARIABLES_PATH=_.FIGMA_PUBLISHED_VARIABLES_PATH;exports.FIGMA_TOKEN_HEADER=_.FIGMA_TOKEN_HEADER;exports.fetcher=_.fetcher;exports.filterVariables=_.filterVariables;exports.mutator=_.mutator;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("./index-5ZyKWuYv.cjs");exports.CONTENT_TYPE_JSON=_.CONTENT_TYPE_JSON;exports.ERROR_MSG_BULK_UPDATE_FAILED=_.ERROR_MSG_BULK_UPDATE_FAILED;exports.ERROR_MSG_CREATE_VARIABLE_FAILED=_.ERROR_MSG_CREATE_VARIABLE_FAILED;exports.ERROR_MSG_DELETE_VARIABLE_FAILED=_.ERROR_MSG_DELETE_VARIABLE_FAILED;exports.ERROR_MSG_FETCH_FIGMA_DATA_FAILED=_.ERROR_MSG_FETCH_FIGMA_DATA_FAILED;exports.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED=_.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED;exports.ERROR_MSG_TOKEN_REQUIRED=_.ERROR_MSG_TOKEN_REQUIRED;exports.ERROR_MSG_UPDATE_VARIABLE_FAILED=_.ERROR_MSG_UPDATE_VARIABLE_FAILED;exports.FIGMA_API_BASE_URL=_.FIGMA_API_BASE_URL;exports.FIGMA_FILES_ENDPOINT=_.FIGMA_FILES_ENDPOINT;exports.FIGMA_FILE_VARIABLES_PATH=_.FIGMA_FILE_VARIABLES_PATH;exports.FIGMA_LOCAL_VARIABLES_ENDPOINT=_.FIGMA_LOCAL_VARIABLES_ENDPOINT;exports.FIGMA_PUBLISHED_VARIABLES_PATH=_.FIGMA_PUBLISHED_VARIABLES_PATH;exports.FIGMA_TOKEN_HEADER=_.FIGMA_TOKEN_HEADER;exports.fetcher=_.fetcher;exports.filterVariables=_.filterVariables;exports.mutator=_.mutator;
package/dist/core.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { C as A, j as R, k as I, l as a, o as L, a as s, E as F, n as T, e as D, g as O, F as G, h as M, b as S, i as N, f as B, d as P, m as U } from "./index-Cd4HQQHO.js";
1
+ import { C as A, j as R, k as I, l as a, o as L, a as s, E as F, n as T, d as D, e as O, F as G, h as M, g as S, i as N, f as B, c as P, m as U } from "./index-ClHLYVvu.js";
2
2
  export {
3
3
  A as CONTENT_TYPE_JSON,
4
4
  R as ERROR_MSG_BULK_UPDATE_FAILED,
@@ -160,4 +160,49 @@ export { useInvalidateVariables } from './useInvalidateVariables';
160
160
  * @public
161
161
  */
162
162
  export { usePublishedVariables } from './usePublishedVariables';
163
+ /**
164
+ * React hook to select a single variable by ID from loaded Figma variables data.
165
+ *
166
+ * @remarks
167
+ * Returns the variable with the specified ID, or undefined if not found.
168
+ *
169
+ * @example
170
+ * ```tsx
171
+ * import { useVariableById } from '@figma-vars/hooks';
172
+ * const variable = useVariableById('VariableID:123:456');
173
+ * ```
174
+ *
175
+ * @public
176
+ */
177
+ export { useVariableById } from './useVariableById';
178
+ /**
179
+ * React hook to select a single variable collection by ID from loaded Figma variables data.
180
+ *
181
+ * @remarks
182
+ * Returns the collection with the specified ID, or undefined if not found.
183
+ *
184
+ * @example
185
+ * ```tsx
186
+ * import { useCollectionById } from '@figma-vars/hooks';
187
+ * const collection = useCollectionById('VariableCollectionId:123:456');
188
+ * ```
189
+ *
190
+ * @public
191
+ */
192
+ export { useCollectionById } from './useCollectionById';
193
+ /**
194
+ * React hook to select modes for a specific variable collection.
195
+ *
196
+ * @remarks
197
+ * Returns an array of modes belonging to the specified collection.
198
+ *
199
+ * @example
200
+ * ```tsx
201
+ * import { useModesByCollection } from '@figma-vars/hooks';
202
+ * const modes = useModesByCollection('VariableCollectionId:123:456');
203
+ * ```
204
+ *
205
+ * @public
206
+ */
207
+ export { useModesByCollection } from './useModesByCollection';
163
208
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AACrE;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAC9D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AACrE;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AACrE;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAC9D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AACrE;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AACnE;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA"}
@@ -0,0 +1,31 @@
1
+ import { FigmaCollection } from 'types';
2
+ /**
3
+ * React hook that selects a single variable collection by ID from loaded Figma variables data.
4
+ *
5
+ * @remarks
6
+ * Returns the collection with the specified ID, or `undefined` if not found.
7
+ * Useful for accessing a specific collection without manually mapping through all collections.
8
+ *
9
+ * @param collectionId - The ID of the collection to retrieve.
10
+ * @returns The collection object, or `undefined` if not found.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * import { useCollectionById } from '@figma-vars/hooks';
15
+ *
16
+ * function CollectionDetails({ collectionId }: { collectionId: string }) {
17
+ * const collection = useCollectionById(collectionId);
18
+ *
19
+ * if (!collection) return <div>Collection not found</div>;
20
+ *
21
+ * return <div>
22
+ * <h2>{collection.name}</h2>
23
+ * <p>Variables: {collection.variableIds.length}</p>
24
+ * </div>;
25
+ * }
26
+ * ```
27
+ *
28
+ * @public
29
+ */
30
+ export declare const useCollectionById: (collectionId: string) => FigmaCollection | undefined;
31
+ //# sourceMappingURL=useCollectionById.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCollectionById.d.ts","sourceRoot":"","sources":["../../src/hooks/useCollectionById.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,iBAAiB,GAC5B,cAAc,MAAM,KACnB,eAAe,GAAG,SAMpB,CAAA"}
@@ -5,6 +5,9 @@
5
5
  * Returns functions to invalidate and revalidate SWR cache for variables hooks.
6
6
  * Use this after mutations to ensure fresh data is fetched.
7
7
  *
8
+ * Supports both live API usage (with token and fileKey) and fallback-only usage
9
+ * (with fallbackFile but no fileKey).
10
+ *
8
11
  * @returns Object with `invalidate` and `revalidate` functions.
9
12
  *
10
13
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"useInvalidateVariables.d.ts","sourceRoot":"","sources":["../../src/hooks/useInvalidateVariables.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,sBAAsB;;;CAgElC,CAAA"}
1
+ {"version":3,"file":"useInvalidateVariables.d.ts","sourceRoot":"","sources":["../../src/hooks/useInvalidateVariables.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,sBAAsB;;;CAoDlC,CAAA"}
@@ -0,0 +1,34 @@
1
+ import { VariableMode } from 'types';
2
+ /**
3
+ * React hook that selects modes for a specific variable collection.
4
+ *
5
+ * @remarks
6
+ * Returns an array of modes belonging to the specified collection, or an empty array if not found.
7
+ * Useful for filtering modes by collection without manually accessing modesByCollectionId.
8
+ *
9
+ * @param collectionId - The ID of the collection to get modes for.
10
+ * @returns An array of VariableMode objects for the collection, or an empty array if not found.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * import { useModesByCollection } from '@figma-vars/hooks';
15
+ *
16
+ * function CollectionModes({ collectionId }: { collectionId: string }) {
17
+ * const modes = useModesByCollection(collectionId);
18
+ *
19
+ * if (!modes.length) return <div>No modes found</div>;
20
+ *
21
+ * return (
22
+ * <ul>
23
+ * {modes.map(mode => (
24
+ * <li key={mode.modeId}>{mode.name}</li>
25
+ * ))}
26
+ * </ul>
27
+ * );
28
+ * }
29
+ * ```
30
+ *
31
+ * @public
32
+ */
33
+ export declare const useModesByCollection: (collectionId: string) => VariableMode[];
34
+ //# sourceMappingURL=useModesByCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useModesByCollection.d.ts","sourceRoot":"","sources":["../../src/hooks/useModesByCollection.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,oBAAoB,GAAI,cAAc,MAAM,KAAG,YAAY,EAMvE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"usePublishedVariables.d.ts","sourceRoot":"","sources":["../../src/hooks/usePublishedVariables.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAI7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,qBAAqB,sMAsCjC,CAAA"}
1
+ {"version":3,"file":"usePublishedVariables.d.ts","sourceRoot":"","sources":["../../src/hooks/usePublishedVariables.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAI7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,qBAAqB,sMA+CjC,CAAA"}
@@ -0,0 +1,31 @@
1
+ import { FigmaVariable } from 'types';
2
+ /**
3
+ * React hook that selects a single variable by ID from loaded Figma variables data.
4
+ *
5
+ * @remarks
6
+ * Returns the variable with the specified ID, or `undefined` if not found.
7
+ * Useful for accessing a specific variable without manually mapping through all variables.
8
+ *
9
+ * @param variableId - The ID of the variable to retrieve.
10
+ * @returns The variable object, or `undefined` if not found.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * import { useVariableById } from '@figma-vars/hooks';
15
+ *
16
+ * function VariableDetails({ variableId }: { variableId: string }) {
17
+ * const variable = useVariableById(variableId);
18
+ *
19
+ * if (!variable) return <div>Variable not found</div>;
20
+ *
21
+ * return <div>
22
+ * <h2>{variable.name}</h2>
23
+ * <p>Type: {variable.resolvedType}</p>
24
+ * </div>;
25
+ * }
26
+ * ```
27
+ *
28
+ * @public
29
+ */
30
+ export declare const useVariableById: (variableId: string) => FigmaVariable | undefined;
31
+ //# sourceMappingURL=useVariableById.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVariableById.d.ts","sourceRoot":"","sources":["../../src/hooks/useVariableById.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,eAAe,GAC1B,YAAY,MAAM,KACjB,aAAa,GAAG,SASlB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"useVariables.d.ts","sourceRoot":"","sources":["../../src/hooks/useVariables.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAGzD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,0LAyCxB,CAAA"}
1
+ {"version":3,"file":"useVariables.d.ts","sourceRoot":"","sources":["../../src/hooks/useVariables.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAIzD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,0LAgDxB,CAAA"}
@@ -0,0 +1 @@
1
+ "use strict";var N=Object.defineProperty;var g=(t,s,r)=>s in t?N(t,s,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[s]=r;var m=(t,s,r)=>g(t,typeof s!="symbol"?s+"":s,r);const T="https://api.figma.com",O=`${T}/v1/files`,v=t=>`/v1/files/${t}/variables/published`,P=t=>`/v1/files/${t}/variables`,y=t=>`${O}/${t}/variables/local`,D="application/json",p="X-FIGMA-TOKEN",h="A Figma API token is required.",B=`${h} and file key are required.`,U="Failed to perform bulk update.",w="Failed to create Figma variable.",b="Failed to delete Figma variable.",C="Failed to update Figma variable.",G="An error occurred while fetching data from the Figma API.";class l extends Error{constructor(r,o,c){super(r);m(this,"statusCode");m(this,"retryAfter");this.name="FigmaApiError",this.statusCode=o,this.retryAfter=c??void 0,Error.captureStackTrace&&Error.captureStackTrace(this,l)}}async function V(t,s,r){if(!s)throw new Error(h);const{signal:o,timeout:c,fetch:F=fetch}=r??{};let i,A;const a=o||(c?(A=new AbortController,i=setTimeout(()=>{A==null||A.abort()},c),A.signal):void 0);try{const E=t.startsWith("http://")||t.startsWith("https://")?t:`${T}${t.startsWith("/")?"":"/"}${t}`,n=await F(E,{method:"GET",headers:{[p]:s,"Content-Type":D},...a!==void 0&&{signal:a}});if(i!==void 0&&(clearTimeout(i),i=void 0),!n.ok){let R=G;const L=n.status;let d;if(L===429){const _=n.headers.get("Retry-After");if(_){const e=parseInt(_,10);Number.isNaN(e)||(d=e)}}try{const _=n.headers.get("content-type");if(_!=null&&_.includes("application/json")){const e=await n.json();e!=null&&e.message?R=e.message:e!=null&&e.err&&(R=e.err)}}catch{}throw new l(R,L,d)}return n.json()}catch(E){throw i!==void 0&&(clearTimeout(i),i=void 0),E}}async function H(t,s,r,o,c){if(!s)throw new Error(h);const{signal:F,timeout:i,fetch:A=fetch}=c??{};let a,E;const n=F||(i?(E=new AbortController,a=setTimeout(()=>{E==null||E.abort()},i),E.signal):void 0);try{const d={method:{CREATE:"POST",UPDATE:"PUT",DELETE:"DELETE"}[r],headers:{"Content-Type":"application/json",[p]:s},...n!==void 0&&{signal:n}};o&&(d.body=JSON.stringify(o));const _=t.startsWith("http://")||t.startsWith("https://")?t:`${T}${t.startsWith("/")?"":"/"}${t}`,e=await A(_,d);if(a!==void 0&&(clearTimeout(a),a=void 0),!e.ok){const S=e.status;let u="An API error occurred",M;if(S===429){const I=e.headers.get("Retry-After");if(I){const f=parseInt(I,10);Number.isNaN(f)||(M=f)}}try{const I=e.headers.get("content-type");if(I!=null&&I.includes("application/json")){const f=await e.json();u=f.err||f.message||u}}catch{}throw new l(u,S,M)}return e.status===204||!e.body?{}:e.json()}catch(R){throw a!==void 0&&(clearTimeout(a),a=void 0),R}}function $(t,s){return t.filter(r=>{let o=!0;return s.resolvedType&&(o=o&&r.resolvedType===s.resolvedType),s.name&&(o=o&&r.name.includes(s.name)),o})}exports.CONTENT_TYPE_JSON=D;exports.ERROR_MSG_BULK_UPDATE_FAILED=U;exports.ERROR_MSG_CREATE_VARIABLE_FAILED=w;exports.ERROR_MSG_DELETE_VARIABLE_FAILED=b;exports.ERROR_MSG_FETCH_FIGMA_DATA_FAILED=G;exports.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED=B;exports.ERROR_MSG_TOKEN_REQUIRED=h;exports.ERROR_MSG_UPDATE_VARIABLE_FAILED=C;exports.FIGMA_API_BASE_URL=T;exports.FIGMA_FILES_ENDPOINT=O;exports.FIGMA_FILE_VARIABLES_PATH=P;exports.FIGMA_LOCAL_VARIABLES_ENDPOINT=y;exports.FIGMA_PUBLISHED_VARIABLES_PATH=v;exports.FIGMA_TOKEN_HEADER=p;exports.FigmaApiError=l;exports.fetcher=V;exports.filterVariables=$;exports.mutator=H;
@@ -0,0 +1,142 @@
1
+ var L = Object.defineProperty;
2
+ var S = (t, s, r) => s in t ? L(t, s, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[s] = r;
3
+ var I = (t, s, r) => S(t, typeof s != "symbol" ? s + "" : s, r);
4
+ const T = "https://api.figma.com", M = `${T}/v1/files`, D = (t) => `/v1/files/${t}/variables/published`, G = (t) => `/v1/files/${t}/variables`, b = (t) => `${M}/${t}/variables/local`, N = "application/json", y = "X-FIGMA-TOKEN", F = "A Figma API token is required.", P = `${F} and file key are required.`, C = "Failed to perform bulk update.", $ = "Failed to create Figma variable.", U = "Failed to delete Figma variable.", j = "Failed to update Figma variable.", O = "An error occurred while fetching data from the Figma API.";
5
+ class p extends Error {
6
+ constructor(r, a, A) {
7
+ super(r);
8
+ /** HTTP status code from the API response. */
9
+ I(this, "statusCode");
10
+ /**
11
+ * Retry-After header value in seconds (for 429 rate limit errors).
12
+ * Undefined if not a rate limit error or header not present.
13
+ */
14
+ I(this, "retryAfter");
15
+ this.name = "FigmaApiError", this.statusCode = a, this.retryAfter = A ?? void 0, Error.captureStackTrace && Error.captureStackTrace(this, p);
16
+ }
17
+ }
18
+ async function B(t, s, r) {
19
+ if (!s)
20
+ throw new Error(F);
21
+ const {
22
+ signal: a,
23
+ timeout: A,
24
+ fetch: u = fetch
25
+ } = r ?? {};
26
+ let o, d;
27
+ const i = a || (A ? (d = new AbortController(), o = setTimeout(() => {
28
+ d == null || d.abort();
29
+ }, A), d.signal) : void 0);
30
+ try {
31
+ const n = t.startsWith("http://") || t.startsWith("https://") ? t : `${T}${t.startsWith("/") ? "" : "/"}${t}`, c = await u(n, {
32
+ method: "GET",
33
+ headers: {
34
+ [y]: s,
35
+ "Content-Type": N
36
+ },
37
+ ...i !== void 0 && { signal: i }
38
+ });
39
+ if (o !== void 0 && (clearTimeout(o), o = void 0), !c.ok) {
40
+ let f = O;
41
+ const m = c.status;
42
+ let h;
43
+ if (m === 429) {
44
+ const E = c.headers.get("Retry-After");
45
+ if (E) {
46
+ const e = parseInt(E, 10);
47
+ Number.isNaN(e) || (h = e);
48
+ }
49
+ }
50
+ try {
51
+ const E = c.headers.get("content-type");
52
+ if (E != null && E.includes("application/json")) {
53
+ const e = await c.json();
54
+ e != null && e.message ? f = e.message : e != null && e.err && (f = e.err);
55
+ }
56
+ } catch {
57
+ }
58
+ throw new p(f, m, h);
59
+ }
60
+ return c.json();
61
+ } catch (n) {
62
+ throw o !== void 0 && (clearTimeout(o), o = void 0), n;
63
+ }
64
+ }
65
+ async function H(t, s, r, a, A) {
66
+ if (!s)
67
+ throw new Error(F);
68
+ const {
69
+ signal: u,
70
+ timeout: o,
71
+ fetch: d = fetch
72
+ } = A ?? {};
73
+ let i, n;
74
+ const c = u || (o ? (n = new AbortController(), i = setTimeout(() => {
75
+ n == null || n.abort();
76
+ }, o), n.signal) : void 0);
77
+ try {
78
+ const h = {
79
+ method: {
80
+ CREATE: "POST",
81
+ UPDATE: "PUT",
82
+ DELETE: "DELETE"
83
+ }[r],
84
+ headers: {
85
+ "Content-Type": "application/json",
86
+ [y]: s
87
+ },
88
+ ...c !== void 0 && { signal: c }
89
+ };
90
+ a && (h.body = JSON.stringify(a));
91
+ const E = t.startsWith("http://") || t.startsWith("https://") ? t : `${T}${t.startsWith("/") ? "" : "/"}${t}`, e = await d(E, h);
92
+ if (i !== void 0 && (clearTimeout(i), i = void 0), !e.ok) {
93
+ const g = e.status;
94
+ let R = "An API error occurred", v;
95
+ if (g === 429) {
96
+ const l = e.headers.get("Retry-After");
97
+ if (l) {
98
+ const _ = parseInt(l, 10);
99
+ Number.isNaN(_) || (v = _);
100
+ }
101
+ }
102
+ try {
103
+ const l = e.headers.get("content-type");
104
+ if (l != null && l.includes("application/json")) {
105
+ const _ = await e.json();
106
+ R = _.err || _.message || R;
107
+ }
108
+ } catch {
109
+ }
110
+ throw new p(R, g, v);
111
+ }
112
+ return e.status === 204 || !e.body ? {} : e.json();
113
+ } catch (f) {
114
+ throw i !== void 0 && (clearTimeout(i), i = void 0), f;
115
+ }
116
+ }
117
+ function V(t, s) {
118
+ return t.filter((r) => {
119
+ let a = !0;
120
+ return s.resolvedType && (a = a && r.resolvedType === s.resolvedType), s.name && (a = a && r.name.includes(s.name)), a;
121
+ });
122
+ }
123
+ export {
124
+ N as C,
125
+ F as E,
126
+ G as F,
127
+ P as a,
128
+ p as b,
129
+ V as c,
130
+ T as d,
131
+ M as e,
132
+ B as f,
133
+ D as g,
134
+ b as h,
135
+ y as i,
136
+ C as j,
137
+ $ as k,
138
+ U as l,
139
+ H as m,
140
+ j as n,
141
+ O as o
142
+ };
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("react/jsx-runtime"),i=require("react"),b=require("swr"),o=require("./index-BIUpDTdr.cjs"),p=i.createContext(void 0);let v=0;const k=({children:e,token:r,fileKey:t,fallbackFile:s,swrConfig:n})=>{const a=i.useMemo(()=>(v+=1,`figma-vars-provider-${v}`),[]),c=i.useMemo(()=>{const l={token:r,fileKey:t,providerId:a,...n!==void 0&&{swrConfig:n}};return s===void 0?l:{...l,fallbackFile:s}},[r,t,s,a,n]);return h.jsx(p.Provider,{value:c,children:e})},d=()=>{const e=i.useContext(p);if(e===void 0)throw new Error("useFigmaTokenContext must be used within a FigmaVarsProvider");return e},_=()=>{const{token:e,fileKey:r,fallbackFile:t,providerId:s,swrConfig:n}=d(),a=r?`https://api.figma.com/v1/files/${r}/variables/local`:null,E=!!(e&&a)?[a,e]:!!t?[`fallback-${s??"default"}`,"fallback"]:null;return b(E,async(...u)=>{const[f,R]=Array.isArray(u[0])?u[0]:[u[0],u[1]];if(t)return typeof t=="string"?JSON.parse(t):t;if(!f||!R)throw new Error("Missing URL or token for live API request");return o.fetcher(f,R)},n)},w=()=>{const{data:e}=_(),r=i.useMemo(()=>e!=null&&e.meta?Object.values(e.meta.variableCollections):[],[e]),t=i.useMemo(()=>e!=null&&e.meta?e.meta.variableCollections:{},[e]);return{collections:r,collectionsById:t}},S=()=>{const{data:e}=_();return i.useMemo(()=>{const r=[],t={},s={};if(e!=null&&e.meta)for(const n of Object.values(e.meta.variableCollections)){r.push(...n.modes),t[n.id]=n.modes;for(const a of n.modes)s[a.modeId]=a}return{modes:r,modesByCollectionId:t,modesById:s}},[e])};function V(e,r){switch(r.type){case"loading":return{...e,status:"loading",error:null};case"success":return{...e,status:"success",data:r.payload};case"error":return{...e,status:"error",error:r.payload};default:return e}}const m=e=>{const r={status:"idle",data:null,error:null},[t,s]=i.useReducer(V,r),n=i.useRef(e),a=i.useRef(!0);return i.useEffect(()=>{n.current=e},[e]),i.useEffect(()=>(a.current=!0,()=>{a.current=!1}),[]),{mutate:i.useCallback(async l=>{if(a.current){s({type:"loading"});try{const E=await n.current(l);return a.current&&s({type:"success",payload:E}),E}catch(E){a.current&&s({type:"error",payload:E});return}}},[]),...t,isLoading:t.status==="loading",isSuccess:t.status==="success",isError:t.status==="error"}},F=()=>{const{token:e,fileKey:r}=d();return m(async s=>{if(!e)throw new Error(o.ERROR_MSG_TOKEN_REQUIRED);if(!r)throw new Error(o.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED);return await o.mutator(o.FIGMA_FILE_VARIABLES_PATH(r),e,"CREATE",{variables:[{action:"CREATE",...s}]})})},g=()=>{const{token:e,fileKey:r}=d();return m(async({variableId:s,payload:n})=>{if(!e)throw new Error(o.ERROR_MSG_TOKEN_REQUIRED);if(!r)throw new Error(o.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED);return await o.mutator(o.FIGMA_FILE_VARIABLES_PATH(r),e,"UPDATE",{variables:[{action:"UPDATE",id:s,...n}]})})},M=()=>{const{token:e,fileKey:r}=d();return m(async s=>{if(!e)throw new Error(o.ERROR_MSG_TOKEN_REQUIRED);if(!r)throw new Error(o.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED);return await o.mutator(o.FIGMA_FILE_VARIABLES_PATH(r),e,"DELETE",{variables:[{action:"DELETE",id:s}]})})},L=()=>{const{token:e,fileKey:r}=d();return m(async s=>{if(!e)throw new Error(o.ERROR_MSG_TOKEN_REQUIRED);if(!r)throw new Error(o.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED);return await o.mutator(o.FIGMA_FILE_VARIABLES_PATH(r),e,"UPDATE",s)})},T=()=>{const{mutate:e}=b.useSWRConfig(),{fileKey:r,providerId:t}=d();return{invalidate:()=>{if(!r)return;const a=[`https://api.figma.com/v1/files/${r}/variables/local`,"token-placeholder"];e(a);const c=[o.FIGMA_PUBLISHED_VARIABLES_PATH(r),"token-placeholder"];if(e(c),t){const l=[`fallback-${t}`,"fallback"];e(l)}},revalidate:()=>{if(!r)return;const a=[`https://api.figma.com/v1/files/${r}/variables/local`,"token-placeholder"];e(a,void 0,{revalidate:!0});const c=[o.FIGMA_PUBLISHED_VARIABLES_PATH(r),"token-placeholder"];if(e(c,void 0,{revalidate:!0}),t){const l=[`fallback-${t}`,"fallback"];e(l,void 0,{revalidate:!0})}}}},K=()=>{const{token:e,fileKey:r,fallbackFile:t,providerId:s,swrConfig:n}=d(),a=r?o.FIGMA_PUBLISHED_VARIABLES_PATH(r):null,E=!!(e&&a)?[a,e]:!!t?[`fallback-${s??"default"}`,"fallback"]:null;return b(E,async(...u)=>{const[f,R]=Array.isArray(u[0])?u[0]:[u[0],u[1]];if(t)return typeof t=="string"?JSON.parse(t):t;if(!f||!R)throw new Error("Missing URL or token for live API request");return o.fetcher(f,R)},n)};function I(e){return e instanceof o.FigmaApiError}function A(e){return I(e)?e.statusCode:null}function P(e,r="An error occurred"){return e instanceof Error?e.message||r:typeof e=="string"?e:r}function O(e,r){return A(e)===r}exports.FigmaApiError=o.FigmaApiError;exports.filterVariables=o.filterVariables;exports.FigmaVarsProvider=k;exports.getErrorMessage=P;exports.getErrorStatus=A;exports.hasErrorStatus=O;exports.isFigmaApiError=I;exports.useBulkUpdateVariables=L;exports.useCreateVariable=F;exports.useDeleteVariable=M;exports.useInvalidateVariables=T;exports.usePublishedVariables=K;exports.useUpdateVariable=g;exports.useVariableCollections=w;exports.useVariableModes=S;exports.useVariables=_;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("react/jsx-runtime"),u=require("react"),m=require("swr"),i=require("./index-5ZyKWuYv.cjs"),k=u.createContext(void 0);function A(e){if(typeof e!="object"||e===null)return!1;const r=e;if(typeof r.meta!="object"||r.meta===null)return!1;const t=r.meta;return!(typeof t.variableCollections!="object"||t.variableCollections===null||typeof t.variables!="object"||t.variables===null)}function _(e){if(A(e))return e}const V=({children:e,token:r,fileKey:t,fallbackFile:o,swrConfig:s})=>{const a=u.useId(),l=u.useMemo(()=>`figma-vars-provider-${a}`,[a]),f=u.useMemo(()=>{if(o){if(typeof o=="object"){const n=_(o);if(n)return n;process.env.NODE_ENV!=="production"&&console.warn("[figma-vars-hooks] fallbackFile object does not match expected Figma Variables API response structure. Expected { meta: { variableCollections: {...}, variables: {...} } }");return}if(typeof o=="string")try{const n=JSON.parse(o),d=_(n);if(d)return d;process.env.NODE_ENV!=="production"&&console.warn("[figma-vars-hooks] Parsed fallbackFile JSON does not match expected Figma Variables API response structure. Expected { meta: { variableCollections: {...}, variables: {...} } }");return}catch(n){process.env.NODE_ENV!=="production"&&console.error(`[figma-vars-hooks] Failed to parse fallbackFile JSON: ${n instanceof Error?n.message:"Unknown error"}`);return}}},[o]),c=u.useMemo(()=>{const n={token:r,fileKey:t,providerId:l,...s!==void 0&&{swrConfig:s}};return o===void 0?n:{...n,fallbackFile:o,parsedFallbackFile:f}},[r,t,o,f,l,s]);return g.jsx(k.Provider,{value:c,children:e})},b=()=>{const e=u.useContext(k);if(e===void 0)throw new Error("useFigmaTokenContext must be used within a FigmaVarsProvider");return e};function M(e){const{fileKey:r,token:t,providerId:o,hasFallback:s}=e;return!!(t&&r)&&t&&r?[`https://api.figma.com/v1/files/${r}/variables/local`,t]:s?[`fallback-${o??"default"}`,"fallback"]:null}function O(e){const{fileKey:r,token:t,providerId:o,hasFallback:s}=e;return!!(t&&r)&&t&&r?[`https://api.figma.com/v1/files/${r}/variables/published`,t]:s?[`fallback-${o??"default"}`,"fallback"]:null}function I(e){const{fileKey:r,token:t,providerId:o,hasFallback:s}=e,a=[];return t&&r&&(a.push([`https://api.figma.com/v1/files/${r}/variables/local`,t]),a.push([`https://api.figma.com/v1/files/${r}/variables/published`,t])),s&&o&&a.push([`fallback-${o}`,"fallback"]),a}const R=()=>{const{token:e,fileKey:r,fallbackFile:t,parsedFallbackFile:o,providerId:s,swrConfig:a}=b(),f=M({fileKey:r,token:e,providerId:s,hasFallback:!!(t||o)});return m(f,async(...n)=>{if(o)return o;if(t&&typeof t=="object")return t;const[d,E]=Array.isArray(n[0])?n[0]:[n[0],n[1]];if(!d||!E)throw new Error("Missing URL or token for live API request");return i.fetcher(d,E)},a)},S=()=>{const{data:e}=R(),r=u.useMemo(()=>e!=null&&e.meta?Object.values(e.meta.variableCollections):[],[e]),t=u.useMemo(()=>e!=null&&e.meta?e.meta.variableCollections:{},[e]);return{collections:r,collectionsById:t}},K=()=>{const{data:e}=R();return u.useMemo(()=>{const r=[],t={},o={};if(e!=null&&e.meta)for(const s of Object.values(e.meta.variableCollections)){r.push(...s.modes),t[s.id]=s.modes;for(const a of s.modes)o[a.modeId]=a}return{modes:r,modesByCollectionId:t,modesById:o}},[e])};function T(e,r){switch(r.type){case"loading":return{...e,status:"loading",error:null};case"success":return{...e,status:"success",data:r.payload};case"error":return{...e,status:"error",error:r.payload};default:return e}}const v=(e,r)=>{const{throwOnError:t=!1}={},o={status:"idle",data:null,error:null},[s,a]=u.useReducer(T,o),l=u.useRef(e),f=u.useRef({throwOnError:t}),c=u.useRef(!0),n=u.useRef(0);return u.useEffect(()=>{l.current=e,f.current={throwOnError:t}},[e,t]),u.useEffect(()=>(c.current=!0,()=>{c.current=!1}),[]),{mutate:u.useCallback(async E=>{if(!c.current)return;const y=++n.current;a({type:"loading"});try{const p=await l.current(E);return c.current&&y===n.current&&a({type:"success",payload:p}),p}catch(p){const h=p;if(c.current&&y===n.current&&a({type:"error",payload:h}),f.current.throwOnError)throw h;return}},[]),...s,isLoading:s.status==="loading",isSuccess:s.status==="success",isError:s.status==="error"}},C=()=>{const{token:e,fileKey:r}=b();return v(async o=>{if(!e)throw new Error(i.ERROR_MSG_TOKEN_REQUIRED);if(!r)throw new Error(i.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED);return await i.mutator(i.FIGMA_FILE_VARIABLES_PATH(r),e,"CREATE",{variables:[{action:"CREATE",...o}]})})},L=()=>{const{token:e,fileKey:r}=b();return v(async({variableId:o,payload:s})=>{if(!e)throw new Error(i.ERROR_MSG_TOKEN_REQUIRED);if(!r)throw new Error(i.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED);return await i.mutator(i.FIGMA_FILE_VARIABLES_PATH(r),e,"UPDATE",{variables:[{action:"UPDATE",id:o,...s}]})})},P=()=>{const{token:e,fileKey:r}=b();return v(async o=>{if(!e)throw new Error(i.ERROR_MSG_TOKEN_REQUIRED);if(!r)throw new Error(i.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED);return await i.mutator(i.FIGMA_FILE_VARIABLES_PATH(r),e,"DELETE",{variables:[{action:"DELETE",id:o}]})})},D=()=>{const{token:e,fileKey:r}=b();return v(async o=>{if(!e)throw new Error(i.ERROR_MSG_TOKEN_REQUIRED);if(!r)throw new Error(i.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED);return await i.mutator(i.FIGMA_FILE_VARIABLES_PATH(r),e,"UPDATE",o)})},U=()=>{const{mutate:e}=m.useSWRConfig(),{token:r,fileKey:t,fallbackFile:o,providerId:s}=b(),a=!!o;return{invalidate:()=>{const c=I({fileKey:t,token:r,providerId:s,hasFallback:a});for(const n of c)e(n)},revalidate:()=>{const c=I({fileKey:t,token:r,providerId:s,hasFallback:a});for(const n of c)e(n,void 0,{revalidate:!0})}}},N=()=>{const{token:e,fileKey:r,fallbackFile:t,parsedFallbackFile:o,providerId:s,swrConfig:a}=b(),f=O({fileKey:r,token:e,providerId:s,hasFallback:!!(t||o)});return m(f,async(...n)=>{if(o)return o;if(t&&typeof t=="object")return t;const[d,E]=Array.isArray(n[0])?n[0]:[n[0],n[1]];if(!d||!E)throw new Error("Missing URL or token for live API request");return i.fetcher(d,E)},a)};function w(e){return e instanceof i.FigmaApiError}function F(e){return w(e)?e.statusCode:null}function j(e,r="An error occurred"){return e instanceof Error?e.message||r:typeof e=="string"?e:r}function B(e,r){return F(e)===r}exports.FigmaApiError=i.FigmaApiError;exports.filterVariables=i.filterVariables;exports.FigmaVarsProvider=V;exports.getErrorMessage=j;exports.getErrorStatus=F;exports.hasErrorStatus=B;exports.isFigmaApiError=w;exports.useBulkUpdateVariables=D;exports.useCreateVariable=C;exports.useDeleteVariable=P;exports.useInvalidateVariables=U;exports.usePublishedVariables=N;exports.useUpdateVariable=L;exports.useVariableCollections=S;exports.useVariableModes=K;exports.useVariables=R;