From 77d49319ff7959a961e79cbe86a789aca41cbb26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Francisco?= <4301103+tomasfrancisco@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:45:59 +0200 Subject: [PATCH] Figma Widget (#27) --- apps/dashboard/next.config.mjs | 26 + packages/api/src/router/resources.ts | 8 +- packages/components/package.json | 1 + packages/components/src/index.ts | 1 + packages/components/src/separator/index.ts | 1 + .../components/src/separator/separator.tsx | 33 + packages/components/vite.config.ts | 2 +- .../migrations/0003_stormy_jasper_sitwell.sql | 2 + .../src/migrations/meta/0003_snapshot.json | 368 +++++ .../src/migrations/meta/_journal.json | 7 + .../src/schema/resources/resources.ts | 45 +- packages/figma-plugin/LICENSE | 427 ------ packages/figma-plugin/README.md | 140 -- packages/figma-plugin/manifest.json | 9 - packages/figma-plugin/package.json | 60 - packages/figma-plugin/src/message.ts | 179 --- packages/figma-plugin/src/message.types.ts | 134 -- packages/figma-plugin/src/plugin/plugin.ts | 75 - packages/figma-plugin/src/plugin/storage.ts | 26 - .../src/plugin/variables/get-file-id.ts | 28 - .../variables/utils/get-figma-variables.ts | 56 - .../variables/utils/transformers/color.ts | 78 - .../utils/transformers/figma-variable.ts | 35 - .../variables/utils/transformers/index.ts | 6 - packages/figma-plugin/src/ui/app.tsx | 66 - .../ui/modules/providers/config-provider.tsx | 41 - packages/figma-plugin/tsconfig.node.json | 9 - .../eslint.config.js | 7 +- packages/figma-utilities/package.json | 37 + packages/figma-utilities/src/config-data.ts | 7 + .../src}/credentials.ts | 0 packages/figma-utilities/src/events.ts | 122 ++ packages/figma-utilities/src/index.ts | 3 + packages/figma-utilities/tsconfig.json | 8 + packages/figma-widget/README.md | 46 + packages/figma-widget/eslint.config.js | 20 + packages/figma-widget/manifest.json | 14 + packages/figma-widget/package.json | 60 + .../postcss.config.mjs | 1 + packages/figma-widget/src/ui/app.tsx | 21 + .../src/ui/components/container.tsx | 7 + .../src/ui/config.ts | 0 .../src/ui/globals.css | 0 packages/figma-widget/src/ui/globals.d.ts | 10 + .../src/ui}/index.html | 7 +- .../src/ui/lib/query-client.ts | 0 packages/figma-widget/src/ui/lib/wait.ts | 2 + .../src/ui/main.tsx | 8 +- packages/figma-widget/src/ui/modules/auth.tsx | 24 + .../ui/modules/link-design-system/index.ts | 0 .../link-design-system/link-design-system.tsx | 9 +- .../src/ui/modules/project/project.ui.tsx | 53 + .../src/ui/modules/providers/api-provider.tsx | 0 .../ui/modules/providers/auth-provider.tsx | 116 +- .../ui/modules/providers/config-provider.tsx | 29 + .../src/ui/modules/providers/index.tsx | 18 +- .../modules/providers/projects-provider.tsx | 52 +- .../src/ui/modules/variables.ui.tsx | 40 + .../src/ui}/tsconfig.json | 9 +- .../src => figma-widget/src/ui}/vite-env.d.ts | 2 - .../src/widget/components/button.tsx | 78 + .../src/widget/components/container.tsx | 76 + .../src/widget/components/divider.tsx | 12 + .../src/widget/components/link.tsx | 26 + .../src/widget/components/project.tsx | 34 + .../src/widget/components/variables.tsx | 56 + .../src/widget}/config.ts | 0 packages/figma-widget/src/widget/hooks/ui.ts | 49 + .../figma-widget/src/widget/icons/caret.ts | 5 + .../src/widget/icons/external-link.ts | 2 + .../figma-widget/src/widget/icons/update.ts | 2 + .../figma-widget/src/widget/lib/widget.ts | 30 + packages/figma-widget/src/widget/main.tsx | 26 + .../src/widget/modules/auth/auth-warning.tsx | 34 + .../src/widget/modules/auth/auth.actions.tsx | 29 + .../src/widget/modules/auth/auth.events.tsx | 13 + .../widget/modules/auth/connect-button.tsx | 15 + .../design-tokens/extract-design-tokens.ts | 0 .../design-tokens/extractors/boolean.ts | 1 - .../design-tokens/extractors/color.ts | 2 +- .../design-tokens/extractors/extract-alias.ts | 0 .../extractors/extract-mode-variable.ts | 0 .../extractors/extract-variable.ts | 0 .../design-tokens/extractors/float.ts | 2 +- .../design-tokens/extractors/string.ts | 0 .../extractors/variable-collection.ts | 0 .../design-tokens/filters/not-implemented.ts | 0 .../design-tokens/transformers/color.ts | 0 .../design-tokens/transformers/index.ts | 0 .../modules}/design-tokens/types/figma.ts | 0 .../modules}/design-tokens/types/index.ts | 0 .../design-tokens/utils/combine-paths.ts | 0 .../design-tokens/utils/get-mode-key.ts | 0 .../utils/get-variable-collection.ts | 0 .../design-tokens/utils/non-nullable.ts | 0 .../design-tokens/utils/tokenize-variable.ts | 0 .../widget/modules/project/project-select.tsx | 29 + .../modules/project/project-warning.tsx | 23 + .../modules/project/project.actions.tsx | 33 + .../widget/modules/project/project.events.tsx | 13 + .../figma-widget/src/widget/modules/state.ts | 17 + .../modules/variables/variables-sync.tsx | 17 + .../modules/variables/variables.actions.ts | 32 + .../modules/variables/variables.events.ts | 3 + .../figma-widget/src/widget/tsconfig.json | 17 + .../tailwind.config.ts | 10 +- .../vite.config.ts | 5 +- .../vite.config.widget.ts} | 11 +- pnpm-lock.yaml | 1335 ++++++++--------- pnpm-workspace.yaml | 3 +- 110 files changed, 2422 insertions(+), 2213 deletions(-) create mode 100644 packages/components/src/separator/index.ts create mode 100644 packages/components/src/separator/separator.tsx create mode 100644 packages/database/src/migrations/0003_stormy_jasper_sitwell.sql create mode 100644 packages/database/src/migrations/meta/0003_snapshot.json delete mode 100644 packages/figma-plugin/LICENSE delete mode 100644 packages/figma-plugin/README.md delete mode 100644 packages/figma-plugin/manifest.json delete mode 100644 packages/figma-plugin/package.json delete mode 100644 packages/figma-plugin/src/message.ts delete mode 100644 packages/figma-plugin/src/message.types.ts delete mode 100644 packages/figma-plugin/src/plugin/plugin.ts delete mode 100644 packages/figma-plugin/src/plugin/storage.ts delete mode 100644 packages/figma-plugin/src/plugin/variables/get-file-id.ts delete mode 100644 packages/figma-plugin/src/plugin/variables/utils/get-figma-variables.ts delete mode 100644 packages/figma-plugin/src/plugin/variables/utils/transformers/color.ts delete mode 100644 packages/figma-plugin/src/plugin/variables/utils/transformers/figma-variable.ts delete mode 100644 packages/figma-plugin/src/plugin/variables/utils/transformers/index.ts delete mode 100644 packages/figma-plugin/src/ui/app.tsx delete mode 100644 packages/figma-plugin/src/ui/modules/providers/config-provider.tsx delete mode 100644 packages/figma-plugin/tsconfig.node.json rename packages/{figma-plugin => figma-utilities}/eslint.config.js (76%) create mode 100644 packages/figma-utilities/package.json create mode 100644 packages/figma-utilities/src/config-data.ts rename packages/{figma-plugin/src/types => figma-utilities/src}/credentials.ts (100%) create mode 100644 packages/figma-utilities/src/events.ts create mode 100644 packages/figma-utilities/src/index.ts create mode 100644 packages/figma-utilities/tsconfig.json create mode 100644 packages/figma-widget/README.md create mode 100644 packages/figma-widget/eslint.config.js create mode 100644 packages/figma-widget/manifest.json create mode 100644 packages/figma-widget/package.json rename packages/{figma-plugin => figma-widget}/postcss.config.mjs (85%) create mode 100644 packages/figma-widget/src/ui/app.tsx create mode 100644 packages/figma-widget/src/ui/components/container.tsx rename packages/{figma-plugin => figma-widget}/src/ui/config.ts (100%) rename packages/{figma-plugin => figma-widget}/src/ui/globals.css (100%) create mode 100644 packages/figma-widget/src/ui/globals.d.ts rename packages/{figma-plugin => figma-widget/src/ui}/index.html (56%) rename packages/{figma-plugin => figma-widget}/src/ui/lib/query-client.ts (100%) create mode 100644 packages/figma-widget/src/ui/lib/wait.ts rename packages/{figma-plugin => figma-widget}/src/ui/main.tsx (80%) create mode 100644 packages/figma-widget/src/ui/modules/auth.tsx rename packages/{figma-plugin => figma-widget}/src/ui/modules/link-design-system/index.ts (100%) rename packages/{figma-plugin => figma-widget}/src/ui/modules/link-design-system/link-design-system.tsx (84%) create mode 100644 packages/figma-widget/src/ui/modules/project/project.ui.tsx rename packages/{figma-plugin => figma-widget}/src/ui/modules/providers/api-provider.tsx (100%) rename packages/{figma-plugin => figma-widget}/src/ui/modules/providers/auth-provider.tsx (60%) create mode 100644 packages/figma-widget/src/ui/modules/providers/config-provider.tsx rename packages/{figma-plugin => figma-widget}/src/ui/modules/providers/index.tsx (52%) rename packages/{figma-plugin => figma-widget}/src/ui/modules/providers/projects-provider.tsx (62%) create mode 100644 packages/figma-widget/src/ui/modules/variables.ui.tsx rename packages/{figma-plugin => figma-widget/src/ui}/tsconfig.json (75%) rename packages/{figma-plugin/src => figma-widget/src/ui}/vite-env.d.ts (61%) create mode 100644 packages/figma-widget/src/widget/components/button.tsx create mode 100644 packages/figma-widget/src/widget/components/container.tsx create mode 100644 packages/figma-widget/src/widget/components/divider.tsx create mode 100644 packages/figma-widget/src/widget/components/link.tsx create mode 100644 packages/figma-widget/src/widget/components/project.tsx create mode 100644 packages/figma-widget/src/widget/components/variables.tsx rename packages/{figma-plugin/src/plugin => figma-widget/src/widget}/config.ts (100%) create mode 100644 packages/figma-widget/src/widget/hooks/ui.ts create mode 100644 packages/figma-widget/src/widget/icons/caret.ts create mode 100644 packages/figma-widget/src/widget/icons/external-link.ts create mode 100644 packages/figma-widget/src/widget/icons/update.ts create mode 100644 packages/figma-widget/src/widget/lib/widget.ts create mode 100644 packages/figma-widget/src/widget/main.tsx create mode 100644 packages/figma-widget/src/widget/modules/auth/auth-warning.tsx create mode 100644 packages/figma-widget/src/widget/modules/auth/auth.actions.tsx create mode 100644 packages/figma-widget/src/widget/modules/auth/auth.events.tsx create mode 100644 packages/figma-widget/src/widget/modules/auth/connect-button.tsx rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/extract-design-tokens.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/extractors/boolean.ts (95%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/extractors/color.ts (96%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/extractors/extract-alias.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/extractors/extract-mode-variable.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/extractors/extract-variable.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/extractors/float.ts (96%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/extractors/string.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/extractors/variable-collection.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/filters/not-implemented.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/transformers/color.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/transformers/index.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/types/figma.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/types/index.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/utils/combine-paths.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/utils/get-mode-key.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/utils/get-variable-collection.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/utils/non-nullable.ts (100%) rename packages/{figma-plugin/src/plugin => figma-widget/src/widget/modules}/design-tokens/utils/tokenize-variable.ts (100%) create mode 100644 packages/figma-widget/src/widget/modules/project/project-select.tsx create mode 100644 packages/figma-widget/src/widget/modules/project/project-warning.tsx create mode 100644 packages/figma-widget/src/widget/modules/project/project.actions.tsx create mode 100644 packages/figma-widget/src/widget/modules/project/project.events.tsx create mode 100644 packages/figma-widget/src/widget/modules/state.ts create mode 100644 packages/figma-widget/src/widget/modules/variables/variables-sync.tsx create mode 100644 packages/figma-widget/src/widget/modules/variables/variables.actions.ts create mode 100644 packages/figma-widget/src/widget/modules/variables/variables.events.ts create mode 100644 packages/figma-widget/src/widget/tsconfig.json rename packages/{figma-plugin => figma-widget}/tailwind.config.ts (51%) rename packages/{figma-plugin => figma-widget}/vite.config.ts (74%) rename packages/{figma-plugin/vite.config.plugin.ts => figma-widget/vite.config.widget.ts} (70%) diff --git a/apps/dashboard/next.config.mjs b/apps/dashboard/next.config.mjs index bc442a8..60bffd2 100644 --- a/apps/dashboard/next.config.mjs +++ b/apps/dashboard/next.config.mjs @@ -18,6 +18,32 @@ const nextConfig = { ], }, + async headers() { + return [ + { + source: '/api/:path*', + headers: [ + { + key: 'Access-Control-Allow-Credentials', + value: 'true', + }, + { + key: 'Access-Control-Allow-Origin', + value: '*', // TODO: Perhaps set figma origin instead? + }, + { + key: 'Access-Control-Allow-Methods', + value: 'POST, PUT, DELETE, OPTIONS', + }, + { + key: 'Access-Control-Allow-Headers', + value: 'Content-Type, Authorization', + }, + ], + }, + ]; + }, + async rewrites() { return [ { diff --git a/packages/api/src/router/resources.ts b/packages/api/src/router/resources.ts index 144207b..df50518 100644 --- a/packages/api/src/router/resources.ts +++ b/packages/api/src/router/resources.ts @@ -66,7 +66,7 @@ export const resourcesRouter = createTRPCRouter({ designTokens: PreprocessedTokensSchema.parse(input.designTokens), }) .onConflictDoUpdate({ - target: Resources.name, + target: [Resources.name, Resources.projectId], set: { designTokens: PreprocessedTokensSchema.parse(input.designTokens), }, @@ -77,7 +77,11 @@ export const resourcesRouter = createTRPCRouter({ if (!resource) return resource; - await release({ ctx, designTokens: resource.insertedDesignTokens }); + try { + await release({ ctx, designTokens: resource.insertedDesignTokens }); + } catch (error) { + console.error('๐Ÿ’ฅ error releasing', error); + } return resource; }), diff --git a/packages/components/package.json b/packages/components/package.json index 3742327..11c732d 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -43,6 +43,7 @@ "@radix-ui/react-navigation-menu": "^1.2.0", "@radix-ui/react-popover": "^1.1.1", "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-switch": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 5d5fc0a..83e3da6 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -15,6 +15,7 @@ export * from './menubar'; export * from './navigation-menu'; export * from './popover'; export * from './select'; +export * from './separator'; export * from './switch'; export * from './tabs'; export * from './text'; diff --git a/packages/components/src/separator/index.ts b/packages/components/src/separator/index.ts new file mode 100644 index 0000000..68fc331 --- /dev/null +++ b/packages/components/src/separator/index.ts @@ -0,0 +1 @@ +export * from './separator'; diff --git a/packages/components/src/separator/separator.tsx b/packages/components/src/separator/separator.tsx new file mode 100644 index 0000000..277177e --- /dev/null +++ b/packages/components/src/separator/separator.tsx @@ -0,0 +1,33 @@ +'use client'; + +import * as React from 'react'; +import * as SeparatorPrimitive from '@radix-ui/react-separator'; + +import { cn } from '@/utils'; + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = 'horizontal', decorative = true, ...props }, + ref + ) => ( + + ) +); +Separator.displayName = SeparatorPrimitive.Root.displayName; + +export { Separator }; diff --git a/packages/components/vite.config.ts b/packages/components/vite.config.ts index 37c2219..97deef3 100644 --- a/packages/components/vite.config.ts +++ b/packages/components/vite.config.ts @@ -46,6 +46,6 @@ export default defineConfig({ }, target: 'esnext', sourcemap: true, - emptyOutDir: true, + emptyOutDir: false, }, }); diff --git a/packages/database/src/migrations/0003_stormy_jasper_sitwell.sql b/packages/database/src/migrations/0003_stormy_jasper_sitwell.sql new file mode 100644 index 0000000..7890f13 --- /dev/null +++ b/packages/database/src/migrations/0003_stormy_jasper_sitwell.sql @@ -0,0 +1,2 @@ +ALTER TABLE "resources" DROP CONSTRAINT "resources_name_unique";--> statement-breakpoint +ALTER TABLE "resources" ADD CONSTRAINT "resources_name_project_id_unique" UNIQUE("name","project_id"); \ No newline at end of file diff --git a/packages/database/src/migrations/meta/0003_snapshot.json b/packages/database/src/migrations/meta/0003_snapshot.json new file mode 100644 index 0000000..0d40cfa --- /dev/null +++ b/packages/database/src/migrations/meta/0003_snapshot.json @@ -0,0 +1,368 @@ +{ + "id": "b00d4eda-c0c9-4e94-a173-cdf8f69c0348", + "prevId": "4b1af46f-d359-4aa2-af46-bda7329d2507", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.accounts": { + "name": "accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "accounts_user_id_users_id_fk": { + "name": "accounts_user_id_users_id_fk", + "tableFrom": "accounts", + "tableTo": "users", + "schemaTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "accounts_user_id_unique": { + "name": "accounts_user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id" + ] + } + } + }, + "public.integrations": { + "name": "integrations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "integration_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrations_project_id_projects_id_fk": { + "name": "integrations_project_id_projects_id_fk", + "tableFrom": "integrations", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "integrations_type_project_id_unique": { + "name": "integrations_type_project_id_unique", + "nullsNotDistinct": false, + "columns": [ + "type", + "project_id" + ] + } + } + }, + "public.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'Default Project'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.accounts_to_projects": { + "name": "accounts_to_projects", + "schema": "", + "columns": { + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "accounts_to_projects_account_id_accounts_id_fk": { + "name": "accounts_to_projects_account_id_accounts_id_fk", + "tableFrom": "accounts_to_projects", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "accounts_to_projects_project_id_projects_id_fk": { + "name": "accounts_to_projects_project_id_projects_id_fk", + "tableFrom": "accounts_to_projects", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.figma_resources": { + "name": "figma_resources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "figma_resources_resource_id_resources_id_fk": { + "name": "figma_resources_resource_id_resources_id_fk", + "tableFrom": "figma_resources", + "tableTo": "resources", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "figma_resources_resource_id_unique": { + "name": "figma_resources_resource_id_unique", + "nullsNotDistinct": false, + "columns": [ + "resource_id" + ] + } + } + }, + "public.resources": { + "name": "resources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "design_tokens": { + "name": "design_tokens", + "type": "json", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "resources_project_id_projects_id_fk": { + "name": "resources_project_id_projects_id_fk", + "tableFrom": "resources", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "resources_name_project_id_unique": { + "name": "resources_name_project_id_unique", + "nullsNotDistinct": false, + "columns": [ + "name", + "project_id" + ] + } + } + } + }, + "enums": { + "public.integration_type": { + "name": "integration_type", + "schema": "public", + "values": [ + "github", + "figma" + ] + } + }, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/database/src/migrations/meta/_journal.json b/packages/database/src/migrations/meta/_journal.json index 519dcb5..5ce5bf0 100644 --- a/packages/database/src/migrations/meta/_journal.json +++ b/packages/database/src/migrations/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1724411204626, "tag": "0002_yummy_nebula", "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1725638596622, + "tag": "0003_stormy_jasper_sitwell", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/database/src/schema/resources/resources.ts b/packages/database/src/schema/resources/resources.ts index cbf9ba1..12edc0e 100644 --- a/packages/database/src/schema/resources/resources.ts +++ b/packages/database/src/schema/resources/resources.ts @@ -1,4 +1,11 @@ -import { json, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'; +import { + json, + pgTable, + text, + timestamp, + unique, + uuid, +} from 'drizzle-orm/pg-core'; import { createInsertSchema } from 'drizzle-zod'; import type { DesignTokens, DesignToken } from 'style-dictionary/types'; import { z } from 'zod'; @@ -46,21 +53,27 @@ export type DesignTokensModel = z.infer; /** * Represents the resources linked to a design system. */ -export const Resources = pgTable('resources', { - id: uuid('id').defaultRandom().primaryKey().notNull(), - createdAt: timestamp('created_at', { withTimezone: true, mode: 'string' }) - .defaultNow() - .notNull(), - updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'string' }) - .defaultNow() - .notNull() - .$onUpdate(() => new Date().toISOString()), - projectId: uuid('project_id') - .references(() => Projects.id, { onDelete: 'cascade' }) - .notNull(), - name: text('name').notNull().unique(), - designTokens: json('design_tokens').$type(), -}); +export const Resources = pgTable( + 'resources', + { + id: uuid('id').defaultRandom().primaryKey().notNull(), + createdAt: timestamp('created_at', { withTimezone: true, mode: 'string' }) + .defaultNow() + .notNull(), + updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'string' }) + .defaultNow() + .notNull() + .$onUpdate(() => new Date().toISOString()), + projectId: uuid('project_id') + .references(() => Projects.id, { onDelete: 'cascade' }) + .notNull(), + name: text('name').notNull(), + designTokens: json('design_tokens').$type(), + }, + (resource) => ({ + unique: unique().on(resource.name, resource.projectId), + }) +); export const InsertResourcesSchema = createInsertSchema(Resources, { designTokens: () => PreprocessedTokensSchema, diff --git a/packages/figma-plugin/LICENSE b/packages/figma-plugin/LICENSE deleted file mode 100644 index 2c66ec6..0000000 --- a/packages/figma-plugin/LICENSE +++ /dev/null @@ -1,427 +0,0 @@ -Attribution-ShareAlike 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - including for purposes of Section 3(b); and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the โ€œLicensor.โ€ The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. \ No newline at end of file diff --git a/packages/figma-plugin/README.md b/packages/figma-plugin/README.md deleted file mode 100644 index ea73ef9..0000000 --- a/packages/figma-plugin/README.md +++ /dev/null @@ -1,140 +0,0 @@ - -

- Logo -

-

Figma Plugin Boilerplate: React + Vite

- - -

- Create scalable Figma plugins with ease, using the power of React + Vite! -

- - -

- - - - - - - - - - -
- - - - - - -

- -# ๐Ÿ— Key Features - -1. **_Logical Sides in Mind:_** Figma plugins that render a UI work on two different processes (split into code.js and index.html in Figma docs). This boilerplate keeps the sides separated by allowing them to share code (under ./src/common/). - -2. **_Intercommunitive:_** Logical sides should be able to communicate with each other without creating huge and unscalable nested if statements. This boilerplate solves it by declaring isolated messages and handlers (under `./src/common/network/messages/`)! (Using the [Monorepo Networker](https://github.com/CoconutGoodie/monorepo-networker) library) - -3. **_Easy to Build:_** Configure the `figma.manifest.ts` config with your plugin credentials once, then just build with your everyday `npm run build` command! The `/dist` folder will be ready to publish already! - -4. **_Bundled into One File:_** Figma plugins only accept a single file for `main` (js) and `ui` (html), which makes deployment of multiple files linked to each other impossible. This boilerplate is configured to bundle/inline most of the things you need like rasterize/vector image asset imports, CSS URL statements, and of course, source code imports. - -5. **_SVG as Component:_** Yes, you can import SVGs as inlined sources with `*.svg?url`, but what about actually importing them as React components? Easy! You can import an SVG file as a React component with `*.svg?component` (See `/src/ui/app.tsx` for examples) (Using the [vite-plugin-react-rich-svg](https://github.com/iGoodie/vite-plugin-react-rich-svg) plugin) - -6. **_Sassy:_** A classic, this boilerplate supports Sass/Scss/Less and modules! Check out `/src/ui/styles/` for 7-1 Sass Template and `/src/ui/components/Button.module.scss` for module examples. - -# ๐Ÿ’ป How to start coding? - -1. First thing after you clone should be to install the dependencies by executing: - -``` -npm install -``` - -2. Create a figma plugin. In Figma, right click while you're in a design file. Follow `Plugins > Development > New Plugin...`. You can also type `"New Plugin...` to the global search (Windows: CTRL + P, Mac: โŒ˜ Command + P) -3. Follow the steps on opened window. I recommend using `Default` or `Run once` layout, because you'll only need to save the manifest (for the plugin id it generates). Click "Save as", and save it to a temporary place. Then click "Open folder" to navigate to the folder it generated -4. Note down the `id` field from the `manifest.json` it generated. -5. Go to `figma.manifest.ts`, and replace the `id` with the id you noted down. Then configure the manifest there as you like. (See [Official Figma Plugin Manifest doc](https://www.figma.com/plugin-docs/manifest/)) - -## ๐Ÿ–ฑ Developing - -Development is very straight forward. Just run the dev command, and it will start compiling your files as you code. - -``` -npm run dev -``` - -Once dev is ran, `dist/` folder will be created, which includes your `manifest.json`. You can load it in Figma, by `Right Click > Plugins > Development > Import plugin from manifest...` - -> [!TIP] -> You can turn on the `Hot reload plugin` option in Figma, to automatically reload when files in `dist/` changes. - -### ๐Ÿฆด Developing without Figma Context - -If you like developing your UI first, then integrating with Figma context; you can run your UI code in browser just like your every other Vite project by running: - -``` -npm run dev:ui-only -``` - -> [!NOTE] -> Since Figma context is not available in "ui-only" mode, any attempt to Figma API/SDK calls will look like a crash on your inspector/console. - -## ๐Ÿ”จ Building - -Building with the following command line will yield with a `dist` folder, which is ready to be used by Figma: - -``` -npm run build -``` - -Then, `dist/manifest.json` can be used to load the plugin. In Figma, right click while you're in a design file. Follow `Plugins > Development > Import plugin from manifest...`. You can also type `"Import plugin from manifest...` to the global search (Windows: CTRL + P, Mac: โŒ˜ Command + P). Then select `dist/manifest.json` - -## ๐Ÿ“ฆ Publishing - -After building, built `dist` folder is going to contain every artifact you need in order to publish your plugin. Just build, and follow [Figma's Official Post on Publishing Plugins](https://help.figma.com/hc/en-us/articles/360042293394-Publish-plugins-to-the-Figma-Community#Publish_your_plugin). - -## ๐Ÿ•ธ File Structure - -- `src` - - `src/common/` : Sources that are intended to be used both by plugin and ui logical sides. - - `src/common/network/` : Networking logic & message declarations used by Plugin - UI logical sides' intercommunication. Whenever a new message type is needed, declare and register here. - - `src/plugin/` : Sources of the plugin logical side. Place everything that interracts with figma here. - - `src/ui/` : Sources of the ui logical side, a classical Vite + React source base. -- `scripts` - - `scripts/vite/` : Potential custom vite plugins written for your project - - `scripts/windows/` : Potential custom Windows OS scripts - - `scripts/macos/` : Potential custom Mac OS scripts -- `figma.manifest.ts` - A module that exports [Figma Plugin Manifest](https://www.figma.com/plugin-docs/manifest/) for the build scripts - -# ๐Ÿ›‘ Caveats - -### 1. Make sure to import SVGS as either component, url or raw! - -Importing image assets other than `.svg` is easy. However, when you are importing `.svg`, by default it will load as a base64 data-uri, to import as a React component, you must add the query string `?component`. - -```tsx -import MyImage from "@ui/assets/my_image.svg?component"; // -import myImage from "@ui/assets/my_image.svg?url"; // "data:svg+xml,..." -import myImageRaw from "@ui/assets/my_image.svg?raw"; // "..." -... - - - -
-``` - ---- - -

- Preview -

- -# ๐Ÿ“œ License of the Template - -© 2024 Taha Anฤฑlcan Metinyurt (iGoodie) - -For any part of this work for which the license is applicable, this work is licensed under the [Attribution-ShareAlike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/) license. (See LICENSE). - -Creative Commons License diff --git a/packages/figma-plugin/manifest.json b/packages/figma-plugin/manifest.json deleted file mode 100644 index 95fed98..0000000 --- a/packages/figma-plugin/manifest.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "DS-Project_Dev", - "id": "1395696887149548600", - "api": "1.0.0", - "editorType": ["figma"], - "permissions": [], - "main": "dist/plugin.js", - "ui": "dist/index.html" -} diff --git a/packages/figma-plugin/package.json b/packages/figma-plugin/package.json deleted file mode 100644 index 3ac9611..0000000 --- a/packages/figma-plugin/package.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "@ds-project/figma-plugin", - "private": true, - "type": "module", - "version": "1.0.0", - "prettier": "@ds-project/prettier", - "scripts": { - "main": "vite build -c ./vite.config.plugin.ts", - "ui": "tsc && vite build --minify esbuild", - "build": "concurrently -n main,ui \"npm run main\" \"npm run ui\"", - "dev": "concurrently -n main,ui \"npm run main -- --watch\" \"npm run ui -- --watch\"", - "lint": "eslint", - "format": "prettier --check . --ignore-path ../../.gitignore --ignore-path ../../.prettierignore", - "type-check": "tsc --noEmit --emitDeclarationOnly false" - }, - "dependencies": { - "@apollo/client": "^3.7.11", - "@ds-project/api": "workspace:*", - "@ds-project/components": "workspace:*", - "@octokit/core": "^6.1.2", - "@octokit/request": "^9.1.3", - "@octokit/types": "^13.5.0", - "@tanstack/react-query": "^5.51.24", - "@trpc/client": "catalog:", - "@trpc/react-query": "catalog:", - "color2k": "^2.0.3", - "crypto-hash": "^3.1.0", - "graphql": "^16.6.0", - "memoize": "^10.0.0", - "object-hash": "^3.0.0", - "octokit": "^4.0.2", - "rambda": "^9.2.1", - "react": "catalog:", - "react-dom": "catalog:", - "react-json-view-lite": "^1.4.0", - "sass": "^1.60.0", - "style-dictionary": "catalog:", - "superjson": "^2.2.1", - "tailwindcss": "catalog:", - "trpc-token-refresh-link": "^0.5.0", - "zod": "catalog:" - }, - "devDependencies": { - "@ds-project/eslint": "workspace:*", - "@ds-project/prettier": "workspace:*", - "@figma/eslint-plugin-figma-plugins": "^0.15.0", - "@figma/plugin-typings": "catalog:", - "@types/object-hash": "^3.0.6", - "@types/react": "catalog:", - "@types/react-dom": "catalog:", - "@vitejs/plugin-react": "catalog:", - "concurrently": "catalog:", - "esbuild": "catalog:", - "eslint": "catalog:", - "rollup-preserve-directives": "^1.1.1", - "typescript": "catalog:", - "vite": "catalog:", - "vite-plugin-singlefile": "catalog:" - } -} diff --git a/packages/figma-plugin/src/message.ts b/packages/figma-plugin/src/message.ts deleted file mode 100644 index 8e8e1e4..0000000 --- a/packages/figma-plugin/src/message.ts +++ /dev/null @@ -1,179 +0,0 @@ -/* eslint-disable no-console -- TODO: replace with monitoring and logging system */ -import hash from 'object-hash'; -import type { - AsyncMessageChannelHandlers, - AsyncMessageRequests, - AsyncMessageRequestsMap, - AsyncMessageResponses, - AsyncMessageTypes, - IncomingMessageEvent, -} from './message.types'; - -type Channel = 'plugin' | 'ui'; - -export class AsyncMessage { - public static plugin: AsyncMessage = new AsyncMessage('plugin'); - public static ui: AsyncMessage = new AsyncMessage('ui'); - - protected channel: Channel = 'ui'; - - protected handlers: Partial = {}; - - constructor(channel: Channel) { - this.channel = channel; - } - - private attachMessageListener( - callback: ( - message: Message - ) => 'off' | undefined | Promise<'off' | undefined> - ): () => void { - if (this.channel === 'plugin') { - const listener = async (message: Message) => { - const possiblePromise = callback(message); - if ( - possiblePromise !== undefined && - (await possiblePromise) === 'off' - ) { - // eslint-disable-next-line @typescript-eslint/no-misused-promises -- We don't expect to use the result of the listener - figma.ui.off('message', listener); - console.log('๐Ÿงฉ Listener OFF. Possible Promise.'); - } - }; - // eslint-disable-next-line @typescript-eslint/no-misused-promises -- We don't expect to use the result of the listener - figma.ui.on('message', listener); - console.log('๐Ÿงฉ Listener ON.'); - return () => { - // eslint-disable-next-line @typescript-eslint/no-misused-promises -- We don't expect to use the result of the listener - figma.ui.off('message', listener); - console.log('๐Ÿงฉ Listener OFF. Return Function.'); - }; - } - - const listener = async (event: { data: { pluginMessage: Message } }) => { - const possiblePromise = callback(event.data.pluginMessage); - if (possiblePromise && (await possiblePromise) === 'off') { - // eslint-disable-next-line @typescript-eslint/no-misused-promises -- We don't expect to use the result of the listener - window.removeEventListener('message', listener); - console.log('๐Ÿ’… Listener OFF.'); - } - }; - // eslint-disable-next-line @typescript-eslint/no-misused-promises -- We don't expect to use the result of the listener - window.addEventListener('message', listener); - console.log('๐Ÿ’… Listener ON.'); - return () => { - // eslint-disable-next-line @typescript-eslint/no-misused-promises -- We don't expect to use the result of the listener - window.removeEventListener('message', listener); - console.log('๐Ÿ’… Listener OFF.'); - }; - } - - /** - * Continuously listens for messages and calls the callback - */ - public handle( - type: MessageType, - callback: AsyncMessageChannelHandlers[MessageType] - ): void { - this.attachMessageListener( - async (msg: { - id?: string; - message?: AsyncMessageRequestsMap[MessageType]; - }) => { - // This appears to be related to the monaco editor being opened. It appears to post a message to the window message event listener with no data. - if (!msg.id || !msg.message || msg.message.type !== type) { - console.warn('๐Ÿงฉ Invalid message received', msg); - return undefined; - } - - try { - // eslint-disable-next-line @typescript-eslint/await-thenable -- callback can in fact be a promise. In the cases it's not, await doesn't have any harm. - const result = await callback(msg.message); - const payload = { ...result, type: msg.message.type }; - - if (this.channel === 'plugin') { - figma.ui.postMessage({ - id: msg.id, - message: payload, - }); - console.log(`๐Ÿงฉ Plugin Message type", ${payload.type}, was sent.`); - } else { - parent.postMessage( - { - pluginMessage: { id: msg.id, message: payload }, - }, - '*' - ); - console.log( - `๐Ÿ’… UI Plugin Message type", ${payload.type}, was sent.` - ); - } - } catch (error) { - if (this.channel === 'plugin') { - figma.ui.postMessage({ - id: msg.id, - error, - }); - console.log(`๐Ÿงฉ Plugin Error Message was sent.`, error); - } else { - parent.postMessage( - { - pluginMessage: { id: msg.id, error }, - }, - '*' - ); - console.log(`๐Ÿ’… UI Plugin Error Message was sent.`); - } - } - } - ); - } - - /** - * Sends a message and expects a reply - */ - public async request( - message: Message - ): Promise { - const messageId = hash({ - message, - datetime: Date.now(), - }); - - const promise = new Promise< - AsyncMessageResponses & { type: Message['type'] } - >((resolve, reject) => { - this.attachMessageListener< - IncomingMessageEvent< - AsyncMessageResponses & { type: Message['type'] } - >['data']['pluginMessage'] - >((receivedMessage) => { - if (receivedMessage.id === messageId) { - if ('message' in receivedMessage) { - resolve(receivedMessage.message); - } else { - // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- as expected - reject(receivedMessage.error); - } - return 'off'; - } - return undefined; - }); - }); - - if (this.channel === 'plugin') { - figma.ui.postMessage({ id: messageId, message }); - console.log(`๐Ÿงฉ Plugin Message type", ${message.type}, was sent.`); - } else { - parent.postMessage( - { - pluginMessage: { id: messageId, message }, - }, - 'https://www.figma.com' - ); - console.log(`๐Ÿ’… UI Plugin Message type", ${message.type}, was sent.`); - } - - return promise; - } -} diff --git a/packages/figma-plugin/src/message.types.ts b/packages/figma-plugin/src/message.types.ts deleted file mode 100644 index fd30b64..0000000 --- a/packages/figma-plugin/src/message.types.ts +++ /dev/null @@ -1,134 +0,0 @@ -import type { DesignTokens } from 'style-dictionary/types'; -import type { Credentials } from './types/credentials'; - -export enum AsyncMessageTypes { - SetCredentials = 'set-credentials', - GetCredentials = 'get-credentials', - GetDesignTokens = 'get-design-tokens', - DeleteCredentials = 'delete-credentials', - SetProjectId = 'set-project-id', - GetProjectId = 'get-project-id', - GetConfig = 'get-config', -} - -export type AsyncMessage< - MessageType extends AsyncMessageTypes, - MessageResponse = unknown, -> = { - type: MessageType; -} & MessageResponse; - -export type PluginMessageEvent< - MessageType extends AsyncMessageTypes, - MessageResponse = unknown, -> = MessageEvent<{ - pluginMessage: { - type: MessageType; - } & MessageResponse; -}>; - -export interface IncomingMessageEvent { - data: { - pluginMessage: - | { - id: string; - message: Message; - } - | { - id: string; - error: unknown; - }; - }; -} - -export type GetCredentialsRequest = - AsyncMessage; -export type SetCredentialsRequest = AsyncMessage< - AsyncMessageTypes.SetCredentials, - { - credentials: Credentials; - } ->; -export type DeleteCredentialsRequest = - AsyncMessage; - -export type GetCredentialsResponse = AsyncMessage< - AsyncMessageTypes.GetCredentials, - { - credentials: Credentials; - } ->; - -export type GetDesignTokensRequest = - AsyncMessage; - -export type GetDesignTokensResponse = AsyncMessage< - AsyncMessageTypes.GetDesignTokens, - { - designTokens: DesignTokens; - } ->; - -export type GetProjectIdRequest = AsyncMessage; - -export type GetProjectIdResponse = AsyncMessage< - AsyncMessageTypes.GetProjectId, - { - projectId?: string; - } ->; - -export type SetProjectIdRequest = AsyncMessage< - AsyncMessageTypes.SetProjectId, - { - projectId: string; - } ->; - -export type GetConfigRequest = AsyncMessage; - -export type GetConfigResponse = AsyncMessage< - AsyncMessageTypes.GetConfig, - { - fileName: string; - } ->; - -export type AsyncMessageRequests = - | GetCredentialsRequest - | SetCredentialsRequest - | DeleteCredentialsRequest - | GetDesignTokensRequest - | GetProjectIdRequest - | SetProjectIdRequest - | GetConfigRequest; - -export type AsyncMessageResponses = - | GetCredentialsResponse - | GetDesignTokensResponse - | GetProjectIdResponse - | GetConfigResponse; - -export type AsyncMessageRequestsMap = { - [K in AsyncMessageTypes]: Extract; -}; -export type AsyncMessageResponsesMap = { - [K in AsyncMessageTypes]: Extract; -}; - -// credits goes to https://github.com/microsoft/TypeScript/issues/23182#issuecomment-379091887 -type IsTypeOnlyObject> = [ - keyof Obj, -] extends ['type'] - ? true - : false; - -export type AsyncMessageChannelHandlers = { - [K in AsyncMessageTypes]: ( - incoming: AsyncMessageRequestsMap[K] - ) => Promise< - IsTypeOnlyObject extends true - ? never - : Omit - >; -}; diff --git a/packages/figma-plugin/src/plugin/plugin.ts b/packages/figma-plugin/src/plugin/plugin.ts deleted file mode 100644 index 0b4198c..0000000 --- a/packages/figma-plugin/src/plugin/plugin.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { AsyncMessage } from '../message'; -import { AsyncMessageTypes } from '../message.types'; -import { CredentialsSchema } from '../types/credentials'; -import { config } from '../ui/config'; -import { storage } from './storage'; -import { extractDesignTokens } from './design-tokens/extract-design-tokens'; - -figma.showUI(__html__, { - themeColors: true, - height: 306, - width: 275, - title: 'DS Project', -}); - -AsyncMessage.plugin.handle(AsyncMessageTypes.GetConfig, async () => { - const fileName = figma.root.name; - return Promise.resolve({ fileName }); -}); - -AsyncMessage.plugin.handle(AsyncMessageTypes.GetCredentials, async () => { - const credentialsString = await storage.get(config.CREDENTIALS_KEY); - const credentials = credentialsString - ? CredentialsSchema.parse(JSON.parse(credentialsString)) - : null; - if (!credentials) { - throw new Error('No DS Credentials found'); - } - - return { credentials }; -}); - -AsyncMessage.plugin.handle( - AsyncMessageTypes.SetCredentials, - async (message) => { - await storage.set( - config.CREDENTIALS_KEY, - JSON.stringify(CredentialsSchema.parse(message.credentials)) - ); - - return {}; - } -); - -AsyncMessage.plugin.handle(AsyncMessageTypes.DeleteCredentials, async () => { - await storage.remove(config.CREDENTIALS_KEY); - - return {}; -}); - -AsyncMessage.plugin.handle(AsyncMessageTypes.GetDesignTokens, async () => { - const designTokens = await extractDesignTokens(); - - console.log({ designTokens }); - - return { - designTokens, - }; -}); - -AsyncMessage.plugin.handle( - AsyncMessageTypes.SetProjectId, - async ({ projectId }) => { - await storage.set(config.PROJECT_ID_KEY, projectId); - - return {}; - } -); - -AsyncMessage.plugin.handle(AsyncMessageTypes.GetProjectId, async () => { - const projectId = (await storage.get(config.PROJECT_ID_KEY)) ?? undefined; - - return Promise.resolve({ - projectId, - }); -}); diff --git a/packages/figma-plugin/src/plugin/storage.ts b/packages/figma-plugin/src/plugin/storage.ts deleted file mode 100644 index 2d37b96..0000000 --- a/packages/figma-plugin/src/plugin/storage.ts +++ /dev/null @@ -1,26 +0,0 @@ -function parse(value: unknown): V | null { - return value as V; -} - -function stringify(value: V): string { - return String(value); -} - -export const storage = { - get: async function get(key: string): Promise { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- getAsync is not sure of what it returns - const value = await figma.clientStorage.getAsync(key); - return value ? parse(value) : null; - }, - - set: async function set( - key: string, - value: V | null - ): Promise { - await figma.clientStorage.setAsync(key, value ? stringify(value) : null); - }, - - remove: async function remove(key: string): Promise { - await figma.clientStorage.deleteAsync(key); - }, -}; diff --git a/packages/figma-plugin/src/plugin/variables/get-file-id.ts b/packages/figma-plugin/src/plugin/variables/get-file-id.ts deleted file mode 100644 index 73727e0..0000000 --- a/packages/figma-plugin/src/plugin/variables/get-file-id.ts +++ /dev/null @@ -1,28 +0,0 @@ -export async function getFileId(): Promise { - const collections = await figma.variables.getLocalVariableCollectionsAsync(); - const configCollection = collections.find((c) => c.name === '__config__'); - - const variablesPromises = - configCollection?.variableIds.map((variableId) => - figma.variables.getVariableByIdAsync(variableId) - ) ?? []; - - const variables = await Promise.all(variablesPromises); - - const fileIdVariable = variables.find( - (variable) => - variable?.name === 'fileId' && variable.resolvedType === 'STRING' - ); - - const modes = Object.keys(fileIdVariable?.valuesByMode ?? {}); - - if (modes.length > 1) { - // eslint-disable-next-line no-console -- TODO: replace with monitoring - console.error('This file has more than one mode. Unsupported.', modes); - return; - } - - const [fileId] = modes.map((mode) => fileIdVariable?.valuesByMode[mode]); - - return typeof fileId === 'string' ? fileId : undefined; -} diff --git a/packages/figma-plugin/src/plugin/variables/utils/get-figma-variables.ts b/packages/figma-plugin/src/plugin/variables/utils/get-figma-variables.ts deleted file mode 100644 index 144ff73..0000000 --- a/packages/figma-plugin/src/plugin/variables/utils/get-figma-variables.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { DesignTokens } from 'style-dictionary/types'; -import * as R from 'rambda'; -import { figmaVariable } from './transformers/figma-variable'; - -/** - * Sizing - * Spacing - * Color - * Border Radius - * Border Width - * Border - * Opacity - * Box Shadow - * Typography - * Font Family - * Font Weight - * Line Height - * Font Size - * Letter Spacing - * Paragraph Spacing - * Text Case - * Text Decoration - * Composition - * Assets - * Dimension - * Boolean - * Text - * Number - * Other - */ -export const getFigmaVariables = async (): Promise => { - const collections = await figma.variables.getLocalVariableCollectionsAsync(); - - const collectionVariablesPromises = collections.map( - async (variableCollection) => { - const variablePromises = - variableCollection.variableIds.map(figmaVariable); - - const variables = await Promise.all(variablePromises); - - return variables; - } - ); - - const collectionVariables = await Promise.all(collectionVariablesPromises); - - const flatCollection = collectionVariables - .flat() - // Filter out null values - .filter(Boolean) as DesignTokens[]; - - return R.reduce( - (accumulator, variable) => R.mergeDeepRight(accumulator, variable), - {} - )(flatCollection); -}; diff --git a/packages/figma-plugin/src/plugin/variables/utils/transformers/color.ts b/packages/figma-plugin/src/plugin/variables/utils/transformers/color.ts deleted file mode 100644 index f41f4c7..0000000 --- a/packages/figma-plugin/src/plugin/variables/utils/transformers/color.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { DesignToken } from 'style-dictionary/types'; - -export function rgbToHex({ r, g, b, ...rest }: RGB | RGBA) { - const a = 'a' in rest ? rest.a : 1; - - const toHex = (value: number) => { - const hex = Math.round(value * 255).toString(16); - return hex.length === 1 ? `0${hex}` : hex; - }; - - const hex = [toHex(r), toHex(g), toHex(b)].join(''); - return `#${hex}${a !== 1 ? toHex(a) : ''}`; -} - -function color(value: VariableValue): string { - if (typeof value === 'string') { - return value; - } - - if (typeof value === 'object' && 'a' in value) { - return rgbToHex(value); - } - - if (typeof value === 'object' && !('a' in value) && 'r' in value) { - return rgbToHex(value); - } - - if ( - typeof value === 'object' && - 'type' in value && - value.type === 'VARIABLE_ALIAS' - ) { - console.error('Variable alias is still not implemented. Returning empty.'); - - return ''; - } - - console.warn('Unexpected color value. Returning empty.'); - return ''; -} - -export function colorVariable({ - modeId, - state, - variable, -}: { - variable: Variable; - modeId: string; - state?: PublishStatus; -}): DesignToken { - if (variable.resolvedType !== 'COLOR') { - console.error('variable is not a color variable. Returning empty.'); - return {}; - } - - const variableKeys = variable.name.split('/'); - - const result = variableKeys.reduceRight((accumulator, variableKey) => { - // Set the value at the lowest leaf of the structure - if (Object.keys(accumulator).length === 0) { - return { - [variableKey]: { - $value: color(variable.valuesByMode[modeId]), - attributes: { - modeId, - state, - hiddenFromPublishing: variable.hiddenFromPublishing, - }, - }, - }; - } - - // Wrap the inner structure at an highest level leaf - return { [variableKey]: accumulator }; - }, {}); - - return result; -} diff --git a/packages/figma-plugin/src/plugin/variables/utils/transformers/figma-variable.ts b/packages/figma-plugin/src/plugin/variables/utils/transformers/figma-variable.ts deleted file mode 100644 index fe4e81c..0000000 --- a/packages/figma-plugin/src/plugin/variables/utils/transformers/figma-variable.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { mergeDeepRight } from 'rambda'; -import type { DesignTokens } from 'style-dictionary/types'; -import { transform } from '.'; - -export async function figmaVariable( - variableId: string -): Promise { - const variable = await figma.variables.getVariableByIdAsync(variableId); - const state = await variable?.getPublishStatusAsync(); - - if (!variable) { - console.error('Variable not found Returning empty.'); - return null; - } - - const modes = Object.keys(variable.valuesByMode); - - const variables = modes.reduce((accumulator, modeId) => { - switch (variable.resolvedType) { - case 'COLOR': - return mergeDeepRight(accumulator, { - $type: 'color', - ...transform.colorVariable({ variable, modeId, state }), - }); - - // TODO: add other variants - - default: - console.warn('unknown type', variable.resolvedType); - return accumulator; - } - }, {}); - - return Object.keys(variables).length > 0 ? variables : null; -} diff --git a/packages/figma-plugin/src/plugin/variables/utils/transformers/index.ts b/packages/figma-plugin/src/plugin/variables/utils/transformers/index.ts deleted file mode 100644 index 6eb263a..0000000 --- a/packages/figma-plugin/src/plugin/variables/utils/transformers/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { colorVariable } from './color'; -import { figmaVariable } from './figma-variable'; -export const transform = { - colorVariable, - figmaVariable, -}; diff --git a/packages/figma-plugin/src/ui/app.tsx b/packages/figma-plugin/src/ui/app.tsx deleted file mode 100644 index 72da02c..0000000 --- a/packages/figma-plugin/src/ui/app.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import '@ds-project/components/globals.css'; -import 'react-json-view-lite/dist/index.css'; -import { useCallback } from 'react'; -import { Button, DSLogo, Icons } from '@ds-project/components'; -import { AsyncMessageTypes } from '../message.types'; -import { AsyncMessage } from '../message'; -import { LinkDesignSystem } from './modules/link-design-system'; -import { useAuth } from './modules/providers/auth-provider'; -import { useConfig } from './modules/providers/config-provider'; -import { api } from '@ds-project/api/react'; -import { useProjects } from './modules/providers/projects-provider'; - -function App() { - const { login, logout, state } = useAuth(); - const { fileName } = useConfig(); - const { mutate: updateDesignTokens } = - api.resources.updateDesignTokens.useMutation(); - const { selectedProjectId } = useProjects(); - - const update = useCallback(() => { - if (!fileName || state !== 'authorized') return; - - AsyncMessage.ui - .request({ - type: AsyncMessageTypes.GetDesignTokens, - }) - .then(({ designTokens }) => { - console.log({ designTokens }); - - if (!selectedProjectId) return; - - void updateDesignTokens({ - designTokens, - name: fileName, - projectId: selectedProjectId, - }); - }) - .catch((error) => { - console.error('Error updating design tokens', error); - }); - }, [fileName, selectedProjectId, state, updateDesignTokens]); - - return ( -
- {state === 'authorized' ? ( - - ) : null} - {state === 'authorized' ? : null} - {state === 'authorized' ? ( - - ) : state === 'authorizing' ? ( -

Authenticating in the browser...

- ) : ( - - )} -
- ); -} - -export default App; diff --git a/packages/figma-plugin/src/ui/modules/providers/config-provider.tsx b/packages/figma-plugin/src/ui/modules/providers/config-provider.tsx deleted file mode 100644 index 8fb3d9f..0000000 --- a/packages/figma-plugin/src/ui/modules/providers/config-provider.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { createContext, useContext, useEffect, useState } from 'react'; -import { AsyncMessage } from '../../../message'; -import { AsyncMessageTypes } from '../../../message.types'; - -interface ContextType { - fileName?: string; - projectId?: string; -} - -const Context = createContext({}); - -export function ConfigProvider({ children }: { children: React.ReactNode }) { - const [config, setConfig] = useState(); - - useEffect(() => { - AsyncMessage.ui - .request({ - type: AsyncMessageTypes.GetConfig, - }) - .then((_config) => { - setConfig(_config); - }) - .catch((error) => { - // eslint-disable-next-line no-console -- TODO: replace with monitoring - console.error('Error fetching config from plugin', error); - }); - }, []); - - return {children}; -} - -export function useConfig() { - const context = useContext(Context); - - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- If provider is not available, this will be undefined - if (!context) { - throw new Error('useConfig should be used within '); - } - - return context; -} diff --git a/packages/figma-plugin/tsconfig.node.json b/packages/figma-plugin/tsconfig.node.json deleted file mode 100644 index 9d31e2a..0000000 --- a/packages/figma-plugin/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/packages/figma-plugin/eslint.config.js b/packages/figma-utilities/eslint.config.js similarity index 76% rename from packages/figma-plugin/eslint.config.js rename to packages/figma-utilities/eslint.config.js index 6596cb1..3132887 100644 --- a/packages/figma-plugin/eslint.config.js +++ b/packages/figma-utilities/eslint.config.js @@ -1,9 +1,10 @@ import baseConfig from '@ds-project/eslint/base'; import reactConfig from '@ds-project/eslint/react'; -// import figmaPlugin from '@figma/eslint-plugin-figma-plugins'; /** @type {import('typescript-eslint').Config} */ export default [ + ...baseConfig, + ...reactConfig, { ignores: ['dist/**'], languageOptions: { @@ -13,9 +14,7 @@ export default [ }, }, rules: { - // ...figmaPlugin.configs.recommended.rules, + '@typescript-eslint/no-unsafe-return': 'off', }, }, - ...baseConfig, - ...reactConfig, ]; diff --git a/packages/figma-utilities/package.json b/packages/figma-utilities/package.json new file mode 100644 index 0000000..0802af9 --- /dev/null +++ b/packages/figma-utilities/package.json @@ -0,0 +1,37 @@ +{ + "name": "@ds-project/figma-utilities", + "version": "1.0.0", + "private": true, + "keywords": [], + "license": "ISC", + "author": "", + "type": "module", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./src/index.ts" + } + }, + "scripts": { + "format": "prettier --check . --ignore-path ../../.gitignore --ignore-path ../../.prettierignore", + "lint": "eslint --max-warnings=0 .", + "type-check": "tsc --noEmit --emitDeclarationOnly false" + }, + "prettier": "@ds-project/prettier", + "dependencies": { + "@create-figma-plugin/utilities": "^3.2.0", + "object-hash": "^3.0.0", + "style-dictionary": "^4.1.0", + "zod": "^3.23.8" + }, + "devDependencies": { + "@ds-project/eslint": "workspace:*", + "@ds-project/prettier": "workspace:*", + "@ds-project/typescript": "workspace:*", + "@figma/plugin-typings": "catalog:", + "@figma/widget-typings": "catalog:", + "@types/object-hash": "^3.0.6", + "eslint": "catalog:", + "typescript": "catalog:" + } +} diff --git a/packages/figma-utilities/src/config-data.ts b/packages/figma-utilities/src/config-data.ts new file mode 100644 index 0000000..03ac75a --- /dev/null +++ b/packages/figma-utilities/src/config-data.ts @@ -0,0 +1,7 @@ +import type { Credentials } from './credentials'; + +export interface ConfigData extends Record { + fileName: string | null; + projectId: string | null; + credentials: Credentials | null; +} diff --git a/packages/figma-plugin/src/types/credentials.ts b/packages/figma-utilities/src/credentials.ts similarity index 100% rename from packages/figma-plugin/src/types/credentials.ts rename to packages/figma-utilities/src/credentials.ts diff --git a/packages/figma-utilities/src/events.ts b/packages/figma-utilities/src/events.ts new file mode 100644 index 0000000..fbef0bb --- /dev/null +++ b/packages/figma-utilities/src/events.ts @@ -0,0 +1,122 @@ +import { + on as defaultOn, + emit as defaultEmit, + once as defaultOnce, +} from '@create-figma-plugin/utilities'; +import type { DesignTokens } from 'style-dictionary/types'; +import type { Credentials } from './credentials'; + +type RequestResponse = Record< + string, + { + request: Record | undefined; + response: Record | undefined; + } +>; + +type Implements = U; + +type Event = Implements< + RequestResponse, + { + 'ui-is-ready': { + request: undefined; + response: undefined; + }; + + connect: { + request: undefined; + response: { credentials: Credentials | null }; + }; + + 'sync-variables': { + request: { variables: DesignTokens }; + response: { + lastSyncedAt: number | null; + }; + }; + + 'set-credentials': { + request: undefined; + response: { credentials: Credentials | null }; + }; + + 'set-project': { + request: undefined; + response: { id: string; name: string }; + }; + + 'open-projects-ui': { + request: undefined; + response: undefined; + }; + } +>; + +type EventName = keyof Event; + +export type ResponseHandler = ( + data: Event[Name]['response'] +) => void; + +export function on( + name: Name, + handler: ResponseHandler +) { + console.log(`๐Ÿ” on ${name}`); + return defaultOn(name, handler); +} + +export function once( + name: Name, + handler: ResponseHandler +) { + console.log(`๐Ÿ” once ${name}`); + return defaultOnce(name, handler); +} + +export function emit( + name: Name, + data: Event[Name]['response'] +) { + console.log(`๐Ÿš€ emit ${name}`); + return defaultEmit(name, data); +} + +export async function request( + name: Name, + data: Event[Name]['request'] +) { + console.log(`โœˆ๏ธ request ${name}`); + const response = new Promise((resolve, _reject) => { + console.log(`โœˆ๏ธ request ๐Ÿš€ emit ${name}`); + defaultEmit(name, data); + + console.log(`โœˆ๏ธ request โฐ wait for ${name}`); + defaultOn(name, resolve); + + // TODO: handle timeout to reject the promise + }); + return response; +} + +export async function handle( + name: Name, + handler: ( + data: Event[Name]['request'] + ) => Promise | Event[Name]['response'] +): Promise { + const response = await new Promise( + (resolve, _reject) => { + console.log(`โœˆ๏ธ handle ๐Ÿ” on ${name}`); + defaultOn(name, (data: Event[Name]['request']) => { + console.log(`โœˆ๏ธ handle ๐Ÿš€ emit ${name}`); + resolve(handler(data)); + }); + + // TODO: handle timeout to reject the promise + } + ); + + return defaultEmit(name, response); +} diff --git a/packages/figma-utilities/src/index.ts b/packages/figma-utilities/src/index.ts new file mode 100644 index 0000000..19d1216 --- /dev/null +++ b/packages/figma-utilities/src/index.ts @@ -0,0 +1,3 @@ +export * from './credentials'; +export * from './config-data'; +export * from './events'; diff --git a/packages/figma-utilities/tsconfig.json b/packages/figma-utilities/tsconfig.json new file mode 100644 index 0000000..276a994 --- /dev/null +++ b/packages/figma-utilities/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@ds-project/typescript/internal-package.json", + "compilerOptions": { + "lib": ["dom", "dom.iterable", "esnext"], + "typeRoots": ["./node_modules/@figma", "./node_modules/@types"] + }, + "include": ["src"] +} diff --git a/packages/figma-widget/README.md b/packages/figma-widget/README.md new file mode 100644 index 0000000..8901f0b --- /dev/null +++ b/packages/figma-widget/README.md @@ -0,0 +1,46 @@ +# @figma/create-widget + +This repo was created by @figma/create-widget + +## Getting started + +Run the following command to start building your widget + +```bash +npm run dev +``` + +1. Log in to your account and open the Figma desktop app +2. You can open any existing FigJam document or create a new one. +3. Go to Menu > Widgets > Development > "Import widget from manifest..." +4. Select the manifest.json in this folder + +## Organization + +This widget uses: + +- [esbuild](https://esbuild.github.io/) for bundling +- [vite](https://vitejs.dev/) and [react](https://reactjs.org/) for the iframe +- [typescript](https://www.typescriptlang.org/) for typechecking + +| file/folder | description | +| ------------- | -------------------------------------------------------------------------------- | +| manifest.json | The widget's [manifest.json](https://www.figma.com/widget-docs/widget-manifest/) | +| widget-src/ | Contains the widget code | +| ui-src/ | Contains the iframe code | + +### `npm run dev` + +This is the only command you need to run in development. It will start the following processes for you: + +- bundling (both widget and iframe code) +- typechecking (both widget and iframe code) +- vite dev server (for iframe development) + +### `npm run build` + +This runs bundling with minification turned on. You should run this command before releasing your widget. + +### `npm run test` + +This runs typechecking and makes sure that your widget builds without errors. diff --git a/packages/figma-widget/eslint.config.js b/packages/figma-widget/eslint.config.js new file mode 100644 index 0000000..3132887 --- /dev/null +++ b/packages/figma-widget/eslint.config.js @@ -0,0 +1,20 @@ +import baseConfig from '@ds-project/eslint/base'; +import reactConfig from '@ds-project/eslint/react'; + +/** @type {import('typescript-eslint').Config} */ +export default [ + ...baseConfig, + ...reactConfig, + { + ignores: ['dist/**'], + languageOptions: { + globals: { + figma: 'readable', + __html__: 'readable', + }, + }, + rules: { + '@typescript-eslint/no-unsafe-return': 'off', + }, + }, +]; diff --git a/packages/figma-widget/manifest.json b/packages/figma-widget/manifest.json new file mode 100644 index 0000000..87dd062 --- /dev/null +++ b/packages/figma-widget/manifest.json @@ -0,0 +1,14 @@ +{ + "name": "DS Pro", + "id": "widget-id-HhiuAqCVpc", + "api": "1.0.0", + "main": "dist/widget.js", + "ui": "dist/src/ui/index.html", + "editorType": ["figma"], + "containsWidget": true, + "widgetApi": "1.0.0", + "networkAccess": { + "allowedDomains": ["https://designsystemproject.pro"], + "devAllowedDomains": ["http://localhost:3000"] + } +} diff --git a/packages/figma-widget/package.json b/packages/figma-widget/package.json new file mode 100644 index 0000000..9fd3187 --- /dev/null +++ b/packages/figma-widget/package.json @@ -0,0 +1,60 @@ +{ + "name": "@ds-project/figma-widget", + "version": "1.0.0", + "private": true, + "description": "DS Pro", + "license": "MIT License", + "author": "Figma", + "type": "module", + "scripts": { + "build": "pnpm run build:ui && pnpm run build:widget -- --minify", + "build:ui": "npx vite build --minify esbuild", + "build:watch": "concurrently -n widget,ui \"pnpm run build:widget --watch\" \"pnpm run build:ui --watch\"", + "build:widget": "vite build -c ./vite.config.widget.ts", + "dev": "concurrently -n type-check,build,vite 'pnpm:type-check:watch' 'pnpm:build:watch' 'vite'", + "format": "prettier --check . --ignore-path ../../.gitignore --ignore-path ../../.prettierignore", + "lint": "eslint", + "test": "pnpm run tsc && pnpm run build", + "type-check": "pnpm run type-check:widget && pnpm run type-check:ui", + "type-check:ui": "tsc -p src/ui/tsconfig.json --noEmit --emitDeclarationOnly false", + "type-check:watch": "concurrently -n widget,ui \"pnpm run type-check:widget\" \"pnpm run type-check:ui\"", + "type-check:widget": "tsc -p src/widget/tsconfig.json --noEmit --emitDeclarationOnly false" + }, + "prettier": "@ds-project/prettier", + "dependencies": { + "@create-figma-plugin/utilities": "^3.2.0", + "@tanstack/react-query": "^5.51.24", + "memoize": "^10.0.0", + "object-hash": "^3.0.0", + "rambda": "^9.2.1", + "react": "catalog:", + "react-dom": "catalog:", + "style-dictionary": "^4.1.0", + "superjson": "^2.2.1", + "trpc-token-refresh-link": "^0.5.0", + "zod": "^3.23.8" + }, + "devDependencies": { + "@ds-project/api": "workspace:*", + "@ds-project/components": "workspace:*", + "@ds-project/eslint": "workspace:*", + "@ds-project/figma-utilities": "workspace:*", + "@ds-project/prettier": "workspace:*", + "@figma/plugin-typings": "catalog:", + "@figma/widget-typings": "catalog:", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", + "@vitejs/plugin-react": "^4.3.1", + "@vitejs/plugin-react-refresh": "^1.3.1", + "autoprefixer": "^10.4.19", + "concurrently": "^6.3.0", + "esbuild": "^0.13.5", + "eslint": "catalog:", + "postcss": "^8.4.45", + "rollup-preserve-directives": "^1.1.1", + "tailwindcss": "^3.4.10", + "typescript": "catalog:", + "vite": "catalog:", + "vite-plugin-singlefile": "^0.5.1" + } +} diff --git a/packages/figma-plugin/postcss.config.mjs b/packages/figma-widget/postcss.config.mjs similarity index 85% rename from packages/figma-plugin/postcss.config.mjs rename to packages/figma-widget/postcss.config.mjs index 1a69fd2..2ef30fc 100644 --- a/packages/figma-plugin/postcss.config.mjs +++ b/packages/figma-widget/postcss.config.mjs @@ -2,6 +2,7 @@ const config = { plugins: { tailwindcss: {}, + autoprefixer: {}, }, }; diff --git a/packages/figma-widget/src/ui/app.tsx b/packages/figma-widget/src/ui/app.tsx new file mode 100644 index 0000000..249a931 --- /dev/null +++ b/packages/figma-widget/src/ui/app.tsx @@ -0,0 +1,21 @@ +import { useEffect } from 'react'; +import { Auth } from './modules/auth'; +import { emit } from '@ds-project/figma-utilities'; +import { VariablesUI } from './modules/variables.ui'; +import { ProjectUI } from './modules/project/project.ui'; +import { Container } from './components/container'; + +export function App() { + useEffect(() => { + // Announce to the plugin that the UI is ready to receive messages + emit('ui-is-ready', undefined); + }, []); + + return ( + + + + + + ); +} diff --git a/packages/figma-widget/src/ui/components/container.tsx b/packages/figma-widget/src/ui/components/container.tsx new file mode 100644 index 0000000..19115d9 --- /dev/null +++ b/packages/figma-widget/src/ui/components/container.tsx @@ -0,0 +1,7 @@ +interface ContainerProps { + children: React.ReactNode; +} + +export function Container({ children }: ContainerProps) { + return
{children}
; +} diff --git a/packages/figma-plugin/src/ui/config.ts b/packages/figma-widget/src/ui/config.ts similarity index 100% rename from packages/figma-plugin/src/ui/config.ts rename to packages/figma-widget/src/ui/config.ts diff --git a/packages/figma-plugin/src/ui/globals.css b/packages/figma-widget/src/ui/globals.css similarity index 100% rename from packages/figma-plugin/src/ui/globals.css rename to packages/figma-widget/src/ui/globals.css diff --git a/packages/figma-widget/src/ui/globals.d.ts b/packages/figma-widget/src/ui/globals.d.ts new file mode 100644 index 0000000..bee78cb --- /dev/null +++ b/packages/figma-widget/src/ui/globals.d.ts @@ -0,0 +1,10 @@ +import type { ConfigData } from '@ds-project/figma-utilities'; + +declare global { + interface Window { + __SHOW_UI_DATA__: ConfigData; + } +} + +// This empty export is necessary to make this a module +export {}; diff --git a/packages/figma-plugin/index.html b/packages/figma-widget/src/ui/index.html similarity index 56% rename from packages/figma-plugin/index.html rename to packages/figma-widget/src/ui/index.html index 6c96fa9..a64f19c 100644 --- a/packages/figma-plugin/index.html +++ b/packages/figma-widget/src/ui/index.html @@ -3,10 +3,13 @@ - Plugin Template + DS Project
- + + diff --git a/packages/figma-plugin/src/ui/lib/query-client.ts b/packages/figma-widget/src/ui/lib/query-client.ts similarity index 100% rename from packages/figma-plugin/src/ui/lib/query-client.ts rename to packages/figma-widget/src/ui/lib/query-client.ts diff --git a/packages/figma-widget/src/ui/lib/wait.ts b/packages/figma-widget/src/ui/lib/wait.ts new file mode 100644 index 0000000..2c68046 --- /dev/null +++ b/packages/figma-widget/src/ui/lib/wait.ts @@ -0,0 +1,2 @@ +export const wait = async (timeout: number) => + await new Promise((resolver) => setTimeout(resolver, timeout)); diff --git a/packages/figma-plugin/src/ui/main.tsx b/packages/figma-widget/src/ui/main.tsx similarity index 80% rename from packages/figma-plugin/src/ui/main.tsx rename to packages/figma-widget/src/ui/main.tsx index e015324..b704dd2 100644 --- a/packages/figma-plugin/src/ui/main.tsx +++ b/packages/figma-widget/src/ui/main.tsx @@ -1,10 +1,10 @@ -import * as React from 'react'; -import { createRoot } from 'react-dom/client'; -import App from './app'; +import React from 'react'; import './globals.css'; import { Providers } from './modules/providers'; +import { createRoot } from 'react-dom/client'; +import { App } from './app'; -// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- TODO: review +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion createRoot(document.getElementById('root')!).render( diff --git a/packages/figma-widget/src/ui/modules/auth.tsx b/packages/figma-widget/src/ui/modules/auth.tsx new file mode 100644 index 0000000..f535a60 --- /dev/null +++ b/packages/figma-widget/src/ui/modules/auth.tsx @@ -0,0 +1,24 @@ +import '@ds-project/components/globals.css'; + +import { useAuth } from './providers/auth-provider'; +import { useEffect } from 'react'; +import { handle } from '@ds-project/figma-utilities'; + +export function Auth() { + const { login } = useAuth(); + + useEffect(() => { + handle('connect', async () => { + console.log('๐Ÿ’… Auth: Performing login'); + const credentials = await login(); + + return { + credentials, + }; + }).catch((error) => { + console.error('๐Ÿ’… Auth: Failed to perform login', error); + }); + }, [login]); + + return null; +} diff --git a/packages/figma-plugin/src/ui/modules/link-design-system/index.ts b/packages/figma-widget/src/ui/modules/link-design-system/index.ts similarity index 100% rename from packages/figma-plugin/src/ui/modules/link-design-system/index.ts rename to packages/figma-widget/src/ui/modules/link-design-system/index.ts diff --git a/packages/figma-plugin/src/ui/modules/link-design-system/link-design-system.tsx b/packages/figma-widget/src/ui/modules/link-design-system/link-design-system.tsx similarity index 84% rename from packages/figma-plugin/src/ui/modules/link-design-system/link-design-system.tsx rename to packages/figma-widget/src/ui/modules/link-design-system/link-design-system.tsx index 99413cc..9731081 100644 --- a/packages/figma-plugin/src/ui/modules/link-design-system/link-design-system.tsx +++ b/packages/figma-widget/src/ui/modules/link-design-system/link-design-system.tsx @@ -17,14 +17,17 @@ export function LinkDesignSystem() { } = useProjects(); const onValueChange = useCallback( - async (projectId: string) => { - await linkProject(projectId); + (projectId: string) => { + linkProject(projectId); }, [linkProject] ); return ( - { + once('open-projects-ui', () => { + setIsVisible(true); + }); + }, []); + + const onValueChange = useCallback( + (projectId: string) => { + linkProject(projectId); + }, + [linkProject] + ); + + if (!isVisible) return null; + + if (isProjectsLoading) return
Loading...
; + + return ( +
+ +

Select project

+
+
    + {projects?.map(({ id, name }, index) => ( +
  • + + {index < projects.length - 1 ? : null} +
  • + ))} +
+
+ ); +} diff --git a/packages/figma-plugin/src/ui/modules/providers/api-provider.tsx b/packages/figma-widget/src/ui/modules/providers/api-provider.tsx similarity index 100% rename from packages/figma-plugin/src/ui/modules/providers/api-provider.tsx rename to packages/figma-widget/src/ui/modules/providers/api-provider.tsx diff --git a/packages/figma-plugin/src/ui/modules/providers/auth-provider.tsx b/packages/figma-widget/src/ui/modules/providers/auth-provider.tsx similarity index 60% rename from packages/figma-plugin/src/ui/modules/providers/auth-provider.tsx rename to packages/figma-widget/src/ui/modules/providers/auth-provider.tsx index 0008e53..3e378cc 100644 --- a/packages/figma-plugin/src/ui/modules/providers/auth-provider.tsx +++ b/packages/figma-widget/src/ui/modules/providers/auth-provider.tsx @@ -7,10 +7,9 @@ import { useState, } from 'react'; import { config } from '../../config'; -import { CredentialsSchema } from '../../../types/credentials'; -import type { Credentials } from '../../../types/credentials'; -import { AsyncMessage } from '../../../message'; -import { AsyncMessageTypes } from '../../../message.types'; +import type { Credentials } from '@ds-project/figma-utilities'; +import { CredentialsSchema, emit } from '@ds-project/figma-utilities'; +import { useConfig } from './config-provider'; interface AuthStartResponse { writeKey: string; @@ -18,7 +17,7 @@ interface AuthStartResponse { } interface ContextType { - credentials: Credentials | undefined; + credentials: Credentials | null; state: | 'initializing' | 'authorizing' @@ -26,24 +25,28 @@ interface ContextType { | 'unauthorized' | 'failed'; refreshAccessToken: () => Promise; - login: () => Promise; - logout: () => Promise; + login: () => Promise; + logout: () => void; } const Context = createContext({ - credentials: undefined, + credentials: null, state: 'initializing', refreshAccessToken: () => Promise.resolve(), - login: () => Promise.resolve(), - logout: () => Promise.resolve(), + login: () => Promise.resolve(null), + // eslint-disable-next-line @typescript-eslint/no-empty-function + logout: () => {}, }); export function AuthProvider({ children }: { children: React.ReactNode }) { + const { credentials: syncedCredentials } = useConfig(); const [state, setState] = useState< 'initializing' | 'authorizing' | 'authorized' | 'unauthorized' | 'failed' >('initializing'); const [shouldUpdatePlugin, setShouldUpdatePlugin] = useState(false); - const [credentials, setCredentials] = useState(); + const [credentials, setCredentials] = useState( + syncedCredentials + ); useEffect(() => { // Try to get credentials from plugin if they exist. @@ -52,17 +55,12 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { return; } - AsyncMessage.ui - .request({ type: AsyncMessageTypes.GetCredentials }) - .then(({ credentials: _credentials }) => { - setCredentials(_credentials); - setState('authorized'); - }) - .catch((error) => { - console.error('Error requesting credentials from plugin', error); - setState('unauthorized'); - }); - }, [state]); + if (credentials) { + setState('authorized'); + } else { + setState('unauthorized'); + } + }, [credentials, state]); useEffect(() => { // Try to update plugin with credentials if they got updated on ui side @@ -71,14 +69,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { } if (state === 'authorized' && credentials) { - void AsyncMessage.ui.request({ - type: AsyncMessageTypes.SetCredentials, - credentials, - }); + void emit('set-credentials', { credentials }); } else if (state === 'unauthorized' && !credentials) { - void AsyncMessage.ui.request({ - type: AsyncMessageTypes.DeleteCredentials, - }); + void emit('set-credentials', { credentials: null }); } setShouldUpdatePlugin(false); @@ -86,7 +79,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { const refreshAccessToken = useCallback(async () => { if (!credentials) { - setCredentials(undefined); + setCredentials(null); setState('unauthorized'); setShouldUpdatePlugin(true); return; @@ -98,7 +91,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { }); if (!response.ok) { - setCredentials(undefined); + setCredentials(null); setState('unauthorized'); setShouldUpdatePlugin(true); return; @@ -112,23 +105,20 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { setState('authorized'); setShouldUpdatePlugin(true); } else { - setCredentials(undefined); + setCredentials(null); setState('unauthorized'); setShouldUpdatePlugin(true); } }, [credentials]); - const logout = useCallback(async () => { - await AsyncMessage.ui.request({ - type: AsyncMessageTypes.DeleteCredentials, - }); - setCredentials(undefined); + const logout = useCallback(() => { + setCredentials(null); setState('unauthorized'); setShouldUpdatePlugin(true); }, []); - const login = useCallback(async () => { - setCredentials(undefined); + const login = useCallback(async (): Promise => { + setCredentials(null); setState('authorizing'); setShouldUpdatePlugin(true); @@ -149,31 +139,37 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { window.open(`${config.AUTH_API_HOST}/auth/sign-in?figma_key=${writeKey}`); - // eslint-disable-next-line @typescript-eslint/no-misused-promises -- we want to use async function with interval - const interval = setInterval(async () => { - const exchangeResponse = await fetch( - `${config.AUTH_API_HOST}/api/auth/exchange`, - { - method: 'POST', - body: JSON.stringify({ readKey }), + return new Promise((resolve, reject) => { + // eslint-disable-next-line @typescript-eslint/no-misused-promises -- we want to use async function with interval + const interval = setInterval(async () => { + const exchangeResponse = await fetch( + `${config.AUTH_API_HOST}/api/auth/exchange`, + { + method: 'POST', + body: JSON.stringify({ readKey }), + } + ); + + if (!exchangeResponse.ok) { + setState('failed'); + return reject(new Error('Error polling for DS token.')); } - ); - if (!exchangeResponse.ok) { - setState('failed'); - throw new Error('Error polling for DS token.'); - } + const { data: _credentials, success: areCredentialsValid } = + CredentialsSchema.safeParse(await exchangeResponse.json()); - const { data: _credentials, success: areCredentialsValid } = - CredentialsSchema.safeParse(await exchangeResponse.json()); + if (areCredentialsValid) { + setCredentials(_credentials); + setState('authorized'); + setShouldUpdatePlugin(true); + clearInterval(interval); - if (areCredentialsValid) { - setCredentials(_credentials); - setState('authorized'); - setShouldUpdatePlugin(true); - clearInterval(interval); - } - }, config.READ_INTERVAL); + return resolve(_credentials); + } + + return; // continue polling + }, config.READ_INTERVAL); + }); }, []); const contextValue = useMemo( diff --git a/packages/figma-widget/src/ui/modules/providers/config-provider.tsx b/packages/figma-widget/src/ui/modules/providers/config-provider.tsx new file mode 100644 index 0000000..7071c8e --- /dev/null +++ b/packages/figma-widget/src/ui/modules/providers/config-provider.tsx @@ -0,0 +1,29 @@ +import { createContext, useContext } from 'react'; +import type { ConfigData } from '@ds-project/figma-utilities'; + +const Context = createContext({ + credentials: null, + fileName: null, + projectId: null, +}); + +interface ConfigProviderProps { + children: React.ReactNode; +} + +export function ConfigProvider({ children }: ConfigProviderProps) { + const config = window.__SHOW_UI_DATA__; + + return {children}; +} + +export function useConfig() { + const context = useContext(Context); + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- If provider is not available, this will be undefined + if (!context) { + throw new Error('useConfig should be used within '); + } + + return context; +} diff --git a/packages/figma-plugin/src/ui/modules/providers/index.tsx b/packages/figma-widget/src/ui/modules/providers/index.tsx similarity index 52% rename from packages/figma-plugin/src/ui/modules/providers/index.tsx rename to packages/figma-widget/src/ui/modules/providers/index.tsx index 276a944..bdaa48e 100644 --- a/packages/figma-plugin/src/ui/modules/providers/index.tsx +++ b/packages/figma-widget/src/ui/modules/providers/index.tsx @@ -3,14 +3,18 @@ import { AuthProvider } from './auth-provider'; import { ConfigProvider } from './config-provider'; import { ProjectsProvider } from './projects-provider'; -export function Providers({ children }: { children: React.ReactNode }) { +interface ProvidersProps { + children: React.ReactNode; +} + +export function Providers({ children }: ProvidersProps) { return ( - - - + + + {children} - - - + + + ); } diff --git a/packages/figma-plugin/src/ui/modules/providers/projects-provider.tsx b/packages/figma-widget/src/ui/modules/providers/projects-provider.tsx similarity index 62% rename from packages/figma-plugin/src/ui/modules/providers/projects-provider.tsx rename to packages/figma-widget/src/ui/modules/providers/projects-provider.tsx index ca061d3..5dbb33a 100644 --- a/packages/figma-plugin/src/ui/modules/providers/projects-provider.tsx +++ b/packages/figma-widget/src/ui/modules/providers/projects-provider.tsx @@ -2,19 +2,18 @@ import { createContext, useCallback, useContext, - useEffect, useMemo, useState, } from 'react'; -import { AsyncMessage } from '../../../message'; -import { AsyncMessageTypes } from '../../../message.types'; + import { api } from '@ds-project/api/react'; import { useConfig } from './config-provider'; import type { SelectProjects } from '../../../../../database/src/schema/projects'; +import { emit } from '@ds-project/figma-utilities'; interface ContextType { - selectedProjectId?: string; - linkProject: (projectId: string) => Promise; + selectedProjectId: string | null; + linkProject: (projectId: string) => void; projects?: Pick[]; isLoading: boolean; } @@ -22,43 +21,32 @@ interface ContextType { const Context = createContext({ isLoading: false, // eslint-disable-next-line @typescript-eslint/no-empty-function - linkProject: async () => {}, - selectedProjectId: undefined, + linkProject: () => {}, + selectedProjectId: null, projects: undefined, }); export function ProjectsProvider({ children }: { children: React.ReactNode }) { - const { fileName } = useConfig(); - const [selectedProjectId, setSelectedProjectId] = useState(); + const { fileName, projectId: defaultProjectId } = useConfig(); + const [selectedProjectId, setSelectedProjectId] = useState( + defaultProjectId + ); const { data: projects, isLoading: isProjectsLoading } = api.projects.account.useQuery(); const { mutate: linkResource } = api.resources.link.useMutation(); - useEffect(() => { - AsyncMessage.ui - .request({ - type: AsyncMessageTypes.GetProjectId, - }) - .then(({ projectId }) => { - if (!projectId) return; - setSelectedProjectId(projectId); - }) - .catch((error) => { - console.error('Error fetching design system from plugin', error); - }); - }, []); - const linkProject = useCallback( - async (projectId: string) => { - if (projectId && fileName) { - linkResource({ projectId, name: fileName }); - } - await AsyncMessage.ui.request({ - type: AsyncMessageTypes.SetProjectId, - projectId, - }); + (projectId: string) => { + const linkedProjectName = projects?.find( + (project) => project.id === projectId + )?.name; + if (!linkedProjectName || !fileName) return; + + linkResource({ projectId, name: fileName }); + setSelectedProjectId(projectId); + emit('set-project', { id: projectId, name: linkedProjectName }); }, - [fileName, linkResource] + [fileName, linkResource, projects] ); const value = useMemo( diff --git a/packages/figma-widget/src/ui/modules/variables.ui.tsx b/packages/figma-widget/src/ui/modules/variables.ui.tsx new file mode 100644 index 0000000..c53deae --- /dev/null +++ b/packages/figma-widget/src/ui/modules/variables.ui.tsx @@ -0,0 +1,40 @@ +import '@ds-project/components/globals.css'; + +import { useEffect } from 'react'; +import { api } from '@ds-project/api/react'; +import { useConfig } from './providers/config-provider'; +import { handle } from '@ds-project/figma-utilities'; +import { useProjects } from './providers/projects-provider'; + +export function VariablesUI() { + const { fileName } = useConfig(); + const { mutateAsync: updateDesignTokens } = + api.resources.updateDesignTokens.useMutation(); + const { selectedProjectId } = useProjects(); + + useEffect(() => { + handle('sync-variables', async ({ variables }) => { + // Update the design tokens when the variables are synced + if (!fileName || !selectedProjectId) { + return { + lastSyncedAt: null, + }; + } + + await updateDesignTokens({ + designTokens: variables, + name: fileName, + projectId: selectedProjectId, + }); + + return { + lastSyncedAt: new Date().getTime(), + }; + }).catch(() => { + console.error('Error handling sync-variables'); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: perhaps refactor handle so no more than one listener to the same message type is added + }, []); + + return null; +} diff --git a/packages/figma-plugin/tsconfig.json b/packages/figma-widget/src/ui/tsconfig.json similarity index 75% rename from packages/figma-plugin/tsconfig.json rename to packages/figma-widget/src/ui/tsconfig.json index fa0b256..2e67403 100644 --- a/packages/figma-plugin/tsconfig.json +++ b/packages/figma-widget/src/ui/tsconfig.json @@ -15,12 +15,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", - "typeRoots": ["./node_modules/@types", "./node_modules/@figma"] + "typeRoots": ["../../node_modules/@figma", "../../node_modules/@types"] }, - "include": ["src"], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] + "include": ["./**/*.ts", "./**/*.tsx"] } diff --git a/packages/figma-plugin/src/vite-env.d.ts b/packages/figma-widget/src/ui/vite-env.d.ts similarity index 61% rename from packages/figma-plugin/src/vite-env.d.ts rename to packages/figma-widget/src/ui/vite-env.d.ts index 99882b1..11f02fe 100644 --- a/packages/figma-plugin/src/vite-env.d.ts +++ b/packages/figma-widget/src/ui/vite-env.d.ts @@ -1,3 +1 @@ /// - -declare module '*.md'; diff --git a/packages/figma-widget/src/widget/components/button.tsx b/packages/figma-widget/src/widget/components/button.tsx new file mode 100644 index 0000000..90bf07c --- /dev/null +++ b/packages/figma-widget/src/widget/components/button.tsx @@ -0,0 +1,78 @@ +import { AutoLayout, Text } from '../lib/widget'; + +export const Button = ({ + onClick, + variant = 'default', + children, + ...props +}: TextChildren & + AutoLayoutProps & { + variant?: 'default' | 'outline' | 'ghost'; + }) => { + const styles: { + textStyles: TextProps; + wrapperStyles: AutoLayoutProps; + } = (() => { + switch (variant) { + case 'default': + return { + textStyles: { + fill: '#ffffff', + }, + wrapperStyles: { + fill: '#0F172A', + stroke: '#0F172A', + }, + }; + case 'outline': + return { + textStyles: { + fill: '#ffffff', + }, + wrapperStyles: { + fill: '#00000000', + stroke: '#f5f5f5', + hoverStyle: { + fill: '#f5f5f5', + }, + }, + }; + case 'ghost': + return { + textStyles: { + fill: '#000000', + fontSize: 14, + fontWeight: 'medium', + }, + wrapperStyles: { + fill: '#00000000', + stroke: '#f5f5f500', + hoverStyle: { + fill: '#f5f5f5', + }, + }, + }; + } + })(); + + return ( + + {typeof children === 'object' && + Array.isArray(children) && + typeof children[0] === 'string' ? ( + {children} + ) : ( + children + )} + + ); +}; diff --git a/packages/figma-widget/src/widget/components/container.tsx b/packages/figma-widget/src/widget/components/container.tsx new file mode 100644 index 0000000..a685aab --- /dev/null +++ b/packages/figma-widget/src/widget/components/container.tsx @@ -0,0 +1,76 @@ +import { AutoLayout, Text } from '../lib/widget'; +import { ConnectButton } from '../modules/auth/connect-button'; +import { Divider } from './divider'; +import { Link } from './link'; + +interface ContainerProps extends AutoLayoutProps { + projectNode?: FigmaDeclarativeNode | FigmaDeclarativeNode[]; +} + +export const Container = ({ + children, + projectNode, + ...props +}: ContainerProps) => { + return ( + + + + DS Pro + / + {projectNode} + + + + + + + + + {children} + + + + Feedback + + + + ); +}; diff --git a/packages/figma-widget/src/widget/components/divider.tsx b/packages/figma-widget/src/widget/components/divider.tsx new file mode 100644 index 0000000..0104067 --- /dev/null +++ b/packages/figma-widget/src/widget/components/divider.tsx @@ -0,0 +1,12 @@ +import { Line } from '../lib/widget'; + +export const Divider = () => { + return ( + + ); +}; diff --git a/packages/figma-widget/src/widget/components/link.tsx b/packages/figma-widget/src/widget/components/link.tsx new file mode 100644 index 0000000..447fb37 --- /dev/null +++ b/packages/figma-widget/src/widget/components/link.tsx @@ -0,0 +1,26 @@ +import { externalLinkIcon } from '../icons/external-link'; +import { AutoLayout, SVG, Text } from '../lib/widget'; + +export interface LinkProps extends TextChildren, TextProps {} + +export const Link = ({ children, onClick, ...props }: LinkProps) => { + return ( + + + {children} + + {props.href ? : null} + + ); +}; diff --git a/packages/figma-widget/src/widget/components/project.tsx b/packages/figma-widget/src/widget/components/project.tsx new file mode 100644 index 0000000..884e4db --- /dev/null +++ b/packages/figma-widget/src/widget/components/project.tsx @@ -0,0 +1,34 @@ +import { caretIcon } from '../icons/caret'; +import { AutoLayout, SVG, Text } from '../lib/widget'; + +interface ProjectSelectorProps { + selectedProject: { name: string; id: string } | null; + onProjectSelect: () => void; +} + +export function ProjectSelector({ + selectedProject, + onProjectSelect, +}: ProjectSelectorProps) { + return ( + + + {selectedProject?.name ?? 'Select a project'} + + + + + ); +} diff --git a/packages/figma-widget/src/widget/components/variables.tsx b/packages/figma-widget/src/widget/components/variables.tsx new file mode 100644 index 0000000..90c68e8 --- /dev/null +++ b/packages/figma-widget/src/widget/components/variables.tsx @@ -0,0 +1,56 @@ +import { updateIcon } from '../icons/update'; +import { AutoLayout, SVG, Text } from '../lib/widget'; +import { Button } from './button'; + +interface VariablesProps { + lastSyncedAt: number | null; + onSyncVariablesClick: () => void; +} + +export function Variables({ + lastSyncedAt, + onSyncVariablesClick, +}: VariablesProps) { + const formatDate = (date: Date) => { + return date.toLocaleString('en-GB', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + hour12: false, + }); + }; + + return ( + + + + ๐Ÿงฉ Local variables + + + + {lastSyncedAt + ? `Last synced ${formatDate(new Date(lastSyncedAt))}` + : 'This is your first time syncing ๐Ÿš€'} + + + + + + + + ); +} diff --git a/packages/figma-plugin/src/plugin/config.ts b/packages/figma-widget/src/widget/config.ts similarity index 100% rename from packages/figma-plugin/src/plugin/config.ts rename to packages/figma-widget/src/widget/config.ts diff --git a/packages/figma-widget/src/widget/hooks/ui.ts b/packages/figma-widget/src/widget/hooks/ui.ts new file mode 100644 index 0000000..9cbc0d6 --- /dev/null +++ b/packages/figma-widget/src/widget/hooks/ui.ts @@ -0,0 +1,49 @@ +import { useSyncedCredentials, useSyncedLinkedProject } from '../modules/state'; +import { once } from '@ds-project/figma-utilities'; + +export function useUI() { + const [syncedLinkedProject] = useSyncedLinkedProject(); + const [syncedCredentials] = useSyncedCredentials(); + + const open = async (options: ShowUIOptions = {}) => { + const hasOpenedPromise = new Promise((resolve) => { + once('ui-is-ready', () => { + console.log('โœจ UI is open - โœ…'); + resolve(void 0); + }); + }); + + void new Promise(() => { + console.log('โœจ Show UI - ๐Ÿ™‹'); + + figma.showUI( + __html__.replace( + '%__SHOW_UI_DATA__%', + JSON.stringify({ + projectId: syncedLinkedProject?.id ?? null, + fileName: figma.root.name, + credentials: syncedCredentials, + }) + ), + { + title: 'DS Project', + visible: false, + themeColors: false, + ...options, + } + ); + }); + + return hasOpenedPromise; + }; + + const close = (message?: string) => { + figma.closePlugin(message); + console.log('โœจ UI is closed - โŒ'); + }; + + return { + open, + close, + }; +} diff --git a/packages/figma-widget/src/widget/icons/caret.ts b/packages/figma-widget/src/widget/icons/caret.ts new file mode 100644 index 0000000..6455a3c --- /dev/null +++ b/packages/figma-widget/src/widget/icons/caret.ts @@ -0,0 +1,5 @@ +export const caretIcon = ` + + + +`; diff --git a/packages/figma-widget/src/widget/icons/external-link.ts b/packages/figma-widget/src/widget/icons/external-link.ts new file mode 100644 index 0000000..9052650 --- /dev/null +++ b/packages/figma-widget/src/widget/icons/external-link.ts @@ -0,0 +1,2 @@ +export const externalLinkIcon = + ''; diff --git a/packages/figma-widget/src/widget/icons/update.ts b/packages/figma-widget/src/widget/icons/update.ts new file mode 100644 index 0000000..882a884 --- /dev/null +++ b/packages/figma-widget/src/widget/icons/update.ts @@ -0,0 +1,2 @@ +export const updateIcon = + ''; diff --git a/packages/figma-widget/src/widget/lib/widget.ts b/packages/figma-widget/src/widget/lib/widget.ts new file mode 100644 index 0000000..c35654d --- /dev/null +++ b/packages/figma-widget/src/widget/lib/widget.ts @@ -0,0 +1,30 @@ +/* eslint-disable @typescript-eslint/unbound-method */ + +/** + * This file is an exporter for the Figma widget API. + */ + +const { widget } = figma; +const { + AutoLayout, + Ellipse, + Frame, + Line, + register: registerWidget, + SVG, + Text, + useSyncedState, + useEffect, +} = widget; + +export { + AutoLayout, + Ellipse, + Frame, + Line, + registerWidget, + SVG, + Text, + useSyncedState, + useEffect, +}; diff --git a/packages/figma-widget/src/widget/main.tsx b/packages/figma-widget/src/widget/main.tsx new file mode 100644 index 0000000..d7a3fee --- /dev/null +++ b/packages/figma-widget/src/widget/main.tsx @@ -0,0 +1,26 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import { Container } from './components/container'; +import { registerWidget } from './lib/widget'; +import { ProjectSelect } from './modules/project/project-select'; +import { AuthEvents } from './modules/auth/auth.events'; +import { AuthWarning } from './modules/auth/auth-warning'; +import { ProjectEvents } from './modules/project/project.events'; +import { VariablesEvents } from './modules/variables/variables.events'; +import { ProjectWarning } from './modules/project/project-warning'; +import { VariablesSync } from './modules/variables/variables-sync'; + +function Widget() { + return ( + }> + + + + + + + + + ); +} + +registerWidget(Widget); diff --git a/packages/figma-widget/src/widget/modules/auth/auth-warning.tsx b/packages/figma-widget/src/widget/modules/auth/auth-warning.tsx new file mode 100644 index 0000000..8d81b38 --- /dev/null +++ b/packages/figma-widget/src/widget/modules/auth/auth-warning.tsx @@ -0,0 +1,34 @@ +import { Button } from '../../components/button'; +import { AutoLayout, Text } from '../../lib/widget'; +import { useAuthActions } from './auth.actions'; + +export function AuthWarning() { + const { isConnected, connect } = useAuthActions(); + + if (isConnected) { + return null; + } + + return ( + + + Connect to DS + + + Connect this widget to DS to synchronize variables and other assets + directly from this Figma file. + + + + ); +} diff --git a/packages/figma-widget/src/widget/modules/auth/auth.actions.tsx b/packages/figma-widget/src/widget/modules/auth/auth.actions.tsx new file mode 100644 index 0000000..8e525bf --- /dev/null +++ b/packages/figma-widget/src/widget/modules/auth/auth.actions.tsx @@ -0,0 +1,29 @@ +import { request } from '@ds-project/figma-utilities'; +import { useUI } from '../../hooks/ui'; +import { useSyncedCredentials } from '../state'; + +export function useAuthActions({ + onDisconnect, +}: { onDisconnect?: () => void } = {}) { + const [syncedCredentials, setSyncedCredentials] = useSyncedCredentials(); + const { open, close } = useUI(); + const isConnected = Boolean(syncedCredentials); + + const disconnect = () => { + setSyncedCredentials(null); + onDisconnect?.(); + }; + + const connect = async () => { + await open(); + const { credentials } = await request('connect', undefined); + setSyncedCredentials(credentials); + close(); + }; + + return { + isConnected, + disconnect, + connect, + }; +} diff --git a/packages/figma-widget/src/widget/modules/auth/auth.events.tsx b/packages/figma-widget/src/widget/modules/auth/auth.events.tsx new file mode 100644 index 0000000..3ba8e47 --- /dev/null +++ b/packages/figma-widget/src/widget/modules/auth/auth.events.tsx @@ -0,0 +1,13 @@ +import { on } from '@ds-project/figma-utilities'; +import { useSyncedCredentials } from '../state'; + +export function AuthEvents() { + const [_, setSyncedCredentials] = useSyncedCredentials(); + + on('set-credentials', ({ credentials }) => { + console.log('handling set-credentials', credentials); + setSyncedCredentials(credentials); + }); + + return null; +} diff --git a/packages/figma-widget/src/widget/modules/auth/connect-button.tsx b/packages/figma-widget/src/widget/modules/auth/connect-button.tsx new file mode 100644 index 0000000..159c9d1 --- /dev/null +++ b/packages/figma-widget/src/widget/modules/auth/connect-button.tsx @@ -0,0 +1,15 @@ +import type { LinkProps } from '../../components/link'; +import { Link } from '../../components/link'; +import { useAuthActions } from './auth.actions'; + +type ConnectButtonProps = LinkProps; + +export function ConnectButton(props: ConnectButtonProps) { + const { isConnected, connect, disconnect } = useAuthActions(); + + return ( + + {isConnected ? 'Disconnect' : 'Connect'} + + ); +} diff --git a/packages/figma-plugin/src/plugin/design-tokens/extract-design-tokens.ts b/packages/figma-widget/src/widget/modules/design-tokens/extract-design-tokens.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/extract-design-tokens.ts rename to packages/figma-widget/src/widget/modules/design-tokens/extract-design-tokens.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/extractors/boolean.ts b/packages/figma-widget/src/widget/modules/design-tokens/extractors/boolean.ts similarity index 95% rename from packages/figma-plugin/src/plugin/design-tokens/extractors/boolean.ts rename to packages/figma-widget/src/widget/modules/design-tokens/extractors/boolean.ts index f8cd8b6..256d6e7 100644 --- a/packages/figma-plugin/src/plugin/design-tokens/extractors/boolean.ts +++ b/packages/figma-widget/src/widget/modules/design-tokens/extractors/boolean.ts @@ -1,5 +1,4 @@ import { DesignToken } from 'style-dictionary/types'; -import { toHex } from 'color2k'; import { FigmaExtractedVariable } from '../types'; export function extractBoolean( diff --git a/packages/figma-plugin/src/plugin/design-tokens/extractors/color.ts b/packages/figma-widget/src/widget/modules/design-tokens/extractors/color.ts similarity index 96% rename from packages/figma-plugin/src/plugin/design-tokens/extractors/color.ts rename to packages/figma-widget/src/widget/modules/design-tokens/extractors/color.ts index 887d36c..1e6ec0c 100644 --- a/packages/figma-plugin/src/plugin/design-tokens/extractors/color.ts +++ b/packages/figma-widget/src/widget/modules/design-tokens/extractors/color.ts @@ -1,7 +1,7 @@ import type { DesignToken } from 'style-dictionary/types'; import { extractAlias } from './extract-alias'; import { tokenizeVariable } from '../utils/tokenize-variable'; -import { config } from '../../config'; +import { config } from '../../../config'; import { rgbToHex } from '../transformers'; export async function extractColor( diff --git a/packages/figma-plugin/src/plugin/design-tokens/extractors/extract-alias.ts b/packages/figma-widget/src/widget/modules/design-tokens/extractors/extract-alias.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/extractors/extract-alias.ts rename to packages/figma-widget/src/widget/modules/design-tokens/extractors/extract-alias.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/extractors/extract-mode-variable.ts b/packages/figma-widget/src/widget/modules/design-tokens/extractors/extract-mode-variable.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/extractors/extract-mode-variable.ts rename to packages/figma-widget/src/widget/modules/design-tokens/extractors/extract-mode-variable.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/extractors/extract-variable.ts b/packages/figma-widget/src/widget/modules/design-tokens/extractors/extract-variable.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/extractors/extract-variable.ts rename to packages/figma-widget/src/widget/modules/design-tokens/extractors/extract-variable.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/extractors/float.ts b/packages/figma-widget/src/widget/modules/design-tokens/extractors/float.ts similarity index 96% rename from packages/figma-plugin/src/plugin/design-tokens/extractors/float.ts rename to packages/figma-widget/src/widget/modules/design-tokens/extractors/float.ts index b3fe268..1f03d5d 100644 --- a/packages/figma-plugin/src/plugin/design-tokens/extractors/float.ts +++ b/packages/figma-widget/src/widget/modules/design-tokens/extractors/float.ts @@ -1,7 +1,7 @@ import type { DesignToken } from 'style-dictionary/types'; import { tokenizeVariable } from '../utils/tokenize-variable'; import { extractAlias } from './extract-alias'; -import { config } from '../../config'; +import { config } from '../../../config'; export async function extractFloat( variable: Variable, diff --git a/packages/figma-plugin/src/plugin/design-tokens/extractors/string.ts b/packages/figma-widget/src/widget/modules/design-tokens/extractors/string.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/extractors/string.ts rename to packages/figma-widget/src/widget/modules/design-tokens/extractors/string.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/extractors/variable-collection.ts b/packages/figma-widget/src/widget/modules/design-tokens/extractors/variable-collection.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/extractors/variable-collection.ts rename to packages/figma-widget/src/widget/modules/design-tokens/extractors/variable-collection.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/filters/not-implemented.ts b/packages/figma-widget/src/widget/modules/design-tokens/filters/not-implemented.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/filters/not-implemented.ts rename to packages/figma-widget/src/widget/modules/design-tokens/filters/not-implemented.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/transformers/color.ts b/packages/figma-widget/src/widget/modules/design-tokens/transformers/color.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/transformers/color.ts rename to packages/figma-widget/src/widget/modules/design-tokens/transformers/color.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/transformers/index.ts b/packages/figma-widget/src/widget/modules/design-tokens/transformers/index.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/transformers/index.ts rename to packages/figma-widget/src/widget/modules/design-tokens/transformers/index.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/types/figma.ts b/packages/figma-widget/src/widget/modules/design-tokens/types/figma.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/types/figma.ts rename to packages/figma-widget/src/widget/modules/design-tokens/types/figma.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/types/index.ts b/packages/figma-widget/src/widget/modules/design-tokens/types/index.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/types/index.ts rename to packages/figma-widget/src/widget/modules/design-tokens/types/index.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/utils/combine-paths.ts b/packages/figma-widget/src/widget/modules/design-tokens/utils/combine-paths.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/utils/combine-paths.ts rename to packages/figma-widget/src/widget/modules/design-tokens/utils/combine-paths.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/utils/get-mode-key.ts b/packages/figma-widget/src/widget/modules/design-tokens/utils/get-mode-key.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/utils/get-mode-key.ts rename to packages/figma-widget/src/widget/modules/design-tokens/utils/get-mode-key.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/utils/get-variable-collection.ts b/packages/figma-widget/src/widget/modules/design-tokens/utils/get-variable-collection.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/utils/get-variable-collection.ts rename to packages/figma-widget/src/widget/modules/design-tokens/utils/get-variable-collection.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/utils/non-nullable.ts b/packages/figma-widget/src/widget/modules/design-tokens/utils/non-nullable.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/utils/non-nullable.ts rename to packages/figma-widget/src/widget/modules/design-tokens/utils/non-nullable.ts diff --git a/packages/figma-plugin/src/plugin/design-tokens/utils/tokenize-variable.ts b/packages/figma-widget/src/widget/modules/design-tokens/utils/tokenize-variable.ts similarity index 100% rename from packages/figma-plugin/src/plugin/design-tokens/utils/tokenize-variable.ts rename to packages/figma-widget/src/widget/modules/design-tokens/utils/tokenize-variable.ts diff --git a/packages/figma-widget/src/widget/modules/project/project-select.tsx b/packages/figma-widget/src/widget/modules/project/project-select.tsx new file mode 100644 index 0000000..c685c97 --- /dev/null +++ b/packages/figma-widget/src/widget/modules/project/project-select.tsx @@ -0,0 +1,29 @@ +import { Button } from '../../components/button'; +import { caretIcon } from '../../icons/caret'; +import { AutoLayout, SVG, Text } from '../../lib/widget'; +import { useProjectActions } from './project.actions'; + +export function ProjectSelect() { + const { selectProject, selectedProject, isReady } = useProjectActions(); + + if (!isReady) { + return null; + } + + if (selectedProject) { + return ( + + ); + } + + return ( + + ); +} diff --git a/packages/figma-widget/src/widget/modules/project/project-warning.tsx b/packages/figma-widget/src/widget/modules/project/project-warning.tsx new file mode 100644 index 0000000..ca6b2ae --- /dev/null +++ b/packages/figma-widget/src/widget/modules/project/project-warning.tsx @@ -0,0 +1,23 @@ +import { Text } from '../../lib/widget'; +import { useProjectActions } from './project.actions'; + +export function ProjectWarning() { + const { selectedProject, isReady } = useProjectActions(); + + if (!isReady) { + // Project is not ready to be selected + return null; + } + + if (selectedProject) { + // Project has been selected + return null; + } + + // Project is ready to be selected + return ( + + โ˜๏ธ Select a project to get started + + ); +} diff --git a/packages/figma-widget/src/widget/modules/project/project.actions.tsx b/packages/figma-widget/src/widget/modules/project/project.actions.tsx new file mode 100644 index 0000000..263a552 --- /dev/null +++ b/packages/figma-widget/src/widget/modules/project/project.actions.tsx @@ -0,0 +1,33 @@ +import { emit, once } from '@ds-project/figma-utilities'; +import { useUI } from '../../hooks/ui'; +import { useSyncedLinkedProject } from '../state'; +import { useAuthActions } from '../auth/auth.actions'; + +export function useProjectActions() { + const { open, close } = useUI(); + const [selectedProject, setSyncedLinkedProject] = useSyncedLinkedProject(); + const { isConnected } = useAuthActions(); + const isReady = isConnected; + + const selectProject = async () => { + await open({ visible: true }); + + // TODO: because it's a visible ui, we need to wait for the user to select a project. Maybe we could do this differently + await new Promise((resolve) => { + emit('open-projects-ui', undefined); + + once('set-project', (project) => { + console.log('project', project); + setSyncedLinkedProject(project); + close(); + resolve(void 0); + }); + }); + }; + + return { + isReady, + selectProject, + selectedProject, + }; +} diff --git a/packages/figma-widget/src/widget/modules/project/project.events.tsx b/packages/figma-widget/src/widget/modules/project/project.events.tsx new file mode 100644 index 0000000..ef407b9 --- /dev/null +++ b/packages/figma-widget/src/widget/modules/project/project.events.tsx @@ -0,0 +1,13 @@ +import { useAuthActions } from '../auth/auth.actions'; +import { useSyncedLinkedProject } from '../state'; + +export function ProjectEvents() { + const [_, setSyncedLinkedProject] = useSyncedLinkedProject(); + useAuthActions({ + onDisconnect: () => { + setSyncedLinkedProject(null); + }, + }); + + return null; +} diff --git a/packages/figma-widget/src/widget/modules/state.ts b/packages/figma-widget/src/widget/modules/state.ts new file mode 100644 index 0000000..80d15dc --- /dev/null +++ b/packages/figma-widget/src/widget/modules/state.ts @@ -0,0 +1,17 @@ +import type { Credentials } from '@ds-project/figma-utilities'; +import { useSyncedState } from '../lib/widget'; + +export const useSyncedCredentials = () => { + return useSyncedState('credentials', null); +}; + +export const useSyncedLinkedProject = () => { + return useSyncedState<{ name: string; id: string } | null>( + 'projectName', + null + ); +}; + +export const useSyncedLastSyncedAt = () => { + return useSyncedState('lastSyncedAt', null); +}; diff --git a/packages/figma-widget/src/widget/modules/variables/variables-sync.tsx b/packages/figma-widget/src/widget/modules/variables/variables-sync.tsx new file mode 100644 index 0000000..02b4d61 --- /dev/null +++ b/packages/figma-widget/src/widget/modules/variables/variables-sync.tsx @@ -0,0 +1,17 @@ +import { Variables } from '../../components/variables'; +import { useVariablesActions } from './variables.actions'; + +export function VariablesSync() { + const { syncVariables, isReady, lastSyncedAt } = useVariablesActions(); + + if (!isReady) { + return null; + } + + return ( + + ); +} diff --git a/packages/figma-widget/src/widget/modules/variables/variables.actions.ts b/packages/figma-widget/src/widget/modules/variables/variables.actions.ts new file mode 100644 index 0000000..118f237 --- /dev/null +++ b/packages/figma-widget/src/widget/modules/variables/variables.actions.ts @@ -0,0 +1,32 @@ +import { request } from '@ds-project/figma-utilities'; +import { useUI } from '../../hooks/ui'; +import { useSyncedLastSyncedAt } from '../state'; +import { extractDesignTokens } from '../design-tokens/extract-design-tokens'; +import { useAuthActions } from '../auth/auth.actions'; +import { useProjectActions } from '../project/project.actions'; + +export function useVariablesActions() { + const { open } = useUI(); + const [lastSyncedAt, setLastSyncedAt] = useSyncedLastSyncedAt(); + const { isConnected } = useAuthActions(); + const { selectedProject } = useProjectActions(); + const isReady = isConnected && selectedProject; + + const syncVariables = async () => { + const designTokens = await extractDesignTokens(); + + await open(); + + const { lastSyncedAt } = await request('sync-variables', { + variables: designTokens, + }); + + setLastSyncedAt(lastSyncedAt); + }; + + return { + isReady, + lastSyncedAt, + syncVariables, + }; +} diff --git a/packages/figma-widget/src/widget/modules/variables/variables.events.ts b/packages/figma-widget/src/widget/modules/variables/variables.events.ts new file mode 100644 index 0000000..b07d218 --- /dev/null +++ b/packages/figma-widget/src/widget/modules/variables/variables.events.ts @@ -0,0 +1,3 @@ +export function VariablesEvents() { + return null; +} diff --git a/packages/figma-widget/src/widget/tsconfig.json b/packages/figma-widget/src/widget/tsconfig.json new file mode 100644 index 0000000..b69404e --- /dev/null +++ b/packages/figma-widget/src/widget/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "jsx": "react", + "jsxFactory": "figma.widget.h", + "jsxFragmentFactory": "figma.widget.Fragment", + "target": "ESNext", + "lib": ["ESNext", "DOM"], + "strict": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "allowSyntheticDefaultImports": true, + "typeRoots": ["../../node_modules/@figma"], + "sourceMap": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} diff --git a/packages/figma-plugin/tailwind.config.ts b/packages/figma-widget/tailwind.config.ts similarity index 51% rename from packages/figma-plugin/tailwind.config.ts rename to packages/figma-widget/tailwind.config.ts index dee3080..d8273ec 100644 --- a/packages/figma-plugin/tailwind.config.ts +++ b/packages/figma-widget/tailwind.config.ts @@ -1,11 +1,11 @@ import type { Config } from 'tailwindcss'; const config: Config = { - content: [ - './src/plugin/**/*.{js,ts,jsx,tsx,mdx}', - './src/ui/**/*.{js,ts,jsx,tsx,mdx}', - ], - + content: ['./src/ui/**/*.{ts,tsx}', './src/ui/index.html'], + theme: { + extend: {}, + }, plugins: [], }; + export default config; diff --git a/packages/figma-plugin/vite.config.ts b/packages/figma-widget/vite.config.ts similarity index 74% rename from packages/figma-plugin/vite.config.ts rename to packages/figma-widget/vite.config.ts index c391654..116d46e 100644 --- a/packages/figma-plugin/vite.config.ts +++ b/packages/figma-widget/vite.config.ts @@ -1,3 +1,4 @@ +import path from 'node:path'; import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { viteSingleFile } from 'vite-plugin-singlefile'; @@ -10,8 +11,10 @@ export default defineConfig({ build: { emptyOutDir: false, cssCodeSplit: false, + outDir: path.resolve('dist'), rollupOptions: { - plugins: [preserveDirectives()], + plugins: [preserveDirectives], + input: path.resolve('src/ui/index.html'), }, }, }); diff --git a/packages/figma-plugin/vite.config.plugin.ts b/packages/figma-widget/vite.config.widget.ts similarity index 70% rename from packages/figma-plugin/vite.config.plugin.ts rename to packages/figma-widget/vite.config.widget.ts index 9618aa7..65ee3ed 100644 --- a/packages/figma-plugin/vite.config.plugin.ts +++ b/packages/figma-widget/vite.config.widget.ts @@ -12,16 +12,11 @@ export default defineConfig(({ mode }) => ({ emptyOutDir: false, outDir: path.resolve('dist'), rollupOptions: { - plugins: [preserveDirectives()], - input: path.resolve('src/plugin/plugin.ts'), + plugins: [preserveDirectives], + input: path.resolve('src/widget/main.tsx'), output: { - entryFileNames: 'plugin.js', + entryFileNames: 'widget.js', }, }, }, - resolve: { - alias: { - '@plugin': path.resolve('src/plugin'), - }, - }, })); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 35cdf20..f6cec8c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,9 +6,63 @@ settings: catalogs: default: + '@figma/plugin-typings': + specifier: ^1.99.0 + version: 1.99.0 + '@figma/widget-typings': + specifier: ^1.9.1 + version: 1.9.1 + '@trpc/react-query': + specifier: 11.0.0-rc.482 + version: 11.0.0-rc.482 + '@types/node': + specifier: ^22.4.1 + version: 22.4.1 + '@types/react': + specifier: ^18.3.3 + version: 18.3.3 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.0 + '@vitejs/plugin-react': + specifier: ^4.3.1 + version: 4.3.1 + concurrently: + specifier: ^8.2.2 + version: 8.2.2 eslint: specifier: ^8.57.0 version: 8.57.0 + next: + specifier: ^14.2.6 + version: 14.2.6 + postcss: + specifier: ^8.4.39 + version: 8.4.41 + prettier: + specifier: ^3.3.3 + version: 3.3.3 + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1 + style-dictionary: + specifier: ^4.0.1 + version: 4.1.0 + tailwindcss: + specifier: ^3.4.7 + version: 3.4.7 + typescript: + specifier: ^5.5.4 + version: 5.5.4 + vite: + specifier: ^5.3.1 + version: 5.3.3 + zod: + specifier: ^3.23.8 + version: 3.23.8 overrides: '@trpc/client': 11.0.0-rc.482 @@ -56,7 +110,7 @@ importers: version: 6.1.2 '@sentry/nextjs': specifier: ^8 - version: 8.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0))(next@14.2.6(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)(webpack@5.94.0) + version: 8.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0))(next@14.2.6(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)(webpack@5.94.0(esbuild@0.19.12)) '@supabase/ssr': specifier: ^0.4.0 version: 0.4.0(@supabase/supabase-js@2.45.0) @@ -140,7 +194,7 @@ importers: version: 0.0.1 style-dictionary: specifier: 'catalog:' - version: 4.0.1 + version: 4.1.0 superjson: specifier: ^2.2.1 version: 2.2.1 @@ -322,7 +376,7 @@ importers: version: 18.3.1 style-dictionary: specifier: 'catalog:' - version: 4.0.1 + version: 4.1.0 superjson: specifier: ^2.2.1 version: 2.2.1 @@ -430,6 +484,9 @@ importers: '@radix-ui/react-select': specifier: ^2.1.1 version: 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-separator': + specifier: ^1.1.0 + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': specifier: ^1.1.0 version: 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -566,58 +623,65 @@ importers: version: 8.57.0 style-dictionary: specifier: 'catalog:' - version: 4.0.1 + version: 4.1.0 typescript: specifier: 'catalog:' version: 5.5.4 - packages/figma-plugin: + packages/figma-utilities: dependencies: - '@apollo/client': - specifier: ^3.7.11 - version: 3.10.8(@types/react@18.3.3)(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@ds-project/api': + '@create-figma-plugin/utilities': + specifier: ^3.2.0 + version: 3.2.0 + object-hash: + specifier: ^3.0.0 + version: 3.0.0 + style-dictionary: + specifier: ^4.1.0 + version: 4.1.0 + zod: + specifier: ^3.23.8 + version: 3.23.8 + devDependencies: + '@ds-project/eslint': specifier: workspace:* - version: link:../api - '@ds-project/components': + version: link:../../tools/eslint + '@ds-project/prettier': specifier: workspace:* - version: link:../components - '@octokit/core': - specifier: ^6.1.2 - version: 6.1.2 - '@octokit/request': - specifier: ^9.1.3 - version: 9.1.3 - '@octokit/types': - specifier: ^13.5.0 - version: 13.5.0 + version: link:../../tools/prettier + '@ds-project/typescript': + specifier: workspace:* + version: link:../../tools/typescript + '@figma/plugin-typings': + specifier: 'catalog:' + version: 1.99.0 + '@figma/widget-typings': + specifier: 'catalog:' + version: 1.9.1(@figma/plugin-typings@1.99.0) + '@types/object-hash': + specifier: ^3.0.6 + version: 3.0.6 + eslint: + specifier: 'catalog:' + version: 8.57.0 + typescript: + specifier: 'catalog:' + version: 5.5.4 + + packages/figma-widget: + dependencies: + '@create-figma-plugin/utilities': + specifier: ^3.2.0 + version: 3.2.0 '@tanstack/react-query': specifier: ^5.51.24 version: 5.51.24(react@18.3.1) - '@trpc/client': - specifier: 11.0.0-rc.482 - version: 11.0.0-rc.482(@trpc/server@11.0.0-rc.482) - '@trpc/react-query': - specifier: 'catalog:' - version: 11.0.0-rc.482(@tanstack/react-query@5.51.24(react@18.3.1))(@trpc/client@11.0.0-rc.482(@trpc/server@11.0.0-rc.482))(@trpc/server@11.0.0-rc.482)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - color2k: - specifier: ^2.0.3 - version: 2.0.3 - crypto-hash: - specifier: ^3.1.0 - version: 3.1.0 - graphql: - specifier: ^16.6.0 - version: 16.9.0 memoize: specifier: ^10.0.0 version: 10.0.0 object-hash: specifier: ^3.0.0 version: 3.0.0 - octokit: - specifier: ^4.0.2 - version: 4.0.2 rambda: specifier: ^9.2.1 version: 9.2.1 @@ -627,43 +691,40 @@ importers: react-dom: specifier: 'catalog:' version: 18.3.1(react@18.3.1) - react-json-view-lite: - specifier: ^1.4.0 - version: 1.4.0(react@18.3.1) - sass: - specifier: ^1.60.0 - version: 1.77.8 style-dictionary: - specifier: 'catalog:' - version: 4.0.1 + specifier: ^4.1.0 + version: 4.1.0 superjson: specifier: ^2.2.1 version: 2.2.1 - tailwindcss: - specifier: 'catalog:' - version: 3.4.7 trpc-token-refresh-link: specifier: ^0.5.0 version: 0.5.0 zod: - specifier: 'catalog:' + specifier: ^3.23.8 version: 3.23.8 devDependencies: + '@ds-project/api': + specifier: workspace:* + version: link:../api + '@ds-project/components': + specifier: workspace:* + version: link:../components '@ds-project/eslint': specifier: workspace:* version: link:../../tools/eslint + '@ds-project/figma-utilities': + specifier: workspace:* + version: link:../figma-utilities '@ds-project/prettier': specifier: workspace:* version: link:../../tools/prettier - '@figma/eslint-plugin-figma-plugins': - specifier: ^0.15.0 - version: 0.15.0(eslint@8.57.0) '@figma/plugin-typings': specifier: 'catalog:' version: 1.99.0 - '@types/object-hash': - specifier: ^3.0.6 - version: 3.0.6 + '@figma/widget-typings': + specifier: 'catalog:' + version: 1.9.1(@figma/plugin-typings@1.99.0) '@types/react': specifier: 'catalog:' version: 18.3.3 @@ -671,20 +732,32 @@ importers: specifier: 'catalog:' version: 18.3.0 '@vitejs/plugin-react': - specifier: 'catalog:' + specifier: ^4.3.1 version: 4.3.1(vite@5.3.3(@types/node@22.4.1)(sass@1.77.8)(terser@5.31.6)) + '@vitejs/plugin-react-refresh': + specifier: ^1.3.1 + version: 1.3.6 + autoprefixer: + specifier: ^10.4.19 + version: 10.4.19(postcss@8.4.45) concurrently: - specifier: 'catalog:' - version: 8.2.2 + specifier: ^6.3.0 + version: 6.5.1 esbuild: - specifier: 'catalog:' - version: 0.23.1 + specifier: ^0.13.5 + version: 0.13.15 eslint: specifier: 'catalog:' version: 8.57.0 + postcss: + specifier: ^8.4.45 + version: 8.4.45 rollup-preserve-directives: specifier: ^1.1.1 - version: 1.1.1(rollup@4.21.0) + version: 1.1.1(rollup@2.79.1) + tailwindcss: + specifier: ^3.4.10 + version: 3.4.10 typescript: specifier: 'catalog:' version: 5.5.4 @@ -692,8 +765,8 @@ importers: specifier: 'catalog:' version: 5.3.3(@types/node@22.4.1)(sass@1.77.8)(terser@5.31.6) vite-plugin-singlefile: - specifier: 'catalog:' - version: 2.0.2(rollup@4.21.0)(vite@5.3.3(@types/node@22.4.1)(sass@1.77.8)(terser@5.31.6)) + specifier: ^0.5.1 + version: 0.5.1(vite@5.3.3(@types/node@22.4.1)(sass@1.77.8)(terser@5.31.6)) packages/services: dependencies: @@ -754,7 +827,7 @@ importers: version: 4.6.2(eslint@8.57.0) eslint-plugin-tailwindcss: specifier: ^3.15.1 - version: 3.17.4(tailwindcss@3.4.7) + version: 3.17.4(tailwindcss@3.4.10) eslint-plugin-turbo: specifier: ^2.0.14 version: 2.0.14(eslint@8.57.0) @@ -794,24 +867,6 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@apollo/client@3.10.8': - resolution: {integrity: sha512-UaaFEitRrPRWV836wY2L7bd3HRCfbMie1jlYMcmazFAK23MVhz/Uq7VG1nwbotPb5xzFsw5RF4Wnp2G3dWPM3g==} - peerDependencies: - graphql: ^15.0.0 || ^16.0.0 - graphql-ws: ^5.5.5 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - subscriptions-transport-ws: ^0.9.0 || ^0.11.0 - peerDependenciesMeta: - graphql-ws: - optional: true - react: - optional: true - react-dom: - optional: true - subscriptions-transport-ws: - optional: true - '@babel/code-frame@7.24.2': resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} engines: {node: '>=6.9.0'} @@ -1546,6 +1601,10 @@ packages: '@bundled-es-modules/memfs@4.9.4': resolution: {integrity: sha512-1XyYPUaIHwEOdF19wYVLBtHJRr42Do+3ctht17cZOHwHf67vkmRNPlYDGY2kJps4RgE5+c7nEZmEzxxvb1NZWA==} + '@create-figma-plugin/utilities@3.2.0': + resolution: {integrity: sha512-+5JddDqI6XjVJs0EqgLd+6B9ukjhHFEBesqPI/e0okqS+Ay7Gt3xsD0vMrZjVYfJcmRAprgJhdGBGJZjOZiQIA==} + engines: {node: '>=20'} + '@drizzle-team/brocli@0.8.2': resolution: {integrity: sha512-zTrFENsqGvOkBOuHDC1pXCkDXNd2UhP4lI3gYGhQ1R1SPeAAfqzPsV1dcpMy4uNU6kB5VpU5NGhvwxVNETR02A==} @@ -1599,12 +1658,6 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.23.1': - resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/android-arm64@0.18.20': resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -1623,12 +1676,6 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.23.1': - resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm@0.18.20': resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} @@ -1647,12 +1694,6 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.23.1': - resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-x64@0.18.20': resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} @@ -1671,12 +1712,6 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.23.1': - resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/darwin-arm64@0.18.20': resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} @@ -1695,12 +1730,6 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.23.1': - resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-x64@0.18.20': resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} @@ -1719,12 +1748,6 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.23.1': - resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/freebsd-arm64@0.18.20': resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} @@ -1743,12 +1766,6 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.23.1': - resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-x64@0.18.20': resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} @@ -1767,12 +1784,6 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.23.1': - resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/linux-arm64@0.18.20': resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} @@ -1791,12 +1802,6 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.23.1': - resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm@0.18.20': resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} @@ -1815,12 +1820,6 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.23.1': - resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-ia32@0.18.20': resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} @@ -1839,12 +1838,6 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.23.1': - resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-loong64@0.18.20': resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} @@ -1863,12 +1856,6 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.23.1': - resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-mips64el@0.18.20': resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} @@ -1887,12 +1874,6 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.23.1': - resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-ppc64@0.18.20': resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} @@ -1911,12 +1892,6 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.23.1': - resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-riscv64@0.18.20': resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} @@ -1935,12 +1910,6 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.23.1': - resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-s390x@0.18.20': resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} @@ -1959,12 +1928,6 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.23.1': - resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-x64@0.18.20': resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} @@ -1983,12 +1946,6 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.23.1': - resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/netbsd-x64@0.18.20': resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} @@ -2007,18 +1964,6 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.23.1': - resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.23.1': - resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-x64@0.18.20': resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} @@ -2037,12 +1982,6 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.23.1': - resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/sunos-x64@0.18.20': resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} @@ -2061,12 +2000,6 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.23.1': - resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/win32-arm64@0.18.20': resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} @@ -2085,12 +2018,6 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.23.1': - resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-ia32@0.18.20': resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} @@ -2109,12 +2036,6 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.23.1': - resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-x64@0.18.20': resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} @@ -2133,12 +2054,6 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.23.1': - resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2169,12 +2084,14 @@ packages: resolution: {integrity: sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@figma/eslint-plugin-figma-plugins@0.15.0': - resolution: {integrity: sha512-ol/v6qje8sxE2npvjCbOQUGlTx++RdYcq98jKaNokL/qN1IF7Y6Y7jgj2wiAYmT2V+aABvtX7MNtKKJ2fbcfWA==} - '@figma/plugin-typings@1.99.0': resolution: {integrity: sha512-eykvxprqZv1kDRaO+DyFSEr2FrravasOL/i8zQagjqDGCRaoxv+XwyTTSM7Vrviz1x832w4TWHJzSkXNwBUdYw==} + '@figma/widget-typings@1.9.1': + resolution: {integrity: sha512-jmh/hsBxLP4aKgtbmxkJe84Ufk93S7TwOxpLD7L58R472boU5vyZ7qF5DKlhwiRjF0sgaryXJxSXuIjdR1GBXQ==} + peerDependencies: + '@figma/plugin-typings': 1.x + '@floating-ui/core@1.6.5': resolution: {integrity: sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==} @@ -2190,11 +2107,6 @@ packages: '@floating-ui/utils@0.2.5': resolution: {integrity: sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==} - '@graphql-typed-document-node/core@3.2.0': - resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} - peerDependencies: - graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@hookform/resolvers@3.9.0': resolution: {integrity: sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==} peerDependencies: @@ -2428,36 +2340,12 @@ packages: '@octokit/openapi-webhooks-types@8.3.0': resolution: {integrity: sha512-vKLsoR4xQxg4Z+6rU/F65ItTUz/EXbD+j/d4mlq2GW8TsA4Tc8Kdma2JTAAJ5hrKWUQzkR/Esn2fjsqiVRYaQg==} - '@octokit/plugin-paginate-graphql@5.2.2': - resolution: {integrity: sha512-7znSVvlNAOJisCqAnjN1FtEziweOHSjPGAuc5W58NeGNAr/ZB57yCsjQbXDlWsVryA7hHQaEQPcBbJYFawlkyg==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': '>=6' - '@octokit/plugin-paginate-rest@11.3.3': resolution: {integrity: sha512-o4WRoOJZlKqEEgj+i9CpcmnByvtzoUYC6I8PD2SA95M+BJ2x8h7oLcVOg9qcowWXBOdcTRsMZiwvM3EyLm9AfA==} engines: {node: '>= 18'} peerDependencies: '@octokit/core': '>=6' - '@octokit/plugin-rest-endpoint-methods@13.2.4': - resolution: {integrity: sha512-gusyAVgTrPiuXOdfqOySMDztQHv6928PQ3E4dqVGEtOvRXAKRbJR4b1zQyniIT9waqaWk/UDaoJ2dyPr7Bk7Iw==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': '>=6' - - '@octokit/plugin-retry@7.1.1': - resolution: {integrity: sha512-G9Ue+x2odcb8E1XIPhaFBnTTIrrUDfXN05iFXiqhR+SeeeDMMILcAnysOsxUpEWcQp2e5Ft397FCXTcPkiPkLw==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': '>=6' - - '@octokit/plugin-throttling@9.3.1': - resolution: {integrity: sha512-Qd91H4liUBhwLB2h6jZ99bsxoQdhgPk6TdwnClPyTBSDAdviGPceViEgUwj+pcQDmB/rfAXAXK7MTochpHM3yQ==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': ^6.0.0 - '@octokit/request-error@6.1.4': resolution: {integrity: sha512-VpAhIUxwhWZQImo/dWAN/NpPqqojR6PSLgLYAituLM6U+ddx9hCioFGwBr5Mi+oi5CLeJkcAs3gJ0PYYzU6wUg==} engines: {node: '>= 18'} @@ -2961,6 +2849,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-separator@1.1.0': + resolution: {integrity: sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.1.0': resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} peerDependencies: @@ -3097,6 +2998,22 @@ packages: rollup: optional: true + '@rollup/plugin-node-resolve@11.2.1': + resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==} + engines: {node: '>= 10.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + + '@rollup/pluginutils@3.1.0': + resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + + '@rollup/pluginutils@4.2.1': + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} + '@rollup/pluginutils@5.1.0': resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} engines: {node: '>=14.0.0'} @@ -3660,6 +3577,9 @@ packages: '@types/escodegen@0.0.6': resolution: {integrity: sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==} + '@types/estree@0.0.39': + resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} + '@types/estree@0.0.51': resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} @@ -3741,18 +3661,15 @@ packages: '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} - '@types/react@17.0.80': - resolution: {integrity: sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA==} - '@types/react@18.3.3': resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} + '@types/resolve@1.17.1': + resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} + '@types/resolve@1.20.6': resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} - '@types/scheduler@0.16.8': - resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} - '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -4002,6 +3919,11 @@ packages: typescript: optional: true + '@vitejs/plugin-react-refresh@1.3.6': + resolution: {integrity: sha512-iNR/UqhUOmFFxiezt0em9CgmiJBdWR+5jGxB2FihaoJfqGt76kiwaKoVOJVU5NYcDWMdN06LbyN2VIGIoYdsEA==} + engines: {node: '>=12.0.0'} + deprecated: This package has been deprecated in favor of @vitejs/plugin-react + '@vitejs/plugin-react@4.3.1': resolution: {integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -4088,26 +4010,6 @@ packages: '@webassemblyjs/wast-printer@1.12.1': resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} - '@wry/caches@1.0.1': - resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==} - engines: {node: '>=8'} - - '@wry/context@0.7.4': - resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==} - engines: {node: '>=8'} - - '@wry/equality@0.5.7': - resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==} - engines: {node: '>=8'} - - '@wry/trie@0.4.3': - resolution: {integrity: sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==} - engines: {node: '>=8'} - - '@wry/trie@0.5.0': - resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==} - engines: {node: '>=8'} - '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -4364,9 +4266,6 @@ packages: resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - bottleneck@2.19.5: - resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} - brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -4498,6 +4397,9 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -4535,9 +4437,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color2k@2.0.3: - resolution: {integrity: sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==} - commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -4570,6 +4469,11 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + concurrently@6.5.1: + resolution: {integrity: sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag==} + engines: {node: '>=10.0.0'} + hasBin: true + concurrently@8.2.2: resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} engines: {node: ^14.13.0 || >=16.0.0} @@ -4624,10 +4528,6 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} - crypto-hash@3.1.0: - resolution: {integrity: sha512-HR8JlZ+Dn54Lc5gGWZJxJitWbOCUzWb9/AlyONGecBnYZ+n/ONvt0gQnEzDNpJMYeRrYO7KogQ4qwyTPKnWKEw==} - engines: {node: '>=18'} - crypto-js@4.2.0: resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} @@ -4986,11 +4886,100 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} + esbuild-android-arm64@0.13.15: + resolution: {integrity: sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==} + cpu: [arm64] + os: [android] + + esbuild-darwin-64@0.13.15: + resolution: {integrity: sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==} + cpu: [x64] + os: [darwin] + + esbuild-darwin-arm64@0.13.15: + resolution: {integrity: sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==} + cpu: [arm64] + os: [darwin] + + esbuild-freebsd-64@0.13.15: + resolution: {integrity: sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==} + cpu: [x64] + os: [freebsd] + + esbuild-freebsd-arm64@0.13.15: + resolution: {integrity: sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==} + cpu: [arm64] + os: [freebsd] + + esbuild-linux-32@0.13.15: + resolution: {integrity: sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==} + cpu: [ia32] + os: [linux] + + esbuild-linux-64@0.13.15: + resolution: {integrity: sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==} + cpu: [x64] + os: [linux] + + esbuild-linux-arm64@0.13.15: + resolution: {integrity: sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==} + cpu: [arm64] + os: [linux] + + esbuild-linux-arm@0.13.15: + resolution: {integrity: sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==} + cpu: [arm] + os: [linux] + + esbuild-linux-mips64le@0.13.15: + resolution: {integrity: sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==} + cpu: [mips64el] + os: [linux] + + esbuild-linux-ppc64le@0.13.15: + resolution: {integrity: sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==} + cpu: [ppc64] + os: [linux] + + esbuild-netbsd-64@0.13.15: + resolution: {integrity: sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==} + cpu: [x64] + os: [netbsd] + + esbuild-openbsd-64@0.13.15: + resolution: {integrity: sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==} + cpu: [x64] + os: [openbsd] + esbuild-register@3.5.0: resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} peerDependencies: esbuild: '>=0.12 <1' + esbuild-sunos-64@0.13.15: + resolution: {integrity: sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==} + cpu: [x64] + os: [sunos] + + esbuild-windows-32@0.13.15: + resolution: {integrity: sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==} + cpu: [ia32] + os: [win32] + + esbuild-windows-64@0.13.15: + resolution: {integrity: sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==} + cpu: [x64] + os: [win32] + + esbuild-windows-arm64@0.13.15: + resolution: {integrity: sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==} + cpu: [arm64] + os: [win32] + + esbuild@0.13.15: + resolution: {integrity: sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==} + hasBin: true + esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} @@ -5006,9 +4995,8 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.23.1: - resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} - engines: {node: '>=18'} + esbuild@0.9.7: + resolution: {integrity: sha512-VtUf6aQ89VTmMLKrWHYG50uByMF4JQlVysb8dmg6cOgW8JnFCipmz7p+HNBl+RR3LLCuBxFGVauAe2wfnF9bLg==} hasBin: true escalade@3.1.2: @@ -5249,6 +5237,9 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-walker@1.0.1: + resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} + estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -5571,16 +5562,6 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - graphql-tag@2.12.6: - resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} - engines: {node: '>=10'} - peerDependencies: - graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - - graphql@16.9.0: - resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -5624,6 +5605,10 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hex-rgb@5.0.0: + resolution: {integrity: sha512-NQO+lgVUCtHxZ792FodgW0zflK+ozS9X9dwGp9XvvmPlH7pyxd588cn24TD3rmPm/N0AIRXF10Otah8yKqGw4w==} + engines: {node: '>=12'} + hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} @@ -5806,6 +5791,9 @@ packages: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + is-nan@1.3.2: resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} engines: {node: '>= 0.4'} @@ -5931,6 +5919,10 @@ packages: jju@1.4.0: resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -5990,6 +5982,9 @@ packages: resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -6301,6 +6296,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -6448,10 +6446,6 @@ packages: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} - octokit@4.0.2: - resolution: {integrity: sha512-wbqF4uc1YbcldtiBFfkSnquHtECEIpYD78YUXI6ri1Im5OO2NLo6ZVpRdbJpdnpZ05zMrVPssNiEo6JQtea+Qg==} - engines: {node: '>= 18'} - ohash@1.1.3: resolution: {integrity: sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==} @@ -6480,9 +6474,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.6.0 - optimism@0.18.0: - resolution: {integrity: sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==} - optimist@0.6.1: resolution: {integrity: sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==} @@ -6705,6 +6696,10 @@ packages: resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.4.45: + resolution: {integrity: sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==} + engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} @@ -6850,11 +6845,6 @@ packages: resolution: {integrity: sha512-i8aF1nyKInZnANZ4uZrH49qn1paRgBZ7wZiCNBMnenlPzEv0mRl+ShpTVEI6wZNl8sSc79xZkivtgLKQArcanQ==} engines: {node: '>=16.14.0'} - react-dom@17.0.2: - resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} - peerDependencies: - react: 17.0.2 - react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -6899,6 +6889,10 @@ packages: react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} + react-refresh@0.10.0: + resolution: {integrity: sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ==} + engines: {node: '>=0.10.0'} + react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} @@ -6939,10 +6933,6 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react@17.0.2: - resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} - engines: {node: '>=0.10.0'} - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -7015,17 +7005,6 @@ packages: resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} hasBin: true - rehackt@0.1.0: - resolution: {integrity: sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==} - peerDependencies: - '@types/react': '*' - react: '*' - peerDependenciesMeta: - '@types/react': - optional: true - react: - optional: true - rehype-external-links@3.0.0: resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==} @@ -7062,10 +7041,6 @@ packages: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true - response-iterator@0.2.6: - resolution: {integrity: sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==} - engines: {node: '>=0.8'} - restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -7074,6 +7049,10 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rgb-hex@4.1.0: + resolution: {integrity: sha512-UZLM57BW09Yi9J1R3OP8B1yCbbDK3NT8BDtihGZkGkGEs2b6EaV85rsfJ6yK4F+8UbxFFmfA+9xHT5ZWhN1gDQ==} + engines: {node: '>=12'} + rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -7089,11 +7068,23 @@ packages: engines: {node: 14 >=14.20 || 16 >=16.20 || >=18} hasBin: true + rollup-plugin-esbuild@3.0.4: + resolution: {integrity: sha512-Txe/qWTx4NykWLwHjQ8vxXB1Mh6nTWnk7nl9lTYBN0DKnbvnSz4u2qiLqceLMZXTk//iYP5jnxlBNciNBp57LQ==} + engines: {node: '>=12'} + peerDependencies: + esbuild: '>=0.9.0' + rollup: ^1.20.0 || ^2.0.0 + rollup-preserve-directives@1.1.1: resolution: {integrity: sha512-+eQafbuEfDPfxQ9hQPlwaROfin4yiVRxap8hnrvvvcSGoukv1tTiYpAW9mvm3uR8J+fe4xd8FdVd5rz9q7jZ+Q==} peerDependencies: rollup: ^2.0.0 || ^3.0.0 || ^4.0.0 + rollup@2.79.1: + resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} + engines: {node: '>=10.0.0'} + hasBin: true + rollup@3.29.4: resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} @@ -7107,6 +7098,10 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} @@ -7129,9 +7124,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - scheduler@0.20.2: - resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} - scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} @@ -7364,8 +7356,8 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - style-dictionary@4.0.1: - resolution: {integrity: sha512-aZ2iouI0i0DIXk3QhCkwOeo5rQeuk5Ja0PhHo32/EXCNuay4jK4CZ+hQJW0Er0J74VWniR+qaeoWgjklcULxOQ==} + style-dictionary@4.1.0: + resolution: {integrity: sha512-DfY64t/XsL0bycnabIcIna/H1GyjK4sKLui2t0q6flr2uM+VpRNoSNCPOpi5YSouhKEFjoiC6ediyrMzraTz8A==} engines: {node: '>=18.0.0'} hasBin: true @@ -7412,10 +7404,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - symbol-observable@4.0.0: - resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} - engines: {node: '>=0.10'} - synckit@0.9.0: resolution: {integrity: sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -7433,6 +7421,11 @@ packages: peerDependencies: tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1' + tailwindcss@3.4.10: + resolution: {integrity: sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==} + engines: {node: '>=14.0.0'} + hasBin: true + tailwindcss@3.4.7: resolution: {integrity: sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==} engines: {node: '>=14.0.0'} @@ -7557,10 +7550,6 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-invariant@0.10.3: - resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==} - engines: {node: '>=8'} - tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -7862,12 +7851,10 @@ packages: vite: optional: true - vite-plugin-singlefile@2.0.2: - resolution: {integrity: sha512-Z2ou6HcvED5CF0hM+vcFSaFa+klyS8RyyLxW0PbMRLnMbvzTI6ueWyxdYNFhpuXZgz/aj6+E/dHFTdEcw6gb9w==} - engines: {node: '>18.0.0'} + vite-plugin-singlefile@0.5.1: + resolution: {integrity: sha512-yA9lWd6bSet0Br4/s34YPNnVBlDl2MbxlHDRrLrBCncD7q+HO5GGsw29Ymp+ydZ3eb4UU2GECgX2MJZW+qnoeQ==} peerDependencies: - rollup: ^4.18.0 - vite: ^5.3.1 + vite: ^2.1.2 vite@5.3.3: resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==} @@ -8034,10 +8021,18 @@ packages: engines: {node: '>= 14'} hasBin: true + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -8051,12 +8046,6 @@ packages: engines: {node: '>=8.0.0'} hasBin: true - zen-observable-ts@1.2.5: - resolution: {integrity: sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==} - - zen-observable@0.8.15: - resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==} - zod-form-data@2.0.2: resolution: {integrity: sha512-sKTi+k0fvkxdakD0V5rq+9WVJA3cuTQUfEmNqvHrTzPLvjfLmkkBLfR0ed3qOi9MScJXTHIDH/jUNnEJ3CBX4g==} peerDependencies: @@ -8076,29 +8065,6 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@apollo/client@3.10.8(@types/react@18.3.3)(graphql@16.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) - '@wry/caches': 1.0.1 - '@wry/equality': 0.5.7 - '@wry/trie': 0.5.0 - graphql: 16.9.0 - graphql-tag: 2.12.6(graphql@16.9.0) - hoist-non-react-statics: 3.3.2 - optimism: 0.18.0 - prop-types: 15.8.1 - rehackt: 0.1.0(@types/react@18.3.3)(react@18.3.1) - response-iterator: 0.2.6 - symbol-observable: 4.0.0 - ts-invariant: 0.10.3 - tslib: 2.6.2 - zen-observable-ts: 1.2.5 - optionalDependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - '@types/react' - '@babel/code-frame@7.24.2': dependencies: '@babel/highlight': 7.24.5 @@ -9075,6 +9041,12 @@ snapshots: stream: 0.0.3 util: 0.12.5 + '@create-figma-plugin/utilities@3.2.0': + dependencies: + hex-rgb: 5.0.0 + natural-compare-lite: 1.4.0 + rgb-hex: 4.1.0 + '@drizzle-team/brocli@0.8.2': {} '@effect/schema@0.71.4(effect@3.7.0)': @@ -9127,9 +9099,6 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.23.1': - optional: true - '@esbuild/android-arm64@0.18.20': optional: true @@ -9139,9 +9108,6 @@ snapshots: '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.23.1': - optional: true - '@esbuild/android-arm@0.18.20': optional: true @@ -9151,9 +9117,6 @@ snapshots: '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.23.1': - optional: true - '@esbuild/android-x64@0.18.20': optional: true @@ -9163,9 +9126,6 @@ snapshots: '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/android-x64@0.23.1': - optional: true - '@esbuild/darwin-arm64@0.18.20': optional: true @@ -9175,9 +9135,6 @@ snapshots: '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.23.1': - optional: true - '@esbuild/darwin-x64@0.18.20': optional: true @@ -9187,9 +9144,6 @@ snapshots: '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/darwin-x64@0.23.1': - optional: true - '@esbuild/freebsd-arm64@0.18.20': optional: true @@ -9199,9 +9153,6 @@ snapshots: '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.23.1': - optional: true - '@esbuild/freebsd-x64@0.18.20': optional: true @@ -9211,9 +9162,6 @@ snapshots: '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.23.1': - optional: true - '@esbuild/linux-arm64@0.18.20': optional: true @@ -9223,9 +9171,6 @@ snapshots: '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-arm64@0.23.1': - optional: true - '@esbuild/linux-arm@0.18.20': optional: true @@ -9235,9 +9180,6 @@ snapshots: '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.23.1': - optional: true - '@esbuild/linux-ia32@0.18.20': optional: true @@ -9247,9 +9189,6 @@ snapshots: '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ia32@0.23.1': - optional: true - '@esbuild/linux-loong64@0.18.20': optional: true @@ -9259,9 +9198,6 @@ snapshots: '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-loong64@0.23.1': - optional: true - '@esbuild/linux-mips64el@0.18.20': optional: true @@ -9271,9 +9207,6 @@ snapshots: '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-mips64el@0.23.1': - optional: true - '@esbuild/linux-ppc64@0.18.20': optional: true @@ -9283,9 +9216,6 @@ snapshots: '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.23.1': - optional: true - '@esbuild/linux-riscv64@0.18.20': optional: true @@ -9295,9 +9225,6 @@ snapshots: '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.23.1': - optional: true - '@esbuild/linux-s390x@0.18.20': optional: true @@ -9307,9 +9234,6 @@ snapshots: '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-s390x@0.23.1': - optional: true - '@esbuild/linux-x64@0.18.20': optional: true @@ -9319,9 +9243,6 @@ snapshots: '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-x64@0.23.1': - optional: true - '@esbuild/netbsd-x64@0.18.20': optional: true @@ -9331,12 +9252,6 @@ snapshots: '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/netbsd-x64@0.23.1': - optional: true - - '@esbuild/openbsd-arm64@0.23.1': - optional: true - '@esbuild/openbsd-x64@0.18.20': optional: true @@ -9346,9 +9261,6 @@ snapshots: '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.23.1': - optional: true - '@esbuild/sunos-x64@0.18.20': optional: true @@ -9358,9 +9270,6 @@ snapshots: '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.23.1': - optional: true - '@esbuild/win32-arm64@0.18.20': optional: true @@ -9370,9 +9279,6 @@ snapshots: '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.23.1': - optional: true - '@esbuild/win32-ia32@0.18.20': optional: true @@ -9382,9 +9288,6 @@ snapshots: '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.23.1': - optional: true - '@esbuild/win32-x64@0.18.20': optional: true @@ -9394,9 +9297,6 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.23.1': - optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': dependencies: eslint: 8.57.0 @@ -9426,17 +9326,12 @@ snapshots: '@eslint/js@9.9.0': {} - '@figma/eslint-plugin-figma-plugins@0.15.0(eslint@8.57.0)': - dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.5.4) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.5.4) - typescript: 5.5.4 - transitivePeerDependencies: - - eslint - - supports-color - '@figma/plugin-typings@1.99.0': {} + '@figma/widget-typings@1.9.1(@figma/plugin-typings@1.99.0)': + dependencies: + '@figma/plugin-typings': 1.99.0 + '@floating-ui/core@1.6.5': dependencies: '@floating-ui/utils': 0.2.5 @@ -9454,10 +9349,6 @@ snapshots: '@floating-ui/utils@0.2.5': {} - '@graphql-typed-document-node/core@3.2.0(graphql@16.9.0)': - dependencies: - graphql: 16.9.0 - '@hookform/resolvers@3.9.0(react-hook-form@7.52.2(react@18.3.1))': dependencies: react-hook-form: 7.52.2(react@18.3.1) @@ -9539,11 +9430,11 @@ snapshots: dependencies: tslib: 2.6.2 - '@mdx-js/react@3.0.1(@types/react@17.0.80)(react@17.0.2)': + '@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 17.0.80 - react: 17.0.2 + '@types/react': 18.3.3 + react: 18.3.1 '@microsoft/api-extractor-model@7.28.13(@types/node@22.4.1)': dependencies: @@ -9727,33 +9618,11 @@ snapshots: '@octokit/openapi-webhooks-types@8.3.0': {} - '@octokit/plugin-paginate-graphql@5.2.2(@octokit/core@6.1.2)': - dependencies: - '@octokit/core': 6.1.2 - '@octokit/plugin-paginate-rest@11.3.3(@octokit/core@6.1.2)': dependencies: '@octokit/core': 6.1.2 '@octokit/types': 13.5.0 - '@octokit/plugin-rest-endpoint-methods@13.2.4(@octokit/core@6.1.2)': - dependencies: - '@octokit/core': 6.1.2 - '@octokit/types': 13.5.0 - - '@octokit/plugin-retry@7.1.1(@octokit/core@6.1.2)': - dependencies: - '@octokit/core': 6.1.2 - '@octokit/request-error': 6.1.4 - '@octokit/types': 13.5.0 - bottleneck: 2.19.5 - - '@octokit/plugin-throttling@9.3.1(@octokit/core@6.1.2)': - dependencies: - '@octokit/core': 6.1.2 - '@octokit/types': 13.5.0 - bottleneck: 2.19.5 - '@octokit/request-error@6.1.4': dependencies: '@octokit/types': 13.5.0 @@ -10336,7 +10205,16 @@ snapshots: aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.5.7(@types/react@18.3.3)(react@18.3.1) + react-remove-scroll: 2.5.7(@types/react@18.3.3)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + + '@radix-ui/react-separator@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 @@ -10467,6 +10345,28 @@ snapshots: optionalDependencies: rollup: 3.29.4 + '@rollup/plugin-node-resolve@11.2.1(rollup@2.79.1)': + dependencies: + '@rollup/pluginutils': 3.1.0(rollup@2.79.1) + '@types/resolve': 1.17.1 + builtin-modules: 3.3.0 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.8 + rollup: 2.79.1 + + '@rollup/pluginutils@3.1.0(rollup@2.79.1)': + dependencies: + '@types/estree': 0.0.39 + estree-walker: 1.0.1 + picomatch: 2.3.1 + rollup: 2.79.1 + + '@rollup/pluginutils@4.2.1': + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 + '@rollup/pluginutils@5.1.0(rollup@3.29.4)': dependencies: '@types/estree': 1.0.5 @@ -10665,7 +10565,7 @@ snapshots: '@sentry/types': 8.27.0 '@sentry/utils': 8.27.0 - '@sentry/nextjs@8.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0))(next@14.2.6(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)(webpack@5.94.0)': + '@sentry/nextjs@8.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0))(next@14.2.6(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react@18.3.1)(webpack@5.94.0(esbuild@0.19.12))': dependencies: '@opentelemetry/instrumentation-http': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.27.0 @@ -10677,14 +10577,14 @@ snapshots: '@sentry/types': 8.27.0 '@sentry/utils': 8.27.0 '@sentry/vercel-edge': 8.27.0 - '@sentry/webpack-plugin': 2.20.1(webpack@5.94.0) + '@sentry/webpack-plugin': 2.20.1(webpack@5.94.0(esbuild@0.19.12)) chalk: 3.0.0 next: 14.2.6(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) resolve: 1.22.8 rollup: 3.29.4 stacktrace-parser: 0.1.10 optionalDependencies: - webpack: 5.94.0 + webpack: 5.94.0(esbuild@0.19.12) transitivePeerDependencies: - '@opentelemetry/api' - '@opentelemetry/core' @@ -10762,12 +10662,12 @@ snapshots: '@sentry/types': 8.27.0 '@sentry/utils': 8.27.0 - '@sentry/webpack-plugin@2.20.1(webpack@5.94.0)': + '@sentry/webpack-plugin@2.20.1(webpack@5.94.0(esbuild@0.19.12))': dependencies: '@sentry/bundler-plugin-core': 2.20.1 unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.94.0 + webpack: 5.94.0(esbuild@0.19.12) transitivePeerDependencies: - encoding - supports-color @@ -10802,15 +10702,15 @@ snapshots: '@storybook/addon-docs@8.2.3(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)))': dependencies: '@babel/core': 7.24.5 - '@mdx-js/react': 3.0.1(@types/react@17.0.80)(react@17.0.2) - '@storybook/blocks': 8.2.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5))) + '@mdx-js/react': 3.0.1(@types/react@18.3.3)(react@18.3.1) + '@storybook/blocks': 8.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5))) '@storybook/csf-plugin': 8.2.3(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5))) '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 8.2.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5))) - '@types/react': 17.0.80 + '@storybook/react-dom-shim': 8.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5))) + '@types/react': 18.3.3 fs-extra: 11.2.0 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) rehype-external-links: 3.0.0 rehype-slug: 6.0.0 storybook: 8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)) @@ -10891,27 +10791,6 @@ snapshots: memoizerific: 1.11.3 storybook: 8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)) - '@storybook/blocks@8.2.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)))': - dependencies: - '@storybook/csf': 0.1.11 - '@storybook/global': 5.0.0 - '@storybook/icons': 1.2.9(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@types/lodash': 4.17.6 - color-convert: 2.0.1 - dequal: 2.0.3 - lodash: 4.17.21 - markdown-to-jsx: 7.4.7(react@17.0.2) - memoizerific: 1.11.3 - polished: 4.3.1 - react-colorful: 5.6.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - storybook: 8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)) - telejson: 7.2.0 - ts-dedent: 2.2.0 - util-deprecate: 1.0.2 - optionalDependencies: - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@storybook/blocks@8.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)))': dependencies: '@storybook/csf': 0.1.11 @@ -11004,11 +10883,6 @@ snapshots: '@storybook/global@5.0.0': {} - '@storybook/icons@1.2.9(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@storybook/icons@1.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 @@ -11021,12 +10895,6 @@ snapshots: storybook: 8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)) util: 0.12.5 - '@storybook/react-dom-shim@8.2.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)))': - dependencies: - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - storybook: 8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)) - '@storybook/react-dom-shim@8.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.3(@babel/preset-env@7.24.8(@babel/core@7.24.5)))': dependencies: react: 18.3.1 @@ -11264,6 +11132,8 @@ snapshots: '@types/escodegen@0.0.6': {} + '@types/estree@0.0.39': {} + '@types/estree@0.0.51': {} '@types/estree@1.0.5': {} @@ -11347,21 +11217,17 @@ snapshots: dependencies: '@types/react': 18.3.3 - '@types/react@17.0.80': + '@types/react@18.3.3': dependencies: '@types/prop-types': 15.7.12 - '@types/scheduler': 0.16.8 csstype: 3.1.3 - '@types/react@18.3.3': + '@types/resolve@1.17.1': dependencies: - '@types/prop-types': 15.7.12 - csstype: 3.1.3 + '@types/node': 22.4.1 '@types/resolve@1.20.6': {} - '@types/scheduler@0.16.8': {} - '@types/semver@7.5.8': {} '@types/send@0.17.4': @@ -11425,7 +11291,7 @@ snapshots: '@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@8.1.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)': dependencies: - '@eslint-community/regexpp': 4.11.0 + '@eslint-community/regexpp': 4.10.0 '@typescript-eslint/parser': 8.1.0(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/scope-manager': 7.16.0 '@typescript-eslint/type-utils': 7.16.0(eslint@8.57.0)(typescript@5.5.4) @@ -11735,6 +11601,16 @@ snapshots: - jest - supports-color + '@vitejs/plugin-react-refresh@1.3.6': + dependencies: + '@babel/core': 7.24.5 + '@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5) + '@rollup/pluginutils': 4.2.1 + react-refresh: 0.10.0 + transitivePeerDependencies: + - supports-color + '@vitejs/plugin-react@4.3.1(vite@5.3.3(@types/node@22.4.1)(sass@1.77.8)(terser@5.31.6))': dependencies: '@babel/core': 7.24.5 @@ -11881,26 +11757,6 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 - '@wry/caches@1.0.1': - dependencies: - tslib: 2.6.2 - - '@wry/context@0.7.4': - dependencies: - tslib: 2.6.2 - - '@wry/equality@0.5.7': - dependencies: - tslib: 2.6.2 - - '@wry/trie@0.4.3': - dependencies: - tslib: 2.6.2 - - '@wry/trie@0.5.0': - dependencies: - tslib: 2.6.2 - '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -12123,6 +11979,16 @@ snapshots: postcss: 8.4.41 postcss-value-parser: 4.2.0 + autoprefixer@10.4.19(postcss@8.4.45): + dependencies: + browserslist: 4.23.2 + caniuse-lite: 1.0.30001642 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.0.1 + postcss: 8.4.45 + postcss-value-parser: 4.2.0 + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 @@ -12224,8 +12090,6 @@ snapshots: transitivePeerDependencies: - supports-color - bottleneck@2.19.5: {} - brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -12364,6 +12228,12 @@ snapshots: client-only@0.0.1: {} + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -12396,8 +12266,6 @@ snapshots: color-name@1.1.4: {} - color2k@2.0.3: {} - commander@2.20.3: {} commander@4.1.1: {} @@ -12417,6 +12285,17 @@ snapshots: concat-map@0.0.1: {} + concurrently@6.5.1: + dependencies: + chalk: 4.1.2 + date-fns: 2.30.0 + lodash: 4.17.21 + rxjs: 6.6.7 + spawn-command: 0.0.2 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 16.2.0 + concurrently@8.2.2: dependencies: chalk: 4.1.2 @@ -12482,8 +12361,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crypto-hash@3.1.0: {} - crypto-js@4.2.0: {} crypto-random-string@4.0.0: @@ -12769,6 +12646,45 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 + esbuild-android-arm64@0.13.15: + optional: true + + esbuild-darwin-64@0.13.15: + optional: true + + esbuild-darwin-arm64@0.13.15: + optional: true + + esbuild-freebsd-64@0.13.15: + optional: true + + esbuild-freebsd-arm64@0.13.15: + optional: true + + esbuild-linux-32@0.13.15: + optional: true + + esbuild-linux-64@0.13.15: + optional: true + + esbuild-linux-arm64@0.13.15: + optional: true + + esbuild-linux-arm@0.13.15: + optional: true + + esbuild-linux-mips64le@0.13.15: + optional: true + + esbuild-linux-ppc64le@0.13.15: + optional: true + + esbuild-netbsd-64@0.13.15: + optional: true + + esbuild-openbsd-64@0.13.15: + optional: true + esbuild-register@3.5.0(esbuild@0.19.12): dependencies: debug: 4.3.4 @@ -12783,6 +12699,38 @@ snapshots: transitivePeerDependencies: - supports-color + esbuild-sunos-64@0.13.15: + optional: true + + esbuild-windows-32@0.13.15: + optional: true + + esbuild-windows-64@0.13.15: + optional: true + + esbuild-windows-arm64@0.13.15: + optional: true + + esbuild@0.13.15: + optionalDependencies: + esbuild-android-arm64: 0.13.15 + esbuild-darwin-64: 0.13.15 + esbuild-darwin-arm64: 0.13.15 + esbuild-freebsd-64: 0.13.15 + esbuild-freebsd-arm64: 0.13.15 + esbuild-linux-32: 0.13.15 + esbuild-linux-64: 0.13.15 + esbuild-linux-arm: 0.13.15 + esbuild-linux-arm64: 0.13.15 + esbuild-linux-mips64le: 0.13.15 + esbuild-linux-ppc64le: 0.13.15 + esbuild-netbsd-64: 0.13.15 + esbuild-openbsd-64: 0.13.15 + esbuild-sunos-64: 0.13.15 + esbuild-windows-32: 0.13.15 + esbuild-windows-64: 0.13.15 + esbuild-windows-arm64: 0.13.15 + esbuild@0.18.20: optionalDependencies: '@esbuild/android-arm': 0.18.20 @@ -12860,32 +12808,7 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.23.1: - optionalDependencies: - '@esbuild/aix-ppc64': 0.23.1 - '@esbuild/android-arm': 0.23.1 - '@esbuild/android-arm64': 0.23.1 - '@esbuild/android-x64': 0.23.1 - '@esbuild/darwin-arm64': 0.23.1 - '@esbuild/darwin-x64': 0.23.1 - '@esbuild/freebsd-arm64': 0.23.1 - '@esbuild/freebsd-x64': 0.23.1 - '@esbuild/linux-arm': 0.23.1 - '@esbuild/linux-arm64': 0.23.1 - '@esbuild/linux-ia32': 0.23.1 - '@esbuild/linux-loong64': 0.23.1 - '@esbuild/linux-mips64el': 0.23.1 - '@esbuild/linux-ppc64': 0.23.1 - '@esbuild/linux-riscv64': 0.23.1 - '@esbuild/linux-s390x': 0.23.1 - '@esbuild/linux-x64': 0.23.1 - '@esbuild/netbsd-x64': 0.23.1 - '@esbuild/openbsd-arm64': 0.23.1 - '@esbuild/openbsd-x64': 0.23.1 - '@esbuild/sunos-x64': 0.23.1 - '@esbuild/win32-arm64': 0.23.1 - '@esbuild/win32-ia32': 0.23.1 - '@esbuild/win32-x64': 0.23.1 + esbuild@0.9.7: {} escalade@3.1.2: {} @@ -13029,7 +12952,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -13211,11 +13134,11 @@ snapshots: - supports-color - typescript - eslint-plugin-tailwindcss@3.17.4(tailwindcss@3.4.7): + eslint-plugin-tailwindcss@3.17.4(tailwindcss@3.4.10): dependencies: fast-glob: 3.3.2 postcss: 8.4.41 - tailwindcss: 3.4.7 + tailwindcss: 3.4.10 eslint-plugin-testing-library@6.2.2(eslint@8.57.0)(typescript@5.5.4): dependencies: @@ -13340,6 +13263,8 @@ snapshots: estraverse@5.3.0: {} + estree-walker@1.0.1: {} + estree-walker@2.0.2: {} estree-walker@3.0.3: @@ -13759,13 +13684,6 @@ snapshots: graphemer@1.4.0: {} - graphql-tag@2.12.6(graphql@16.9.0): - dependencies: - graphql: 16.9.0 - tslib: 2.6.2 - - graphql@16.9.0: {} - has-bigints@1.0.2: {} has-flag@3.0.0: {} @@ -13802,6 +13720,8 @@ snapshots: he@1.2.0: {} + hex-rgb@5.0.0: {} + hoist-non-react-statics@3.3.2: dependencies: react-is: 16.13.1 @@ -13848,7 +13768,8 @@ snapshots: ignore@5.3.1: {} - immutable@4.3.6: {} + immutable@4.3.6: + optional: true import-fresh@3.3.0: dependencies: @@ -13973,6 +13894,8 @@ snapshots: is-map@2.0.3: {} + is-module@1.0.0: {} + is-nan@1.3.2: dependencies: call-bind: 1.0.7 @@ -14084,6 +14007,8 @@ snapshots: jju@1.4.0: {} + joycon@3.1.1: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -14151,6 +14076,8 @@ snapshots: espree: 9.6.1 semver: 7.6.2 + jsonc-parser@3.3.1: {} + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -14292,10 +14219,6 @@ snapshots: map-or-similar@1.5.0: {} - markdown-to-jsx@7.4.7(react@17.0.2): - dependencies: - react: 17.0.2 - markdown-to-jsx@7.4.7(react@18.3.1): dependencies: react: 18.3.1 @@ -14426,6 +14349,8 @@ snapshots: nanoid@3.3.7: {} + natural-compare-lite@1.4.0: {} + natural-compare@1.4.0: {} negotiator@0.6.3: {} @@ -14568,19 +14493,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 - octokit@4.0.2: - dependencies: - '@octokit/app': 15.1.0 - '@octokit/core': 6.1.2 - '@octokit/oauth-app': 7.1.3 - '@octokit/plugin-paginate-graphql': 5.2.2(@octokit/core@6.1.2) - '@octokit/plugin-paginate-rest': 11.3.3(@octokit/core@6.1.2) - '@octokit/plugin-rest-endpoint-methods': 13.2.4(@octokit/core@6.1.2) - '@octokit/plugin-retry': 7.1.1(@octokit/core@6.1.2) - '@octokit/plugin-throttling': 9.3.1(@octokit/core@6.1.2) - '@octokit/request-error': 6.1.4 - '@octokit/types': 13.5.0 - ohash@1.1.3: {} on-finished@2.4.1: @@ -14613,13 +14525,6 @@ snapshots: - supports-color optional: true - optimism@0.18.0: - dependencies: - '@wry/caches': 1.0.1 - '@wry/context': 0.7.4 - '@wry/trie': 0.4.3 - tslib: 2.6.2 - optimist@0.6.1: dependencies: minimist: 0.0.10 @@ -14801,11 +14706,23 @@ snapshots: read-cache: 1.0.0 resolve: 1.22.8 + postcss-import@15.1.0(postcss@8.4.45): + dependencies: + postcss: 8.4.45 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + postcss-js@4.0.1(postcss@8.4.41): dependencies: camelcase-css: 2.0.1 postcss: 8.4.41 + postcss-js@4.0.1(postcss@8.4.45): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.45 + postcss-load-config@4.0.2(postcss@8.4.41): dependencies: lilconfig: 3.1.1 @@ -14813,11 +14730,23 @@ snapshots: optionalDependencies: postcss: 8.4.41 + postcss-load-config@4.0.2(postcss@8.4.45): + dependencies: + lilconfig: 3.1.1 + yaml: 2.4.2 + optionalDependencies: + postcss: 8.4.45 + postcss-nested@6.0.1(postcss@8.4.41): dependencies: postcss: 8.4.41 postcss-selector-parser: 6.1.1 + postcss-nested@6.0.1(postcss@8.4.45): + dependencies: + postcss: 8.4.45 + postcss-selector-parser: 6.1.1 + postcss-selector-parser@6.1.1: dependencies: cssesc: 3.0.0 @@ -14837,6 +14766,12 @@ snapshots: picocolors: 1.0.1 source-map-js: 1.2.0 + postcss@8.4.45: + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + postgres-array@2.0.0: {} postgres-bytea@1.0.0: {} @@ -14946,11 +14881,6 @@ snapshots: lodash.flow: 3.5.0 pure-color: 1.3.0 - react-colorful@5.6.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2): - dependencies: - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - react-colorful@5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: react: 18.3.1 @@ -14993,13 +14923,6 @@ snapshots: transitivePeerDependencies: - supports-color - react-dom@17.0.2(react@17.0.2): - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react: 17.0.2 - scheduler: 0.20.2 - react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 @@ -15044,6 +14967,8 @@ snapshots: react-lifecycles-compat@3.0.4: {} + react-refresh@0.10.0: {} + react-refresh@0.14.2: {} react-remove-scroll-bar@2.3.6(@types/react@18.3.3)(react@18.3.1): @@ -15083,11 +15008,6 @@ snapshots: transitivePeerDependencies: - '@types/react' - react@17.0.2: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -15182,11 +15102,6 @@ snapshots: dependencies: jsesc: 0.5.0 - rehackt@0.1.0(@types/react@18.3.3)(react@18.3.1): - optionalDependencies: - '@types/react': 18.3.3 - react: 18.3.1 - rehype-external-links@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -15237,8 +15152,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - response-iterator@0.2.6: {} - restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -15246,6 +15159,8 @@ snapshots: reusify@1.0.4: {} + rgb-hex@4.1.0: {} + rimraf@2.6.3: dependencies: glob: 7.2.3 @@ -15258,11 +15173,28 @@ snapshots: dependencies: glob: 10.4.5 + rollup-plugin-esbuild@3.0.4(esbuild@0.9.7)(rollup@2.79.1): + dependencies: + '@rollup/pluginutils': 4.2.1 + esbuild: 0.9.7 + joycon: 3.1.1 + jsonc-parser: 3.3.1 + rollup: 2.79.1 + + rollup-preserve-directives@1.1.1(rollup@2.79.1): + dependencies: + magic-string: 0.30.10 + rollup: 2.79.1 + rollup-preserve-directives@1.1.1(rollup@4.21.0): dependencies: magic-string: 0.30.10 rollup: 4.21.0 + rollup@2.79.1: + optionalDependencies: + fsevents: 2.3.3 + rollup@3.29.4: optionalDependencies: fsevents: 2.3.3 @@ -15293,6 +15225,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@6.6.7: + dependencies: + tslib: 1.14.1 + rxjs@7.8.1: dependencies: tslib: 2.6.2 @@ -15319,11 +15255,7 @@ snapshots: chokidar: 3.6.0 immutable: 4.3.6 source-map-js: 1.2.0 - - scheduler@0.20.2: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 + optional: true scheduler@0.23.2: dependencies: @@ -15615,7 +15547,7 @@ snapshots: strip-json-comments@3.1.1: {} - style-dictionary@4.0.1: + style-dictionary@4.1.0: dependencies: '@bundled-es-modules/deepmerge': 4.3.1 '@bundled-es-modules/glob': 10.4.2 @@ -15672,8 +15604,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - symbol-observable@4.0.0: {} - synckit@0.9.0: dependencies: '@pkgr/core': 0.1.1 @@ -15689,6 +15619,33 @@ snapshots: dependencies: tailwindcss: 3.4.7 + tailwindcss@3.4.10: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.6 + lilconfig: 2.1.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.1 + postcss: 8.4.45 + postcss-import: 15.1.0(postcss@8.4.45) + postcss-js: 4.0.1(postcss@8.4.45) + postcss-load-config: 4.0.2(postcss@8.4.45) + postcss-nested: 6.0.1(postcss@8.4.45) + postcss-selector-parser: 6.1.1 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + tailwindcss@3.4.7: dependencies: '@alloc/quick-lru': 5.2.0 @@ -15753,14 +15710,16 @@ snapshots: type-fest: 2.19.0 unique-string: 3.0.0 - terser-webpack-plugin@5.3.10(webpack@5.94.0): + terser-webpack-plugin@5.3.10(esbuild@0.19.12)(webpack@5.94.0(esbuild@0.19.12)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.94.0 + webpack: 5.94.0(esbuild@0.19.12) + optionalDependencies: + esbuild: 0.19.12 terser@5.31.6: dependencies: @@ -15824,10 +15783,6 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-invariant@0.10.3: - dependencies: - tslib: 2.6.2 - tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -16115,16 +16070,18 @@ snapshots: - rollup - supports-color - vite-plugin-singlefile@2.0.2(rollup@4.21.0)(vite@5.3.3(@types/node@22.4.1)(sass@1.77.8)(terser@5.31.6)): + vite-plugin-singlefile@0.5.1(vite@5.3.3(@types/node@22.4.1)(sass@1.77.8)(terser@5.31.6)): dependencies: - micromatch: 4.0.8 - rollup: 4.21.0 + '@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1) + esbuild: 0.9.7 + rollup: 2.79.1 + rollup-plugin-esbuild: 3.0.4(esbuild@0.9.7)(rollup@2.79.1) vite: 5.3.3(@types/node@22.4.1)(sass@1.77.8)(terser@5.31.6) vite@5.3.3(@types/node@22.4.1)(sass@1.77.8)(terser@5.31.6): dependencies: esbuild: 0.21.5 - postcss: 8.4.41 + postcss: 8.4.45 rollup: 4.21.0 optionalDependencies: '@types/node': 22.4.1 @@ -16167,7 +16124,7 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.94.0: + webpack@5.94.0(esbuild@0.19.12): dependencies: '@types/estree': 1.0.5 '@webassemblyjs/ast': 1.12.1 @@ -16189,7 +16146,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.94.0) + terser-webpack-plugin: 5.3.10(esbuild@0.19.12)(webpack@5.94.0(esbuild@0.19.12)) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -16289,8 +16246,20 @@ snapshots: yaml@2.4.2: {} + yargs-parser@20.2.9: {} + yargs-parser@21.1.1: {} + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -16311,12 +16280,6 @@ snapshots: optionalDependencies: commander: 9.5.0 - zen-observable-ts@1.2.5: - dependencies: - zen-observable: 0.8.15 - - zen-observable@0.8.15: {} - zod-form-data@2.0.2(zod@3.23.8): dependencies: zod: 3.23.8 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5b8e62c..63d39b4 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,7 +4,8 @@ packages: - tools/* catalog: - "@figma/plugin-typings": ^1.98.0 + "@figma/plugin-typings": ^1.99.0 + "@figma/widget-typings": ^1.9.1 "@trpc/client": 11.0.0-rc.482 "@trpc/react-query": 11.0.0-rc.482 "@trpc/server": 11.0.0-rc.482