Repository: stitchesjs/stitches Branch: canary Commit: 50fd8a1adc63 Files: 180 Total size: 11.9 MB Directory structure: gitextract_6f0xewf7/ ├── .codesandbox/ │ └── ci.json ├── .editorconfig ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ └── workflows/ │ └── test.yml ├── .gitignore ├── .npmrc ├── .task/ │ ├── build-csstype.js │ ├── build.js │ ├── internal/ │ │ ├── child_process.js │ │ ├── color.js │ │ ├── dirs.js │ │ ├── expect.js │ │ ├── fs-test.js │ │ ├── fs.js │ │ ├── js.js │ │ ├── js.transformDestructuring.js │ │ ├── js.transformIIFE.js │ │ ├── js.transformModulesToCJS.js │ │ ├── js.transformOptionalCatchToParam.js │ │ ├── process.js │ │ ├── readline.js │ │ └── url.js │ ├── lint-esm.js │ ├── lint-pkg.js │ ├── lint-tsc.js │ ├── lint.js │ ├── release.js │ ├── test-coverage.js │ └── test.js ├── .vscode/ │ ├── package.schema.json │ └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── package.json ├── packages/ │ ├── core/ │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── ThemeToken.js │ │ │ ├── convert/ │ │ │ │ ├── toCamelCase.js │ │ │ │ ├── toCssRules.js │ │ │ │ ├── toHash.js │ │ │ │ ├── toHyphenCase.js │ │ │ │ ├── toPolyfilledValue.js │ │ │ │ ├── toResolvedMediaQueryRanges.js │ │ │ │ ├── toResolvedSelectors.js │ │ │ │ ├── toSizingValue.js │ │ │ │ ├── toTailDashed.js │ │ │ │ └── toTokenizedValue.js │ │ │ ├── createStitches.js │ │ │ ├── default/ │ │ │ │ └── defaultThemeMap.js │ │ │ ├── features/ │ │ │ │ ├── createTheme.js │ │ │ │ ├── css.js │ │ │ │ ├── globalCss.js │ │ │ │ └── keyframes.js │ │ │ ├── index.js │ │ │ ├── sheet.js │ │ │ └── utility/ │ │ │ ├── createMemo.js │ │ │ ├── define.js │ │ │ ├── getCachedConfig.js │ │ │ ├── getNonce.js │ │ │ ├── hasNames.js │ │ │ ├── hasOwn.js │ │ │ ├── index.d.ts │ │ │ └── internal.js │ │ ├── tests/ │ │ │ ├── basic.js │ │ │ ├── component-composition.js │ │ │ ├── component-conditions.js │ │ │ ├── component-css-prop.js │ │ │ ├── component-empty-variants.js │ │ │ ├── component-utils-and-types.js │ │ │ ├── component-variants.js │ │ │ ├── global-atrules.js │ │ │ ├── issue-450.js │ │ │ ├── issue-492.js │ │ │ ├── issue-652.js │ │ │ ├── issue-655.js │ │ │ ├── issue-725.js │ │ │ ├── issue-788.js │ │ │ ├── issue-908.js │ │ │ ├── issue-921.ts │ │ │ ├── issue-943.js │ │ │ ├── issue-999.js │ │ │ ├── keyframes.js │ │ │ ├── theme.js │ │ │ ├── types.test.ts │ │ │ ├── universal-autoprefixer.js │ │ │ ├── universal-functionality.js │ │ │ ├── universal-logical-properties.js │ │ │ ├── universal-nesting.js │ │ │ ├── universal-numeric-values.js │ │ │ ├── universal-polyfill-prefixed-values.js │ │ │ ├── universal-prefix.js │ │ │ ├── universal-serialization.js │ │ │ ├── universal-tokens.js │ │ │ ├── universal-with-typing.ts │ │ │ ├── utils.js │ │ │ └── with-config-api.js │ │ └── types/ │ │ ├── config.d.ts │ │ ├── css-util.d.ts │ │ ├── css.d.ts │ │ ├── index.d.ts │ │ ├── stitches.d.ts │ │ ├── styled-component.d.ts │ │ ├── theme.d.ts │ │ └── util.d.ts │ ├── react/ │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── createStitches.js │ │ │ ├── features/ │ │ │ │ └── styled.js │ │ │ ├── index.js │ │ │ └── utility/ │ │ │ └── getCachedConfig.js │ │ ├── tests/ │ │ │ ├── basic.js │ │ │ ├── component-as-props.js │ │ │ ├── component-className-prop.js │ │ │ ├── component-composition.js │ │ │ ├── component-css-prop-react.js │ │ │ ├── component-css-prop.js │ │ │ ├── component-repeated-variants.js │ │ │ ├── component-variants.js │ │ │ ├── component.js │ │ │ ├── issue-416.js │ │ │ ├── issue-450.js │ │ │ ├── issue-555.js │ │ │ ├── issue-671-forwardRef.js │ │ │ ├── issue-671.js │ │ │ ├── issue-737.js │ │ │ ├── issue-921.tsx │ │ │ ├── issue-943.js │ │ │ ├── react.js │ │ │ ├── types.test.tsx │ │ │ ├── universal-serialization.js │ │ │ ├── variants.js │ │ │ └── with-config-api.js │ │ └── types/ │ │ ├── config.d.ts │ │ ├── css-util.d.ts │ │ ├── css.d.ts │ │ ├── index.d.ts │ │ ├── stitches.d.ts │ │ ├── styled-component.d.ts │ │ ├── theme.d.ts │ │ └── util.d.ts │ ├── stringify/ │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── Array.js │ │ │ ├── getResolvedSelectors.js │ │ │ ├── index.js │ │ │ └── toCase.js │ │ ├── tests/ │ │ │ ├── at-rule-font-face.js │ │ │ ├── at-rule-import.js │ │ │ ├── at-rule-keyframes.js │ │ │ ├── index.js │ │ │ ├── internal-toCase.js │ │ │ ├── nesting-rules.js │ │ │ └── replacer-prefixing.js │ │ └── types/ │ │ └── index.d.ts │ └── test/ │ ├── .eslintrc │ ├── Issue-803-core.ts │ ├── Issue-803-react.ts │ ├── Issue-813-core.ts │ ├── Issue-813-react.ts │ ├── built-types/ │ │ ├── Issue-803-core.d.ts │ │ ├── Issue-803-react.d.ts │ │ ├── Issue-813-core.d.ts │ │ ├── Issue-813-react.d.ts │ │ ├── built-types-test.tsx │ │ ├── index.d.ts │ │ ├── issue-749-react.d.ts │ │ └── stitches.config.d.ts │ ├── index.tsx │ ├── issue-749-react.tsx │ ├── package.json │ ├── stitches.config.ts │ ├── traces/ │ │ ├── trace.json │ │ └── types.json │ └── tsconfig.json ├── tsconfig.json └── tslint.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .codesandbox/ci.json ================================================ { "node": "14", "packages": ["packages/core", "packages/react"], "sandboxes": ["7njqn", "2uwsq"] } ================================================ FILE: .editorconfig ================================================ root = true [*] end_of_line = lf insert_final_newline = true indent_style = tab trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false [*.{json,md,yml}] indent_size = 2 indent_style = space ================================================ FILE: .github/CODEOWNERS ================================================ # Learn how to add code owners here: # https://help.github.com/en/articles/about-code-owners * @jonathantneal @peduarte ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- # Bug report ## Describe the bug A clear and concise description of what the bug is. ## To Reproduce Steps to reproduce the behavior, please provide code snippets or a repository: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error ## Expected behavior A clear and concise description of what you expected to happen. ## Screenshots If applicable, add screenshots to help explain your problem. ## System information - OS: [e.g. macOS, Windows] - Browser (if applies) [e.g. chrome, safari] - Version of Stitches: [e.g. 0.0.2] - Version of Node.js: [e.g. 10.10.0] ## Additional context Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/workflows/test.yml ================================================ name: CI on: push jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: '16' - name: Install modules run: yarn - name: Run tests run: yarn test ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* es lib .DS_Store # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids package-lock.json yarn.lock *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage *.lcov # nyc test coverage .nyc_output # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ packages/*/utils/ # TypeScript v1 declaration files typings/ # TypeScript cache *.tsbuildinfo # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Microbundle cache .rpt2_cache/ .rts2_cache_cjs/ .rts2_cache_es/ .rts2_cache_umd/ # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env .env.test # parcel-bundler cache (https://parceljs.org/) .cache # Next.js build output .next # Nuxt.js build / generate output .nuxt dist # Gatsby files .cache/ # Comment in the public line in if your project uses Gatsby and *not* Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public # vuepress build output .vuepress/dist # Serverless directories .serverless/ # FuseBox cache .fusebox/ # DynamoDB Local files .dynamodb/ # TernJS port file .tern-port # IntelliJ .idea/ ================================================ FILE: .npmrc ================================================ package-lock = false save-exact = true ================================================ FILE: .task/build-csstype.js ================================================ import * as fs from './internal/fs.js' import URL from './internal/url.js' const rootUrl = URL.from(import.meta.url).to('../') const dtsOriginalURL = rootUrl.to('./node_modules/csstype/index.d.ts') const generateType = async (packageUrl) => { const dtsOriginalTxt = await fs.readFile(dtsOriginalURL, 'utf8') const dtsModifiedURL = packageUrl.to('types/css.d.ts') console.log(dtsModifiedURL.pathname) const dtsModifiedTxt = new ModifiedString(dtsOriginalTxt) .withoutVendorTyping .withCamelCasedColors .withAddedLicense .withAddedColorFunctions .withFixedColorScheme .withFixedFontFamily .withFixedMatchingSelector .withFixedNestingSelectors .withFixedProperties .withFixedPropertyAtRule .withFixedStretchValue .withFixedSystemColor .withoutBrowserComments .withoutImplicitGlobals .withoutPropertyValueTyping .withoutGenericTyping .withoutNarrowingPatch .withoutNeverInChain .withoutTrailingSpace .toString() await fs.writeFile(dtsModifiedURL, dtsModifiedTxt) } const generateTypes = async () => { await generateType(rootUrl.to('packages/core/')) await generateType(rootUrl.to('packages/react/')) } class ModifiedString extends String { replace(matcher, replacer) { replacer = typeof replacer === 'function' ? replacer : replacer return new ModifiedString(super.replace(matcher, replacer)) } // with get withAddedColorFunctions() { return this.replace( /"CurrentColor"/g, '"CurrentColor" | "hsl(" | "lab(" | "rgb("' ) } get withAddedLicense() { const licenseComment = `/** @license MIT License\n * Copyright (c) 2017-present, Fredrik Nicol\n * Copyright (c) 2021-present, Jonathan Neal\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the "Software"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */` return this.replace( /^/, `${licenseComment}\n\n` ) } get withCamelCasedColors() { const cssColorNames = ['AliceBlue', 'AntiqueWhite', 'Aqua', 'Aquamarine', 'Azure', 'Beige', 'Bisque', 'Black', 'BlanchedAlmond', 'Blue', 'BlueViolet', 'Brown', 'BurlyWood', 'CadetBlue', 'Chartreuse', 'Chocolate', 'Coral', 'CornflowerBlue', 'Cornsilk', 'CurrentColor', 'Crimson', 'Cyan', 'DarkBlue', 'DarkCyan', 'DarkGoldenRod', 'DarkGray', 'DarkGrey', 'DarkGreen', 'DarkKhaki', 'DarkMagenta', 'DarkOliveGreen', 'DarkOrange', 'DarkOrchid', 'DarkRed', 'DarkSalmon', 'DarkSeaGreen', 'DarkSlateBlue', 'DarkSlateGray', 'DarkSlateGrey', 'DarkTurquoise', 'DarkViolet', 'DeepPink', 'DeepSkyBlue', 'DimGray', 'DimGrey', 'DodgerBlue', 'FireBrick', 'FloralWhite', 'ForestGreen', 'Fuchsia', 'Gainsboro', 'GhostWhite', 'Gold', 'GoldenRod', 'Gray', 'Grey', 'Green', 'GreenYellow', 'HoneyDew', 'HotPink', 'IndianRed', 'Indigo', 'Ivory', 'Khaki', 'Lavender', 'LavenderBlush', 'LawnGreen', 'LemonChiffon', 'LightBlue', 'LightCoral', 'LightCyan', 'LightGoldenRodYellow', 'LightGray', 'LightGrey', 'LightGreen', 'LightPink', 'LightSalmon', 'LightSeaGreen', 'LightSkyBlue', 'LightSlateGray', 'LightSlateGrey', 'LightSteelBlue', 'LightYellow', 'Lime', 'LimeGreen', 'Linen', 'Magenta', 'Maroon', 'MediumAquaMarine', 'MediumBlue', 'MediumOrchid', 'MediumPurple', 'MediumSeaGreen', 'MediumSlateBlue', 'MediumSpringGreen', 'MediumTurquoise', 'MediumVioletRed', 'MidnightBlue', 'MintCream', 'MistyRose', 'Moccasin', 'NavajoWhite', 'Navy', 'OldLace', 'Olive', 'OliveDrab', 'Orange', 'OrangeRed', 'Orchid', 'PaleGoldenRod', 'PaleGreen', 'PaleTurquoise', 'PaleVioletRed', 'PapayaWhip', 'PeachPuff', 'Peru', 'Pink', 'Plum', 'PowderBlue', 'Purple', 'RebeccaPurple', 'Red', 'RosyBrown', 'RoyalBlue', 'SaddleBrown', 'Salmon', 'SandyBrown', 'SeaGreen', 'SeaShell', 'Sienna', 'Silver', 'SkyBlue', 'SlateBlue', 'SlateGray', 'SlateGrey', 'Snow', 'SpringGreen', 'SteelBlue', 'Tan', 'Teal', 'Thistle', 'Tomato', 'Turquoise', 'Violet', 'Wheat', 'White', 'WhiteSmoke', 'Yellow', 'YellowGreen'].reduce( (colors, UpperCamelCaseColorName) => Object.assign(colors, { [`"${UpperCamelCaseColorName.toLowerCase()}"`]: `"${UpperCamelCaseColorName}"`, }), Object.create(null), ) return this.replace( RegExp(Object.keys(cssColorNames).join('|'), 'ig'), $0 => cssColorNames[$0.toLowerCase()] ) } get withFixedColorScheme() { return this.replace( 'type ColorScheme = Globals | "dark" | "light" | "normal"', 'type ColorScheme = Globals | "dark" | "light" | "light dark" | "normal"' ) } get withFixedFontFamily() { return this.replace( 'type GenericFamily = "cursive" | "fantasy" | "monospace" | "sans-serif" | "serif"', 'type GenericFamily = "cursive" | "emoji" | "fangsong" | "fantasy" | "math" | "monospace" | "sans-serif" | "serif" | "system-ui" | "ui-monospace" | "ui-rounded" | "ui-sans-serif" | "ui-serif"' ) } get withFixedNestingSelectors() { return this.replace( /Pseudos =[\W\w]+?;/g, fragment => fragment.replace( /":/g, '"&:' ).replace( / \| "&:matches"\n/, '' ) ).replace( /AdvancedPseudos =[\W\w]+?;/g, fragment => fragment.replace( /"&[^"]+/g, '$&(' ) ) } get withFixedProperties() { return this.replace( 'type ZIndex = Globals | "auto" | (number & {})', 'type ZIndex = Globals | "auto" | (number & {}) | (string & {})' ).replace( 'type LetterSpacing = Globals | TLength | "normal"', 'type LetterSpacing = Globals | "normal" | (number & {}) | (string & {})' ).replace( /Property.LetterSpacing/g, 'Property.LetterSpacing' ).replace( 'FontWeightAbsolute = "bold" | "normal"', 'FontWeightAbsolute = "bold" | "normal" | (string & {})' ).replace( 'DataType.FontWeightAbsolute | (string & {})', 'DataType.FontWeightAbsolute' ).replace( 'FlexGrow = Globals | (number & {})', 'FlexGrow = Globals | (number & {}) | (string & {})' ) } get withFixedPropertyAtRule() { return this.replace( 'type Inherits = "false" | "true";', 'type Inherits = "false" | "true" | boolean;' ).replace( 'initialValue?: string;', 'initialValue?: boolean | number | string', ) } get withFixedMatchingSelector() { return this.replace( /matches\(\)/g, 'matches' ) } get withFixedStretchValue() { return this.replace( /(\n +\| +)?"fit-content"/g, ($0, $1) => $1 ? `${$1}"stretch"${$1}"fit-content"` : '"stretch" | "fit-content"' ) } get withFixedSystemColor() { return this.replace( /type DeprecatedSystemColor[^;]+;/, 'type DeprecatedSystemColor = "ActiveText" | "ButtonFace" | "ButtonText" | "ButtonBorder" | "Canvas" | "CanvasText" | "Field" | "FieldText" | "GrayText" | "Highlight" | "HighlightText" | "LinkText" | "Mark" | "MarkText" | "VisitedText"' ).replace( /DeprecatedSystemColor/g, 'SystemColor' ) } // without get withoutGenericTyping() { return this.replace( /\n? *(<(TLength|TTime)[^>]*>)|\| TTime|TTime \|/g, '' ).replace( /\| TLength/g, '| number' ).replace( /TLength \|/g, 'number |' ) } get withoutBrowserComments() { return this.replace( /(?<= )\* [-_|][\W\w]+?(?=\*\/)/g, '' ) } get withoutImplicitGlobals() { return this.replace( /\n?( +\| +)?(?\n\n' + 'export type OnlyNumber = number & OnlyObject\n\n' + 'export type OnlyString = string & OnlyObject\n\n' + 'export type OnlyStringNumeric = (number | string) & OnlyObject\n\n' + 'export namespace Property' ) } get withoutNeverInChain() { return this.replace( /(never \| | \| never)/g, '' ) } get withoutPropertyValueTyping() { return this.replace( /export type PropertyValue[\W\w]+?;/, '' ) } get withoutTrailingSpace() { return this.replace( /\n? +(?=\n)/g, '' ).replace( /\n{4,}/g, '\n\n\n' ) } get withoutVendorTyping() { return this.replace( /\nexport (interface|type) (Obsolete|Vendor)[^\n]+?\{\n[\W\w]+?\n\};?(?=\n)/g, '' ).replace( /\nexport interface (Obsolete|Vendor)[^\n]+?\>\n[\W\w]+?\{\};?(?=\n)/g, '' ).replace( /\nexport interface (Obsolete|Vendor)[^\n]+?{};?(?=\n)/g, '' ).replace( /\n (Obsolete|Vendor)[^\n]+?,(?=\n)/g, '' ).replace( /\n *\| *":*-[^"]+"/g, '' ).replace( '\n "-moz-font-feature-settings"?: FontFeatureSettings;', '' ).replace( /\n? *\| *"-[^"]+"/g, '' ).replace( /"-[^"]+" *\| *\n?/g, '' ).replace( /\n? *\| *"-[^\n]+(?=\n)/g, '' ).replace( /\n MozFontFeatureSettings?: FontFeatureSettings;/, '' ) } } generateTypes() ================================================ FILE: .task/build.js ================================================ import * as fs from './internal/fs.js' import * as js from './internal/js.js' import URL from './internal/url.js' import { box } from './internal/color.js' import { transformDestructuring } from './internal/js.transformDestructuring.js' import { transformModulesToCJS } from './internal/js.transformModulesToCJS.js' import { transformOptionalCatchToParam } from './internal/js.transformOptionalCatchToParam.js' import { transformIIFE } from './internal/js.transformIIFE.js' import { corePackageUrl, reactPackageUrl, stringifyPackageUrl } from './internal/dirs.js' import { isProcessMeta, getProcessArgOf } from './internal/process.js' import esbuild from 'esbuild' import nodemon from 'nodemon' import zlib from 'zlib' import { minify } from 'terser' const matchImports = /import\s*([\w*${}\n\r\t, ]+)from\s*["']([^"']+)["'];?/g const matchExports = /export\s*([\w*${}\n\r\t, ]+);?$/g const matchNamings = /[{,]?([$\w]+)(?:\s+as\s+(\w+))?/gy const variants = { esm: { extension: 'mjs', async transform(code, smap) { return await minify(code, { sourceMap: { content: smap }, compress: true, module: true, mangle: true, toplevel: true, }) }, }, cjs: { extension: 'cjs', async transform(code, smap) { let cjsast = js.parse(code) transformModulesToCJS(cjsast) transformOptionalCatchToParam(cjsast) transformDestructuring(cjsast) return await minify(cjsast.toString(), { sourceMap: { content: smap }, compress: true, module: true, mangle: true, toplevel: true, }) }, }, gjs: { extension: 'global.js', async transform(code, smap) { let cjsast = js.parse(code) transformIIFE(cjsast) return await minify(cjsast.toString(), { sourceMap: { content: smap }, compress: true, module: true, mangle: true, toplevel: true, }) }, }, } export const build = async (packageUrl, opts) => { opts = Object.assign({ only: [] }, opts) const initPackageUrl = new URL('src/', packageUrl) const distPackageUrl = new URL('dist/', packageUrl) const packageJsonUrl = new URL(`package.json`, packageUrl) const packageName = JSON.parse(await fs.readFile(packageJsonUrl, 'utf8')).name if (!opts.only.length || opts.only.includes(packageName)) { const targetPathname = new URL('index.js', initPackageUrl).pathname const outputPathname = new URL('index.js', distPackageUrl).pathname // Build ESM version let { outputFiles: [{ text: smap }, { text: code }], } = await esbuild.build({ entryPoints: [targetPathname], outfile: outputPathname, bundle: true, external: ['react'], format: 'esm', sourcemap: 'external', write: false, }) // ensure empty dist directory await fs.mkdir(distPackageUrl, { recursive: true }) // write map fs.writeFile(new URL(`index.map`, distPackageUrl), smap) // prepare variations const size = { name: packageName, types: {}, } // write variation builds for (const variant in variants) { const variantInfo = variants[variant] const variantPath = new URL(`dist/index.${variantInfo.extension}`, packageUrl).pathname let { code: variantCode } = await variantInfo.transform(code, smap) const variantMins = (Buffer.byteLength(variantCode) / 1000).toFixed(2) const variantGzip = Number(zlib.gzipSync(variantCode, { level: 9 }).length / 1000).toFixed(2) size.types[variant] = { min: variantMins, gzp: variantGzip, } await fs.writeFile(variantPath, variantCode + `\n//# sourceMappingUrl=index.map`) } console.log(box(size)) } } export const buildAll = async (opts) => { await build(stringifyPackageUrl, opts) await build(corePackageUrl, opts) await build(reactPackageUrl, opts) } if (isProcessMeta(import.meta)) { if (getProcessArgOf('watch').includes(true)) { let onlyArgs = getProcessArgOf('only') onlyArgs = onlyArgs.length ? ['--only', ...onlyArgs] : onlyArgs nodemon( [ '-q', `--watch packages/core/src`, `--watch packages/core/tests`, `--watch packages/core/types`, `--watch packages/react/src`, `--watch packages/react/tests`, `--watch packages/react/types`, `--watch packages/stringify/src`, `--watch packages/stringify/tests`, `--watch packages/stringify/types`, // exec `--exec "${['node', './.task/build.js', ...onlyArgs].join(' ')}"`, ].join(' '), ).on('start', () => { process.stdout.write('\u001b[3J\u001b[2J\u001b[1J') console.clear() }).on('quit', () => process.exit()) } else { buildAll({ only: getProcessArgOf('only'), }).catch((error) => { console.error(error) process.exitCode = 1 }) } } ================================================ FILE: .task/internal/child_process.js ================================================ import cp from 'child_process' import { rootUrl } from './dirs.js' export * from 'child_process' export const spawn = ( /** @type {string} */ exec, /** @type {readonly string[]} */ args = [], /** @type {cp.SpawnOptionsWithoutStdio} */ opts = {} ) => new Promise( (close, error) => { cp.spawn(exec, [].concat(args || []), { cwd: rootUrl.pathname, env: { ...process.env }, stdio: 'inherit', ...Object(opts) })._events = { close, error } } ) ================================================ FILE: .task/internal/color.js ================================================ const ansi = (id) => `\x1b[${id}m` const escape = (string) => string.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&') const ansiRe = RegExp(escape(ansi(0)), 'g') export const color = (string, id) => ansi(id) + string.replace(ansiRe, ansi(0) + ansi(id)) + ansi(0) export const bold = (string) => color(string, 1) export const dim = (string) => color(string, 2) export const underline = (string) => color(string, 4) export const invert = (string) => color(string, 7) export const black = (string) => color(string, 30) export const red = (string) => color(string, 31) export const green = (string) => color(string, 32) export const yellow = (string) => color(string, 33) export const blue = (string) => color(string, 34) export const magenta = (string) => color(string, 35) export const cyan = (string) => color(string, 36) export const white = (string) => color(string, 37) export const bgBlack = (string) => color(string, 40) export const bgRed = (string) => color(string, 41) export const bgGreen = (string) => color(string, 42) export const bgYellow = (string) => color(string, 43) export const bgBlue = (string) => color(string, 44) export const bgMagenta = (string) => color(string, 45) export const bgCyan = (string) => color(string, 46) export const bgWhite = (string) => color(string, 47) export const pad = (string, size = 0, char = ' ') => string.padStart((string.length + size) / 2, char).padEnd(size, char) export const box = ({ name, types }) => { const border = (text) => dim(cyan(text)) const v = border('│') const h = (size) => border(pad('', size, '┈')) const nameLead = pad('', 16 - name.length / 2) const nameTail = pad('', nameLead.length + name.length % 2) const nullLine = pad('', 32) const kb = (kb) => bold(green(kb.slice(0, -3))) + ' ' + dim(kb.slice(-2)) return [ border(`╭────────────────────────────────╮`), `${v}${nameLead}${bold(white(name))}${nameTail}${v}`, `${v}${nullLine}${v}`, ...Object.entries(types).map(([type, { min, gzp }]) => [ `${v} ${h(15 - type.length)} ${cyan(type)} ${h(15 - type.length - type.length % 2)} ${v}`, `${v} ${' '.repeat(3 - min.length % 2)}${kb(min + ' kB')}${' '.repeat(3)} ${border('╷')} ${' '.repeat(3 - gzp.length % 2)}${kb(gzp + ' kB')}${' '.repeat(3)} ${v}`, `${v} ${dim(cyan('minified'))} ${border('╵')} ${dim(cyan('gzipped'))} ${v}`, ].join('\n')), border(`╰────────────────────────────────╯`), ].join('\n') } export const passIcon = green('✔') export const failIcon = red('✖') export const passText = (text = 'PASS') => invert(green(bold(` ${text} `))) export const failText = (text = 'FAIL') => invert(red(bold(` ${text} `))) export const infoText = (text = 'INFO') => dim(text) ================================================ FILE: .task/internal/dirs.js ================================================ import process from 'node:process' import URL from './url.js' /** Root directory. */ export const rootUrl = new URL('../../', import.meta.url) /** Packages directory. */ export const packagesUrl = new URL('packages/', rootUrl) /** Core package directory. */ export const corePackageUrl = new URL('core/', packagesUrl) /** Core tests directory. */ export const coreTestsUrl = new URL('tests/', corePackageUrl) /** React package directory. */ export const reactPackageUrl = new URL('react/', packagesUrl) /** React tests directory. */ export const reactTestsUrl = new URL('tests/', reactPackageUrl) /** Stringify package directory */ export const stringifyPackageUrl = new URL('stringify/', packagesUrl) /** React tests directory. */ export const stringifyTestsUrl = new URL('tests/', stringifyPackageUrl) /** Current file href. */ export const argv1Url = new URL(process.argv[1], 'file:').href ================================================ FILE: .task/internal/expect.js ================================================ import { deepEqual as toEqual, equal as toBe, notDeepEqual as toNotEqual, notEqual as toNotBe } from 'node:assert/strict' export default function expect(actual) { return { /** Tests for strict equality between the actual and expected parameters. */ toBe: toBe.bind(this, actual), /** Tests that the actual object is an instance of the expected class. */ toBeInstanceOf: toBeInstanceOf.bind(this, actual), /** Tests for deep equality between the actual and expected parameters. */ toEqual: toEqual.bind(this, actual), /** Tests that the actual function does throw when it is called. */ toThrow: toThrow.bind(this, actual), /** Tests for strict inequality between the actual and expected parameters. */ toNotBe: toNotBe.bind(this, actual), /** Tests that the actual object is not an instance of the expected class. */ toNotBeInstanceOf: toNotBeInstanceOf.bind(this, actual), /** Tests for deep inequality between the actual and expected parameters. */ toNotEqual: toNotEqual.bind(this, actual), /** Tests that the actual function does not throw when it is called. */ toNotThrow: toNotThrow.bind(this, actual), } } /** Tests that the actual object is an instance of the expected class. */ function toBeInstanceOf(actual, expected) { if (!(actual instanceof expected)) { throw new AssertionError({ message: 'Expected value to be instance:', operator: 'instanceOf', actual, expected, stackStartFn: toBeInstanceOf, }) } } /** Tests that the actual object is not an instance of the expected class. */ function toNotBeInstanceOf(actual, expected) { if (actual instanceof expected) { throw new AssertionError({ message: 'Expected value to be instance:', operator: 'instanceOf', actual, expected, stackStartFn: toNotBeInstanceOf, }) } } /** Tests that the actual function does throw when it is called. */ async function toThrow(actualFunction, expected) { let actual = undefined try { actual = await actualFunction() } catch (error) { // do nothing and continue return } throw new AssertionError({ message: 'Expected exception:', operator: 'throws', stackStartFn: toThrow, actual, expected, }) } /** Tests that the actual function does not throw when it is called. */ async function toNotThrow(actualFunction, expected) { let actual = undefined try { actual = await actualFunction() // do nothing and continue return } catch (error) { throw new AssertionError({ message: 'Unexpected exception:', operator: 'doesNotThrow', stackStartFn: toThrow, actual, expected, }) } } ================================================ FILE: .task/internal/fs-test.js ================================================ import * as fs from './fs.js' let source = new URL('./test-source/', import.meta.url) let target = new URL('./test-target/', import.meta.url) fs.copydir(source, target) ================================================ FILE: .task/internal/fs.js ================================================ import fs from 'fs/promises' import { copyFile, mkdir, readdir } from 'fs/promises' import URL from './url.js' export * from 'fs/promises' export { existsSync as exists } from 'fs' /** Asynchronously copies dir to dest. By default, dest is overwritten if it already exists. */ export const copydir = async function copydir(src, dst) { let copydir = async (src, dst) => { await mkdir(dst, { recursive: true }) for (const dirent of await readdir(src, { withFileTypes: true })) { await (dirent.isDirectory() ? copydir : copyFile)( src.dir.to(dirent.name), dst.dir.to(dirent.name) ) } } copydir(URL.from(src), URL.from(dst)) } /** Asynchronously reads a file as parsed JSON. */ export const readFileJson = { async readFileJson(/** @type {import('fs').PathLike | fs.FileHandle} */ path) { const json = await fs.readFile(path, 'utf8') /** @type {JSONValue} */ const data = JSON.parse(json) return data } }.readFileJson fs.copydir = copydir fs.readFileJson = readFileJson /** @typedef { string | number | boolean | null | JSONArray | JSONObject } JSONValue */ /** @typedef { JSONValue[] } JSONArray */ /** @typedef {{ [k: string]: JSONValue }} JSONObject */ export default fs ================================================ FILE: .task/internal/js.js ================================================ import { generate } from 'astring' import { importAssertions } from 'acorn-import-assertions' import { Node, Parser } from 'acorn' import acornClassFields from 'acorn-class-fields' import acornJsx from 'acorn-jsx' import acornLogicalAssignment from 'acorn-logical-assignment' import acornPrivateMethods from 'acorn-private-methods' let acornPlugins = [ acornJsx({ allowNamespaces: true, allowNamespacedObjects: true }), acornClassFields, acornLogicalAssignment, acornPrivateMethods, importAssertions ] let prototype = Node.prototype let parser = Parser.extend(...acornPlugins) export let parse = (code) => { let parsed = parser.parse(code, { sourceType: 'module', ecmaVersion: 'latest' }) return parsed } export let stringify = (ast) => generate(ast) let defaultProps = { ArrowFunctionExpression: { expression: false, generator: false, async: false, params: [], body: null, }, AssignmentExpression: { operator: '=', left: null, right: null, }, BlockStatement: { body: [], }, CallExpression: { callee: null, arguments: [], optional: false, }, CatchClause: { param: null, body: { type: 'BlockStatement', body: [] } }, ExportNamedDeclaration: { declaration: null, specifiers: [] }, ExportSpecifier: { local: null, exported: null, }, ExpressionStatement: { expression: { operator: '=', left: null, right: null, }, }, Identifier: { name: '_' }, ImportDefaultSpecifier: { local: null }, ImportDeclaration: { specifiers: [], source: null, }, Literal: { value: '_', raw: '\'_\'', optional: false, }, MemberExpression: { object: null, property: null, computed: false, optional: false, }, ObjectExpression: { properties: [], }, ObjectPattern: { properties: [], }, Program: { body: [], }, Property: { method: false, shorthand: false, computed: false, key: null, value: null, kind: 'init', }, RestElement: { argument: null, }, ReturnStatement: { argument: null, }, TryStatement: { block: null, handler: null, finalizer: null, }, VariableDeclaration: { declarations: [], kind: 'var', }, VariableDeclarator: { id: null, init: { type: 'CallExpression', callee: null, arguments: [], } }, } let createNode = (...props) => Object.assign(Object.create(prototype), ...props) export let create = (type, props) => createNode({ type }, defaultProps[type], props) export let ArrowFunctionExpression = (props) => create('ArrowFunctionExpression', props) export let AssignmentExpression = (props) => create('AssignmentExpression', props) export let BlockStatement = (props) => create('BlockStatement', props) export let CallExpression = (props) => create('CallExpression', props) export let CatchClause = (props) => create('CatchClause', props) export let ExportNamedDeclaration = (props) => create('ExportNamedDeclaration', props) export let ExportSpecifier = (props) => create('ExportSpecifierExportSpecifier', props) export let ExpressionStatement = (props) => create('ExpressionStatement', props) export let Identifier = (props) => create('Identifier', props) export let ImportDeclaration = (props) => create('ImportDeclaration', props) export let ImportDefaultSpecifier = (props) => create('ImportDefaultSpecifier', props) export let Literal = (props) => create('Literal', props) export let MemberExpression = (props) => create('MemberExpression', props) export let ObjectExpression = (props) => create('ObjectExpression', props) export let Program = (props) => create('Program', props) export let Property = (props) => create('Property', props) export let ReturnStatement = (props) => create('ReturnStatement', props) export let TryStatement = (props) => create('TryStatement', props) export let VariableDeclaration = (props) => create('VariableDeclaration', props) export let VariableDeclarator = (props) => create('VariableDeclarator', props) export let parents = new WeakMap() let createPrototypeOf = (value) => value == null ? value : Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value)) Object.defineProperties(prototype, { clone: { value: { clone(overrides) { let process = (object) => { let clone = createPrototypeOf(object) for (let name of Object.keys(object)) { if (object[name] instanceof Object) { clone[name] = process(object[name]) parents.set(clone[name], [name, clone]) } else { clone[name] = object[name] } } return clone } return Object.assign(process(this), overrides) } }.clone, configurable: true, writable: true, }, find: { value: { find(type, call) { let find = (object) => { if (object.type === type) call(object) for (let name of Object.keys(object)) { if (object[name] instanceof Object) { parents.set(object[name], [name, object]) find(object[name]) } } } find(this) } }.find, configurable: true, writable: true, }, parent: { get: { parent() { return (parents.get(this) || [])[1] || null }, }.parent, configurable: true, }, parentNode: { get: { parentNode() { let object = this while (true) { object = parentOf(object) if (object == null) return null if (object instanceof Array) continue return object } }, }.parentNode, configurable: true, }, keyOfParent: { get: { keyOfParent() { return (parents.get(this) || [])[0] || null } }.keyOfParent, configurable: true, }, keyOfParentNode: { get: { keyOfParentNode() { let object = this, key while (true) { key = keyOfParent(object) object = parentOf(object) if (object == null) return null if (Array.isArray(object)) continue return key } }, }.keyOfParentNode, configurable: true, }, remove: { value: { remove() { return this.replaceWith() } }.remove, configurable: true, writable: true, }, replaceWith: { value: { replaceWith(...nodes) { let [name, node] = parents.get(this) || [] if (!node) return if (Array.isArray(node)) { node.splice(name, 1, ...nodes) } else { node[name] = Array.isArray(node[name]) || nodes.length > 1 ? nodes : nodes[0] || null } } }.replaceWith, configurable: true, writable: true, }, toString: { value: { toString() { return stringify(this) }, }.toString, configurable: true, writable: true, }, }) export let keyOfParent = (object) => (parents.get(object) || [])[0] || null export let parentOf = (object) => (parents.get(object) || [])[1] || null export let find = (node, type, next) => { if (node.type === type) { if (next) next(node) else return node } for (let name in node) { if (name === 'type') continue let data = node[name] if (Array.isArray(data)) { parents.set(data, this) for (let each of data) { if (each instanceof Node) { parents.set(each, data) let deep = find(each, type, next) if (deep && !next) return deep } } } else if (data instanceof Node) { parents.set(data, this) let deep = find(data, type, next) if (deep && !next) return deep } } return null } ================================================ FILE: .task/internal/js.transformDestructuring.js ================================================ import * as js from './js.js' export let transformDestructuring = (ast) => { // replace destructuring ast.find('ObjectPattern', (objectPattern) => { if (objectPattern.keyOfParentNode === 'params') { let { parentNode } = objectPattern if ( parentNode.body.type !== 'BlockStatement' ) { parentNode.body.replaceWith( js.BlockStatement({ body: [ js.ReturnStatement({ argument: parentNode.body }) ] }) ) } let argName = `_arg${objectPattern.keyOfParent}` objectPattern.replaceWith( js.Identifier({ name: argName }) ) parentNode.body.body.unshift( js.VariableDeclaration({ kind: 'let', declarations: [ js.VariableDeclarator({ id: objectPattern, init: js.Identifier({ name: argName }), }) ] }) ) } }) return ast } ================================================ FILE: .task/internal/js.transformIIFE.js ================================================ import * as js from './js.js' export let transformIIFE = (ast) => { ast.body = [ js.ExpressionStatement({ expression: js.AssignmentExpression({ left: js.Identifier({ name: 'stitches' }), right: js.CallExpression({ callee: js.ArrowFunctionExpression({ body: js.BlockStatement({ body: ast.body }) }) }) }) }) ] // remove imports ast.find('ImportDeclaration', (importDeclaration) => { importDeclaration.remove() }) // change exports to returns ast.find('ExportNamedDeclaration', (exportNamedDeclaration) => { exportNamedDeclaration.replaceWith( js.ReturnStatement({ argument: js.ObjectExpression({ properties: exportNamedDeclaration.specifiers.map( (exportSpecifier) => js.Property({ key: exportSpecifier.exported, value: exportSpecifier.local, }) ) }) }) ) }) return ast } ================================================ FILE: .task/internal/js.transformModulesToCJS.js ================================================ import * as js from './js.js' export let transformModulesToCJS = (ast) => { // replace exports ast.find('ExportNamedDeclaration', (exportNamedDeclaration) => { let expressionStatement = js.ExpressionStatement({ expression: js.AssignmentExpression({ left: js.MemberExpression({ object: js.Identifier({ name: 'module' }), property: js.Identifier({ name: 'exports' }) }), right: js.ObjectExpression({ properties: [], }), }) }) exportNamedDeclaration.find('ExportSpecifier', (exportSpecifier) => { expressionStatement.expression.right.properties.push( js.create('Property', { key: js.create('Identifier', { name: exportSpecifier.exported.name }), value: js.create('Identifier', { name: exportSpecifier.local.name }), }) ) }) exportNamedDeclaration.replaceWith(expressionStatement) }) // replace imports ast.find('ImportDeclaration', (importDeclaration) => { let variableDeclaration = js.VariableDeclaration({ declarations: [ js.VariableDeclarator({ id: js.Identifier({ name: importDeclaration.specifiers[0].local.name }), init: js.CallExpression({ callee: js.Identifier({ name: 'require' }), arguments: [ importDeclaration.source, ], }), }) ] }) importDeclaration.replaceWith(variableDeclaration) }) return ast } ================================================ FILE: .task/internal/js.transformOptionalCatchToParam.js ================================================ import * as js from './js.js' export let transformOptionalCatchToParam = (ast) => { // replace optional catch ast.find('CatchClause', (catchClause) => { if (catchClause.param === null) { catchClause.param = js.Identifier({ name: 'e' }) } }) return ast } ================================================ FILE: .task/internal/process.js ================================================ import URL from './url.js' const { argv: [, file, ...argv], } = process /** Returns whether the import.meta matches the current process. */ export const isProcessMeta = (meta) => new URL(meta.url).href === URL.from(file).href /** Returns the values for a given process argument. */ export const getProcessArgOf = (name) => { const lead = argv.indexOf('--' + name) + 1 const tail = lead ? argv.slice(lead).findIndex((arg) => arg.startsWith('--')) : 0 const vals = lead ? argv.slice(lead, ~tail ? lead + tail : argv.length) : [] return lead ? (vals.length ? vals : [true]) : vals } ================================================ FILE: .task/internal/readline.js ================================================ import * as readline from 'readline' export * from 'readline' /** Displays the query, awaits user input, and returns the provided input. */ export const question = ( /** @type {string} */ query, /** @type {import('events').Abortable} */ opts = undefined ) => new Promise(resolver => { query = String(query).replace(/[^\s]$/, '$& ') opts = Object(opts) const int = readline.createInterface({ input: process.stdin, output: process.stdout, }) int.question(query, opts, answer => { int.close() resolver(answer) }) }) ================================================ FILE: .task/internal/url.js ================================================ import { fileURLToPath, pathToFileURL } from 'url'; export default class URL extends globalThis.URL { to(/** @type {string[]} */ ...segments) { return segments.reduce((/** @type URL */ url, segment) => new URL(segment, url), this) } includes(/** @type {string} */ searchString, position = 0) { return this.href.includes(searchString, position) } endsWith(/** @type {string} */ searchString, length = this.href.length) { return this.href.endsWith(searchString, length) } get dir() { return new URL(this.href + '/') } get ospathname() { return fileURLToPath(this) } static from(/** @type {string | globalThis.URL} */ segment, /** @type {string[]} */ ...segments) { return ( /^file:/.test(segment) ? new URL(segment) : new URL(pathToFileURL(segment)) ).to(...segments) } } ================================================ FILE: .task/lint-esm.js ================================================ import fs from './internal/fs.js' import { bold, underline } from './internal/color.js' import { corePackageUrl, reactPackageUrl, stringifyPackageUrl } from './internal/dirs.js' import { isProcessMeta, getProcessArgOf } from './internal/process.js' import { ESLint } from 'eslint' export const lint = async (packageUrl, opts) => { opts = Object.assign({ only: [] }, opts) const packageJsonUrl = new URL(`package.json`, packageUrl) const packageName = JSON.parse(await fs.readFile(packageJsonUrl, 'utf8')).name const packageTsUrl = new URL(`types/index.d.ts`, packageUrl) if (!opts.only.length || opts.only.includes(packageName)) { console.log(underline(bold(packageName))) console.log(packageTsUrl.pathname) const eslint = new ESLint() const results = await eslint.lintFiles([packageTsUrl.pathname]) const formatter = await eslint.loadFormatter('stylish') const resultText = formatter.format(results) if (resultText) console.log(resultText) else console.log('\x1b[32m✔\x1b[0m', 'Your code is flawless.', 'Hopefully this determination is flawless, too.') } } export const lintAll = async (opts) => { await lint(stringifyPackageUrl, opts) await lint(corePackageUrl, opts) await lint(reactPackageUrl, opts) } if (isProcessMeta(import.meta)) { lintAll({ only: getProcessArgOf('only'), }).catch((error) => { console.error(error) process.exitCode = 1 }) } ================================================ FILE: .task/lint-pkg.js ================================================ import fs from './internal/fs.js' import { bold, underline } from './internal/color.js' import { isProcessMeta, getProcessArgOf } from './internal/process.js' import { corePackageUrl, reactPackageUrl, stringifyPackageUrl } from './internal/dirs.js' import * as cp from './internal/child_process.js' export const lint = async (packageUrl, opts) => { opts = Object.assign({ only: [] }, opts) const packageJsonUrl = new URL(`package.json`, packageUrl) const packageName = JSON.parse(await fs.readFile(packageJsonUrl, 'utf8')).name if (!opts.only.length || opts.only.includes(packageName)) { console.log(underline(bold(packageName))) await cp.spawn('./node_modules/.bin/package-check', ['--cwd', packageUrl.pathname]) } } export const lintAll = async (opts) => { await lint(stringifyPackageUrl, opts) await lint(corePackageUrl, opts) await lint(reactPackageUrl, opts) } if (isProcessMeta(import.meta)) { lintAll({ only: getProcessArgOf('only'), }).catch((error) => { console.error(error) process.exitCode = 1 }) } ================================================ FILE: .task/lint-tsc.js ================================================ import fs from './internal/fs.js' import { bold, underline } from './internal/color.js' import { corePackageUrl, reactPackageUrl, stringifyPackageUrl } from './internal/dirs.js' import { isProcessMeta, getProcessArgOf } from './internal/process.js' import * as cp from './internal/child_process.js' export const lint = async (packageUrl, opts) => { opts = Object.assign({ only: [] }, opts) const packageJsonUrl = new URL(`package.json`, packageUrl) const packageName = JSON.parse(await fs.readFile(packageJsonUrl, 'utf8')).name const packageTsUrl = new URL(`types/index.d.ts`, packageUrl) if (!opts.only.length || opts.only.includes(packageName)) { console.log(underline(bold(packageName))) console.log(packageTsUrl.pathname) await cp.spawn('./node_modules/.bin/tsc', ['--noEmit', '--skipLibCheck', packageTsUrl.pathname]) } } export const lintAll = async (opts) => { await lint(stringifyPackageUrl, opts) await lint(corePackageUrl, opts) await lint(reactPackageUrl, opts) } if (isProcessMeta(import.meta)) { lintAll({ only: getProcessArgOf('only'), }).catch((error) => { console.error(error) process.exitCode = 1 }) } ================================================ FILE: .task/lint.js ================================================ import { isProcessMeta, getProcessArgOf } from './internal/process.js' import { lintAll as lintAllEsm } from './lint-esm.js' import { lintAll as lintAllPkg } from './lint-pkg.js' import { lintAll as lintAllTsc } from './lint-tsc.js' export const lintAll = async (opts) => { await lintAllEsm(opts) await lintAllTsc(opts) await lintAllPkg(opts) } if (isProcessMeta(import.meta)) { lintAll({ only: getProcessArgOf('only'), }).catch((error) => { console.error(error) process.exitCode = 1 }) } ================================================ FILE: .task/release.js ================================================ import URL from './internal/url.js' import * as co from './internal/color.js' import * as cp from './internal/child_process.js' import * as fs from './internal/fs.js' import * as rl from './internal/readline.js' const main = async () => { const root = URL.from(import.meta.url).to('../') const pkg = await fs.readFileJson(root.to('package.json'), 'utf8') const state = {} const q1option = new Set(['major', 'minor', 'patch', 'prerelease']) state.release = await rl.question(`Release Type ${co.dim('(major, minor, patch, prerelease)')}:`) state.npmtag = state.release === 'prerelease' ? 'canary' : 'latest' if (!q1option.has(state.release)) return await cp.spawn('npm', ['version', state.release, '--workspaces'], { stdio: 'pipe' }) const workspacepkgpaths = new Set const workspacetags = new Set for (let workspace of pkg.workspaces) { workspace = root.to(workspace).dir const workspacepkgpath = workspace.to('package.json') const workspacepkg = await fs.readFileJson(workspacepkgpath) state.version = `v${workspacepkg.version}` workspacepkgpaths.add(workspacepkgpath) workspacetags.add(`${workspacepkg.name}@${workspacepkg.version}`) } console.log(`Bumped ${co.bold(state.version)}`) const confirm = await rl.question(`Publish ${co.bold(state.version)} as ${co.bold(state.npmtag)} ${co.dim('(y/n)')}:`) if (confirm !== 'y') { for (const workspacepkgpath of workspacepkgpaths) { await cp.spawn('git', ['checkout', '--', workspacepkgpath.ospathname]) } return } await cp.spawn('npm', ['run', 'build'], { stdio: 'ignore' }) state.otp = await rl.question(`OTP:`) if (!state.otp) return for (const workspacepkgpath of workspacepkgpaths) { await cp.spawn('git', ['add', workspacepkgpath.ospathname]) } await cp.spawn('git', ['commit', '-m', state.version]) await cp.spawn('git', ['tag', state.version]) await cp.spawn('git', ['push']) await cp.spawn('git', ['push', '--tags']) await cp.spawn('npm', ['publish', '--tag', state.npmtag, '--workspaces', '--otp', state.otp]) } main() ================================================ FILE: .task/test-coverage.js ================================================ import * as cp from './internal/child_process.js' import * as fp from 'path' import * as fs from './internal/fs.js' import * as os from 'os' import { bold, dim, green, red } from './internal/color.js' // Creates a unique temporary directory !(async () => { /** Directory storing code coverage. */ const NODE_V8_COVERAGE = await fs.mkdtemp(os.tmpdir()) /** Exit code from the covered NodeJS process. */ await new Promise((close, error) => { cp.spawn('node', process.argv.slice(2), { stdio: 'inherit', env: { ...process.env, NODE_V8_COVERAGE }, })._events = { close, error } }) /** Combined coverage results */ const results = [] for (const filename of await fs.readdir(NODE_V8_COVERAGE)) { results.push(...JSON.parse(await fs.readFile(fp.join(NODE_V8_COVERAGE, filename), 'utf8')).result) } await fs.rmdir(NODE_V8_COVERAGE, { recursive: true }) /** Combined LCOV results. */ let lcovList = [] /** Combined LCOV results. */ let lcovInfo = '' /** Filter for filtered results */ const filter = (url) => !url.protocol.startsWith('node') && !url.pathname.includes('/node_modules/') && url.pathname.includes('/src/') for (let result of results) { /** URL classed result URL */ const url = new URL(result.url) if (filter(url)) { /** Contents of the file whose coverage was collected. */ const data = await fs.readFile(url, 'utf8') /** List of code lines, where the line of code is a `data` property on the object. */ const rows = data.split(/^/gm).map((line) => ({ data: line })) const lcov = { /** Test name */ TN: [''], /** Source file */ SF: [url.pathname], /** Line numbers for each function name. */ FN: [], /** Execution count for the given function.*/ FNDA: [], /** Number of functions found. */ FNF: [0], /** Number of functions hit. */ FNH: [0], /** Execution count for the given line. */ DA: [], /** Number of collected lines with a positive execution count. */ LH: [0], /** Number of collected lines. */ LF: [0], } lcovList.push(lcov) /** Convert */ const convert = (range, isFirstRun) => { let lineOffset = 0 for (const lineIndex in rows) { const nextLineOffset = lineOffset + rows[lineIndex].data.length if (range.startLine == null && range.startOffset >= lineOffset && range.startOffset < nextLineOffset) { range.startLine = Number(lineIndex) + 1 range.startCol = range.startOffset - lineOffset + 1 } if (range.endOffset >= lineOffset && range.endOffset < nextLineOffset) { range.endLine = Number(lineIndex) + 1 range.endCol = range.endOffset - lineOffset + 1 if (!isFirstRun) { for (let j = range.startLine; j <= range.endLine; ++j) { if (rows[j]) { if (!range.count) { rows[j].exec = 0 } else if (rows[j].exec == null) { rows[j].exec = range.count } else if (rows[j].exec > 0) { rows[j].exec += range.count } } } } break } lineOffset = nextLineOffset } return range } for (const coverage of result.functions) { let startRange = convert(coverage.ranges[0], true) let count = 0 ++lcov.FNF[0] lcov.FN.push([startRange.startLine, coverage.functionName]) for (const range of coverage.ranges) { count += convert(range).count } lcov.FNDA.push([count, coverage.functionName]) if (count) ++lcov.FNH[0] } for (const line in rows) { ++lcov.LF[0] if ('exec' in rows[line]) { lcov.DA.push([line, rows[line].exec]) if (rows[line].exec) ++lcov.LH[0] } } lcovInfo += `${Object.entries(lcov).reduce((report, [name, data]) => report.concat(data.reduce((string, each) => string.concat(`${name.toUpperCase()}:${each}\n`), '')), '')}end_of_record\n` } } fs.writeFile('coverage/lcov.info', lcovInfo) /** Returns a unicode meter based on LCOV coverage. */ const meter = (lcov) => { const per = (lcov.FNH[0] / lcov.FNF[0]) * 100 const sol = Math.trunc(per / 10) const haf = per % 10 >= 5 ? 1 : 0 const emt = 10 - sol - haf return [`▰`.repeat(sol), `▱`.repeat(haf), dim(`▱`.repeat(emt))].join('') } /** Returns the ratio of 2 fields in LCOV data. */ const ratio = (lcov, l, r) => `${lcov[l]}${dim('/')}${lcov[r]}`.padStart(17) /** Based on the given LCOV data, returns the given data in a shade of green or red. */ const shade = (lcov, data) => (lcov.FNH / lcov.FNF > 0.6 ? green : red)(data) const trtd = (lcov) => dim('│ ') + shade( lcov, lcov.SF[0] .slice(-31) .replace(/^[^/]*\//, '') .padEnd(31, ' '), ) + ' ' + shade(lcov, meter(lcov)) + dim(' │ ') + shade(lcov, ratio(lcov, 'FNH', 'FNF')) + dim(' │ ') + shade(lcov, ratio(lcov, 'LH', 'LF')) + dim(' │') lcovList.sort((a, b) => a.SF[0] - b.SF[0]) console.log( [ [dim('╭'), dim('─'.repeat(44)), dim('┬'), dim('─'.repeat(11)), dim('┬'), dim('─'.repeat(11)), dim('╮')].join(''), [dim('│'), bold('Coverage') + ' '.repeat(34), dim('│'), bold('Functions'), dim('│'), ' '.repeat(4) + bold('Lines'), dim('│')].join(' '), [dim('├'), dim('─'.repeat(44)), dim('┼'), dim('─'.repeat(11)), dim('┼'), dim('─'.repeat(11)), dim('┤')].join(''), trtd( lcovList.reduce( (all, lcov) => { all.FNF[0] += lcov.FNF[0] all.FNH[0] += lcov.FNH[0] all.LF[0] += lcov.LF[0] all.LH[0] += lcov.LH[0] return all }, { TN: [''], SF: ['All files'], FN: [], FNDA: [], FNF: [0], FNH: [0], DA: [], LH: [0], LF: [0] }, ), ), [dim('╞'), ' '.repeat(42), dim('╪'), ' '.repeat(9), dim('╪'), ' '.repeat(9), dim('╡')].join(' '), ...lcovList.map((lcov) => trtd(lcov)), [dim('╰'), dim('─'.repeat(44)), dim('┴'), dim('─'.repeat(11)), dim('┴'), dim('─'.repeat(11)), dim('╯')].join(''), ].join('\n'), ) })() ================================================ FILE: .task/test.js ================================================ import { passIcon, failIcon, passText, failText, infoText, dim, green } from './internal/color.js' import { isProcessMeta, getProcessArgOf } from './internal/process.js' import * as fs from './internal/fs.js' import nodemon from 'nodemon' import URL from './internal/url.js' const root = URL.from(import.meta.url).to('../') const main = async (pkg, opts) => { let didFailLast // for each file in the testing directory for (let file of await fs.readdir(pkg.to('tests/'))) { file = pkg.to('tests/').to(file) // filter non-js files if (!file.endsWith('.js')) continue // filter non-matching files if (opts.only.length && !opts.only.some(name => file.includes(name))) continue /** Test results. */ const results = Object.create(null) // bootstrap the expect api globalThis.expect = (await import('./internal/expect.js')).default // bootstrap the describe api global.describe = async (description, call) => { // prepare description results results[description] = Object.create(null) // bootstrap the test api global.test = async (test, call) => { // prepare test results results[description][test] = [] try { // run the test await call() // assign success to the results results[description][test].push(`${passIcon} ${infoText(test)}`) } catch (error) { error.stack = error.stack || error.message || String(error || '') error.stack = [ ...error.stack.split(/\n/g).slice(1)].join('\n') // assign failure to the results const errorMessage = error.message.split('\n')[0] results[description][test].push(`${failIcon} ${infoText(test)}\n\t${errorMessage}`, getErrorStack(error), '') results[description][test][didFail] = error results[description][didFail] = true results[didFail] = true } } try { // run the description await call() } catch (error) { // assign description failure to the results results[description][''] = [`${failIcon} ${infoText('Error')}`, String(error.message)] } } try { // run the test file await import(file) } catch (error) { // report errors running the test file results[didFail] = error } const failure = results[didFail] // space out failures if (didFailLast && !!didFailLast != !!failure) console.log() // report details if there is a failure console.group(failure ? failText('FAIL') : passText('PASS'), infoText(file.href.slice(root.href.length))) if (failure) { process.exitCode = 1 for (let description in results) { // report each description console.group(failure ? failIcon : passIcon, infoText(description)) for (let test in results[description]) { // report each test console.log(results[description][test].join('\n')) } console.groupEnd() } // report any file error if (typeof failure === 'object') { console.log(getErrorStack(failure)) } } console.groupEnd() didFailLast = results[didFail] } } const didFail = Symbol.for('test.failure') const getErrorStack = (error) => error.stack.split(/\n/g).filter( (line) => !line.includes(import.meta.url) && !line.includes('node:') ).map( (line) => line.replace( /(.*?)\(?(file:[^:]+)(.*?)\)?$/, ($0, before, file, after) => ( before.replace(/(at) ([^\s]+)?(.*)/, `${dim('$1')} ${green('$2')}$3`) + file.slice(root.href.length) + dim(after) ) ) ).join('\n') export const testAll = async (opts) => { await main(URL.from(import.meta.url, '../packages/stringify/'), opts) await main(URL.from(import.meta.url, '../packages/core/'), opts) await main(URL.from(import.meta.url, '../packages/react/'), opts) } if (isProcessMeta(import.meta)) { if (getProcessArgOf('watch').includes(true)) { let onlyArgs = getProcessArgOf('only') onlyArgs = onlyArgs.length ? ['--only', ...onlyArgs] : onlyArgs nodemon( [ '-q', `--watch packages/core/src`, `--watch packages/core/tests`, `--watch packages/core/types`, `--watch packages/react/src`, `--watch packages/react/tests`, `--watch packages/react/types`, `--watch packages/stringify/src`, `--watch packages/stringify/tests`, `--watch packages/stringify/types`, // exec `--exec "${['node', './.task/test.js', ...onlyArgs].join(' ')}"`, ].join(' '), ).on('start', () => { process.stdout.write('\u001b[3J\u001b[2J\u001b[1J') console.clear() }).on('quit', () => process.exit()) } else { testAll({ only: getProcessArgOf('only'), }).catch((error) => { console.error(error) process.exitCode = 1 }) } } ================================================ FILE: .vscode/package.schema.json ================================================ { "$schema": "http://json-schema.org/draft-07/schema#", "allOf": [ { "$ref": "http://json.schemastore.org/package" }, { "properties": { "eslintConfig": { "title": "ESLint configuration", "$ref": "http://json.schemastore.org/eslintrc" }, "prettier": { "title": "Prettier configuration", "$ref": "http://json.schemastore.org/prettierrc" } } } ] } ================================================ FILE: .vscode/settings.json ================================================ { "debug.console.historySuggestions": false, "editor.formatOnSave": false, "editor.insertSpaces": false, "editor.snippetSuggestions": "none", "editor.suggest.snippetsPreventQuickSuggestions": false, "editor.suggestSelection": "recentlyUsedByPrefix", "editor.wordBasedSuggestions": false, "emmet.showAbbreviationSuggestions": false, "emmet.showExpandedAbbreviation": "never", "files.exclude": { "**/.DS_Store": true, "**/.git": true, "**/node_modules": true, "**/package-lock.json": true, "**/yarn.lock": true }, "javascript.suggest.enabled": false, "javascript.suggest.names": false, "typescript.tsserver.maxTsServerMemory": 8192 } ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at colm@workos.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Stitches Welcome and thanks for your interest! Before submitting a pull request, please take a moment to review these guidelines. ## Reporting Issues Found a problem? Want a new feature? - See if your issue or idea has [already been reported]. - Provide a [reduced test case] or a [live example]. Remember, a bug is a _demonstrable problem_ caused by _our_ code. ## Submitting Pull Requests Pull requests are the greatest contributions, so be sure they are focused in scope and avoid unrelated commits. 1. To begin: [fork this project], clone your fork, and add our upstream. ```bash # Clone your fork of the repo into the current directory git clone git@github.com:$(npx github-username-cli $(git config user.email))/stitches.git # Navigate to the newly cloned directory cd stitches # Assign the original repo to a remote called "upstream" git remote add upstream git@github.com:modulez/stitches.git # Install the tools necessary for testing yarn # or npm install ``` 2. Create a branch for your feature or fix: ```bash # Move into a new branch for your feature git checkout -b feature/thing ``` ```bash # Move into a new branch for your fix git checkout -b fix/something ``` 3. If your code passes all the tests, then push your feature branch: ```bash # Test current code yarn test # or npm test # Build current code yarn build # or npm run build ``` > Note: ensure your version of Node is 14 or higher to run scripts ```bash # Push the branch for your new feature git push origin feature/thing ``` ```bash # Or, push the branch for your update git push origin update/something ``` That’s it! Now [open a pull request] with a clear title and description. [already been reported]: https://github.com/stitchesjs/stitches/issues [fork this project]: https://github.com/stitchesjs/stitches/fork [live example]: https://codesandbox.io/ [open a pull request]: https://help.github.com/articles/using-pull-requests/ [reduced test case]: https://css-tricks.com/reduced-test-cases/ ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2022 WorkOS Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 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. ================================================ FILE: README.md ================================================ Update June 19, 2023: Stitches is no longer actively maintained due to changes in the React ecosystem and maintainer availability. You can read more here. --- stitches # Stitches ## Style your components with confidence CSS-in-JS with near-zero runtime, SSR, multi-variant support, and a best-in-class developer experience. #### Stitches Core Framework-agnostic implementation. ```sh npm install @stitches/core ``` [Read more](https://github.com/stitchesjs/stitches/tree/main/packages/core) #### Stitches React React wrapper including the `styled` API. ```sh npm install @stitches/react ``` [Read more](https://github.com/stitchesjs/stitches/tree/main/packages/react) --- ## Documentation For full documentation, visit [stitches.dev](https://stitches.dev). ## Contributing Please follow our [contributing guidelines](./CONTRIBUTING.md). ## Community You can join the [Stitches Discord](https://discord.com/invite/H4eG3Mk) to chat with other members of the community. Here's a list of community-built projects: - [babel-plugin-transform-stitches-display-name](https://github.com/afzalsayed96/babel-plugin-transform-stitches-display-name) - [stitches-normalize-css](https://github.com/psongpin/stitches-normalize-css) - [stitches-crochet](https://github.com/orenelbaum/stitches-crochet) - [stitches-native](https://github.com/Temzasse/stitches-native) ## Authors - Pedro Duarte ([@peduarte](https://twitter.com/peduarte)) - Jonathan Neal ([@jon_neal](https://twitter.com/jon_neal)) - Abdulhadi Alhallak ([@hadi_hlk](https://twitter.com/hadi_hlk)) - [WorkOS](https://workos.com) ## License Licensed under the MIT License, Copyright © 2022-present WorkOS. See [LICENSE](./LICENSE.md) for more information. ================================================ FILE: package.json ================================================ { "$schema": "./.vscode/package.schema.json", "name": "stitches", "type": "module", "license": "MIT", "contributors": [ "Pedro Duarte", "Abdulhadi Alhallak ", "Jonathan Neal" ], "scripts": { "build:test:types": "yarn workspace @stitches/test build", "build": "node .task/build.js", "build:watch": "node .task/build.js --watch", "lint": "node .task/lint.js", "lint:esm": "node .task/lint-esm.js", "lint:pkg": "node .task/lint-pkg.js", "lint:tsc": "node .task/lint-tsc.js", "release": "node .task/release.js", "test": "node .task/test.js", "test:coverage": "node .task/test-coverage.js .task/test.js", "test:watch": "node .task/test.js --watch" }, "workspaces": [ "packages/core", "packages/react", "packages/test", "packages/stringify" ], "dependencies": { "@radix-ui/react-polymorphic": "0.0.14", "@radix-ui/react-separator": "0.1.0", "@skypack/package-check": "0.2.2", "@types/node": "16.9.6", "@types/react": "17.0.33", "@types/react-dom": "17.0.9", "@types/react-test-renderer": "17.0.1", "@typescript-eslint/eslint-plugin": "5.36.2", "@typescript-eslint/parser": "5.36.2", "acorn": "8.5.0", "acorn-class-fields": "1.0.0", "acorn-import-assertions": "1.7.6", "acorn-jsx": "5.3.2", "acorn-logical-assignment": "0.1.4", "acorn-private-methods": "1.0.0", "astring": "1.7.5", "csstype": "3.0.9", "esbuild": "0.13.2", "eslint": "7.32.0", "nodemon": "2.0.13", "react": "17.0.2", "react-test-renderer": "17.0.2", "terser": "5.9.0", "typescript": "4.8.2" }, "browserslist": [ "last 1 chrome versions", "last 1 firefox versions", "last 1 safari versions", "maintained node versions" ], "eslintConfig": { "env": { "browser": true, "es6": true, "node": true }, "extends": "eslint:recommended", "globals": { "describe": false, "expect": false, "test": false }, "parserOptions": { "ecmaVersion": 12, "sourceType": "module", "ecmaFeatures": { "modules": true } }, "rules": { "semi": [ "error", "never" ] }, "overrides": [ { "files": "*.ts", "env": { "browser": true, "es6": true, "node": true }, "extends": [ "plugin:@typescript-eslint/recommended" ], "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 2020, "sourceType": "module", "ecmaFeatures": { "jsx": true } }, "settings": { "react": { "version": "detect" } }, "rules": { "@typescript-eslint/ban-types": [ "error", { "extendDefaults": true, "types": { "{}": false } } ], "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-for-in-array": "off", "@typescript-eslint/no-unnecessary-qualifier": "off", "@typescript-eslint/no-unnecessary-type-assertion": "off", "@typescript-eslint/promise-function-async": "off", "@typescript-eslint/restrict-plus-operands": "off" } } ] }, "prettier": { "arrowParens": "always", "bracketSpacing": true, "printWidth": 240, "quoteProps": "consistent", "semi": false, "singleQuote": true, "tabWidth": 2, "trailingComma": "all", "useTabs": true, "overrides": [ { "files": [ "*.json", "*.md", ".prettierrc", "*.yml" ], "options": { "useTabs": false } } ] }, "private": true } ================================================ FILE: packages/core/README.md ================================================ # @stitches/core **@stitches/core** is a framework-agnostic implementation of [stitches](https://stitches.dev), a CSS-in-JS library with a best-in-class developer experience.


