diff --git a/packages/button/package.json b/packages/button/package.json index 62cdf7ce12..02c7072e0e 100644 --- a/packages/button/package.json +++ b/packages/button/package.json @@ -87,6 +87,7 @@ "@spectrum-web-components/close-button": "^0.3.12", "@spectrum-web-components/icon": "^0.12.11", "@spectrum-web-components/icons-ui": "^0.9.12", + "@spectrum-web-components/progress-circle": "^0.7.9", "@spectrum-web-components/shared": "^0.15.7" }, "devDependencies": { diff --git a/packages/button/src/Button.ts b/packages/button/src/Button.ts index 113b68da23..aa704ce57f 100644 --- a/packages/button/src/Button.ts +++ b/packages/button/src/Button.ts @@ -12,8 +12,10 @@ governing permissions and limitations under the License. import { CSSResultArray, + html, PropertyValues, SizedMixin, + TemplateResult, } from '@spectrum-web-components/base'; import { property } from '@spectrum-web-components/base/src/decorators.js'; import { ButtonBase } from './ButtonBase.js'; @@ -51,6 +53,45 @@ export class Button extends SizedMixin(ButtonBase) { return [...super.styles, buttonStyles]; } + protected pendingCooldown = -1; + + constructor() { + super(); + this.addEventListener( + 'click', + (event: Event): void | boolean => { + if (this.pending) { + event.preventDefault(); + event.stopImmediatePropagation(); + event.stopPropagation(); + return false; + } + }, + { + capture: true, + } + ); + } + + protected disabledByPending = false; + + @property({ type: Boolean, reflect: true }) + public set pending(value: boolean) { + if (value) { + this.pendingCooldown = window.setTimeout(() => { + if (!this.disabled) { + this.disabledByPending = true; + } + this.disabled = true; + }, 1000); + } else { + window.clearTimeout(this.pendingCooldown); + if (this.disabledByPending) { + this.disabled = false; + } + } + } + /** * The visual variant to apply to this button. */ @@ -136,4 +177,15 @@ export class Button extends SizedMixin(ButtonBase) { this.setAttribute('variant', this.variant); } } + + protected override renderButton(): TemplateResult { + return html` + ${this.buttonContent} + + `; + } } diff --git a/packages/button/src/button.css b/packages/button/src/button.css index 5e58a4941d..e04febd35f 100644 --- a/packages/button/src/button.css +++ b/packages/button/src/button.css @@ -25,3 +25,24 @@ governing permissions and limitations under the License. ::slotted([slot='icon']) { inset: unset; } + +#container { + position: relative; + display: flex; +} + +sp-progress-circle { + display: none; +} + +:host([pending][disabled]) sp-progress-circle { + display: block; + position: absolute; + left: 50%; + transform: translate(-50%, 0); +} + +:host([pending][disabled]) slot[name='icon'], +:host([pending][disabled]) #label { + visibility: hidden; +} diff --git a/packages/button/stories/button-accent-fill-pending.stories.ts b/packages/button/stories/button-accent-fill-pending.stories.ts new file mode 100644 index 0000000000..1b07e0b4ef --- /dev/null +++ b/packages/button/stories/button-accent-fill-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'accent'; +const treatment = 'fill'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Accent/Fill/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-accent-outline-pending.stories.ts b/packages/button/stories/button-accent-outline-pending.stories.ts new file mode 100644 index 0000000000..e4f8f15509 --- /dev/null +++ b/packages/button/stories/button-accent-outline-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'accent'; +const treatment = 'outline'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Accent/Outline/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-black-fill-pending.stories.ts b/packages/button/stories/button-black-fill-pending.stories.ts new file mode 100644 index 0000000000..f6909fa3ff --- /dev/null +++ b/packages/button/stories/button-black-fill-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'black'; +const treatment = 'fill'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Black/Fill/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-black-outline-pending.stories.ts b/packages/button/stories/button-black-outline-pending.stories.ts new file mode 100644 index 0000000000..389188f2cf --- /dev/null +++ b/packages/button/stories/button-black-outline-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'black'; +const treatment = 'outline'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Black/Outline/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-negative-fill-pending.stories.ts b/packages/button/stories/button-negative-fill-pending.stories.ts new file mode 100644 index 0000000000..e30c6334c6 --- /dev/null +++ b/packages/button/stories/button-negative-fill-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'negative'; +const treatment = 'fill'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Negative/Fill/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-negative-outline-pending.stories.ts b/packages/button/stories/button-negative-outline-pending.stories.ts new file mode 100644 index 0000000000..b487ccd858 --- /dev/null +++ b/packages/button/stories/button-negative-outline-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'negative'; +const treatment = 'outline'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Negative/Outline/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-primary-fill-pending.stories.ts b/packages/button/stories/button-primary-fill-pending.stories.ts new file mode 100644 index 0000000000..63a0f8400a --- /dev/null +++ b/packages/button/stories/button-primary-fill-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'primary'; +const treatment = 'fill'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Primary/Fill/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-primary-outline-pending.stories.ts b/packages/button/stories/button-primary-outline-pending.stories.ts new file mode 100644 index 0000000000..c26510d8be --- /dev/null +++ b/packages/button/stories/button-primary-outline-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'primary'; +const treatment = 'outline'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Primary/Outline/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-secondary-fill-pending.stories.ts b/packages/button/stories/button-secondary-fill-pending.stories.ts new file mode 100644 index 0000000000..eafefb9d43 --- /dev/null +++ b/packages/button/stories/button-secondary-fill-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'secondary'; +const treatment = 'fill'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Secondary/Fill/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-secondary-outline-pending.stories.ts b/packages/button/stories/button-secondary-outline-pending.stories.ts new file mode 100644 index 0000000000..5fb92e5acb --- /dev/null +++ b/packages/button/stories/button-secondary-outline-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'secondary'; +const treatment = 'outline'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/Secondary/Outline/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-white-fill-pending.stories.ts b/packages/button/stories/button-white-fill-pending.stories.ts new file mode 100644 index 0000000000..75ec88bd21 --- /dev/null +++ b/packages/button/stories/button-white-fill-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'white'; +const treatment = 'fill'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/White/Fill/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/button-white-outline-pending.stories.ts b/packages/button/stories/button-white-outline-pending.stories.ts new file mode 100644 index 0000000000..9cfa56c6e3 --- /dev/null +++ b/packages/button/stories/button-white-outline-pending.stories.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 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 { TemplateResult } from '@spectrum-web-components/base'; +import { Properties, renderButtonSet } from './index.js'; +import { args, argTypes } from './index.js'; + +const variant = 'white'; +const treatment = 'outline'; +const pending = true; + +export default { + component: 'sp-button', + title: 'Button/White/Outline/Pending', + args: { + ...args, + variant, + treatment, + pending, + }, + argTypes, +}; + +export const s = (args: Properties): TemplateResult => renderButtonSet(args); +s.args = { + size: 's', +}; + +export const m = (args: Properties): TemplateResult => renderButtonSet(args); +m.args = { + size: 'm', +}; + +export const l = (args: Properties): TemplateResult => renderButtonSet(args); +l.args = { + size: 'l', +}; + +export const XL = (args: Properties): TemplateResult => renderButtonSet(args); +XL.args = { + size: 'xl', +}; diff --git a/packages/button/stories/index.ts b/packages/button/stories/index.ts index 43bd040d45..dc5a88b878 100644 --- a/packages/button/stories/index.ts +++ b/packages/button/stories/index.ts @@ -23,6 +23,7 @@ import { export const args = { disabled: false, variant: 'cta', + pending: false, }; export const argTypes = { @@ -74,12 +75,25 @@ export const argTypes = { options: ['fill', 'outline'], }, }, + pending: { + name: 'pending', + type: { name: 'boolean', required: false }, + description: 'Shows the pending state of the button.', + table: { + type: { summary: 'boolean' }, + defaultValue: { summary: false }, + }, + control: { + type: 'boolean', + }, + }, }; export interface Properties { variant?: ButtonVariants; treatment?: ButtonTreatments; quiet?: boolean; + pending?: boolean; content?: TemplateResult; disabled?: boolean; size?: 's' | 'm' | 'l' | 'xl'; @@ -123,6 +137,7 @@ export function renderButton(properties: Properties): TemplateResult { href=${ifDefined(properties.href)} target=${ifDefined(properties.target)} ?warning=${properties.warning} + ?pending=${!!properties.pending} > ${properties.content || 'Click Me'} @@ -133,6 +148,7 @@ export function renderButton(properties: Properties): TemplateResult { ?quiet="${!!properties.quiet}" ?disabled=${!!properties.disabled} size=${properties.size} + ?pending=${!!properties.pending} > ${properties.content || 'Click Me'} diff --git a/packages/button/test/button.test.ts b/packages/button/test/button.test.ts index 4b8593b17a..1011c2cec4 100644 --- a/packages/button/test/button.test.ts +++ b/packages/button/test/button.test.ts @@ -513,6 +513,32 @@ describe('Button', () => { expect(el.active).to.be.false; }); + it('shows pending state after delay', async () => { + const el = await fixture