diff --git a/packages/webawesome/docs/docs/resources/changelog.md b/packages/webawesome/docs/docs/resources/changelog.md index bc4553f9f..aa9cfb0ba 100644 --- a/packages/webawesome/docs/docs/resources/changelog.md +++ b/packages/webawesome/docs/docs/resources/changelog.md @@ -22,6 +22,7 @@ Components with the Experimental badge sh - Fixed a bug in `` that caused the browser to hang when cancelling the `wa-hide` event [issue:1483] - Fixed a bug in `` that prevented the icon dependency from being imported [issue:1825] - Improved performance of `` so initial rendering occurs faster, especially with multiple icons on the page [issue:1729] +- Improved performance of all components by fixing how CSS is imported and reused [issue:1812] - Modified the default `transition` styles of `` to use design tokens [pr:1693] ## 3.0.0 diff --git a/packages/webawesome/scripts/build.js b/packages/webawesome/scripts/build.js index f9c6112ef..4bfe15c27 100644 --- a/packages/webawesome/scripts/build.js +++ b/packages/webawesome/scripts/build.js @@ -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 = { diff --git a/packages/webawesome/src/components/animated-image/animated-image.css b/packages/webawesome/src/components/animated-image/animated-image.css deleted file mode 100644 index 59f659044..000000000 --- a/packages/webawesome/src/components/animated-image/animated-image.css +++ /dev/null @@ -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); - } -} diff --git a/packages/webawesome/src/components/animated-image/animated-image.styles.ts b/packages/webawesome/src/components/animated-image/animated-image.styles.ts new file mode 100644 index 000000000..94675b814 --- /dev/null +++ b/packages/webawesome/src/components/animated-image/animated-image.styles.ts @@ -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); + } + } +`; diff --git a/packages/webawesome/src/components/animated-image/animated-image.ts b/packages/webawesome/src/components/animated-image/animated-image.ts index f12ad4f06..c041841fa 100644 --- a/packages/webawesome/src/components/animated-image/animated-image.ts +++ b/packages/webawesome/src/components/animated-image/animated-image.ts @@ -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. diff --git a/packages/webawesome/src/components/animation/animation.css b/packages/webawesome/src/components/animation/animation.css deleted file mode 100644 index 92d692cdd..000000000 --- a/packages/webawesome/src/components/animation/animation.css +++ /dev/null @@ -1,3 +0,0 @@ -:host { - display: contents; -} diff --git a/packages/webawesome/src/components/animation/animation.styles.ts b/packages/webawesome/src/components/animation/animation.styles.ts new file mode 100644 index 000000000..1ef4bf6f3 --- /dev/null +++ b/packages/webawesome/src/components/animation/animation.styles.ts @@ -0,0 +1,7 @@ +import { css } from 'lit'; + +export default css` + :host { + display: contents; + } +`; diff --git a/packages/webawesome/src/components/animation/animation.ts b/packages/webawesome/src/components/animation/animation.ts index e77ee92aa..7a0e9b06d 100644 --- a/packages/webawesome/src/components/animation/animation.ts +++ b/packages/webawesome/src/components/animation/animation.ts @@ -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'; /** diff --git a/packages/webawesome/src/components/avatar/avatar.css b/packages/webawesome/src/components/avatar/avatar.css deleted file mode 100644 index 2c071cb5c..000000000 --- a/packages/webawesome/src/components/avatar/avatar.css +++ /dev/null @@ -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; -} diff --git a/packages/webawesome/src/components/avatar/avatar.styles.ts b/packages/webawesome/src/components/avatar/avatar.styles.ts new file mode 100644 index 000000000..98d8c5ae4 --- /dev/null +++ b/packages/webawesome/src/components/avatar/avatar.styles.ts @@ -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; + } +`; diff --git a/packages/webawesome/src/components/avatar/avatar.ts b/packages/webawesome/src/components/avatar/avatar.ts index 7dc7a1530..4b2c983c9 100644 --- a/packages/webawesome/src/components/avatar/avatar.ts +++ b/packages/webawesome/src/components/avatar/avatar.ts @@ -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. diff --git a/packages/webawesome/src/components/badge/badge.css b/packages/webawesome/src/components/badge/badge.css deleted file mode 100644 index 6fceaac75..000000000 --- a/packages/webawesome/src/components/badge/badge.css +++ /dev/null @@ -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; -} diff --git a/packages/webawesome/src/components/badge/badge.styles.ts b/packages/webawesome/src/components/badge/badge.styles.ts new file mode 100644 index 000000000..14147861e --- /dev/null +++ b/packages/webawesome/src/components/badge/badge.styles.ts @@ -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; + } +`; diff --git a/packages/webawesome/src/components/badge/badge.ts b/packages/webawesome/src/components/badge/badge.ts index 13c3fa375..892eadb27 100644 --- a/packages/webawesome/src/components/badge/badge.ts +++ b/packages/webawesome/src/components/badge/badge.ts @@ -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. diff --git a/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.css b/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.css deleted file mode 100644 index 4784fa017..000000000 --- a/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.css +++ /dev/null @@ -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; -} diff --git a/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.styles.ts b/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.styles.ts new file mode 100644 index 000000000..b7370f626 --- /dev/null +++ b/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.styles.ts @@ -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; + } +`; diff --git a/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts b/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts index ff9c8b29d..83ec368c5 100644 --- a/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts +++ b/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts @@ -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. diff --git a/packages/webawesome/src/components/breadcrumb/breadcrumb.css b/packages/webawesome/src/components/breadcrumb/breadcrumb.css deleted file mode 100644 index a45d4f776..000000000 --- a/packages/webawesome/src/components/breadcrumb/breadcrumb.css +++ /dev/null @@ -1,5 +0,0 @@ -.breadcrumb { - display: flex; - align-items: center; - flex-wrap: wrap; -} diff --git a/packages/webawesome/src/components/breadcrumb/breadcrumb.styles.ts b/packages/webawesome/src/components/breadcrumb/breadcrumb.styles.ts new file mode 100644 index 000000000..86c0e16e0 --- /dev/null +++ b/packages/webawesome/src/components/breadcrumb/breadcrumb.styles.ts @@ -0,0 +1,9 @@ +import { css } from 'lit'; + +export default css` + .breadcrumb { + display: flex; + align-items: center; + flex-wrap: wrap; + } +`; diff --git a/packages/webawesome/src/components/breadcrumb/breadcrumb.ts b/packages/webawesome/src/components/breadcrumb/breadcrumb.ts index be3e24a24..0f2f77093 100644 --- a/packages/webawesome/src/components/breadcrumb/breadcrumb.ts +++ b/packages/webawesome/src/components/breadcrumb/breadcrumb.ts @@ -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. diff --git a/packages/webawesome/src/components/button-group/button-group.css b/packages/webawesome/src/components/button-group/button-group.css deleted file mode 100644 index ee7e152c0..000000000 --- a/packages/webawesome/src/components/button-group/button-group.css +++ /dev/null @@ -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)); - } -} diff --git a/packages/webawesome/src/components/button-group/button-group.styles.ts b/packages/webawesome/src/components/button-group/button-group.styles.ts new file mode 100644 index 000000000..dfa4d85c9 --- /dev/null +++ b/packages/webawesome/src/components/button-group/button-group.styles.ts @@ -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)); + } + } +`; diff --git a/packages/webawesome/src/components/button-group/button-group.ts b/packages/webawesome/src/components/button-group/button-group.ts index 0a491c3ad..cda7123c5 100644 --- a/packages/webawesome/src/components/button-group/button-group.ts +++ b/packages/webawesome/src/components/button-group/button-group.ts @@ -4,7 +4,7 @@ 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 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. diff --git a/packages/webawesome/src/components/button/button.css b/packages/webawesome/src/components/button/button.css deleted file mode 100644 index ac7ddc3f2..000000000 --- a/packages/webawesome/src/components/button/button.css +++ /dev/null @@ -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, 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); -} diff --git a/packages/webawesome/src/components/button/button.styles.ts b/packages/webawesome/src/components/button/button.styles.ts new file mode 100644 index 000000000..2cd955897 --- /dev/null +++ b/packages/webawesome/src/components/button/button.styles.ts @@ -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); + } +`; diff --git a/packages/webawesome/src/components/button/button.ts b/packages/webawesome/src/components/button/button.ts index 6c1225559..19a3dc6cf 100644 --- a/packages/webawesome/src/components/button/button.ts +++ b/packages/webawesome/src/components/button/button.ts @@ -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. diff --git a/packages/webawesome/src/components/callout/callout.css b/packages/webawesome/src/components/callout/callout.css deleted file mode 100644 index b7118c2e4..000000000 --- a/packages/webawesome/src/components/callout/callout.css +++ /dev/null @@ -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; -} diff --git a/packages/webawesome/src/components/callout/callout.styles.ts b/packages/webawesome/src/components/callout/callout.styles.ts new file mode 100644 index 000000000..9b3b59a54 --- /dev/null +++ b/packages/webawesome/src/components/callout/callout.styles.ts @@ -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; + } +`; diff --git a/packages/webawesome/src/components/callout/callout.ts b/packages/webawesome/src/components/callout/callout.ts index d33f6600b..f8a2a55aa 100644 --- a/packages/webawesome/src/components/callout/callout.ts +++ b/packages/webawesome/src/components/callout/callout.ts @@ -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. diff --git a/packages/webawesome/src/components/card/card.css b/packages/webawesome/src/components/card/card.css deleted file mode 100644 index cb06f19f6..000000000 --- a/packages/webawesome/src/components/card/card.css +++ /dev/null @@ -1,141 +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-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); -} diff --git a/packages/webawesome/src/components/card/card.styles.ts b/packages/webawesome/src/components/card/card.styles.ts new file mode 100644 index 000000000..3c8ed1ce0 --- /dev/null +++ b/packages/webawesome/src/components/card/card.styles.ts @@ -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); + } +`; diff --git a/packages/webawesome/src/components/card/card.ts b/packages/webawesome/src/components/card/card.ts index 58c072852..b4e0ce8e5 100644 --- a/packages/webawesome/src/components/card/card.ts +++ b/packages/webawesome/src/components/card/card.ts @@ -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. diff --git a/packages/webawesome/src/components/carousel-item/carousel-item.css b/packages/webawesome/src/components/carousel-item/carousel-item.css deleted file mode 100644 index abc65e317..000000000 --- a/packages/webawesome/src/components/carousel-item/carousel-item.css +++ /dev/null @@ -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; -} diff --git a/packages/webawesome/src/components/carousel-item/carousel-item.styles.ts b/packages/webawesome/src/components/carousel-item/carousel-item.styles.ts new file mode 100644 index 000000000..11e07af3c --- /dev/null +++ b/packages/webawesome/src/components/carousel-item/carousel-item.styles.ts @@ -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; + } +`; diff --git a/packages/webawesome/src/components/carousel-item/carousel-item.ts b/packages/webawesome/src/components/carousel-item/carousel-item.ts index a655b317c..8b80fd536 100644 --- a/packages/webawesome/src/components/carousel-item/carousel-item.ts +++ b/packages/webawesome/src/components/carousel-item/carousel-item.ts @@ -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. diff --git a/packages/webawesome/src/components/carousel/carousel.css b/packages/webawesome/src/components/carousel/carousel.css deleted file mode 100644 index 004d30a0a..000000000 --- a/packages/webawesome/src/components/carousel/carousel.css +++ /dev/null @@ -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); -} diff --git a/packages/webawesome/src/components/carousel/carousel.styles.ts b/packages/webawesome/src/components/carousel/carousel.styles.ts new file mode 100644 index 000000000..7882b603c --- /dev/null +++ b/packages/webawesome/src/components/carousel/carousel.styles.ts @@ -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); + } +`; diff --git a/packages/webawesome/src/components/carousel/carousel.ts b/packages/webawesome/src/components/carousel/carousel.ts index a3f369dc7..b8353dd95 100644 --- a/packages/webawesome/src/components/carousel/carousel.ts +++ b/packages/webawesome/src/components/carousel/carousel.ts @@ -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. diff --git a/packages/webawesome/src/components/checkbox/checkbox.css b/packages/webawesome/src/components/checkbox/checkbox.css deleted file mode 100644 index ae45abbd6..000000000 --- a/packages/webawesome/src/components/checkbox/checkbox.css +++ /dev/null @@ -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); -} diff --git a/packages/webawesome/src/components/checkbox/checkbox.styles.ts b/packages/webawesome/src/components/checkbox/checkbox.styles.ts new file mode 100644 index 000000000..77fe0c11b --- /dev/null +++ b/packages/webawesome/src/components/checkbox/checkbox.styles.ts @@ -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); + } +`; diff --git a/packages/webawesome/src/components/checkbox/checkbox.ts b/packages/webawesome/src/components/checkbox/checkbox.ts index 1f1decf62..444472b1d 100644 --- a/packages/webawesome/src/components/checkbox/checkbox.ts +++ b/packages/webawesome/src/components/checkbox/checkbox.ts @@ -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. diff --git a/packages/webawesome/src/components/color-picker/color-picker.css b/packages/webawesome/src/components/color-picker/color-picker.css deleted file mode 100644 index f9cd5283e..000000000 --- a/packages/webawesome/src/components/color-picker/color-picker.css +++ /dev/null @@ -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; -} diff --git a/packages/webawesome/src/components/color-picker/color-picker.styles.ts b/packages/webawesome/src/components/color-picker/color-picker.styles.ts new file mode 100644 index 000000000..d2eedca15 --- /dev/null +++ b/packages/webawesome/src/components/color-picker/color-picker.styles.ts @@ -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; + } +`; diff --git a/packages/webawesome/src/components/color-picker/color-picker.ts b/packages/webawesome/src/components/color-picker/color-picker.ts index 25b94b9ec..c039f5034 100644 --- a/packages/webawesome/src/components/color-picker/color-picker.ts +++ b/packages/webawesome/src/components/color-picker/color-picker.ts @@ -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; diff --git a/packages/webawesome/src/components/comparison/comparison.css b/packages/webawesome/src/components/comparison/comparison.css deleted file mode 100644 index 139cb3dd9..000000000 --- a/packages/webawesome/src/components/comparison/comparison.css +++ /dev/null @@ -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); -} diff --git a/packages/webawesome/src/components/comparison/comparison.styles.ts b/packages/webawesome/src/components/comparison/comparison.styles.ts new file mode 100644 index 000000000..192aee4e4 --- /dev/null +++ b/packages/webawesome/src/components/comparison/comparison.styles.ts @@ -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); + } +`; diff --git a/packages/webawesome/src/components/comparison/comparison.ts b/packages/webawesome/src/components/comparison/comparison.ts index 12f458fb9..8500931b3 100644 --- a/packages/webawesome/src/components/comparison/comparison.ts +++ b/packages/webawesome/src/components/comparison/comparison.ts @@ -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. diff --git a/packages/webawesome/src/components/copy-button/copy-button.css b/packages/webawesome/src/components/copy-button/copy-button.css deleted file mode 100644 index 7d7be5126..000000000 --- a/packages/webawesome/src/components/copy-button/copy-button.css +++ /dev/null @@ -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; - } -} diff --git a/packages/webawesome/src/components/copy-button/copy-button.styles.ts b/packages/webawesome/src/components/copy-button/copy-button.styles.ts new file mode 100644 index 000000000..97082278c --- /dev/null +++ b/packages/webawesome/src/components/copy-button/copy-button.styles.ts @@ -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; + } + } +`; diff --git a/packages/webawesome/src/components/copy-button/copy-button.ts b/packages/webawesome/src/components/copy-button/copy-button.ts index b29967fd6..533bb61c7 100644 --- a/packages/webawesome/src/components/copy-button/copy-button.ts +++ b/packages/webawesome/src/components/copy-button/copy-button.ts @@ -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. diff --git a/packages/webawesome/src/components/details/details.css b/packages/webawesome/src/components/details/details.css deleted file mode 100644 index 858fb0a89..000000000 --- a/packages/webawesome/src/components/details/details.css +++ /dev/null @@ -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 */ -} diff --git a/packages/webawesome/src/components/details/details.styles.ts b/packages/webawesome/src/components/details/details.styles.ts new file mode 100644 index 000000000..70c4af31e --- /dev/null +++ b/packages/webawesome/src/components/details/details.styles.ts @@ -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 */ + } +`; diff --git a/packages/webawesome/src/components/details/details.ts b/packages/webawesome/src/components/details/details.ts index 416f746a7..42ccc8c34 100644 --- a/packages/webawesome/src/components/details/details.ts +++ b/packages/webawesome/src/components/details/details.ts @@ -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. diff --git a/packages/webawesome/src/components/dialog/dialog.css b/packages/webawesome/src/components/dialog/dialog.css deleted file mode 100644 index cb6e4f7de..000000000 --- a/packages/webawesome/src/components/dialog/dialog.css +++ /dev/null @@ -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; - } -} diff --git a/packages/webawesome/src/components/dialog/dialog.styles.ts b/packages/webawesome/src/components/dialog/dialog.styles.ts new file mode 100644 index 000000000..1d0b730b2 --- /dev/null +++ b/packages/webawesome/src/components/dialog/dialog.styles.ts @@ -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; + } + } +`; diff --git a/packages/webawesome/src/components/dialog/dialog.ts b/packages/webawesome/src/components/dialog/dialog.ts index 4d0259a99..95993da1c 100644 --- a/packages/webawesome/src/components/dialog/dialog.ts +++ b/packages/webawesome/src/components/dialog/dialog.ts @@ -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. diff --git a/packages/webawesome/src/components/divider/divider.css b/packages/webawesome/src/components/divider/divider.css deleted file mode 100644 index 8eeb3a599..000000000 --- a/packages/webawesome/src/components/divider/divider.css +++ /dev/null @@ -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; -} diff --git a/packages/webawesome/src/components/divider/divider.styles.ts b/packages/webawesome/src/components/divider/divider.styles.ts new file mode 100644 index 000000000..0f4d34a3b --- /dev/null +++ b/packages/webawesome/src/components/divider/divider.styles.ts @@ -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; + } +`; diff --git a/packages/webawesome/src/components/divider/divider.ts b/packages/webawesome/src/components/divider/divider.ts index 7d24696ac..30c181a58 100644 --- a/packages/webawesome/src/components/divider/divider.ts +++ b/packages/webawesome/src/components/divider/divider.ts @@ -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. diff --git a/packages/webawesome/src/components/drawer/drawer.css b/packages/webawesome/src/components/drawer/drawer.css deleted file mode 100644 index b380caebf..000000000 --- a/packages/webawesome/src/components/drawer/drawer.css +++ /dev/null @@ -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; - } -} diff --git a/packages/webawesome/src/components/drawer/drawer.styles.ts b/packages/webawesome/src/components/drawer/drawer.styles.ts new file mode 100644 index 000000000..f2bfcf4dc --- /dev/null +++ b/packages/webawesome/src/components/drawer/drawer.styles.ts @@ -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; + } + } +`; diff --git a/packages/webawesome/src/components/drawer/drawer.ts b/packages/webawesome/src/components/drawer/drawer.ts index 15131dccd..502b1561c 100644 --- a/packages/webawesome/src/components/drawer/drawer.ts +++ b/packages/webawesome/src/components/drawer/drawer.ts @@ -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 './drawer.css'; +import styles from './drawer.styles.js'; /** * @summary Drawers slide in from a container to expose additional options and information. diff --git a/packages/webawesome/src/components/dropdown-item/dropdown-item.css b/packages/webawesome/src/components/dropdown-item/dropdown-item.css deleted file mode 100644 index f663f0191..000000000 --- a/packages/webawesome/src/components/dropdown-item/dropdown-item.css +++ /dev/null @@ -1,227 +0,0 @@ -:host { - display: flex; - position: relative; - align-items: center; - padding: 0.5em 1em; - border-radius: var(--wa-border-radius-s); - isolation: isolate; - color: var(--wa-color-text-normal); - line-height: var(--wa-line-height-condensed); - cursor: pointer; - transition: - var(--wa-transition-fast) background-color var(--wa-transition-easing), - var(--wa-transition-fast) color var(--wa-transition-easing); -} - -@media (hover: hover) { - :host(:hover:not(:state(disabled))) { - background-color: var(--wa-color-neutral-fill-normal); - } -} - -:host(:focus-visible) { - z-index: 1; - outline: var(--wa-focus-ring); - background-color: var(--wa-color-neutral-fill-normal); -} - -:host(:state(disabled)) { - opacity: 0.5; - cursor: not-allowed; -} - -/* Danger variant */ -:host([variant='danger']), -:host([variant='danger']) #details { - color: var(--wa-color-danger-on-quiet); -} - -@media (hover: hover) { - :host([variant='danger']:hover) { - background-color: var(--wa-color-danger-fill-normal); - color: var(--wa-color-danger-on-normal); - } -} - -:host([variant='danger']:focus-visible) { - background-color: var(--wa-color-danger-fill-normal); - color: var(--wa-color-danger-on-normal); -} - -:host([checkbox-adjacent]) { - padding-inline-start: 2em; -} - -/* Only add padding when item actually has a submenu */ -:host([submenu-adjacent]:not(:state(has-submenu))) #details { - padding-inline-end: 0; -} - -:host(:state(has-submenu)[submenu-adjacent]) #details { - padding-inline-end: 1.75em; -} - -#check { - visibility: hidden; - margin-inline-start: -1.5em; - margin-inline-end: 0.5em; - font-size: var(--wa-font-size-smaller); -} - -:host(:state(checked)) #check { - visibility: visible; -} - -#icon ::slotted(*) { - display: flex; - flex: 0 0 auto; - align-items: center; - margin-inline-end: 0.75em !important; - font-size: var(--wa-font-size-smaller); -} - -#label { - flex: 1 1 auto; - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -#details { - display: flex; - flex: 0 0 auto; - align-items: center; - justify-content: end; - color: var(--wa-color-text-quiet); - font-size: var(--wa-font-size-smaller) !important; -} - -#details ::slotted(*) { - margin-inline-start: 2em !important; -} - -/* Submenu indicator icon */ -#submenu-indicator { - position: absolute; - inset-inline-end: 1em; - color: var(--wa-color-neutral-on-quiet); - font-size: var(--wa-font-size-smaller); -} - -/* Flip chevron icon when RTL */ -:host(:dir(rtl)) #submenu-indicator { - transform: scaleX(-1); -} - -/* Submenu styles */ -#submenu { - display: flex; - z-index: 10; - position: absolute; - top: 0; - left: 0; - flex-direction: column; - width: max-content; - margin: 0; - padding: 0.25em; - border: var(--wa-border-style) var(--wa-border-width-s) var(--wa-color-surface-border); - border-radius: var(--wa-border-radius-m); - background-color: var(--wa-color-surface-raised); - box-shadow: var(--wa-shadow-m); - color: var(--wa-color-text-normal); - text-align: start; - user-select: none; - - /* Override default popover styles */ - &[popover] { - margin: 0; - inset: auto; - padding: 0.25em; - overflow: visible; - border-radius: var(--wa-border-radius-m); - } - - &.show { - animation: submenu-show var(--show-duration, 50ms) ease; - } - - &.hide { - animation: submenu-show var(--show-duration, 50ms) ease reverse; - } - - /* Submenu placement transform origins */ - &[data-placement^='top'] { - transform-origin: bottom; - } - - &[data-placement^='bottom'] { - transform-origin: top; - } - - &[data-placement^='left'] { - transform-origin: right; - } - - &[data-placement^='right'] { - transform-origin: left; - } - - &[data-placement='left-start'] { - transform-origin: right top; - } - - &[data-placement='left-end'] { - transform-origin: right bottom; - } - - &[data-placement='right-start'] { - transform-origin: left top; - } - - &[data-placement='right-end'] { - transform-origin: left bottom; - } - - /* Safe triangle styling */ - &::before { - display: none; - z-index: 9; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: transparent; - content: ''; - clip-path: polygon( - var(--safe-triangle-cursor-x, 0) var(--safe-triangle-cursor-y, 0), - var(--safe-triangle-submenu-start-x, 0) var(--safe-triangle-submenu-start-y, 0), - var(--safe-triangle-submenu-end-x, 0) var(--safe-triangle-submenu-end-y, 0) - ); - pointer-events: auto; /* Enable mouse events on the triangle */ - } - - &[data-visible]::before { - display: block; - } -} - -::slotted(wa-dropdown-item) { - font-size: inherit; -} - -::slotted(wa-divider) { - --spacing: 0.25em; -} - -@keyframes submenu-show { - from { - scale: 0.9; - opacity: 0; - } - to { - scale: 1; - opacity: 1; - } -} diff --git a/packages/webawesome/src/components/dropdown-item/dropdown-item.styles.ts b/packages/webawesome/src/components/dropdown-item/dropdown-item.styles.ts new file mode 100644 index 000000000..f88aa9d03 --- /dev/null +++ b/packages/webawesome/src/components/dropdown-item/dropdown-item.styles.ts @@ -0,0 +1,231 @@ +import { css } from 'lit'; + +export default css` + :host { + display: flex; + position: relative; + align-items: center; + padding: 0.5em 1em; + border-radius: var(--wa-border-radius-s); + isolation: isolate; + color: var(--wa-color-text-normal); + line-height: var(--wa-line-height-condensed); + cursor: pointer; + transition: + var(--wa-transition-fast) background-color var(--wa-transition-easing), + var(--wa-transition-fast) color var(--wa-transition-easing); + } + + @media (hover: hover) { + :host(:hover:not(:state(disabled))) { + background-color: var(--wa-color-neutral-fill-normal); + } + } + + :host(:focus-visible) { + z-index: 1; + outline: var(--wa-focus-ring); + background-color: var(--wa-color-neutral-fill-normal); + } + + :host(:state(disabled)) { + opacity: 0.5; + cursor: not-allowed; + } + + /* Danger variant */ + :host([variant='danger']), + :host([variant='danger']) #details { + color: var(--wa-color-danger-on-quiet); + } + + @media (hover: hover) { + :host([variant='danger']:hover) { + background-color: var(--wa-color-danger-fill-normal); + color: var(--wa-color-danger-on-normal); + } + } + + :host([variant='danger']:focus-visible) { + background-color: var(--wa-color-danger-fill-normal); + color: var(--wa-color-danger-on-normal); + } + + :host([checkbox-adjacent]) { + padding-inline-start: 2em; + } + + /* Only add padding when item actually has a submenu */ + :host([submenu-adjacent]:not(:state(has-submenu))) #details { + padding-inline-end: 0; + } + + :host(:state(has-submenu)[submenu-adjacent]) #details { + padding-inline-end: 1.75em; + } + + #check { + visibility: hidden; + margin-inline-start: -1.5em; + margin-inline-end: 0.5em; + font-size: var(--wa-font-size-smaller); + } + + :host(:state(checked)) #check { + visibility: visible; + } + + #icon ::slotted(*) { + display: flex; + flex: 0 0 auto; + align-items: center; + margin-inline-end: 0.75em !important; + font-size: var(--wa-font-size-smaller); + } + + #label { + flex: 1 1 auto; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + #details { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: end; + color: var(--wa-color-text-quiet); + font-size: var(--wa-font-size-smaller) !important; + } + + #details ::slotted(*) { + margin-inline-start: 2em !important; + } + + /* Submenu indicator icon */ + #submenu-indicator { + position: absolute; + inset-inline-end: 1em; + color: var(--wa-color-neutral-on-quiet); + font-size: var(--wa-font-size-smaller); + } + + /* Flip chevron icon when RTL */ + :host(:dir(rtl)) #submenu-indicator { + transform: scaleX(-1); + } + + /* Submenu styles */ + #submenu { + display: flex; + z-index: 10; + position: absolute; + top: 0; + left: 0; + flex-direction: column; + width: max-content; + margin: 0; + padding: 0.25em; + border: var(--wa-border-style) var(--wa-border-width-s) var(--wa-color-surface-border); + border-radius: var(--wa-border-radius-m); + background-color: var(--wa-color-surface-raised); + box-shadow: var(--wa-shadow-m); + color: var(--wa-color-text-normal); + text-align: start; + user-select: none; + + /* Override default popover styles */ + &[popover] { + margin: 0; + inset: auto; + padding: 0.25em; + overflow: visible; + border-radius: var(--wa-border-radius-m); + } + + &.show { + animation: submenu-show var(--show-duration, 50ms) ease; + } + + &.hide { + animation: submenu-show var(--show-duration, 50ms) ease reverse; + } + + /* Submenu placement transform origins */ + &[data-placement^='top'] { + transform-origin: bottom; + } + + &[data-placement^='bottom'] { + transform-origin: top; + } + + &[data-placement^='left'] { + transform-origin: right; + } + + &[data-placement^='right'] { + transform-origin: left; + } + + &[data-placement='left-start'] { + transform-origin: right top; + } + + &[data-placement='left-end'] { + transform-origin: right bottom; + } + + &[data-placement='right-start'] { + transform-origin: left top; + } + + &[data-placement='right-end'] { + transform-origin: left bottom; + } + + /* Safe triangle styling */ + &::before { + display: none; + z-index: 9; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: transparent; + content: ''; + clip-path: polygon( + var(--safe-triangle-cursor-x, 0) var(--safe-triangle-cursor-y, 0), + var(--safe-triangle-submenu-start-x, 0) var(--safe-triangle-submenu-start-y, 0), + var(--safe-triangle-submenu-end-x, 0) var(--safe-triangle-submenu-end-y, 0) + ); + pointer-events: auto; /* Enable mouse events on the triangle */ + } + + &[data-visible]::before { + display: block; + } + } + + ::slotted(wa-dropdown-item) { + font-size: inherit; + } + + ::slotted(wa-divider) { + --spacing: 0.25em; + } + + @keyframes submenu-show { + from { + scale: 0.9; + opacity: 0; + } + to { + scale: 1; + opacity: 1; + } + } +`; diff --git a/packages/webawesome/src/components/dropdown-item/dropdown-item.ts b/packages/webawesome/src/components/dropdown-item/dropdown-item.ts index c01b7fcb9..b773662bb 100644 --- a/packages/webawesome/src/components/dropdown-item/dropdown-item.ts +++ b/packages/webawesome/src/components/dropdown-item/dropdown-item.ts @@ -5,7 +5,7 @@ import { animateWithClass } from '../../internal/animate.js'; import { HasSlotController } from '../../internal/slot.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import '../icon/icon.js'; -import styles from './dropdown-item.css'; +import styles from './dropdown-item.styles.js'; /** * @summary Represents an individual item within a dropdown menu, supporting standard items, checkboxes, and submenus. diff --git a/packages/webawesome/src/components/dropdown/dropdown.css b/packages/webawesome/src/components/dropdown/dropdown.css deleted file mode 100644 index 693bdc013..000000000 --- a/packages/webawesome/src/components/dropdown/dropdown.css +++ /dev/null @@ -1,93 +0,0 @@ -:host { - --show-duration: 50ms; - --hide-duration: 50ms; - display: contents; -} - -#menu { - display: flex; - flex-direction: column; - width: max-content; - margin: 0; - padding: 0.25em; - border: var(--wa-border-style) var(--wa-border-width-s) var(--wa-color-surface-border); - border-radius: var(--wa-border-radius-m); - background-color: var(--wa-color-surface-raised); - box-shadow: var(--wa-shadow-m); - color: var(--wa-color-text-normal); - text-align: start; - user-select: none; - overflow: auto; - max-width: var(--auto-size-available-width) !important; - max-height: var(--auto-size-available-height) !important; - - &.show { - animation: show var(--show-duration) ease; - } - - &.hide { - animation: show var(--hide-duration) ease reverse; - } - - ::slotted(h1), - ::slotted(h2), - ::slotted(h3), - ::slotted(h4), - ::slotted(h5), - ::slotted(h6) { - display: block !important; - margin: 0.25em 0 !important; - padding: 0.25em 0.75em !important; - color: var(--wa-color-text-quiet) !important; - font-family: var(--wa-font-family-body) !important; - font-weight: var(--wa-font-weight-semibold) !important; - font-size: var(--wa-font-size-smaller) !important; - } - - ::slotted(wa-divider) { - --spacing: 0.25em; /* Component-specific, left as-is */ - } -} - -wa-popup[data-current-placement^='top'] #menu { - transform-origin: bottom; -} - -wa-popup[data-current-placement^='bottom'] #menu { - transform-origin: top; -} - -wa-popup[data-current-placement^='left'] #menu { - transform-origin: right; -} - -wa-popup[data-current-placement^='right'] #menu { - transform-origin: left; -} - -wa-popup[data-current-placement='left-start'] #menu { - transform-origin: right top; -} - -wa-popup[data-current-placement='left-end'] #menu { - transform-origin: right bottom; -} - -wa-popup[data-current-placement='right-start'] #menu { - transform-origin: left top; -} - -wa-popup[data-current-placement='right-end'] #menu { - transform-origin: left bottom; -} - -@keyframes show { - from { - scale: 0.9; - opacity: 0; - } - to { - scale: 1; - opacity: 1; - } -} diff --git a/packages/webawesome/src/components/dropdown/dropdown.styles.ts b/packages/webawesome/src/components/dropdown/dropdown.styles.ts new file mode 100644 index 000000000..11d247602 --- /dev/null +++ b/packages/webawesome/src/components/dropdown/dropdown.styles.ts @@ -0,0 +1,97 @@ +import { css } from 'lit'; + +export default css` + :host { + --show-duration: 50ms; + --hide-duration: 50ms; + display: contents; + } + + #menu { + display: flex; + flex-direction: column; + width: max-content; + margin: 0; + padding: 0.25em; + border: var(--wa-border-style) var(--wa-border-width-s) var(--wa-color-surface-border); + border-radius: var(--wa-border-radius-m); + background-color: var(--wa-color-surface-raised); + box-shadow: var(--wa-shadow-m); + color: var(--wa-color-text-normal); + text-align: start; + user-select: none; + overflow: auto; + max-width: var(--auto-size-available-width) !important; + max-height: var(--auto-size-available-height) !important; + + &.show { + animation: show var(--show-duration) ease; + } + + &.hide { + animation: show var(--hide-duration) ease reverse; + } + + ::slotted(h1), + ::slotted(h2), + ::slotted(h3), + ::slotted(h4), + ::slotted(h5), + ::slotted(h6) { + display: block !important; + margin: 0.25em 0 !important; + padding: 0.25em 0.75em !important; + color: var(--wa-color-text-quiet) !important; + font-family: var(--wa-font-family-body) !important; + font-weight: var(--wa-font-weight-semibold) !important; + font-size: var(--wa-font-size-smaller) !important; + } + + ::slotted(wa-divider) { + --spacing: 0.25em; /* Component-specific, left as-is */ + } + } + + wa-popup[data-current-placement^='top'] #menu { + transform-origin: bottom; + } + + wa-popup[data-current-placement^='bottom'] #menu { + transform-origin: top; + } + + wa-popup[data-current-placement^='left'] #menu { + transform-origin: right; + } + + wa-popup[data-current-placement^='right'] #menu { + transform-origin: left; + } + + wa-popup[data-current-placement='left-start'] #menu { + transform-origin: right top; + } + + wa-popup[data-current-placement='left-end'] #menu { + transform-origin: right bottom; + } + + wa-popup[data-current-placement='right-start'] #menu { + transform-origin: left top; + } + + wa-popup[data-current-placement='right-end'] #menu { + transform-origin: left bottom; + } + + @keyframes show { + from { + scale: 0.9; + opacity: 0; + } + to { + scale: 1; + opacity: 1; + } + } +`; diff --git a/packages/webawesome/src/components/dropdown/dropdown.ts b/packages/webawesome/src/components/dropdown/dropdown.ts index a8d03f4fc..b3a1a70e9 100644 --- a/packages/webawesome/src/components/dropdown/dropdown.ts +++ b/packages/webawesome/src/components/dropdown/dropdown.ts @@ -12,13 +12,13 @@ import { activeElements } from '../../internal/active-elements.js'; import { animateWithClass } from '../../internal/animate.js'; import { uniqueId } from '../../internal/math.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import sizeStyles from '../../styles/utilities/size.css'; +import sizeStyles from '../../styles/component/size.styles.js'; import { LocalizeController } from '../../utilities/localize.js'; import type WaButton from '../button/button.js'; import '../dropdown-item/dropdown-item.js'; import type WaDropdownItem from '../dropdown-item/dropdown-item.js'; import WaPopup from '../popup/popup.js'; // Added import for wa-popup -import styles from './dropdown.css'; +import styles from './dropdown.styles.js'; const openDropdowns = new Set(); diff --git a/packages/webawesome/src/components/icon/icon.css b/packages/webawesome/src/components/icon/icon.css deleted file mode 100644 index 9a90c004f..000000000 --- a/packages/webawesome/src/components/icon/icon.css +++ /dev/null @@ -1,40 +0,0 @@ -:host { - --primary-color: currentColor; - --primary-opacity: 1; - --secondary-color: currentColor; - --secondary-opacity: 0.4; - - box-sizing: content-box; - display: inline-flex; - align-items: center; - justify-content: center; - vertical-align: -0.125em; -} - -/* Standard */ -:host(:not([auto-width])) { - width: 1.25em; - height: 1em; -} - -/* Auto-width */ -:host([auto-width]) { - width: auto; - height: 1em; -} - -svg { - height: 1em; - overflow: visible; - - /* Duotone colors with path-specific opacity fallback */ - path[data-duotone-primary] { - color: var(--primary-color); - opacity: var(--path-opacity, var(--primary-opacity)); - } - - path[data-duotone-secondary] { - color: var(--secondary-color); - opacity: var(--path-opacity, var(--secondary-opacity)); - } -} diff --git a/packages/webawesome/src/components/icon/icon.styles.ts b/packages/webawesome/src/components/icon/icon.styles.ts new file mode 100644 index 000000000..30c656645 --- /dev/null +++ b/packages/webawesome/src/components/icon/icon.styles.ts @@ -0,0 +1,44 @@ +import { css } from 'lit'; + +export default css` + :host { + --primary-color: currentColor; + --primary-opacity: 1; + --secondary-color: currentColor; + --secondary-opacity: 0.4; + + box-sizing: content-box; + display: inline-flex; + align-items: center; + justify-content: center; + vertical-align: -0.125em; + } + + /* Standard */ + :host(:not([auto-width])) { + width: 1.25em; + height: 1em; + } + + /* Auto-width */ + :host([auto-width]) { + width: auto; + height: 1em; + } + + svg { + height: 1em; + overflow: visible; + + /* Duotone colors with path-specific opacity fallback */ + path[data-duotone-primary] { + color: var(--primary-color); + opacity: var(--path-opacity, var(--primary-opacity)); + } + + path[data-duotone-secondary] { + color: var(--secondary-color); + opacity: var(--path-opacity, var(--secondary-opacity)); + } + } +`; diff --git a/packages/webawesome/src/components/icon/icon.ts b/packages/webawesome/src/components/icon/icon.ts index b30ac07f6..85dbe554d 100644 --- a/packages/webawesome/src/components/icon/icon.ts +++ b/packages/webawesome/src/components/icon/icon.ts @@ -5,7 +5,7 @@ import { WaErrorEvent } from '../../events/error.js'; import { WaLoadEvent } from '../../events/load.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import styles from './icon.css'; +import styles from './icon.styles.js'; import { getDefaultIconFamily, getIconLibrary, unwatchIcon, watchIcon, type IconLibrary } from './library.js'; import type { HTMLTemplateResult, PropertyValues } from 'lit'; diff --git a/packages/webawesome/src/components/include/include.css b/packages/webawesome/src/components/include/include.css deleted file mode 100644 index 5d4e87f30..000000000 --- a/packages/webawesome/src/components/include/include.css +++ /dev/null @@ -1,3 +0,0 @@ -:host { - display: block; -} diff --git a/packages/webawesome/src/components/include/include.styles.ts b/packages/webawesome/src/components/include/include.styles.ts new file mode 100644 index 000000000..940a1557b --- /dev/null +++ b/packages/webawesome/src/components/include/include.styles.ts @@ -0,0 +1,7 @@ +import { css } from 'lit'; + +export default css` + :host { + display: block; + } +`; diff --git a/packages/webawesome/src/components/include/include.ts b/packages/webawesome/src/components/include/include.ts index 267047801..8f9c661f8 100644 --- a/packages/webawesome/src/components/include/include.ts +++ b/packages/webawesome/src/components/include/include.ts @@ -4,7 +4,7 @@ import { WaIncludeErrorEvent } from '../../events/include-error.js'; import { WaLoadEvent } from '../../events/load.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import styles from './include.css'; +import styles from './include.styles.js'; import { requestInclude } from './request.js'; /** diff --git a/packages/webawesome/src/components/input/input.css b/packages/webawesome/src/components/input/input.css deleted file mode 100644 index be657138a..000000000 --- a/packages/webawesome/src/components/input/input.css +++ /dev/null @@ -1,227 +0,0 @@ -:host { - border-width: 0; -} - -.text-field { - flex: auto; - display: flex; - align-items: stretch; - justify-content: start; - position: relative; - transition: inherit; - height: var(--wa-form-control-height); - border-color: var(--wa-form-control-border-color); - border-radius: var(--wa-form-control-border-radius); - border-style: var(--wa-form-control-border-style); - border-width: var(--wa-form-control-border-width); - cursor: text; - color: var(--wa-form-control-value-color); - font-size: var(--wa-form-control-value-font-size); - font-family: inherit; - font-weight: var(--wa-form-control-value-font-weight); - line-height: var(--wa-form-control-value-line-height); - vertical-align: middle; - width: 100%; - transition: - background-color var(--wa-transition-normal), - border var(--wa-transition-normal), - outline var(--wa-transition-fast); - transition-timing-function: var(--wa-transition-easing); - background-color: var(--wa-form-control-background-color); - box-shadow: var(--box-shadow); - padding: 0 var(--wa-form-control-padding-inline); - - &:focus-within { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); - } - - /* Style disabled inputs */ - &:has(:disabled) { - cursor: not-allowed; - opacity: 0.5; - } -} - -/* Appearance modifiers */ -:host([appearance='outlined']) .text-field { - background-color: var(--wa-form-control-background-color); - border-color: var(--wa-form-control-border-color); -} - -:host([appearance='filled']) .text-field { - background-color: var(--wa-color-neutral-fill-quiet); - border-color: var(--wa-color-neutral-fill-quiet); -} - -:host([appearance='filled-outlined']) .text-field { - background-color: var(--wa-color-neutral-fill-quiet); - border-color: var(--wa-form-control-border-color); -} - -:host([pill]) .text-field { - border-radius: var(--wa-border-radius-pill) !important; -} - -.text-field { - /* Show autofill styles over the entire text field, not just the native */ - &:has(:autofill), - &:has(:-webkit-autofill) { - background-color: var(--wa-color-brand-fill-quiet) !important; - } - - input, - textarea { - /* - Fixes an alignment issue with placeholders. - https://github.com/shoelace-style/webawesome/issues/342 - */ - height: 100%; - - padding: 0; - border: none; - outline: none; - box-shadow: none; - margin: 0; - cursor: inherit; - -webkit-appearance: none; - font: inherit; - - /* Turn off Safari's autofill styles */ - &:-webkit-autofill, - &:-webkit-autofill:hover, - &:-webkit-autofill:focus, - &:-webkit-autofill:active { - -webkit-background-clip: text; - background-color: transparent; - -webkit-text-fill-color: inherit; - } - } -} - -input { - flex: 1 1 auto; - min-width: 0; - height: 100%; - transition: inherit; - - /* prettier-ignore */ - background-color: rgb(118 118 118 / 0); /* ensures proper placeholder styles in webkit's date input */ - height: calc(var(--wa-form-control-height) - var(--border-width) * 2); - padding-block: 0; - color: inherit; - - &:autofill { - &, - &:hover, - &:focus, - &:active { - box-shadow: none; - caret-color: var(--wa-form-control-value-color); - } - } - - &::placeholder { - color: var(--wa-form-control-placeholder-color); - user-select: none; - -webkit-user-select: none; - } - - &::-webkit-search-decoration, - &::-webkit-search-cancel-button, - &::-webkit-search-results-button, - &::-webkit-search-results-decoration { - -webkit-appearance: none; - } - - &:focus { - outline: none; - } -} - -textarea { - &:autofill { - &, - &:hover, - &:focus, - &:active { - box-shadow: none; - caret-color: var(--wa-form-control-value-color); - } - } - - &::placeholder { - color: var(--wa-form-control-placeholder-color); - user-select: none; - -webkit-user-select: none; - } -} - -.start, -.end { - display: inline-flex; - flex: 0 0 auto; - align-items: center; - cursor: default; - - &::slotted(wa-icon) { - color: var(--wa-color-neutral-on-quiet); - } -} - -.start::slotted(*) { - margin-inline-end: var(--wa-form-control-padding-inline); -} - -.end::slotted(*) { - margin-inline-start: var(--wa-form-control-padding-inline); -} - -/* - * Clearable + Password Toggle - */ - -.clear, -.password-toggle { - display: inline-flex; - align-items: center; - justify-content: center; - font-size: inherit; - color: var(--wa-color-neutral-on-quiet); - border: none; - background: none; - padding: 0; - transition: var(--wa-transition-normal) color; - cursor: pointer; - margin-inline-start: var(--wa-form-control-padding-inline); - - @media (hover: hover) { - &:hover { - color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover)); - } - } - - &:active { - color: color-mix(in oklab, currentColor, var(--wa-color-mix-active)); - } - - &:focus { - outline: none; - } -} - -/* Don't show the browser's password toggle in Edge */ -::-ms-reveal { - display: none; -} - -/* Hide the built-in number spinner */ -:host([without-spin-buttons]) input[type='number'] { - -moz-appearance: textfield; - - &::-webkit-outer-spin-button, - &::-webkit-inner-spin-button { - -webkit-appearance: none; - display: none; - } -} diff --git a/packages/webawesome/src/components/input/input.styles.ts b/packages/webawesome/src/components/input/input.styles.ts new file mode 100644 index 000000000..5332a7d69 --- /dev/null +++ b/packages/webawesome/src/components/input/input.styles.ts @@ -0,0 +1,231 @@ +import { css } from 'lit'; + +export default css` + :host { + border-width: 0; + } + + .text-field { + flex: auto; + display: flex; + align-items: stretch; + justify-content: start; + position: relative; + transition: inherit; + height: var(--wa-form-control-height); + border-color: var(--wa-form-control-border-color); + border-radius: var(--wa-form-control-border-radius); + border-style: var(--wa-form-control-border-style); + border-width: var(--wa-form-control-border-width); + cursor: text; + color: var(--wa-form-control-value-color); + font-size: var(--wa-form-control-value-font-size); + font-family: inherit; + font-weight: var(--wa-form-control-value-font-weight); + line-height: var(--wa-form-control-value-line-height); + vertical-align: middle; + width: 100%; + transition: + background-color var(--wa-transition-normal), + border var(--wa-transition-normal), + outline var(--wa-transition-fast); + transition-timing-function: var(--wa-transition-easing); + background-color: var(--wa-form-control-background-color); + box-shadow: var(--box-shadow); + padding: 0 var(--wa-form-control-padding-inline); + + &:focus-within { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + + /* Style disabled inputs */ + &:has(:disabled) { + cursor: not-allowed; + opacity: 0.5; + } + } + + /* Appearance modifiers */ + :host([appearance='outlined']) .text-field { + background-color: var(--wa-form-control-background-color); + border-color: var(--wa-form-control-border-color); + } + + :host([appearance='filled']) .text-field { + background-color: var(--wa-color-neutral-fill-quiet); + border-color: var(--wa-color-neutral-fill-quiet); + } + + :host([appearance='filled-outlined']) .text-field { + background-color: var(--wa-color-neutral-fill-quiet); + border-color: var(--wa-form-control-border-color); + } + + :host([pill]) .text-field { + border-radius: var(--wa-border-radius-pill) !important; + } + + .text-field { + /* Show autofill styles over the entire text field, not just the native */ + &:has(:autofill), + &:has(:-webkit-autofill) { + background-color: var(--wa-color-brand-fill-quiet) !important; + } + + input, + textarea { + /* + Fixes an alignment issue with placeholders. + https://github.com/shoelace-style/webawesome/issues/342 + */ + height: 100%; + + padding: 0; + border: none; + outline: none; + box-shadow: none; + margin: 0; + cursor: inherit; + -webkit-appearance: none; + font: inherit; + + /* Turn off Safari's autofill styles */ + &:-webkit-autofill, + &:-webkit-autofill:hover, + &:-webkit-autofill:focus, + &:-webkit-autofill:active { + -webkit-background-clip: text; + background-color: transparent; + -webkit-text-fill-color: inherit; + } + } + } + + input { + flex: 1 1 auto; + min-width: 0; + height: 100%; + transition: inherit; + + /* prettier-ignore */ + background-color: rgb(118 118 118 / 0); /* ensures proper placeholder styles in webkit's date input */ + height: calc(var(--wa-form-control-height) - var(--border-width) * 2); + padding-block: 0; + color: inherit; + + &:autofill { + &, + &:hover, + &:focus, + &:active { + box-shadow: none; + caret-color: var(--wa-form-control-value-color); + } + } + + &::placeholder { + color: var(--wa-form-control-placeholder-color); + user-select: none; + -webkit-user-select: none; + } + + &::-webkit-search-decoration, + &::-webkit-search-cancel-button, + &::-webkit-search-results-button, + &::-webkit-search-results-decoration { + -webkit-appearance: none; + } + + &:focus { + outline: none; + } + } + + textarea { + &:autofill { + &, + &:hover, + &:focus, + &:active { + box-shadow: none; + caret-color: var(--wa-form-control-value-color); + } + } + + &::placeholder { + color: var(--wa-form-control-placeholder-color); + user-select: none; + -webkit-user-select: none; + } + } + + .start, + .end { + display: inline-flex; + flex: 0 0 auto; + align-items: center; + cursor: default; + + &::slotted(wa-icon) { + color: var(--wa-color-neutral-on-quiet); + } + } + + .start::slotted(*) { + margin-inline-end: var(--wa-form-control-padding-inline); + } + + .end::slotted(*) { + margin-inline-start: var(--wa-form-control-padding-inline); + } + + /* + * Clearable + Password Toggle + */ + + .clear, + .password-toggle { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: inherit; + color: var(--wa-color-neutral-on-quiet); + border: none; + background: none; + padding: 0; + transition: var(--wa-transition-normal) color; + cursor: pointer; + margin-inline-start: var(--wa-form-control-padding-inline); + + @media (hover: hover) { + &:hover { + color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover)); + } + } + + &:active { + color: color-mix(in oklab, currentColor, var(--wa-color-mix-active)); + } + + &:focus { + outline: none; + } + } + + /* Don't show the browser's password toggle in Edge */ + ::-ms-reveal { + display: none; + } + + /* Hide the built-in number spinner */ + :host([without-spin-buttons]) input[type='number'] { + -moz-appearance: textfield; + + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + -webkit-appearance: none; + display: none; + } + } +`; diff --git a/packages/webawesome/src/components/input/input.ts b/packages/webawesome/src/components/input/input.ts index 4be80e1b0..3dfa32771 100644 --- a/packages/webawesome/src/components/input/input.ts +++ b/packages/webawesome/src/components/input/input.ts @@ -9,11 +9,11 @@ import { submitOnEnter } from '../../internal/submit-on-enter.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 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 { LocalizeController } from '../../utilities/localize.js'; import '../icon/icon.js'; -import styles from './input.css'; +import styles from './input.styles.js'; /** * @summary Inputs collect data from the user. diff --git a/packages/webawesome/src/components/intersection-observer/intersection-observer.css b/packages/webawesome/src/components/intersection-observer/intersection-observer.css deleted file mode 100644 index 92d692cdd..000000000 --- a/packages/webawesome/src/components/intersection-observer/intersection-observer.css +++ /dev/null @@ -1,3 +0,0 @@ -:host { - display: contents; -} diff --git a/packages/webawesome/src/components/intersection-observer/intersection-observer.styles.ts b/packages/webawesome/src/components/intersection-observer/intersection-observer.styles.ts new file mode 100644 index 000000000..1ef4bf6f3 --- /dev/null +++ b/packages/webawesome/src/components/intersection-observer/intersection-observer.styles.ts @@ -0,0 +1,7 @@ +import { css } from 'lit'; + +export default css` + :host { + display: contents; + } +`; diff --git a/packages/webawesome/src/components/intersection-observer/intersection-observer.ts b/packages/webawesome/src/components/intersection-observer/intersection-observer.ts index e703be0d0..5dbdb1eae 100644 --- a/packages/webawesome/src/components/intersection-observer/intersection-observer.ts +++ b/packages/webawesome/src/components/intersection-observer/intersection-observer.ts @@ -5,7 +5,7 @@ import { clamp } from '../../internal/math.js'; import { parseSpaceDelimitedTokens } from '../../internal/parse.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import styles from './intersection-observer.css'; +import styles from './intersection-observer.styles.js'; /** * @summary Tracks immediate child elements and fires events as they move in and out of view. diff --git a/packages/webawesome/src/components/mutation-observer/mutation-observer.css b/packages/webawesome/src/components/mutation-observer/mutation-observer.css deleted file mode 100644 index 92d692cdd..000000000 --- a/packages/webawesome/src/components/mutation-observer/mutation-observer.css +++ /dev/null @@ -1,3 +0,0 @@ -:host { - display: contents; -} diff --git a/packages/webawesome/src/components/mutation-observer/mutation-observer.styles.ts b/packages/webawesome/src/components/mutation-observer/mutation-observer.styles.ts new file mode 100644 index 000000000..1ef4bf6f3 --- /dev/null +++ b/packages/webawesome/src/components/mutation-observer/mutation-observer.styles.ts @@ -0,0 +1,7 @@ +import { css } from 'lit'; + +export default css` + :host { + display: contents; + } +`; diff --git a/packages/webawesome/src/components/mutation-observer/mutation-observer.ts b/packages/webawesome/src/components/mutation-observer/mutation-observer.ts index 5c0ad0c6b..28fe4b97d 100644 --- a/packages/webawesome/src/components/mutation-observer/mutation-observer.ts +++ b/packages/webawesome/src/components/mutation-observer/mutation-observer.ts @@ -3,7 +3,7 @@ import { customElement, property } from 'lit/decorators.js'; import { WaMutationEvent } from '../../events/mutation.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import styles from './mutation-observer.css'; +import styles from './mutation-observer.styles.js'; /** * @summary The Mutation Observer component offers a thin, declarative interface to the [`MutationObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver). diff --git a/packages/webawesome/src/components/option/option.css b/packages/webawesome/src/components/option/option.css deleted file mode 100644 index 31ec2647a..000000000 --- a/packages/webawesome/src/components/option/option.css +++ /dev/null @@ -1,80 +0,0 @@ -:host { - display: block; - color: var(--wa-color-text-normal); - -webkit-user-select: none; - user-select: none; - - position: relative; - display: flex; - align-items: center; - font: inherit; - padding: 0.5em 1em 0.5em 0.25em; - line-height: var(--wa-line-height-condensed); - transition: fill var(--wa-transition-normal) var(--wa-transition-easing); - cursor: pointer; -} - -:host(:focus) { - outline: none; -} - -@media (hover: hover) { - :host(:not([disabled], :state(current)):is(:state(hover), :hover)) { - background-color: var(--wa-color-neutral-fill-normal); - color: var(--wa-color-neutral-on-normal); - } -} - -:host(:state(current)), -:host([disabled]:state(current)) { - background-color: var(--wa-color-brand-fill-loud); - color: var(--wa-color-brand-on-loud); - opacity: 1; -} - -:host([disabled]) { - outline: none; - opacity: 0.5; - cursor: not-allowed; -} - -.label { - flex: 1 1 auto; - display: inline-block; -} - -.check { - flex: 0 0 auto; - display: flex; - align-items: center; - justify-content: center; - font-size: var(--wa-font-size-smaller); - visibility: hidden; - width: 2em; -} - -:host(:state(selected)) .check { - visibility: visible; -} - -.start, -.end { - flex: 0 0 auto; - display: flex; - align-items: center; -} - -.start::slotted(*) { - margin-inline-end: 0.5em; -} - -.end::slotted(*) { - margin-inline-start: 0.5em; -} - -@media (forced-colors: active) { - :host(:hover:not([aria-disabled='true'])) { - outline: dashed 1px SelectedItem; - outline-offset: -1px; - } -} diff --git a/packages/webawesome/src/components/option/option.styles.ts b/packages/webawesome/src/components/option/option.styles.ts new file mode 100644 index 000000000..a0779c251 --- /dev/null +++ b/packages/webawesome/src/components/option/option.styles.ts @@ -0,0 +1,84 @@ +import { css } from 'lit'; + +export default css` + :host { + display: block; + color: var(--wa-color-text-normal); + -webkit-user-select: none; + user-select: none; + + position: relative; + display: flex; + align-items: center; + font: inherit; + padding: 0.5em 1em 0.5em 0.25em; + line-height: var(--wa-line-height-condensed); + transition: fill var(--wa-transition-normal) var(--wa-transition-easing); + cursor: pointer; + } + + :host(:focus) { + outline: none; + } + + @media (hover: hover) { + :host(:not([disabled], :state(current)):is(:state(hover), :hover)) { + background-color: var(--wa-color-neutral-fill-normal); + color: var(--wa-color-neutral-on-normal); + } + } + + :host(:state(current)), + :host([disabled]:state(current)) { + background-color: var(--wa-color-brand-fill-loud); + color: var(--wa-color-brand-on-loud); + opacity: 1; + } + + :host([disabled]) { + outline: none; + opacity: 0.5; + cursor: not-allowed; + } + + .label { + flex: 1 1 auto; + display: inline-block; + } + + .check { + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: center; + font-size: var(--wa-font-size-smaller); + visibility: hidden; + width: 2em; + } + + :host(:state(selected)) .check { + visibility: visible; + } + + .start, + .end { + flex: 0 0 auto; + display: flex; + align-items: center; + } + + .start::slotted(*) { + margin-inline-end: 0.5em; + } + + .end::slotted(*) { + margin-inline-start: 0.5em; + } + + @media (forced-colors: active) { + :host(:hover:not([aria-disabled='true'])) { + outline: dashed 1px SelectedItem; + outline-offset: -1px; + } + } +`; diff --git a/packages/webawesome/src/components/option/option.ts b/packages/webawesome/src/components/option/option.ts index 5c0f10957..852957ade 100644 --- a/packages/webawesome/src/components/option/option.ts +++ b/packages/webawesome/src/components/option/option.ts @@ -5,7 +5,7 @@ import getText from '../../internal/get-text.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import { LocalizeController } from '../../utilities/localize.js'; import '../icon/icon.js'; -import styles from './option.css'; +import styles from './option.styles.js'; /** * @summary Options define the selectable items within a select component. diff --git a/packages/webawesome/src/components/popover/popover.css b/packages/webawesome/src/components/popover/popover.css deleted file mode 100644 index 1afa32574..000000000 --- a/packages/webawesome/src/components/popover/popover.css +++ /dev/null @@ -1,91 +0,0 @@ -:host { - --arrow-size: 0.375rem; - --max-width: 25rem; - --show-duration: 100ms; - --hide-duration: 100ms; - - /* Internal calculated properties */ - --arrow-diagonal-size: calc((var(--arrow-size) * sin(45deg))); - - display: contents; - - /** Defaults for inherited CSS properties */ - font-size: var(--wa-font-size-m); - line-height: var(--wa-line-height-normal); - text-align: start; - white-space: normal; -} - -/* The native dialog element */ -.dialog { - display: none; - position: fixed; - inset: 0; - width: 100%; - height: 100%; - margin: 0; - padding: 0; - border: none; - background: transparent; - overflow: visible; - pointer-events: none; - - &:focus { - outline: none; - } - - &[open] { - display: block; - } -} - -/* The element */ -.popover { - --arrow-size: inherit; - --show-duration: inherit; - --hide-duration: inherit; - - pointer-events: auto; - - &::part(arrow) { - background-color: var(--wa-color-surface-default); - border-top: none; - border-left: none; - border-bottom: solid var(--wa-panel-border-width) var(--wa-color-surface-border); - border-right: solid var(--wa-panel-border-width) var(--wa-color-surface-border); - box-shadow: none; - } -} - -.popover[placement^='top']::part(popup) { - transform-origin: bottom; -} - -.popover[placement^='bottom']::part(popup) { - transform-origin: top; -} - -.popover[placement^='left']::part(popup) { - transform-origin: right; -} - -.popover[placement^='right']::part(popup) { - transform-origin: left; -} - -/* Body */ -.body { - display: flex; - flex-direction: column; - width: max-content; - max-width: var(--max-width); - padding: var(--wa-space-l); - background-color: var(--wa-color-surface-default); - border: var(--wa-panel-border-width) solid var(--wa-color-surface-border); - border-radius: var(--wa-panel-border-radius); - border-style: var(--wa-panel-border-style); - box-shadow: var(--wa-shadow-l); - color: var(--wa-color-text-normal); - user-select: none; - -webkit-user-select: none; -} diff --git a/packages/webawesome/src/components/popover/popover.styles.ts b/packages/webawesome/src/components/popover/popover.styles.ts new file mode 100644 index 000000000..f2163e8e2 --- /dev/null +++ b/packages/webawesome/src/components/popover/popover.styles.ts @@ -0,0 +1,95 @@ +import { css } from 'lit'; + +export default css` + :host { + --arrow-size: 0.375rem; + --max-width: 25rem; + --show-duration: 100ms; + --hide-duration: 100ms; + + /* Internal calculated properties */ + --arrow-diagonal-size: calc((var(--arrow-size) * sin(45deg))); + + display: contents; + + /** Defaults for inherited CSS properties */ + font-size: var(--wa-font-size-m); + line-height: var(--wa-line-height-normal); + text-align: start; + white-space: normal; + } + + /* The native dialog element */ + .dialog { + display: none; + position: fixed; + inset: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + border: none; + background: transparent; + overflow: visible; + pointer-events: none; + + &:focus { + outline: none; + } + + &[open] { + display: block; + } + } + + /* The element */ + .popover { + --arrow-size: inherit; + --show-duration: inherit; + --hide-duration: inherit; + + pointer-events: auto; + + &::part(arrow) { + background-color: var(--wa-color-surface-default); + border-top: none; + border-left: none; + border-bottom: solid var(--wa-panel-border-width) var(--wa-color-surface-border); + border-right: solid var(--wa-panel-border-width) var(--wa-color-surface-border); + box-shadow: none; + } + } + + .popover[placement^='top']::part(popup) { + transform-origin: bottom; + } + + .popover[placement^='bottom']::part(popup) { + transform-origin: top; + } + + .popover[placement^='left']::part(popup) { + transform-origin: right; + } + + .popover[placement^='right']::part(popup) { + transform-origin: left; + } + + /* Body */ + .body { + display: flex; + flex-direction: column; + width: max-content; + max-width: var(--max-width); + padding: var(--wa-space-l); + background-color: var(--wa-color-surface-default); + border: var(--wa-panel-border-width) solid var(--wa-color-surface-border); + border-radius: var(--wa-panel-border-radius); + border-style: var(--wa-panel-border-style); + box-shadow: var(--wa-shadow-l); + color: var(--wa-color-text-normal); + user-select: none; + -webkit-user-select: none; + } +`; diff --git a/packages/webawesome/src/components/popover/popover.ts b/packages/webawesome/src/components/popover/popover.ts index 63ed3a14a..60eaeba84 100644 --- a/packages/webawesome/src/components/popover/popover.ts +++ b/packages/webawesome/src/components/popover/popover.ts @@ -12,7 +12,7 @@ import { uniqueId } from '../../internal/math.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import WaPopup from '../popup/popup.js'; -import styles from './popover.css'; +import styles from './popover.styles.js'; const openPopovers = new Set(); diff --git a/packages/webawesome/src/components/popup/popup.css b/packages/webawesome/src/components/popup/popup.css deleted file mode 100644 index 7db983610..000000000 --- a/packages/webawesome/src/components/popup/popup.css +++ /dev/null @@ -1,121 +0,0 @@ -:host { - --arrow-color: black; - --arrow-size: var(--wa-tooltip-arrow-size); - --show-duration: 100ms; - --hide-duration: 100ms; - - /* - * These properties are computed to account for the arrow's dimensions after being rotated 45º. The constant - * 0.7071 is derived from sin(45), which is the diagonal size of the arrow's container after rotating. - */ - --arrow-size-diagonal: calc(var(--arrow-size) * 0.7071); - --arrow-padding-offset: calc(var(--arrow-size-diagonal) - var(--arrow-size)); - - display: contents; -} - -.popup { - position: absolute; - isolation: isolate; - max-width: var(--auto-size-available-width, none); - max-height: var(--auto-size-available-height, none); - - /* Clear UA styles for [popover] */ - :where(&) { - inset: unset; - padding: unset; - margin: unset; - width: unset; - height: unset; - color: unset; - background: unset; - border: unset; - overflow: unset; - } -} - -.popup-fixed { - position: fixed; -} - -.popup:not(.popup-active) { - display: none; -} - -.arrow { - position: absolute; - width: calc(var(--arrow-size-diagonal) * 2); - height: calc(var(--arrow-size-diagonal) * 2); - rotate: 45deg; - background: var(--arrow-color); - z-index: 3; -} - -:host([data-current-placement~='left']) .arrow { - rotate: -45deg; -} - -:host([data-current-placement~='right']) .arrow { - rotate: 135deg; -} - -:host([data-current-placement~='bottom']) .arrow { - rotate: 225deg; -} - -/* Hover bridge */ -.popup-hover-bridge:not(.popup-hover-bridge-visible) { - display: none; -} - -.popup-hover-bridge { - position: fixed; - z-index: 899; - top: 0; - right: 0; - bottom: 0; - left: 0; - clip-path: polygon( - var(--hover-bridge-top-left-x, 0) var(--hover-bridge-top-left-y, 0), - var(--hover-bridge-top-right-x, 0) var(--hover-bridge-top-right-y, 0), - var(--hover-bridge-bottom-right-x, 0) var(--hover-bridge-bottom-right-y, 0), - var(--hover-bridge-bottom-left-x, 0) var(--hover-bridge-bottom-left-y, 0) - ); -} - -/* Built-in animations */ -.show { - animation: show var(--show-duration) ease; -} - -.hide { - animation: show var(--hide-duration) ease reverse; -} - -@keyframes show { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.show-with-scale { - animation: show-with-scale var(--show-duration) ease; -} - -.hide-with-scale { - animation: show-with-scale var(--hide-duration) ease reverse; -} - -@keyframes show-with-scale { - from { - opacity: 0; - scale: 0.8; - } - to { - opacity: 1; - scale: 1; - } -} diff --git a/packages/webawesome/src/components/popup/popup.styles.ts b/packages/webawesome/src/components/popup/popup.styles.ts new file mode 100644 index 000000000..92932f04c --- /dev/null +++ b/packages/webawesome/src/components/popup/popup.styles.ts @@ -0,0 +1,125 @@ +import { css } from 'lit'; + +export default css` + :host { + --arrow-color: black; + --arrow-size: var(--wa-tooltip-arrow-size); + --show-duration: 100ms; + --hide-duration: 100ms; + + /* + * These properties are computed to account for the arrow's dimensions after being rotated 45º. The constant + * 0.7071 is derived from sin(45), which is the diagonal size of the arrow's container after rotating. + */ + --arrow-size-diagonal: calc(var(--arrow-size) * 0.7071); + --arrow-padding-offset: calc(var(--arrow-size-diagonal) - var(--arrow-size)); + + display: contents; + } + + .popup { + position: absolute; + isolation: isolate; + max-width: var(--auto-size-available-width, none); + max-height: var(--auto-size-available-height, none); + + /* Clear UA styles for [popover] */ + :where(&) { + inset: unset; + padding: unset; + margin: unset; + width: unset; + height: unset; + color: unset; + background: unset; + border: unset; + overflow: unset; + } + } + + .popup-fixed { + position: fixed; + } + + .popup:not(.popup-active) { + display: none; + } + + .arrow { + position: absolute; + width: calc(var(--arrow-size-diagonal) * 2); + height: calc(var(--arrow-size-diagonal) * 2); + rotate: 45deg; + background: var(--arrow-color); + z-index: 3; + } + + :host([data-current-placement~='left']) .arrow { + rotate: -45deg; + } + + :host([data-current-placement~='right']) .arrow { + rotate: 135deg; + } + + :host([data-current-placement~='bottom']) .arrow { + rotate: 225deg; + } + + /* Hover bridge */ + .popup-hover-bridge:not(.popup-hover-bridge-visible) { + display: none; + } + + .popup-hover-bridge { + position: fixed; + z-index: 899; + top: 0; + right: 0; + bottom: 0; + left: 0; + clip-path: polygon( + var(--hover-bridge-top-left-x, 0) var(--hover-bridge-top-left-y, 0), + var(--hover-bridge-top-right-x, 0) var(--hover-bridge-top-right-y, 0), + var(--hover-bridge-bottom-right-x, 0) var(--hover-bridge-bottom-right-y, 0), + var(--hover-bridge-bottom-left-x, 0) var(--hover-bridge-bottom-left-y, 0) + ); + } + + /* Built-in animations */ + .show { + animation: show var(--show-duration) ease; + } + + .hide { + animation: show var(--hide-duration) ease reverse; + } + + @keyframes show { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + .show-with-scale { + animation: show-with-scale var(--show-duration) ease; + } + + .hide-with-scale { + animation: show-with-scale var(--hide-duration) ease reverse; + } + + @keyframes show-with-scale { + from { + opacity: 0; + scale: 0.8; + } + to { + opacity: 1; + scale: 1; + } + } +`; diff --git a/packages/webawesome/src/components/popup/popup.ts b/packages/webawesome/src/components/popup/popup.ts index 80ec2f254..cd95780e5 100644 --- a/packages/webawesome/src/components/popup/popup.ts +++ b/packages/webawesome/src/components/popup/popup.ts @@ -17,7 +17,7 @@ import { classMap } from 'lit/directives/class-map.js'; import { WaRepositionEvent } from '../../events/reposition.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import { LocalizeController } from '../../utilities/localize.js'; -import styles from './popup.css'; +import styles from './popup.styles.js'; export interface VirtualElement { getBoundingClientRect: () => DOMRect; diff --git a/packages/webawesome/src/components/progress-bar/progress-bar.css b/packages/webawesome/src/components/progress-bar/progress-bar.css deleted file mode 100644 index 821320cc4..000000000 --- a/packages/webawesome/src/components/progress-bar/progress-bar.css +++ /dev/null @@ -1,66 +0,0 @@ -:host { - --track-height: 1rem; - --track-color: var(--wa-color-neutral-fill-normal); - --indicator-color: var(--wa-color-brand-fill-loud); - - display: flex; -} - -.progress-bar { - flex: 1 1 auto; - display: flex; - position: relative; - overflow: hidden; - height: var(--track-height); - border-radius: var(--wa-border-radius-pill); - background-color: var(--track-color); - color: var(--wa-color-brand-on-loud); - font-size: var(--wa-font-size-s); -} - -.indicator { - width: var(--percentage); - display: flex; - align-items: center; - justify-content: center; - background-color: var(--indicator-color); - text-align: center; - white-space: nowrap; - overflow: hidden; - line-height: 1; - font-weight: var(--wa-font-weight-semibold); - transition: all var(--wa-transition-slow, 200ms) var(--wa-transition-easing, ease); - user-select: none; - -webkit-user-select: none; -} - -/* Indeterminate */ -:host([indeterminate]) .indicator { - position: absolute; - inset-block: 0; - inline-size: 50%; - animation: wa-progress-indeterminate 2.5s infinite cubic-bezier(0.37, 0, 0.63, 1); -} - -@media (forced-colors: active) { - .progress-bar { - outline: solid 1px SelectedItem; - background-color: var(--wa-color-surface-default); - } - - .indicator { - outline: solid 1px SelectedItem; - background-color: SelectedItem; - } -} - -@keyframes wa-progress-indeterminate { - 0% { - inset-inline-start: -50%; - } - - 75%, - 100% { - inset-inline-start: 100%; - } -} diff --git a/packages/webawesome/src/components/progress-bar/progress-bar.styles.ts b/packages/webawesome/src/components/progress-bar/progress-bar.styles.ts new file mode 100644 index 000000000..b2ed39885 --- /dev/null +++ b/packages/webawesome/src/components/progress-bar/progress-bar.styles.ts @@ -0,0 +1,70 @@ +import { css } from 'lit'; + +export default css` + :host { + --track-height: 1rem; + --track-color: var(--wa-color-neutral-fill-normal); + --indicator-color: var(--wa-color-brand-fill-loud); + + display: flex; + } + + .progress-bar { + flex: 1 1 auto; + display: flex; + position: relative; + overflow: hidden; + height: var(--track-height); + border-radius: var(--wa-border-radius-pill); + background-color: var(--track-color); + color: var(--wa-color-brand-on-loud); + font-size: var(--wa-font-size-s); + } + + .indicator { + width: var(--percentage); + display: flex; + align-items: center; + justify-content: center; + background-color: var(--indicator-color); + text-align: center; + white-space: nowrap; + overflow: hidden; + line-height: 1; + font-weight: var(--wa-font-weight-semibold); + transition: all var(--wa-transition-slow, 200ms) var(--wa-transition-easing, ease); + user-select: none; + -webkit-user-select: none; + } + + /* Indeterminate */ + :host([indeterminate]) .indicator { + position: absolute; + inset-block: 0; + inline-size: 50%; + animation: wa-progress-indeterminate 2.5s infinite cubic-bezier(0.37, 0, 0.63, 1); + } + + @media (forced-colors: active) { + .progress-bar { + outline: solid 1px SelectedItem; + background-color: var(--wa-color-surface-default); + } + + .indicator { + outline: solid 1px SelectedItem; + background-color: SelectedItem; + } + } + + @keyframes wa-progress-indeterminate { + 0% { + inset-inline-start: -50%; + } + + 75%, + 100% { + inset-inline-start: 100%; + } + } +`; diff --git a/packages/webawesome/src/components/progress-bar/progress-bar.ts b/packages/webawesome/src/components/progress-bar/progress-bar.ts index 7ef5a3dce..708c72f3a 100644 --- a/packages/webawesome/src/components/progress-bar/progress-bar.ts +++ b/packages/webawesome/src/components/progress-bar/progress-bar.ts @@ -5,7 +5,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { clamp } from '../../internal/math.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import { LocalizeController } from '../../utilities/localize.js'; -import styles from './progress-bar.css'; +import styles from './progress-bar.styles.js'; /** * @summary Progress bars are used to show the status of an ongoing operation. diff --git a/packages/webawesome/src/components/progress-ring/progress-ring.css b/packages/webawesome/src/components/progress-ring/progress-ring.css deleted file mode 100644 index 19f95b903..000000000 --- a/packages/webawesome/src/components/progress-ring/progress-ring.css +++ /dev/null @@ -1,64 +0,0 @@ -:host { - --size: 8rem; - --track-width: 0.25em; /* avoid using rems here */ - --track-color: var(--wa-color-neutral-fill-normal); - --indicator-width: var(--track-width); - --indicator-color: var(--wa-color-brand-fill-loud); - --indicator-transition-duration: 0.35s; - - display: inline-flex; -} - -.progress-ring { - display: inline-flex; - align-items: center; - justify-content: center; - position: relative; -} - -.image { - width: var(--size); - height: var(--size); - rotate: -90deg; - transform-origin: 50% 50%; -} - -.track, -.indicator { - --radius: calc(var(--size) / 2 - max(var(--track-width), var(--indicator-width)) * 0.5); - --circumference: calc(var(--radius) * 2 * 3.141592654); - - fill: none; - r: var(--radius); - cx: calc(var(--size) / 2); - cy: calc(var(--size) / 2); -} - -.track { - stroke: var(--track-color); - stroke-width: var(--track-width); -} - -.indicator { - stroke: var(--indicator-color); - stroke-width: var(--indicator-width); - stroke-linecap: round; - transition-property: stroke-dashoffset; - transition-duration: var(--indicator-transition-duration); - stroke-dasharray: var(--circumference) var(--circumference); - stroke-dashoffset: calc(var(--circumference) - var(--percentage) * var(--circumference)); -} - -.label { - display: flex; - align-items: center; - justify-content: center; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - text-align: center; - user-select: none; - -webkit-user-select: none; -} diff --git a/packages/webawesome/src/components/progress-ring/progress-ring.styles.ts b/packages/webawesome/src/components/progress-ring/progress-ring.styles.ts new file mode 100644 index 000000000..9af84ea77 --- /dev/null +++ b/packages/webawesome/src/components/progress-ring/progress-ring.styles.ts @@ -0,0 +1,68 @@ +import { css } from 'lit'; + +export default css` + :host { + --size: 8rem; + --track-width: 0.25em; /* avoid using rems here */ + --track-color: var(--wa-color-neutral-fill-normal); + --indicator-width: var(--track-width); + --indicator-color: var(--wa-color-brand-fill-loud); + --indicator-transition-duration: 0.35s; + + display: inline-flex; + } + + .progress-ring { + display: inline-flex; + align-items: center; + justify-content: center; + position: relative; + } + + .image { + width: var(--size); + height: var(--size); + rotate: -90deg; + transform-origin: 50% 50%; + } + + .track, + .indicator { + --radius: calc(var(--size) / 2 - max(var(--track-width), var(--indicator-width)) * 0.5); + --circumference: calc(var(--radius) * 2 * 3.141592654); + + fill: none; + r: var(--radius); + cx: calc(var(--size) / 2); + cy: calc(var(--size) / 2); + } + + .track { + stroke: var(--track-color); + stroke-width: var(--track-width); + } + + .indicator { + stroke: var(--indicator-color); + stroke-width: var(--indicator-width); + stroke-linecap: round; + transition-property: stroke-dashoffset; + transition-duration: var(--indicator-transition-duration); + stroke-dasharray: var(--circumference) var(--circumference); + stroke-dashoffset: calc(var(--circumference) - var(--percentage) * var(--circumference)); + } + + .label { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; + user-select: none; + -webkit-user-select: none; + } +`; diff --git a/packages/webawesome/src/components/progress-ring/progress-ring.ts b/packages/webawesome/src/components/progress-ring/progress-ring.ts index 53ef182a8..93187de19 100644 --- a/packages/webawesome/src/components/progress-ring/progress-ring.ts +++ b/packages/webawesome/src/components/progress-ring/progress-ring.ts @@ -3,7 +3,7 @@ import { html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import { LocalizeController } from '../../utilities/localize.js'; -import styles from './progress-ring.css'; +import styles from './progress-ring.styles.js'; /** * @summary Progress rings are used to show the progress of a determinate operation in a circular fashion. diff --git a/packages/webawesome/src/components/qr-code/qr-code.css b/packages/webawesome/src/components/qr-code/qr-code.css deleted file mode 100644 index 2777d853f..000000000 --- a/packages/webawesome/src/components/qr-code/qr-code.css +++ /dev/null @@ -1,12 +0,0 @@ -:host { - --size: 128px; - display: inline-block; -} - -:host, -canvas { - max-width: var(--size); - max-height: var(--size); - width: var(--size); - height: var(--size); -} diff --git a/packages/webawesome/src/components/qr-code/qr-code.styles.ts b/packages/webawesome/src/components/qr-code/qr-code.styles.ts new file mode 100644 index 000000000..b790cc3b0 --- /dev/null +++ b/packages/webawesome/src/components/qr-code/qr-code.styles.ts @@ -0,0 +1,16 @@ +import { css } from 'lit'; + +export default css` + :host { + --size: 128px; + display: inline-block; + } + + :host, + canvas { + max-width: var(--size); + max-height: var(--size); + width: var(--size); + height: var(--size); + } +`; diff --git a/packages/webawesome/src/components/qr-code/qr-code.ts b/packages/webawesome/src/components/qr-code/qr-code.ts index dcc211857..a4247d394 100644 --- a/packages/webawesome/src/components/qr-code/qr-code.ts +++ b/packages/webawesome/src/components/qr-code/qr-code.ts @@ -4,7 +4,7 @@ import { customElement, property, query, state } from 'lit/decorators.js'; import type _QrCreator from 'qr-creator'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import styles from './qr-code.css'; +import styles from './qr-code.styles.js'; let QrCreator: _QrCreator.default; diff --git a/packages/webawesome/src/components/radio-group/radio-group.css b/packages/webawesome/src/components/radio-group/radio-group.css deleted file mode 100644 index 8b60d8ab2..000000000 --- a/packages/webawesome/src/components/radio-group/radio-group.css +++ /dev/null @@ -1,36 +0,0 @@ -:host { - display: block; -} - -.form-control { - position: relative; - border: none; - padding: 0; - margin: 0; -} - -.label { - padding: 0; -} - -.radio-group-required .label::after { - content: var(--wa-form-control-required-content); - margin-inline-start: var(--wa-form-control-required-content-offset); -} - -[part~='form-control-input'] { - display: flex; - flex-direction: column; - flex-wrap: wrap; - gap: 0; /* Radios handle their own spacing */ -} - -/* Horizontal */ -:host([orientation='horizontal']) [part~='form-control-input'] { - flex-direction: row; -} - -/* Help text */ -[part~='hint'] { - margin-block-start: 0.5em; -} diff --git a/packages/webawesome/src/components/radio-group/radio-group.styles.ts b/packages/webawesome/src/components/radio-group/radio-group.styles.ts new file mode 100644 index 000000000..e06ca4067 --- /dev/null +++ b/packages/webawesome/src/components/radio-group/radio-group.styles.ts @@ -0,0 +1,40 @@ +import { css } from 'lit'; + +export default css` + :host { + display: block; + } + + .form-control { + position: relative; + border: none; + padding: 0; + margin: 0; + } + + .label { + padding: 0; + } + + .radio-group-required .label::after { + content: var(--wa-form-control-required-content); + margin-inline-start: var(--wa-form-control-required-content-offset); + } + + [part~='form-control-input'] { + display: flex; + flex-direction: column; + flex-wrap: wrap; + gap: 0; /* Radios handle their own spacing */ + } + + /* Horizontal */ + :host([orientation='horizontal']) [part~='form-control-input'] { + flex-direction: row; + } + + /* Help text */ + [part~='hint'] { + margin-block-start: 0.5em; + } +`; diff --git a/packages/webawesome/src/components/radio-group/radio-group.ts b/packages/webawesome/src/components/radio-group/radio-group.ts index 7e39a0872..b202a226d 100644 --- a/packages/webawesome/src/components/radio-group/radio-group.ts +++ b/packages/webawesome/src/components/radio-group/radio-group.ts @@ -6,11 +6,11 @@ import { uniqueId } from '../../internal/math.js'; import { HasSlotController } from '../../internal/slot.js'; import { RequiredValidator } from '../../internal/validators/required-validator.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 '../radio/radio.js'; import type WaRadio from '../radio/radio.js'; -import styles from './radio-group.css'; +import styles from './radio-group.styles.js'; /** * @summary Radio groups are used to group multiple [radios](/docs/components/radio) so they function as a single form control. diff --git a/packages/webawesome/src/components/radio/radio.css b/packages/webawesome/src/components/radio/radio.css deleted file mode 100644 index 159237479..000000000 --- a/packages/webawesome/src/components/radio/radio.css +++ /dev/null @@ -1,199 +0,0 @@ -:host { - --checked-icon-color: var(--wa-form-control-activated-color); - --checked-icon-scale: 0.7; - - color: var(--wa-form-control-value-color); - display: inline-flex; - flex-direction: row; - align-items: top; - font-family: inherit; - font-weight: var(--wa-form-control-value-font-weight); - line-height: var(--wa-form-control-value-line-height); - cursor: pointer; - user-select: none; - -webkit-user-select: none; -} - -:host(:focus) { - outline: none; -} - -/* When the control isn't checked, hide the circle for Windows High Contrast mode a11y */ -:host(:not(:state(checked))) svg circle { - opacity: 0; -} - -[part~='label'] { - display: inline; -} - -[part~='hint'] { - margin-block-start: 0.5em; -} - -/* Default spacing for default appearance radios */ -:host([appearance='default']) { - margin-block: 0.375em; /* Half of the original 0.75em gap on each side */ -} - -:host([appearance='default'][data-wa-radio-horizontal]) { - margin-block: 0; - margin-inline: 0.5em; /* Half of the original 1em gap on each side */ -} - -/* Remove margin from first/last items to prevent extra space */ -:host([appearance='default'][data-wa-radio-first]) { - margin-block-start: 0; - margin-inline-start: 0; -} - -:host([appearance='default'][data-wa-radio-last]) { - margin-block-end: 0; - margin-inline-end: 0; -} - -/* Button appearance have no spacing, they get handled by the overlap margins below */ -:host([appearance='button']) { - margin: 0; - align-items: center; - min-height: var(--wa-form-control-height); - background-color: var(--wa-color-surface-default); - border: var(--wa-form-control-border-width) var(--wa-form-control-border-style) var(--wa-form-control-border-color); - border-radius: var(--wa-border-radius-m); - padding: 0 var(--wa-form-control-padding-inline); - transition: - background-color var(--wa-transition-fast), - border-color var(--wa-transition-fast); -} - -/* Default appearance */ -:host([appearance='default']) { - .control { - flex: 0 0 auto; - position: relative; - display: inline-flex; - 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: 50%; - border-style: var(--wa-form-control-border-style); - border-width: var(--wa-form-control-border-width); - background-color: var(--wa-form-control-background-color); - color: transparent; - 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; - } - - .checked-icon { - display: flex; - fill: currentColor; - width: var(--wa-form-control-toggle-size); - height: var(--wa-form-control-toggle-size); - scale: var(--checked-icon-scale); - } -} - -/* Button appearance */ -:host([appearance='button']) { - .control { - display: none; - } -} - -/* Checked */ -:host(:state(checked)) .control { - color: var(--checked-icon-color); - border-color: var(--wa-form-control-activated-color); - background-color: var(--wa-form-control-background-color); -} - -/* Focus */ -:host(:focus-visible) .control { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); -} - -/* Disabled */ -:host(:state(disabled)) { - opacity: 0.5; - cursor: not-allowed; -} - -/* Horizontal grouping - remove inner border radius */ -:host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-inner]) { - border-radius: 0; -} - -:host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-first]) { - border-start-end-radius: 0; - border-end-end-radius: 0; -} - -:host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-last]) { - border-start-start-radius: 0; - border-end-start-radius: 0; -} - -/* Vertical grouping - remove inner border radius */ -:host([appearance='button'][data-wa-radio-vertical][data-wa-radio-inner]) { - border-radius: 0; -} - -:host([appearance='button'][data-wa-radio-vertical][data-wa-radio-first]) { - border-end-start-radius: 0; - border-end-end-radius: 0; -} - -:host([appearance='button'][data-wa-radio-vertical][data-wa-radio-last]) { - border-start-start-radius: 0; - border-start-end-radius: 0; -} - -@media (hover: hover) { - :host([appearance='button']:hover:not(:state(disabled), :state(checked))) { - background-color: color-mix(in srgb, var(--wa-color-surface-default) 95%, var(--wa-color-mix-hover)); - } -} - -:host([appearance='button']:focus-visible) { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); -} - -:host([appearance='button']:state(checked)) { - border-color: var(--wa-form-control-activated-color); - background-color: var(--wa-color-brand-fill-quiet); -} - -:host([appearance='button']:state(checked):focus-visible) { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); -} - -/* Button overlap margins */ -:host([appearance='button'][data-wa-radio-horizontal]:not([data-wa-radio-first])) { - margin-inline-start: calc(-1 * var(--wa-form-control-border-width)); -} - -:host([appearance='button'][data-wa-radio-vertical]:not([data-wa-radio-first])) { - margin-block-start: calc(-1 * var(--wa-form-control-border-width)); -} - -/* Ensure interactive states are visible above adjacent buttons */ -:host([appearance='button']:hover), -:host([appearance='button']:state(checked)) { - position: relative; - z-index: 1; -} - -:host([appearance='button']:focus-visible) { - z-index: 2; -} diff --git a/packages/webawesome/src/components/radio/radio.styles.ts b/packages/webawesome/src/components/radio/radio.styles.ts new file mode 100644 index 000000000..2ec3bcfdc --- /dev/null +++ b/packages/webawesome/src/components/radio/radio.styles.ts @@ -0,0 +1,203 @@ +import { css } from 'lit'; + +export default css` + :host { + --checked-icon-color: var(--wa-form-control-activated-color); + --checked-icon-scale: 0.7; + + color: var(--wa-form-control-value-color); + display: inline-flex; + flex-direction: row; + align-items: top; + font-family: inherit; + font-weight: var(--wa-form-control-value-font-weight); + line-height: var(--wa-form-control-value-line-height); + cursor: pointer; + user-select: none; + -webkit-user-select: none; + } + + :host(:focus) { + outline: none; + } + + /* When the control isn't checked, hide the circle for Windows High Contrast mode a11y */ + :host(:not(:state(checked))) svg circle { + opacity: 0; + } + + [part~='label'] { + display: inline; + } + + [part~='hint'] { + margin-block-start: 0.5em; + } + + /* Default spacing for default appearance radios */ + :host([appearance='default']) { + margin-block: 0.375em; /* Half of the original 0.75em gap on each side */ + } + + :host([appearance='default'][data-wa-radio-horizontal]) { + margin-block: 0; + margin-inline: 0.5em; /* Half of the original 1em gap on each side */ + } + + /* Remove margin from first/last items to prevent extra space */ + :host([appearance='default'][data-wa-radio-first]) { + margin-block-start: 0; + margin-inline-start: 0; + } + + :host([appearance='default'][data-wa-radio-last]) { + margin-block-end: 0; + margin-inline-end: 0; + } + + /* Button appearance have no spacing, they get handled by the overlap margins below */ + :host([appearance='button']) { + margin: 0; + align-items: center; + min-height: var(--wa-form-control-height); + background-color: var(--wa-color-surface-default); + border: var(--wa-form-control-border-width) var(--wa-form-control-border-style) var(--wa-form-control-border-color); + border-radius: var(--wa-border-radius-m); + padding: 0 var(--wa-form-control-padding-inline); + transition: + background-color var(--wa-transition-fast), + border-color var(--wa-transition-fast); + } + + /* Default appearance */ + :host([appearance='default']) { + .control { + flex: 0 0 auto; + position: relative; + display: inline-flex; + 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: 50%; + border-style: var(--wa-form-control-border-style); + border-width: var(--wa-form-control-border-width); + background-color: var(--wa-form-control-background-color); + color: transparent; + 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; + } + + .checked-icon { + display: flex; + fill: currentColor; + width: var(--wa-form-control-toggle-size); + height: var(--wa-form-control-toggle-size); + scale: var(--checked-icon-scale); + } + } + + /* Button appearance */ + :host([appearance='button']) { + .control { + display: none; + } + } + + /* Checked */ + :host(:state(checked)) .control { + color: var(--checked-icon-color); + border-color: var(--wa-form-control-activated-color); + background-color: var(--wa-form-control-background-color); + } + + /* Focus */ + :host(:focus-visible) .control { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + + /* Disabled */ + :host(:state(disabled)) { + opacity: 0.5; + cursor: not-allowed; + } + + /* Horizontal grouping - remove inner border radius */ + :host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-inner]) { + border-radius: 0; + } + + :host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-first]) { + border-start-end-radius: 0; + border-end-end-radius: 0; + } + + :host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-last]) { + border-start-start-radius: 0; + border-end-start-radius: 0; + } + + /* Vertical grouping - remove inner border radius */ + :host([appearance='button'][data-wa-radio-vertical][data-wa-radio-inner]) { + border-radius: 0; + } + + :host([appearance='button'][data-wa-radio-vertical][data-wa-radio-first]) { + border-end-start-radius: 0; + border-end-end-radius: 0; + } + + :host([appearance='button'][data-wa-radio-vertical][data-wa-radio-last]) { + border-start-start-radius: 0; + border-start-end-radius: 0; + } + + @media (hover: hover) { + :host([appearance='button']:hover:not(:state(disabled), :state(checked))) { + background-color: color-mix(in srgb, var(--wa-color-surface-default) 95%, var(--wa-color-mix-hover)); + } + } + + :host([appearance='button']:focus-visible) { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + + :host([appearance='button']:state(checked)) { + border-color: var(--wa-form-control-activated-color); + background-color: var(--wa-color-brand-fill-quiet); + } + + :host([appearance='button']:state(checked):focus-visible) { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + + /* Button overlap margins */ + :host([appearance='button'][data-wa-radio-horizontal]:not([data-wa-radio-first])) { + margin-inline-start: calc(-1 * var(--wa-form-control-border-width)); + } + + :host([appearance='button'][data-wa-radio-vertical]:not([data-wa-radio-first])) { + margin-block-start: calc(-1 * var(--wa-form-control-border-width)); + } + + /* Ensure interactive states are visible above adjacent buttons */ + :host([appearance='button']:hover), + :host([appearance='button']:state(checked)) { + position: relative; + z-index: 1; + } + + :host([appearance='button']:focus-visible) { + z-index: 2; + } +`; diff --git a/packages/webawesome/src/components/radio/radio.ts b/packages/webawesome/src/components/radio/radio.ts index 3898b3b20..d2b5377f4 100644 --- a/packages/webawesome/src/components/radio/radio.ts +++ b/packages/webawesome/src/components/radio/radio.ts @@ -2,10 +2,10 @@ import type { PropertyValues } from 'lit'; import { html, isServer } from 'lit'; import { customElement, property, state } from 'lit/decorators.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 './radio.css'; +import styles from './radio.styles.js'; /** * @summary Radios allow the user to select a single option from a group. diff --git a/packages/webawesome/src/components/rating/rating.css b/packages/webawesome/src/components/rating/rating.css deleted file mode 100644 index 606a2f263..000000000 --- a/packages/webawesome/src/components/rating/rating.css +++ /dev/null @@ -1,85 +0,0 @@ -:host { - --symbol-color: var(--wa-color-neutral-on-quiet); - --symbol-color-active: var(--wa-color-yellow-70); - --symbol-spacing: 0.125em; - - display: inline-flex; -} - -.rating { - position: relative; - display: inline-flex; - border-radius: var(--wa-border-radius-m); - vertical-align: middle; -} - -.rating:focus { - outline: none; -} - -.rating:focus-visible { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); -} - -.symbols { - display: inline-flex; - gap: 0.125em; - position: relative; - line-height: 0; - color: var(--symbol-color); - white-space: nowrap; - cursor: pointer; -} - -.symbols > * { - padding: var(--symbol-spacing); -} - -.symbol-active, -.partial-filled { - color: var(--symbol-color-active); -} - -.partial-symbol-container { - position: relative; -} - -.partial-filled { - position: absolute; - top: var(--symbol-spacing); - left: var(--symbol-spacing); -} - -.symbol { - transition: scale var(--wa-transition-normal) var(--wa-transition-easing); - pointer-events: none; -} - -.symbol-hover { - scale: 1.2; -} - -.rating-readonly .symbols { - cursor: default; -} - -:host([disabled]) .symbol-hover, -.rating-readonly .symbol-hover { - scale: none; -} - -:host([disabled]) { - opacity: 0.5; -} - -:host([disabled]) .symbols { - cursor: not-allowed; -} - -/* Forced colors mode */ -@media (forced-colors: active) { - .symbol-active { - color: SelectedItem; - } -} diff --git a/packages/webawesome/src/components/rating/rating.styles.ts b/packages/webawesome/src/components/rating/rating.styles.ts new file mode 100644 index 000000000..7c6eeecab --- /dev/null +++ b/packages/webawesome/src/components/rating/rating.styles.ts @@ -0,0 +1,89 @@ +import { css } from 'lit'; + +export default css` + :host { + --symbol-color: var(--wa-color-neutral-on-quiet); + --symbol-color-active: var(--wa-color-yellow-70); + --symbol-spacing: 0.125em; + + display: inline-flex; + } + + .rating { + position: relative; + display: inline-flex; + border-radius: var(--wa-border-radius-m); + vertical-align: middle; + } + + .rating:focus { + outline: none; + } + + .rating:focus-visible { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + + .symbols { + display: inline-flex; + gap: 0.125em; + position: relative; + line-height: 0; + color: var(--symbol-color); + white-space: nowrap; + cursor: pointer; + } + + .symbols > * { + padding: var(--symbol-spacing); + } + + .symbol-active, + .partial-filled { + color: var(--symbol-color-active); + } + + .partial-symbol-container { + position: relative; + } + + .partial-filled { + position: absolute; + top: var(--symbol-spacing); + left: var(--symbol-spacing); + } + + .symbol { + transition: scale var(--wa-transition-normal) var(--wa-transition-easing); + pointer-events: none; + } + + .symbol-hover { + scale: 1.2; + } + + .rating-readonly .symbols { + cursor: default; + } + + :host([disabled]) .symbol-hover, + .rating-readonly .symbol-hover { + scale: none; + } + + :host([disabled]) { + opacity: 0.5; + } + + :host([disabled]) .symbols { + cursor: not-allowed; + } + + /* Forced colors mode */ + @media (forced-colors: active) { + .symbol-active { + color: SelectedItem; + } + } +`; diff --git a/packages/webawesome/src/components/rating/rating.ts b/packages/webawesome/src/components/rating/rating.ts index d8615dd58..ebbbe3de4 100644 --- a/packages/webawesome/src/components/rating/rating.ts +++ b/packages/webawesome/src/components/rating/rating.ts @@ -7,10 +7,10 @@ import { WaHoverEvent } from '../../events/hover.js'; import { clamp } from '../../internal/math.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import sizeStyles from '../../styles/utilities/size.css'; +import sizeStyles from '../../styles/component/size.styles.js'; import { LocalizeController } from '../../utilities/localize.js'; import '../icon/icon.js'; -import styles from './rating.css'; +import styles from './rating.styles.js'; /** * @summary Ratings give users a way to quickly view and provide feedback. diff --git a/packages/webawesome/src/components/resize-observer/resize-observer.css b/packages/webawesome/src/components/resize-observer/resize-observer.css deleted file mode 100644 index 92d692cdd..000000000 --- a/packages/webawesome/src/components/resize-observer/resize-observer.css +++ /dev/null @@ -1,3 +0,0 @@ -:host { - display: contents; -} diff --git a/packages/webawesome/src/components/resize-observer/resize-observer.styles.ts b/packages/webawesome/src/components/resize-observer/resize-observer.styles.ts new file mode 100644 index 000000000..1ef4bf6f3 --- /dev/null +++ b/packages/webawesome/src/components/resize-observer/resize-observer.styles.ts @@ -0,0 +1,7 @@ +import { css } from 'lit'; + +export default css` + :host { + display: contents; + } +`; diff --git a/packages/webawesome/src/components/resize-observer/resize-observer.ts b/packages/webawesome/src/components/resize-observer/resize-observer.ts index b26d0e5e9..e77727abb 100644 --- a/packages/webawesome/src/components/resize-observer/resize-observer.ts +++ b/packages/webawesome/src/components/resize-observer/resize-observer.ts @@ -3,7 +3,7 @@ import { customElement, property } from 'lit/decorators.js'; import { WaResizeEvent } from '../../events/resize.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import styles from './resize-observer.css'; +import styles from './resize-observer.styles.js'; /** * @summary The Resize Observer component offers a thin, declarative interface to the [`ResizeObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver). diff --git a/packages/webawesome/src/components/scroller/scroller.css b/packages/webawesome/src/components/scroller/scroller.css deleted file mode 100644 index 3b4080c9e..000000000 --- a/packages/webawesome/src/components/scroller/scroller.css +++ /dev/null @@ -1,125 +0,0 @@ -:host { - --shadow-color: var(--wa-color-surface-default); - --shadow-size: 2rem; - - /* private (defined dynamically) */ - --start-shadow-opacity: 0; - --end-shadow-opacity: 0; - - display: block; - position: relative; - max-width: 100%; - isolation: isolate; -} - -:host([orientation='vertical']) { - display: flex; - flex-direction: column; - height: 100%; -} - -#content { - z-index: 1; /* below shadows */ - border-radius: inherit; - scroll-behavior: smooth; - scrollbar-width: thin; - - /* Prevent text in mobile Safari from being larger when the container width larger than the viewport */ - -webkit-text-size-adjust: 100%; - - &:focus { - outline: none; - } - - &:focus-visible { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); - } -} - -:host([without-scrollbar]) #content { - scrollbar-width: none; -} - -:host([orientation='horizontal']) #content { - overflow-x: auto; - overflow-y: hidden; -} - -:host([orientation='vertical']) #content { - flex: 1 1 auto; - min-height: 0; /* This is crucial for flex children to respect overflow */ - overflow-x: hidden; - overflow-y: auto; -} - -#start-shadow, -#end-shadow { - z-index: 2; -} - -#start-shadow { - opacity: var(--start-shadow-opacity); -} - -#end-shadow { - opacity: var(--end-shadow-opacity); -} - -/* Horizontal shadows */ -:host([orientation='horizontal']) { - #start-shadow, - #end-shadow { - position: absolute; - top: 0; - bottom: 0; - width: var(--shadow-size); - pointer-events: none; - } - - #start-shadow { - &:dir(ltr) { - left: 0; - background: linear-gradient(to right, var(--shadow-color), transparent 100%); - } - - &:dir(rtl) { - right: 0; - background: linear-gradient(to left, var(--shadow-color), transparent 100%); - } - } - - #end-shadow { - &:dir(ltr) { - right: 0; - background: linear-gradient(to left, var(--shadow-color), transparent 100%); - } - - &:dir(rtl) { - left: 0; - background: linear-gradient(to right, var(--shadow-color), transparent 100%); - } - } -} - -/* Vertical shadows */ -:host([orientation='vertical']) { - #start-shadow, - #end-shadow { - position: absolute; - right: 0; - left: 0; - height: var(--shadow-size); - pointer-events: none; - } - - #start-shadow { - top: 0; - background: linear-gradient(to bottom, var(--shadow-color), transparent 100%); - } - - #end-shadow { - bottom: 0; - background: linear-gradient(to top, var(--shadow-color), transparent 100%); - } -} diff --git a/packages/webawesome/src/components/scroller/scroller.styles.ts b/packages/webawesome/src/components/scroller/scroller.styles.ts new file mode 100644 index 000000000..a57493291 --- /dev/null +++ b/packages/webawesome/src/components/scroller/scroller.styles.ts @@ -0,0 +1,129 @@ +import { css } from 'lit'; + +export default css` + :host { + --shadow-color: var(--wa-color-surface-default); + --shadow-size: 2rem; + + /* private (defined dynamically) */ + --start-shadow-opacity: 0; + --end-shadow-opacity: 0; + + display: block; + position: relative; + max-width: 100%; + isolation: isolate; + } + + :host([orientation='vertical']) { + display: flex; + flex-direction: column; + height: 100%; + } + + #content { + z-index: 1; /* below shadows */ + border-radius: inherit; + scroll-behavior: smooth; + scrollbar-width: thin; + + /* Prevent text in mobile Safari from being larger when the container width larger than the viewport */ + -webkit-text-size-adjust: 100%; + + &:focus { + outline: none; + } + + &:focus-visible { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + } + + :host([without-scrollbar]) #content { + scrollbar-width: none; + } + + :host([orientation='horizontal']) #content { + overflow-x: auto; + overflow-y: hidden; + } + + :host([orientation='vertical']) #content { + flex: 1 1 auto; + min-height: 0; /* This is crucial for flex children to respect overflow */ + overflow-x: hidden; + overflow-y: auto; + } + + #start-shadow, + #end-shadow { + z-index: 2; + } + + #start-shadow { + opacity: var(--start-shadow-opacity); + } + + #end-shadow { + opacity: var(--end-shadow-opacity); + } + + /* Horizontal shadows */ + :host([orientation='horizontal']) { + #start-shadow, + #end-shadow { + position: absolute; + top: 0; + bottom: 0; + width: var(--shadow-size); + pointer-events: none; + } + + #start-shadow { + &:dir(ltr) { + left: 0; + background: linear-gradient(to right, var(--shadow-color), transparent 100%); + } + + &:dir(rtl) { + right: 0; + background: linear-gradient(to left, var(--shadow-color), transparent 100%); + } + } + + #end-shadow { + &:dir(ltr) { + right: 0; + background: linear-gradient(to left, var(--shadow-color), transparent 100%); + } + + &:dir(rtl) { + left: 0; + background: linear-gradient(to right, var(--shadow-color), transparent 100%); + } + } + } + + /* Vertical shadows */ + :host([orientation='vertical']) { + #start-shadow, + #end-shadow { + position: absolute; + right: 0; + left: 0; + height: var(--shadow-size); + pointer-events: none; + } + + #start-shadow { + top: 0; + background: linear-gradient(to bottom, var(--shadow-color), transparent 100%); + } + + #end-shadow { + bottom: 0; + background: linear-gradient(to top, var(--shadow-color), transparent 100%); + } + } +`; diff --git a/packages/webawesome/src/components/scroller/scroller.ts b/packages/webawesome/src/components/scroller/scroller.ts index 6f0db2e5b..8c5f7dff8 100644 --- a/packages/webawesome/src/components/scroller/scroller.ts +++ b/packages/webawesome/src/components/scroller/scroller.ts @@ -2,7 +2,7 @@ import { html } from 'lit'; import { customElement, eventOptions, property, query, state } from 'lit/decorators.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import { LocalizeController } from '../../utilities/localize.js'; -import styles from './scroller.css'; +import styles from './scroller.styles.js'; /** * @summary Scrollers create an accessible container while providing visual cues that help users identify and navigate diff --git a/packages/webawesome/src/components/select/select.css b/packages/webawesome/src/components/select/select.css deleted file mode 100644 index 6318fb590..000000000 --- a/packages/webawesome/src/components/select/select.css +++ /dev/null @@ -1,272 +0,0 @@ -:host { - --tag-max-size: 10ch; - --show-duration: 100ms; - --hide-duration: 100ms; -} - -/* Add ellipses to multi select options */ -:host wa-tag::part(content) { - display: initial; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - max-width: var(--tag-max-size); -} - -:host .disabled [part~='combobox'] { - opacity: 0.5; - cursor: not-allowed; - outline: none; -} - -:host .enabled:is(.open, :focus-within) [part~='combobox'] { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); -} - -/** The popup */ -.select { - flex: 1 1 auto; - display: inline-flex; - width: 100%; - position: relative; - vertical-align: middle; - - /* Pass through from select to the popup */ - --show-duration: inherit; - --hide-duration: inherit; - - &::part(popup) { - z-index: 900; - } - - &[data-current-placement^='top']::part(popup) { - transform-origin: bottom; - } - - &[data-current-placement^='bottom']::part(popup) { - transform-origin: top; - } -} - -/* Combobox */ -.combobox { - flex: 1; - display: flex; - width: 100%; - min-width: 0; - align-items: center; - justify-content: start; - - min-height: var(--wa-form-control-height); - - background-color: var(--wa-form-control-background-color); - border-color: var(--wa-form-control-border-color); - border-radius: var(--wa-form-control-border-radius); - border-style: var(--wa-form-control-border-style); - border-width: var(--wa-form-control-border-width); - color: var(--wa-form-control-value-color); - cursor: pointer; - font-family: inherit; - font-weight: var(--wa-form-control-value-font-weight); - line-height: var(--wa-form-control-value-line-height); - overflow: hidden; - padding: 0 var(--wa-form-control-padding-inline); - position: relative; - vertical-align: middle; - transition: - background-color var(--wa-transition-normal), - border var(--wa-transition-normal), - outline var(--wa-transition-fast); - transition-timing-function: var(--wa-transition-easing); - - :host([multiple]) .select:not(.placeholder-visible) & { - padding-inline-start: 0; - padding-block: calc(var(--wa-form-control-height) * 0.1 - var(--wa-form-control-border-width)); - } - - /* Pills */ - :host([pill]) & { - border-radius: var(--wa-border-radius-pill); - } -} - -/* Appearance modifiers */ -:host([appearance='outlined']) .combobox { - background-color: var(--wa-form-control-background-color); - border-color: var(--wa-form-control-border-color); -} - -:host([appearance='filled']) .combobox { - background-color: var(--wa-color-neutral-fill-quiet); - border-color: var(--wa-color-neutral-fill-quiet); -} - -:host([appearance='filled-outlined']) .combobox { - background-color: var(--wa-color-neutral-fill-quiet); - border-color: var(--wa-form-control-border-color); -} - -.display-input { - position: relative; - width: 100%; - font: inherit; - border: none; - background: none; - line-height: var(--wa-form-control-value-line-height); - color: var(--wa-form-control-value-color); - cursor: inherit; - overflow: hidden; - padding: 0; - margin: 0; - -webkit-appearance: none; - - &:focus { - outline: none; - } - - &::placeholder { - color: var(--wa-form-control-placeholder-color); - } -} - -/* Visually hide the display input when multiple is enabled */ -:host([multiple]) .select:not(.placeholder-visible) .display-input { - position: absolute; - z-index: -1; - top: 0; - left: 0; - width: 100%; - height: 100%; - opacity: 0; -} - -.value-input { - position: absolute; - z-index: -1; - top: 0; - left: 0; - width: 100%; - height: 100%; - opacity: 0; - padding: 0; - margin: 0; -} - -.tags { - display: flex; - flex: 1; - align-items: center; - flex-wrap: wrap; - margin-inline-start: 0.25em; - gap: 0.25em; - - &::slotted(wa-tag) { - cursor: pointer !important; - } - - .disabled &, - .disabled &::slotted(wa-tag) { - cursor: not-allowed !important; - } -} - -/* Start and End */ - -.start, -.end { - flex: 0; - display: inline-flex; - align-items: center; - color: var(--wa-color-neutral-on-quiet); -} - -.end::slotted(*) { - margin-inline-start: var(--wa-form-control-padding-inline); -} - -.start::slotted(*) { - margin-inline-end: var(--wa-form-control-padding-inline); -} - -:host([multiple]) .start::slotted(*) { - margin-inline: var(--wa-form-control-padding-inline); -} - -/* Clear button */ -[part~='clear-button'] { - display: inline-flex; - align-items: center; - justify-content: center; - font-size: inherit; - color: var(--wa-color-neutral-on-quiet); - border: none; - background: none; - padding: 0; - transition: color var(--wa-transition-normal); - cursor: pointer; - margin-inline-start: var(--wa-form-control-padding-inline); - - &:focus { - outline: none; - } - - @media (hover: hover) { - &:hover { - color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover)); - } - } - - &:active { - color: color-mix(in oklab, currentColor, var(--wa-color-mix-active)); - } -} - -/* Expand icon */ -.expand-icon { - flex: 0 0 auto; - display: flex; - align-items: center; - color: var(--wa-color-neutral-on-quiet); - transition: rotate var(--wa-transition-slow) ease; - rotate: 0deg; - margin-inline-start: var(--wa-form-control-padding-inline); - - .open & { - rotate: -180deg; - } -} - -/* Listbox */ -.listbox { - display: block; - position: relative; - font: inherit; - box-shadow: var(--wa-shadow-m); - background: var(--wa-color-surface-raised); - border-color: var(--wa-color-surface-border); - border-radius: var(--wa-border-radius-m); - border-style: var(--wa-border-style); - border-width: var(--wa-border-width-s); - padding-block: 0.5em; - padding-inline: 0; - overflow: auto; - overscroll-behavior: none; - - /* Make sure it adheres to the popup's auto size */ - max-width: var(--auto-size-available-width); - max-height: var(--auto-size-available-height); - - &::slotted(wa-divider) { - --spacing: 0.5em; - } -} - -slot:not([name])::slotted(small) { - display: block; - font-size: var(--wa-font-size-smaller); - font-weight: var(--wa-font-weight-semibold); - color: var(--wa-color-text-quiet); - padding-block: 0.5em; - padding-inline: 2.25em; -} diff --git a/packages/webawesome/src/components/select/select.styles.ts b/packages/webawesome/src/components/select/select.styles.ts new file mode 100644 index 000000000..b837ebd5b --- /dev/null +++ b/packages/webawesome/src/components/select/select.styles.ts @@ -0,0 +1,276 @@ +import { css } from 'lit'; + +export default css` + :host { + --tag-max-size: 10ch; + --show-duration: 100ms; + --hide-duration: 100ms; + } + + /* Add ellipses to multi select options */ + :host wa-tag::part(content) { + display: initial; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + max-width: var(--tag-max-size); + } + + :host .disabled [part~='combobox'] { + opacity: 0.5; + cursor: not-allowed; + outline: none; + } + + :host .enabled:is(.open, :focus-within) [part~='combobox'] { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + + /** The popup */ + .select { + flex: 1 1 auto; + display: inline-flex; + width: 100%; + position: relative; + vertical-align: middle; + + /* Pass through from select to the popup */ + --show-duration: inherit; + --hide-duration: inherit; + + &::part(popup) { + z-index: 900; + } + + &[data-current-placement^='top']::part(popup) { + transform-origin: bottom; + } + + &[data-current-placement^='bottom']::part(popup) { + transform-origin: top; + } + } + + /* Combobox */ + .combobox { + flex: 1; + display: flex; + width: 100%; + min-width: 0; + align-items: center; + justify-content: start; + + min-height: var(--wa-form-control-height); + + background-color: var(--wa-form-control-background-color); + border-color: var(--wa-form-control-border-color); + border-radius: var(--wa-form-control-border-radius); + border-style: var(--wa-form-control-border-style); + border-width: var(--wa-form-control-border-width); + color: var(--wa-form-control-value-color); + cursor: pointer; + font-family: inherit; + font-weight: var(--wa-form-control-value-font-weight); + line-height: var(--wa-form-control-value-line-height); + overflow: hidden; + padding: 0 var(--wa-form-control-padding-inline); + position: relative; + vertical-align: middle; + transition: + background-color var(--wa-transition-normal), + border var(--wa-transition-normal), + outline var(--wa-transition-fast); + transition-timing-function: var(--wa-transition-easing); + + :host([multiple]) .select:not(.placeholder-visible) & { + padding-inline-start: 0; + padding-block: calc(var(--wa-form-control-height) * 0.1 - var(--wa-form-control-border-width)); + } + + /* Pills */ + :host([pill]) & { + border-radius: var(--wa-border-radius-pill); + } + } + + /* Appearance modifiers */ + :host([appearance='outlined']) .combobox { + background-color: var(--wa-form-control-background-color); + border-color: var(--wa-form-control-border-color); + } + + :host([appearance='filled']) .combobox { + background-color: var(--wa-color-neutral-fill-quiet); + border-color: var(--wa-color-neutral-fill-quiet); + } + + :host([appearance='filled-outlined']) .combobox { + background-color: var(--wa-color-neutral-fill-quiet); + border-color: var(--wa-form-control-border-color); + } + + .display-input { + position: relative; + width: 100%; + font: inherit; + border: none; + background: none; + line-height: var(--wa-form-control-value-line-height); + color: var(--wa-form-control-value-color); + cursor: inherit; + overflow: hidden; + padding: 0; + margin: 0; + -webkit-appearance: none; + + &:focus { + outline: none; + } + + &::placeholder { + color: var(--wa-form-control-placeholder-color); + } + } + + /* Visually hide the display input when multiple is enabled */ + :host([multiple]) .select:not(.placeholder-visible) .display-input { + position: absolute; + z-index: -1; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0; + } + + .value-input { + position: absolute; + z-index: -1; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0; + padding: 0; + margin: 0; + } + + .tags { + display: flex; + flex: 1; + align-items: center; + flex-wrap: wrap; + margin-inline-start: 0.25em; + gap: 0.25em; + + &::slotted(wa-tag) { + cursor: pointer !important; + } + + .disabled &, + .disabled &::slotted(wa-tag) { + cursor: not-allowed !important; + } + } + + /* Start and End */ + + .start, + .end { + flex: 0; + display: inline-flex; + align-items: center; + color: var(--wa-color-neutral-on-quiet); + } + + .end::slotted(*) { + margin-inline-start: var(--wa-form-control-padding-inline); + } + + .start::slotted(*) { + margin-inline-end: var(--wa-form-control-padding-inline); + } + + :host([multiple]) .start::slotted(*) { + margin-inline: var(--wa-form-control-padding-inline); + } + + /* Clear button */ + [part~='clear-button'] { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: inherit; + color: var(--wa-color-neutral-on-quiet); + border: none; + background: none; + padding: 0; + transition: color var(--wa-transition-normal); + cursor: pointer; + margin-inline-start: var(--wa-form-control-padding-inline); + + &:focus { + outline: none; + } + + @media (hover: hover) { + &:hover { + color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover)); + } + } + + &:active { + color: color-mix(in oklab, currentColor, var(--wa-color-mix-active)); + } + } + + /* Expand icon */ + .expand-icon { + flex: 0 0 auto; + display: flex; + align-items: center; + color: var(--wa-color-neutral-on-quiet); + transition: rotate var(--wa-transition-slow) ease; + rotate: 0deg; + margin-inline-start: var(--wa-form-control-padding-inline); + + .open & { + rotate: -180deg; + } + } + + /* Listbox */ + .listbox { + display: block; + position: relative; + font: inherit; + box-shadow: var(--wa-shadow-m); + background: var(--wa-color-surface-raised); + border-color: var(--wa-color-surface-border); + border-radius: var(--wa-border-radius-m); + border-style: var(--wa-border-style); + border-width: var(--wa-border-width-s); + padding-block: 0.5em; + padding-inline: 0; + overflow: auto; + overscroll-behavior: none; + + /* Make sure it adheres to the popup's auto size */ + max-width: var(--auto-size-available-width); + max-height: var(--auto-size-available-height); + + &::slotted(wa-divider) { + --spacing: 0.5em; + } + } + + slot:not([name])::slotted(small) { + display: block; + font-size: var(--wa-font-size-smaller); + font-weight: var(--wa-font-weight-semibold); + color: var(--wa-color-text-quiet); + padding-block: 0.5em; + padding-inline: 2.25em; + } +`; diff --git a/packages/webawesome/src/components/select/select.ts b/packages/webawesome/src/components/select/select.ts index 2e1459e1c..37f0c0d02 100644 --- a/packages/webawesome/src/components/select/select.ts +++ b/packages/webawesome/src/components/select/select.ts @@ -16,8 +16,8 @@ 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 { LocalizeController } from '../../utilities/localize.js'; import '../icon/icon.js'; import '../option/option.js'; @@ -25,7 +25,7 @@ import type WaOption from '../option/option.js'; import '../popup/popup.js'; import type WaPopup from '../popup/popup.js'; import '../tag/tag.js'; -import styles from './select.css'; +import styles from './select.styles.js'; /** * @summary Selects allow you to choose items from a menu of predefined options. diff --git a/packages/webawesome/src/components/skeleton/skeleton.css b/packages/webawesome/src/components/skeleton/skeleton.css deleted file mode 100644 index 65a7f794a..000000000 --- a/packages/webawesome/src/components/skeleton/skeleton.css +++ /dev/null @@ -1,54 +0,0 @@ -:host { - --color: var(--wa-color-neutral-fill-normal); - --sheen-color: color-mix(in oklab, var(--color), var(--wa-color-surface-raised)); - - display: flex; - position: relative; - width: 100%; - height: 100%; - min-height: 1rem; -} - -.indicator { - flex: 1 1 auto; - background: var(--color); - border-radius: var(--wa-border-radius-pill); -} - -:host([effect='sheen']) .indicator { - background: linear-gradient(270deg, var(--sheen-color), var(--color), var(--color), var(--sheen-color)); - background-size: 400% 100%; - animation: sheen 8s ease-in-out infinite; -} - -:host([effect='pulse']) .indicator { - animation: pulse 2s ease-in-out 0.5s infinite; -} - -/* Forced colors mode */ -@media (forced-colors: active) { - :host { - --color: GrayText; - } -} - -@keyframes sheen { - 0% { - background-position: 200% 0; - } - to { - background-position: -200% 0; - } -} - -@keyframes pulse { - 0% { - opacity: 1; - } - 50% { - opacity: 0.4; - } - 100% { - opacity: 1; - } -} diff --git a/packages/webawesome/src/components/skeleton/skeleton.styles.ts b/packages/webawesome/src/components/skeleton/skeleton.styles.ts new file mode 100644 index 000000000..9fd766ede --- /dev/null +++ b/packages/webawesome/src/components/skeleton/skeleton.styles.ts @@ -0,0 +1,58 @@ +import { css } from 'lit'; + +export default css` + :host { + --color: var(--wa-color-neutral-fill-normal); + --sheen-color: color-mix(in oklab, var(--color), var(--wa-color-surface-raised)); + + display: flex; + position: relative; + width: 100%; + height: 100%; + min-height: 1rem; + } + + .indicator { + flex: 1 1 auto; + background: var(--color); + border-radius: var(--wa-border-radius-pill); + } + + :host([effect='sheen']) .indicator { + background: linear-gradient(270deg, var(--sheen-color), var(--color), var(--color), var(--sheen-color)); + background-size: 400% 100%; + animation: sheen 8s ease-in-out infinite; + } + + :host([effect='pulse']) .indicator { + animation: pulse 2s ease-in-out 0.5s infinite; + } + + /* Forced colors mode */ + @media (forced-colors: active) { + :host { + --color: GrayText; + } + } + + @keyframes sheen { + 0% { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } + } + + @keyframes pulse { + 0% { + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + opacity: 1; + } + } +`; diff --git a/packages/webawesome/src/components/skeleton/skeleton.ts b/packages/webawesome/src/components/skeleton/skeleton.ts index b22178fd9..2b4723d77 100644 --- a/packages/webawesome/src/components/skeleton/skeleton.ts +++ b/packages/webawesome/src/components/skeleton/skeleton.ts @@ -1,7 +1,7 @@ import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import styles from './skeleton.css'; +import styles from './skeleton.styles.js'; /** * @summary Skeletons are used to provide a visual representation of where content will eventually be drawn. diff --git a/packages/webawesome/src/components/slider/slider.css b/packages/webawesome/src/components/slider/slider.css deleted file mode 100644 index efb206130..000000000 --- a/packages/webawesome/src/components/slider/slider.css +++ /dev/null @@ -1,229 +0,0 @@ -:host { - --track-size: 0.5em; - --thumb-width: 1.4em; - --thumb-height: 1.4em; - --marker-width: 0.1875em; - --marker-height: 0.1875em; -} - -:host([orientation='vertical']) { - width: auto; -} - -#label:has(~ .vertical) { - display: block; - order: 2; - max-width: none; - text-align: center; -} - -#description:has(~ .vertical) { - order: 3; - text-align: center; -} - -/* Add extra space between slider and label, when present */ -#label:has(*:not(:empty)) ~ #slider { - &.horizontal { - margin-block-start: 0.5em; - } - &.vertical { - margin-block-end: 0.5em; - } -} - -#slider { - touch-action: none; - - &:focus { - outline: none; - } - - &:focus-visible:not(.disabled) #thumb, - &:focus-visible:not(.disabled) #thumb-min, - &:focus-visible:not(.disabled) #thumb-max { - outline: var(--wa-focus-ring); - /* intentionally no offset due to border */ - } -} - -#track { - position: relative; - border-radius: 9999px; - background: var(--wa-color-neutral-fill-normal); - isolation: isolate; -} - -/* Orientation */ -.horizontal #track { - height: var(--track-size); -} - -.vertical #track { - order: 1; - width: var(--track-size); - height: 200px; -} - -/* Disabled */ -.disabled #track { - cursor: not-allowed; - opacity: 0.5; -} - -/* Indicator */ -#indicator { - position: absolute; - border-radius: inherit; - background-color: var(--wa-form-control-activated-color); - - &:dir(ltr) { - right: calc(100% - max(var(--start), var(--end))); - left: min(var(--start), var(--end)); - } - - &:dir(rtl) { - right: min(var(--start), var(--end)); - left: calc(100% - max(var(--start), var(--end))); - } -} - -.horizontal #indicator { - top: 0; - height: 100%; -} - -.vertical #indicator { - top: calc(100% - var(--end)); - bottom: var(--start); - left: 0; - width: 100%; -} - -/* Thumbs */ -#thumb, -#thumb-min, -#thumb-max { - z-index: 3; - position: absolute; - width: var(--thumb-width); - height: var(--thumb-height); - border: solid 0.125em var(--wa-color-surface-default); - border-radius: 50%; - background-color: var(--wa-form-control-activated-color); - cursor: pointer; -} - -.disabled #thumb, -.disabled #thumb-min, -.disabled #thumb-max { - cursor: inherit; -} - -.horizontal #thumb, -.horizontal #thumb-min, -.horizontal #thumb-max { - top: calc(50% - var(--thumb-height) / 2); - - &:dir(ltr) { - right: auto; - left: calc(var(--position) - var(--thumb-width) / 2); - } - - &:dir(rtl) { - right: calc(var(--position) - var(--thumb-width) / 2); - left: auto; - } -} - -.vertical #thumb, -.vertical #thumb-min, -.vertical #thumb-max { - bottom: calc(var(--position) - var(--thumb-height) / 2); - left: calc(50% - var(--thumb-width) / 2); -} - -/* Range-specific thumb styles */ -:host([range]) { - #thumb-min:focus-visible, - #thumb-max:focus-visible { - z-index: 4; /* Ensure focused thumb appears on top */ - outline: var(--wa-focus-ring); - /* intentionally no offset due to border */ - } -} - -/* Markers */ -#markers { - pointer-events: none; -} - -.marker { - z-index: 2; - position: absolute; - width: var(--marker-width); - height: var(--marker-height); - border-radius: 50%; - background-color: var(--wa-color-surface-default); -} - -.marker:first-of-type, -.marker:last-of-type { - display: none; -} - -.horizontal .marker { - top: calc(50% - var(--marker-height) / 2); - left: calc(var(--position) - var(--marker-width) / 2); -} - -.vertical .marker { - top: calc(var(--position) - var(--marker-height) / 2); - left: calc(50% - var(--marker-width) / 2); -} - -/* Marker labels */ -#references { - position: relative; - - slot { - display: flex; - justify-content: space-between; - height: 100%; - } - - ::slotted(*) { - color: var(--wa-color-text-quiet); - font-size: 0.875em; - line-height: 1; - } -} - -.horizontal { - #references { - margin-block-start: 0.5em; - } -} - -.vertical { - display: flex; - margin-inline: auto; - - #track { - order: 1; - } - - #references { - order: 2; - width: min-content; - margin-inline-start: 0.75em; - - slot { - flex-direction: column; - } - } -} - -.vertical #references slot { - flex-direction: column; -} diff --git a/packages/webawesome/src/components/slider/slider.styles.ts b/packages/webawesome/src/components/slider/slider.styles.ts new file mode 100644 index 000000000..5e3b5a6c7 --- /dev/null +++ b/packages/webawesome/src/components/slider/slider.styles.ts @@ -0,0 +1,233 @@ +import { css } from 'lit'; + +export default css` + :host { + --track-size: 0.5em; + --thumb-width: 1.4em; + --thumb-height: 1.4em; + --marker-width: 0.1875em; + --marker-height: 0.1875em; + } + + :host([orientation='vertical']) { + width: auto; + } + + #label:has(~ .vertical) { + display: block; + order: 2; + max-width: none; + text-align: center; + } + + #description:has(~ .vertical) { + order: 3; + text-align: center; + } + + /* Add extra space between slider and label, when present */ + #label:has(*:not(:empty)) ~ #slider { + &.horizontal { + margin-block-start: 0.5em; + } + &.vertical { + margin-block-end: 0.5em; + } + } + + #slider { + touch-action: none; + + &:focus { + outline: none; + } + + &:focus-visible:not(.disabled) #thumb, + &:focus-visible:not(.disabled) #thumb-min, + &:focus-visible:not(.disabled) #thumb-max { + outline: var(--wa-focus-ring); + /* intentionally no offset due to border */ + } + } + + #track { + position: relative; + border-radius: 9999px; + background: var(--wa-color-neutral-fill-normal); + isolation: isolate; + } + + /* Orientation */ + .horizontal #track { + height: var(--track-size); + } + + .vertical #track { + order: 1; + width: var(--track-size); + height: 200px; + } + + /* Disabled */ + .disabled #track { + cursor: not-allowed; + opacity: 0.5; + } + + /* Indicator */ + #indicator { + position: absolute; + border-radius: inherit; + background-color: var(--wa-form-control-activated-color); + + &:dir(ltr) { + right: calc(100% - max(var(--start), var(--end))); + left: min(var(--start), var(--end)); + } + + &:dir(rtl) { + right: min(var(--start), var(--end)); + left: calc(100% - max(var(--start), var(--end))); + } + } + + .horizontal #indicator { + top: 0; + height: 100%; + } + + .vertical #indicator { + top: calc(100% - var(--end)); + bottom: var(--start); + left: 0; + width: 100%; + } + + /* Thumbs */ + #thumb, + #thumb-min, + #thumb-max { + z-index: 3; + position: absolute; + width: var(--thumb-width); + height: var(--thumb-height); + border: solid 0.125em var(--wa-color-surface-default); + border-radius: 50%; + background-color: var(--wa-form-control-activated-color); + cursor: pointer; + } + + .disabled #thumb, + .disabled #thumb-min, + .disabled #thumb-max { + cursor: inherit; + } + + .horizontal #thumb, + .horizontal #thumb-min, + .horizontal #thumb-max { + top: calc(50% - var(--thumb-height) / 2); + + &:dir(ltr) { + right: auto; + left: calc(var(--position) - var(--thumb-width) / 2); + } + + &:dir(rtl) { + right: calc(var(--position) - var(--thumb-width) / 2); + left: auto; + } + } + + .vertical #thumb, + .vertical #thumb-min, + .vertical #thumb-max { + bottom: calc(var(--position) - var(--thumb-height) / 2); + left: calc(50% - var(--thumb-width) / 2); + } + + /* Range-specific thumb styles */ + :host([range]) { + #thumb-min:focus-visible, + #thumb-max:focus-visible { + z-index: 4; /* Ensure focused thumb appears on top */ + outline: var(--wa-focus-ring); + /* intentionally no offset due to border */ + } + } + + /* Markers */ + #markers { + pointer-events: none; + } + + .marker { + z-index: 2; + position: absolute; + width: var(--marker-width); + height: var(--marker-height); + border-radius: 50%; + background-color: var(--wa-color-surface-default); + } + + .marker:first-of-type, + .marker:last-of-type { + display: none; + } + + .horizontal .marker { + top: calc(50% - var(--marker-height) / 2); + left: calc(var(--position) - var(--marker-width) / 2); + } + + .vertical .marker { + top: calc(var(--position) - var(--marker-height) / 2); + left: calc(50% - var(--marker-width) / 2); + } + + /* Marker labels */ + #references { + position: relative; + + slot { + display: flex; + justify-content: space-between; + height: 100%; + } + + ::slotted(*) { + color: var(--wa-color-text-quiet); + font-size: 0.875em; + line-height: 1; + } + } + + .horizontal { + #references { + margin-block-start: 0.5em; + } + } + + .vertical { + display: flex; + margin-inline: auto; + + #track { + order: 1; + } + + #references { + order: 2; + width: min-content; + margin-inline-start: 0.75em; + + slot { + flex-direction: column; + } + } + } + + .vertical #references slot { + flex-direction: column; + } +`; diff --git a/packages/webawesome/src/components/slider/slider.ts b/packages/webawesome/src/components/slider/slider.ts index 4a4817aad..55e7df338 100644 --- a/packages/webawesome/src/components/slider/slider.ts +++ b/packages/webawesome/src/components/slider/slider.ts @@ -8,12 +8,12 @@ import { HasSlotController } from '../../internal/slot.js'; import { submitOnEnter } from '../../internal/submit-on-enter.js'; import { SliderValidator } from '../../internal/validators/slider-validator.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 { LocalizeController } from '../../utilities/localize.js'; import '../tooltip/tooltip.js'; import type WaTooltip from '../tooltip/tooltip.js'; -import styles from './slider.css'; +import styles from './slider.styles.js'; /** * diff --git a/packages/webawesome/src/components/spinner/spinner.css b/packages/webawesome/src/components/spinner/spinner.css deleted file mode 100644 index cc28a04c8..000000000 --- a/packages/webawesome/src/components/spinner/spinner.css +++ /dev/null @@ -1,59 +0,0 @@ -:host { - --track-width: 2px; - --track-color: var(--wa-color-neutral-fill-normal); - --indicator-color: var(--wa-color-brand-fill-loud); - --speed: 2s; - - /* Resizing a spinner element using anything but font-size will break the animation because the animation uses em units. - Therefore, if a spinner is used in a flex container without `flex: none` applied, the spinner can grow/shrink and - break the animation. The use of `flex: none` on the host element prevents this by always having the spinner sized - according to its actual dimensions. - */ - flex: none; - display: inline-flex; - width: 1em; - height: 1em; -} - -svg { - width: 100%; - height: 100%; - aspect-ratio: 1; - animation: spin var(--speed) linear infinite; -} - -.track { - stroke: var(--track-color); -} - -.indicator { - stroke: var(--indicator-color); - stroke-dasharray: 75, 100; - stroke-dashoffset: -5; - animation: dash 1.5s ease-in-out infinite; - stroke-linecap: round; -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -@keyframes dash { - 0% { - stroke-dasharray: 1, 150; - stroke-dashoffset: 0; - } - 50% { - stroke-dasharray: 90, 150; - stroke-dashoffset: -35; - } - 100% { - stroke-dasharray: 90, 150; - stroke-dashoffset: -124; - } -} diff --git a/packages/webawesome/src/components/spinner/spinner.styles.ts b/packages/webawesome/src/components/spinner/spinner.styles.ts new file mode 100644 index 000000000..f965c6fd9 --- /dev/null +++ b/packages/webawesome/src/components/spinner/spinner.styles.ts @@ -0,0 +1,64 @@ +import { css } from 'lit'; + +export default css` + :host { + --track-width: 2px; + --track-color: var(--wa-color-neutral-fill-normal); + --indicator-color: var(--wa-color-brand-fill-loud); + --speed: 2s; + + /* + Resizing a spinner element using anything but font-size will break the animation because the animation uses em + units. Therefore, if a spinner is used in a flex container without \`flex: none\` applied, the spinner can + grow/shrink and break the animation. The use of \`flex: none\` on the host element prevents this by always having + the spinner sized according to its actual dimensions. + */ + flex: none; + display: inline-flex; + width: 1em; + height: 1em; + } + + svg { + width: 100%; + height: 100%; + aspect-ratio: 1; + animation: spin var(--speed) linear infinite; + } + + .track { + stroke: var(--track-color); + } + + .indicator { + stroke: var(--indicator-color); + stroke-dasharray: 75, 100; + stroke-dashoffset: -5; + animation: dash 1.5s ease-in-out infinite; + stroke-linecap: round; + } + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } + + @keyframes dash { + 0% { + stroke-dasharray: 1, 150; + stroke-dashoffset: 0; + } + 50% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -35; + } + 100% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -124; + } + } +`; diff --git a/packages/webawesome/src/components/spinner/spinner.ts b/packages/webawesome/src/components/spinner/spinner.ts index ca3d2b45d..9985a492c 100644 --- a/packages/webawesome/src/components/spinner/spinner.ts +++ b/packages/webawesome/src/components/spinner/spinner.ts @@ -2,7 +2,7 @@ import { html } from 'lit'; import { customElement } from 'lit/decorators.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import { LocalizeController } from '../../utilities/localize.js'; -import styles from './spinner.css'; +import styles from './spinner.styles.js'; /** * @summary Spinners are used to show the progress of an indeterminate operation. diff --git a/packages/webawesome/src/components/split-panel/split-panel.css b/packages/webawesome/src/components/split-panel/split-panel.css deleted file mode 100644 index 4c9187b7e..000000000 --- a/packages/webawesome/src/components/split-panel/split-panel.css +++ /dev/null @@ -1,73 +0,0 @@ -:host { - --divider-width: 0.25rem; - --divider-hit-area: 0.75rem; - --min: 0%; - --max: 100%; - - display: grid; -} - -.start, -.end { - overflow: hidden; -} - -.divider { - flex: 0 0 var(--divider-width); - display: flex; - position: relative; - align-items: center; - justify-content: center; - background-color: var(--wa-color-neutral-border-normal); - color: var(--wa-color-neutral-on-normal); - z-index: 1; -} - -.divider:focus { - outline: none; -} - -:host(:not([disabled])) .divider:focus-visible { - outline: var(--wa-focus-ring); -} - -:host([disabled]) .divider { - cursor: not-allowed; -} - -/* Horizontal */ -:host(:not([orientation='vertical'], [disabled])) .divider { - cursor: col-resize; -} - -:host(:not([orientation='vertical'])) .divider::after { - display: flex; - content: ''; - position: absolute; - height: 100%; - left: calc(var(--divider-hit-area) / -2 + var(--divider-width) / 2); - width: var(--divider-hit-area); -} - -/* Vertical */ -:host([orientation='vertical']) { - flex-direction: column; -} - -:host([orientation='vertical']:not([disabled])) .divider { - cursor: row-resize; -} - -:host([orientation='vertical']) .divider::after { - content: ''; - position: absolute; - width: 100%; - top: calc(var(--divider-hit-area) / -2 + var(--divider-width) / 2); - height: var(--divider-hit-area); -} - -@media (forced-colors: active) { - .divider { - outline: solid 1px transparent; - } -} diff --git a/packages/webawesome/src/components/split-panel/split-panel.styles.ts b/packages/webawesome/src/components/split-panel/split-panel.styles.ts new file mode 100644 index 000000000..aada89211 --- /dev/null +++ b/packages/webawesome/src/components/split-panel/split-panel.styles.ts @@ -0,0 +1,77 @@ +import { css } from 'lit'; + +export default css` + :host { + --divider-width: 0.25rem; + --divider-hit-area: 0.75rem; + --min: 0%; + --max: 100%; + + display: grid; + } + + .start, + .end { + overflow: hidden; + } + + .divider { + flex: 0 0 var(--divider-width); + display: flex; + position: relative; + align-items: center; + justify-content: center; + background-color: var(--wa-color-neutral-border-normal); + color: var(--wa-color-neutral-on-normal); + z-index: 1; + } + + .divider:focus { + outline: none; + } + + :host(:not([disabled])) .divider:focus-visible { + outline: var(--wa-focus-ring); + } + + :host([disabled]) .divider { + cursor: not-allowed; + } + + /* Horizontal */ + :host(:not([orientation='vertical'], [disabled])) .divider { + cursor: col-resize; + } + + :host(:not([orientation='vertical'])) .divider::after { + display: flex; + content: ''; + position: absolute; + height: 100%; + left: calc(var(--divider-hit-area) / -2 + var(--divider-width) / 2); + width: var(--divider-hit-area); + } + + /* Vertical */ + :host([orientation='vertical']) { + flex-direction: column; + } + + :host([orientation='vertical']:not([disabled])) .divider { + cursor: row-resize; + } + + :host([orientation='vertical']) .divider::after { + content: ''; + position: absolute; + width: 100%; + top: calc(var(--divider-hit-area) / -2 + var(--divider-width) / 2); + height: var(--divider-hit-area); + } + + @media (forced-colors: active) { + .divider { + outline: solid 1px transparent; + } + } +`; diff --git a/packages/webawesome/src/components/split-panel/split-panel.ts b/packages/webawesome/src/components/split-panel/split-panel.ts index 7e83bb90b..e3930db79 100644 --- a/packages/webawesome/src/components/split-panel/split-panel.ts +++ b/packages/webawesome/src/components/split-panel/split-panel.ts @@ -7,7 +7,7 @@ import { clamp } from '../../internal/math.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import { LocalizeController } from '../../utilities/localize.js'; -import styles from './split-panel.css'; +import styles from './split-panel.styles.js'; /** * @summary Split panels display two adjacent panels, allowing the user to reposition them. diff --git a/packages/webawesome/src/components/switch/switch.css b/packages/webawesome/src/components/switch/switch.css deleted file mode 100644 index 941bf017c..000000000 --- a/packages/webawesome/src/components/switch/switch.css +++ /dev/null @@ -1,98 +0,0 @@ -:host { - --height: var(--wa-form-control-toggle-size); - --width: calc(var(--height) * 1.75); - --thumb-size: 0.75em; - - display: inline-flex; - line-height: var(--wa-form-control-value-line-height); -} - -label { - position: relative; - display: flex; - align-items: center; - font: inherit; - color: var(--wa-form-control-value-color); - vertical-align: middle; - cursor: pointer; -} - -.switch { - flex: 0 0 auto; - position: relative; - display: flex; - align-items: center; - justify-content: center; - width: var(--width); - height: var(--height); - background-color: var(--wa-form-control-background-color); - border-color: var(--wa-form-control-border-color); - border-radius: var(--height); - border-style: var(--wa-form-control-border-style); - border-width: var(--wa-form-control-border-width); - transition-property: translate, background, border-color, box-shadow; - transition-duration: var(--wa-transition-normal); - transition-timing-function: var(--wa-transition-easing); -} - -.switch .thumb { - aspect-ratio: 1 / 1; - width: var(--thumb-size); - height: var(--thumb-size); - background-color: var(--wa-form-control-border-color); - border-radius: 50%; - translate: calc((var(--width) - var(--height)) / -2); - transition: inherit; -} - -.input { - position: absolute; - opacity: 0; - padding: 0; - margin: 0; - pointer-events: none; -} - -/* Focus */ -label:not(.disabled) .input:focus-visible ~ .switch .thumb { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); -} - -/* Checked */ -.checked .switch { - background-color: var(--wa-form-control-activated-color); - border-color: var(--wa-form-control-activated-color); -} - -.checked .switch .thumb { - background-color: var(--wa-color-surface-default); - translate: calc((var(--width) - var(--height)) / 2); -} - -/* Disabled */ -label:has(> :disabled) { - opacity: 0.5; - cursor: not-allowed; -} - -[part~='label'] { - display: inline-block; - line-height: var(--height); - margin-inline-start: 0.5em; - user-select: none; - -webkit-user-select: none; -} - -: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); -} - -@media (forced-colors: active) { - :checked:enabled + .switch:hover .thumb, - :checked + .switch .thumb { - background-color: ButtonText; - } -} diff --git a/packages/webawesome/src/components/switch/switch.styles.ts b/packages/webawesome/src/components/switch/switch.styles.ts new file mode 100644 index 000000000..f1b689e57 --- /dev/null +++ b/packages/webawesome/src/components/switch/switch.styles.ts @@ -0,0 +1,102 @@ +import { css } from 'lit'; + +export default css` + :host { + --height: var(--wa-form-control-toggle-size); + --width: calc(var(--height) * 1.75); + --thumb-size: 0.75em; + + display: inline-flex; + line-height: var(--wa-form-control-value-line-height); + } + + label { + position: relative; + display: flex; + align-items: center; + font: inherit; + color: var(--wa-form-control-value-color); + vertical-align: middle; + cursor: pointer; + } + + .switch { + flex: 0 0 auto; + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: var(--width); + height: var(--height); + background-color: var(--wa-form-control-background-color); + border-color: var(--wa-form-control-border-color); + border-radius: var(--height); + border-style: var(--wa-form-control-border-style); + border-width: var(--wa-form-control-border-width); + transition-property: translate, background, border-color, box-shadow; + transition-duration: var(--wa-transition-normal); + transition-timing-function: var(--wa-transition-easing); + } + + .switch .thumb { + aspect-ratio: 1 / 1; + width: var(--thumb-size); + height: var(--thumb-size); + background-color: var(--wa-form-control-border-color); + border-radius: 50%; + translate: calc((var(--width) - var(--height)) / -2); + transition: inherit; + } + + .input { + position: absolute; + opacity: 0; + padding: 0; + margin: 0; + pointer-events: none; + } + + /* Focus */ + label:not(.disabled) .input:focus-visible ~ .switch .thumb { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + + /* Checked */ + .checked .switch { + background-color: var(--wa-form-control-activated-color); + border-color: var(--wa-form-control-activated-color); + } + + .checked .switch .thumb { + background-color: var(--wa-color-surface-default); + translate: calc((var(--width) - var(--height)) / 2); + } + + /* Disabled */ + label:has(> :disabled) { + opacity: 0.5; + cursor: not-allowed; + } + + [part~='label'] { + display: inline-block; + line-height: var(--height); + margin-inline-start: 0.5em; + user-select: none; + -webkit-user-select: none; + } + + :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); + } + + @media (forced-colors: active) { + :checked:enabled + .switch:hover .thumb, + :checked + .switch .thumb { + background-color: ButtonText; + } + } +`; diff --git a/packages/webawesome/src/components/switch/switch.ts b/packages/webawesome/src/components/switch/switch.ts index a78807122..14f06084e 100644 --- a/packages/webawesome/src/components/switch/switch.ts +++ b/packages/webawesome/src/components/switch/switch.ts @@ -8,9 +8,9 @@ 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 formControlStyles from '../../styles/component/form-control.css'; -import sizeStyles from '../../styles/utilities/size.css'; -import styles from './switch.css'; +import formControlStyles from '../../styles/component/form-control.styles.js'; +import sizeStyles from '../../styles/component/size.styles.js'; +import styles from './switch.styles.js'; /** * @summary Switches allow the user to toggle an option on or off. diff --git a/packages/webawesome/src/components/tab-group/tab-group.css b/packages/webawesome/src/components/tab-group/tab-group.css deleted file mode 100644 index 6606fa163..000000000 --- a/packages/webawesome/src/components/tab-group/tab-group.css +++ /dev/null @@ -1,224 +0,0 @@ -:host { - --indicator-color: var(--wa-color-brand-fill-loud); - --track-color: var(--wa-color-neutral-fill-normal); - --track-width: 0.125rem; - - display: block; -} - -.tab-group { - display: flex; - border-radius: 0; -} - -.tabs { - display: flex; - position: relative; -} - -.indicator { - position: absolute; -} - -.tab-group-has-scroll-controls .nav-container { - position: relative; - padding: 0 1.5em; -} - -.body { - display: block; -} - -.scroll-button { - display: flex; - align-items: center; - justify-content: center; - position: absolute; - top: 0; - bottom: 0; - width: 1.5em; -} - -.scroll-button-start { - inset-inline-start: 0; -} - -.scroll-button-end { - inset-inline-end: 0; -} - -/* - * Top - */ - -.tab-group-top { - flex-direction: column; -} - -.tab-group-top .nav-container { - order: 1; -} - -.tab-group-top .nav { - display: flex; - overflow-x: auto; - - /* Hide scrollbar in Firefox */ - scrollbar-width: none; -} - -/* Hide scrollbar in Chrome/Safari */ -.tab-group-top .nav::-webkit-scrollbar { - width: 0; - height: 0; -} - -.tab-group-top .tabs { - flex: 1 1 auto; - position: relative; - flex-direction: row; - border-bottom: solid var(--track-width) var(--track-color); -} - -.tab-group-top .indicator { - bottom: calc(-1 * var(--track-width)); - border-bottom: solid var(--track-width) var(--indicator-color); -} - -.tab-group-top .body { - order: 2; -} - -.tab-group-top ::slotted(wa-tab[active]) { - border-block-end: solid var(--track-width) var(--indicator-color); - margin-block-end: calc(-1 * var(--track-width)); -} - -.tab-group-top ::slotted(wa-tab-panel) { - --padding: var(--wa-space-xl) 0; -} - -/* - * Bottom - */ - -.tab-group-bottom { - flex-direction: column; -} - -.tab-group-bottom .nav-container { - order: 2; -} - -.tab-group-bottom .nav { - display: flex; - overflow-x: auto; - - /* Hide scrollbar in Firefox */ - scrollbar-width: none; -} - -/* Hide scrollbar in Chrome/Safari */ -.tab-group-bottom .nav::-webkit-scrollbar { - width: 0; - height: 0; -} - -.tab-group-bottom .tabs { - flex: 1 1 auto; - position: relative; - flex-direction: row; - border-top: solid var(--track-width) var(--track-color); -} - -.tab-group-bottom .indicator { - top: calc(-1 * var(--track-width)); - border-top: solid var(--track-width) var(--indicator-color); -} - -.tab-group-bottom .body { - order: 1; -} - -.tab-group-bottom ::slotted(wa-tab[active]) { - border-block-start: solid var(--track-width) var(--indicator-color); - margin-block-start: calc(-1 * var(--track-width)); -} - -.tab-group-bottom ::slotted(wa-tab-panel) { - --padding: var(--wa-space-xl) 0; -} - -/* - * Start - */ - -.tab-group-start { - flex-direction: row; -} - -.tab-group-start .nav-container { - order: 1; -} - -.tab-group-start .tabs { - flex: 0 0 auto; - flex-direction: column; - border-inline-end: solid var(--track-width) var(--track-color); -} - -.tab-group-start .indicator { - inset-inline-end: calc(-1 * var(--track-width)); - border-right: solid var(--track-width) var(--indicator-color); -} - -.tab-group-start .body { - flex: 1 1 auto; - order: 2; -} - -.tab-group-start ::slotted(wa-tab[active]) { - border-inline-end: solid var(--track-width) var(--indicator-color); - margin-inline-end: calc(-1 * var(--track-width)); -} - -.tab-group-start ::slotted(wa-tab-panel) { - --padding: 0 var(--wa-space-xl); -} - -/* - * End - */ - -.tab-group-end { - flex-direction: row; -} - -.tab-group-end .nav-container { - order: 2; -} - -.tab-group-end .tabs { - flex: 0 0 auto; - flex-direction: column; - border-left: solid var(--track-width) var(--track-color); -} - -.tab-group-end .indicator { - inset-inline-start: calc(-1 * var(--track-width)); - border-inline-start: solid var(--track-width) var(--indicator-color); -} - -.tab-group-end .body { - flex: 1 1 auto; - order: 1; -} - -.tab-group-end ::slotted(wa-tab[active]) { - border-inline-start: solid var(--track-width) var(--indicator-color); - margin-inline-start: calc(-1 * var(--track-width)); -} - -.tab-group-end ::slotted(wa-tab-panel) { - --padding: 0 var(--wa-space-xl); -} diff --git a/packages/webawesome/src/components/tab-group/tab-group.styles.ts b/packages/webawesome/src/components/tab-group/tab-group.styles.ts new file mode 100644 index 000000000..ce98145fb --- /dev/null +++ b/packages/webawesome/src/components/tab-group/tab-group.styles.ts @@ -0,0 +1,228 @@ +import { css } from 'lit'; + +export default css` + :host { + --indicator-color: var(--wa-color-brand-fill-loud); + --track-color: var(--wa-color-neutral-fill-normal); + --track-width: 0.125rem; + + display: block; + } + + .tab-group { + display: flex; + border-radius: 0; + } + + .tabs { + display: flex; + position: relative; + } + + .indicator { + position: absolute; + } + + .tab-group-has-scroll-controls .nav-container { + position: relative; + padding: 0 1.5em; + } + + .body { + display: block; + } + + .scroll-button { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + top: 0; + bottom: 0; + width: 1.5em; + } + + .scroll-button-start { + inset-inline-start: 0; + } + + .scroll-button-end { + inset-inline-end: 0; + } + + /* + * Top + */ + + .tab-group-top { + flex-direction: column; + } + + .tab-group-top .nav-container { + order: 1; + } + + .tab-group-top .nav { + display: flex; + overflow-x: auto; + + /* Hide scrollbar in Firefox */ + scrollbar-width: none; + } + + /* Hide scrollbar in Chrome/Safari */ + .tab-group-top .nav::-webkit-scrollbar { + width: 0; + height: 0; + } + + .tab-group-top .tabs { + flex: 1 1 auto; + position: relative; + flex-direction: row; + border-bottom: solid var(--track-width) var(--track-color); + } + + .tab-group-top .indicator { + bottom: calc(-1 * var(--track-width)); + border-bottom: solid var(--track-width) var(--indicator-color); + } + + .tab-group-top .body { + order: 2; + } + + .tab-group-top ::slotted(wa-tab[active]) { + border-block-end: solid var(--track-width) var(--indicator-color); + margin-block-end: calc(-1 * var(--track-width)); + } + + .tab-group-top ::slotted(wa-tab-panel) { + --padding: var(--wa-space-xl) 0; + } + + /* + * Bottom + */ + + .tab-group-bottom { + flex-direction: column; + } + + .tab-group-bottom .nav-container { + order: 2; + } + + .tab-group-bottom .nav { + display: flex; + overflow-x: auto; + + /* Hide scrollbar in Firefox */ + scrollbar-width: none; + } + + /* Hide scrollbar in Chrome/Safari */ + .tab-group-bottom .nav::-webkit-scrollbar { + width: 0; + height: 0; + } + + .tab-group-bottom .tabs { + flex: 1 1 auto; + position: relative; + flex-direction: row; + border-top: solid var(--track-width) var(--track-color); + } + + .tab-group-bottom .indicator { + top: calc(-1 * var(--track-width)); + border-top: solid var(--track-width) var(--indicator-color); + } + + .tab-group-bottom .body { + order: 1; + } + + .tab-group-bottom ::slotted(wa-tab[active]) { + border-block-start: solid var(--track-width) var(--indicator-color); + margin-block-start: calc(-1 * var(--track-width)); + } + + .tab-group-bottom ::slotted(wa-tab-panel) { + --padding: var(--wa-space-xl) 0; + } + + /* + * Start + */ + + .tab-group-start { + flex-direction: row; + } + + .tab-group-start .nav-container { + order: 1; + } + + .tab-group-start .tabs { + flex: 0 0 auto; + flex-direction: column; + border-inline-end: solid var(--track-width) var(--track-color); + } + + .tab-group-start .indicator { + inset-inline-end: calc(-1 * var(--track-width)); + border-right: solid var(--track-width) var(--indicator-color); + } + + .tab-group-start .body { + flex: 1 1 auto; + order: 2; + } + + .tab-group-start ::slotted(wa-tab[active]) { + border-inline-end: solid var(--track-width) var(--indicator-color); + margin-inline-end: calc(-1 * var(--track-width)); + } + + .tab-group-start ::slotted(wa-tab-panel) { + --padding: 0 var(--wa-space-xl); + } + + /* + * End + */ + + .tab-group-end { + flex-direction: row; + } + + .tab-group-end .nav-container { + order: 2; + } + + .tab-group-end .tabs { + flex: 0 0 auto; + flex-direction: column; + border-left: solid var(--track-width) var(--track-color); + } + + .tab-group-end .indicator { + inset-inline-start: calc(-1 * var(--track-width)); + border-inline-start: solid var(--track-width) var(--indicator-color); + } + + .tab-group-end .body { + flex: 1 1 auto; + order: 1; + } + + .tab-group-end ::slotted(wa-tab[active]) { + border-inline-start: solid var(--track-width) var(--indicator-color); + margin-inline-start: calc(-1 * var(--track-width)); + } + + .tab-group-end ::slotted(wa-tab-panel) { + --padding: 0 var(--wa-space-xl); + } +`; diff --git a/packages/webawesome/src/components/tab-group/tab-group.ts b/packages/webawesome/src/components/tab-group/tab-group.ts index abd684f9f..2421cd96c 100644 --- a/packages/webawesome/src/components/tab-group/tab-group.ts +++ b/packages/webawesome/src/components/tab-group/tab-group.ts @@ -12,7 +12,7 @@ import '../tab-panel/tab-panel.js'; import type WaTabPanel from '../tab-panel/tab-panel.js'; import '../tab/tab.js'; import type WaTab from '../tab/tab.js'; -import styles from './tab-group.css'; +import styles from './tab-group.styles.js'; /** * @summary Tab groups organize content into a container that shows one section at a time. diff --git a/packages/webawesome/src/components/tab-panel/tab-panel.css b/packages/webawesome/src/components/tab-panel/tab-panel.css deleted file mode 100644 index cc74c9f1c..000000000 --- a/packages/webawesome/src/components/tab-panel/tab-panel.css +++ /dev/null @@ -1,14 +0,0 @@ -:host { - --padding: 0; - - display: none; -} - -:host([active]) { - display: block; -} - -.tab-panel { - display: block; - padding: var(--padding); -} diff --git a/packages/webawesome/src/components/tab-panel/tab-panel.styles.ts b/packages/webawesome/src/components/tab-panel/tab-panel.styles.ts new file mode 100644 index 000000000..e0c9f2142 --- /dev/null +++ b/packages/webawesome/src/components/tab-panel/tab-panel.styles.ts @@ -0,0 +1,18 @@ +import { css } from 'lit'; + +export default css` + :host { + --padding: 0; + + display: none; + } + + :host([active]) { + display: block; + } + + .tab-panel { + display: block; + padding: var(--padding); + } +`; diff --git a/packages/webawesome/src/components/tab-panel/tab-panel.ts b/packages/webawesome/src/components/tab-panel/tab-panel.ts index 1974f92f8..53d9b239d 100644 --- a/packages/webawesome/src/components/tab-panel/tab-panel.ts +++ b/packages/webawesome/src/components/tab-panel/tab-panel.ts @@ -3,7 +3,7 @@ import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import styles from './tab-panel.css'; +import styles from './tab-panel.styles.js'; let id = 0; diff --git a/packages/webawesome/src/components/tab/tab.css b/packages/webawesome/src/components/tab/tab.css deleted file mode 100644 index ef87dd807..000000000 --- a/packages/webawesome/src/components/tab/tab.css +++ /dev/null @@ -1,56 +0,0 @@ -:host { - display: inline-block; - color: var(--wa-color-neutral-on-quiet); - font-weight: var(--wa-font-weight-action); -} - -.tab { - display: inline-flex; - align-items: center; - font: inherit; - padding: 1em 1.5em; - white-space: nowrap; - user-select: none; - -webkit-user-select: none; - cursor: pointer; - transition: color var(--wa-transition-fast) var(--wa-transition-easing); - - ::slotted(wa-icon:first-child) { - margin-inline-end: 0.5em; - } - - ::slotted(wa-icon:last-child) { - margin-inline-start: 0.5em; - } -} - -@media (hover: hover) { - :host(:hover:not([disabled])) .tab { - color: currentColor; - } -} - -:host(:focus) { - outline: transparent; -} - -:host(:focus-visible) .tab { - outline: var(--wa-focus-ring); - outline-offset: calc(-1 * var(--wa-border-width-l) - var(--wa-focus-ring-offset)); -} - -:host([active]:not([disabled])) { - color: var(--wa-color-brand-on-quiet); -} - -:host([disabled]) .tab { - opacity: 0.5; - cursor: not-allowed; -} - -@media (forced-colors: active) { - :host([active]:not([disabled])) { - outline: solid 1px transparent; - outline-offset: -3px; - } -} diff --git a/packages/webawesome/src/components/tab/tab.styles.ts b/packages/webawesome/src/components/tab/tab.styles.ts new file mode 100644 index 000000000..61977cff2 --- /dev/null +++ b/packages/webawesome/src/components/tab/tab.styles.ts @@ -0,0 +1,60 @@ +import { css } from 'lit'; + +export default css` + :host { + display: inline-block; + color: var(--wa-color-neutral-on-quiet); + font-weight: var(--wa-font-weight-action); + } + + .tab { + display: inline-flex; + align-items: center; + font: inherit; + padding: 1em 1.5em; + white-space: nowrap; + user-select: none; + -webkit-user-select: none; + cursor: pointer; + transition: color var(--wa-transition-fast) var(--wa-transition-easing); + + ::slotted(wa-icon:first-child) { + margin-inline-end: 0.5em; + } + + ::slotted(wa-icon:last-child) { + margin-inline-start: 0.5em; + } + } + + @media (hover: hover) { + :host(:hover:not([disabled])) .tab { + color: currentColor; + } + } + + :host(:focus) { + outline: transparent; + } + + :host(:focus-visible) .tab { + outline: var(--wa-focus-ring); + outline-offset: calc(-1 * var(--wa-border-width-l) - var(--wa-focus-ring-offset)); + } + + :host([active]:not([disabled])) { + color: var(--wa-color-brand-on-quiet); + } + + :host([disabled]) .tab { + opacity: 0.5; + cursor: not-allowed; + } + + @media (forced-colors: active) { + :host([active]:not([disabled])) { + outline: solid 1px transparent; + outline-offset: -3px; + } + } +`; diff --git a/packages/webawesome/src/components/tab/tab.ts b/packages/webawesome/src/components/tab/tab.ts index aedb2f988..546d41a45 100644 --- a/packages/webawesome/src/components/tab/tab.ts +++ b/packages/webawesome/src/components/tab/tab.ts @@ -3,7 +3,7 @@ import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; -import styles from './tab.css'; +import styles from './tab.styles.js'; let id = 0; diff --git a/packages/webawesome/src/components/tag/tag.css b/packages/webawesome/src/components/tag/tag.css deleted file mode 100644 index 6289ad822..000000000 --- a/packages/webawesome/src/components/tag/tag.css +++ /dev/null @@ -1,78 +0,0 @@ -@layer wa-component { - :host { - display: inline-flex; - gap: 0.5em; - border-radius: var(--wa-border-radius-m); - align-items: center; - background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)); - border-color: var(--wa-color-border-normal, var(--wa-color-neutral-border-normal)); - border-style: var(--wa-border-style); - border-width: var(--wa-border-width-s); - color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet)); - font-size: inherit; - line-height: 1; - white-space: nowrap; - user-select: none; - -webkit-user-select: none; - height: calc(var(--wa-form-control-height) * 0.8); - line-height: calc(var(--wa-form-control-height) - var(--wa-form-control-border-width) * 2); - padding: 0 0.75em; - } - - /* Appearance modifiers */ - :host([appearance='outlined']) { - 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)); - } - - :host([appearance='filled']) { - 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)); - border-color: transparent; - } - - :host([appearance='filled-outlined']) { - 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)); - border-color: var(--wa-color-border-normal, var(--wa-color-neutral-border-normal)); - } - - :host([appearance='accent']) { - 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; - } -} - -.content { - font-size: var(--wa-font-size-smaller); -} - -[part='remove-button'] { - color: inherit; - line-height: 1; -} - -[part='remove-button']::part(base) { - padding: 0; - height: 1em; - width: 1em; -} - -@media (hover: hover) { - :host(:hover) > [part='remove-button']::part(base) { - color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover)); - } -} - -:host(:active) > [part='remove-button']::part(base) { - color: color-mix(in oklab, currentColor, var(--wa-color-mix-active)); -} - -/* - * Pill modifier - */ -:host([pill]) { - border-radius: var(--wa-border-radius-pill); -} diff --git a/packages/webawesome/src/components/tag/tag.styles.ts b/packages/webawesome/src/components/tag/tag.styles.ts new file mode 100644 index 000000000..17d91c99c --- /dev/null +++ b/packages/webawesome/src/components/tag/tag.styles.ts @@ -0,0 +1,82 @@ +import { css } from 'lit'; + +export default css` + @layer wa-component { + :host { + display: inline-flex; + gap: 0.5em; + border-radius: var(--wa-border-radius-m); + align-items: center; + background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)); + border-color: var(--wa-color-border-normal, var(--wa-color-neutral-border-normal)); + border-style: var(--wa-border-style); + border-width: var(--wa-border-width-s); + color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet)); + font-size: inherit; + line-height: 1; + white-space: nowrap; + user-select: none; + -webkit-user-select: none; + height: calc(var(--wa-form-control-height) * 0.8); + line-height: calc(var(--wa-form-control-height) - var(--wa-form-control-border-width) * 2); + padding: 0 0.75em; + } + + /* Appearance modifiers */ + :host([appearance='outlined']) { + 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)); + } + + :host([appearance='filled']) { + 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)); + border-color: transparent; + } + + :host([appearance='filled-outlined']) { + 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)); + border-color: var(--wa-color-border-normal, var(--wa-color-neutral-border-normal)); + } + + :host([appearance='accent']) { + 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; + } + } + + .content { + font-size: var(--wa-font-size-smaller); + } + + [part='remove-button'] { + color: inherit; + line-height: 1; + } + + [part='remove-button']::part(base) { + padding: 0; + height: 1em; + width: 1em; + } + + @media (hover: hover) { + :host(:hover) > [part='remove-button']::part(base) { + color: color-mix(in oklab, currentColor, var(--wa-color-mix-hover)); + } + } + + :host(:active) > [part='remove-button']::part(base) { + color: color-mix(in oklab, currentColor, var(--wa-color-mix-active)); + } + + /* + * Pill modifier + */ + :host([pill]) { + border-radius: var(--wa-border-radius-pill); + } +`; diff --git a/packages/webawesome/src/components/tag/tag.ts b/packages/webawesome/src/components/tag/tag.ts index d2d1fbbe2..f72bf5b14 100644 --- a/packages/webawesome/src/components/tag/tag.ts +++ b/packages/webawesome/src/components/tag/tag.ts @@ -2,11 +2,11 @@ import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { WaRemoveEvent } from '../../events/remove.js'; import WebAwesomeElement from '../../internal/webawesome-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 '../button/button.js'; -import styles from './tag.css'; +import styles from './tag.styles.js'; /** * @summary Tags are used as labels to organize things or to indicate a selection. diff --git a/packages/webawesome/src/components/textarea/textarea.css b/packages/webawesome/src/components/textarea/textarea.css deleted file mode 100644 index da7091971..000000000 --- a/packages/webawesome/src/components/textarea/textarea.css +++ /dev/null @@ -1,120 +0,0 @@ -:host { - border-width: 0; -} - -.textarea { - display: grid; - align-items: center; - margin: 0; - border: none; - outline: none; - cursor: inherit; - font: inherit; - background-color: var(--wa-form-control-background-color); - border-color: var(--wa-form-control-border-color); - border-radius: var(--wa-form-control-border-radius); - border-style: var(--wa-form-control-border-style); - border-width: var(--wa-form-control-border-width); - -webkit-appearance: none; - - &:focus-within { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); - } -} - -/* Appearance modifiers */ -:host([appearance='outlined']) .textarea { - background-color: var(--wa-form-control-background-color); - border-color: var(--wa-form-control-border-color); -} - -:host([appearance='filled']) .textarea { - background-color: var(--wa-color-neutral-fill-quiet); - border-color: var(--wa-color-neutral-fill-quiet); -} - -:host([appearance='filled-outlined']) .textarea { - background-color: var(--wa-color-neutral-fill-quiet); - border-color: var(--wa-form-control-border-color); -} - -textarea { - display: block; - width: 100%; - border: none; - background: transparent; - font: inherit; - color: inherit; - padding: calc(var(--wa-form-control-padding-block) - ((1lh - 1em) / 2)) var(--wa-form-control-padding-inline); /* accounts for the larger line height of textarea content */ - min-height: calc(var(--wa-form-control-height) - var(--border-width) * 2); - box-shadow: none; - margin: 0; - - &::placeholder { - color: var(--wa-form-control-placeholder-color); - user-select: none; - -webkit-user-select: none; - } - - &:autofill { - &, - &:hover, - &:focus, - &:active { - box-shadow: none; - caret-color: var(--wa-form-control-value-color); - } - } - - &:focus { - outline: none; - } -} - -/* Shared textarea and size-adjuster positioning */ -.control, -.size-adjuster { - grid-area: 1 / 1 / 2 / 2; -} - -.size-adjuster { - visibility: hidden; - pointer-events: none; - opacity: 0; - padding: 0; -} - -textarea::-webkit-search-decoration, -textarea::-webkit-search-cancel-button, -textarea::-webkit-search-results-button, -textarea::-webkit-search-results-decoration { - -webkit-appearance: none; -} - -/* - * Resize types - */ - -:host([resize='none']) textarea { - resize: none; -} - -textarea, -:host([resize='vertical']) textarea { - resize: vertical; -} - -:host([resize='horizontal']) textarea { - resize: horizontal; -} - -:host([resize='both']) textarea { - resize: both; -} - -:host([resize='auto']) textarea { - height: auto; - resize: none; - overflow-y: hidden; -} diff --git a/packages/webawesome/src/components/textarea/textarea.styles.ts b/packages/webawesome/src/components/textarea/textarea.styles.ts new file mode 100644 index 000000000..4db3e6e16 --- /dev/null +++ b/packages/webawesome/src/components/textarea/textarea.styles.ts @@ -0,0 +1,124 @@ +import { css } from 'lit'; + +export default css` + :host { + border-width: 0; + } + + .textarea { + display: grid; + align-items: center; + margin: 0; + border: none; + outline: none; + cursor: inherit; + font: inherit; + background-color: var(--wa-form-control-background-color); + border-color: var(--wa-form-control-border-color); + border-radius: var(--wa-form-control-border-radius); + border-style: var(--wa-form-control-border-style); + border-width: var(--wa-form-control-border-width); + -webkit-appearance: none; + + &:focus-within { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + } + + /* Appearance modifiers */ + :host([appearance='outlined']) .textarea { + background-color: var(--wa-form-control-background-color); + border-color: var(--wa-form-control-border-color); + } + + :host([appearance='filled']) .textarea { + background-color: var(--wa-color-neutral-fill-quiet); + border-color: var(--wa-color-neutral-fill-quiet); + } + + :host([appearance='filled-outlined']) .textarea { + background-color: var(--wa-color-neutral-fill-quiet); + border-color: var(--wa-form-control-border-color); + } + + textarea { + display: block; + width: 100%; + border: none; + background: transparent; + font: inherit; + color: inherit; + padding: calc(var(--wa-form-control-padding-block) - ((1lh - 1em) / 2)) var(--wa-form-control-padding-inline); /* accounts for the larger line height of textarea content */ + min-height: calc(var(--wa-form-control-height) - var(--border-width) * 2); + box-shadow: none; + margin: 0; + + &::placeholder { + color: var(--wa-form-control-placeholder-color); + user-select: none; + -webkit-user-select: none; + } + + &:autofill { + &, + &:hover, + &:focus, + &:active { + box-shadow: none; + caret-color: var(--wa-form-control-value-color); + } + } + + &:focus { + outline: none; + } + } + + /* Shared textarea and size-adjuster positioning */ + .control, + .size-adjuster { + grid-area: 1 / 1 / 2 / 2; + } + + .size-adjuster { + visibility: hidden; + pointer-events: none; + opacity: 0; + padding: 0; + } + + textarea::-webkit-search-decoration, + textarea::-webkit-search-cancel-button, + textarea::-webkit-search-results-button, + textarea::-webkit-search-results-decoration { + -webkit-appearance: none; + } + + /* + * Resize types + */ + + :host([resize='none']) textarea { + resize: none; + } + + textarea, + :host([resize='vertical']) textarea { + resize: vertical; + } + + :host([resize='horizontal']) textarea { + resize: horizontal; + } + + :host([resize='both']) textarea { + resize: both; + } + + :host([resize='auto']) textarea { + height: auto; + resize: none; + overflow-y: hidden; + } +`; diff --git a/packages/webawesome/src/components/textarea/textarea.ts b/packages/webawesome/src/components/textarea/textarea.ts index 954b325be..5f63a5e50 100644 --- a/packages/webawesome/src/components/textarea/textarea.ts +++ b/packages/webawesome/src/components/textarea/textarea.ts @@ -8,9 +8,9 @@ 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 formControlStyles from '../../styles/component/form-control.css'; -import sizeStyles from '../../styles/utilities/size.css'; -import styles from './textarea.css'; +import formControlStyles from '../../styles/component/form-control.styles.js'; +import sizeStyles from '../../styles/component/size.styles.js'; +import styles from './textarea.styles.js'; /** * @summary Textareas collect data from the user and allow multiple lines of text. diff --git a/packages/webawesome/src/components/tooltip/tooltip.css b/packages/webawesome/src/components/tooltip/tooltip.css deleted file mode 100644 index 6dc3d2ebc..000000000 --- a/packages/webawesome/src/components/tooltip/tooltip.css +++ /dev/null @@ -1,56 +0,0 @@ -:host { - --max-width: 30ch; - - /** These styles are added so we don't interfere in the DOM. */ - display: inline-block; - position: absolute; - - /** Defaults for inherited CSS properties */ - color: var(--wa-tooltip-content-color); - font-size: var(--wa-tooltip-font-size); - line-height: var(--wa-tooltip-line-height); - text-align: start; - white-space: normal; -} - -.tooltip { - --arrow-size: var(--wa-tooltip-arrow-size); - --arrow-color: var(--wa-tooltip-background-color); -} - -.tooltip::part(popup) { - z-index: 1000; -} - -.tooltip[placement^='top']::part(popup) { - transform-origin: bottom; -} - -.tooltip[placement^='bottom']::part(popup) { - transform-origin: top; -} - -.tooltip[placement^='left']::part(popup) { - transform-origin: right; -} - -.tooltip[placement^='right']::part(popup) { - transform-origin: left; -} - -.body { - display: block; - width: max-content; - max-width: var(--max-width); - border-radius: var(--wa-tooltip-border-radius); - background-color: var(--wa-tooltip-background-color); - border: var(--wa-tooltip-border-width) var(--wa-tooltip-border-style) var(--wa-tooltip-border-color); - padding: 0.25em 0.5em; - user-select: none; - -webkit-user-select: none; -} - -.tooltip::part(arrow) { - border-bottom: var(--wa-tooltip-border-width) var(--wa-tooltip-border-style) var(--wa-tooltip-border-color); - border-right: var(--wa-tooltip-border-width) var(--wa-tooltip-border-style) var(--wa-tooltip-border-color); -} diff --git a/packages/webawesome/src/components/tooltip/tooltip.styles.ts b/packages/webawesome/src/components/tooltip/tooltip.styles.ts new file mode 100644 index 000000000..6bb5be759 --- /dev/null +++ b/packages/webawesome/src/components/tooltip/tooltip.styles.ts @@ -0,0 +1,60 @@ +import { css } from 'lit'; + +export default css` + :host { + --max-width: 30ch; + + /** These styles are added so we don't interfere in the DOM. */ + display: inline-block; + position: absolute; + + /** Defaults for inherited CSS properties */ + color: var(--wa-tooltip-content-color); + font-size: var(--wa-tooltip-font-size); + line-height: var(--wa-tooltip-line-height); + text-align: start; + white-space: normal; + } + + .tooltip { + --arrow-size: var(--wa-tooltip-arrow-size); + --arrow-color: var(--wa-tooltip-background-color); + } + + .tooltip::part(popup) { + z-index: 1000; + } + + .tooltip[placement^='top']::part(popup) { + transform-origin: bottom; + } + + .tooltip[placement^='bottom']::part(popup) { + transform-origin: top; + } + + .tooltip[placement^='left']::part(popup) { + transform-origin: right; + } + + .tooltip[placement^='right']::part(popup) { + transform-origin: left; + } + + .body { + display: block; + width: max-content; + max-width: var(--max-width); + border-radius: var(--wa-tooltip-border-radius); + background-color: var(--wa-tooltip-background-color); + border: var(--wa-tooltip-border-width) var(--wa-tooltip-border-style) var(--wa-tooltip-border-color); + padding: 0.25em 0.5em; + user-select: none; + -webkit-user-select: none; + } + + .tooltip::part(arrow) { + border-bottom: var(--wa-tooltip-border-width) var(--wa-tooltip-border-style) var(--wa-tooltip-border-color); + border-right: var(--wa-tooltip-border-width) var(--wa-tooltip-border-style) var(--wa-tooltip-border-color); + } +`; diff --git a/packages/webawesome/src/components/tooltip/tooltip.ts b/packages/webawesome/src/components/tooltip/tooltip.ts index abbbcfd85..db5d6bebd 100644 --- a/packages/webawesome/src/components/tooltip/tooltip.ts +++ b/packages/webawesome/src/components/tooltip/tooltip.ts @@ -11,7 +11,7 @@ import { uniqueId } from '../../internal/math.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import WaPopup from '../popup/popup.js'; -import styles from './tooltip.css'; +import styles from './tooltip.styles.js'; /** * @summary Tooltips display additional information based on a specific action. diff --git a/packages/webawesome/src/components/tree-item/tree-item.css b/packages/webawesome/src/components/tree-item/tree-item.css deleted file mode 100644 index a34ed4d3d..000000000 --- a/packages/webawesome/src/components/tree-item/tree-item.css +++ /dev/null @@ -1,150 +0,0 @@ -:host { - --show-duration: 200ms; - --hide-duration: 200ms; - - display: block; - color: var(--wa-color-text-normal); - outline: 0; - z-index: 0; -} - -:host(:focus) { - outline: none; -} - -slot:not([name])::slotted(wa-icon) { - margin-inline-end: var(--wa-space-xs); -} - -.tree-item { - position: relative; - display: flex; - align-items: stretch; - flex-direction: column; - cursor: default; - user-select: none; - -webkit-user-select: none; -} - -.checkbox { - line-height: var(--wa-form-control-value-line-height); - pointer-events: none; -} - -.expand-button, -.checkbox, -.label { - font-family: inherit; - font-size: var(--wa-font-size-m); - font-weight: inherit; -} - -.checkbox::part(base) { - display: flex; - align-items: center; -} - -.indentation { - display: block; - width: 1em; - flex-shrink: 0; -} - -.expand-button { - display: flex; - align-items: center; - justify-content: center; - color: var(--wa-color-text-quiet); - width: 2em; - height: 2em; - flex-shrink: 0; - cursor: pointer; -} - -.expand-button { - transition: rotate var(--wa-transition-normal) var(--wa-transition-easing); -} - -.tree-item-expanded .expand-button { - rotate: 90deg; -} - -.tree-item-expanded:dir(rtl) .expand-button { - rotate: -90deg; -} - -.tree-item-expanded:not(.tree-item-loading) slot[name='expand-icon'], -.tree-item:not(.tree-item-expanded) slot[name='collapse-icon'] { - display: none; -} - -.tree-item:not(.tree-item-has-expand-button):not(.tree-item-loading) .expand-icon-slot { - display: none; -} - -.tree-item-loading .expand-icon-slot wa-icon { - display: none; -} - -.expand-button-visible { - cursor: pointer; -} - -.item { - display: flex; - align-items: center; - border-inline-start: solid 3px transparent; -} - -:host([disabled]) .item { - opacity: 0.5; - outline: none; - cursor: not-allowed; -} - -:host(:focus-visible) .item { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); - z-index: 2; -} - -:host(:not([aria-disabled='true'])) .tree-item-selected .item { - background-color: var(--wa-color-neutral-fill-quiet); - border-inline-start-color: var(--wa-color-brand-fill-loud); -} - -:host(:not([aria-disabled='true'])) .expand-button { - color: var(--wa-color-text-quiet); -} - -.label { - display: flex; - align-items: center; - transition: color var(--wa-transition-normal) var(--wa-transition-easing); -} - -.children { - display: block; - font-size: calc(1em + var(--indent-size, var(--wa-space-m))); -} - -/* Indentation lines */ -.children { - position: relative; -} - -.children::before { - content: ''; - position: absolute; - top: var(--indent-guide-offset); - bottom: var(--indent-guide-offset); - inset-inline-start: calc(1em - (var(--indent-guide-width) / 2) - 1px); - border-inline-end: var(--indent-guide-width) var(--indent-guide-style) var(--indent-guide-color); - z-index: 1; -} - -@media (forced-colors: active) { - :host(:not([aria-disabled='true'])) .tree-item-selected .item { - outline: dashed 1px SelectedItem; - } -} diff --git a/packages/webawesome/src/components/tree-item/tree-item.styles.ts b/packages/webawesome/src/components/tree-item/tree-item.styles.ts new file mode 100644 index 000000000..e2c49c6fc --- /dev/null +++ b/packages/webawesome/src/components/tree-item/tree-item.styles.ts @@ -0,0 +1,154 @@ +import { css } from 'lit'; + +export default css` + :host { + --show-duration: 200ms; + --hide-duration: 200ms; + + display: block; + color: var(--wa-color-text-normal); + outline: 0; + z-index: 0; + } + + :host(:focus) { + outline: none; + } + + slot:not([name])::slotted(wa-icon) { + margin-inline-end: var(--wa-space-xs); + } + + .tree-item { + position: relative; + display: flex; + align-items: stretch; + flex-direction: column; + cursor: default; + user-select: none; + -webkit-user-select: none; + } + + .checkbox { + line-height: var(--wa-form-control-value-line-height); + pointer-events: none; + } + + .expand-button, + .checkbox, + .label { + font-family: inherit; + font-size: var(--wa-font-size-m); + font-weight: inherit; + } + + .checkbox::part(base) { + display: flex; + align-items: center; + } + + .indentation { + display: block; + width: 1em; + flex-shrink: 0; + } + + .expand-button { + display: flex; + align-items: center; + justify-content: center; + color: var(--wa-color-text-quiet); + width: 2em; + height: 2em; + flex-shrink: 0; + cursor: pointer; + } + + .expand-button { + transition: rotate var(--wa-transition-normal) var(--wa-transition-easing); + } + + .tree-item-expanded .expand-button { + rotate: 90deg; + } + + .tree-item-expanded:dir(rtl) .expand-button { + rotate: -90deg; + } + + .tree-item-expanded:not(.tree-item-loading) slot[name='expand-icon'], + .tree-item:not(.tree-item-expanded) slot[name='collapse-icon'] { + display: none; + } + + .tree-item:not(.tree-item-has-expand-button):not(.tree-item-loading) .expand-icon-slot { + display: none; + } + + .tree-item-loading .expand-icon-slot wa-icon { + display: none; + } + + .expand-button-visible { + cursor: pointer; + } + + .item { + display: flex; + align-items: center; + border-inline-start: solid 3px transparent; + } + + :host([disabled]) .item { + opacity: 0.5; + outline: none; + cursor: not-allowed; + } + + :host(:focus-visible) .item { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + z-index: 2; + } + + :host(:not([aria-disabled='true'])) .tree-item-selected .item { + background-color: var(--wa-color-neutral-fill-quiet); + border-inline-start-color: var(--wa-color-brand-fill-loud); + } + + :host(:not([aria-disabled='true'])) .expand-button { + color: var(--wa-color-text-quiet); + } + + .label { + display: flex; + align-items: center; + transition: color var(--wa-transition-normal) var(--wa-transition-easing); + } + + .children { + display: block; + font-size: calc(1em + var(--indent-size, var(--wa-space-m))); + } + + /* Indentation lines */ + .children { + position: relative; + } + + .children::before { + content: ''; + position: absolute; + top: var(--indent-guide-offset); + bottom: var(--indent-guide-offset); + inset-inline-start: calc(1em - (var(--indent-guide-width) / 2) - 1px); + border-inline-end: var(--indent-guide-width) var(--indent-guide-style) var(--indent-guide-color); + z-index: 1; + } + + @media (forced-colors: active) { + :host(:not([aria-disabled='true'])) .tree-item-selected .item { + outline: dashed 1px SelectedItem; + } + } +`; diff --git a/packages/webawesome/src/components/tree-item/tree-item.ts b/packages/webawesome/src/components/tree-item/tree-item.ts index dc15888d6..2a1ff4cf0 100644 --- a/packages/webawesome/src/components/tree-item/tree-item.ts +++ b/packages/webawesome/src/components/tree-item/tree-item.ts @@ -17,7 +17,7 @@ import { LocalizeController } from '../../utilities/localize.js'; import '../checkbox/checkbox.js'; import '../icon/icon.js'; import '../spinner/spinner.js'; -import styles from './tree-item.css'; +import styles from './tree-item.styles.js'; /** * @summary A tree item serves as a hierarchical node that lives inside a [tree](/docs/components/tree). diff --git a/packages/webawesome/src/components/tree/tree.css b/packages/webawesome/src/components/tree/tree.styles.ts similarity index 53% rename from packages/webawesome/src/components/tree/tree.css rename to packages/webawesome/src/components/tree/tree.styles.ts index b5ca3878e..666100ae2 100644 --- a/packages/webawesome/src/components/tree/tree.css +++ b/packages/webawesome/src/components/tree/tree.styles.ts @@ -1,19 +1,23 @@ -:host { - /* +import { css } from 'lit'; + +export default css` + :host { + /* * These are actually used by tree item, but we define them here so they can more easily be set and all tree items * stay consistent. */ - --indent-guide-color: var(--wa-color-surface-border); - --indent-guide-offset: 0; - --indent-guide-style: solid; - --indent-guide-width: 0; - --indent-size: var(--wa-space-l); + --indent-guide-color: var(--wa-color-surface-border); + --indent-guide-offset: 0; + --indent-guide-style: solid; + --indent-guide-width: 0; + --indent-size: var(--wa-space-l); - display: block; + display: block; - /* + /* * Tree item indentation uses the "em" unit to increment its width on each level, so setting the font size to zero * here removes the indentation for all the nodes on the first level. */ - font-size: 0; -} + font-size: 0; + } +`; diff --git a/packages/webawesome/src/components/tree/tree.ts b/packages/webawesome/src/components/tree/tree.ts index e82dab664..762cb7d44 100644 --- a/packages/webawesome/src/components/tree/tree.ts +++ b/packages/webawesome/src/components/tree/tree.ts @@ -6,7 +6,7 @@ import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import { LocalizeController } from '../../utilities/localize.js'; import WaTreeItem from '../tree-item/tree-item.js'; -import styles from './tree.css'; +import styles from './tree.styles.js'; function syncCheckboxes(changedTreeItem: WaTreeItem, initialSync = false) { function syncParentItem(treeItem: WaTreeItem) { diff --git a/packages/webawesome/src/components/zoomable-frame/zoomable-frame.css b/packages/webawesome/src/components/zoomable-frame/zoomable-frame.css deleted file mode 100644 index fbd1af03b..000000000 --- a/packages/webawesome/src/components/zoomable-frame/zoomable-frame.css +++ /dev/null @@ -1,82 +0,0 @@ -:host { - display: block; - position: relative; - aspect-ratio: 16 / 9; - width: 100%; - overflow: hidden; - border-radius: var(--wa-border-radius-m); -} - -#frame-container { - position: absolute; - top: 0; - left: 0; - width: calc(100% / var(--zoom)); - height: calc(100% / var(--zoom)); - transform: scale(var(--zoom)); - transform-origin: 0 0; -} - -#iframe { - width: 100%; - height: 100%; - border: none; - border-radius: inherit; - /* Prevent the iframe from being selected, e.g. by a double click. Doesn't affect selection withing the iframe. */ - user-select: none; - -webkit-user-select: none; -} - -#controls { - display: flex; - position: absolute; - bottom: 0.5em; - align-items: center; - font-weight: var(--wa-font-weight-semibold); - padding: 0.25em 0.5em; - gap: 0.5em; - border-radius: var(--wa-border-radius-s); - background: #000b; - color: white; - font-size: min(12px, 0.75em); - user-select: none; - -webkit-user-select: none; - - &:dir(ltr) { - right: 0.5em; - } - - &:dir(rtl) { - left: 0.5em; - } - - button { - display: flex; - align-items: center; - padding: 0.25em; - border: none; - background: none; - color: inherit; - cursor: pointer; - - &:focus { - outline: none; - } - - &:focus-visible { - outline: var(--wa-focus-ring); - outline-offset: var(--wa-focus-ring-offset); - } - - &:disabled { - cursor: not-allowed; - opacity: 0.5; - } - } - - span { - min-width: 4.5ch; /* extra space so numbers don't shift */ - font-variant-numeric: tabular-nums; - text-align: center; - } -} diff --git a/packages/webawesome/src/components/zoomable-frame/zoomable-frame.styles.ts b/packages/webawesome/src/components/zoomable-frame/zoomable-frame.styles.ts new file mode 100644 index 000000000..a40151dec --- /dev/null +++ b/packages/webawesome/src/components/zoomable-frame/zoomable-frame.styles.ts @@ -0,0 +1,86 @@ +import { css } from 'lit'; + +export default css` + :host { + display: block; + position: relative; + aspect-ratio: 16 / 9; + width: 100%; + overflow: hidden; + border-radius: var(--wa-border-radius-m); + } + + #frame-container { + position: absolute; + top: 0; + left: 0; + width: calc(100% / var(--zoom)); + height: calc(100% / var(--zoom)); + transform: scale(var(--zoom)); + transform-origin: 0 0; + } + + #iframe { + width: 100%; + height: 100%; + border: none; + border-radius: inherit; + /* Prevent the iframe from being selected, e.g. by a double click. Doesn't affect selection withing the iframe. */ + user-select: none; + -webkit-user-select: none; + } + + #controls { + display: flex; + position: absolute; + bottom: 0.5em; + align-items: center; + font-weight: var(--wa-font-weight-semibold); + padding: 0.25em 0.5em; + gap: 0.5em; + border-radius: var(--wa-border-radius-s); + background: #000b; + color: white; + font-size: min(12px, 0.75em); + user-select: none; + -webkit-user-select: none; + + &:dir(ltr) { + right: 0.5em; + } + + &:dir(rtl) { + left: 0.5em; + } + + button { + display: flex; + align-items: center; + padding: 0.25em; + border: none; + background: none; + color: inherit; + cursor: pointer; + + &:focus { + outline: none; + } + + &:focus-visible { + outline: var(--wa-focus-ring); + outline-offset: var(--wa-focus-ring-offset); + } + + &:disabled { + cursor: not-allowed; + opacity: 0.5; + } + } + + span { + min-width: 4.5ch; /* extra space so numbers don't shift */ + font-variant-numeric: tabular-nums; + text-align: center; + } + } +`; diff --git a/packages/webawesome/src/components/zoomable-frame/zoomable-frame.ts b/packages/webawesome/src/components/zoomable-frame/zoomable-frame.ts index 6414d6313..1b2854e87 100644 --- a/packages/webawesome/src/components/zoomable-frame/zoomable-frame.ts +++ b/packages/webawesome/src/components/zoomable-frame/zoomable-frame.ts @@ -5,7 +5,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { parseSpaceDelimitedTokens } from '../../internal/parse.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import { LocalizeController } from '../../utilities/localize.js'; -import styles from './zoomable-frame.css'; +import styles from './zoomable-frame.styles.js'; /** * @summary Zoomable frames render iframe content with zoom and interaction controls. diff --git a/packages/webawesome/src/internal/webawesome-element.ts b/packages/webawesome/src/internal/webawesome-element.ts index 68faf36e1..ef0e54fd5 100644 --- a/packages/webawesome/src/internal/webawesome-element.ts +++ b/packages/webawesome/src/internal/webawesome-element.ts @@ -1,13 +1,13 @@ -import type { CSSResult, CSSResultGroup, PropertyValues } from 'lit'; -import { LitElement, isServer, unsafeCSS } from 'lit'; +import type { CSSResultGroup, PropertyValues } from 'lit'; +import { LitElement, isServer } from 'lit'; import { property } from 'lit/decorators.js'; -import hostStyles from '../styles/component/host.css'; +import hostStyles from '../styles/component/host.styles.js'; // Augment Lit's module declare module 'lit' { interface PropertyDeclaration { /** - * Specifies the property’s default value + * Specifies the property's default value */ default?: any; initial?: any; @@ -15,20 +15,13 @@ declare module 'lit' { } export default class WebAwesomeElement extends LitElement { - /** - * One or more CSS files to include in the component's shadow root. Host styles are automatically prepended. We use - * this instead of Lit's styles property because we're importing CSS files as strings and need to convert them using - * unsafeCSS. - */ - static css?: CSSResultGroup | CSSResult | string | (CSSResult | string)[]; + /** One or more CSSResultGroup to include in the component's shadow root. Host styles are automatically prepended. */ + static css?: CSSResultGroup; - /** - * Override the default styles property to fetch and convert string CSS files. Components can override this behavior - * by setting their own `static styles = []` property. - */ + /** Prepends host styles to the component's styles. */ static get styles(): CSSResultGroup { const styles = Array.isArray(this.css) ? this.css : this.css ? [this.css] : []; - return [hostStyles, ...styles].map(style => (typeof style === 'string' ? unsafeCSS(style) : style)); + return [hostStyles, ...styles]; } #hasRecordedInitialProperties = false; diff --git a/packages/webawesome/src/styles/component/form-control.css b/packages/webawesome/src/styles/component/form-control.css deleted file mode 100644 index f9e1efb77..000000000 --- a/packages/webawesome/src/styles/component/form-control.css +++ /dev/null @@ -1,34 +0,0 @@ -:host { - display: flex; - flex-direction: column; -} - -/* Label */ -:is([part~='form-control-label'], [part~='label']):has(*:not(:empty)) { - display: inline-flex; - color: var(--wa-form-control-label-color); - font-weight: var(--wa-form-control-label-font-weight); - line-height: var(--wa-form-control-label-line-height); - margin-block-end: 0.5em; -} - -:host([required]) :is([part~='form-control-label'], [part~='label'])::after { - content: var(--wa-form-control-required-content); - margin-inline-start: var(--wa-form-control-required-content-offset); - color: var(--wa-form-control-required-content-color); -} - -/* Help text */ -[part~='hint'] { - display: block; - color: var(--wa-form-control-hint-color); - font-weight: var(--wa-form-control-hint-font-weight); - line-height: var(--wa-form-control-hint-line-height); - margin-block-start: 0.5em; - font-size: var(--wa-font-size-smaller); - line-height: var(--wa-form-control-label-line-height); - - &:not(.has-slotted) { - display: none; - } -} diff --git a/packages/webawesome/src/styles/component/form-control.styles.ts b/packages/webawesome/src/styles/component/form-control.styles.ts new file mode 100644 index 000000000..461d732e5 --- /dev/null +++ b/packages/webawesome/src/styles/component/form-control.styles.ts @@ -0,0 +1,38 @@ +import { css } from 'lit'; + +export default css` + :host { + display: flex; + flex-direction: column; + } + + /* Label */ + :is([part~='form-control-label'], [part~='label']):has(*:not(:empty)) { + display: inline-flex; + color: var(--wa-form-control-label-color); + font-weight: var(--wa-form-control-label-font-weight); + line-height: var(--wa-form-control-label-line-height); + margin-block-end: 0.5em; + } + + :host([required]) :is([part~='form-control-label'], [part~='label'])::after { + content: var(--wa-form-control-required-content); + margin-inline-start: var(--wa-form-control-required-content-offset); + color: var(--wa-form-control-required-content-color); + } + + /* Help text */ + [part~='hint'] { + display: block; + color: var(--wa-form-control-hint-color); + font-weight: var(--wa-form-control-hint-font-weight); + line-height: var(--wa-form-control-hint-line-height); + margin-block-start: 0.5em; + font-size: var(--wa-font-size-smaller); + line-height: var(--wa-form-control-label-line-height); + + &:not(.has-slotted) { + display: none; + } + } +`; diff --git a/packages/webawesome/src/styles/component/host.css b/packages/webawesome/src/styles/component/host.css deleted file mode 100644 index 7239526e1..000000000 --- a/packages/webawesome/src/styles/component/host.css +++ /dev/null @@ -1,13 +0,0 @@ -:host { - box-sizing: border-box !important; -} - -:host *, -:host *::before, -:host *::after { - box-sizing: inherit !important; -} - -[hidden] { - display: none !important; -} diff --git a/packages/webawesome/src/styles/component/host.styles.ts b/packages/webawesome/src/styles/component/host.styles.ts new file mode 100644 index 000000000..510b37dbd --- /dev/null +++ b/packages/webawesome/src/styles/component/host.styles.ts @@ -0,0 +1,17 @@ +import { css } from 'lit'; + +export default css` + :host { + box-sizing: border-box !important; + } + + :host *, + :host *::before, + :host *::after { + box-sizing: inherit !important; + } + + [hidden] { + display: none !important; + } +`; diff --git a/packages/webawesome/src/styles/component/size.styles.ts b/packages/webawesome/src/styles/component/size.styles.ts new file mode 100644 index 000000000..2b06e5862 --- /dev/null +++ b/packages/webawesome/src/styles/component/size.styles.ts @@ -0,0 +1,18 @@ +import { css } from 'lit'; + +export default css` + :host([size='small']), + .wa-size-s { + font-size: var(--wa-font-size-s); + } + + :host([size='medium']), + .wa-size-m { + font-size: var(--wa-font-size-m); + } + + :host([size='large']), + .wa-size-l { + font-size: var(--wa-font-size-l); + } +`; diff --git a/packages/webawesome/src/styles/component/variants.styles.ts b/packages/webawesome/src/styles/component/variants.styles.ts new file mode 100644 index 000000000..2498610ad --- /dev/null +++ b/packages/webawesome/src/styles/component/variants.styles.ts @@ -0,0 +1,69 @@ +import { css } from 'lit'; + +export default css` + :where(:root), + .wa-neutral, + :host([variant='neutral']) { + --wa-color-fill-loud: var(--wa-color-neutral-fill-loud); + --wa-color-fill-normal: var(--wa-color-neutral-fill-normal); + --wa-color-fill-quiet: var(--wa-color-neutral-fill-quiet); + --wa-color-border-loud: var(--wa-color-neutral-border-loud); + --wa-color-border-normal: var(--wa-color-neutral-border-normal); + --wa-color-border-quiet: var(--wa-color-neutral-border-quiet); + --wa-color-on-loud: var(--wa-color-neutral-on-loud); + --wa-color-on-normal: var(--wa-color-neutral-on-normal); + --wa-color-on-quiet: var(--wa-color-neutral-on-quiet); + } + + .wa-brand, + :host([variant='brand']) { + --wa-color-fill-loud: var(--wa-color-brand-fill-loud); + --wa-color-fill-normal: var(--wa-color-brand-fill-normal); + --wa-color-fill-quiet: var(--wa-color-brand-fill-quiet); + --wa-color-border-loud: var(--wa-color-brand-border-loud); + --wa-color-border-normal: var(--wa-color-brand-border-normal); + --wa-color-border-quiet: var(--wa-color-brand-border-quiet); + --wa-color-on-loud: var(--wa-color-brand-on-loud); + --wa-color-on-normal: var(--wa-color-brand-on-normal); + --wa-color-on-quiet: var(--wa-color-brand-on-quiet); + } + + .wa-success, + :host([variant='success']) { + --wa-color-fill-loud: var(--wa-color-success-fill-loud); + --wa-color-fill-normal: var(--wa-color-success-fill-normal); + --wa-color-fill-quiet: var(--wa-color-success-fill-quiet); + --wa-color-border-loud: var(--wa-color-success-border-loud); + --wa-color-border-normal: var(--wa-color-success-border-normal); + --wa-color-border-quiet: var(--wa-color-success-border-quiet); + --wa-color-on-loud: var(--wa-color-success-on-loud); + --wa-color-on-normal: var(--wa-color-success-on-normal); + --wa-color-on-quiet: var(--wa-color-success-on-quiet); + } + + .wa-warning, + :host([variant='warning']) { + --wa-color-fill-loud: var(--wa-color-warning-fill-loud); + --wa-color-fill-normal: var(--wa-color-warning-fill-normal); + --wa-color-fill-quiet: var(--wa-color-warning-fill-quiet); + --wa-color-border-loud: var(--wa-color-warning-border-loud); + --wa-color-border-normal: var(--wa-color-warning-border-normal); + --wa-color-border-quiet: var(--wa-color-warning-border-quiet); + --wa-color-on-loud: var(--wa-color-warning-on-loud); + --wa-color-on-normal: var(--wa-color-warning-on-normal); + --wa-color-on-quiet: var(--wa-color-warning-on-quiet); + } + + .wa-danger, + :host([variant='danger']) { + --wa-color-fill-loud: var(--wa-color-danger-fill-loud); + --wa-color-fill-normal: var(--wa-color-danger-fill-normal); + --wa-color-fill-quiet: var(--wa-color-danger-fill-quiet); + --wa-color-border-loud: var(--wa-color-danger-border-loud); + --wa-color-border-normal: var(--wa-color-danger-border-normal); + --wa-color-border-quiet: var(--wa-color-danger-border-quiet); + --wa-color-on-loud: var(--wa-color-danger-on-loud); + --wa-color-on-normal: var(--wa-color-danger-on-normal); + --wa-color-on-quiet: var(--wa-color-danger-on-quiet); + } +`; diff --git a/packages/webawesome/src/styles/component/visually-hidden.styles.ts b/packages/webawesome/src/styles/component/visually-hidden.styles.ts new file mode 100644 index 000000000..866bae7a7 --- /dev/null +++ b/packages/webawesome/src/styles/component/visually-hidden.styles.ts @@ -0,0 +1,18 @@ +import { css } from 'lit'; + +export default css` + .wa-visually-hidden:not(:focus-within), + .wa-visually-hidden-force, + .wa-visually-hidden-hint::part(hint), + .wa-visually-hidden-label::part(label) { + 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; + } +`; diff --git a/packages/webawesome/src/styles/utilities/size.css b/packages/webawesome/src/styles/utilities/size.css index ca8a43f36..6ad984091 100644 --- a/packages/webawesome/src/styles/utilities/size.css +++ b/packages/webawesome/src/styles/utilities/size.css @@ -1,15 +1,12 @@ @layer wa-utilities { - :host([size='small']), .wa-size-s { font-size: var(--wa-font-size-s); } - :host([size='medium']), .wa-size-m { font-size: var(--wa-font-size-m); } - :host([size='large']), .wa-size-l { font-size: var(--wa-font-size-l); } diff --git a/packages/webawesome/src/styles/utilities/variants.css b/packages/webawesome/src/styles/utilities/variants.css index df7eb08ec..b93da35a3 100644 --- a/packages/webawesome/src/styles/utilities/variants.css +++ b/packages/webawesome/src/styles/utilities/variants.css @@ -1,7 +1,6 @@ @layer wa-utilities { :where(:root), - .wa-neutral, - :host([variant='neutral']) { + .wa-neutral { --wa-color-fill-loud: var(--wa-color-neutral-fill-loud); --wa-color-fill-normal: var(--wa-color-neutral-fill-normal); --wa-color-fill-quiet: var(--wa-color-neutral-fill-quiet); @@ -13,8 +12,7 @@ --wa-color-on-quiet: var(--wa-color-neutral-on-quiet); } - .wa-brand, - :host([variant='brand']) { + .wa-brand { --wa-color-fill-loud: var(--wa-color-brand-fill-loud); --wa-color-fill-normal: var(--wa-color-brand-fill-normal); --wa-color-fill-quiet: var(--wa-color-brand-fill-quiet); @@ -26,8 +24,7 @@ --wa-color-on-quiet: var(--wa-color-brand-on-quiet); } - .wa-success, - :host([variant='success']) { + .wa-success { --wa-color-fill-loud: var(--wa-color-success-fill-loud); --wa-color-fill-normal: var(--wa-color-success-fill-normal); --wa-color-fill-quiet: var(--wa-color-success-fill-quiet); @@ -39,8 +36,7 @@ --wa-color-on-quiet: var(--wa-color-success-on-quiet); } - .wa-warning, - :host([variant='warning']) { + .wa-warning { --wa-color-fill-loud: var(--wa-color-warning-fill-loud); --wa-color-fill-normal: var(--wa-color-warning-fill-normal); --wa-color-fill-quiet: var(--wa-color-warning-fill-quiet); @@ -52,8 +48,7 @@ --wa-color-on-quiet: var(--wa-color-warning-on-quiet); } - .wa-danger, - :host([variant='danger']) { + .wa-danger { --wa-color-fill-loud: var(--wa-color-danger-fill-loud); --wa-color-fill-normal: var(--wa-color-danger-fill-normal); --wa-color-fill-quiet: var(--wa-color-danger-fill-quiet);