diff --git a/README.md b/README.md index df0cfaab..71e7b15c 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,11 @@ pnpm add @eqtylab/equality ```css @import '@eqtylab/equality/theme-config.css'; +@import '@eqtylab/equality/preflight.css' layer(base); ``` +See the [Usage guide](https://equality.eqtylab.io/getting-started/usage) for the available stylesheets and how to embed Equality in a site that has its own base styles. + Or ```ts @@ -159,4 +162,4 @@ Requirements: ## Troubleshooting - If the demo doesn’t start, ensure Node ≥ 18 and pnpm ≥ 9. -- If styles don't appear, confirm the CSS import: `@import '@eqtylab/equality/theme-config.css'`. +- If styles don't appear, confirm the CSS imports listed in the [Usage guide](https://equality.eqtylab.io/getting-started/usage). diff --git a/packages/demo/astro.config.mjs b/packages/demo/astro.config.mjs index 3550bc13..d49cd27c 100644 --- a/packages/demo/astro.config.mjs +++ b/packages/demo/astro.config.mjs @@ -17,6 +17,13 @@ const uiSrc = resolve(__dirname, "../ui/src"); // Resolve @eqty/equality to local ui package when viewing demo const PKG = "@eqtylab/equality"; +// Published CSS subpaths whose specifier doesn't match its path under src/. +/** @type {Record} */ +const CSS_SUBPATHS = { + "theme-config.css": "theme/global-theme-config.css", + "preflight.css": "theme/theme-preflight-global.css", + "preflight-scoped.css": "theme/theme-preflight-scoped.css", +}; const resolveUiFromSource = { name: "resolve-ui-from-source", enforce: /** @type {const} */ ("pre"), @@ -29,8 +36,11 @@ const resolveUiFromSource = { async resolveId(id, importer, options) { /** @type {string | undefined} */ let target; - if (id === `${PKG}/theme-config.css`) { - target = resolve(uiSrc, "theme/global-theme-config.css"); + const cssSubpath = id.startsWith(`${PKG}/`) + ? CSS_SUBPATHS[id.slice(PKG.length + 1)] + : undefined; + if (cssSubpath) { + target = resolve(uiSrc, cssSubpath); } else if (id === PKG) { target = uiSrc; // directory -> index.ts } else if (id.startsWith(`${PKG}/`)) { diff --git a/packages/demo/src/pages/getting-started/usage.mdx b/packages/demo/src/pages/getting-started/usage.mdx index c649c045..ada6524a 100644 --- a/packages/demo/src/pages/getting-started/usage.mdx +++ b/packages/demo/src/pages/getting-started/usage.mdx @@ -25,10 +25,47 @@ Please follow either of the setup configurations below depending on your project ### Tailwind v4 -Import the Equality Tailwind v4 configuration into your global stylesheet (this includes preflight (base styles), theme colors, variables, utilities and components): +The package ships three stylesheets: + +| Stylesheet | Contains | +| ---------------------------------------- | ----------------------------------------------------- | +| `@eqtylab/equality/theme-config.css` | Tokens, theme, utilities and components. No reset. | +| `@eqtylab/equality/preflight.css` | Base styles reset for `html` and everything under it. | +| `@eqtylab/equality/preflight-scoped.css` | The same reset, only inside `[data-equality-root]`. | + +In an app you own, import the config followed by the global preflight: + +```css +@import "@eqtylab/equality/theme-config.css"; +@import "@eqtylab/equality/preflight.css" layer(base); +``` + +`theme-config.css` must come first — it declares the `theme, base, components, utilities` layer order that the preflight relies on. + +### Embedding in a host site + +The preflight is a document-wide reset, so it will flatten the typography of a site that ships its own base styles, such as a Starlight or Zensical documentation site. Use the scoped preflight there instead: ```css @import "@eqtylab/equality/theme-config.css"; +@import "@eqtylab/equality/preflight-scoped.css" layer(base); +``` + +`` sets `data-equality-root` for you. You can also mark a plain wrapper, as many times per page as you need: + +```html +
...
+``` + +Neither preflight declares a layer of its own, so `layer()` can place the reset wherever the host's cascade needs it — for example `layer(equality-reset)` ordered against Starlight's own layer. + +Note that Equality's dark palette activates on `html[data-equality-theme="dark"]`, which a host's theme toggle won't set. Mirror the host's attribute to follow its switcher: + +```js +const html = document.documentElement; +new MutationObserver(() => { + html.dataset.equalityTheme = html.dataset.theme; +}).observe(html, { attributes: true, attributeFilter: ["data-theme"] }); ``` ### Other CSS frameworks diff --git a/packages/demo/src/styles/global.css b/packages/demo/src/styles/global.css index 97dcaa28..cba08b3c 100644 --- a/packages/demo/src/styles/global.css +++ b/packages/demo/src/styles/global.css @@ -1,6 +1,7 @@ @import "tailwindcss"; @import "@eqtylab/equality/theme-config.css"; +@import "@eqtylab/equality/preflight.css" layer(base); @layer components { body { diff --git a/packages/demo/tsconfig.json b/packages/demo/tsconfig.json index 9095de24..2fcc9ce9 100644 --- a/packages/demo/tsconfig.json +++ b/packages/demo/tsconfig.json @@ -15,6 +15,12 @@ "@eqtylab/equality/theme-config.css": [ "../ui/src/theme/global-theme-config.css" ], + "@eqtylab/equality/preflight.css": [ + "../ui/src/theme/theme-preflight-global.css" + ], + "@eqtylab/equality/preflight-scoped.css": [ + "../ui/src/theme/theme-preflight-scoped.css" + ], "@eqtylab/equality/*": ["../ui/src/*"], "@/": ["../ui/src"], "@/*": ["../ui/src/*"] diff --git a/packages/ui/package.json b/packages/ui/package.json index 84df5dfc..34c156b4 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -2,7 +2,7 @@ "name": "@eqtylab/equality", "description": "EQTYLab's component and token-based design system", "homepage": "https://equality.eqtylab.io/", - "version": "2.5.0", + "version": "3.0.0", "license": "Apache-2.0", "keywords": [ "component library", @@ -25,7 +25,9 @@ "import": "./dist/scripts.js", "require": "./dist/scripts.cjs" }, - "./theme-config.css": "./dist/global-theme-config.css" + "./theme-config.css": "./dist/global-theme-config.css", + "./preflight.css": "./dist/theme-preflight-global.css", + "./preflight-scoped.css": "./dist/theme-preflight-scoped.css" }, "files": [ "dist", @@ -93,7 +95,8 @@ "dev": "pnpm run watch:tokens", "build": "pnpm run build:tokens && pnpm run build:lib", "build:tokens": "node src/scripts/build-tokens.js && prettier --write ../tokens/equality-tokens.json", - "build:lib": "tsup --config tsup.config.ts && cp src/theme/*.css dist/ && mkdir -p dist/generated && cp src/theme/generated/*.css dist/generated/", + "build:preflight": "node src/scripts/build-preflight.js && prettier --write src/theme/theme-preflight-global.css", + "build:lib": "pnpm run build:preflight && tsup --config tsup.config.ts && cp src/theme/*.css dist/ && mkdir -p dist/generated && cp src/theme/generated/*.css dist/generated/", "watch": "tsup --config tsup.config.ts --watch", "watch:tokens": "chokidar '../tokens/equality-tokens.json' --debounce 300 --initial=false -c 'pnpm run build:tokens'", "release": "pnpm run build && pnpm publish --access public --no-git-checks" diff --git a/packages/ui/src/scripts/build-preflight.js b/packages/ui/src/scripts/build-preflight.js new file mode 100644 index 00000000..bf087849 --- /dev/null +++ b/packages/ui/src/scripts/build-preflight.js @@ -0,0 +1,48 @@ +/** + * Generates the global preflight from the scoped one. + * + * `theme-preflight-scoped.css` is the single authored copy of the reset. The + * only difference in the global build is the root selector, so deriving it here + * keeps the two from drifting. + */ +import { readFileSync, writeFileSync } from 'fs'; +import { dirname, resolve } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const SOURCE = resolve(__dirname, '../theme/theme-preflight-scoped.css'); +const OUTPUT = resolve(__dirname, '../theme/theme-preflight-global.css'); + +const SCOPED_ROOT = '[data-equality-root]'; +const GLOBAL_ROOT = 'html'; + +const BANNER = `/* ========================================================= + GLOBAL PREFLIGHT — GENERATED FILE, DO NOT EDIT + + Generated from \`theme-preflight-scoped.css\` by + \`src/scripts/build-preflight.js\`. Edit that file instead, then run + \`pnpm build:preflight\`. + + Deliberately carries no \`@layer\` wrapper: the importer assigns the layer, + so a consumer can place the reset wherever their cascade needs it. + + @import '@eqtylab/equality/preflight.css' layer(base); + ========================================================= */`; + +const source = readFileSync(SOURCE, 'utf8'); + +// Drop the source's own header comment; the generated file gets its own. +const body = source.replace(/^\/\*[\s\S]*?\*\/\n/, ''); + +if (!body.includes(SCOPED_ROOT)) { + throw new Error( + `Expected to find "${SCOPED_ROOT}" in ${SOURCE}. Did the scoped root selector change?` + ); +} + +const output = `${BANNER}\n\n${body.split(SCOPED_ROOT).join(GLOBAL_ROOT)}`; + +writeFileSync(OUTPUT, output); + +console.log(`Generated ${OUTPUT} from ${SOURCE}`); diff --git a/packages/ui/src/theme/global-theme-config.css b/packages/ui/src/theme/global-theme-config.css index bc60d9db..6baca332 100644 --- a/packages/ui/src/theme/global-theme-config.css +++ b/packages/ui/src/theme/global-theme-config.css @@ -10,6 +10,14 @@ @import './generated/tailwind-tokens.css'; @import './theme-base.css'; -@import './theme-preflight-global.css'; @import './theme-components.css'; @import './theme-utilities.css'; + +/* NOTE: preflight is deliberately NOT imported here. It is an opt-in import so + that host sites with their own base styles can skip it or scope it: + + @import '@eqtylab/equality/preflight.css' layer(base); // own the document + @import '@eqtylab/equality/preflight-scoped.css' layer(base); // reset only inside + // [data-equality-root] + Import this file first so the layer order above is registered before the + preflight lands in `base`. */ diff --git a/packages/ui/src/theme/theme-preflight-global.css b/packages/ui/src/theme/theme-preflight-global.css index 165726e7..b7696738 100644 --- a/packages/ui/src/theme/theme-preflight-global.css +++ b/packages/ui/src/theme/theme-preflight-global.css @@ -1,258 +1,265 @@ -@layer base { - /* ========================================================= - GLOBAL PREFLIGHT (kept intact) - ========================================================= */ - - /* 1) Box model + resets + border-color */ - html, - html *, - html ::after, - html ::before, - html ::backdrop, - html ::file-selector-button { - box-sizing: border-box; - margin: 0; - padding: 0; - border: 0 solid; - border-color: var(--color-border); - } +/* ========================================================= + GLOBAL PREFLIGHT — GENERATED FILE, DO NOT EDIT + + Generated from `theme-preflight-scoped.css` by + `src/scripts/build-preflight.js`. Edit that file instead, then run + `pnpm build:preflight`. + + Deliberately carries no `@layer` wrapper: the importer assigns the layer, + so a consumer can place the reset wherever their cascade needs it. + + @import '@eqtylab/equality/preflight.css' layer(base); + ========================================================= */ + +/* 1) Box model + resets + border-color */ +html, +html *, +html ::after, +html ::before, +html ::backdrop, +html ::file-selector-button { + box-sizing: border-box; + margin: 0; + padding: 0; + border: 0 solid; + border-color: var(--color-border); +} - /* Cursor for buttons */ - html button { - cursor: pointer; - } +/* Cursor for buttons */ +html button { + cursor: pointer; +} - /* Typography + platform defaults */ - html { - line-height: 1.5; - -webkit-text-size-adjust: 100%; - tab-size: 4; - font-family: var(--font-sans); - -webkit-tap-highlight-color: transparent; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - } +/* Typography + platform defaults */ +html { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + tab-size: 4; + font-family: var(--font-sans); + -webkit-tap-highlight-color: transparent; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} - /* Horizontal rule */ - html hr { - height: 0; - color: inherit; - border-top-width: 1px; - } +/* Horizontal rule */ +html hr { + height: 0; + color: inherit; + border-top-width: 1px; +} - /* Abbr */ - html abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; - } +/* Abbr */ +html abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} - /* Headings reset */ - html h1, - html h2, - html h3, - html h4, - html h5, - html h6 { - font-size: inherit; - font-weight: inherit; - } +/* Headings reset */ +html h1, +html h2, +html h3, +html h4, +html h5, +html h6 { + font-size: inherit; + font-weight: inherit; +} - /* Links */ - html a { - color: inherit; - -webkit-text-decoration: inherit; - text-decoration: inherit; - } +/* Links */ +html a { + color: inherit; + -webkit-text-decoration: inherit; + text-decoration: inherit; +} - /* Strong */ - html b, - html strong { - font-weight: bolder; - } +/* Strong */ +html b, +html strong { + font-weight: bolder; +} - /* Code fonts */ - html code, - html kbd, - html samp, - html pre { - font-family: var(--font-mono), monospace; - font-size: 1em; - } +/* Code fonts */ +html code, +html kbd, +html samp, +html pre { + font-family: var(--font-mono), monospace; + font-size: 1em; +} - /* Small */ - html small { - font-size: 80%; - } +/* Small */ +html small { + font-size: 80%; +} - /* Sub/Sup */ - html sub, - html sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; - } - html sub { - bottom: -0.25em; - } - html sup { - top: -0.5em; - } +/* Sub/Sup */ +html sub, +html sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +html sub { + bottom: -0.25em; +} +html sup { + top: -0.5em; +} - /* Tables */ - html table { - text-indent: 0; - border-color: inherit; - border-collapse: collapse; - } +/* Tables */ +html table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; +} - /* Firefox focus */ - html :-moz-focusring { - outline: auto; - } +/* Firefox focus */ +html :-moz-focusring { + outline: auto; +} - /* Progress baseline */ - html progress { - vertical-align: baseline; - } +/* Progress baseline */ +html progress { + vertical-align: baseline; +} - /* Summary display */ - html summary { - display: list-item; - } +/* Summary display */ +html summary { + display: list-item; +} - /* Lists unstyled */ - html ol, - html ul, - html menu { - list-style: none; - } +/* Lists unstyled */ +html ol, +html ul, +html menu { + list-style: none; +} - /* Replaced elements */ - html img, - html svg, - html video, - html canvas, - html audio, - html iframe, - html embed, - html object { - display: block; - vertical-align: middle; - } +/* Replaced elements */ +html img, +html svg, +html video, +html canvas, +html audio, +html iframe, +html embed, +html object { + display: block; + vertical-align: middle; +} - /* Media constraints */ - html img, - html video { - max-width: 100%; - height: auto; - } +/* Media constraints */ +html img, +html video { + max-width: 100%; + height: auto; +} - /* Form element normalizations */ - html button, - html input, - html select, - html optgroup, - html textarea, - html ::file-selector-button { - font: inherit; - font-feature-settings: inherit; - font-variation-settings: inherit; - letter-spacing: inherit; - color: inherit; - border-radius: 0; - background-color: transparent; - opacity: 1; - } +/* Form element normalizations */ +html button, +html input, +html select, +html optgroup, +html textarea, +html ::file-selector-button { + font: inherit; + font-feature-settings: inherit; + font-variation-settings: inherit; + letter-spacing: inherit; + color: inherit; + border-radius: 0; + background-color: transparent; + opacity: 1; +} - /* Select optgroup weight */ - html :where(select:is([multiple], [size])) optgroup { - font-weight: bolder; - } +/* Select optgroup weight */ +html :where(select:is([multiple], [size])) optgroup { + font-weight: bolder; +} - /* Select optgroup option indent */ - html :where(select:is([multiple], [size])) optgroup option { - padding-inline-start: 20px; - } +/* Select optgroup option indent */ +html :where(select:is([multiple], [size])) optgroup option { + padding-inline-start: 20px; +} - /* File button spacing */ - html ::file-selector-button { - margin-inline-end: 4px; - } +/* File button spacing */ +html ::file-selector-button { + margin-inline-end: 4px; +} - /* Placeholder */ - html ::placeholder { - opacity: 1; - } +/* Placeholder */ +html ::placeholder { + opacity: 1; +} - @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { - html ::placeholder { - color: color-mix(in oklab, currentcolor 50%, transparent); - } +@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { + html ::placeholder { + color: color-mix(in oklab, currentcolor 50%, transparent); } +} - /* Textarea resize */ - html textarea { - resize: vertical; - } +/* Textarea resize */ +html textarea { + resize: vertical; +} - /* WebKit search decoration */ - html ::-webkit-search-decoration { - -webkit-appearance: none; - } +/* WebKit search decoration */ +html ::-webkit-search-decoration { + -webkit-appearance: none; +} - /* iOS date/time */ - html ::-webkit-date-and-time-value { - min-height: 1lh; - text-align: inherit; - } +/* iOS date/time */ +html ::-webkit-date-and-time-value { + min-height: 1lh; + text-align: inherit; +} - html ::-webkit-datetime-edit { - display: inline-flex; - } +html ::-webkit-datetime-edit { + display: inline-flex; +} - html ::-webkit-datetime-edit-fields-wrapper { - padding: 0; - } +html ::-webkit-datetime-edit-fields-wrapper { + padding: 0; +} - html ::-webkit-datetime-edit, - html ::-webkit-datetime-edit-year-field, - html ::-webkit-datetime-edit-month-field, - html ::-webkit-datetime-edit-day-field, - html ::-webkit-datetime-edit-hour-field, - html ::-webkit-datetime-edit-minute-field, - html ::-webkit-datetime-edit-second-field, - html ::-webkit-datetime-edit-millisecond-field, - html ::-webkit-datetime-edit-meridiem-field { - padding-block: 0; - } +html ::-webkit-datetime-edit, +html ::-webkit-datetime-edit-year-field, +html ::-webkit-datetime-edit-month-field, +html ::-webkit-datetime-edit-day-field, +html ::-webkit-datetime-edit-hour-field, +html ::-webkit-datetime-edit-minute-field, +html ::-webkit-datetime-edit-second-field, +html ::-webkit-datetime-edit-millisecond-field, +html ::-webkit-datetime-edit-meridiem-field { + padding-block: 0; +} - html ::-webkit-calendar-picker-indicator { - line-height: 1; - } +html ::-webkit-calendar-picker-indicator { + line-height: 1; +} - /* Firefox invalid */ - html :-moz-ui-invalid { - box-shadow: none; - } +/* Firefox invalid */ +html :-moz-ui-invalid { + box-shadow: none; +} - /* Button appearances */ - html button, - html input:where([type='button'], [type='reset'], [type='submit']), - html ::file-selector-button { - appearance: button; - } +/* Button appearances */ +html button, +html input:where([type='button'], [type='reset'], [type='submit']), +html ::file-selector-button { + appearance: button; +} - /* Safari spin buttons */ - html ::-webkit-inner-spin-button, - html ::-webkit-outer-spin-button { - height: auto; - } +/* Safari spin buttons */ +html ::-webkit-inner-spin-button, +html ::-webkit-outer-spin-button { + height: auto; +} - /* Hidden */ - html [hidden]:where(:not([hidden='until-found'])) { - display: none !important; - } +/* Hidden */ +html [hidden]:where(:not([hidden='until-found'])) { + display: none !important; } diff --git a/packages/ui/src/theme/theme-preflight-scoped.css b/packages/ui/src/theme/theme-preflight-scoped.css index 4a2c8af6..3c3f1c76 100644 --- a/packages/ui/src/theme/theme-preflight-scoped.css +++ b/packages/ui/src/theme/theme-preflight-scoped.css @@ -1,259 +1,265 @@ -@layer base { - /* ========================================================= - SCOPED PREFLIGHT (kept intact; selectors retargeted) - ========================================================= */ - - /* 1) Box model + resets + border-color */ - :global(#equality-theme-provider-root), - :global(#equality-theme-provider-root) *, - :global(#equality-theme-provider-root) ::after, - :global(#equality-theme-provider-root) ::before, - :global(#equality-theme-provider-root) ::backdrop, - :global(#equality-theme-provider-root) ::file-selector-button { - box-sizing: border-box; - margin: 0; - padding: 0; - border: 0 solid; - border-color: var(--color-border); - } +/* ========================================================= + SCOPED PREFLIGHT — CANONICAL SOURCE + + Edit this file. `theme-preflight-global.css` is generated from it by + `src/scripts/build-preflight.js`, which swaps `[data-equality-root]` for + `html`. Run `pnpm build:preflight` after changing anything here. + + Deliberately carries no `@layer` wrapper: the importer assigns the layer, + so a consumer can place the reset wherever their cascade needs it. + + @import '@eqtylab/equality/preflight-scoped.css' layer(base); + ========================================================= */ + +/* 1) Box model + resets + border-color */ +[data-equality-root], +[data-equality-root] *, +[data-equality-root] ::after, +[data-equality-root] ::before, +[data-equality-root] ::backdrop, +[data-equality-root] ::file-selector-button { + box-sizing: border-box; + margin: 0; + padding: 0; + border: 0 solid; + border-color: var(--color-border); +} - /* Cursor for buttons */ - :global(#equality-theme-provider-root) button { - cursor: pointer; - } +/* Cursor for buttons */ +[data-equality-root] button { + cursor: pointer; +} - /* Typography + platform defaults */ - :global(#equality-theme-provider-root) { - line-height: 1.5; - -webkit-text-size-adjust: 100%; - tab-size: 4; - font-family: var(--font-sans); - -webkit-tap-highlight-color: transparent; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - } +/* Typography + platform defaults */ +[data-equality-root] { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + tab-size: 4; + font-family: var(--font-sans); + -webkit-tap-highlight-color: transparent; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} - /* Horizontal rule */ - :global(#equality-theme-provider-root) hr { - height: 0; - color: inherit; - border-top-width: 1px; - } +/* Horizontal rule */ +[data-equality-root] hr { + height: 0; + color: inherit; + border-top-width: 1px; +} - /* Abbr */ - :global(#equality-theme-provider-root) abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; - } +/* Abbr */ +[data-equality-root] abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} - /* Headings reset */ - :global(#equality-theme-provider-root) h1, - :global(#equality-theme-provider-root) h2, - :global(#equality-theme-provider-root) h3, - :global(#equality-theme-provider-root) h4, - :global(#equality-theme-provider-root) h5, - :global(#equality-theme-provider-root) h6 { - font-size: inherit; - font-weight: inherit; - } +/* Headings reset */ +[data-equality-root] h1, +[data-equality-root] h2, +[data-equality-root] h3, +[data-equality-root] h4, +[data-equality-root] h5, +[data-equality-root] h6 { + font-size: inherit; + font-weight: inherit; +} - /* Links */ - :global(#equality-theme-provider-root) a { - color: inherit; - -webkit-text-decoration: inherit; - text-decoration: inherit; - } +/* Links */ +[data-equality-root] a { + color: inherit; + -webkit-text-decoration: inherit; + text-decoration: inherit; +} - /* Strong */ - :global(#equality-theme-provider-root) b, - :global(#equality-theme-provider-root) strong { - font-weight: bolder; - } +/* Strong */ +[data-equality-root] b, +[data-equality-root] strong { + font-weight: bolder; +} - /* Code fonts */ - :global(#equality-theme-provider-root) code, - :global(#equality-theme-provider-root) kbd, - :global(#equality-theme-provider-root) samp, - :global(#equality-theme-provider-root) pre { - font-family: var(--font-mono), monospace; - font-size: 1em; - } +/* Code fonts */ +[data-equality-root] code, +[data-equality-root] kbd, +[data-equality-root] samp, +[data-equality-root] pre { + font-family: var(--font-mono), monospace; + font-size: 1em; +} - /* Small */ - :global(#equality-theme-provider-root) small { - font-size: 80%; - } +/* Small */ +[data-equality-root] small { + font-size: 80%; +} - /* Sub/Sup */ - :global(#equality-theme-provider-root) sub, - :global(#equality-theme-provider-root) sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; - } - :global(#equality-theme-provider-root) sub { - bottom: -0.25em; - } - :global(#equality-theme-provider-root) sup { - top: -0.5em; - } +/* Sub/Sup */ +[data-equality-root] sub, +[data-equality-root] sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +[data-equality-root] sub { + bottom: -0.25em; +} +[data-equality-root] sup { + top: -0.5em; +} - /* Tables */ - :global(#equality-theme-provider-root) table { - text-indent: 0; - border-color: inherit; - border-collapse: collapse; - } +/* Tables */ +[data-equality-root] table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; +} - /* Firefox focus */ - :global(#equality-theme-provider-root) :-moz-focusring { - outline: auto; - } +/* Firefox focus */ +[data-equality-root] :-moz-focusring { + outline: auto; +} - /* Progress baseline */ - :global(#equality-theme-provider-root) progress { - vertical-align: baseline; - } +/* Progress baseline */ +[data-equality-root] progress { + vertical-align: baseline; +} - /* Summary display */ - :global(#equality-theme-provider-root) summary { - display: list-item; - } +/* Summary display */ +[data-equality-root] summary { + display: list-item; +} - /* Lists unstyled */ - :global(#equality-theme-provider-root) ol, - :global(#equality-theme-provider-root) ul, - :global(#equality-theme-provider-root) menu { - list-style: none; - } +/* Lists unstyled */ +[data-equality-root] ol, +[data-equality-root] ul, +[data-equality-root] menu { + list-style: none; +} - /* Replaced elements */ - :global(#equality-theme-provider-root) img, - :global(#equality-theme-provider-root) svg, - :global(#equality-theme-provider-root) video, - :global(#equality-theme-provider-root) canvas, - :global(#equality-theme-provider-root) audio, - :global(#equality-theme-provider-root) iframe, - :global(#equality-theme-provider-root) embed, - :global(#equality-theme-provider-root) object { - display: block; - vertical-align: middle; - } +/* Replaced elements */ +[data-equality-root] img, +[data-equality-root] svg, +[data-equality-root] video, +[data-equality-root] canvas, +[data-equality-root] audio, +[data-equality-root] iframe, +[data-equality-root] embed, +[data-equality-root] object { + display: block; + vertical-align: middle; +} - /* Media constraints */ - :global(#equality-theme-provider-root) img, - :global(#equality-theme-provider-root) video { - max-width: 100%; - height: auto; - } +/* Media constraints */ +[data-equality-root] img, +[data-equality-root] video { + max-width: 100%; + height: auto; +} - /* Form element normalizations */ - :global(#equality-theme-provider-root) button, - :global(#equality-theme-provider-root) input, - :global(#equality-theme-provider-root) select, - :global(#equality-theme-provider-root) optgroup, - :global(#equality-theme-provider-root) textarea, - :global(#equality-theme-provider-root) ::file-selector-button { - font: inherit; - font-feature-settings: inherit; - font-variation-settings: inherit; - letter-spacing: inherit; - color: inherit; - border-radius: 0; - background-color: transparent; - opacity: 1; - } +/* Form element normalizations */ +[data-equality-root] button, +[data-equality-root] input, +[data-equality-root] select, +[data-equality-root] optgroup, +[data-equality-root] textarea, +[data-equality-root] ::file-selector-button { + font: inherit; + font-feature-settings: inherit; + font-variation-settings: inherit; + letter-spacing: inherit; + color: inherit; + border-radius: 0; + background-color: transparent; + opacity: 1; +} - /* Select optgroup weight */ - :global(#equality-theme-provider-root) :where(select:is([multiple], [size])) optgroup { - font-weight: bolder; - } +/* Select optgroup weight */ +[data-equality-root] :where(select:is([multiple], [size])) optgroup { + font-weight: bolder; +} - /* Select optgroup option indent */ - :global(#equality-theme-provider-root) :where(select:is([multiple], [size])) optgroup option { - padding-inline-start: 20px; - } +/* Select optgroup option indent */ +[data-equality-root] :where(select:is([multiple], [size])) optgroup option { + padding-inline-start: 20px; +} - /* File button spacing */ - :global(#equality-theme-provider-root) ::file-selector-button { - margin-inline-end: 4px; - } +/* File button spacing */ +[data-equality-root] ::file-selector-button { + margin-inline-end: 4px; +} - /* Placeholder */ - :global(#equality-theme-provider-root) ::placeholder { - opacity: 1; - } +/* Placeholder */ +[data-equality-root] ::placeholder { + opacity: 1; +} - @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { - :global(#equality-theme-provider-root) ::placeholder { - color: color-mix(in oklab, currentcolor 50%, transparent); - } +@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { + [data-equality-root] ::placeholder { + color: color-mix(in oklab, currentcolor 50%, transparent); } +} - /* Textarea resize */ - :global(#equality-theme-provider-root) textarea { - resize: vertical; - } +/* Textarea resize */ +[data-equality-root] textarea { + resize: vertical; +} - /* WebKit search decoration */ - :global(#equality-theme-provider-root) ::-webkit-search-decoration { - -webkit-appearance: none; - } +/* WebKit search decoration */ +[data-equality-root] ::-webkit-search-decoration { + -webkit-appearance: none; +} - /* iOS date/time */ - :global(#equality-theme-provider-root) ::-webkit-date-and-time-value { - min-height: 1lh; - text-align: inherit; - } +/* iOS date/time */ +[data-equality-root] ::-webkit-date-and-time-value { + min-height: 1lh; + text-align: inherit; +} - :global(#equality-theme-provider-root) ::-webkit-datetime-edit { - display: inline-flex; - } +[data-equality-root] ::-webkit-datetime-edit { + display: inline-flex; +} - :global(#equality-theme-provider-root) ::-webkit-datetime-edit-fields-wrapper { - padding: 0; - } +[data-equality-root] ::-webkit-datetime-edit-fields-wrapper { + padding: 0; +} - :global(#equality-theme-provider-root) ::-webkit-datetime-edit, - :global(#equality-theme-provider-root) ::-webkit-datetime-edit-year-field, - :global(#equality-theme-provider-root) ::-webkit-datetime-edit-month-field, - :global(#equality-theme-provider-root) ::-webkit-datetime-edit-day-field, - :global(#equality-theme-provider-root) ::-webkit-datetime-edit-hour-field, - :global(#equality-theme-provider-root) ::-webkit-datetime-edit-minute-field, - :global(#equality-theme-provider-root) ::-webkit-datetime-edit-second-field, - :global(#equality-theme-provider-root) ::-webkit-datetime-edit-millisecond-field, - :global(#equality-theme-provider-root) ::-webkit-datetime-edit-meridiem-field { - padding-block: 0; - } +[data-equality-root] ::-webkit-datetime-edit, +[data-equality-root] ::-webkit-datetime-edit-year-field, +[data-equality-root] ::-webkit-datetime-edit-month-field, +[data-equality-root] ::-webkit-datetime-edit-day-field, +[data-equality-root] ::-webkit-datetime-edit-hour-field, +[data-equality-root] ::-webkit-datetime-edit-minute-field, +[data-equality-root] ::-webkit-datetime-edit-second-field, +[data-equality-root] ::-webkit-datetime-edit-millisecond-field, +[data-equality-root] ::-webkit-datetime-edit-meridiem-field { + padding-block: 0; +} - :global(#equality-theme-provider-root) ::-webkit-calendar-picker-indicator { - line-height: 1; - } +[data-equality-root] ::-webkit-calendar-picker-indicator { + line-height: 1; +} - /* Firefox invalid */ - :global(#equality-theme-provider-root) :-moz-ui-invalid { - box-shadow: none; - } +/* Firefox invalid */ +[data-equality-root] :-moz-ui-invalid { + box-shadow: none; +} - /* Button appearances */ - :global(#equality-theme-provider-root) button, - :global(#equality-theme-provider-root) - input:where([type='button'], [type='reset'], [type='submit']), - :global(#equality-theme-provider-root) ::file-selector-button { - appearance: button; - } +/* Button appearances */ +[data-equality-root] button, +[data-equality-root] input:where([type='button'], [type='reset'], [type='submit']), +[data-equality-root] ::file-selector-button { + appearance: button; +} - /* Safari spin buttons */ - :global(#equality-theme-provider-root) ::-webkit-inner-spin-button, - :global(#equality-theme-provider-root) ::-webkit-outer-spin-button { - height: auto; - } +/* Safari spin buttons */ +[data-equality-root] ::-webkit-inner-spin-button, +[data-equality-root] ::-webkit-outer-spin-button { + height: auto; +} - /* Hidden */ - :global(#equality-theme-provider-root) [hidden]:where(:not([hidden='until-found'])) { - display: none !important; - } +/* Hidden */ +[data-equality-root] [hidden]:where(:not([hidden='until-found'])) { + display: none !important; } diff --git a/packages/ui/src/theme/theme-provider.tsx b/packages/ui/src/theme/theme-provider.tsx index a62ffb9e..c99ce2e0 100644 --- a/packages/ui/src/theme/theme-provider.tsx +++ b/packages/ui/src/theme/theme-provider.tsx @@ -28,7 +28,12 @@ const ThemeProvider = ({ customVars, portalContainer, children }: ThemeProviderP return ( -
+
{children} {usesOwnPortal && }
diff --git a/packages/ui/src/theme/theme.module.css b/packages/ui/src/theme/theme.module.css index 919d6646..f8ec3df6 100644 --- a/packages/ui/src/theme/theme.module.css +++ b/packages/ui/src/theme/theme.module.css @@ -10,6 +10,6 @@ @import './tokens.css'; @import './theme-base.css'; -@import './theme-preflight-scoped.css'; +@import './theme-preflight-scoped.css' layer(base); @import './theme-components.css'; @import './theme-utilities.css';