Skip to content

Commit c37eaab

Browse files
OS-martacarlosbrandyscarneygnbmthetaPC
authored
feat(divider): add new ion-divider component (#30270)
Issue number: internal --------- ## What is the new behavior? - Introduces a new component, `ion-divider` which has two props, `spacing` and `inset`. - Adds e2e tests to both `spacing` and `inset` props ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information - As discussed with the PO, using this new component inside an `ion-item` is out of scope , for now. --------- Co-authored-by: Brandy Smith <[email protected]> Co-authored-by: Gonçalo M. <[email protected]> Co-authored-by: Maria Hutt <[email protected]>
1 parent 02c9d64 commit c37eaab

File tree

77 files changed

+483
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+483
-0
lines changed

core/api.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,22 @@ ion-datetime-button,prop,mode,"ios" | "md",undefined,false,false
731731
ion-datetime-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
732732
ion-datetime-button,part,native
733733

734+
ion-divider,shadow
735+
ion-divider,prop,inset,boolean,false,false,false
736+
ion-divider,prop,spacing,"large" | "medium" | "small" | "xlarge" | "xsmall" | "xxlarge" | "xxsmall" | undefined,'xxsmall',false,true
737+
ion-divider,css-prop,--margin-bottom,ionic
738+
ion-divider,css-prop,--margin-bottom,ios
739+
ion-divider,css-prop,--margin-bottom,md
740+
ion-divider,css-prop,--margin-top,ionic
741+
ion-divider,css-prop,--margin-top,ios
742+
ion-divider,css-prop,--margin-top,md
743+
ion-divider,css-prop,--padding-end,ionic
744+
ion-divider,css-prop,--padding-end,ios
745+
ion-divider,css-prop,--padding-end,md
746+
ion-divider,css-prop,--padding-start,ionic
747+
ion-divider,css-prop,--padding-start,ios
748+
ion-divider,css-prop,--padding-start,md
749+
734750
ion-fab,shadow
735751
ion-fab,prop,activated,boolean,false,false,false
736752
ion-fab,prop,edge,boolean,false,false,false

core/src/components.d.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,16 @@ export namespace Components {
11641164
*/
11651165
"theme"?: "ios" | "md" | "ionic";
11661166
}
1167+
interface IonDivider {
1168+
/**
1169+
* If `true`, the divider will have horizontal margins By default, it's `false`
1170+
*/
1171+
"inset": boolean;
1172+
/**
1173+
* Set to `"xxsmall"` for the smallest spacing. Set to "xsmall" for very small spacing. Set to `"small"` for small spacing. Set to "medium" for medium spacing. Set to "large" for large spacing. Set to `"xlarge"` for the largest spacing. Defaults to `"xxsmall"`.
1174+
*/
1175+
"spacing"?: 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge';
1176+
}
11671177
interface IonFab {
11681178
/**
11691179
* If `true`, both the `ion-fab-button` and all `ion-fab-list` inside `ion-fab` will become active. That means `ion-fab-button` will become a `close` icon and `ion-fab-list` will become visible.
@@ -4440,6 +4450,12 @@ declare global {
44404450
prototype: HTMLIonDatetimeButtonElement;
44414451
new (): HTMLIonDatetimeButtonElement;
44424452
};
4453+
interface HTMLIonDividerElement extends Components.IonDivider, HTMLStencilElement {
4454+
}
4455+
var HTMLIonDividerElement: {
4456+
prototype: HTMLIonDividerElement;
4457+
new (): HTMLIonDividerElement;
4458+
};
44434459
interface HTMLIonFabElement extends Components.IonFab, HTMLStencilElement {
44444460
}
44454461
var HTMLIonFabElement: {
@@ -5399,6 +5415,7 @@ declare global {
53995415
"ion-content": HTMLIonContentElement;
54005416
"ion-datetime": HTMLIonDatetimeElement;
54015417
"ion-datetime-button": HTMLIonDatetimeButtonElement;
5418+
"ion-divider": HTMLIonDividerElement;
54025419
"ion-fab": HTMLIonFabElement;
54035420
"ion-fab-button": HTMLIonFabButtonElement;
54045421
"ion-fab-list": HTMLIonFabListElement;
@@ -6619,6 +6636,16 @@ declare namespace LocalJSX {
66196636
*/
66206637
"theme"?: "ios" | "md" | "ionic";
66216638
}
6639+
interface IonDivider {
6640+
/**
6641+
* If `true`, the divider will have horizontal margins By default, it's `false`
6642+
*/
6643+
"inset"?: boolean;
6644+
/**
6645+
* Set to `"xxsmall"` for the smallest spacing. Set to "xsmall" for very small spacing. Set to `"small"` for small spacing. Set to "medium" for medium spacing. Set to "large" for large spacing. Set to `"xlarge"` for the largest spacing. Defaults to `"xxsmall"`.
6646+
*/
6647+
"spacing"?: 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge';
6648+
}
66226649
interface IonFab {
66236650
/**
66246651
* If `true`, both the `ion-fab-button` and all `ion-fab-list` inside `ion-fab` will become active. That means `ion-fab-button` will become a `close` icon and `ion-fab-list` will become visible.
@@ -9532,6 +9559,7 @@ declare namespace LocalJSX {
95329559
"ion-content": IonContent;
95339560
"ion-datetime": IonDatetime;
95349561
"ion-datetime-button": IonDatetimeButton;
9562+
"ion-divider": IonDivider;
95359563
"ion-fab": IonFab;
95369564
"ion-fab-button": IonFabButton;
95379565
"ion-fab-list": IonFabList;
@@ -9634,6 +9662,7 @@ declare module "@stencil/core" {
96349662
"ion-content": LocalJSX.IonContent & JSXBase.HTMLAttributes<HTMLIonContentElement>;
96359663
"ion-datetime": LocalJSX.IonDatetime & JSXBase.HTMLAttributes<HTMLIonDatetimeElement>;
96369664
"ion-datetime-button": LocalJSX.IonDatetimeButton & JSXBase.HTMLAttributes<HTMLIonDatetimeButtonElement>;
9665+
"ion-divider": LocalJSX.IonDivider & JSXBase.HTMLAttributes<HTMLIonDividerElement>;
96379666
"ion-fab": LocalJSX.IonFab & JSXBase.HTMLAttributes<HTMLIonFabElement>;
96389667
"ion-fab-button": LocalJSX.IonFabButton & JSXBase.HTMLAttributes<HTMLIonFabButtonElement>;
96399668
"ion-fab-list": LocalJSX.IonFabList & JSXBase.HTMLAttributes<HTMLIonFabListElement>;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
@import "../../themes/mixins";
2+
3+
:host {
4+
/**
5+
* @prop --margin-top: Top margin of the divider
6+
* @prop --margin-bottom: Bottom margin of the divider
7+
* @prop --padding-end: Right padding if direction is left-to-right, and left padding if direction is right-to-left of the divider
8+
* @prop --padding-start: Left padding if direction is left-to-right, and right padding if direction is right-to-left of the divider
9+
*/
10+
--margin-top: 0px;
11+
--margin-bottom: 0px;
12+
--padding-start: 0px;
13+
--padding-end: 0px;
14+
15+
display: block;
16+
17+
width: 100%;
18+
19+
/* stylelint-disable */
20+
@include ltr() {
21+
padding-right: calc(var(--padding-end) + var(--ion-safe-area-right, 0px));
22+
padding-left: calc(var(--padding-start) + var(--ion-safe-area-left, 0px));
23+
}
24+
25+
@include rtl() {
26+
padding-right: calc(var(--padding-start) + var(--ion-safe-area-right, 0px));
27+
padding-left: calc(var(--padding-end) + var(--ion-safe-area-left, 0px));
28+
}
29+
/* stylelint-enable */
30+
}
31+
32+
:host hr {
33+
display: block;
34+
35+
width: 100%;
36+
37+
margin-top: var(--margin-top);
38+
margin-bottom: var(--margin-bottom);
39+
40+
border: none;
41+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
@use "../../themes/ionic/ionic.globals.scss" as globals;
2+
@use "./divider.common.scss";
3+
4+
:host hr {
5+
border-top: globals.$ion-border-size-025 globals.$ion-border-style-solid globals.$ion-border-default;
6+
}
7+
8+
// Divider Inset
9+
// --------------------------------------------------
10+
11+
:host(.divider-inset) {
12+
--padding-start: #{globals.$ion-space-400};
13+
--padding-end: #{globals.$ion-space-400};
14+
}
15+
16+
// Divider Spacing
17+
// --------------------------------------------------
18+
19+
:host(.divider-spacing-xsmall) {
20+
--margin-top: #{globals.$ion-space-200};
21+
--margin-bottom: #{globals.$ion-space-200};
22+
}
23+
24+
:host(.divider-spacing-small) {
25+
--margin-top: #{globals.$ion-space-300};
26+
--margin-bottom: #{globals.$ion-space-300};
27+
}
28+
29+
:host(.divider-spacing-medium) {
30+
--margin-top: #{globals.$ion-space-400};
31+
--margin-bottom: #{globals.$ion-space-400};
32+
}
33+
34+
:host(.divider-spacing-large) {
35+
--margin-top: #{globals.$ion-space-600};
36+
--margin-bottom: #{globals.$ion-space-600};
37+
}
38+
39+
:host(.divider-spacing-xlarge) {
40+
--margin-top: #{globals.$ion-space-800};
41+
--margin-bottom: #{globals.$ion-space-800};
42+
}
43+
44+
:host(.divider-spacing-xxlarge) {
45+
--margin-top: #{globals.$ion-space-1000};
46+
--margin-bottom: #{globals.$ion-space-1000};
47+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@import "./divider.native.scss";
2+
3+
// iOS Divider
4+
// --------------------------------------------------
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@import "./divider.native.scss";
2+
3+
// Material Design Divider
4+
// --------------------------------------------------
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
@import "./divider.common.scss";
2+
3+
:host hr {
4+
border-top: 1px solid #e0e0e0;
5+
}
6+
7+
// Divider Inset
8+
// --------------------------------------------------
9+
10+
:host(.divider-inset) {
11+
--padding-start: 16px;
12+
--padding-end: 16px;
13+
}
14+
15+
// Divider Spacing
16+
// --------------------------------------------------
17+
18+
:host(.divider-spacing-xsmall) {
19+
--margin-top: 8px;
20+
--margin-bottom: 8px;
21+
}
22+
23+
:host(.divider-spacing-small) {
24+
--margin-top: 12px;
25+
--margin-bottom: 12px;
26+
}
27+
28+
:host(.divider-spacing-medium) {
29+
--margin-top: 16px;
30+
--margin-bottom: 16px;
31+
}
32+
33+
:host(.divider-spacing-large) {
34+
--margin-top: 24px;
35+
--margin-bottom: 24px;
36+
}
37+
38+
:host(.divider-spacing-xlarge) {
39+
--margin-top: 32px;
40+
--margin-bottom: 32px;
41+
}
42+
43+
:host(.divider-spacing-xxlarge) {
44+
--margin-top: 40px;
45+
--margin-bottom: 40px;
46+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { getIonTheme } from '@global/ionic-global';
2+
import type { ComponentInterface } from '@stencil/core';
3+
import { Component, Prop, Host, h } from '@stencil/core';
4+
5+
@Component({
6+
tag: 'ion-divider',
7+
styleUrls: {
8+
ios: 'divider.ios.scss',
9+
md: 'divider.md.scss',
10+
ionic: 'divider.ionic.scss',
11+
},
12+
shadow: true,
13+
})
14+
export class Divider implements ComponentInterface {
15+
/**
16+
* Set to `"xxsmall"` for the smallest spacing.
17+
* Set to "xsmall" for very small spacing.
18+
* Set to `"small"` for small spacing.
19+
* Set to "medium" for medium spacing.
20+
* Set to "large" for large spacing.
21+
* Set to `"xlarge"` for the largest spacing.
22+
*
23+
* Defaults to `"xxsmall"`.
24+
*/
25+
@Prop({ reflect: true }) spacing?: 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' =
26+
'xxsmall';
27+
28+
/**
29+
* If `true`, the divider will have horizontal margins
30+
* By default, it's `false`
31+
*/
32+
@Prop() inset: boolean = false;
33+
34+
render() {
35+
const { inset, spacing } = this;
36+
const theme = getIonTheme(this);
37+
38+
return (
39+
<Host
40+
class={{
41+
[theme]: true,
42+
[`divider-spacing-${spacing}`]: spacing !== undefined,
43+
[`divider-inset`]: inset,
44+
}}
45+
>
46+
<hr />
47+
</Host>
48+
);
49+
}
50+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { expect } from '@playwright/test';
2+
import { configs, test } from '@utils/test/playwright';
3+
4+
configs({ directions: ['ltr'], modes: ['md', 'ionic-md'] }).forEach(({ config, screenshot, title }) => {
5+
test.describe(title('divider: rendering'), () => {
6+
test('should not have visual regressions', async ({ page }) => {
7+
await page.setContent(
8+
`
9+
<div id="container">
10+
top
11+
<ion-divider></ion-divider>
12+
bottom
13+
</div>
14+
`,
15+
config
16+
);
17+
18+
const container = page.locator('#container');
19+
20+
await expect(container).toHaveScreenshot(screenshot(`divider-basic-default`));
21+
});
22+
});
23+
});
24+
25+
configs({ modes: ['md', 'ionic-md'] }).forEach(({ config, screenshot, title }) => {
26+
test.describe(title('divider: inset'), () => {
27+
test('should not have visual regressions when inset is enabled', async ({ page }) => {
28+
await page.setContent(
29+
`
30+
<div id="container">
31+
top
32+
<ion-divider inset="true"></ion-divider>
33+
bottom
34+
</div>
35+
`,
36+
config
37+
);
38+
39+
const container = page.locator('#container');
40+
41+
await expect(container).toHaveScreenshot(screenshot(`divider-basic-inset`));
42+
});
43+
});
44+
});
1.35 KB
Loading

0 commit comments

Comments
 (0)