mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 17:42:15 +08:00
feat(split-pane): convert to shadow component, add width, max-width, and min-width vars (#19754)
resolves #17088 Co-authored-by: troyanskiy <roman.rosluk@utopix.ch>
This commit is contained in:
@ -1098,12 +1098,15 @@ ion-spinner,prop,name,"bubbles" | "circles" | "circular" | "crescent" | "dots" |
|
|||||||
ion-spinner,prop,paused,boolean,false,false,false
|
ion-spinner,prop,paused,boolean,false,false,false
|
||||||
ion-spinner,css-prop,--color
|
ion-spinner,css-prop,--color
|
||||||
|
|
||||||
ion-split-pane,none
|
ion-split-pane,shadow
|
||||||
ion-split-pane,prop,contentId,string | undefined,undefined,false,false
|
ion-split-pane,prop,contentId,string | undefined,undefined,false,false
|
||||||
ion-split-pane,prop,disabled,boolean,false,false,false
|
ion-split-pane,prop,disabled,boolean,false,false,false
|
||||||
ion-split-pane,prop,when,boolean | string,QUERY['lg'],false,false
|
ion-split-pane,prop,when,boolean | string,QUERY['lg'],false,false
|
||||||
ion-split-pane,event,ionSplitPaneVisible,{ visible: boolean; },true
|
ion-split-pane,event,ionSplitPaneVisible,{ visible: boolean; },true
|
||||||
ion-split-pane,css-prop,--border
|
ion-split-pane,css-prop,--border
|
||||||
|
ion-split-pane,css-prop,--side-max-width
|
||||||
|
ion-split-pane,css-prop,--side-min-width
|
||||||
|
ion-split-pane,css-prop,--side-width
|
||||||
|
|
||||||
ion-tab,shadow
|
ion-tab,shadow
|
||||||
ion-tab,prop,component,Function | HTMLElement | null | string | undefined,undefined,false,false
|
ion-tab,prop,component,Function | HTMLElement | null | string | undefined,undefined,false,false
|
||||||
|
@ -126,6 +126,12 @@ ion-backdrop {
|
|||||||
// Menu Split Pane
|
// Menu Split Pane
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
:host(.menu-pane-visible) {
|
||||||
|
width: var(--width);
|
||||||
|
min-width: var(--min-width);
|
||||||
|
max-width: var(--max-width);
|
||||||
|
}
|
||||||
|
|
||||||
:host(.menu-pane-visible) .menu-inner {
|
:host(.menu-pane-visible) .menu-inner {
|
||||||
@include position-horizontal(0, 0);
|
@include position-horizontal(0, 0);
|
||||||
|
|
||||||
|
@ -150,8 +150,11 @@ export const SplitPlaneExample: React.SFC<{}> = () => (
|
|||||||
## CSS Custom Properties
|
## CSS Custom Properties
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| ---------- | -------------------- |
|
| ------------------ | ---------------------------------------------------------------------------- |
|
||||||
| `--border` | Border between panes |
|
| `--border` | Border between panes |
|
||||||
|
| `--side-max-width` | Maximum width of the side pane. Does not apply when split pane is collapsed. |
|
||||||
|
| `--side-min-width` | Minimum width of the side pane. Does not apply when split pane is collapsed. |
|
||||||
|
| `--side-width` | Width of the side pane. Does not apply when split pane is collapsed. |
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
@ -4,21 +4,23 @@
|
|||||||
// Split Pane
|
// Split Pane
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
.split-pane-ios {
|
:host {
|
||||||
--border: #{$split-pane-ios-border};
|
--border: #{$split-pane-ios-border};
|
||||||
|
--side-min-width: #{$split-pane-ios-side-min-width};
|
||||||
|
--side-max-width: #{$split-pane-ios-side-max-width};
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-pane-ios.split-pane-visible > .split-pane-side {
|
:host(.split-pane-visible) ::slotted(.split-pane-side) {
|
||||||
min-width: $split-pane-ios-side-min-width;
|
min-width: var(--side-min-width);
|
||||||
max-width: $split-pane-ios-side-max-width;
|
max-width: var(--side-max-width);
|
||||||
|
|
||||||
border-right: var(--border);
|
border-right: var(--border);
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-pane-ios.split-pane-visible > .split-pane-side[side=end] {
|
:host(.split-pane-visible) ::slotted(.split-pane-side[side=end]) {
|
||||||
min-width: $split-pane-ios-side-min-width;
|
min-width: var(--side-min-width);
|
||||||
max-width: $split-pane-ios-side-max-width;
|
max-width: var(--side-max-width);
|
||||||
|
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
border-left: var(--border);
|
border-left: var(--border);
|
||||||
|
@ -4,21 +4,23 @@
|
|||||||
// Split Pane
|
// Split Pane
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
.split-pane-md {
|
:host {
|
||||||
--border: #{$split-pane-md-border};
|
--border: #{$split-pane-md-border};
|
||||||
|
--side-min-width: #{$split-pane-md-side-min-width};
|
||||||
|
--side-max-width: #{$split-pane-md-side-max-width};
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-pane-md.split-pane-visible > .split-pane-side {
|
:host(.split-pane-visible) ::slotted(.split-pane-side) {
|
||||||
min-width: $split-pane-md-side-min-width;
|
min-width: var(--side-min-width);
|
||||||
max-width: $split-pane-md-side-max-width;
|
max-width: var(--side-max-width);
|
||||||
|
|
||||||
border-right: var(--border);
|
border-right: var(--border);
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-pane-md.split-pane-visible > .split-pane-side[side=end] {
|
:host(.split-pane-visible) ::slotted(.split-pane-side[side=end]) {
|
||||||
min-width: $split-pane-md-side-min-width;
|
min-width: var(--side-min-width);
|
||||||
max-width: $split-pane-md-side-max-width;
|
max-width: var(--side-max-width);
|
||||||
|
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
border-left: var(--border);
|
border-left: var(--border);
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
@import "./split-pane.vars";
|
@import "./split-pane.vars";
|
||||||
|
@import "../menu/menu.vars";
|
||||||
|
|
||||||
// Split Pane
|
// Split Pane
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
ion-split-pane {
|
:host {
|
||||||
/**
|
/**
|
||||||
* @prop --border: Border between panes
|
* @prop --border: Border between panes
|
||||||
|
* @prop --side-min-width: Minimum width of the side pane. Does not apply when split pane is collapsed.
|
||||||
|
* @prop --side-max-width: Maximum width of the side pane. Does not apply when split pane is collapsed.
|
||||||
|
* @prop --side-width: Width of the side pane. Does not apply when split pane is collapsed.
|
||||||
*/
|
*/
|
||||||
|
--side-width: 100%;
|
||||||
|
|
||||||
@include position(0, 0, 0, 0);
|
@include position(0, 0, 0, 0);
|
||||||
|
|
||||||
@ -19,34 +24,50 @@ ion-split-pane {
|
|||||||
contain: strict;
|
contain: strict;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-pane-visible > .split-pane-side,
|
/**
|
||||||
.split-pane-visible > .split-pane-main {
|
* Do not pass CSS Variables down on larger
|
||||||
|
* screens as we want them to affect the outer
|
||||||
|
* `ion-menu` rather than the inner content
|
||||||
|
*/
|
||||||
|
::slotted(ion-menu.menu-pane-visible) {
|
||||||
|
|
||||||
|
flex: 0 1 auto;
|
||||||
|
|
||||||
|
width: var(--side-width);
|
||||||
|
min-width: var(--side-min-width);
|
||||||
|
max-width: var(--side-max-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.split-pane-visible) ::slotted(.split-pane-side),
|
||||||
|
:host(.split-pane-visible) ::slotted(.split-pane-main) {
|
||||||
@include position(0, 0, 0, 0);
|
@include position(0, 0, 0, 0);
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
/* stylelint-disable-next-line declaration-no-important */
|
/* stylelint-disable-next-line declaration-no-important */
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-pane-visible > .split-pane-side:not(ion-menu),
|
:host(.split-pane-visible) ::slotted(.split-pane-main) {
|
||||||
.split-pane-visible > ion-menu.split-pane-side.menu-enabled {
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.split-pane-visible) ::slotted(.split-pane-side:not(ion-menu)),
|
||||||
|
:host(.split-pane-visible) ::slotted(ion-menu.split-pane-side.menu-enabled) {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-pane-side:not(ion-menu) {
|
::slotted(.split-pane-side:not(ion-menu)) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-pane-visible > .split-pane-side {
|
:host(.split-pane-visible) ::slotted(.split-pane-side) {
|
||||||
order: -1;
|
order: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-pane-visible > .split-pane-side[side=end] {
|
:host(.split-pane-visible) ::slotted(.split-pane-side[side=end]) {
|
||||||
order: 1;
|
order: 1;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@ const QUERY: { [key: string]: string } = {
|
|||||||
styleUrls: {
|
styleUrls: {
|
||||||
ios: 'split-pane.ios.scss',
|
ios: 'split-pane.ios.scss',
|
||||||
md: 'split-pane.md.scss'
|
md: 'split-pane.md.scss'
|
||||||
}
|
},
|
||||||
|
shadow: true
|
||||||
})
|
})
|
||||||
export class SplitPane implements ComponentInterface {
|
export class SplitPane implements ComponentInterface {
|
||||||
|
|
||||||
@ -159,6 +160,7 @@ export class SplitPane implements ComponentInterface {
|
|||||||
'split-pane-visible': this.visible
|
'split-pane-visible': this.visible
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<slot></slot>
|
||||||
</Host>
|
</Host>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,28 @@ test('split-pane: basic', async () => {
|
|||||||
url: '/src/components/split-pane/test/basic?ionic:_testing=true'
|
url: '/src/components/split-pane/test/basic?ionic:_testing=true'
|
||||||
});
|
});
|
||||||
|
|
||||||
const compare = await page.compareScreenshot();
|
const screenshotCompares = [];
|
||||||
expect(compare).toMatchScreenshot();
|
const MIN_WIDTH = '#side-min-width';
|
||||||
|
const MAX_WIDTH = '#side-max-width';
|
||||||
|
const WIDTH = '#side-width';
|
||||||
|
|
||||||
|
screenshotCompares.push(await page.compareScreenshot());
|
||||||
|
|
||||||
|
await page.click(MIN_WIDTH);
|
||||||
|
|
||||||
|
screenshotCompares.push(await page.compareScreenshot());
|
||||||
|
|
||||||
|
await page.click(MIN_WIDTH);
|
||||||
|
await page.click(MAX_WIDTH);
|
||||||
|
|
||||||
|
screenshotCompares.push(await page.compareScreenshot());
|
||||||
|
|
||||||
|
await page.click(MAX_WIDTH);
|
||||||
|
await page.click(WIDTH);
|
||||||
|
|
||||||
|
screenshotCompares.push(await page.compareScreenshot());
|
||||||
|
|
||||||
|
for (const screenshotCompare of screenshotCompares) {
|
||||||
|
expect(screenshotCompare).toMatchScreenshot();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -69,8 +69,22 @@
|
|||||||
<f></f>
|
<f></f>
|
||||||
<f></f>
|
<f></f>
|
||||||
<f></f>
|
<f></f>
|
||||||
</ion-content>
|
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Toggle Side Min Width</ion-label>
|
||||||
|
<ion-toggle id="side-min-width"></ion-toggle>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Toggle Side Max Width</ion-label>
|
||||||
|
<ion-toggle id="side-max-width"></ion-toggle>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Toggle Side Fixed Width</ion-label>
|
||||||
|
<ion-toggle id="side-width"></ion-toggle>
|
||||||
|
</ion-item>
|
||||||
|
</ion-content>
|
||||||
</div>
|
</div>
|
||||||
</ion-split-pane>
|
</ion-split-pane>
|
||||||
|
|
||||||
@ -78,6 +92,16 @@
|
|||||||
<ion-menu-controller></ion-menu-controller>
|
<ion-menu-controller></ion-menu-controller>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
const sideMinWidth = document.querySelector('ion-toggle#side-min-width');
|
||||||
|
const sideMaxWidth = document.querySelector('ion-toggle#side-max-width');
|
||||||
|
const sideWidth = document.querySelector('ion-toggle#side-width');
|
||||||
|
|
||||||
|
const splitPane = document.querySelector('ion-split-pane');
|
||||||
|
|
||||||
|
sideMinWidth.addEventListener('ionChange', () => splitPane.classList.toggle('side-min-width'));
|
||||||
|
sideMaxWidth.addEventListener('ionChange', () => splitPane.classList.toggle('side-max-width'));
|
||||||
|
sideWidth.addEventListener('ionChange', () => splitPane.classList.toggle('side-width'));
|
||||||
|
|
||||||
const menuCtrl = document.querySelector('ion-menu-controller');
|
const menuCtrl = document.querySelector('ion-menu-controller');
|
||||||
function openStart() {
|
function openStart() {
|
||||||
menuCtrl.open('start');
|
menuCtrl.open('start');
|
||||||
@ -89,6 +113,20 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.side-width {
|
||||||
|
--side-width: 150px;
|
||||||
|
--side-min-width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-min-width {
|
||||||
|
--side-min-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-max-width {
|
||||||
|
--side-max-width: 75px;
|
||||||
|
--side-min-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
f {
|
f {
|
||||||
display: block;
|
display: block;
|
||||||
height: 150px;
|
height: 150px;
|
||||||
|
@ -76,6 +76,10 @@ body.backdrop-no-scroll {
|
|||||||
z-index: $z-index-page-container;
|
z-index: $z-index-page-container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.split-pane-visible > .ion-page.split-pane-main {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
ion-route,
|
ion-route,
|
||||||
ion-route-redirect,
|
ion-route-redirect,
|
||||||
ion-router,
|
ion-router,
|
||||||
|
Reference in New Issue
Block a user