Skip to content

Commit 19eb783

Browse files
committed
chore(dropzone): address feedback
1 parent 95690c9 commit 19eb783

7 files changed

Lines changed: 108 additions & 11 deletions

File tree

2nd-gen/packages/core/components/illustrated-message/IllustratedMessage.base.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import { PropertyValues } from 'lit';
14-
import { property } from 'lit/decorators.js';
14+
import { property, state } from 'lit/decorators.js';
1515

1616
import { SpectrumElement } from '@spectrum-web-components/core/element/index.js';
1717

@@ -82,6 +82,14 @@ export abstract class IllustratedMessageBase extends SpectrumElement {
8282
}
8383
);
8484

85+
/**
86+
* Tracks whether the default (illustration) slot has assigned content, so
87+
* rendering subclasses can collapse the illustration wrapper when no
88+
* illustration is provided instead of reserving its fixed size.
89+
*/
90+
@state()
91+
protected _hasIllustration = false;
92+
8593
protected override updated(changedProperties: PropertyValues): void {
8694
super.updated(changedProperties);
8795

@@ -116,6 +124,16 @@ export abstract class IllustratedMessageBase extends SpectrumElement {
116124
this._sizePropagation.propagate();
117125
}
118126

127+
/**
128+
* Rendering subclasses must wire this to the default slot's `slotchange`
129+
* event (e.g. `<slot @slotchange=${this.handleIllustrationSlotChange}>`)
130+
* so the illustration wrapper collapses when no illustration is slotted.
131+
*/
132+
protected handleIllustrationSlotChange(event: Event): void {
133+
const slot = event.target as HTMLSlotElement;
134+
this._hasIllustration = slot.assignedElements({ flatten: true }).length > 0;
135+
}
136+
119137
/**
120138
* @internal
121139
*

2nd-gen/packages/swc/components/dropzone/Dropzone.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ import styles from './dropzone.css';
4444
* @cssprop --swc-dropzone-background-color - Background color of the drop zone. Defaults to transparent; overridden to a subtle accent tint in the dragged state.
4545
* @cssprop --swc-dropzone-border-color - Border color. Defaults to the gray-300 token in the default state; overridden to the accent visual color in the dragged and focus-within states.
4646
* @cssprop --swc-dropzone-border-style - Border style. Defaults to dashed; overridden to solid in the dragged and focus-within states.
47-
* @cssprop --swc-dropzone-border-width - Border width. Defaults to the border-width-200 token (2px).
48-
* @cssprop --swc-dropzone-corner-radius - Corner radius. Defaults to the corner-radius-400 token.
4947
* @cssprop --swc-dropzone-padding - Padding inside the drop zone. Defaults vary by size: spacing-300 (s), spacing-400 (m), spacing-600 (l).
5048
*/
5149
export class Dropzone extends DropzoneBase {

2nd-gen/packages/swc/components/dropzone/dropzone.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
background: var(--swc-dropzone-background-color, transparent);
3434
border-color: var(--swc-dropzone-border-color, token("gray-300"));
3535
border-style: var(--swc-dropzone-border-style, dashed);
36-
border-width: var(--swc-dropzone-border-width, token("border-width-200"));
37-
border-radius: var(--swc-dropzone-corner-radius, token("corner-radius-400"));
36+
border-width: token("border-width-200");
37+
border-radius: token("corner-radius-400");
3838
}
3939

4040
/* ─────────────────────────────────────

2nd-gen/packages/swc/components/dropzone/stories/dropzone.stories.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,21 @@ const sizeLabels = {
7070
} as const satisfies Record<DropzoneSize, string>;
7171

7272
const DROPZONE_SVG = `
73-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 103" slot="" aria-hidden="true">
74-
<path d="M133.7,8.5h-118c-1.9,0-3.5,1.6-3.5,3.5v27c0,0.8,0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5V12c0-0.3,0.2-0.5,0.5-0.5h118c0.3,0,0.5,0.2,0.5,0.5v91c0,0.3-0.2,0.5-0.5,0.5h-118c-0.3,0-0.5-0.2-0.5-0.5V69c0-0.8-0.7-1.5-1.5-1.5s-1.5,0.7-1.5,1.5v34c0,1.9,1.6,3.5,3.5,3.5h118c1.9,0,3.5-1.6,3.5-3.5V12C137.2,10.1,135.6,8.5,133.7,8.5z"/>
75-
<path d="M31.4,44.5c0,0.8,0.7,1.5,1.5,1.5h50c0.8,0,1.5-0.7,1.5-1.5s-0.7-1.5-1.5-1.5h-50C32.1,43,31.4,43.7,31.4,44.5z"/>
73+
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 96 96">
74+
<path d="M12 68.74a2 2 0 0 1 2 2v3.5a1.5 1.5 0 0 0 1.5 1.5H19a2 2 0 1 1 0 4h-3.5a5.5 5.5 0 0 1-5.5-5.5v-3.5a2 2 0 0 1 2-2m22.5 7a2 2 0 1 1 0 4H27a2 2 0 1 1 0-4zm17 0a2 2 0 1 1 0 4H44a2 2 0 1 1 0-4zm17 0a2 2 0 1 1 0 4H61a2 2 0 1 1 0-4zm15.5-7a2 2 0 0 1 2 2v3.5a5.5 5.5 0 0 1-5.5 5.5H77a2 2 0 1 1 0-4h3.5a1.5 1.5 0 0 0 1.5-1.5v-3.5a2 2 0 0 1 2-2m-36.441-53c1.973 0 3.868.78 5.267 2.17l14.987 14.9A7.4 7.4 0 0 1 70 38.063v21.254c0 4.11-3.348 7.423-7.454 7.423H33.454c-4.106 0-7.454-3.313-7.454-7.423V23.163c0-4.11 3.348-7.423 7.454-7.423zM84 55.24a2 2 0 0 1 2 2v7.5a2 2 0 1 1-4 0v-7.5a2 2 0 0 1 2-2m-72-.5a2 2 0 0 1 2 2v7.5a2 2 0 1 1-4 0v-7.5a2 2 0 0 1 2-2m21.454-35c-1.918 0-3.454 1.544-3.454 3.423v36.154c0 1.88 1.536 3.423 3.454 3.423h29.092c1.918 0 3.454-1.544 3.454-3.423V38.063c0-.904-.361-1.773-1.008-2.416l-14.986-14.9a3.47 3.47 0 0 0-2.447-1.007zm13.594 12a2 2 0 0 1 1.996 2.004l-.035 15.781 5.214-4.324a2 2 0 0 1 2.554 3.078l-8.438 7a2 2 0 0 1-1.31.459l-.033.002a2 2 0 0 1-1.54-.729l-8.222-6.722a2 2 0 0 1 2.532-3.098l5.243 4.286.035-15.74a2 2 0 0 1 2.004-1.997M19 40.74a2 2 0 1 1 0 4h-3.5a1.5 1.5 0 0 0-1.5 1.5v3.5a2 2 0 1 1-4 0v-3.5a5.5 5.5 0 0 1 5.5-5.5zm61.5 0a5.5 5.5 0 0 1 5.5 5.5v3.5a2 2 0 1 1-4 0v-3.5a1.5 1.5 0 0 0-1.5-1.5H77a2 2 0 1 1 0-4z"/>
7675
</svg>
7776
`;
7877

79-
const makeDropzoneSlot = (headingText: string) => html`
78+
const DEFAULT_DROPZONE_DESCRIPTION = 'Or, select a file from your computer';
79+
80+
const makeDropzoneSlot = (
81+
headingText: string,
82+
descriptionText: string = DEFAULT_DROPZONE_DESCRIPTION
83+
) => html`
8084
<swc-illustrated-message>
8185
${unsafeHTML(DROPZONE_SVG)}
8286
<h2 slot="heading">${headingText}</h2>
87+
<span slot="description">${descriptionText}</span>
8388
<swc-button slot="actions" variant="accent">Browse files</swc-button>
8489
</swc-illustrated-message>
8590
`;
@@ -89,6 +94,7 @@ const DROPZONE_SLOT_HTML = `
8994
<swc-illustrated-message>
9095
${DROPZONE_SVG}
9196
<h2 slot="heading">Drag and drop your file</h2>
97+
<span slot="description">${DEFAULT_DROPZONE_DESCRIPTION}</span>
9298
<swc-button slot="actions" variant="accent">Browse files</swc-button>
9399
</swc-illustrated-message>
94100
`;

2nd-gen/packages/swc/components/illustrated-message/IllustratedMessage.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ export class IllustratedMessage extends IllustratedMessageBase {
4646
protected override render(): TemplateResult {
4747
return html`
4848
<div class="swc-IllustratedMessage">
49-
<div class="swc-IllustratedMessage-illustration">
50-
<slot></slot>
49+
<div
50+
class="swc-IllustratedMessage-illustration"
51+
?hidden=${!this._hasIllustration}
52+
>
53+
<slot @slotchange=${this.handleIllustrationSlotChange}></slot>
5154
</div>
5255
<div class="swc-IllustratedMessage-content">
5356
<slot

2nd-gen/packages/swc/components/illustrated-message/illustrated-message.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@
4040
color: var(--swc-illustrated-message-illustration-color, token("neutral-content-color-default"));
4141
}
4242

43+
/*
44+
* [hidden] and .swc-IllustratedMessage-illustration share specificity, so the
45+
* class rule above wins over the UA stylesheet's [hidden] { display: none }
46+
* unless this rule raises the specificity explicitly.
47+
*/
48+
.swc-IllustratedMessage-illustration[hidden] {
49+
display: none;
50+
}
51+
4352
.swc-IllustratedMessage-content {
4453
display: flex;
4554
flex-direction: column;

2nd-gen/packages/swc/components/illustrated-message/test/illustrated-message.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,69 @@ export const DefaultSlotIllustrationTest: Story = {
201201
},
202202
};
203203

204+
export const IllustrationWrapperCollapsesWhenEmptyTest: Story = {
205+
render: () => html`
206+
<swc-illustrated-message>
207+
<h2 slot="heading">Heading</h2>
208+
</swc-illustrated-message>
209+
`,
210+
play: async ({ canvasElement, step }) => {
211+
const illustratedMessage = await getComponent<IllustratedMessage>(
212+
canvasElement,
213+
'swc-illustrated-message'
214+
);
215+
216+
await step(
217+
'hides the illustration wrapper when no illustration is slotted',
218+
async () => {
219+
const wrapper = illustratedMessage.shadowRoot?.querySelector(
220+
'.swc-IllustratedMessage-illustration'
221+
);
222+
expect(wrapper?.hasAttribute('hidden'), 'wrapper has [hidden]').toBe(
223+
true
224+
);
225+
}
226+
);
227+
228+
await step(
229+
'reveals the illustration wrapper once an illustration is slotted',
230+
async () => {
231+
const illustrationSlot =
232+
illustratedMessage.shadowRoot?.querySelector<HTMLSlotElement>(
233+
'slot:not([name])'
234+
);
235+
if (!illustrationSlot) {
236+
return;
237+
}
238+
239+
const slotChanged = new Promise<void>((resolve) =>
240+
illustrationSlot.addEventListener('slotchange', () => resolve(), {
241+
once: true,
242+
})
243+
);
244+
245+
const svg = document.createElementNS(
246+
'http://www.w3.org/2000/svg',
247+
'svg'
248+
);
249+
svg.setAttribute('aria-hidden', 'true');
250+
illustratedMessage.prepend(svg);
251+
252+
await slotChanged;
253+
await illustratedMessage.updateComplete;
254+
255+
const wrapper = illustratedMessage.shadowRoot?.querySelector(
256+
'.swc-IllustratedMessage-illustration'
257+
);
258+
expect(
259+
wrapper?.hasAttribute('hidden'),
260+
'wrapper no longer has [hidden]'
261+
).toBe(false);
262+
}
263+
);
264+
},
265+
};
266+
204267
export const DescriptionSlotTest: Story = {
205268
render: () => html`
206269
<swc-illustrated-message>

0 commit comments

Comments
 (0)