diff --git a/first-gen/packages/divider/package.json b/first-gen/packages/divider/package.json index b4027d98c02..1b092ae98f8 100644 --- a/first-gen/packages/divider/package.json +++ b/first-gen/packages/divider/package.json @@ -58,6 +58,7 @@ ], "types": "./src/index.d.ts", "dependencies": { + "@spectrum-web-components/base": "1.8.0", "@swc/core": "workspace:*" }, "keywords": [ diff --git a/second-gen/packages/core/components/divider/Divider.base.ts b/second-gen/packages/core/components/divider/Divider.base.ts index 7c7b6d2a893..8b2f00c8b18 100644 --- a/second-gen/packages/core/components/divider/Divider.base.ts +++ b/second-gen/packages/core/components/divider/Divider.base.ts @@ -15,13 +15,25 @@ import { property } from 'lit/decorators.js'; import { SizedMixin, SpectrumElement } from '@swc/core/shared/base'; +import { + DIVIDER_STATIC_COLORS, + DIVIDER_VALID_SIZES, + type DividerStaticColor, +} from './Divider.types'; + /** * @element swc-divider */ export abstract class DividerBase extends SizedMixin(SpectrumElement, { - validSizes: ['s', 'm', 'l'], + validSizes: DIVIDER_VALID_SIZES, noDefaultSize: true, }) { + /** + * @internal + * + * A readonly array of the valid static color variants for the divider. + */ + static readonly STATIC_COLORS: readonly string[] = DIVIDER_STATIC_COLORS; /** * Whether the divider is vertical. If false, the divider is horizontal. The default is false. */ @@ -30,9 +42,13 @@ export abstract class DividerBase extends SizedMixin(SpectrumElement, { /** * The static color variant to use for the divider. + * + * @todo Add runtime validation separately. When implementing, + * access STATIC_COLORS from this.constructor.STATIC_COLORS to ensure + * correct values are used. */ @property({ reflect: true, attribute: 'static-color' }) - public staticColor?: 'white' | 'black'; + public staticColor?: DividerStaticColor; protected override firstUpdated(changed: PropertyValues): void { super.firstUpdated(changed); diff --git a/second-gen/packages/core/components/divider/Divider.types.ts b/second-gen/packages/core/components/divider/Divider.types.ts new file mode 100644 index 00000000000..813892fb530 --- /dev/null +++ b/second-gen/packages/core/components/divider/Divider.types.ts @@ -0,0 +1,18 @@ +/** + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import type { ElementSize } from '@swc/core/shared/base'; + +export const DIVIDER_VALID_SIZES: ElementSize[] = ['s', 'm', 'l'] as const; +export const DIVIDER_STATIC_COLORS = ['white', 'black'] as const; + +export type DividerStaticColor = (typeof DIVIDER_STATIC_COLORS)[number]; diff --git a/second-gen/packages/core/components/divider/index.ts b/second-gen/packages/core/components/divider/index.ts index bb4e539cbcf..c8f22a05695 100644 --- a/second-gen/packages/core/components/divider/index.ts +++ b/second-gen/packages/core/components/divider/index.ts @@ -10,3 +10,4 @@ * governing permissions and limitations under the License. */ export * from './Divider.base'; +export * from './Divider.types'; diff --git a/second-gen/packages/swc/.storybook/decorators/static-color-background.ts b/second-gen/packages/swc/.storybook/decorators/static-color-background.ts new file mode 100644 index 00000000000..8463ac9258f --- /dev/null +++ b/second-gen/packages/swc/.storybook/decorators/static-color-background.ts @@ -0,0 +1,55 @@ +/** + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import { html } from 'lit'; +import { makeDecorator } from '@storybook/preview-api'; +import type { DecoratorFunction } from '@storybook/types'; + +/** + * Static color background settings - matching spectrum-css gradients + */ +const staticColorSettings = { + black: 'linear-gradient(45deg, rgb(255 241 246), rgb(238 245 255))', + white: 'linear-gradient(45deg, rgb(64 0 22), rgb(14 24 67))', +} as const; + +/** + * Decorator that applies background colors based on static-color arg. + * Wraps the story in a div with the appropriate background when static-color is set. + */ +export const withStaticColorBackground: DecoratorFunction = makeDecorator({ + name: 'withStaticColorBackground', + parameterName: 'staticColorBackground', + wrapper: (StoryFn, context) => { + const { args } = context; + const staticColor = args?.[ + 'static-color' + ] as keyof typeof staticColorSettings; + + const background = + staticColor && staticColorSettings[staticColor] + ? staticColorSettings[staticColor] + : ''; + + // If no static color is set, just return the story as-is + if (!background) { + return StoryFn(context); + } + + // Wrap the story with the background + return html` +
+ ${StoryFn(context)} +
+ `; + }, +}); diff --git a/second-gen/packages/swc/.storybook/preview-head.html b/second-gen/packages/swc/.storybook/preview-head.html new file mode 100644 index 00000000000..c35f67b94da --- /dev/null +++ b/second-gen/packages/swc/.storybook/preview-head.html @@ -0,0 +1,9 @@ + diff --git a/second-gen/packages/swc/.storybook/preview.ts b/second-gen/packages/swc/.storybook/preview.ts index f5db9158f8d..baef8b1d57a 100644 --- a/second-gen/packages/swc/.storybook/preview.ts +++ b/second-gen/packages/swc/.storybook/preview.ts @@ -10,6 +10,7 @@ import { type Options, } from '@wc-toolkit/storybook-helpers'; import customElements from './custom-elements.json'; +import { withStaticColorBackground } from './decorators/static-color-background'; const options: Options = { categoryOrder: [ @@ -31,6 +32,7 @@ setStorybookHelpersConfig(options); setCustomElementsManifest(customElements); const preview = { + decorators: [withStaticColorBackground], parameters: { layout: 'centered', controls: { diff --git a/second-gen/packages/swc/components/divider/Divider.ts b/second-gen/packages/swc/components/divider/Divider.ts index 9aeb7fbf831..64878e25f79 100644 --- a/second-gen/packages/swc/components/divider/Divider.ts +++ b/second-gen/packages/swc/components/divider/Divider.ts @@ -11,18 +11,42 @@ */ import { CSSResultArray, html, TemplateResult } from 'lit'; +import { classMap } from 'lit/directives/class-map.js'; import { DividerBase } from '@swc/core/components/divider'; import styles from './divider.css'; +// @todo Pull this up into a utility function for all components to leverage +function capitalize(str?: string): string { + if (typeof str !== 'string') { + return ''; + } + return str.charAt(0).toUpperCase() + str.slice(1); +} + /** - * @element sp-divider + * @element swc-divider */ export class Divider extends DividerBase { + // ──────────────────── + // RENDERING & STYLING + // ──────────────────── + public static override styles: CSSResultArray = [styles]; protected override render(): TemplateResult { - return html``; + return html` +
+ `; } } diff --git a/second-gen/packages/swc/components/divider/divider.css b/second-gen/packages/swc/components/divider/divider.css index 0d1e83601b4..e8d5e573f8e 100644 --- a/second-gen/packages/swc/components/divider/divider.css +++ b/second-gen/packages/swc/components/divider/divider.css @@ -12,111 +12,77 @@ :host { display: block; - - --spectrum-divider-background-color: var(--spectrum-gray-300); - --spectrum-divider-background-color-static-white: var( - --spectrum-transparent-white-300 - ); - --spectrum-divider-background-color-static-black: var( - --spectrum-transparent-black-300 - ); -} - -hr { - border: none; - margin: 0; } -@media (forced-colors: active) { - :host { - --highcontrast-divider-background-color: CanvasText; - } -} - -:host { +.spectrum-Divider { + --spectrum-divider-background-color: var(--spectrum-gray-200); --spectrum-divider-thickness: var(--spectrum-divider-thickness-medium); + --spectrum-divider-inline-minimum-size: var( + --spectrum-divider-horizontal-minimum-width + ); + --spectrum-divider-block-minimum-size: var( + --spectrum-divider-vertical-minimum-height + ); } -:host([size='s']) { +.spectrum-Divider--sizeS { --spectrum-divider-thickness: var(--spectrum-divider-thickness-small); } -:host([size='l']) { +.spectrum-Divider--sizeL { --spectrum-divider-thickness: var(--spectrum-divider-thickness-large); --spectrum-divider-background-color: var(--spectrum-gray-800); } -:host([static-color='white']) { - --mod-divider-background-color: var( - --mod-divider-background-color-medium-static-white, - var(--spectrum-divider-background-color-static-white) - ); -} - -:host([static-color='white'][size='s']) { - --mod-divider-background-color: var( - --mod-divider-background-color-small-static-white, - var(--spectrum-divider-background-color-static-white) - ); -} - -:host([static-color='white'][size='l']) { - --mod-divider-background-color: var( - --mod-divider-background-color-large-static-white, - var(--spectrum-transparent-white-800) - ); +/* static white variant colors */ +.spectrum-Divider--staticWhite { + --spectrum-divider-background-color: var(--spectrum-transparent-white-200); } -:host([static-color='black']) { - --mod-divider-background-color: var( - --mod-divider-background-color-medium-static-black, - var(--spectrum-divider-background-color-static-black) - ); +.spectrum-Divider--staticWhite.spectrum-Divider--sizeL { + --spectrum-divider-background-color: var(--spectrum-transparent-white-800); } -:host([static-color='black'][size='s']) { - --mod-divider-background-color: var( - --mod-divider-background-color-small-static-black, - var(--spectrum-divider-background-color-static-black) - ); +/* static black variant colors */ +.spectrum-Divider--staticBlack { + --spectrum-divider-background-color: var(--spectrum-transparent-black-200); } -:host([static-color='black'][size='l']) { - --mod-divider-background-color: var( - --mod-divider-background-color-large-static-black, - var(--spectrum-transparent-black-800) - ); +.spectrum-Divider--staticBlack.spectrum-Divider--sizeL { + --spectrum-divider-background-color: var(--spectrum-transparent-black-800); } -:host { - block-size: var(--mod-divider-thickness, var(--spectrum-divider-thickness)); +.spectrum-Divider { + block-size: var(--spectrum-divider-thickness); inline-size: 100%; + + /* Show the overflow for hr in Edge and IE. */ + overflow: visible; border: none; - border-width: var( - --mod-divider-thickness, - var(--spectrum-divider-thickness) - ); - border-radius: var( - --mod-divider-thickness, - var(--spectrum-divider-thickness) - ); + border-width: var(--spectrum-divider-thickness); + border-radius: var(--spectrum-divider-thickness); background-color: var( --highcontrast-divider-background-color, - var( - --mod-divider-background-color, - var(--spectrum-divider-background-color) - ) + var(--spectrum-divider-background-color) ); - overflow: visible; } -:host([vertical]) { - inline-size: var( - --mod-divider-thickness, - var(--spectrum-divider-thickness) - ); +.spectrum-Divider:not(.spectrum-Divider--vertical) { + min-inline-size: var(--spectrum-divider-inline-minimum-size); +} + +/* vertical dividers */ +.spectrum-Divider--vertical { + inline-size: var(--spectrum-divider-thickness); + min-block-size: var(--spectrum-divider-block-minimum-size); + margin-block: 0; block-size: 100%; - block-size: var(--mod-divider-vertical-height, 100%); - margin-block: var(--mod-divider-vertical-margin); - align-self: var(--mod-divider-vertical-align); + align-self: flex-start; +} + +/* windows high contrast mode */ +@media (forced-colors: active) { + .spectrum-Divider { + --highcontrast-divider-background-color: CanvasText; + } } diff --git a/second-gen/packages/swc/components/divider/stories/divider.stories.ts b/second-gen/packages/swc/components/divider/stories/divider.stories.ts index 69d3822adcd..67f1e671bb2 100644 --- a/second-gen/packages/swc/components/divider/stories/divider.stories.ts +++ b/second-gen/packages/swc/components/divider/stories/divider.stories.ts @@ -11,25 +11,143 @@ */ import { html } from 'lit'; -import type { Meta, StoryObj } from '@storybook/web-components'; +import type { Meta, StoryObj as Story } from '@storybook/web-components'; +import { getStorybookHelpers } from '@wc-toolkit/storybook-helpers'; + +import { Divider } from '@swc/components/divider'; import '@swc/components/divider'; +// ──────────────── +// METADATA +// ──────────────── + +const { events, args, argTypes, template } = getStorybookHelpers('swc-divider'); + +/* + * @todo This is properly configuring the Select, but the control doesn't + * seem to work; need to investigate. + */ + +// argTypes.size = { +// ...argTypes.size, +// control: { type: 'select' }, +// options: Divider.VALID_SIZES, +// }; + +argTypes['static-color'] = { + ...argTypes['static-color'], + control: { type: 'select' }, + options: [undefined, ...Divider.STATIC_COLORS], +}; + +/** + * Dividers bring clarity to a layout by grouping and dividing content that exists in close proximity. It can also be used to establish rhythm and hierarchy. + */ const meta: Meta = { title: 'Divider', component: 'swc-divider', + args, + argTypes, + render: (args) => template(args), + parameters: { + actions: { + handles: events, + }, + }, + tags: ['migrated'], }; export default meta; -type Story = StoryObj; +// ─────────────── +// STORIES +// ─────────────── + +type DividerSize = typeof Divider.prototype.size; + +/** + * By default, dividers are horizontal and should be used for separating content vertically. The medium divider is the default size. + */ export const Default: Story = { + args: { + size: 'm', + }, +}; + +/** + * The small divider is used to divide similar components such as table rows, action button groups, and components within a panel. + * + * The medium divider is used for dividing subsections on a page, or to separate different groupings of components such as panels, rails, etc. + * + * The large divider should only be used for page titles or section titles. + */ +export const Sizes: Story = { render: () => html` -

Small

- -

- Divide like-elements (tables, tool groups, elements within a panel, - etc.) -

+
+ ${Divider.VALID_SIZES.map( + (size) => html` +
+

+ ${size === 's' + ? 'Small' + : size === 'l' + ? 'Large' + : 'Medium'} +

+ ${template({ size: size as DividerSize })} +
+ ` + )} +
+ `, + tags: ['!dev'], +}; + +/** + * Vertical dividers are used to separate content horizontally. + */ +export const Vertical: Story = { + args: { + vertical: true, + }, + render: (args: Record) => html` +
+ ${Divider.VALID_SIZES.map((size) => + template({ ...args, size: size as DividerSize }) + )} +
+ `, + tags: ['!dev'], +}; + +/** + * Use the static color options when a divider needs to be placed on top of a color background or visual. Static color dividers are available in black or white regardless of color theme. + */ +export const StaticBlack: Story = { + args: { + 'static-color': 'black', + }, + render: (args: Record) => html` +
+ ${Divider.VALID_SIZES.map((size) => + template({ ...args, size: size as DividerSize }) + )} +
+ `, + tags: ['!dev'], +}; + +export const StaticWhite: Story = { + args: { + 'static-color': 'white', + }, + render: (args: Record) => html` +
+ ${Divider.VALID_SIZES.map((size) => + template({ ...args, size: size as DividerSize }) + )} +
`, + tags: ['!dev'], }; diff --git a/yarn.lock b/yarn.lock index c71be09f561..8dbd142f0a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5760,6 +5760,7 @@ __metadata: version: 0.0.0-use.local resolution: "@spectrum-web-components/divider@workspace:first-gen/packages/divider" dependencies: + "@spectrum-web-components/base": "npm:1.8.0" "@swc/core": "workspace:*" languageName: unknown linkType: soft