@figma-vars/hooks 3.1.0 → 4.0.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.
- package/README.md +83 -24
- package/dist/api/fetcher.d.ts +5 -0
- package/dist/api/fetcher.d.ts.map +1 -1
- package/dist/api/mutator.d.ts +5 -0
- package/dist/api/mutator.d.ts.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.mjs +1 -1
- package/dist/hooks/useBulkUpdateVariables.d.ts +18 -4
- package/dist/hooks/useBulkUpdateVariables.d.ts.map +1 -1
- package/dist/hooks/useCreateVariable.d.ts +22 -4
- package/dist/hooks/useCreateVariable.d.ts.map +1 -1
- package/dist/hooks/useDeleteVariable.d.ts +19 -3
- package/dist/hooks/useDeleteVariable.d.ts.map +1 -1
- package/dist/hooks/useUpdateVariable.d.ts +19 -3
- package/dist/hooks/useUpdateVariable.d.ts.map +1 -1
- package/dist/index-DFB8mxu_.cjs +1 -0
- package/dist/index-Dqg9kaMQ.js +150 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +49 -49
- package/dist/types/mutations.d.ts +61 -3
- package/dist/types/mutations.d.ts.map +1 -1
- package/dist/utils/filterVariables.d.ts +25 -5
- package/dist/utils/filterVariables.d.ts.map +1 -1
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/redactToken.d.ts +44 -0
- package/dist/utils/redactToken.d.ts.map +1 -0
- package/dist/utils/retry.d.ts +65 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/index-5ZyKWuYv.cjs +0 -1
- package/dist/index-ClHLYVvu.js +0 -142
package/README.md
CHANGED
|
@@ -10,24 +10,25 @@ A fast, typed React 19.2.3 hooks library for the Figma Variables API: fetch, upd
|
|
|
10
10
|
|
|
11
11
|
Built for the modern web, this library provides a suite of hooks to fetch, manage, and mutate your design tokens/variables, making it easy to sync them between Figma and your React applications, Storybooks, or design system dashboards.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
[
|
|
18
|
-
](https://www.npmjs.com/package/@figma-vars/hooks) |  |  |
|
|
16
|
+
|  | [](https://codecov.io/gh/marklearst/figma-vars-hooks) |  |
|
|
17
|
+
|  |  |  |
|
|
18
|
+
|  |  |  |
|
|
19
|
+
|
|
20
|
+
## 📌 Why 4.0.0
|
|
21
|
+
|
|
22
|
+
- ✨ **New Utilities**: `withRetry()` for automatic retry with exponential backoff, `redactToken()` for safe logging
|
|
23
|
+
- 🔧 **Flexible API**: `baseUrl` option for fetcher/mutator, `caseInsensitive` option for filterVariables
|
|
24
|
+
- 🛡️ **Better Error Handling**: Improved parsing for non-JSON API responses (HTML, plain text)
|
|
25
|
+
- 🐛 **Critical Bug Fix**: SWR cache keys now correctly separate fallback and live data
|
|
26
|
+
- 📚 **Improved Docs**: Comprehensive mutation return type documentation with examples
|
|
28
27
|
- 📦 **Modern Tooling**: Node 20+ toolchain, strict TypeScript, and ESM-first packaging with CJS interop
|
|
29
28
|
- 🖥️ **CLI Export Tool**: Automate variable exports with `figma-vars-export` for CI/CD (Enterprise required)
|
|
30
29
|
|
|
30
|
+
> ⚠️ **Breaking Change**: `useFigmaToken` is now a named export. See [Migration Guide](#-migration-guide-3x--40).
|
|
31
|
+
|
|
31
32
|
## 🚀 Features at a Glance
|
|
32
33
|
|
|
33
34
|
- **Modern React 19.2 hooks** for variables, collections, modes, and published variables
|
|
@@ -301,7 +302,7 @@ if (isLocalVariablesResponse(data)) {
|
|
|
301
302
|
|
|
302
303
|
### Error Utilities
|
|
303
304
|
|
|
304
|
-
|
|
305
|
+
v3 introduces powerful error handling utilities for type-safe error checking:
|
|
305
306
|
|
|
306
307
|
```tsx
|
|
307
308
|
import { isFigmaApiError, getErrorStatus, getErrorMessage, hasErrorStatus } from '@figma-vars/hooks'
|
|
@@ -424,11 +425,13 @@ Customize SWR behavior globally through the provider:
|
|
|
424
425
|
|
|
425
426
|
### Utilities
|
|
426
427
|
|
|
427
|
-
- **Filtering**: `filterVariables` (filter by type, name,
|
|
428
|
-
- **
|
|
428
|
+
- **Filtering**: `filterVariables` (filter by type, name, with optional `caseInsensitive` matching)
|
|
429
|
+
- **Retry**: `withRetry` (automatic retry with exponential backoff for rate limits)
|
|
430
|
+
- **Security**: `redactToken` (safely redact tokens for logging/display)
|
|
431
|
+
- **Error Handling**: `isFigmaApiError`, `getErrorStatus`, `getErrorMessage`, `hasErrorStatus`, `isRateLimited`, `getRetryAfter`
|
|
429
432
|
- **Type Guards**: `isLocalVariablesResponse`, `isPublishedVariablesResponse`, `validateFallbackData` (runtime validation)
|
|
430
433
|
- **SWR Keys**: `getVariablesKey`, `getPublishedVariablesKey`, `getInvalidationKeys` (centralized cache key construction)
|
|
431
|
-
- **Core helpers**: `fetcher`, `mutator
|
|
434
|
+
- **Core helpers**: `fetcher`, `mutator` (with `baseUrl` option), constants for endpoints and headers
|
|
432
435
|
|
|
433
436
|
### Types
|
|
434
437
|
|
|
@@ -454,13 +457,30 @@ Customize SWR behavior globally through the provider:
|
|
|
454
457
|
- Never commit PATs or file keys to git, Storybook static builds, or client bundles.
|
|
455
458
|
- Use environment variables (`process.env` / `import.meta.env`) and secret managers; keep them server-side where possible.
|
|
456
459
|
- Prefer `fallbackFile` with `token={null}`/`fileKey={null}` for demos and public Storybooks.
|
|
457
|
-
-
|
|
460
|
+
- Use `redactToken()` when logging tokens for debugging:
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
import { redactToken } from '@figma-vars/hooks'
|
|
464
|
+
|
|
465
|
+
// Safe logging
|
|
466
|
+
console.log('Using token:', redactToken(token))
|
|
467
|
+
// Output: "Using token: figd_***...***cret"
|
|
468
|
+
```
|
|
458
469
|
|
|
459
470
|
## 📈 Rate Limits
|
|
460
471
|
|
|
461
472
|
- Figma enforces per-token limits. Rely on SWR/TanStack caching, avoid unnecessary refetches, and prefer fallback JSON for static sites.
|
|
462
473
|
- Use `swrConfig` to customize `dedupingInterval` and `errorRetryCount` to optimize API usage.
|
|
463
|
-
-
|
|
474
|
+
- Use `withRetry()` utility for automatic retry with exponential backoff on 429 errors:
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
import { withRetry, fetcher } from '@figma-vars/hooks'
|
|
478
|
+
|
|
479
|
+
const fetchWithRetry = withRetry(() => fetcher('/v1/files/KEY/variables/local', token), {
|
|
480
|
+
maxRetries: 3,
|
|
481
|
+
onRetry: (attempt, delay) => console.log(`Retry ${attempt}...`),
|
|
482
|
+
})
|
|
483
|
+
```
|
|
464
484
|
|
|
465
485
|
## 📚 Storybook & Next.js
|
|
466
486
|
|
|
@@ -511,11 +531,50 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
511
531
|
- `pnpm run build`, `pnpm test`, `pnpm run test:coverage`
|
|
512
532
|
- `pnpm run check:publint`, `pnpm run check:attw`, `pnpm run check:size`
|
|
513
533
|
|
|
514
|
-
## 🧭 Release Checklist (for
|
|
534
|
+
## 🧭 Release Checklist (for 4.0.0)
|
|
515
535
|
|
|
516
536
|
- Run `pnpm run check:release`
|
|
517
|
-
-
|
|
518
|
-
-
|
|
537
|
+
- Run `pnpm version major` (creates `v4.0.0` tag)
|
|
538
|
+
- CI publishes to npm automatically
|
|
539
|
+
- Update dist-tags on npm if needed (`latest` → 4.0.0)
|
|
540
|
+
|
|
541
|
+
## 🔄 Migration Guide (3.x → 4.0)
|
|
542
|
+
|
|
543
|
+
### Breaking Change: `useFigmaToken` Export
|
|
544
|
+
|
|
545
|
+
```tsx
|
|
546
|
+
// Before (3.x) - NO LONGER WORKS
|
|
547
|
+
import useFigmaToken from '@figma-vars/hooks'
|
|
548
|
+
|
|
549
|
+
// After (4.0) - USE THIS
|
|
550
|
+
import { useFigmaToken } from '@figma-vars/hooks'
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### New Utilities (opt-in)
|
|
554
|
+
|
|
555
|
+
```ts
|
|
556
|
+
import { withRetry, redactToken, filterVariables } from '@figma-vars/hooks'
|
|
557
|
+
|
|
558
|
+
// Automatic retry with exponential backoff
|
|
559
|
+
const fetchWithRetry = withRetry(() => myApiCall(), { maxRetries: 3 })
|
|
560
|
+
|
|
561
|
+
// Safe token logging
|
|
562
|
+
console.log('Token:', redactToken(token)) // "figd_***...***cret"
|
|
563
|
+
|
|
564
|
+
// Case-insensitive filtering
|
|
565
|
+
filterVariables(vars, { name: 'primary', caseInsensitive: true })
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Custom API Base URL
|
|
569
|
+
|
|
570
|
+
```ts
|
|
571
|
+
import { fetcher, mutator } from '@figma-vars/hooks/core'
|
|
572
|
+
|
|
573
|
+
// Use mock server for testing
|
|
574
|
+
await fetcher('/v1/files/KEY/variables/local', token, {
|
|
575
|
+
baseUrl: 'http://localhost:3000',
|
|
576
|
+
})
|
|
577
|
+
```
|
|
519
578
|
|
|
520
579
|
---
|
|
521
580
|
|
package/dist/api/fetcher.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ export interface FetcherOptions {
|
|
|
16
16
|
* Optional fetch implementation override (useful for testing or custom fetch implementations).
|
|
17
17
|
*/
|
|
18
18
|
fetch?: typeof fetch;
|
|
19
|
+
/**
|
|
20
|
+
* Optional base URL override. Defaults to 'https://api.figma.com'.
|
|
21
|
+
* Useful for testing with mocks or proxies.
|
|
22
|
+
*/
|
|
23
|
+
baseUrl?: string;
|
|
19
24
|
}
|
|
20
25
|
/**
|
|
21
26
|
* Low-level utility to fetch data from the Figma Variables REST API with authentication.
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;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,CAyGpB"}
|
package/dist/api/mutator.d.ts
CHANGED
|
@@ -17,6 +17,11 @@ export interface MutatorOptions {
|
|
|
17
17
|
* Optional fetch implementation override (useful for testing or custom fetch implementations).
|
|
18
18
|
*/
|
|
19
19
|
fetch?: typeof fetch;
|
|
20
|
+
/**
|
|
21
|
+
* Optional base URL override. Defaults to 'https://api.figma.com'.
|
|
22
|
+
* Useful for testing with mocks or proxies.
|
|
23
|
+
*/
|
|
24
|
+
baseUrl?: string;
|
|
20
25
|
}
|
|
21
26
|
/**
|
|
22
27
|
* Low-level utility to send authenticated POST, PUT, or DELETE requests to the Figma Variables REST API.
|
|
@@ -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;;;;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;
|
|
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;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;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,CAwHpB"}
|
package/dist/core.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("./index-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("./index-DFB8mxu_.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, 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-
|
|
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-Dqg9kaMQ.js";
|
|
2
2
|
export {
|
|
3
3
|
A as CONTENT_TYPE_JSON,
|
|
4
4
|
R as ERROR_MSG_BULK_UPDATE_FAILED,
|
|
@@ -6,21 +6,35 @@ import { BulkUpdatePayload } from '../types/mutations';
|
|
|
6
6
|
* This hook is designed to perform a batch operation for creating, updating, and deleting variables, collections, and modes.
|
|
7
7
|
* It provides an ergonomic API with `mutate` and loading/error state for easy integration.
|
|
8
8
|
*
|
|
9
|
+
* ## Return Value
|
|
10
|
+
*
|
|
11
|
+
* The `mutate` function returns `Promise<TData | undefined>`:
|
|
12
|
+
* - On success: Returns the API response data
|
|
13
|
+
* - On error: Returns `undefined` (error stored in `error` state)
|
|
14
|
+
*
|
|
15
|
+
* Use `isSuccess`/`isError` flags or check the return value to handle results.
|
|
16
|
+
*
|
|
17
|
+
* @returns MutationResult with `mutate`, status flags (`isLoading`, `isSuccess`, `isError`),
|
|
18
|
+
* `data` (API response), and `error` (if failed).
|
|
19
|
+
*
|
|
9
20
|
* @example
|
|
10
21
|
* ```tsx
|
|
11
22
|
* import { useBulkUpdateVariables } from '@figma-vars/hooks';
|
|
12
23
|
*
|
|
13
24
|
* function BulkUpdateButton() {
|
|
14
|
-
* const { mutate, isLoading, error } = useBulkUpdateVariables();
|
|
25
|
+
* const { mutate, isLoading, isError, error } = useBulkUpdateVariables();
|
|
15
26
|
*
|
|
16
|
-
* const handleBulkUpdate = () => {
|
|
17
|
-
* mutate({
|
|
27
|
+
* const handleBulkUpdate = async () => {
|
|
28
|
+
* const result = await mutate({
|
|
18
29
|
* variables: [{ action: 'UPDATE', id: 'VariableId:123', name: 'new-name' }],
|
|
19
30
|
* });
|
|
31
|
+
* if (result) {
|
|
32
|
+
* console.log('Bulk update successful');
|
|
33
|
+
* }
|
|
20
34
|
* };
|
|
21
35
|
*
|
|
22
36
|
* if (isLoading) return <div>Updating...</div>;
|
|
23
|
-
* if (
|
|
37
|
+
* if (isError) return <div>Error: {error?.message}</div>;
|
|
24
38
|
* return <button onClick={handleBulkUpdate}>Bulk Update</button>;
|
|
25
39
|
* }
|
|
26
40
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBulkUpdateVariables.d.ts","sourceRoot":"","sources":["../../src/hooks/useBulkUpdateVariables.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAQxD
|
|
1
|
+
{"version":3,"file":"useBulkUpdateVariables.d.ts","sourceRoot":"","sources":["../../src/hooks/useBulkUpdateVariables.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAQxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,sBAAsB,4EAiBlC,CAAA"}
|
|
@@ -5,19 +5,37 @@ import { CreateVariablePayload } from '../types/mutations';
|
|
|
5
5
|
* @remarks
|
|
6
6
|
* The hook returns a `mutate` function to trigger the creation along with state flags and data.
|
|
7
7
|
*
|
|
8
|
+
* ## Return Value
|
|
9
|
+
*
|
|
10
|
+
* The `mutate` function returns `Promise<TData | undefined>`:
|
|
11
|
+
* - On success: Returns the API response data
|
|
12
|
+
* - On error: Returns `undefined` (error stored in `error` state)
|
|
13
|
+
*
|
|
14
|
+
* Use `isSuccess`/`isError` flags or check the return value to handle results.
|
|
15
|
+
*
|
|
16
|
+
* @returns MutationResult with `mutate`, status flags (`isLoading`, `isSuccess`, `isError`),
|
|
17
|
+
* `data` (API response), and `error` (if failed).
|
|
18
|
+
*
|
|
8
19
|
* @example
|
|
9
20
|
* ```tsx
|
|
10
21
|
* import { useCreateVariable } from '@figma-vars/hooks';
|
|
11
22
|
*
|
|
12
23
|
* function CreateVariableButton() {
|
|
13
|
-
* const { mutate, isLoading, error } = useCreateVariable();
|
|
24
|
+
* const { mutate, isLoading, isError, error } = useCreateVariable();
|
|
14
25
|
*
|
|
15
|
-
* const handleCreate = () => {
|
|
16
|
-
*
|
|
26
|
+
* const handleCreate = async () => {
|
|
27
|
+
* const result = await mutate({
|
|
28
|
+
* name: 'new-variable',
|
|
29
|
+
* variableCollectionId: 'VariableCollectionId:1:1',
|
|
30
|
+
* resolvedType: 'COLOR'
|
|
31
|
+
* });
|
|
32
|
+
* if (result) {
|
|
33
|
+
* console.log('Created successfully:', result);
|
|
34
|
+
* }
|
|
17
35
|
* };
|
|
18
36
|
*
|
|
19
37
|
* if (isLoading) return <div>Creating...</div>;
|
|
20
|
-
* if (
|
|
38
|
+
* if (isError) return <div>Error: {error?.message}</div>;
|
|
21
39
|
* return <button onClick={handleCreate}>Create Variable</button>;
|
|
22
40
|
* }
|
|
23
41
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCreateVariable.d.ts","sourceRoot":"","sources":["../../src/hooks/useCreateVariable.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAQ5D
|
|
1
|
+
{"version":3,"file":"useCreateVariable.d.ts","sourceRoot":"","sources":["../../src/hooks/useCreateVariable.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAQ5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,eAAO,MAAM,iBAAiB,gFAmB7B,CAAA"}
|
|
@@ -4,17 +4,33 @@
|
|
|
4
4
|
* @remarks
|
|
5
5
|
* This hook provides a `mutate` function to trigger the deletion and exposes loading and error states.
|
|
6
6
|
*
|
|
7
|
+
* ## Return Value
|
|
8
|
+
*
|
|
9
|
+
* The `mutate` function returns `Promise<TData | undefined>`:
|
|
10
|
+
* - On success: Returns the API response data
|
|
11
|
+
* - On error: Returns `undefined` (error stored in `error` state)
|
|
12
|
+
*
|
|
13
|
+
* Use `isSuccess`/`isError` flags or check the return value to handle results.
|
|
14
|
+
*
|
|
15
|
+
* @returns MutationResult with `mutate`, status flags (`isLoading`, `isSuccess`, `isError`),
|
|
16
|
+
* `data` (API response), and `error` (if failed).
|
|
17
|
+
*
|
|
7
18
|
* @example
|
|
8
19
|
* ```tsx
|
|
9
20
|
* import { useDeleteVariable } from '@figma-vars/hooks';
|
|
10
21
|
*
|
|
11
22
|
* function DeleteVariableButton({ id }: { id: string }) {
|
|
12
|
-
* const { mutate, isLoading, error } = useDeleteVariable();
|
|
23
|
+
* const { mutate, isLoading, isError, error } = useDeleteVariable();
|
|
13
24
|
*
|
|
14
|
-
* const onDelete = () =>
|
|
25
|
+
* const onDelete = async () => {
|
|
26
|
+
* const result = await mutate(id);
|
|
27
|
+
* if (result) {
|
|
28
|
+
* console.log('Deleted successfully');
|
|
29
|
+
* }
|
|
30
|
+
* };
|
|
15
31
|
*
|
|
16
32
|
* if (isLoading) return <div>Deleting...</div>;
|
|
17
|
-
* if (
|
|
33
|
+
* if (isError) return <div>Error: {error?.message}</div>;
|
|
18
34
|
* return <button onClick={onDelete}>Delete Variable</button>;
|
|
19
35
|
* }
|
|
20
36
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDeleteVariable.d.ts","sourceRoot":"","sources":["../../src/hooks/useDeleteVariable.ts"],"names":[],"mappings":"AASA
|
|
1
|
+
{"version":3,"file":"useDeleteVariable.d.ts","sourceRoot":"","sources":["../../src/hooks/useDeleteVariable.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,iBAAiB,oDAmB7B,CAAA"}
|
|
@@ -5,17 +5,33 @@ import { UpdateVariablePayload } from '../types/mutations';
|
|
|
5
5
|
* @remarks
|
|
6
6
|
* The hook returns a `mutate` function to trigger the update with given payload and exposes state flags.
|
|
7
7
|
*
|
|
8
|
+
* ## Return Value
|
|
9
|
+
*
|
|
10
|
+
* The `mutate` function returns `Promise<TData | undefined>`:
|
|
11
|
+
* - On success: Returns the API response data
|
|
12
|
+
* - On error: Returns `undefined` (error stored in `error` state)
|
|
13
|
+
*
|
|
14
|
+
* Use `isSuccess`/`isError` flags or check the return value to handle results.
|
|
15
|
+
*
|
|
16
|
+
* @returns MutationResult with `mutate`, status flags (`isLoading`, `isSuccess`, `isError`),
|
|
17
|
+
* `data` (API response), and `error` (if failed).
|
|
18
|
+
*
|
|
8
19
|
* @example
|
|
9
20
|
* ```tsx
|
|
10
21
|
* import { useUpdateVariable } from '@figma-vars/hooks';
|
|
11
22
|
*
|
|
12
23
|
* function UpdateVariableButton({ id }: { id: string }) {
|
|
13
|
-
* const { mutate, isLoading, error } = useUpdateVariable();
|
|
24
|
+
* const { mutate, isLoading, isError, error } = useUpdateVariable();
|
|
14
25
|
*
|
|
15
|
-
* const onUpdate = () =>
|
|
26
|
+
* const onUpdate = async () => {
|
|
27
|
+
* const result = await mutate({ variableId: id, payload: { name: 'new-name' } });
|
|
28
|
+
* if (result) {
|
|
29
|
+
* console.log('Updated successfully');
|
|
30
|
+
* }
|
|
31
|
+
* };
|
|
16
32
|
*
|
|
17
33
|
* if (isLoading) return <div>Updating...</div>;
|
|
18
|
-
* if (
|
|
34
|
+
* if (isError) return <div>Error: {error?.message}</div>;
|
|
19
35
|
* return <button onClick={onUpdate}>Update Variable</button>;
|
|
20
36
|
* }
|
|
21
37
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useUpdateVariable.d.ts","sourceRoot":"","sources":["../../src/hooks/useUpdateVariable.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAQ5D
|
|
1
|
+
{"version":3,"file":"useUpdateVariable.d.ts","sourceRoot":"","sources":["../../src/hooks/useUpdateVariable.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAQ5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,iBAAiB;gBAOZ,MAAM;aACT,qBAAqB;EAyBnC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var y=Object.defineProperty;var N=(e,s,r)=>s in e?y(e,s,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[s]=r;var g=(e,s,r)=>N(e,typeof s!="symbol"?s+"":s,r);const L="https://api.figma.com",O=`${L}/v1/files`,v=e=>`/v1/files/${e}/variables/published`,P=e=>`/v1/files/${e}/variables`,w=e=>`${O}/${e}/variables/local`,D="application/json",S="X-FIGMA-TOKEN",m="A Figma API token is required.",B=`${m} and file key are required.`,U="Failed to perform bulk update.",b="Failed to create Figma variable.",C="Failed to delete Figma variable.",x="Failed to update Figma variable.",G="An error occurred while fetching data from the Figma API.";class h extends Error{constructor(r,o,l){super(r);g(this,"statusCode");g(this,"retryAfter");this.name="FigmaApiError",this.statusCode=o,this.retryAfter=l??void 0,Error.captureStackTrace&&Error.captureStackTrace(this,h)}}async function V(e,s,r){if(!s)throw new Error(m);const{signal:o,timeout:l,fetch:F=fetch,baseUrl:f=L}=r??{};let E,A;const i=o||(l?(A=new AbortController,E=setTimeout(()=>{A==null||A.abort()},l),A.signal):void 0);try{const c=e.startsWith("http://")||e.startsWith("https://")?e:`${f}${e.startsWith("/")?"":"/"}${e}`,a=await F(c,{method:"GET",headers:{[S]:s,"Content-Type":D},...i!==void 0&&{signal:i}});if(E!==void 0&&(clearTimeout(E),E=void 0),!a.ok){let R=G;const u=a.status;let I;if(u===429){const _=a.headers.get("Retry-After");if(_){const t=parseInt(_,10);Number.isNaN(t)||(I=t)}}try{const _=a.headers.get("content-type")??"";if(_.includes("application/json")){const t=await a.json();t!=null&&t.message?R=t.message:t!=null&&t.err&&(R=t.err)}else if(_.includes("text/plain")||_.includes("text/html")){const t=await a.text();t&&(R=t.length>200?`${t.slice(0,200)}...`:t)}}catch{}throw new h(R,u,I)}return a.json()}catch(c){throw E!==void 0&&(clearTimeout(E),E=void 0),c}}async function $(e,s,r,o,l){if(!s)throw new Error(m);const{signal:F,timeout:f,fetch:E=fetch,baseUrl:A=L}=l??{};let i,c;const a=F||(f?(c=new AbortController,i=setTimeout(()=>{c==null||c.abort()},f),c.signal):void 0);try{const I={method:{CREATE:"POST",UPDATE:"PUT",DELETE:"DELETE"}[r],headers:{"Content-Type":"application/json",[S]:s},...a!==void 0&&{signal:a}};o&&(I.body=JSON.stringify(o));const _=e.startsWith("http://")||e.startsWith("https://")?e:`${A}${e.startsWith("/")?"":"/"}${e}`,t=await E(_,I);if(i!==void 0&&(clearTimeout(i),i=void 0),!t.ok){const p=t.status;let T="An API error occurred",M;if(p===429){const d=t.headers.get("Retry-After");if(d){const n=parseInt(d,10);Number.isNaN(n)||(M=n)}}try{const d=t.headers.get("content-type")??"";if(d.includes("application/json")){const n=await t.json();T=n.err||n.message||T}else if(d.includes("text/plain")||d.includes("text/html")){const n=await t.text();n&&(T=n.length>200?`${n.slice(0,200)}...`:n)}}catch{}throw new h(T,p,M)}return t.status===204||!t.body?{}:t.json()}catch(R){throw i!==void 0&&(clearTimeout(i),i=void 0),R}}function H(e,s){return e.filter(r=>{let o=!0;return s.resolvedType&&(o=o&&r.resolvedType===s.resolvedType),s.name&&(s.caseInsensitive?o=o&&r.name.toLowerCase().includes(s.name.toLowerCase()):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=b;exports.ERROR_MSG_DELETE_VARIABLE_FAILED=C;exports.ERROR_MSG_FETCH_FIGMA_DATA_FAILED=G;exports.ERROR_MSG_TOKEN_FILE_KEY_REQUIRED=B;exports.ERROR_MSG_TOKEN_REQUIRED=m;exports.ERROR_MSG_UPDATE_VARIABLE_FAILED=x;exports.FIGMA_API_BASE_URL=L;exports.FIGMA_FILES_ENDPOINT=O;exports.FIGMA_FILE_VARIABLES_PATH=P;exports.FIGMA_LOCAL_VARIABLES_ENDPOINT=w;exports.FIGMA_PUBLISHED_VARIABLES_PATH=v;exports.FIGMA_TOKEN_HEADER=S;exports.FigmaApiError=h;exports.fetcher=V;exports.filterVariables=H;exports.mutator=$;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
var w = Object.defineProperty;
|
|
2
|
+
var S = (e, s, a) => s in e ? w(e, s, { enumerable: !0, configurable: !0, writable: !0, value: a }) : e[s] = a;
|
|
3
|
+
var g = (e, s, a) => S(e, typeof s != "symbol" ? s + "" : s, a);
|
|
4
|
+
const F = "https://api.figma.com", M = `${F}/v1/files`, D = (e) => `/v1/files/${e}/variables/published`, G = (e) => `/v1/files/${e}/variables`, P = (e) => `${M}/${e}/variables/local`, N = "application/json", v = "X-FIGMA-TOKEN", L = "A Figma API token is required.", C = `${L} and file key are required.`, $ = "Failed to perform bulk update.", U = "Failed to create Figma variable.", B = "Failed to delete Figma variable.", j = "Failed to update Figma variable.", O = "An error occurred while fetching data from the Figma API.";
|
|
5
|
+
class u extends Error {
|
|
6
|
+
constructor(a, o, f) {
|
|
7
|
+
super(a);
|
|
8
|
+
/** HTTP status code from the API response. */
|
|
9
|
+
g(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
|
+
g(this, "retryAfter");
|
|
15
|
+
this.name = "FigmaApiError", this.statusCode = o, this.retryAfter = f ?? void 0, Error.captureStackTrace && Error.captureStackTrace(this, u);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function H(e, s, a) {
|
|
19
|
+
if (!s)
|
|
20
|
+
throw new Error(L);
|
|
21
|
+
const {
|
|
22
|
+
signal: o,
|
|
23
|
+
timeout: f,
|
|
24
|
+
fetch: T = fetch,
|
|
25
|
+
baseUrl: _ = F
|
|
26
|
+
} = a ?? {};
|
|
27
|
+
let c, E;
|
|
28
|
+
const r = o || (f ? (E = new AbortController(), c = setTimeout(() => {
|
|
29
|
+
E == null || E.abort();
|
|
30
|
+
}, f), E.signal) : void 0);
|
|
31
|
+
try {
|
|
32
|
+
const l = e.startsWith("http://") || e.startsWith("https://") ? e : `${_}${e.startsWith("/") ? "" : "/"}${e}`, i = await T(l, {
|
|
33
|
+
method: "GET",
|
|
34
|
+
headers: {
|
|
35
|
+
[v]: s,
|
|
36
|
+
"Content-Type": N
|
|
37
|
+
},
|
|
38
|
+
...r !== void 0 && { signal: r }
|
|
39
|
+
});
|
|
40
|
+
if (c !== void 0 && (clearTimeout(c), c = void 0), !i.ok) {
|
|
41
|
+
let h = O;
|
|
42
|
+
const R = i.status;
|
|
43
|
+
let m;
|
|
44
|
+
if (R === 429) {
|
|
45
|
+
const d = i.headers.get("Retry-After");
|
|
46
|
+
if (d) {
|
|
47
|
+
const t = parseInt(d, 10);
|
|
48
|
+
Number.isNaN(t) || (m = t);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const d = i.headers.get("content-type") ?? "";
|
|
53
|
+
if (d.includes("application/json")) {
|
|
54
|
+
const t = await i.json();
|
|
55
|
+
t != null && t.message ? h = t.message : t != null && t.err && (h = t.err);
|
|
56
|
+
} else if (d.includes("text/plain") || d.includes("text/html")) {
|
|
57
|
+
const t = await i.text();
|
|
58
|
+
t && (h = t.length > 200 ? `${t.slice(0, 200)}...` : t);
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
throw new u(h, R, m);
|
|
63
|
+
}
|
|
64
|
+
return i.json();
|
|
65
|
+
} catch (l) {
|
|
66
|
+
throw c !== void 0 && (clearTimeout(c), c = void 0), l;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function V(e, s, a, o, f) {
|
|
70
|
+
if (!s)
|
|
71
|
+
throw new Error(L);
|
|
72
|
+
const {
|
|
73
|
+
signal: T,
|
|
74
|
+
timeout: _,
|
|
75
|
+
fetch: c = fetch,
|
|
76
|
+
baseUrl: E = F
|
|
77
|
+
} = f ?? {};
|
|
78
|
+
let r, l;
|
|
79
|
+
const i = T || (_ ? (l = new AbortController(), r = setTimeout(() => {
|
|
80
|
+
l == null || l.abort();
|
|
81
|
+
}, _), l.signal) : void 0);
|
|
82
|
+
try {
|
|
83
|
+
const m = {
|
|
84
|
+
method: {
|
|
85
|
+
CREATE: "POST",
|
|
86
|
+
UPDATE: "PUT",
|
|
87
|
+
DELETE: "DELETE"
|
|
88
|
+
}[a],
|
|
89
|
+
headers: {
|
|
90
|
+
"Content-Type": "application/json",
|
|
91
|
+
[v]: s
|
|
92
|
+
},
|
|
93
|
+
...i !== void 0 && { signal: i }
|
|
94
|
+
};
|
|
95
|
+
o && (m.body = JSON.stringify(o));
|
|
96
|
+
const d = e.startsWith("http://") || e.startsWith("https://") ? e : `${E}${e.startsWith("/") ? "" : "/"}${e}`, t = await c(d, m);
|
|
97
|
+
if (r !== void 0 && (clearTimeout(r), r = void 0), !t.ok) {
|
|
98
|
+
const I = t.status;
|
|
99
|
+
let p = "An API error occurred", y;
|
|
100
|
+
if (I === 429) {
|
|
101
|
+
const A = t.headers.get("Retry-After");
|
|
102
|
+
if (A) {
|
|
103
|
+
const n = parseInt(A, 10);
|
|
104
|
+
Number.isNaN(n) || (y = n);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const A = t.headers.get("content-type") ?? "";
|
|
109
|
+
if (A.includes("application/json")) {
|
|
110
|
+
const n = await t.json();
|
|
111
|
+
p = n.err || n.message || p;
|
|
112
|
+
} else if (A.includes("text/plain") || A.includes("text/html")) {
|
|
113
|
+
const n = await t.text();
|
|
114
|
+
n && (p = n.length > 200 ? `${n.slice(0, 200)}...` : n);
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
throw new u(p, I, y);
|
|
119
|
+
}
|
|
120
|
+
return t.status === 204 || !t.body ? {} : t.json();
|
|
121
|
+
} catch (h) {
|
|
122
|
+
throw r !== void 0 && (clearTimeout(r), r = void 0), h;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function k(e, s) {
|
|
126
|
+
return e.filter((a) => {
|
|
127
|
+
let o = !0;
|
|
128
|
+
return s.resolvedType && (o = o && a.resolvedType === s.resolvedType), s.name && (s.caseInsensitive ? o = o && a.name.toLowerCase().includes(s.name.toLowerCase()) : o = o && a.name.includes(s.name)), o;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
export {
|
|
132
|
+
N as C,
|
|
133
|
+
L as E,
|
|
134
|
+
G as F,
|
|
135
|
+
C as a,
|
|
136
|
+
u as b,
|
|
137
|
+
k as c,
|
|
138
|
+
F as d,
|
|
139
|
+
M as e,
|
|
140
|
+
H as f,
|
|
141
|
+
D as g,
|
|
142
|
+
P as h,
|
|
143
|
+
v as i,
|
|
144
|
+
$ as j,
|
|
145
|
+
U as k,
|
|
146
|
+
B as l,
|
|
147
|
+
V as m,
|
|
148
|
+
j as n,
|
|
149
|
+
O as o
|
|
150
|
+
};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("react/jsx-runtime"),u=require("react"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("react/jsx-runtime"),u=require("react"),v=require("swr"),i=require("./index-DFB8mxu_.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(),d=u.useMemo(()=>`figma-vars-provider-${a}`,[a]),l=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),f=_(n);if(f)return f;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:d,...s!==void 0&&{swrConfig:s}};return o===void 0?n:{...n,fallbackFile:o,parsedFallbackFile:l}},[r,t,o,l,d,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 s?[`fallback-${o??"default"}`,"fallback"]:t&&r?[`https://api.figma.com/v1/files/${r}/variables/local`,t]:null}function O(e){const{fileKey:r,token:t,providerId:o,hasFallback:s}=e;return s?[`fallback-${o??"default"}`,"fallback"]:t&&r?[`https://api.figma.com/v1/files/${r}/variables/published`,t]: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(),l=M({fileKey:r,token:e,providerId:s,hasFallback:!!(t||o)});return v(l,async(...n)=>{if(o)return o;if(t&&typeof t=="object")return t;const[f,E]=Array.isArray(n[0])?n[0]:[n[0],n[1]];if(!f||!E)throw new Error("Missing URL or token for live API request");return i.fetcher(f,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 m=(e,r)=>{const{throwOnError:t=!1}={},o={status:"idle",data:null,error:null},[s,a]=u.useReducer(T,o),d=u.useRef(e),l=u.useRef({throwOnError:t}),c=u.useRef(!0),n=u.useRef(0);return u.useEffect(()=>{d.current=e,l.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 d.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}),l.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 m(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}]})})},P=()=>{const{token:e,fileKey:r}=b();return m(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}]})})},D=()=>{const{token:e,fileKey:r}=b();return m(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}]})})},L=()=>{const{token:e,fileKey:r}=b();return m(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}=v.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(),l=O({fileKey:r,token:e,providerId:s,hasFallback:!!(t||o)});return v(l,async(...n)=>{if(o)return o;if(t&&typeof t=="object")return t;const[f,E]=Array.isArray(n[0])?n[0]:[n[0],n[1]];if(!f||!E)throw new Error("Missing URL or token for live API request");return i.fetcher(f,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 x(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=x;exports.isFigmaApiError=w;exports.useBulkUpdateVariables=L;exports.useCreateVariable=C;exports.useDeleteVariable=D;exports.useInvalidateVariables=U;exports.usePublishedVariables=N;exports.useUpdateVariable=P;exports.useVariableCollections=S;exports.useVariableModes=K;exports.useVariables=R;
|