diff --git a/.gitignore b/.gitignore index bcac9e498..47e893a7c 100755 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,9 @@ dist/ tests/results/ tests/test-case/dist +# for my ai friends +ai/meta/agent-guestbook.md + # Numerous always-ignore extensions *.diff *.err diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 37df40d55..0e5088bba 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -4,6 +4,28 @@ This is a pre-release version and APIs will change quickly. Before `1.0` release Please note after `1.0` Semver will be followed using normal protocols. +# Version 0.12.0 +* **Tailwind** - Added a plugin for using Tailwind inside Semantic UI components. This can be used alongside the css tokens provided by the css framework, or instead of it. This will scan your component javascript, html and css and attach only the tailwind styles used. + +> Note: the plugin code may be modified if `defineComponent` gets a formal 'Plugin API'. For now you will need to pass in the component to the plugin before defining the component. + + +```javascript +import { TailwindPlugin } from '@semantic-ui/tailwind'; +const tailwindPlugin = TailwindPlugin(); + + +// Transform with Tailwind plugin +const definition = { + // your component definition + template: `
` +} +defineComponent( await tailwindPlugin(definition) ); + +``` + +* **Template Compiler** - Fixed an issue with nested conditionals inside svg. + # Version 0.11.3 * **Input** - Fix placeholder focused color to be theme aware diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index a03edf851..d899d3397 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -63,7 +63,7 @@ export default defineConfig({ }, optimizeDeps: { force: true, - exclude: ['playground-elements'], + exclude: ['playground-elements', 'tailwindcss-iso'], }, }, diff --git a/docs/src/components/CodePlayground/CodePlayground.js b/docs/src/components/CodePlayground/CodePlayground.js index 34f8602cd..80a862314 100644 --- a/docs/src/components/CodePlayground/CodePlayground.js +++ b/docs/src/components/CodePlayground/CodePlayground.js @@ -398,7 +398,6 @@ const createComponent = ( // and the right pane is just the iframe preview if (filter && self.onlyPageFiles(fileArray)) { if (filter == 'main') { - console.log(fileArray.filter(file => self.isPageFile(file.filename))); return fileArray.filter(file => self.isPageFile(file.filename)); } else if (filter == 'page') { diff --git a/docs/src/content/examples/cdn.mdx b/docs/src/content/examples/cdn.mdx index 6b90e1851..91d876714 100644 --- a/docs/src/content/examples/cdn.mdx +++ b/docs/src/content/examples/cdn.mdx @@ -1,7 +1,7 @@ --- title: 'CDN' exampleType: 'page' -category: 'UI Framework' +category: 'Components' subcategory: 'Usage' tags: ['component', 'usage'] description: An example of using the component framework from a cdn diff --git a/docs/src/content/examples/tailwind.mdx b/docs/src/content/examples/tailwind.mdx new file mode 100644 index 000000000..f3cc0b9f2 --- /dev/null +++ b/docs/src/content/examples/tailwind.mdx @@ -0,0 +1,9 @@ +--- +title: 'Tailwind' +exampleType: 'component' +category: 'Components' +subcategory: 'Usage' +fold: false +tags: ['component', 'usage'] +description: An example of using Tailwinds with web components +--- diff --git a/docs/src/examples/tailwind/component.css b/docs/src/examples/tailwind/component.css new file mode 100644 index 000000000..57c1d901f --- /dev/null +++ b/docs/src/examples/tailwind/component.css @@ -0,0 +1,15 @@ +/* + Example using @theme inside a component + +*/ + +@theme { + /* This changes the bluish grays to a monochrome color */ + --color-gray-100: theme(colors.zinc.100); + --color-gray-300: theme(colors.zinc.300); + --color-gray-700: theme(colors.zinc.700); + --color-gray-950: theme(colors.zinc.950); +} + +/* this allows us to add "dark" class to component to trigger dark mode */ +@custom-variant dark (&:where(.dark, .dark *)); diff --git a/docs/src/examples/tailwind/component.html b/docs/src/examples/tailwind/component.html new file mode 100644 index 000000000..8cc5b2592 --- /dev/null +++ b/docs/src/examples/tailwind/component.html @@ -0,0 +1,39 @@ +{#snippet bullet} +
  • + + + + + +

    + {#html content} +

    +
  • +{/snippet} + +
    +
    +
    +
    + Tailwind Play + +
    +

    An advanced online playground for Tailwind CSS, including support for things like:

    +
      + {#each item in proofPoints} + {>bullet content=item} + {/each} +
    +

    Perfect for learning how the framework works, prototyping a new idea, or creating a demo to share online.

    +
    +
    +

    Want to dig deeper into Tailwind?

    + Read the docs +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/docs/src/examples/tailwind/component.js b/docs/src/examples/tailwind/component.js new file mode 100644 index 000000000..666431ff6 --- /dev/null +++ b/docs/src/examples/tailwind/component.js @@ -0,0 +1,21 @@ +import { defineComponent, getText } from '@semantic-ui/component'; +import { TailwindPlugin } from '@semantic-ui/tailwind'; + +const template = await getText('./component.html'); +const css = await getText('./component.css'); + +const defaultSettings = { + proofPoints: [], +}; + +let definition = { + tagName: 'tailwind-demo', + template, + css, + defaultSettings, +}; + +// Transform with Tailwind plugin +definition = await TailwindPlugin(definition); + +export const TailwindDemo = defineComponent(definition); diff --git a/docs/src/examples/tailwind/page.css b/docs/src/examples/tailwind/page.css new file mode 100644 index 000000000..3175b39d5 --- /dev/null +++ b/docs/src/examples/tailwind/page.css @@ -0,0 +1,8 @@ +html { + /* + note tailwind base em size is 16px instead of semantic ui's 14px + this means to have everything sized the same as other tailwind projects + when using sui + tailwinds you will want to resize semantic components + */ + --font-size: 16px; +} diff --git a/docs/src/examples/tailwind/page.js b/docs/src/examples/tailwind/page.js new file mode 100644 index 000000000..4d79b85b9 --- /dev/null +++ b/docs/src/examples/tailwind/page.js @@ -0,0 +1,10 @@ +import { $ } from '@semantic-ui/query'; + +$('tailwind-demo').settings({ + proofPoints: [ + `Customizing your theme with @theme`, + `Adding custom utilities with @utility`, + `Adding custom variants with @variant`, + `Code completion with instant preview`, + ], +}); diff --git a/docs/src/pages/examples/importmap.json.js b/docs/src/pages/examples/importmap.json.js index bad8d6394..418a68a88 100644 --- a/docs/src/pages/examples/importmap.json.js +++ b/docs/src/pages/examples/importmap.json.js @@ -12,6 +12,7 @@ export const npmPackages = [ '@semantic-ui/renderer', '@semantic-ui/query', '@semantic-ui/specs', + '@semantic-ui/tailwind', '@semantic-ui/utils', ]; @@ -26,6 +27,7 @@ export const localPackages = [ '@semantic-ui/core/packages/specs', '@semantic-ui/core/packages/utils', '@semantic-ui/core/packages/reactivity', + '@semantic-ui/core/packages/tailwind', ]; // note NPM packages is no longer used for static builds @@ -39,11 +41,10 @@ const packageImports = { imports: {} }; for (const pkg of importPackages) { try { - // use jsdelivr - if(isStaticBuild) { + if (isStaticBuild) { let url = `${packageBase}/${pkg}/`; - if(packageBase.includes('jsdelivr')) { + if (packageBase.includes('jsdelivr')) { url += '+esm'; } packageImports.imports[pkg] = url; @@ -88,6 +89,7 @@ export const importMap = packageImports; export const importMapJSON = JSON.stringify(packageImports, null, 2); export const GET = async () => { + console.log(importMapJSON); return new Response(importMapJSON, { headers: { 'Content-Type': 'application/importmap+json', diff --git a/docs/src/pages/examples/package.json.js b/docs/src/pages/examples/package.json.js index a51e265b1..d7996f725 100755 --- a/docs/src/pages/examples/package.json.js +++ b/docs/src/pages/examples/package.json.js @@ -17,7 +17,6 @@ export const packageFile = { }; export const packageJSON = JSON.stringify(packageFile, null, 2); - export const GET = async () => { return new Response(packageJSON, { headers: { diff --git a/internal-packages/esbuild-callback/LICENSE b/internal-packages/esbuild-callback/LICENSE index 6d65704bd..3d01df1fb 100644 --- a/internal-packages/esbuild-callback/LICENSE +++ b/internal-packages/esbuild-callback/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Jack Lukic +Copyright (c) 2025 Jack Lukic Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/internal-packages/esbuild-resolve-bare-imports/LICENSE b/internal-packages/esbuild-resolve-bare-imports/LICENSE index cb66593ce..654a7d134 100644 --- a/internal-packages/esbuild-resolve-bare-imports/LICENSE +++ b/internal-packages/esbuild-resolve-bare-imports/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2024 Jack Lukic +Copyright (c) 2025 Jack Lukic Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff --git a/internal-packages/scripts/package.json b/internal-packages/scripts/package.json index 51c6c5f9a..4e80ba7f6 100644 --- a/internal-packages/scripts/package.json +++ b/internal-packages/scripts/package.json @@ -38,5 +38,8 @@ "@semantic-ui/specs": "^0.11.2", "esbuild": "^0.25.1", "tiny-glob": "^0.2.9" + }, + "devDependencies": { + "@chialab/esbuild-plugin-worker": "^0.18.1" } } diff --git a/internal-packages/scripts/src/lib/config.js b/internal-packages/scripts/src/lib/config.js index 397503188..3f248cfab 100644 --- a/internal-packages/scripts/src/lib/config.js +++ b/internal-packages/scripts/src/lib/config.js @@ -1,5 +1,6 @@ // package is package.json -export const getBanner = (packageFile) => `/** +export const getBanner = (packageFile) => + `/** * ${packageFile.name} v${packageFile.version} * ${packageFile.description || ''} * @@ -11,19 +12,17 @@ export const getBanner = (packageFile) => `/** * LICENSE file in the root directory of this source tree. */`; - // This is used for files build internally to concatenate css (see build-ui-deps.js) - export const INTERNAL_CSS_BANNER = `/** +export const INTERNAL_CSS_BANNER = `/** ---DO NOT EDIT THIS FILE DIRECTLY--- This CSS file was concatenated from files listed in the css/ folder as part of a build process This is to allow for js import with @import links which will not be followed **/ -` +`; - export const TARGET_BROWSERS = ['chrome80', 'edge80', 'firefox78', 'safari14', 'ios14', 'opera67']; +export const TARGET_BROWSERS = ['chrome80', 'edge80', 'firefox78', 'safari14', 'ios14', 'opera67']; export const JS_BUILD_CONFIG = { - // target browser by default for dist target: TARGET_BROWSERS, @@ -40,6 +39,7 @@ export const JS_BUILD_CONFIG = { '.ts': 'ts', '.html': 'text', '.css': 'text', + '.wasm': 'file', '.png': 'file', '.svg': 'file', '.jpg': 'file', @@ -49,7 +49,6 @@ export const JS_BUILD_CONFIG = { }; export const CSS_BUILD_CONFIG = { - // target browser by default for dist target: TARGET_BROWSERS, diff --git a/package-lock.json b/package-lock.json index 1b4f0e30d..7bfd607b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -77,6 +77,90 @@ "@semantic-ui/specs": "^0.11.2", "esbuild": "^0.25.1", "tiny-glob": "^0.2.9" + }, + "devDependencies": { + "@chialab/esbuild-plugin-worker": "^0.18.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@chialab/esbuild-plugin-meta-url": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@chialab/esbuild-plugin-meta-url/-/esbuild-plugin-meta-url-0.18.2.tgz", + "integrity": "sha512-uIRIdLvYnw5mLrTRXY0BTgeZx6ANL2/OHkWFl8FaiTYNb7cyXmwEDRE1mh6kBXPRPtGuqv6XSpNX+koEkElu4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@chialab/esbuild-rna": "^0.18.1", + "@chialab/estransform": "^0.18.1", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@chialab/esbuild-plugin-worker": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@chialab/esbuild-plugin-worker/-/esbuild-plugin-worker-0.18.1.tgz", + "integrity": "sha512-FCpdhMQkrwBejY+uWo3xLdqHhUK3hbn0ICedyqo97hzRX98ErB2fhRq4LEEPMEaiplF2se2ToYTQaoxHDpkouw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@chialab/esbuild-plugin-meta-url": "^0.18.2", + "@chialab/esbuild-rna": "^0.18.0", + "@chialab/estransform": "^0.18.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@chialab/esbuild-rna": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@chialab/esbuild-rna/-/esbuild-rna-0.18.2.tgz", + "integrity": "sha512-ckzskez7bxstVQ4c5cxbx0DRP2teldzrcSGQl2KPh1VJGdO2ZmRrb6vNkBBD5K3dx9tgTyvskWp4dV+Fbg07Ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@chialab/estransform": "^0.18.0", + "@chialab/node-resolve": "^0.18.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@chialab/estransform": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@chialab/estransform/-/estransform-0.18.1.tgz", + "integrity": "sha512-W/WmjpQL2hndD0/XfR0FcPBAUj+aLNeoAVehOjV/Q9bSnioz0GVSAXXhzp59S33ZynxJBBfn8DNiMTVNJmk4Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/source-map": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@chialab/node-resolve": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@chialab/node-resolve/-/node-resolve-0.18.0.tgz", + "integrity": "sha512-eV1m70Qn9pLY9xwFmZ2FlcOzwiaUywsJ7NB/ud8VB7DouvCQtIHkQ3Om7uPX0ojXGEG1LCyO96kZkvbNTxNu0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" } }, "node_modules/@commitlint/cli": { @@ -638,11 +722,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@commitlint/load/node_modules/lines-and-columns": { - "version": "1.2.4", - "dev": true, - "license": "MIT" - }, "node_modules/@commitlint/load/node_modules/lodash.isplainobject": { "version": "4.0.6", "dev": true, @@ -691,11 +770,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/load/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, "node_modules/@commitlint/load/node_modules/require-from-string": { "version": "2.0.2", "dev": true, @@ -1397,6 +1471,19 @@ "node": ">=12" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "dev": true, @@ -1405,6 +1492,59 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@lit/reactive-element": { "version": "2.0.4", "license": "BSD-3-Clause", @@ -1418,6 +1558,43 @@ "license": "BSD-3-Clause", "peer": true }, + "node_modules/@parcel/source-map": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz", + "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": "^12.18.3 || >=14" + } + }, + "node_modules/@parcel/source-map/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@semantic-ui/component": { "resolved": "packages/component", "link": true @@ -1454,6 +1631,10 @@ "resolved": "packages/specs", "link": true }, + "node_modules/@semantic-ui/tailwind": { + "resolved": "packages/tailwind", + "link": true + }, "node_modules/@semantic-ui/templating": { "resolved": "packages/templating", "link": true @@ -1462,109 +1643,369 @@ "resolved": "packages/utils", "link": true }, - "node_modules/@testing-library/dom": { - "version": "10.4.0", - "dev": true, + "node_modules/@tailwindcss/node": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.9.tgz", + "integrity": "sha512-ZFsgw6lbtcZKYPWvf6zAuCVSuer7UQ2Z5P8BETHcpA4x/3NwOjAIXmRnYfG77F14f9bPeuR4GaNz3ji1JkQMeQ==", "license": "MIT", + "optional": true, "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" + "@ampproject/remapping": "^2.3.0", + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.9" } }, - "node_modules/@testing-library/dom/node_modules/@babel/code-frame": { - "version": "7.26.2", - "dev": true, + "node_modules/@tailwindcss/node/node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "license": "MIT", + "optional": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.9.tgz", + "integrity": "sha512-oqjNxOBt1iNRAywjiH+VFsfovx/hVt4mxe0kOkRMAbbcCwbJg5e2AweFqyGN7gtmE1TJXnvnyX7RWTR1l72ciQ==", + "hasInstallScript": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "detect-libc": "^2.0.4", + "tar": "^7.4.3" }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@testing-library/dom/node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "dev": true, + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.9", + "@tailwindcss/oxide-darwin-arm64": "4.1.9", + "@tailwindcss/oxide-darwin-x64": "4.1.9", + "@tailwindcss/oxide-freebsd-x64": "4.1.9", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.9", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.9", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.9", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.9", + "@tailwindcss/oxide-linux-x64-musl": "4.1.9", + "@tailwindcss/oxide-wasm32-wasi": "4.1.9", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.9", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.9" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.9.tgz", + "integrity": "sha512-X4mBUUJ3DPqODhtdT5Ju55feJwBN+hP855Z7c0t11Jzece9KRtdM41ljMrCcureKMh96mcOh2gxahkp1yE+BOQ==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">= 10" } }, - "node_modules/@testing-library/dom/node_modules/@babel/runtime": { - "version": "7.26.10", - "dev": true, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.9.tgz", + "integrity": "sha512-jnWnqz71ZLXUbJLW53m9dSQakLBfaWxAd9TAibimrNdQfZKyie+xGppdDCZExtYwUdflt3kOT9y1JUgYXVEQmw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" + "node": ">= 10" } }, - "node_modules/@testing-library/dom/node_modules/@types/aria-query": { - "version": "5.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@testing-library/dom/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.9.tgz", + "integrity": "sha512-+Ui6LlvZ6aCPvSwv3l16nYb6gu1N6RamFz7hSu5aqaiPrDQqD1LPT/e8r2/laSVwFjRyOZxQQ/gvGxP3ihA2rw==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.9.tgz", + "integrity": "sha512-BWqCh0uoXMprwWfG7+oyPW53VCh6G08pxY0IIN/i5DQTpPnCJ4zm2W8neH9kW1v1f6RXP3b2qQjAzrAcnQ5e9w==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "5.3.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" + "node": ">= 10" } }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "dev": true, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.9.tgz", + "integrity": "sha512-U8itjQb5TVc80aV5Yo+JtKo+qS95CV4XLrKEtSLQFoTD/c9j3jk4WZipYT+9Jxqem29qCMRPxjEZ3s+wTT4XCw==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 10" } }, - "node_modules/@testing-library/dom/node_modules/dequal": { - "version": "2.0.3", - "dev": true, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.9.tgz", + "integrity": "sha512-dKlGraoNvyTrR7ovLw3Id9yTwc+l0NYg8bwOkYqk+zltvGns8bPvVr6PH5jATdc75kCGd6kDRmP4p1LwqCnPJQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.9.tgz", + "integrity": "sha512-qCZ4QTrZaBEgNM13pGjvakdmid1Kw3CUCEQzgVAn64Iud7zSxOGwK1usg+hrwrOfFH7vXZZr8OhzC8fJTRq5NA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.9.tgz", + "integrity": "sha512-bmzkAWQjRlY9udmg/a1bOtZpV14ZCdrB74PZrd7Oz/wK62Rk+m9+UV3BsgGfOghyO5Qu5ZDciADzDMZbi9n1+g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.9.tgz", + "integrity": "sha512-NpvPQsXj1raDHhd+g2SUvZQoTPWfYAsyYo9h4ZqV7EOmR+aj7LCAE5hnXNnrJ5Egy/NiO3Hs7BNpSbsPEOpORg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.9.tgz", + "integrity": "sha512-G93Yuf3xrpTxDUCSh685d1dvOkqOB0Gy+Bchv9Zy3k+lNw/9SEgsHit50xdvp1/p9yRH2TeDHJeDLUiV4mlTkA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.10", + "@tybys/wasm-util": "^0.9.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.9.tgz", + "integrity": "sha512-Eq9FZzZe/NPkUiSMY+eY7r5l7msuFlm6wC6lnV11m8885z0vs9zx48AKTfw0UbVecTRV5wMxKb3Kmzx2LoUIWg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.9.tgz", + "integrity": "sha512-oZ4zkthMXMJN2w/vu3jEfuqWTW7n8giGYDV/SfhBGRNehNMOBqh3YUAEv+8fv2YDJEzL4JpXTNTiSXW3UiUwBw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/@babel/code-frame": { + "version": "7.26.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@testing-library/dom/node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@testing-library/dom/node_modules/@babel/runtime": { + "version": "7.26.10", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@testing-library/dom/node_modules/@types/aria-query": { + "version": "5.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/dom/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/dequal": { + "version": "2.0.3", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -1596,11 +2037,6 @@ "lz-string": "bin/bin.js" } }, - "node_modules/@testing-library/dom/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, "node_modules/@testing-library/dom/node_modules/pretty-format": { "version": "27.5.1", "dev": true, @@ -1756,25 +2192,6 @@ "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@typescript-eslint/parser/node_modules/minimatch": { "version": "9.0.5", "dev": true, @@ -1876,25 +2293,6 @@ "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { "version": "9.0.5", "dev": true, @@ -1996,25 +2394,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@typescript-eslint/utils/node_modules/minimatch": { "version": "9.0.5", "dev": true, @@ -2175,61 +2554,6 @@ "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/@vitest/browser/node_modules/nanoid": { - "version": "3.3.11", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/@vitest/browser/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true - }, - "node_modules/@vitest/browser/node_modules/postcss": { - "version": "8.5.3", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "nanoid": "^3.3.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/@vitest/browser/node_modules/rollup": { "version": "4.36.0", "dev": true, @@ -2555,16 +2879,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/@vitest/browser/node_modules/source-map-js": { - "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@vitest/browser/node_modules/tinyspy": { "version": "3.0.2", "dev": true, @@ -2801,6 +3115,19 @@ "balanced-match": "^1.0.0" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/chalk": { "version": "5.4.1", "dev": true, @@ -2858,28 +3185,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chokidar/node_modules/braces": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/fill-range": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/chokidar/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2892,75 +3197,29 @@ "darwin" ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chokidar/node_modules/is-binary-path": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/is-number": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/chokidar/node_modules/normalize-path": { - "version": "3.0.0", + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, - "node_modules/chokidar/node_modules/picomatch": { - "version": "2.3.1", + "node_modules/chokidar/node_modules/is-binary-path": { + "version": "2.1.0", "dev": true, "license": "MIT", - "engines": { - "node": ">=8.6" + "dependencies": { + "binary-extensions": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": ">=8" } }, "node_modules/chokidar/node_modules/readdirp": { @@ -2974,15 +3233,14 @@ "node": ">=8.10.0" } }, - "node_modules/chokidar/node_modules/to-regex-range": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "optional": true, "engines": { - "node": ">=8.0" + "node": ">=18" } }, "node_modules/color-convert": { @@ -3236,6 +3494,16 @@ "dev": true, "license": "MIT" }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/dprint": { "version": "0.49.1", "dev": true, @@ -3382,6 +3650,20 @@ "dev": true, "license": "MIT" }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "license": "MIT", + "optional": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/esbuild": { "version": "0.25.1", "hasInstallScript": true, @@ -4319,18 +4601,6 @@ "node": ">=16" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/eslint/node_modules/globals": { "version": "14.0.0", "dev": true, @@ -4377,27 +4647,6 @@ "node": ">=0.8.19" } }, - "node_modules/eslint/node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eslint/node_modules/js-yaml": { "version": "4.1.0", "dev": true, @@ -4691,17 +4940,6 @@ "node": ">= 8" } }, - "node_modules/fast-glob/node_modules/braces": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/fast-glob/node_modules/fastq": { "version": "1.19.1", "dev": true, @@ -4710,17 +4948,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fast-glob/node_modules/fill-range": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", "dev": true, @@ -4732,33 +4959,6 @@ "node": ">= 6" } }, - "node_modules/fast-glob/node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-number": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/fast-glob/node_modules/merge2": { "version": "1.4.1", "dev": true, @@ -4767,29 +4967,6 @@ "node": ">= 8" } }, - "node_modules/fast-glob/node_modules/micromatch": { - "version": "4.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/fast-glob/node_modules/picomatch": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/fast-glob/node_modules/queue-microtask": { "version": "1.2.3", "dev": true, @@ -4840,22 +5017,24 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/fast-glob/node_modules/to-regex-range": { - "version": "5.0.1", + "node_modules/fflate": { + "version": "0.8.2", + "dev": true, + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">=8.0" + "node": ">=8" } }, - "node_modules/fflate": { - "version": "0.8.2", - "dev": true, - "license": "MIT" - }, "node_modules/flatted": { "version": "3.3.3", "dev": true, @@ -4982,14 +5161,6 @@ "node": ">= 0.4" } }, - "node_modules/form-data/node_modules/function-bind": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/form-data/node_modules/get-intrinsic": { "version": "1.3.0", "dev": true, @@ -5061,17 +5232,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/form-data/node_modules/hasown": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/form-data/node_modules/math-intrinsics": { "version": "1.1.0", "dev": true, @@ -5080,23 +5240,14 @@ "node": ">= 0.4" } }, - "node_modules/form-data/node_modules/mime-db": { - "version": "1.52.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/form-data/node_modules/mime-types": { - "version": "2.1.35", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/glob": { @@ -5123,6 +5274,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/globalyzer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", @@ -5133,11 +5298,31 @@ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "devOptional": true, + "license": "ISC" + }, "node_modules/graphemer": { "version": "1.4.0", "dev": true, "license": "MIT" }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "dev": true, @@ -5222,6 +5407,16 @@ } } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5232,6 +5427,29 @@ "node": ">=8" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "dev": true, @@ -5259,24 +5477,12 @@ "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/@ampproject/remapping": { - "version": "2.3.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" } }, "node_modules/istanbul-lib-instrument/node_modules/@babel/code-frame": { @@ -5495,49 +5701,6 @@ "node": ">=6.9.0" } }, - "node_modules/istanbul-lib-instrument/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "dev": true, - "license": "MIT" - }, - "node_modules/istanbul-lib-instrument/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/istanbul-lib-instrument/node_modules/browserslist": { "version": "4.24.4", "dev": true, @@ -5662,11 +5825,6 @@ "dev": true, "license": "MIT" }, - "node_modules/istanbul-lib-instrument/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, "node_modules/istanbul-lib-instrument/node_modules/update-browserslist-db": { "version": "1.1.3", "dev": true, @@ -5760,28 +5918,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-source-maps/node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "dev": true, - "license": "MIT" - }, - "node_modules/istanbul-lib-source-maps/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/istanbul-reports": { "version": "3.1.7", "dev": true, @@ -5815,6 +5951,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/jsdom": { "version": "26.0.0", "dev": true, @@ -5859,6 +6007,262 @@ "dev": true, "license": "MIT" }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, "node_modules/lit": { "version": "3.2.1", "license": "BSD-3-Clause", @@ -5909,17 +6313,12 @@ }, "node_modules/magic-string": { "version": "0.30.17", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, - "node_modules/magic-string/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "dev": true, - "license": "MIT" - }, "node_modules/magicast": { "version": "0.3.5", "dev": true, @@ -5969,15 +6368,44 @@ "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { - "node": ">=6.9.0" + "node": ">=6.9.0" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/magicast/node_modules/source-map-js": { - "version": "1.2.1", + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, "node_modules/minimatch": { @@ -6000,12 +6428,41 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "license": "MIT", + "optional": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/msw": { "version": "2.7.3", "dev": true, @@ -6180,11 +6637,6 @@ "dev": true, "license": "MIT" }, - "node_modules/msw/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, "node_modules/msw/node_modules/psl": { "version": "1.15.0", "dev": true, @@ -6277,11 +6729,40 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "dev": true, "license": "MIT" }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/nwsapi": { "version": "2.2.19", "dev": true, @@ -6348,6 +6829,26 @@ "dev": true, "license": "MIT" }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/playwright": { "version": "1.51.1", "dev": true, @@ -6391,6 +6892,35 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/postcss": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz", + "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/proper-lockfile": { "version": "4.1.2", "dev": true, @@ -6401,11 +6931,6 @@ "signal-exit": "^3.0.2" } }, - "node_modules/proper-lockfile/node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "license": "ISC" - }, "node_modules/proper-lockfile/node_modules/retry": { "version": "0.12.0", "dev": true, @@ -6553,6 +7078,16 @@ "node": ">=6" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -6662,6 +7197,53 @@ "dev": true, "license": "MIT" }, + "node_modules/tailwindcss": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.9.tgz", + "integrity": "sha512-anBZRcvfNMsQdHB9XSGzAtIQWlhs49uK75jfkwrqjRUbjt4d7q9RE1wR1xWyfYZhLFnFX4ahWp88Au2lcEw5IQ==", + "license": "MIT" + }, + "node_modules/tailwindcss-iso": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tailwindcss-iso/-/tailwindcss-iso-1.0.0.tgz", + "integrity": "sha512-3gfODToA+O46jLcLMm7k7LCbKwi7v0O9pbBUjjGnGsmwQLt9mleTQ2R3+x83SboEOzyy2WmR48GAAziHZ54Idw==", + "license": "ISC", + "optionalDependencies": { + "@tailwindcss/node": "^4.1.9", + "@tailwindcss/oxide": "^4.1.9" + }, + "peerDependencies": { + "tailwindcss": "^3.0.0 || ^4.0.0" + } + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "license": "ISC", + "optional": true, + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/test-exclude": { "version": "7.0.1", "dev": true, @@ -6675,15 +7257,6 @@ "node": ">=18" } }, - "node_modules/test-exclude/node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/test-exclude/node_modules/glob": { "version": "10.4.5", "dev": true, @@ -6812,6 +7385,19 @@ "node": ">=14.0.0" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tough-cookie": { "version": "5.1.2", "dev": true, @@ -7127,23 +7713,6 @@ "dev": true, "license": "MIT" }, - "node_modules/vitest/node_modules/nanoid": { - "version": "3.3.11", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/vitest/node_modules/pathval": { "version": "2.0.0", "dev": true, @@ -7152,38 +7721,6 @@ "node": ">= 14.16" } }, - "node_modules/vitest/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, - "node_modules/vitest/node_modules/postcss": { - "version": "8.5.3", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/vitest/node_modules/rollup": { "version": "4.36.0", "dev": true, @@ -7493,14 +8030,6 @@ "dev": true, "license": "ISC" }, - "node_modules/vitest/node_modules/source-map-js": { - "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/vitest/node_modules/stackback": { "version": "0.0.2", "dev": true, @@ -7921,6 +8450,31 @@ "node": ">=18" } }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/yargs": { "version": "17.7.2", "dev": true, @@ -8130,6 +8684,56 @@ "vitest": "^3.0.4" } }, + "packages/tailwind": { + "name": "@semantic-ui/tailwind", + "version": "0.11.2", + "license": "ISC", + "dependencies": { + "@semantic-ui/component": "^0.11.2", + "@semantic-ui/utils": "^0.11.2", + "tailwindcss-iso": "^1.0.0" + }, + "devDependencies": { + "@semantic-ui/internal-scripts": "^0.11.2", + "vitest": "^3.0.8" + }, + "peerDependencies": { + "tailwindcss": "^3.0.0 || ^4.0.0" + } + }, + "packages/tailwindcss-iso": { + "version": "1.0.0", + "extraneous": true, + "license": "ISC", + "devDependencies": { + "vitest": "^3.0.8" + }, + "optionalDependencies": { + "@tailwindcss/node": "^4.1.9", + "@tailwindcss/oxide": "^4.1.9" + }, + "peerDependencies": { + "tailwindcss": "^3.0.0 || ^4.0.0" + } + }, + "packages/tailwinds": { + "name": "@semantic-ui/tailwinds", + "version": "0.11.2", + "extraneous": true, + "license": "ISC", + "dependencies": { + "@mhsdesign/jit-browser-tailwindcss": "^0.4.2", + "@semantic-ui/component": "^0.11.2", + "@semantic-ui/utils": "^0.11.2" + }, + "devDependencies": { + "@semantic-ui/internal-scripts": "^0.11.2", + "vitest": "^3.0.8" + }, + "peerDependencies": { + "tailwindcss": "^3.0.0 || ^4.0.0" + } + }, "packages/templating": { "name": "@semantic-ui/templating", "version": "0.11.2", diff --git a/packages/component/LICENSE b/packages/component/LICENSE index cb66593ce..654a7d134 100755 --- a/packages/component/LICENSE +++ b/packages/component/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2024 Jack Lukic +Copyright (c) 2025 Jack Lukic Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff --git a/packages/component/src/web-component.js b/packages/component/src/web-component.js index af46c3129..1562181a6 100755 --- a/packages/component/src/web-component.js +++ b/packages/component/src/web-component.js @@ -88,10 +88,10 @@ class WebComponentBase extends LitElement { properties[propertyName] = (defaultValue?.type) ? defaultSettings : WebComponentBase.getPropertySettings({ - name: propertyName, - type: defaultValue?.constructor, - propertyOnly: isClassInstance(defaultValue), // cant serialize custom classes - }); + name: propertyName, + type: defaultValue?.constructor, + propertyOnly: isClassInstance(defaultValue), // cant serialize custom classes + }); }); } @@ -112,18 +112,17 @@ class WebComponentBase extends LitElement { // accessors can break certain special dom attrs const specialAttrs = ['value', 'checked']; each(specialAttrs, (attr) => { - if(properties[attr]) { - //properties[attr].noAccessor = true; + if (properties[attr]) { + // properties[attr].noAccessor = true; } }); return properties; } - static getPropertySettings({name, type = String, propertyOnly = false } = {}) { - + static getPropertySettings({ name, type = String, propertyOnly = false } = {}) { // converts type = 'string' -> String // this is because compont spec cannot serialize prototypes in JSON - if(isString(type)) { + if (isString(type)) { const types = { string: String, number: Number, @@ -318,7 +317,7 @@ class WebComponentBase extends LitElement { isDarkMode() { return (isServer) ? undefined - : $(this).cssVar('dark-mode') == 'true'; + : $(this).cssVar('dark-mode') == 'true' || $('html').hasClass('dark'); } /******************************* diff --git a/packages/query/LICENSE b/packages/query/LICENSE index cb66593ce..654a7d134 100755 --- a/packages/query/LICENSE +++ b/packages/query/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2024 Jack Lukic +Copyright (c) 2025 Jack Lukic Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff --git a/packages/reactivity/LICENSE b/packages/reactivity/LICENSE index cb66593ce..654a7d134 100755 --- a/packages/reactivity/LICENSE +++ b/packages/reactivity/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2024 Jack Lukic +Copyright (c) 2025 Jack Lukic Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff --git a/packages/renderer/LICENSE b/packages/renderer/LICENSE index cb66593ce..654a7d134 100755 --- a/packages/renderer/LICENSE +++ b/packages/renderer/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2024 Jack Lukic +Copyright (c) 2025 Jack Lukic Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff --git a/packages/tailwind/AGENTS.md b/packages/tailwind/AGENTS.md new file mode 100644 index 000000000..ceeb684bc --- /dev/null +++ b/packages/tailwind/AGENTS.md @@ -0,0 +1,244 @@ +# Agent Memory & Project Architecture + +This document outlines the core architectural decisions and technical implementation details for the `@semantic-ui/tailwind` package, a Semantic UI component plugin for Tailwind CSS integration. + +## 1. Primary Goal & Core Problem + +The primary objective is to provide seamless Tailwind CSS integration with Semantic UI web components. This plugin automatically scans component definitions for Tailwind classes and generates the appropriate CSS for shadow DOM encapsulation. + +Key challenges addressed: + +* **Shadow DOM Compatibility**: Tailwind CSS needs to be scoped within web component shadow boundaries +* **Component Definition Scanning**: Classes can appear in templates, JavaScript functions, CSS files, and sub-templates +* **Async Plugin Architecture**: Since WASM loading is async, plugins must be applied before `defineComponent()` rather than during +* **Environment Consistency**: Must work identically in browser and Node.js environments + +## 2. Architectural Solution: Pre-Processing Plugin Pattern + +Instead of integrating into `defineComponent()` directly (which would require async support), the plugin transforms component definitions before they are passed to `defineComponent()`. + +### 2.1. Plugin API Design + +The plugin follows a simple transformation pattern: + +```javascript +// Before +let definition = { + tagName: 'my-component', + template: '
    Content
    ', + css: '@theme { --color-blue: #007bff; }' +}; + +// Transform +definition = await TailwindPlugin(definition); + +// After - CSS replaced with generated Tailwind CSS +defineComponent(definition); +``` + +This approach: +- Keeps `defineComponent()` synchronous for SSR compatibility +- Allows chaining multiple async plugins +- Provides clear transformation pipeline +- Maintains component definition immutability + +### 2.2. Environment-Specific Implementations + +The package provides conditional exports that automatically select the correct Tailwind engine: + +```json +"exports": { + ".": { + "types": "./types/index.d.ts", + "browser": "./src/browser.js", + "node": "./src/server.js", + "default": "./src/server.js" + } +} +``` + +**Browser Implementation (`src/browser.js`)**: +```javascript +import { generateTailwindCSS } from 'tailwindcss-iso/browser'; +``` + +**Server Implementation (`src/server.js`)**: +```javascript +import { generateTailwindCSS } from 'tailwindcss-iso/server'; +``` + +Both implementations share identical logic but import from different `tailwindcss-iso` endpoints to ensure the correct engine is used. + +## 3. Component Scanning Strategy + +The plugin comprehensively scans component definitions for Tailwind class usage: + +### 3.1. Content Sources Scanned + +* **Template HTML**: Primary source of Tailwind classes +* **Component CSS**: @theme, @utility, and custom CSS with embedded classes +* **JavaScript Functions**: All lifecycle and event handler functions converted to strings +* **Sub-templates**: Recursive scanning of nested template definitions + +### 3.2. Content Extraction (`extract-definition-content.js`) + +```javascript +export function extractDefinitionContent(definition) { + // Scans: + // - definition.template + // - definition.css + // - definition.createComponent.toString() + // - definition.events[key].toString() + // - definition.subTemplates recursively + + return { content, css }; +} +``` + +This comprehensive scanning ensures all Tailwind classes are detected regardless of where they appear in the component definition. + +## 4. CSS Generation & Replacement + +### 4.1. Tailwind Compilation + +The plugin uses `tailwindcss-iso` to generate CSS: + +```javascript +const tailwindCSS = await generateTailwindCSS({ + content, // Combined HTML + JS content + css, // Component CSS with @theme/@utility +}); +``` + +### 4.2. Definition Transformation + +The generated CSS completely replaces the component's original CSS: + +```javascript +return { + ...definition, + css: tailwindCSS, // Replace with generated CSS +}; +``` + +This ensures: +- All Tailwind utilities are available in shadow DOM +- Component-specific @theme customizations are applied +- Custom @utility definitions are compiled +- Existing component CSS is preserved and enhanced + +## 5. Integration with Semantic UI Framework + +### 5.1. Component Lifecycle Integration + +```javascript +import { defineComponent, getText } from '@semantic-ui/component'; +import { TailwindPlugin } from '@semantic-ui/tailwind'; + +// Standard component definition +const template = await getText('./component.html'); +const css = await getText('./component.css'); + +let definition = { + tagName: 'my-component', + template, + css, + defaultSettings: { /* ... */ } +}; + +// Apply Tailwind transformation +definition = await TailwindPlugin(definition); + +// Define component with enhanced CSS +export const MyComponent = defineComponent(definition); +``` + +### 5.2. Shadow DOM Optimization + +The generated CSS is specifically optimized for shadow DOM: +- Tailwind utilities are scoped to the component +- No global style pollution +- CSS custom properties work across shadow boundaries +- @theme customizations respect component isolation + +## 6. Performance Considerations + +### 6.1. Async Pipeline + +Since the plugin is async, component modules must use top-level await or async initialization: + +```javascript +// Top-level await (recommended) +export const MyComponent = defineComponent( + await TailwindPlugin(definition) +); + +// Or async factory pattern +export async function createMyComponent() { + return defineComponent(await TailwindPlugin(definition)); +} +``` + +### 6.2. Build-Time Optimization + +For production builds, the plugin transformation can be moved to build time: +- Pre-compile all component definitions +- Generate static CSS bundles +- Eliminate runtime WASM loading in browser + +## 7. Package Structure + +``` +@semantic-ui/tailwind/ +├── src/ +│ ├── browser.js # Browser-specific plugin (WASM) +│ ├── server.js # Server-specific plugin (Native) +│ └── extract-definition-content.js # Shared content extraction logic +├── types/ +│ └── index.d.ts # TypeScript definitions +└── package.json # Conditional exports + dependencies +``` + +### 7.1. Dependencies + +- **Runtime**: `tailwindcss-iso` (isomorphic Tailwind compiler) +- **Shared**: `@semantic-ui/component`, `@semantic-ui/utils` +- **Peer**: `tailwindcss` (for configuration and theme extensions) + +## 8. Usage Patterns + +### 8.1. Basic Component + +```javascript +let definition = { + tagName: 'ui-button', + template: '', + css: '@theme { --color-blue-500: #3b82f6; }' +}; + +definition = await TailwindPlugin(definition); +export const Button = defineComponent(definition); +``` + +### 8.2. Complex Component with Sub-templates + +```javascript +let definition = { + tagName: 'ui-card', + template: '
    {>header}{>body}
    ', + css: '@utility shadow-lg { box-shadow: 0 10px 15px rgba(0,0,0,0.1); }', + subTemplates: { + header: { + template: '
    ' + }, + body: { + template: '
    ' + } + } +}; + +definition = await TailwindPlugin(definition); +export const Card = defineComponent(definition); +``` + +This architecture provides a clean, performant, and flexible way to integrate Tailwind CSS with Semantic UI components while maintaining the framework's design principles. \ No newline at end of file diff --git a/packages/tailwind/LICENSE b/packages/tailwind/LICENSE new file mode 100644 index 000000000..4e9fe8f56 --- /dev/null +++ b/packages/tailwind/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2025, Jack Lukic + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/packages/tailwind/README.md b/packages/tailwind/README.md new file mode 100644 index 000000000..af5b39f65 --- /dev/null +++ b/packages/tailwind/README.md @@ -0,0 +1,62 @@ +# Semantic UI Tailwind Plugin + +A plugin for integrating Tailwind CSS with Semantic UI components. Automatically scans component definitions for Tailwind classes and generates the corresponding CSS for shadow DOM encapsulation. + +## Features + +* **Automatic Class Detection**: Scans templates, JavaScript functions, and CSS for Tailwind class usage +* **Shadow DOM Optimized**: Generates scoped CSS that works within web component shadow boundaries +* **Isomorphic**: Works in both Node.js and browser environments +* **@theme and @utility Support**: Full support for Tailwind's theme customization and custom utilities + +## Usage + +```javascript +import { defineComponent, getText } from '@semantic-ui/component'; +import { TailwindPlugin } from '@semantic-ui/tailwind'; + +const template = await getText('./button.html'); +const css = await getText('./button.css'); + +let definition = { + tagName: 'my-button', + template, + css, + defaultSettings: { + variant: 'primary' + } +}; + +// Transform definition to include generated Tailwind CSS +definition = await TailwindPlugin(definition); + +export const MyButton = defineComponent(definition); +``` + +### Template Example (button.html) +```html + +``` + +### CSS Example (button.css) +```css +@theme { + --color-blue-500: #3b82f6; + --color-blue-600: #2563eb; +} + +/* Custom utilities */ +@utility transition-colors { + transition-property: color, background-color, border-color; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} +``` + +The plugin will scan all content and generate the appropriate Tailwind CSS, replacing the component's CSS with the compiled output. + +## License + +[ISC](LICENSE) diff --git a/packages/tailwind/browser-wasm/tailwindcss_oxide.d.ts b/packages/tailwind/browser-wasm/tailwindcss_oxide.d.ts new file mode 100644 index 000000000..4f89e6fb0 --- /dev/null +++ b/packages/tailwind/browser-wasm/tailwindcss_oxide.d.ts @@ -0,0 +1,66 @@ +/* tslint:disable */ +/* eslint-disable */ +export function wasm_init(): void; +export class WasmCandidateWithPosition { + private constructor(); + free(): void; + readonly candidate: string; + readonly position: number; +} +export class WasmChangedContent { + free(): void; + constructor(content: string | null | undefined, extension: string); + readonly content: string | undefined; + readonly extension: string; +} +export class WasmScanner { + free(): void; + constructor(); + getCandidatesWithPositions(content: WasmChangedContent): WasmCandidateWithPosition[]; +} + +export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; + +export interface InitOutput { + readonly memory: WebAssembly.Memory; + readonly __wbg_wasmchangedcontent_free: (a: number, b: number) => void; + readonly wasmchangedcontent_new: (a: number, b: number, c: number, d: number) => number; + readonly wasmchangedcontent_content: (a: number) => [number, number]; + readonly wasmchangedcontent_extension: (a: number) => [number, number]; + readonly __wbg_wasmcandidatewithposition_free: (a: number, b: number) => void; + readonly wasmcandidatewithposition_candidate: (a: number) => [number, number]; + readonly wasmcandidatewithposition_position: (a: number) => number; + readonly __wbg_wasmscanner_free: (a: number, b: number) => void; + readonly wasmscanner_new: () => number; + readonly wasmscanner_getCandidatesWithPositions: (a: number, b: number) => [number, number]; + readonly wasm_init: () => void; + readonly __wbindgen_free: (a: number, b: number, c: number) => void; + readonly __wbindgen_malloc: (a: number, b: number) => number; + readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; + readonly __wbindgen_export_3: WebAssembly.Table; + readonly __externref_drop_slice: (a: number, b: number) => void; + readonly __wbindgen_start: () => void; +} + +export type SyncInitInput = BufferSource | WebAssembly.Module; +/** + * Instantiates the given `module`, which can either be bytes or + * a precompiled `WebAssembly.Module`. + * + * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated. + * + * @returns {InitOutput} + */ +export function initSync(module: { module: SyncInitInput; } | SyncInitInput): InitOutput; + +/** + * If `module_or_path` is {RequestInfo} or {URL}, makes a request and + * for everything else, calls `WebAssembly.instantiate` directly. + * + * @param {{ module_or_path: InitInput | Promise }} module_or_path - Passing `InitInput` directly is deprecated. + * + * @returns {Promise} + */ +export default function __wbg_init( + module_or_path?: { module_or_path: InitInput | Promise; } | InitInput | Promise, +): Promise; diff --git a/packages/tailwind/browser-wasm/tailwindcss_oxide.js b/packages/tailwind/browser-wasm/tailwindcss_oxide.js new file mode 100644 index 000000000..56d1c761f --- /dev/null +++ b/packages/tailwind/browser-wasm/tailwindcss_oxide.js @@ -0,0 +1,417 @@ +let wasm; + +const cachedTextDecoder = + (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { + decode: () => { + throw Error('TextDecoder not available'); + }, + }); + +if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); } + +let cachedUint8ArrayMemory0 = null; + +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8ArrayMemory0; +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); +} + +let WASM_VECTOR_LEN = 0; + +const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { + encode: () => { + throw Error('TextEncoder not available'); + }, +}); + +const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' + ? function(arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } + : function(arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length, + }; + }); + +function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8ArrayMemory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) { break; } + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +let cachedDataViewMemory0 = null; + +function getDataViewMemory0() { + if ( + cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true + || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer) + ) { + cachedDataViewMemory0 = new DataView(wasm.memory.buffer); + } + return cachedDataViewMemory0; +} + +export function wasm_init() { + wasm.wasm_init(); +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +function _assertClass(instance, klass) { + if (!(instance instanceof klass)) { + throw new Error(`expected instance of ${klass.name}`); + } +} + +function getArrayJsValueFromWasm0(ptr, len) { + ptr = ptr >>> 0; + const mem = getDataViewMemory0(); + const result = []; + for (let i = ptr; i < ptr + 4 * len; i += 4) { + result.push(wasm.__wbindgen_export_3.get(mem.getUint32(i, true))); + } + wasm.__externref_drop_slice(ptr, len); + return result; +} + +const WasmCandidateWithPositionFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_wasmcandidatewithposition_free(ptr >>> 0, 1)); + +export class WasmCandidateWithPosition { + static __wrap(ptr) { + ptr = ptr >>> 0; + const obj = Object.create(WasmCandidateWithPosition.prototype); + obj.__wbg_ptr = ptr; + WasmCandidateWithPositionFinalization.register(obj, obj.__wbg_ptr, obj); + return obj; + } + + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + WasmCandidateWithPositionFinalization.unregister(this); + return ptr; + } + + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_wasmcandidatewithposition_free(ptr, 0); + } + /** + * @returns {string} + */ + get candidate() { + let deferred1_0; + let deferred1_1; + try { + const ret = wasm.wasmcandidatewithposition_candidate(this.__wbg_ptr); + deferred1_0 = ret[0]; + deferred1_1 = ret[1]; + return getStringFromWasm0(ret[0], ret[1]); + } + finally { + wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); + } + } + /** + * @returns {number} + */ + get position() { + const ret = wasm.wasmcandidatewithposition_position(this.__wbg_ptr); + return ret >>> 0; + } +} + +const WasmChangedContentFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_wasmchangedcontent_free(ptr >>> 0, 1)); + +export class WasmChangedContent { + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + WasmChangedContentFinalization.unregister(this); + return ptr; + } + + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_wasmchangedcontent_free(ptr, 0); + } + /** + * @param {string | null | undefined} content + * @param {string} extension + */ + constructor(content, extension) { + var ptr0 = isLikeNone(content) ? 0 : passStringToWasm0(content, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + const ptr1 = passStringToWasm0(extension, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + const ret = wasm.wasmchangedcontent_new(ptr0, len0, ptr1, len1); + this.__wbg_ptr = ret >>> 0; + WasmChangedContentFinalization.register(this, this.__wbg_ptr, this); + return this; + } + /** + * @returns {string | undefined} + */ + get content() { + const ret = wasm.wasmchangedcontent_content(this.__wbg_ptr); + let v1; + if (ret[0] !== 0) { + v1 = getStringFromWasm0(ret[0], ret[1]).slice(); + wasm.__wbindgen_free(ret[0], ret[1] * 1, 1); + } + return v1; + } + /** + * @returns {string} + */ + get extension() { + let deferred1_0; + let deferred1_1; + try { + const ret = wasm.wasmchangedcontent_extension(this.__wbg_ptr); + deferred1_0 = ret[0]; + deferred1_1 = ret[1]; + return getStringFromWasm0(ret[0], ret[1]); + } + finally { + wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); + } + } +} + +const WasmScannerFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_wasmscanner_free(ptr >>> 0, 1)); + +export class WasmScanner { + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + WasmScannerFinalization.unregister(this); + return ptr; + } + + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_wasmscanner_free(ptr, 0); + } + constructor() { + const ret = wasm.wasmscanner_new(); + this.__wbg_ptr = ret >>> 0; + WasmScannerFinalization.register(this, this.__wbg_ptr, this); + return this; + } + /** + * @param {WasmChangedContent} content + * @returns {WasmCandidateWithPosition[]} + */ + getCandidatesWithPositions(content) { + _assertClass(content, WasmChangedContent); + var ptr0 = content.__destroy_into_raw(); + const ret = wasm.wasmscanner_getCandidatesWithPositions(this.__wbg_ptr, ptr0); + var v2 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice(); + wasm.__wbindgen_free(ret[0], ret[1] * 4, 4); + return v2; + } +} + +async function __wbg_load(module, imports) { + if (typeof Response === 'function' && module instanceof Response) { + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + } + catch (e) { + if (module.headers.get('Content-Type') != 'application/wasm') { + console.warn( + '`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n', + e, + ); + } + else { + throw e; + } + } + } + + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + } + else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + } + else { + return instance; + } + } +} + +function __wbg_get_imports() { + const imports = {}; + imports.wbg = {}; + imports.wbg.__wbg_error_7534b8e9a36f1ab4 = function(arg0, arg1) { + let deferred0_0; + let deferred0_1; + try { + deferred0_0 = arg0; + deferred0_1 = arg1; + console.error(getStringFromWasm0(arg0, arg1)); + } + finally { + wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); + } + }; + imports.wbg.__wbg_new_8a6f238a6ece86ea = function() { + const ret = new Error(); + return ret; + }; + imports.wbg.__wbg_stack_0ed75d68575b0f3c = function(arg0, arg1) { + const ret = arg1.stack; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }; + imports.wbg.__wbg_wasmcandidatewithposition_new = function(arg0) { + const ret = WasmCandidateWithPosition.__wrap(arg0); + return ret; + }; + imports.wbg.__wbindgen_init_externref_table = function() { + const table = wasm.__wbindgen_export_3; + const offset = table.grow(4); + table.set(0, undefined); + table.set(offset + 0, undefined); + table.set(offset + 1, null); + table.set(offset + 2, true); + table.set(offset + 3, false); + }; + imports.wbg.__wbindgen_throw = function(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }; + + return imports; +} + +function __wbg_init_memory(imports, memory) { +} + +function __wbg_finalize_init(instance, module) { + wasm = instance.exports; + __wbg_init.__wbindgen_wasm_module = module; + cachedDataViewMemory0 = null; + cachedUint8ArrayMemory0 = null; + + wasm.__wbindgen_start(); + return wasm; +} + +function initSync(module) { + if (wasm !== undefined) { return wasm; } + + if (typeof module !== 'undefined') { + if (Object.getPrototypeOf(module) === Object.prototype) { + ({ module } = module); + } + else { + console.warn('using deprecated parameters for `initSync()`; pass a single object instead'); + } + } + + const imports = __wbg_get_imports(); + + __wbg_init_memory(imports); + + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } + + const instance = new WebAssembly.Instance(module, imports); + + return __wbg_finalize_init(instance, module); +} + +async function __wbg_init(module_or_path) { + if (wasm !== undefined) { return wasm; } + + if (typeof module_or_path !== 'undefined') { + if (Object.getPrototypeOf(module_or_path) === Object.prototype) { + ({ module_or_path } = module_or_path); + } + else { + console.warn('using deprecated parameters for the initialization function; pass a single object instead'); + } + } + + if (typeof module_or_path === 'undefined') { + module_or_path = new URL('tailwindcss_oxide_bg.wasm', import.meta.url); + } + const imports = __wbg_get_imports(); + + if ( + typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) + || (typeof URL === 'function' && module_or_path instanceof URL) + ) { + module_or_path = fetch(module_or_path); + } + + __wbg_init_memory(imports); + + const { instance, module } = await __wbg_load(await module_or_path, imports); + + return __wbg_finalize_init(instance, module); +} + +export { initSync }; +export default __wbg_init; diff --git a/packages/tailwind/browser-wasm/tailwindcss_oxide_bg.wasm b/packages/tailwind/browser-wasm/tailwindcss_oxide_bg.wasm new file mode 100644 index 000000000..df1aca3ae Binary files /dev/null and b/packages/tailwind/browser-wasm/tailwindcss_oxide_bg.wasm differ diff --git a/packages/tailwind/browser-wasm/tailwindcss_oxide_bg.wasm.d.ts b/packages/tailwind/browser-wasm/tailwindcss_oxide_bg.wasm.d.ts new file mode 100644 index 000000000..50517fd15 --- /dev/null +++ b/packages/tailwind/browser-wasm/tailwindcss_oxide_bg.wasm.d.ts @@ -0,0 +1,20 @@ +/* tslint:disable */ +/* eslint-disable */ +export const memory: WebAssembly.Memory; +export const __wbg_wasmchangedcontent_free: (a: number, b: number) => void; +export const wasmchangedcontent_new: (a: number, b: number, c: number, d: number) => number; +export const wasmchangedcontent_content: (a: number) => [number, number]; +export const wasmchangedcontent_extension: (a: number) => [number, number]; +export const __wbg_wasmcandidatewithposition_free: (a: number, b: number) => void; +export const wasmcandidatewithposition_candidate: (a: number) => [number, number]; +export const wasmcandidatewithposition_position: (a: number) => number; +export const __wbg_wasmscanner_free: (a: number, b: number) => void; +export const wasmscanner_new: () => number; +export const wasmscanner_getCandidatesWithPositions: (a: number, b: number) => [number, number]; +export const wasm_init: () => void; +export const __wbindgen_free: (a: number, b: number, c: number) => void; +export const __wbindgen_malloc: (a: number, b: number) => number; +export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; +export const __wbindgen_export_3: WebAssembly.Table; +export const __externref_drop_slice: (a: number, b: number) => void; +export const __wbindgen_start: () => void; diff --git a/packages/tailwind/package.json b/packages/tailwind/package.json new file mode 100644 index 000000000..dfd54606f --- /dev/null +++ b/packages/tailwind/package.json @@ -0,0 +1,63 @@ +{ + "name": "@semantic-ui/tailwind", + "title": "Semantic UI Tailwind Plugin", + "description": "A plugin for integrating Tailwind CSS with Semantic UI components.", + "author": "Jack Lukic", + "license": "ISC", + "version": "0.11.2", + "sideEffects": false, + "type": "module", + "main": "src/server.js", + "module": "src/browser.js", + "types": "types/index.d.ts", + "exports": { + ".": { + "types": "./types/index.d.ts", + "browser": "./src/browser.js", + "node": "./src/server.js", + "default": "./src/server.js" + } + }, + "scripts": { + "build": "wireit", + "build:esm": "wireit", + "build:cdn": "wireit", + "test": "vitest" + }, + "files": [ + "src", + "dist", + "types", + "LICENSE" + ], + "peerDependencies": { + "tailwindcss": "^3.0.0 || ^4.0.0" + }, + "dependencies": { + "@semantic-ui/component": "^0.11.2", + "@semantic-ui/utils": "^0.11.2", + "tailwindcss-iso": "^1.0.0" + }, + "devDependencies": { + "@semantic-ui/internal-scripts": "^0.11.2", + "vitest": "^3.0.8" + }, + "wireit": { + "build": { + "dependencies": [ + "build:esm", + "build:bundle", + "build:cdn" + ] + }, + "build:esm": { + "command": "node ../../internal-packages/scripts/src/build-esm.js" + }, + "build:bundle": { + "command": "node ../../internal-packages/scripts/src/build-bundle.js" + }, + "build:cdn": { + "command": "node ../../internal-packages/scripts/src/build-cdn.js" + } + } +} diff --git a/packages/tailwind/src/browser.js b/packages/tailwind/src/browser.js new file mode 100644 index 000000000..ee748bf29 --- /dev/null +++ b/packages/tailwind/src/browser.js @@ -0,0 +1,31 @@ +import { generateTailwindCSS } from 'tailwindcss-iso/browser'; +import { extractDefinitionContent } from './extract-definition-content.js'; + +export async function TailwindPlugin(definition) { + // Collect all content and CSS from the component definition + const { content, css } = extractDefinitionContent(definition); + + // Quick check - if no content, return unchanged + if (!content.trim()) { + return definition; + } + + // Generate CSS using tailwindcss-iso browser implementation + const tailwindCSS = await generateTailwindCSS({ + content, + css, + }); + + // If no CSS was generated, return unchanged + if (!tailwindCSS.trim()) { + return definition; + } + + // Replace component CSS with Tailwind-enhanced version + return { + ...definition, + css: tailwindCSS, + }; +} + +export { extractDefinitionContent } from './extract-definition-content.js'; \ No newline at end of file diff --git a/packages/tailwind/src/extract-definition-content.js b/packages/tailwind/src/extract-definition-content.js new file mode 100644 index 000000000..086da2372 --- /dev/null +++ b/packages/tailwind/src/extract-definition-content.js @@ -0,0 +1,85 @@ +/** + * Scans component definition and collects all content for Tailwind class extraction + */ + +import { each, isFunction, isObject } from '@semantic-ui/utils'; + +export function extractDefinitionContent(definition) { + const htmlContent = []; + const jsContent = []; + const cssContent = []; + + // 1. Template HTML + if (definition.template) { + htmlContent.push(definition.template); + } + + // 1.5. Main component CSS + if (definition.css) { + cssContent.push(definition.css); + } + + // 2. createComponent function + if (isFunction(definition.createComponent)) { + jsContent.push(definition.createComponent.toString()); + } + + // 3. Lifecycle functions + if (isFunction(definition.onCreated)) { + jsContent.push(definition.onCreated.toString()); + } + if (isFunction(definition.onRendered)) { + jsContent.push(definition.onRendered.toString()); + } + if (isFunction(definition.onDestroyed)) { + jsContent.push(definition.onDestroyed.toString()); + } + if (isFunction(definition.onThemeChanged)) { + jsContent.push(definition.onThemeChanged.toString()); + } + if (isFunction(definition.onAttributeChanged)) { + jsContent.push(definition.onAttributeChanged.toString()); + } + + // 4. Events object - functions as values + if (isObject(definition.events)) { + each(definition.events, (eventHandler) => { + if (isFunction(eventHandler)) { + jsContent.push(eventHandler.toString()); + } + }); + } + + // 5. Keys object - functions as values + if (isObject(definition.keys)) { + each(definition.keys, (keyHandler) => { + if (isFunction(keyHandler)) { + jsContent.push(keyHandler.toString()); + } + }); + } + + // 6. SubTemplates - scan their HTML and CSS + if (isObject(definition.subTemplates)) { + each(definition.subTemplates, (subTemplate) => { + if (subTemplate.template) { + htmlContent.push(subTemplate.template); + } + if (subTemplate.css) { + cssContent.push(subTemplate.css); + } + }); + } + + const html = htmlContent.join('\n'); + const js = jsContent.join('\n'); + const css = cssContent.join('\n'); + const content = `${html}\n${js}`; + + return { + html, + js, + css, + content, + }; +} diff --git a/packages/tailwind/src/server.js b/packages/tailwind/src/server.js new file mode 100644 index 000000000..f4c508ac0 --- /dev/null +++ b/packages/tailwind/src/server.js @@ -0,0 +1,31 @@ +import { generateTailwindCSS } from 'tailwindcss-iso/server'; +import { extractDefinitionContent } from './extract-definition-content.js'; + +export async function TailwindPlugin(definition) { + // Collect all content and CSS from the component definition + const { content, css } = extractDefinitionContent(definition); + + // Quick check - if no content, return unchanged + if (!content.trim()) { + return definition; + } + + // Generate CSS using tailwindcss-iso server implementation + const tailwindCSS = await generateTailwindCSS({ + content, + css, + }); + + // If no CSS was generated, return unchanged + if (!tailwindCSS.trim()) { + return definition; + } + + // Replace component CSS with Tailwind-enhanced version + return { + ...definition, + css: tailwindCSS, + }; +} + +export { extractDefinitionContent } from './extract-definition-content.js'; \ No newline at end of file diff --git a/packages/tailwind/test/basic.test.js b/packages/tailwind/test/basic.test.js new file mode 100644 index 000000000..840f0e33c --- /dev/null +++ b/packages/tailwind/test/basic.test.js @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest'; +import { extractDefinitionContent } from '../src/extract-definition-content.js'; +import { TailwindPlugin as ServerPlugin } from '../src/server.js'; + +describe('Server-Side Tailwind Plugin (Native)', () => { + it('should generate CSS using the native Node.js implementation', async () => { + const definition = { + template: '
    ', + }; + + const result = await ServerPlugin(definition); + + // Verify that CSS was generated + expect(result.css).toBeDefined(); + expect(result.css).toContain('.p-4'); + expect(result.css).toContain('.bg-red-500'); + }); + + it('should return the original definition if no content is found', async () => { + const definition = { css: '.original {}' }; // No template or classes + const result = await ServerPlugin(definition); + expect(result).toEqual(definition); + }); +}); diff --git a/packages/tailwind/types/index.d.ts b/packages/tailwind/types/index.d.ts new file mode 100644 index 000000000..8606725ca --- /dev/null +++ b/packages/tailwind/types/index.d.ts @@ -0,0 +1,129 @@ +// Re-export useful types from dependencies +import type { DefineComponentOptions } from '@semantic-ui/component'; +import type { GenerateTailwindCSSOptions } from 'tailwindcss-iso'; + +/** + * Content extracted from a component definition for Tailwind class scanning + */ +export interface ExtractedContent { + /** Combined HTML content from templates */ + html: string; + /** Combined JavaScript content from functions */ + js: string; + /** Combined CSS content from component styles */ + css: string; + /** Combined HTML and JavaScript content for scanning */ + content: string; +} + +/** + * Semantic UI component definition that can be processed by TailwindPlugin. + * This is a subset of DefineComponentOptions that includes the properties + * that TailwindPlugin scans for Tailwind classes. + */ +export interface ComponentDefinition extends Partial> { + /** HTML template string */ + template?: string; + /** CSS styles string */ + css?: string; + /** Component creation function */ + createComponent?: Function; + /** Lifecycle callback functions */ + onCreated?: Function; + onRendered?: Function; + onDestroyed?: Function; + onThemeChanged?: Function; + onAttributeChanged?: Function; + /** Event handlers object */ + events?: Record; + /** Key binding handlers object */ + keys?: Record; + /** Sub-template definitions */ + subTemplates?: Record; +} + +/** + * Scans a Semantic UI component definition and extracts all content + * that may contain Tailwind classes for processing. + * + * This function comprehensively scans: + * - Template HTML strings + * - Component CSS styles + * - JavaScript function bodies (converted to strings) + * - Sub-template content recursively + * + * @param definition - The component definition to scan + * @returns Object containing extracted HTML, JS, CSS, and combined content + * + * @example + * ```javascript + * import { extractDefinitionContent } from '@semantic-ui/tailwind'; + * + * const definition = { + * tagName: 'my-button', + * template: '', + * css: '@theme { --color-blue-500: #3b82f6; }', + * createComponent: () => ({ click() { console.log('clicked'); } }) + * }; + * + * const { content, css } = extractDefinitionContent(definition); + * // content includes all scannable text + * // css includes the component CSS + * ``` + */ +export function extractDefinitionContent(definition: ComponentDefinition): ExtractedContent; + +/** + * Transforms a Semantic UI component definition by scanning it for Tailwind classes + * and generating the corresponding CSS to replace the component's existing CSS. + * + * This plugin: + * 1. Scans all component content for Tailwind class usage + * 2. Generates optimized CSS using the appropriate engine (WASM in browser, native in Node.js) + * 3. Replaces the component's CSS with the generated Tailwind CSS + * 4. Preserves all other component definition properties + * + * The generated CSS is optimized for shadow DOM and includes: + * - Tailwind utilities for detected classes + * - Component-specific @theme customizations + * - Custom @utility definitions + * - Existing component CSS integrated with Tailwind + * + * @param definition - The component definition to transform + * @param options - Optional Tailwind generation options + * @returns Promise that resolves to the transformed component definition + * + * @example + * ```javascript + * import { defineComponent, getText } from '@semantic-ui/component'; + * import { TailwindPlugin } from '@semantic-ui/tailwind'; + * + * let definition = { + * tagName: 'my-button', + * template: '', + * css: '@theme { --color-blue-500: #3b82f6; --color-blue-600: #2563eb; }', + * defaultSettings: { variant: 'primary' } + * }; + * + * // Transform the definition + * definition = await TailwindPlugin(definition); + * + * // CSS is now generated Tailwind utilities + * export const MyButton = defineComponent(definition); + * ``` + * + * @example + * ```javascript + * // With multiple plugins + * definition = await SomeOtherPlugin( + * await TailwindPlugin(definition) + * ); + * ``` + */ +export function TailwindPlugin( + definition: ComponentDefinition, + options?: Partial +): Promise; \ No newline at end of file diff --git a/packages/templating/LICENSE b/packages/templating/LICENSE index cb66593ce..654a7d134 100755 --- a/packages/templating/LICENSE +++ b/packages/templating/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2024 Jack Lukic +Copyright (c) 2025 Jack Lukic Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff --git a/packages/templating/src/compiler/template-compiler.js b/packages/templating/src/compiler/template-compiler.js index fff3d566b..a6361be69 100644 --- a/packages/templating/src/compiler/template-compiler.js +++ b/packages/templating/src/compiler/template-compiler.js @@ -417,7 +417,7 @@ class TemplateCompiler { type: 'html', html: '', }; - (contentBranch || ast).push(newNode); + (contentTarget || ast).push(newNode); break; } } diff --git a/packages/templating/src/template.js b/packages/templating/src/template.js index 5cd9054d3..1a793fa1c 100644 --- a/packages/templating/src/template.js +++ b/packages/templating/src/template.js @@ -60,6 +60,7 @@ export const Template = class Template { ast = compiler.compile(); } this.events = events; + this.observers = []; this.keys = keys || {}; this.ast = ast; this.css = css; @@ -136,7 +137,7 @@ export const Template = class Template { } removeParent() { - if(!this.parentTemplate?._childTemplates) { + if (!this.parentTemplate?._childTemplates) { return; } this.parentTemplate._childTemplates = this.parentTemplate._childTemplates.filter(template => { @@ -176,7 +177,7 @@ export const Template = class Template { this.call(this.onRenderedCallback); // allow a single hook for after render // this is used for binding events that cant use event delegation - if(isFunction(this.onRenderOnce)) { + if (isFunction(this.onRenderOnce)) { this.onRenderOnce(); delete this.onRenderOnce; } @@ -194,6 +195,7 @@ export const Template = class Template { this.destroyed = true; this.clearReactions(); this.removeEvents(); + this.removeObservers(); this.removeParent(); this.call(this.onDestroyedCallback); this.dispatchEvent('destroyed', { component: this.instance }, {}, { triggerCallback: false }); @@ -376,8 +378,17 @@ export const Template = class Template { // this.eventController = new AbortController(); - // This makes an assumption that a custom event will be emitted when a theme change occurs if (!Template.isServer && this.onThemeChangedCallback !== noop) { + // when the dark class is added or removed from + // we will fire theme changed + const observer = new MutationObserver(this.onThemeChanged); + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['class'], + }); + this.observers.push(observer); + + // we will also fire the handler if onThemeChanged occurs on html $('html').on('themechange', (event) => { this.onThemeChanged({ additionalData: { @@ -478,6 +489,12 @@ export const Template = class Template { } } + removeObservers() { + each(this.observers, (observer) => { + observer.disconnect(); + }); + } + bindKeys(keys = this.keys) { if (isServer) { return; diff --git a/packages/utils/LICENSE b/packages/utils/LICENSE index cb66593ce..654a7d134 100755 --- a/packages/utils/LICENSE +++ b/packages/utils/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2024 Jack Lukic +Copyright (c) 2025 Jack Lukic Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.