Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions BREAKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- [Row](#version-10x-row)
- [Skeleton Text](#version-10x-skeleton-text)
- [Spinner](#version-10x-spinner)
- [Split Pane](#version-10x-split-pane)
- [Text](#version-10x-text)
- [Textarea](#version-10x-textarea)
- [Thumbnail](#version-10x-thumbnail)
Expand Down Expand Up @@ -496,6 +497,10 @@ Remove any instances that target the theme classes: `ion-skeleton-text.md`, `ion
- `.spinner-[spinner-name]` → `.spinner-name-[spinner-name]`
- Specific theme classes (e.g., `ion-spinner.md`) are no longer supported. Style modifications based on the active theme must be implemented using theme tokens rather than direct class targeting.

<h4 id="version-10x-split-pane">Split Pane</h4>

- The default value of the `when` property changed from `'(min-width: 992px)'` to the equivalent `'lg'` shortcut. The default behavior is unchanged, but the shortcut now resolves through the global `screenBreakpoints` config, so overriding `lg` also changes when the split pane becomes visible. Code that compares `when` against the literal `'(min-width: 992px)'` should be updated.

<h4 id="version-10x-text">Text</h4>

The following breaking changes apply to `ion-text`:
Expand Down
2 changes: 1 addition & 1 deletion core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2605,7 +2605,7 @@ ion-split-pane,prop,contentId,string | undefined,undefined,false,true
ion-split-pane,prop,disabled,boolean,false,false,false
ion-split-pane,prop,mode,"ios" | "md",undefined,false,false
ion-split-pane,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-split-pane,prop,when,boolean | string,'(min-width: 992px)',false,false
ion-split-pane,prop,when,boolean | string,'lg',false,false
ion-split-pane,event,ionSplitPaneVisible,{ visible: boolean; },true
ion-split-pane,css-prop,--border,ionic
ion-split-pane,css-prop,--border,ios
Expand Down
8 changes: 4 additions & 4 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3878,8 +3878,8 @@ export namespace Components {
*/
"theme"?: "ios" | "md" | "ionic";
/**
* When the split-pane should be shown. Can be a CSS media query expression, or a shortcut expression. Can also be a boolean expression.
* @default '(min-width: 992px)'
* When the split-pane should be shown. Can be a CSS media query expression, or a shortcut expression. Can also be a boolean expression. The shortcut expressions are the names of the global screen breakpoints (`"xs"`, `"sm"`, `"md"`, `"lg"`, `"xl"` and `"xxl"`), which expand to the `min-width` media query for that breakpoint, plus `"never"`, which keeps the split pane hidden at every size. The width each breakpoint activates at can be changed with the `screenBreakpoints` config.
* @default 'lg'
*/
"when": string | boolean;
}
Expand Down Expand Up @@ -9848,8 +9848,8 @@ declare namespace LocalJSX {
*/
"theme"?: "ios" | "md" | "ionic";
/**
* When the split-pane should be shown. Can be a CSS media query expression, or a shortcut expression. Can also be a boolean expression.
* @default '(min-width: 992px)'
* When the split-pane should be shown. Can be a CSS media query expression, or a shortcut expression. Can also be a boolean expression. The shortcut expressions are the names of the global screen breakpoints (`"xs"`, `"sm"`, `"md"`, `"lg"`, `"xl"` and `"xxl"`), which expand to the `min-width` media query for that breakpoint, plus `"never"`, which keeps the split pane hidden at every size. The width each breakpoint activates at can be changed with the `screenBreakpoints` config.
* @default 'lg'
*/
"when"?: string | boolean;
}
Expand Down
42 changes: 32 additions & 10 deletions core/src/components/split-pane/split-pane.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Build, Component, Element, Event, Host, Method, Prop, State, Watch, h } from '@stencil/core';
import { getScreenBreakpointMediaQuery } from '@utils/breakpoints';
import { printIonWarning } from '@utils/logging';

import { getIonTheme } from '../../global/ionic-global';
Expand All @@ -8,14 +9,29 @@ import { getIonTheme } from '../../global/ionic-global';

const SPLIT_PANE_MAIN = 'split-pane-main';
const SPLIT_PANE_SIDE = 'split-pane-side';
// TODO(FW-7285): Replace with global breakpoints
const QUERY: { [key: string]: string } = {
xs: '(min-width: 0px)',
sm: '(min-width: 576px)',
md: '(min-width: 768px)',
lg: '(min-width: 992px)',
xl: '(min-width: 1200px)',
never: '',

/**
* The shortcut expression that keeps the split pane hidden at every size.
*/
const NEVER = 'never';

/**
* Resolve the `when` property to the media query to listen on. A shortcut
* expression is expanded to the `min-width` query of the matching global
* screen breakpoint, so it reflects any `screenBreakpoints` config the
* application has set. Anything else is treated as a media query and used
* as-is.
*
* @param when The `when` property value.
* @return The media query to listen on, or an empty string when the split
* pane should never be shown.
*/
const getMediaQuery = (when: string): string => {
if (when === NEVER) {
return '';
}

return getScreenBreakpointMediaQuery(when) ?? when;
};

/**
Expand Down Expand Up @@ -55,8 +71,14 @@ export class SplitPane implements ComponentInterface {
* When the split-pane should be shown.
* Can be a CSS media query expression, or a shortcut expression.
* Can also be a boolean expression.
*
* The shortcut expressions are the names of the global screen breakpoints
* (`"xs"`, `"sm"`, `"md"`, `"lg"`, `"xl"` and `"xxl"`), which expand to the
* `min-width` media query for that breakpoint, plus `"never"`, which keeps
* the split pane hidden at every size. The width each breakpoint activates
* at can be changed with the `screenBreakpoints` config.
*/
@Prop() when: string | boolean = QUERY['lg'];
@Prop() when: string | boolean = 'lg';

/**
* Expression to be called when the split-pane visibility has changed
Expand Down Expand Up @@ -118,7 +140,7 @@ export class SplitPane implements ComponentInterface {
}

// When query is a string, let's find first if it is a shortcut
const mediaQuery = QUERY[query] || query;
const mediaQuery = getMediaQuery(query);

// Media query is empty or null, we hide it
if (mediaQuery.length === 0) {
Expand Down
127 changes: 127 additions & 0 deletions core/src/components/split-pane/test/when/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Split Pane - When</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>
/**
* Override the global screen breakpoints. `md` is moved well below its
* default of 768 so a viewport that would only match `xs` or `sm` by
* default matches `md` here.
*
* This must run before `scripts.js` and the Ionic bundle so the values
* are picked up by `initialize()`.
*/
const SCREEN_BREAKPOINTS = {
xs: 0,
sm: 200,
md: 400,
lg: 600,
xl: 800,
xxl: 1000,
};

window.Ionic = {
config: {
screenBreakpoints: SCREEN_BREAKPOINTS,
},
};
</script>
<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>
<style>
/* Stays on screen while the window is resized */
#breakpoint-readout {
position: fixed;
z-index: 100;

/* A heads-up display: it overlays the demo but never blocks it */
pointer-events: none;

inset-block-end: 16px;
inset-inline-end: 16px;

display: flex;
flex-direction: column;
align-items: center;

min-width: 92px;
padding: 10px 14px;

border-radius: 10px;

background-color: #1b1b1b;
box-shadow: 0 2px 10px rgb(0 0 0 / 35%);

color: #fff;
font-family: monospace;
line-height: 1.1;
}

#active-breakpoint {
font-size: 2rem;
font-weight: bold;
letter-spacing: 0.05em;
}

#breakpoint-readout small {
opacity: 0.7;
font-size: 0.8rem;
}
</style>
</head>

<body>
<ion-app>
<ion-split-pane id="split-pane" when="md" content-id="main">
<ion-menu side="start" content-id="main">
<ion-content class="ion-padding">Menu</ion-content>
</ion-menu>

<div class="ion-page" id="main">
<ion-content class="ion-padding">
Main content. The split pane is shown at <code>md</code> and above, which this page configures as 400px.
</ion-content>
</div>
</ion-split-pane>

<div id="breakpoint-readout" aria-live="polite">
<span id="active-breakpoint">…</span>
<small><span id="viewport-width">–</span>px</small>
</div>
</ion-app>

<script>
/**
* Resolve the active breakpoint from the same map the config was set
* from, so the readout cannot drift from what the components resolve.
* The largest matching breakpoint wins, which is how a `min-width`
* query resolves.
*/
const label = document.getElementById('active-breakpoint');
const width = document.getElementById('viewport-width');

const getActiveBreakpoint = () => {
return Object.keys(SCREEN_BREAKPOINTS)
.filter((breakpoint) => window.matchMedia(`(min-width: ${SCREEN_BREAKPOINTS[breakpoint]}px)`).matches)
.pop();
};

const showActiveBreakpoint = () => {
label.textContent = getActiveBreakpoint() ?? 'none';
width.textContent = window.innerWidth;
};

window.addEventListener('resize', showActiveBreakpoint);

customElements.whenDefined('ion-split-pane').then(showActiveBreakpoint);
</script>
</body>
</html>
Loading
Loading