feat(button): add spinner sizes for ionic theme (#30233)

This commit is contained in:
Marta Carlos
2025-03-11 16:56:20 +00:00
committed by GitHub
parent ab81f3de7e
commit aa5d109fb1
8 changed files with 250 additions and 20 deletions

View File

@ -211,10 +211,11 @@
flex-shrink: 0; flex-shrink: 0;
} }
// Button Icons // Button Icons & Spinners
// -------------------------------------------------- // --------------------------------------------------
::slotted(ion-icon) { ::slotted(ion-icon),
::slotted(ion-spinner) {
pointer-events: none; pointer-events: none;
} }

View File

@ -93,18 +93,6 @@
// Button Sizes // Button Sizes
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
/* Extra Small and Small Button */
:host(.button-xsmall),
:host(.button-small) {
::slotted(ion-icon[slot="start"]) {
@include globals.margin-horizontal(null, globals.$ion-space-100);
}
::slotted(ion-icon[slot="end"]) {
@include globals.margin-horizontal(globals.$ion-space-100, null);
}
}
/* Extra Small Button */ /* Extra Small Button */
:host(.button-xsmall) { :host(.button-xsmall) {
--padding-top: #{globals.$ion-space-100}; --padding-top: #{globals.$ion-space-100};
@ -172,6 +160,25 @@
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
} }
// Button with Spinner
// -------------------------------------------------------------------------------
::slotted(ion-spinner) {
--color: currentColor;
}
/* Button containing only a spinner */
::slotted(ion-spinner[slot="start"]),
::slotted(ion-spinner[slot="end"]),
::slotted(ion-spinner[slot="icon-only"]) {
width: globals.$ion-space-500;
height: globals.$ion-space-500;
}
:host(.button-xlarge) ::slotted(ion-spinner) {
width: globals.$ion-space-600;
height: globals.$ion-space-600;
}
// Button Shapes // Button Shapes
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
@ -246,26 +253,40 @@
font-size: globals.$ion-font-size-500; font-size: globals.$ion-font-size-500;
} }
:host(.button-small) ::slotted(ion-icon[slot="start"]) { :host(.button-xsmall) ::slotted(ion-icon[slot="start"]),
:host(.button-xsmall) ::slotted(ion-spinner[slot="start"]),
:host(.button-small) ::slotted(ion-icon[slot="start"]),
:host(.button-small) ::slotted(ion-spinner[slot="start"]) {
@include globals.margin-horizontal(null, globals.$ion-space-200); @include globals.margin-horizontal(null, globals.$ion-space-200);
} }
::slotted(ion-icon[slot="start"]) { ::slotted(ion-icon[slot="start"]),
::slotted(ion-spinner[slot="start"]) {
@include globals.margin-horizontal(null, globals.$ion-space-250); @include globals.margin-horizontal(null, globals.$ion-space-250);
} }
:host(.button-large) ::slotted(ion-icon[slot="start"]) { :host(.button-large) ::slotted(ion-icon[slot="start"]),
:host(.button-large) ::slotted(ion-spinner[slot="start"]),
:host(.button-xlarge) ::slotted(ion-icon[slot="start"]),
:host(.button-xlarge) ::slotted(ion-spinner[slot="start"]) {
@include globals.margin-horizontal(null, globals.$ion-space-300); @include globals.margin-horizontal(null, globals.$ion-space-300);
} }
:host(.button-small) ::slotted(ion-icon[slot="end"]) { :host(.button-xsmall) ::slotted(ion-icon[slot="end"]),
:host(.button-xsmall) ::slotted(ion-spinner[slot="end"]),
:host(.button-small) ::slotted(ion-icon[slot="end"]),
:host(.button-small) ::slotted(ion-spinner[slot="end"]) {
@include globals.margin-horizontal(globals.$ion-space-200, null); @include globals.margin-horizontal(globals.$ion-space-200, null);
} }
::slotted(ion-icon[slot="end"]) { ::slotted(ion-icon[slot="end"]),
::slotted(ion-spinner[slot="end"]) {
@include globals.margin-horizontal(globals.$ion-space-250, null); @include globals.margin-horizontal(globals.$ion-space-250, null);
} }
:host(.button-large) ::slotted(ion-icon[slot="end"]) { :host(.button-large) ::slotted(ion-icon[slot="end"]),
:host(.button-large) ::slotted(ion-spinner[slot="end"]),
:host(.button-xlarge) ::slotted(ion-icon[slot="end"]),
:host(.button-xlarge) ::slotted(ion-spinner[slot="end"]) {
@include globals.margin-horizontal(globals.$ion-space-300, null); @include globals.margin-horizontal(globals.$ion-space-300, null);
} }

