diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..e1d14e38b --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +//registry.npmjs.org/:_authToken=${NPM_TOKEN} +auto-install-peers=true + diff --git a/.yarnrc.yml b/.yarnrc.yml index 5413a22d8..f2e97e603 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -2,6 +2,11 @@ nmHoistingLimits: workspaces nodeLinker: node-modules +npmScopes: + magiclabs: + npmRegistryServer: "https://registry.npmjs.org" + npmAuthToken: "${NPM_TOKEN}" + plugins: - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs spec: "@yarnpkg/plugin-workspace-tools" diff --git a/packages/@magic-ext/magic-widget/.lintstagedrc.yml b/packages/@magic-ext/magic-widget/.lintstagedrc.yml new file mode 100644 index 000000000..1c250ad65 --- /dev/null +++ b/packages/@magic-ext/magic-widget/.lintstagedrc.yml @@ -0,0 +1,2 @@ +'*.{ts,tsx}': + - eslint --fix diff --git a/packages/@magic-ext/magic-widget/.prettierrc.js b/packages/@magic-ext/magic-widget/.prettierrc.js new file mode 100644 index 000000000..6177cac66 --- /dev/null +++ b/packages/@magic-ext/magic-widget/.prettierrc.js @@ -0,0 +1 @@ +module.exports = require('../../../.prettierrc.js'); diff --git a/packages/@magic-ext/magic-widget/LICENSE b/packages/@magic-ext/magic-widget/LICENSE new file mode 100644 index 000000000..7335bc897 --- /dev/null +++ b/packages/@magic-ext/magic-widget/LICENSE @@ -0,0 +1,177 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/packages/@magic-ext/magic-widget/babel.config.json b/packages/@magic-ext/magic-widget/babel.config.json new file mode 100644 index 000000000..7521eb073 --- /dev/null +++ b/packages/@magic-ext/magic-widget/babel.config.json @@ -0,0 +1,7 @@ +{ + "env": { + "test": { + "plugins": ["@babel/plugin-transform-modules-commonjs"] + } + } +} diff --git a/packages/@magic-ext/magic-widget/eslint.config.mjs b/packages/@magic-ext/magic-widget/eslint.config.mjs new file mode 100644 index 000000000..adae3ceb4 --- /dev/null +++ b/packages/@magic-ext/magic-widget/eslint.config.mjs @@ -0,0 +1,30 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import rootEslintConfig from '../../../eslint.config.mjs'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export default [ + ...rootEslintConfig, + { + ignores: [ + 'node_modules', + 'coverage', + 'dist', + 'eslint.config.mjs', + 'jest.config.ts', + 'panda.config.ts', + 'postcss.config.cjs', + 'styled-system', + ], + }, + { + languageOptions: { + parserOptions: { + project: ['./tsconfig.json'], + tsconfigRootDir: __dirname, + }, + }, + }, +]; diff --git a/packages/@magic-ext/magic-widget/jest.config.ts b/packages/@magic-ext/magic-widget/jest.config.ts new file mode 100644 index 000000000..433182c4b --- /dev/null +++ b/packages/@magic-ext/magic-widget/jest.config.ts @@ -0,0 +1,13 @@ +import baseJestConfig from '../../../jest.config'; +import type { Config } from '@jest/types'; + +const config: Config.InitialOptions = { + ...baseJestConfig, + transform: { + '^.+\\.(js|jsx)$': 'babel-jest', + '\\.(ts|tsx)$': 'ts-jest', + }, + coveragePathIgnorePatterns: ['index.cdn.ts', 'index.native.ts'], +}; + +export default config; diff --git a/packages/@magic-ext/magic-widget/package.json b/packages/@magic-ext/magic-widget/package.json new file mode 100644 index 000000000..a115f894c --- /dev/null +++ b/packages/@magic-ext/magic-widget/package.json @@ -0,0 +1,74 @@ +{ + "name": "@magic-ext/magic-widget", + "useCustomBuild": true, + "version": "0.0.1", + "description": "Magic SDK Widget Extension with React components.", + "author": "Magic (https://magic.link/)", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/magiclabs/magic-js" + }, + "scripts": { + "prepare": "panda codegen", + "build:css": "panda cssgen --outfile dist/styles.css", + "build": "rollup -c rollup.config.mjs" + }, + "files": [ + "dist" + ], + "target": "browser", + "main": "./dist/cjs/index.js", + "module": "./dist/es/index.mjs", + "types": "./dist/types/index.d.ts", + "exports": { + ".": { + "import": "./dist/es/index.mjs", + "types": "./dist/types/index.d.ts", + "require": "./dist/cjs/index.js" + } + }, + "externals": { + "include": [ + "@magic-sdk/provider", + "react", + "react-dom" + ], + "exclude": [ + "@magiclabs/ui-components" + ] + }, + "esbuildAliases": { + "@styled/css": "./styled-system/css", + "@styled/jsx": "./styled-system/jsx", + "@styled/tokens": "./styled-system/tokens", + "@styled/patterns": "./styled-system/patterns" + }, + "dependencies": { + "@magiclabs/ui-components": "^1.49.0", + "@reown/appkit": "1.8.14", + "@reown/appkit-adapter-wagmi": "1.8.14", + "@tanstack/react-query": "^5.0.0", + "@wagmi/core": "^2.21.2", + "viem": "^2.37.9", + "wagmi": "^2.17.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "@magic-sdk/provider": "^31.0.0", + "@pandacss/dev": "^0.35.0", + "@rollup/plugin-commonjs": "^26.0.1", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-typescript": "^11.1.6", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "rollup": "^4.18.0", + "tslib": "^2.6.3" + } +} diff --git a/packages/@magic-ext/magic-widget/panda.config.ts b/packages/@magic-ext/magic-widget/panda.config.ts new file mode 100644 index 000000000..3c36167dd --- /dev/null +++ b/packages/@magic-ext/magic-widget/panda.config.ts @@ -0,0 +1,50 @@ +import { magicPreset } from '@magiclabs/ui-components/presets'; +import { defineConfig } from '@pandacss/dev'; + +export default defineConfig({ + // Whether to use css reset + preflight: true, + // Minify the generated css + minify: true, + // Hash all classnames + hash: true, + // Clean the output directory before generating the css + clean: true, + // Note: @layer directives are stripped in rollup.config.mjs for Tailwind compatibility + + importMap: '@styled', + + // Where to look for your css declarations + include: ['./node_modules/@magiclabs/ui-components/dist/panda.buildinfo.json', './src/**/*.{js,jsx,ts,tsx}'], + + // Files to exclude + exclude: [], + + // Styling conditions / modes + conditions: { + light: '[data-color-mode=light] &', + dark: '[data-color-mode=dark] &', + }, + + presets: ['@pandacss/dev/presets', magicPreset], + + // Useful for theme customization + theme: { + extend: {}, + }, + + // The output directory for your css system + outdir: 'styled-system', + + // Output extension impacting build + outExtension: 'js', + + // The JSX framework to use + jsxFramework: 'react', + + globalCss: { + html: { + '--primary': 'black', + }, + }, +}); diff --git a/packages/@magic-ext/magic-widget/pnpm-lock.yaml b/packages/@magic-ext/magic-widget/pnpm-lock.yaml new file mode 100644 index 000000000..9abbee0dc --- /dev/null +++ b/packages/@magic-ext/magic-widget/pnpm-lock.yaml @@ -0,0 +1,123 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@magic-sdk/provider': + specifier: ^31.0.0 + version: 31.2.0(localforage@1.10.0) + '@types/react': + specifier: ^18.0.0 + version: 18.3.27 + react: + specifier: ^18.0.0 + version: 18.3.1 + react-dom: + specifier: ^18.0.0 + version: 18.3.1(react@18.3.1) + +packages: + + '@magic-sdk/provider@31.2.0': + resolution: {integrity: sha512-BiLnTn97HFnUWDT04m38t2z0IyoaVx1b9wb96T7YeYylDrIyOab/ma7L2P2gnLwAOmQq8N8Ky+gid1cVExbKWA==} + peerDependencies: + localforage: ^1.7.4 + + '@magic-sdk/types@25.2.0': + resolution: {integrity: sha512-/S78nj/jBND68Cp6L1JIDugpzIdAGRMsL+XsUHyVmyMhVcZvkZycEOOrmDH0SP0mjd29UvNLnPsJY1RT6A4NeA==} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react@18.3.27': + resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + lie@3.1.1: + resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==} + + localforage@1.10.0: + resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + +snapshots: + + '@magic-sdk/provider@31.2.0(localforage@1.10.0)': + dependencies: + '@magic-sdk/types': 25.2.0 + eventemitter3: 4.0.7 + localforage: 1.10.0 + + '@magic-sdk/types@25.2.0': {} + + '@types/prop-types@15.7.15': {} + + '@types/react@18.3.27': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.2.3 + + csstype@3.2.3: {} + + eventemitter3@4.0.7: {} + + immediate@3.0.6: {} + + js-tokens@4.0.0: {} + + lie@3.1.1: + dependencies: + immediate: 3.0.6 + + localforage@1.10.0: + dependencies: + lie: 3.1.1 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + react-dom@18.3.1(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 diff --git a/packages/@magic-ext/magic-widget/postcss.config.cjs b/packages/@magic-ext/magic-widget/postcss.config.cjs new file mode 100644 index 000000000..678b267b6 --- /dev/null +++ b/packages/@magic-ext/magic-widget/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + '@pandacss/dev/postcss': {}, + }, +}; + diff --git a/packages/@magic-ext/magic-widget/rollup.config.mjs b/packages/@magic-ext/magic-widget/rollup.config.mjs new file mode 100644 index 000000000..91f4c5c0e --- /dev/null +++ b/packages/@magic-ext/magic-widget/rollup.config.mjs @@ -0,0 +1,201 @@ +/* eslint-env node */ +/* global process */ +import resolve from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import typescript from '@rollup/plugin-typescript'; +import replace from '@rollup/plugin-replace'; +import { readFileSync, existsSync, mkdirSync } from 'fs'; +import { resolve as pathResolve, join } from 'path'; +import { execSync } from 'child_process'; + +// Ensure dist directory exists +if (!existsSync('./dist')) { + mkdirSync('./dist', { recursive: true }); +} + +// Generate CSS first +try { + execSync('./node_modules/.bin/panda cssgen --outfile dist/styles.css', { stdio: 'inherit' }); +} catch { + // CSS generation failed, using existing CSS +} + +// Read the CSS to inject +let cssContent = ''; +try { + cssContent = readFileSync('./dist/styles.css', 'utf-8'); + + // CRITICAL: Remove @layer wrappers - they lower specificity and lose to Tailwind's preflight + function stripLayers(css) { + // Remove @layer declarations like "@layer reset, base, tokens;" + css = css.replace(/@layer\s+[\w\s,]+;/g, ''); + + // Find and unwrap @layer blocks + let result = ''; + let i = 0; + while (i < css.length) { + // Check for @layer + if (css.slice(i, i + 6) === '@layer') { + // Skip past @layer and optional name until { + let j = i + 6; + while (j < css.length && css[j] !== '{') j++; + if (j < css.length) { + j++; // skip the { + // Now find the matching } + let braceCount = 1; + let start = j; + while (j < css.length && braceCount > 0) { + if (css[j] === '{') braceCount++; + else if (css[j] === '}') braceCount--; + j++; + } + // Extract content without the outer braces + result += css.slice(start, j - 1); + i = j; + } else { + result += css[i]; + i++; + } + } else { + result += css[i]; + i++; + } + } + return result; + } + + // Strip layers multiple times to handle nesting + cssContent = stripLayers(cssContent); + cssContent = stripLayers(cssContent); + cssContent = stripLayers(cssContent); + + // Escape for JS string + cssContent = cssContent.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$'); +} catch { + // Could not read CSS file +} + +const pkg = JSON.parse(readFileSync('./package.json', 'utf-8')); + +// External dependencies - not bundled by us, resolved by consumer's bundler +const external = [ + 'react', + 'react-dom', + 'react-dom/client', + 'react/jsx-runtime', + '@magic-sdk/provider', + // Wagmi stack - too complex to bundle, consumer's bundler handles it + 'wagmi', + 'viem', + '@wagmi/core', + '@tanstack/react-query', + '@reown/appkit', + '@reown/appkit/networks', + '@reown/appkit-adapter-wagmi', +]; + +// Alias for @styled/* paths +const aliasPlugin = { + name: 'styled-alias', + resolveId(source) { + if (source.startsWith('@styled/')) { + // Convert @styled/css -> styled-system/css + // Convert @styled/css/cx -> styled-system/css/cx + const relativePath = source.replace('@styled/', 'styled-system/'); + const absolutePath = pathResolve(process.cwd(), relativePath); + + // Try with .js extension + if (existsSync(absolutePath + '.js')) { + return absolutePath + '.js'; + } + + // Try as directory with index.js + if (existsSync(join(absolutePath, 'index.js'))) { + return join(absolutePath, 'index.js'); + } + + // Return as-is and let resolve plugin handle it + return absolutePath; + } + return null; + }, +}; + +const plugins = [ + aliasPlugin, + replace({ + preventAssignment: true, + values: { + MAGIC_WIDGET_CSS: JSON.stringify(cssContent), + }, + }), + resolve({ + extensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs'], + }), + commonjs({ + transformMixedEsModules: true, + }), + typescript({ + tsconfig: './tsconfig.json', + declaration: false, + }), +]; + +export default [ + // ESM build + { + input: 'src/index.ts', + output: { + file: pkg.module, + format: 'esm', + sourcemap: true, + inlineDynamicImports: true, + }, + external, + plugins, + onwarn(warning, warn) { + // Suppress circular dependency warnings from third-party libs + if (warning.code === 'CIRCULAR_DEPENDENCY') return; + // Suppress "this" rewrite warnings + if (warning.code === 'THIS_IS_UNDEFINED') return; + warn(warning); + }, + }, + // CJS build + { + input: 'src/index.ts', + output: { + file: pkg.main, + format: 'cjs', + sourcemap: true, + exports: 'named', + inlineDynamicImports: true, + }, + external, + plugins: [ + aliasPlugin, + replace({ + preventAssignment: true, + values: { + MAGIC_WIDGET_CSS: JSON.stringify(cssContent), + }, + }), + resolve({ + extensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs'], + }), + commonjs({ + transformMixedEsModules: true, + }), + typescript({ + tsconfig: './tsconfig.json', + declaration: true, + declarationDir: './dist/types', + }), + ], + onwarn(warning, warn) { + if (warning.code === 'CIRCULAR_DEPENDENCY') return; + if (warning.code === 'THIS_IS_UNDEFINED') return; + warn(warning); + }, + }, +]; diff --git a/packages/@magic-ext/magic-widget/src/MagicWidget.tsx b/packages/@magic-ext/magic-widget/src/MagicWidget.tsx new file mode 100644 index 000000000..20beea305 --- /dev/null +++ b/packages/@magic-ext/magic-widget/src/MagicWidget.tsx @@ -0,0 +1,81 @@ +import { Footer, Modal } from '@magiclabs/ui-components'; +import { VStack } from '../styled-system/jsx'; +import React, { useEffect, useReducer } from 'react'; +import { WagmiProvider } from 'wagmi'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { LoginView } from './views/LoginView'; +import { WalletPendingView } from './views/WalletPendingView'; +import { widgetReducer, initialState, WidgetAction, WidgetState } from './reducer'; +import { OAuthProvider, ThirdPartyWallets } from './types'; +import { wagmiConfig } from './wagmi/config'; +import { OAuthPendingView } from './views/OAuthPendingView'; + +// Create a query client for react-query +const queryClient = new QueryClient(); + +// Inject CSS into document head (only once) +let cssInjected = false; +function injectCSS() { + if (cssInjected || typeof document === 'undefined') return; + + const styleElement = document.createElement('style'); + styleElement.id = 'magic-widget-styles'; + styleElement.textContent = MAGIC_WIDGET_CSS; + document.head.appendChild(styleElement); + cssInjected = true; +} + +// The actual widget content +function WidgetContent({ state, dispatch }: { state: WidgetState; dispatch: React.Dispatch }) { + // Render the current view + const renderView = () => { + switch (state.view) { + case 'login': + return ; + case 'wallet_pending': + return ; + case 'oauth_pending': + return ; + // Add more views here as you implement them: + // case 'email_input': + // return ; + // case 'otp': + // return ; + // case 'error': + // return ; + default: + return ; + } + }; + + return ( + + + {renderView()} +