Skip to content

Commit

Permalink
feat(radio): display as block when justify or alignment properties ar…
Browse files Browse the repository at this point in the history
…e defined (#29801)

- Change the radio's `display` property to `block` when the `justify` or `alignment` property is set.
- Set the default `justify-content` style to `space-between` so that a radio with `width: 100%` set without `justify` or `alignment` set will still have the same default
- Modifies the `label-placement` e2e test to remove the explicit width as setting the property will make them full-width
- Adds two examples to the `label-placement` e2e test of labels that do not have `justify` set but use `width: 100%` to ensure they are working as expected without it
- Adds one example to the `label-placement` e2e test of a long label that uses `justify` to ensure it still wraps properly
  • Loading branch information
brandyscarney authored Aug 29, 2024
1 parent 0332c8c commit 18b02b3
Show file tree
Hide file tree
Showing 181 changed files with 120 additions and 44 deletions.
4 changes: 2 additions & 2 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1319,10 +1319,10 @@ ion-progress-bar,part,stream
ion-progress-bar,part,track

ion-radio,shadow
ion-radio,prop,alignment,"center" | "start",'center',false,false
ion-radio,prop,alignment,"center" | "start" | undefined,undefined,false,false
ion-radio,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-radio,prop,disabled,boolean,false,false,false
ion-radio,prop,justify,"end" | "space-between" | "start",'space-between',false,false
ion-radio,prop,justify,"end" | "space-between" | "start" | undefined,undefined,false,false
ion-radio,prop,labelPlacement,"end" | "fixed" | "stacked" | "start",'start',false,false
ion-radio,prop,mode,"ios" | "md",undefined,false,false
ion-radio,prop,name,string,this.inputId,false,false
Expand Down
12 changes: 6 additions & 6 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2248,9 +2248,9 @@ export namespace Components {
}
interface IonRadio {
/**
* How to control the alignment of the radio and label on the cross axis. `"start"`: The label and control will appear on the left of the cross axis in LTR, and on the right side in RTL. `"center"`: The label and control will appear at the center of the cross axis in both LTR and RTL.
* How to control the alignment of the radio and label on the cross axis. `"start"`: The label and control will appear on the left of the cross axis in LTR, and on the right side in RTL. `"center"`: The label and control will appear at the center of the cross axis in both LTR and RTL. Setting this property will change the radio `display` to `block`.
*/
"alignment": 'start' | 'center';
"alignment"?: 'start' | 'center';
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
Expand All @@ -2260,9 +2260,9 @@ export namespace Components {
*/
"disabled": boolean;
/**
* How to pack the label and radio within a line. `"start"`: The label and radio will appear on the left in LTR and on the right in RTL. `"end"`: The label and radio will appear on the right in LTR and on the left in RTL. `"space-between"`: The label and radio will appear on opposite ends of the line with space between the two elements.
* How to pack the label and radio within a line. `"start"`: The label and radio will appear on the left in LTR and on the right in RTL. `"end"`: The label and radio will appear on the right in LTR and on the left in RTL. `"space-between"`: The label and radio will appear on opposite ends of the line with space between the two elements. Setting this property will change the radio `display` to `block`.
*/
"justify": 'start' | 'end' | 'space-between';
"justify"?: 'start' | 'end' | 'space-between';
/**
* Where to place the label relative to the radio. `"start"`: The label will appear to the left of the radio in LTR and to the right in RTL. `"end"`: The label will appear to the right of the radio in LTR and to the left in RTL. `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("..."). `"stacked"`: The label will appear above the radio regardless of the direction. The alignment of the label can be controlled with the `alignment` property.
*/
Expand Down Expand Up @@ -6939,7 +6939,7 @@ declare namespace LocalJSX {
}
interface IonRadio {
/**
* How to control the alignment of the radio and label on the cross axis. `"start"`: The label and control will appear on the left of the cross axis in LTR, and on the right side in RTL. `"center"`: The label and control will appear at the center of the cross axis in both LTR and RTL.
* How to control the alignment of the radio and label on the cross axis. `"start"`: The label and control will appear on the left of the cross axis in LTR, and on the right side in RTL. `"center"`: The label and control will appear at the center of the cross axis in both LTR and RTL. Setting this property will change the radio `display` to `block`.
*/
"alignment"?: 'start' | 'center';
/**
Expand All @@ -6951,7 +6951,7 @@ declare namespace LocalJSX {
*/
"disabled"?: boolean;
/**
* How to pack the label and radio within a line. `"start"`: The label and radio will appear on the left in LTR and on the right in RTL. `"end"`: The label and radio will appear on the right in LTR and on the left in RTL. `"space-between"`: The label and radio will appear on opposite ends of the line with space between the two elements.
* How to pack the label and radio within a line. `"start"`: The label and radio will appear on the left in LTR and on the right in RTL. `"end"`: The label and radio will appear on the right in LTR and on the left in RTL. `"space-between"`: The label and radio will appear on opposite ends of the line with space between the two elements. Setting this property will change the radio `display` to `block`.
*/
"justify"?: 'start' | 'end' | 'space-between';
/**
Expand Down
15 changes: 15 additions & 0 deletions core/src/components/radio/radio.scss
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ input {
flex-grow: 1;

align-items: center;
justify-content: space-between;

height: inherit;

Expand Down Expand Up @@ -165,6 +166,20 @@ input {
align-items: center;
}

// Justify Content & Align Items
// ---------------------------------------------

// The radio should be displayed as block when either justify
// or alignment is set; otherwise, these properties will have no
// visible effect.
:host(.radio-justify-space-between),
:host(.radio-justify-start),
:host(.radio-justify-end),
:host(.radio-alignment-start),
:host(.radio-alignment-center) {
display: block;
}

// Radio Label Placement - Start
// ----------------------------------------------------------------

Expand Down
10 changes: 6 additions & 4 deletions core/src/components/radio/radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,17 @@ export class Radio implements ComponentInterface {
* on the left in RTL.
* `"space-between"`: The label and radio will appear on opposite
* ends of the line with space between the two elements.
* Setting this property will change the radio `display` to `block`.
*/
@Prop() justify: 'start' | 'end' | 'space-between' = 'space-between';
@Prop() justify?: 'start' | 'end' | 'space-between';

/**
* How to control the alignment of the radio and label on the cross axis.
* `"start"`: The label and control will appear on the left of the cross axis in LTR, and on the right side in RTL.
* `"center"`: The label and control will appear at the center of the cross axis in both LTR and RTL.
* Setting this property will change the radio `display` to `block`.
*/
@Prop() alignment: 'start' | 'center' = 'center';
@Prop() alignment?: 'start' | 'center';

/**
* Emitted when the radio button has focus.
Expand Down Expand Up @@ -223,8 +225,8 @@ export class Radio implements ComponentInterface {
'in-item': inItem,
'radio-checked': checked,
'radio-disabled': disabled,
[`radio-justify-${justify}`]: true,
[`radio-alignment-${alignment}`]: true,
[`radio-justify-${justify}`]: justify !== undefined,
[`radio-alignment-${alignment}`]: alignment !== undefined,
[`radio-label-placement-${labelPlacement}`]: true,
// Focus and active styling should not apply when the radio is in an item
'ion-activatable': !inItem,
Expand Down
32 changes: 23 additions & 9 deletions core/src/components/radio/test/basic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@

<style>
ion-radio {
display: block;
margin-bottom: 8px;
}

hr {
background: #ddd;
}
</style>
</head>

Expand All @@ -31,17 +34,28 @@

<ion-content class="ion-padding">
<div id="radios">
<ion-radio-group>
<ion-radio value="radio" justify="start" label-placement="end">Unchecked</ion-radio>
</ion-radio-group>
<ion-radio-group> <ion-radio value="radio" label-placement="end">Unchecked</ion-radio> </ion-radio-group
><br />
<ion-radio-group value="radio">
<ion-radio value="radio" justify="start" label-placement="end">Checked</ion-radio>
</ion-radio-group>
<ion-radio value="radio" label-placement="end">Checked</ion-radio> </ion-radio-group
><br />
<ion-radio-group>
<ion-radio value="radio" justify="start" label-placement="end" disabled>Disabled</ion-radio>
</ion-radio-group>
<ion-radio value="radio" label-placement="end" disabled>Disabled</ion-radio> </ion-radio-group
><br />
<ion-radio-group value="radio">
<ion-radio value="radio" label-placement="end" disabled>Disabled, Checked</ion-radio> </ion-radio-group
><br />

<hr />

<ion-radio-group value="radio"> <ion-radio value="radio">Default width</ion-radio> </ion-radio-group><br />

<ion-radio-group value="radio">
<ion-radio value="radio" style="width: 200px">Specified width </ion-radio> </ion-radio-group
><br />

<ion-radio-group value="radio">
<ion-radio value="radio" justify="start" label-placement="end" disabled>Disabled, Checked</ion-radio>
<ion-radio value="radio" style="width: 100%">Full-width </ion-radio>
</ion-radio-group>
</div>
</ion-content>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 0 additions & 4 deletions core/src/components/radio/test/label-placement/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@
padding: 0;
}
}

ion-radio {
width: 100%;
}
</style>
</head>

Expand Down
87 changes: 68 additions & 19 deletions core/src/components/radio/test/label-placement/radio.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,55 @@ import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

/**
* By default ion-radio only takes up
* as much space as it needs. Justification is
* used for when the radio takes up the full
* line (such as in an ion-item). As a result,
* we set the width of the radio so we can
* see the justification results.
* By default ion-radio only takes up as much space
* as it needs. Justification is used for when the
* radio should take up the full line (such as in an
* ion-item or when it has 100% width).
*/

configs().forEach(({ title, screenshot, config }) => {
test.describe(title('radio: label'), () => {
test.describe('radio: default placement', () => {
test('should render a space between justification with a full width radio', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio value="1" style="width: 100%">
Label
</ion-radio>
</ion-radio-group>
`,
config
);

const radio = page.locator('ion-radio');
await expect(radio).toHaveScreenshot(screenshot(`radio-label-full-width`));
});

test('should truncate long labels with ellipses', async ({ page }) => {
// radio needs to be full width to truncate properly
// because it is not inside of an `ion-app` in tests
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio value="1" style="width: 100%">
Long Label Long Label Long Label Long Label Long Label Long Label
</ion-radio>
</ion-radio-group>
`,
config
);

const radio = page.locator('ion-radio');
await expect(radio).toHaveScreenshot(screenshot(`radio-label-long-label`));
});
});

test.describe('radio: start placement', () => {
test('should render a start justification with label in the start position', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="start" justify="start" style="width: 200px" value="1">Label</ion-radio>
<ion-radio label-placement="start" justify="start" value="1">Label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -30,7 +63,7 @@ configs().forEach(({ title, screenshot, config }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="start" justify="end" style="width: 200px" value="1">Label</ion-radio>
<ion-radio label-placement="start" justify="end" value="1">Label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -43,7 +76,7 @@ configs().forEach(({ title, screenshot, config }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="start" justify="space-between" style="width: 200px" value="1">Label</ion-radio>
<ion-radio label-placement="start" justify="space-between" value="1">Label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -52,14 +85,30 @@ configs().forEach(({ title, screenshot, config }) => {
const radio = page.locator('ion-radio');
await expect(radio).toHaveScreenshot(screenshot(`radio-label-start-justify-space-between`));
});

test('should truncate long labels with ellipses', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio value="1" label-placement="start" justify="start">
Long Label Long Label Long Label Long Label Long Label Long Label
</ion-radio>
</ion-radio-group>
`,
config
);

const radio = page.locator('ion-radio');
await expect(radio).toHaveScreenshot(screenshot(`radio-label-start-justify-start-long-label`));
});
});

test.describe('radio: end placement', () => {
test('should render a start justification with label in the end position', async ({ page }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="end" justify="start" style="width: 200px" value="1">Label</ion-radio>
<ion-radio label-placement="end" justify="start" value="1">Label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -72,7 +121,7 @@ configs().forEach(({ title, screenshot, config }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="end" justify="end" style="width: 200px" value="1">Label</ion-radio>
<ion-radio label-placement="end" justify="end" value="1">Label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -85,7 +134,7 @@ configs().forEach(({ title, screenshot, config }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="end" justify="space-between" style="width: 200px" value="1">Label</ion-radio>
<ion-radio label-placement="end" justify="space-between" value="1">Label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -101,7 +150,7 @@ configs().forEach(({ title, screenshot, config }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="fixed" justify="start" style="width: 200px" value="1">This is a long label</ion-radio>
<ion-radio label-placement="fixed" justify="start" value="1">This is a long label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -114,7 +163,7 @@ configs().forEach(({ title, screenshot, config }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="fixed" justify="end" style="width: 200px" value="1">This is a long label</ion-radio>
<ion-radio label-placement="fixed" justify="end" value="1">This is a long label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -127,7 +176,7 @@ configs().forEach(({ title, screenshot, config }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="fixed" justify="space-between" style="width: 200px" value="1">This is a long label</ion-radio>
<ion-radio label-placement="fixed" justify="space-between" value="1">This is a long label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -142,7 +191,7 @@ configs().forEach(({ title, screenshot, config }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="stacked" alignment="start" style="width: 200px" value="1">This is a long label</ion-radio>
<ion-radio label-placement="stacked" alignment="start" value="1">This is a long label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -156,7 +205,7 @@ configs().forEach(({ title, screenshot, config }) => {
await page.setContent(
`
<ion-radio-group value="1">
<ion-radio label-placement="stacked" alignment="center" style="width: 200px" value="1">This is a long label</ion-radio>
<ion-radio label-placement="stacked" alignment="center" value="1">This is a long label</ion-radio>
</ion-radio-group>
`,
config
Expand All @@ -174,7 +223,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config, screen
test('long label should truncate', async ({ page }) => {
await page.setContent(
`
<ion-radio label-placement="stacked" alignment="start" style="width: 200px">Enable Notifications Enable Notifications Enable Notifications Enable Notifications Enable Notifications Enable Notifications Enable Notifications</ion-radio>
<ion-radio label-placement="stacked" alignment="start">Enable Notifications Enable Notifications Enable Notifications Enable Notifications Enable Notifications Enable Notifications Enable Notifications</ion-radio>
`,
config
);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 18b02b3

Please sign in to comment.