-
Notifications
You must be signed in to change notification settings - Fork 233
feat(badge): s2 styling and render #5718
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fe12a3c
e89e302
e1d2421
b52e52a
5b47c1c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,13 +16,16 @@ import { SizedMixin, SpectrumElement } from '@swc/core/shared/base'; | |
import { ObserveSlotPresence } from '@swc/core/shared/observe-slot-presence'; | ||
import { ObserveSlotText } from '@swc/core/shared/observe-slot-text'; | ||
|
||
export const BADGE_VARIANTS = [ | ||
export const BADGE_VARIANTS_SEMANTIC = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rubencarvalho Initially I started updating these assets per the S2 guidelines before I realized this is the base class being imported into S1 components as well. Would it make sense to hoist this folder to sit between the first- and second-get folders so it's clear that it's a shared resource? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the key here is just going to be to make it clear (via docs and other means) that the S1/S2 distinction is not the same as the 1st-gen/2nd-gen distinction. The As a layer of the architecture that explicitly supports both S1 and S2, I think it's actually OK if |
||
'accent', | ||
'neutral', | ||
'informative', | ||
'positive', | ||
'negative', | ||
'notice', | ||
] as const; | ||
|
||
export const BADGE_VARIANTS_COLOR = [ | ||
'fuchsia', | ||
'indigo', | ||
'magenta', | ||
|
@@ -38,6 +41,11 @@ export const BADGE_VARIANTS = [ | |
'cyan', | ||
'blue', | ||
] as const; | ||
|
||
export const BADGE_VARIANTS = [ | ||
...BADGE_VARIANTS_SEMANTIC, | ||
...BADGE_VARIANTS_COLOR, | ||
] as const; | ||
export type BadgeVariant = (typeof BADGE_VARIANTS)[number]; | ||
export const FIXED_VALUES = [ | ||
'inline-start', | ||
|
@@ -49,8 +57,9 @@ export type FixedValues = (typeof FIXED_VALUES)[number]; | |
|
||
/** | ||
* @element sp-badge-base | ||
* @slot - The text label to display in the badge. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this doesn't have a render, should we define these only on the render layer? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's better to define them here on the base class, since these slots are effectively part of the component architecture dictated by the base class (i.e., any concrete implementation building on this base class will need to include the slots), and the base class includes the mixin functionality associated with the slots. |
||
* @slot icon - The icon to display in the badge. | ||
* @attribute {ElementSize} size - The size of the badge. | ||
* @attribute {BadgeVariant} variant - The variant of the badge. | ||
* @attribute {FixedValues} fixed - The fixed position of the badge. | ||
*/ | ||
export abstract class BadgeBase extends SizedMixin( | ||
ObserveSlotText(ObserveSlotPresence(SpectrumElement, '[slot="icon"]'), ''), | ||
|
@@ -61,27 +70,12 @@ export abstract class BadgeBase extends SizedMixin( | |
@property({ type: String, reflect: true }) | ||
public variant: BadgeVariant = 'informative'; | ||
|
||
@property({ reflect: true }) | ||
public get fixed(): FixedValues | undefined { | ||
return this._fixed; | ||
} | ||
|
||
public set fixed(fixed: FixedValues | undefined) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to me to be how the @Property works by default. I don't see any regressions when I simplify this but let me know if I've missed a nuance here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At a glance, I think you're right—at least, I can't immediately see why this property would need a bespoke getter and setter. That said, the aim of the Barebones milestone is to avoid any changes not strictly related to migrating these components to the new architecture, so I think the best course of action here would be to add a |
||
if (fixed === this.fixed) { | ||
return; | ||
} | ||
const oldValue = this.fixed; | ||
this._fixed = fixed; | ||
if (fixed) { | ||
this.setAttribute('fixed', fixed); | ||
} else { | ||
this.removeAttribute('fixed'); | ||
} | ||
this.requestUpdate('fixed', oldValue); | ||
} | ||
|
||
private _fixed?: FixedValues; | ||
@property({ type: String, reflect: true }) | ||
public fixed?: FixedValues; | ||
|
||
/** | ||
* @internal Used for rendering gap when the badge has an icon. | ||
*/ | ||
protected get hasIcon(): boolean { | ||
return this.slotContentIsPresent; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,15 +10,40 @@ | |
* governing permissions and limitations under the License. | ||
*/ | ||
|
||
import { CSSResultArray, html, nothing, TemplateResult } from 'lit'; | ||
import { CSSResultArray, html, PropertyValues, TemplateResult } from 'lit'; | ||
import { property } from 'lit/decorators.js'; | ||
import { classMap } from 'lit/directives/class-map.js'; | ||
import { when } from 'lit/directives/when.js'; | ||
|
||
import { BadgeBase } from '@swc/core/components/badge'; | ||
import { | ||
BADGE_VARIANTS_COLOR as BADGE_VARIANTS_COLOR_BASE, | ||
BADGE_VARIANTS_SEMANTIC, | ||
BadgeBase, | ||
} from '@swc/core/components/badge'; | ||
|
||
export const BADGE_VARIANTS_COLOR = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This re-exports the const with the addition of the new colors. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we definitely need to define a constant representing the full set of S2 colors. As I mentioned in an earlier comment, I've done some additional exploration into patterns for managing differences in S1 & S2 types, which I'll put in a separate PR (to land after this one). |
||
...BADGE_VARIANTS_COLOR_BASE, | ||
'pink', | ||
'turquoise', | ||
'brown', | ||
'cinnamon', | ||
'silver', | ||
] as const; | ||
|
||
export const BADGE_VARIANTS = [ | ||
...BADGE_VARIANTS_SEMANTIC, | ||
...BADGE_VARIANTS_COLOR, | ||
] as const; | ||
export type BadgeVariant = (typeof BADGE_VARIANTS)[number]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if I need to redefine this since technically it's the same but the content of the BADGE_VARIANTS has changed so I went ahead and did that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rubencarvalho Do you know how that works in Typescript? Would it calculate the value of BadgeVariant at the time of use based on the new definition of BADGE_VARIANTS? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, as far as TypeScript is concerned, the type defined in this module is completely different from the type defined in the Again, though, I'll make a separate follow-on PR to propose some patterns for managing S1 and S2 types. |
||
|
||
import styles from './badge.css'; | ||
|
||
// Export types and values to avoid breaking changes | ||
export { BADGE_VARIANTS, FIXED_VALUES } from '@swc/core/components/badge'; | ||
export type { BadgeVariant, FixedValues } from '@swc/core/components/badge'; | ||
export { | ||
BADGE_VARIANTS_SEMANTIC, | ||
FIXED_VALUES, | ||
} from '@swc/core/components/badge'; | ||
export type { FixedValues } from '@swc/core/components/badge'; | ||
|
||
/** | ||
* A badge component that displays short, descriptive information about an element. | ||
|
@@ -28,14 +53,16 @@ export type { BadgeVariant, FixedValues } from '@swc/core/components/badge'; | |
* @since 1.0.0 | ||
* @status stable | ||
* @github https://github.com/adobe/spectrum-web-components/tree/main/... | ||
* @figma https://www.figma.com/design/... | ||
* @figma https://www.figma.com/design/Mngz9H7WZLbrCvGQf3GnsY/S2-%2F-Desktop?node-id=36806-6551 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At one point, we talked about not sharing Figma links. Are we concerned at all with committing this link to the repo? I know we have it in CSS, but I thought that ended up being sort of a no-no. Or was that just for in PR descriptions? Or am I misremembering (which could totally be)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great question! I'm not sure. I know we don't post Jira links publicly but I thought since the Figma assets are behind a login, it was okay to include them in Storybook. @najikahalsema do you know? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think, since we're not going to be releasing any S2 components for a while (even in preview form), we might as well take the conservative approach and not include any real Figma links for the time being. |
||
* | ||
* @attribute {BadgeVariant} variant - The variant of the badge. | ||
* @attribute {boolean} subtle - Whether the badge is subtle. | ||
* @attribute {boolean} outline - Whether the badge is outlined. | ||
* @attribute {FixedValues} fixed - The fixed position of the badge. | ||
* | ||
* @slot - Text label of the badge | ||
* @slot icon - Optional icon that appears to the left of the label | ||
* | ||
* @csspart label - The text content area of the badge | ||
* @csspart icon - The icon area of the badge (when present) | ||
* | ||
* @example | ||
* <swc-badge variant="positive">New</swc-badge> | ||
* | ||
|
@@ -46,23 +73,68 @@ export type { BadgeVariant, FixedValues } from '@swc/core/components/badge'; | |
* </swc-badge> | ||
*/ | ||
export class Badge extends BadgeBase { | ||
@property({ type: Boolean, reflect: true }) | ||
public subtle: boolean = false; | ||
|
||
@property({ type: Boolean, reflect: true }) | ||
public outline: boolean = false; | ||
|
||
public static override get styles(): CSSResultArray { | ||
return [styles]; | ||
} | ||
|
||
protected override render(): TemplateResult { | ||
return html` | ||
${this.hasIcon | ||
? html` | ||
<slot | ||
name="icon" | ||
?icon-only=${!this.slotHasContent} | ||
></slot> | ||
` | ||
: nothing} | ||
<div class="label"> | ||
<slot></slot> | ||
<div | ||
class=${classMap({ | ||
['spectrum-Badge']: true, | ||
[`spectrum-Badge--size${this.size?.toUpperCase()}`]: | ||
typeof this.size !== 'undefined', | ||
[`spectrum-Badge--${this.variant}`]: | ||
typeof this.variant !== 'undefined', | ||
[`spectrum-Badge--subtle`]: this.subtle, | ||
[`spectrum-Badge--outline`]: this.outline, | ||
[`spectrum-Badge--fixed-${this.fixed}`]: | ||
typeof this.fixed !== 'undefined', | ||
})} | ||
> | ||
${when( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I updated the ternary to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Since the 2nd-gen |
||
this.hasIcon, | ||
() => html` | ||
<div | ||
class=${classMap({ | ||
[`spectrum-Badge-icon`]: true, | ||
[`spectrum-Badge-icon--no-label`]: | ||
!this.slotHasContent, | ||
})} | ||
> | ||
<slot name="icon"></slot> | ||
</div> | ||
` | ||
)} | ||
<div class="spectrum-Badge-label"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tested adding this class to the slot itself and it didn't render padding correctly. Maybe just a case of needing the appropriate display settings but I didn't dig into it too much. Would be good to have a standard "best practice" in place for whether we want to wrap slots to apply styles or style slot containers directly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it looks like adding a rule to the component styles that sets I think in general it would be better to avoid systematically wrapping slots for styling purposes. |
||
<slot></slot> | ||
</div> | ||
</div> | ||
`; | ||
} | ||
|
||
protected override update(changedProperties: PropertyValues): void { | ||
super.update(changedProperties); | ||
if (window.__swc?.DEBUG) { | ||
if ( | ||
this.outline && | ||
!BADGE_VARIANTS_SEMANTIC.includes(this.variant) | ||
) { | ||
window.__swc.warn( | ||
this, | ||
`<${this.localName}> element only supports the outline styling if the variant is a semantic color variant.`, | ||
'https://opensource.adobe.com/spectrum-web-components/components/badge/#variants', | ||
{ | ||
issues: [...BADGE_VARIANTS_SEMANTIC], | ||
} | ||
); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separating out the semantic variants from the color variants helps us in Storybook (and possibly down the road) because only semantic variants support outline styling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this seems like a good idea!