```sh # with npm npm install @stitches/core # with yarn yarn add @stitches/core ```


open in codepen
```html ```


open in codepen
```js ```


## Documentation For full documentation, visit [stitches.dev](https://stitches.dev). ## Contributing Please follow our [contributing guidelines](./CONTRIBUTING.md). ## Authors - Pedro Duarte ([@peduarte](https://twitter.com/peduarte)) - Abdulhadi Alhallak ([@hadi_hlk](https://twitter.com/hadi_hlk)) - [WorkOS](https://workos.com) - Jonathan Neal ([@jon_neal](https://twitter.com/jon_neal)) ## License Licensed under the MIT License, Copyright © 2022-present WorkOS. See [LICENSE](./LICENSE.md) for more information. ================================================ FILE: packages/core/package.json ================================================ { "name": "@stitches/core", "version": "1.3.1-1", "description": "The modern CSS-in-JS library", "type": "module", "main": "dist/index.cjs", "module": "dist/index.mjs", "types": "types/index.d.ts", "typesVersions": { ">= 4.1": { "*": [ "types/*" ] } }, "jsdelivr": "dist/index.global.js", "unpkg": "dist/index.global.js", "exports": { ".": { "require": "./dist/index.cjs", "import": "./dist/index.mjs", "types": "./types/index.d.ts" }, "./global": "./dist/index.global.js" }, "files": [ "dist/*.cjs", "dist/*.js", "dist/*.map", "dist/*.mjs", "types/*.d.ts" ], "sideEffects": false, "license": "MIT", "repository": "stitchesjs/stitches", "homepage": "https://stitches.dev/", "bugs": "https://github.com/stitchesjs/stitches/issues", "contributors": [ "Pedro Duarte", "Abdulhadi Alhallak ", "Jonathan Neal" ], "publishConfig": { "access": "public" }, "keywords": [ "component", "components", "create", "css", "css-in-js", "global", "globals", "javascript", "js", "nesting", "object", "object-oriented", "oo", "oocss", "oriented", "scope", "scoped", "style", "styled", "styles", "stylesheet", "stylesheets", "theme", "themes", "theming", "token", "tokens", "type", "typed", "types", "transform", "ts", "variable", "variables" ] } ================================================ FILE: packages/core/src/ThemeToken.js ================================================ import { toTailDashed } from './convert/toTailDashed.js' export class ThemeToken { constructor(token, value, scale, prefix) { this.token = token == null ? '' : String(token) this.value = value == null ? '' : String(value) this.scale = scale == null ? '' : String(scale) this.prefix = prefix == null ? '' : String(prefix) } get computedValue() { return 'var(' + this.variable + ')' } get variable() { return '--' + toTailDashed(this.prefix) + toTailDashed(this.scale) + this.token } toString() { return this.computedValue } } ================================================ FILE: packages/core/src/convert/toCamelCase.js ================================================ /** Returns the given value converted to camel-case. */ export const toCamelCase = (/** @type {string} */ value) => (!/[A-Z]/.test(value) ? value.replace(/-[^]/g, (capital) => capital[1].toUpperCase()) : value) ================================================ FILE: packages/core/src/convert/toCssRules.js ================================================ import { toCamelCase } from './toCamelCase.js' import { toHyphenCase } from './toHyphenCase.js' import { toPolyfilledValue } from './toPolyfilledValue.js' import { toResolvedMediaQueryRanges } from './toResolvedMediaQueryRanges.js' import { toResolvedSelectors } from './toResolvedSelectors.js' import { toSizingValue } from './toSizingValue.js' import { toTailDashed } from './toTailDashed.js' import { toTokenizedValue } from './toTokenizedValue.js' /** Comma matcher outside rounded brackets. */ const comma = /\s*,\s*(?![^()]*\))/ /** Default toString method of Objects. */ const toStringOfObject = Object.prototype.toString export const toCssRules = ( style, selectors, conditions, config, onCssText ) => { /** @type {[string[], string[], string[]]} CSSOM-compatible rule being created. */ let currentRule = undefined /** Last utility that was used, cached to prevent recursion. */ let lastUtil /** Last polyfill that was used, cached to prevent recursion. */ let lastPoly /** Walks CSS styles and converts them into CSSOM-compatible rules. */ const walk = ( /** @type {Style} Set of CSS styles */ style, /** @type {string[]} Selectors that define the elements to which a set of CSS styles apply. */ selectors, /** @type {string[]} Conditions that define the queries to which a set of CSS styles apply. */ conditions, ) => { /** @type {keyof style} Represents the left-side "name" for the property (the at-rule prelude, style-rule selector, or declaration name). */ let name /** @type {style[keyof style]} Represents the right-side "data" for the property (the rule block, or declaration value). */ let data const each = (style) => { for (name in style) { /** Whether the current name represents an at-rule. */ const isAtRuleLike = name.charCodeAt(0) === 64 const datas = isAtRuleLike && Array.isArray(style[name]) ? style[name] : [style[name]] for (data of datas) { const camelName = toCamelCase(name) /** Whether the current data represents a nesting rule, which is a plain object whose key is not already a util. */ const isRuleLike = typeof data === 'object' && data && data.toString === toStringOfObject && (!config.utils[camelName] || !selectors.length) // if the left-hand "name" matches a configured utility // conditionally transform the current data using the configured utility if (camelName in config.utils && !isRuleLike) { const util = config.utils[camelName] if (util !== lastUtil) { lastUtil = util each(util(data)) lastUtil = null continue } } // otherwise, if the left-hand "name" matches a configured polyfill // conditionally transform the current data using the polyfill else if (camelName in toPolyfilledValue) { const poly = toPolyfilledValue[camelName] if (poly !== lastPoly) { lastPoly = poly each(poly(data)) lastPoly = null continue } } // if the left-hand "name" matches a configured at-rule if (isAtRuleLike) { // transform the current name with the configured media at-rule prelude name = toResolvedMediaQueryRanges(name.slice(1) in config.media ? '@media ' + config.media[name.slice(1)] : name) } if (isRuleLike) { /** Next conditions, which may include one new condition (if this is an at-rule). */ const nextConditions = isAtRuleLike ? conditions.concat(name) : [...conditions] /** Next selectors, which may include one new selector (if this is not an at-rule). */ const nextSelections = isAtRuleLike ? [...selectors] : toResolvedSelectors(selectors, name.split(comma)) if (currentRule !== undefined) { onCssText(toCssString(...currentRule)) } currentRule = undefined walk(data, nextSelections, nextConditions) } else { if (currentRule === undefined) currentRule = [[], selectors, conditions] /** CSS left-hand side value, which may be a specially-formatted custom property. */ name = !isAtRuleLike && name.charCodeAt(0) === 36 ? `--${toTailDashed(config.prefix)}${name.slice(1).replace(/\$/g, '-')}` : name /** CSS right-hand side value, which may be a specially-formatted custom property. */ data = ( // preserve object-like data isRuleLike ? data // replace all non-unitless props that are not custom properties with pixel versions : typeof data === 'number' ? data && !(camelName in unitlessProps) && !(name.charCodeAt(0) === 45) ? String(data) + 'px' : String(data) // replace tokens with stringified primitive values : toTokenizedValue( toSizingValue(camelName, data == null ? '' : data), config.prefix, config.themeMap[camelName] ) ) currentRule[0].push(`${isAtRuleLike ? `${name} ` : `${toHyphenCase(name)}:`}${data}`) } } } } each(style) if (currentRule !== undefined) { onCssText(toCssString(...currentRule)) } currentRule = undefined } walk(style, selectors, conditions) } const toCssString = (declarations, selectors, conditions) => ( `${conditions.map((condition) => `${condition}{`).join('')}${selectors.length ? `${selectors.join(',')}{` : ''}${declarations.join(';')}${selectors.length ? `}` : ''}${Array(conditions.length ? conditions.length + 1 : 0).join('}')}` ) /** CSS Properties whose number values should be unitless. */ export const unitlessProps = { animationIterationCount: 1, borderImageOutset: 1, borderImageSlice: 1, borderImageWidth: 1, boxFlex: 1, boxFlexGroup: 1, boxOrdinalGroup: 1, columnCount: 1, columns: 1, flex: 1, flexGrow: 1, flexPositive: 1, flexShrink: 1, flexNegative: 1, flexOrder: 1, gridRow: 1, gridRowEnd: 1, gridRowSpan: 1, gridRowStart: 1, gridColumn: 1, gridColumnEnd: 1, gridColumnSpan: 1, gridColumnStart: 1, msGridRow: 1, msGridRowSpan: 1, msGridColumn: 1, msGridColumnSpan: 1, fontWeight: 1, lineHeight: 1, opacity: 1, order: 1, orphans: 1, tabSize: 1, widows: 1, zIndex: 1, zoom: 1, WebkitLineClamp: 1, // SVG-related properties fillOpacity: 1, floodOpacity: 1, stopOpacity: 1, strokeDasharray: 1, strokeDashoffset: 1, strokeMiterlimit: 1, strokeOpacity: 1, strokeWidth: 1 } ================================================ FILE: packages/core/src/convert/toHash.js ================================================ const toAlphabeticChar = (/** @type {number} */ code) => String.fromCharCode(code + (code > 25 ? 39 : 97)) const toAlphabeticName = (/** @type {number} */ code) => { let name = '' let x for (x = Math.abs(code); x > 52; x = (x / 52) | 0) name = toAlphabeticChar(x % 52) + name return toAlphabeticChar(x % 52) + name } const toPhash = (/** @type {number} */ h, /** @type {string} */ x) => { let i = x.length while (i) h = (h * 33) ^ x.charCodeAt(--i) return h } export const toHash = (/** @type {object} */ value) => toAlphabeticName( toPhash( 5381, JSON.stringify(value) ) >>> 0 ) ================================================ FILE: packages/core/src/convert/toHyphenCase.js ================================================ /** Returns the given value converted to kebab-case. */ export const toHyphenCase = (/** @type {string} */ value) => ( // ignore kebab-like values value.includes('-') ? value // replace any upper-case letter with a dash and the lower-case variant : value.replace(/[A-Z]/g, (capital) => '-' + capital.toLowerCase()) ) ================================================ FILE: packages/core/src/convert/toPolyfilledValue.js ================================================ const splitBySpace = /\s+(?![^()]*\))/ const split = (fn) => (data) => fn(...(typeof data === 'string' ? String(data).split(splitBySpace) : [data])) export const toPolyfilledValue = { // prefixed properties appearance: (d) => ({ WebkitAppearance: d, appearance: d }), backfaceVisibility: (d) => ({ WebkitBackfaceVisibility: d, backfaceVisibility: d }), backdropFilter: (d) => ({ WebkitBackdropFilter: d, backdropFilter: d }), backgroundClip: (d) => ({ WebkitBackgroundClip: d, backgroundClip: d }), boxDecorationBreak: (d) => ({ WebkitBoxDecorationBreak: d, boxDecorationBreak: d }), clipPath: (d) => ({ WebkitClipPath: d, clipPath: d }), content: (d) => ({ content: d.includes('"') || d.includes("'") || /^([A-Za-z]+\([^]*|[^]*-quote|inherit|initial|none|normal|revert|unset)$/.test(d) ? d : `"${d}"` }), hyphens: (d) => ({ WebkitHyphens: d, hyphens: d }), maskImage: (d) => ({ WebkitMaskImage: d, maskImage: d }), maskSize: (d) => ({ WebkitMaskSize: d, maskSize: d }), textSizeAdjust: (d) => ({ WebkitTextSizeAdjust: d, textSizeAdjust: d }), userSelect: (d) => ({ WebkitUserSelect: d, userSelect: d }), // logical properties marginBlock: split((s, e) => ({ marginBlockStart: s, marginBlockEnd: e || s })), marginInline: split((s, e) => ({ marginInlineStart: s, marginInlineEnd: e || s })), maxSize: split((b, i) => ({ maxBlockSize: b, maxInlineSize: i || b })), minSize: split((b, i) => ({ minBlockSize: b, minInlineSize: i || b })), paddingBlock: split((s, e) => ({ paddingBlockStart: s, paddingBlockEnd: e || s })), paddingInline: split((s, e) => ({ paddingInlineStart: s, paddingInlineEnd: e || s })), } ================================================ FILE: packages/core/src/convert/toResolvedMediaQueryRanges.js ================================================ const mqunit = /([\d.]+)([^]*)/ /** Returns a media query with polyfilled ranges. */ export const toResolvedMediaQueryRanges = ( /** @type {string} */ media ) => media.replace( /\(\s*([\w-]+)\s*(=|<|<=|>|>=)\s*([\w-]+)\s*(?:(<|<=|>|>=)\s*([\w-]+)\s*)?\)/g, ( __, /** @type {string} 1st param, either the name or value in the query. */ p1, /** @type {string} 1st operator. */ o1, /** @type {string} 2nd param, either the name or value in the query. */ p2, /** @type {string} Optional 2nd operator. */ o2, /** @type {string} Optional 3rd param, always a value in the query.*/ p3 ) => { /** Whether the first param is a value. */ const isP1Value = mqunit.test(p1) /** Numeric shift applied to a value when an operator is `<` or `>`. */ const shift = 0.0625 * (isP1Value ? -1 : 1) const [name, value] = isP1Value ? [p2, p1] : [p1, p2] return ( '(' + ( o1[0] === '=' ? '' : (o1[0] === '>' === isP1Value ? 'max-' : 'min-') ) + name + ':' + (o1[0] !== '=' && o1.length === 1 ? value.replace(mqunit, (_, v, u) => Number(v) + shift * (o1 === '>' ? 1 : -1) + u) : value) + ( o2 ? ') and (' + ( (o2[0] === '>' ? 'min-' : 'max-') + name + ':' + (o2.length === 1 ? p3.replace(mqunit, (_, v, u) => Number(v) + shift * (o2 === '>' ? -1 : 1) + u) : p3) ) : '' ) + ')' ) } ) ================================================ FILE: packages/core/src/convert/toResolvedSelectors.js ================================================ /** Returns selectors resolved from parent selectors and nested selectors. */ export const toResolvedSelectors = ( /** @type {string[]} Parent selectors (e.g. `["a", "button"]`). */ parentSelectors, /** @type {string[]} Nested selectors (e.g. `["&:hover", "&:focus"]`). */ nestedSelectors, ) => ( parentSelectors.length ? parentSelectors.reduce( (resolvedSelectors, parentSelector) => { resolvedSelectors.push( ...nestedSelectors.map( (selector) => ( selector.includes('&') ? selector.replace( /&/g, /[ +>|~]/.test(parentSelector) && /&.*&/.test(selector) ? `:is(${parentSelector})` : parentSelector ) : parentSelector + ' ' + selector ) ) ) return resolvedSelectors }, [] ) : nestedSelectors ) ================================================ FILE: packages/core/src/convert/toSizingValue.js ================================================ import { toHyphenCase } from './toHyphenCase.js' /** Returns a declaration sizing value with polyfilled sizing keywords. */ export const toSizingValue = (/** @type {string} */ declarationName, /** @type {string} */ declarationValue) => ( declarationName in sizeProps && typeof declarationValue === 'string' ? declarationValue.replace( /^((?:[^]*[^\w-])?)(fit-content|stretch)((?:[^\w-][^]*)?)$/, (data, lead, main, tail) => ( lead + ( main === 'stretch' ? `-moz-available${tail};${toHyphenCase(declarationName)}:${lead}-webkit-fill-available` : `-moz-fit-content${tail};${toHyphenCase(declarationName)}:${lead}fit-content` ) + tail ), ) : String(declarationValue) ) /** CSS Properties whose value include a sizing keyword. */ const sizeProps = { blockSize: 1, height: 1, inlineSize: 1, maxBlockSize: 1, maxHeight: 1, maxInlineSize: 1, maxWidth: 1, minBlockSize: 1, minHeight: 1, minInlineSize: 1, minWidth: 1, width: 1, } ================================================ FILE: packages/core/src/convert/toTailDashed.js ================================================ /** Returns a filled value with a dash prefix. */ export const toTailDashed = (/** @type {string} */ value) => value ? value + '-' : '' ================================================ FILE: packages/core/src/convert/toTokenizedValue.js ================================================ import { toTailDashed } from './toTailDashed.js' /** Returns a declaration value with transformed token values. */ export const toTokenizedValue = ( /** @type {string} */ value, /** @type {string} */ prefix, /** @type {string} */ scale, ) => value.replace( /([+-])?((?:\d+(?:\.\d*)?|\.\d+)(?:[Ee][+-]?\d+)?)?(\$|--)([$\w-]+)/g, ($0, direction, multiplier, separator, token) => ( separator == "$" == !!multiplier ? $0 : ( direction || separator == '--' ? 'calc(' : '' ) + ( 'var(--' + ( separator === '$' ? toTailDashed(prefix) + ( !token.includes('$') ? toTailDashed(scale) : '' ) + token.replace(/\$/g, '-') : token ) + ')' + ( direction || separator == '--' ? '*' + ( direction || '' ) + ( multiplier || '1' ) + ')' : '' ) ) ), ) ================================================ FILE: packages/core/src/createStitches.js ================================================ import { defaultThemeMap } from './default/defaultThemeMap.js' import { createMemo } from './utility/createMemo.js' import { createCssFunction } from './features/css.js' import { createGlobalCssFunction } from './features/globalCss.js' import { createKeyframesFunction } from './features/keyframes.js' import { createCreateThemeFunction } from './features/createTheme.js' import { createSheet } from './sheet.js' const createCssMap = createMemo() export const createStitches = (config) => { let didRun = false const instance = createCssMap(config, (initConfig) => { didRun = true initConfig = typeof initConfig === 'object' && initConfig || {} // internal configuration const prefix = 'prefix' in initConfig ? String(initConfig.prefix) : '' const media = typeof initConfig.media === 'object' && initConfig.media || {} const root = typeof initConfig.root === 'object' ? initConfig.root || null : globalThis.document || null const theme = typeof initConfig.theme === 'object' && initConfig.theme || {} const themeMap = typeof initConfig.themeMap === 'object' && initConfig.themeMap || { ...defaultThemeMap } const utils = typeof initConfig.utils === 'object' && initConfig.utils || {} /** External configuration. */ const config = { prefix, media, theme, themeMap, utils, } /** Internal stylesheet. */ const sheet = createSheet(root) const returnValue = { css: createCssFunction(config, sheet), globalCss: createGlobalCssFunction(config, sheet), keyframes: createKeyframesFunction(config, sheet), createTheme: createCreateThemeFunction(config, sheet), reset() { sheet.reset() returnValue.theme.toString() }, theme: {}, sheet, config, prefix, getCssText: sheet.toString, toString: sheet.toString, } // initialize default theme String( returnValue.theme = returnValue.createTheme(theme) ) return returnValue }) if (!didRun) instance.reset() return instance } ================================================ FILE: packages/core/src/default/defaultThemeMap.js ================================================ const borderStyles = 'borderStyles' const borderWidths = 'borderWidths' const colors = 'colors' const fonts = 'fonts' const fontSizes = 'fontSizes' const fontWeights = 'fontWeights' const letterSpacings = 'letterSpacings' const lineHeights = 'lineHeights' const radii = 'radii' const shadows = 'shadows' const sizes = 'sizes' const space = 'space' const transitions = 'transitions' const zIndices = 'zIndices' /** @type {DefaultThemeMap} */ export const defaultThemeMap = { gap: space, gridGap: space, columnGap: space, gridColumnGap: space, rowGap: space, gridRowGap: space, inset: space, insetBlock: space, insetBlockEnd: space, insetBlockStart: space, insetInline: space, insetInlineEnd: space, insetInlineStart: space, margin: space, marginTop: space, marginRight: space, marginBottom: space, marginLeft: space, marginBlock: space, marginBlockEnd: space, marginBlockStart: space, marginInline: space, marginInlineEnd: space, marginInlineStart: space, padding: space, paddingTop: space, paddingRight: space, paddingBottom: space, paddingLeft: space, paddingBlock: space, paddingBlockEnd: space, paddingBlockStart: space, paddingInline: space, paddingInlineEnd: space, paddingInlineStart: space, top: space, right: space, bottom: space, left: space, scrollMargin: space, scrollMarginTop: space, scrollMarginRight: space, scrollMarginBottom: space, scrollMarginLeft: space, scrollMarginX: space, scrollMarginY: space, scrollMarginBlock: space, scrollMarginBlockEnd: space, scrollMarginBlockStart: space, scrollMarginInline: space, scrollMarginInlineEnd: space, scrollMarginInlineStart: space, scrollPadding: space, scrollPaddingTop: space, scrollPaddingRight: space, scrollPaddingBottom: space, scrollPaddingLeft: space, scrollPaddingX: space, scrollPaddingY: space, scrollPaddingBlock: space, scrollPaddingBlockEnd: space, scrollPaddingBlockStart: space, scrollPaddingInline: space, scrollPaddingInlineEnd: space, scrollPaddingInlineStart: space, fontSize: fontSizes, background: colors, backgroundColor: colors, backgroundImage: colors, borderImage: colors, border: colors, borderBlock: colors, borderBlockEnd: colors, borderBlockStart: colors, borderBottom: colors, borderBottomColor: colors, borderColor: colors, borderInline: colors, borderInlineEnd: colors, borderInlineStart: colors, borderLeft: colors, borderLeftColor: colors, borderRight: colors, borderRightColor: colors, borderTop: colors, borderTopColor: colors, caretColor: colors, color: colors, columnRuleColor: colors, fill: colors, outline: colors, outlineColor: colors, stroke: colors, textDecorationColor: colors, fontFamily: fonts, fontWeight: fontWeights, lineHeight: lineHeights, letterSpacing: letterSpacings, blockSize: sizes, minBlockSize: sizes, maxBlockSize: sizes, inlineSize: sizes, minInlineSize: sizes, maxInlineSize: sizes, width: sizes, minWidth: sizes, maxWidth: sizes, height: sizes, minHeight: sizes, maxHeight: sizes, flexBasis: sizes, gridTemplateColumns: sizes, gridTemplateRows: sizes, borderWidth: borderWidths, borderTopWidth: borderWidths, borderRightWidth: borderWidths, borderBottomWidth: borderWidths, borderLeftWidth: borderWidths, borderStyle: borderStyles, borderTopStyle: borderStyles, borderRightStyle: borderStyles, borderBottomStyle: borderStyles, borderLeftStyle: borderStyles, borderRadius: radii, borderTopLeftRadius: radii, borderTopRightRadius: radii, borderBottomRightRadius: radii, borderBottomLeftRadius: radii, boxShadow: shadows, textShadow: shadows, transition: transitions, zIndex: zIndices, } /** * @typedef {Object} DefaultThemeMap * @property {space} gap * @property {space} gridGap * @property {space} columnGap * @property {space} gridColumnGap * @property {space} rowGap * @property {space} gridRowGap * @property {space} inset * @property {space} insetBlock * @property {space} insetBlockEnd * @property {space} insetBlockStart * @property {space} insetInline * @property {space} insetInlineEnd * @property {space} insetInlineStart * @property {space} margin * @property {space} marginTop * @property {space} marginRight * @property {space} marginBottom * @property {space} marginLeft * @property {space} marginBlock * @property {space} marginBlockEnd * @property {space} marginBlockStart * @property {space} marginInline * @property {space} marginInlineEnd * @property {space} marginInlineStart * @property {space} padding * @property {space} paddingTop * @property {space} paddingRight * @property {space} paddingBottom * @property {space} paddingLeft * @property {space} paddingBlock * @property {space} paddingBlockEnd * @property {space} paddingBlockStart * @property {space} paddingInline * @property {space} paddingInlineEnd * @property {space} paddingInlineStart * @property {space} top * @property {space} right * @property {space} bottom * @property {space} left * @property {space} scrollMargin * @property {space} scrollMarginTop * @property {space} scrollMarginRight * @property {space} scrollMarginBottom * @property {space} scrollMarginLeft * @property {space} scrollMarginX * @property {space} scrollMarginY * @property {space} scrollMarginBlock * @property {space} scrollMarginBlockEnd * @property {space} scrollMarginBlockStart * @property {space} scrollMarginInline * @property {space} scrollMarginInlineEnd * @property {space} scrollMarginInlineStart * @property {space} scrollPadding * @property {space} scrollPaddingTop * @property {space} scrollPaddingRight * @property {space} scrollPaddingBottom * @property {space} scrollPaddingLeft * @property {space} scrollPaddingX * @property {space} scrollPaddingY * @property {space} scrollPaddingBlock * @property {space} scrollPaddingBlockEnd * @property {space} scrollPaddingBlockStart * @property {space} scrollPaddingInline * @property {space} scrollPaddingInlineEnd * @property {space} scrollPaddingInlineStart * @property {fontSizes} fontSize * @property {colors} background * @property {colors} backgroundColor * @property {colors} backgroundImage * @property {colors} border * @property {colors} borderBlock * @property {colors} borderBlockEnd * @property {colors} borderBlockStart * @property {colors} borderBottom * @property {colors} borderBottomColor * @property {colors} borderColor * @property {colors} borderInline * @property {colors} borderInlineEnd * @property {colors} borderInlineStart * @property {colors} borderLeft * @property {colors} borderLeftColor * @property {colors} borderRight * @property {colors} borderRightColor * @property {colors} borderTop * @property {colors} borderTopColor * @property {colors} caretColor * @property {colors} color * @property {colors} columnRuleColor * @property {colors} fill * @property {colors} outline * @property {colors} outlineColor * @property {colors} stroke * @property {colors} textDecorationColor * @property {fonts} fontFamily * @property {fontWeights} fontWeight * @property {lineHeights} lineHeight * @property {letterSpacings} letterSpacing * @property {sizes} blockSize * @property {sizes} minBlockSize * @property {sizes} maxBlockSize * @property {sizes} inlineSize * @property {sizes} minInlineSize * @property {sizes} maxInlineSize * @property {sizes} width * @property {sizes} minWidth * @property {sizes} maxWidth * @property {sizes} height * @property {sizes} minHeight * @property {sizes} maxHeight * @property {sizes} flexBasis * @property {sizes} gridTemplateColumns * @property {sizes} gridTemplateRows * @property {borderWidths} borderWidth * @property {borderWidths} borderTopWidth * @property {borderWidths} borderRightWidth * @property {borderWidths} borderBottomWidth * @property {borderWidths} borderLeftWidth * @property {borderStyles} borderStyle * @property {borderStyles} borderTopStyle * @property {borderStyles} borderRightStyle * @property {borderStyles} borderBottomStyle * @property {borderStyles} borderLeftStyle * @property {radii} borderRadius * @property {radii} borderTopLeftRadius * @property {radii} borderTopRightRadius * @property {radii} borderBottomRightRadius * @property {radii} borderBottomLeftRadius * @property {shadows} boxShadow * @property {shadows} textShadow * @property {transitions} transition * @property {zIndices} zIndex */ ================================================ FILE: packages/core/src/features/createTheme.js ================================================ import { ThemeToken } from '../ThemeToken.js' import { createMemo } from '../utility/createMemo.js' import { toHash } from '../convert/toHash.js' import { toTailDashed } from '../convert/toTailDashed.js' import { toTokenizedValue } from '../convert/toTokenizedValue.js' const createCreateThemeFunctionMap = createMemo() /** Returns a function that applies a theme and returns tokens of that theme. */ export const createCreateThemeFunction = ( config, sheet ) => ( createCreateThemeFunctionMap(config, () => (className, style) => { // theme is the first argument if it is an object, otherwise the second argument as an object style = typeof className === 'object' && className || Object(style) // class name is the first argument if it is a string, otherwise an empty string className = typeof className === 'string' ? className : '' /** @type {string} Theme name. @see `{CONFIG_PREFIX}t-{THEME_UUID}` */ className = className || `${toTailDashed(config.prefix)}t-${toHash(style)}` const selector = `.${className}` const themeObject = {} const cssProps = [] for (const scale in style) { themeObject[scale] = {} for (const token in style[scale]) { const propertyName = `--${toTailDashed(config.prefix)}${scale}-${token}` const propertyValue = toTokenizedValue(String(style[scale][token]), config.prefix, scale) themeObject[scale][token] = new ThemeToken(token, propertyValue, scale, config.prefix) cssProps.push(`${propertyName}:${propertyValue}`) } } const render = () => { if (cssProps.length && !sheet.rules.themed.cache.has(className)) { sheet.rules.themed.cache.add(className) const rootPrelude = style === config.theme ? ':root,' : '' const cssText = `${rootPrelude}.${className}{${cssProps.join(';')}}` sheet.rules.themed.apply(cssText) } return className } return { ...themeObject, get className() { return render() }, selector, toString: render, } }) ) ================================================ FILE: packages/core/src/features/css.js ================================================ import { internal } from '../utility/internal.js' import { createMemo } from '../utility/createMemo.js' import { define } from '../utility/define.js' import { hasNames } from '../utility/hasNames.js' import { hasOwn } from '../utility/hasOwn.js' import { toCssRules } from '../convert/toCssRules.js' import { toHash } from '../convert/toHash.js' import { toTailDashed } from '../convert/toTailDashed.js' import { createRulesInjectionDeferrer } from '../sheet.js' const createCssFunctionMap = createMemo() /** Returns a function that applies component styles. */ export const createCssFunction = (config, sheet) => createCssFunctionMap(config, () => { const _css = (args, componentConfig = {}) => { let internals = { type: null, composers: new Set(), } for (const arg of args) { // skip any void argument if (arg == null) continue // conditionally extend the component if (arg[internal]) { if (internals.type == null) internals.type = arg[internal].type for (const composer of arg[internal].composers) { internals.composers.add(composer) } } // otherwise, conditionally define the component type else if (arg.constructor !== Object || arg.$$typeof) { if (internals.type == null) internals.type = arg } // otherwise, add a new composer to this component else { internals.composers.add(createComposer(arg, config, componentConfig)) } } // set the component type if none was set if (internals.type == null) internals.type = 'span' if (!internals.composers.size) internals.composers.add(['PJLV', {}, [], [], {}, []]) return createRenderer(config, internals, sheet, componentConfig) } const css = (...args) => _css(args) css.withConfig = (componentConfig) => (...args) => _css(args, componentConfig) return css }) /** Creates a composer from a configuration object. */ const createComposer = ({ variants: initSingularVariants, compoundVariants: initCompoundVariants, defaultVariants: initDefaultVariants, ...style }, config, {componentId, displayName}) => { /** @type {string} Composer Unique Identifier. @see `{CONFIG_PREFIX}-?c-{STYLE_HASH}` */ const hash = componentId || toHash(style) const componentNamePrefix = displayName ? ('c-' + displayName +'') : 'c' const className = `${toTailDashed(config.prefix)}${componentNamePrefix}-${hash}` const singularVariants = [] const compoundVariants = [] const prefilledVariants = Object.create(null) const undefinedVariants = [] for (const variantName in initDefaultVariants) { prefilledVariants[variantName] = String(initDefaultVariants[variantName]) } // add singular variants if (typeof initSingularVariants === 'object' && initSingularVariants) { for (const name in initSingularVariants) { if (!hasOwn(prefilledVariants, name)) prefilledVariants[name] = 'undefined' const variantPairs = initSingularVariants[name] for (const pair in variantPairs) { const vMatch = { [name]: String(pair) } if (String(pair) === 'undefined') undefinedVariants.push(name) const vStyle = variantPairs[pair] const variant = [vMatch, vStyle, !hasNames(vStyle)] singularVariants.push(variant) } } } // add compound variants if (typeof initCompoundVariants === 'object' && initCompoundVariants) { for (const compoundVariant of initCompoundVariants) { let { css: vStyle, ...vMatch } = compoundVariant vStyle = typeof vStyle === 'object' && vStyle || {} // serialize all compound variant pairs for (const name in vMatch) vMatch[name] = String(vMatch[name]) const variant = [vMatch, vStyle, !hasNames(vStyle)] compoundVariants.push(variant) } } return ([className, style, singularVariants, compoundVariants, prefilledVariants, undefinedVariants]) } const createRenderer = (config, internals, sheet, { shouldForwardStitchesProp }) => { const [ baseClassName, baseClassNames, prefilledVariants, undefinedVariants ] = getPreparedDataFromComposers(internals.composers) const deferredInjector = typeof internals.type === 'function' || !!internals.type.$$typeof ? createRulesInjectionDeferrer(sheet) : null const injectionTarget = (deferredInjector || sheet).rules const selector = `.${baseClassName}${baseClassNames.length > 1 ? `:where(.${baseClassNames.slice(1).join('.')})` : ``}` const render = (props) => { props = typeof props === 'object' && props || empty // 1. we cannot mutate `props` // 2. we delete variant props // 3. we delete `css` prop // therefore: we must create a new props & css variables const { ...forwardProps } = props const variantProps = {} for (const name in prefilledVariants) { if (name in props) { if (!shouldForwardStitchesProp?.(name)) delete forwardProps[name] let data = props[name] if (typeof data === 'object' && data) { variantProps[name] = { '@initial': prefilledVariants[name], ...data, } } else { data = String(data) variantProps[name] = ( data === 'undefined' && !undefinedVariants.has(name) ? prefilledVariants[name] : data ) } } else { variantProps[name] = prefilledVariants[name] } } const classSet = new Set([ ...baseClassNames ]) // 1. builds up the variants (fills in defaults, calculates @initial on responsive, etc.) // 2. iterates composers // 2.1. add their base class // 2.2. iterate their variants, add their variant classes // 2.2.1. orders regular variants before responsive variants // 2.3. iterate their compound variants, add their compound variant classes for (const [composerBaseClass, composerBaseStyle, singularVariants, compoundVariants] of internals.composers) { if (!sheet.rules.styled.cache.has(composerBaseClass)) { sheet.rules.styled.cache.add(composerBaseClass) toCssRules(composerBaseStyle, [`.${composerBaseClass}`], [], config, (cssText) => { injectionTarget.styled.apply(cssText) }) } const singularVariantsToAdd = getTargetVariantsToAdd(singularVariants, variantProps, config.media) const compoundVariantsToAdd = getTargetVariantsToAdd(compoundVariants, variantProps, config.media, true) for (const variantToAdd of singularVariantsToAdd) { if (variantToAdd === undefined) continue for (const [vClass, vStyle, isResponsive] of variantToAdd) { const variantClassName = `${composerBaseClass}-${toHash(vStyle)}-${vClass}` classSet.add(variantClassName) const groupCache = (isResponsive ? sheet.rules.resonevar : sheet.rules.onevar ).cache /* * make sure that normal variants are injected before responsive ones * @see {@link https://github.com/stitchesjs/stitches/issues/737|github} */ const targetInjectionGroup = isResponsive ? injectionTarget.resonevar : injectionTarget.onevar if (!groupCache.has(variantClassName)) { groupCache.add(variantClassName) toCssRules(vStyle, [`.${variantClassName}`], [], config, (cssText) => { targetInjectionGroup.apply(cssText) }) } } } for (const variantToAdd of compoundVariantsToAdd) { if (variantToAdd === undefined) continue for (const [vClass, vStyle] of variantToAdd) { const variantClassName = `${composerBaseClass}-${toHash(vStyle)}-${vClass}` classSet.add(variantClassName) if (!sheet.rules.allvar.cache.has(variantClassName)) { sheet.rules.allvar.cache.add(variantClassName) toCssRules(vStyle, [`.${variantClassName}`], [], config, (cssText) => { injectionTarget.allvar.apply(cssText) }) } } } } // apply css property styles const css = forwardProps.css if (typeof css === 'object' && css) { if (!shouldForwardStitchesProp?.('css')) delete forwardProps.css /** @type {string} Inline Class Unique Identifier. @see `{COMPOSER_UUID}-i{VARIANT_UUID}-css` */ const iClass = `${baseClassName}-i${toHash(css)}-css` classSet.add(iClass) if (!sheet.rules.inline.cache.has(iClass)) { sheet.rules.inline.cache.add(iClass) toCssRules(css, [`.${iClass}`], [], config, (cssText) => { injectionTarget.inline.apply(cssText) }) } } for (const propClassName of String(props.className || '').trim().split(/\s+/)) { if (propClassName) classSet.add(propClassName) } const renderedClassName = forwardProps.className = [ ...classSet ].join(' ') const renderedToString = () => renderedClassName return { type: internals.type, className: renderedClassName, selector, props: forwardProps, toString: renderedToString, deferredInjector, } } const toString = () => { if (!sheet.rules.styled.cache.has(baseClassName)) render() return baseClassName } return define(render, { className: baseClassName, selector, [internal]: internals, toString, }) } /** Returns useful data that can be known before rendering. */ const getPreparedDataFromComposers = (composers) => { /** Class name of the first composer. */ let baseClassName = '' /** @type {string[]} Combined class names for all composers. */ const baseClassNames = [] /** @type {PrefilledVariants} Combined variant pairings for all composers. */ const combinedPrefilledVariants = {} /** @type {UndefinedVariants} List of variant names that can have an "undefined" pairing. */ const combinedUndefinedVariants = [] for (const [className, , , , prefilledVariants, undefinedVariants] of composers) { if (baseClassName === '') baseClassName = className baseClassNames.push(className) combinedUndefinedVariants.push(...undefinedVariants) for (const name in prefilledVariants) { const data = prefilledVariants[name] if (combinedPrefilledVariants[name] === undefined || data !== 'undefined' || undefinedVariants.includes(data)) combinedPrefilledVariants[name] = data } } const preparedData = [ baseClassName, baseClassNames, combinedPrefilledVariants, new Set(combinedUndefinedVariants) ] return preparedData } const getTargetVariantsToAdd = ( targetVariants, variantProps, media, isCompoundVariant, ) => { const targetVariantsToAdd = [] targetVariants: for (let [vMatch, vStyle, vEmpty] of targetVariants) { // skip empty variants if (vEmpty) continue /** Position the variant should be inserted into. */ let vOrder = 0 let vName let isResponsive = false for (vName in vMatch) { const vPair = vMatch[vName] let pPair = variantProps[vName] // exact matches if (pPair === vPair) continue // responsive matches else if (typeof pPair === 'object' && pPair) { /** @type {boolean} Whether the responsive variant is matched. */ let didMatch let qOrder = 0 // media queries matching the same variant let matchedQueries for (const query in pPair) { if (vPair === String(pPair[query])) { if (query !== '@initial') { // check if the cleanQuery is in the media config and then we push the resulting media query to the matchedQueries array, // if not, we remove the @media from the beginning and push it to the matched queries which then will be resolved a few lines down // when we finish working on this variant and want wrap the vStyles with the matchedQueries const cleanQuery = query.slice(1); (matchedQueries = matchedQueries || []).push(cleanQuery in media ? media[cleanQuery] : query.replace(/^@media ?/, '')) isResponsive = true } vOrder += qOrder didMatch = true } ++qOrder } if (matchedQueries && matchedQueries.length) { vStyle = { ['@media ' + matchedQueries.join(', ')]: vStyle, } } if (!didMatch) continue targetVariants } // non-matches else continue targetVariants } (targetVariantsToAdd[vOrder] = targetVariantsToAdd[vOrder] || []).push([isCompoundVariant ? `cv` : `${vName}-${vMatch[vName]}`, vStyle, isResponsive]) } return targetVariantsToAdd } /** Fallback props object used when no props are passed. */ const empty = {} ================================================ FILE: packages/core/src/features/globalCss.js ================================================ import { createMemo } from '../utility/createMemo.js' import { define } from '../utility/define.js' import { toCssRules } from '../convert/toCssRules.js' import { toHash } from '../convert/toHash.js' const createGlobalCssFunctionMap = createMemo() /** Returns a function that applies global styles. */ export const createGlobalCssFunction = ( config, sheet ) => createGlobalCssFunctionMap(config, () => ( ...styles ) => { const render = () => { for (let style of styles) { style = typeof style === 'object' && style || {} let uuid = toHash(style) if (!sheet.rules.global.cache.has(uuid)) { sheet.rules.global.cache.add(uuid) // support @import rules if ('@import' in style) { let importIndex = [].indexOf.call(sheet.sheet.cssRules, sheet.rules.themed.group) - 1 // wrap import in quotes as a convenience for ( let importValue of /** @type {string[]} */ ([].concat(style['@import'])) ) { importValue = importValue.includes('"') || importValue.includes("'") ? importValue : `"${importValue}"` sheet.sheet.insertRule(`@import ${importValue};`, importIndex++) } delete style['@import'] } toCssRules(style, [], [], config, (cssText) => { sheet.rules.global.apply(cssText) }) } } return '' } return define(render, { toString: render, }) }) ================================================ FILE: packages/core/src/features/keyframes.js ================================================ import { createMemo } from '../utility/createMemo.js' import { define } from '../utility/define.js' import { toCssRules } from '../convert/toCssRules.js' import { toHash } from '../convert/toHash.js' import { toTailDashed } from '../convert/toTailDashed.js' /** @typedef {import('..').Config} Config */ /** @typedef {import('..').Style} Style */ /** @typedef {import('..').GroupSheet} GroupSheet */ const createKeyframesFunctionMap = createMemo() /** Returns a function that applies a keyframes rule. */ export const createKeyframesFunction = (/** @type {Config} */ config, /** @type {GroupSheet} */ sheet) => ( createKeyframesFunctionMap(config, () => (style) => { /** @type {string} Keyframes Unique Identifier. @see `{CONFIG_PREFIX}-?k-{KEYFRAME_UUID}` */ const name = `${toTailDashed(config.prefix)}k-${toHash(style)}` const render = () => { if (!sheet.rules.global.cache.has(name)) { sheet.rules.global.cache.add(name) const cssRules = [] toCssRules(style, [], [], config, (cssText) => cssRules.push(cssText)) const cssText = `@keyframes ${name}{${cssRules.join('')}}` sheet.rules.global.apply(cssText) } return name } return define(render, { get name() { return render() }, toString: render, }) }) ) ================================================ FILE: packages/core/src/index.js ================================================ import { getCachedConfig } from './utility/getCachedConfig.js' export { createStitches } from './createStitches.js' export { defaultThemeMap } from './default/defaultThemeMap.js' export const createTheme = (...args) => getCachedConfig().createTheme(...args) export const globalCss = (...args) => getCachedConfig().globalCss(...args) export const keyframes = (...args) => getCachedConfig().keyframes(...args) export const css = (...args) => getCachedConfig().css(...args) ================================================ FILE: packages/core/src/sheet.js ================================================ import { getNonce } from './utility/getNonce.js' /** * Rules in the sheet appear in this order: * 1. theme rules (themed) * 2. global rules (global) * 3. component rules (styled) * 4. non-responsive variants rules (onevar) * 5. responsive variants rules (resonevar) * 6. compound variants rules (allvar) * 7. inline rules (inline) */ /** @type {RuleGroupNames} */ export const names = ['themed', 'global', 'styled', 'onevar', 'resonevar', 'allvar', 'inline'] const isSheetAccessible = (/** @type {CSSStyleSheet} */ sheet) => { if (sheet.href && !sheet.href.startsWith(location.origin)) { return false } try { return !!sheet.cssRules } catch (e) { return false } } export const createSheet = (/** @type {DocumentOrShadowRoot} */ root) => { /** @type {SheetGroup} Object hosting the hydrated stylesheet. */ let groupSheet const toString = () => { const { cssRules } = groupSheet.sheet return [].map .call(cssRules, (cssRule, cssRuleIndex) => { const { cssText } = cssRule let lastRuleCssText = '' if (cssText.startsWith('--sxs')) return '' if (cssRules[cssRuleIndex - 1] && (lastRuleCssText = cssRules[cssRuleIndex - 1].cssText).startsWith('--sxs')) { if (!cssRule.cssRules.length) return '' for (const name in groupSheet.rules) { if (groupSheet.rules[name].group === cssRule) { return `--sxs{--sxs:${[...groupSheet.rules[name].cache].join(' ')}}${cssText}` } } return cssRule.cssRules.length ? `${lastRuleCssText}${cssText}` : '' } return cssText }) .join('') } const reset = () => { if (groupSheet) { const { rules, sheet } = groupSheet if (!sheet.deleteRule) { while (Object(Object(sheet.cssRules)[0]).type === 3) sheet.cssRules.splice(0, 1) sheet.cssRules = [] } for (const groupName in rules) { delete rules[groupName] } } /** @type {StyleSheetList} */ const sheets = Object(root).styleSheets || [] // iterate all stylesheets until a hydratable stylesheet is found for (const sheet of sheets) { if (!isSheetAccessible(sheet)) continue for (let index = 0, rules = sheet.cssRules; rules[index]; ++index) { /** @type {CSSStyleRule} Possible indicator rule. */ const check = Object(rules[index]) // a hydratable set of rules will start with a style rule (type: 1), ignore all others if (check.type !== 1) continue /** @type {CSSMediaRule} Possible styling group. */ const group = Object(rules[index + 1]) // a hydratable set of rules will follow with a media rule (type: 4), ignore all others if (group.type !== 4) continue ++index const { cssText } = check // a hydratable style rule will have a selector of `--sxs`, ignore all others if (!cssText.startsWith('--sxs')) continue const cache = cssText.slice(14, -3).trim().split(/\s+/) /** @type {GroupName} Name of the group. */ const groupName = names[cache[0]] // a hydratable style rule will have a parsable group, ignore all others if (!groupName) continue // create a group sheet if one does not already exist if (!groupSheet) groupSheet = { sheet, reset, rules: {}, toString } // add the group to the group sheet groupSheet.rules[groupName] = { group, index, cache: new Set(cache) } } // if a hydratable stylesheet is found, stop looking if (groupSheet) break } // if no hydratable stylesheet is found if (!groupSheet) { const createCSSMediaRule = (/** @type {string} */ sourceCssText, type) => { return /** @type {CSSMediaRule} */ ({ type, cssRules: [], insertRule(cssText, index) { this.cssRules.splice(index, 0, createCSSMediaRule(cssText, { import: 3, undefined: 1 }[(cssText.toLowerCase().match(/^@([a-z]+)/) || [])[1]] || 4)) }, get cssText() { return sourceCssText === '@media{}' ? `@media{${[].map.call(this.cssRules, (cssRule) => cssRule.cssText).join('')}}` : sourceCssText }, }) } const createSheet = () => { if (!root) { return createCSSMediaRule('', 'text/css') } const styleEl = document.createElement('style') const nonce = getNonce() if (nonce) { styleEl.setAttribute('nonce', nonce) } return (root.head || root).appendChild(styleEl).sheet } groupSheet = { sheet: createSheet(), rules: {}, reset, toString, } } const { sheet, rules } = groupSheet for (let i = names.length - 1; i >= 0; --i) { // name of group on current index const name = names[i] if (!rules[name]) { // name of prev group const prevName = names[i + 1] // get the index of that prev group or else get the length of the whole sheet const index = rules[prevName] ? rules[prevName].index : sheet.cssRules.length // insert the grouping & the sxs rule sheet.insertRule('@media{}', index) sheet.insertRule(`--sxs{--sxs:${i}}`, index) // add the group to the group sheet rules[name] = { group: sheet.cssRules[index + 1], index, cache: new Set([i]) } } addApplyToGroup(rules[name]) } } reset() return groupSheet } const addApplyToGroup = (/** @type {RuleGroup} */ group) => { const groupingRule = group.group let index = groupingRule.cssRules.length group.apply = (cssText) => { try { groupingRule.insertRule(cssText, index) ++index } catch (__) { // do nothing and continue } } } /** Pending rules for injection */ const $pr = Symbol() /** * When a stitches component is extending some other random react component, * it’s gonna create a react component (Injector) using this function and then render it after the children, * this way, we would force the styles of the wrapper to be injected after the wrapped component */ export const createRulesInjectionDeferrer = (globalSheet) => { // the injection deferrer function injector() { for (let i = 0; i < injector[$pr].length; i++) { const [sheet, cssString] = injector[$pr][i] globalSheet.rules[sheet].apply(cssString) } injector[$pr] = [] return null } // private prop to store pending rules injector[$pr] = [] // mocking the rules.apply api used on the sheet injector.rules = {} // creating the apply methods under rules[something] names.forEach((sheetName) => (injector.rules[sheetName] = { apply: (rule) => injector[$pr].push([sheetName, rule]) })) return injector } ================================================ FILE: packages/core/src/utility/createMemo.js ================================================ const stringifyReplacer = (name, data) => (typeof data === 'function' ? { '()': Function.prototype.toString.call(data) } : data) const stringify = (value) => JSON.stringify(value, stringifyReplacer) export const createMemo = () => { const cache = Object.create(null) return (value, apply, ...args) => { const vjson = stringify(value) return vjson in cache ? cache[vjson] : (cache[vjson] = apply(value, ...args)) } } ================================================ FILE: packages/core/src/utility/define.js ================================================ /** @type {(target: T, source: any) => T} */ export const define = (target, source) => Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) ================================================ FILE: packages/core/src/utility/getCachedConfig.js ================================================ import { createStitches } from '../createStitches.js' let cachedConfig export const getCachedConfig = () => cachedConfig || (cachedConfig = createStitches()) ================================================ FILE: packages/core/src/utility/getNonce.js ================================================ export const getNonce = () => { if (typeof window.__webpack_nonce__ !== 'undefined') return window.__webpack_nonce__ if (typeof window.nonce !== 'undefined') return window.nonce return null } ================================================ FILE: packages/core/src/utility/hasNames.js ================================================ export const hasNames = (target) => { for (const name in target) return true return false } ================================================ FILE: packages/core/src/utility/hasOwn.js ================================================ const { hasOwnProperty } = Object.prototype export const hasOwn = (target, key) => hasOwnProperty.call(target, key) ================================================ FILE: packages/core/src/utility/index.d.ts ================================================ export type Primitive = string | number | bigint | boolean | symbol export type Optional = Primitive | void export type Try = T1 extends T2 ? T4 : T3 export type ToString = `${T1}` export type ToTailDashed = T1 extends '' ? '' : `${T1}-` ================================================ FILE: packages/core/src/utility/internal.js ================================================ export const internal = Symbol.for('sxs.internal') ================================================ FILE: packages/core/tests/basic.js ================================================ import { createStitches } from '../src/index.js' describe('Basic', () => { test('Existance of methods', () => { const stitches = createStitches() expect(stitches).toBeInstanceOf(Object) expect(stitches.css).toBeInstanceOf(Function) expect(stitches.globalCss).toBeInstanceOf(Function) expect(stitches.keyframes).toBeInstanceOf(Function) expect(stitches.createTheme).toBeInstanceOf(Function) }) test('Functionality of getCssText()', () => { const { getCssText } = createStitches() expect(getCssText()).toBe('') }) test('Functionality of css()', () => { const { css, getCssText } = createStitches() const component1of2 = css() const className1of2 = `${component1of2}` const cssString1of2 = getCssText() expect(component1of2).toBeInstanceOf(Function) expect(className1of2).toBe('PJLV') expect(cssString1of2).toBe('') const component2of2 = css({ color: 'DodgerBlue' }) const className2of2 = `${component2of2}` const cssString2of2 = getCssText() expect(component2of2).toBeInstanceOf(Function) expect(className2of2).toBe('c-dataoT') expect(cssString2of2).toBe(`--sxs{--sxs:2 PJLV c-dataoT}@media{.c-dataoT{color:DodgerBlue}}`) }) test('Functionality of reset()', () => { const { reset, getCssText } = createStitches() expect(reset).toBeInstanceOf(Function) expect(getCssText()).toBe('') reset() expect(getCssText()).toBe('') }) test('Functionality of globalCss()', () => { const { globalCss, getCssText } = createStitches() const rendering1of2 = globalCss() const className1of2 = `${rendering1of2}` const cssString1of2 = getCssText() expect(rendering1of2).toBeInstanceOf(Function) expect(className1of2).toBe('') expect(cssString1of2).toBe('') const rendering2of2 = globalCss({ body: { margin: 0 } }) const className2of2 = `${rendering2of2}` const cssString2of2 = getCssText() expect(rendering2of2).toBeInstanceOf(Function) expect(className2of2).toBe('') expect(cssString2of2).toBe(`--sxs{--sxs:1 cSHHDh}@media{body{margin:0}}`) }) test('Functionality of keyframes()', () => { const { keyframes, getCssText } = createStitches() const rendering1of1 = keyframes({ '0%': { color: 'Black', }, '100%': { color: 'White', }, }) const className1of1 = `${rendering1of1}` const cssString1of1 = getCssText() expect(rendering1of1).toBeInstanceOf(Function) expect(className1of1).toBe('k-jOrSYg') expect(cssString1of1).toBe(`--sxs{--sxs:1 k-jOrSYg}@media{@keyframes k-jOrSYg{0%{color:Black}100%{color:White}}}`) }) test('Functionality of createTheme()', () => { const { createTheme, getCssText } = createStitches() const rendering1of1 = createTheme({ colors: { red: 'Crimson', blue: 'DodgerBlue', }, }) const className1of1 = `${rendering1of1}` const cssString1of1 = getCssText() expect(rendering1of1).toBeInstanceOf(Object) expect(className1of1).toBe('t-kfidiM') expect(cssString1of1).toBe(`--sxs{--sxs:0 t-kfidiM}@media{.t-kfidiM{--colors-red:Crimson;--colors-blue:DodgerBlue}}`) }) test('Functionality of css() — css prop', () => { const { css, getCssText } = createStitches() const component1of1 = css({ color: 'DodgerBlue' }) const className1of1 = `${component1of1({ css: { color: 'Crimson' } })}` const cssString1of1 = getCssText() expect(component1of1).toBeInstanceOf(Function) expect(className1of1).toBe('c-dataoT c-dataoT-icaIZdx-css') expect(cssString1of1).toBe( `--sxs{--sxs:2 c-dataoT}@media{` + `.c-dataoT{color:DodgerBlue}` + `}` + `--sxs{--sxs:6 c-dataoT-icaIZdx-css}@media{` + `.c-dataoT-icaIZdx-css{color:Crimson}` + `}` ) }) test('Functionality of css() — variants', () => { const { css, getCssText } = createStitches() const component1of1 = css({ fontSize: '100%', variants: { shade: { red: { color: 'Crimson', }, blue: { color: 'DodgerBlue', }, }, }, }) const className1of1 = `${component1of1({ shade: 'red' })}` const cssString1of1 = getCssText() expect(component1of1).toBeInstanceOf(Function) expect(className1of1).toBe('c-imTdEZ c-imTdEZ-caIZdx-shade-red') expect(cssString1of1).toBe(`--sxs{--sxs:2 c-imTdEZ}@media{.c-imTdEZ{font-size:100%}}--sxs{--sxs:3 c-imTdEZ-caIZdx-shade-red}@media{.c-imTdEZ-caIZdx-shade-red{color:Crimson}}`) }) test('Functionality of css() — utils', () => { const { css, getCssText } = createStitches({ utils: { userSelect: (value) => ({ WebkitUserSelector: value, userSelect: value, }), }, }) const component1of1 = css({ userSelect: 'none', }) const className1of1 = `${component1of1()}` const cssString1of1 = getCssText() expect(className1of1).toBe('c-bStdfw') expect(cssString1of1).toBe(`--sxs{--sxs:2 c-bStdfw}@media{.c-bStdfw{-webkit-user-selector:none;user-select:none}}`) }) test('Functionality of stringification — numeric pixel values', () => { const { css, getCssText } = createStitches() const component1of1 = css({ width: 100, }) const className1of1 = `${component1of1()}` const cssString1of1 = getCssText() expect(className1of1).toBe('c-eBcQxc') expect(cssString1of1).toBe(`--sxs{--sxs:2 c-eBcQxc}@media{.c-eBcQxc{width:100px}}`) }) test('Functionality of stringification — token values', () => { const { css, getCssText } = createStitches() const component1of1 = css({ width: '$brand', }) const className1of1 = `${component1of1()}` const cssString1of1 = getCssText() expect(className1of1).toBe('c-lpaZZu') expect(cssString1of1).toBe(`--sxs{--sxs:2 c-lpaZZu}@media{.c-lpaZZu{width:var(--sizes-brand)}}`) }) test('Functionality of stringification — local tokens', () => { const { css, getCssText } = createStitches() const component1of1 = css({ $$brand: '500px', width: '$$brand', }) const className1of1 = `${component1of1()}` const cssString1of1 = getCssText() expect(className1of1).toBe('c-elRGCe') expect(cssString1of1).toBe(`--sxs{--sxs:2 c-elRGCe}@media{.c-elRGCe{---brand:500px;width:var(---brand)}}`) }) test('Functionality of stringification — local tokens prefixed', () => { const { css, getCssText } = createStitches({ prefix: 'fusion', }) const component1of1 = css({ $$brand: '500px', width: '$$brand', }) const className1of1 = `${component1of1()}` const cssString1of1 = getCssText() expect(className1of1).toBe('fusion-c-elRGCe') expect(cssString1of1).toBe(`--sxs{--sxs:2 fusion-c-elRGCe}@media{.fusion-c-elRGCe{--fusion--brand:500px;width:var(--fusion--brand)}}`) }) test('Stringification: Utils + Local Tokens', () => { const { css, getCssText } = createStitches({ utils: { backdropFilter: (value) => ({ WebkitBackdropFilter: value, backdropFilter: value, }), }, }) const component1of1 = css({ $$blur: 'test', backdropFilter: '$$blur', }) const className1of1 = `${component1of1()}` const cssString1of1 = getCssText() expect(className1of1).toBe('c-brAtkJ') expect(cssString1of1).toBe(`--sxs{--sxs:2 c-brAtkJ}@media{.c-brAtkJ{---blur:test;-webkit-backdrop-filter:var(---blur);backdrop-filter:var(---blur)}}`) }) test('Theme', () => { const { getCssText } = createStitches({ theme: { colors: { red: 'Crimson', blue: 'DodgerBlue', }, }, }) expect(getCssText()).toBe(`--sxs{--sxs:0 t-kfidiM}@media{:root,.t-kfidiM{--colors-red:Crimson;--colors-blue:DodgerBlue}}`) }) }) ================================================ FILE: packages/core/tests/component-composition.js ================================================ import { createStitches } from '../src/index.js' describe('Composition', () => { test('Renders an empty component', () => { const { css, toString } = createStitches() const generic = css() expect(generic().props).toEqual({ className: 'PJLV' }) expect(toString()).toBe('') }) test('Renders a component as the final composition by default', () => { const { css, toString } = createStitches() const red = css({ color: 'red' }) const size14 = css({ fontSize: '14px' }) const bold = css({ fontWeight: 'bold' }) const title = css(red, size14, bold, { fontFamily: 'monospace' }) expect(title.className).toBe('c-gmqXFB') expect(toString()).toBe('') expect(String(title)).toBe('c-gmqXFB') expect(toString()).toBe( `--sxs{--sxs:2 c-gmqXFB c-hzkWus c-cQFdVt c-kngyIZ}@media{` + `.c-gmqXFB{color:red}` + `.c-hzkWus{font-size:14px}` + `.c-cQFdVt{font-weight:bold}` + `.c-kngyIZ{font-family:monospace}` + `}` ) }) test('Renders a component with all compositions', () => { const { css, toString } = createStitches() const red = css({ color: 'red' }) const size14 = css({ fontSize: '14px' }) const bold = css({ fontWeight: 'bold' }) const title = css(red, size14, bold, { fontFamily: 'monospace' }) expect(title().className).toBe('c-gmqXFB c-hzkWus c-cQFdVt c-kngyIZ') expect(toString()).toBe( `--sxs{--sxs:2 c-gmqXFB c-hzkWus c-cQFdVt c-kngyIZ}@media{` + `.c-gmqXFB{color:red}` + `.c-hzkWus{font-size:14px}` + `.c-cQFdVt{font-weight:bold}` + `.c-kngyIZ{font-family:monospace}` + `}` ) }) }) ================================================ FILE: packages/core/tests/component-conditions.js ================================================ import { createStitches } from '../src/index.js' describe('Component Medias', () => { test('Authors can define medias applied to components', () => { const { css, toString } = createStitches({ media: { mediumUp: '(width >= 768px)', }, }) css({ 'fontSize': '16px', '@mediumUp': { fontSize: '24px', }, })() expect(toString()).toBe( `--sxs{--sxs:2 c-jEGvho}@media{` + `.c-jEGvho{font-size:16px}` + `@media (min-width:768px){.c-jEGvho{font-size:24px}}` + `}`, ) }) }) ================================================ FILE: packages/core/tests/component-css-prop.js ================================================ import { createStitches } from '../src/index.js' describe('Component with CSS prop', () => { test('Authors can create a component and pass it a css prop of overrides', () => { const { css, toString } = createStitches({ media: { bp0: '(width < 768px)', bp1: '(768px <= width < 1400px)', bp2: '(1400px <= width)', }, }) css({ order: 1, })({ css: { order: 2, }, }) expect(toString()).toBe( `--sxs{--sxs:2 c-hhyRYU}@media{` + `.c-hhyRYU{order:1}` + `}` + `--sxs{--sxs:6 c-hhyRYU-ilhKMMn-css}@media{` + `.c-hhyRYU-ilhKMMn-css{order:2}` + `}` ) }) }) ================================================ FILE: packages/core/tests/component-empty-variants.js ================================================ import { createStitches } from '../src/index.js' describe('Empty Variants', () => { test('Empty Variants', () => { const { css, getCssText } = createStitches() css({ variants: { size: { xl: {}, }, tone: { primary: {}, }, }, compoundVariants: [ { tone: 'primary', size: 'xl', }, ], })({ tone: 'primary', size: { '@initial': 'xl' }, }) expect(getCssText()).toBe('') }) test('Empty Variants', () => { const { css, getCssText } = createStitches() css({ variants: { size: { xl: {}, }, tone: { primary: {}, }, }, compoundVariants: [ { tone: 'primary', size: 'xl', css: { fontSize: '24px', color: 'black' }, }, ], })({ tone: 'primary', size: { '@initial': 'xl' }, }) expect(getCssText()).toBe( `--sxs{--sxs:5 c-PJLV-lhHHWD-cv}@media{` + `.c-PJLV-lhHHWD-cv{font-size:24px;color:black}` + `}` ) }) }) ================================================ FILE: packages/core/tests/component-utils-and-types.js ================================================ import { createStitches } from '../src/index.js' describe('Component: Utilities & Tokens', () => { test('Utilities & Tokens of the same type', () => { const { css, toString } = createStitches({ utils: { px: (value) => ({ paddingLeft: value, paddingRight: value, }), }, }) css({ px: 15, })() expect(toString()).toBe(`--sxs{--sxs:2 c-ccgTVz}@media{.c-ccgTVz{padding-left:15px;padding-right:15px}}`) }) test('Utilities & Tokens of different types', () => { const { css, toString } = createStitches({ utils: { ftw: (value) => ({ color: value, paddingLeft: value, paddingRight: value, }), }, }) css({ ftw: '$sp', })() expect(toString()).toBe(`--sxs{--sxs:2 c-ilqzId}@media{.c-ilqzId{color:var(--colors-sp);padding-left:var(--space-sp);padding-right:var(--space-sp)}}`) }) }) ================================================ FILE: packages/core/tests/component-variants.js ================================================ import { createStitches } from '../src/index.js' describe('Variants', () => { const componentConfig = { variants: { color: { blue: { backgroundColor: 'dodgerblue', color: 'white', }, red: { backgroundColor: 'tomato', color: 'white', }, }, size: { small: { fontSize: '16px', }, large: { fontSize: '24px', }, }, level: { 1: { padding: '0.5em', }, 2: { padding: '1em', }, }, }, compoundVariants: [ { size: 'small', color: 'blue', css: { transform: 'scale(1.2)', }, }, ], } test('Renders a component without any initial styles', () => { const { css, getCssText } = createStitches() const component = css(componentConfig) const expression = component() expect(expression.className).toBe('c-PJLV') expect(getCssText()).toBe('') }) test('Renders a component with 1 matching variant', () => { const { css, getCssText } = createStitches() const component = css(componentConfig) const expression1 = component({ size: 'small' }) const expression1CssText = '.c-PJLV-Gaggi-size-small{font-size:16px}' expect(expression1.className).toBe('c-PJLV c-PJLV-Gaggi-size-small') expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-Gaggi-size-small}@media{${expression1CssText}}`) const expression2 = component({ color: 'blue' }) const expression2CssText = '.c-PJLV-kaCQqN-color-blue{background-color:dodgerblue;color:white}' expect(expression2.className).toBe('c-PJLV c-PJLV-kaCQqN-color-blue') expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-Gaggi-size-small c-PJLV-kaCQqN-color-blue}@media{${expression1CssText + expression2CssText}}`) }) test('Renders a component with 2 matching variants', () => { const { css, getCssText } = createStitches() const component = css({ variants: { size: { small: { fontSize: '16px', }, large: { fontSize: '24px', }, }, level: { 1: { padding: '0.5em', }, 2: { padding: '1em', }, }, } }) const expression = component({ size: 'small', level: 1 }) expect(expression.className).toBe('c-PJLV c-PJLV-Gaggi-size-small c-PJLV-iRwLiB-level-1') const expressionSizeSmallCssText = '.c-PJLV-Gaggi-size-small{font-size:16px}' const expressionLevel1CssText = '.c-PJLV-iRwLiB-level-1{padding:0.5em}' expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-Gaggi-size-small c-PJLV-iRwLiB-level-1}@media{${expressionSizeSmallCssText + expressionLevel1CssText}}`) }) test('Renders a component with a 2 matching variants and 1 matching compound', () => { const { css, getCssText } = createStitches() const component = css(componentConfig) const expression = component({ size: 'small', color: 'blue' }) const expressionColorBlueCssText = '.c-PJLV-kaCQqN-color-blue{background-color:dodgerblue;color:white}' const expressionSizeSmallCssText = '.c-PJLV-Gaggi-size-small{font-size:16px}' const expressionCompoundCssText = '.c-PJLV-cChFtv-cv{transform:scale(1.2)}' expect(expression.className).toBe(`c-PJLV c-PJLV-kaCQqN-color-blue c-PJLV-Gaggi-size-small c-PJLV-cChFtv-cv`) expect(getCssText()).toBe( `--sxs{--sxs:3 c-PJLV-kaCQqN-color-blue c-PJLV-Gaggi-size-small}@media{${ expressionColorBlueCssText + expressionSizeSmallCssText }}--sxs{--sxs:5 c-PJLV-cChFtv-cv}@media{${ expressionCompoundCssText }}` ) }) }) describe('Variants with defaults', () => { const componentConfig = { variants: { color: { blue: { backgroundColor: 'dodgerblue', color: 'white', }, red: { backgroundColor: 'tomato', color: 'white', }, }, size: { small: { fontSize: '16px', }, large: { fontSize: '24px', }, }, level: { 1: { padding: '0.5em', }, 2: { padding: '1em', }, }, }, compoundVariants: [ { size: 'small', color: 'blue', css: { transform: 'scale(1.2)', }, }, ], defaultVariants: { size: 'small', }, } test('Renders a component with the default variant applied', () => { const { css, getCssText } = createStitches() const component = css(componentConfig) const expression = component() expect(expression.className).toBe('c-PJLV c-PJLV-Gaggi-size-small') expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-Gaggi-size-small}@media{.c-PJLV-Gaggi-size-small{font-size:16px}}`) }) test('Renders a component with the default variant explicitly applied', () => { const { css, getCssText } = createStitches() const component = css(componentConfig) const expression = component({ size: 'small' }) expect(expression.className).toBe('c-PJLV c-PJLV-Gaggi-size-small') expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-Gaggi-size-small}@media{.c-PJLV-Gaggi-size-small{font-size:16px}}`) }) test('Renders a component with the non-default variant explicitly applied', () => { const { css, getCssText } = createStitches() const component = css(componentConfig) const expression = component({ size: 'large' }) expect(expression.className).toBe('c-PJLV c-PJLV-hsYHIj-size-large') expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-hsYHIj-size-large}@media{.c-PJLV-hsYHIj-size-large{font-size:24px}}`) }) test('Renders a component with the default variant applied and a different variant explicitly applied', () => { const { css, getCssText } = createStitches() const component = css(componentConfig) const expression = component({ level: 1 }) expect(expression.className).toBe('c-PJLV c-PJLV-Gaggi-size-small c-PJLV-iRwLiB-level-1') expect(getCssText()).toBe( `--sxs{--sxs:3 c-PJLV-Gaggi-size-small c-PJLV-iRwLiB-level-1}@media{` + // implicit size:small `.c-PJLV-Gaggi-size-small{font-size:16px}` + // explicit level:1 `.c-PJLV-iRwLiB-level-1{padding:0.5em}` + `}`, ) }) test('Renders a component with the default variant applied, a different variant explicitly applied, and a compound applied', () => { const { css, getCssText } = createStitches() const component = css(componentConfig) const expression = component({ color: 'blue' }) expect(expression.className).toBe('c-PJLV c-PJLV-kaCQqN-color-blue c-PJLV-Gaggi-size-small c-PJLV-cChFtv-cv') expect(getCssText()).toBe( `--sxs{--sxs:3 c-PJLV-kaCQqN-color-blue c-PJLV-Gaggi-size-small}@media{` + // explicit color:blue `.c-PJLV-kaCQqN-color-blue{background-color:dodgerblue;color:white}` + // implicit size:small `.c-PJLV-Gaggi-size-small{font-size:16px}` + `}--sxs{--sxs:5 c-PJLV-cChFtv-cv}@media{` + // compound color:blue + size:small `.c-PJLV-cChFtv-cv{transform:scale(1.2)}` + `}`, ) }) test('Returns a component class without the default variant applied when stringified', () => { const { css, getCssText } = createStitches() const component = css(componentConfig) const className = `${component}` expect(className).toBe('c-PJLV') expect(getCssText()).toBe('--sxs{--sxs:3 c-PJLV-Gaggi-size-small}@media{.c-PJLV-Gaggi-size-small{font-size:16px}}') }) }) describe('Conditional variants', () => { const config = { media: { bp1: '(max-width: 767px)', bp2: '(min-width: 768px)', }, } /** Component with variants and compound variants */ const componentConfig = { variants: { color: { blue: { backgroundColor: 'dodgerblue', color: 'white', }, red: { backgroundColor: 'tomato', color: 'white', }, }, size: { small: { fontSize: '16px', }, large: { fontSize: '24px', }, }, level: { 1: { padding: '0.5em', }, 2: { padding: '1em', }, }, }, compoundVariants: [ { size: 'small', color: 'blue', css: { transform: 'scale(1.2)', }, }, ], } test('Renders a component with no variant applied', () => { const { css, getCssText } = createStitches(config) const component = css(componentConfig) const componentClassName = 'c-PJLV' expect(component().className).toBe(componentClassName) expect(getCssText()).toBe('') }) test('Renders a component with one variant applied', () => { const { css, getCssText } = createStitches(config) const component = css(componentConfig) const componentClassName = `c-PJLV` const componentSmallClassName = `${componentClassName}-Gaggi-size-small` const componentSmallCssText = `.${componentSmallClassName}{font-size:16px}` expect(component({ size: 'small' }).className).toBe([componentClassName, componentSmallClassName].join(' ')) expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-Gaggi-size-small}@media{${componentSmallCssText}}`) }) test('Renders a component with one conditional variant on one breakpoint applied', () => { const { css, getCssText } = createStitches(config) const component = css(componentConfig) expect(component({ size: { '@bp1': 'small' } }).className).toBe(`c-PJLV c-PJLV-fHtTAQ-size-small`) expect(getCssText()).toBe( `--sxs{--sxs:4 c-PJLV-fHtTAQ-size-small}@media{` + `@media (max-width: 767px){.c-PJLV-fHtTAQ-size-small{font-size:16px}}` + `}` ) }) test('Renders a component with one conditional variant on two breakpoints applied', () => { const { css, getCssText } = createStitches(config) const component = css(componentConfig) const componentClassName = `c-PJLV` const componentSmallBp1ClassName = `${componentClassName}-fHtTAQ-size-small` const componentLargeBp2ClassName = `${componentClassName}-XwbVw-size-large` const componentSmallBp1CssText = `@media (max-width: 767px){.${componentSmallBp1ClassName}{font-size:16px}}` const componentLargeBp2CssText = `@media (min-width: 768px){.${componentLargeBp2ClassName}{font-size:24px}}` expect(component({ size: { '@bp1': 'small', '@bp2': 'large' } }).className).toBe([componentClassName, componentSmallBp1ClassName, componentLargeBp2ClassName].join(' ')) expect(getCssText()).toBe( `--sxs{--sxs:4 c-PJLV-fHtTAQ-size-small c-PJLV-XwbVw-size-large}@media{` + componentSmallBp1CssText + componentLargeBp2CssText + `}` ) }) test('Renders a component with a conditional variant repeatedly', () => { const { css, getCssText } = createStitches(config) const component = css(componentConfig) expect(component({ size: { '@bp1': 'small', '@bp2': 'large' } }).className).toBe(`c-PJLV c-PJLV-fHtTAQ-size-small c-PJLV-XwbVw-size-large`) expect(getCssText()).toBe( `--sxs{--sxs:4 c-PJLV-fHtTAQ-size-small c-PJLV-XwbVw-size-large}@media{` + `@media (max-width: 767px){.c-PJLV-fHtTAQ-size-small{font-size:16px}}` + `@media (min-width: 768px){.c-PJLV-XwbVw-size-large{font-size:24px}}` + `}` ) expect(component({ size: { '@bp1': 'small', '@bp2': 'large' } }).className).toBe(`c-PJLV c-PJLV-fHtTAQ-size-small c-PJLV-XwbVw-size-large`) expect(getCssText()).toBe( `--sxs{--sxs:4 c-PJLV-fHtTAQ-size-small c-PJLV-XwbVw-size-large}@media{` + `@media (max-width: 767px){.c-PJLV-fHtTAQ-size-small{font-size:16px}}` + `@media (min-width: 768px){.c-PJLV-XwbVw-size-large{font-size:24px}}` + `}` ) expect(component({ size: { '@bp1': 'small', '@bp2': 'large' } }).className).toBe(`c-PJLV c-PJLV-fHtTAQ-size-small c-PJLV-XwbVw-size-large`) expect(getCssText()).toBe( `--sxs{--sxs:4 c-PJLV-fHtTAQ-size-small c-PJLV-XwbVw-size-large}@media{` + `@media (max-width: 767px){.c-PJLV-fHtTAQ-size-small{font-size:16px}}` + `@media (min-width: 768px){.c-PJLV-XwbVw-size-large{font-size:24px}}` + `}` ) }) test('Renders a component with a conditional inline variant repeatedly', () => { { const { css, getCssText } = createStitches(config) const component = css({ variants: { size: { small: { fontSize: '16px', }, large: { fontSize: '24px', }, }, }, }) expect( component({ size: { '@media (width < 768px)': 'small', '@media (width >= 768px)': 'large', }, }).className, ).toBe('c-PJLV c-PJLV-gjWYHE-size-small c-PJLV-fzmUzy-size-large') expect(getCssText()).toBe( `--sxs{--sxs:4 c-PJLV-gjWYHE-size-small c-PJLV-fzmUzy-size-large}@media{` + `@media (max-width:767.9375px){.c-PJLV-gjWYHE-size-small{font-size:16px}}` + `@media (min-width:768px){.c-PJLV-fzmUzy-size-large{font-size:24px}}` + `}` ) } { const { css, getCssText } = createStitches(config) const component = css({ variants: { size: { large: { fontSize: '24px', }, small: { fontSize: '16px', }, }, }, }) expect( component({ size: { '@media (width < 768px)': 'small', '@media (width >= 768px)': 'large', }, }).className, ).toBe('c-PJLV c-PJLV-gjWYHE-size-small c-PJLV-fzmUzy-size-large') expect(getCssText()).toBe( `--sxs{--sxs:4 c-PJLV-gjWYHE-size-small c-PJLV-fzmUzy-size-large}@media{` + `@media (max-width:767.9375px){.c-PJLV-gjWYHE-size-small{font-size:16px}}` + `@media (min-width:768px){.c-PJLV-fzmUzy-size-large{font-size:24px}}` + `}` ) } }) }) describe('Variant pairing types', () => { const componentConfigForBooleanVariant = { '--component': true, variants: { testBoolean: { true: { '--test-boolean': true, }, false: { '--test-boolean': false, } } } } test('Renders a variant with an inactive string variant', () => { const { css, getCssText } = createStitches() const component = css(componentConfigForBooleanVariant) const rendering = component() expect(rendering.className).toBe('c-foEXqW') expect(getCssText()).toBe(`--sxs{--sxs:2 c-foEXqW}@media{` + `.c-foEXqW{--component:true}` + `}`) }) test('Renders a variant with an active string variant', () => { const { css, getCssText } = createStitches() const component = css(componentConfigForBooleanVariant) const rendering = component({ testBoolean: 'true' }) expect(rendering.className).toBe('c-foEXqW c-foEXqW-iloXEi-testBoolean-true') expect(getCssText()).toBe( `--sxs{--sxs:2 c-foEXqW}@media{` + `.c-foEXqW{--component:true}` + `}` + `--sxs{--sxs:3 c-foEXqW-iloXEi-testBoolean-true}@media{` + `.c-foEXqW-iloXEi-testBoolean-true{--test-boolean:true}` + `}` ) }) test('Renders a variant with an active boolean variant', () => { const { css, getCssText } = createStitches() const component = css(componentConfigForBooleanVariant) const rendering = component({ testBoolean: true }) expect(rendering.className).toBe('c-foEXqW c-foEXqW-iloXEi-testBoolean-true') expect(getCssText()).toBe( `--sxs{--sxs:2 c-foEXqW}@media{` + `.c-foEXqW{--component:true}` + `}` + `--sxs{--sxs:3 c-foEXqW-iloXEi-testBoolean-true}@media{` + `.c-foEXqW-iloXEi-testBoolean-true{--test-boolean:true}` + `}` ) }) test('Renders a variant with an active responsive string variant', () => { const { css, getCssText } = createStitches() const component = css(componentConfigForBooleanVariant) const rendering = component({ testBoolean: { '@media (min-width: 640px)': 'true' } }) expect(rendering.className).toBe('c-foEXqW c-foEXqW-brOaTK-testBoolean-true') expect(getCssText()).toBe( `--sxs{--sxs:2 c-foEXqW}@media{` + `.c-foEXqW{--component:true}` + `}` + `--sxs{--sxs:4 c-foEXqW-brOaTK-testBoolean-true}@media{` + `@media (min-width: 640px){` + `.c-foEXqW-brOaTK-testBoolean-true{--test-boolean:true}` + `}` + `}` ) }) test('Renders a variant with an active responsive boolean variant', () => { const { css, getCssText } = createStitches() const component = css(componentConfigForBooleanVariant) const rendering = component({ testBoolean: { '@media (min-width: 640px)': true } }) expect(rendering.className).toBe('c-foEXqW c-foEXqW-brOaTK-testBoolean-true') expect(getCssText()).toBe( `--sxs{--sxs:2 c-foEXqW}@media{` + `.c-foEXqW{--component:true}` + `}` + `--sxs{--sxs:4 c-foEXqW-brOaTK-testBoolean-true}@media{` + `@media (min-width: 640px){` + `.c-foEXqW-brOaTK-testBoolean-true{--test-boolean:true}` + `}` + `}` ) }) }) ================================================ FILE: packages/core/tests/global-atrules.js ================================================ import { createStitches } from '../src/index.js' describe('Support @import', () => { test('Authors can define an @import rule', () => { const { globalCss, getCssText } = createStitches() const importURL = `https://unpkg.com/sanitize.css@12.0.1/sanitize.css` globalCss({ '@import': `"${importURL}"`, })() expect(getCssText()).toBe(`@import "${importURL}";`) }) test('Authors can define multiple @import rules', () => { const { globalCss, getCssText } = createStitches() const importURL1 = `https://unpkg.com/sanitize.css@12.0.1/sanitize.css` const importURL2 = `https://unpkg.com/sanitize.css@12.0.1/typography.css` globalCss({ '@import': [`"${importURL1}"`, `"${importURL2}"`], })() expect(getCssText()).toBe(`@import "${importURL1}";@import "${importURL2}";`) }) test('Authors can an @import rule without quotes', () => { const { globalCss, getCssText } = createStitches() const importURL = `https://unpkg.com/sanitize.css@12.0.1/sanitize.css` globalCss({ '@import': importURL, })() expect(getCssText()).toBe(`@import "${importURL}";`) }) }) describe('Support @font-face', () => { test('Authors can define a @font-face rule', () => { const { globalCss, getCssText } = createStitches() globalCss({ '@font-face': { fontFamily: 'system-ui', fontStyle: 'normal', fontWeight: 400, src: [ `local(".SFNS-Regular")`, `local(".SFNSText-Regular")`, `local(".HelveticaNeueDeskInterface-Regular")`, `local(".LucidaGrandeUI")`, `local("Segoe UI")`, `local("Ubuntu")`, `local("Roboto-Regular")`, `local("DroidSans")`, `local("Tahoma")`, ], }, })() expect(getCssText()).toBe( `--sxs{--sxs:1 PCbjJ}` + `@media{` + `@font-face{` + `font-family:system-ui;` + `font-style:normal;` + `font-weight:400;` + `src:local(".SFNS-Regular"),local(".SFNSText-Regular"),local(".HelveticaNeueDeskInterface-Regular"),local(".LucidaGrandeUI"),local("Segoe UI"),local("Ubuntu"),local("Roboto-Regular"),local("DroidSans"),local("Tahoma")` + `}` + `}`, ) }) test('Authors can define multiple @font-face rules', () => { const { globalCss, getCssText } = createStitches() globalCss({ '@font-face': [ { fontFamily: 'system-ui', fontStyle: 'normal', fontWeight: 400, src: [ `local(".SFNS-Regular")`, `local(".SFNSText-Regular")`, `local(".HelveticaNeueDeskInterface-Regular")`, `local(".LucidaGrandeUI")`, `local("Segoe UI")`, `local("Ubuntu")`, `local("Roboto-Regular")`, `local("DroidSans")`, `local("Tahoma")`, ], }, { fontFamily: 'system-ui', fontStyle: 'italic', fontWeight: 400, src: [ `local(".SFNS-Italic")`, `local(".SFNSText-Italic")`, `local(".HelveticaNeueDeskInterface-Italic")`, `local(".LucidaGrandeUI")`, `local("Segoe UI Italic")`, `local("Ubuntu Italic")`, `local("Roboto-Italic")`, `local("DroidSans")`, `local("Tahoma")`, ], }, ], })() expect(getCssText()).toBe( `--sxs{--sxs:1 JJHhj}` + `@media{` + `@font-face{` + `font-family:system-ui;` + `font-style:normal;` + `font-weight:400;` + `src:local(".SFNS-Regular"),local(".SFNSText-Regular"),local(".HelveticaNeueDeskInterface-Regular"),local(".LucidaGrandeUI"),local("Segoe UI"),local("Ubuntu"),local("Roboto-Regular"),local("DroidSans"),local("Tahoma")` + `}` + `@font-face{` + `font-family:system-ui;` + `font-style:italic;` + `font-weight:400;` + `src:local(".SFNS-Italic"),local(".SFNSText-Italic"),local(".HelveticaNeueDeskInterface-Italic"),local(".LucidaGrandeUI"),local("Segoe UI Italic"),local("Ubuntu Italic"),local("Roboto-Italic"),local("DroidSans"),local("Tahoma")` + `}` + `}` ) }) }) ================================================ FILE: packages/core/tests/issue-450.js ================================================ import { createStitches } from '../src/index.js' describe('Issue #450', () => { test('Basic Tests', () => { const getFreshComponents = () => { const { css, getCssText } = createStitches() const component1 = css({ variants: { color: { red: { color: 'red', }, blue: { color: 'blue', }, }, }, defaultVariants: { color: 'red', }, }); const component2 = css(component1, { variants: { color: { orange: { color: 'orange', }, }, }, defaultVariants: { color: 'orange', }, }); const component3 = css(component2, { variants: { color: { purple: { color: 'rebeccapurple', }, }, }, defaultVariants: { color: 'purple', }, }) return { component1, component2, component3, getCssText } } test('Render component1() as red, inherited from defaultVariants', () => { const { component1, getCssText } = getFreshComponents() const render = component1() expect(render.className).toBe(`c-PJLV c-PJLV-gmqXFB-color-red`) expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-gmqXFB-color-red}@media{.c-PJLV-gmqXFB-color-red{color:red}}`) }) test('Render component1({ color: "blue" }) as blue, assigned from props', () => { const { component1, getCssText } = getFreshComponents() const render = component1({ color: 'blue' }) expect(render.className).toBe(`c-PJLV c-PJLV-kydkiA-color-blue`) expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-kydkiA-color-blue}@media{.c-PJLV-kydkiA-color-blue{color:blue}}`) }) test('Render component1({ color: "red" }) as red, assigned from props', () => { const { component1, getCssText } = getFreshComponents() const render = component1({ color: 'red' }) expect(render.className).toBe(`c-PJLV c-PJLV-gmqXFB-color-red`) expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-gmqXFB-color-red}@media{.c-PJLV-gmqXFB-color-red{color:red}}`) }) test('Render component1({ color: { "@media (width >= 640px)": "blue" } }) as red then blue, inherited from defaultVariants, assigned from props', () => { const { component1, getCssText } = getFreshComponents() const render = component1({ color: { '@media (min-width: 640px)': 'blue' } }) expect(render.className).toBe(`c-PJLV c-PJLV-gmqXFB-color-red c-PJLV-bBevdw-color-blue`) expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-gmqXFB-color-red}@media{.c-PJLV-gmqXFB-color-red{color:red}}--sxs{--sxs:4 c-PJLV-bBevdw-color-blue}@media{@media (min-width: 640px){.c-PJLV-bBevdw-color-blue{color:blue}}}`) }) test('Render component2() as orange, inherited from defaultVariants', () => { const { component2, getCssText } = getFreshComponents() const render = component2() expect(render.className).toBe(`c-PJLV c-PJLV-vMTTG-color-orange`) expect(getCssText()).toBe(`--sxs{--sxs:3 c-PJLV-vMTTG-color-orange}@media{.c-PJLV-vMTTG-color-orange{color:orange}}`) }) test('Render component2({ color: { "@media (width >= 640px)": "blue" } }) as orange then blue, inherited from defaultVariants, assigned from props', () => { const { component2, getCssText } = getFreshComponents() const render = component2({ color: { '@media (min-width: 640px)': 'blue' } }) expect(render.className).toBe(`c-PJLV c-PJLV-bBevdw-color-blue c-PJLV-vMTTG-color-orange`) expect(getCssText()).toBe( `--sxs{--sxs:3 c-PJLV-vMTTG-color-orange}` + `@media{.c-PJLV-vMTTG-color-orange{color:orange}}` + `--sxs{--sxs:4 c-PJLV-bBevdw-color-blue}@media{` + `@media (min-width: 640px){.c-PJLV-bBevdw-color-blue{color:blue}}` + `}`, ) }) }) test('Basic Tests ported from the React version', () => { const getFreshComponents = () => { const { css, getCssText } = createStitches() const component1 = css({ '--component': 1, variants: { appearance: { primary: {}, secondary: { '--appearance': 'secondary' }, }, color: { red: {}, purple: { '--color': 'purple' }, lightBlue: { '--color': 'lightBlue' }, }, }, compoundVariants: [ { appearance: 'secondary', color: 'lightBlue', css: { '--compound': 'appearance secondary / color lightBlue', }, }, ], defaultVariants: { appearance: 'primary', color: 'red', }, }) const component2 = css(component1, { '--component': 2, 'defaultVariants': { appearance: 'secondary', color: 'lightBlue', }, }) return { component1, component2, getCssText } } test('Render component1()', () => { const { component1, getCssText } = getFreshComponents() const render = component1() expect(render.className).toBe(`c-jyxqjt`) expect(getCssText()).toBe(`--sxs{--sxs:2 c-jyxqjt}@media{.c-jyxqjt{--component:1}}`) }) test('Render component1({ color: "lightBlue" })', () => { const { component1, getCssText } = getFreshComponents() const render = component1({ color: 'lightBlue' }) expect(render.className).toBe(`c-jyxqjt c-jyxqjt-ilDyRi-color-lightBlue`) expect(getCssText()).toBe( `--sxs{--sxs:2 c-jyxqjt}@media{` + `.c-jyxqjt{--component:1}` + `}` + `--sxs{--sxs:3 c-jyxqjt-ilDyRi-color-lightBlue}@media{` + `.c-jyxqjt-ilDyRi-color-lightBlue{--color:lightBlue}` + `}` ) }) test('Render component1({ appearance: "secondary" })', () => { const { component1, getCssText } = getFreshComponents() const render = component1({ appearance: 'secondary' }) expect(render.className).toBe(`c-jyxqjt c-jyxqjt-cOChOn-appearance-secondary`) expect(getCssText()).toBe( `--sxs{--sxs:2 c-jyxqjt}@media{` + `.c-jyxqjt{--component:1}` + `}` + `--sxs{--sxs:3 c-jyxqjt-cOChOn-appearance-secondary}@media{` + `.c-jyxqjt-cOChOn-appearance-secondary{--appearance:secondary}` + `}` ) }) test('Render component1({ appearance: "secondary", color: "lightBlue" })', () => { const { component1, getCssText } = getFreshComponents() const render = component1({ appearance: 'secondary', color: 'lightBlue' }) expect(render.className).toBe(`c-jyxqjt c-jyxqjt-cOChOn-appearance-secondary c-jyxqjt-ilDyRi-color-lightBlue c-jyxqjt-gYqlvA-cv`) expect(getCssText()).toBe( `--sxs{--sxs:2 c-jyxqjt}@media{` + `.c-jyxqjt{--component:1}` + `}` + `--sxs{--sxs:3 c-jyxqjt-cOChOn-appearance-secondary c-jyxqjt-ilDyRi-color-lightBlue}@media{` + `.c-jyxqjt-cOChOn-appearance-secondary{--appearance:secondary}` + `.c-jyxqjt-ilDyRi-color-lightBlue{--color:lightBlue}` + `}` + `--sxs{--sxs:5 c-jyxqjt-gYqlvA-cv}@media{` + `.c-jyxqjt-gYqlvA-cv{--compound:appearance secondary / color lightBlue}` + `}`, ) }) test('Render component2()', () => { const { component2, getCssText } = getFreshComponents() const render = component2() expect(render.className).toBe(`c-jyxqjt c-dkRcuu c-jyxqjt-cOChOn-appearance-secondary c-jyxqjt-ilDyRi-color-lightBlue c-jyxqjt-gYqlvA-cv`) expect(getCssText()).toBe( `--sxs{--sxs:2 c-jyxqjt c-dkRcuu}@media{` + `.c-jyxqjt{--component:1}` + `.c-dkRcuu{--component:2}` + `}` + `--sxs{--sxs:3 c-jyxqjt-cOChOn-appearance-secondary c-jyxqjt-ilDyRi-color-lightBlue}@media{` + `.c-jyxqjt-cOChOn-appearance-secondary{--appearance:secondary}` + `.c-jyxqjt-ilDyRi-color-lightBlue{--color:lightBlue}` + `}` + `--sxs{--sxs:5 c-jyxqjt-gYqlvA-cv}@media{` + `.c-jyxqjt-gYqlvA-cv{--compound:appearance secondary / color lightBlue}` + `}`, ) }) test('Render component2({ appearance: "secondary", color: "lightBlue" })', () => { const { component2, getCssText } = getFreshComponents() const render = component2({ appearance: 'secondary', color: 'lightBlue' }) expect(render.className).toBe(`c-jyxqjt c-dkRcuu c-jyxqjt-cOChOn-appearance-secondary c-jyxqjt-ilDyRi-color-lightBlue c-jyxqjt-gYqlvA-cv`) expect(getCssText()).toBe( `--sxs{--sxs:2 c-jyxqjt c-dkRcuu}@media{` + `.c-jyxqjt{--component:1}` + `.c-dkRcuu{--component:2}` + `}` + `--sxs{--sxs:3 c-jyxqjt-cOChOn-appearance-secondary c-jyxqjt-ilDyRi-color-lightBlue}@media{` + `.c-jyxqjt-cOChOn-appearance-secondary{--appearance:secondary}` + `.c-jyxqjt-ilDyRi-color-lightBlue{--color:lightBlue}` + `}` + `--sxs{--sxs:5 c-jyxqjt-gYqlvA-cv}@media{` + `.c-jyxqjt-gYqlvA-cv{--compound:appearance secondary / color lightBlue}` + `}`, ) }) }) }) ================================================ FILE: packages/core/tests/issue-492.js ================================================ import { createStitches } from '../src/index.js' describe('Issue #492', () => { test('Conditionally apply default variants as the @initial value', () => { const { css, getCssText } = createStitches() const component = css({ variants: { sweet: { caroline: { '--sweet-caroline': true, }, dreams: { '--sweet-dreams': true, }, }, }, defaultVariants: { sweet: 'caroline', }, }) const componentClassName = `c-PJLV` const variantSweetCarolineClassName = `c-PJLV-bVaDOZ-sweet-caroline` const variantSweetDreamsClassName = `c-PJLV-loBWDA-sweet-dreams` const variantResponsiveSweetCarolineClassName = `c-PJLV-iuHgfx-sweet-caroline` const variantResponsiveSweetDreamsClassName = `c-PJLV-cNdtIU-sweet-dreams` /** Rendering of the component as-is. */ const rendering1 = component() expect( rendering1.className ).toBe( `${componentClassName} ${variantSweetCarolineClassName}` ) expect( getCssText() ).toBe( `--sxs{--sxs:3 ${variantSweetCarolineClassName}}@media{` + `.${variantSweetCarolineClassName}{--sweet-caroline:true}` + `}` ) /** Rendering of the component as-is. */ const rendering2 = component({ sweet: { '@media (min-width: 640px)': 'dreams', }, }) expect( rendering2.className ).toBe( `${componentClassName} ${variantSweetCarolineClassName} ${variantResponsiveSweetDreamsClassName}` ) expect(getCssText()).toBe( `--sxs{--sxs:3 ${variantSweetCarolineClassName}}` + `@media{.${variantSweetCarolineClassName}{--sweet-caroline:true}}` + `--sxs{--sxs:4 ${variantResponsiveSweetDreamsClassName}}@media{` + `@media (min-width: 640px){.${variantResponsiveSweetDreamsClassName}{--sweet-dreams:true}}` + `}`, ) /** Rendering of the component as-is. */ const rendering3 = component({ sweet: { '@media (min-width: 640px)': 'caroline', '@initial': 'dreams', }, }) expect(rendering3.className).toBe(`${componentClassName} ${variantSweetDreamsClassName} ${variantResponsiveSweetCarolineClassName}`) expect(getCssText()).toBe( // initial variants `--sxs{--sxs:3 ${variantSweetCarolineClassName} ${variantSweetDreamsClassName}}` + `@media{.${variantSweetCarolineClassName}{--sweet-caroline:true}.${variantSweetDreamsClassName}{--sweet-dreams:true}}` + // responsive variants `--sxs{--sxs:4 ${variantResponsiveSweetDreamsClassName} ${variantResponsiveSweetCarolineClassName}}@media{` + `@media (min-width: 640px){.${variantResponsiveSweetDreamsClassName}{--sweet-dreams:true}}` + `@media (min-width: 640px){.${variantResponsiveSweetCarolineClassName}{--sweet-caroline:true}}` + `}`, ) }) test('Apply apply @initial styles first', () => { const { css, getCssText } = createStitches() const component = css({ '--rock': true, variants: { heavy: { 'iron-butterfly': { '--weight-iron-butterfly': true, }, 'led-zeppelin': { '--weight-led-zeppelin': true, }, }, }, }) /** Rendering of the component as-is. */ const rendering1 = component({ heavy: { '@media (min-width: 640px)': 'led-zeppelin', '@initial': 'iron-butterfly', }, }) const componentClassName = `c-evVBJo` const variantInitialHeavyIronButterfly = `c-evVBJo-kiVNrc-heavy-iron-butterfly` const variantMinWidth640LedZeppelin = `c-evVBJo-lgYcvN-heavy-led-zeppelin` expect( rendering1.className ).toBe( `${componentClassName} ${variantInitialHeavyIronButterfly} ${variantMinWidth640LedZeppelin}` ) expect( getCssText() ).toBe('--sxs{--sxs:2 c-evVBJo}@media{.c-evVBJo{--rock:true}}--sxs{--sxs:3 c-evVBJo-kiVNrc-heavy-iron-butterfly}@media{.c-evVBJo-kiVNrc-heavy-iron-butterfly{--weight-iron-butterfly:true}}--sxs{--sxs:4 c-evVBJo-lgYcvN-heavy-led-zeppelin}@media{@media (min-width: 640px){.c-evVBJo-lgYcvN-heavy-led-zeppelin{--weight-led-zeppelin:true}}}') }) }) ================================================ FILE: packages/core/tests/issue-652.js ================================================ import { createStitches } from '../src/index.js' describe('Issue #652', () => { test('Applying both variants from the one default variant', () => { const { css } = createStitches() const component1 = css({ variants: { hue: { primary: { color: 'red', }, }, }, defaultVariants: { hue: 'primary', }, }) const component2 = css(component1, { variants: { hue: { primary: { color: 'blue', }, }, }, }) const expression2 = component2() expect(expression2.className).toBe(`c-PJLV c-PJLV-gmqXFB-hue-primary c-PJLV-kydkiA-hue-primary`) }) }) ================================================ FILE: packages/core/tests/issue-655.js ================================================ import { createStitches } from '../src/index.js' describe('Issue #655', () => { test('Applying both variants from the one default variant', () => { const { css, getCssText } = createStitches() css({ maxWidth: 'fit-content', minWidth: 'fit-content', })() expect(getCssText()).toBe( `--sxs{--sxs:2 c-dAAqmb}` + `@media{.c-dAAqmb{` + `max-width:-moz-fit-content;max-width:fit-content;` + `min-width:-moz-fit-content;min-width:fit-content` + `}}` ) }) }) ================================================ FILE: packages/core/tests/issue-725.js ================================================ import { createStitches } from '../src/index.js' describe('Issue #725', () => { test('Minimum reproduction of bug', () => { const { css, getCssText } = createStitches({ media: { tablet: `(min-width: 720px)`, wide: `(min-width: 1536px)`, }, }) const Flex = css({ variants: { justify: { end: { justifyContent: 'flex-end' }, }, }, }) Flex({ justify: { '@tablet': 'end', '@wide': 'end', }, }) expect(getCssText()).toBe(`--sxs{--sxs:4 c-PJLV-jobbEJ-justify-end}@media{@media (min-width: 720px), (min-width: 1536px){.c-PJLV-jobbEJ-justify-end{justify-content:flex-end}}}`) }) test('Combination with other variants', () => { const { css, getCssText } = createStitches({ media: { mobile: `(min-width: 420px)`, tablet: `(min-width: 720px)`, wide: `(min-width: 1536px)`, }, }) const Flex = css({ variants: { justify: { end: { justifyContent: 'flex-end' }, start: { justifyContent: 'flex-start' }, }, color: { red: { color: 'red' }, }, }, defaultVariants: { color: 'red', }, }) Flex({ justify: { '@tablet': 'end', '@wide': 'end', '@mobile': 'start', }, }) expect(getCssText()).toBe( `--sxs{--sxs:3 c-PJLV-gmqXFB-color-red}@media{.c-PJLV-gmqXFB-color-red{color:red}}--sxs{--sxs:4 c-PJLV-jobbEJ-justify-end c-PJLV-kxjDkG-justify-start}@media{@media (min-width: 720px), (min-width: 1536px){.c-PJLV-jobbEJ-justify-end{justify-content:flex-end}}@media (min-width: 420px){.c-PJLV-kxjDkG-justify-start{justify-content:flex-start}}}`, ) }) test('Test compound variants', () => { const { css, getCssText } = createStitches({ media: { bp1: `(min-width: 720px)`, bp2: `(min-width: 1536px)`, }, }) const Button = css({ variants: { variant: { red: { backgroundColor: 'tomato' }, blue: { backgroundColor: 'SkyBlue' }, }, disabled: { true: { backgroundColor: 'gray' }, }, }, compoundVariants: [ { variant: 'red', disabled: true, css: { padding: 50, }, }, ], }) Button({ variant: { '@bp1': 'red', '@bp2': 'red' }, disabled: { '@bp2': true, '@bp1': false }, }) expect(getCssText()).toBe(`--sxs{--sxs:4 c-PJLV-dJnmKC-disabled-true c-PJLV-gSmlSg-variant-red}@media{@media (min-width: 1536px){.c-PJLV-dJnmKC-disabled-true{background-color:gray}}@media (min-width: 720px), (min-width: 1536px){.c-PJLV-gSmlSg-variant-red{background-color:tomato}}}--sxs{--sxs:5 c-PJLV-elpmbs-cv}@media{@media (min-width: 1536px){@media (min-width: 720px), (min-width: 1536px){.c-PJLV-elpmbs-cv{padding:50px}}}}`) }) }) ================================================ FILE: packages/core/tests/issue-788.js ================================================ import { createStitches } from '../src/index.js' describe('Issue #788', () => { test('Test that a util with the name of a selector works in globalCss', () => { const { globalCss, getCssText } = createStitches({ utils: { p: (value) => ({ paddingTop: value, paddingBottom: value, paddingLeft: value, paddingRight: value, }), }, }) globalCss({ p: { color: 'red', } })() expect(getCssText()).toBe( `--sxs{--sxs:1 gllaiB}` + `@media{p{` + `color:red` + `}}` ) }) test('Test that a util with the name of a selector works in a component', () => { const { css, getCssText } = createStitches({ utils: { p: (value) => ({ paddingTop: value, paddingBottom: value, paddingLeft: value, paddingRight: value, }), }, }) css({ p: 10 })() expect(getCssText()).toBe( `--sxs{--sxs:2 c-csWWxC}` + `@media{.c-csWWxC{` + `padding-top:10px;` + `padding-bottom:10px;` + `padding-left:10px;` + `padding-right:10px` + `}}` ) }) }) ================================================ FILE: packages/core/tests/issue-908.js ================================================ import { createStitches } from '../src/index.js' const styleRule = `--sxs { --sxs:1 lTyTw fJmROo; }`; const mediaRule = `@media { body { margin: auto; }`; const createStylesheet = (...preloadedStyles) => { let rules = []; const insertRule = (rule, index = rules.length) => { if (rule.startsWith('--sxs')) { rules.splice(index, 0, {type: 1, cssText: rule}); } if (rule.startsWith('@media')) { rules.splice(index, 0, {type: 4, cssText: rule, cssRules: []}); } }; preloadedStyles.forEach(insertRule); return { insertRule, cssRules: rules }; } describe('Issue #908', () => { test('Getting hydratable stylesheet', () => { const { getCssText } = createStitches({ root: { styleSheets: [createStylesheet(styleRule, mediaRule)] } }); expect(getCssText()).toBe(mediaRule) }) }) ================================================ FILE: packages/core/tests/issue-921.ts ================================================ import { createStitches, PropertyValue, CSS } from '../types/index' const config = { utils: { background: (value: boolean | PropertyValue<'background'>) => { if (typeof value === 'boolean') { return value ? { background: 'red' } : {} } else { return { background: value } } } }, } const { css, globalCss } = createStitches(config) globalCss({ html: { background: true }, body: { background: 'green' }, }) const Component = css({ background: true, '> *': { background: 'green' } }) Component({ background: 'green', '> *': { background: true } }) css(Component, { background: 'green' }) css(Component, { background: true }) const style: CSS = { // @ts-expect-error background: true } const style2: CSS = { background: true } const style3: CSS = { background: 'green' } ================================================ FILE: packages/core/tests/issue-943.js ================================================ import { createStitches } from '../src/index.js' describe('Issue #943', () => { test('@font-face descriptors', () => { const { globalCss, getCssText } = createStitches() globalCss({ '@font-face': [ { fontFamily: 'fallback-font', ascentOverride: '83.6%', descentOverride: '20.5%', lineGapOverride: '0%', advanceOverride: '10', src: 'local(Arial)', } ] })() expect(getCssText()).toBe('--sxs{--sxs:1 jGZRm}@media{@font-face{font-family:fallback-font;ascent-override:83.6%;descent-override:20.5%;line-gap-override:0%;advance-override:10;src:local(Arial)}}') }) }) ================================================ FILE: packages/core/tests/issue-999.js ================================================ import { createStitches } from '../src/index.js' describe('Issue #519', () => { test('locally scoped token works 1 time', () => { const { css, getCssText } = createStitches({ prefix: 'fusion' }) css({ $$syntax: 'red', h1: { color: '$$syntax', }, })() expect(getCssText()).toBe( `--sxs{--sxs:2 fusion-c-fjkySu}` + `@media{` + `.fusion-c-fjkySu{--fusion--syntax:red}` + `.fusion-c-fjkySu h1{color:var(--fusion--syntax)}` + `}` ) }) test('locally scoped prefix-free token works 1 time', () => { const { css, getCssText } = createStitches() css({ $$syntax: 'red', h1: { color: '$$syntax', }, })() expect(getCssText()).toBe( `--sxs{--sxs:2 c-fjkySu}` + `@media{` + `.c-fjkySu{---syntax:red}` + `.c-fjkySu h1{color:var(---syntax)}` + `}` ) }) test('locally scoped token works 2 times', () => { const { css, getCssText } = createStitches({ prefix: 'fusion' }) css({ $$syntax: 'red', h1: { color: '$$syntax', }, h2: { color: '$$syntax', }, })() expect(getCssText()).toBe( `--sxs{--sxs:2 fusion-c-lkpaIy}` + `@media{` + `.fusion-c-lkpaIy{--fusion--syntax:red}` + `.fusion-c-lkpaIy h1{color:var(--fusion--syntax)}` + `.fusion-c-lkpaIy h2{color:var(--fusion--syntax)}` + `}` ) }) test('locally scoped prefix-free token works 2 times', () => { const { css, getCssText } = createStitches() css({ $$syntax: 'red', h1: { color: '$$syntax', }, h2: { color: '$$syntax', }, })() expect(getCssText()).toBe( `--sxs{--sxs:2 c-lkpaIy}` + `@media{` + `.c-lkpaIy{---syntax:red}` + `.c-lkpaIy h1{color:var(---syntax)}` + `.c-lkpaIy h2{color:var(---syntax)}` + `}` ) }) test('locally scoped token works 3 times', () => { const { css, getCssText } = createStitches({ prefix: 'fusion' }) css({ $$syntax: 'red', h1: { color: '$$syntax', }, h2: { color: '$$syntax', }, h3: { color: '$$syntax', }, })() expect(getCssText()).toBe( `--sxs{--sxs:2 fusion-c-kbkiiL}` + `@media{` + `.fusion-c-kbkiiL{--fusion--syntax:red}` + `.fusion-c-kbkiiL h1{color:var(--fusion--syntax)}` + `.fusion-c-kbkiiL h2{color:var(--fusion--syntax)}` + `.fusion-c-kbkiiL h3{color:var(--fusion--syntax)}` + `}` ) }) test('locally scoped prefix-free token works 3 times', () => { const { css, getCssText } = createStitches() css({ $$syntax: 'red', h1: { color: '$$syntax', }, h2: { color: '$$syntax', }, h3: { color: '$$syntax', }, })() expect(getCssText()).toBe( `--sxs{--sxs:2 c-kbkiiL}` + `@media{` + `.c-kbkiiL{---syntax:red}` + `.c-kbkiiL h1{color:var(---syntax)}` + `.c-kbkiiL h2{color:var(---syntax)}` + `.c-kbkiiL h3{color:var(---syntax)}` + `}` ) }) }) ================================================ FILE: packages/core/tests/keyframes.js ================================================ import { createStitches } from '../src/index.js' describe('Keyframes', () => { test('Expected behavior for the keyframes() method', () => { const { keyframes, toString } = createStitches() const myKeyframes = keyframes({ '0%': { opacity: '0', }, '1%': { opacity: '1', }, }) expect(toString()).toBe('') expect(`animation: 1s ${myKeyframes};`).toBe('animation: 1s k-hMEmNJ;') expect(toString()).toBe(`--sxs{--sxs:1 k-hMEmNJ}@media{@keyframes k-hMEmNJ{0%{opacity:0}1%{opacity:1}}}`) expect(myKeyframes.name).toBe('k-hMEmNJ') }) }) ================================================ FILE: packages/core/tests/theme.js ================================================ import { createStitches } from '../src/index.js' describe('Theme', () => { test('Expected behavior for the createTheme() method', () => { const { createTheme, getCssText } = createStitches() const myTheme = createTheme('my', { colors: { blue: 'dodgerblue', }, }) expect(getCssText()).toBe('') expect(`
`).toBe('
') expect(getCssText()).toBe(`--sxs{--sxs:0 my}@media{.my{--colors-blue:dodgerblue}}`) expect(myTheme.className).toBe('my') expect(myTheme.selector).toBe('.my') }) test('createTheme() support for non-strings', () => { { const { getCssText } = createStitches({ theme: { sizes: { sm: 100, md: 200, lg: 500, }, } }) expect(getCssText()).toBe( `--sxs{--sxs:0 t-egkarf}@media{` + `:root,.t-egkarf{--sizes-sm:100;--sizes-md:200;--sizes-lg:500}` + `}` ) } { const { getCssText } = createStitches({ theme: { sizes: { sm: 100, md: 'calc($sm * 3)', lg: 'calc($md * 3)', }, } }) expect(getCssText()).toBe( `--sxs{--sxs:0 t-eJkcVD}@media{` + `:root,.t-eJkcVD{` + `--sizes-sm:100;` + `--sizes-md:calc(var(--sizes-sm) * 3);` + `--sizes-lg:calc(var(--sizes-md) * 3)` + `}` + `}` ) } }) test('theme.className injects the theme', () => { const { getCssText, createTheme } = createStitches() const theme = createTheme({ colors: { blue: '#0000ff', } }) expect(getCssText()).toBe(``) void theme.className expect(getCssText()).toBe(`--sxs{--sxs:0 t-gpVVQE}@media{.t-gpVVQE{--colors-blue:#0000ff}}`) }) }) ================================================ FILE: packages/core/tests/types.test.ts ================================================ import { createStitches } from '../types/index' const { css, globalCss, keyframes } = createStitches({ utils: { mx: () => ({ backgroundColor: 'red', }), }, theme: { colors: { hiContrast: 'hsl(200, 12%, 5%)', loContrast: 'white', gray100: 'hsl(206, 20%, 98.8%)', gray200: 'hsl(206, 14%, 96.0%)', gray300: 'hsl(206, 13%, 93.7%)', gray400: 'hsl(206, 12%, 92.0%)', gray500: 'hsl(206, 12%, 89.5%)', gray600: 'hsl(206, 11%, 85.2%)', gray700: 'hsl(206, 10%, 80.0%)', gray800: 'hsl(206, 6%, 56.1%)', gray900: 'hsl(206, 6%, 43.9%)', pedro: '$gray100', }, space: { 1: '10px', 2: '20px', }, fontSizes: { '1': '11px', '2': '13px', '3': '15px', '4': '17px', '5': '19px', '6': '21px', '7': '27px', '8': '35px', '9': '59px', }, }, media: { bp1: '(min-width: 620px)', }, }) keyframes({ from: { color: '$gray100', }, to: { color: '$gray900', }, }) globalCss({ body: { '@bp1': { backgroundColor: '$gray100', }, backgroundColor: '$gray300', }, }) const PotatoButton = css({ variants: { peace: { mercy: { color: 'MediumOrchid', }, trust: { color: 'Turquoise', }, }, variant: { blue: { backgroundColor: '$gray100', }, red: { backgroundColor: '$gray100', }, }, }, compoundVariants: [ { variant: 'blue', css: { backgroundColor: '$gray200', }, }, ], }) PotatoButton({ peace: 'mercy', }) const two = css(PotatoButton, { $$max: '2px', width: '$$max', variants: { hue: { green: { width: '$$max', backgroundColor: '$gray100', }, red: { backgroundColor: '$gray100', }, }, love: { free: { color: 'ForestGreen', }, good: { color: 'GoldenRod', }, } }, defaultVariants: { hue: 'red', }, compoundVariants: [ { hue: 'green', css: { backgroundColor: '$gray200', }, }, ], }) two({ peace: 'mercy', hue: 'green', love: 'free', }) PotatoButton({ className: '', css: { backgroundColor: '$gray300', '@all': { backgroundColor: 'initial' }, '@bp1': { backgroundColor: 'initial', } }, }) ================================================ FILE: packages/core/tests/universal-autoprefixer.js ================================================ import { createStitches } from '../src/index.js' describe('Autoprefixer', () => { test('appearance', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { appearance: 'none', }, })() expect(toString()).toBe('--sxs{--sxs:1 kozGVo}@media{x-element{-webkit-appearance:none;appearance:none}}') }) test('backfaceVisibility', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { backfaceVisibility: 'visible', }, })() expect(toString()).toBe('--sxs{--sxs:1 gaCVoe}@media{x-element{-webkit-backface-visibility:visible;backface-visibility:visible}}') }) test('backgroundClip', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { backgroundClip: 'border-box', }, })() expect(toString()).toBe('--sxs{--sxs:1 gIcRdw}@media{x-element{-webkit-background-clip:border-box;background-clip:border-box}}') }) test('clipPath', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { clipPath: 'circle(40%)', }, })() expect(toString()).toBe('--sxs{--sxs:1 ccZNl}@media{x-element{-webkit-clip-path:circle(40%);clip-path:circle(40%)}}') }) test('hyphens', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { hyphens: 'none', }, })() expect(toString()).toBe('--sxs{--sxs:1 cRggdz}@media{x-element{-webkit-hyphens:none;hyphens:none}}') }) test('maskImage', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { maskImage: 'none', }, })() expect(toString()).toBe('--sxs{--sxs:1 eNBesV}@media{x-element{-webkit-mask-image:none;mask-image:none}}') }) test('tabSize', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { tabSize: 'none', }, })() expect(toString()).toBe('--sxs{--sxs:1 kPCdtQ}@media{x-element{tab-size:none}}') }) test('textSizeAdjust', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { textSizeAdjust: '100%', }, })() expect(toString()).toBe('--sxs{--sxs:1 gVFtip}@media{x-element{-webkit-text-size-adjust:100%;text-size-adjust:100%}}') }) test('userSelect', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { userSelect: 'none', }, })() expect(toString()).toBe('--sxs{--sxs:1 kEUokv}@media{x-element{-webkit-user-select:none;user-select:none}}') }) }) ================================================ FILE: packages/core/tests/universal-functionality.js ================================================ import { createStitches } from '../src/index.js' describe('Configuration', () => { let stitches test('createStitches()', () => { const { css, globalCss } = createStitches() expect(css).toBeInstanceOf(Function) expect(globalCss).toBeInstanceOf(Function) }) test('createStitches({})', () => { const { css, globalCss } = createStitches({}) expect(css).toBeInstanceOf(Function) expect(globalCss).toBeInstanceOf(Function) }) test('createStitches({ prefix: "fusion-" })', () => { const { config } = createStitches({ prefix: 'fusion-' }) expect(config.prefix).toBe('fusion-') }) test('createStitches({ theme })', () => { const themeConfig = { colors: { blue: 'dodgerblue' } } const { config } = createStitches({ theme: themeConfig }) expect(config.theme).toBe(themeConfig) }) }) ================================================ FILE: packages/core/tests/universal-logical-properties.js ================================================ import { createStitches } from '../src/index.js' describe('Logical Properties', () => { test('marginBlock', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { marginBlock: 0, }, 'y-element': { marginBlock: 10, }, 'z-element': { marginBlock: '5px 10px', }, })() expect(toString()).toBe( `--sxs{--sxs:1 IvBLl}@media{` + `x-element{margin-block-start:0;margin-block-end:0}` + `y-element{margin-block-start:10px;margin-block-end:10px}` + `z-element{margin-block-start:5px;margin-block-end:10px}` + `}` ) }) test('marginInline', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { marginInline: 0, }, 'y-element': { marginInline: 10, }, 'z-element': { marginInline: '5px 10px', }, })() expect(toString()).toBe( `--sxs{--sxs:1 eNPHKF}@media{` + `x-element{margin-inline-start:0;margin-inline-end:0}` + `y-element{margin-inline-start:10px;margin-inline-end:10px}` + `z-element{margin-inline-start:5px;margin-inline-end:10px}` + `}` ) }) test('paddingBlock', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { paddingBlock: 0, }, 'y-element': { paddingBlock: 10, }, 'z-element': { paddingBlock: '5px 10px', }, })() expect(toString()).toBe( `--sxs{--sxs:1 kcHEgy}@media{` + `x-element{padding-block-start:0;padding-block-end:0}` + `y-element{padding-block-start:10px;padding-block-end:10px}` + `z-element{padding-block-start:5px;padding-block-end:10px}` + `}` ) }) test('paddingInline', () => { const { globalCss, toString } = createStitches() globalCss({ 'x-element': { paddingInline: 0, }, 'y-element': { paddingInline: 10, }, 'z-element': { paddingInline: '5px 10px', }, })() expect(toString()).toBe( `--sxs{--sxs:1 cVrbiG}@media{` + `x-element{padding-inline-start:0;padding-inline-end:0}` + `y-element{padding-inline-start:10px;padding-inline-end:10px}` + `z-element{padding-inline-start:5px;padding-inline-end:10px}` + `}` ) }) }) ================================================ FILE: packages/core/tests/universal-nesting.js ================================================ import { createStitches } from '../src/index.js' describe('Nesting', () => { test('Authors can define globalCss nesting rules', () => { const { globalCss, getCssText } = createStitches() globalCss({ 'body > a': { '&:not(:hover)': { textDecoration: 'none', }, }, })() expect(getCssText()).toBe(`--sxs{--sxs:1 hXsVBR}@media{body > a:not(:hover){text-decoration:none}}`) }) test('Authors can define component nesting rules', () => { const { css, getCssText } = createStitches() css({ '&:not(:hover)': { textDecoration: 'none', }, })() expect(getCssText()).toBe(`--sxs{--sxs:2 c-dweUti}@media{.c-dweUti:not(:hover){text-decoration:none}}`) }) test('Authors can define recursive globalCss nesting rules', () => { const { globalCss, getCssText } = createStitches() globalCss({ p: { 'margin': 0, '& ~ &': { marginTop: 0, }, }, })() expect(getCssText()).toBe(`--sxs{--sxs:1 gkqgGk}@media{p{margin:0}p ~ p{margin-top:0}}`) }) test('Authors can define recursive component nesting rules', () => { const { css, getCssText } = createStitches() css({ 'margin': 0, '& ~ &': { marginTop: 0, }, })() expect(getCssText()).toBe(`--sxs{--sxs:2 c-fuGzNQ}@media{.c-fuGzNQ{margin:0}.c-fuGzNQ ~ .c-fuGzNQ{margin-top:0}}`) }) test('Authors can define complex recursive globalCss nesting rules', () => { const { globalCss, getCssText } = createStitches() globalCss({ 'body > p, body > ul': { 'margin': 0, '& ~ &': { marginTop: 0, }, }, })() const parentCssRule = `body > p,body > ul{margin:0}` const nestingCssRule = `:is(body > p) ~ :is(body > p),:is(body > ul) ~ :is(body > ul){margin-top:0}` expect(getCssText()).toBe(`--sxs{--sxs:1 cugdJ}@media{${parentCssRule + nestingCssRule}}`) }) test('Authors can define complex recursive component nesting rules', () => { const { css, getCssText } = createStitches() css({ '& > p, & > ul': { 'margin': 0, '& ~ &': { marginTop: 0, }, }, })() const parentCssRule = `.c-iJLHRt > p,.c-iJLHRt > ul{margin:0}` const nestingCssRule = `:is(.c-iJLHRt > p) ~ :is(.c-iJLHRt > p),:is(.c-iJLHRt > ul) ~ :is(.c-iJLHRt > ul){margin-top:0}` expect(getCssText()).toBe(`--sxs{--sxs:2 c-iJLHRt}@media{${parentCssRule + nestingCssRule}}`) }) }) ================================================ FILE: packages/core/tests/universal-numeric-values.js ================================================ import { createStitches } from '../src/index.js' describe('Numeric Values', () => { test('Authors can use numeric values to assign px values', () => { const { globalCss, toString } = createStitches() expect(toString()).toBe('') globalCss({ body: { margin: 0, }, })() expect(toString()).toBe(`--sxs{--sxs:1 cSHHDh}@media{body{margin:0}}`) globalCss({ body: { margin: 10, }, })() expect(toString()).toBe(`--sxs{--sxs:1 cSHHDh fFIrKk}@media{body{margin:0}body{margin:10px}}`) }) test('Authors can use numeric values to assign numeric values', () => { const { globalCss, toString } = createStitches() expect(toString()).toBe('') globalCss({ body: { lineHeight: 0, width: 0, }, })() expect(toString()).toBe(`--sxs{--sxs:1 bpctHq}@media{body{line-height:0;width:0}}`) globalCss({ body: { lineHeight: 10, width: 10, }, })() expect(toString()).toBe(`--sxs{--sxs:1 bpctHq cudWGu}@media{body{line-height:0;width:0}body{line-height:10;width:10px}}`) }) test('Authors can use unit-less properties as known to React', () => { for (let i = 0; i <= 33; i += 11) { const { globalCss, getCssText } = createStitches() globalCss({ div: { animationIterationCount: i, borderImageOutset: i, borderImageSlice: i, borderImageWidth: i, boxFlex: i, boxFlexGroup: i, boxOrdinalGroup: i, columnCount: i, columns: i, flex: i, flexGrow: i, flexShrink: i, flexOrder: i, gridRow: i, gridRowEnd: i, gridRowSpan: i, gridRowStart: i, gridColumn: i, gridColumnEnd: i, gridColumnSpan: i, gridColumnStart: i, fontWeight: i, lineHeight: i, opacity: i, order: i, orphans: i, tabSize: i, widows: i, zIndex: i, zoom: i, }, })() const cssText = getCssText().replace(/^.+@media\{|\}$/g, '') expect(cssText).toBe( 'div' + '{' + 'animation-iteration-count:' + i + ';' + 'border-image-outset:' + i + ';' + 'border-image-slice:' + i + ';' + 'border-image-width:' + i + ';' + 'box-flex:' + i + ';' + 'box-flex-group:' + i + ';' + 'box-ordinal-group:' + i + ';' + 'column-count:' + i + ';' + 'columns:' + i + ';' + 'flex:' + i + ';' + 'flex-grow:' + i + ';' + 'flex-shrink:' + i + ';' + 'flex-order:' + i + ';' + 'grid-row:' + i + ';' + 'grid-row-end:' + i + ';' + 'grid-row-span:' + i + ';' + 'grid-row-start:' + i + ';' + 'grid-column:' + i + ';' + 'grid-column-end:' + i + ';' + 'grid-column-span:' + i + ';' + 'grid-column-start:' + i + ';' + 'font-weight:' + i + ';' + 'line-height:' + i + ';' + 'opacity:' + i + ';' + 'order:' + i + ';' + 'orphans:' + i + ';' + 'tab-size:' + i + ';' + 'widows:' + i + ';' + 'z-index:' + i + ';' + 'zoom:' + i + '}' ) } }) const commonProps = 'fontSize margin marginTop marginRight marginBottom marginLeft padding paddingTop paddingRight paddingBottom paddingLeft'.split(' ') for (const prop of commonProps) { const kebabProp = prop.replace(/[A-Z]/g, (letter) => '-' + letter.toLowerCase()) test(`Author can use the unit-only ${kebabProp} property`, () => { for (let i = 0; i <= 33; i += 11) { const { globalCss, getCssText } = createStitches() globalCss({ div: { [prop]: i, }, })() const cssText = getCssText().replace(/^.+@media\{|\}$/g, '') expect(cssText).toBe( `div{` + kebabProp + `:` + i + (i ? 'px' : '') + `}` ) } }) } }) ================================================ FILE: packages/core/tests/universal-polyfill-prefixed-values.js ================================================ import { createStitches } from '../src/index.js' describe('Polyfill prefixed values', () => { test('width:stretch', () => { const { globalCss, toString } = createStitches() globalCss({ '.gro': { width: 'stretch', }, })() expect(toString()).toBe( `--sxs{--sxs:1 coIeei}@media{.gro{width:-moz-available;width:-webkit-fill-available}}` ) }) test('width:fit-content', () => { const { globalCss, toString } = createStitches() globalCss({ '.fit': { width: 'fit-content', }, })() expect(toString()).toBe( `--sxs{--sxs:1 gZsLvv}@media{.fit{width:-moz-fit-content;width:fit-content}}` ) }) }) ================================================ FILE: packages/core/tests/universal-prefix.js ================================================ import { createStitches } from '../src/index.js' describe('Prefix', () => { const prefix = 'fusion' test('Authors can define a prefix applied to themes', () => { const { createTheme, toString } = createStitches({ prefix }) expect(toString()).toBe('') const hash = 'iknykm' expect(createTheme({ colors: { red: 'tomato' } }).toString()).toBe(`${prefix}-t-${hash}`) expect(toString()).toBe(`--sxs{--sxs:0 fusion-t-iknykm}@media{.${prefix}-t-${hash}{--fusion-colors-red:tomato}}`) }) test('Authors can define a prefix not applied to named themes', () => { const { createTheme, toString } = createStitches({ prefix }) expect(toString()).toBe('') const themeName = 'my-theme-name' const myTheme = createTheme(themeName, { colors: { red: 'tomato' } }) expect(myTheme.toString()).toBe(`${themeName}`) expect(toString()).toBe(`--sxs{--sxs:0 my-theme-name}@media{.${themeName}{--fusion-colors-red:tomato}}`) }) test('Authors can define a prefix applied to components', () => { const { css, toString } = createStitches({ prefix }) expect(toString()).toBe('') const component = css({ color: 'red' }) expect(toString()).toBe('') component.toString() expect(toString()).toBe(`--sxs{--sxs:2 fusion-c-gmqXFB}@media{.fusion-c-gmqXFB{color:red}}`) }) }) ================================================ FILE: packages/core/tests/universal-serialization.js ================================================ import { createStitches } from '../src/index.js' describe('Serialization', () => { const sheet = createStitches() const { css, getCssText, toString, createTheme } = sheet const myComponent = css({ all: 'unset', font: 'inherit', margin: 0, padding: '0.5em 1em', }) const myComponentClassName = 'c-cLikna' const myTheme = createTheme({ colors: { blue: 'dodgerblue', }, }) const myThemeClassName = 't-jPkpUS' test('Components implicitly return their class name', () => { expect(String(myComponent)).toBe(myComponentClassName) expect('' + myComponent).toBe(myComponentClassName) expect(`${myComponent}`).toBe(myComponentClassName) }) test('Themes implicitly return their class name', () => { expect(String(myTheme)).toBe(myThemeClassName) expect('' + myTheme).toBe(myThemeClassName) expect(`${myTheme}`).toBe(myThemeClassName) }) test('Components can explicitly return their class name', () => { expect(myComponent.className).toBe(myComponentClassName) expect(myComponent.toString()).toBe(myComponentClassName) }) test('Themes can explicitly return their class name', () => { expect(myTheme.className).toBe(myThemeClassName) expect(myTheme.toString()).toBe(myThemeClassName) }) test('Components and themes can explicitly return their selector', () => { expect(myComponent.selector).toBe(`.${myComponentClassName}`) expect(myTheme.selector).toBe(`.${myThemeClassName}`) }) const sheetCssText = `--sxs{--sxs:0 t-jPkpUS}@media{.${myThemeClassName}{--colors-blue:dodgerblue}}--sxs{--sxs:2 c-cLikna}@media{.${myComponentClassName}{all:unset;font:inherit;margin:0;padding:0.5em 1em}}` test('Sheets implicitly return their cssText', () => { expect(String(sheet)).toBe(sheetCssText) expect('' + sheet).toBe(sheetCssText) expect(`${sheet}`).toBe(sheetCssText) }) test('Sheets can explicitly return their cssText', () => { expect(getCssText()).toBe(sheetCssText) expect(toString()).toBe(sheetCssText) }) }) ================================================ FILE: packages/core/tests/universal-tokens.js ================================================ import { createStitches } from '../src/index.js' describe('Tokens', () => { test('Authors can use a regular token #1', () => { const { globalCss, getCssText } = createStitches({ theme: { colors: { red: 'tomato', }, }, }) globalCss({ article: { color: '$red', }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-iknykm}@media{` + `:root,.t-iknykm{--colors-red:tomato}` + `}--sxs{--sxs:1 fMIGFF}@media{` + `article{color:var(--colors-red)}` + `}` ) }) test('Authors can use a regular token #2', () => { const { globalCss, getCssText } = createStitches({ theme: { shadows: { red: 'tomato', }, }, }) globalCss({ article: { boxShadow: '0 0 0 1px $red', }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-daOLKV}@media{` + `:root,.t-daOLKV{--shadows-red:tomato}` + `}--sxs{--sxs:1 bstpNq}@media{` + `article{box-shadow:0 0 0 1px var(--shadows-red)}` + `}` ) }) test('Authors can use a relative token #1', () => { const { globalCss, getCssText } = createStitches({ theme: { colors: { red: 'tomato', red500: '$red', }, }, }) globalCss({ article: { color: '$red500', }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-eZaaph}@media{` + `:root,.t-eZaaph{--colors-red:tomato;--colors-red500:var(--colors-red)}` + `}--sxs{--sxs:1 fdgxsg}@media{` + `article{color:var(--colors-red500)}` + `}` ) }) test('Authors can use a relative token #1', () => { const { globalCss, getCssText } = createStitches({ theme: { shadows: { red: 'tomato', red500: '$red', redUnique: '$$red' }, }, }) globalCss({ article: { boxShadow: '0 0 0 1px $red500', }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-gxqihb}@media{` + `:root,.t-gxqihb{--shadows-red:tomato;--shadows-red500:var(--shadows-red);--shadows-redUnique:var(---red)}` + `}` + `--sxs{--sxs:1 kyFUgb}@media{` + `article{box-shadow:0 0 0 1px var(--shadows-red500)}` + `}` ) }) test('Authors can use an absolute token #1', () => { const { globalCss, getCssText } = createStitches({ theme: { colors: { red: 'tomato', }, }, }) globalCss({ article: { boxShadow: '0 0 0 1px $colors$red', }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-iknykm}@media{` + `:root,.t-iknykm{--colors-red:tomato}` + `}` + `--sxs{--sxs:1 hNRkrs}@media{` + `article{box-shadow:0 0 0 1px var(--colors-red)}` + `}` ) }) test('Authors can use an absolute token #2', () => { const { globalCss, getCssText } = createStitches({ theme: { colors: { red: 'tomato', }, }, }) globalCss({ article: { boxShadow: '0 0 0 1px $colors$red', }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-iknykm}@media{` + `:root,.t-iknykm{--colors-red:tomato}` + `}` + `--sxs{--sxs:1 hNRkrs}@media{` + `article{box-shadow:0 0 0 1px var(--colors-red)}` + `}` ) }) test('Authors can use a negative token #1', () => { const { globalCss, getCssText } = createStitches({ theme: { space: { sp1: '100px', sp2: '200px', }, }, }) globalCss({ article: { marginLeft: '-$sp1', marginTop: '-$sp2', }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-hxjLZl}@media{` + `:root,.t-hxjLZl{--space-sp1:100px;--space-sp2:200px}` + `}` + `--sxs{--sxs:1 kTSGli}@media{` + `article{margin-left:calc(var(--space-sp1)*-1);margin-top:calc(var(--space-sp2)*-1)}` + `}` ) }) test('Authors can use a negative token #2', () => { const { globalCss, getCssText } = createStitches({ theme: { sizes: { sp1: '10px', sp2: '20px', sp3: '30px', }, }, }) globalCss({ article: { marginLeft: '-$sizes$sp1', width: '$sp1', }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-ereMzu}@media{` + `:root,.t-ereMzu{--sizes-sp1:10px;--sizes-sp2:20px;--sizes-sp3:30px}` + `}` + `--sxs{--sxs:1 kuTEdV}@media{` + `article{margin-left:calc(var(--sizes-sp1)*-1);width:var(--sizes-sp1)}` + `}` ) }) test('Authors can use tokens from the globalCss theme object', () => { const { globalCss, theme, getCssText } = createStitches({ theme: { space: { sp1: '100px', sp2: '200px', }, }, }) globalCss({ article: { marginLeft: theme.space.sp1, marginTop: theme.space.sp2, }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-hxjLZl}@media{` + `:root,.t-hxjLZl{--space-sp1:100px;--space-sp2:200px}` + `}` + `--sxs{--sxs:1 lcIUgV}@media{` + `article{margin-left:var(--space-sp1);margin-top:var(--space-sp2)}` + `}` ) }) test('Authors can use tokens from a new theme object', () => { const { globalCss, createTheme, getCssText } = createStitches() const mytheme = createTheme('my-theme', { space: { sp1: '100px', sp2: '200px', }, }) globalCss({ article: { marginLeft: mytheme.space.sp1, marginTop: mytheme.space.sp2, }, })() expect(getCssText()).toBe( `--sxs{--sxs:1 lcIUgV}@media{article{margin-left:var(--space-sp1);margin-top:var(--space-sp2)}}`, ) void `${mytheme}` expect(getCssText()).toBe( `--sxs{--sxs:0 my-theme}@media{` + `.my-theme{--space-sp1:100px;--space-sp2:200px}` + `}--sxs{--sxs:1 lcIUgV}@media{` + `article{margin-left:var(--space-sp1);margin-top:var(--space-sp2)}` + `}` ) }) test('Authors can use tokens from the globalCss theme object', () => { const { globalCss, theme, getCssText } = createStitches({ theme: { space: { sp1: '100px', sp2: '200px', }, }, }) globalCss({ article: { marginLeft: theme.space.sp1, marginTop: theme.space.sp2, }, })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-hxjLZl}@media{` + `:root,.t-hxjLZl{--space-sp1:100px;--space-sp2:200px}` + `}` + `--sxs{--sxs:1 lcIUgV}@media{` + `article{margin-left:var(--space-sp1);margin-top:var(--space-sp2)}` + `}` ) }) test('Authors can use the class from the root theme object', () => { const { theme, getCssText } = createStitches({ prefix: 'pedro', theme: { colors: { blue: 'dodgerblue', }, } }) expect(`
`).toBe(`
`) expect(getCssText()).toBe( `--sxs{--sxs:0 pedro-t-jPkpUS}@media{` + `:root,.pedro-t-jPkpUS{--pedro-colors-blue:dodgerblue}` + `}` ) }) test('Authors can render custom units', () => { const { globalCss, getCssText } = createStitches({ theme: { sizes: { five: '5px', }, } }) globalCss({ body: { marginLeft: '5--sizes-five' } })() expect(getCssText()).toBe( `--sxs{--sxs:0 t-bhZLEQ}@media{` + `:root,.t-bhZLEQ{--sizes-five:5px}` + `}--sxs{--sxs:1 gvABwA}@media{` + `body{margin-left:calc(var(--sizes-five)*5)}` + `}` ) }) }) ================================================ FILE: packages/core/tests/universal-with-typing.ts ================================================ import { createStitches } from '../types' const { css, toString } = createStitches({ media: { bp1: '(min-width: 640px)', }, }) const xyz = css({ color: 'red', }) void xyz() void toString() ================================================ FILE: packages/core/tests/utils.js ================================================ import { createStitches } from '../src/index.js' describe('Utils', () => { test('Authors can define utilties applied to components', () => { const stitches = createStitches({ utils: { bg: (value) => ({ backgroundColor: value }), }, }) const component = stitches.css({ bg: 'red', }) expect(stitches.toString()).toBe('') component.toString() expect(stitches.toString()).toBe(`--sxs{--sxs:2 c-bzwKCF}@media{.c-bzwKCF{background-color:red}}`) }) }) ================================================ FILE: packages/core/tests/with-config-api.js ================================================ import { createStitches } from '../src/index.js' describe('css.withConfig', () => { test('Basic css calls without a config', () => { const { css, getCssText } = createStitches() expect(css.withConfig).toBeInstanceOf(Function) const component1of2 = css.withConfig()() const className1of2 = `${component1of2}` const cssString1of2 = getCssText() expect(component1of2).toBeInstanceOf(Function) expect(className1of2).toBe('PJLV') expect(cssString1of2).toBe('') const componentToRender = css.withConfig()({ color: 'DodgerBlue' }) const className = componentToRender().toString() const cssString = getCssText() expect(componentToRender).toBeInstanceOf(Function) expect(className).toBe('c-dataoT') expect(cssString).toBe(`--sxs{--sxs:2 PJLV c-dataoT}@media{.c-dataoT{color:DodgerBlue}}`) }) test('Creates the correct className with a componentId', () => { const { css, getCssText } = createStitches() const componentConfig = { componentId: 'cool-id', } const componentToRender = css.withConfig(componentConfig)({ color: 'red' }) const className = componentToRender().toString() const cssString = getCssText() expect(componentToRender).toBeInstanceOf(Function) expect(className).toBe('c-cool-id') expect(cssString).toBe(`--sxs{--sxs:2 c-cool-id}@media{.c-cool-id{color:red}}`) }) test('Creates the correct className with a displayName', () => { const { css, getCssText } = createStitches() const componentConfig = { displayName: 'my-cool-display-name', } const componentToRender = css.withConfig(componentConfig)({ color: 'red' }) const className = componentToRender().toString() const cssString = getCssText() expect(componentToRender).toBeInstanceOf(Function) expect(className).toBe('c-my-cool-display-name-gmqXFB') expect(cssString).toBe(`--sxs{--sxs:2 c-my-cool-display-name-gmqXFB}@media{.c-my-cool-display-name-gmqXFB{color:red}}`) }) test('Creates the correct className with a displayName and componentId', () => { const { css, getCssText } = createStitches() const componentConfig = { componentId: 'cool-id', displayName: 'my-cool-display-name', } const componentToRender = css.withConfig(componentConfig)({ color: 'red' }) const className = componentToRender().toString() const cssString = getCssText() expect(componentToRender).toBeInstanceOf(Function) expect(className).toBe('c-my-cool-display-name-cool-id') expect(cssString).toBe(`--sxs{--sxs:2 c-my-cool-display-name-cool-id}@media{.c-my-cool-display-name-cool-id{color:red}}`) }) test('Creates the correct className with a componentConfig while extending components', () => { const { css, getCssText } = createStitches() const ComponentToExtend = css.withConfig({ componentId: 'component-to-extend-id', })({ color: 'red' }) const componentToRender = css.withConfig({ componentId: 'cool-component-id' })(ComponentToExtend, { color: 'blue' }) const className = componentToRender().toString() expect(className).toBe('c-component-to-extend-id c-cool-component-id') const cssString = getCssText() expect(cssString).toBe(`--sxs{--sxs:2 c-component-to-extend-id c-cool-component-id}@media{.c-component-to-extend-id{color:red}.c-cool-component-id{color:blue}}`) }) }) describe('shouldForwardStitchesProp', () => { test('does not omit stitches props when shouldForwardStitchesProp returns true', () => { const { css } = createStitches() const componentOneConfig = { shouldForwardStitchesProp: () => false, } const componentOne = css.withConfig(componentOneConfig)('button', { variants: { variant: { red: { background: 'red' }, }, }, }) const {props: firstComponentProps} = componentOne({ variant: 'red', css: {} }) expect(firstComponentProps.variant).toBe(undefined) expect(firstComponentProps.css).toEqual(undefined) const componentTwoConfig = { shouldForwardStitchesProp: () => true, } const componentTwo = css.withConfig(componentTwoConfig)('button', { variants: { variant: { red: { background: 'red' }, }, }, }) const {props: secondComponentProps} = componentTwo({ variant: 'red', css: {} }) expect(secondComponentProps.variant).toBe('red') expect(secondComponentProps.css).toEqual({}) }) test('does not omit a non-stitches props when shouldForwardStitchesProp returns true', () => { const { css } = createStitches() const componentConfig = { shouldForwardStitchesProp: () => true, } const componentToRender = css.withConfig(componentConfig)('button', { variants: { variant: { red: { background: 'red' }, }, }, }) const props = componentToRender({ href: 'www.hello.com' }).props expect(props.href).toBe('www.hello.com') }) test('Omits variants when shouldForwardStitchesProp returns false', () => { const { css } = createStitches() const componentConfig = { shouldForwardStitchesProp: () => false, } const componentToRender = css.withConfig(componentConfig)('button', { variants: { variant: { red: { background: 'red' }, }, }, }) const props = componentToRender({ variant: 'red' }).props expect(props.variant).toBe(undefined) }) }) ================================================ FILE: packages/core/types/config.d.ts ================================================ import type * as CSSUtil from './css-util.js' import type Stitches from './stitches.js' /** Configuration Interface */ declare namespace ConfigType { /** Prefix interface. */ export type Prefix = T extends string ? T: string /** Media interface. */ export type Media = { [name in keyof T]: T[name] extends string ? T[name] : string } /** Theme interface. */ export type Theme = { borderStyles?: { [token in number | string]: boolean | number | string } borderWidths?: { [token in number | string]: boolean | number | string } colors?: { [token in number | string]: boolean | number | string } fonts?: { [token in number | string]: boolean | number | string } fontSizes?: { [token in number | string]: boolean | number | string } fontWeights?: { [token in number | string]: boolean | number | string } letterSpacings?: { [token in number | string]: boolean | number | string } lineHeights?: { [token in number | string]: boolean | number | string } radii?: { [token in number | string]: boolean | number | string } shadows?: { [token in number | string]: boolean | number | string } sizes?: { [token in number | string]: boolean | number | string } space?: { [token in number | string]: boolean | number | string } transitions?: { [token in number | string]: boolean | number | string } zIndices?: { [token in number | string]: boolean | number | string } } & { [Scale in keyof T]: { [Token in keyof T[Scale]]: T[Scale][Token] extends (boolean | number | string) ? T[Scale][Token] : (boolean | number | string) } } /** ThemeMap interface. */ export type ThemeMap = { [Property in keyof T]: T[Property] extends string ? T[Property] : string } /** Utility interface. */ export type Utils = { [Property in keyof T]: T[Property] extends (value: infer V) => {} ? T[Property] | ((value: V) => { [K in keyof CSSUtil.CSSProperties]?: CSSUtil.CSSProperties[K] | V }) : never } } /** Default ThemeMap. */ export interface DefaultThemeMap { gap: 'space' gridGap: 'space' columnGap: 'space' gridColumnGap: 'space' rowGap: 'space' gridRowGap: 'space' inset: 'space' insetBlock: 'space' insetBlockEnd: 'space' insetBlockStart: 'space' insetInline: 'space' insetInlineEnd: 'space' insetInlineStart: 'space' margin: 'space' marginTop: 'space' marginRight: 'space' marginBottom: 'space' marginLeft: 'space' marginBlock: 'space' marginBlockEnd: 'space' marginBlockStart: 'space' marginInline: 'space' marginInlineEnd: 'space' marginInlineStart: 'space' padding: 'space' paddingTop: 'space' paddingRight: 'space' paddingBottom: 'space' paddingLeft: 'space' paddingBlock: 'space' paddingBlockEnd: 'space' paddingBlockStart: 'space' paddingInline: 'space' paddingInlineEnd: 'space' paddingInlineStart: 'space' scrollMargin: 'space' scrollMarginTop: 'space' scrollMarginRight: 'space' scrollMarginBottom: 'space' scrollMarginLeft: 'space' scrollMarginBlock: 'space' scrollMarginBlockEnd: 'space' scrollMarginBlockStart: 'space' scrollMarginInline: 'space' scrollMarginInlineEnd: 'space' scrollMarginInlineStart: 'space' scrollPadding: 'space' scrollPaddingTop: 'space' scrollPaddingRight: 'space' scrollPaddingBottom: 'space' scrollPaddingLeft: 'space' scrollPaddingBlock: 'space' scrollPaddingBlockEnd: 'space' scrollPaddingBlockStart: 'space' scrollPaddingInline: 'space' scrollPaddingInlineEnd: 'space' scrollPaddingInlineStart: 'space' top: 'space' right: 'space' bottom: 'space' left: 'space' fontSize: 'fontSizes' background: 'colors' backgroundColor: 'colors' backgroundImage: 'colors' borderImage: 'colors' border: 'colors' borderBlock: 'colors' borderBlockEnd: 'colors' borderBlockStart: 'colors' borderBottom: 'colors' borderBottomColor: 'colors' borderColor: 'colors' borderInline: 'colors' borderInlineEnd: 'colors' borderInlineStart: 'colors' borderLeft: 'colors' borderLeftColor: 'colors' borderRight: 'colors' borderRightColor: 'colors' borderTop: 'colors' borderTopColor: 'colors' caretColor: 'colors' color: 'colors' columnRuleColor: 'colors' outline: 'colors' outlineColor: 'colors' fill: 'colors' stroke: 'colors' textDecorationColor: 'colors' fontFamily: 'fonts' fontWeight: 'fontWeights' lineHeight: 'lineHeights' letterSpacing: 'letterSpacings' blockSize: 'sizes' minBlockSize: 'sizes' maxBlockSize: 'sizes' inlineSize: 'sizes' minInlineSize: 'sizes' maxInlineSize: 'sizes' width: 'sizes' minWidth: 'sizes' maxWidth: 'sizes' height: 'sizes' minHeight: 'sizes' maxHeight: 'sizes' flexBasis: 'sizes' gridTemplateColumns: 'sizes' gridTemplateRows: 'sizes' borderWidth: 'borderWidths' borderTopWidth: 'borderWidths' borderLeftWidth: 'borderWidths' borderRightWidth: 'borderWidths' borderBottomWidth: 'borderWidths' borderStyle: 'borderStyles' borderTopStyle: 'borderStyles' borderLeftStyle: 'borderStyles' borderRightStyle: 'borderStyles' borderBottomStyle: 'borderStyles' borderRadius: 'radii' borderTopLeftRadius: 'radii' borderTopRightRadius: 'radii' borderBottomRightRadius: 'radii' borderBottomLeftRadius: 'radii' boxShadow: 'shadows' textShadow: 'shadows' transition: 'transitions' zIndex: 'zIndices' } /** Returns a function used to create a new Stitches interface. */ export type CreateStitches = { < Prefix extends string = '', Media extends {} = {}, Theme extends {} = {}, ThemeMap extends {} = DefaultThemeMap, Utils extends {} = {} >( config?: { prefix?: ConfigType.Prefix media?: ConfigType.Media theme?: ConfigType.Theme themeMap?: ConfigType.ThemeMap utils?: ConfigType.Utils } ): Stitches } ================================================ FILE: packages/core/types/css-util.d.ts ================================================ import type * as Native from './css.js' import type * as Config from './config.js' import type * as ThemeUtil from './theme.js' import type * as Util from './util.js' export { Native } /** CSS style declaration object. */ export interface CSSProperties extends Native.StandardLonghandProperties, Native.StandardShorthandProperties, Native.SvgProperties {} type ValueByPropertyName = PropertyName extends keyof CSSProperties ? CSSProperties[PropertyName] : never type TokenByPropertyName = PropertyName extends keyof ThemeMap ? TokenByScaleName : never type TokenByScaleName = ScaleName extends keyof Theme ? Util.Prefixed<'$', keyof Theme[ScaleName]> : never /** Returns a Style interface, leveraging the given media and style map. */ export type CSS< Media = {}, Theme = {}, ThemeMap = Config.DefaultThemeMap, Utils = {}, > = ( // nested at-rule css styles & { [K in Util.Prefixed<'@', keyof Media>]?: CSS } // known property styles & { [K in keyof CSSProperties as K extends keyof Utils ? never : K]?: ( | ValueByPropertyName | TokenByPropertyName | Native.Globals | ThemeUtil.ScaleValue | Util.Index | undefined ) } // known utility styles & { [K in keyof Utils]?: Utils[K] extends (arg: infer P) => any ? ( | ( P extends any[] ? ( | ( $$PropertyValue extends keyof P[0] ? ( | ValueByPropertyName | TokenByPropertyName | Native.Globals | ThemeUtil.ScaleValue | undefined ) : $$ScaleValue extends keyof P[0] ? ( | TokenByScaleName | { scale: P[0][$$ScaleValue] } | undefined ) : never )[] | P ) : $$PropertyValue extends keyof P ? ( | ValueByPropertyName | TokenByPropertyName | Native.Globals | undefined ) : $$ScaleValue extends keyof P ? ( | TokenByScaleName | { scale: P[$$ScaleValue] } | undefined ) : never ) | P ) : never } // known theme styles & { [K in keyof ThemeMap as K extends keyof CSSProperties ? never : K extends keyof Utils ? never : K]?: ( | Native.Globals | Util.Index | undefined ) } // unknown css declaration styles & { /** Unknown property. */ [K: string]: ( | number | string | CSS | {} | undefined ) } ) /** Unique symbol used to reference a property value. */ export declare const $$PropertyValue: unique symbol /** Unique symbol used to reference a property value. */ export type $$PropertyValue = typeof $$PropertyValue /** Unique symbol used to reference a token value. */ export declare const $$ScaleValue: unique symbol /** Unique symbol used to reference a token value. */ export type $$ScaleValue = typeof $$ScaleValue export declare const $$ThemeValue: unique symbol export type $$ThemeValue = typeof $$ThemeValue // https://github.com/microsoft/TypeScript/issues/37888#issuecomment-846638356 export type WithPropertyValue = { readonly [K in $$PropertyValue]: T } export type WithScaleValue = { readonly [K in $$ScaleValue]: T; } ================================================ FILE: packages/core/types/css.d.ts ================================================ /** @license MIT License * Copyright (c) 2017-present, Fredrik Nicol * Copyright (c) 2021-present, Jonathan Neal * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 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. */ export {}; export interface StandardLonghandProperties { /** * The CSS **`align-content`** property sets the distribution of space between and around content items along a flexbox's cross-axis or a grid's block axis. * * **Syntax**: `normal | | | ? ` * * **Initial value**: `normal` * */ alignContent?: Property.AlignContent; /** * The CSS **`align-items`** property sets the `align-self` value on all direct children as a group. In Flexbox, it controls the alignment of items on the Cross Axis. In Grid Layout, it controls the alignment of items on the Block Axis within their grid area. * * **Syntax**: `normal | stretch | | [ ? ]` * * **Initial value**: `normal` * */ alignItems?: Property.AlignItems; /** * The **`align-self`** CSS property overrides a grid or flex item's `align-items` value. In Grid, it aligns the item inside the grid area. In Flexbox, it aligns the item on the cross axis. * * **Syntax**: `auto | normal | stretch | | ? ` * * **Initial value**: `auto` * */ alignSelf?: Property.AlignSelf; /** * The **`align-tracks`** CSS property sets the alignment in the masonry axis for grid containers that have masonry in their block axis. * * **Syntax**: `[ normal | | | ? ]#` * * **Initial value**: `normal` * */ alignTracks?: Property.AlignTracks; /** * The **`animation-delay`** CSS property specifies the amount of time to wait from applying the animation to an element before beginning to perform the animation. The animation can start later, immediately from its beginning, or immediately and partway through the animation. * * **Syntax**: `