mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
merging
This commit is contained in:
@@ -20,4 +20,5 @@ packages/**/*/src/react/index.ts
|
||||
node_modules
|
||||
|
||||
packages/**/*/_site
|
||||
packages/**/*/_bundle_
|
||||
packages/webawesome/docs/assets/scripts/prism-downloaded.js
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
3.0.0
|
||||
3.1.0
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
"keydown",
|
||||
"keyframes",
|
||||
"keymaker",
|
||||
"Kickstarter",
|
||||
"Konnor",
|
||||
"Kool",
|
||||
"labelledby",
|
||||
@@ -117,6 +118,7 @@
|
||||
"lowercasing",
|
||||
"Lucide",
|
||||
"maxlength",
|
||||
"mdash",
|
||||
"Menlo",
|
||||
"menuitemcheckbox",
|
||||
"menuitemradio",
|
||||
@@ -130,6 +132,7 @@
|
||||
"mouseout",
|
||||
"mouseup",
|
||||
"multiselectable",
|
||||
"nbsp",
|
||||
"nextjs",
|
||||
"nocheck",
|
||||
"noindex",
|
||||
@@ -179,6 +182,7 @@
|
||||
"shadowrootmode",
|
||||
"Shortcode",
|
||||
"Shortcodes",
|
||||
"signup",
|
||||
"sitedir",
|
||||
"slotchange",
|
||||
"smartquotes",
|
||||
|
||||
216
package-lock.json
generated
216
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@webawesome/monorepo",
|
||||
"version": "3.0.0-alpha.13",
|
||||
"version": "3.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@webawesome/monorepo",
|
||||
"version": "3.0.0-alpha.13",
|
||||
"version": "3.1.0",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
@@ -593,6 +593,10 @@
|
||||
"resolved": "packages/webawesome",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@awesome.me/webawesome-pro": {
|
||||
"resolved": "packages/webawesome-pro",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
|
||||
@@ -2519,10 +2523,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@shoelace-style/localize/-/localize-3.2.1.tgz",
|
||||
"integrity": "sha512-r4C9C/5kSfMBIr0D9imvpRdCNXtUNgyYThc4YlS6K5Hchv1UyxNQ9mxwj+BTRH2i1Neits260sR3OjKMnplsFA=="
|
||||
},
|
||||
"node_modules/@shoelace-style/webawesome-pro": {
|
||||
"resolved": "packages/webawesome-pro",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@sindresorhus/is": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
|
||||
@@ -12139,6 +12139,16 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-typescript-paths": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-typescript-paths/-/rollup-plugin-typescript-paths-1.5.0.tgz",
|
||||
"integrity": "sha512-zly2aiGNjYJNq5YUi6eyGrQnCYUQ8b5czOtHZIGriwG9U3Ba2F9hlSklafXCdsNulK/IlNmE0Kzj0h+fVV32pA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"typescript": ">=3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/run-async": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz",
|
||||
@@ -14013,7 +14023,7 @@
|
||||
},
|
||||
"packages/webawesome": {
|
||||
"name": "@awesome.me/webawesome",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ctrl/tinycolor": "4.1.0",
|
||||
@@ -14029,15 +14039,16 @@
|
||||
"devDependencies": {
|
||||
"@wc-toolkit/jsx-types": "^1.3.0",
|
||||
"eleventy-plugin-git-commit-date": "^0.1.3",
|
||||
"esbuild": "^0.25.11"
|
||||
"esbuild": "^0.25.11",
|
||||
"npm-check-updates": "^19.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17.0"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro": {
|
||||
"name": "@shoelace-style/webawesome-pro",
|
||||
"version": "3.0.0-beta.6",
|
||||
"name": "@awesome.me/webawesome-pro",
|
||||
"version": "3.1.0",
|
||||
"dependencies": {
|
||||
"@ctrl/tinycolor": "4.1.0",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
@@ -14051,8 +14062,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wc-toolkit/jsx-types": "^1.3.0",
|
||||
"@web/dev-server-rollup": "^0.6.4",
|
||||
"eleventy-plugin-git-commit-date": "^0.1.3",
|
||||
"esbuild": "^0.25.11"
|
||||
"esbuild": "^0.25.11",
|
||||
"npm-check-updates": "^19.1.2",
|
||||
"rollup-plugin-typescript-paths": "^1.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17.0"
|
||||
@@ -14466,6 +14480,84 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/@web/dev-server-core": {
|
||||
"version": "0.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@web/dev-server-core/-/dev-server-core-0.7.5.tgz",
|
||||
"integrity": "sha512-Da65zsiN6iZPMRuj4Oa6YPwvsmZmo5gtPWhW2lx3GTUf5CAEapjVpZVlUXnKPL7M7zRuk72jSsIl8lo+XpTCtw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/koa": "^2.11.6",
|
||||
"@types/ws": "^7.4.0",
|
||||
"@web/parse5-utils": "^2.1.0",
|
||||
"chokidar": "^4.0.1",
|
||||
"clone": "^2.1.2",
|
||||
"es-module-lexer": "^1.0.0",
|
||||
"get-stream": "^6.0.0",
|
||||
"is-stream": "^2.0.0",
|
||||
"isbinaryfile": "^5.0.0",
|
||||
"koa": "^2.13.0",
|
||||
"koa-etag": "^4.0.0",
|
||||
"koa-send": "^5.0.1",
|
||||
"koa-static": "^5.0.0",
|
||||
"lru-cache": "^8.0.4",
|
||||
"mime-types": "^2.1.27",
|
||||
"parse5": "^6.0.1",
|
||||
"picomatch": "^2.2.2",
|
||||
"ws": "^7.5.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/@web/dev-server-rollup": {
|
||||
"version": "0.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@web/dev-server-rollup/-/dev-server-rollup-0.6.4.tgz",
|
||||
"integrity": "sha512-sJZfTGCCrdku5xYnQQG51odGI092hKY9YFM0X3Z0tRY3iXKXcYRaLZrErw5KfCxr6g0JRuhe4BBhqXTA5Q2I3Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@web/dev-server-core": "^0.7.2",
|
||||
"nanocolors": "^0.2.1",
|
||||
"parse5": "^6.0.1",
|
||||
"rollup": "^4.4.0",
|
||||
"whatwg-url": "^14.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/@web/parse5-utils": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@web/parse5-utils/-/parse5-utils-2.1.0.tgz",
|
||||
"integrity": "sha512-GzfK5disEJ6wEjoPwx8AVNwUe9gYIiwc+x//QYxYDAFKUp4Xb1OJAGLc2l2gVrSQmtPGLKrTRcW90Hv4pEq1qA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/parse5": "^6.0.1",
|
||||
"parse5": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/esbuild": {
|
||||
"version": "0.25.11",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz",
|
||||
@@ -14508,6 +14600,16 @@
|
||||
"@esbuild/win32-x64": "0.25.11"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/lru-cache": {
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz",
|
||||
"integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=16.14"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/nanoid": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz",
|
||||
@@ -14525,6 +14627,84 @@
|
||||
"node": "^18 || >=20"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/npm-check-updates": {
|
||||
"version": "19.1.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-19.1.2.tgz",
|
||||
"integrity": "sha512-FNeFCVgPOj0fz89hOpGtxP2rnnRHR7hD2E8qNU8SMWfkyDZXA/xpgjsL3UMLSo3F/K13QvJDnbxPngulNDDo/g==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"ncu": "build/cli.js",
|
||||
"npm-check-updates": "build/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0",
|
||||
"npm": ">=8.12.1"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/readdirp": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/tr46": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
|
||||
"integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"punycode": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/whatwg-url": {
|
||||
"version": "14.2.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
|
||||
"integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "^5.1.0",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"packages/webawesome-pro/node_modules/ws": {
|
||||
"version": "7.5.10",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
|
||||
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"packages/webawesome/node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.11",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz",
|
||||
@@ -14966,6 +15146,20 @@
|
||||
"engines": {
|
||||
"node": "^18 || >=20"
|
||||
}
|
||||
},
|
||||
"packages/webawesome/node_modules/npm-check-updates": {
|
||||
"version": "19.1.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-19.1.2.tgz",
|
||||
"integrity": "sha512-FNeFCVgPOj0fz89hOpGtxP2rnnRHR7hD2E8qNU8SMWfkyDZXA/xpgjsL3UMLSo3F/K13QvJDnbxPngulNDDo/g==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"ncu": "build/cli.js",
|
||||
"npm-check-updates": "build/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0",
|
||||
"npm": ">=8.12.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@webawesome/monorepo",
|
||||
"private": true,
|
||||
"description": "A forward-thinking library of web components.",
|
||||
"version": "3.0.0-alpha.13",
|
||||
"version": "3.1.0",
|
||||
"homepage": "https://webawesome.com/",
|
||||
"author": "Web Awesome",
|
||||
"license": "MIT",
|
||||
@@ -85,4 +85,4 @@
|
||||
"prettier --write"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { nanoid } from 'nanoid';
|
||||
import { parse as HTMLParse } from 'node-html-parser';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { anchorHeadingsTransformer } from './_transformers/anchor-headings.js';
|
||||
@@ -21,7 +20,6 @@ import { replaceTextPlugin } from './_plugins/replace-text.js';
|
||||
import { searchPlugin } from './_plugins/search.js';
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
||||
const isDev = process.argv.includes('--develop');
|
||||
const ignoreGit = process.env.ELEVENTY_IGNORE_GIT === 'true';
|
||||
const passThroughExtensions = ['js', 'css', 'png', 'svg', 'jpg', 'mp4'];
|
||||
|
||||
async function getPackageData() {
|
||||
@@ -60,15 +58,6 @@ export default async function (eleventyConfig) {
|
||||
if (updateComponentData) {
|
||||
allComponents = getComponents();
|
||||
}
|
||||
|
||||
// Invalidate last-modified cache for changed content files during watch
|
||||
if (Array.isArray(changedFiles)) {
|
||||
for (const file of changedFiles) {
|
||||
if (/\.(md|njk|html)$/i.test(file)) {
|
||||
lastModCache.delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -102,6 +91,31 @@ export default async function (eleventyConfig) {
|
||||
image: 'https://webawesome.com/assets/images/open-graph/default.png',
|
||||
};
|
||||
|
||||
// Title composition/stripping config - single source of truth
|
||||
const SITE_NAME = siteMetadata.name;
|
||||
const SITE_TITLE_SEPARATORS = ['|'];
|
||||
|
||||
// Helper to escape user-provided strings for safe use inside RegExp sources
|
||||
const escapeRegExp = string => (string + '').replace(/[.*+?^${}()|[\\]\\]/g, '\\$&');
|
||||
|
||||
// Precompute a reusable regex to strip a trailing site name suffix from titles, e.g. " | Web Awesome"
|
||||
// Supports configured separators and flexible whitespace. This keeps search titles clean and improves Lunr scoring
|
||||
const siteNameEscapedForRegex = escapeRegExp(SITE_NAME);
|
||||
const separatorsEscaped = SITE_TITLE_SEPARATORS.map(s => escapeRegExp(s)).join('');
|
||||
const siteTitleSuffixPattern = new RegExp(`\\s*[${separatorsEscaped}]\\s*${siteNameEscapedForRegex}$`);
|
||||
|
||||
// Helper to remove the site suffix from a page title. Keep this in sync with how page titles
|
||||
// are composed (see eleventyComputed.pageTitle) so search indexing stays consistent
|
||||
const stripSiteTitleSuffix = title => (title || '').replace(siteTitleSuffixPattern, '');
|
||||
|
||||
// Helper to compose a full page title with site suffix when appropriate
|
||||
// Uses the same separator set as the stripping logic for consistency
|
||||
const composePageTitle = baseTitle => {
|
||||
const title = baseTitle || SITE_NAME;
|
||||
const preferredSeparator = SITE_TITLE_SEPARATORS[0] || '|';
|
||||
return title !== SITE_NAME ? `${title} ${preferredSeparator} ${SITE_NAME}` : title;
|
||||
};
|
||||
|
||||
eleventyConfig.addGlobalData('siteMetadata', siteMetadata);
|
||||
|
||||
// Template filters - {{ content | filter }}
|
||||
@@ -110,88 +124,12 @@ export default async function (eleventyConfig) {
|
||||
eleventyConfig.addFilter('stripExtension', string => path.parse(string + '').name);
|
||||
eleventyConfig.addFilter('stripPrefix', content => content.replace(/^wa-/, ''));
|
||||
eleventyConfig.addFilter('uniqueId', (_value, length = 8) => nanoid(length));
|
||||
// Returns last modified date as ISO 8601 (UTC, Z-suffixed)
|
||||
// Fallback order: front matter override -> Git last commit date -> filesystem mtime -> now
|
||||
// Caching: in-memory per inputPath during one build/dev session
|
||||
// Override: pass a Date or string: {{ page.inputPath | gitLastModifiedISO(lastUpdated) }}
|
||||
const lastModCache = new Map();
|
||||
let repoRoot = null; // lazily resolved; null => not resolved, undefined => failed
|
||||
|
||||
function getLastModifiedISO(inputPath, overrideDate) {
|
||||
if (overrideDate instanceof Date) {
|
||||
return overrideDate.toISOString();
|
||||
}
|
||||
if (typeof overrideDate === 'string' && overrideDate) {
|
||||
const parsed = new Date(overrideDate);
|
||||
if (!isNaN(parsed.getTime())) return parsed.toISOString();
|
||||
}
|
||||
if (!inputPath) return new Date().toISOString();
|
||||
if (lastModCache.has(inputPath)) return lastModCache.get(inputPath);
|
||||
|
||||
// Try Git (ISO via %cI). Use a repo-root-relative path for portability.
|
||||
if (!ignoreGit) {
|
||||
try {
|
||||
if (repoRoot === null) {
|
||||
try {
|
||||
repoRoot = execFileSync('git', ['rev-parse', '--show-toplevel'], {
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
cwd: __dirname,
|
||||
})
|
||||
.toString()
|
||||
.trim();
|
||||
} catch (_) {
|
||||
repoRoot = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const gitPath = repoRoot ? path.relative(repoRoot, inputPath) : inputPath;
|
||||
const args = ['log', '-1', '--format=%cI', '--follow', '--', gitPath];
|
||||
const result = execFileSync('git', args, {
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
cwd: repoRoot || path.dirname(inputPath),
|
||||
})
|
||||
.toString()
|
||||
.trim();
|
||||
if (result) {
|
||||
const iso = new Date(result).toISOString();
|
||||
lastModCache.set(inputPath, iso);
|
||||
return iso;
|
||||
}
|
||||
} catch (_) {
|
||||
// continue to fs fallback
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to filesystem mtime
|
||||
try {
|
||||
const stats = fs.statSync(inputPath);
|
||||
const iso = new Date(stats.mtime).toISOString();
|
||||
lastModCache.set(inputPath, iso);
|
||||
return iso;
|
||||
} catch (_) {
|
||||
const now = new Date().toISOString();
|
||||
lastModCache.set(inputPath, now);
|
||||
return now;
|
||||
}
|
||||
}
|
||||
|
||||
eleventyConfig.addFilter('gitLastModifiedISO', function (inputPath, overrideDate) {
|
||||
return getLastModifiedISO(inputPath, overrideDate);
|
||||
});
|
||||
|
||||
// Attach lastUpdatedISO to page data so templates can use {{ lastUpdatedISO }} directly
|
||||
eleventyConfig.addGlobalData('eleventyComputed', {
|
||||
lastUpdatedISO: data => getLastModifiedISO(data.page?.inputPath, data.lastUpdated),
|
||||
// Page title with smart + default site name formatting
|
||||
pageTitle: data => {
|
||||
const title = data.title || siteMetadata.name;
|
||||
return title !== siteMetadata.name ? `${title} | ${siteMetadata.name}` : title;
|
||||
},
|
||||
pageTitle: data => composePageTitle(data.title),
|
||||
// Open Graph title with smart + default site name formatting
|
||||
ogTitle: data => {
|
||||
const ogTitle = data.ogTitle || data.title || siteMetadata.name;
|
||||
return ogTitle !== siteMetadata.name ? `${ogTitle} | ${siteMetadata.name}` : ogTitle;
|
||||
},
|
||||
ogTitle: data => composePageTitle(data.ogTitle || data.title),
|
||||
ogDescription: data => data.ogDescription || data.description,
|
||||
ogImage: data => data.ogImage || siteMetadata.image,
|
||||
ogUrl: data => {
|
||||
@@ -201,6 +139,7 @@ export default async function (eleventyConfig) {
|
||||
},
|
||||
ogType: data => data.ogType || 'website',
|
||||
});
|
||||
|
||||
// Trims whitespace and pipes from the start and end of a string. Useful for CEM types, which can be pipe-delimited.
|
||||
// With Prettier 3, this means a leading pipe will exist be present when the line wraps.
|
||||
eleventyConfig.addFilter('trimPipes', content => {
|
||||
@@ -354,6 +293,11 @@ export default async function (eleventyConfig) {
|
||||
searchPlugin({
|
||||
filename: '',
|
||||
selectorsToIgnore: ['code.example'],
|
||||
// Use <title> but strip a trailing site name suffix for cleaner search results
|
||||
getTitle: doc => {
|
||||
const raw = doc.querySelector('title')?.textContent ?? '';
|
||||
return stripSiteTitleSuffix(raw);
|
||||
},
|
||||
getContent: doc => doc.querySelector('#content')?.textContent ?? '',
|
||||
}),
|
||||
);
|
||||
@@ -369,18 +313,19 @@ export default async function (eleventyConfig) {
|
||||
|
||||
// This needs to happen in "eleventy.after" otherwise incremental builds never update.
|
||||
eleventyConfig.on('eleventy.after', function () {
|
||||
let assetsDir = path.join(process.env.BASE_DIR || 'docs', 'assets');
|
||||
const baseDir = process.env.BASE_DIR || 'docs';
|
||||
let assetsDir = path.join(baseDir, 'assets');
|
||||
const siteAssetsDir = path.join(eleventyConfig.directories.output, 'assets');
|
||||
fs.cpSync(assetsDir, siteAssetsDir, { recursive: true });
|
||||
|
||||
// Passthrough copy for manifest.json (PWA manifest file)
|
||||
fs.cpSync(path.join(baseDir, 'manifest.json'), path.join(eleventyConfig.directories.output, 'manifest.json'));
|
||||
});
|
||||
|
||||
for (let glob of passThrough) {
|
||||
eleventyConfig.addPassthroughCopy(glob);
|
||||
}
|
||||
|
||||
// Passthrough copy for manifest.json (PWA manifest file)
|
||||
eleventyConfig.addPassthroughCopy('manifest.json');
|
||||
|
||||
// // SSR plugin
|
||||
// if (!isDev) {
|
||||
// //
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% raw %}
|
||||
{%- if not currentUser.hasPro -%}
|
||||
{%- if req.stripe.discount.active and not currentUser.hasPro -%}
|
||||
<div slot="banner" class="banner-wa-launch wa-dark">
|
||||
<div class="banner-content wa-split">
|
||||
<div class="wa-cluster wa-gap-s">
|
||||
|
||||
77
packages/webawesome/docs/_includes/_dialog-wa-launch.njk
Normal file
77
packages/webawesome/docs/_includes/_dialog-wa-launch.njk
Normal file
@@ -0,0 +1,77 @@
|
||||
{% raw %}
|
||||
{%- if req.stripe.discount.active and not currentUser.hasPro -%}
|
||||
<wa-dialog id="dialog-site" light-dismiss without-header>
|
||||
|
||||
<div class="background-wa-pattern" style="justify-content: center; margin-inline: calc(var(--spacing) * -1); margin-block-start: calc(var(--spacing) * -1); margin-block-end: var(--spacing); background: linear-gradient(to bottom, var(--wa-color-brand), var(--wa-color-brand-50)); color: var(--wa-color-brand-on-loud); padding: var(--wa-space-3xl) var(--spacing); --background-pattern-opacity: 0.2; --background-pattern-image: url('/assets/images/bg-wa-pattern.svg');">
|
||||
|
||||
<div class="wa-stack wa-align-items-center" style="text-align: center;">
|
||||
<wa-icon name="party-horn" family="duotone" variant="solid" style="font-size: var(--wa-font-size-3xl); --secondary-color: var(--wa-color-brand-40); --secondary-opacity: 1.0;"></wa-icon>
|
||||
<h2 class="wa-heading-2xl brand-font">Get a lifetime discount on Web Awesome Pro!</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wa-stack wa-gap-l">
|
||||
<p>Celebrate our official launch with a 20% discount on a Web Awesome Pro plan…<span class="appearance-underlined variant-drawn" style="--underline-color: var(--wa-color-brand);">for life</span>! But hurry, this lifetime discount is only available for a limited time.</p>
|
||||
|
||||
<div class="wa-split">
|
||||
<wa-button type="button" appearance="plain" data-dialog="close">Maybe Later</wa-button>
|
||||
<wa-button variant="neutral" appearance="accent" href="/purchase" class="brand-font">
|
||||
<wa-icon slot="start" variant="regular" name="rocket-launch"></wa-icon>
|
||||
Get Pro + Save 20%
|
||||
</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
</wa-dialog>
|
||||
|
||||
<script type="module">
|
||||
(function() {
|
||||
const SITE_DIALOG_DISMISSED_KEY = 'dialog-wa-launch-sale-dismissed';
|
||||
|
||||
// Early exit if user has dismissed the dialog
|
||||
try {
|
||||
if (localStorage.getItem(SITE_DIALOG_DISMISSED_KEY) === 'true') {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
// localStorage may be disabled or unavailable
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for DOM and dialog element
|
||||
const dialog = document.getElementById('dialog-site');
|
||||
if (!dialog) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize dialog functionality
|
||||
let initCalled = false;
|
||||
const initDialog = () => {
|
||||
// Prevent double initialization
|
||||
if (initCalled) {
|
||||
return;
|
||||
}
|
||||
initCalled = true;
|
||||
|
||||
// Save dismissal state when dialog is hidden
|
||||
dialog.addEventListener('wa-hide', (event) => {
|
||||
// Save dismissal state to localStorage
|
||||
try {
|
||||
localStorage.setItem(SITE_DIALOG_DISMISSED_KEY, 'true');
|
||||
} catch (e) {
|
||||
// localStorage may be disabled or unavailable
|
||||
}
|
||||
}, { once: true });
|
||||
|
||||
// Show dialog after a short delay to ensure page is loaded
|
||||
setTimeout(() => {
|
||||
dialog.open = true;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
customElements.whenDefined("wa-dialog").then(() => {
|
||||
initDialog()
|
||||
})
|
||||
})();
|
||||
</script>
|
||||
{%- endif -%}
|
||||
{% endraw %}
|
||||
@@ -1,5 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-fa-kit-code="38c11e3f20" data-version="{{ package.version }}" class="wa-cloak">
|
||||
{% if hasAnchors == undefined %}{% set hasAnchors = true %}{% endif %}
|
||||
{% if hasBanner == undefined %}{% set hasBanner = true %}{% endif %}
|
||||
{% if hasSiteDialog == undefined %}{% set hasSiteDialog = true %}{% endif %}
|
||||
{% if hasGeneratedTitle == undefined %}{% set hasGeneratedTitle = true %}{% endif %}
|
||||
<html lang="en" data-fa-kit-code="38c11e3f20" data-version="{{ package.version }}" class="wa-cloak"{% if hasAnchors == false %} data-no-anchor{% endif %}>
|
||||
<head>
|
||||
{% include 'head.njk' %}
|
||||
<meta name="theme-color" content="#f36944">
|
||||
@@ -13,7 +17,6 @@
|
||||
<script type="module" src="/assets/scripts/color-scheme.js"></script>
|
||||
<script type="module" src="/assets/scripts/theme.js"></script>
|
||||
{% if hasSidebar %}<script type="module" src="/assets/scripts/sidebar.js"></script>{% endif %}
|
||||
<script defer data-domain="webawesome.com" src="https://plausible.io/js/script.js"></script>
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="/assets/styles/docs.css" />
|
||||
@@ -27,9 +30,6 @@
|
||||
</script>
|
||||
</head>
|
||||
<body class="layout-{{ layout | stripExtension }} page-{{ pageClass or page.fileSlug or 'home' }}{{ ' page-wide' if wide }}">
|
||||
{% if hasBanner == undefined %}
|
||||
{% set hasBanner = true %}
|
||||
{% endif %}
|
||||
|
||||
{% set defaultWaPageAttributes = defaultWaPageAttributes or { view: 'desktop', 'disable-navigation-toggle': true, 'mobile-breakpoint': 1180, 'disable-sticky': 'banner' } %}
|
||||
{% set waPageAttributes = waPageAttributes or {} %}
|
||||
@@ -120,7 +120,9 @@
|
||||
<div id="flashes">{% server "flashes" %}</div>
|
||||
|
||||
{% block header %}
|
||||
<h1 class="title">{{ title }}</h1>
|
||||
{% if hasGeneratedTitle %}
|
||||
<h1 class="title">{{ title }}</h1>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block beforeContent %}{% endblock %}
|
||||
@@ -134,6 +136,14 @@
|
||||
|
||||
{% include 'search.njk' %}
|
||||
|
||||
{#- Site-Wide Dialog -#}
|
||||
{% if hasSiteDialog %}
|
||||
{% include "_dialog-wa-launch.njk" ignore missing %}
|
||||
{% endif %}
|
||||
|
||||
{#- Cookie Consent Dialog -#}
|
||||
{% include "cookie-consent.njk" ignore missing %}
|
||||
|
||||
{# Footer #}
|
||||
{% block pageFooter %}{% endblock %}
|
||||
</wa-page>
|
||||
|
||||
7
packages/webawesome/docs/_includes/free-badge.njk
Normal file
7
packages/webawesome/docs/_includes/free-badge.njk
Normal file
@@ -0,0 +1,7 @@
|
||||
{% macro freeBadge(params) %}
|
||||
{% set description = params.description or "This feature is available in the free version of Web Awesome" %}
|
||||
{% set badgeId = params.id or ("free-badge-" + ("" | uniqueId(8))) %}
|
||||
<wa-badge appearance="filled" variant="neutral" pill class="free" id="{{ badgeId }}" data-free-badge>Free</wa-badge>
|
||||
<wa-tooltip for="{{ badgeId }}">{{ description }}</wa-tooltip>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% macro proBadge(params) %}
|
||||
{% set description = params.description or "This requires access to Web Awesome Pro" %}
|
||||
{% set badgeId = params.id or ("pro-badge-" + ("" | uniqueId(8))) %}
|
||||
<wa-badge appearance="accent" pill class="pro" id="{{ badgeId }}">Pro</wa-badge>
|
||||
<wa-badge appearance="accent" pill class="pro" id="{{ badgeId }}" data-pro-badge>Pro</wa-badge>
|
||||
<wa-tooltip for="{{ badgeId }}">{{ description }}</wa-tooltip>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
<li><a href="/docs/resources/contributing">Contributing</a></li>
|
||||
<li><a href="/docs/resources/changelog">Changelog</a></li>
|
||||
<li><a href="/docs/resources/visual-tests">Visual Tests</a></li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- Components -->
|
||||
@@ -78,10 +76,18 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><span class="is-planned wa-split">Charts <a href="https://github.com/shoelace-style/webawesome/issues/1073" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a></span></li>
|
||||
<li><span class="is-planned wa-split">Charts <span><a href="https://github.com/shoelace-style/webawesome/issues/1073" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a>{{ proBadge({ description: "This will require access to Web Awesome Pro" }) }}</span></span></li>
|
||||
<li><a href="/docs/components/checkbox/">Checkbox</a></li>
|
||||
<li><a href="/docs/components/color-picker/">Color Picker</a></li>
|
||||
<li><span class="is-planned wa-split">Combobox <a href="https://github.com/shoelace-style/webawesome/issues/1074" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a></span></li>
|
||||
<li>
|
||||
<span class="wa-split">
|
||||
<span>
|
||||
<a href="/docs/components/combobox">Combobox</a>
|
||||
<wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
|
||||
</span>
|
||||
{{ proBadge() }}
|
||||
</span>
|
||||
</li>
|
||||
<li><a href="/docs/components/comparison/">Comparison</a></li>
|
||||
<li>
|
||||
<a class="wa-cluster wa-gap-xs" href="/docs/components/copy-button/">
|
||||
@@ -89,8 +95,8 @@
|
||||
<wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
|
||||
</a>
|
||||
</li>
|
||||
<li><span class="is-planned wa-split">Data Grid <a href="https://github.com/shoelace-style/webawesome/issues/1072" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a></span></li>
|
||||
<li><span class="is-planned wa-split">Datepicker <a href="https://github.com/shoelace-style/webawesome/issues/1075" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a></span></li>
|
||||
<li><span class="is-planned wa-split">Data Grid <span><a href="https://github.com/shoelace-style/webawesome/issues/1072" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a>{{ proBadge({ description: "This will require access to Web Awesome Pro" }) }}</span></span></li>
|
||||
<li><span class="is-planned wa-split">Date Picker <span><a href="https://github.com/shoelace-style/webawesome/issues/1075" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a>{{ proBadge({ description: "This will require access to Web Awesome Pro" }) }}</span></span></li>
|
||||
<li><a href="/docs/components/details/">Details</a></li>
|
||||
<li><a href="/docs/components/dialog/">Dialog</a></li>
|
||||
<li><a href="/docs/components/divider/">Divider</a></li>
|
||||
@@ -101,6 +107,7 @@
|
||||
<li><a href="/docs/components/dropdown-item">Dropdown Item</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><span class="is-planned wa-split">File Input <span><a href="https://github.com/shoelace-style/webawesome/issues/1240" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a>{{ proBadge({ description: "This will require access to Web Awesome Pro" }) }}</span></span></li>
|
||||
<li><a href="/docs/components/format-bytes/">Format Bytes</a></li>
|
||||
<li><a href="/docs/components/format-date/">Format Date</a></li>
|
||||
<li><a href="/docs/components/format-number/">Format Number</a></li>
|
||||
@@ -109,6 +116,7 @@
|
||||
<li><a href="/docs/components/input/">Input</a></li>
|
||||
<li><a href="/docs/components/intersection-observer">Intersection Observer</a></li>
|
||||
<li><a href="/docs/components/mutation-observer/">Mutation Observer</a></li>
|
||||
<li><span class="is-planned wa-split">Number Input <a href="https://github.com/shoelace-style/webawesome/issues/1688" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a></span></li>
|
||||
<li><a href="/docs/components/popover/">Popover</a></li>
|
||||
<li><a href="/docs/components/popup/">Popup</a></li>
|
||||
<li><a href="/docs/components/progress-bar/">Progress Bar</a></li>
|
||||
@@ -144,6 +152,7 @@
|
||||
</li>
|
||||
<li><a href="/docs/components/tag/">Tag</a></li>
|
||||
<li><a href="/docs/components/textarea/">Textarea</a></li>
|
||||
<li><span class="is-planned wa-split">Toast <span><a href="https://github.com/shoelace-style/webawesome/issues/105" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a>{{ proBadge( { description: "This will require access to Web Awesome Pro" }) }}</span></span></li>
|
||||
<li><a href="/docs/components/tooltip/">Tooltip</a></li>
|
||||
<li><a href="/docs/components/tree/">Tree</a></li>
|
||||
<li><a href="/docs/components/tree-item/">Tree Item</a></li>
|
||||
@@ -165,6 +174,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><span class="is-planned wa-split">Video <span><a href="https://github.com/shoelace-style/webawesome/issues/985" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a>{{ proBadge( { description: "This will require access to Web Awesome Pro" }) }}</span></span></li>
|
||||
<li><a href="/docs/components/zoomable-frame">Zoomable Frame</a></li>
|
||||
{# PLOP_NEW_COMPONENT_PLACEHOLDER #}
|
||||
</ul>
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
<wa-badge variant="neutral">Since {{ component.since }}</wa-badge>
|
||||
<wa-badge
|
||||
{% if component.status == 'stable' %}variant="brand"{% endif %}
|
||||
{% if component.status == 'experimental' %}variant="warning"{% endif %}
|
||||
{% if component.status == 'experimental' %}variant="warning" appearance="filled"{% endif %}
|
||||
>
|
||||
{{ component.status }}
|
||||
</wa-badge>
|
||||
{% if isProComponent %}
|
||||
<wa-badge class="pro">Pro</wa-badge>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="component-summary">
|
||||
{{ component.summary | inlineMarkdown | safe }}
|
||||
@@ -20,6 +23,37 @@
|
||||
|
||||
{# Component API #}
|
||||
{% block afterContent %}
|
||||
{# Importing #}
|
||||
<h2>Importing</h2>
|
||||
<p>
|
||||
Autoloading components via <a href="/docs/#using-a-project">projects</a> is the recommended way to import components. If you prefer to do it manually, use one of the following code snippets.
|
||||
</p>
|
||||
|
||||
{% set componentName = component.tagName | stripPrefix %}
|
||||
{% set componentPath = ["components/", componentName, "/", componentName, ".js"] | join("") %}
|
||||
<wa-tab-group label="How would you like to import this component?">
|
||||
<wa-tab panel="cdn">CDN</wa-tab>
|
||||
<wa-tab panel="npm">npm</wa-tab>
|
||||
<wa-tab panel="react">React</wa-tab>
|
||||
<wa-tab-panel name="cdn">
|
||||
<p>
|
||||
Let your project code do the work! <a href="/signup">Sign up for free</a> to use a project with your very own CDN — it's the fastest and easiest way to use Web Awesome.
|
||||
</p>
|
||||
</wa-tab-panel>
|
||||
<wa-tab-panel name="npm">
|
||||
<p>
|
||||
To manually import this component from NPM, use the following code.
|
||||
</p>
|
||||
<pre><code class="language-js">import '@awesome.me/webawesome/dist/{{ componentPath }}';</code></pre>
|
||||
</wa-tab-panel>
|
||||
<wa-tab-panel name="react">
|
||||
<p>
|
||||
To manually import this component from React, use the following code.
|
||||
</p>
|
||||
<pre><code class="language-js">import {{ component.name }} from '@awesome.me/webawesome/dist/react/{{ componentName }}';</code></pre>
|
||||
</wa-tab-panel>
|
||||
</wa-tab-group>
|
||||
|
||||
{# Slots #}
|
||||
{% if component.slots.length %}
|
||||
<h2>Slots</h2>
|
||||
@@ -270,38 +304,6 @@
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{# Importing #}
|
||||
<h2>Importing</h2>
|
||||
<p>
|
||||
Autoloading components via <a href="/docs/#using-a-project">projects</a> is the recommended way to import components. If you prefer to do it manually, use one of the following code snippets.
|
||||
</p>
|
||||
|
||||
|
||||
{% set componentName = component.tagName | stripPrefix %}
|
||||
{% set componentPath = ["components/", componentName, "/", componentName, ".js"] | join("") %}
|
||||
<wa-tab-group label="How would you like to import this component?">
|
||||
<wa-tab panel="cdn">CDN</wa-tab>
|
||||
<wa-tab panel="npm">npm</wa-tab>
|
||||
<wa-tab panel="react">React</wa-tab>
|
||||
<wa-tab-panel name="cdn">
|
||||
<p>
|
||||
Let your project code do the work! <a href="/signup">Sign up for free</a> to use a project with your very own CDN — it's the fastest and easiest way to use Web Awesome.
|
||||
</p>
|
||||
</wa-tab-panel>
|
||||
<wa-tab-panel name="npm">
|
||||
<p>
|
||||
To manually import this component from NPM, use the following code.
|
||||
</p>
|
||||
<pre><code class="language-js">import '@awesome.me/webawesome/dist/{{ componentPath }}';</code></pre>
|
||||
</wa-tab-panel>
|
||||
<wa-tab-panel name="react">
|
||||
<p>
|
||||
To manually import this component from React, use the following code.
|
||||
</p>
|
||||
<pre><code class="language-js">import {{ component.name }} from '@awesome.me/webawesome/dist/react/{{ componentName }}';</code></pre>
|
||||
</wa-tab-panel>
|
||||
</wa-tab-group>
|
||||
|
||||
<wa-divider></wa-divider>
|
||||
|
||||
<div class="component-help">
|
||||
|
||||
@@ -35,9 +35,23 @@ export function anchorHeadingsTransformer(options = {}) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
// Look for headings
|
||||
let selector = `:is(${options.headingSelector}):not([data-no-anchor], [data-no-anchor] *)`;
|
||||
// Check if the document or container has data-no-anchor (view-level)
|
||||
const hasNoAnchorOnDocument = doc.querySelector('html')?.hasAttribute('data-no-anchor') || false;
|
||||
const hasNoAnchorOnContainer = container.closest('[data-no-anchor]') !== null;
|
||||
|
||||
// If view-level data-no-anchor is set, skip processing all headings
|
||||
if (hasNoAnchorOnDocument || hasNoAnchorOnContainer) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
// Look for headings (selector excludes headings with data-no-anchor attribute)
|
||||
let selector = `:is(${options.headingSelector}):not([data-no-anchor])`;
|
||||
container.querySelectorAll(selector).forEach(heading => {
|
||||
// Skip if heading is a descendant of an element with data-no-anchor
|
||||
// (selector already excludes headings with the attribute directly)
|
||||
if (heading.closest('[data-no-anchor]') !== null) {
|
||||
return;
|
||||
}
|
||||
const hasAnchor = heading.querySelector('a');
|
||||
const existingId = heading.getAttribute('id');
|
||||
const clone = parse(heading.outerHTML);
|
||||
@@ -65,7 +79,7 @@ export function anchorHeadingsTransformer(options = {}) {
|
||||
const anchor = parse(`
|
||||
<a href="#${encodeURIComponent(id)}">
|
||||
<span class="wa-visually-hidden"></span>
|
||||
<span aria-hidden="true">#</span>
|
||||
<wa-icon variant="regular" name="hashtag" class="icon-shrink"></wa-icon>
|
||||
</a>
|
||||
`);
|
||||
anchor.querySelector('.wa-visually-hidden').textContent = options.anchorLabel;
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import * as path from 'node:path';
|
||||
import nunjucks from 'nunjucks';
|
||||
|
||||
const baseDir = process.env.BASE_DIR || 'docs';
|
||||
|
||||
const views = [path.join(baseDir), path.join(baseDir, '_layouts'), path.join(baseDir, '_includes')];
|
||||
|
||||
const nunjucksEnv = new nunjucks.Environment(new nunjucks.FileSystemLoader(views), {
|
||||
autoescape: true,
|
||||
noCache: process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test',
|
||||
});
|
||||
|
||||
/**
|
||||
* This function simulates what a server would do running "on top" of eleventy.
|
||||
*/
|
||||
export function SimulateWebAwesomeApp(str) {
|
||||
return nunjucks.renderString(str, {
|
||||
return nunjucksEnv.renderString(str, {
|
||||
// Stub the server EJS shortcodes.
|
||||
currentUser: {
|
||||
hasPro: false,
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
// Search data
|
||||
const version = document.documentElement.getAttribute('data-version') || '';
|
||||
const res = await Promise.all([import('https://cdn.jsdelivr.net/npm/lunr/+esm'), fetch(`/search.json?v=${version}`)]);
|
||||
const res = await Promise.all([
|
||||
import('https://cdn.jsdelivr.net/npm/lunr/+esm'),
|
||||
fetch(`/search.json?v=${version}`),
|
||||
import('/assets/scripts/track.js').catch(() => null),
|
||||
]);
|
||||
const lunr = res[0].default;
|
||||
const searchData = await res[1].json();
|
||||
const searchIndex = lunr.Index.load(searchData.searchIndex);
|
||||
const map = searchData.map;
|
||||
const searchDebounce = 200;
|
||||
const queryTrackDelay = 1000;
|
||||
let searchTimeout;
|
||||
let queryTrackTimeout;
|
||||
let lastTrackedQuery = '';
|
||||
let resultSelected = false;
|
||||
|
||||
// Optional event tracking - works standalone if track.js isn't available
|
||||
const trackModule = res[2];
|
||||
const trackEvent = trackModule?.trackEvent || window.trackEvent || (() => {});
|
||||
|
||||
// We're using Turbo, so references to these elements aren't guaranteed to remain intact
|
||||
function getElements() {
|
||||
@@ -17,6 +29,24 @@ function getElements() {
|
||||
};
|
||||
}
|
||||
|
||||
function trackQuerySubmit(query, resultSelectedValue) {
|
||||
if (!query || query.length === 0) return;
|
||||
|
||||
const { results } = getElements();
|
||||
if (!results) return;
|
||||
|
||||
const matches = results.querySelectorAll('li').length;
|
||||
const truncatedQuery = query.length > 500 ? query.substring(0, 500) : query;
|
||||
|
||||
trackEvent('navigation:search_query_submit', {
|
||||
query: truncatedQuery,
|
||||
query_length: query.length,
|
||||
result_count: matches,
|
||||
has_results: matches > 0,
|
||||
result_selected: resultSelectedValue,
|
||||
});
|
||||
}
|
||||
|
||||
// Show the search dialog when slash (or CMD+K) is pressed and focus is not inside a form element
|
||||
document.addEventListener('keydown', event => {
|
||||
if (
|
||||
@@ -42,40 +72,98 @@ document.addEventListener('click', event => {
|
||||
|
||||
function show() {
|
||||
const { dialog, input, results } = getElements();
|
||||
if (!dialog || !input || !results) return;
|
||||
|
||||
const wasAlreadyOpen = dialog.open;
|
||||
|
||||
// Remove existing listeners before adding to prevent duplicates
|
||||
input.removeEventListener('input', handleInput);
|
||||
results.removeEventListener('click', handleSelection);
|
||||
dialog.removeEventListener('keydown', handleKeyDown);
|
||||
dialog.removeEventListener('wa-hide', handleClose);
|
||||
resultSelected = false;
|
||||
lastTrackedQuery = '';
|
||||
input.addEventListener('input', handleInput);
|
||||
results.addEventListener('click', handleSelection);
|
||||
dialog.addEventListener('keydown', handleKeyDown);
|
||||
dialog.addEventListener('wa-hide', handleClose);
|
||||
dialog.open = true;
|
||||
if (!wasAlreadyOpen) {
|
||||
trackEvent('navigation:search_dialog_open');
|
||||
}
|
||||
}
|
||||
|
||||
function hide() {
|
||||
function cleanup() {
|
||||
const { dialog, input, results } = getElements();
|
||||
|
||||
if (!dialog || !input || !results) return;
|
||||
clearTimeout(searchTimeout);
|
||||
clearTimeout(queryTrackTimeout);
|
||||
input.removeEventListener('input', handleInput);
|
||||
results.removeEventListener('click', handleSelection);
|
||||
dialog.removeEventListener('keydown', handleKeyDown);
|
||||
dialog.removeEventListener('wa-hide', handleClose);
|
||||
dialog.open = false;
|
||||
|
||||
// Reset state to prevent leakage between dialog sessions
|
||||
resultSelected = false;
|
||||
lastTrackedQuery = '';
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
const { input } = getElements();
|
||||
async function handleClose() {
|
||||
const { dialog, input } = getElements();
|
||||
if (!dialog || !input) return;
|
||||
clearTimeout(queryTrackTimeout);
|
||||
queryTrackTimeout = null;
|
||||
dialog.removeEventListener('wa-hide', handleClose);
|
||||
if (!resultSelected) {
|
||||
const query = input.value.trim();
|
||||
if (query.length > 0 && query !== lastTrackedQuery) {
|
||||
trackQuerySubmit(query, false);
|
||||
lastTrackedQuery = query;
|
||||
}
|
||||
}
|
||||
|
||||
input.value = '';
|
||||
updateResults();
|
||||
try {
|
||||
await updateResults();
|
||||
} catch (error) {
|
||||
// Silently handle errors - UI cleanup should continue
|
||||
}
|
||||
cleanup();
|
||||
trackEvent('navigation:search_dialog_close');
|
||||
}
|
||||
|
||||
function handleInput() {
|
||||
const { input } = getElements();
|
||||
|
||||
if (!input) return;
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(() => updateResults(input.value), searchDebounce);
|
||||
clearTimeout(queryTrackTimeout);
|
||||
|
||||
const query = input.value.trim();
|
||||
|
||||
if (query.length === 0) {
|
||||
lastTrackedQuery = '';
|
||||
}
|
||||
|
||||
searchTimeout = setTimeout(async () => {
|
||||
await updateResults(query);
|
||||
if (query.length > 0 && query !== lastTrackedQuery) {
|
||||
queryTrackTimeout = setTimeout(() => {
|
||||
const { input: currentInput, results } = getElements();
|
||||
if (!currentInput || resultSelected) return;
|
||||
|
||||
const currentQuery = currentInput.value.trim();
|
||||
if (currentQuery === query && currentQuery !== lastTrackedQuery) {
|
||||
trackQuerySubmit(currentQuery, false);
|
||||
lastTrackedQuery = currentQuery;
|
||||
}
|
||||
}, queryTrackDelay);
|
||||
}
|
||||
}, searchDebounce);
|
||||
}
|
||||
|
||||
function handleKeyDown(event) {
|
||||
const { input, results } = getElements();
|
||||
if (!input || !results) return;
|
||||
|
||||
// Handle keyboard selections
|
||||
if (['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter'].includes(event.key)) {
|
||||
@@ -104,7 +192,12 @@ function handleKeyDown(event) {
|
||||
nextEl = items[items.length - 1];
|
||||
break;
|
||||
case 'Enter':
|
||||
currentEl?.querySelector('a')?.click();
|
||||
if (currentEl) {
|
||||
const link = currentEl.querySelector('a');
|
||||
if (link) {
|
||||
selectResult(link, 'keyboard_enter');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -121,27 +214,62 @@ function handleKeyDown(event) {
|
||||
}
|
||||
}
|
||||
|
||||
function selectResult(link, selectionMethod) {
|
||||
const { input, results } = getElements();
|
||||
if (!input || !link) return;
|
||||
|
||||
// Clear pending query tracking timeout to prevent duplicate events
|
||||
clearTimeout(queryTrackTimeout);
|
||||
queryTrackTimeout = null;
|
||||
resultSelected = true; // Set immediately so timeout callback (if executing) sees it
|
||||
|
||||
const query = input.value.trim();
|
||||
if (!link.dataset.searchResultIndex) return;
|
||||
const resultIndex = parseInt(link.dataset.searchResultIndex, 10);
|
||||
if (isNaN(resultIndex) || resultIndex < 1) return;
|
||||
|
||||
const resultUrl = link.dataset.searchResultUrl || link.getAttribute('href');
|
||||
if (!resultUrl) return;
|
||||
lastTrackedQuery = query;
|
||||
trackQuerySubmit(query, true);
|
||||
trackEvent('navigation:search_result_click', {
|
||||
query,
|
||||
result_index: resultIndex,
|
||||
result_url: resultUrl,
|
||||
selection_method: selectionMethod,
|
||||
});
|
||||
|
||||
const { dialog } = getElements();
|
||||
if (dialog) {
|
||||
dialog.removeEventListener('wa-hide', handleClose);
|
||||
cleanup();
|
||||
trackEvent('navigation:search_dialog_close');
|
||||
dialog.open = false;
|
||||
}
|
||||
|
||||
if (window.Turbo) {
|
||||
Turbo.visit(resultUrl);
|
||||
} else {
|
||||
location.href = resultUrl;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSelection(event) {
|
||||
const link = event.target.closest('a');
|
||||
|
||||
if (link) {
|
||||
event.preventDefault();
|
||||
hide();
|
||||
|
||||
if (window.Turbo) {
|
||||
Turbo.visit(link.href);
|
||||
} else {
|
||||
location.href = link.href;
|
||||
}
|
||||
selectResult(link, 'mouse_click');
|
||||
}
|
||||
}
|
||||
|
||||
// Queries the search index and updates the results
|
||||
async function updateResults(query = '') {
|
||||
const { dialog, input, results } = getElements();
|
||||
|
||||
if (!dialog || !input || !results) return;
|
||||
try {
|
||||
const hasQuery = query.length > 0;
|
||||
const trimmedQuery = query.trim();
|
||||
const hasQuery = trimmedQuery.length > 0;
|
||||
let matches = [];
|
||||
|
||||
if (hasQuery) {
|
||||
@@ -149,13 +277,13 @@ async function updateResults(query = '') {
|
||||
const seenRefs = new Set();
|
||||
|
||||
// Start with a standard search to get the best "exact match" result
|
||||
searchIndex.search(`${query}`).forEach(match => {
|
||||
searchIndex.search(`${trimmedQuery}`).forEach(match => {
|
||||
matches.push(match);
|
||||
seenRefs.add(match.ref);
|
||||
});
|
||||
|
||||
// Add wildcard matches if not already included
|
||||
searchIndex.search(`${query}*`).forEach(match => {
|
||||
searchIndex.search(`${trimmedQuery}*`).forEach(match => {
|
||||
if (!seenRefs.has(match.ref)) {
|
||||
matches.push(match);
|
||||
seenRefs.add(match.ref);
|
||||
@@ -163,11 +291,10 @@ async function updateResults(query = '') {
|
||||
});
|
||||
|
||||
// Add fuzzy search matches last
|
||||
const fuzzyTokens = query
|
||||
const fuzzyTokens = trimmedQuery
|
||||
.split(' ')
|
||||
.map(term => `${term}~1`)
|
||||
.join(' ');
|
||||
|
||||
searchIndex.search(fuzzyTokens).forEach(match => {
|
||||
if (!seenRefs.has(match.ref)) {
|
||||
matches.push(match);
|
||||
@@ -180,12 +307,12 @@ async function updateResults(query = '') {
|
||||
|
||||
dialog.classList.toggle('has-results', hasQuery && hasResults);
|
||||
dialog.classList.toggle('no-results', hasQuery && !hasResults);
|
||||
|
||||
input.setAttribute('aria-activedescendant', '');
|
||||
results.innerHTML = '';
|
||||
|
||||
matches.forEach((match, index) => {
|
||||
const page = map[match.ref];
|
||||
if (!page || !page.url) return;
|
||||
|
||||
const li = document.createElement('li');
|
||||
const a = document.createElement('a');
|
||||
const displayTitle = page.title ?? '';
|
||||
@@ -197,12 +324,10 @@ async function updateResults(query = '') {
|
||||
li.setAttribute('role', 'option');
|
||||
li.setAttribute('id', `search-result-item-${match.ref}`);
|
||||
li.setAttribute('data-selected', index === 0 ? 'true' : 'false');
|
||||
|
||||
if (page.url === '/') icon = 'home';
|
||||
if (page.url.startsWith('/docs/utilities/native')) icon = 'code';
|
||||
if (page.url.startsWith('/docs/components')) icon = 'puzzle-piece';
|
||||
if (page.url.startsWith('/docs/theme') || page.url.startsWith('/docs/restyle')) icon = 'palette';
|
||||
|
||||
a.href = page.url;
|
||||
a.innerHTML = `
|
||||
<div class="site-search-result-icon" aria-hidden="true">
|
||||
@@ -218,6 +343,9 @@ async function updateResults(query = '') {
|
||||
a.querySelector('.site-search-result-description').textContent = displayDescription;
|
||||
a.querySelector('.site-search-result-url').textContent = displayUrl;
|
||||
|
||||
// Use 1-based indexing for analytics
|
||||
a.dataset.searchResultIndex = (index + 1).toString();
|
||||
a.dataset.searchResultUrl = page.url;
|
||||
li.appendChild(a);
|
||||
results.appendChild(li);
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ wa-page > [slot='banner'] {
|
||||
}
|
||||
|
||||
&.banner-wa-launch {
|
||||
/* custom brand colors carrried over from theme-site for the banner */
|
||||
/* custom brand colors carried over from theme-site for the banner */
|
||||
--wa-color-brand-95: #fef0ec;
|
||||
--wa-color-brand-90: #fce0d8;
|
||||
--wa-color-brand-80: #f8bcac;
|
||||
@@ -64,6 +64,24 @@ wa-page > [slot='banner'] {
|
||||
}
|
||||
}
|
||||
|
||||
/* Site-Wide Dialog */
|
||||
#dialog-site {
|
||||
/* custom brand colors carrried over from theme-site for the banner */
|
||||
--wa-color-brand-95: #fef0ec;
|
||||
--wa-color-brand-90: #fce0d8;
|
||||
--wa-color-brand-80: #f8bcac;
|
||||
--wa-color-brand-70: #fa9378;
|
||||
--wa-color-brand-60: #f46a45;
|
||||
--wa-color-brand-50: #cb4b27;
|
||||
--wa-color-brand-40: #9d371a;
|
||||
--wa-color-brand-30: #7c2a13;
|
||||
--wa-color-brand-20: #5d1d0b;
|
||||
--wa-color-brand-10: #3b0f05;
|
||||
--wa-color-brand-05: #270802;
|
||||
--wa-color-brand: var(--wa-color-brand-60);
|
||||
--wa-color-brand-on: var(--wa-color-brand-10);
|
||||
}
|
||||
|
||||
/* Header */
|
||||
wa-page::part(header) {
|
||||
background-color: var(--wa-color-surface-default);
|
||||
@@ -351,26 +369,6 @@ h1.title {
|
||||
}
|
||||
}
|
||||
|
||||
/* Anchor headings */
|
||||
.anchor-heading a {
|
||||
visibility: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.anchor-heading:hover a {
|
||||
visibility: visible;
|
||||
padding: 0 0.125em;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
/* Show URLs for printed links */
|
||||
a:not(.anchor-heading)[href]::after {
|
||||
content: ' (' attr(href) ')';
|
||||
}
|
||||
}
|
||||
|
||||
/* Callouts */
|
||||
.callout {
|
||||
display: flex;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
|
||||
&::part(dialog) {
|
||||
margin-block-start: 10vh;
|
||||
|
||||
@@ -70,9 +70,8 @@
|
||||
/* #region shared UI */
|
||||
/* pro badge */
|
||||
wa-badge.pro {
|
||||
color: white;
|
||||
color: var(--wa-color-brand-on-loud);
|
||||
background-color: var(--wa-brand-orange);
|
||||
border-color: var(--wa-brand-orange);
|
||||
|
||||
+ wa-tooltip {
|
||||
font-size: var(--wa-font-size-xs);
|
||||
@@ -80,6 +79,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* free badge */
|
||||
wa-badge.free {
|
||||
+ wa-tooltip {
|
||||
font-size: var(--wa-font-size-xs);
|
||||
--max-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
/* planned badge */
|
||||
wa-badge.planned {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
@@ -123,6 +130,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* anchor headings */
|
||||
.anchor-heading a {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
text-decoration: none;
|
||||
transition: opacity var(--wa-transition-normal) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.anchor-heading:hover a {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
padding: var(--wa-space-3xs);
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
/* show URLs for printed links */
|
||||
a:not(.anchor-heading)[href]::after {
|
||||
content: ' (' attr(href) ')';
|
||||
}
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
/* #region funsies + cosmetics */
|
||||
|
||||
@@ -40,60 +40,6 @@ Set the `orientation` attribute to `vertical` to make a vertical button group.
|
||||
</wa-button-group>
|
||||
```
|
||||
|
||||
### Theme Buttons
|
||||
|
||||
Theme buttons are supported through the button group's `variant` attribute.
|
||||
|
||||
```html {.example}
|
||||
<wa-button-group label="Alignment" variant="brand">
|
||||
<wa-button>Left</wa-button>
|
||||
<wa-button>Center</wa-button>
|
||||
<wa-button>Right</wa-button>
|
||||
</wa-button-group>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<wa-button-group label="Alignment" variant="success">
|
||||
<wa-button>Left</wa-button>
|
||||
<wa-button>Center</wa-button>
|
||||
<wa-button>Right</wa-button>
|
||||
</wa-button-group>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<wa-button-group label="Alignment">
|
||||
<wa-button>Left</wa-button>
|
||||
<wa-button>Center</wa-button>
|
||||
<wa-button>Right</wa-button>
|
||||
</wa-button-group>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<wa-button-group label="Alignment" variant="warning">
|
||||
<wa-button>Left</wa-button>
|
||||
<wa-button>Center</wa-button>
|
||||
<wa-button>Right</wa-button>
|
||||
</wa-button-group>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<wa-button-group label="Alignment" variant="danger">
|
||||
<wa-button>Left</wa-button>
|
||||
<wa-button>Center</wa-button>
|
||||
<wa-button>Right</wa-button>
|
||||
</wa-button-group>
|
||||
```
|
||||
|
||||
You can still use the buttons’ own `variant` attribute to override the inherited variant.
|
||||
|
||||
```html {.example}
|
||||
<wa-button-group label="Alignment" variant="brand">
|
||||
<wa-button>Left</wa-button>
|
||||
<wa-button>Center</wa-button>
|
||||
<wa-button variant="neutral">Right</wa-button>
|
||||
</wa-button-group>
|
||||
```
|
||||
|
||||
### Pill Buttons
|
||||
|
||||
Pill buttons are supported through the button's `pill` attribute.
|
||||
@@ -141,7 +87,7 @@ Dropdowns can be placed into button groups.
|
||||
|
||||
### Split Buttons
|
||||
|
||||
Create a split button using a button and a dropdown. Use a [visually hidden](/docs/components/visually-hidden) label to ensure the dropdown is accessible to users with assistive devices.
|
||||
Create a split button using a button and a dropdown. Use a [visually hidden](/docs/utilities/visually-hidden) label to ensure the dropdown is accessible to users with assistive devices.
|
||||
|
||||
```html {.example}
|
||||
<wa-button-group label="Example Button Group">
|
||||
|
||||
@@ -5,7 +5,7 @@ layout: component
|
||||
category: Imagery
|
||||
---
|
||||
|
||||
This is especially useful for comparing images, but can be used for comparing any type of content (for an example of using it to compare entire UIs, check out our [theme pages](/docs/themes/default/)).
|
||||
This is especially useful for comparing images, but can be used for comparing any type of content (for an example of using it to compare entire UIs, check out our [theme page](/docs/themes)).
|
||||
For best results, use content that shares the same dimensions.
|
||||
The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)
|
||||
|
||||
|
||||
@@ -53,9 +53,9 @@ The default orientation for dividers is `horizontal`. Set `orientation` attribut
|
||||
</div>
|
||||
```
|
||||
|
||||
### Menu Dividers
|
||||
### Dropdown Dividers
|
||||
|
||||
Use dividers in [menus](/docs/components/menu) to visually group menu items.
|
||||
Use dividers in [dropdowns](/docs/components/dropdown) to visually group dropdown items.
|
||||
|
||||
```html {.example}
|
||||
<wa-dropdown style="max-width: 200px;">
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Intersection Observer
|
||||
description: Tracks immediate child elements and fires events as they move in and out of view.
|
||||
layout: component
|
||||
category: Utilities
|
||||
---
|
||||
|
||||
This component leverages the [IntersectionObserver API](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) to track when its direct children enter or leave a designated root element. The `wa-intersect` event fires whenever elements cross the visibility threshold.
|
||||
|
||||
@@ -102,7 +102,7 @@ The default orientation for radio items is `vertical`. Set the `orientation` to
|
||||
|
||||
### Sizing Options
|
||||
|
||||
The size of [Radios](/docs/components/radio) will be determined by the Radio Group's `size` attribute.
|
||||
The size of radios will be determined by the Radio Group's `size` attribute.
|
||||
|
||||
```html {.example}
|
||||
<wa-radio-group label="Select an option" size="medium" value="medium" onchange="this.size = this.value">
|
||||
@@ -113,7 +113,7 @@ The size of [Radios](/docs/components/radio) will be determined by the Radio Gro
|
||||
```
|
||||
|
||||
:::info
|
||||
[Radios](/docs/components/radio) and [Radio Buttons](/docs/components/radio-button) also have a `size` attribute,
|
||||
[Radios](/docs/components/radio) also have a `size` attribute,
|
||||
which will override the inherited size when used.
|
||||
:::
|
||||
|
||||
|
||||
@@ -285,9 +285,10 @@ Remember that custom tags are rendered in a shadow root. To style them, you can
|
||||
const name = option.querySelector('wa-icon[slot="start"]').name;
|
||||
|
||||
// You can return a string, a Lit Template, or an HTMLElement here
|
||||
// Important: include data-value so the tag can be removed properly!
|
||||
return `
|
||||
<wa-tag with-remove>
|
||||
<wa-icon name="${name}" style="padding-inline-end: .5rem;"></wa-icon>
|
||||
<wa-tag with-remove data-value="${option.value}">
|
||||
<wa-icon name="${name}"></wa-icon>
|
||||
${option.label}
|
||||
</wa-tag>
|
||||
`;
|
||||
@@ -299,6 +300,10 @@ Remember that custom tags are rendered in a shadow root. To style them, you can
|
||||
Be sure you trust the content you are outputting! Passing unsanitized user input to `getTag()` can result in XSS vulnerabilities.
|
||||
:::
|
||||
|
||||
:::info
|
||||
When using custom tags with `with-remove`, you must include the `data-value` attribute set to the option's value. This allows the select to identify which option to deselect when the tag's remove button is clicked.
|
||||
:::
|
||||
|
||||
### Lazy loading options
|
||||
|
||||
Lazy loading options works similarly to native `<select>` elements. The select component handles various scenarios intelligently:
|
||||
|
||||
@@ -1,21 +1,45 @@
|
||||
---
|
||||
title: Changelog
|
||||
dateLastUpdated: 2025-11-07
|
||||
description: Changes to each version of the project are documented here.
|
||||
layout: page-outline
|
||||
---
|
||||
|
||||
<p class="wa-caption-s">Last updated: <wa-format-date month="long" day="numeric" year="numeric" date="{{ lastUpdatedISO }}"></wa-format-date></p>
|
||||
<p class="wa-caption-s">Last updated: <wa-format-date month="long" day="numeric" year="numeric" date="{{ dateLastUpdated }}"></wa-format-date></p>
|
||||
|
||||
Web Awesome follows [Semantic Versioning](https://semver.org/). Breaking changes in components with the <wa-badge variant="brand">Stable</wa-badge> badge will not be accepted until the next major version. As such, all contributions must consider the project's roadmap and take this into consideration. Features that are deemed no longer necessary will be deprecated but not removed.
|
||||
|
||||
Components with the <wa-badge variant="warning">Experimental</wa-badge> badge should not be used in production. They are made available as release candidates for development and testing purposes. As such, changes to experimental components will not be subject to semantic versioning.
|
||||
|
||||
## 3.1.0
|
||||
|
||||
- Added `<wa-combobox>` as an experimental pro component [issue:1074]
|
||||
- Added version 2.0.0 of the [official Web Awesome Figma Design Kit](/docs/resources/figma)
|
||||
- Added npm support for Web Awesome Pro
|
||||
- Added `layers.css` to define cascade layer order and updated palettes, themes, native styles, and utilities to import the new rule for more fail-safe modularity [pr:1793]
|
||||
- [PRO]: Fixed a few sizing bugs in `<wa-page>` and `slot="footer"` no longer will always "overflow" the container.
|
||||
- Fixed a bug in `<wa-slider>` that caused some touch devices to end up with the incorrect value [issue:1703]
|
||||
- Fixed a bug in `<wa-card>` that prevented some slots from being detected correctly [discuss:1450]
|
||||
- Fixed a z-index bug in `<wa-scroller>` styles [issue:1724]
|
||||
- Fixed a bug in `<wa-icon>` that caused some icon libraries to render with the incorrect SVG fill [issue:1733]
|
||||
- Fixed a bug in `<wa-tree-item>` that caused the spinner to not show when lazy loading [issue:1678]
|
||||
- Fixed a bug in `<wa-dropdown>` that caused the browser to hang when cancelling the `wa-hide` event [issue:1483]
|
||||
- Fixed a bug in `<wa-dropdown-item>` that prevented the icon dependency from being imported [issue:1825]
|
||||
- Fixed a bug in `<wa-select>` that prevented clicks on the tag's remove button from removing options in multiple mode
|
||||
- Fixed a bug in `<wa-select>` that caused tags to appear in alphabetical order instead of selection order when using `multiple`
|
||||
- Improved performance of `<wa-icon>` so initial rendering occurs faster, especially with multiple icons on the page [issue:1729]
|
||||
- Improved `<wa-slider>` to not throw an error when string values are passed to the `min`, `max`, and `step` properties [issue:1823]
|
||||
- Fixed a bug in Web Awesome form controls that caused `<wa-input form="foo">` to set the form property to equal `"foo"` instead of returning an `HTMLFormElement` breaking platform expectations. [pr:1815]
|
||||
- Fixed a bug in `<wa-button>` causing it to not copy over attributes for form submissions. [pr:1815]
|
||||
- Improved performance of all components by fixing how CSS is imported and reused [issue:1812]
|
||||
- Modified the default `transition` styles of `<wa-dropdown-item>` to use design tokens [pr:1693]
|
||||
|
||||
## 3.0.0
|
||||
|
||||
- 🚨 BREAKING: Changed `appearance="filled outlined"` to `appearance="filled-outlined"` in the following elements [issue:1127]
|
||||
- `<wa-badge>`
|
||||
- `<wa-button>`
|
||||
- `<wa-callout>`
|
||||
- `<wa-card>`
|
||||
- `<wa-details>`
|
||||
- `<wa-input>`
|
||||
- `<wa-select>`
|
||||
@@ -245,7 +269,7 @@ Many of these changes and improvements were the direct result of feedback from u
|
||||
- 🚨 BREAKING: Renamed `<image-comparer>` to `<wa-comparison>` and improved compatibility for non-image content
|
||||
- 🚨 BREAKING: Added slot detection to `<wa-dialog>` and `<wa-drawer>` so you don't need to specify `with-header` and `with-footer`; headers are on by default now, but you can use the `without-header` attribute to turn them off
|
||||
- 🚨 BREAKING: Renamed the `image` slot to `media` for a more appropriate naming convention
|
||||
- Added [a theme builder](/docs/themes/edit/) to create your own themes
|
||||
- Added Theme Builder to create your own themes
|
||||
- Added a new Blog & News pattern category
|
||||
- Added a new free component: `<wa-scroller>` (#1 of 14 per stretch goals)
|
||||
- Added support for Duotone Thin, Light, and Regular styles and the Sharp Duotone family of styles to `<wa-icon>`
|
||||
@@ -262,7 +286,7 @@ Many of these changes and improvements were the direct result of feedback from u
|
||||
|
||||
### Enhancements {data-no-outline}
|
||||
|
||||
- Added `appearance` to [`<wa-details>`](/docs/components/details) and [`<wa-card>`](/docs/components/card) and support for the [appearance utilities](/docs/utilities/appearance/) in the [`<details>` native styles](/docs/utilities/native/details).
|
||||
- Added `appearance` to [`<wa-details>`](/docs/components/details) and [`<wa-card>`](/docs/components/card) and support for the appearance utilities in the [`<details>` native styles](/docs/utilities/native/#details).
|
||||
- Added an `orange` scale to all color palettes
|
||||
- Added the [`.wa-cloak` utility](/docs/utilities/fouce) to prevent FOUCE
|
||||
- Added the [`allDefined()` utility](/docs/usage/#all-defined) for awaiting component registration
|
||||
@@ -287,7 +311,7 @@ Many of these changes and improvements were the direct result of feedback from u
|
||||
- Revert `<wa-dialog>` structure and CSS to fix clipped content in dialogs (WA-A #123) and light dismiss in iOS Safari (WA-A #201)
|
||||
- Fixed a bug in `<wa-color-picker>` that prevented light dismiss from working when clicking immediately above the color picker dropdown
|
||||
- Fixed a bug in `<wa-progress>` that prevented Safari from animation progress changes
|
||||
- Fixed the missing indeterminate icon in [native checkbox styles](/docs/utilities/native/checkbox)
|
||||
- Fixed the missing indeterminate icon in [native checkbox styles](/docs/utilities/native/#form-controls)
|
||||
- Fixed a bug in `<wa-radio>` where elements would stack instead of display inline
|
||||
- Docs fixes:
|
||||
- Fixed the search dialog's styles so it doesn't jump around as you search
|
||||
@@ -434,13 +458,13 @@ Many of these changes and improvements were the direct result of feedback from u
|
||||
### Native styles {data-no-outline}
|
||||
|
||||
- Added native styles for
|
||||
[buttons](/docs/utilities/native/button),
|
||||
[input fields](/docs/utilities/native/input),
|
||||
[dialogs](/docs/utilities/native/dialog),
|
||||
[details](/docs/utilities/native/details),
|
||||
[tables](/docs/utilities/native/table),
|
||||
[lists](/docs/utilities/native/lists),
|
||||
and most [content elements](/docs/utilities/native/content).
|
||||
[buttons](/docs/utilities/native/#buttons),
|
||||
[input fields](/docs/utilities/native/#form-controls),
|
||||
[dialogs](/docs/utilities/native/#dialog),
|
||||
[details](/docs/utilities/native/#details),
|
||||
[tables](/docs/utilities/native/#tables),
|
||||
[lists](/docs/utilities/native/#lists),
|
||||
and most [content elements](/docs/utilities/native/#typography).
|
||||
|
||||
### Style utilities {data-no-outline}
|
||||
|
||||
@@ -448,7 +472,7 @@ Many of these changes and improvements were the direct result of feedback from u
|
||||
- Added [appearance utilities](/docs/utilities/appearance/)
|
||||
- Added [size utilities](/docs/utilities/size/)
|
||||
- Added [layout utilities](/docs/layout/#utilities)
|
||||
- Added [`.wa-visually hidden`](/docs/utilities/a11y/#visually-hidden) utility
|
||||
- Added [`.wa-visually hidden`](/docs/utilities/visually-hidden) utility
|
||||
- Added [`<wa-page>`](/docs/components/page/#styles) native styles and utilities
|
||||
|
||||
### Components {data-no-outline}
|
||||
|
||||
@@ -164,7 +164,7 @@ This section can be a lot to digest in one sitting, so don't feel like you need
|
||||
|
||||
Web Awesome is built with accessibility in mind. Creating generic components that are fully accessible to users with varying capabilities across a multitude of circumstances is a daunting challenge. Oftentimes, the solution to an a11y problem is not written in black and white and, therefore, we may not get it right the first time around. There are, however, guidelines we can follow in our effort to make Web Awesome an accessible foundation from which applications and websites can be built.
|
||||
|
||||
We take this commitment seriously, so please ensure your contributions have this goal in mind. If you need help with anything a11y-related, please [reach out to the community](/resources/community) for assistance. If you discover an accessibility concern within the library, please file a bug on the [issue tracker](https://github.com/shoelace-style/webawesome/issues).
|
||||
We take this commitment seriously, so please ensure your contributions have this goal in mind. If you need help with anything a11y-related, please reach out on the [community chat](https://discord.gg/mg8f26C) for assistance. If you discover an accessibility concern within the library, please file a bug on the [issue tracker](https://github.com/shoelace-style/webawesome/issues).
|
||||
|
||||
It's important to remember that, although accessibility starts with foundational components, it doesn't end with them. It everyone's responsibility to encourage best practices and ensure we're providing an optimal experience for all of our users.
|
||||
|
||||
@@ -364,7 +364,7 @@ Form controls should support submission and validation through the following con
|
||||
|
||||
### System Icons
|
||||
|
||||
Avoid inlining SVG icons inside of templates. If a component requires an icon, make sure `<wa-icon>` is a dependency of the component and use the [system library](/components/icon#customizing-the-system-library):
|
||||
Avoid inlining SVG icons inside of templates. If a component requires an icon, make sure `<wa-icon>` is a dependency of the component and use the [system library](/docs/components/icon#customizing-the-system-library):
|
||||
|
||||
```html
|
||||
<wa-icon library="system" name="..." variant="..."></wa-icon>
|
||||
|
||||
@@ -11,7 +11,7 @@ layout: page
|
||||
<div class="wa-stack wa-gap-xl">
|
||||
<div class="wa-stack wa-align-items-start">
|
||||
<div class="wa-stack wa-gap-s">
|
||||
<h2 class="anchor-heading wa-cluster wa-gap-xs" data-no-anchor><wa-icon name="github" family="brands" style="font-size: 2ch;"></wa-icon>Github</h2>
|
||||
<h2 class="anchor-heading wa-cluster wa-gap-xs" data-no-anchor><wa-icon name="github" family="brands" style="font-size: 2ch;"></wa-icon>GitHub</h2>
|
||||
<span class="wa-heading-m">Feature requests & bugs</span>
|
||||
<p class="wa-caption-l">Notice a bug or have an idea? Open an issue on GitHub so we can triage, track, and ship fixes.</p>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,9 @@ description: Style (and restyle) your website at will with any of Web Awesome's
|
||||
layout: page
|
||||
---
|
||||
|
||||
{% from "pro-badge.njk" import proBadge %}
|
||||
{% from "free-badge.njk" import freeBadge %}
|
||||
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
<p>Themes are collections of <a href="/docs/tokens">design tokens</a> that give a cohesive look and feel to the entire Web Awesome library. Style and restyle your website at will by loading any pre-built theme.</p>
|
||||
@@ -64,8 +67,9 @@ to create a project with any one of these themes.
|
||||
<header class="wa-stack">
|
||||
<div class="wa-cluster">
|
||||
<h2 data-theme-name="name">Theme</h2>
|
||||
<wa-badge data-free-badge appearance="outlined" variant="neutral" hidden>FREE</wa-badge>
|
||||
<wa-badge data-pro-badge appearance="accent" hidden>PRO</wa-badge>
|
||||
{{ freeBadge({ id: "free-badge", description: "This theme is available in the free version of Web Awesome." }) }}
|
||||
{{ proBadge({ id: "pro-badge", description: "This theme requires access to Web Awesome Pro." }) }}
|
||||
|
||||
</div>
|
||||
<p data-theme-description>Description</p>
|
||||
</header>
|
||||
@@ -162,8 +166,12 @@ Then apply the following classes to the `<html>` element:
|
||||
const beforeFrame = document.querySelector('wa-zoomable-frame[slot="before"]');
|
||||
const nameElement = document.querySelector('[data-theme-name]');
|
||||
const descriptionElement = document.querySelector('[data-theme-description]');
|
||||
const freeBadge = document.querySelector('[data-free-badge]');
|
||||
const proBadge = document.querySelector('[data-pro-badge]');
|
||||
const freeBadge = document.getElementById('free-badge');
|
||||
const proBadge = document.getElementById('pro-badge');
|
||||
|
||||
// Hide both badges initially
|
||||
if (freeBadge) freeBadge.hidden = true;
|
||||
if (proBadge) proBadge.hidden = true;
|
||||
|
||||
function updateFrames(selectedValue, title, description, isPro, palette, brand) {
|
||||
// Update theme classes on both frames
|
||||
|
||||
@@ -84,7 +84,7 @@ Clusters are great for inline lists and aligning items of varying sizes.
|
||||
|
||||
## Align Items
|
||||
|
||||
By default, items are centered in the block direction of the `wa-cluster` container. You can add any of the following [`wa-align-items-*`](/docs/style-utilities/align-items) classes to an element with `wa-cluster` to specify how items are aligned in the block direction:
|
||||
By default, items are centered in the block direction of the `wa-cluster` container. You can add any of the following [`wa-align-items-*`](/docs/utilities/align-items) classes to an element with `wa-cluster` to specify how items are aligned in the block direction:
|
||||
|
||||
- `wa-align-items-start`
|
||||
- `wa-align-items-end`
|
||||
@@ -119,7 +119,7 @@ By default, items are centered in the block direction of the `wa-cluster` contai
|
||||
|
||||
## Gap
|
||||
|
||||
By default, the gap between cluster items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/style-utilities/gap) classes to an element with `wa-cluster` to specify the gap between items:
|
||||
By default, the gap between cluster items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/utilities/gap) classes to an element with `wa-cluster` to specify the gap between items:
|
||||
|
||||
- `wa-gap-0`
|
||||
- `wa-gap-3xs`
|
||||
|
||||
@@ -137,7 +137,7 @@ The main content fills the remaining inline space of the container. By default,
|
||||
|
||||
## Align Items
|
||||
|
||||
By default, items are centered in the block direction of the `wa-flank` container. You can add any of the following [`wa-align-items-*`](/docs/style-utilities/align-items) classes to an element with `wa-flank` to specify how items are aligned in the block direction:
|
||||
By default, items are centered in the block direction of the `wa-flank` container. You can add any of the following [`wa-align-items-*`](/docs/utilities/align-items) classes to an element with `wa-flank` to specify how items are aligned in the block direction:
|
||||
|
||||
- `wa-align-items-start`
|
||||
- `wa-align-items-end`
|
||||
@@ -168,7 +168,7 @@ By default, items are centered in the block direction of the `wa-flank` containe
|
||||
|
||||
## Gap
|
||||
|
||||
By default, the gap between flank items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/style-utilities/gap) classes to an element with `wa-flank` to specify the gap between items:
|
||||
By default, the gap between flank items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/utilities/gap) classes to an element with `wa-flank` to specify the gap between items:
|
||||
|
||||
- `wa-gap-0`
|
||||
- `wa-gap-3xs`
|
||||
|
||||
@@ -22,7 +22,7 @@ As soon as all elements are registered _or_ after two seconds have elapsed, the
|
||||
|
||||
:::details Are you using Turbo in your app?
|
||||
|
||||
If you're using [Turbo](https://turbo.hotwired.dev/) to serve a multi-page application (MPA) as a single page application (SPA), you might notice FOUCE when navigating from page to page. This is because Turbo renders the new page's content before the autoloader has a change to register new components.
|
||||
If you're using [Turbo](https://turbo.hotwired.dev/) to serve a multi-page application (MPA) as a single page application (SPA), you might notice FOUCE when navigating from page to page. This is because Turbo renders the new page's content before the autoloader has a chance to register new components.
|
||||
|
||||
The following function acts as a middleware to ensure components are registered _before_ the page shows, eliminating FOUCE for page-to-page navigation with Turbo.
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ Frames have a square aspect ratio by default. You can append `:square` (1 / 1),
|
||||
|
||||
## Border Radius
|
||||
|
||||
Frames have a square border radius by default. You can add any of the following [`wa-border-radius-*`](/docs/style-utilities/border-radius) classes to an element with `wa-frame` to specify the border radius:
|
||||
Frames have a square border radius by default. You can add any of the following [`wa-border-radius-*`](/docs/utilities/rounding) classes to an element with `wa-frame` to specify the border radius:
|
||||
|
||||
- `wa-border-radius-s`
|
||||
- `wa-border-radius-m`
|
||||
|
||||
@@ -14,7 +14,7 @@ tags: layoutUtilities
|
||||
}
|
||||
</style>
|
||||
|
||||
Web Awesome includes classes to set the `gap` property of flex and grid containers. They can be used alongside other Web Awesome layout utilities, like [cluster](/docs/layout/cluster) and [stack](/docs/layout/stack), to change the space between items.
|
||||
Web Awesome includes classes to set the `gap` property of flex and grid containers. They can be used alongside other Web Awesome layout utilities, like [cluster](/docs/utilities/cluster) and [stack](/docs/utilities/stack), to change the space between items.
|
||||
Or even by themselves — all gap properties also set `display: flex` with a specificity of 0 so that it can be trivially overridden.
|
||||
|
||||
Besides `wa-gap-0`, which sets `gap` to zero, each class corresponds to one of the [`--wa-space-*`](/docs/tokens/space) tokens in your theme.
|
||||
|
||||
@@ -169,7 +169,7 @@ By default, grid items will wrap when the grid's column size is less than `20ch`
|
||||
|
||||
## Gap
|
||||
|
||||
By default, the gap between grid items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/style-utilities/gap) classes to an element with `wa-grid` to specify the gap between items:
|
||||
By default, the gap between grid items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/utilities/gap) classes to an element with `wa-grid` to specify the gap between items:
|
||||
|
||||
- `wa-gap-0`
|
||||
- `wa-gap-3xs`
|
||||
|
||||
@@ -12,7 +12,7 @@ tags: styleUtilities
|
||||
}
|
||||
</style>
|
||||
|
||||
Web Awesome includes classes to set an element's `border-radius` property. They can be used alongside Web Awesome layout utilities, like [frame](/docs/layout/frame), to round all corners of an element.
|
||||
Web Awesome includes classes to set an element's `border-radius` property. They can be used alongside Web Awesome layout utilities, like [frame](/docs/utilities/frame), to round all corners of an element.
|
||||
|
||||
Each class corresponds to one of the [`--wa-border-radius-*`](/docs/tokens/borders/#radius) tokens in your theme.
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ Items can be split across a row or a column by appending `:row` or `:column` to
|
||||
|
||||
## Align Items
|
||||
|
||||
By default, items are centered on the cross axis of the `wa-split` container. You can add any of the following [`wa-align-items-*`](/docs/style-utilities/align-items) classes to an element with `wa-split` to specify how items are aligned:
|
||||
By default, items are centered on the cross axis of the `wa-split` container. You can add any of the following [`wa-align-items-*`](/docs/utilities/align-items) classes to an element with `wa-split` to specify how items are aligned:
|
||||
|
||||
- `wa-align-items-start`
|
||||
- `wa-align-items-end`
|
||||
@@ -139,7 +139,7 @@ These modifiers specify how items are aligned in the block direction for `wa-spl
|
||||
|
||||
## Gap
|
||||
|
||||
A split's gap determines how close items can be before they wrap. By default, the gap between split items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/style-utilities/gap) classes to an element with `wa-split` to specify the gap between items:
|
||||
A split's gap determines how close items can be before they wrap. By default, the gap between split items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/utilities/gap) classes to an element with `wa-split` to specify the gap between items:
|
||||
|
||||
- `wa-gap-0`
|
||||
- `wa-gap-3xs`
|
||||
|
||||
@@ -62,7 +62,7 @@ Stacks are well suited for forms, text, and ensuring consistent spacing between
|
||||
|
||||
## Align Items
|
||||
|
||||
By default, items stretch to fill the inline size of the `wa-stack` container. You can add any of the following [`wa-align-items-*`](/docs/style-utilities/align-items) classes to an element with `wa-stack` to specify how items are aligned in the inline direction:
|
||||
By default, items stretch to fill the inline size of the `wa-stack` container. You can add any of the following [`wa-align-items-*`](/docs/utilities/align-items) classes to an element with `wa-stack` to specify how items are aligned in the inline direction:
|
||||
|
||||
- `wa-align-items-start`
|
||||
- `wa-align-items-end`
|
||||
@@ -92,7 +92,7 @@ By default, items stretch to fill the inline size of the `wa-stack` container. Y
|
||||
|
||||
## Gap
|
||||
|
||||
By default, the gap between stack items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/style-utilities/gap) classes to an element with `wa-stack` to specify the gap between items:
|
||||
By default, the gap between stack items uses `--wa-space-m` from your theme. You can add any of the following [`wa-gap-*`](/docs/utilities/gap) classes to an element with `wa-stack` to specify the gap between items:
|
||||
|
||||
- `wa-gap-0`
|
||||
- `wa-gap-3xs`
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"access": "public"
|
||||
},
|
||||
"description": "A forward-thinking library of web components.",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0",
|
||||
"homepage": "https://webawesome.com/",
|
||||
"author": "Web Awesome",
|
||||
"license": "MIT",
|
||||
@@ -64,10 +64,10 @@
|
||||
"spellcheck": "cspell \"**/*.{js,ts,json,html,css,md}\" --no-progress --config=\"../../cspell.json\"",
|
||||
"verify": "npm run prettier && npm run build && npm run test",
|
||||
"prepublishOnly": "npm run verify",
|
||||
"check-updates": "npx npm-check-updates --interactive --format group",
|
||||
"check-updates": "npm-check-updates --cooldown 7 --interactive --format group",
|
||||
"print-version": "echo $npm_package_version",
|
||||
"tag-version": "git tag -a \"v$(npm run print-version | tail -n1)\" -m \"tag v$(npm run print-version | tail -n1)\"",
|
||||
"postversion": "npm run tag-version"
|
||||
"postversion": "node ./scripts/update-root-version.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17.0"
|
||||
@@ -91,6 +91,7 @@
|
||||
"devDependencies": {
|
||||
"@wc-toolkit/jsx-types": "^1.3.0",
|
||||
"eleventy-plugin-git-commit-date": "^0.1.3",
|
||||
"esbuild": "^0.25.11"
|
||||
"esbuild": "^0.25.11",
|
||||
"npm-check-updates": "^19.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,9 +230,6 @@ export async function build(options = {}) {
|
||||
js: `/*! Copyright ${currentYear} Fonticons, Inc. - https://webawesome.com/license */`,
|
||||
},
|
||||
plugins: [replace({ __WEBAWESOME_VERSION__: await getVersion() })],
|
||||
loader: {
|
||||
'.css': 'text',
|
||||
},
|
||||
};
|
||||
|
||||
const unbundledConfig = {
|
||||
|
||||
27
packages/webawesome/scripts/update-root-version.js
Executable file
27
packages/webawesome/scripts/update-root-version.js
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import * as url from 'url';
|
||||
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
||||
|
||||
const monorepoRoot = path.resolve(__dirname, '..', '..', '..');
|
||||
const rootPackageJSONFile = path.join(monorepoRoot, 'package.json');
|
||||
const webawesomePackageJSONFile = path.join(path.resolve(__dirname, '..'), 'package.json');
|
||||
|
||||
const rootPackageJSON = JSON.parse(fs.readFileSync(rootPackageJSONFile, { encoding: 'utf8' }));
|
||||
const webawesomePackageJSON = JSON.parse(fs.readFileSync(webawesomePackageJSONFile, { encoding: 'utf8' }));
|
||||
|
||||
const currentVersion = webawesomePackageJSON.version;
|
||||
rootPackageJSON.version = currentVersion;
|
||||
|
||||
fs.writeFileSync(rootPackageJSONFile, JSON.stringify(rootPackageJSON, null, 2));
|
||||
|
||||
const versionsFile = path.join(monorepoRoot, 'VERSIONS.txt');
|
||||
const versions = fs.readFileSync(versionsFile, { encoding: 'utf8' }).split(/\r?\n/);
|
||||
|
||||
// TODO: Make this smart and understand semver and "insert" in the correct spot instead of appending.
|
||||
if (!versions.includes(currentVersion)) {
|
||||
fs.appendFileSync(versionsFile, webawesomePackageJSON.version);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
:host {
|
||||
--control-box-size: 3rem;
|
||||
--icon-size: calc(var(--control-box-size) * 0.625);
|
||||
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
img[aria-hidden='true'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.control-box {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
top: calc(50% - var(--control-box-size) / 2);
|
||||
right: calc(50% - var(--control-box-size) / 2);
|
||||
width: var(--control-box-size);
|
||||
height: var(--control-box-size);
|
||||
font-size: calc(var(--icon-size) * 0.75);
|
||||
background: none;
|
||||
border: solid var(--wa-border-width-s) currentColor;
|
||||
background-color: rgb(0 0 0 / 50%);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
color: white;
|
||||
pointer-events: none;
|
||||
transition: opacity var(--wa-transition-normal) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
:host([play]:hover) .control-box {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
:where(:host([play]:not(:hover))) .control-box {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
:host([play]) slot[name='play-icon'],
|
||||
:host(:not([play])) slot[name='pause-icon'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Show control box on keyboard focus */
|
||||
.animated-image {
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible .control-box {
|
||||
opacity: 1;
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--control-box-size: 3rem;
|
||||
--icon-size: calc(var(--control-box-size) * 0.625);
|
||||
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
img[aria-hidden='true'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.control-box {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
top: calc(50% - var(--control-box-size) / 2);
|
||||
right: calc(50% - var(--control-box-size) / 2);
|
||||
width: var(--control-box-size);
|
||||
height: var(--control-box-size);
|
||||
font-size: calc(var(--icon-size) * 0.75);
|
||||
background: none;
|
||||
border: solid var(--wa-border-width-s) currentColor;
|
||||
background-color: rgb(0 0 0 / 50%);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
color: white;
|
||||
pointer-events: none;
|
||||
transition: opacity var(--wa-transition-normal) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
:host([play]:hover) .control-box {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
:where(:host([play]:not(:hover))) .control-box {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
:host([play]) slot[name='play-icon'],
|
||||
:host(:not([play])) slot[name='pause-icon'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Show control box on keyboard focus */
|
||||
.animated-image {
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible .control-box {
|
||||
opacity: 1;
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -6,7 +6,7 @@ import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import '../icon/icon.js';
|
||||
import styles from './animated-image.css';
|
||||
import styles from './animated-image.styles.js';
|
||||
|
||||
/**
|
||||
* @summary A component for displaying animated GIFs and WEBPs that play and pause on interaction.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
:host {
|
||||
display: contents;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
display: contents;
|
||||
}
|
||||
`;
|
||||
@@ -5,7 +5,7 @@ import { WaFinishEvent } from '../../events/finish.js';
|
||||
import { WaStartEvent } from '../../events/start.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import styles from './animation.css';
|
||||
import styles from './animation.styles.js';
|
||||
import { animations } from './animations.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
:host {
|
||||
--size: 3rem;
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
color: var(--wa-color-neutral-on-normal);
|
||||
font: inherit;
|
||||
font-size: calc(var(--size) * 0.4);
|
||||
vertical-align: middle;
|
||||
background-color: var(--wa-color-neutral-fill-normal);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
:host([shape='square']) {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
:host([shape='rounded']) {
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.initials {
|
||||
line-height: 1;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
border-radius: inherit;
|
||||
}
|
||||
57
packages/webawesome/src/components/avatar/avatar.styles.ts
Normal file
57
packages/webawesome/src/components/avatar/avatar.styles.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--size: 3rem;
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
color: var(--wa-color-neutral-on-normal);
|
||||
font: inherit;
|
||||
font-size: calc(var(--size) * 0.4);
|
||||
vertical-align: middle;
|
||||
background-color: var(--wa-color-neutral-fill-normal);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
:host([shape='square']) {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
:host([shape='rounded']) {
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.initials {
|
||||
line-height: 1;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
border-radius: inherit;
|
||||
}
|
||||
`;
|
||||
@@ -4,7 +4,7 @@ import { WaErrorEvent } from '../../events/error.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import '../icon/icon.js';
|
||||
import styles from './avatar.css';
|
||||
import styles from './avatar.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Avatars are used to represent a person or object.
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
:host {
|
||||
--pulse-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.375em 0.625em;
|
||||
color: var(--wa-color-on-loud, var(--wa-color-brand-on-loud));
|
||||
font-size: max(var(--wa-font-size-2xs), 0.75em);
|
||||
font-weight: var(--wa-font-weight-semibold);
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
border-color: transparent;
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
border-style: var(--wa-border-style);
|
||||
border-width: var(--wa-border-width-s);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance='outlined']) {
|
||||
--pulse-color: var(--wa-color-border-loud, var(--wa-color-brand-border-loud));
|
||||
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-brand-on-quiet));
|
||||
background-color: transparent;
|
||||
border-color: var(--wa-color-border-loud, var(--wa-color-brand-border-loud));
|
||||
}
|
||||
|
||||
:host([appearance='filled']) {
|
||||
--pulse-color: var(--wa-color-fill-normal, var(--wa-color-brand-fill-normal));
|
||||
|
||||
color: var(--wa-color-on-normal, var(--wa-color-brand-on-normal));
|
||||
background-color: var(--wa-color-fill-normal, var(--wa-color-brand-fill-normal));
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance='filled-outlined']) {
|
||||
--pulse-color: var(--wa-color-border-normal, var(--wa-color-brand-border-normal));
|
||||
|
||||
color: var(--wa-color-on-normal, var(--wa-color-brand-on-normal));
|
||||
background-color: var(--wa-color-fill-normal, var(--wa-color-brand-fill-normal));
|
||||
border-color: var(--wa-color-border-normal, var(--wa-color-brand-border-normal));
|
||||
}
|
||||
|
||||
:host([appearance='accent']) {
|
||||
--pulse-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
|
||||
color: var(--wa-color-on-loud, var(--wa-color-brand-on-loud));
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
/* Pill modifier */
|
||||
:host([pill]) {
|
||||
border-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
/* Pulse attention */
|
||||
:host([attention='pulse']) {
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 var(--pulse-color);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 0.5rem transparent;
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bounce attention */
|
||||
:host([attention='bounce']) {
|
||||
animation: bounce 1s cubic-bezier(0.28, 0.84, 0.42, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%,
|
||||
20%,
|
||||
50%,
|
||||
80%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
40% {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
60% {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
::slotted(wa-icon) {
|
||||
margin-inline-end: var(--wa-space-2xs, 0.25em);
|
||||
opacity: 90%;
|
||||
line-height: 1;
|
||||
height: 0.85em;
|
||||
}
|
||||
108
packages/webawesome/src/components/badge/badge.styles.ts
Normal file
108
packages/webawesome/src/components/badge/badge.styles.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--pulse-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.375em 0.625em;
|
||||
color: var(--wa-color-on-loud, var(--wa-color-brand-on-loud));
|
||||
font-size: max(var(--wa-font-size-2xs), 0.75em);
|
||||
font-weight: var(--wa-font-weight-semibold);
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
border-color: transparent;
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
border-style: var(--wa-border-style);
|
||||
border-width: var(--wa-border-width-s);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance='outlined']) {
|
||||
--pulse-color: var(--wa-color-border-loud, var(--wa-color-brand-border-loud));
|
||||
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-brand-on-quiet));
|
||||
background-color: transparent;
|
||||
border-color: var(--wa-color-border-loud, var(--wa-color-brand-border-loud));
|
||||
}
|
||||
|
||||
:host([appearance='filled']) {
|
||||
--pulse-color: var(--wa-color-fill-normal, var(--wa-color-brand-fill-normal));
|
||||
|
||||
color: var(--wa-color-on-normal, var(--wa-color-brand-on-normal));
|
||||
background-color: var(--wa-color-fill-normal, var(--wa-color-brand-fill-normal));
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance='filled-outlined']) {
|
||||
--pulse-color: var(--wa-color-border-normal, var(--wa-color-brand-border-normal));
|
||||
|
||||
color: var(--wa-color-on-normal, var(--wa-color-brand-on-normal));
|
||||
background-color: var(--wa-color-fill-normal, var(--wa-color-brand-fill-normal));
|
||||
border-color: var(--wa-color-border-normal, var(--wa-color-brand-border-normal));
|
||||
}
|
||||
|
||||
:host([appearance='accent']) {
|
||||
--pulse-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
|
||||
color: var(--wa-color-on-loud, var(--wa-color-brand-on-loud));
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
/* Pill modifier */
|
||||
:host([pill]) {
|
||||
border-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
/* Pulse attention */
|
||||
:host([attention='pulse']) {
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 var(--pulse-color);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 0.5rem transparent;
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bounce attention */
|
||||
:host([attention='bounce']) {
|
||||
animation: bounce 1s cubic-bezier(0.28, 0.84, 0.42, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%,
|
||||
20%,
|
||||
50%,
|
||||
80%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
40% {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
60% {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
::slotted(wa-icon) {
|
||||
margin-inline-end: var(--wa-space-2xs, 0.25em);
|
||||
opacity: 90%;
|
||||
line-height: 1;
|
||||
height: 0.85em;
|
||||
}
|
||||
`;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import variantStyles from '../../styles/utilities/variants.css';
|
||||
import styles from './badge.css';
|
||||
import variantStyles from '../../styles/component/variants.styles.js';
|
||||
import styles from './badge.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Badges are used to draw attention and display statuses or counts.
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
:host {
|
||||
color: var(--wa-color-text-link);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font: inherit;
|
||||
font-weight: var(--wa-font-weight-action);
|
||||
line-height: var(--wa-line-height-normal);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:host(:last-of-type) {
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
.label {
|
||||
display: inline-block;
|
||||
font: inherit;
|
||||
text-decoration: none;
|
||||
color: currentColor;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
transition: color var(--wa-transition-normal) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
:host(:not(:last-of-type)) .label:hover {
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover));
|
||||
}
|
||||
}
|
||||
|
||||
:host(:not(:last-of-type)) .label:active {
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-active));
|
||||
}
|
||||
|
||||
.label:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.label:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
.start,
|
||||
.end {
|
||||
display: none;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.start,
|
||||
.end {
|
||||
display: inline-flex;
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
::slotted([slot='start']) {
|
||||
margin-inline-end: var(--wa-space-s);
|
||||
}
|
||||
|
||||
::slotted([slot='end']) {
|
||||
margin-inline-start: var(--wa-space-s);
|
||||
}
|
||||
|
||||
:host(:last-of-type) .separator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: var(--wa-color-text-quiet);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin: 0 var(--wa-space-s);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
color: var(--wa-color-text-link);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font: inherit;
|
||||
font-weight: var(--wa-font-weight-action);
|
||||
line-height: var(--wa-line-height-normal);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:host(:last-of-type) {
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
.label {
|
||||
display: inline-block;
|
||||
font: inherit;
|
||||
text-decoration: none;
|
||||
color: currentColor;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
transition: color var(--wa-transition-normal) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
:host(:not(:last-of-type)) .label:hover {
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover));
|
||||
}
|
||||
}
|
||||
|
||||
:host(:not(:last-of-type)) .label:active {
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-active));
|
||||
}
|
||||
|
||||
.label:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.label:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
.start,
|
||||
.end {
|
||||
display: none;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.start,
|
||||
.end {
|
||||
display: inline-flex;
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
::slotted([slot='start']) {
|
||||
margin-inline-end: var(--wa-space-s);
|
||||
}
|
||||
|
||||
::slotted([slot='end']) {
|
||||
margin-inline-start: var(--wa-space-s);
|
||||
}
|
||||
|
||||
:host(:last-of-type) .separator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: var(--wa-color-text-quiet);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin: 0 var(--wa-space-s);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
`;
|
||||
@@ -3,7 +3,7 @@ import { customElement, property, query, state } from 'lit/decorators.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import styles from './breadcrumb-item.css';
|
||||
import styles from './breadcrumb-item.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Breadcrumb Items are used inside breadcrumbs to represent different links.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
`;
|
||||
@@ -4,7 +4,7 @@ import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import type WaBreadcrumbItem from '../breadcrumb-item/breadcrumb-item.js';
|
||||
import '../icon/icon.js';
|
||||
import styles from './breadcrumb.css';
|
||||
import styles from './breadcrumb.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Breadcrumbs provide a group of links so users can easily navigate a website's hierarchy.
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
:host {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
flex-wrap: wrap;
|
||||
gap: 1px;
|
||||
|
||||
@media (hover: hover) {
|
||||
> :hover,
|
||||
&::slotted(:hover) {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus and checked are always on top */
|
||||
> :focus,
|
||||
&::slotted(:focus),
|
||||
> [aria-checked='true'],
|
||||
&::slotted([aria-checked='true']),
|
||||
> [checked],
|
||||
&::slotted([checked]) {
|
||||
z-index: 2 !important;
|
||||
}
|
||||
}
|
||||
:host([orientation='vertical']) .button-group {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Button groups with at least one outlined button will not have a gap and instead have borders overlap */
|
||||
.button-group.has-outlined {
|
||||
gap: 0;
|
||||
|
||||
&:not([aria-orientation='vertical']):not(.button-group-vertical)::slotted(:not(:first-child)) {
|
||||
margin-inline-start: calc(-1 * var(--border-width));
|
||||
}
|
||||
|
||||
&:is([aria-orientation='vertical'], .button-group-vertical)::slotted(:not(:first-child)) {
|
||||
margin-block-start: calc(-1 * var(--border-width));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
flex-wrap: wrap;
|
||||
gap: 1px;
|
||||
|
||||
@media (hover: hover) {
|
||||
> :hover,
|
||||
&::slotted(:hover) {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus and checked are always on top */
|
||||
> :focus,
|
||||
&::slotted(:focus),
|
||||
> [aria-checked='true'],
|
||||
&::slotted([aria-checked='true']),
|
||||
> [checked],
|
||||
&::slotted([checked]) {
|
||||
z-index: 2 !important;
|
||||
}
|
||||
}
|
||||
:host([orientation='vertical']) .button-group {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Button groups with at least one outlined button will not have a gap and instead have borders overlap */
|
||||
.button-group.has-outlined {
|
||||
gap: 0;
|
||||
|
||||
&:not([aria-orientation='vertical']):not(.button-group-vertical)::slotted(:not(:first-child)) {
|
||||
margin-inline-start: calc(-1 * var(--border-width));
|
||||
}
|
||||
|
||||
&:is([aria-orientation='vertical'], .button-group-vertical)::slotted(:not(:first-child)) {
|
||||
margin-block-start: calc(-1 * var(--border-width));
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -3,9 +3,8 @@ import { html } from 'lit';
|
||||
import { customElement, property, query, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import variantStyles from '../../styles/utilities/variants.css';
|
||||
import type WaButton from '../button/button.js';
|
||||
import styles from './button-group.css';
|
||||
import styles from './button-group.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Button groups can be used to group related buttons into sections.
|
||||
@@ -19,7 +18,7 @@ import styles from './button-group.css';
|
||||
*/
|
||||
@customElement('wa-button-group')
|
||||
export default class WaButtonGroup extends WebAwesomeElement {
|
||||
static css = [variantStyles, styles];
|
||||
static css = [styles];
|
||||
|
||||
@query('slot') defaultSlot: HTMLSlotElement;
|
||||
|
||||
@@ -35,9 +34,6 @@ export default class WaButtonGroup extends WebAwesomeElement {
|
||||
/** The button group's orientation. */
|
||||
@property({ reflect: true }) orientation: 'horizontal' | 'vertical' = 'horizontal';
|
||||
|
||||
/** The button group's theme variant. Defaults to `neutral` if not within another element with a variant. */
|
||||
@property({ reflect: true }) variant: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' = 'neutral';
|
||||
|
||||
updated(changedProperties: PropertyValues<this>) {
|
||||
super.updated(changedProperties);
|
||||
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
@layer wa-component {
|
||||
:host {
|
||||
display: inline-block;
|
||||
|
||||
/* Workaround because Chrome doesn't like :host(:has()) below
|
||||
* https://issues.chromium.org/issues/40062355
|
||||
* Firefox doesn't like this nested rule, so both are needed */
|
||||
&:has(wa-badge) {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply relative positioning only when needed to position wa-badge
|
||||
* This avoids creating a new stacking context for every button */
|
||||
:host(:has(wa-badge)) {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
transition-property: background, border, box-shadow, color;
|
||||
transition-duration: var(--wa-transition-fast);
|
||||
transition-timing-function: var(--wa-transition-easing);
|
||||
cursor: pointer;
|
||||
padding: 0 var(--wa-form-control-padding-inline);
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
font-weight: var(--wa-font-weight-action);
|
||||
line-height: calc(var(--wa-form-control-height) - var(--border-width) * 2);
|
||||
height: var(--wa-form-control-height);
|
||||
width: 100%;
|
||||
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud));
|
||||
border-color: transparent;
|
||||
color: var(--wa-color-on-loud, var(--wa-color-neutral-on-loud));
|
||||
border-radius: var(--wa-form-control-border-radius);
|
||||
border-style: var(--wa-border-style);
|
||||
border-width: var(--wa-border-width-s);
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance='plain']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet));
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
:host([appearance='outlined']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: transparent;
|
||||
border-color: var(--wa-color-border-loud, var(--wa-color-neutral-border-loud));
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet));
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
:host([appearance='filled']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal));
|
||||
border-color: transparent;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
|
||||
var(--wa-color-mix-hover)
|
||||
);
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
:host([appearance='filled-outlined']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal));
|
||||
border-color: var(--wa-color-border-normal, var(--wa-color-neutral-border-normal));
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
|
||||
var(--wa-color-mix-hover)
|
||||
);
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
:host([appearance='accent']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-loud, var(--wa-color-neutral-on-loud));
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud));
|
||||
border-color: transparent;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
|
||||
var(--wa-color-mix-hover)
|
||||
);
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus states */
|
||||
.button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
/* Disabled state */
|
||||
.button.disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* When disabled, prevent mouse events from bubbling up from children */
|
||||
.button.disabled * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Keep it last so Safari doesn't stop parsing this block */
|
||||
.button::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Icon buttons */
|
||||
.button.is-icon-button {
|
||||
outline-offset: 2px;
|
||||
width: var(--wa-form-control-height);
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.button.is-icon-button:has(wa-icon) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* Pill modifier */
|
||||
:host([pill]) .button {
|
||||
border-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
/*
|
||||
* Label
|
||||
*/
|
||||
|
||||
.start,
|
||||
.end {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.is-icon-button .label {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.label::slotted(wa-icon) {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/*
|
||||
* Caret modifier
|
||||
*/
|
||||
|
||||
wa-icon[part='caret'] {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
align-items: center;
|
||||
|
||||
&::part(svg) {
|
||||
width: 0.875em;
|
||||
height: 0.875em;
|
||||
}
|
||||
|
||||
.button:has(&) .end {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Loading modifier
|
||||
*/
|
||||
|
||||
.loading {
|
||||
position: relative;
|
||||
cursor: wait;
|
||||
|
||||
.start,
|
||||
.label,
|
||||
.end,
|
||||
.caret {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
wa-spinner {
|
||||
--indicator-color: currentColor;
|
||||
--track-color: color-mix(in oklab, currentColor, transparent 90%);
|
||||
|
||||
position: absolute;
|
||||
font-size: 1em;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
top: calc(50% - 0.5em);
|
||||
left: calc(50% - 0.5em);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Badges
|
||||
*/
|
||||
|
||||
.button ::slotted(wa-badge) {
|
||||
border-color: var(--wa-color-surface-default);
|
||||
position: absolute;
|
||||
inset-block-start: 0;
|
||||
inset-inline-end: 0;
|
||||
translate: 50% -50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host(:dir(rtl)) ::slotted(wa-badge) {
|
||||
translate: -50% -50%;
|
||||
}
|
||||
|
||||
/*
|
||||
* Button spacing
|
||||
*/
|
||||
|
||||
slot[name='start']::slotted(*) {
|
||||
margin-inline-end: 0.75em;
|
||||
}
|
||||
|
||||
slot[name='end']::slotted(*),
|
||||
.button:not(.visually-hidden-label) [part='caret'] {
|
||||
margin-inline-start: 0.75em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Button group border radius modifications
|
||||
*/
|
||||
|
||||
/* Remove border radius from all grouped buttons by default */
|
||||
:host(.wa-button-group__button) .button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* Horizontal orientation */
|
||||
:host(.wa-button-group__horizontal.wa-button-group__button-first) .button {
|
||||
border-start-start-radius: var(--wa-form-control-border-radius);
|
||||
border-end-start-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
:host(.wa-button-group__horizontal.wa-button-group__button-last) .button {
|
||||
border-start-end-radius: var(--wa-form-control-border-radius);
|
||||
border-end-end-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
/* Vertical orientation */
|
||||
:host(.wa-button-group__vertical) {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
:host(.wa-button-group__vertical) .button {
|
||||
width: 100%;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
:host(.wa-button-group__vertical.wa-button-group__button-first) .button {
|
||||
border-start-start-radius: var(--wa-form-control-border-radius);
|
||||
border-start-end-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
:host(.wa-button-group__vertical.wa-button-group__button-last) .button {
|
||||
border-end-start-radius: var(--wa-form-control-border-radius);
|
||||
border-end-end-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
/* Handle pill modifier for button groups */
|
||||
:host([pill].wa-button-group__horizontal.wa-button-group__button-first) .button {
|
||||
border-start-start-radius: var(--wa-border-radius-pill);
|
||||
border-end-start-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
:host([pill].wa-button-group__horizontal.wa-button-group__button-last) .button {
|
||||
border-start-end-radius: var(--wa-border-radius-pill);
|
||||
border-end-end-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
:host([pill].wa-button-group__vertical.wa-button-group__button-first) .button {
|
||||
border-start-start-radius: var(--wa-border-radius-pill);
|
||||
border-start-end-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
:host([pill].wa-button-group__vertical.wa-button-group__button-last) .button {
|
||||
border-end-start-radius: var(--wa-border-radius-pill);
|
||||
border-end-end-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
376
packages/webawesome/src/components/button/button.styles.ts
Normal file
376
packages/webawesome/src/components/button/button.styles.ts
Normal file
@@ -0,0 +1,376 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
@layer wa-component {
|
||||
:host {
|
||||
display: inline-block;
|
||||
|
||||
/* Workaround because Chrome doesn't like :host(:has()) below
|
||||
* https://issues.chromium.org/issues/40062355
|
||||
* Firefox doesn't like this nested rule, so both are needed */
|
||||
&:has(wa-badge) {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply relative positioning only when needed to position wa-badge
|
||||
* This avoids creating a new stacking context for every button */
|
||||
:host(:has(wa-badge)) {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
transition-property: background, border, box-shadow, color, opacity;
|
||||
transition-duration: var(--wa-transition-fast);
|
||||
transition-timing-function: var(--wa-transition-easing);
|
||||
cursor: pointer;
|
||||
padding: 0 var(--wa-form-control-padding-inline);
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
font-weight: var(--wa-font-weight-action);
|
||||
line-height: calc(var(--wa-form-control-height) - var(--border-width) * 2);
|
||||
height: var(--wa-form-control-height);
|
||||
width: 100%;
|
||||
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud));
|
||||
border-color: transparent;
|
||||
color: var(--wa-color-on-loud, var(--wa-color-neutral-on-loud));
|
||||
border-radius: var(--wa-form-control-border-radius);
|
||||
border-style: var(--wa-border-style);
|
||||
border-width: var(--wa-border-width-s);
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance='plain']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet));
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
:host([appearance='outlined']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: transparent;
|
||||
border-color: var(--wa-color-border-loud, var(--wa-color-neutral-border-loud));
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet));
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
:host([appearance='filled']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal));
|
||||
border-color: transparent;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
|
||||
var(--wa-color-mix-hover)
|
||||
);
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
:host([appearance='filled-outlined']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal));
|
||||
border-color: var(--wa-color-border-normal, var(--wa-color-neutral-border-normal));
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
|
||||
var(--wa-color-mix-hover)
|
||||
);
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
:host([appearance='accent']) {
|
||||
.button {
|
||||
color: var(--wa-color-on-loud, var(--wa-color-neutral-on-loud));
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud));
|
||||
border-color: transparent;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.button:not(.disabled):not(.loading):hover {
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
|
||||
var(--wa-color-mix-hover)
|
||||
);
|
||||
}
|
||||
}
|
||||
.button:not(.disabled):not(.loading):active {
|
||||
background-color: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
|
||||
var(--wa-color-mix-active)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus states */
|
||||
.button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
/* Disabled state */
|
||||
.button.disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* When disabled, prevent mouse events from bubbling up from children */
|
||||
.button.disabled * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Keep it last so Safari doesn't stop parsing this block */
|
||||
.button::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Icon buttons */
|
||||
.button.is-icon-button {
|
||||
outline-offset: 2px;
|
||||
width: var(--wa-form-control-height);
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.button.is-icon-button:has(wa-icon) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* Pill modifier */
|
||||
:host([pill]) .button {
|
||||
border-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
/*
|
||||
* Label
|
||||
*/
|
||||
|
||||
.start,
|
||||
.end {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.is-icon-button .label {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.label::slotted(wa-icon) {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/*
|
||||
* Caret modifier
|
||||
*/
|
||||
|
||||
wa-icon[part='caret'] {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
align-items: center;
|
||||
|
||||
&::part(svg) {
|
||||
width: 0.875em;
|
||||
height: 0.875em;
|
||||
}
|
||||
|
||||
.button:has(&) .end {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Loading modifier
|
||||
*/
|
||||
|
||||
.loading {
|
||||
position: relative;
|
||||
cursor: wait;
|
||||
|
||||
.start,
|
||||
.label,
|
||||
.end,
|
||||
.caret {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
wa-spinner {
|
||||
--indicator-color: currentColor;
|
||||
--track-color: color-mix(in oklab, currentColor, transparent 90%);
|
||||
|
||||
position: absolute;
|
||||
font-size: 1em;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
top: calc(50% - 0.5em);
|
||||
left: calc(50% - 0.5em);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Badges
|
||||
*/
|
||||
|
||||
.button ::slotted(wa-badge) {
|
||||
border-color: var(--wa-color-surface-default);
|
||||
position: absolute;
|
||||
inset-block-start: 0;
|
||||
inset-inline-end: 0;
|
||||
translate: 50% -50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host(:dir(rtl)) ::slotted(wa-badge) {
|
||||
translate: -50% -50%;
|
||||
}
|
||||
|
||||
/*
|
||||
* Button spacing
|
||||
*/
|
||||
|
||||
slot[name='start']::slotted(*) {
|
||||
margin-inline-end: 0.75em;
|
||||
}
|
||||
|
||||
slot[name='end']::slotted(*),
|
||||
.button:not(.visually-hidden-label) [part='caret'] {
|
||||
margin-inline-start: 0.75em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Button group border radius modifications
|
||||
*/
|
||||
|
||||
/* Remove border radius from all grouped buttons by default */
|
||||
:host(.wa-button-group__button) .button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* Horizontal orientation */
|
||||
:host(.wa-button-group__horizontal.wa-button-group__button-first) .button {
|
||||
border-start-start-radius: var(--wa-form-control-border-radius);
|
||||
border-end-start-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
:host(.wa-button-group__horizontal.wa-button-group__button-last) .button {
|
||||
border-start-end-radius: var(--wa-form-control-border-radius);
|
||||
border-end-end-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
/* Vertical orientation */
|
||||
:host(.wa-button-group__vertical) {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
:host(.wa-button-group__vertical) .button {
|
||||
width: 100%;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
:host(.wa-button-group__vertical.wa-button-group__button-first) .button {
|
||||
border-start-start-radius: var(--wa-form-control-border-radius);
|
||||
border-start-end-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
:host(.wa-button-group__vertical.wa-button-group__button-last) .button {
|
||||
border-end-start-radius: var(--wa-form-control-border-radius);
|
||||
border-end-end-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
/* Handle pill modifier for button groups */
|
||||
:host([pill].wa-button-group__horizontal.wa-button-group__button-first) .button {
|
||||
border-start-start-radius: var(--wa-border-radius-pill);
|
||||
border-end-start-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
:host([pill].wa-button-group__horizontal.wa-button-group__button-last) .button {
|
||||
border-start-end-radius: var(--wa-border-radius-pill);
|
||||
border-end-end-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
:host([pill].wa-button-group__vertical.wa-button-group__button-first) .button {
|
||||
border-start-start-radius: var(--wa-border-radius-pill);
|
||||
border-start-end-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
|
||||
:host([pill].wa-button-group__vertical.wa-button-group__button-last) .button {
|
||||
border-end-start-radius: var(--wa-border-radius-pill);
|
||||
border-end-end-radius: var(--wa-border-radius-pill);
|
||||
}
|
||||
`;
|
||||
@@ -7,13 +7,13 @@ import { HasSlotController } from '../../internal/slot.js';
|
||||
import { MirrorValidator } from '../../internal/validators/mirror-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import variantStyles from '../../styles/utilities/variants.css';
|
||||
import sizeStyles from '../../styles/component/size.styles.js';
|
||||
import variantStyles from '../../styles/component/variants.styles.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import '../icon/icon.js';
|
||||
import type WaIcon from '../icon/icon.js';
|
||||
import '../spinner/spinner.js';
|
||||
import styles from './button.css';
|
||||
import styles from './button.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Buttons represent actions that are available to the user.
|
||||
@@ -115,7 +115,6 @@ export default class WaButton extends WebAwesomeFormAssociatedElement {
|
||||
* The "form owner" to associate the button with. If omitted, the closest containing form will be used instead. The
|
||||
* value of this attribute must be an id of a form in the same document or shadow root as the button.
|
||||
*/
|
||||
@property({ reflect: true }) form: string | null = null;
|
||||
|
||||
/** Used to override the form owner's `action` attribute. */
|
||||
@property({ attribute: 'formaction' }) formAction: string;
|
||||
@@ -135,24 +134,27 @@ export default class WaButton extends WebAwesomeFormAssociatedElement {
|
||||
|
||||
private constructLightDOMButton() {
|
||||
const button = document.createElement('button');
|
||||
|
||||
for (const attribute of this.attributes) {
|
||||
if (attribute.name === 'style') {
|
||||
// Skip style attributes as they *shouldn't* be necessary
|
||||
continue;
|
||||
}
|
||||
button.setAttribute(attribute.name, attribute.value);
|
||||
}
|
||||
|
||||
button.type = this.type;
|
||||
button.style.position = 'absolute';
|
||||
button.style.width = '0';
|
||||
button.style.height = '0';
|
||||
button.style.clipPath = 'inset(50%)';
|
||||
button.style.overflow = 'hidden';
|
||||
button.style.whiteSpace = 'nowrap';
|
||||
button.style.position = 'absolute !important';
|
||||
button.style.width = '0 !important';
|
||||
button.style.height = '0 !important';
|
||||
button.style.clipPath = 'inset(50%) !important';
|
||||
button.style.overflow = 'hidden !important';
|
||||
button.style.whiteSpace = 'nowrap !important';
|
||||
if (this.name) {
|
||||
button.name = this.name;
|
||||
}
|
||||
button.value = this.value || '';
|
||||
|
||||
['form', 'formaction', 'formenctype', 'formmethod', 'formnovalidate', 'formtarget'].forEach(attr => {
|
||||
if (this.hasAttribute(attr)) {
|
||||
button.setAttribute(attr, this.getAttribute(attr)!);
|
||||
}
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
:host {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: stretch;
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
background-color: var(--wa-color-fill-quiet, var(--wa-color-brand-fill-quiet));
|
||||
border-color: var(--wa-color-border-quiet, var(--wa-color-brand-border-quiet));
|
||||
border-style: var(--wa-panel-border-style);
|
||||
border-width: var(--wa-panel-border-width);
|
||||
color: var(--wa-color-text-normal);
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance~='plain']) {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance~='outlined']) {
|
||||
background-color: transparent;
|
||||
border-color: var(--wa-color-border-loud, var(--wa-color-brand-border-loud));
|
||||
}
|
||||
|
||||
:host([appearance~='filled']) {
|
||||
background-color: var(--wa-color-fill-quiet, var(--wa-color-brand-fill-quiet));
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance~='filled-outlined']) {
|
||||
border-color: var(--wa-color-border-quiet, var(--wa-color-brand-border-quiet));
|
||||
}
|
||||
|
||||
:host([appearance~='accent']) {
|
||||
color: var(--wa-color-on-loud, var(--wa-color-brand-on-loud));
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
border-color: transparent;
|
||||
|
||||
[part~='icon'] {
|
||||
color: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
[part~='icon'] {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--wa-color-on-quiet);
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
::slotted([slot='icon']) {
|
||||
margin-inline-end: var(--wa-form-control-padding-inline);
|
||||
}
|
||||
|
||||
[part~='message'] {
|
||||
flex: 1 1 auto;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
64
packages/webawesome/src/components/callout/callout.styles.ts
Normal file
64
packages/webawesome/src/components/callout/callout.styles.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: stretch;
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
background-color: var(--wa-color-fill-quiet, var(--wa-color-brand-fill-quiet));
|
||||
border-color: var(--wa-color-border-quiet, var(--wa-color-brand-border-quiet));
|
||||
border-style: var(--wa-panel-border-style);
|
||||
border-width: var(--wa-panel-border-width);
|
||||
color: var(--wa-color-text-normal);
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance~='plain']) {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance~='outlined']) {
|
||||
background-color: transparent;
|
||||
border-color: var(--wa-color-border-loud, var(--wa-color-brand-border-loud));
|
||||
}
|
||||
|
||||
:host([appearance~='filled']) {
|
||||
background-color: var(--wa-color-fill-quiet, var(--wa-color-brand-fill-quiet));
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance~='filled-outlined']) {
|
||||
border-color: var(--wa-color-border-quiet, var(--wa-color-brand-border-quiet));
|
||||
}
|
||||
|
||||
:host([appearance~='accent']) {
|
||||
color: var(--wa-color-on-loud, var(--wa-color-brand-on-loud));
|
||||
background-color: var(--wa-color-fill-loud, var(--wa-color-brand-fill-loud));
|
||||
border-color: transparent;
|
||||
|
||||
[part~='icon'] {
|
||||
color: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
[part~='icon'] {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--wa-color-on-quiet);
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
::slotted([slot='icon']) {
|
||||
margin-inline-end: var(--wa-form-control-padding-inline);
|
||||
}
|
||||
|
||||
[part~='message'] {
|
||||
flex: 1 1 auto;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
`;
|
||||
@@ -1,9 +1,9 @@
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import variantStyles from '../../styles/utilities/variants.css';
|
||||
import styles from './callout.css';
|
||||
import sizeStyles from '../../styles/component/size.styles.js';
|
||||
import variantStyles from '../../styles/component/variants.styles.js';
|
||||
import styles from './callout.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Callouts are used to display important messages inline.
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
:host {
|
||||
--spacing: var(--wa-space-l);
|
||||
|
||||
/* Internal calculated properties */
|
||||
--inner-border-radius: calc(var(--wa-panel-border-radius) - var(--wa-panel-border-width));
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
border-style: var(--wa-panel-border-style);
|
||||
box-shadow: var(--wa-shadow-s);
|
||||
border-width: var(--wa-panel-border-width);
|
||||
color: var(--wa-color-text-normal);
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance~='plain']) {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
:host([appearance~='outlined']) {
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
}
|
||||
|
||||
:host([appearance~='filled']) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance~='filled'][appearance~='outlined']) {
|
||||
border-color: var(--wa-color-neutral-border-quiet);
|
||||
}
|
||||
|
||||
:host([appearance~='accent']) {
|
||||
color: var(--wa-color-neutral-on-loud);
|
||||
background-color: var(--wa-color-neutral-fill-loud);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
/* Take care of top and bottom radii */
|
||||
.media,
|
||||
:host(:not([with-media])) .header,
|
||||
:host(:not([with-media], [with-header])) .body {
|
||||
border-start-start-radius: var(--inner-border-radius);
|
||||
border-start-end-radius: var(--inner-border-radius);
|
||||
}
|
||||
|
||||
:host(:not([with-footer])) .body,
|
||||
.footer {
|
||||
border-end-start-radius: var(--inner-border-radius);
|
||||
border-end-end-radius: var(--inner-border-radius);
|
||||
}
|
||||
|
||||
.media {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
&::slotted(*) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Round all corners for plain appearance */
|
||||
:host([appearance='plain']) .media {
|
||||
border-radius: var(--inner-border-radius);
|
||||
|
||||
&::slotted(*) {
|
||||
border-radius: inherit !important;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: block;
|
||||
border-block-end-style: inherit;
|
||||
border-block-end-color: var(--wa-color-surface-border);
|
||||
border-block-end-width: var(--wa-panel-border-width);
|
||||
padding: calc(var(--spacing) / 2) var(--spacing);
|
||||
}
|
||||
|
||||
.body {
|
||||
display: block;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: block;
|
||||
border-block-start-style: inherit;
|
||||
border-block-start-color: var(--wa-color-surface-border);
|
||||
border-block-start-width: var(--wa-panel-border-width);
|
||||
padding: var(--spacing);
|
||||
}
|
||||
|
||||
/* Push slots to sides when the action slots renders */
|
||||
.has-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
:host(:not([with-header])) .header,
|
||||
:host(:not([with-footer])) .footer,
|
||||
:host(:not([with-media])) .media {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Orientation Styles */
|
||||
:host([orientation='horizontal']) {
|
||||
flex-direction: row;
|
||||
|
||||
.media {
|
||||
border-start-start-radius: var(--inner-border-radius);
|
||||
border-end-start-radius: var(--inner-border-radius);
|
||||
border-start-end-radius: 0;
|
||||
|
||||
&::slotted(*) {
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:host([orientation='horizontal']) ::slotted([slot='body']) {
|
||||
display: block;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:host([orientation='horizontal']) ::slotted([slot='actions']) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
145
packages/webawesome/src/components/card/card.styles.ts
Normal file
145
packages/webawesome/src/components/card/card.styles.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--spacing: var(--wa-space-l);
|
||||
|
||||
/* Internal calculated properties */
|
||||
--inner-border-radius: calc(var(--wa-panel-border-radius) - var(--wa-panel-border-width));
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
border-style: var(--wa-panel-border-style);
|
||||
box-shadow: var(--wa-shadow-s);
|
||||
border-width: var(--wa-panel-border-width);
|
||||
color: var(--wa-color-text-normal);
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance='plain']) {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
:host([appearance='outlined']) {
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
}
|
||||
|
||||
:host([appearance='filled']) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance='filled-outlined']) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
}
|
||||
|
||||
:host([appearance='accent']) {
|
||||
color: var(--wa-color-neutral-on-loud);
|
||||
background-color: var(--wa-color-neutral-fill-loud);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
/* Take care of top and bottom radii */
|
||||
.media,
|
||||
:host(:not([with-media])) .header,
|
||||
:host(:not([with-media], [with-header])) .body {
|
||||
border-start-start-radius: var(--inner-border-radius);
|
||||
border-start-end-radius: var(--inner-border-radius);
|
||||
}
|
||||
|
||||
:host(:not([with-footer])) .body,
|
||||
.footer {
|
||||
border-end-start-radius: var(--inner-border-radius);
|
||||
border-end-end-radius: var(--inner-border-radius);
|
||||
}
|
||||
|
||||
.media {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
&::slotted(*) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Round all corners for plain appearance */
|
||||
:host([appearance='plain']) .media {
|
||||
border-radius: var(--inner-border-radius);
|
||||
|
||||
&::slotted(*) {
|
||||
border-radius: inherit !important;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: block;
|
||||
border-block-end-style: inherit;
|
||||
border-block-end-color: var(--wa-color-surface-border);
|
||||
border-block-end-width: var(--wa-panel-border-width);
|
||||
padding: calc(var(--spacing) / 2) var(--spacing);
|
||||
}
|
||||
|
||||
.body {
|
||||
display: block;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: block;
|
||||
border-block-start-style: inherit;
|
||||
border-block-start-color: var(--wa-color-surface-border);
|
||||
border-block-start-width: var(--wa-panel-border-width);
|
||||
padding: var(--spacing);
|
||||
}
|
||||
|
||||
/* Push slots to sides when the action slots renders */
|
||||
.has-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
:host(:not([with-header])) .header,
|
||||
:host(:not([with-footer])) .footer,
|
||||
:host(:not([with-media])) .media {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Orientation Styles */
|
||||
:host([orientation='horizontal']) {
|
||||
flex-direction: row;
|
||||
|
||||
.media {
|
||||
border-start-start-radius: var(--inner-border-radius);
|
||||
border-end-start-radius: var(--inner-border-radius);
|
||||
border-start-end-radius: 0;
|
||||
|
||||
&::slotted(*) {
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:host([orientation='horizontal']) ::slotted([slot='body']) {
|
||||
display: block;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:host([orientation='horizontal']) ::slotted([slot='actions']) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
`;
|
||||
@@ -2,8 +2,8 @@ import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { HasSlotController } from '../../internal/slot.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import styles from './card.css';
|
||||
import sizeStyles from '../../styles/component/size.styles.js';
|
||||
import styles from './card.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Cards can be used to group related subjects in a container.
|
||||
@@ -30,11 +30,19 @@ import styles from './card.css';
|
||||
export default class WaCard extends WebAwesomeElement {
|
||||
static css = [sizeStyles, styles];
|
||||
|
||||
private readonly hasSlotController = new HasSlotController(this, 'footer', 'header', 'media');
|
||||
private readonly hasSlotController = new HasSlotController(
|
||||
this,
|
||||
'footer',
|
||||
'header',
|
||||
'media',
|
||||
'header-actions',
|
||||
'footer-actions',
|
||||
'actions',
|
||||
);
|
||||
|
||||
/** The card's visual appearance. */
|
||||
@property({ reflect: true })
|
||||
appearance: 'accent' | 'filled' | 'outlined' | 'plain' = 'outlined';
|
||||
appearance: 'accent' | 'filled' | 'outlined' | 'filled-outlined' | 'plain' = 'outlined';
|
||||
|
||||
/** Renders the card with a header. Only needed for SSR, otherwise is automatically added. */
|
||||
@property({ attribute: 'with-header', type: Boolean, reflect: true }) withHeader = false;
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
:host {
|
||||
--aspect-ratio: inherit;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
aspect-ratio: var(--aspect-ratio);
|
||||
scroll-snap-align: start;
|
||||
scroll-snap-stop: always;
|
||||
}
|
||||
|
||||
::slotted(img) {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
object-fit: cover;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--aspect-ratio: inherit;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
aspect-ratio: var(--aspect-ratio);
|
||||
scroll-snap-align: start;
|
||||
scroll-snap-stop: always;
|
||||
}
|
||||
|
||||
::slotted(img) {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
object-fit: cover;
|
||||
}
|
||||
`;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { html } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import styles from './carousel-item.css';
|
||||
import styles from './carousel-item.styles.js';
|
||||
|
||||
/**
|
||||
* @summary A carousel item represent a slide within a carousel.
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
:host {
|
||||
--aspect-ratio: 16 / 9;
|
||||
--scroll-hint: 0px;
|
||||
--slide-gap: var(--wa-space-m, 1rem); /* fallback value is necessary */
|
||||
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.carousel {
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr min-content;
|
||||
grid-template-rows: 1fr min-content;
|
||||
grid-template-areas:
|
||||
'. slides .'
|
||||
'. pagination .';
|
||||
gap: var(--wa-space-m);
|
||||
align-items: center;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
grid-area: pagination;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: var(--wa-space-s);
|
||||
}
|
||||
|
||||
.slides {
|
||||
grid-area: slides;
|
||||
|
||||
display: grid;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
overflow: auto;
|
||||
overscroll-behavior-x: contain;
|
||||
scrollbar-width: none;
|
||||
aspect-ratio: calc(var(--aspect-ratio) * var(--slides-per-page));
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
|
||||
--slide-size: calc((100% - (var(--slides-per-page) - 1) * var(--slide-gap)) / var(--slides-per-page));
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
:where(.slides) {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.slides-horizontal {
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: var(--slide-size);
|
||||
grid-auto-rows: 100%;
|
||||
column-gap: var(--slide-gap);
|
||||
scroll-snap-type: x mandatory;
|
||||
scroll-padding-inline: var(--scroll-hint);
|
||||
padding-inline: var(--scroll-hint);
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.slides-vertical {
|
||||
grid-auto-flow: row;
|
||||
grid-auto-columns: 100%;
|
||||
grid-auto-rows: var(--slide-size);
|
||||
row-gap: var(--slide-gap);
|
||||
scroll-snap-type: y mandatory;
|
||||
scroll-padding-block: var(--scroll-hint);
|
||||
padding-block: var(--scroll-hint);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.slides-dragging,
|
||||
.slides-dropping {
|
||||
scroll-snap-type: unset;
|
||||
}
|
||||
|
||||
:host([vertical]) ::slotted(wa-carousel-item) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.slides::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navigation {
|
||||
grid-area: navigation;
|
||||
display: contents;
|
||||
font-size: var(--wa-font-size-l);
|
||||
}
|
||||
|
||||
.navigation-button {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
font-size: inherit;
|
||||
color: var(--wa-color-text-quiet);
|
||||
padding: var(--wa-space-xs);
|
||||
cursor: pointer;
|
||||
transition: var(--wa-transition-normal) color;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.navigation-button-disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.navigation-button-disabled::part(base) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.navigation-button-previous {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.navigation-button-next {
|
||||
grid-column: 3;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.pagination-item {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: 0;
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
width: var(--wa-space-s);
|
||||
height: var(--wa-space-s);
|
||||
background-color: var(--wa-color-neutral-fill-normal);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
transition: transform var(--wa-transition-slow);
|
||||
}
|
||||
|
||||
.pagination-item-active {
|
||||
background-color: var(--wa-form-control-activated-color);
|
||||
transform: scale(1.25);
|
||||
}
|
||||
|
||||
/* Focus styles */
|
||||
.slides:focus-visible,
|
||||
.navigation-button:focus-visible,
|
||||
.pagination-item:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
158
packages/webawesome/src/components/carousel/carousel.styles.ts
Normal file
158
packages/webawesome/src/components/carousel/carousel.styles.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--aspect-ratio: 16 / 9;
|
||||
--scroll-hint: 0px;
|
||||
--slide-gap: var(--wa-space-m, 1rem); /* fallback value is necessary */
|
||||
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.carousel {
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr min-content;
|
||||
grid-template-rows: 1fr min-content;
|
||||
grid-template-areas:
|
||||
'. slides .'
|
||||
'. pagination .';
|
||||
gap: var(--wa-space-m);
|
||||
align-items: center;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
grid-area: pagination;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: var(--wa-space-s);
|
||||
}
|
||||
|
||||
.slides {
|
||||
grid-area: slides;
|
||||
|
||||
display: grid;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
overflow: auto;
|
||||
overscroll-behavior-x: contain;
|
||||
scrollbar-width: none;
|
||||
aspect-ratio: calc(var(--aspect-ratio) * var(--slides-per-page));
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
|
||||
--slide-size: calc((100% - (var(--slides-per-page) - 1) * var(--slide-gap)) / var(--slides-per-page));
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
:where(.slides) {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.slides-horizontal {
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: var(--slide-size);
|
||||
grid-auto-rows: 100%;
|
||||
column-gap: var(--slide-gap);
|
||||
scroll-snap-type: x mandatory;
|
||||
scroll-padding-inline: var(--scroll-hint);
|
||||
padding-inline: var(--scroll-hint);
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.slides-vertical {
|
||||
grid-auto-flow: row;
|
||||
grid-auto-columns: 100%;
|
||||
grid-auto-rows: var(--slide-size);
|
||||
row-gap: var(--slide-gap);
|
||||
scroll-snap-type: y mandatory;
|
||||
scroll-padding-block: var(--scroll-hint);
|
||||
padding-block: var(--scroll-hint);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.slides-dragging,
|
||||
.slides-dropping {
|
||||
scroll-snap-type: unset;
|
||||
}
|
||||
|
||||
:host([vertical]) ::slotted(wa-carousel-item) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.slides::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navigation {
|
||||
grid-area: navigation;
|
||||
display: contents;
|
||||
font-size: var(--wa-font-size-l);
|
||||
}
|
||||
|
||||
.navigation-button {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
font-size: inherit;
|
||||
color: var(--wa-color-text-quiet);
|
||||
padding: var(--wa-space-xs);
|
||||
cursor: pointer;
|
||||
transition: var(--wa-transition-normal) color;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.navigation-button-disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.navigation-button-disabled::part(base) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.navigation-button-previous {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.navigation-button-next {
|
||||
grid-column: 3;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.pagination-item {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: 0;
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
width: var(--wa-space-s);
|
||||
height: var(--wa-space-s);
|
||||
background-color: var(--wa-color-neutral-fill-normal);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
transition: transform var(--wa-transition-slow);
|
||||
}
|
||||
|
||||
.pagination-item-active {
|
||||
background-color: var(--wa-form-control-activated-color);
|
||||
transform: scale(1.25);
|
||||
}
|
||||
|
||||
/* Focus styles */
|
||||
.slides:focus-visible,
|
||||
.navigation-button:focus-visible,
|
||||
.pagination-item:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
`;
|
||||
@@ -16,7 +16,7 @@ import { LocalizeController } from '../../utilities/localize.js';
|
||||
import type WaCarouselItem from '../carousel-item/carousel-item.js';
|
||||
import '../icon/icon.js';
|
||||
import { AutoplayController } from './autoplay-controller.js';
|
||||
import styles from './carousel.css';
|
||||
import styles from './carousel.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Carousels display an arbitrary number of content slides along a horizontal or vertical axis.
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
:host {
|
||||
--checked-icon-color: var(--wa-color-brand-on-loud);
|
||||
--checked-icon-scale: 0.8;
|
||||
|
||||
display: inline-flex;
|
||||
color: var(--wa-form-control-value-color);
|
||||
font-family: inherit;
|
||||
font-weight: var(--wa-form-control-value-font-weight);
|
||||
line-height: var(--wa-form-control-value-line-height);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
[part~='control'] {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--wa-form-control-toggle-size);
|
||||
height: var(--wa-form-control-toggle-size);
|
||||
border-color: var(--wa-form-control-border-color);
|
||||
border-radius: min(
|
||||
calc(var(--wa-form-control-toggle-size) * 0.375),
|
||||
var(--wa-border-radius-s)
|
||||
); /* min prevents entirely circular checkbox */
|
||||
border-style: var(--wa-border-style);
|
||||
border-width: var(--wa-form-control-border-width);
|
||||
background-color: var(--wa-form-control-background-color);
|
||||
transition:
|
||||
background var(--wa-transition-normal),
|
||||
border-color var(--wa-transition-fast),
|
||||
box-shadow var(--wa-transition-fast),
|
||||
color var(--wa-transition-fast);
|
||||
transition-timing-function: var(--wa-transition-easing);
|
||||
|
||||
margin-inline-end: 0.5em;
|
||||
}
|
||||
|
||||
[part~='base'] {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
color: currentColor;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
[part~='label'] {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* Checked */
|
||||
[part~='control']:has(:checked, :indeterminate) {
|
||||
color: var(--checked-icon-color);
|
||||
border-color: var(--wa-form-control-activated-color);
|
||||
background-color: var(--wa-form-control-activated-color);
|
||||
}
|
||||
|
||||
/* Focus */
|
||||
[part~='control']:has(> input:focus-visible:not(:disabled)) {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
:host [part~='base']:has(input:disabled) {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
input {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[part~='icon'] {
|
||||
display: flex;
|
||||
scale: var(--checked-icon-scale);
|
||||
|
||||
/* Without this, Safari renders the icon slightly to the left */
|
||||
&::part(svg) {
|
||||
translate: 0.0009765625em;
|
||||
}
|
||||
|
||||
input:not(:checked, :indeterminate) + & {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
:host([required]) [part~='label']::after {
|
||||
content: var(--wa-form-control-required-content);
|
||||
color: var(--wa-form-control-required-content-color);
|
||||
margin-inline-start: var(--wa-form-control-required-content-offset);
|
||||
}
|
||||
104
packages/webawesome/src/components/checkbox/checkbox.styles.ts
Normal file
104
packages/webawesome/src/components/checkbox/checkbox.styles.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--checked-icon-color: var(--wa-color-brand-on-loud);
|
||||
--checked-icon-scale: 0.8;
|
||||
|
||||
display: inline-flex;
|
||||
color: var(--wa-form-control-value-color);
|
||||
font-family: inherit;
|
||||
font-weight: var(--wa-form-control-value-font-weight);
|
||||
line-height: var(--wa-form-control-value-line-height);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
[part~='control'] {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--wa-form-control-toggle-size);
|
||||
height: var(--wa-form-control-toggle-size);
|
||||
border-color: var(--wa-form-control-border-color);
|
||||
border-radius: min(
|
||||
calc(var(--wa-form-control-toggle-size) * 0.375),
|
||||
var(--wa-border-radius-s)
|
||||
); /* min prevents entirely circular checkbox */
|
||||
border-style: var(--wa-border-style);
|
||||
border-width: var(--wa-form-control-border-width);
|
||||
background-color: var(--wa-form-control-background-color);
|
||||
transition:
|
||||
background var(--wa-transition-normal),
|
||||
border-color var(--wa-transition-fast),
|
||||
box-shadow var(--wa-transition-fast),
|
||||
color var(--wa-transition-fast);
|
||||
transition-timing-function: var(--wa-transition-easing);
|
||||
|
||||
margin-inline-end: 0.5em;
|
||||
}
|
||||
|
||||
[part~='base'] {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
color: currentColor;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
[part~='label'] {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* Checked */
|
||||
[part~='control']:has(:checked, :indeterminate) {
|
||||
color: var(--checked-icon-color);
|
||||
border-color: var(--wa-form-control-activated-color);
|
||||
background-color: var(--wa-form-control-activated-color);
|
||||
}
|
||||
|
||||
/* Focus */
|
||||
[part~='control']:has(> input:focus-visible:not(:disabled)) {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
:host [part~='base']:has(input:disabled) {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
input {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[part~='icon'] {
|
||||
display: flex;
|
||||
scale: var(--checked-icon-scale);
|
||||
|
||||
/* Without this, Safari renders the icon slightly to the left */
|
||||
&::part(svg) {
|
||||
translate: 0.0009765625em;
|
||||
}
|
||||
|
||||
input:not(:checked, :indeterminate) + & {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
:host([required]) [part~='label']::after {
|
||||
content: var(--wa-form-control-required-content);
|
||||
color: var(--wa-form-control-required-content-color);
|
||||
margin-inline-start: var(--wa-form-control-required-content-offset);
|
||||
}
|
||||
`;
|
||||
@@ -8,10 +8,10 @@ import { HasSlotController } from '../../internal/slot.js';
|
||||
import { RequiredValidator } from '../../internal/validators/required-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
|
||||
import formControlStyles from '../../styles/component/form-control.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import formControlStyles from '../../styles/component/form-control.styles.js';
|
||||
import sizeStyles from '../../styles/component/size.styles.js';
|
||||
import '../icon/icon.js';
|
||||
import styles from './checkbox.css';
|
||||
import styles from './checkbox.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Checkboxes allow the user to toggle an option on or off.
|
||||
@@ -108,13 +108,6 @@ export default class WaCheckbox extends WebAwesomeFormAssociatedElement {
|
||||
@property({ type: Boolean, reflect: true, attribute: 'checked' }) defaultChecked: boolean =
|
||||
this.hasAttribute('checked');
|
||||
|
||||
/**
|
||||
* By default, form controls are associated with the nearest containing `<form>` element. This attribute allows you
|
||||
* to place the form control outside of a form and associate it with the form that has this `id`. The form must be in
|
||||
* the same document or shadow root for this to work.
|
||||
*/
|
||||
@property({ reflect: true }) form = null;
|
||||
|
||||
/** Makes the checkbox a required field. */
|
||||
@property({ type: Boolean, reflect: true }) required = false;
|
||||
|
||||
|
||||
@@ -1,341 +0,0 @@
|
||||
:host {
|
||||
--grid-width: 17em;
|
||||
--grid-height: 12em;
|
||||
--grid-handle-size: 1.25em;
|
||||
--slider-height: 1em;
|
||||
--slider-handle-size: calc(var(--slider-height) + 0.25em);
|
||||
}
|
||||
|
||||
.color-picker {
|
||||
background-color: var(--wa-color-surface-raised);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
border-style: var(--wa-border-style);
|
||||
border-width: var(--wa-border-width-s);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
box-shadow: var(--wa-shadow-m);
|
||||
color: var(--color);
|
||||
font: inherit;
|
||||
font-size: inherit;
|
||||
user-select: none;
|
||||
width: var(--grid-width);
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.grid {
|
||||
position: relative;
|
||||
height: var(--grid-height);
|
||||
background-image:
|
||||
linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%),
|
||||
linear-gradient(to right, #fff 0%, rgba(255, 255, 255, 0) 100%);
|
||||
border-top-left-radius: calc(var(--wa-border-radius-m) - var(--wa-border-width-s));
|
||||
border-top-right-radius: calc(var(--wa-border-radius-m) - var(--wa-border-width-s));
|
||||
cursor: crosshair;
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.grid-handle {
|
||||
position: absolute;
|
||||
width: var(--grid-handle-size);
|
||||
height: var(--grid-handle-size);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
box-shadow: 0 0 0 0.0625rem rgba(0, 0, 0, 0.2);
|
||||
border: solid 0.125rem white;
|
||||
margin-top: calc(var(--grid-handle-size) / -2);
|
||||
margin-left: calc(var(--grid-handle-size) / -2);
|
||||
transition: scale var(--wa-transition-normal) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
.grid-handle-dragging {
|
||||
cursor: none;
|
||||
scale: 1.5;
|
||||
}
|
||||
|
||||
.grid-handle:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
}
|
||||
|
||||
.controls {
|
||||
padding: 0.75em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sliders {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: relative;
|
||||
height: var(--slider-height);
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
box-shadow: inset 0 0 0 0.0625rem rgba(0, 0, 0, 0.2);
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.slider:not(:last-of-type) {
|
||||
margin-bottom: 0.75em;
|
||||
}
|
||||
|
||||
.slider-handle {
|
||||
position: absolute;
|
||||
top: calc(50% - var(--slider-handle-size) / 2);
|
||||
width: var(--slider-handle-size);
|
||||
height: var(--slider-handle-size);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
border: solid 0.125rem white;
|
||||
box-shadow: 0 0 0 0.0625rem rgba(0, 0, 0, 0.2);
|
||||
margin-left: calc(var(--slider-handle-size) / -2);
|
||||
}
|
||||
|
||||
.slider-handle:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
}
|
||||
|
||||
.hue {
|
||||
background-image: linear-gradient(
|
||||
to right,
|
||||
rgb(255, 0, 0) 0%,
|
||||
rgb(255, 255, 0) 17%,
|
||||
rgb(0, 255, 0) 33%,
|
||||
rgb(0, 255, 255) 50%,
|
||||
rgb(0, 0, 255) 67%,
|
||||
rgb(255, 0, 255) 83%,
|
||||
rgb(255, 0, 0) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.alpha .alpha-gradient {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.preview {
|
||||
flex: 0 0 auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
border: none;
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
background: none;
|
||||
font-size: inherit;
|
||||
margin-inline-start: 0.75em;
|
||||
cursor: copy;
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.preview:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
box-shadow: inset 0 0 0 0.0625rem rgba(0, 0, 0, 0.2);
|
||||
|
||||
/* We use a custom property in lieu of currentColor because of https://bugs.webkit.org/show_bug.cgi?id=216780 */
|
||||
background-color: var(--preview-color);
|
||||
}
|
||||
|
||||
.preview:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
.preview-color {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: solid 0.0625rem rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
.preview-color-copied {
|
||||
animation: pulse 850ms;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 var(--wa-color-brand-fill-loud);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 0.5rem transparent;
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.user-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.75em 0.75em 0.75em;
|
||||
}
|
||||
|
||||
.user-input wa-input {
|
||||
min-width: 0; /* fix input width in Safari */
|
||||
flex: 1 1 auto;
|
||||
|
||||
&::part(form-control-label) {
|
||||
/* Visually hidden */
|
||||
position: absolute !important;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
clip: rect(0 0 0 0) !important;
|
||||
clip-path: inset(50%) !important;
|
||||
border: none !important;
|
||||
overflow: hidden !important;
|
||||
white-space: nowrap !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.user-input wa-button-group {
|
||||
margin-inline-start: 0.75em;
|
||||
|
||||
&::part(base) {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.user-input wa-button:first-of-type {
|
||||
min-width: 3em;
|
||||
max-width: 3em;
|
||||
}
|
||||
|
||||
.swatches {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(1.5em, 100%), 1fr));
|
||||
grid-gap: 0.5em;
|
||||
justify-items: center;
|
||||
border-block-start: var(--wa-form-control-border-style) var(--wa-form-control-border-width)
|
||||
var(--wa-color-surface-border);
|
||||
padding: 0.5em;
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.swatch {
|
||||
position: relative;
|
||||
aspect-ratio: 1 / 1;
|
||||
width: 100%;
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
}
|
||||
|
||||
.swatch .swatch-color {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: solid 0.0625rem rgba(0, 0, 0, 0.125);
|
||||
border-radius: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.swatch:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
.transparent-bg {
|
||||
background-image:
|
||||
linear-gradient(45deg, var(--wa-color-neutral-fill-normal) 25%, transparent 25%),
|
||||
linear-gradient(45deg, transparent 75%, var(--wa-color-neutral-fill-normal) 75%),
|
||||
linear-gradient(45deg, transparent 75%, var(--wa-color-neutral-fill-normal) 75%),
|
||||
linear-gradient(45deg, var(--wa-color-neutral-fill-normal) 25%, transparent 25%);
|
||||
background-size: 0.5rem 0.5rem;
|
||||
background-position:
|
||||
0 0,
|
||||
0 0,
|
||||
-0.25rem -0.25rem,
|
||||
0.25rem 0.25rem;
|
||||
}
|
||||
|
||||
:host([disabled]) {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
|
||||
.grid,
|
||||
.grid-handle,
|
||||
.slider,
|
||||
.slider-handle,
|
||||
.preview,
|
||||
.swatch,
|
||||
.swatch-color {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Color dropdown
|
||||
*/
|
||||
|
||||
.color-dropdown {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.color-dropdown::part(panel) {
|
||||
max-height: none;
|
||||
background-color: var(--wa-color-surface-raised);
|
||||
border: var(--wa-border-style) var(--wa-border-width-s) var(--wa-color-surface-border);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.trigger {
|
||||
display: block;
|
||||
position: relative;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: inherit;
|
||||
forced-color-adjust: none;
|
||||
width: var(--wa-form-control-height);
|
||||
height: var(--wa-form-control-height);
|
||||
border-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
.trigger:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
background-color: currentColor;
|
||||
box-shadow:
|
||||
inset 0 0 0 var(--wa-form-control-border-width) var(--wa-form-control-border-color),
|
||||
inset 0 0 0 calc(var(--wa-form-control-border-width) * 3) var(--wa-color-surface-default);
|
||||
}
|
||||
|
||||
.trigger-empty:before {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.trigger:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.trigger:focus-visible:not(.trigger:disabled) {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
:host([disabled]) :is(.label, .trigger) {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.form-control.form-control-has-label .label {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--grid-width: 17em;
|
||||
--grid-height: 12em;
|
||||
--grid-handle-size: 1.25em;
|
||||
--slider-height: 1em;
|
||||
--slider-handle-size: calc(var(--slider-height) + 0.25em);
|
||||
}
|
||||
|
||||
.color-picker {
|
||||
background-color: var(--wa-color-surface-raised);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
border-style: var(--wa-border-style);
|
||||
border-width: var(--wa-border-width-s);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
box-shadow: var(--wa-shadow-m);
|
||||
color: var(--color);
|
||||
font: inherit;
|
||||
font-size: inherit;
|
||||
user-select: none;
|
||||
width: var(--grid-width);
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.grid {
|
||||
position: relative;
|
||||
height: var(--grid-height);
|
||||
background-image:
|
||||
linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%),
|
||||
linear-gradient(to right, #fff 0%, rgba(255, 255, 255, 0) 100%);
|
||||
border-top-left-radius: calc(var(--wa-border-radius-m) - var(--wa-border-width-s));
|
||||
border-top-right-radius: calc(var(--wa-border-radius-m) - var(--wa-border-width-s));
|
||||
cursor: crosshair;
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.grid-handle {
|
||||
position: absolute;
|
||||
width: var(--grid-handle-size);
|
||||
height: var(--grid-handle-size);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
box-shadow: 0 0 0 0.0625rem rgba(0, 0, 0, 0.2);
|
||||
border: solid 0.125rem white;
|
||||
margin-top: calc(var(--grid-handle-size) / -2);
|
||||
margin-left: calc(var(--grid-handle-size) / -2);
|
||||
transition: scale var(--wa-transition-normal) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
.grid-handle-dragging {
|
||||
cursor: none;
|
||||
scale: 1.5;
|
||||
}
|
||||
|
||||
.grid-handle:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
}
|
||||
|
||||
.controls {
|
||||
padding: 0.75em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sliders {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: relative;
|
||||
height: var(--slider-height);
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
box-shadow: inset 0 0 0 0.0625rem rgba(0, 0, 0, 0.2);
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.slider:not(:last-of-type) {
|
||||
margin-bottom: 0.75em;
|
||||
}
|
||||
|
||||
.slider-handle {
|
||||
position: absolute;
|
||||
top: calc(50% - var(--slider-handle-size) / 2);
|
||||
width: var(--slider-handle-size);
|
||||
height: var(--slider-handle-size);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
border: solid 0.125rem white;
|
||||
box-shadow: 0 0 0 0.0625rem rgba(0, 0, 0, 0.2);
|
||||
margin-left: calc(var(--slider-handle-size) / -2);
|
||||
}
|
||||
|
||||
.slider-handle:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
}
|
||||
|
||||
.hue {
|
||||
background-image: linear-gradient(
|
||||
to right,
|
||||
rgb(255, 0, 0) 0%,
|
||||
rgb(255, 255, 0) 17%,
|
||||
rgb(0, 255, 0) 33%,
|
||||
rgb(0, 255, 255) 50%,
|
||||
rgb(0, 0, 255) 67%,
|
||||
rgb(255, 0, 255) 83%,
|
||||
rgb(255, 0, 0) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.alpha .alpha-gradient {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.preview {
|
||||
flex: 0 0 auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
border: none;
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
background: none;
|
||||
font-size: inherit;
|
||||
margin-inline-start: 0.75em;
|
||||
cursor: copy;
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.preview:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
box-shadow: inset 0 0 0 0.0625rem rgba(0, 0, 0, 0.2);
|
||||
|
||||
/* We use a custom property in lieu of currentColor because of https://bugs.webkit.org/show_bug.cgi?id=216780 */
|
||||
background-color: var(--preview-color);
|
||||
}
|
||||
|
||||
.preview:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
.preview-color {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: solid 0.0625rem rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
.preview-color-copied {
|
||||
animation: pulse 850ms;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 var(--wa-color-brand-fill-loud);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 0.5rem transparent;
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.user-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.75em 0.75em 0.75em;
|
||||
}
|
||||
|
||||
.user-input wa-input {
|
||||
min-width: 0; /* fix input width in Safari */
|
||||
flex: 1 1 auto;
|
||||
|
||||
&::part(form-control-label) {
|
||||
/* Visually hidden */
|
||||
position: absolute !important;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
clip: rect(0 0 0 0) !important;
|
||||
clip-path: inset(50%) !important;
|
||||
border: none !important;
|
||||
overflow: hidden !important;
|
||||
white-space: nowrap !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.user-input wa-button-group {
|
||||
margin-inline-start: 0.75em;
|
||||
|
||||
&::part(base) {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.user-input wa-button:first-of-type {
|
||||
min-width: 3em;
|
||||
max-width: 3em;
|
||||
}
|
||||
|
||||
.swatches {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(1.5em, 100%), 1fr));
|
||||
grid-gap: 0.5em;
|
||||
justify-items: center;
|
||||
border-block-start: var(--wa-form-control-border-style) var(--wa-form-control-border-width)
|
||||
var(--wa-color-surface-border);
|
||||
padding: 0.5em;
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.swatch {
|
||||
position: relative;
|
||||
aspect-ratio: 1 / 1;
|
||||
width: 100%;
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
}
|
||||
|
||||
.swatch .swatch-color {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: solid 0.0625rem rgba(0, 0, 0, 0.125);
|
||||
border-radius: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.swatch:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
.transparent-bg {
|
||||
background-image:
|
||||
linear-gradient(45deg, var(--wa-color-neutral-fill-normal) 25%, transparent 25%),
|
||||
linear-gradient(45deg, transparent 75%, var(--wa-color-neutral-fill-normal) 75%),
|
||||
linear-gradient(45deg, transparent 75%, var(--wa-color-neutral-fill-normal) 75%),
|
||||
linear-gradient(45deg, var(--wa-color-neutral-fill-normal) 25%, transparent 25%);
|
||||
background-size: 0.5rem 0.5rem;
|
||||
background-position:
|
||||
0 0,
|
||||
0 0,
|
||||
-0.25rem -0.25rem,
|
||||
0.25rem 0.25rem;
|
||||
}
|
||||
|
||||
:host([disabled]) {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
|
||||
.grid,
|
||||
.grid-handle,
|
||||
.slider,
|
||||
.slider-handle,
|
||||
.preview,
|
||||
.swatch,
|
||||
.swatch-color {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Color dropdown
|
||||
*/
|
||||
|
||||
.color-dropdown {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.color-dropdown::part(panel) {
|
||||
max-height: none;
|
||||
background-color: var(--wa-color-surface-raised);
|
||||
border: var(--wa-border-style) var(--wa-border-width-s) var(--wa-color-surface-border);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.trigger {
|
||||
display: block;
|
||||
position: relative;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: inherit;
|
||||
forced-color-adjust: none;
|
||||
width: var(--wa-form-control-height);
|
||||
height: var(--wa-form-control-height);
|
||||
border-radius: var(--wa-form-control-border-radius);
|
||||
}
|
||||
|
||||
.trigger:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
background-color: currentColor;
|
||||
box-shadow:
|
||||
inset 0 0 0 var(--wa-form-control-border-width) var(--wa-form-control-border-color),
|
||||
inset 0 0 0 calc(var(--wa-form-control-border-width) * 3) var(--wa-color-surface-default);
|
||||
}
|
||||
|
||||
.trigger-empty:before {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.trigger:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.trigger:focus-visible:not(.trigger:disabled) {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
:host([disabled]) :is(.label, .trigger) {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.form-control.form-control-has-label .label {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
`;
|
||||
@@ -14,9 +14,9 @@ import { HasSlotController } from '../../internal/slot.js';
|
||||
import { RequiredValidator } from '../../internal/validators/required-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
|
||||
import formControlStyles from '../../styles/component/form-control.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import visuallyHidden from '../../styles/utilities/visually-hidden.css';
|
||||
import formControlStyles from '../../styles/component/form-control.styles.js';
|
||||
import sizeStyles from '../../styles/component/size.styles.js';
|
||||
import visuallyHidden from '../../styles/component/visually-hidden.styles.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import '../button-group/button-group.js';
|
||||
import '../button/button.js';
|
||||
@@ -25,7 +25,7 @@ import '../input/input.js';
|
||||
import type WaInput from '../input/input.js';
|
||||
import '../popup/popup.js';
|
||||
import type WaPopup from '../popup/popup.js';
|
||||
import styles from './color-picker.css';
|
||||
import styles from './color-picker.styles.js';
|
||||
|
||||
interface EyeDropperConstructor {
|
||||
new (): EyeDropperInterface;
|
||||
@@ -220,13 +220,6 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
|
||||
*/
|
||||
@property() swatches: string | string[] = '';
|
||||
|
||||
/**
|
||||
* By default, form controls are associated with the nearest containing `<form>` element. This attribute allows you
|
||||
* to place the form control outside of a form and associate it with the form that has this `id`. The form must be in
|
||||
* the same document or shadow root for this to work.
|
||||
*/
|
||||
@property({ reflect: true }) form = null;
|
||||
|
||||
/** Makes the color picker a required field. */
|
||||
@property({ type: Boolean, reflect: true }) required = false;
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
:host {
|
||||
--divider-width: 0.125rem;
|
||||
--handle-size: 2.5rem;
|
||||
|
||||
display: block;
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.before,
|
||||
.after {
|
||||
display: block;
|
||||
|
||||
&::slotted(img),
|
||||
&::slotted(svg) {
|
||||
display: block;
|
||||
max-width: 100% !important;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&::slotted(:not(img, svg)) {
|
||||
isolation: isolate;
|
||||
}
|
||||
}
|
||||
|
||||
.after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Disable pointer-events while dragging. This is especially important for iframes. */
|
||||
:host(:state(dragging)) {
|
||||
.before,
|
||||
.after {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: var(--divider-width);
|
||||
height: 100%;
|
||||
background-color: var(--wa-color-surface-default);
|
||||
translate: calc(var(--divider-width) / -2);
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
.handle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: calc(50% - (var(--handle-size) / 2));
|
||||
width: var(--handle-size);
|
||||
height: var(--handle-size);
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
font-size: calc(var(--handle-size) * 0.4);
|
||||
color: var(--wa-color-neutral-on-quiet);
|
||||
cursor: inherit;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.handle:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--divider-width: 0.125rem;
|
||||
--handle-size: 2.5rem;
|
||||
|
||||
display: block;
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.before,
|
||||
.after {
|
||||
display: block;
|
||||
|
||||
&::slotted(img),
|
||||
&::slotted(svg) {
|
||||
display: block;
|
||||
max-width: 100% !important;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&::slotted(:not(img, svg)) {
|
||||
isolation: isolate;
|
||||
}
|
||||
}
|
||||
|
||||
.after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Disable pointer-events while dragging. This is especially important for iframes. */
|
||||
:host(:state(dragging)) {
|
||||
.before,
|
||||
.after {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: var(--divider-width);
|
||||
height: 100%;
|
||||
background-color: var(--wa-color-surface-default);
|
||||
translate: calc(var(--divider-width) / -2);
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
.handle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: calc(50% - (var(--handle-size) / 2));
|
||||
width: var(--handle-size);
|
||||
height: var(--handle-size);
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
font-size: calc(var(--handle-size) * 0.4);
|
||||
color: var(--wa-color-neutral-on-quiet);
|
||||
cursor: inherit;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.handle:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
`;
|
||||
@@ -7,7 +7,7 @@ import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import '../icon/icon.js';
|
||||
import styles from './comparison.css';
|
||||
import styles from './comparison.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Compare visual differences between similar content with a sliding panel.
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
:host {
|
||||
display: inline-block;
|
||||
color: var(--wa-color-neutral-on-quiet);
|
||||
}
|
||||
|
||||
.button {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: var(--wa-form-control-border-radius);
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
padding: 0.5em;
|
||||
cursor: pointer;
|
||||
transition: color var(--wa-transition-fast) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.button:hover:not([disabled]) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover));
|
||||
}
|
||||
}
|
||||
|
||||
.button:focus-visible:not([disabled]) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover));
|
||||
}
|
||||
|
||||
.button:active:not([disabled]) {
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-active));
|
||||
}
|
||||
|
||||
slot[name='success-icon'] {
|
||||
color: var(--wa-color-success-on-quiet);
|
||||
}
|
||||
|
||||
slot[name='error-icon'] {
|
||||
color: var(--wa-color-danger-on-quiet);
|
||||
}
|
||||
|
||||
.button:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
.button[disabled] {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
slot {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.show {
|
||||
animation: show 100ms ease;
|
||||
}
|
||||
|
||||
.hide {
|
||||
animation: show 100ms ease reverse;
|
||||
}
|
||||
|
||||
@keyframes show {
|
||||
from {
|
||||
scale: 0.25;
|
||||
opacity: 0.25;
|
||||
}
|
||||
to {
|
||||
scale: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
display: inline-block;
|
||||
color: var(--wa-color-neutral-on-quiet);
|
||||
}
|
||||
|
||||
.button {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: var(--wa-form-control-border-radius);
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
padding: 0.5em;
|
||||
cursor: pointer;
|
||||
transition: color var(--wa-transition-fast) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.button:hover:not([disabled]) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover));
|
||||
}
|
||||
}
|
||||
|
||||
.button:focus-visible:not([disabled]) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover));
|
||||
}
|
||||
|
||||
.button:active:not([disabled]) {
|
||||
color: color-mix(in oklab, currentColor, var(--wa-color-mix-active));
|
||||
}
|
||||
|
||||
slot[name='success-icon'] {
|
||||
color: var(--wa-color-success-on-quiet);
|
||||
}
|
||||
|
||||
slot[name='error-icon'] {
|
||||
color: var(--wa-color-danger-on-quiet);
|
||||
}
|
||||
|
||||
.button:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
|
||||
.button[disabled] {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
slot {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.show {
|
||||
animation: show 100ms ease;
|
||||
}
|
||||
|
||||
.hide {
|
||||
animation: show 100ms ease reverse;
|
||||
}
|
||||
|
||||
@keyframes show {
|
||||
from {
|
||||
scale: 0.25;
|
||||
opacity: 0.25;
|
||||
}
|
||||
to {
|
||||
scale: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -5,12 +5,12 @@ import { WaCopyEvent } from '../../events/copy.js';
|
||||
import { WaErrorEvent } from '../../events/error.js';
|
||||
import { animateWithClass } from '../../internal/animate.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import visuallyHidden from '../../styles/utilities/visually-hidden.css';
|
||||
import visuallyHidden from '../../styles/component/visually-hidden.styles.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import '../icon/icon.js';
|
||||
import '../tooltip/tooltip.js';
|
||||
import type WaTooltip from '../tooltip/tooltip.js';
|
||||
import styles from './copy-button.css';
|
||||
import styles from './copy-button.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Copies text data to the clipboard when the user clicks the trigger.
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
:host {
|
||||
--spacing: var(--wa-space-m);
|
||||
--show-duration: 200ms;
|
||||
--hide-duration: 200ms;
|
||||
|
||||
display: block;
|
||||
}
|
||||
|
||||
details {
|
||||
display: block;
|
||||
overflow-anchor: none;
|
||||
border: var(--wa-panel-border-width) var(--wa-color-surface-border) var(--wa-panel-border-style);
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
color: var(--wa-color-text-normal);
|
||||
|
||||
/* Print styles */
|
||||
@media print {
|
||||
background: none;
|
||||
border: solid var(--wa-border-width-s) var(--wa-color-surface-border);
|
||||
|
||||
summary {
|
||||
list-style: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance='plain']) details {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
:host([appearance='outlined']) details {
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
}
|
||||
|
||||
:host([appearance='filled']) details {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance='filled-outlined']) details {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
border-color: var(--wa-color-neutral-border-quiet);
|
||||
}
|
||||
|
||||
:host([disabled]) details {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing);
|
||||
padding: var(--spacing); /* Add padding here */
|
||||
border-radius: calc(var(--wa-panel-border-radius) - var(--wa-panel-border-width));
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
cursor: pointer;
|
||||
|
||||
&::marker,
|
||||
&::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: calc(var(--wa-panel-border-width) + var(--wa-focus-ring-offset));
|
||||
}
|
||||
}
|
||||
|
||||
:host([open]) summary {
|
||||
border-end-start-radius: 0;
|
||||
border-end-end-radius: 0;
|
||||
}
|
||||
|
||||
/* 'Start' icon placement */
|
||||
:host([icon-placement='start']) summary {
|
||||
flex-direction: row-reverse;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
[part~='icon'] {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--wa-color-text-quiet);
|
||||
transition: rotate var(--wa-transition-normal) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
:host([open]) [part~='icon'] {
|
||||
rotate: 90deg;
|
||||
}
|
||||
|
||||
:host([open]:dir(rtl)) [part~='icon'] {
|
||||
rotate: -90deg;
|
||||
}
|
||||
|
||||
:host([open]) slot[name='expand-icon'],
|
||||
:host(:not([open])) slot[name='collapse-icon'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.body.animating {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: block;
|
||||
padding-block-start: var(--spacing);
|
||||
padding-inline: var(--spacing); /* Add horizontal padding */
|
||||
padding-block-end: var(--spacing); /* Add bottom padding */
|
||||
}
|
||||
126
packages/webawesome/src/components/details/details.styles.ts
Normal file
126
packages/webawesome/src/components/details/details.styles.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--spacing: var(--wa-space-m);
|
||||
--show-duration: 200ms;
|
||||
--hide-duration: 200ms;
|
||||
|
||||
display: block;
|
||||
}
|
||||
|
||||
details {
|
||||
display: block;
|
||||
overflow-anchor: none;
|
||||
border: var(--wa-panel-border-width) var(--wa-color-surface-border) var(--wa-panel-border-style);
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
color: var(--wa-color-text-normal);
|
||||
|
||||
/* Print styles */
|
||||
@media print {
|
||||
background: none;
|
||||
border: solid var(--wa-border-width-s) var(--wa-color-surface-border);
|
||||
|
||||
summary {
|
||||
list-style: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Appearance modifiers */
|
||||
:host([appearance='plain']) details {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
:host([appearance='outlined']) details {
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
}
|
||||
|
||||
:host([appearance='filled']) details {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
:host([appearance='filled-outlined']) details {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
border-color: var(--wa-color-neutral-border-quiet);
|
||||
}
|
||||
|
||||
:host([disabled]) details {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing);
|
||||
padding: var(--spacing); /* Add padding here */
|
||||
border-radius: calc(var(--wa-panel-border-radius) - var(--wa-panel-border-width));
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
cursor: pointer;
|
||||
|
||||
&::marker,
|
||||
&::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: calc(var(--wa-panel-border-width) + var(--wa-focus-ring-offset));
|
||||
}
|
||||
}
|
||||
|
||||
:host([open]) summary {
|
||||
border-end-start-radius: 0;
|
||||
border-end-end-radius: 0;
|
||||
}
|
||||
|
||||
/* 'Start' icon placement */
|
||||
:host([icon-placement='start']) summary {
|
||||
flex-direction: row-reverse;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
[part~='icon'] {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--wa-color-text-quiet);
|
||||
transition: rotate var(--wa-transition-normal) var(--wa-transition-easing);
|
||||
}
|
||||
|
||||
:host([open]) [part~='icon'] {
|
||||
rotate: 90deg;
|
||||
}
|
||||
|
||||
:host([open]:dir(rtl)) [part~='icon'] {
|
||||
rotate: -90deg;
|
||||
}
|
||||
|
||||
:host([open]) slot[name='expand-icon'],
|
||||
:host(:not([open])) slot[name='collapse-icon'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.body.animating {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: block;
|
||||
padding-block-start: var(--spacing);
|
||||
padding-inline: var(--spacing); /* Add horizontal padding */
|
||||
padding-block-end: var(--spacing); /* Add bottom padding */
|
||||
}
|
||||
`;
|
||||
@@ -13,7 +13,7 @@ import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import '../icon/icon.js';
|
||||
import styles from './details.css';
|
||||
import styles from './details.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Details show a brief summary and expand to show additional content.
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
:host {
|
||||
--width: 31rem;
|
||||
--spacing: var(--wa-space-l);
|
||||
--show-duration: 200ms;
|
||||
--hide-duration: 200ms;
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host([open]) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: var(--width);
|
||||
max-width: calc(100% - var(--wa-space-2xl));
|
||||
max-height: calc(100% - var(--wa-space-2xl));
|
||||
background-color: var(--wa-color-surface-raised);
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
border: none;
|
||||
box-shadow: var(--wa-shadow-l);
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
|
||||
&.show {
|
||||
animation: show-dialog var(--show-duration) ease;
|
||||
|
||||
&::backdrop {
|
||||
animation: show-backdrop var(--show-duration, 200ms) ease;
|
||||
}
|
||||
}
|
||||
|
||||
&.hide {
|
||||
animation: show-dialog var(--hide-duration) ease reverse;
|
||||
|
||||
&::backdrop {
|
||||
animation: show-backdrop var(--hide-duration, 200ms) ease reverse;
|
||||
}
|
||||
}
|
||||
|
||||
&.pulse {
|
||||
animation: pulse 250ms ease;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Ensure there's enough vertical padding for phones that don't update vh when chrome appears (e.g. iPhone) */
|
||||
@media screen and (max-width: 420px) {
|
||||
.dialog {
|
||||
max-height: 80vh;
|
||||
}
|
||||
}
|
||||
|
||||
.open {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
padding-inline-start: var(--spacing);
|
||||
padding-block-end: 0;
|
||||
|
||||
/* Subtract the close button's padding so that the X is visually aligned with the edges of the dialog content */
|
||||
padding-inline-end: calc(var(--spacing) - var(--wa-form-control-padding-block));
|
||||
padding-block-start: calc(var(--spacing) - var(--wa-form-control-padding-block));
|
||||
}
|
||||
|
||||
.title {
|
||||
align-self: center;
|
||||
flex: 1 1 auto;
|
||||
font-family: inherit;
|
||||
font-size: var(--wa-font-size-l);
|
||||
font-weight: var(--wa-font-weight-heading);
|
||||
line-height: var(--wa-line-height-condensed);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
align-self: start;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
justify-content: end;
|
||||
gap: var(--wa-space-2xs);
|
||||
padding-inline-start: var(--spacing);
|
||||
}
|
||||
|
||||
.header-actions wa-button,
|
||||
.header-actions ::slotted(wa-button) {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1 1 auto;
|
||||
display: block;
|
||||
padding: var(--spacing);
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--wa-space-xs);
|
||||
justify-content: end;
|
||||
padding: var(--spacing);
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
.footer ::slotted(wa-button:not(:first-of-type)) {
|
||||
margin-inline-start: var(--wa-spacing-xs);
|
||||
}
|
||||
|
||||
.dialog::backdrop {
|
||||
/*
|
||||
NOTE: the ::backdrop element doesn't inherit properly in Safari yet, but it will in 17.4! At that time, we can
|
||||
remove the fallback values here.
|
||||
*/
|
||||
background-color: var(--wa-color-overlay-modal, rgb(0 0 0 / 0.25));
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
scale: 1;
|
||||
}
|
||||
50% {
|
||||
scale: 1.02;
|
||||
}
|
||||
100% {
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-dialog {
|
||||
from {
|
||||
opacity: 0;
|
||||
scale: 0.8;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-backdrop {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.dialog {
|
||||
border: solid 1px white;
|
||||
}
|
||||
}
|
||||
187
packages/webawesome/src/components/dialog/dialog.styles.ts
Normal file
187
packages/webawesome/src/components/dialog/dialog.styles.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--width: 31rem;
|
||||
--spacing: var(--wa-space-l);
|
||||
--show-duration: 200ms;
|
||||
--hide-duration: 200ms;
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host([open]) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: var(--width);
|
||||
max-width: calc(100% - var(--wa-space-2xl));
|
||||
max-height: calc(100% - var(--wa-space-2xl));
|
||||
background-color: var(--wa-color-surface-raised);
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
border: none;
|
||||
box-shadow: var(--wa-shadow-l);
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
|
||||
&.show {
|
||||
animation: show-dialog var(--show-duration) ease;
|
||||
|
||||
&::backdrop {
|
||||
animation: show-backdrop var(--show-duration, 200ms) ease;
|
||||
}
|
||||
}
|
||||
|
||||
&.hide {
|
||||
animation: show-dialog var(--hide-duration) ease reverse;
|
||||
|
||||
&::backdrop {
|
||||
animation: show-backdrop var(--hide-duration, 200ms) ease reverse;
|
||||
}
|
||||
}
|
||||
|
||||
&.pulse {
|
||||
animation: pulse 250ms ease;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Ensure there's enough vertical padding for phones that don't update vh when chrome appears (e.g. iPhone) */
|
||||
@media screen and (max-width: 420px) {
|
||||
.dialog {
|
||||
max-height: 80vh;
|
||||
}
|
||||
}
|
||||
|
||||
.open {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
padding-inline-start: var(--spacing);
|
||||
padding-block-end: 0;
|
||||
|
||||
/* Subtract the close button's padding so that the X is visually aligned with the edges of the dialog content */
|
||||
padding-inline-end: calc(var(--spacing) - var(--wa-form-control-padding-block));
|
||||
padding-block-start: calc(var(--spacing) - var(--wa-form-control-padding-block));
|
||||
}
|
||||
|
||||
.title {
|
||||
align-self: center;
|
||||
flex: 1 1 auto;
|
||||
font-family: inherit;
|
||||
font-size: var(--wa-font-size-l);
|
||||
font-weight: var(--wa-font-weight-heading);
|
||||
line-height: var(--wa-line-height-condensed);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
align-self: start;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
justify-content: end;
|
||||
gap: var(--wa-space-2xs);
|
||||
padding-inline-start: var(--spacing);
|
||||
}
|
||||
|
||||
.header-actions wa-button,
|
||||
.header-actions ::slotted(wa-button) {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1 1 auto;
|
||||
display: block;
|
||||
padding: var(--spacing);
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--wa-space-xs);
|
||||
justify-content: end;
|
||||
padding: var(--spacing);
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
.footer ::slotted(wa-button:not(:first-of-type)) {
|
||||
margin-inline-start: var(--wa-spacing-xs);
|
||||
}
|
||||
|
||||
.dialog::backdrop {
|
||||
/*
|
||||
NOTE: the ::backdrop element doesn't inherit properly in Safari yet, but it will in 17.4! At that time, we can
|
||||
remove the fallback values here.
|
||||
*/
|
||||
background-color: var(--wa-color-overlay-modal, rgb(0 0 0 / 0.25));
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
scale: 1;
|
||||
}
|
||||
50% {
|
||||
scale: 1.02;
|
||||
}
|
||||
100% {
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-dialog {
|
||||
from {
|
||||
opacity: 0;
|
||||
scale: 0.8;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-backdrop {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.dialog {
|
||||
border: solid 1px white;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -13,7 +13,7 @@ import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import '../button/button.js';
|
||||
import styles from './dialog.css';
|
||||
import styles from './dialog.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Dialogs, sometimes called "modals", appear above the page and require the user's immediate attention.
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
:host {
|
||||
--color: var(--wa-color-surface-border);
|
||||
--width: var(--wa-border-width-s);
|
||||
--spacing: var(--wa-space-m);
|
||||
}
|
||||
|
||||
:host(:not([orientation='vertical'])) {
|
||||
display: block;
|
||||
border-top: solid var(--width) var(--color);
|
||||
margin: var(--spacing) 0;
|
||||
}
|
||||
|
||||
:host([orientation='vertical']) {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
border-inline-start: solid var(--width) var(--color);
|
||||
margin: 0 var(--spacing);
|
||||
min-block-size: 1lh;
|
||||
}
|
||||
23
packages/webawesome/src/components/divider/divider.styles.ts
Normal file
23
packages/webawesome/src/components/divider/divider.styles.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--color: var(--wa-color-surface-border);
|
||||
--width: var(--wa-border-width-s);
|
||||
--spacing: var(--wa-space-m);
|
||||
}
|
||||
|
||||
:host(:not([orientation='vertical'])) {
|
||||
display: block;
|
||||
border-top: solid var(--width) var(--color);
|
||||
margin: var(--spacing) 0;
|
||||
}
|
||||
|
||||
:host([orientation='vertical']) {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
border-inline-start: solid var(--width) var(--color);
|
||||
margin: 0 var(--spacing);
|
||||
min-block-size: 1lh;
|
||||
}
|
||||
`;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import styles from './divider.css';
|
||||
import styles from './divider.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Dividers are used to visually separate or group elements.
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
:host {
|
||||
--size: 25rem;
|
||||
--spacing: var(--wa-space-l);
|
||||
--show-duration: 200ms;
|
||||
--hide-duration: 200ms;
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host([open]) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.drawer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: var(--wa-color-surface-raised);
|
||||
border: none;
|
||||
box-shadow: var(--wa-shadow-l);
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
animation-duration: var(--show-duration);
|
||||
animation-timing-function: ease;
|
||||
|
||||
&.show::backdrop {
|
||||
animation: show-backdrop var(--show-duration, 200ms) ease;
|
||||
}
|
||||
|
||||
&.hide::backdrop {
|
||||
animation: show-backdrop var(--hide-duration, 200ms) ease reverse;
|
||||
}
|
||||
|
||||
&.show.top {
|
||||
animation: show-drawer-from-top var(--show-duration) ease;
|
||||
}
|
||||
|
||||
&.hide.top {
|
||||
animation: show-drawer-from-top var(--hide-duration) ease reverse;
|
||||
}
|
||||
|
||||
&.show.end {
|
||||
animation: show-drawer-from-end var(--show-duration) ease;
|
||||
|
||||
&:dir(rtl) {
|
||||
animation-name: show-drawer-from-start;
|
||||
}
|
||||
}
|
||||
|
||||
&.hide.end {
|
||||
animation: show-drawer-from-end var(--hide-duration) ease reverse;
|
||||
|
||||
&:dir(rtl) {
|
||||
animation-name: show-drawer-from-start;
|
||||
}
|
||||
}
|
||||
|
||||
&.show.bottom {
|
||||
animation: show-drawer-from-bottom var(--show-duration) ease;
|
||||
}
|
||||
|
||||
&.hide.bottom {
|
||||
animation: show-drawer-from-bottom var(--hide-duration) ease reverse;
|
||||
}
|
||||
|
||||
&.show.start {
|
||||
animation: show-drawer-from-start var(--show-duration) ease;
|
||||
|
||||
&:dir(rtl) {
|
||||
animation-name: show-drawer-from-end;
|
||||
}
|
||||
}
|
||||
|
||||
&.hide.start {
|
||||
animation: show-drawer-from-start var(--hide-duration) ease reverse;
|
||||
|
||||
&:dir(rtl) {
|
||||
animation-name: show-drawer-from-end;
|
||||
}
|
||||
}
|
||||
|
||||
&.pulse {
|
||||
animation: pulse 250ms ease;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.top {
|
||||
top: 0;
|
||||
inset-inline-end: auto;
|
||||
bottom: auto;
|
||||
inset-inline-start: 0;
|
||||
width: 100%;
|
||||
height: var(--size);
|
||||
}
|
||||
|
||||
.end {
|
||||
top: 0;
|
||||
inset-inline-end: 0;
|
||||
bottom: auto;
|
||||
inset-inline-start: auto;
|
||||
width: var(--size);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
top: auto;
|
||||
inset-inline-end: auto;
|
||||
bottom: 0;
|
||||
inset-inline-start: 0;
|
||||
width: 100%;
|
||||
height: var(--size);
|
||||
}
|
||||
|
||||
.start {
|
||||
top: 0;
|
||||
inset-inline-end: auto;
|
||||
bottom: auto;
|
||||
inset-inline-start: 0;
|
||||
width: var(--size);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
padding-inline-start: var(--spacing);
|
||||
padding-block-end: 0;
|
||||
|
||||
/* Subtract the close button's padding so that the X is visually aligned with the edges of the dialog content */
|
||||
padding-inline-end: calc(var(--spacing) - var(--wa-form-control-padding-block));
|
||||
padding-block-start: calc(var(--spacing) - var(--wa-form-control-padding-block));
|
||||
}
|
||||
|
||||
.title {
|
||||
align-self: center;
|
||||
flex: 1 1 auto;
|
||||
font: inherit;
|
||||
font-size: var(--wa-font-size-l);
|
||||
font-weight: var(--wa-font-weight-heading);
|
||||
line-height: var(--wa-line-height-condensed);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
align-self: start;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
justify-content: end;
|
||||
gap: var(--wa-space-2xs);
|
||||
padding-inline-start: var(--spacing);
|
||||
}
|
||||
|
||||
.header-actions wa-button,
|
||||
.header-actions ::slotted(wa-button) {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1 1 auto;
|
||||
display: block;
|
||||
padding: var(--spacing);
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--wa-space-xs);
|
||||
justify-content: end;
|
||||
padding: var(--spacing);
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
.footer ::slotted(wa-button:not(:last-of-type)) {
|
||||
margin-inline-end: var(--wa-spacing-xs);
|
||||
}
|
||||
|
||||
.drawer::backdrop {
|
||||
/*
|
||||
NOTE: the ::backdrop element doesn't inherit properly in Safari yet, but it will in 17.4! At that time, we can
|
||||
remove the fallback values here.
|
||||
*/
|
||||
background-color: var(--wa-color-overlay-modal, rgb(0 0 0 / 0.25));
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
scale: 1;
|
||||
}
|
||||
50% {
|
||||
scale: 1.01;
|
||||
}
|
||||
100% {
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer {
|
||||
from {
|
||||
opacity: 0;
|
||||
scale: 0.8;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer-from-top {
|
||||
from {
|
||||
opacity: 0;
|
||||
translate: 0 -100%;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer-from-end {
|
||||
from {
|
||||
opacity: 0;
|
||||
translate: 100%;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer-from-bottom {
|
||||
from {
|
||||
opacity: 0;
|
||||
translate: 0 100%;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer-from-start {
|
||||
from {
|
||||
opacity: 0;
|
||||
translate: -100% 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-backdrop {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.drawer {
|
||||
border: solid 1px white;
|
||||
}
|
||||
}
|
||||
294
packages/webawesome/src/components/drawer/drawer.styles.ts
Normal file
294
packages/webawesome/src/components/drawer/drawer.styles.ts
Normal file
@@ -0,0 +1,294 @@
|
||||
import { css } from 'lit';
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
--size: 25rem;
|
||||
--spacing: var(--wa-space-l);
|
||||
--show-duration: 200ms;
|
||||
--hide-duration: 200ms;
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host([open]) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.drawer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: var(--wa-color-surface-raised);
|
||||
border: none;
|
||||
box-shadow: var(--wa-shadow-l);
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
animation-duration: var(--show-duration);
|
||||
animation-timing-function: ease;
|
||||
|
||||
&.show::backdrop {
|
||||
animation: show-backdrop var(--show-duration, 200ms) ease;
|
||||
}
|
||||
|
||||
&.hide::backdrop {
|
||||
animation: show-backdrop var(--hide-duration, 200ms) ease reverse;
|
||||
}
|
||||
|
||||
&.show.top {
|
||||
animation: show-drawer-from-top var(--show-duration) ease;
|
||||
}
|
||||
|
||||
&.hide.top {
|
||||
animation: show-drawer-from-top var(--hide-duration) ease reverse;
|
||||
}
|
||||
|
||||
&.show.end {
|
||||
animation: show-drawer-from-end var(--show-duration) ease;
|
||||
|
||||
&:dir(rtl) {
|
||||
animation-name: show-drawer-from-start;
|
||||
}
|
||||
}
|
||||
|
||||
&.hide.end {
|
||||
animation: show-drawer-from-end var(--hide-duration) ease reverse;
|
||||
|
||||
&:dir(rtl) {
|
||||
animation-name: show-drawer-from-start;
|
||||
}
|
||||
}
|
||||
|
||||
&.show.bottom {
|
||||
animation: show-drawer-from-bottom var(--show-duration) ease;
|
||||
}
|
||||
|
||||
&.hide.bottom {
|
||||
animation: show-drawer-from-bottom var(--hide-duration) ease reverse;
|
||||
}
|
||||
|
||||
&.show.start {
|
||||
animation: show-drawer-from-start var(--show-duration) ease;
|
||||
|
||||
&:dir(rtl) {
|
||||
animation-name: show-drawer-from-end;
|
||||
}
|
||||
}
|
||||
|
||||
&.hide.start {
|
||||
animation: show-drawer-from-start var(--hide-duration) ease reverse;
|
||||
|
||||
&:dir(rtl) {
|
||||
animation-name: show-drawer-from-end;
|
||||
}
|
||||
}
|
||||
|
||||
&.pulse {
|
||||
animation: pulse 250ms ease;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.top {
|
||||
top: 0;
|
||||
inset-inline-end: auto;
|
||||
bottom: auto;
|
||||
inset-inline-start: 0;
|
||||
width: 100%;
|
||||
height: var(--size);
|
||||
}
|
||||
|
||||
.end {
|
||||
top: 0;
|
||||
inset-inline-end: 0;
|
||||
bottom: auto;
|
||||
inset-inline-start: auto;
|
||||
width: var(--size);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
top: auto;
|
||||
inset-inline-end: auto;
|
||||
bottom: 0;
|
||||
inset-inline-start: 0;
|
||||
width: 100%;
|
||||
height: var(--size);
|
||||
}
|
||||
|
||||
.start {
|
||||
top: 0;
|
||||
inset-inline-end: auto;
|
||||
bottom: auto;
|
||||
inset-inline-start: 0;
|
||||
width: var(--size);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
padding-inline-start: var(--spacing);
|
||||
padding-block-end: 0;
|
||||
|
||||
/* Subtract the close button's padding so that the X is visually aligned with the edges of the dialog content */
|
||||
padding-inline-end: calc(var(--spacing) - var(--wa-form-control-padding-block));
|
||||
padding-block-start: calc(var(--spacing) - var(--wa-form-control-padding-block));
|
||||
}
|
||||
|
||||
.title {
|
||||
align-self: center;
|
||||
flex: 1 1 auto;
|
||||
font: inherit;
|
||||
font-size: var(--wa-font-size-l);
|
||||
font-weight: var(--wa-font-weight-heading);
|
||||
line-height: var(--wa-line-height-condensed);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
align-self: start;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
justify-content: end;
|
||||
gap: var(--wa-space-2xs);
|
||||
padding-inline-start: var(--spacing);
|
||||
}
|
||||
|
||||
.header-actions wa-button,
|
||||
.header-actions ::slotted(wa-button) {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1 1 auto;
|
||||
display: block;
|
||||
padding: var(--spacing);
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: var(--wa-focus-ring-offset);
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--wa-space-xs);
|
||||
justify-content: end;
|
||||
padding: var(--spacing);
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
.footer ::slotted(wa-button:not(:last-of-type)) {
|
||||
margin-inline-end: var(--wa-spacing-xs);
|
||||
}
|
||||
|
||||
.drawer::backdrop {
|
||||
/*
|
||||
NOTE: the ::backdrop element doesn't inherit properly in Safari yet, but it will in 17.4! At that time, we can
|
||||
remove the fallback values here.
|
||||
*/
|
||||
background-color: var(--wa-color-overlay-modal, rgb(0 0 0 / 0.25));
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
scale: 1;
|
||||
}
|
||||
50% {
|
||||
scale: 1.01;
|
||||
}
|
||||
100% {
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer {
|
||||
from {
|
||||
opacity: 0;
|
||||
scale: 0.8;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer-from-top {
|
||||
from {
|
||||
opacity: 0;
|
||||
translate: 0 -100%;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer-from-end {
|
||||
from {
|
||||
opacity: 0;
|
||||
translate: 100%;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer-from-bottom {
|
||||
from {
|
||||
opacity: 0;
|
||||
translate: 0 100%;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-drawer-from-start {
|
||||
from {
|
||||
opacity: 0;
|
||||
translate: -100% 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show-backdrop {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.drawer {
|
||||
border: solid 1px white;
|
||||
}
|
||||
}
|
||||
`;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user