View File

@ -0,0 +1,14 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['ionic-md'], directions: ['ltr'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('button: spinner'), () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/spinner`, config);
await page.setIonViewport();
await expect(page).toHaveScreenshot(screenshot(`button-spinner`));
});
});
});

View File

@ -0,0 +1,147 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Button - Spinner</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Button - Spinner</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding" id="content" no-bounce>
<p>
<ion-button>
<ion-spinner slot="start"></ion-spinner>
Left Spinner
</ion-button>
<ion-button href="#">
<ion-spinner slot="start"></ion-spinner>
Left Spinner
</ion-button>
</p>
<p>
<ion-button>
<ion-spinner name="lines" slot="end"></ion-spinner>
Right Spinner
</ion-button>
<ion-button href="#">
<ion-spinner name="lines" slot="end"></ion-spinner>
Right Spinner
</ion-button>
</p>
<p>
<ion-button>
<ion-spinner name="lines-sharp" slot="icon-only"></ion-spinner>
</ion-button>
<ion-button href="#">
<ion-spinner name="lines-sharp" slot="icon-only"></ion-spinner>
</ion-button>
</p>
<p>
<ion-button size="large">
<ion-spinner name="lines-small" slot="start"></ion-spinner>
Left, Large
</ion-button>
<ion-button size="large" href="#">
<ion-spinner name="lines-small" slot="start"></ion-spinner>
Left, Large
</ion-button>
</p>
<p>
<ion-button size="large">
<ion-spinner slot="end"></ion-spinner>
Right, Large
</ion-button>
<ion-button size="large" href="#">
<ion-spinner slot="end"></ion-spinner>
Right, Large
</ion-button>
</p>
<p>
<ion-button size="large">
<ion-spinner slot="icon-only"></ion-spinner>
</ion-button>
<ion-button size="large" href="#">
<ion-spinner slot="icon-only"></ion-spinner>
</ion-button>
</p>
<p>
<ion-button size="small">
<ion-spinner slot="start"></ion-spinner>
Left, Small
</ion-button>
<ion-button size="small" href="#">
<ion-spinner slot="start"></ion-spinner>
Left, Small
</ion-button>
</p>
<p>
<ion-button size="small">
<ion-spinner slot="end"></ion-spinner>
Right, Small
</ion-button>
<ion-button size="small" href="#">
<ion-spinner slot="end"></ion-spinner>
Right, Small
</ion-button>
</p>
<p>
<ion-button size="small">
<ion-spinner slot="icon-only"></ion-spinner>
</ion-button>
<ion-button size="small" href="#">
<ion-spinner slot="icon-only"></ion-spinner>
</ion-button>
</p>
<p>
<ion-button size="xlarge">
<ion-spinner slot="start"></ion-spinner>
Left, Extra Large
</ion-button>
</p>
<p>
<ion-button size="xlarge" href="#">
<ion-spinner slot="start"></ion-spinner>
Left, Extra Large
</ion-button>
</p>
<p>
<ion-button size="xlarge">
<ion-spinner slot="end"></ion-spinner>
Right, Extra Large
</ion-button>
</p>
<p>
<ion-button size="xlarge" href="#">
<ion-spinner slot="end"></ion-spinner>
Right, Extra Large
</ion-button>
</p>
<p>
<ion-button size="xlarge">
<ion-spinner slot="icon-only"></ion-spinner>
</ion-button>
</p>
<p>
<ion-button size="xlarge" href="#">
<ion-spinner slot="icon-only"></ion-spinner>
</ion-button>
</p>
</ion-content>
</ion-app>
</body>
</html>

View File

@ -52,6 +52,14 @@
<ion-select-option value="outline">Outline</ion-select-option> <ion-select-option value="outline">Outline</ion-select-option>
<ion-select-option value="clear">Clear</ion-select-option> <ion-select-option value="clear">Clear</ion-select-option>
</ion-select> </ion-select>
<ion-select id="select-color" justify="space-between" interface="alert" label="Color" placeholder="">
<ion-select-option value="">default</ion-select-option>
<ion-select-option value="primary">Primary</ion-select-option>
<ion-select-option value="success">Success</ion-select-option>
<ion-select-option value="warning">Warning</ion-select-option>
<ion-select-option value="neutral">Neutral</ion-select-option>
</ion-select>
</p> </p>
<div id="screenshot-wrapper" class="ion-margin-top"> <div id="screenshot-wrapper" class="ion-margin-top">
@ -86,10 +94,30 @@
</ion-button> </ion-button>
</p> </p>
<p>
<ion-button theme="ionic">
Button
<ion-spinner slot="end" name="lines-small" />
</ion-button>
<ion-button theme="ionic">
<ion-spinner slot="icon-only" name="lines-small"></ion-spinner>
</ion-button>
</p>
<p>
<ion-button theme="ionic">
Button
<ion-spinner slot="start" name="lines-small" />
</ion-button>
</p>
<h4 class="ion-margin-top">States</h4> <h4 class="ion-margin-top">States</h4>
<p> <p>
<ion-button theme="ionic">Default</ion-button> <ion-button theme="ionic">Default</ion-button>
<ion-button theme="ionic">
Button
<ion-spinner slot="end" name="lines-small" />
</ion-button>
<ion-button theme="ionic"> <ion-button theme="ionic">
<ion-icon slot="icon-only" name="rocket"></ion-icon> <ion-icon slot="icon-only" name="rocket"></ion-icon>
</ion-button> </ion-button>
@ -97,6 +125,10 @@
<p> <p>
<ion-button theme="ionic" class="ion-activated">Activated</ion-button> <ion-button theme="ionic" class="ion-activated">Activated</ion-button>
<ion-button theme="ionic" class="ion-activated">
Button
<ion-spinner slot="end" name="lines-small" />
</ion-button>
<ion-button theme="ionic" class="ion-activated"> <ion-button theme="ionic" class="ion-activated">
<ion-icon slot="icon-only" name="rocket"></ion-icon> <ion-icon slot="icon-only" name="rocket"></ion-icon>
</ion-button> </ion-button>
@ -104,6 +136,10 @@
<p> <p>
<ion-button theme="ionic" class="ion-focused">Focused</ion-button> <ion-button theme="ionic" class="ion-focused">Focused</ion-button>
<ion-button theme="ionic" class="ion-focused">
Button
<ion-spinner slot="end" name="lines-small" />
</ion-button>
<ion-button theme="ionic" class="ion-focused ion-margin-start"> <ion-button theme="ionic" class="ion-focused ion-margin-start">
<ion-icon slot="icon-only" name="rocket"></ion-icon> <ion-icon slot="icon-only" name="rocket"></ion-icon>
</ion-button> </ion-button>
@ -111,6 +147,10 @@
<p> <p>
<ion-button theme="ionic" disabled="true">Disabled</ion-button> <ion-button theme="ionic" disabled="true">Disabled</ion-button>
<ion-button theme="ionic" disabled="true">
Button
<ion-spinner slot="end" name="lines-small" />
</ion-button>
<ion-button theme="ionic" disabled="true"> <ion-button theme="ionic" disabled="true">
<ion-icon slot="icon-only" name="rocket"></ion-icon> <ion-icon slot="icon-only" name="rocket"></ion-icon>
</ion-button> </ion-button>
@ -150,6 +190,13 @@
updateAttr(el, 'fill', e.detail.value); updateAttr(el, 'fill', e.detail.value);
} }
}); });
const selectColor = document.getElementById('select-color');
selectColor.addEventListener('ionChange', (e) => {
for (const el of listOfBtns) {
updateAttr(el, 'color', e.detail.value);
}
});
</script> </script>
</body> </body>
</html> </html>