diff --git a/docs/angular/lifecycle.mdx b/docs/angular/lifecycle.mdx index a26dac31283..324c78f0a64 100644 --- a/docs/angular/lifecycle.mdx +++ b/docs/angular/lifecycle.mdx @@ -28,7 +28,11 @@ For more info on the Angular Component Life Cycle events, visit their [component :::note -Components that use `ion-nav` or `ion-router-outlet` should not use the `OnPush` change detection strategy. Doing so will prevent lifecycle hooks such as `ngOnInit` from firing. Additionally, asynchronous state changes may not render properly. +If your pages keep state in plain fields rather than signals, the component hosting `ion-router-outlet` or `ion-tabs` needs eager change detection, as does every component between it and your application root. A change detection pass starts at the application root and skips a clean `OnPush` view along with everything below it, so an `OnPush` component above the outlet stops updates from reaching the routed pages under it. The pages themselves can use `OnPush`, as long as their state is a signal or they call `markForCheck()`. + +On **Angular 18 through 21** this only affects you if you set `OnPush` on those components yourself, because a component that does not declare a strategy is eager. + +**Angular 22** makes `OnPush` the default for components that do not declare one, so refer to [Change detection on Angular 22](/docs/angular/zoneless.mdx#change-detection-on-angular-22) for what your app shell has to declare. ::: diff --git a/docs/angular/your-first-app.mdx b/docs/angular/your-first-app.mdx index a1e5363b11b..24a55a9da3d 100644 --- a/docs/angular/your-first-app.mdx +++ b/docs/angular/your-first-app.mdx @@ -38,7 +38,7 @@ Highlights include: - One Angular-based codebase that runs on the web, iOS, and Android using Ionic Framework [UI components](../components.mdx). - Deployed as a native iOS and Android mobile app using [Capacitor](https://capacitorjs.com), Ionic's official native app runtime. -- Photo Gallery functionality powered by the Capacitor [Camera](../native/camera.md), [Filesystem](../native/filesystem.md), and [Preferences](../native/preferences.md) APIs. +- Photo Gallery functionality powered by the Capacitor [Camera](../native/camera.mdx), [Filesystem](../native/filesystem.mdx), and [Preferences](../native/preferences.mdx) APIs. Find the [complete app code](https://github.com/ionic-team/tutorial-photo-gallery-angular) referenced in this guide on GitHub. @@ -104,7 +104,7 @@ npm install @capacitor/camera @capacitor/preferences @capacitor/filesystem ### PWA Elements -Some Capacitor plugins, including the [Camera API](../native/camera.md), provide the web-based functionality and UI via the Ionic [PWA Elements library](https://github.com/ionic-team/pwa-elements). +Some Capacitor plugins, including the [Camera API](../native/camera.mdx), provide the web-based functionality and UI via the Ionic [PWA Elements library](https://github.com/ionic-team/pwa-elements). It's a separate dependency, so install it next: diff --git a/docs/angular/your-first-app/2-taking-photos.mdx b/docs/angular/your-first-app/2-taking-photos.mdx index ee52853881c..d99b1f934af 100644 --- a/docs/angular/your-first-app/2-taking-photos.mdx +++ b/docs/angular/your-first-app/2-taking-photos.mdx @@ -11,7 +11,7 @@ sidebar_label: Taking Photos /> -Now for the fun part - adding the ability to take photos with the device’s camera using the Capacitor [Camera API](../../native/camera.md). We’ll begin with building it for the web, then make some small tweaks to make it work on mobile (iOS and Android). +Now for the fun part - adding the ability to take photos with the device’s camera using the Capacitor [Camera API](../../native/camera.mdx). We’ll begin with building it for the web, then make some small tweaks to make it work on mobile (iOS and Android). ## Photo Service diff --git a/docs/angular/your-first-app/3-saving-photos.mdx b/docs/angular/your-first-app/3-saving-photos.mdx index 4eb1fdfef95..d8bed67ff42 100644 --- a/docs/angular/your-first-app/3-saving-photos.mdx +++ b/docs/angular/your-first-app/3-saving-photos.mdx @@ -86,7 +86,7 @@ export interface UserPhoto { } ``` -We'll use the Capacitor [Filesystem API](../../native/filesystem.md) to save the photo. First, convert the photo to base64 format. +We'll use the Capacitor [Filesystem API](../../native/filesystem.mdx) to save the photo. First, convert the photo to base64 format. Then, pass the data to the Filesystem's `writeFile` method. Recall that we display photos by setting the image's source path (`src`) to the `webviewPath` property. So, set the `webviewPath` and return the new `Photo` object. diff --git a/docs/angular/your-first-app/4-loading-photos.mdx b/docs/angular/your-first-app/4-loading-photos.mdx index f5ea15d6ed6..8dba9303247 100644 --- a/docs/angular/your-first-app/4-loading-photos.mdx +++ b/docs/angular/your-first-app/4-loading-photos.mdx @@ -13,7 +13,7 @@ sidebar_label: Loading Photos We’ve implemented photo taking and saving to the filesystem. There’s one last piece of functionality missing: the photos are stored in the filesystem, but we need a way to save pointers to each file so that they can be displayed again in the photo gallery. -Fortunately, this is easy: we’ll leverage the Capacitor [Preferences API](../../native/preferences.md) to store our array of Photos in a key-value store. +Fortunately, this is easy: we’ll leverage the Capacitor [Preferences API](../../native/preferences.mdx) to store our array of Photos in a key-value store. ## Preferences API diff --git a/docs/angular/zoneless.mdx b/docs/angular/zoneless.mdx index bc06e66b8ba..0d961474817 100644 --- a/docs/angular/zoneless.mdx +++ b/docs/angular/zoneless.mdx @@ -28,7 +28,7 @@ You do not need to change these. Angular schedules change detection for them in :::note[Angular 22] -Angular 22 also makes `OnPush` the default change detection strategy. Under `OnPush`, synchronous state set as a plain field (including in the lifecycle hooks above) no longer re-renders on its own, even though Ionic notifies Angular. Signals still update the view. For the migration path, refer to the [OnPush Change Detection section of the Ionic 9 upgrade guide](/docs/updating/9-0.mdx#onpush-change-detection-on-angular-22). +Angular 22 also makes `OnPush` the default change detection strategy. Under `OnPush`, synchronous state set as a plain field (including in the lifecycle hooks above) no longer re-renders on its own, even though Ionic notifies Angular. Signals still update the view. Refer to [Change detection on Angular 22](#change-detection-on-angular-22) for what this means for your app shell, and to the [OnPush Change Detection section of the Ionic 9 upgrade guide](/docs/updating/9-0.mdx#onpush-change-detection-on-angular-22) for the migration steps. ::: @@ -153,6 +153,25 @@ export class AppComponent { } ``` +## Change detection on Angular 22 + +On Angular 22 a component that does not declare a strategy is `OnPush`. If your pages keep state in plain fields rather than signals, every component from your application root down to the one hosting `ion-router-outlet` or `ion-tabs` (your app shell) must stay eager. A tick starts at the application root and skips a clean `OnPush` view and everything below it, so an `OnPush` ancestor strands the page even when the page itself is eager: + +```ts +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + changeDetection: ChangeDetectionStrategy.Eager, + template: '', +}) +export class AppComponent {} +``` + +If other components sit between your application root and `ion-router-outlet`, each of them needs the same declaration. Pages that set state through signals, or that call `markForCheck()`, are unaffected: both mark the ancestor chain, so a tick reaches them whatever the shell declares. Converting your pages that way is the alternative to keeping the shell eager. + +Hosting an `ion-nav` is fine either way, because its pages are attached as root views and are checked independently of the component hosting them. + ## Staying on Zone.js If you are not ready to adopt zoneless change detection, you can opt back into Zone.js with `provideZoneChangeDetection()`. Refer to the [Keeping Zone.js section of the Ionic 9 upgrade guide](/docs/updating/9-0.mdx#keeping-zonejs) for the exact configuration. diff --git a/docs/cli/configuration.mdx b/docs/cli/configuration.mdx index 7bebbae6846..48c56086070 100644 --- a/docs/cli/configuration.mdx +++ b/docs/cli/configuration.mdx @@ -14,7 +14,7 @@ title: Configuration Configuration values are stored in JSON files. The Ionic CLI maintains a global configuration file, usually located at `~/.ionic/config.json`, and project configuration files, usually at the project's root directory as `ionic.config.json`. -The CLI provides commands for setting and printing config values from project config files and the global CLI config file. Run `ionic config --help` or refer to the documentation for usage of [`ionic config get`](commands/config-get.md) and [`ionic config set`](commands/config-set.md). +The CLI provides commands for setting and printing config values from project config files and the global CLI config file. Run `ionic config --help` or refer to the documentation for usage of [`ionic config get`](commands/config-get.mdx) and [`ionic config set`](commands/config-set.mdx). ### Project Configuration File diff --git a/docs/cli/livereload.mdx b/docs/cli/livereload.mdx index db6b96ff5fb..e8baecdb272 100644 --- a/docs/cli/livereload.mdx +++ b/docs/cli/livereload.mdx @@ -59,7 +59,7 @@ Remember, with the `--external` option, others on your Wi-Fi network will be abl ## Tips -- With Cordova, use the `--device`, `--emulator`, and `--target` options to narrow down target devices. Use the `--list` option to list all targets. See usage in the [command docs](commands/cordova-run.md). +- With Cordova, use the `--device`, `--emulator`, and `--target` options to narrow down target devices. Use the `--list` option to list all targets. See usage in the [command docs](commands/cordova-run.mdx). - You can separate the dev server process and the deploy process by using `ionic serve` and the `--livereload-url` option of `ionic cordova run` or `ionic capacitor run`. - For Android, it is possible to configure [adb](https://developer.android.com/studio/command-line/adb) to always forward ports while the adb server is running (refer to `adb reverse`). With port forwarding set up, an external address would no longer be required. You can also setup the adb bridge over TCP such that subsequent deploys no longer need a USB cable. - If you are using a development container with Angular, live reload may not work. To fix it, set `projects.app.architect.serve.configurations.development.poll` to `1` in `angular.json`. diff --git a/docs/developing/scaffolding.mdx b/docs/developing/scaffolding.mdx index 9098949889b..b1ba4685af7 100644 --- a/docs/developing/scaffolding.mdx +++ b/docs/developing/scaffolding.mdx @@ -50,7 +50,7 @@ This command is only supported in Ionic Angular. ::: -The Ionic CLI can generate new app features with the [`ionic generate`](../cli/commands/generate.md) command. By running `ionic generate` in the command line, a selection prompt is displayed which lists the available features that can be generated. +The Ionic CLI can generate new app features with the [`ionic generate`](../cli/commands/generate.mdx) command. By running `ionic generate` in the command line, a selection prompt is displayed which lists the available features that can be generated. ```shell-session $ ionic generate @@ -96,4 +96,4 @@ The Ionic CLI uses the underlying framework tooling to stay close to best practi After creating the files and directories for the new page, the CLI will also update the router configuration to include the new page. This reduces the amount of manual work needed to keep the development lifecycle moving. -For more details, run `ionic g --help` from the command line or refer to the [`ionic generate` documentation](../cli/commands/generate.md). +For more details, run `ionic g --help` from the command line or refer to the [`ionic generate` documentation](../cli/commands/generate.mdx). diff --git a/docs/native-setup.mdx b/docs/native-setup.mdx index 8e77bb84a7f..03a10ea2864 100644 --- a/docs/native-setup.mdx +++ b/docs/native-setup.mdx @@ -37,7 +37,7 @@ $ npm install @capacitor/camera Once installed, plugins can be imported into a component and you can call the native functionality directly from your code. -Using the [Camera plugin](native/camera.md) as an example, first install it: +Using the [Camera plugin](native/camera.mdx) as an example, first install it: ````mdx-code-block -Now for the fun part - adding the ability to take photos with the device’s camera using the Capacitor [Camera API](../../native/camera.md). We’ll begin with building it for the web, then make some small tweaks to make it work on mobile (iOS and Android). +Now for the fun part - adding the ability to take photos with the device’s camera using the Capacitor [Camera API](../../native/camera.mdx). We’ll begin with building it for the web, then make some small tweaks to make it work on mobile (iOS and Android). ## Photo Gallery Hook diff --git a/docs/react/your-first-app/3-saving-photos.mdx b/docs/react/your-first-app/3-saving-photos.mdx index b8fa334d414..3be5237e5fe 100644 --- a/docs/react/your-first-app/3-saving-photos.mdx +++ b/docs/react/your-first-app/3-saving-photos.mdx @@ -93,7 +93,7 @@ export interface UserPhoto { } ``` -We'll use the Capacitor [Filesystem API](../../native/filesystem.md) to save the photo. First, convert the photo to base64 format. +We'll use the Capacitor [Filesystem API](../../native/filesystem.mdx) to save the photo. First, convert the photo to base64 format. Then, pass the data to the Filesystem's `writeFile` method. Recall that we display photos by setting the image's source path (`src`) to the `webviewPath` property. So, set the `webviewPath` and return the new `Photo` object. diff --git a/docs/react/your-first-app/4-loading-photos.mdx b/docs/react/your-first-app/4-loading-photos.mdx index 1fa9e9c3ad7..75958791b42 100644 --- a/docs/react/your-first-app/4-loading-photos.mdx +++ b/docs/react/your-first-app/4-loading-photos.mdx @@ -13,7 +13,7 @@ sidebar_label: Loading Photos We’ve implemented photo taking and saving to the filesystem. There’s one last piece of functionality missing: the photos are stored in the filesystem, but we need a way to save pointers to each file so that they can be displayed again in the photo gallery. -Fortunately, this is easy: we’ll leverage the Capacitor [Preferences API](../../native/preferences.md) to store our array of Photos in a key-value store. +Fortunately, this is easy: we’ll leverage the Capacitor [Preferences API](../../native/preferences.mdx) to store our array of Photos in a key-value store. ## Preferences API diff --git a/docs/vue/your-first-app.mdx b/docs/vue/your-first-app.mdx index 7245297ac81..981c5ed8a36 100644 --- a/docs/vue/your-first-app.mdx +++ b/docs/vue/your-first-app.mdx @@ -32,7 +32,7 @@ Highlights include: - One Vue-based codebase that runs on the web, iOS, and Android using Ionic Framework [UI components](../components.mdx). - Deployed as a native iOS and Android mobile app using [Capacitor](https://capacitorjs.com), Ionic's official native app runtime. -- Photo Gallery functionality powered by the Capacitor [Camera](../native/camera.md), [Filesystem](../native/filesystem.md), and [Preferences](../native/preferences.md) APIs. +- Photo Gallery functionality powered by the Capacitor [Camera](../native/camera.mdx), [Filesystem](../native/filesystem.mdx), and [Preferences](../native/preferences.mdx) APIs. Find the [complete app code](https://github.com/ionic-team/tutorial-photo-gallery-vue) referenced in this guide on GitHub. @@ -92,7 +92,7 @@ npm install @capacitor/camera @capacitor/preferences @capacitor/filesystem ### PWA Elements -Some Capacitor plugins, including the [Camera API](../native/camera.md), provide the web-based functionality and UI via the Ionic [PWA Elements library](https://github.com/ionic-team/pwa-elements). +Some Capacitor plugins, including the [Camera API](../native/camera.mdx), provide the web-based functionality and UI via the Ionic [PWA Elements library](https://github.com/ionic-team/pwa-elements). It's a separate dependency, so install it next: diff --git a/docs/vue/your-first-app/2-taking-photos.mdx b/docs/vue/your-first-app/2-taking-photos.mdx index 80e0e8d98fd..e383d9abbcb 100644 --- a/docs/vue/your-first-app/2-taking-photos.mdx +++ b/docs/vue/your-first-app/2-taking-photos.mdx @@ -11,7 +11,7 @@ sidebar_label: Taking Photos /> -Now for the fun part - adding the ability to take photos with the device’s camera using the Capacitor [Camera API](../../native/camera.md). We’ll begin with building it for the web, then make some small tweaks to make it work on mobile (iOS and Android). +Now for the fun part - adding the ability to take photos with the device’s camera using the Capacitor [Camera API](../../native/camera.mdx). We’ll begin with building it for the web, then make some small tweaks to make it work on mobile (iOS and Android). ## Photo Gallery Composable diff --git a/docs/vue/your-first-app/3-saving-photos.mdx b/docs/vue/your-first-app/3-saving-photos.mdx index c674e7c7d1a..23ab4798711 100644 --- a/docs/vue/your-first-app/3-saving-photos.mdx +++ b/docs/vue/your-first-app/3-saving-photos.mdx @@ -92,7 +92,7 @@ export interface UserPhoto { } ``` -We'll use the Capacitor [Filesystem API](../../native/filesystem.md) to save the photo. First, convert the photo to base64 format. +We'll use the Capacitor [Filesystem API](../../native/filesystem.mdx) to save the photo. First, convert the photo to base64 format. Then, pass the data to the Filesystem's `writeFile` method. Recall that we display photos by setting the image's source path (`src`) to the `webviewPath` property. So, set the `webviewPath` and return the new `Photo` object. diff --git a/docs/vue/your-first-app/4-loading-photos.mdx b/docs/vue/your-first-app/4-loading-photos.mdx index 50841a176a6..53e340e4ae3 100644 --- a/docs/vue/your-first-app/4-loading-photos.mdx +++ b/docs/vue/your-first-app/4-loading-photos.mdx @@ -13,7 +13,7 @@ sidebar_label: Loading Photos We’ve implemented photo taking and saving to the filesystem. There’s one last piece of functionality missing: the photos are stored in the filesystem, but we need a way to save pointers to each file so that they can be displayed again in the photo gallery. -Fortunately, this is easy: we’ll leverage the Capacitor [Preferences API](../../native/preferences.md) to store our array of Photos in a key-value store. +Fortunately, this is easy: we’ll leverage the Capacitor [Preferences API](../../native/preferences.mdx) to store our array of Photos in a key-value store. ## Preferences API diff --git a/package-lock.json b/package-lock.json index 29521b62968..6fec5c99641 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "ionic-docs", "version": "0.0.0", "dependencies": { + "@crowdin/cli": "^5.0.1", "@docusaurus/core": "^3.10.2", "@docusaurus/faster": "^3.10.2", "@docusaurus/preset-classic": "^3.10.2", @@ -18,7 +19,6 @@ "@prismicio/react": "^3.4.1", "@stackblitz/sdk": "^1.11.1", "clsx": "^2.1.1", - "crowdin": "^3.5.0", "docusaurus-plugin-copy-page-button": "^0.8.4", "docusaurus-plugin-module-alias": "^0.0.2", "docusaurus-plugin-sass": "^0.2.6", @@ -2023,6 +2023,130 @@ "node": ">=0.1.90" } }, + "node_modules/@crowdin/cli": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@crowdin/cli/-/cli-5.0.2.tgz", + "integrity": "sha512-TBUGFCIzAexEvePLet8aBRUEicB1A8r+A3/3gz+4paVKEc86cHK2CtaNhbto1ptKMRPkgFGXq8Z3f/TaoF09Lw==", + "license": "MIT", + "bin": { + "crowdin": "bin/crowdin.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@crowdin/cli-darwin-arm64": "5.0.2", + "@crowdin/cli-darwin-x64": "5.0.2", + "@crowdin/cli-linux-arm64": "5.0.2", + "@crowdin/cli-linux-arm64-musl": "5.0.2", + "@crowdin/cli-linux-x64": "5.0.2", + "@crowdin/cli-linux-x64-musl": "5.0.2", + "@crowdin/cli-win32-x64": "5.0.2" + } + }, + "node_modules/@crowdin/cli-darwin-arm64": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@crowdin/cli-darwin-arm64/-/cli-darwin-arm64-5.0.2.tgz", + "integrity": "sha512-gMNXyJYxkfgJF4cAXrss6mgkvPoFOkwRi4PO/93+wlOMTLOQ7ENlq45hbjQqxAsLbysYF1oHyzafaPNlC7JuMQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@crowdin/cli-darwin-x64": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@crowdin/cli-darwin-x64/-/cli-darwin-x64-5.0.2.tgz", + "integrity": "sha512-0iBJLy+kn0W095lFlkPG0jE0uLamFGjSR15N9yW3Q+Yps1zJBVyIH9IpjvALZOEHX0w9l5DZdCWzDowD9GTSQg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@crowdin/cli-linux-arm64": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@crowdin/cli-linux-arm64/-/cli-linux-arm64-5.0.2.tgz", + "integrity": "sha512-8LPMdQqqdVrn5t1KWywv/ewmxslwvUKMaFLFlNj44DFwRyd34yCXM3J56HazepMhuXIBD8tx0W6WMt9axv4j5w==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@crowdin/cli-linux-arm64-musl": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@crowdin/cli-linux-arm64-musl/-/cli-linux-arm64-musl-5.0.2.tgz", + "integrity": "sha512-/cfHw6bvPgFCGdIhYyFltGSQt33vgYbK1gFZO3BVGpM4gxLj/7cHz6sU4IRw+vHvSIHanfqeyAZzVLpCsfQwiA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@crowdin/cli-linux-x64": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@crowdin/cli-linux-x64/-/cli-linux-x64-5.0.2.tgz", + "integrity": "sha512-Fk1abpG2a9tM+49NyZU6l1/OyooNz9ZPIrpsR4xWP/c6ui0rh1l2XjOtbPjvXh2dW3YWemeOqiatW2j+WFj/cg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@crowdin/cli-linux-x64-musl": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@crowdin/cli-linux-x64-musl/-/cli-linux-x64-musl-5.0.2.tgz", + "integrity": "sha512-0BwcXbcBvCqutHyegSUqdUfSSrkNSxaar4y4TZE3Kgfjcw2laiTeOK8CAWhWxk523Jj/3/6P45wById07g0qKQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@crowdin/cli-win32-x64": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@crowdin/cli-win32-x64/-/cli-win32-x64-5.0.2.tgz", + "integrity": "sha512-cMarWbzeJvJ6f0MNwRH2fEEKKUM8gQn+oEtCo2PQ3a3wXXMpOb1gRw96tthgYxaHIHISYxdYalNNITnswLGE/A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@cspell/cspell-bundled-dicts": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-10.1.0.tgz", @@ -6676,14 +6800,6 @@ "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", "license": "MIT" }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "engines": { - "node": ">=6" - } - }, "node_modules/@slorber/remark-comment": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", @@ -7504,17 +7620,6 @@ "@swc/counter": "^0.1.3" } }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", @@ -7894,16 +7999,16 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -7912,13 +8017,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.10", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -7939,9 +8044,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -7952,13 +8057,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.10", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -7966,14 +8071,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -7982,9 +8087,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -7992,13 +8097,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -8463,11 +8568,6 @@ "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", "dev": true }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, "node_modules/autoprefixer": { "version": "10.5.4", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.4.tgz", @@ -8866,58 +8966,6 @@ "node": ">=14.16" } }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" - }, - "node_modules/cacheable-request/node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "engines": { - "node": ">=8" - } - }, "node_modules/call-bind": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", @@ -8977,6 +9025,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, "dependencies": { "no-case": "^2.2.0", "upper-case": "^1.1.1" @@ -9101,6 +9150,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.1.0.tgz", "integrity": "sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==", + "dev": true, "dependencies": { "camel-case": "^3.0.0", "constant-case": "^2.0.0", @@ -9166,14 +9216,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", - "engines": { - "node": "*" - } - }, "node_modules/cheerio": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", @@ -9353,14 +9395,6 @@ "node": ">=8" } }, - "node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "engines": { - "node": ">=0.8" - } - }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -9374,17 +9408,6 @@ "node": ">=6" } }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -9439,17 +9462,6 @@ "node": ">=10" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -9577,6 +9589,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dev": true, "dependencies": { "snake-case": "^2.1.0", "upper-case": "^1.1.1" @@ -9767,49 +9780,6 @@ "node": ">= 8" } }, - "node_modules/crowdin": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/crowdin/-/crowdin-3.5.0.tgz", - "integrity": "sha512-qyLtfanpacJq/2SFkkm+Pty6mUTBgV3YySrFAxAY+y3iOILIMuNcKxJ2CpyvIeIqZ2YoUo/AeDzQMchM4FdMZg==", - "dependencies": { - "change-case": "^3.1.0", - "form-data": "^2.5.1", - "got": "^9.6.0", - "js-yaml": "^3.13.1", - "json-schema-deref-sync": "^0.10.1", - "lodash": "^4.17.15", - "pupa": "^2.0.1" - } - }, - "node_modules/crowdin/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/crowdin/node_modules/js-yaml": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz", - "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==", - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", - "engines": { - "node": "*" - } - }, "node_modules/cspell": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/cspell/-/cspell-10.1.0.tgz", @@ -10493,11 +10463,6 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, - "node_modules/dag-map": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz", - "integrity": "sha512-+LSAiGFwQ9dRnRdOeaj7g47ZFJcOUPukAP8J3A3fuZ1g9Y44BG+P1sgApjLXTQPOzC4+7S9Wr8kXsfpINM4jpw==" - }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", @@ -10532,17 +10497,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -10609,11 +10563,6 @@ "node": ">=0.8" } }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -10670,14 +10619,6 @@ "node": ">=8.0.0" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -10797,9 +10738,10 @@ } }, "node_modules/docusaurus-plugin-sass": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/docusaurus-plugin-sass/-/docusaurus-plugin-sass-0.2.6.tgz", - "integrity": "sha512-2hKQQDkrufMong9upKoG/kSHJhuwd+FA3iAe/qzS/BmWpbIpe7XKmq5wlz4J5CJaOPu4x+iDJbgAxZqcoQf0kg==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/docusaurus-plugin-sass/-/docusaurus-plugin-sass-0.2.7.tgz", + "integrity": "sha512-v+XWW2BBlKiBfqNbDr8iF/DUcWIXDTsAVAfkbG0/pzCx9yV0zK6Qu0ZVFxpZXcMihokzl0zFD1HIN/M4TnzEwA==", + "license": "MIT", "dependencies": { "sass-loader": "^16.0.2" }, @@ -10874,6 +10816,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dev": true, "dependencies": { "no-case": "^2.2.0" } @@ -10897,11 +10840,6 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, - "node_modules/duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -10971,14 +10909,6 @@ "node": ">= 0.8" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { "version": "5.24.5", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", @@ -11076,21 +11006,6 @@ "node": ">= 0.4" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -11099,14 +11014,6 @@ "node": ">=6" } }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "engines": { - "node": ">=8" - } - }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -11145,6 +11052,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -11754,23 +11662,6 @@ } } }, - "node_modules/form-data": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.6.tgz", - "integrity": "sha512-Ogz/E85h9tlfJzpI6TuFpGcHZFhLrb9Gw8wq9v40CxSCPnv7ahKr6Xgtkn0KYCDQJ8DNn5VoMO8EXr9V5PadyA==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.4", - "mime-types": "^2.1.35", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/form-data-encoder": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", @@ -11946,17 +11837,6 @@ "node": ">= 0.4" } }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/github-slugger": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", @@ -12048,27 +11928,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -12126,21 +11985,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-yarn": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", @@ -12380,6 +12224,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dev": true, "dependencies": { "no-case": "^2.2.0", "upper-case": "^1.1.3" @@ -13110,11 +12955,6 @@ "node": ">=8" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", @@ -13289,40 +13129,11 @@ "node": ">=8" } }, - "node_modules/is-invalid-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-invalid-path/-/is-invalid-path-0.1.0.tgz", - "integrity": "sha512-aZMG0T3F34mTg4eTdszcGXx54oiZ4NtHSft3hWNJMGJXUUqdIj3cOZuHcU0nCWWcY3jd7yRe/3AEm3vSNTpBGQ==", - "dependencies": { - "is-glob": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-invalid-path/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-invalid-path/node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-lower-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dev": true, "dependencies": { "lower-case": "^1.1.0" } @@ -13458,21 +13269,11 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dev": true, "dependencies": { "upper-case": "^1.1.0" } }, - "node_modules/is-valid-path": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-valid-path/-/is-valid-path-0.1.1.tgz", - "integrity": "sha512-+kwPrVDu9Ms03L90Qaml+79+6DZHqHyRoANI6IsZJ/g8frhnfchDOBCa0RbQ6/kdHt5CS5OeIEyrYznNuVN+8A==", - "dependencies": { - "is-invalid-path": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -13646,24 +13447,6 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "node_modules/json-schema-deref-sync": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/json-schema-deref-sync/-/json-schema-deref-sync-0.10.1.tgz", - "integrity": "sha512-ESkdgGyLg5H0el8VvLe3ss8ANsRH05dPOG19HQ2T4hWG/rD1N6Iei7Xltc8Wwcz4pqc+mGWihP2d4mFWtk7A3A==", - "dependencies": { - "clone": "^2.1.2", - "dag-map": "~1.0.0", - "is-valid-path": "^0.1.1", - "lodash": "^4.17.13", - "md5": "~2.2.0", - "memory-cache": "~0.2.0", - "traverse": "~0.6.6", - "valid-url": "~1.0.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -14101,24 +13884,18 @@ "node_modules/lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==" + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true }, "node_modules/lower-case-first": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dev": true, "dependencies": { "lower-case": "^1.1.2" } }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -14166,16 +13943,6 @@ "node": ">= 0.4" } }, - "node_modules/md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha512-PlGG4z5mBANDGCKsYQe0CaUYHdZYZt8ZPZLmEt+Urf0W4GlpTX4HescwHU+dc9+Z/G/vZKYZYFrwgm9VxK6QOQ==", - "dependencies": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" - } - }, "node_modules/mdast-util-directive": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", @@ -14596,11 +14363,6 @@ "url": "https://github.com/sponsors/streamich" } }, - "node_modules/memory-cache": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz", - "integrity": "sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==" - }, "node_modules/merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", @@ -16355,14 +16117,6 @@ "node": ">=6" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "engines": { - "node": ">=4" - } - }, "node_modules/mini-css-extract-plugin": { "version": "2.10.2", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz", @@ -16573,6 +16327,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, "dependencies": { "lower-case": "^1.1.1" } @@ -16626,14 +16381,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "engines": { - "node": ">=8" - } - }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -16821,14 +16568,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -16891,14 +16630,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "engines": { - "node": ">=6" - } - }, "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -17151,6 +16882,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, "dependencies": { "no-case": "^2.2.0" } @@ -17239,6 +16971,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dev": true, "dependencies": { "camel-case": "^3.0.0", "upper-case-first": "^1.1.0" @@ -17248,6 +16981,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dev": true, "dependencies": { "no-case": "^2.2.0" } @@ -18899,14 +18633,6 @@ "postcss": "^8.4.31" } }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "engines": { - "node": ">=4" - } - }, "node_modules/prettier": { "version": "3.9.6", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", @@ -19027,26 +18753,6 @@ "node": ">= 0.10" } }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dependencies": { - "escape-goat": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/pvtsutils": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", @@ -19738,14 +19444,6 @@ "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -20147,6 +19845,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, "dependencies": { "no-case": "^2.2.0", "upper-case-first": "^1.1.2" @@ -20522,6 +20221,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dev": true, "dependencies": { "no-case": "^2.2.0" } @@ -20621,7 +20321,8 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true }, "node_modules/srcset": { "version": "4.0.0", @@ -20905,6 +20606,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dev": true, "dependencies": { "lower-case": "^1.1.1", "upper-case": "^1.1.1" @@ -21171,19 +20873,12 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dev": true, "dependencies": { "no-case": "^2.2.0", "upper-case": "^1.0.3" } }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "engines": { - "node": ">=6" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -21213,14 +20908,6 @@ "node": ">=6" } }, - "node_modules/traverse": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", - "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/tree-dump": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", @@ -21701,12 +21388,14 @@ "node_modules/upper-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==" + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true }, "node_modules/upper-case-first": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, "dependencies": { "upper-case": "^1.1.1" } @@ -21799,17 +21488,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -21848,11 +21526,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/valid-url": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", - "integrity": "sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==" - }, "node_modules/value-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", @@ -21999,19 +21672,19 @@ } }, "node_modules/vitest": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", - "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.10", - "@vitest/mocker": "4.1.10", - "@vitest/pretty-format": "4.1.10", - "@vitest/runner": "4.1.10", - "@vitest/snapshot": "4.1.10", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -22039,12 +21712,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.10", - "@vitest/browser-preview": "4.1.10", - "@vitest/browser-webdriverio": "4.1.10", - "@vitest/coverage-istanbul": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "@vitest/ui": "4.1.10", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -22089,9 +21762,9 @@ } }, "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -22595,11 +22268,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", diff --git a/package.json b/package.json index 71538c014d3..517f6e2d1d6 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ ] }, "dependencies": { + "@crowdin/cli": "^5.0.1", "@docusaurus/core": "^3.10.2", "@docusaurus/faster": "^3.10.2", "@docusaurus/preset-classic": "^3.10.2", @@ -49,7 +50,6 @@ "@prismicio/react": "^3.4.1", "@stackblitz/sdk": "^1.11.1", "clsx": "^2.1.1", - "crowdin": "^3.5.0", "docusaurus-plugin-copy-page-button": "^0.8.4", "docusaurus-plugin-module-alias": "^0.0.2", "docusaurus-plugin-sass": "^0.2.6", diff --git a/renovate.json b/renovate.json index 336f5f47c8a..43ef586a85e 100644 --- a/renovate.json +++ b/renovate.json @@ -11,6 +11,7 @@ "semanticCommits": "enabled", "rebaseWhen": "never", "includePaths": [ + "package.json", "static/code/stackblitz/**/*/package.json", ".github/workflows/**" ], @@ -22,21 +23,25 @@ { "matchPackageNames": ["@ionic/**"], "minimumReleaseAge": "0 days", - "groupName": "ionic" + "groupName": "ionic", + "matchFileNames": ["static/code/stackblitz/**"] }, { "description": "Angular majors land on a fixed cadence, so this group is restricted to the 1st of each month, 6-10am ET.", "matchPackageNames": ["@angular/**", "@angular-devkit/**"], "groupName": "angular", - "schedule": ["* 6-10 1 * *"] + "schedule": ["* 6-10 1 * *"], + "matchFileNames": ["static/code/stackblitz/**"] }, { "matchPackageNames": ["react", "react-dom"], - "groupName": "react" + "groupName": "react", + "matchFileNames": ["static/code/stackblitz/**"] }, { "matchPackageNames": ["react-router", "react-router-dom"], - "groupName": "react-router" + "groupName": "react-router", + "matchFileNames": ["static/code/stackblitz/**"] }, { "matchPackageNames": ["vite", "vite-plugin-static-copy"], @@ -126,6 +131,24 @@ "static/code/stackblitz/v9/react/package.json", "static/code/stackblitz/v9/vue/package.json" ] + }, + { + "matchPackageNames": ["@docusaurus/**"], + "groupName": "docusaurus", + "matchFileNames": ["package.json"] + }, + { + "description": "Docusaurus 3 supports react 19.", + "matchPackageNames": ["react", "react-dom"], + "allowedVersions": "<20.0.0", + "groupName": "react-root", + "matchFileNames": ["package.json"] + }, + { + "description": "Docusaurus 3 requires typescript v5.", + "matchPackageNames": ["typescript"], + "allowedVersions": "<6.0.0", + "matchFileNames": ["package.json"] } ] } diff --git a/scripts/cli.mjs b/scripts/cli.mjs index ca713d3a050..580aed23809 100644 --- a/scripts/cli.mjs +++ b/scripts/cli.mjs @@ -11,7 +11,6 @@ const commandToKebab = (str) => .toLowerCase(); (async function () { - // console.log(cliJSON); const { commands } = cliJSON; commands.map(writePage); @@ -28,7 +27,7 @@ function writePage(page) { renderExamples(page), ].join(''); - const path = `cli/commands/${commandToKebab(page.name)}.md`; + const path = `cli/commands/${commandToKebab(page.name)}.mdx`; writeFileSync(`docs/${path}`, data); writeFileSync(`versioned_docs/version-v8/${path}`, data); writeFileSync(`versioned_docs/version-v9/${path}`, data); @@ -118,113 +117,3 @@ function renderAdvancedOptions({ options }) { } return utils.renderOptions('Advanced Options', options); } - -// function renderProperties({ props: properties }) { -// if (properties.length === 0) { -// return ""; -// } - -// return ` -// ## Properties - -// ${properties -// .map( -// prop => ` -// ### ${prop.name} - -// | | | -// | --- | --- | -// | **Description** | ${prop.docs.split("\n").join("
")} | -// | **Attribute** | \`${prop.attr}\` | -// | **Type** | \`${prop.type.replace(/\|/g, "\\|")}\` | -// | **Default** | \`${prop.default}\` | - -// ` -// ) -// .join("\n")} -// `; -// } - -// function renderEvents({ events }) { -// if (events.length === 0) { -// return ""; -// } - -// return ` -// ## Events - -// | Name | Description | -// | --- | --- | -// ${events.map(event => `| \`${event.event}\` | ${event.docs} |`).join("\n")} - -// `; -// } - -// function renderMethods({ methods }) { -// if (methods.length === 0) { -// return ""; -// } - -// return ` -// ## Methods - -// ${methods -// .map( -// method => ` -// ### ${method.name} - -// | | | -// | --- | --- | -// | **Description** | ${method.docs.split("\n").join("
")} | -// | **Signature** | \`${method.signature.replace(/\|/g, "\\|")}\` | -// ` -// ) -// .join("\n")} - -// `; -// } - -// function renderParts({ parts }) { -// if (parts.length === 0) { -// return ""; -// } - -// return ` -// ## CSS Shadow Parts - -// | Name | Description | -// | --- | --- | -// ${parts.map(prop => `| \`${prop.name}\` | ${prop.docs} |`).join("\n")} - -// `; -// } - -// function renderCustomProps({ styles: customProps }) { -// if (customProps.length === 0) { -// return ""; -// } - -// return ` -// ## CSS Custom Properties - -// | Name | Description | -// | --- | --- | -// ${customProps.map(prop => `| \`${prop.name}\` | ${prop.docs} |`).join("\n")} - -// `; -// } - -// function renderSlots({ slots }) { -// if (slots.length === 0) { -// return ""; -// } - -// return ` -// ## Slots - -// | Name | Description | -// | --- | --- | -// ${slots.map(slot => `| \`${slot.name}\` | ${slot.docs} |`).join("\n")} - -// `; -// } diff --git a/scripts/native.mjs b/scripts/native.mjs index 55b48c6f3ee..1b8a9e0bb6c 100644 --- a/scripts/native.mjs +++ b/scripts/native.mjs @@ -33,7 +33,7 @@ async function buildPluginApiDocs(pluginId) { const [readme, pkgJson] = await Promise.all([getReadme(pluginId), getPkgJsonData(pluginId)]); const apiContent = createApiPage(pluginId, readme, pkgJson); - const fileName = `${pluginId}.md`; + const fileName = `${pluginId}.mdx`; writeFileSync(`docs/native/${fileName}`, apiContent); writeFileSync(`versioned_docs/version-v8/native/${fileName}`, apiContent); diff --git a/src/components/global/BestPracticeFigure/index.tsx b/src/components/global/BestPracticeFigure/index.tsx index b0254eca824..cc024dca957 100644 --- a/src/components/global/BestPracticeFigure/index.tsx +++ b/src/components/global/BestPracticeFigure/index.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { type ReactNode } from 'react'; import './best-practice-figure.css'; @@ -54,6 +54,14 @@ export default function BestPracticeFigure({ doImage, doNotImage, cautionImage, +}: { + text: ReactNode; + doText: ReactNode; + doNotText?: ReactNode; + cautionText?: ReactNode; + doImage: ReactNode; + doNotImage?: ReactNode; + cautionImage?: ReactNode; }) { return (
diff --git a/src/components/global/Codepen/index.tsx b/src/components/global/Codepen/index.tsx index 8b7b8854da9..bea888275b1 100644 --- a/src/components/global/Codepen/index.tsx +++ b/src/components/global/Codepen/index.tsx @@ -2,9 +2,16 @@ import React, { type ReactNode } from 'react'; import { useScript } from '@site/src/utils/hooks'; -function CodePen(props): ReactNode { - const status = useScript('https://static.codepen.io/assets/embed/ei.js'); - // console.log('test',status, props) +function CodePen(props: { + height?: number | string; + theme?: string; + defaultTab?: string; + user?: string; + slug?: string; + preview?: boolean; + penTitle?: string; +}): ReactNode { + useScript('https://static.codepen.io/assets/embed/ei.js'); return (
ion-icon { - margin-right: 5px; -} -/* -@media (max-width: 1160px) { - .docs-demo-device, - .docs-demo-mode-toggle, - .docs-demo-source { - display: none; - } -} */ diff --git a/src/components/global/DocDemo/index.js b/src/components/global/DocDemo/index.js index 61740542956..a03f01fb987 100644 --- a/src/components/global/DocDemo/index.js +++ b/src/components/global/DocDemo/index.js @@ -58,7 +58,7 @@ const DocDemo = (props) => { const sourceLink = ( - {/* */} View Source + View Source ); diff --git a/src/components/global/DocsCard/index.tsx b/src/components/global/DocsCard/index.tsx index 0e191ae6618..b4e8724c63e 100644 --- a/src/components/global/DocsCard/index.tsx +++ b/src/components/global/DocsCard/index.tsx @@ -11,7 +11,6 @@ interface Props extends React.HTMLAttributes { icon?: string; hoverIcon?: string; iconset?: string; - ionicon?: string; img?: string; size?: 'md' | 'lg'; } @@ -32,7 +31,6 @@ function DocsCard(props: Props): ReactNode { {hoverIcon && }
)} - {props.ionicon && } {props.iconset && (
{props.iconset.split(',').map((icon, index, array) => ( @@ -53,11 +51,10 @@ function DocsCard(props: Props): ReactNode { ); - const className = clsx({ + const className = clsx(props.className, { 'Card-with-image': typeof props.img !== 'undefined', 'Card-without-image': typeof props.img === 'undefined', 'Card-size-lg': props.size === 'lg', - [props.className]: props.className, }); if (isStatic) { diff --git a/src/components/global/DocsCard/styles.module.scss b/src/components/global/DocsCard/styles.module.scss index a57e862b16c..89e7e801302 100644 --- a/src/components/global/DocsCard/styles.module.scss +++ b/src/components/global/DocsCard/styles.module.scss @@ -131,13 +131,6 @@ docs-card[disabled]::after { font-weight: 600; } - .Card-ionicon { - width: 48px; - height: 48px; - float: left; - margin-right: 1em; - } - .Card-content > *:first-child { margin-top: 0; } @@ -178,7 +171,6 @@ docs-card[disabled]::after { } .Card-size-lg .Card-icon, - .Card-size-lg .Card-ionicon, .Card-size-lg .Card-iconset__container { width: 80px; height: 80px; diff --git a/src/components/global/DocsCards/index.tsx b/src/components/global/DocsCards/index.tsx index ea2d310e791..1f040dc8148 100644 --- a/src/components/global/DocsCards/index.tsx +++ b/src/components/global/DocsCards/index.tsx @@ -2,7 +2,7 @@ import React, { type ReactNode } from 'react'; import './cards.css'; -function DocsCards(props): ReactNode { +function DocsCards(props: { className?: string; children?: ReactNode }): ReactNode { return {props.children}; } diff --git a/src/components/global/Playground/index.tsx b/src/components/global/Playground/index.tsx index e47a69075ca..b5c117ffc84 100644 --- a/src/components/global/Playground/index.tsx +++ b/src/components/global/Playground/index.tsx @@ -1,10 +1,19 @@ -import React, { RefObject, forwardRef, useEffect, useMemo, useRef, useState } from 'react'; +import React, { + ForwardedRef, + type ReactElement, + type ReactNode, + forwardRef, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; import useBaseUrl from '@docusaurus/useBaseUrl'; import './playground.css'; import { EditorOptions, openAngularEditor, openHtmlEditor, openReactEditor, openVueEditor } from './stackblitz.utils'; import { useColorMode } from '@docusaurus/theme-common'; -import { ConsoleItem, Mode, UsageTarget } from './playground.types'; +import { CodeSnippets, ConsoleItem, Mode, UsageTarget } from './playground.types'; import Tooltip from '../Tooltip'; import PlaygroundTabs from '../PlaygroundTabs'; @@ -30,7 +39,7 @@ const ControlButton = forwardRef( label: string; disabled?: boolean; }, - ref: RefObject + ref: ForwardedRef ) => { const controlButton = ( - -
- A plain div with an unbounded ripple effect - -
- - - - -``` - -```css -.ripple-parent { - position: relative; - overflow: hidden; -} -``` - - - - - -```html - - -
- A plain div with a bounded ripple effect - -
- - - -
- A plain div with an unbounded ripple effect - -
- - -
-
-``` - -```css -.ripple-parent { - position: relative; - overflow: hidden; -} -``` - -
- - - -```tsx -import React from 'react'; -import { IonApp, IonContent, IonRippleEffect } from '@ionic/react'; -import './RippleEffectExample.css'; - -export const RippleExample: React.FC = () => ( - - -
- A plain div with a bounded ripple effect - -
- - - -
- A plain div with an unbounded ripple effect - -
- - -
-
-); -``` - -```css -.ripple-parent { - position: relative; - overflow: hidden; -} -``` - -
- - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'ripple-effect-example', - styleUrl: 'ripple-effect-example.css', -}) -export class RippleEffectExample { - render() { - return [ - - -
- A plain div with a bounded ripple effect - -
- - - -
- A plain div with an unbounded ripple effect - -
- - -
-
, - ]; - } -} -``` - -```css -.ripple-parent { - position: relative; - overflow: hidden; -} -``` - -
- - - -```html - - - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/ripple-effect.mdx b/versioned_docs/version-v5/api/ripple-effect.mdx new file mode 100644 index 00000000000..116b89e11a6 --- /dev/null +++ b/versioned_docs/version-v5/api/ripple-effect.mdx @@ -0,0 +1,265 @@ +--- +sidebar_label: 'ion-ripple-effect' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/ripple-effect/props.mdx'; +import Events from '@ionic-internal/component-api/v5/ripple-effect/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/ripple-effect/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/ripple-effect/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/ripple-effect/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/ripple-effect/slots.mdx'; + +# ion-ripple-effect + +The ripple effect component adds the [Material Design ink ripple interaction effect](https://material.io/develop/web/components/ripples/). This component can only be used inside of an `` and can be added to any component. + +It's important to note that the parent should have [relative positioning](https://developer.mozilla.org/en-US/docs/Web/CSS/position) because the ripple effect is absolutely positioned and will cover the closest parent with relative positioning. The parent element should also be given the `ion-activatable` class, which tells the ripple effect that the element is clickable. + +The default type, `"bounded"`, will expand the ripple effect from the click position outwards. To add a ripple effect that always starts in the center of the element and expands in a circle, add an `"unbounded"` type. It's recommended to add `overflow: hidden` to the parent element to avoid the ripple overflowing its container, especially with an unbounded ripple. + +## Usage + + + + + +```html + + +
+ A plain div with a bounded ripple effect + +
+ + + +
+ A plain div with an unbounded ripple effect + +
+ + +
+
+``` + +```css +.ripple-parent { + position: relative; + overflow: hidden; +} +``` + +
+ + + +```html + + +
+ A plain div with a bounded ripple effect + +
+ + + +
+ A plain div with an unbounded ripple effect + +
+ + +
+
+``` + +```css +.ripple-parent { + position: relative; + overflow: hidden; +} +``` + +
+ + + +```tsx +import React from 'react'; +import { IonApp, IonContent, IonRippleEffect } from '@ionic/react'; +import './RippleEffectExample.css'; + +export const RippleExample: React.FC = () => ( + + +
+ A plain div with a bounded ripple effect + +
+ + + +
+ A plain div with an unbounded ripple effect + +
+ + +
+
+); +``` + +```css +.ripple-parent { + position: relative; + overflow: hidden; +} +``` + +
+ + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'ripple-effect-example', + styleUrl: 'ripple-effect-example.css', +}) +export class RippleEffectExample { + render() { + return [ + + +
+ A plain div with a bounded ripple effect + +
+ + + +
+ A plain div with an unbounded ripple effect + +
+ + +
+
, + ]; + } +} +``` + +```css +.ripple-parent { + position: relative; + overflow: hidden; +} +``` + +
+ + + +```html + + + + + +``` + + + +
+ +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/route-redirect.md b/versioned_docs/version-v5/api/route-redirect.md deleted file mode 100644 index b2e35af1827..00000000000 --- a/versioned_docs/version-v5/api/route-redirect.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -sidebar_label: 'ion-route-redirect' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/route-redirect/props.md'; -import Events from '@ionic-internal/component-api/v5/route-redirect/events.md'; -import Methods from '@ionic-internal/component-api/v5/route-redirect/methods.md'; -import Parts from '@ionic-internal/component-api/v5/route-redirect/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/route-redirect/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/route-redirect/slots.md'; - -# ion-route-redirect - -A route redirect can only be used with an `ion-router` as a direct child of it. - -> Note: this component should only be used with vanilla and Stencil JavaScript projects. For Angular projects, use [`ion-router-outlet`](router-outlet.md) and the Angular router. - -The route redirect has two configurable properties: - -- `from` -- `to` - -It redirects "from" a URL "to" another URL. When the defined `ion-route-redirect` rule matches, the router will redirect from the path specified in the `from` property to the path in the `to` property. In order for a redirect to occur the `from` path needs to be an exact match to the navigated URL. - -## Multiple Route Redirects - -An arbitrary number of redirect routes can be defined inside an `ion-router`, but only one can match. - -A route redirect will never call another redirect after its own redirect, since this could lead to infinite loops. - -Take the following two redirects: - -```html - - - - -``` - -If the user navigates to `/admin` the router will redirect to `/login` and stop there. It will never evaluate more than one redirect. - -## Usage - -```html - - - - - -``` - -### Route Redirects as Guards - -Redirection routes can work as guards to prevent users from navigating to certain areas of an application based on a given condition, such as if the user is authenticated or not. - -A route redirect can be added and removed dynamically to redirect (or guard) some routes from being accessed. In the following example, all urls `*` will be redirected to the `/login` url if `isLoggedIn` is `false`. - -```tsx -const isLoggedIn = false; - -const router = document.querySelector('ion-router'); -const routeRedirect = document.createElement('ion-route-redirect'); -routeRedirect.setAttribute('from', '*'); -routeRedirect.setAttribute('to', '/login'); - -if (!isLoggedIn) { - router.appendChild(routeRedirect); -} -``` - -Alternatively, the value of `to` can be modified based on a condition. In the following example, the route redirect will check if the user is logged in and redirect to the `/login` url if not. - -```html - -``` - -```javascript -const isLoggedIn = false; -const routeRedirect = document.querySelector('#tutorialRedirect'); - -routeRedirect.setAttribute('to', isLoggedIn ? undefined : '/login'); -``` - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/route-redirect.mdx b/versioned_docs/version-v5/api/route-redirect.mdx new file mode 100644 index 00000000000..e3cd5b7ba69 --- /dev/null +++ b/versioned_docs/version-v5/api/route-redirect.mdx @@ -0,0 +1,111 @@ +--- +sidebar_label: 'ion-route-redirect' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/route-redirect/props.mdx'; +import Events from '@ionic-internal/component-api/v5/route-redirect/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/route-redirect/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/route-redirect/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/route-redirect/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/route-redirect/slots.mdx'; + +# ion-route-redirect + +A route redirect can only be used with an `ion-router` as a direct child of it. + +> Note: this component should only be used with vanilla and Stencil JavaScript projects. For Angular projects, use [`ion-router-outlet`](router-outlet.mdx) and the Angular router. + +The route redirect has two configurable properties: + +- `from` +- `to` + +It redirects "from" a URL "to" another URL. When the defined `ion-route-redirect` rule matches, the router will redirect from the path specified in the `from` property to the path in the `to` property. In order for a redirect to occur the `from` path needs to be an exact match to the navigated URL. + +## Multiple Route Redirects + +An arbitrary number of redirect routes can be defined inside an `ion-router`, but only one can match. + +A route redirect will never call another redirect after its own redirect, since this could lead to infinite loops. + +Take the following two redirects: + +```html + + + + +``` + +If the user navigates to `/admin` the router will redirect to `/login` and stop there. It will never evaluate more than one redirect. + +## Usage + +```html + + + + + +``` + +### Route Redirects as Guards + +Redirection routes can work as guards to prevent users from navigating to certain areas of an application based on a given condition, such as if the user is authenticated or not. + +A route redirect can be added and removed dynamically to redirect (or guard) some routes from being accessed. In the following example, all urls `*` will be redirected to the `/login` url if `isLoggedIn` is `false`. + +```tsx +const isLoggedIn = false; + +const router = document.querySelector('ion-router'); +const routeRedirect = document.createElement('ion-route-redirect'); +routeRedirect.setAttribute('from', '*'); +routeRedirect.setAttribute('to', '/login'); + +if (!isLoggedIn) { + router.appendChild(routeRedirect); +} +``` + +Alternatively, the value of `to` can be modified based on a condition. In the following example, the route redirect will check if the user is logged in and redirect to the `/login` url if not. + +```html + +``` + +```javascript +const isLoggedIn = false; +const routeRedirect = document.querySelector('#tutorialRedirect'); + +routeRedirect.setAttribute('to', isLoggedIn ? undefined : '/login'); +``` + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/route.md b/versioned_docs/version-v5/api/route.md deleted file mode 100644 index 0c12b788a85..00000000000 --- a/versioned_docs/version-v5/api/route.md +++ /dev/null @@ -1,260 +0,0 @@ ---- -sidebar_label: 'ion-route' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/route/props.md'; -import Events from '@ionic-internal/component-api/v5/route/events.md'; -import Methods from '@ionic-internal/component-api/v5/route/methods.md'; -import Parts from '@ionic-internal/component-api/v5/route/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/route/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/route/slots.md'; - -# ion-route - -The route component takes a component and renders it when the Browser URL matches the url property. - -> Note: this component should only be used with vanilla and Stencil JavaScript projects. For Angular projects, use [`ion-router-outlet`](router-outlet.md) and the Angular router. - -## Navigation Hooks - -Navigation hooks can be used to perform tasks or act as navigation guards. Hooks are used by providing functions to the `beforeEnter` and `beforeLeave` properties on each `ion-route`. Returning `true` allows navigation to proceed, while returning `false` causes it to be cancelled. Returning an object of type `NavigationHookOptions` allows you to redirect navigation to another page. - -## Interfaces - -```tsx -interface NavigationHookOptions { - /** - * A valid path to redirect navigation to. - */ - redirect: string; -} -``` - -## Usage - - - - - -```html - - - - - - -``` - -```javascript -const dashboardPage = document.querySelector('ion-route[url="/dashboard"]'); -dashboardPage.beforeEnter = isLoggedInGuard; - -const newMessagePage = document.querySelector('ion-route[url="/dashboard"]'); -newMessagePage.beforeLeave = hasUnsavedDataGuard; - -const isLoggedInGuard = async () => { - const isLoggedIn = await UserData.isLoggedIn(); // Replace this with actual login validation - - if (isLoggedIn) { - return true; - } else { - return { redirect: '/login' }; // If a user is not logged in, they will be redirected to the /login page - } -}; - -const hasUnsavedDataGuard = async () => { - const hasUnsavedData = await checkData(); // Replace this with actual validation - - if (hasUnsavedData) { - return await confirmDiscardChanges(); - } else { - return true; - } -}; - -const confirmDiscardChanges = async () => { - const route = document.createElement('ion-route'); - route.header = 'Discard Unsaved Changes?'; - route.message = 'Are you sure you want to leave? Any unsaved changed will be lost.'; - route.buttons = [ - { - text: 'Cancel', - role: 'Cancel', - }, - { - text: 'Discard', - role: 'destructive', - }, - ]; - - document.body.appendChild(route); - - await route.present(); - - const { role } = await route.onDidDismiss(); - - return role === 'Cancel' ? false : true; -}; -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; -import { routeController } from '@ionic/core'; - -@Component({ - tag: 'router-example', - styleUrl: 'router-example.css', -}) -export class RouterExample { - render() { - return ( - - - - - - - ); - } -} - -const isLoggedInGuard = async () => { - const isLoggedIn = await UserData.isLoggedIn(); // Replace this with actual login validation - - if (isLoggedIn) { - return true; - } else { - return { redirect: '/login' }; // If a user is not logged in, they will be redirected to the /login page - } -}; - -const hasUnsavedDataGuard = async () => { - const hasUnsavedData = await checkData(); // Replace this with actual validation - - if (hasUnsavedData) { - return await confirmDiscardChanges(); - } else { - return true; - } -}; - -const confirmDiscardChanges = async () => { - const route = await routeController.create({ - header: 'Discard Unsaved Changes?', - message: 'Are you sure you want to leave? Any unsaved changed will be lost.', - buttons: [ - { - text: 'Cancel', - role: 'Cancel', - }, - { - text: 'Discard', - role: 'destructive', - }, - ], - }); - - await route.present(); - - const { role } = await route.onDidDismiss(); - - return role === 'Cancel' ? false : true; -}; -``` - - - - - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/route.mdx b/versioned_docs/version-v5/api/route.mdx new file mode 100644 index 00000000000..d3e0a64bbc0 --- /dev/null +++ b/versioned_docs/version-v5/api/route.mdx @@ -0,0 +1,260 @@ +--- +sidebar_label: 'ion-route' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/route/props.mdx'; +import Events from '@ionic-internal/component-api/v5/route/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/route/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/route/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/route/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/route/slots.mdx'; + +# ion-route + +The route component takes a component and renders it when the Browser URL matches the url property. + +> Note: this component should only be used with vanilla and Stencil JavaScript projects. For Angular projects, use [`ion-router-outlet`](router-outlet.mdx) and the Angular router. + +## Navigation Hooks + +Navigation hooks can be used to perform tasks or act as navigation guards. Hooks are used by providing functions to the `beforeEnter` and `beforeLeave` properties on each `ion-route`. Returning `true` allows navigation to proceed, while returning `false` causes it to be cancelled. Returning an object of type `NavigationHookOptions` allows you to redirect navigation to another page. + +## Interfaces + +```tsx +interface NavigationHookOptions { + /** + * A valid path to redirect navigation to. + */ + redirect: string; +} +``` + +## Usage + + + + + +```html + + + + + + +``` + +```javascript +const dashboardPage = document.querySelector('ion-route[url="/dashboard"]'); +dashboardPage.beforeEnter = isLoggedInGuard; + +const newMessagePage = document.querySelector('ion-route[url="/dashboard"]'); +newMessagePage.beforeLeave = hasUnsavedDataGuard; + +const isLoggedInGuard = async () => { + const isLoggedIn = await UserData.isLoggedIn(); // Replace this with actual login validation + + if (isLoggedIn) { + return true; + } else { + return { redirect: '/login' }; // If a user is not logged in, they will be redirected to the /login page + } +}; + +const hasUnsavedDataGuard = async () => { + const hasUnsavedData = await checkData(); // Replace this with actual validation + + if (hasUnsavedData) { + return await confirmDiscardChanges(); + } else { + return true; + } +}; + +const confirmDiscardChanges = async () => { + const route = document.createElement('ion-route'); + route.header = 'Discard Unsaved Changes?'; + route.message = 'Are you sure you want to leave? Any unsaved changed will be lost.'; + route.buttons = [ + { + text: 'Cancel', + role: 'Cancel', + }, + { + text: 'Discard', + role: 'destructive', + }, + ]; + + document.body.appendChild(route); + + await route.present(); + + const { role } = await route.onDidDismiss(); + + return role === 'Cancel' ? false : true; +}; +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; +import { routeController } from '@ionic/core'; + +@Component({ + tag: 'router-example', + styleUrl: 'router-example.css', +}) +export class RouterExample { + render() { + return ( + + + + + + + ); + } +} + +const isLoggedInGuard = async () => { + const isLoggedIn = await UserData.isLoggedIn(); // Replace this with actual login validation + + if (isLoggedIn) { + return true; + } else { + return { redirect: '/login' }; // If a user is not logged in, they will be redirected to the /login page + } +}; + +const hasUnsavedDataGuard = async () => { + const hasUnsavedData = await checkData(); // Replace this with actual validation + + if (hasUnsavedData) { + return await confirmDiscardChanges(); + } else { + return true; + } +}; + +const confirmDiscardChanges = async () => { + const route = await routeController.create({ + header: 'Discard Unsaved Changes?', + message: 'Are you sure you want to leave? Any unsaved changed will be lost.', + buttons: [ + { + text: 'Cancel', + role: 'Cancel', + }, + { + text: 'Discard', + role: 'destructive', + }, + ], + }); + + await route.present(); + + const { role } = await route.onDidDismiss(); + + return role === 'Cancel' ? false : true; +}; +``` + + + + + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/router-link.md b/versioned_docs/version-v5/api/router-link.md deleted file mode 100644 index 6ba51db4500..00000000000 --- a/versioned_docs/version-v5/api/router-link.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: 'Router Link | Navigating The ion-router-link Component' -description: 'Use the ion-router-link component to navigate to a specified link. The router link can accept an href for location and a direction for the transition animation.' -sidebar_label: 'ion-router-link' -demoUrl: '/docs/demos/api/router-link/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/router-link/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/router-link/props.md'; -import Events from '@ionic-internal/component-api/v5/router-link/events.md'; -import Methods from '@ionic-internal/component-api/v5/router-link/methods.md'; -import Parts from '@ionic-internal/component-api/v5/router-link/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/router-link/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/router-link/slots.md'; - -# ion-router-link - -The router link component is used for navigating to a specified link. Similar to the browser's anchor tag, it can accept a href for the location, and a direction for the transition animation. - -> Note: this component should only be used with vanilla and Stencil JavaScript projects. For Angular projects, use an `
` and `routerLink` with the Angular router. - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/router-link.mdx b/versioned_docs/version-v5/api/router-link.mdx new file mode 100644 index 00000000000..adc9da84dde --- /dev/null +++ b/versioned_docs/version-v5/api/router-link.mdx @@ -0,0 +1,47 @@ +--- +title: 'Router Link | Navigating The ion-router-link Component' +description: 'Use the ion-router-link component to navigate to a specified link. The router link can accept an href for location and a direction for the transition animation.' +sidebar_label: 'ion-router-link' +demoUrl: '/docs/demos/api/router-link/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/router-link/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/router-link/props.mdx'; +import Events from '@ionic-internal/component-api/v5/router-link/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/router-link/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/router-link/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/router-link/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/router-link/slots.mdx'; + +# ion-router-link + +The router link component is used for navigating to a specified link. Similar to the browser's anchor tag, it can accept a href for the location, and a direction for the transition animation. + +> Note: this component should only be used with vanilla and Stencil JavaScript projects. For Angular projects, use an `` and `routerLink` with the Angular router. + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/router-outlet.md b/versioned_docs/version-v5/api/router-outlet.md deleted file mode 100644 index f74db7657f5..00000000000 --- a/versioned_docs/version-v5/api/router-outlet.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -sidebar_label: 'ion-router-outlet' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/router-outlet/props.md'; -import Events from '@ionic-internal/component-api/v5/router-outlet/events.md'; -import Methods from '@ionic-internal/component-api/v5/router-outlet/methods.md'; -import Parts from '@ionic-internal/component-api/v5/router-outlet/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/router-outlet/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/router-outlet/slots.md'; - -# ion-router-outlet - -Router outlet is a component used in routing within an Angular or Vue app. It behaves in a similar way to Angular's built-in router outlet component and Vue's router view component, but contains the logic for providing a stacked navigation, and animating views in and out. - -> Note: this component should only be used with Angular and Vue projects. For vanilla or Stencil JavaScript projects, use [`ion-router`](router.md) and [`ion-route`](route.md). - -Although router outlet has methods for navigating around, it's recommended to use the navigation methods in your framework's router. - -## Life Cycle Hooks - -Routes rendered in a Router Outlet have access to specific Ionic events that are wired up to animations - -| Event Name | Trigger | -| ------------------ | ------------------------------------------------------------------ | -| `ionViewWillEnter` | Fired when the component routing to is about to animate into view. | -| `ionViewDidEnter` | Fired when the component routing to has finished animating. | -| `ionViewWillLeave` | Fired when the component routing from is about to animate. | -| `ionViewDidLeave` | Fired when the component routing to has finished animating. | - -These event tie into Ionic's animation system and can be used to coordinate parts of your app when a Components is done with its animation. These events are not a replacement for your framework's own event system, but an addition. - -For handling Router Guards, the older `ionViewCanEnter` and `ionViewCanLeave` have been replaced with their framework specific equivalent. For Angular, there are [Router Guards](https://angular.io/guide/router#milestone-5-route-guards). - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/router-outlet.mdx b/versioned_docs/version-v5/api/router-outlet.mdx new file mode 100644 index 00000000000..5c459a4d337 --- /dev/null +++ b/versioned_docs/version-v5/api/router-outlet.mdx @@ -0,0 +1,60 @@ +--- +sidebar_label: 'ion-router-outlet' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/router-outlet/props.mdx'; +import Events from '@ionic-internal/component-api/v5/router-outlet/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/router-outlet/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/router-outlet/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/router-outlet/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/router-outlet/slots.mdx'; + +# ion-router-outlet + +Router outlet is a component used in routing within an Angular or Vue app. It behaves in a similar way to Angular's built-in router outlet component and Vue's router view component, but contains the logic for providing a stacked navigation, and animating views in and out. + +> Note: this component should only be used with Angular and Vue projects. For vanilla or Stencil JavaScript projects, use [`ion-router`](router.mdx) and [`ion-route`](route.mdx). + +Although router outlet has methods for navigating around, it's recommended to use the navigation methods in your framework's router. + +## Life Cycle Hooks + +Routes rendered in a Router Outlet have access to specific Ionic events that are wired up to animations + +| Event Name | Trigger | +| ------------------ | ------------------------------------------------------------------ | +| `ionViewWillEnter` | Fired when the component routing to is about to animate into view. | +| `ionViewDidEnter` | Fired when the component routing to has finished animating. | +| `ionViewWillLeave` | Fired when the component routing from is about to animate. | +| `ionViewDidLeave` | Fired when the component routing to has finished animating. | + +These event tie into Ionic's animation system and can be used to coordinate parts of your app when a Components is done with its animation. These events are not a replacement for your framework's own event system, but an addition. + +For handling Router Guards, the older `ionViewCanEnter` and `ionViewCanLeave` have been replaced with their framework specific equivalent. For Angular, there are [Router Guards](https://angular.io/guide/router#milestone-5-route-guards). + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/router.md b/versioned_docs/version-v5/api/router.md deleted file mode 100644 index 72c38e55959..00000000000 --- a/versioned_docs/version-v5/api/router.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: 'ion-router: Router Component to Coordinate URL Navigation' -description: 'ion-router is a URL coordinator for navigation outlets of ionic: ion-nav and ion-tabs. Router components handle routing inside vanilla and Stencil JavaScript.' -sidebar_label: 'ion-router' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/router/props.md'; -import Events from '@ionic-internal/component-api/v5/router/events.md'; -import Methods from '@ionic-internal/component-api/v5/router/methods.md'; -import Parts from '@ionic-internal/component-api/v5/router/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/router/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/router/slots.md'; - -# ion-router - -The router is a component for handling routing inside vanilla and Stencil JavaScript projects. - -> Note: this component should only be used with vanilla and Stencil JavaScript projects. For Angular projects, use [`ion-router-outlet`](router-outlet.md) and the Angular router. - -Apps should have a single `ion-router` component in the codebase. -This component controls all interactions with the browser history and it aggregates updates through an event system. - -`ion-router` is just a URL coordinator for the navigation outlets of ionic: `ion-nav` and `ion-tabs`. - -That means the `ion-router` never touches the DOM, it does NOT show the components or emit any kind of lifecycle events, it just tells `ion-nav` and `ion-tabs` what and when to "show" based on the browser's URL. - -In order to configure this relationship between components (to load/select) and URLs, `ion-router` uses a declarative syntax using JSX/HTML to define a tree of routes. - -## Usage - -```html - - - - - - - - - - - - - - - - - - - - - - - -``` - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/router.mdx b/versioned_docs/version-v5/api/router.mdx new file mode 100644 index 00000000000..93b0dfb7518 --- /dev/null +++ b/versioned_docs/version-v5/api/router.mdx @@ -0,0 +1,82 @@ +--- +title: 'ion-router: Router Component to Coordinate URL Navigation' +description: 'ion-router is a URL coordinator for navigation outlets of ionic: ion-nav and ion-tabs. Router components handle routing inside vanilla and Stencil JavaScript.' +sidebar_label: 'ion-router' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/router/props.mdx'; +import Events from '@ionic-internal/component-api/v5/router/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/router/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/router/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/router/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/router/slots.mdx'; + +# ion-router + +The router is a component for handling routing inside vanilla and Stencil JavaScript projects. + +> Note: this component should only be used with vanilla and Stencil JavaScript projects. For Angular projects, use [`ion-router-outlet`](router-outlet.mdx) and the Angular router. + +Apps should have a single `ion-router` component in the codebase. +This component controls all interactions with the browser history and it aggregates updates through an event system. + +`ion-router` is just a URL coordinator for the navigation outlets of ionic: `ion-nav` and `ion-tabs`. + +That means the `ion-router` never touches the DOM, it does NOT show the components or emit any kind of lifecycle events, it just tells `ion-nav` and `ion-tabs` what and when to "show" based on the browser's URL. + +In order to configure this relationship between components (to load/select) and URLs, `ion-router` uses a declarative syntax using JSX/HTML to define a tree of routes. + +## Usage + +```html + + + + + + + + + + + + + + + + + + + + + + + +``` + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/row.md b/versioned_docs/version-v5/api/row.md deleted file mode 100644 index 025c3a24bed..00000000000 --- a/versioned_docs/version-v5/api/row.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -sidebar_label: 'ion-row' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/row/props.md'; -import Events from '@ionic-internal/component-api/v5/row/events.md'; -import Methods from '@ionic-internal/component-api/v5/row/methods.md'; -import Parts from '@ionic-internal/component-api/v5/row/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/row/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/row/slots.md'; - -# ion-row - -Rows are horizontal components of the [grid](grid.md) system and contain varying numbers of -[columns](col.md). They ensure the columns are positioned properly. - -See [Grid Layout](../layout/grid.md) for more information. - -## Row Alignment - -By default, columns will stretch to fill the entire height of the row and wrap when necessary. Rows are [flex containers](https://developer.mozilla.org/en-US/docs/Glossary/Flex_Container), so there are several [CSS classes](../layout/css-utilities.md#flex-container-properties) that can be applied to a row to customize this behavior. - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/row.mdx b/versioned_docs/version-v5/api/row.mdx new file mode 100644 index 00000000000..273251dfb6f --- /dev/null +++ b/versioned_docs/version-v5/api/row.mdx @@ -0,0 +1,48 @@ +--- +sidebar_label: 'ion-row' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/row/props.mdx'; +import Events from '@ionic-internal/component-api/v5/row/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/row/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/row/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/row/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/row/slots.mdx'; + +# ion-row + +Rows are horizontal components of the [grid](grid.mdx) system and contain varying numbers of +[columns](col.mdx). They ensure the columns are positioned properly. + +See [Grid Layout](../layout/grid.mdx) for more information. + +## Row Alignment + +By default, columns will stretch to fill the entire height of the row and wrap when necessary. Rows are [flex containers](https://developer.mozilla.org/en-US/docs/Glossary/Flex_Container), so there are several [CSS classes](../layout/css-utilities.mdx#flex-container-properties) that can be applied to a row to customize this behavior. + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/searchbar.md b/versioned_docs/version-v5/api/searchbar.md deleted file mode 100644 index c6ec518ade0..00000000000 --- a/versioned_docs/version-v5/api/searchbar.md +++ /dev/null @@ -1,390 +0,0 @@ ---- -title: 'Search Bar Icon for Keyboard Text Display | Ion-Search Bar' -description: 'Search bars represent a text field that can be used to search through a collection. Learn to input Ion-Search Bar as an icon on Android & iOS keyboard displays.' -sidebar_label: 'ion-searchbar' -demoUrl: '/docs/demos/api/searchbar/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/searchbar/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/searchbar/props.md'; -import Events from '@ionic-internal/component-api/v5/searchbar/events.md'; -import Methods from '@ionic-internal/component-api/v5/searchbar/methods.md'; -import Parts from '@ionic-internal/component-api/v5/searchbar/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/searchbar/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/searchbar/slots.md'; - -# ion-searchbar - -Searchbars represent a text field that can be used to search through a collection. They can be displayed inside of a toolbar or the main content. - -A Searchbar should be used instead of an input to search lists. A clear button is displayed upon entering input in the searchbar's text field. Clicking on the clear button will erase the text field and the input will remain focused. A cancel button can be enabled which will clear the input and lose the focus upon click. - -## Keyboard Display - -### Android - -By default, tapping the input will cause the keyboard to appear with a magnifying glass icon on the submit button. You can optionally set the `inputmode` property to `"search"`, which will change the icon from a magnifying glass to a carriage return. - -### iOS - -By default, tapping the input will cause the keyboard to appear with the text "return" on a gray submit button. You can optionally set the `inputmode` property to `"search"`, which will change the text from "return" to "go", and change the button color from gray to blue. Alternatively, you can wrap the `ion-searchbar` in a `form` element with an `action` property. This will cause the keyboard to appear with a blue submit button that says "search". - -## Usage - - - - - -```html - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - - - - - -```html - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - - - - - -```tsx -import React, { useState } from 'react'; -import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonSearchbar, IonFooter } from '@ionic/react'; - -export const SearchBarExamples: React.FC = () => { - const [searchText, setSearchText] = useState(''); - return ( - - - - IonSearchBar Examples - - - -

Default Searchbar

- setSearchText(e.detail.value!)}> - -

Searchbar with cancel button always shown

- setSearchText(e.detail.value!)} - showCancelButton="always" - > - -

Searchbar with cancel button never shown

- setSearchText(e.detail.value!)} - showCancelButton="never" - > - -

Searchbar with cancel button shown on focus

- setSearchText(e.detail.value!)} - showCancelButton="focus" - > - -

Searchbar with danger color

- setSearchText(e.detail.value!)} - color="danger" - > - -

Searchbar with telephone type

- setSearchText(e.detail.value!)} type="tel"> - -

Searchbar with numeric inputmode

- setSearchText(e.detail.value!)} - inputmode="numeric" - > - -

Searchbar disabled

- setSearchText(e.detail.value!)} - disabled={true} - > - -

Searchbar with a cancel button and custom cancel button text

- setSearchText(e.detail.value!)} - showCancelButton="focus" - cancelButtonText="Custom Cancel" - > - -

Searchbar with a custom debounce - Note: debounce only works on onIonChange event

- setSearchText(e.detail.value!)} - debounce={1000} - > - -

Animated Searchbar

- setSearchText(e.detail.value!)} animated> - -

Searchbar with a placeholder

- setSearchText(e.detail.value!)} - placeholder="Filter Schedules" - > - -

Searchbar in a Toolbar

- - setSearchText(e.detail.value!)}> - -
- - Search Text: {searchText ?? '(none)'} - -
- ); -}; -``` - -
- - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'searchbar-example', - styleUrl: 'searchbar-example.css', -}) -export class SearchbarExample { - render() { - return [ - // Default Searchbar - , - - // Searchbar with cancel button always shown - , - - // Searchbar with cancel button never shown - , - - // Searchbar with cancel button shown on focus - , - - // Searchbar with danger color - , - - // Searchbar with value - , - - // Searchbar with telephone type - , - - // Searchbar with numeric inputmode - , - - // Searchbar disabled - , - - // Searchbar with a cancel button and custom cancel button text - , - - // Searchbar with a custom debounce - , - - // Animated Searchbar - , - - // Searchbar with a placeholder - , - - // Searchbar in a Toolbar - - - , - ]; - } -} -``` - - - - - -```html - - - -``` - - - -
- -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/searchbar.mdx b/versioned_docs/version-v5/api/searchbar.mdx new file mode 100644 index 00000000000..2cf0a6c7f7f --- /dev/null +++ b/versioned_docs/version-v5/api/searchbar.mdx @@ -0,0 +1,390 @@ +--- +title: 'Search Bar Icon for Keyboard Text Display | Ion-Search Bar' +description: 'Search bars represent a text field that can be used to search through a collection. Learn to input Ion-Search Bar as an icon on Android & iOS keyboard displays.' +sidebar_label: 'ion-searchbar' +demoUrl: '/docs/demos/api/searchbar/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/searchbar/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/searchbar/props.mdx'; +import Events from '@ionic-internal/component-api/v5/searchbar/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/searchbar/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/searchbar/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/searchbar/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/searchbar/slots.mdx'; + +# ion-searchbar + +Searchbars represent a text field that can be used to search through a collection. They can be displayed inside of a toolbar or the main content. + +A Searchbar should be used instead of an input to search lists. A clear button is displayed upon entering input in the searchbar's text field. Clicking on the clear button will erase the text field and the input will remain focused. A cancel button can be enabled which will clear the input and lose the focus upon click. + +## Keyboard Display + +### Android + +By default, tapping the input will cause the keyboard to appear with a magnifying glass icon on the submit button. You can optionally set the `inputmode` property to `"search"`, which will change the icon from a magnifying glass to a carriage return. + +### iOS + +By default, tapping the input will cause the keyboard to appear with the text "return" on a gray submit button. You can optionally set the `inputmode` property to `"search"`, which will change the text from "return" to "go", and change the button color from gray to blue. Alternatively, you can wrap the `ion-searchbar` in a `form` element with an `action` property. This will cause the keyboard to appear with a blue submit button that says "search". + +## Usage + + + + + +```html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + + + + + +```html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + + + + + +```tsx +import React, { useState } from 'react'; +import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonSearchbar, IonFooter } from '@ionic/react'; + +export const SearchBarExamples: React.FC = () => { + const [searchText, setSearchText] = useState(''); + return ( + + + + IonSearchBar Examples + + + +

Default Searchbar

+ setSearchText(e.detail.value!)}> + +

Searchbar with cancel button always shown

+ setSearchText(e.detail.value!)} + showCancelButton="always" + > + +

Searchbar with cancel button never shown

+ setSearchText(e.detail.value!)} + showCancelButton="never" + > + +

Searchbar with cancel button shown on focus

+ setSearchText(e.detail.value!)} + showCancelButton="focus" + > + +

Searchbar with danger color

+ setSearchText(e.detail.value!)} + color="danger" + > + +

Searchbar with telephone type

+ setSearchText(e.detail.value!)} type="tel"> + +

Searchbar with numeric inputmode

+ setSearchText(e.detail.value!)} + inputmode="numeric" + > + +

Searchbar disabled

+ setSearchText(e.detail.value!)} + disabled={true} + > + +

Searchbar with a cancel button and custom cancel button text

+ setSearchText(e.detail.value!)} + showCancelButton="focus" + cancelButtonText="Custom Cancel" + > + +

Searchbar with a custom debounce - Note: debounce only works on onIonChange event

+ setSearchText(e.detail.value!)} + debounce={1000} + > + +

Animated Searchbar

+ setSearchText(e.detail.value!)} animated> + +

Searchbar with a placeholder

+ setSearchText(e.detail.value!)} + placeholder="Filter Schedules" + > + +

Searchbar in a Toolbar

+ + setSearchText(e.detail.value!)}> + +
+ + Search Text: {searchText ?? '(none)'} + +
+ ); +}; +``` + +
+ + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'searchbar-example', + styleUrl: 'searchbar-example.css', +}) +export class SearchbarExample { + render() { + return [ + // Default Searchbar + , + + // Searchbar with cancel button always shown + , + + // Searchbar with cancel button never shown + , + + // Searchbar with cancel button shown on focus + , + + // Searchbar with danger color + , + + // Searchbar with value + , + + // Searchbar with telephone type + , + + // Searchbar with numeric inputmode + , + + // Searchbar disabled + , + + // Searchbar with a cancel button and custom cancel button text + , + + // Searchbar with a custom debounce + , + + // Animated Searchbar + , + + // Searchbar with a placeholder + , + + // Searchbar in a Toolbar + + + , + ]; + } +} +``` + + + + + +```html + + + +``` + + + +
+ +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/segment-button.md b/versioned_docs/version-v5/api/segment-button.md deleted file mode 100644 index 9f028812e04..00000000000 --- a/versioned_docs/version-v5/api/segment-button.md +++ /dev/null @@ -1,849 +0,0 @@ ---- -sidebar_label: 'ion-segment-button' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/segment-button/props.md'; -import Events from '@ionic-internal/component-api/v5/segment-button/events.md'; -import Methods from '@ionic-internal/component-api/v5/segment-button/methods.md'; -import Parts from '@ionic-internal/component-api/v5/segment-button/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/segment-button/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/segment-button/slots.md'; - -# ion-segment-button - -Segment buttons are groups of related buttons inside of a [Segment](segment.md). They are displayed in a horizontal row. A segment button can be checked by default by setting the `value` of the segment to the `value` of the segment button. Only one segment button can be selected at a time. - -## Usage - - - - - -```html - - - - Friends - - - Enemies - - - - - - - Paid - - - Free - - - Top - - - - - - - - - - - - - - - - - Bookmarks - - - Reading List - - - Shared Links - - - - - - - Item One - - - Item Two - - - Item Three - - - - - - - - - - - - - - - - - - - - Item One - - - - Item Two - - - - Item Three - - - - - - - - - Item One - - - - Item Two - - - - Item Three - - - - - - - Item One - - - - Item Two - - - - Item Three - - - - - - - - - Item One - - - - Item Two - - - - Item Three - - -``` - -```tsx -import { Component } from '@angular/core'; - -@Component({ - selector: 'segment-button-example', - templateUrl: 'segment-button-example.html', - styleUrls: ['./segment-button-example.css'], -}) -export class SegmentButtonExample { - segmentChanged(ev: any) { - console.log('Segment changed', ev); - } -} -``` - - - - - -```html - - - - Friends - - - Enemies - - - - - - - Paid - - - Free - - - Top - - - - - - - - - - - - - - - - - Bookmarks - - - Reading List - - - Shared Links - - - - - - - Item One - - - Item Two - - - Item Three - - - - - - - - - - - - - - - - - - - - Item One - - - - Item Two - - - - Item Three - - - - - - - - - Item One - - - - Item Two - - - - Item Three - - - - - - - Item One - - - - Item Two - - - - Item Three - - - - - - - - - Item One - - - - Item Two - - - - Item Three - - -``` - -```javascript -// Listen for ionChange on segment -const segment = document.querySelector('ion-segment'); -segment.addEventListener('ionChange', (ev) => { - console.log('Segment changed', ev); -}); -``` - - - - - -```tsx -import React from 'react'; -import { - IonContent, - IonHeader, - IonPage, - IonTitle, - IonToolbar, - IonSegment, - IonSegmentButton, - IonLabel, - IonIcon, -} from '@ionic/react'; -import { call, camera, bookmark, heart, pin } from 'ionicons/icons'; - -export const SegmentButtonExamples: React.FC = () => { - return ( - - - - SegmentButton - - - - {/*-- Segment buttons with text and click listener --*/} - console.log(`${e.detail.value} segment selected`)}> - - Friends - - - Enemies - - - - {/*-- Segment buttons with the first checked and the last disabled --*/} - - - Paid - - - Free - - - Top - - - - {/*-- Segment buttons with values and icons --*/} - - - - - - - - - - {/*-- Segment with a value that checks the last button --*/} - - - Bookmarks - - - Reading List - - - Shared Links - - - - {/*-- Label only --*/} - - - Item One - - - Item Two - - - Item Three - - - - {/*-- Icon only --*/} - - - - - - - - - - - - - {/*-- Icon top --*/} - - - Item One - - - - Item Two - - - - Item Three - - - - - {/*-- Icon bottom --*/} - - - - Item One - - - - Item Two - - - - Item Three - - - - {/*-- Icon start --*/} - - - Item One - - - - Item Two - - - - Item Three - - - - - {/*-- Icon end --*/} - - - - Item One - - - - Item Two - - - - Item Three - - - - - ); -}; -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'segment-button-example', - styleUrl: 'segment-button-example.css', -}) -export class SegmentButtonExample { - segmentChanged(ev: any) { - console.log('Segment changed', ev); - } - - render() { - return [ - // Segment buttons with text and click listener - this.segmentChanged(ev)}> - - Friends - - - Enemies - - , - - // Segment buttons with the first checked and the last disabled - - - Paid - - - Free - - - Top - - , - - // Segment buttons with values and icons - - - - - - - - , - - // Segment with a value that checks the last button - - - Bookmarks - - - Reading List - - - Shared Links - - , - - // Label only - - - Item One - - - Item Two - - - Item Three - - , - - // Icon only - - - - - - - - - - - , - - // Icon top - - - Item One - - - - Item Two - - - - Item Three - - - , - - // Icon bottom - - - - Item One - - - - Item Two - - - - Item Three - - , - - // Icon start - - - Item One - - - - Item Two - - - - Item Three - - - , - - // Icon end - - - - Item One - - - - Item Two - - - - Item Three - - , - ]; - } -} -``` - - - - - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/segment-button.mdx b/versioned_docs/version-v5/api/segment-button.mdx new file mode 100644 index 00000000000..fa857f32b6d --- /dev/null +++ b/versioned_docs/version-v5/api/segment-button.mdx @@ -0,0 +1,849 @@ +--- +sidebar_label: 'ion-segment-button' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/segment-button/props.mdx'; +import Events from '@ionic-internal/component-api/v5/segment-button/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/segment-button/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/segment-button/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/segment-button/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/segment-button/slots.mdx'; + +# ion-segment-button + +Segment buttons are groups of related buttons inside of a [Segment](segment.mdx). They are displayed in a horizontal row. A segment button can be checked by default by setting the `value` of the segment to the `value` of the segment button. Only one segment button can be selected at a time. + +## Usage + + + + + +```html + + + + Friends + + + Enemies + + + + + + + Paid + + + Free + + + Top + + + + + + + + + + + + + + + + + Bookmarks + + + Reading List + + + Shared Links + + + + + + + Item One + + + Item Two + + + Item Three + + + + + + + + + + + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + +``` + +```tsx +import { Component } from '@angular/core'; + +@Component({ + selector: 'segment-button-example', + templateUrl: 'segment-button-example.html', + styleUrls: ['./segment-button-example.css'], +}) +export class SegmentButtonExample { + segmentChanged(ev: any) { + console.log('Segment changed', ev); + } +} +``` + + + + + +```html + + + + Friends + + + Enemies + + + + + + + Paid + + + Free + + + Top + + + + + + + + + + + + + + + + + Bookmarks + + + Reading List + + + Shared Links + + + + + + + Item One + + + Item Two + + + Item Three + + + + + + + + + + + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + +``` + +```javascript +// Listen for ionChange on segment +const segment = document.querySelector('ion-segment'); +segment.addEventListener('ionChange', (ev) => { + console.log('Segment changed', ev); +}); +``` + + + + + +```tsx +import React from 'react'; +import { + IonContent, + IonHeader, + IonPage, + IonTitle, + IonToolbar, + IonSegment, + IonSegmentButton, + IonLabel, + IonIcon, +} from '@ionic/react'; +import { call, camera, bookmark, heart, pin } from 'ionicons/icons'; + +export const SegmentButtonExamples: React.FC = () => { + return ( + + + + SegmentButton + + + + {/*-- Segment buttons with text and click listener --*/} + console.log(`${e.detail.value} segment selected`)}> + + Friends + + + Enemies + + + + {/*-- Segment buttons with the first checked and the last disabled --*/} + + + Paid + + + Free + + + Top + + + + {/*-- Segment buttons with values and icons --*/} + + + + + + + + + + {/*-- Segment with a value that checks the last button --*/} + + + Bookmarks + + + Reading List + + + Shared Links + + + + {/*-- Label only --*/} + + + Item One + + + Item Two + + + Item Three + + + + {/*-- Icon only --*/} + + + + + + + + + + + + + {/*-- Icon top --*/} + + + Item One + + + + Item Two + + + + Item Three + + + + + {/*-- Icon bottom --*/} + + + + Item One + + + + Item Two + + + + Item Three + + + + {/*-- Icon start --*/} + + + Item One + + + + Item Two + + + + Item Three + + + + + {/*-- Icon end --*/} + + + + Item One + + + + Item Two + + + + Item Three + + + + + ); +}; +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'segment-button-example', + styleUrl: 'segment-button-example.css', +}) +export class SegmentButtonExample { + segmentChanged(ev: any) { + console.log('Segment changed', ev); + } + + render() { + return [ + // Segment buttons with text and click listener + this.segmentChanged(ev)}> + + Friends + + + Enemies + + , + + // Segment buttons with the first checked and the last disabled + + + Paid + + + Free + + + Top + + , + + // Segment buttons with values and icons + + + + + + + + , + + // Segment with a value that checks the last button + + + Bookmarks + + + Reading List + + + Shared Links + + , + + // Label only + + + Item One + + + Item Two + + + Item Three + + , + + // Icon only + + + + + + + + + + + , + + // Icon top + + + Item One + + + + Item Two + + + + Item Three + + + , + + // Icon bottom + + + + Item One + + + + Item Two + + + + Item Three + + , + + // Icon start + + + Item One + + + + Item Two + + + + Item Three + + + , + + // Icon end + + + + Item One + + + + Item Two + + + + Item Three + + , + ]; + } +} +``` + + + + + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/segment.md b/versioned_docs/version-v5/api/segment.md deleted file mode 100644 index 62768f8c02d..00000000000 --- a/versioned_docs/version-v5/api/segment.md +++ /dev/null @@ -1,619 +0,0 @@ ---- -sidebar_label: 'ion-segment' -demoUrl: '/docs/demos/api/segment/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/segment/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/segment/props.md'; -import Events from '@ionic-internal/component-api/v5/segment/events.md'; -import Methods from '@ionic-internal/component-api/v5/segment/methods.md'; -import Parts from '@ionic-internal/component-api/v5/segment/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/segment/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/segment/slots.md'; - -# ion-segment - -Segments display a group of related buttons, sometimes known as segmented controls, in a horizontal row. They can be displayed inside of a toolbar or the main content. - -Their functionality is similar to tabs, where selecting one will deselect all others. Segments are useful for toggling between different views inside of the content. Tabs should be used instead of a segment when clicking on a control should navigate between pages. - -## Scrollable Segments - -Segments are not scrollable by default. Each segment button has a fixed width, and the width is determined by dividing the number of segment buttons by the screen width. This ensures that each segment button can be displayed on the screen without having to scroll. As a result, some segment buttons with longer labels may get cut off. To avoid this we recommend either using a shorter label or switching to a scrollable segment by setting the `scrollable` property to `true`. This will cause the segment to scroll horizontally, but will allow each segment button to have a variable width. - -## Usage - - - - - -```html - - - - Friends - - - Enemies - - - - - - - Sunny - - - Rainy - - - - - - - Dogs - - - Cats - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Standard - - - Hybrid - - - Satellite - - - - - - - - - - - - - - - - - - - Python - - - Javascript - - -``` - -```tsx -import { Component } from '@angular/core'; - -@Component({ - selector: 'segment-example', - templateUrl: 'segment-example.html', - styleUrls: ['./segment-example.css'], -}) -export class SegmentExample { - segmentChanged(ev: any) { - console.log('Segment changed', ev); - } -} -``` - - - - - -```html - - - - Friends - - - Enemies - - - - - - - Sunny - - - Rainy - - - - - - - Dogs - - - Cats - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Standard - - - Hybrid - - - Satellite - - - - - - - - - - - - - - - - - - - Python - - - Javascript - - -``` - -```javascript -// Listen for ionChange on all segments -const segments = document.querySelectorAll('ion-segment'); -for (let i = 0; i < segments.length; i++) { - segments[i].addEventListener('ionChange', (ev) => { - console.log('Segment changed', ev); - }); -} -``` - - - - - -```tsx -import React from 'react'; -import { - IonContent, - IonHeader, - IonPage, - IonTitle, - IonToolbar, - IonSegment, - IonSegmentButton, - IonLabel, - IonIcon, -} from '@ionic/react'; -import { call, home, heart, pin, star, globe, basket, camera, bookmark } from 'ionicons/icons'; - -export const SegmentExamples: React.FC = () => { - return ( - - - - SegmentExamples - - - - {/*-- Default Segment --*/} - console.log('Segment selected', e.detail.value)}> - - Friends - - - Enemies - - - - {/*-- Disabled Segment --*/} - console.log('Segment selected', e.detail.value)} disabled value="sunny"> - - Sunny - - - Rainy - - - - {/*-- Segment with anchors --*/} - console.log('Segment selected', e.detail.value)}> - - Dogs - - - Cats - - - - {/*-- Scrollable Segment --*/} - - - - - - - - - - - - - - - - - - - - - - - - - {/*-- Segment with secondary color --*/} - console.log('Segment selected', e.detail.value)} color="secondary"> - - Standard - - - Hybrid - - - Satellite - - - - {/*-- Segment in a toolbar --*/} - - console.log('Segment selected', e.detail.value)}> - - - - - - - - - - {/*-- Segment with default selection --*/} - console.log('Segment selected', e.detail.value)} value="javascript"> - - Python - - - Javascript - - - - - ); -}; -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'segment-example', - styleUrl: 'segment-example.css', -}) -export class SegmentExample { - segmentChanged(ev: any) { - console.log('Segment changed', ev); - } - - render() { - return [ - // Default Segment - this.segmentChanged(ev)}> - - Friends - - - Enemies - - , - - // Disabled Segment - this.segmentChanged(ev)} disabled={true} value="sunny"> - - Sunny - - - Rainy - - , - - // Segment with anchors - this.segmentChanged(ev)}> - - Dogs - - - Cats - - , - - // Scrollable Segment - - - - - - - - - - - - - - - - - - - - - - - , - - // Segment with secondary color - this.segmentChanged(ev)} color="secondary"> - - Standard - - - Hybrid - - - Satellite - - , - - // Segment in a toolbar - - this.segmentChanged(ev)}> - - - - - - - - , - - // Segment with default selection - this.segmentChanged(ev)} value="javascript"> - - Python - - - Javascript - - , - ]; - } -} -``` - - - - - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/segment.mdx b/versioned_docs/version-v5/api/segment.mdx new file mode 100644 index 00000000000..15c2121357e --- /dev/null +++ b/versioned_docs/version-v5/api/segment.mdx @@ -0,0 +1,619 @@ +--- +sidebar_label: 'ion-segment' +demoUrl: '/docs/demos/api/segment/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/segment/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/segment/props.mdx'; +import Events from '@ionic-internal/component-api/v5/segment/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/segment/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/segment/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/segment/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/segment/slots.mdx'; + +# ion-segment + +Segments display a group of related buttons, sometimes known as segmented controls, in a horizontal row. They can be displayed inside of a toolbar or the main content. + +Their functionality is similar to tabs, where selecting one will deselect all others. Segments are useful for toggling between different views inside of the content. Tabs should be used instead of a segment when clicking on a control should navigate between pages. + +## Scrollable Segments + +Segments are not scrollable by default. Each segment button has a fixed width, and the width is determined by dividing the number of segment buttons by the screen width. This ensures that each segment button can be displayed on the screen without having to scroll. As a result, some segment buttons with longer labels may get cut off. To avoid this we recommend either using a shorter label or switching to a scrollable segment by setting the `scrollable` property to `true`. This will cause the segment to scroll horizontally, but will allow each segment button to have a variable width. + +## Usage + + + + + +```html + + + + Friends + + + Enemies + + + + + + + Sunny + + + Rainy + + + + + + + Dogs + + + Cats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Standard + + + Hybrid + + + Satellite + + + + + + + + + + + + + + + + + + + Python + + + Javascript + + +``` + +```tsx +import { Component } from '@angular/core'; + +@Component({ + selector: 'segment-example', + templateUrl: 'segment-example.html', + styleUrls: ['./segment-example.css'], +}) +export class SegmentExample { + segmentChanged(ev: any) { + console.log('Segment changed', ev); + } +} +``` + + + + + +```html + + + + Friends + + + Enemies + + + + + + + Sunny + + + Rainy + + + + + + + Dogs + + + Cats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Standard + + + Hybrid + + + Satellite + + + + + + + + + + + + + + + + + + + Python + + + Javascript + + +``` + +```javascript +// Listen for ionChange on all segments +const segments = document.querySelectorAll('ion-segment'); +for (let i = 0; i < segments.length; i++) { + segments[i].addEventListener('ionChange', (ev) => { + console.log('Segment changed', ev); + }); +} +``` + + + + + +```tsx +import React from 'react'; +import { + IonContent, + IonHeader, + IonPage, + IonTitle, + IonToolbar, + IonSegment, + IonSegmentButton, + IonLabel, + IonIcon, +} from '@ionic/react'; +import { call, home, heart, pin, star, globe, basket, camera, bookmark } from 'ionicons/icons'; + +export const SegmentExamples: React.FC = () => { + return ( + + + + SegmentExamples + + + + {/*-- Default Segment --*/} + console.log('Segment selected', e.detail.value)}> + + Friends + + + Enemies + + + + {/*-- Disabled Segment --*/} + console.log('Segment selected', e.detail.value)} disabled value="sunny"> + + Sunny + + + Rainy + + + + {/*-- Segment with anchors --*/} + console.log('Segment selected', e.detail.value)}> + + Dogs + + + Cats + + + + {/*-- Scrollable Segment --*/} + + + + + + + + + + + + + + + + + + + + + + + + + {/*-- Segment with secondary color --*/} + console.log('Segment selected', e.detail.value)} color="secondary"> + + Standard + + + Hybrid + + + Satellite + + + + {/*-- Segment in a toolbar --*/} + + console.log('Segment selected', e.detail.value)}> + + + + + + + + + + {/*-- Segment with default selection --*/} + console.log('Segment selected', e.detail.value)} value="javascript"> + + Python + + + Javascript + + + + + ); +}; +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'segment-example', + styleUrl: 'segment-example.css', +}) +export class SegmentExample { + segmentChanged(ev: any) { + console.log('Segment changed', ev); + } + + render() { + return [ + // Default Segment + this.segmentChanged(ev)}> + + Friends + + + Enemies + + , + + // Disabled Segment + this.segmentChanged(ev)} disabled={true} value="sunny"> + + Sunny + + + Rainy + + , + + // Segment with anchors + this.segmentChanged(ev)}> + + Dogs + + + Cats + + , + + // Scrollable Segment + + + + + + + + + + + + + + + + + + + + + + + , + + // Segment with secondary color + this.segmentChanged(ev)} color="secondary"> + + Standard + + + Hybrid + + + Satellite + + , + + // Segment in a toolbar + + this.segmentChanged(ev)}> + + + + + + + + , + + // Segment with default selection + this.segmentChanged(ev)} value="javascript"> + + Python + + + Javascript + + , + ]; + } +} +``` + + + + + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/select-option.md b/versioned_docs/version-v5/api/select-option.md deleted file mode 100644 index 1b52d1a6811..00000000000 --- a/versioned_docs/version-v5/api/select-option.md +++ /dev/null @@ -1,716 +0,0 @@ ---- -title: 'Select Option | What Is An Option Select on Ionic Framework Apps' -description: 'What is an option select? Select Options are child element components of a Select—each option defined is passed and displayed in the Select dialog.' -sidebar_label: 'ion-select-option' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/select-option/props.md'; -import Events from '@ionic-internal/component-api/v5/select-option/events.md'; -import Methods from '@ionic-internal/component-api/v5/select-option/methods.md'; -import Parts from '@ionic-internal/component-api/v5/select-option/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/select-option/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/select-option/slots.md'; - -# ion-select-option - -Select Options are components that are child elements of a Select. Each option defined is passed and displayed in the Select dialog. For more information, see the [Select docs](select.md). - -## Customization - -Each `ion-select-option` component that is added as a child of an `ion-select` is passed to the interface to display it in the dialog. It's important to note that the `ion-select-option` element itself is hidden from the view. This means that attempting to style it will not have any effect on the option in the dialog: - -```css -/* DOES NOT work */ -ion-select-option { - color: red; -} -``` - -Instead, each interface option has the class `.select-interface-option` which can be styled. Keep in mind that due to the overlays being scoped components the selector by itself will not work and a custom `cssClass` is recommended to be passed to the interface. - -```css -/* This will NOT work on its own */ -.select-interface-option { - color: red; -} - -/* - * "my-custom-interface" needs to be passed in through - * the cssClass of the interface options for this to work - */ -.my-custom-interface .select-interface-option { - color: red; -} -``` - -> Note: Some interfaces require more in depth styling due to how the options are rendered. See usage for expanded information on this. - -The options can be styled individually by adding your own class on the `ion-select-option` which gets passed to the interface option. See the [Usage](#usage) section below for examples of styling and setting individual classes on options. - -## Usage - - - - - -```html - - Select - - Brown - Blonde - Black - Red - - -``` - -### Customizing Options - -```html - - Select: Alert Interface - - Brown - Blonde - Black - Red - - - - - Select: Alert Interface (Multiple Selection) - - Brown - Blonde - Black - Red - - - - - Select: Popover Interface - - Brown - Blonde - Black - Red - - - - - Select: Action Sheet Interface - - Brown - Blonde - Black - Red - - -``` - -```css -/* Popover Interface: set color for the popover using Item's CSS variables */ -.my-custom-interface .select-interface-option { - --color: #971e49; - --color-hover: #79193b; -} - -/* Action Sheet Interface: set color for the action sheet using its button CSS variables */ -.my-custom-interface .select-interface-option { - --button-color: #971e49; - --button-color-hover: #79193b; -} - -/* Alert Interface: set color for alert options (single selection) */ -.my-custom-interface .select-interface-option .alert-radio-label { - color: #971e49; -} - -/* Alert Interface: set color for alert options (multiple selection) */ -.my-custom-interface .select-interface-option .alert-checkbox-label { - color: #971e49; -} - -/* Alert Interface: set color for checked alert options (single selection) */ -.my-custom-interface .select-interface-option[aria-checked='true'] .alert-radio-label { - color: #79193b; -} - -/* Alert Interface: set color for checked alert options (multiple selection) */ -.my-custom-interface .select-interface-option[aria-checked='true'] .alert-checkbox-label { - color: #79193b; -} -``` - -```javascript -// Pass a custom class to each select interface for styling -const selects = document.querySelectorAll('.custom-options'); - -for (var i = 0; i < selects.length; i++) { - selects[i].interfaceOptions = { - cssClass: 'my-custom-interface', - }; -} -``` - -> Note: In the CSS examples, some of the selectors could be combined together, but are separated out in order to better explain what each selector is for. - -### Customizing Individual Options - -To customize an individual option, set a class on the `ion-select-option`: - -```html - - Select - - Brown - Blonde - Black - Red - - -``` - -```css -/* Popover Interface: set color for the popover using Item's CSS variables */ -.my-custom-interface .brown-option { - --color: #5e3e2c; - --color-hover: #362419; -} -``` - -```javascript -// Pass a custom class to each select interface for styling -const select = document.querySelector('.custom-options'); -select.interfaceOptions = { - cssClass: 'my-custom-interface', -}; -``` - - - - - -```tsx -import React from 'react'; -import { IonContent, IonItem, IonLabel, IonSelect, IonSelectOption, IonPage } from '@ionic/react'; - -export const SelectOptionExample: React.FC = () => { - return ( - - - - Select - - Brown - Blonde - Black - Red - - - - - ); -}; -``` - -### Customizing Options - -```tsx -import React from 'react'; -import { IonContent, IonItem, IonLabel, IonSelect, IonSelectOption, IonPage } from '@ionic/react'; - -const options = { - cssClass: 'my-custom-interface', -}; - -export const SelectOptionExample: React.FC = () => { - return ( - - - - Select: Alert Interface - - Brown - Blonde - Black - Red - - - - - Select: Alert Interface (Multiple Selection) - - Brown - Blonde - Black - Red - - - - - Select: Popover Interface - - Brown - Blonde - Black - Red - - - - - Select: Action Sheet Interface - - Brown - Blonde - Black - Red - - - - - ); -}; -``` - -```css -/* Popover Interface: set color for the popover using Item's CSS variables */ -.my-custom-interface .select-interface-option { - --color: #971e49; - --color-hover: #79193b; -} - -/* Action Sheet Interface: set color for the action sheet using its button CSS variables */ -.my-custom-interface .select-interface-option { - --button-color: #971e49; - --button-color-hover: #79193b; -} - -/* Alert Interface: set color for alert options (single selection) */ -.my-custom-interface .select-interface-option .alert-radio-label { - color: #971e49; -} - -/* Alert Interface: set color for alert options (multiple selection) */ -.my-custom-interface .select-interface-option .alert-checkbox-label { - color: #971e49; -} - -/* Alert Interface: set color for checked alert options (single selection) */ -.my-custom-interface .select-interface-option[aria-checked='true'] .alert-radio-label { - color: #79193b; -} - -/* Alert Interface: set color for checked alert options (multiple selection) */ -.my-custom-interface .select-interface-option[aria-checked='true'] .alert-checkbox-label { - color: #79193b; -} -``` - -> Note: In the CSS examples, some of the selectors could be combined together, but are separated out in order to better explain what each selector is for. - -### Customizing Individual Options - -To customize an individual option, set a class on the `ion-select-option`: - -```tsx -import React from 'react'; -import { IonContent, IonItem, IonLabel, IonSelect, IonSelectOption, IonPage } from '@ionic/react'; - -const options = { - cssClass: 'my-custom-interface', -}; - -export const SelectOptionExample: React.FC = () => { - return ( - - - - Select - - - Brown - - Blonde - Black - Red - - - - - ); -}; -``` - -```css -/* Popover Interface: set color for the popover using Item's CSS variables */ -.my-custom-interface .brown-option { - --color: #5e3e2c; - --color-hover: #362419; -} -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'select-option-example', - styleUrl: 'select-option-example.css', -}) -export class SelectOptionExample { - render() { - return [ - - Select - - Brown - Blonde - Black - Red - - , - ]; - } -} -``` - -### Customizing Options - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'select-option-example', - styleUrl: 'select-option-example.css', -}) -export class SelectOptionExample { - options = { - cssClass: 'my-custom-interface', - }; - - render() { - return [ - - Select: Alert Interface - - Brown - Blonde - Black - Red - - , - - - Select: Alert Interface (Multiple Selection) - - Brown - Blonde - Black - Red - - , - - - Select: Popover Interface - - Brown - Blonde - Black - Red - - , - - - Select: Action Sheet Interface - - Brown - Blonde - Black - Red - - , - ]; - } -} -``` - -```css -/* Popover Interface: set color for the popover using Item's CSS variables */ -.my-custom-interface .select-interface-option { - --color: #971e49; - --color-hover: #79193b; -} - -/* Action Sheet Interface: set color for the action sheet using its button CSS variables */ -.my-custom-interface .select-interface-option { - --button-color: #971e49; - --button-color-hover: #79193b; -} - -/* Alert Interface: set color for alert options (single selection) */ -.my-custom-interface .select-interface-option .alert-radio-label { - color: #971e49; -} - -/* Alert Interface: set color for alert options (multiple selection) */ -.my-custom-interface .select-interface-option .alert-checkbox-label { - color: #971e49; -} - -/* Alert Interface: set color for checked alert options (single selection) */ -.my-custom-interface .select-interface-option[aria-checked='true'] .alert-radio-label { - color: #79193b; -} - -/* Alert Interface: set color for checked alert options (multiple selection) */ -.my-custom-interface .select-interface-option[aria-checked='true'] .alert-checkbox-label { - color: #79193b; -} -``` - -> Note: In the CSS examples, some of the selectors could be combined together, but are separated out in order to better explain what each selector is for. - -### Customizing Individual Options - -To customize an individual option, set a class on the `ion-select-option`: - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'select-option-example', - styleUrl: 'select-option-example.css', -}) -export class SelectOptionExample { - options = { - cssClass: 'my-custom-interface', - }; - - render() { - return [ - - Select - - - Brown - - Blonde - Black - Red - - , - ]; - } -} -``` - -```css -/* Popover Interface: set color for the popover using Item's CSS variables */ -.my-custom-interface .brown-option { - --color: #5e3e2c; - --color-hover: #362419; -} -``` - - - - - -```html - - - -``` - -### Customizing Options - -```html - - - -``` - -```css -/* Popover Interface: set color for the popover using Item's CSS variables */ -.my-custom-interface .select-interface-option { - --color: #971e49; - --color-hover: #79193b; -} - -/* Action Sheet Interface: set color for the action sheet using its button CSS variables */ -.my-custom-interface .select-interface-option { - --button-color: #971e49; - --button-color-hover: #79193b; -} - -/* Alert Interface: set color for alert options (single selection) */ -.my-custom-interface .select-interface-option .alert-radio-label { - color: #971e49; -} - -/* Alert Interface: set color for alert options (multiple selection) */ -.my-custom-interface .select-interface-option .alert-checkbox-label { - color: #971e49; -} - -/* Alert Interface: set color for checked alert options (single selection) */ -.my-custom-interface .select-interface-option[aria-checked='true'] .alert-radio-label { - color: #79193b; -} - -/* Alert Interface: set color for checked alert options (multiple selection) */ -.my-custom-interface .select-interface-option[aria-checked='true'] .alert-checkbox-label { - color: #79193b; -} -``` - -> Note: In the CSS examples, some of the selectors could be combined together, but are separated out in order to better explain what each selector is for. - -### Customizing Individual Options - -To customize an individual option, set a class on the `ion-select-option`: - -```html - - - -``` - -```css -/* Popover Interface: set color for the popover using Item's CSS variables */ -.my-custom-interface .brown-option { - --color: #5e3e2c; - --color-hover: #362419; -} -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/select-option.mdx b/versioned_docs/version-v5/api/select-option.mdx new file mode 100644 index 00000000000..1dae0c0d47a --- /dev/null +++ b/versioned_docs/version-v5/api/select-option.mdx @@ -0,0 +1,716 @@ +--- +title: 'Select Option | What Is An Option Select on Ionic Framework Apps' +description: 'What is an option select? Select Options are child element components of a Select—each option defined is passed and displayed in the Select dialog.' +sidebar_label: 'ion-select-option' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/select-option/props.mdx'; +import Events from '@ionic-internal/component-api/v5/select-option/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/select-option/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/select-option/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/select-option/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/select-option/slots.mdx'; + +# ion-select-option + +Select Options are components that are child elements of a Select. Each option defined is passed and displayed in the Select dialog. For more information, see the [Select docs](select.mdx). + +## Customization + +Each `ion-select-option` component that is added as a child of an `ion-select` is passed to the interface to display it in the dialog. It's important to note that the `ion-select-option` element itself is hidden from the view. This means that attempting to style it will not have any effect on the option in the dialog: + +```css +/* DOES NOT work */ +ion-select-option { + color: red; +} +``` + +Instead, each interface option has the class `.select-interface-option` which can be styled. Keep in mind that due to the overlays being scoped components the selector by itself will not work and a custom `cssClass` is recommended to be passed to the interface. + +```css +/* This will NOT work on its own */ +.select-interface-option { + color: red; +} + +/* + * "my-custom-interface" needs to be passed in through + * the cssClass of the interface options for this to work + */ +.my-custom-interface .select-interface-option { + color: red; +} +``` + +> Note: Some interfaces require more in depth styling due to how the options are rendered. See usage for expanded information on this. + +The options can be styled individually by adding your own class on the `ion-select-option` which gets passed to the interface option. See the [Usage](#usage) section below for examples of styling and setting individual classes on options. + +## Usage + + + + + +```html + + Select + + Brown + Blonde + Black + Red + + +``` + +### Customizing Options + +```html + + Select: Alert Interface + + Brown + Blonde + Black + Red + + + + + Select: Alert Interface (Multiple Selection) + + Brown + Blonde + Black + Red + + + + + Select: Popover Interface + + Brown + Blonde + Black + Red + + + + + Select: Action Sheet Interface + + Brown + Blonde + Black + Red + + +``` + +```css +/* Popover Interface: set color for the popover using Item's CSS variables */ +.my-custom-interface .select-interface-option { + --color: #971e49; + --color-hover: #79193b; +} + +/* Action Sheet Interface: set color for the action sheet using its button CSS variables */ +.my-custom-interface .select-interface-option { + --button-color: #971e49; + --button-color-hover: #79193b; +} + +/* Alert Interface: set color for alert options (single selection) */ +.my-custom-interface .select-interface-option .alert-radio-label { + color: #971e49; +} + +/* Alert Interface: set color for alert options (multiple selection) */ +.my-custom-interface .select-interface-option .alert-checkbox-label { + color: #971e49; +} + +/* Alert Interface: set color for checked alert options (single selection) */ +.my-custom-interface .select-interface-option[aria-checked='true'] .alert-radio-label { + color: #79193b; +} + +/* Alert Interface: set color for checked alert options (multiple selection) */ +.my-custom-interface .select-interface-option[aria-checked='true'] .alert-checkbox-label { + color: #79193b; +} +``` + +```javascript +// Pass a custom class to each select interface for styling +const selects = document.querySelectorAll('.custom-options'); + +for (var i = 0; i < selects.length; i++) { + selects[i].interfaceOptions = { + cssClass: 'my-custom-interface', + }; +} +``` + +> Note: In the CSS examples, some of the selectors could be combined together, but are separated out in order to better explain what each selector is for. + +### Customizing Individual Options + +To customize an individual option, set a class on the `ion-select-option`: + +```html + + Select + + Brown + Blonde + Black + Red + + +``` + +```css +/* Popover Interface: set color for the popover using Item's CSS variables */ +.my-custom-interface .brown-option { + --color: #5e3e2c; + --color-hover: #362419; +} +``` + +```javascript +// Pass a custom class to each select interface for styling +const select = document.querySelector('.custom-options'); +select.interfaceOptions = { + cssClass: 'my-custom-interface', +}; +``` + + + + + +```tsx +import React from 'react'; +import { IonContent, IonItem, IonLabel, IonSelect, IonSelectOption, IonPage } from '@ionic/react'; + +export const SelectOptionExample: React.FC = () => { + return ( + + + + Select + + Brown + Blonde + Black + Red + + + + + ); +}; +``` + +### Customizing Options + +```tsx +import React from 'react'; +import { IonContent, IonItem, IonLabel, IonSelect, IonSelectOption, IonPage } from '@ionic/react'; + +const options = { + cssClass: 'my-custom-interface', +}; + +export const SelectOptionExample: React.FC = () => { + return ( + + + + Select: Alert Interface + + Brown + Blonde + Black + Red + + + + + Select: Alert Interface (Multiple Selection) + + Brown + Blonde + Black + Red + + + + + Select: Popover Interface + + Brown + Blonde + Black + Red + + + + + Select: Action Sheet Interface + + Brown + Blonde + Black + Red + + + + + ); +}; +``` + +```css +/* Popover Interface: set color for the popover using Item's CSS variables */ +.my-custom-interface .select-interface-option { + --color: #971e49; + --color-hover: #79193b; +} + +/* Action Sheet Interface: set color for the action sheet using its button CSS variables */ +.my-custom-interface .select-interface-option { + --button-color: #971e49; + --button-color-hover: #79193b; +} + +/* Alert Interface: set color for alert options (single selection) */ +.my-custom-interface .select-interface-option .alert-radio-label { + color: #971e49; +} + +/* Alert Interface: set color for alert options (multiple selection) */ +.my-custom-interface .select-interface-option .alert-checkbox-label { + color: #971e49; +} + +/* Alert Interface: set color for checked alert options (single selection) */ +.my-custom-interface .select-interface-option[aria-checked='true'] .alert-radio-label { + color: #79193b; +} + +/* Alert Interface: set color for checked alert options (multiple selection) */ +.my-custom-interface .select-interface-option[aria-checked='true'] .alert-checkbox-label { + color: #79193b; +} +``` + +> Note: In the CSS examples, some of the selectors could be combined together, but are separated out in order to better explain what each selector is for. + +### Customizing Individual Options + +To customize an individual option, set a class on the `ion-select-option`: + +```tsx +import React from 'react'; +import { IonContent, IonItem, IonLabel, IonSelect, IonSelectOption, IonPage } from '@ionic/react'; + +const options = { + cssClass: 'my-custom-interface', +}; + +export const SelectOptionExample: React.FC = () => { + return ( + + + + Select + + + Brown + + Blonde + Black + Red + + + + + ); +}; +``` + +```css +/* Popover Interface: set color for the popover using Item's CSS variables */ +.my-custom-interface .brown-option { + --color: #5e3e2c; + --color-hover: #362419; +} +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'select-option-example', + styleUrl: 'select-option-example.css', +}) +export class SelectOptionExample { + render() { + return [ + + Select + + Brown + Blonde + Black + Red + + , + ]; + } +} +``` + +### Customizing Options + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'select-option-example', + styleUrl: 'select-option-example.css', +}) +export class SelectOptionExample { + options = { + cssClass: 'my-custom-interface', + }; + + render() { + return [ + + Select: Alert Interface + + Brown + Blonde + Black + Red + + , + + + Select: Alert Interface (Multiple Selection) + + Brown + Blonde + Black + Red + + , + + + Select: Popover Interface + + Brown + Blonde + Black + Red + + , + + + Select: Action Sheet Interface + + Brown + Blonde + Black + Red + + , + ]; + } +} +``` + +```css +/* Popover Interface: set color for the popover using Item's CSS variables */ +.my-custom-interface .select-interface-option { + --color: #971e49; + --color-hover: #79193b; +} + +/* Action Sheet Interface: set color for the action sheet using its button CSS variables */ +.my-custom-interface .select-interface-option { + --button-color: #971e49; + --button-color-hover: #79193b; +} + +/* Alert Interface: set color for alert options (single selection) */ +.my-custom-interface .select-interface-option .alert-radio-label { + color: #971e49; +} + +/* Alert Interface: set color for alert options (multiple selection) */ +.my-custom-interface .select-interface-option .alert-checkbox-label { + color: #971e49; +} + +/* Alert Interface: set color for checked alert options (single selection) */ +.my-custom-interface .select-interface-option[aria-checked='true'] .alert-radio-label { + color: #79193b; +} + +/* Alert Interface: set color for checked alert options (multiple selection) */ +.my-custom-interface .select-interface-option[aria-checked='true'] .alert-checkbox-label { + color: #79193b; +} +``` + +> Note: In the CSS examples, some of the selectors could be combined together, but are separated out in order to better explain what each selector is for. + +### Customizing Individual Options + +To customize an individual option, set a class on the `ion-select-option`: + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'select-option-example', + styleUrl: 'select-option-example.css', +}) +export class SelectOptionExample { + options = { + cssClass: 'my-custom-interface', + }; + + render() { + return [ + + Select + + + Brown + + Blonde + Black + Red + + , + ]; + } +} +``` + +```css +/* Popover Interface: set color for the popover using Item's CSS variables */ +.my-custom-interface .brown-option { + --color: #5e3e2c; + --color-hover: #362419; +} +``` + + + + + +```html + + + +``` + +### Customizing Options + +```html + + + +``` + +```css +/* Popover Interface: set color for the popover using Item's CSS variables */ +.my-custom-interface .select-interface-option { + --color: #971e49; + --color-hover: #79193b; +} + +/* Action Sheet Interface: set color for the action sheet using its button CSS variables */ +.my-custom-interface .select-interface-option { + --button-color: #971e49; + --button-color-hover: #79193b; +} + +/* Alert Interface: set color for alert options (single selection) */ +.my-custom-interface .select-interface-option .alert-radio-label { + color: #971e49; +} + +/* Alert Interface: set color for alert options (multiple selection) */ +.my-custom-interface .select-interface-option .alert-checkbox-label { + color: #971e49; +} + +/* Alert Interface: set color for checked alert options (single selection) */ +.my-custom-interface .select-interface-option[aria-checked='true'] .alert-radio-label { + color: #79193b; +} + +/* Alert Interface: set color for checked alert options (multiple selection) */ +.my-custom-interface .select-interface-option[aria-checked='true'] .alert-checkbox-label { + color: #79193b; +} +``` + +> Note: In the CSS examples, some of the selectors could be combined together, but are separated out in order to better explain what each selector is for. + +### Customizing Individual Options + +To customize an individual option, set a class on the `ion-select-option`: + +```html + + + +``` + +```css +/* Popover Interface: set color for the popover using Item's CSS variables */ +.my-custom-interface .brown-option { + --color: #5e3e2c; + --color-hover: #362419; +} +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/select.md b/versioned_docs/version-v5/api/select.md deleted file mode 100644 index f803eab81c5..00000000000 --- a/versioned_docs/version-v5/api/select.md +++ /dev/null @@ -1,1396 +0,0 @@ ---- -sidebar_label: 'ion-select' -demoUrl: '/docs/demos/api/select/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/select/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/select/props.md'; -import Events from '@ionic-internal/component-api/v5/select/events.md'; -import Methods from '@ionic-internal/component-api/v5/select/methods.md'; -import Parts from '@ionic-internal/component-api/v5/select/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/select/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/select/slots.md'; - -# ion-select - -Selects are form controls to select an option, or options, from a set of options, similar to a native `` element. When a user taps the select, a dialog appears with all of the options in a large, easy to select list. + +A select should be used with child `` elements. If the child option is not given a `value` attribute then its text will be used as the value. + +If `value` is set on the ``, the selected option will be chosen based on that value. + +## Interfaces + +By default, select uses [ion-alert](alert.mdx) to open up the overlay of options in an alert. The interface can be changed to use [ion-action-sheet](action-sheet.mdx) or [ion-popover](popover.mdx) by passing `action-sheet` or `popover`, respectively, to the `interface` property. Read on to the other sections for the limitations of the different interfaces. + +## Single Selection + +By default, the select allows the user to select only one option. The alert interface presents users with a radio button styled list of options. The action sheet interface can only be used with a single value select. The select component's value receives the value of the selected option's value. + +## Multiple Selection + +By adding the `multiple` attribute to select, users are able to select multiple options. When multiple options can be selected, the alert overlay presents users with a checkbox styled list of options. The select component's value receives an array of all of the selected option values. + +Note: the `action-sheet` and `popover` interfaces will not work with multiple selection. + +## Object Value References + +When using objects for select values, it is possible for the identities of these objects to change if they are coming from a server or database, while the selected value's identity remains the same. For example, this can occur when an existing record with the desired object value is loaded into the select, but the newly retrieved select options now have different identities. This will result in the select appearing to have no value at all, even though the original selection in still intact. + +By default, the select uses object equality (`===`) to determine if an option is selected. This can be overridden by providing a property name or a function to the `compareWith` property. + +## Select Buttons + +The alert supports two buttons: `Cancel` and `OK`. Each button's text can be customized using the `cancelText` and `okText` properties. + +The `action-sheet` and `popover` interfaces do not have an `OK` button, clicking on any of the options will automatically close the overlay and select that value. The `popover` interface does not have a `Cancel` button, clicking on the backdrop will close the overlay. + +## Interface Options + +Since select uses the alert, action sheet and popover interfaces, options can be passed to these components through the `interfaceOptions` property. This can be used to pass a custom header, subheader, css class, and more. + +See the [ion-alert docs](alert.mdx), [ion-action-sheet docs](action-sheet.mdx), and [ion-popover docs](popover.mdx) for the properties that each interface accepts. + +Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert` interface. + +## Customization + +There are two units that make up the Select component and each need to be styled separately. The `ion-select` element is represented on the view by the selected value(s), or placeholder if there is none, and dropdown icon. The interface, which is defined in the [Interfaces](#interfaces) section above, is the dialog that opens when clicking on the `ion-select`. The interface contains all of the options defined by adding `ion-select-option` elements. The following sections will go over the differences between styling these. + +### Styling Select Element + +As mentioned, the `ion-select` element consists only of the value(s), or placeholder, and icon that is displayed on the view. To customize this, style using a combination of CSS and any of the [CSS custom properties](#css-custom-properties): + +```css +ion-select { + /* Applies to the value and placeholder color */ + color: #545ca7; + + /* Set a different placeholder color */ + --placeholder-color: #971e49; + + /* Set full opacity on the placeholder */ + --placeholder-opacity: 1; +} +``` + +Alternatively, depending on the [browser support](https://caniuse.com/#feat=mdn-css_selectors_part) needed, CSS shadow parts can be used to style the select: + +```css +/* Set the width to the full container and center the content */ +ion-select { + width: 100%; + + justify-content: center; +} + +/* Set the flex in order to size the text width to its content */ +ion-select::part(placeholder), +ion-select::part(text) { + flex: 0 0 auto; +} + +/* Set the placeholder color and opacity */ +ion-select::part(placeholder) { + color: #20a08a; + opacity: 1; +} + +/* + * Set the font of the first letter of the placeholder + * Shadow parts work with pseudo-elements, too! + * https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements + */ +ion-select::part(placeholder)::first-letter { + font-size: 24px; + font-weight: 500; +} + +/* Set the text color */ +ion-select::part(text) { + color: #545ca7; +} + +/* Set the icon color and opacity */ +ion-select::part(icon) { + color: #971e49; + opacity: 1; +} +``` + +Notice that by using `::part`, any CSS property on the element can be targeted. + +### Styling Select Interface + +Customizing the interface dialog should be done by following the Customization section in that interface's documentation: + +- [Alert Customization](alert.mdx#customization) +- [Action Sheet Customization](action-sheet.mdx#customization) +- [Popover Customization](popover.mdx#customization) + +However, the Select Option does set a class for easier styling and allows for the ability to pass a class to the overlay option, see the [Select Options documentation](select-option.mdx) for usage examples of customizing options. + +## Usage + + + + + +### Single Selection + +```html + + + Single Selection + + + + Gender + + Female + Male + + + + + Hair Color + + Brown + Blonde + Black + Red + + + +``` + +### Multiple Selection + +```html + + + Multiple Selection + + + + Toppings + + Bacon + Black Olives + Extra Cheese + Green Peppers + Mushrooms + Onions + Pepperoni + Pineapple + Sausage + Spinach + + + + + Pets + + Bird + Cat + Dog + Honey Badger + + + +``` + +### Objects as Values + +```html + + + Objects as Values (compareWith) + + + + Users + + {{user.first + ' ' + user.last}} + + + +``` + +```tsx +import { Component } from '@angular/core'; + +interface User { + id: number; + first: string; + last: string; +} + +@Component({ + selector: 'select-example', + templateUrl: 'select-example.html', + styleUrls: ['./select-example.css'], +}) +export class SelectExample { + users: User[] = [ + { + id: 1, + first: 'Alice', + last: 'Smith', + }, + { + id: 2, + first: 'Bob', + last: 'Davis', + }, + { + id: 3, + first: 'Charlie', + last: 'Rosenburg', + }, + ]; + + compareWith(o1: User, o2: User) { + return o1 && o2 ? o1.id === o2.id : o1 === o2; + } +} +``` + +### Objects as Values with Multiple Selection + +```html + + + Objects as Values (compareWith) + + + + Users + + {{user.first + ' ' + user.last}} + + + +``` + +```tsx +import { Component } from '@angular/core'; + +interface User { + id: number; + first: string; + last: string; +} + +@Component({ + selector: 'select-example', + templateUrl: 'select-example.html', + styleUrls: ['./select-example.css'], +}) +export class SelectExample { + users: User[] = [ + { + id: 1, + first: 'Alice', + last: 'Smith', + }, + { + id: 2, + first: 'Bob', + last: 'Davis', + }, + { + id: 3, + first: 'Charlie', + last: 'Rosenburg', + }, + ]; + + compareWith(o1: User, o2: User | User[]) { + if (!o1 || !o2) { + return o1 === o2; + } + + if (Array.isArray(o2)) { + return o2.some((u: User) => u.id === o1.id); + } + + return o1.id === o2.id; + } +} +``` + +### Interface Options + +```html + + + Interface Options + + + + Alert + + Bacon + Black Olives + Extra Cheese + Green Peppers + Mushrooms + Onions + Pepperoni + Pineapple + Sausage + Spinach + + + + + Popover + + Brown + Blonde + Black + Red + + + + + Action Sheet + + Red + Purple + Yellow + Orange + Green + + + +``` + +```tsx +import { Component } from '@angular/core'; + +@Component({ + selector: 'select-example', + templateUrl: 'select-example.html', + styleUrls: ['./select-example.css'], +}) +export class SelectExample { + customAlertOptions: any = { + header: 'Pizza Toppings', + subHeader: 'Select your toppings', + message: '$1.00 per topping', + translucent: true, + }; + + customPopoverOptions: any = { + header: 'Hair Color', + subHeader: 'Select your hair color', + message: 'Only select your dominant hair color', + }; + + customActionSheetOptions: any = { + header: 'Colors', + subHeader: 'Select your favorite color', + }; +} +``` + + + + + +### Single Selection + +```html + + + Single Selection + + + + Gender + + Female + Male + + + + + Hair Color + + Brown + Blonde + Black + Red + + + +``` + +### Multiple Selection + +```html + + + Multiple Selection + + + + Toppings + + Bacon + Black Olives + Extra Cheese + Green Peppers + Mushrooms + Onions + Pepperoni + Pineapple + Sausage + Spinach + + + + + Pets + + Bird + Cat + Dog + Honey Badger + + + +``` + +```javascript +const select = document.querySelector('multiple'); +select.value = ['bird', 'dog']; +``` + +### Objects as Values + +```html + + + Objects as Values (compareWith) + + + + Users + + + +``` + +```javascript + let objectOptions = [ + { + id: 1, + first: 'Alice', + last: 'Smith', + }, + { + id: 2, + first: 'Bob', + last: 'Davis', + }, + { + id: 3, + first: 'Charlie', + last: 'Rosenburg', + } + ]; + + let compareWithFn = (o1, o2) => { + return o1 && o2 ? o1.id === o2.id : o1 === o2; + }; + + let objectSelectElement = document.getElementById('objectSelectCompareWith'); + objectSelectElement.compareWith = compareWithFn; + + objectOptions.forEach((option, i) => { + let selectOption = document.createElement('ion-select-option'); + selectOption.value = option; + selectOption.textContent = option.first + ' ' + option.last; + + objectSelectElement.appendChild(selectOption) + }); + + objectSelectElement.value = objectOptions[0]; +} +``` + +### Interface Options + +```html + + + Interface Options + + + + Alert + + Bacon + Black Olives + Extra Cheese + Green Peppers + Mushrooms + Onions + Pepperoni + Pineapple + Sausage + Spinach + + + + + Popover + + Brown + Blonde + Black + Red + + + + + Action Sheet + + Red + Purple + Yellow + Orange + Green + + + +``` + +```javascript +var customAlertSelect = document.getElementById('customAlertSelect'); +var customAlertOptions = { + header: 'Pizza Toppings', + subHeader: 'Select your toppings', + message: '$1.00 per topping', + translucent: true, +}; +customAlertSelect.interfaceOptions = customAlertOptions; + +var customPopoverSelect = document.getElementById('customPopoverSelect'); +var customPopoverOptions = { + header: 'Hair Color', + subHeader: 'Select your hair color', + message: 'Only select your dominant hair color', +}; +customPopoverSelect.interfaceOptions = customPopoverOptions; + +var customActionSheetSelect = document.getElementById('customActionSheetSelect'); +var customActionSheetOptions = { + header: 'Colors', + subHeader: 'Select your favorite color', +}; +customActionSheetSelect.interfaceOptions = customActionSheetOptions; +``` + + + + + +### Single Selection + +```tsx +import React, { useState } from 'react'; +import { + IonContent, + IonItem, + IonLabel, + IonList, + IonListHeader, + IonSelect, + IonSelectOption, + IonPage, + IonItemDivider, +} from '@ionic/react'; + +export const SingleSelection: React.FC = () => { + const [gender, setGender] = useState(); + const [hairColor, setHairColor] = useState('brown'); + + return ( + + + + + Single Selection + + + + Gender + setGender(e.detail.value)}> + Female + Male + + + + + Hair Color + setHairColor(e.detail.value)} + > + Brown + Blonde + Black + Red + + + Your Selections + Gender: {gender ?? '(none selected)'} + Hair Color: {hairColor} + + + + ); +}; +``` + +### Multiple Selection + +```tsx +import React, { useState } from 'react'; +import { + IonContent, + IonItem, + IonLabel, + IonList, + IonListHeader, + IonSelect, + IonSelectOption, + IonPage, + IonItemDivider, +} from '@ionic/react'; + +export const MultipleSelection: React.FC = () => { + const [toppings, setToppings] = useState([]); + const [pets, setPets] = useState(['bird', 'dog']); + + return ( + + + + + Multiple Selection + + + + Toppings + setToppings(e.detail.value)} + > + Bacon + Black Olives + Extra Cheese + Green Peppers + Mushrooms + Onions + Pepperoni + Pineapple + Sausage + Spinach + + + + + Pets + setPets(e.detail.value)}> + Bird + Cat + Dog + Honey Badger + + + Your Selections + + Toppings: {toppings.length ? toppings.reduce((curr, prev) => prev + ', ' + curr, '') : '(none selected)'} + + + Pets: {pets.length ? pets.reduce((curr, prev) => prev + ', ' + curr, '') : '(none selected)'} + + + + + ); +}; +``` + +### Objects as Values + +```tsx +import React, { useState } from 'react'; +import { + IonContent, + IonItem, + IonLabel, + IonList, + IonListHeader, + IonSelect, + IonSelectOption, + IonPage, + IonItemDivider, +} from '@ionic/react'; + +const users = [ + { + id: 1, + first: 'Alice', + last: 'Smith', + }, + { + id: 2, + first: 'Bob', + last: 'Davis', + }, + { + id: 3, + first: 'Charlie', + last: 'Rosenburg', + }, +]; + +type User = (typeof users)[number]; + +const compareWith = (o1: User, o2: User) => { + return o1 && o2 ? o1.id === o2.id : o1 === o2; +}; + +export const ObjectSelection: React.FC = () => { + const [selectedUsers, setSelectedUsers] = useState([]); + + return ( + + + + + Objects as Values (compareWith) + + + Users + setSelectedUsers(e.detail.value)} + > + {users.map((user) => ( + + {user.first} {user.last} + + ))} + + + Selected Users + {selectedUsers.length ? ( + selectedUsers.map((user) => ( + + {user.first} {user.last} + + )) + ) : ( + (none selected) + )} + + + + ); +}; +``` + +### Interface Options + +```tsx +import React, { useState } from 'react'; +import { + IonContent, + IonItem, + IonLabel, + IonList, + IonListHeader, + IonSelect, + IonSelectOption, + IonPage, + IonItemDivider, +} from '@ionic/react'; + +const customAlertOptions = { + header: 'Pizza Toppings', + subHeader: 'Select your toppings', + message: '$1.00 per topping', + translucent: true, +}; + +const customPopoverOptions = { + header: 'Hair Color', + subHeader: 'Select your hair color', + message: 'Only select your dominant hair color', +}; + +const customActionSheetOptions = { + header: 'Colors', + subHeader: 'Select your favorite color', +}; + +export const InterfaceOptionsSelection: React.FC = () => { + const [toppings, setToppings] = useState([]); + const [hairColor, setHairColor] = useState('brown'); + const [color, setColor] = useState(); + + return ( + + + + + Interface Options + + + + Alert + setToppings(e.detail.value)} + value={toppings} + > + Bacon + Black Olives + Extra Cheese + Green Peppers + Mushrooms + Onions + Pepperoni + Pineapple + Sausage + Spinach + + + + + Popover + setHairColor(e.detail.value)} + value={hairColor} + > + Brown + Blonde + Black + Red + + + + + Action Sheet + setColor(e.detail.value)} + value={color} + > + Red + Purple + Yellow + Orange + Green + + + + Your Selections + + Toppings: {toppings.length ? toppings.reduce((curr, prev) => prev + ', ' + curr, '') : '(none selected)'} + + Hair Color: {hairColor} + Color: {color ?? '(none selected)'} + + + + ); +}; +``` + + + + + +### Single Selection + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'select-example', + styleUrl: 'select-example.css', +}) +export class SelectExample { + render() { + return [ + + + Single Selection + + + + Gender + + Female + Male + + + + + Hair Color + + Brown + Blonde + Black + Red + + + , + ]; + } +} +``` + +### Multiple Selection + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'select-example', + styleUrl: 'select-example.css', +}) +export class SelectExample { + render() { + return [ + + + Multiple Selection + + + + Toppings + + Bacon + Black Olives + Extra Cheese + Green Peppers + Mushrooms + Onions + Pepperoni + Pineapple + Sausage + Spinach + + + + + Pets + + Bird + Cat + Dog + Honey Badger + + + , + ]; + } +} +``` + +### Objects as Values + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'select-example', + styleUrl: 'select-example.css', +}) +export class SelectExample { + private users: any[] = [ + { + id: 1, + first: 'Alice', + last: 'Smith', + }, + { + id: 2, + first: 'Bob', + last: 'Davis', + }, + { + id: 3, + first: 'Charlie', + last: 'Rosenburg', + }, + ]; + + compareWith = (o1, o2) => { + return o1 && o2 ? o1.id === o2.id : o1 === o2; + }; + + render() { + return [ + + + Objects as Values (compareWith) + + + + Users + + {this.users.map((user) => ( + {user.first + ' ' + user.last} + ))} + + + , + ]; + } +} +``` + +### Interface Options + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'select-example', + styleUrl: 'select-example.css', +}) +export class SelectExample { + private customAlertOptions: any = { + header: 'Pizza Toppings', + subHeader: 'Select your toppings', + message: '$1.00 per topping', + translucent: true, + }; + + private customPopoverOptions: any = { + header: 'Hair Color', + subHeader: 'Select your hair color', + message: 'Only select your dominant hair color', + }; + + private customActionSheetOptions: any = { + header: 'Colors', + subHeader: 'Select your favorite color', + }; + + render() { + return [ + + + Interface Options + + + + Alert + + Bacon + Black Olives + Extra Cheese + Green Peppers + Mushrooms + Onions + Pepperoni + Pineapple + Sausage + Spinach + + + + + Popover + + Brown + Blonde + Black + Red + + + + + Action Sheet + + Red + Purple + Yellow + Orange + Green + + + , + ]; + } +} +``` + + + + + +### Single Selection + +```html + + + +``` + +### Multiple Selection + +```html + + + +``` + +### Interface Options + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/skeleton-text.md b/versioned_docs/version-v5/api/skeleton-text.md deleted file mode 100644 index 3a420685677..00000000000 --- a/versioned_docs/version-v5/api/skeleton-text.md +++ /dev/null @@ -1,824 +0,0 @@ ---- -title: 'Skeleton Text | Skeleton Loading Placeholder & Framework for Text' -description: 'ion-skeleton-text is a component for rendering placeholder content. The element will render a gray block at the specified width as a loading text framework.' -sidebar_label: 'ion-skeleton-text' -demoUrl: '/docs/demos/api/skeleton-text/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/skeleton-text/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/skeleton-text/props.md'; -import Events from '@ionic-internal/component-api/v5/skeleton-text/events.md'; -import Methods from '@ionic-internal/component-api/v5/skeleton-text/methods.md'; -import Parts from '@ionic-internal/component-api/v5/skeleton-text/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/skeleton-text/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/skeleton-text/slots.md'; - -# ion-skeleton-text - -Skeleton Text is a component for rendering placeholder content. The element will render a gray block at the specified width. - -## Usage - - - - - -```html - -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac eros est. Cras iaculis pulvinar arcu non vehicula. - Fusce at quam a eros malesuada condimentum. Aliquam tincidunt tincidunt vehicula. -
- - - - Data - - - - - - -

{{ data.heading }}

-

{{ data.para1 }}

-

{{ data.para2 }}

-
-
- - - - - -

{{ data.heading }}

-

{{ data.para1 }}

-

{{ data.para2 }}

-
-
- - - -

{{ data.heading }}

-

{{ data.para1 }}

-

{{ data.para2 }}

-
-
-
-
- - -
-
- - - - - -
- - - - - - - - - - - - -

- -

-

- -

-

- -

-
-
- - - - - -

- -

-

- -

-

- -

-
-
- - - -

- -

-

- -

-

- -

-
-
-
-
-``` - -```css -/* Custom Skeleton Line Height and Margin */ -.custom-skeleton ion-skeleton-text { - line-height: 13px; -} - -.custom-skeleton ion-skeleton-text:last-child { - margin-bottom: 5px; -} -``` - -```tsx -import { Component } from '@angular/core'; - -@Component({ - selector: 'skeleton-text-example', - templateUrl: 'skeleton-text-example.html', - styleUrls: ['./skeleton-text-example.css'], -}) -export class SkeletonTextExample { - data: any; - - constructor() {} - - ionViewWillEnter() { - setTimeout(() => { - this.data = { - heading: 'Normal text', - para1: 'Lorem ipsum dolor sit amet, consectetur', - para2: 'adipiscing elit.', - }; - }, 5000); - } -} -``` - -
- - - -```html - -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac eros est. Cras iaculis pulvinar arcu non vehicula. - Fusce at quam a eros malesuada condimentum. Aliquam tincidunt tincidunt vehicula. -
- - - - Data - - - - - - -

Normal text

-

Lorem ipsum dolor sit amet, consectetur

-

adipiscing elit.

-
-
- - - - - -

Normal text

-

Lorem ipsum dolor sit amet, consectetur

-

adipiscing elit.

-
-
- - - -

Normal text

-

Lorem ipsum dolor sit amet, consectetur

-

adipiscing elit.

-
-
-
-
- - -
-
- - - - - -
- - - - - - - - - - - - -

- -

-

- -

-

- -

-
-
- - - - - -

- -

-

- -

-

- -

-
-
- - - -

- -

-

- -

-

- -

-
-
-
-
-``` - -```css -#data { - display: none; -} - -/* Custom Skeleton Line Height and Margin */ -.custom-skeleton ion-skeleton-text { - line-height: 13px; -} - -.custom-skeleton ion-skeleton-text:last-child { - margin-bottom: 5px; -} -``` - -```javascript -function onLoad() { - const skeletonEl = document.getElementById('skeleton'); - const dataEl = document.getElementById('data'); - - setTimeout(() => { - skeletonEl.style.display = 'none'; - dataEl.style.display = 'block'; - }, 5000); -} -``` - -
- - - -```tsx -import React, { useState } from 'react'; -import { - IonContent, - IonItem, - IonAvatar, - IonLabel, - IonSkeletonText, - IonListHeader, - IonIcon, - IonThumbnail, - IonList, -} from '@ionic/react'; -import { call } from 'ionicons/icons'; - -import './SkeletonTextExample.css'; - -export const SkeletonTextExample: React.FC = () => { - const [data, setData] = useState(); - - setTimeout(() => { - setData({ - heading: 'Normal text', - para1: 'Lorem ipsum dolor sit amet, consectetur', - para2: 'adipiscing elit.', - }); - }, 5000); - - return ( - - {data ? ( - <> -
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac eros est. Cras iaculis pulvinar arcu non - vehicula. Fusce at quam a eros malesuada condimentum. Aliquam tincidunt tincidunt vehicula. -
- - - - Data - - - - - - -

{data.heading}

-

{data.para1}

-

{data.para2}

-
-
- - - - - -

{data.heading}

-

{data.para1}

-

{data.para2}

-
-
- - - -

{data.heading}

-

{data.para1}

-

{data.para2}

-
-
-
- - ) : ( - <> -
- - - - - -
- - - - - - - - - - - - -

- -

-

- -

-

- -

-
-
- - - - - -

- -

-

- -

-

- -

-
-
- - - -

- -

-

- -

-

- -

-
-
-
- - )} -
- ); -}; -``` - -```css -/* Custom Skeleton Line Height and Margin */ -.custom-skeleton ion-skeleton-text { - line-height: 13px; -} - -.custom-skeleton ion-skeleton-text:last-child { - margin-bottom: 5px; -} -``` - -
- - - -```tsx -import { Component, State, h } from '@stencil/core'; - -@Component({ - tag: 'skeleton-text-example', - styleUrl: 'skeleton-text-example.css', -}) -export class SkeletonTextExample { - @State() data: any; - - componentWillLoad() { - // Data will show after 5 seconds - setTimeout(() => { - this.data = { - heading: 'Normal text', - para1: 'Lorem ipsum dolor sit amet, consectetur', - para2: 'adipiscing elit.', - }; - }, 5000); - } - - // Render skeleton screen when there is no data - renderSkeletonScreen() { - return [ - -
- - - - - -
- - - - - - - - - - - - -

- -

-

- -

-

- -

-
-
- - - - - -

- -

-

- -

-

- -

-
-
- - - -

- -

-

- -

-

- -

-
-
-
-
, - ]; - } - - // Render the elements with data - renderDataScreen() { - return [ - -
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac eros est. Cras iaculis pulvinar arcu non - vehicula. Fusce at quam a eros malesuada condimentum. Aliquam tincidunt tincidunt vehicula. -
- - - - Data - - - - - - -

{this.data.heading}

-

{this.data.para1}

-

{this.data.para2}

-
-
- - - - - -

{this.data.heading}

-

{this.data.para1}

-

{this.data.para2}

-
-
- - - -

{this.data.heading}

-

{this.data.para1}

-

{this.data.para2}

-
-
-
-
, - ]; - } - - render() { - if (this.data) { - return this.renderDataScreen(); - } else { - return this.renderSkeletonScreen(); - } - } -} -``` - -```css -/* Custom Skeleton Line Height and Margin */ -.custom-skeleton ion-skeleton-text { - line-height: 13px; -} - -.custom-skeleton ion-skeleton-text:last-child { - margin-bottom: 5px; -} -``` - -
- - - -```html - - - - - -``` - - - -
- -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/skeleton-text.mdx b/versioned_docs/version-v5/api/skeleton-text.mdx new file mode 100644 index 00000000000..71cc17ad803 --- /dev/null +++ b/versioned_docs/version-v5/api/skeleton-text.mdx @@ -0,0 +1,824 @@ +--- +title: 'Skeleton Text | Skeleton Loading Placeholder & Framework for Text' +description: 'ion-skeleton-text is a component for rendering placeholder content. The element will render a gray block at the specified width as a loading text framework.' +sidebar_label: 'ion-skeleton-text' +demoUrl: '/docs/demos/api/skeleton-text/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/skeleton-text/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/skeleton-text/props.mdx'; +import Events from '@ionic-internal/component-api/v5/skeleton-text/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/skeleton-text/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/skeleton-text/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/skeleton-text/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/skeleton-text/slots.mdx'; + +# ion-skeleton-text + +Skeleton Text is a component for rendering placeholder content. The element will render a gray block at the specified width. + +## Usage + + + + + +```html + +
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac eros est. Cras iaculis pulvinar arcu non vehicula. + Fusce at quam a eros malesuada condimentum. Aliquam tincidunt tincidunt vehicula. +
+ + + + Data + + + + + + +

{{ data.heading }}

+

{{ data.para1 }}

+

{{ data.para2 }}

+
+
+ + + + + +

{{ data.heading }}

+

{{ data.para1 }}

+

{{ data.para2 }}

+
+
+ + + +

{{ data.heading }}

+

{{ data.para1 }}

+

{{ data.para2 }}

+
+
+
+
+ + +
+
+ + + + + +
+ + + + + + + + + + + + +

+ +

+

+ +

+

+ +

+
+
+ + + + + +

+ +

+

+ +

+

+ +

+
+
+ + + +

+ +

+

+ +

+

+ +

+
+
+
+
+``` + +```css +/* Custom Skeleton Line Height and Margin */ +.custom-skeleton ion-skeleton-text { + line-height: 13px; +} + +.custom-skeleton ion-skeleton-text:last-child { + margin-bottom: 5px; +} +``` + +```tsx +import { Component } from '@angular/core'; + +@Component({ + selector: 'skeleton-text-example', + templateUrl: 'skeleton-text-example.html', + styleUrls: ['./skeleton-text-example.css'], +}) +export class SkeletonTextExample { + data: any; + + constructor() {} + + ionViewWillEnter() { + setTimeout(() => { + this.data = { + heading: 'Normal text', + para1: 'Lorem ipsum dolor sit amet, consectetur', + para2: 'adipiscing elit.', + }; + }, 5000); + } +} +``` + +
+ + + +```html + +
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac eros est. Cras iaculis pulvinar arcu non vehicula. + Fusce at quam a eros malesuada condimentum. Aliquam tincidunt tincidunt vehicula. +
+ + + + Data + + + + + + +

Normal text

+

Lorem ipsum dolor sit amet, consectetur

+

adipiscing elit.

+
+
+ + + + + +

Normal text

+

Lorem ipsum dolor sit amet, consectetur

+

adipiscing elit.

+
+
+ + + +

Normal text

+

Lorem ipsum dolor sit amet, consectetur

+

adipiscing elit.

+
+
+
+
+ + +
+
+ + + + + +
+ + + + + + + + + + + + +

+ +

+

+ +

+

+ +

+
+
+ + + + + +

+ +

+

+ +

+

+ +

+
+
+ + + +

+ +

+

+ +

+

+ +

+
+
+
+
+``` + +```css +#data { + display: none; +} + +/* Custom Skeleton Line Height and Margin */ +.custom-skeleton ion-skeleton-text { + line-height: 13px; +} + +.custom-skeleton ion-skeleton-text:last-child { + margin-bottom: 5px; +} +``` + +```javascript +function onLoad() { + const skeletonEl = document.getElementById('skeleton'); + const dataEl = document.getElementById('data'); + + setTimeout(() => { + skeletonEl.style.display = 'none'; + dataEl.style.display = 'block'; + }, 5000); +} +``` + +
+ + + +```tsx +import React, { useState } from 'react'; +import { + IonContent, + IonItem, + IonAvatar, + IonLabel, + IonSkeletonText, + IonListHeader, + IonIcon, + IonThumbnail, + IonList, +} from '@ionic/react'; +import { call } from 'ionicons/icons'; + +import './SkeletonTextExample.css'; + +export const SkeletonTextExample: React.FC = () => { + const [data, setData] = useState(); + + setTimeout(() => { + setData({ + heading: 'Normal text', + para1: 'Lorem ipsum dolor sit amet, consectetur', + para2: 'adipiscing elit.', + }); + }, 5000); + + return ( + + {data ? ( + <> +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac eros est. Cras iaculis pulvinar arcu non + vehicula. Fusce at quam a eros malesuada condimentum. Aliquam tincidunt tincidunt vehicula. +
+ + + + Data + + + + + + +

{data.heading}

+

{data.para1}

+

{data.para2}

+
+
+ + + + + +

{data.heading}

+

{data.para1}

+

{data.para2}

+
+
+ + + +

{data.heading}

+

{data.para1}

+

{data.para2}

+
+
+
+ + ) : ( + <> +
+ + + + + +
+ + + + + + + + + + + + +

+ +

+

+ +

+

+ +

+
+
+ + + + + +

+ +

+

+ +

+

+ +

+
+
+ + + +

+ +

+

+ +

+

+ +

+
+
+
+ + )} +
+ ); +}; +``` + +```css +/* Custom Skeleton Line Height and Margin */ +.custom-skeleton ion-skeleton-text { + line-height: 13px; +} + +.custom-skeleton ion-skeleton-text:last-child { + margin-bottom: 5px; +} +``` + +
+ + + +```tsx +import { Component, State, h } from '@stencil/core'; + +@Component({ + tag: 'skeleton-text-example', + styleUrl: 'skeleton-text-example.css', +}) +export class SkeletonTextExample { + @State() data: any; + + componentWillLoad() { + // Data will show after 5 seconds + setTimeout(() => { + this.data = { + heading: 'Normal text', + para1: 'Lorem ipsum dolor sit amet, consectetur', + para2: 'adipiscing elit.', + }; + }, 5000); + } + + // Render skeleton screen when there is no data + renderSkeletonScreen() { + return [ + +
+ + + + + +
+ + + + + + + + + + + + +

+ +

+

+ +

+

+ +

+
+
+ + + + + +

+ +

+

+ +

+

+ +

+
+
+ + + +

+ +

+

+ +

+

+ +

+
+
+
+
, + ]; + } + + // Render the elements with data + renderDataScreen() { + return [ + +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac eros est. Cras iaculis pulvinar arcu non + vehicula. Fusce at quam a eros malesuada condimentum. Aliquam tincidunt tincidunt vehicula. +
+ + + + Data + + + + + + +

{this.data.heading}

+

{this.data.para1}

+

{this.data.para2}

+
+
+ + + + + +

{this.data.heading}

+

{this.data.para1}

+

{this.data.para2}

+
+
+ + + +

{this.data.heading}

+

{this.data.para1}

+

{this.data.para2}

+
+
+
+
, + ]; + } + + render() { + if (this.data) { + return this.renderDataScreen(); + } else { + return this.renderSkeletonScreen(); + } + } +} +``` + +```css +/* Custom Skeleton Line Height and Margin */ +.custom-skeleton ion-skeleton-text { + line-height: 13px; +} + +.custom-skeleton ion-skeleton-text:last-child { + margin-bottom: 5px; +} +``` + +
+ + + +```html + + + + + +``` + + + +
+ +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/slide.md b/versioned_docs/version-v5/api/slide.md deleted file mode 100644 index 878add9fea3..00000000000 --- a/versioned_docs/version-v5/api/slide.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -sidebar_label: 'ion-slide' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/slide/props.md'; -import Events from '@ionic-internal/component-api/v5/slide/events.md'; -import Methods from '@ionic-internal/component-api/v5/slide/methods.md'; -import Parts from '@ionic-internal/component-api/v5/slide/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/slide/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/slide/slots.md'; - -# ion-slide - -The Slide component is a child component of [Slides](slides.md). The template -should be written as `ion-slide`. Any slide content should be written -in this component and it should be used in conjunction with [Slides](slides.md). - -See the [Slides API Docs](slides.md) for more usage information. - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/slide.mdx b/versioned_docs/version-v5/api/slide.mdx new file mode 100644 index 00000000000..e25abda7106 --- /dev/null +++ b/versioned_docs/version-v5/api/slide.mdx @@ -0,0 +1,45 @@ +--- +sidebar_label: 'ion-slide' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/slide/props.mdx'; +import Events from '@ionic-internal/component-api/v5/slide/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/slide/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/slide/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/slide/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/slide/slots.mdx'; + +# ion-slide + +The Slide component is a child component of [Slides](slides.mdx). The template +should be written as `ion-slide`. Any slide content should be written +in this component and it should be used in conjunction with [Slides](slides.mdx). + +See the [Slides API Docs](slides.mdx) for more usage information. + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/slides.md b/versioned_docs/version-v5/api/slides.md deleted file mode 100644 index 8461e82c3d9..00000000000 --- a/versioned_docs/version-v5/api/slides.md +++ /dev/null @@ -1,719 +0,0 @@ ---- -title: 'Ion-Slides: Mobile Touch Slider with Built-In & Custom Animation' -description: 'Ion-Slides is a multi-section container which offers custom and built-in mobile touch slider animation effects. See how Ion-Slides works with iOS and Android.' -sidebar_label: 'ion-slides' -demoUrl: '/docs/demos/api/slides/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/slides/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/slides/props.md'; -import Events from '@ionic-internal/component-api/v5/slides/events.md'; -import Methods from '@ionic-internal/component-api/v5/slides/methods.md'; -import Parts from '@ionic-internal/component-api/v5/slides/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/slides/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/slides/slots.md'; - -# ion-slides - -The Slides component is a multi-section container. Each section can be swiped -or dragged between. It contains any number of [Slide](slide.md) components. - -Adopted from Swiper.js: -The most modern mobile touch slider and framework with hardware accelerated transitions. - -http://www.idangero.us/swiper/ - -Copyright 2016, Vladimir Kharlampidi -The iDangero.us -http://www.idangero.us/ - -Licensed under MIT - -## Custom Animations - -By default, Ionic slides use the built-in `slide` animation effect. Custom animations can be provided via the `options` property. Examples of other animations can be found below. - -### Coverflow - -```tsx -const slideOpts = { - slidesPerView: 3, - coverflowEffect: { - rotate: 50, - stretch: 0, - depth: 100, - modifier: 1, - slideShadows: true, - }, - on: { - beforeInit() { - const swiper = this; - - swiper.classNames.push(`${swiper.params.containerModifierClass}coverflow`); - swiper.classNames.push(`${swiper.params.containerModifierClass}3d`); - - swiper.params.watchSlidesProgress = true; - swiper.originalParams.watchSlidesProgress = true; - }, - setTranslate() { - const swiper = this; - const { width: swiperWidth, height: swiperHeight, slides, $wrapperEl, slidesSizesGrid, $ } = swiper; - const params = swiper.params.coverflowEffect; - const isHorizontal = swiper.isHorizontal(); - const transform$$1 = swiper.translate; - const center = isHorizontal ? -transform$$1 + swiperWidth / 2 : -transform$$1 + swiperHeight / 2; - const rotate = isHorizontal ? params.rotate : -params.rotate; - const translate = params.depth; - // Each slide offset from center - for (let i = 0, length = slides.length; i < length; i += 1) { - const $slideEl = slides.eq(i); - const slideSize = slidesSizesGrid[i]; - const slideOffset = $slideEl[0].swiperSlideOffset; - const offsetMultiplier = ((center - slideOffset - slideSize / 2) / slideSize) * params.modifier; - - let rotateY = isHorizontal ? rotate * offsetMultiplier : 0; - let rotateX = isHorizontal ? 0 : rotate * offsetMultiplier; - // var rotateZ = 0 - let translateZ = -translate * Math.abs(offsetMultiplier); - - let translateY = isHorizontal ? 0 : params.stretch * offsetMultiplier; - let translateX = isHorizontal ? params.stretch * offsetMultiplier : 0; - - // Fix for ultra small values - if (Math.abs(translateX) < 0.001) translateX = 0; - if (Math.abs(translateY) < 0.001) translateY = 0; - if (Math.abs(translateZ) < 0.001) translateZ = 0; - if (Math.abs(rotateY) < 0.001) rotateY = 0; - if (Math.abs(rotateX) < 0.001) rotateX = 0; - - const slideTransform = `translate3d(${translateX}px,${translateY}px,${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`; - - $slideEl.transform(slideTransform); - $slideEl[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1; - if (params.slideShadows) { - // Set shadows - let $shadowBeforeEl = isHorizontal - ? $slideEl.find('.swiper-slide-shadow-left') - : $slideEl.find('.swiper-slide-shadow-top'); - let $shadowAfterEl = isHorizontal - ? $slideEl.find('.swiper-slide-shadow-right') - : $slideEl.find('.swiper-slide-shadow-bottom'); - if ($shadowBeforeEl.length === 0) { - $shadowBeforeEl = swiper.$(`
`); - $slideEl.append($shadowBeforeEl); - } - if ($shadowAfterEl.length === 0) { - $shadowAfterEl = swiper.$(`
`); - $slideEl.append($shadowAfterEl); - } - if ($shadowBeforeEl.length) $shadowBeforeEl[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0; - if ($shadowAfterEl.length) $shadowAfterEl[0].style.opacity = -offsetMultiplier > 0 ? -offsetMultiplier : 0; - } - } - - // Set correct perspective for IE10 - if (swiper.support.pointerEvents || swiper.support.prefixedPointerEvents) { - const ws = $wrapperEl[0].style; - ws.perspectiveOrigin = `${center}px 50%`; - } - }, - setTransition(duration) { - const swiper = this; - swiper.slides - .transition(duration) - .find( - '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left' - ) - .transition(duration); - }, - }, -}; -``` - -### Cube - -```tsx -const slideOpts = { - grabCursor: true, - cubeEffect: { - shadow: true, - slideShadows: true, - shadowOffset: 20, - shadowScale: 0.94, - }, - on: { - beforeInit: function () { - const swiper = this; - swiper.classNames.push(`${swiper.params.containerModifierClass}cube`); - swiper.classNames.push(`${swiper.params.containerModifierClass}3d`); - - const overwriteParams = { - slidesPerView: 1, - slidesPerColumn: 1, - slidesPerGroup: 1, - watchSlidesProgress: true, - resistanceRatio: 0, - spaceBetween: 0, - centeredSlides: false, - virtualTranslate: true, - }; - - this.params = Object.assign(this.params, overwriteParams); - this.originalParams = Object.assign(this.originalParams, overwriteParams); - }, - setTranslate: function () { - const swiper = this; - const { - $el, - $wrapperEl, - slides, - width: swiperWidth, - height: swiperHeight, - rtlTranslate: rtl, - size: swiperSize, - } = swiper; - const params = swiper.params.cubeEffect; - const isHorizontal = swiper.isHorizontal(); - const isVirtual = swiper.virtual && swiper.params.virtual.enabled; - let wrapperRotate = 0; - let $cubeShadowEl; - if (params.shadow) { - if (isHorizontal) { - $cubeShadowEl = $wrapperEl.find('.swiper-cube-shadow'); - if ($cubeShadowEl.length === 0) { - $cubeShadowEl = swiper.$('
'); - $wrapperEl.append($cubeShadowEl); - } - $cubeShadowEl.css({ height: `${swiperWidth}px` }); - } else { - $cubeShadowEl = $el.find('.swiper-cube-shadow'); - if ($cubeShadowEl.length === 0) { - $cubeShadowEl = swiper.$('
'); - $el.append($cubeShadowEl); - } - } - } - - for (let i = 0; i < slides.length; i += 1) { - const $slideEl = slides.eq(i); - let slideIndex = i; - if (isVirtual) { - slideIndex = parseInt($slideEl.attr('data-swiper-slide-index'), 10); - } - let slideAngle = slideIndex * 90; - let round = Math.floor(slideAngle / 360); - if (rtl) { - slideAngle = -slideAngle; - round = Math.floor(-slideAngle / 360); - } - const progress = Math.max(Math.min($slideEl[0].progress, 1), -1); - let tx = 0; - let ty = 0; - let tz = 0; - if (slideIndex % 4 === 0) { - tx = -round * 4 * swiperSize; - tz = 0; - } else if ((slideIndex - 1) % 4 === 0) { - tx = 0; - tz = -round * 4 * swiperSize; - } else if ((slideIndex - 2) % 4 === 0) { - tx = swiperSize + round * 4 * swiperSize; - tz = swiperSize; - } else if ((slideIndex - 3) % 4 === 0) { - tx = -swiperSize; - tz = 3 * swiperSize + swiperSize * 4 * round; - } - if (rtl) { - tx = -tx; - } - - if (!isHorizontal) { - ty = tx; - tx = 0; - } - - const transform$$1 = `rotateX(${isHorizontal ? 0 : -slideAngle}deg) rotateY(${ - isHorizontal ? slideAngle : 0 - }deg) translate3d(${tx}px, ${ty}px, ${tz}px)`; - if (progress <= 1 && progress > -1) { - wrapperRotate = slideIndex * 90 + progress * 90; - if (rtl) wrapperRotate = -slideIndex * 90 - progress * 90; - } - $slideEl.transform(transform$$1); - if (params.slideShadows) { - // Set shadows - let shadowBefore = isHorizontal - ? $slideEl.find('.swiper-slide-shadow-left') - : $slideEl.find('.swiper-slide-shadow-top'); - let shadowAfter = isHorizontal - ? $slideEl.find('.swiper-slide-shadow-right') - : $slideEl.find('.swiper-slide-shadow-bottom'); - if (shadowBefore.length === 0) { - shadowBefore = swiper.$(`
`); - $slideEl.append(shadowBefore); - } - if (shadowAfter.length === 0) { - shadowAfter = swiper.$(`
`); - $slideEl.append(shadowAfter); - } - if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0); - if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0); - } - } - $wrapperEl.css({ - '-webkit-transform-origin': `50% 50% -${swiperSize / 2}px`, - '-moz-transform-origin': `50% 50% -${swiperSize / 2}px`, - '-ms-transform-origin': `50% 50% -${swiperSize / 2}px`, - 'transform-origin': `50% 50% -${swiperSize / 2}px`, - }); - - if (params.shadow) { - if (isHorizontal) { - $cubeShadowEl.transform( - `translate3d(0px, ${swiperWidth / 2 + params.shadowOffset}px, ${ - -swiperWidth / 2 - }px) rotateX(90deg) rotateZ(0deg) scale(${params.shadowScale})` - ); - } else { - const shadowAngle = Math.abs(wrapperRotate) - Math.floor(Math.abs(wrapperRotate) / 90) * 90; - const multiplier = - 1.5 - (Math.sin((shadowAngle * 2 * Math.PI) / 360) / 2 + Math.cos((shadowAngle * 2 * Math.PI) / 360) / 2); - const scale1 = params.shadowScale; - const scale2 = params.shadowScale / multiplier; - const offset$$1 = params.shadowOffset; - $cubeShadowEl.transform( - `scale3d(${scale1}, 1, ${scale2}) translate3d(0px, ${swiperHeight / 2 + offset$$1}px, ${ - -swiperHeight / 2 / scale2 - }px) rotateX(-90deg)` - ); - } - } - - const zFactor = swiper.browser.isSafari || swiper.browser.isUiWebView ? -swiperSize / 2 : 0; - $wrapperEl.transform( - `translate3d(0px,0,${zFactor}px) rotateX(${swiper.isHorizontal() ? 0 : wrapperRotate}deg) rotateY(${ - swiper.isHorizontal() ? -wrapperRotate : 0 - }deg)` - ); - }, - setTransition: function (duration) { - const swiper = this; - const { $el, slides } = swiper; - slides - .transition(duration) - .find( - '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left' - ) - .transition(duration); - if (swiper.params.cubeEffect.shadow && !swiper.isHorizontal()) { - $el.find('.swiper-cube-shadow').transition(duration); - } - }, - }, -}; -``` - -### Fade - -```tsx -const slideOpts = { - on: { - beforeInit() { - const swiper = this; - swiper.classNames.push(`${swiper.params.containerModifierClass}fade`); - const overwriteParams = { - slidesPerView: 1, - slidesPerColumn: 1, - slidesPerGroup: 1, - watchSlidesProgress: true, - spaceBetween: 0, - virtualTranslate: true, - }; - swiper.params = Object.assign(swiper.params, overwriteParams); - swiper.params = Object.assign(swiper.originalParams, overwriteParams); - }, - setTranslate() { - const swiper = this; - const { slides } = swiper; - for (let i = 0; i < slides.length; i += 1) { - const $slideEl = swiper.slides.eq(i); - const offset$$1 = $slideEl[0].swiperSlideOffset; - let tx = -offset$$1; - if (!swiper.params.virtualTranslate) tx -= swiper.translate; - let ty = 0; - if (!swiper.isHorizontal()) { - ty = tx; - tx = 0; - } - const slideOpacity = swiper.params.fadeEffect.crossFade - ? Math.max(1 - Math.abs($slideEl[0].progress), 0) - : 1 + Math.min(Math.max($slideEl[0].progress, -1), 0); - $slideEl - .css({ - opacity: slideOpacity, - }) - .transform(`translate3d(${tx}px, ${ty}px, 0px)`); - } - }, - setTransition(duration) { - const swiper = this; - const { slides, $wrapperEl } = swiper; - slides.transition(duration); - if (swiper.params.virtualTranslate && duration !== 0) { - let eventTriggered = false; - slides.transitionEnd(() => { - if (eventTriggered) return; - if (!swiper || swiper.destroyed) return; - eventTriggered = true; - swiper.animating = false; - const triggerEvents = ['webkitTransitionEnd', 'transitionend']; - for (let i = 0; i < triggerEvents.length; i += 1) { - $wrapperEl.trigger(triggerEvents[i]); - } - }); - } - }, - }, -}; -``` - -### Flip - -```tsx -const slideOpts = { - on: { - beforeInit() { - const swiper = this; - swiper.classNames.push(`${swiper.params.containerModifierClass}flip`); - swiper.classNames.push(`${swiper.params.containerModifierClass}3d`); - const overwriteParams = { - slidesPerView: 1, - slidesPerColumn: 1, - slidesPerGroup: 1, - watchSlidesProgress: true, - spaceBetween: 0, - virtualTranslate: true, - }; - swiper.params = Object.assign(swiper.params, overwriteParams); - swiper.originalParams = Object.assign(swiper.originalParams, overwriteParams); - }, - setTranslate() { - const swiper = this; - const { $, slides, rtlTranslate: rtl } = swiper; - for (let i = 0; i < slides.length; i += 1) { - const $slideEl = slides.eq(i); - let progress = $slideEl[0].progress; - if (swiper.params.flipEffect.limitRotation) { - progress = Math.max(Math.min($slideEl[0].progress, 1), -1); - } - const offset$$1 = $slideEl[0].swiperSlideOffset; - const rotate = -180 * progress; - let rotateY = rotate; - let rotateX = 0; - let tx = -offset$$1; - let ty = 0; - if (!swiper.isHorizontal()) { - ty = tx; - tx = 0; - rotateX = -rotateY; - rotateY = 0; - } else if (rtl) { - rotateY = -rotateY; - } - - $slideEl[0].style.zIndex = -Math.abs(Math.round(progress)) + slides.length; - - if (swiper.params.flipEffect.slideShadows) { - // Set shadows - let shadowBefore = swiper.isHorizontal() - ? $slideEl.find('.swiper-slide-shadow-left') - : $slideEl.find('.swiper-slide-shadow-top'); - let shadowAfter = swiper.isHorizontal() - ? $slideEl.find('.swiper-slide-shadow-right') - : $slideEl.find('.swiper-slide-shadow-bottom'); - if (shadowBefore.length === 0) { - shadowBefore = swiper.$( - `
` - ); - $slideEl.append(shadowBefore); - } - if (shadowAfter.length === 0) { - shadowAfter = swiper.$( - `
` - ); - $slideEl.append(shadowAfter); - } - if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0); - if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0); - } - $slideEl.transform(`translate3d(${tx}px, ${ty}px, 0px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`); - } - }, - setTransition(duration) { - const swiper = this; - const { slides, activeIndex, $wrapperEl } = swiper; - slides - .transition(duration) - .find( - '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left' - ) - .transition(duration); - if (swiper.params.virtualTranslate && duration !== 0) { - let eventTriggered = false; - // eslint-disable-next-line - slides.eq(activeIndex).transitionEnd(function onTransitionEnd() { - if (eventTriggered) return; - if (!swiper || swiper.destroyed) return; - - eventTriggered = true; - swiper.animating = false; - const triggerEvents = ['webkitTransitionEnd', 'transitionend']; - for (let i = 0; i < triggerEvents.length; i += 1) { - $wrapperEl.trigger(triggerEvents[i]); - } - }); - } - }, - }, -}; -``` - -## Usage - - - - - -```tsx -import { Component } from '@angular/core'; - -@Component({ - selector: 'slides-example', - template: ` - - - -

Slide 1

-
- -

Slide 2

-
- -

Slide 3

-
-
-
- `, -}) -export class SlideExample { - // Optional parameters to pass to the swiper instance. - // See http://idangero.us/swiper/api/ for valid options. - slideOpts = { - initialSlide: 1, - speed: 400, - }; - constructor() {} -} -``` - -```css -/* Without setting height the slides will take up the height of the slide's content */ -ion-slides { - height: 100%; -} -``` - -
- - - -```html - - - -

Slide 1

-
- - -

Slide 2

-
- - -

Slide 3

-
-
-
-``` - -```javascript -var slides = document.querySelector('ion-slides'); - -// Optional parameters to pass to the swiper instance. -// See http://idangero.us/swiper/api/ for valid options. -slides.options = { - initialSlide: 1, - speed: 400, -}; -``` - -```css -/* Without setting height the slides will take up the height of the slide's content */ -ion-slides { - height: 100%; -} -``` - -
- - - -```tsx -import React from 'react'; -import { IonSlides, IonSlide, IonContent } from '@ionic/react'; - -// Optional parameters to pass to the swiper instance. -// See http://idangero.us/swiper/api/ for valid options. -const slideOpts = { - initialSlide: 1, - speed: 400, -}; - -export const SlidesExample: React.FC = () => ( - - - -

Slide 1

-
- -

Slide 2

-
- -

Slide 3

-
-
-
-); -``` - -```css -/* Without setting height the slides will take up the height of the slide's content */ -ion-slides { - height: 100%; -} -``` - -
- - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'slides-example', - styleUrl: 'slides-example.css', -}) -export class SlidesExample { - // Optional parameters to pass to the swiper instance. - // See http://idangero.us/swiper/api/ for valid options. - private slideOpts = { - initialSlide: 1, - speed: 400, - }; - - render() { - return [ - - - -

Slide 1

-
- - -

Slide 2

-
- - -

Slide 3

-
-
-
, - ]; - } -} -``` - -```css -/* Without setting height the slides will take up the height of the slide's content */ -ion-slides { - height: 100%; -} -``` - -
- - - -```html - - - -``` - - - -
- -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/slides.mdx b/versioned_docs/version-v5/api/slides.mdx new file mode 100644 index 00000000000..ca3fd8b55f3 --- /dev/null +++ b/versioned_docs/version-v5/api/slides.mdx @@ -0,0 +1,719 @@ +--- +title: 'Ion-Slides: Mobile Touch Slider with Built-In & Custom Animation' +description: 'Ion-Slides is a multi-section container which offers custom and built-in mobile touch slider animation effects. See how Ion-Slides works with iOS and Android.' +sidebar_label: 'ion-slides' +demoUrl: '/docs/demos/api/slides/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/slides/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/slides/props.mdx'; +import Events from '@ionic-internal/component-api/v5/slides/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/slides/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/slides/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/slides/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/slides/slots.mdx'; + +# ion-slides + +The Slides component is a multi-section container. Each section can be swiped +or dragged between. It contains any number of [Slide](slide.mdx) components. + +Adopted from Swiper.js: +The most modern mobile touch slider and framework with hardware accelerated transitions. + +http://www.idangero.us/swiper/ + +Copyright 2016, Vladimir Kharlampidi +The iDangero.us +http://www.idangero.us/ + +Licensed under MIT + +## Custom Animations + +By default, Ionic slides use the built-in `slide` animation effect. Custom animations can be provided via the `options` property. Examples of other animations can be found below. + +### Coverflow + +```tsx +const slideOpts = { + slidesPerView: 3, + coverflowEffect: { + rotate: 50, + stretch: 0, + depth: 100, + modifier: 1, + slideShadows: true, + }, + on: { + beforeInit() { + const swiper = this; + + swiper.classNames.push(`${swiper.params.containerModifierClass}coverflow`); + swiper.classNames.push(`${swiper.params.containerModifierClass}3d`); + + swiper.params.watchSlidesProgress = true; + swiper.originalParams.watchSlidesProgress = true; + }, + setTranslate() { + const swiper = this; + const { width: swiperWidth, height: swiperHeight, slides, $wrapperEl, slidesSizesGrid, $ } = swiper; + const params = swiper.params.coverflowEffect; + const isHorizontal = swiper.isHorizontal(); + const transform$$1 = swiper.translate; + const center = isHorizontal ? -transform$$1 + swiperWidth / 2 : -transform$$1 + swiperHeight / 2; + const rotate = isHorizontal ? params.rotate : -params.rotate; + const translate = params.depth; + // Each slide offset from center + for (let i = 0, length = slides.length; i < length; i += 1) { + const $slideEl = slides.eq(i); + const slideSize = slidesSizesGrid[i]; + const slideOffset = $slideEl[0].swiperSlideOffset; + const offsetMultiplier = ((center - slideOffset - slideSize / 2) / slideSize) * params.modifier; + + let rotateY = isHorizontal ? rotate * offsetMultiplier : 0; + let rotateX = isHorizontal ? 0 : rotate * offsetMultiplier; + // var rotateZ = 0 + let translateZ = -translate * Math.abs(offsetMultiplier); + + let translateY = isHorizontal ? 0 : params.stretch * offsetMultiplier; + let translateX = isHorizontal ? params.stretch * offsetMultiplier : 0; + + // Fix for ultra small values + if (Math.abs(translateX) < 0.001) translateX = 0; + if (Math.abs(translateY) < 0.001) translateY = 0; + if (Math.abs(translateZ) < 0.001) translateZ = 0; + if (Math.abs(rotateY) < 0.001) rotateY = 0; + if (Math.abs(rotateX) < 0.001) rotateX = 0; + + const slideTransform = `translate3d(${translateX}px,${translateY}px,${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`; + + $slideEl.transform(slideTransform); + $slideEl[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1; + if (params.slideShadows) { + // Set shadows + let $shadowBeforeEl = isHorizontal + ? $slideEl.find('.swiper-slide-shadow-left') + : $slideEl.find('.swiper-slide-shadow-top'); + let $shadowAfterEl = isHorizontal + ? $slideEl.find('.swiper-slide-shadow-right') + : $slideEl.find('.swiper-slide-shadow-bottom'); + if ($shadowBeforeEl.length === 0) { + $shadowBeforeEl = swiper.$(`
`); + $slideEl.append($shadowBeforeEl); + } + if ($shadowAfterEl.length === 0) { + $shadowAfterEl = swiper.$(`
`); + $slideEl.append($shadowAfterEl); + } + if ($shadowBeforeEl.length) $shadowBeforeEl[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0; + if ($shadowAfterEl.length) $shadowAfterEl[0].style.opacity = -offsetMultiplier > 0 ? -offsetMultiplier : 0; + } + } + + // Set correct perspective for IE10 + if (swiper.support.pointerEvents || swiper.support.prefixedPointerEvents) { + const ws = $wrapperEl[0].style; + ws.perspectiveOrigin = `${center}px 50%`; + } + }, + setTransition(duration) { + const swiper = this; + swiper.slides + .transition(duration) + .find( + '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left' + ) + .transition(duration); + }, + }, +}; +``` + +### Cube + +```tsx +const slideOpts = { + grabCursor: true, + cubeEffect: { + shadow: true, + slideShadows: true, + shadowOffset: 20, + shadowScale: 0.94, + }, + on: { + beforeInit: function () { + const swiper = this; + swiper.classNames.push(`${swiper.params.containerModifierClass}cube`); + swiper.classNames.push(`${swiper.params.containerModifierClass}3d`); + + const overwriteParams = { + slidesPerView: 1, + slidesPerColumn: 1, + slidesPerGroup: 1, + watchSlidesProgress: true, + resistanceRatio: 0, + spaceBetween: 0, + centeredSlides: false, + virtualTranslate: true, + }; + + this.params = Object.assign(this.params, overwriteParams); + this.originalParams = Object.assign(this.originalParams, overwriteParams); + }, + setTranslate: function () { + const swiper = this; + const { + $el, + $wrapperEl, + slides, + width: swiperWidth, + height: swiperHeight, + rtlTranslate: rtl, + size: swiperSize, + } = swiper; + const params = swiper.params.cubeEffect; + const isHorizontal = swiper.isHorizontal(); + const isVirtual = swiper.virtual && swiper.params.virtual.enabled; + let wrapperRotate = 0; + let $cubeShadowEl; + if (params.shadow) { + if (isHorizontal) { + $cubeShadowEl = $wrapperEl.find('.swiper-cube-shadow'); + if ($cubeShadowEl.length === 0) { + $cubeShadowEl = swiper.$('
'); + $wrapperEl.append($cubeShadowEl); + } + $cubeShadowEl.css({ height: `${swiperWidth}px` }); + } else { + $cubeShadowEl = $el.find('.swiper-cube-shadow'); + if ($cubeShadowEl.length === 0) { + $cubeShadowEl = swiper.$('
'); + $el.append($cubeShadowEl); + } + } + } + + for (let i = 0; i < slides.length; i += 1) { + const $slideEl = slides.eq(i); + let slideIndex = i; + if (isVirtual) { + slideIndex = parseInt($slideEl.attr('data-swiper-slide-index'), 10); + } + let slideAngle = slideIndex * 90; + let round = Math.floor(slideAngle / 360); + if (rtl) { + slideAngle = -slideAngle; + round = Math.floor(-slideAngle / 360); + } + const progress = Math.max(Math.min($slideEl[0].progress, 1), -1); + let tx = 0; + let ty = 0; + let tz = 0; + if (slideIndex % 4 === 0) { + tx = -round * 4 * swiperSize; + tz = 0; + } else if ((slideIndex - 1) % 4 === 0) { + tx = 0; + tz = -round * 4 * swiperSize; + } else if ((slideIndex - 2) % 4 === 0) { + tx = swiperSize + round * 4 * swiperSize; + tz = swiperSize; + } else if ((slideIndex - 3) % 4 === 0) { + tx = -swiperSize; + tz = 3 * swiperSize + swiperSize * 4 * round; + } + if (rtl) { + tx = -tx; + } + + if (!isHorizontal) { + ty = tx; + tx = 0; + } + + const transform$$1 = `rotateX(${isHorizontal ? 0 : -slideAngle}deg) rotateY(${ + isHorizontal ? slideAngle : 0 + }deg) translate3d(${tx}px, ${ty}px, ${tz}px)`; + if (progress <= 1 && progress > -1) { + wrapperRotate = slideIndex * 90 + progress * 90; + if (rtl) wrapperRotate = -slideIndex * 90 - progress * 90; + } + $slideEl.transform(transform$$1); + if (params.slideShadows) { + // Set shadows + let shadowBefore = isHorizontal + ? $slideEl.find('.swiper-slide-shadow-left') + : $slideEl.find('.swiper-slide-shadow-top'); + let shadowAfter = isHorizontal + ? $slideEl.find('.swiper-slide-shadow-right') + : $slideEl.find('.swiper-slide-shadow-bottom'); + if (shadowBefore.length === 0) { + shadowBefore = swiper.$(`
`); + $slideEl.append(shadowBefore); + } + if (shadowAfter.length === 0) { + shadowAfter = swiper.$(`
`); + $slideEl.append(shadowAfter); + } + if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0); + if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0); + } + } + $wrapperEl.css({ + '-webkit-transform-origin': `50% 50% -${swiperSize / 2}px`, + '-moz-transform-origin': `50% 50% -${swiperSize / 2}px`, + '-ms-transform-origin': `50% 50% -${swiperSize / 2}px`, + 'transform-origin': `50% 50% -${swiperSize / 2}px`, + }); + + if (params.shadow) { + if (isHorizontal) { + $cubeShadowEl.transform( + `translate3d(0px, ${swiperWidth / 2 + params.shadowOffset}px, ${ + -swiperWidth / 2 + }px) rotateX(90deg) rotateZ(0deg) scale(${params.shadowScale})` + ); + } else { + const shadowAngle = Math.abs(wrapperRotate) - Math.floor(Math.abs(wrapperRotate) / 90) * 90; + const multiplier = + 1.5 - (Math.sin((shadowAngle * 2 * Math.PI) / 360) / 2 + Math.cos((shadowAngle * 2 * Math.PI) / 360) / 2); + const scale1 = params.shadowScale; + const scale2 = params.shadowScale / multiplier; + const offset$$1 = params.shadowOffset; + $cubeShadowEl.transform( + `scale3d(${scale1}, 1, ${scale2}) translate3d(0px, ${swiperHeight / 2 + offset$$1}px, ${ + -swiperHeight / 2 / scale2 + }px) rotateX(-90deg)` + ); + } + } + + const zFactor = swiper.browser.isSafari || swiper.browser.isUiWebView ? -swiperSize / 2 : 0; + $wrapperEl.transform( + `translate3d(0px,0,${zFactor}px) rotateX(${swiper.isHorizontal() ? 0 : wrapperRotate}deg) rotateY(${ + swiper.isHorizontal() ? -wrapperRotate : 0 + }deg)` + ); + }, + setTransition: function (duration) { + const swiper = this; + const { $el, slides } = swiper; + slides + .transition(duration) + .find( + '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left' + ) + .transition(duration); + if (swiper.params.cubeEffect.shadow && !swiper.isHorizontal()) { + $el.find('.swiper-cube-shadow').transition(duration); + } + }, + }, +}; +``` + +### Fade + +```tsx +const slideOpts = { + on: { + beforeInit() { + const swiper = this; + swiper.classNames.push(`${swiper.params.containerModifierClass}fade`); + const overwriteParams = { + slidesPerView: 1, + slidesPerColumn: 1, + slidesPerGroup: 1, + watchSlidesProgress: true, + spaceBetween: 0, + virtualTranslate: true, + }; + swiper.params = Object.assign(swiper.params, overwriteParams); + swiper.params = Object.assign(swiper.originalParams, overwriteParams); + }, + setTranslate() { + const swiper = this; + const { slides } = swiper; + for (let i = 0; i < slides.length; i += 1) { + const $slideEl = swiper.slides.eq(i); + const offset$$1 = $slideEl[0].swiperSlideOffset; + let tx = -offset$$1; + if (!swiper.params.virtualTranslate) tx -= swiper.translate; + let ty = 0; + if (!swiper.isHorizontal()) { + ty = tx; + tx = 0; + } + const slideOpacity = swiper.params.fadeEffect.crossFade + ? Math.max(1 - Math.abs($slideEl[0].progress), 0) + : 1 + Math.min(Math.max($slideEl[0].progress, -1), 0); + $slideEl + .css({ + opacity: slideOpacity, + }) + .transform(`translate3d(${tx}px, ${ty}px, 0px)`); + } + }, + setTransition(duration) { + const swiper = this; + const { slides, $wrapperEl } = swiper; + slides.transition(duration); + if (swiper.params.virtualTranslate && duration !== 0) { + let eventTriggered = false; + slides.transitionEnd(() => { + if (eventTriggered) return; + if (!swiper || swiper.destroyed) return; + eventTriggered = true; + swiper.animating = false; + const triggerEvents = ['webkitTransitionEnd', 'transitionend']; + for (let i = 0; i < triggerEvents.length; i += 1) { + $wrapperEl.trigger(triggerEvents[i]); + } + }); + } + }, + }, +}; +``` + +### Flip + +```tsx +const slideOpts = { + on: { + beforeInit() { + const swiper = this; + swiper.classNames.push(`${swiper.params.containerModifierClass}flip`); + swiper.classNames.push(`${swiper.params.containerModifierClass}3d`); + const overwriteParams = { + slidesPerView: 1, + slidesPerColumn: 1, + slidesPerGroup: 1, + watchSlidesProgress: true, + spaceBetween: 0, + virtualTranslate: true, + }; + swiper.params = Object.assign(swiper.params, overwriteParams); + swiper.originalParams = Object.assign(swiper.originalParams, overwriteParams); + }, + setTranslate() { + const swiper = this; + const { $, slides, rtlTranslate: rtl } = swiper; + for (let i = 0; i < slides.length; i += 1) { + const $slideEl = slides.eq(i); + let progress = $slideEl[0].progress; + if (swiper.params.flipEffect.limitRotation) { + progress = Math.max(Math.min($slideEl[0].progress, 1), -1); + } + const offset$$1 = $slideEl[0].swiperSlideOffset; + const rotate = -180 * progress; + let rotateY = rotate; + let rotateX = 0; + let tx = -offset$$1; + let ty = 0; + if (!swiper.isHorizontal()) { + ty = tx; + tx = 0; + rotateX = -rotateY; + rotateY = 0; + } else if (rtl) { + rotateY = -rotateY; + } + + $slideEl[0].style.zIndex = -Math.abs(Math.round(progress)) + slides.length; + + if (swiper.params.flipEffect.slideShadows) { + // Set shadows + let shadowBefore = swiper.isHorizontal() + ? $slideEl.find('.swiper-slide-shadow-left') + : $slideEl.find('.swiper-slide-shadow-top'); + let shadowAfter = swiper.isHorizontal() + ? $slideEl.find('.swiper-slide-shadow-right') + : $slideEl.find('.swiper-slide-shadow-bottom'); + if (shadowBefore.length === 0) { + shadowBefore = swiper.$( + `
` + ); + $slideEl.append(shadowBefore); + } + if (shadowAfter.length === 0) { + shadowAfter = swiper.$( + `
` + ); + $slideEl.append(shadowAfter); + } + if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0); + if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0); + } + $slideEl.transform(`translate3d(${tx}px, ${ty}px, 0px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`); + } + }, + setTransition(duration) { + const swiper = this; + const { slides, activeIndex, $wrapperEl } = swiper; + slides + .transition(duration) + .find( + '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left' + ) + .transition(duration); + if (swiper.params.virtualTranslate && duration !== 0) { + let eventTriggered = false; + // eslint-disable-next-line + slides.eq(activeIndex).transitionEnd(function onTransitionEnd() { + if (eventTriggered) return; + if (!swiper || swiper.destroyed) return; + + eventTriggered = true; + swiper.animating = false; + const triggerEvents = ['webkitTransitionEnd', 'transitionend']; + for (let i = 0; i < triggerEvents.length; i += 1) { + $wrapperEl.trigger(triggerEvents[i]); + } + }); + } + }, + }, +}; +``` + +## Usage + + + + + +```tsx +import { Component } from '@angular/core'; + +@Component({ + selector: 'slides-example', + template: ` + + + +

Slide 1

+
+ +

Slide 2

+
+ +

Slide 3

+
+
+
+ `, +}) +export class SlideExample { + // Optional parameters to pass to the swiper instance. + // See http://idangero.us/swiper/api/ for valid options. + slideOpts = { + initialSlide: 1, + speed: 400, + }; + constructor() {} +} +``` + +```css +/* Without setting height the slides will take up the height of the slide's content */ +ion-slides { + height: 100%; +} +``` + +
+ + + +```html + + + +

Slide 1

+
+ + +

Slide 2

+
+ + +

Slide 3

+
+
+
+``` + +```javascript +var slides = document.querySelector('ion-slides'); + +// Optional parameters to pass to the swiper instance. +// See http://idangero.us/swiper/api/ for valid options. +slides.options = { + initialSlide: 1, + speed: 400, +}; +``` + +```css +/* Without setting height the slides will take up the height of the slide's content */ +ion-slides { + height: 100%; +} +``` + +
+ + + +```tsx +import React from 'react'; +import { IonSlides, IonSlide, IonContent } from '@ionic/react'; + +// Optional parameters to pass to the swiper instance. +// See http://idangero.us/swiper/api/ for valid options. +const slideOpts = { + initialSlide: 1, + speed: 400, +}; + +export const SlidesExample: React.FC = () => ( + + + +

Slide 1

+
+ +

Slide 2

+
+ +

Slide 3

+
+
+
+); +``` + +```css +/* Without setting height the slides will take up the height of the slide's content */ +ion-slides { + height: 100%; +} +``` + +
+ + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'slides-example', + styleUrl: 'slides-example.css', +}) +export class SlidesExample { + // Optional parameters to pass to the swiper instance. + // See http://idangero.us/swiper/api/ for valid options. + private slideOpts = { + initialSlide: 1, + speed: 400, + }; + + render() { + return [ + + + +

Slide 1

+
+ + +

Slide 2

+
+ + +

Slide 3

+
+
+
, + ]; + } +} +``` + +```css +/* Without setting height the slides will take up the height of the slide's content */ +ion-slides { + height: 100%; +} +``` + +
+ + + +```html + + + +``` + + + +
+ +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/spinner.md b/versioned_docs/version-v5/api/spinner.md deleted file mode 100644 index deb453e6bbb..00000000000 --- a/versioned_docs/version-v5/api/spinner.md +++ /dev/null @@ -1,233 +0,0 @@ ---- -title: 'ion-spinner | Animated Spinner Icon Components and Properties' -description: 'The ion-spinner component provides a variety of animated SVG spinners. These icons indicate that the app is loading or performing another process to wait on.' -sidebar_label: 'ion-spinner' -demoUrl: '/docs/demos/api/spinner/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/spinner/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/spinner/props.md'; -import Events from '@ionic-internal/component-api/v5/spinner/events.md'; -import Methods from '@ionic-internal/component-api/v5/spinner/methods.md'; -import Parts from '@ionic-internal/component-api/v5/spinner/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/spinner/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/spinner/slots.md'; - -# ion-spinner - -The Spinner component provides a variety of animated SVG spinners. Spinners are visual indicators that the app is loading content or performing another process that the user needs to wait on. - -The default spinner to use is based on the platform. The default spinner for `ios` is `"lines"`, and the default for `android` is `"crescent"`. If the platform is not `ios` or `android`, the spinner will default to `crescent`. If the `name` property is set, then that spinner will be used instead of the platform specific spinner. - -## Usage - - - - - -```html - - - - - - - - - - - - - - - - - - - - - - - -``` - - - - - -```html - - - - - - - - - - - - - - - - - - - - - - - -``` - - - - - -```tsx -import React from 'react'; -import { IonSpinner, IonContent } from '@ionic/react'; - -export const SpinnerExample: React.FC = () => ( - - {/*-- Default Spinner --*/} - - - {/*-- Lines --*/} - - - {/*-- Lines Small --*/} - - - {/*-- Dots --*/} - - - {/*-- Bubbles --*/} - - - {/*-- Circles --*/} - - - {/*-- Crescent --*/} - - - {/*-- Paused Default Spinner --*/} - - -); -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'spinner-example', - styleUrl: 'spinner-example.css', -}) -export class SpinnerExample { - render() { - return [ - // Default Spinner - , - - // Lines - , - - // Lines Small - , - - // Dots - , - - // Bubbles - , - - // Circles - , - - // Crescent - , - - // Paused Default Spinner - , - ]; - } -} -``` - - - - - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/spinner.mdx b/versioned_docs/version-v5/api/spinner.mdx new file mode 100644 index 00000000000..1be74353c42 --- /dev/null +++ b/versioned_docs/version-v5/api/spinner.mdx @@ -0,0 +1,233 @@ +--- +title: 'ion-spinner | Animated Spinner Icon Components and Properties' +description: 'The ion-spinner component provides a variety of animated SVG spinners. These icons indicate that the app is loading or performing another process to wait on.' +sidebar_label: 'ion-spinner' +demoUrl: '/docs/demos/api/spinner/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/spinner/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/spinner/props.mdx'; +import Events from '@ionic-internal/component-api/v5/spinner/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/spinner/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/spinner/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/spinner/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/spinner/slots.mdx'; + +# ion-spinner + +The Spinner component provides a variety of animated SVG spinners. Spinners are visual indicators that the app is loading content or performing another process that the user needs to wait on. + +The default spinner to use is based on the platform. The default spinner for `ios` is `"lines"`, and the default for `android` is `"crescent"`. If the platform is not `ios` or `android`, the spinner will default to `crescent`. If the `name` property is set, then that spinner will be used instead of the platform specific spinner. + +## Usage + + + + + +```html + + + + + + + + + + + + + + + + + + + + + + + +``` + + + + + +```html + + + + + + + + + + + + + + + + + + + + + + + +``` + + + + + +```tsx +import React from 'react'; +import { IonSpinner, IonContent } from '@ionic/react'; + +export const SpinnerExample: React.FC = () => ( + + {/*-- Default Spinner --*/} + + + {/*-- Lines --*/} + + + {/*-- Lines Small --*/} + + + {/*-- Dots --*/} + + + {/*-- Bubbles --*/} + + + {/*-- Circles --*/} + + + {/*-- Crescent --*/} + + + {/*-- Paused Default Spinner --*/} + + +); +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'spinner-example', + styleUrl: 'spinner-example.css', +}) +export class SpinnerExample { + render() { + return [ + // Default Spinner + , + + // Lines + , + + // Lines Small + , + + // Dots + , + + // Bubbles + , + + // Circles + , + + // Crescent + , + + // Paused Default Spinner + , + ]; + } +} +``` + + + + + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/split-pane.md b/versioned_docs/version-v5/api/split-pane.md deleted file mode 100644 index 9a975a062f4..00000000000 --- a/versioned_docs/version-v5/api/split-pane.md +++ /dev/null @@ -1,220 +0,0 @@ ---- -title: 'ion-split-pane: Split Plane View for Menus and Multi-View Layouts' -description: 'ion-split-pane is useful when creating multi-view app layouts. It allows UI elements, like menus, to be displayed as the viewport width increases.' -sidebar_label: 'ion-split-pane' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/split-pane/props.md'; -import Events from '@ionic-internal/component-api/v5/split-pane/events.md'; -import Methods from '@ionic-internal/component-api/v5/split-pane/methods.md'; -import Parts from '@ionic-internal/component-api/v5/split-pane/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/split-pane/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/split-pane/slots.md'; - -# ion-split-pane - -A split pane is useful when creating multi-view layouts. It allows UI elements, like menus, to be -displayed as the viewport width increases. - -If the device's screen width is below a certain size, the split pane will collapse and the menu will be hidden. This is ideal for creating an app that will be served in a browser and deployed through the app store to phones and tablets. - -## Setting Breakpoints - -By default, the split pane will expand when the screen is larger than 992px. To customize this, pass a breakpoint in the `when` property. The `when` property can accept a boolean value, any valid media query, or one of Ionic's predefined sizes. - -```html - - - - - -``` - -| Size | Value | Description | -| ---- | --------------------- | --------------------------------------------------------------------- | -| `xs` | `(min-width: 0px)` | Show the split-pane when the min-width is 0px (meaning, always) | -| `sm` | `(min-width: 576px)` | Show the split-pane when the min-width is 576px | -| `md` | `(min-width: 768px)` | Show the split-pane when the min-width is 768px | -| `lg` | `(min-width: 992px)` | Show the split-pane when the min-width is 992px (default break point) | -| `xl` | `(min-width: 1200px)` | Show the split-pane when the min-width is 1200px | - -## Usage - - - - - -```html - - - - - - Menu - - - - - - - -``` - - - - - -```html - - - - - - Menu - - - - - - -

Hello

-
-
-``` - -
- - - -```tsx -import React from 'react'; -import { - IonSplitPane, - IonMenu, - IonHeader, - IonToolbar, - IonTitle, - IonRouterOutlet, - IonContent, - IonPage, -} from '@ionic/react'; - -export const SplitPlaneExample: React.SFC<{}> = () => ( - - - {/*-- the side menu --*/} - - - - Menu - - - - - {/*-- the main content --*/} - - - -); -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'split-pane-example', - styleUrl: 'split-pane-example.css', -}) -export class SplitPaneExample { - render() { - return [ - - {/* the side menu */} - - - - Menu - - - - - {/* the main content */} - - , - ]; - } -} -``` - - - - - -```html - - - -``` - - - -
- -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/split-pane.mdx b/versioned_docs/version-v5/api/split-pane.mdx new file mode 100644 index 00000000000..d2c3a15bd7c --- /dev/null +++ b/versioned_docs/version-v5/api/split-pane.mdx @@ -0,0 +1,220 @@ +--- +title: 'ion-split-pane: Split Plane View for Menus and Multi-View Layouts' +description: 'ion-split-pane is useful when creating multi-view app layouts. It allows UI elements, like menus, to be displayed as the viewport width increases.' +sidebar_label: 'ion-split-pane' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/split-pane/props.mdx'; +import Events from '@ionic-internal/component-api/v5/split-pane/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/split-pane/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/split-pane/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/split-pane/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/split-pane/slots.mdx'; + +# ion-split-pane + +A split pane is useful when creating multi-view layouts. It allows UI elements, like menus, to be +displayed as the viewport width increases. + +If the device's screen width is below a certain size, the split pane will collapse and the menu will be hidden. This is ideal for creating an app that will be served in a browser and deployed through the app store to phones and tablets. + +## Setting Breakpoints + +By default, the split pane will expand when the screen is larger than 992px. To customize this, pass a breakpoint in the `when` property. The `when` property can accept a boolean value, any valid media query, or one of Ionic's predefined sizes. + +```html + + + + + +``` + +| Size | Value | Description | +| ---- | --------------------- | --------------------------------------------------------------------- | +| `xs` | `(min-width: 0px)` | Show the split-pane when the min-width is 0px (meaning, always) | +| `sm` | `(min-width: 576px)` | Show the split-pane when the min-width is 576px | +| `md` | `(min-width: 768px)` | Show the split-pane when the min-width is 768px | +| `lg` | `(min-width: 992px)` | Show the split-pane when the min-width is 992px (default break point) | +| `xl` | `(min-width: 1200px)` | Show the split-pane when the min-width is 1200px | + +## Usage + + + + + +```html + + + + + + Menu + + + + + + + +``` + + + + + +```html + + + + + + Menu + + + + + + +

Hello

+
+
+``` + +
+ + + +```tsx +import React from 'react'; +import { + IonSplitPane, + IonMenu, + IonHeader, + IonToolbar, + IonTitle, + IonRouterOutlet, + IonContent, + IonPage, +} from '@ionic/react'; + +export const SplitPlaneExample: React.SFC<{}> = () => ( + + + {/*-- the side menu --*/} + + + + Menu + + + + + {/*-- the main content --*/} + + + +); +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'split-pane-example', + styleUrl: 'split-pane-example.css', +}) +export class SplitPaneExample { + render() { + return [ + + {/* the side menu */} + + + + Menu + + + + + {/* the main content */} + + , + ]; + } +} +``` + + + + + +```html + + + +``` + + + +
+ +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/tab-bar.md b/versioned_docs/version-v5/api/tab-bar.md deleted file mode 100644 index b3884fcbcd7..00000000000 --- a/versioned_docs/version-v5/api/tab-bar.md +++ /dev/null @@ -1,159 +0,0 @@ ---- -sidebar_label: 'ion-tab-bar' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/tab-bar/props.md'; -import Events from '@ionic-internal/component-api/v5/tab-bar/events.md'; -import Methods from '@ionic-internal/component-api/v5/tab-bar/methods.md'; -import Parts from '@ionic-internal/component-api/v5/tab-bar/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/tab-bar/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/tab-bar/slots.md'; - -# ion-tab-bar - -The tab bar is a UI component that contains a set of [tab buttons](tab-button.md). A tab bar must be provided inside of [tabs](tabs.md) to communicate with each [tab](tab.md). - -## Usage - - - - - -```html - - - - - - - - - - - - - - -``` - - - - - -```html - - - - - - - - - - - - - - - - - - - -``` - - - - - -```tsx -import React from 'react'; -import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonContent } from '@ionic/react'; -import { call, person, settings } from 'ionicons/icons'; - -export const TabBarExample: React.FC = () => ( - - - {/*-- Tab bar --*/} - - - - - - - - - - - - - -); -``` - - - - - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/tab-bar.mdx b/versioned_docs/version-v5/api/tab-bar.mdx new file mode 100644 index 00000000000..e6c42a1286f --- /dev/null +++ b/versioned_docs/version-v5/api/tab-bar.mdx @@ -0,0 +1,159 @@ +--- +sidebar_label: 'ion-tab-bar' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/tab-bar/props.mdx'; +import Events from '@ionic-internal/component-api/v5/tab-bar/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/tab-bar/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/tab-bar/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/tab-bar/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/tab-bar/slots.mdx'; + +# ion-tab-bar + +The tab bar is a UI component that contains a set of [tab buttons](tab-button.mdx). A tab bar must be provided inside of [tabs](tabs.mdx) to communicate with each [tab](tab.mdx). + +## Usage + + + + + +```html + + + + + + + + + + + + + + +``` + + + + + +```html + + + + + + + + + + + + + + + + + + + +``` + + + + + +```tsx +import React from 'react'; +import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonContent } from '@ionic/react'; +import { call, person, settings } from 'ionicons/icons'; + +export const TabBarExample: React.FC = () => ( + + + {/*-- Tab bar --*/} + + + + + + + + + + + + + +); +``` + + + + + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/tab-button.md b/versioned_docs/version-v5/api/tab-button.md deleted file mode 100644 index dc197bd54cb..00000000000 --- a/versioned_docs/version-v5/api/tab-button.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -sidebar_label: 'ion-tab-button' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/tab-button/props.md'; -import Events from '@ionic-internal/component-api/v5/tab-button/events.md'; -import Methods from '@ionic-internal/component-api/v5/tab-button/methods.md'; -import Parts from '@ionic-internal/component-api/v5/tab-button/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/tab-button/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/tab-button/slots.md'; - -# ion-tab-button - -A tab button is a UI component that is placed inside of a [tab bar](tab-bar.md). The tab button can specify the layout of the icon and label and connect to a [tab view](tab.md). - -See the [tabs documentation](tabs.md) for more details on configuring tabs. - -## Usage - - - - - -```html - - - - - - Schedule - - - - - Speakers - - - - - Map - - - - - About - - - -``` - - - - - -```html - - - - - - - - - - - - - - - - - - - - - - - Schedule - - - - - Speakers - - - - - Map - - - - - About - - - -``` - - - - - -```tsx -import React from 'react'; -import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel, IonContent } from '@ionic/react'; -import { calendar, personCircle, map, informationCircle } from 'ionicons/icons'; - -export const TabButtonExample: React.FC = () => ( - - - {/*-- Tab bar --*/} - - - - Schedule - - - - - Speakers - - - - - Map - - - - - About - - - - -); -``` - - - - - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/tab-button.mdx b/versioned_docs/version-v5/api/tab-button.mdx new file mode 100644 index 00000000000..d98af53f787 --- /dev/null +++ b/versioned_docs/version-v5/api/tab-button.mdx @@ -0,0 +1,219 @@ +--- +sidebar_label: 'ion-tab-button' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/tab-button/props.mdx'; +import Events from '@ionic-internal/component-api/v5/tab-button/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/tab-button/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/tab-button/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/tab-button/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/tab-button/slots.mdx'; + +# ion-tab-button + +A tab button is a UI component that is placed inside of a [tab bar](tab-bar.mdx). The tab button can specify the layout of the icon and label and connect to a [tab view](tab.mdx). + +See the [tabs documentation](tabs.mdx) for more details on configuring tabs. + +## Usage + + + + + +```html + + + + + + Schedule + + + + + Speakers + + + + + Map + + + + + About + + + +``` + + + + + +```html + + + + + + + + + + + + + + + + + + + + + + + Schedule + + + + + Speakers + + + + + Map + + + + + About + + + +``` + + + + + +```tsx +import React from 'react'; +import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel, IonContent } from '@ionic/react'; +import { calendar, personCircle, map, informationCircle } from 'ionicons/icons'; + +export const TabButtonExample: React.FC = () => ( + + + {/*-- Tab bar --*/} + + + + Schedule + + + + + Speakers + + + + + Map + + + + + About + + + + +); +``` + + + + + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/tab.md b/versioned_docs/version-v5/api/tab.md deleted file mode 100644 index 5b15146cccd..00000000000 --- a/versioned_docs/version-v5/api/tab.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -sidebar_label: 'ion-tab' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/tab/props.md'; -import Events from '@ionic-internal/component-api/v5/tab/events.md'; -import Methods from '@ionic-internal/component-api/v5/tab/methods.md'; -import Parts from '@ionic-internal/component-api/v5/tab/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/tab/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/tab/slots.md'; - -# ion-tab - -The tab component is a child component of [tabs](tabs.md). Each tab can contain a top level navigation stack for an app or a single view. An app can have many tabs, all with their own independent navigation. - -> Note: This component should only be used with vanilla JavaScript projects. For Angular, React, and Vue apps you do not need to use `ion-tab` to declare your tab components. - -See the [tabs documentation](tabs.md) for more details on configuring tabs. - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/tab.mdx b/versioned_docs/version-v5/api/tab.mdx new file mode 100644 index 00000000000..4d541c312d6 --- /dev/null +++ b/versioned_docs/version-v5/api/tab.mdx @@ -0,0 +1,45 @@ +--- +sidebar_label: 'ion-tab' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/tab/props.mdx'; +import Events from '@ionic-internal/component-api/v5/tab/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/tab/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/tab/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/tab/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/tab/slots.mdx'; + +# ion-tab + +The tab component is a child component of [tabs](tabs.mdx). Each tab can contain a top level navigation stack for an app or a single view. An app can have many tabs, all with their own independent navigation. + +> Note: This component should only be used with vanilla JavaScript projects. For Angular, React, and Vue apps you do not need to use `ion-tab` to declare your tab components. + +See the [tabs documentation](tabs.mdx) for more details on configuring tabs. + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/tabs.md b/versioned_docs/version-v5/api/tabs.md deleted file mode 100644 index 5a8d9777831..00000000000 --- a/versioned_docs/version-v5/api/tabs.md +++ /dev/null @@ -1,447 +0,0 @@ ---- -title: 'Ion-Tabs: Tab-Based Component for App Top-Level Navigation' -description: 'Tabs are top-level components to implement tab-based navigation. Ion-tabs have no styling & work as router outlets for navigation that behaves like native apps.' -sidebar_label: 'ion-tabs' -demoUrl: '/docs/demos/api/tabs/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/tabs/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/tabs/props.md'; -import Events from '@ionic-internal/component-api/v5/tabs/events.md'; -import Methods from '@ionic-internal/component-api/v5/tabs/methods.md'; -import Parts from '@ionic-internal/component-api/v5/tabs/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/tabs/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/tabs/slots.md'; - -# ion-tabs - -Tabs are a top level navigation component to implement a tab-based navigation. -The component is a container of individual [Tab](tab.md) components. - -The `ion-tabs` component does not have any styling and works as a router outlet in order to handle navigation. It does not provide any UI feedback or mechanism to switch between tabs. In order to do so, an `ion-tab-bar` should be provided as a direct child of `ion-tabs`. - -Both `ion-tabs` and `ion-tab-bar` can be used as standalone elements. They don’t depend on each other to work, but they are usually used together in order to implement a tab-based navigation that behaves like a native app. - -The `ion-tab-bar` needs a slot defined in order to be projected to the right place in an `ion-tabs` component. - -## Usage - - - - - -```html - - - - - Schedule - 6 - - - - - Speakers - - - - - Map - - - - - About - - - -``` - -### Router integration - -When used with Angular's router the `tab` property of the `ion-tab-button` should be a reference to the route path. - -```html - - - - - Schedule - - - -``` - -```tsx -import { Routes } from '@angular/router'; -import { TabsPage } from './tabs-page'; - -const routes: Routes = [ - { - path: 'tabs', - component: TabsPage, - children: [ - { - path: 'schedule', - children: [ - { - path: '', - loadChildren: '../schedule/schedule.module#ScheduleModule', - }, - ], - }, - { - path: '', - redirectTo: '/app/tabs/schedule', - pathMatch: 'full', - }, - ], - }, -]; -``` - - - - - -```html - - - - - - - - - - - - - - - - - - - - - Schedule - 6 - - - - - Speakers - - - - - Map - - - - - About - - - -``` - -### Activating Tabs - -Each `ion-tab-button` will activate one of the tabs when pressed. In order to link the `ion-tab-button` to the `ion-tab` container, a matching `tab` property should be set on each component. - -```html - ... - - ... -``` - -The `ion-tab-button` and `ion-tab` above are linked by the common `tab` property. - -The `tab` property identifies each tab, and it has to be unique within the `ion-tabs`. It's important to always set the `tab` property on the `ion-tab` and `ion-tab-button`, even if one component is not used. - -### Router integration - -When used with Ionic's router (`ion-router`) the `tab` property of the `ion-tab` matches the `component` property of an `ion-route`. - -The following route within the scope of an `ion-tabs` outlet: - -```html - -``` - -will match the following tab: - -```html - -``` - - - - - -```tsx -import React from 'react'; -import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel, IonBadge } from '@ionic/react'; -import { calendar, personCircle, map, informationCircle } from 'ionicons/icons'; - -export const TabsExample: React.FC = () => ( - - - - - Schedule - 6 - - - - - Speakers - - - - - Map - - - - - About - - - -); -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'tabs-example', - styleUrl: 'tabs-example.css', -}) -export class TabsExample { - render() { - return [ - - - - - - - - - - - - - - - - - - - - - Schedule - 6 - - - - - Speakers - - - - - Map - - - - - About - - - , - ]; - } -} -``` - -### Activating Tabs - -Each `ion-tab-button` will activate one of the tabs when pressed. In order to link the `ion-tab-button` to the `ion-tab` container, a matching `tab` property should be set on each component. - -```jsx - - ... - - - - ... - -``` - -The `ion-tab-button` and `ion-tab` above are linked by the common `tab` property. - -The `tab` property identifies each tab, and it has to be unique within the `ion-tabs`. It's important to always set the `tab` property on the `ion-tab` and `ion-tab-button`, even if one component is not used. - -### Router integration - -When used with Ionic's router (`ion-router`) the `tab` property of the `ion-tab` matches the `component` property of an `ion-route`. - -The following route within the scope of an `ion-tabs` outlet: - -```tsx - -``` - -will match the following tab: - -```tsx - -``` - - - - - -**Tabs.vue** - -```html - - - -``` - -**Schedule.vue** - -```html - - - -``` - -**Speakers.vue** - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/tabs.mdx b/versioned_docs/version-v5/api/tabs.mdx new file mode 100644 index 00000000000..7a560efed87 --- /dev/null +++ b/versioned_docs/version-v5/api/tabs.mdx @@ -0,0 +1,447 @@ +--- +title: 'Ion-Tabs: Tab-Based Component for App Top-Level Navigation' +description: 'Tabs are top-level components to implement tab-based navigation. Ion-tabs have no styling & work as router outlets for navigation that behaves like native apps.' +sidebar_label: 'ion-tabs' +demoUrl: '/docs/demos/api/tabs/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/tabs/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/tabs/props.mdx'; +import Events from '@ionic-internal/component-api/v5/tabs/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/tabs/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/tabs/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/tabs/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/tabs/slots.mdx'; + +# ion-tabs + +Tabs are a top level navigation component to implement a tab-based navigation. +The component is a container of individual [Tab](tab.mdx) components. + +The `ion-tabs` component does not have any styling and works as a router outlet in order to handle navigation. It does not provide any UI feedback or mechanism to switch between tabs. In order to do so, an `ion-tab-bar` should be provided as a direct child of `ion-tabs`. + +Both `ion-tabs` and `ion-tab-bar` can be used as standalone elements. They don’t depend on each other to work, but they are usually used together in order to implement a tab-based navigation that behaves like a native app. + +The `ion-tab-bar` needs a slot defined in order to be projected to the right place in an `ion-tabs` component. + +## Usage + + + + + +```html + + + + + Schedule + 6 + + + + + Speakers + + + + + Map + + + + + About + + + +``` + +### Router integration + +When used with Angular's router the `tab` property of the `ion-tab-button` should be a reference to the route path. + +```html + + + + + Schedule + + + +``` + +```tsx +import { Routes } from '@angular/router'; +import { TabsPage } from './tabs-page'; + +const routes: Routes = [ + { + path: 'tabs', + component: TabsPage, + children: [ + { + path: 'schedule', + children: [ + { + path: '', + loadChildren: '../schedule/schedule.module#ScheduleModule', + }, + ], + }, + { + path: '', + redirectTo: '/app/tabs/schedule', + pathMatch: 'full', + }, + ], + }, +]; +``` + + + + + +```html + + + + + + + + + + + + + + + + + + + + + Schedule + 6 + + + + + Speakers + + + + + Map + + + + + About + + + +``` + +### Activating Tabs + +Each `ion-tab-button` will activate one of the tabs when pressed. In order to link the `ion-tab-button` to the `ion-tab` container, a matching `tab` property should be set on each component. + +```html + ... + + ... +``` + +The `ion-tab-button` and `ion-tab` above are linked by the common `tab` property. + +The `tab` property identifies each tab, and it has to be unique within the `ion-tabs`. It's important to always set the `tab` property on the `ion-tab` and `ion-tab-button`, even if one component is not used. + +### Router integration + +When used with Ionic's router (`ion-router`) the `tab` property of the `ion-tab` matches the `component` property of an `ion-route`. + +The following route within the scope of an `ion-tabs` outlet: + +```html + +``` + +will match the following tab: + +```html + +``` + + + + + +```tsx +import React from 'react'; +import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel, IonBadge } from '@ionic/react'; +import { calendar, personCircle, map, informationCircle } from 'ionicons/icons'; + +export const TabsExample: React.FC = () => ( + + + + + Schedule + 6 + + + + + Speakers + + + + + Map + + + + + About + + + +); +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'tabs-example', + styleUrl: 'tabs-example.css', +}) +export class TabsExample { + render() { + return [ + + + + + + + + + + + + + + + + + + + + + Schedule + 6 + + + + + Speakers + + + + + Map + + + + + About + + + , + ]; + } +} +``` + +### Activating Tabs + +Each `ion-tab-button` will activate one of the tabs when pressed. In order to link the `ion-tab-button` to the `ion-tab` container, a matching `tab` property should be set on each component. + +```jsx + + ... + + + + ... + +``` + +The `ion-tab-button` and `ion-tab` above are linked by the common `tab` property. + +The `tab` property identifies each tab, and it has to be unique within the `ion-tabs`. It's important to always set the `tab` property on the `ion-tab` and `ion-tab-button`, even if one component is not used. + +### Router integration + +When used with Ionic's router (`ion-router`) the `tab` property of the `ion-tab` matches the `component` property of an `ion-route`. + +The following route within the scope of an `ion-tabs` outlet: + +```tsx + +``` + +will match the following tab: + +```tsx + +``` + + + + + +**Tabs.vue** + +```html + + + +``` + +**Schedule.vue** + +```html + + + +``` + +**Speakers.vue** + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/text.md b/versioned_docs/version-v5/api/text.md deleted file mode 100644 index 81af4617abc..00000000000 --- a/versioned_docs/version-v5/api/text.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -sidebar_label: 'ion-text' -demoUrl: '/docs/demos/api/text/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/text/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/text/props.md'; -import Events from '@ionic-internal/component-api/v5/text/events.md'; -import Methods from '@ionic-internal/component-api/v5/text/methods.md'; -import Parts from '@ionic-internal/component-api/v5/text/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/text/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/text/slots.md'; - -# ion-text - -The text component is a simple component that can be used to style the text color of any element. The `ion-text` element should wrap the element in order to change the text color of that element. - -## Usage - -```html - -

H1: The quick brown fox jumps over the lazy dog

-
- - -

H2: The quick brown fox jumps over the lazy dog

-
- - -

H3: The quick brown fox jumps over the lazy dog

-
- - -

H4: The quick brown fox jumps over the lazy dog

-
- - -
H5: The quick brown fox jumps over the lazy dog
-
- -

- I saw a werewolf with a Chinese menu in his hand. Walking through the - streets of Soho in the rain. He - was looking for a place called Lee Ho Fook's. Gonna get a - big dish of beef chow mein. - -

-``` - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/text.mdx b/versioned_docs/version-v5/api/text.mdx new file mode 100644 index 00000000000..e8591180047 --- /dev/null +++ b/versioned_docs/version-v5/api/text.mdx @@ -0,0 +1,75 @@ +--- +sidebar_label: 'ion-text' +demoUrl: '/docs/demos/api/text/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/text/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/text/props.mdx'; +import Events from '@ionic-internal/component-api/v5/text/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/text/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/text/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/text/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/text/slots.mdx'; + +# ion-text + +The text component is a simple component that can be used to style the text color of any element. The `ion-text` element should wrap the element in order to change the text color of that element. + +## Usage + +```html + +

H1: The quick brown fox jumps over the lazy dog

+
+ + +

H2: The quick brown fox jumps over the lazy dog

+
+ + +

H3: The quick brown fox jumps over the lazy dog

+
+ + +

H4: The quick brown fox jumps over the lazy dog

+
+ + +
H5: The quick brown fox jumps over the lazy dog
+
+ +

+ I saw a werewolf with a Chinese menu in his hand. Walking through the + streets of Soho in the rain. He + was looking for a place called Lee Ho Fook's. Gonna get a + big dish of beef chow mein. + +

+``` + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/textarea.md b/versioned_docs/version-v5/api/textarea.md deleted file mode 100644 index 166bd8d6fd0..00000000000 --- a/versioned_docs/version-v5/api/textarea.md +++ /dev/null @@ -1,314 +0,0 @@ ---- -sidebar_label: 'ion-textarea' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/textarea/props.md'; -import Events from '@ionic-internal/component-api/v5/textarea/events.md'; -import Methods from '@ionic-internal/component-api/v5/textarea/methods.md'; -import Parts from '@ionic-internal/component-api/v5/textarea/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/textarea/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/textarea/slots.md'; - -# ion-textarea - -The textarea component is used for multi-line text input. A native textarea element is rendered inside of the component. The user experience and interactivity of the textarea component is improved by having control over the native textarea. - -Unlike the native textarea element, the Ionic textarea does not support loading its value from the inner content. The textarea value should be set in the `value` attribute. - -The textarea component accepts the [native textarea attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) in addition to the Ionic properties. - -## Usage - - - - - -```html - - - - - - - - - - - Description - - - - - - Summary - - - - - - - Comment - - - - - - Notes - - -``` - - - - - -```html - - - - - - - - - - - Description - - - - - - Summary - - - - - - - Comment - - - - - - Notes - - -``` - - - - - -```tsx -import React, { useState } from 'react'; -import { - IonContent, - IonHeader, - IonPage, - IonTitle, - IonToolbar, - IonTextarea, - IonItem, - IonLabel, - IonItemDivider, - IonList, -} from '@ionic/react'; - -export const TextAreaExamples: React.FC = () => { - const [text, setText] = useState(); - - return ( - - - - TextArea Examples - - - - - Default textarea - - setText(e.detail.value!)}> - - - Textarea in an item with a placeholder - - setText(e.detail.value!)} - > - - - Textarea in an item with a floating label - - Description - setText(e.detail.value!)}> - - - Disabled and readonly textarea in an item with a stacked label - - Summary - setText(e.detail.value!)}> - - - Textarea that clears the value on edit - - Comment - setText(e.detail.value!)}> - - - Textarea with custom number of rows and cols - - Notes - setText(e.detail.value!)} - > - - - - - ); -}; -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'textarea-example', - styleUrl: 'textarea-example.css', -}) -export class TextareaExample { - render() { - return [ - // Default textarea - , - - // Textarea in an item with a placeholder - - - , - - // Textarea in an item with a floating label - - Description - - , - - // Disabled and readonly textarea in an item with a stacked label - - Summary - - , - - // Textarea that clears the value on edit - - Comment - - , - - // Textarea with custom number of rows and cols - - Notes - - , - ]; - } -} -``` - - - - - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/textarea.mdx b/versioned_docs/version-v5/api/textarea.mdx new file mode 100644 index 00000000000..82602f9ff83 --- /dev/null +++ b/versioned_docs/version-v5/api/textarea.mdx @@ -0,0 +1,314 @@ +--- +sidebar_label: 'ion-textarea' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/textarea/props.mdx'; +import Events from '@ionic-internal/component-api/v5/textarea/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/textarea/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/textarea/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/textarea/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/textarea/slots.mdx'; + +# ion-textarea + +The textarea component is used for multi-line text input. A native textarea element is rendered inside of the component. The user experience and interactivity of the textarea component is improved by having control over the native textarea. + +Unlike the native textarea element, the Ionic textarea does not support loading its value from the inner content. The textarea value should be set in the `value` attribute. + +The textarea component accepts the [native textarea attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) in addition to the Ionic properties. + +## Usage + + + + + +```html + + + + + + + + + + + Description + + + + + + Summary + + + + + + + Comment + + + + + + Notes + + +``` + + + + + +```html + + + + + + + + + + + Description + + + + + + Summary + + + + + + + Comment + + + + + + Notes + + +``` + + + + + +```tsx +import React, { useState } from 'react'; +import { + IonContent, + IonHeader, + IonPage, + IonTitle, + IonToolbar, + IonTextarea, + IonItem, + IonLabel, + IonItemDivider, + IonList, +} from '@ionic/react'; + +export const TextAreaExamples: React.FC = () => { + const [text, setText] = useState(); + + return ( + + + + TextArea Examples + + + + + Default textarea + + setText(e.detail.value!)}> + + + Textarea in an item with a placeholder + + setText(e.detail.value!)} + > + + + Textarea in an item with a floating label + + Description + setText(e.detail.value!)}> + + + Disabled and readonly textarea in an item with a stacked label + + Summary + setText(e.detail.value!)}> + + + Textarea that clears the value on edit + + Comment + setText(e.detail.value!)}> + + + Textarea with custom number of rows and cols + + Notes + setText(e.detail.value!)} + > + + + + + ); +}; +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'textarea-example', + styleUrl: 'textarea-example.css', +}) +export class TextareaExample { + render() { + return [ + // Default textarea + , + + // Textarea in an item with a placeholder + + + , + + // Textarea in an item with a floating label + + Description + + , + + // Disabled and readonly textarea in an item with a stacked label + + Summary + + , + + // Textarea that clears the value on edit + + Comment + + , + + // Textarea with custom number of rows and cols + + Notes + + , + ]; + } +} +``` + + + + + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/thumbnail.md b/versioned_docs/version-v5/api/thumbnail.md deleted file mode 100644 index e8fa9edeba2..00000000000 --- a/versioned_docs/version-v5/api/thumbnail.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -sidebar_label: 'ion-thumbnail' -demoUrl: '/docs/demos/api/thumbnail/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/thumbnail/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/thumbnail/props.md'; -import Events from '@ionic-internal/component-api/v5/thumbnail/events.md'; -import Methods from '@ionic-internal/component-api/v5/thumbnail/methods.md'; -import Parts from '@ionic-internal/component-api/v5/thumbnail/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/thumbnail/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/thumbnail/slots.md'; - -# ion-thumbnail - -Thumbnails are square components that usually wrap an image or icon. They can be used to make it easier to display a group of larger images or provide a preview of the full-size image. - -Thumbnails can be used by themselves or inside of any element. If placed inside of an `ion-item`, the thumbnail will resize to fit the parent component. To position a thumbnail on the left or right side of an item, set the slot to `start` or `end`, respectively. - -## Usage - - - - - -```html - - - - - - - - - Item Thumbnail - -``` - - - - - -```html - - - - - - - - - Item Thumbnail - -``` - - - - - -```tsx -import React from 'react'; -import { IonThumbnail, IonItem, IonLabel, IonContent } from '@ionic/react'; - -export const ThumbnailExample: React.FC = () => ( - - - - - - - - - - Item Thumbnail - - -); -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'thumbnail-example', - styleUrl: 'thumbnail-example.css', -}) -export class ThumbnailExample { - render() { - return [ - - - , - - - - - - Item Thumbnail - , - ]; - } -} -``` - - - - - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/thumbnail.mdx b/versioned_docs/version-v5/api/thumbnail.mdx new file mode 100644 index 00000000000..679161f4f61 --- /dev/null +++ b/versioned_docs/version-v5/api/thumbnail.mdx @@ -0,0 +1,166 @@ +--- +sidebar_label: 'ion-thumbnail' +demoUrl: '/docs/demos/api/thumbnail/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/thumbnail/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/thumbnail/props.mdx'; +import Events from '@ionic-internal/component-api/v5/thumbnail/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/thumbnail/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/thumbnail/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/thumbnail/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/thumbnail/slots.mdx'; + +# ion-thumbnail + +Thumbnails are square components that usually wrap an image or icon. They can be used to make it easier to display a group of larger images or provide a preview of the full-size image. + +Thumbnails can be used by themselves or inside of any element. If placed inside of an `ion-item`, the thumbnail will resize to fit the parent component. To position a thumbnail on the left or right side of an item, set the slot to `start` or `end`, respectively. + +## Usage + + + + + +```html + + + + + + + + + Item Thumbnail + +``` + + + + + +```html + + + + + + + + + Item Thumbnail + +``` + + + + + +```tsx +import React from 'react'; +import { IonThumbnail, IonItem, IonLabel, IonContent } from '@ionic/react'; + +export const ThumbnailExample: React.FC = () => ( + + + + + + + + + + Item Thumbnail + + +); +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'thumbnail-example', + styleUrl: 'thumbnail-example.css', +}) +export class ThumbnailExample { + render() { + return [ + + + , + + + + + + Item Thumbnail + , + ]; + } +} +``` + + + + + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/title.md b/versioned_docs/version-v5/api/title.md deleted file mode 100644 index f55c320ea96..00000000000 --- a/versioned_docs/version-v5/api/title.md +++ /dev/null @@ -1,657 +0,0 @@ ---- -title: 'ion-title: Ionic Framework App Title Component for Toolbars' -description: 'ion-title is a component that sets the title of the toolbar. Read to learn more about title and collapsible title components and usage for Ionic Framework Apps.' -sidebar_label: 'ion-title' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/title/props.md'; -import Events from '@ionic-internal/component-api/v5/title/events.md'; -import Methods from '@ionic-internal/component-api/v5/title/methods.md'; -import Parts from '@ionic-internal/component-api/v5/title/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/title/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/title/slots.md'; - -# ion-title - -`ion-title` is a component that sets the title of the `Toolbar`. - -## Usage - - - - - -```html - - - Default Title - - - - - Small Title above a Default Title - - - Default Title - - - - - Large Title - -``` - -### Collapsible Large Titles - -Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `ion-title`, `ion-header`, and (optionally) `ion-buttons` elements. - -```html - - - Settings - - - - - - - Settings - - - - - - - ... - -``` - -In the example above, notice there are two `ion-header` elements. The first `ion-header` represents the "collapsed" state of your collapsible header, and the second `ion-header` represents the "expanded" state of your collapsible header. Notice that the second `ion-header` must have `collapse="condense"` and must exist within `ion-content`. Additionally, in order to get the large title styling, `ion-title` must have `size="large"`. - -```html - - - - Click Me - - Settings - - - - - - - - Click Me - - Settings - - - - - - - ... - -``` - -In this example, notice that we have added two sets of `ion-buttons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `ion-title` element. - -`ion-buttons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. - -> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `ion-content` and `translucent` is set to `true` on the main `ion-header`. - -### Styling Collapsible Large Titles - -The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `ion-toolbar` that contains the collapsible large title should always match the background color of `ion-content`. - -By default, the `ion-toolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `ion-content`. - -You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `ion-toolbar`. This will give the effect of the header changing color as you collapse the large title. - -When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. - -```css -ion-title.large-title { - color: purple; - font-size: 30px; -} -``` - - - - - -```html - - - Default Title - - - - - Small Title above a Default Title - - - Default Title - - - - - Large Title - -``` - -### Collapsible Large Titles - -Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `ion-title`, `ion-header`, and (optionally) `ion-buttons` elements. - -```html - - - Settings - - - - - - - Settings - - - - - - - ... - -``` - -In the example above, notice there are two `ion-header` elements. The first `ion-header` represents the "collapsed" state of your collapsible header, and the second `ion-header` represents the "expanded" state of your collapsible header. Notice that the second `ion-header` must have `collapse="condense"` and must exist within `ion-content`. Additionally, in order to get the large title styling, `ion-title` must have `size="large"`. - -```html - - - - Click Me - - Settings - - - - - - - - Click Me - - Settings - - - - - - - ... - -``` - -In this example, notice that we have added two sets of `ion-buttons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `ion-title` element. - -`ion-buttons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. - -> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `ion-content` and `translucent` is set to `true` on the main `ion-header`. - -### Styling Collapsible Large Titles - -The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `ion-toolbar` that contains the collapsible large title should always match the background color of `ion-content`. - -By default, the `ion-toolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `ion-content`. - -You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `ion-toolbar`. This will give the effect of the header changing color as you collapse the large title. - -When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. - -```css -ion-title.large-title { - color: purple; - font-size: 30px; -} -``` - - - - - -```tsx -import React from 'react'; -import { - IonTitle, - IonToolbar -} from '@ionic/react'; - -export const ToolbarExample: React.FC = () => ( - {/*-- Default title --*/} - - Default Title - - - {/*-- Small title --*/} - - Small Title above a Default Title - - - Default Title - - - {/*-- Large title --*/} - - Large Title - -); -``` - -### Collapsible Large Titles - -Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `IonTitle`, `IonHeader`, and (optionally) `IonButtons` elements. - -```tsx -import React from 'react'; -import { IonContent, IonHeader, IonSearchbar, IonTitle, IonToolbar } from '@ionic/react'; - -export const LargeTitleExample: React.FC = () => ( - <> - - - Settings - - - - - - - Settings - - - - - - ... - - -); -``` - -In the example above, notice there are two `IonHeader` elements. The first `IonHeader` represents the "collapsed" state of your collapsible header, and the second `IonHeader` represents the "expanded" state of your collapsible header. Notice that the second `IonHeader` must have `collapse="condense"` and must exist within `IonContent`. Additionally, in order to get the large title styling, `IonTitle` must have `size="large"`. - -```tsx -import React from 'react'; -import { IonButton, IonButtons, IonContent, IonHeader, IonSearchbar, IonTitle, IonToolbar } from '@ionic/react'; - -export const LargeTitleExample: React.FC = () => ( - <> - - - - Click Me - - Settings - - - - - - - - Click Me - - Settings - - - - - - ... - - -); -``` - -In this example, notice that we have added two sets of `IonButtons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `IonTitle` element. - -`IonButtons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. - -> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `IonContent` and `translucent="true"` be set on the main `IonHeader`. - -### Styling Collapsible Large Titles - -The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `IonToolbar` that contains the collapsible large title should always match the background color of `IonContent`. - -By default, the `IonToolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `IonContent`. - -You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `IonToolbar`. This will give the effect of the header changing color as you collapse the large title. - -When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. - -```css -ion-title.large-title { - color: purple; - font-size: 30px; -} -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'title-example', - styleUrl: 'title-example.css', -}) -export class TitleExample { - render() { - return [ - // Default title - - Default Title - , - - // Small title above a default title - - Small Title above a Default Title - , - - Default Title - , - - // Large title - - Large Title - , - ]; - } -} -``` - -### Collapsible Large Titles - -Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `ion-title`, `ion-header`, and (optionally) `ion-buttons` elements. - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'title-example', - styleUrl: 'title-example.css', -}) -export class TitleExample { - render() { - return [ - - - Settings - - , - - - - - Settings - - - - - - ... - , - ]; - } -} -``` - -In the example above, notice there are two `ion-header` elements. The first `ion-header` represents the "collapsed" state of your collapsible header, and the second `ion-header` represents the "expanded" state of your collapsible header. Notice that the second `ion-header` must have `collapse="condense"` and must exist within `ion-content`. Additionally, in order to get the large title styling, `ion-title` must have `size="large"`. - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'title-example', - styleUrl: 'title-example.css', -}) -export class TitleExample { - render() { - return [ - - - - Click Me - - Settings - - , - - - - - - Click Me - - Settings - - - - - - ... - , - ]; - } -} -``` - -In this example, notice that we have added two sets of `ion-buttons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `ion-title` element. - -`ion-buttons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. - -When styling the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. - -> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `ion-content` and `translucent` is set to `true` on the main `ion-header`. - -### Styling Collapsible Large Titles - -The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `ion-toolbar` that contains the collapsible large title should always match the background color of `ion-content`. - -By default, the `ion-toolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `ion-content`. - -You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `ion-toolbar`. This will give the effect of the header changing color as you collapse the large title. - -When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. - -```css -ion-title.large-title { - color: purple; - font-size: 30px; -} -``` - - - - - -```html - - - -``` - -### Collapsible Large Titles - -Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `ion-title`, `ion-header`, and (optionally) `ion-buttons` elements. - -```html - - - -``` - -In the example above, notice there are two `ion-header` elements. The first `ion-header` represents the "collapsed" state of your collapsible header, and the second `ion-header` represents the "expanded" state of your collapsible header. Notice that the second `ion-header` must have `collapse="condense"` and must exist within `ion-content`. Additionally, in order to get the large title styling, `ion-title` must have `size="large"`. - -```html - - - -``` - -In this example, notice that we have added two sets of `ion-buttons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `ion-title` element. - -`ion-buttons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. - -> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `ion-content` and `translucent` is set to `true` on the main `ion-header`. - -### Styling Collapsible Large Titles - -The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `ion-toolbar` that contains the collapsible large title should always match the background color of `ion-content`. - -By default, the `ion-toolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `ion-content`. - -You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `ion-toolbar`. This will give the effect of the header changing color as you collapse the large title. - -When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. - -```css -ion-title.large-title { - color: purple; - font-size: 30px; -} -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/title.mdx b/versioned_docs/version-v5/api/title.mdx new file mode 100644 index 00000000000..ecba94e8a66 --- /dev/null +++ b/versioned_docs/version-v5/api/title.mdx @@ -0,0 +1,657 @@ +--- +title: 'ion-title: Ionic Framework App Title Component for Toolbars' +description: 'ion-title is a component that sets the title of the toolbar. Read to learn more about title and collapsible title components and usage for Ionic Framework Apps.' +sidebar_label: 'ion-title' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/title/props.mdx'; +import Events from '@ionic-internal/component-api/v5/title/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/title/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/title/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/title/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/title/slots.mdx'; + +# ion-title + +`ion-title` is a component that sets the title of the `Toolbar`. + +## Usage + + + + + +```html + + + Default Title + + + + + Small Title above a Default Title + + + Default Title + + + + + Large Title + +``` + +### Collapsible Large Titles + +Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `ion-title`, `ion-header`, and (optionally) `ion-buttons` elements. + +```html + + + Settings + + + + + + + Settings + + + + + + + ... + +``` + +In the example above, notice there are two `ion-header` elements. The first `ion-header` represents the "collapsed" state of your collapsible header, and the second `ion-header` represents the "expanded" state of your collapsible header. Notice that the second `ion-header` must have `collapse="condense"` and must exist within `ion-content`. Additionally, in order to get the large title styling, `ion-title` must have `size="large"`. + +```html + + + + Click Me + + Settings + + + + + + + + Click Me + + Settings + + + + + + + ... + +``` + +In this example, notice that we have added two sets of `ion-buttons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `ion-title` element. + +`ion-buttons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. + +> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `ion-content` and `translucent` is set to `true` on the main `ion-header`. + +### Styling Collapsible Large Titles + +The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `ion-toolbar` that contains the collapsible large title should always match the background color of `ion-content`. + +By default, the `ion-toolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `ion-content`. + +You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `ion-toolbar`. This will give the effect of the header changing color as you collapse the large title. + +When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. + +```css +ion-title.large-title { + color: purple; + font-size: 30px; +} +``` + + + + + +```html + + + Default Title + + + + + Small Title above a Default Title + + + Default Title + + + + + Large Title + +``` + +### Collapsible Large Titles + +Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `ion-title`, `ion-header`, and (optionally) `ion-buttons` elements. + +```html + + + Settings + + + + + + + Settings + + + + + + + ... + +``` + +In the example above, notice there are two `ion-header` elements. The first `ion-header` represents the "collapsed" state of your collapsible header, and the second `ion-header` represents the "expanded" state of your collapsible header. Notice that the second `ion-header` must have `collapse="condense"` and must exist within `ion-content`. Additionally, in order to get the large title styling, `ion-title` must have `size="large"`. + +```html + + + + Click Me + + Settings + + + + + + + + Click Me + + Settings + + + + + + + ... + +``` + +In this example, notice that we have added two sets of `ion-buttons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `ion-title` element. + +`ion-buttons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. + +> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `ion-content` and `translucent` is set to `true` on the main `ion-header`. + +### Styling Collapsible Large Titles + +The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `ion-toolbar` that contains the collapsible large title should always match the background color of `ion-content`. + +By default, the `ion-toolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `ion-content`. + +You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `ion-toolbar`. This will give the effect of the header changing color as you collapse the large title. + +When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. + +```css +ion-title.large-title { + color: purple; + font-size: 30px; +} +``` + + + + + +```tsx +import React from 'react'; +import { + IonTitle, + IonToolbar +} from '@ionic/react'; + +export const ToolbarExample: React.FC = () => ( + {/*-- Default title --*/} + + Default Title + + + {/*-- Small title --*/} + + Small Title above a Default Title + + + Default Title + + + {/*-- Large title --*/} + + Large Title + +); +``` + +### Collapsible Large Titles + +Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `IonTitle`, `IonHeader`, and (optionally) `IonButtons` elements. + +```tsx +import React from 'react'; +import { IonContent, IonHeader, IonSearchbar, IonTitle, IonToolbar } from '@ionic/react'; + +export const LargeTitleExample: React.FC = () => ( + <> + + + Settings + + + + + + + Settings + + + + + + ... + + +); +``` + +In the example above, notice there are two `IonHeader` elements. The first `IonHeader` represents the "collapsed" state of your collapsible header, and the second `IonHeader` represents the "expanded" state of your collapsible header. Notice that the second `IonHeader` must have `collapse="condense"` and must exist within `IonContent`. Additionally, in order to get the large title styling, `IonTitle` must have `size="large"`. + +```tsx +import React from 'react'; +import { IonButton, IonButtons, IonContent, IonHeader, IonSearchbar, IonTitle, IonToolbar } from '@ionic/react'; + +export const LargeTitleExample: React.FC = () => ( + <> + + + + Click Me + + Settings + + + + + + + + Click Me + + Settings + + + + + + ... + + +); +``` + +In this example, notice that we have added two sets of `IonButtons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `IonTitle` element. + +`IonButtons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. + +> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `IonContent` and `translucent="true"` be set on the main `IonHeader`. + +### Styling Collapsible Large Titles + +The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `IonToolbar` that contains the collapsible large title should always match the background color of `IonContent`. + +By default, the `IonToolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `IonContent`. + +You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `IonToolbar`. This will give the effect of the header changing color as you collapse the large title. + +When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. + +```css +ion-title.large-title { + color: purple; + font-size: 30px; +} +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'title-example', + styleUrl: 'title-example.css', +}) +export class TitleExample { + render() { + return [ + // Default title + + Default Title + , + + // Small title above a default title + + Small Title above a Default Title + , + + Default Title + , + + // Large title + + Large Title + , + ]; + } +} +``` + +### Collapsible Large Titles + +Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `ion-title`, `ion-header`, and (optionally) `ion-buttons` elements. + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'title-example', + styleUrl: 'title-example.css', +}) +export class TitleExample { + render() { + return [ + + + Settings + + , + + + + + Settings + + + + + + ... + , + ]; + } +} +``` + +In the example above, notice there are two `ion-header` elements. The first `ion-header` represents the "collapsed" state of your collapsible header, and the second `ion-header` represents the "expanded" state of your collapsible header. Notice that the second `ion-header` must have `collapse="condense"` and must exist within `ion-content`. Additionally, in order to get the large title styling, `ion-title` must have `size="large"`. + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'title-example', + styleUrl: 'title-example.css', +}) +export class TitleExample { + render() { + return [ + + + + Click Me + + Settings + + , + + + + + + Click Me + + Settings + + + + + + ... + , + ]; + } +} +``` + +In this example, notice that we have added two sets of `ion-buttons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `ion-title` element. + +`ion-buttons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. + +When styling the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. + +> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `ion-content` and `translucent` is set to `true` on the main `ion-header`. + +### Styling Collapsible Large Titles + +The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `ion-toolbar` that contains the collapsible large title should always match the background color of `ion-content`. + +By default, the `ion-toolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `ion-content`. + +You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `ion-toolbar`. This will give the effect of the header changing color as you collapse the large title. + +When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. + +```css +ion-title.large-title { + color: purple; + font-size: 30px; +} +``` + + + + + +```html + + + +``` + +### Collapsible Large Titles + +Ionic provides a way to create the collapsible titles that exist on stock iOS apps. Getting this setup requires configuring your `ion-title`, `ion-header`, and (optionally) `ion-buttons` elements. + +```html + + + +``` + +In the example above, notice there are two `ion-header` elements. The first `ion-header` represents the "collapsed" state of your collapsible header, and the second `ion-header` represents the "expanded" state of your collapsible header. Notice that the second `ion-header` must have `collapse="condense"` and must exist within `ion-content`. Additionally, in order to get the large title styling, `ion-title` must have `size="large"`. + +```html + + + +``` + +In this example, notice that we have added two sets of `ion-buttons` both with `collapse` set to `true`. When the secondary header collapses, the buttons in the secondary header will hide, and the buttons in the primary header will show. This is useful for ensuring that your header buttons always appear next to an `ion-title` element. + +`ion-buttons` elements that do not have `collapse` set will always be visible, regardless of collapsed state. When using the large title and `ion-buttons` elements inside of `ion-content`, the `ion-buttons` elements should always be placed in the `end` slot. + +> When using collapsible large titles, it is required that `fullscreen` is set to `true` on `ion-content` and `translucent` is set to `true` on the main `ion-header`. + +### Styling Collapsible Large Titles + +The collapsible large title should appear seamless in relation to the rest of your content. This means that the background color of the `ion-toolbar` that contains the collapsible large title should always match the background color of `ion-content`. + +By default, the `ion-toolbar` that contains the standard title is hidden using `opacity: 0` and is progressively shown as you collapse the large title by scrolling. As a result, the background color that you see behind the standard title is actually the background color of `ion-content`. + +You can change the background color of the toolbar with the standard title by setting the `--background` CSS variable on `ion-toolbar`. This will give the effect of the header changing color as you collapse the large title. + +When styling the text color of the large title, you should target the large title globally as opposed to within the context of a particular page or tab, otherwise its styles will not be applied during the navigation animation. + +```css +ion-title.large-title { + color: purple; + font-size: 30px; +} +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/toast.md b/versioned_docs/version-v5/api/toast.md deleted file mode 100644 index dd4b4b7b962..00000000000 --- a/versioned_docs/version-v5/api/toast.md +++ /dev/null @@ -1,403 +0,0 @@ ---- -sidebar_label: 'ion-toast' -demoUrl: '/docs/demos/api/toast/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/toast/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/toast/props.md'; -import Events from '@ionic-internal/component-api/v5/toast/events.md'; -import Methods from '@ionic-internal/component-api/v5/toast/methods.md'; -import Parts from '@ionic-internal/component-api/v5/toast/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/toast/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/toast/slots.md'; - -# ion-toast - -A Toast is a subtle notification commonly used in modern applications. It can be used to provide feedback about an operation or to display a system message. The toast appears on top of the app's content, and can be dismissed by the app to resume user interaction with the app. - -## Positioning - -Toasts can be positioned at the top, bottom or middle of the viewport. The position can be passed upon creation. The possible values are `top`, `bottom` and `middle`. If the position is not specified, the toast will be displayed at the bottom of the viewport. - -## Dismissing - -The toast can be dismissed automatically after a specific amount of time by passing the number of milliseconds to display it in the `duration` of the toast options. If a button with a role of `"cancel"` is added, then that button will dismiss the toast. To dismiss the toast after creation, call the `dismiss()` method on the instance. - -## Usage - - - - - -```tsx -import { Component } from '@angular/core'; -import { ToastController } from '@ionic/angular'; - -@Component({ - selector: 'toast-example', - templateUrl: 'toast-example.html', - styleUrls: ['./toast-example.css'], -}) -export class ToastExample { - constructor(public toastController: ToastController) {} - - async presentToast() { - const toast = await this.toastController.create({ - message: 'Your settings have been saved.', - duration: 2000, - }); - toast.present(); - } - - async presentToastWithOptions() { - const toast = await this.toastController.create({ - header: 'Toast header', - message: 'Click to Close', - position: 'top', - buttons: [ - { - side: 'start', - icon: 'star', - text: 'Favorite', - handler: () => { - console.log('Favorite clicked'); - }, - }, - { - text: 'Done', - role: 'cancel', - handler: () => { - console.log('Cancel clicked'); - }, - }, - ], - }); - await toast.present(); - - const { role } = await toast.onDidDismiss(); - console.log('onDidDismiss resolved with role', role); - } -} -``` - - - - - -```javascript -async function presentToast() { - const toast = document.createElement('ion-toast'); - toast.message = 'Your settings have been saved.'; - toast.duration = 2000; - - document.body.appendChild(toast); - return toast.present(); -} - -async function presentToastWithOptions() { - const toast = document.createElement('ion-toast'); - toast.header = 'Toast header'; - toast.message = 'Click to Close'; - toast.position = 'top'; - toast.buttons = [ - { - side: 'start', - icon: 'star', - text: 'Favorite', - handler: () => { - console.log('Favorite clicked'); - }, - }, - { - text: 'Done', - role: 'cancel', - handler: () => { - console.log('Cancel clicked'); - }, - }, - ]; - - document.body.appendChild(toast); - await toast.present(); - - const { role } = await toast.onDidDismiss(); - console.log('onDidDismiss resolved with role', role); -} -``` - - - - - -```tsx -/* Using the useIonToast Hook */ - -import React from 'react'; -import { IonButton, IonContent, IonPage, useIonToast } from '@ionic/react'; - -const ToastExample: React.FC = () => { - const [present, dismiss] = useIonToast(); - - return ( - - - - present({ - buttons: [{ text: 'hide', handler: () => dismiss() }], - message: 'toast from hook, click hide to dismiss', - onDidDismiss: () => console.log('dismissed'), - onWillDismiss: () => console.log('will dismiss'), - }) - } - > - Show Toast - - present('hello from hook', 3000)}> - Show Toast using params, closes in 3 secs - - - Hide Toast - - - - ); -}; -``` - -```tsx -/* Using the IonToast Component */ - -import React, { useState } from 'react'; -import { IonToast, IonContent, IonButton } from '@ionic/react'; - -export const ToastExample: React.FC = () => { - const [showToast1, setShowToast1] = useState(false); - const [showToast2, setShowToast2] = useState(false); - - return ( - - setShowToast1(true)} expand="block"> - Show Toast 1 - - setShowToast2(true)} expand="block"> - Show Toast 2 - - setShowToast1(false)} - message="Your settings have been saved." - duration={200} - /> - - setShowToast2(false)} - message="Click to Close" - position="top" - buttons={[ - { - side: 'start', - icon: 'star', - text: 'Favorite', - handler: () => { - console.log('Favorite clicked'); - }, - }, - { - text: 'Done', - role: 'cancel', - handler: () => { - console.log('Cancel clicked'); - }, - }, - ]} - /> - - ); -}; -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -import { toastController } from '@ionic/core'; - -@Component({ - tag: 'toast-example', - styleUrl: 'toast-example.css', -}) -export class ToastExample { - async presentToast() { - const toast = await toastController.create({ - message: 'Your settings have been saved.', - duration: 2000, - }); - toast.present(); - } - - async presentToastWithOptions() { - const toast = await toastController.create({ - header: 'Toast header', - message: 'Click to Close', - position: 'top', - buttons: [ - { - side: 'start', - icon: 'star', - text: 'Favorite', - handler: () => { - console.log('Favorite clicked'); - }, - }, - { - text: 'Done', - role: 'cancel', - handler: () => { - console.log('Cancel clicked'); - }, - }, - ], - }); - await toast.present(); - - const { role } = await toast.onDidDismiss(); - console.log('onDidDismiss resolved with role', role); - } - - render() { - return [ - - this.presentToast()}>Present Toast - this.presentToastWithOptions()}>Present Toast: Options - , - ]; - } -} -``` - - - - - -```html - - - -``` - -Developers can also use this component directly in their template: - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/toast.mdx b/versioned_docs/version-v5/api/toast.mdx new file mode 100644 index 00000000000..ccfb535affc --- /dev/null +++ b/versioned_docs/version-v5/api/toast.mdx @@ -0,0 +1,403 @@ +--- +sidebar_label: 'ion-toast' +demoUrl: '/docs/demos/api/toast/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/toast/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/toast/props.mdx'; +import Events from '@ionic-internal/component-api/v5/toast/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/toast/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/toast/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/toast/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/toast/slots.mdx'; + +# ion-toast + +A Toast is a subtle notification commonly used in modern applications. It can be used to provide feedback about an operation or to display a system message. The toast appears on top of the app's content, and can be dismissed by the app to resume user interaction with the app. + +## Positioning + +Toasts can be positioned at the top, bottom or middle of the viewport. The position can be passed upon creation. The possible values are `top`, `bottom` and `middle`. If the position is not specified, the toast will be displayed at the bottom of the viewport. + +## Dismissing + +The toast can be dismissed automatically after a specific amount of time by passing the number of milliseconds to display it in the `duration` of the toast options. If a button with a role of `"cancel"` is added, then that button will dismiss the toast. To dismiss the toast after creation, call the `dismiss()` method on the instance. + +## Usage + + + + + +```tsx +import { Component } from '@angular/core'; +import { ToastController } from '@ionic/angular'; + +@Component({ + selector: 'toast-example', + templateUrl: 'toast-example.html', + styleUrls: ['./toast-example.css'], +}) +export class ToastExample { + constructor(public toastController: ToastController) {} + + async presentToast() { + const toast = await this.toastController.create({ + message: 'Your settings have been saved.', + duration: 2000, + }); + toast.present(); + } + + async presentToastWithOptions() { + const toast = await this.toastController.create({ + header: 'Toast header', + message: 'Click to Close', + position: 'top', + buttons: [ + { + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + }, + }, + { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + }, + }, + ], + }); + await toast.present(); + + const { role } = await toast.onDidDismiss(); + console.log('onDidDismiss resolved with role', role); + } +} +``` + + + + + +```javascript +async function presentToast() { + const toast = document.createElement('ion-toast'); + toast.message = 'Your settings have been saved.'; + toast.duration = 2000; + + document.body.appendChild(toast); + return toast.present(); +} + +async function presentToastWithOptions() { + const toast = document.createElement('ion-toast'); + toast.header = 'Toast header'; + toast.message = 'Click to Close'; + toast.position = 'top'; + toast.buttons = [ + { + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + }, + }, + { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + }, + }, + ]; + + document.body.appendChild(toast); + await toast.present(); + + const { role } = await toast.onDidDismiss(); + console.log('onDidDismiss resolved with role', role); +} +``` + + + + + +```tsx +/* Using the useIonToast Hook */ + +import React from 'react'; +import { IonButton, IonContent, IonPage, useIonToast } from '@ionic/react'; + +const ToastExample: React.FC = () => { + const [present, dismiss] = useIonToast(); + + return ( + + + + present({ + buttons: [{ text: 'hide', handler: () => dismiss() }], + message: 'toast from hook, click hide to dismiss', + onDidDismiss: () => console.log('dismissed'), + onWillDismiss: () => console.log('will dismiss'), + }) + } + > + Show Toast + + present('hello from hook', 3000)}> + Show Toast using params, closes in 3 secs + + + Hide Toast + + + + ); +}; +``` + +```tsx +/* Using the IonToast Component */ + +import React, { useState } from 'react'; +import { IonToast, IonContent, IonButton } from '@ionic/react'; + +export const ToastExample: React.FC = () => { + const [showToast1, setShowToast1] = useState(false); + const [showToast2, setShowToast2] = useState(false); + + return ( + + setShowToast1(true)} expand="block"> + Show Toast 1 + + setShowToast2(true)} expand="block"> + Show Toast 2 + + setShowToast1(false)} + message="Your settings have been saved." + duration={200} + /> + + setShowToast2(false)} + message="Click to Close" + position="top" + buttons={[ + { + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + }, + }, + { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + }, + }, + ]} + /> + + ); +}; +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +import { toastController } from '@ionic/core'; + +@Component({ + tag: 'toast-example', + styleUrl: 'toast-example.css', +}) +export class ToastExample { + async presentToast() { + const toast = await toastController.create({ + message: 'Your settings have been saved.', + duration: 2000, + }); + toast.present(); + } + + async presentToastWithOptions() { + const toast = await toastController.create({ + header: 'Toast header', + message: 'Click to Close', + position: 'top', + buttons: [ + { + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + }, + }, + { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + }, + }, + ], + }); + await toast.present(); + + const { role } = await toast.onDidDismiss(); + console.log('onDidDismiss resolved with role', role); + } + + render() { + return [ + + this.presentToast()}>Present Toast + this.presentToastWithOptions()}>Present Toast: Options + , + ]; + } +} +``` + + + + + +```html + + + +``` + +Developers can also use this component directly in their template: + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/toggle.md b/versioned_docs/version-v5/api/toggle.md deleted file mode 100644 index 009cecf1b54..00000000000 --- a/versioned_docs/version-v5/api/toggle.md +++ /dev/null @@ -1,513 +0,0 @@ ---- -title: 'Toggle | ion-toggle: Custom Toggle Button for Ionic Applications' -description: 'Toggle changes the state of a single option. Use ion-toggle to create customizable toggle buttons that can be switched on or off for your applications.' -sidebar_label: 'ion-toggle' -demoUrl: '/docs/demos/api/toggle/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/toggle/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/toggle/props.md'; -import Events from '@ionic-internal/component-api/v5/toggle/events.md'; -import Methods from '@ionic-internal/component-api/v5/toggle/methods.md'; -import Parts from '@ionic-internal/component-api/v5/toggle/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/toggle/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/toggle/slots.md'; - -# ion-toggle - -Toggles change the state of a single option. Toggles can be switched on or off by pressing or swiping them. They can also be checked programmatically by setting the `checked` property. - -## Customization - -### Customizing Background - -The background of the toggle track and handle can be customized using CSS variables. There are also variables for setting the background differently when the toggle is checked. - -```css -ion-toggle { - --background: #000; - --background-checked: #7a49a5; - - --handle-background: #7a49a5; - --handle-background-checked: #000; -} -``` - -Because these variables set the `background` property, which is a shorthand, it can accept any value that the [background property](https://developer.mozilla.org/en-US/docs/Web/CSS/background) accepts. - -A more complex case may involve adding an image to the handle background. - -```css -ion-toggle { - --handle-background-checked: #fff url(/assets/power-icon.png) no-repeat center / contain; -} -``` - -Taking it a step further, we could use the `::before` or `::after` pseudo-elements to position text on top of the background. - -```css -ion-toggle::before { - position: absolute; - - top: 16px; - left: 10px; - - content: 'ON'; - - color: white; - font-size: 8px; - - z-index: 1; -} -``` - -### Customizing Width - -Adjusting the width of the toggle **smaller** will result in a narrower track, with the handle remaining the default width. If desired, set `--handle-width` to make the handle narrower. - -```css -ion-toggle { - width: 40px; -} -``` - -Adjusting the width of the toggle **larger** will result in a wider track, with the handle remaining the default width. If desired, set `--handle-width` to make the handle wider. - -```css -ion-toggle { - width: 100px; -} -``` - -### Customizing Height - -Adjusting the height of the toggle **smaller** than the default will result in the handle height auto-sizing itself to the track. In `ios` the handle is shorter than the track (`100% - 4px`) and in `md` the handle is taller than the track (`100% + 6px`). - -```css -ion-toggle { - height: 15px; -} -``` - -> Note: this does not affect the handle width, width should be set using `--handle-width`. - -Adjusting the height of the toggle **larger** will keep the handle in the center at the default height. This can be modified by setting `--handle-height` which can be set to any amount but will not exceed the `--handle-max-height`. - -```css -ion-toggle { - height: 60px; -} -``` - -> Note: this does not affect the handle width, width should be set using `--handle-width`. - -### Customizing Spacing - -The spacing refers to the horizontal gap between the handle and the track. By default, the handle has `2px` of spacing around it in `ios` **only**. In `md` mode there is no default spacing. - -To remove the **horizontal** spacing, set `--handle-spacing` to `0px`. - -```css -ion-toggle { - --handle-spacing: 0px; -} -``` - -Due to the handle having a fixed height, to remove the spacing on the top and bottom, set the height to 100%. - -```css -ion-toggle { - --handle-spacing: 0px; - --handle-height: 100%; -} -``` - -### Customizing Border Radius - -The `--handle-border-radius` can be used to change the `border-radius` on the handle. - -```css -ion-toggle { - --handle-border-radius: 14px 4px 4px 14px; -} -``` - -To target the `border-radius` only when the toggle is checked, target `.toggle-checked`: - -```css -ion-toggle.toggle-checked { - --handle-border-radius: 4px 14px 14px 4px; -} -``` - -### Customizing Box Shadow - -The `--handle-box-shadow` can be used to change the `box-shadow` on the handle. - -```css -ion-toggle { - --handle-box-shadow: 4px 0 2px 0 red; -} -``` - -To target the box shadow only when the toggle is checked, target `.toggle-checked`: - -```css -ion-toggle.toggle-checked { - --handle-box-shadow: -4px 0 2px 0 red; -} -``` - -See the section on [customizing overflow](#customizing-overflow) to allow the `box-shadow` to overflow the toggle container. - -### Customizing Overflow - -Setting `overflow` on the toggle will be inherited by the toggle handle. By default, overflow is set to `hidden` in `ios` only. The `box-shadow` will still appear cut off due to the `contain` css property. Set `contain` to `none` in order to overflow the toggle container. - -```css -ion-toggle { - --handle-box-shadow: 0 3px 12px rgba(255, 0, 0, 0.6), 0 3px 1px rgba(50, 70, 255, 0.6); - - overflow: visible; - - contain: none; -} -``` - -## Usage - - - - - -```html - - - - - - - - - - - - - - - - - - - - Pepperoni - - - - - Sausage - - - - - Mushrooms - - - -``` - - - - - -```html - - - - - - - - - - - - - - - - - - - - Pepperoni - - - - - Sausage - - - - - Mushrooms - - - -``` - - - - - -```tsx -import React, { useState } from 'react'; -import { - IonContent, - IonHeader, - IonPage, - IonTitle, - IonToolbar, - IonToggle, - IonList, - IonItem, - IonLabel, - IonItemDivider, -} from '@ionic/react'; - -export const ToggleExamples: React.FC = () => { - const [checked, setChecked] = useState(false); - return ( - - - - ToggleExamples - - - - - Default Toggle - - Checked: {JSON.stringify(checked)} - setChecked(e.detail.checked)} /> - - - Disabled Toggle - - - - - Checked Toggle - - - - - Toggle Colors - - - - - - - - - - - - - - - - - Toggles in a List - - Pepperoni - - - - - Sausage - - - - - Mushrooms - - - - - - ); -}; -``` - - - - - -```tsx -import { Component, State, h } from '@stencil/core'; - -@Component({ - tag: 'toggle-example', - styleUrl: 'toggle-example.css', -}) -export class ToggleExample { - @State() pepperoni: boolean = false; - @State() sausage: boolean = true; - @State() mushrooms: boolean = false; - - render() { - return [ - // Default Toggle - , - - // Disabled Toggle - , - - // Checked Toggle - , - - // Toggle Colors - , - , - , - , - , - - // Toggles in a List - - - Pepperoni - (this.pepperoni = ev.detail.checked)}> - - - - Sausage - (this.sausage = ev.detail.checked)} - disabled={true} - > - - - - Mushrooms - (this.mushrooms = ev.detail.checked)}> - - , - -
- Pepperoni: {this.pepperoni ? 'true' : 'false'} -
- Sausage: {this.sausage ? 'true' : 'false'} -
- Mushrooms: {this.mushrooms ? 'true' : 'false'} -
, - ]; - } -} -``` - -
- - - -```html - - - -``` - - - -
- -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/toggle.mdx b/versioned_docs/version-v5/api/toggle.mdx new file mode 100644 index 00000000000..0c0fbcc9a55 --- /dev/null +++ b/versioned_docs/version-v5/api/toggle.mdx @@ -0,0 +1,513 @@ +--- +title: 'Toggle | ion-toggle: Custom Toggle Button for Ionic Applications' +description: 'Toggle changes the state of a single option. Use ion-toggle to create customizable toggle buttons that can be switched on or off for your applications.' +sidebar_label: 'ion-toggle' +demoUrl: '/docs/demos/api/toggle/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/toggle/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/toggle/props.mdx'; +import Events from '@ionic-internal/component-api/v5/toggle/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/toggle/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/toggle/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/toggle/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/toggle/slots.mdx'; + +# ion-toggle + +Toggles change the state of a single option. Toggles can be switched on or off by pressing or swiping them. They can also be checked programmatically by setting the `checked` property. + +## Customization + +### Customizing Background + +The background of the toggle track and handle can be customized using CSS variables. There are also variables for setting the background differently when the toggle is checked. + +```css +ion-toggle { + --background: #000; + --background-checked: #7a49a5; + + --handle-background: #7a49a5; + --handle-background-checked: #000; +} +``` + +Because these variables set the `background` property, which is a shorthand, it can accept any value that the [background property](https://developer.mozilla.org/en-US/docs/Web/CSS/background) accepts. + +A more complex case may involve adding an image to the handle background. + +```css +ion-toggle { + --handle-background-checked: #fff url(/assets/power-icon.png) no-repeat center / contain; +} +``` + +Taking it a step further, we could use the `::before` or `::after` pseudo-elements to position text on top of the background. + +```css +ion-toggle::before { + position: absolute; + + top: 16px; + left: 10px; + + content: 'ON'; + + color: white; + font-size: 8px; + + z-index: 1; +} +``` + +### Customizing Width + +Adjusting the width of the toggle **smaller** will result in a narrower track, with the handle remaining the default width. If desired, set `--handle-width` to make the handle narrower. + +```css +ion-toggle { + width: 40px; +} +``` + +Adjusting the width of the toggle **larger** will result in a wider track, with the handle remaining the default width. If desired, set `--handle-width` to make the handle wider. + +```css +ion-toggle { + width: 100px; +} +``` + +### Customizing Height + +Adjusting the height of the toggle **smaller** than the default will result in the handle height auto-sizing itself to the track. In `ios` the handle is shorter than the track (`100% - 4px`) and in `md` the handle is taller than the track (`100% + 6px`). + +```css +ion-toggle { + height: 15px; +} +``` + +> Note: this does not affect the handle width, width should be set using `--handle-width`. + +Adjusting the height of the toggle **larger** will keep the handle in the center at the default height. This can be modified by setting `--handle-height` which can be set to any amount but will not exceed the `--handle-max-height`. + +```css +ion-toggle { + height: 60px; +} +``` + +> Note: this does not affect the handle width, width should be set using `--handle-width`. + +### Customizing Spacing + +The spacing refers to the horizontal gap between the handle and the track. By default, the handle has `2px` of spacing around it in `ios` **only**. In `md` mode there is no default spacing. + +To remove the **horizontal** spacing, set `--handle-spacing` to `0px`. + +```css +ion-toggle { + --handle-spacing: 0px; +} +``` + +Due to the handle having a fixed height, to remove the spacing on the top and bottom, set the height to 100%. + +```css +ion-toggle { + --handle-spacing: 0px; + --handle-height: 100%; +} +``` + +### Customizing Border Radius + +The `--handle-border-radius` can be used to change the `border-radius` on the handle. + +```css +ion-toggle { + --handle-border-radius: 14px 4px 4px 14px; +} +``` + +To target the `border-radius` only when the toggle is checked, target `.toggle-checked`: + +```css +ion-toggle.toggle-checked { + --handle-border-radius: 4px 14px 14px 4px; +} +``` + +### Customizing Box Shadow + +The `--handle-box-shadow` can be used to change the `box-shadow` on the handle. + +```css +ion-toggle { + --handle-box-shadow: 4px 0 2px 0 red; +} +``` + +To target the box shadow only when the toggle is checked, target `.toggle-checked`: + +```css +ion-toggle.toggle-checked { + --handle-box-shadow: -4px 0 2px 0 red; +} +``` + +See the section on [customizing overflow](#customizing-overflow) to allow the `box-shadow` to overflow the toggle container. + +### Customizing Overflow + +Setting `overflow` on the toggle will be inherited by the toggle handle. By default, overflow is set to `hidden` in `ios` only. The `box-shadow` will still appear cut off due to the `contain` css property. Set `contain` to `none` in order to overflow the toggle container. + +```css +ion-toggle { + --handle-box-shadow: 0 3px 12px rgba(255, 0, 0, 0.6), 0 3px 1px rgba(50, 70, 255, 0.6); + + overflow: visible; + + contain: none; +} +``` + +## Usage + + + + + +```html + + + + + + + + + + + + + + + + + + + + Pepperoni + + + + + Sausage + + + + + Mushrooms + + + +``` + + + + + +```html + + + + + + + + + + + + + + + + + + + + Pepperoni + + + + + Sausage + + + + + Mushrooms + + + +``` + + + + + +```tsx +import React, { useState } from 'react'; +import { + IonContent, + IonHeader, + IonPage, + IonTitle, + IonToolbar, + IonToggle, + IonList, + IonItem, + IonLabel, + IonItemDivider, +} from '@ionic/react'; + +export const ToggleExamples: React.FC = () => { + const [checked, setChecked] = useState(false); + return ( + + + + ToggleExamples + + + + + Default Toggle + + Checked: {JSON.stringify(checked)} + setChecked(e.detail.checked)} /> + + + Disabled Toggle + + + + + Checked Toggle + + + + + Toggle Colors + + + + + + + + + + + + + + + + + Toggles in a List + + Pepperoni + + + + + Sausage + + + + + Mushrooms + + + + + + ); +}; +``` + + + + + +```tsx +import { Component, State, h } from '@stencil/core'; + +@Component({ + tag: 'toggle-example', + styleUrl: 'toggle-example.css', +}) +export class ToggleExample { + @State() pepperoni: boolean = false; + @State() sausage: boolean = true; + @State() mushrooms: boolean = false; + + render() { + return [ + // Default Toggle + , + + // Disabled Toggle + , + + // Checked Toggle + , + + // Toggle Colors + , + , + , + , + , + + // Toggles in a List + + + Pepperoni + (this.pepperoni = ev.detail.checked)}> + + + + Sausage + (this.sausage = ev.detail.checked)} + disabled={true} + > + + + + Mushrooms + (this.mushrooms = ev.detail.checked)}> + + , + +
+ Pepperoni: {this.pepperoni ? 'true' : 'false'} +
+ Sausage: {this.sausage ? 'true' : 'false'} +
+ Mushrooms: {this.mushrooms ? 'true' : 'false'} +
, + ]; + } +} +``` + +
+ + + +```html + + + +``` + + + +
+ +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/toolbar.md b/versioned_docs/version-v5/api/toolbar.md deleted file mode 100644 index 28d9eb1255b..00000000000 --- a/versioned_docs/version-v5/api/toolbar.md +++ /dev/null @@ -1,907 +0,0 @@ ---- -title: 'Toolbar | Customize App Menu Toolbar Buttons and Icons' -description: 'Ion-toolbar component lets you customize toolbar buttons on your app menu. Add fixed toolbars above or below content or use full screen to scroll with content.' -sidebar_label: 'ion-toolbar' -demoUrl: '/docs/demos/api/toolbar/index.html' -demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/toolbar/index.html' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/toolbar/props.md'; -import Events from '@ionic-internal/component-api/v5/toolbar/events.md'; -import Methods from '@ionic-internal/component-api/v5/toolbar/methods.md'; -import Parts from '@ionic-internal/component-api/v5/toolbar/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/toolbar/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/toolbar/slots.md'; - -# ion-toolbar - -Toolbars are positioned above or below content. When a toolbar is placed in an `` it will appear fixed at the top of the content, and when it is in an `` it will appear fixed at the bottom. Fullscreen content will scroll behind a toolbar in a header or footer. When placed within an ``, toolbars will scroll with the content. - -## Buttons - -Buttons placed in a toolbar should be placed inside of the `` element. The `` element can be positioned inside of the toolbar using a named slot. The below chart has a description of each slot. - -| Slot | Description | -| ----------- | ------------------------------------------------------------------------------------------------------- | -| `secondary` | Positions element to the `left` of the content in `ios` mode, and directly to the `right` in `md` mode. | -| `primary` | Positions element to the `right` of the content in `ios` mode, and to the far `right` in `md` mode. | -| `start` | Positions to the `left` of the content in LTR, and to the `right` in RTL. | -| `end` | Positions to the `right` of the content in LTR, and to the `left` in RTL. | - -## Borders - -In `md` mode, the `` will receive a box-shadow on the bottom, and the `` will receive a box-shadow on the top. In `ios` mode, the `` will receive a border on the bottom, and the `` will receive a border on the top. - -## Usage - - - - - -```html - - Title Only - - - - - - - Back Button - - - - Small Title above a Default Title - - - Default Title - - - - - - - - - - - - - - - - - Default Buttons - - - - - - - Contact - - - Solid Buttons - - - Help - - - - - - - - - - Star - - - Outline Buttons - - - Edit - - - - - - - - Account - - - Edit - - Text Only Buttons - - - - - - - - - - - - Left side menu toggle - - - - - - - - - Right side menu toggle - - - - - - - - - - - - - - - - - All - Favorites - - - - - - - - - - - - - - - - - - Secondary Toolbar - - - - - - - - - - - - - - - - - Dark Toolbar - -``` - - - - - -```html - - Title Only - - - - - - - Back Button - - - - Small Title above a Default Title - - - Default Title - - - - - - - - - - - - - - - - - Default Buttons - - - - - - - Contact - - - Solid Buttons - - - Help - - - - - - - - - - Star - - - Outline Buttons - - - Edit - - - - - - - - Account - - - Edit - - Text Only Buttons - - - - - - - - - - - - Left side menu toggle - - - - - - - - - Right side menu toggle - - - - - - - - - - - - - - - - - All - Favorites - - - - - - - - - - - - - - - - - - Secondary Toolbar - - - - - - - - - - - - - - - - - Dark Toolbar - -``` - - - - - -```tsx -import React from 'react'; -import { IonToolbar, IonTitle, IonButtons, IonBackButton, IonButton, IonIcon, IonMenuButton, IonSearchbar, IonSegment, IonSegmentButton } from '@ionic/react'; -import { personCircle, search, helpCircle, star, create, ellipsisHorizontal, ellipsisVertical } from 'ionicons/icons'; - -export const ToolbarExample: React.FC = () => ( - - Title Only - - - - - - - Back Button - - - - Small Title above a Default Title - - - Default Title - - - - - - - - - - - - - - - - - Default Buttons - - - - - - - Contact - - - Solid Buttons - - - Help - - - - - - - - - - Star - - - Outline Buttons - - - Edit - - - - - - - - Account - - - Edit - - Text Only Buttons - - - - - - - - - - - - Left side menu toggle - - - - - {}}> - - - - Right side menu toggle - - - - - - - - {}}> - - - - - - - - - - All - - Favorites - - - - - - - - - - - - - - - - - - Secondary Toolbar - - - - - - - - - - - - - - - - - Dark Toolbar - -); -``` - - - - - -```tsx -import { Component, h } from '@stencil/core'; - -@Component({ - tag: 'toolbar-example', - styleUrl: 'toolbar-example.css', -}) -export class ToolbarExample { - clickedStar() { - console.log('Clicked star button'); - } - - clickedSearch() { - console.log('Clicked search button'); - } - - render() { - return [ - - Title Only - , - - - - - - Back Button - , - - - Small Title above a Default Title - , - - Default Title - , - - - - - - - - - - - - - - - - Default Buttons - , - - - - - - Contact - - - Solid Buttons - - - Help - - - - , - - - - - - Star - - - Outline Buttons - - - Edit - - - - , - - - - Account - - - Edit - - Text Only Buttons - , - - - - - - - - - - - Left side menu toggle - , - - - - this.clickedStar()}> - - - - Right side menu toggle - - - - , - - - - this.clickedSearch()}> - - - - - , - - - - All - Favorites - - , - - - - - - - - - - - - - - - - Secondary Toolbar - , - - - - - - - - - - - - - - - - Dark Toolbar - , - ]; - } -} -``` - - - - - -```html - - - -``` - - - - - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/toolbar.mdx b/versioned_docs/version-v5/api/toolbar.mdx new file mode 100644 index 00000000000..2b2076ffaad --- /dev/null +++ b/versioned_docs/version-v5/api/toolbar.mdx @@ -0,0 +1,907 @@ +--- +title: 'Toolbar | Customize App Menu Toolbar Buttons and Icons' +description: 'Ion-toolbar component lets you customize toolbar buttons on your app menu. Add fixed toolbars above or below content or use full screen to scroll with content.' +sidebar_label: 'ion-toolbar' +demoUrl: '/docs/demos/api/toolbar/index.html' +demoSourceUrl: 'https://github.com/ionic-team/ionic-docs/tree/main/static/demos/api/toolbar/index.html' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/toolbar/props.mdx'; +import Events from '@ionic-internal/component-api/v5/toolbar/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/toolbar/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/toolbar/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/toolbar/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/toolbar/slots.mdx'; + +# ion-toolbar + +Toolbars are positioned above or below content. When a toolbar is placed in an `` it will appear fixed at the top of the content, and when it is in an `` it will appear fixed at the bottom. Fullscreen content will scroll behind a toolbar in a header or footer. When placed within an ``, toolbars will scroll with the content. + +## Buttons + +Buttons placed in a toolbar should be placed inside of the `` element. The `` element can be positioned inside of the toolbar using a named slot. The below chart has a description of each slot. + +| Slot | Description | +| ----------- | ------------------------------------------------------------------------------------------------------- | +| `secondary` | Positions element to the `left` of the content in `ios` mode, and directly to the `right` in `md` mode. | +| `primary` | Positions element to the `right` of the content in `ios` mode, and to the far `right` in `md` mode. | +| `start` | Positions to the `left` of the content in LTR, and to the `right` in RTL. | +| `end` | Positions to the `right` of the content in LTR, and to the `left` in RTL. | + +## Borders + +In `md` mode, the `` will receive a box-shadow on the bottom, and the `` will receive a box-shadow on the top. In `ios` mode, the `` will receive a border on the bottom, and the `` will receive a border on the top. + +## Usage + + + + + +```html + + Title Only + + + + + + + Back Button + + + + Small Title above a Default Title + + + Default Title + + + + + + + + + + + + + + + + + Default Buttons + + + + + + + Contact + + + Solid Buttons + + + Help + + + + + + + + + + Star + + + Outline Buttons + + + Edit + + + + + + + + Account + + + Edit + + Text Only Buttons + + + + + + + + + + + + Left side menu toggle + + + + + + + + + Right side menu toggle + + + + + + + + + + + + + + + + + All + Favorites + + + + + + + + + + + + + + + + + + Secondary Toolbar + + + + + + + + + + + + + + + + + Dark Toolbar + +``` + + + + + +```html + + Title Only + + + + + + + Back Button + + + + Small Title above a Default Title + + + Default Title + + + + + + + + + + + + + + + + + Default Buttons + + + + + + + Contact + + + Solid Buttons + + + Help + + + + + + + + + + Star + + + Outline Buttons + + + Edit + + + + + + + + Account + + + Edit + + Text Only Buttons + + + + + + + + + + + + Left side menu toggle + + + + + + + + + Right side menu toggle + + + + + + + + + + + + + + + + + All + Favorites + + + + + + + + + + + + + + + + + + Secondary Toolbar + + + + + + + + + + + + + + + + + Dark Toolbar + +``` + + + + + +```tsx +import React from 'react'; +import { IonToolbar, IonTitle, IonButtons, IonBackButton, IonButton, IonIcon, IonMenuButton, IonSearchbar, IonSegment, IonSegmentButton } from '@ionic/react'; +import { personCircle, search, helpCircle, star, create, ellipsisHorizontal, ellipsisVertical } from 'ionicons/icons'; + +export const ToolbarExample: React.FC = () => ( + + Title Only + + + + + + + Back Button + + + + Small Title above a Default Title + + + Default Title + + + + + + + + + + + + + + + + + Default Buttons + + + + + + + Contact + + + Solid Buttons + + + Help + + + + + + + + + + Star + + + Outline Buttons + + + Edit + + + + + + + + Account + + + Edit + + Text Only Buttons + + + + + + + + + + + + Left side menu toggle + + + + + {}}> + + + + Right side menu toggle + + + + + + + + {}}> + + + + + + + + + + All + + Favorites + + + + + + + + + + + + + + + + + + Secondary Toolbar + + + + + + + + + + + + + + + + + Dark Toolbar + +); +``` + + + + + +```tsx +import { Component, h } from '@stencil/core'; + +@Component({ + tag: 'toolbar-example', + styleUrl: 'toolbar-example.css', +}) +export class ToolbarExample { + clickedStar() { + console.log('Clicked star button'); + } + + clickedSearch() { + console.log('Clicked search button'); + } + + render() { + return [ + + Title Only + , + + + + + + Back Button + , + + + Small Title above a Default Title + , + + Default Title + , + + + + + + + + + + + + + + + + Default Buttons + , + + + + + + Contact + + + Solid Buttons + + + Help + + + + , + + + + + + Star + + + Outline Buttons + + + Edit + + + + , + + + + Account + + + Edit + + Text Only Buttons + , + + + + + + + + + + + Left side menu toggle + , + + + + this.clickedStar()}> + + + + Right side menu toggle + + + + , + + + + this.clickedSearch()}> + + + + + , + + + + All + Favorites + + , + + + + + + + + + + + + + + + + Secondary Toolbar + , + + + + + + + + + + + + + + + + Dark Toolbar + , + ]; + } +} +``` + + + + + +```html + + + +``` + + + + + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/api/virtual-scroll.md b/versioned_docs/version-v5/api/virtual-scroll.md deleted file mode 100644 index 073d48ac72f..00000000000 --- a/versioned_docs/version-v5/api/virtual-scroll.md +++ /dev/null @@ -1,273 +0,0 @@ ---- -title: 'ion-virtual-scroll | Angular Virtual Scroll List for Ionic Apps' -description: 'ion-virtual-scroll, supported in Angular, displays a virtual, infinite list. Records are passed to the virtual scroll containing the data to create templates.' -sidebar_label: 'ion-virtual-scroll' ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import Props from '@ionic-internal/component-api/v5/virtual-scroll/props.md'; -import Events from '@ionic-internal/component-api/v5/virtual-scroll/events.md'; -import Methods from '@ionic-internal/component-api/v5/virtual-scroll/methods.md'; -import Parts from '@ionic-internal/component-api/v5/virtual-scroll/parts.md'; -import CustomProps from '@ionic-internal/component-api/v5/virtual-scroll/custom-props.mdx'; -import Slots from '@ionic-internal/component-api/v5/virtual-scroll/slots.md'; - -# ion-virtual-scroll - -Virtual Scroll displays a virtual, "infinite" list. An array of records -is passed to the virtual scroll containing the data to create templates -for. The template created for each record, referred to as a cell, can -consist of items, headers, and footers. For performance reasons, not every record -in the list is rendered at once; instead a small subset of records (enough to fill the viewport) -are rendered and reused as the user scrolls. - -## Approximate Widths and Heights - -If the height of items in the virtual scroll are not close to the -default size of `40px`, it is extremely important to provide a value for -the `approxItemHeight` property. An exact pixel-perfect size is not necessary, -but without an estimate the virtual scroll will not render correctly. - -The approximate width and height of each template is used to help -determine how many cells should be created, and to help calculate -the height of the scrollable area. Note that the actual rendered size -of each cell comes from the app's CSS, whereas this approximation -is only used to help calculate initial dimensions. - -It's also important to know that Ionic's default item sizes have -slightly different heights between platforms, which is perfectly fine. - -## Images Within Virtual Scroll - -HTTP requests, image decoding, and image rendering can cause jank while -scrolling. In order to better control images, Ionic provides `` -to manage HTTP requests and image rendering. While scrolling through items -quickly, `` knows when and when not to make requests, when and -when not to render images, and only loads the images that are viewable -after scrolling. [Read more about `ion-img`.](img.md) - -It's also important for app developers to ensure image sizes are locked in, -and after images have fully loaded they do not change size and affect any -other element sizes. Simply put, to ensure rendering bugs are not introduced, -it's vital that elements within a virtual item does not dynamically change. - -For virtual scrolling, the natural effects of the `` are not desirable -features. We recommend using the `` component over the native -`` element because when an `` element is added to the DOM, it -immediately makes a HTTP request for the image file. Additionally, `` -renders whenever it wants which could be while the user is scrolling. However, -`` is governed by the containing `ion-content` and does not render -images while scrolling quickly. - -## Virtual Scroll Performance Tips - -### iOS Cordova WKWebView - -When deploying to iOS with Cordova, it's highly recommended to use the -[WKWebView plugin](https://blog.ionicframework.com/cordova-ios-performance-improvements-drop-in-speed-with-wkwebview/) -in order to take advantage of iOS's higher performing webview. Additionally, -WKWebView is superior at scrolling efficiently in comparison to the older -UIWebView. - -### Lock in element dimensions and locations - -In order for virtual scroll to efficiently size and locate every item, it's -very important every element within each virtual item does not dynamically -change its dimensions or location. The best way to ensure size and location -does not change, it's recommended each virtual item has locked in its size -via CSS. - -### Use `ion-img` for images - -When including images within Virtual Scroll, be sure to use -[`ion-img`](img.md) rather than the standard `` HTML element. -With `ion-img`, images are lazy loaded so only the viewable ones are -rendered, and HTTP requests are efficiently controlled while scrolling. - -### Set Approximate Widths and Heights - -As mentioned above, all elements should lock in their dimensions. However, -virtual scroll isn't aware of the dimensions until after they have been -rendered. For the initial render, virtual scroll still needs to set -how many items should be built. With "approx" property inputs, such as -`approxItemHeight`, we're able to give virtual scroll an approximate size, -therefore allowing virtual scroll to decide how many items should be -created. - -### Changing dataset should use `trackBy` - -It is possible for the identities of elements in the iterator to change -while the data does not. This can happen, for example, if the iterator -produced from an RPC to the server, and that RPC is re-run. Even if the -"data" hasn't changed, the second response will produce objects with -different identities, and Ionic will tear down the entire DOM and rebuild -it. This is an expensive operation and should be avoided if possible. - -### Efficient headers and footer functions - -Each virtual item must stay extremely efficient, but one way to really -kill its performance is to perform any DOM operations within section header -and footer functions. These functions are called for every record in the -dataset, so please make sure they're performant. - -## React - -The Virtual Scroll component is not supported in React. - -## Vue - -`ion-virtual-scroll` is not supported in Vue. We plan on integrating with existing community-driven solutions for virtual scroll in the near future. Follow our [GitHub issue thread](https://github.com/ionic-team/ionic-framework/issues/17887) for the latest updates. - -## Usage - -```html - - - -
- -
- - {{ item.name }} - - {{ item.content }} -
-
-
-``` - -```tsx -export class VirtualScrollPageComponent { - items: any[] = []; - - constructor() { - for (let i = 0; i < 1000; i++) { - this.items.push({ - name: i + ' - ' + images[rotateImg], - imgSrc: getImgSrc(), - avatarSrc: getImgSrc(), - imgHeight: Math.floor(Math.random() * 50 + 150), - content: lorem.substring(0, Math.random() * (lorem.length - 100) + 100), - }); - - rotateImg++; - if (rotateImg === images.length) { - rotateImg = 0; - } - } - } -} - -const lorem = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, seddo eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; - -const images = [ - 'bandit', - 'batmobile', - 'blues-brothers', - 'bueller', - 'delorean', - 'eleanor', - 'general-lee', - 'ghostbusters', - 'knight-rider', - 'mirth-mobile', -]; - -function getImgSrc() { - const src = 'https://dummyimage.com/600x400/${Math.round( Math.random() * 99999)}/fff.png'; - rotateImg++; - if (rotateImg === images.length) { - rotateImg = 0; - } - return src; -} - -let rotateImg = 0; -``` - -### Basic - -The array of records should be passed to the `items` property on the `ion-virtual-scroll` element. -The data given to the `items` property must be an array. An item template with the `*virtualItem` property is required in the `ion-virtual-scroll`. The `*virtualItem` property can be added to any element. - -```html - - {{ item }} - -``` - -### Section Headers and Footers - -Section headers and footers are optional. They can be dynamically created -from developer-defined functions. For example, a large list of contacts -usually has a divider for each letter in the alphabet. Developers provide -their own custom function to be called on each record. The logic in the -custom function should determine whether to create the section template -and what data to provide to the template. The custom function should -return `null` if a template shouldn't be created. - -```html - - {{ header }} - Item: {{ item }} - -``` - -Below is an example of a custom function called on every record. It -gets passed the individual record, the record's index number, -and the entire array of records. In this example, after every 20 -records a header will be inserted. So between the 19th and 20th records, -between the 39th and 40th, and so on, a `` will -be created and the template's data will come from the function's -returned data. - -```ts -myHeaderFn(record, recordIndex, records) { - if (recordIndex % 20 === 0) { - return 'Header ' + recordIndex; - } - return null; -} -``` - -### Custom Components - -If a custom component is going to be used within Virtual Scroll, it's best -to wrap it with a `
` to ensure the component is rendered correctly. Since -each custom component's implementation and internals can be quite different, wrapping -within a `
` is a safe way to make sure dimensions are measured correctly. - -```html - -
- {{ item }} -
-
-``` - -## Properties - - - -## Events - - - -## Methods - - - -## CSS Shadow Parts - - - -## CSS Custom Properties - - - -## Slots - - diff --git a/versioned_docs/version-v5/api/virtual-scroll.mdx b/versioned_docs/version-v5/api/virtual-scroll.mdx new file mode 100644 index 00000000000..bf3c81ae57d --- /dev/null +++ b/versioned_docs/version-v5/api/virtual-scroll.mdx @@ -0,0 +1,273 @@ +--- +title: 'ion-virtual-scroll | Angular Virtual Scroll List for Ionic Apps' +description: 'ion-virtual-scroll, supported in Angular, displays a virtual, infinite list. Records are passed to the virtual scroll containing the data to create templates.' +sidebar_label: 'ion-virtual-scroll' +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Props from '@ionic-internal/component-api/v5/virtual-scroll/props.mdx'; +import Events from '@ionic-internal/component-api/v5/virtual-scroll/events.mdx'; +import Methods from '@ionic-internal/component-api/v5/virtual-scroll/methods.mdx'; +import Parts from '@ionic-internal/component-api/v5/virtual-scroll/parts.mdx'; +import CustomProps from '@ionic-internal/component-api/v5/virtual-scroll/custom-props.mdx'; +import Slots from '@ionic-internal/component-api/v5/virtual-scroll/slots.mdx'; + +# ion-virtual-scroll + +Virtual Scroll displays a virtual, "infinite" list. An array of records +is passed to the virtual scroll containing the data to create templates +for. The template created for each record, referred to as a cell, can +consist of items, headers, and footers. For performance reasons, not every record +in the list is rendered at once; instead a small subset of records (enough to fill the viewport) +are rendered and reused as the user scrolls. + +## Approximate Widths and Heights + +If the height of items in the virtual scroll are not close to the +default size of `40px`, it is extremely important to provide a value for +the `approxItemHeight` property. An exact pixel-perfect size is not necessary, +but without an estimate the virtual scroll will not render correctly. + +The approximate width and height of each template is used to help +determine how many cells should be created, and to help calculate +the height of the scrollable area. Note that the actual rendered size +of each cell comes from the app's CSS, whereas this approximation +is only used to help calculate initial dimensions. + +It's also important to know that Ionic's default item sizes have +slightly different heights between platforms, which is perfectly fine. + +## Images Within Virtual Scroll + +HTTP requests, image decoding, and image rendering can cause jank while +scrolling. In order to better control images, Ionic provides `` +to manage HTTP requests and image rendering. While scrolling through items +quickly, `` knows when and when not to make requests, when and +when not to render images, and only loads the images that are viewable +after scrolling. [Read more about `ion-img`.](img.mdx) + +It's also important for app developers to ensure image sizes are locked in, +and after images have fully loaded they do not change size and affect any +other element sizes. Simply put, to ensure rendering bugs are not introduced, +it's vital that elements within a virtual item does not dynamically change. + +For virtual scrolling, the natural effects of the `` are not desirable +features. We recommend using the `` component over the native +`` element because when an `` element is added to the DOM, it +immediately makes a HTTP request for the image file. Additionally, `` +renders whenever it wants which could be while the user is scrolling. However, +`` is governed by the containing `ion-content` and does not render +images while scrolling quickly. + +## Virtual Scroll Performance Tips + +### iOS Cordova WKWebView + +When deploying to iOS with Cordova, it's highly recommended to use the +[WKWebView plugin](https://blog.ionicframework.com/cordova-ios-performance-improvements-drop-in-speed-with-wkwebview/) +in order to take advantage of iOS's higher performing webview. Additionally, +WKWebView is superior at scrolling efficiently in comparison to the older +UIWebView. + +### Lock in element dimensions and locations + +In order for virtual scroll to efficiently size and locate every item, it's +very important every element within each virtual item does not dynamically +change its dimensions or location. The best way to ensure size and location +does not change, it's recommended each virtual item has locked in its size +via CSS. + +### Use `ion-img` for images + +When including images within Virtual Scroll, be sure to use +[`ion-img`](img.mdx) rather than the standard `` HTML element. +With `ion-img`, images are lazy loaded so only the viewable ones are +rendered, and HTTP requests are efficiently controlled while scrolling. + +### Set Approximate Widths and Heights + +As mentioned above, all elements should lock in their dimensions. However, +virtual scroll isn't aware of the dimensions until after they have been +rendered. For the initial render, virtual scroll still needs to set +how many items should be built. With "approx" property inputs, such as +`approxItemHeight`, we're able to give virtual scroll an approximate size, +therefore allowing virtual scroll to decide how many items should be +created. + +### Changing dataset should use `trackBy` + +It is possible for the identities of elements in the iterator to change +while the data does not. This can happen, for example, if the iterator +produced from an RPC to the server, and that RPC is re-run. Even if the +"data" hasn't changed, the second response will produce objects with +different identities, and Ionic will tear down the entire DOM and rebuild +it. This is an expensive operation and should be avoided if possible. + +### Efficient headers and footer functions + +Each virtual item must stay extremely efficient, but one way to really +kill its performance is to perform any DOM operations within section header +and footer functions. These functions are called for every record in the +dataset, so please make sure they're performant. + +## React + +The Virtual Scroll component is not supported in React. + +## Vue + +`ion-virtual-scroll` is not supported in Vue. We plan on integrating with existing community-driven solutions for virtual scroll in the near future. Follow our [GitHub issue thread](https://github.com/ionic-team/ionic-framework/issues/17887) for the latest updates. + +## Usage + +```html + + + +
+ +
+ + {{ item.name }} + + {{ item.content }} +
+
+
+``` + +```tsx +export class VirtualScrollPageComponent { + items: any[] = []; + + constructor() { + for (let i = 0; i < 1000; i++) { + this.items.push({ + name: i + ' - ' + images[rotateImg], + imgSrc: getImgSrc(), + avatarSrc: getImgSrc(), + imgHeight: Math.floor(Math.random() * 50 + 150), + content: lorem.substring(0, Math.random() * (lorem.length - 100) + 100), + }); + + rotateImg++; + if (rotateImg === images.length) { + rotateImg = 0; + } + } + } +} + +const lorem = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, seddo eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; + +const images = [ + 'bandit', + 'batmobile', + 'blues-brothers', + 'bueller', + 'delorean', + 'eleanor', + 'general-lee', + 'ghostbusters', + 'knight-rider', + 'mirth-mobile', +]; + +function getImgSrc() { + const src = 'https://dummyimage.com/600x400/${Math.round( Math.random() * 99999)}/fff.png'; + rotateImg++; + if (rotateImg === images.length) { + rotateImg = 0; + } + return src; +} + +let rotateImg = 0; +``` + +### Basic + +The array of records should be passed to the `items` property on the `ion-virtual-scroll` element. +The data given to the `items` property must be an array. An item template with the `*virtualItem` property is required in the `ion-virtual-scroll`. The `*virtualItem` property can be added to any element. + +```html + + {{ item }} + +``` + +### Section Headers and Footers + +Section headers and footers are optional. They can be dynamically created +from developer-defined functions. For example, a large list of contacts +usually has a divider for each letter in the alphabet. Developers provide +their own custom function to be called on each record. The logic in the +custom function should determine whether to create the section template +and what data to provide to the template. The custom function should +return `null` if a template shouldn't be created. + +```html + + {{ header }} + Item: {{ item }} + +``` + +Below is an example of a custom function called on every record. It +gets passed the individual record, the record's index number, +and the entire array of records. In this example, after every 20 +records a header will be inserted. So between the 19th and 20th records, +between the 39th and 40th, and so on, a `` will +be created and the template's data will come from the function's +returned data. + +```ts +myHeaderFn(record, recordIndex, records) { + if (recordIndex % 20 === 0) { + return 'Header ' + recordIndex; + } + return null; +} +``` + +### Custom Components + +If a custom component is going to be used within Virtual Scroll, it's best +to wrap it with a `
` to ensure the component is rendered correctly. Since +each custom component's implementation and internals can be quite different, wrapping +within a `
` is a safe way to make sure dimensions are measured correctly. + +```html + +
+ {{ item }} +
+
+``` + +## Properties + + + +## Events + + + +## Methods + + + +## CSS Shadow Parts + + + +## CSS Custom Properties + + + +## Slots + + diff --git a/versioned_docs/version-v5/cli.md b/versioned_docs/version-v5/cli.mdx similarity index 100% rename from versioned_docs/version-v5/cli.md rename to versioned_docs/version-v5/cli.mdx diff --git a/versioned_docs/version-v5/cli/commands/build.md b/versioned_docs/version-v5/cli/commands/build.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/build.md rename to versioned_docs/version-v5/cli/commands/build.mdx diff --git a/versioned_docs/version-v5/cli/commands/capacitor-add.md b/versioned_docs/version-v5/cli/commands/capacitor-add.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/capacitor-add.md rename to versioned_docs/version-v5/cli/commands/capacitor-add.mdx diff --git a/versioned_docs/version-v5/cli/commands/capacitor-build.md b/versioned_docs/version-v5/cli/commands/capacitor-build.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/capacitor-build.md rename to versioned_docs/version-v5/cli/commands/capacitor-build.mdx diff --git a/versioned_docs/version-v5/cli/commands/capacitor-copy.md b/versioned_docs/version-v5/cli/commands/capacitor-copy.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/capacitor-copy.md rename to versioned_docs/version-v5/cli/commands/capacitor-copy.mdx diff --git a/versioned_docs/version-v5/cli/commands/capacitor-open.md b/versioned_docs/version-v5/cli/commands/capacitor-open.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/capacitor-open.md rename to versioned_docs/version-v5/cli/commands/capacitor-open.mdx diff --git a/versioned_docs/version-v5/cli/commands/capacitor-run.md b/versioned_docs/version-v5/cli/commands/capacitor-run.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/capacitor-run.md rename to versioned_docs/version-v5/cli/commands/capacitor-run.mdx diff --git a/versioned_docs/version-v5/cli/commands/capacitor-sync.md b/versioned_docs/version-v5/cli/commands/capacitor-sync.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/capacitor-sync.md rename to versioned_docs/version-v5/cli/commands/capacitor-sync.mdx diff --git a/versioned_docs/version-v5/cli/commands/capacitor-update.md b/versioned_docs/version-v5/cli/commands/capacitor-update.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/capacitor-update.md rename to versioned_docs/version-v5/cli/commands/capacitor-update.mdx diff --git a/versioned_docs/version-v5/cli/commands/completion.md b/versioned_docs/version-v5/cli/commands/completion.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/completion.md rename to versioned_docs/version-v5/cli/commands/completion.mdx diff --git a/versioned_docs/version-v5/cli/commands/config-get.md b/versioned_docs/version-v5/cli/commands/config-get.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/config-get.md rename to versioned_docs/version-v5/cli/commands/config-get.mdx diff --git a/versioned_docs/version-v5/cli/commands/config-set.md b/versioned_docs/version-v5/cli/commands/config-set.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/config-set.md rename to versioned_docs/version-v5/cli/commands/config-set.mdx diff --git a/versioned_docs/version-v5/cli/commands/config-unset.md b/versioned_docs/version-v5/cli/commands/config-unset.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/config-unset.md rename to versioned_docs/version-v5/cli/commands/config-unset.mdx diff --git a/versioned_docs/version-v5/cli/commands/cordova-build.md b/versioned_docs/version-v5/cli/commands/cordova-build.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/cordova-build.md rename to versioned_docs/version-v5/cli/commands/cordova-build.mdx diff --git a/versioned_docs/version-v5/cli/commands/cordova-compile.md b/versioned_docs/version-v5/cli/commands/cordova-compile.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/cordova-compile.md rename to versioned_docs/version-v5/cli/commands/cordova-compile.mdx diff --git a/versioned_docs/version-v5/cli/commands/cordova-emulate.md b/versioned_docs/version-v5/cli/commands/cordova-emulate.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/cordova-emulate.md rename to versioned_docs/version-v5/cli/commands/cordova-emulate.mdx diff --git a/versioned_docs/version-v5/cli/commands/cordova-platform.md b/versioned_docs/version-v5/cli/commands/cordova-platform.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/cordova-platform.md rename to versioned_docs/version-v5/cli/commands/cordova-platform.mdx diff --git a/versioned_docs/version-v5/cli/commands/cordova-plugin.md b/versioned_docs/version-v5/cli/commands/cordova-plugin.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/cordova-plugin.md rename to versioned_docs/version-v5/cli/commands/cordova-plugin.mdx diff --git a/versioned_docs/version-v5/cli/commands/cordova-prepare.md b/versioned_docs/version-v5/cli/commands/cordova-prepare.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/cordova-prepare.md rename to versioned_docs/version-v5/cli/commands/cordova-prepare.mdx diff --git a/versioned_docs/version-v5/cli/commands/cordova-requirements.md b/versioned_docs/version-v5/cli/commands/cordova-requirements.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/cordova-requirements.md rename to versioned_docs/version-v5/cli/commands/cordova-requirements.mdx diff --git a/versioned_docs/version-v5/cli/commands/cordova-resources.md b/versioned_docs/version-v5/cli/commands/cordova-resources.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/cordova-resources.md rename to versioned_docs/version-v5/cli/commands/cordova-resources.mdx diff --git a/versioned_docs/version-v5/cli/commands/cordova-run.md b/versioned_docs/version-v5/cli/commands/cordova-run.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/cordova-run.md rename to versioned_docs/version-v5/cli/commands/cordova-run.mdx diff --git a/versioned_docs/version-v5/cli/commands/deploy-add.md b/versioned_docs/version-v5/cli/commands/deploy-add.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/deploy-add.md rename to versioned_docs/version-v5/cli/commands/deploy-add.mdx diff --git a/versioned_docs/version-v5/cli/commands/deploy-build.md b/versioned_docs/version-v5/cli/commands/deploy-build.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/deploy-build.md rename to versioned_docs/version-v5/cli/commands/deploy-build.mdx diff --git a/versioned_docs/version-v5/cli/commands/deploy-configure.md b/versioned_docs/version-v5/cli/commands/deploy-configure.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/deploy-configure.md rename to versioned_docs/version-v5/cli/commands/deploy-configure.mdx diff --git a/versioned_docs/version-v5/cli/commands/deploy-manifest.md b/versioned_docs/version-v5/cli/commands/deploy-manifest.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/deploy-manifest.md rename to versioned_docs/version-v5/cli/commands/deploy-manifest.mdx diff --git a/versioned_docs/version-v5/cli/commands/docs.md b/versioned_docs/version-v5/cli/commands/docs.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/docs.md rename to versioned_docs/version-v5/cli/commands/docs.mdx diff --git a/versioned_docs/version-v5/cli/commands/doctor-check.md b/versioned_docs/version-v5/cli/commands/doctor-check.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/doctor-check.md rename to versioned_docs/version-v5/cli/commands/doctor-check.mdx diff --git a/versioned_docs/version-v5/cli/commands/doctor-list.md b/versioned_docs/version-v5/cli/commands/doctor-list.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/doctor-list.md rename to versioned_docs/version-v5/cli/commands/doctor-list.mdx diff --git a/versioned_docs/version-v5/cli/commands/doctor-treat.md b/versioned_docs/version-v5/cli/commands/doctor-treat.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/doctor-treat.md rename to versioned_docs/version-v5/cli/commands/doctor-treat.mdx diff --git a/versioned_docs/version-v5/cli/commands/enterprise-register.md b/versioned_docs/version-v5/cli/commands/enterprise-register.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/enterprise-register.md rename to versioned_docs/version-v5/cli/commands/enterprise-register.mdx diff --git a/versioned_docs/version-v5/cli/commands/generate.md b/versioned_docs/version-v5/cli/commands/generate.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/generate.md rename to versioned_docs/version-v5/cli/commands/generate.mdx diff --git a/versioned_docs/version-v5/cli/commands/git-remote.md b/versioned_docs/version-v5/cli/commands/git-remote.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/git-remote.md rename to versioned_docs/version-v5/cli/commands/git-remote.mdx diff --git a/versioned_docs/version-v5/cli/commands/info.md b/versioned_docs/version-v5/cli/commands/info.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/info.md rename to versioned_docs/version-v5/cli/commands/info.mdx diff --git a/versioned_docs/version-v5/cli/commands/init.md b/versioned_docs/version-v5/cli/commands/init.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/init.md rename to versioned_docs/version-v5/cli/commands/init.mdx diff --git a/versioned_docs/version-v5/cli/commands/integrations-disable.md b/versioned_docs/version-v5/cli/commands/integrations-disable.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/integrations-disable.md rename to versioned_docs/version-v5/cli/commands/integrations-disable.mdx diff --git a/versioned_docs/version-v5/cli/commands/integrations-enable.md b/versioned_docs/version-v5/cli/commands/integrations-enable.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/integrations-enable.md rename to versioned_docs/version-v5/cli/commands/integrations-enable.mdx diff --git a/versioned_docs/version-v5/cli/commands/integrations-list.md b/versioned_docs/version-v5/cli/commands/integrations-list.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/integrations-list.md rename to versioned_docs/version-v5/cli/commands/integrations-list.mdx diff --git a/versioned_docs/version-v5/cli/commands/link.md b/versioned_docs/version-v5/cli/commands/link.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/link.md rename to versioned_docs/version-v5/cli/commands/link.mdx diff --git a/versioned_docs/version-v5/cli/commands/login.md b/versioned_docs/version-v5/cli/commands/login.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/login.md rename to versioned_docs/version-v5/cli/commands/login.mdx diff --git a/versioned_docs/version-v5/cli/commands/logout.md b/versioned_docs/version-v5/cli/commands/logout.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/logout.md rename to versioned_docs/version-v5/cli/commands/logout.mdx diff --git a/versioned_docs/version-v5/cli/commands/package-build.md b/versioned_docs/version-v5/cli/commands/package-build.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/package-build.md rename to versioned_docs/version-v5/cli/commands/package-build.mdx diff --git a/versioned_docs/version-v5/cli/commands/package-deploy.md b/versioned_docs/version-v5/cli/commands/package-deploy.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/package-deploy.md rename to versioned_docs/version-v5/cli/commands/package-deploy.mdx diff --git a/versioned_docs/version-v5/cli/commands/repair.md b/versioned_docs/version-v5/cli/commands/repair.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/repair.md rename to versioned_docs/version-v5/cli/commands/repair.mdx diff --git a/versioned_docs/version-v5/cli/commands/serve.md b/versioned_docs/version-v5/cli/commands/serve.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/serve.md rename to versioned_docs/version-v5/cli/commands/serve.mdx diff --git a/versioned_docs/version-v5/cli/commands/signup.md b/versioned_docs/version-v5/cli/commands/signup.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/signup.md rename to versioned_docs/version-v5/cli/commands/signup.mdx diff --git a/versioned_docs/version-v5/cli/commands/ssh-add.md b/versioned_docs/version-v5/cli/commands/ssh-add.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/ssh-add.md rename to versioned_docs/version-v5/cli/commands/ssh-add.mdx diff --git a/versioned_docs/version-v5/cli/commands/ssh-delete.md b/versioned_docs/version-v5/cli/commands/ssh-delete.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/ssh-delete.md rename to versioned_docs/version-v5/cli/commands/ssh-delete.mdx diff --git a/versioned_docs/version-v5/cli/commands/ssh-generate.md b/versioned_docs/version-v5/cli/commands/ssh-generate.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/ssh-generate.md rename to versioned_docs/version-v5/cli/commands/ssh-generate.mdx diff --git a/versioned_docs/version-v5/cli/commands/ssh-list.md b/versioned_docs/version-v5/cli/commands/ssh-list.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/ssh-list.md rename to versioned_docs/version-v5/cli/commands/ssh-list.mdx diff --git a/versioned_docs/version-v5/cli/commands/ssh-setup.md b/versioned_docs/version-v5/cli/commands/ssh-setup.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/ssh-setup.md rename to versioned_docs/version-v5/cli/commands/ssh-setup.mdx diff --git a/versioned_docs/version-v5/cli/commands/ssh-use.md b/versioned_docs/version-v5/cli/commands/ssh-use.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/ssh-use.md rename to versioned_docs/version-v5/cli/commands/ssh-use.mdx diff --git a/versioned_docs/version-v5/cli/commands/ssl-generate.md b/versioned_docs/version-v5/cli/commands/ssl-generate.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/ssl-generate.md rename to versioned_docs/version-v5/cli/commands/ssl-generate.mdx diff --git a/versioned_docs/version-v5/cli/commands/start.md b/versioned_docs/version-v5/cli/commands/start.mdx similarity index 100% rename from versioned_docs/version-v5/cli/commands/start.md rename to versioned_docs/version-v5/cli/commands/start.mdx diff --git a/versioned_docs/version-v5/cli/configuration.md b/versioned_docs/version-v5/cli/configuration.md deleted file mode 100644 index 63d6ca786af..00000000000 --- a/versioned_docs/version-v5/cli/configuration.md +++ /dev/null @@ -1,233 +0,0 @@ -# Configuration - -## Files - -Configuration values are stored in JSON files. The Ionic CLI maintains a global configuration file, usually located at `~/.ionic/config.json`, and project configuration files, usually at the project's root directory as `ionic.config.json`. - -The CLI provides commands for setting and printing config values from project config files and the global CLI config file. See `ionic config --help` or see the documentation for usage of [`ionic config get`](commands/config-get.md) and [`ionic config set`](commands/config-set.md). - -### Project Configuration File - -Each Ionic project has a project configuration file, usually at the project's root directory. The following is an annotated `ionic.config.json` file. - -```json -{ - // The human-readable name of the app. - "name": "My App", - - // The project type of the app. The CLI uses this value to determine which - // commands and command options are available, what to output for help - // documentation, and what to use for web asset builds and the dev server. - "type": "angular", - - // The App ID for Appflow. - "id": "abc123", - - // Configuration object for integrations such as Cordova and Capacitor. - "integrations": { - "cordova": { - ... - } - }, - - // Hook configuration--see the Hooks section below for details. - "hooks": { - ... - } -} -``` - -## Environment Variables - -The CLI will look for the following environment variables: - -- `IONIC_CONFIG_DIRECTORY`: The directory of the global CLI config. Defaults to `~/.ionic`. -- `IONIC_HTTP_PROXY`: Set a URL for proxying all CLI requests through. See [Using a Proxy](using-a-proxy.md). -- `IONIC_TOKEN`: Automatically authenticates with [Appflow](https://ionic.io/appflow). - -## Flags - -CLI flags are global options that alter the behavior of a CLI command. - -- `--help`: Instead of running the command, view its help page. -- `--verbose`: Show all log messages for debugging purposes. -- `--quiet`: Only show `WARN` and `ERROR` log messages. -- `--no-interactive`: Turn off interactive prompts and fancy outputs. If CI or a non-TTY terminal is detected, the CLI is automatically non-interactive. -- `--confirm`: Turn on auto-confirmation of confirmation prompts. Careful: the CLI prompts before doing something potentially harmful. Auto-confirming may have unintended results. - -## Hooks - -The CLI can run scripts during certain events, such as before and after builds. To hook into the CLI, the following [npm scripts](https://docs.npmjs.com/misc/scripts) can be used in `package.json`: - -- `ionic:serve:before`: executed before the dev server starts -- `ionic:serve:after`: executed after the dev server is terminated -- `ionic:build:before`: executed before a web asset build begins -- `ionic:build:after`: executed after a web asset build finishes -- `ionic:capacitor:run:before`: executed during `ionic capacitor run` before capacitor open is executed -- `ionic:capacitor:build:before`: executed during `ionic capacitor build` before capacitor open is executed -- `ionic:capacitor:sync:after`: executed during `ionic capacitor sync` after a sync - -When using a shell script for any of the hooks, hook context is defined in environment variables prefixed with `IONIC_CLI_HOOK_CTX_`. - -The following example shows the environment variables that are set for the `ionic:capacitor:build` hook. - -```shell -IONIC_CLI_HOOK_CTX_NAME=capacitor:build:before -IONIC_CLI_HOOK_CTX_BUILD_CORDOVA_ASSETS=true -IONIC_CLI_HOOK_CTX_BUILD_ENGINE=browser -IONIC_CLI_HOOK_CTX_BUILD_PROJECT=app -IONIC_CLI_HOOK_CTX_BUILD_TYPE=angular -IONIC_CLI_HOOK_CTX_BUILD_VERBOSE=false -IONIC_CLI_HOOK_CTX_CAPACITOR_APP_ID=io.ionic.starter -IONIC_CLI_HOOK_CTX_CAPACITOR_APP_NAME=ionic-starter-app -IONIC_CLI_HOOK_CTX_CAPACITOR_VERBOSE=false -``` - -Hooks can also be defined in `ionic.config.json`. Define a `hooks` object within the project, where each key is the name of the hook (without the `ionic:` prefix), and the value is a path to a JavaScript file or an array of paths. - -In the following example, the file is imported and run during the `ionic:build:before` hook. - -```json -"hooks": { - "build:before": "./scripts/build-before.js" -}, -``` - -JavaScript hook files should export a single function, which is passed a single argument (`ctx`) whenever the hook executes. - -The argument is the context given to the hook file, which differs from hook to hook and with different invocations. - -`./scripts/build-before.js`: - -```javascript -module.exports = function (ctx) { - console.log(ctx); -}; -``` - -## Multi-app Projects - - - Available in CLI 6.2.0+ - - -The Ionic CLI supports a multi-app configuration setup, which involves multiple Ionic apps and shared code within a single repository, or [monorepo](../reference/glossary.md#monorepo). - -:::note -These docs give an overview of the multi-app feature of the Ionic CLI, but don't really go into details for each framework. - -If you're using Angular, please see [this article](https://github.com/ionic-team/ionic-cli/wiki/Angular-Monorepo) for examples. -::: - -### Setup Steps - -1. Create a directory and initialize a monorepo (see [Project Structure](#project-structure) for full details). -1. Initialize the monorepo as an Ionic multi-app project. This will create a multi-app `ionic.config.json` file. See [Config File](#config-file) for full details. - - ```shell - $ ionic init --multi-app - ``` - -1. Use `ionic start` to create Ionic apps or `ionic init` to initialize existing apps (see [Adding an App](#adding-an-app) for full details). - -### Project Structure - -In a multi-app project, project structure is flexible. The only requirement is a multi-app `ionic.config.json` file at the root of the repository. - -Below is an example setup, where apps in the `apps/` directory are separated from the shared code in the `lib/` directory. Notice the root `ionic.config.json` file and the monorepo's `package.json` file. - -```bash -apps/ -├── myApp/ -└── myOtherApp/ -lib/ -ionic.config.json -package.json -``` - -### Config File - -In a multi-app project, apps share a single `ionic.config.json` file at the root of the repository instead of each app having their own. The multi-app config file contains the configuration for each app by nesting configuration objects in a `projects` object. A default app can be specified using `defaultProject`. - -Below is an example file, which corresponds to the file structure above. - -```json -{ - "defaultProject": "myApp", - "projects": { - "myApp": { - "name": "My App", - "integrations": {}, - "type": "angular", - "root": "apps/myApp" - }, - "myOtherApp": { - "name": "My Other App", - "integrations": {}, - "type": "angular", - "root": "apps/myOtherApp" - } - } -} -``` - -When a multi-app project is detected, the Ionic CLI will operate under the context of an app configured in the root `ionic.config.json`. Project selection criteria is as follows: - -1. If the global CLI option `--project` is specified, the project is looked up by key in the `projects` object. For example, `--project=myApp` will select the `myApp` project. -1. If the CLI detects it is being run within a project path, configured with the `root` key, it will select the matched project. For example, using the CLI within the `apps/myOtherApp/src` directory will select the `myOtherApp` project. -1. If a `defaultProject` is specified in `ionic.config.json`, it will select the specified project when the above criteria is not met. - -### Adding an App - -Apps can be registered in a multi-app project either by using `ionic start` to create new apps or `ionic init` to initialize existing apps. - -#### Using `ionic start` - -If a multi-app project is detected during `ionic start`, the CLI will add the app configuration to the root `ionic.config.json` file instead of creating a project-specific one. - -Dependency installation can be skipped using `--no-deps` if dependencies are hoisted to the root of the monorepo. - -```shell -$ cd apps/ -$ ionic start "My New App" --no-deps -``` - -#### Using `ionic init` - -If an app was created in a way other than `ionic start`, for example by using a prebuilt template, use `ionic init` to register the existing app with the multi-app project. - -:::note -Make sure the app doesn't have an existing `ionic.config.json`. -::: - -```shell -$ cd apps/existing-app/ -$ ionic init -``` - -## Advanced Configuration - -### Overriding the Build - -Normally, the CLI runs a hard-coded set of commands based on the project type. For example, the standard web asset build for Angular projects is `ng run app:build`. The web asset build can be overridden and `ionic build` can continue to be used by utilizing the `ionic:build` [npm script](https://docs.npmjs.com/misc/scripts). Similarly, the dev server can be overridden by using the `ionic:serve` npm script. - -Pay close attention to the flags supplied to the script by the Ionic CLI. Irregularities may occur if options are not respected, especially for livereload on devices. - -### Command Options - -Command options can be expressed with environment variables. They are normally set with `--opt=value` syntax. The naming of these environment variables follows a pattern: start with `IONIC_CMDOPTS_`, add the command name (replacing any spaces with underscores), add the option name (replacing any hyphens with underscores), and then uppercase everything. Boolean flags (command-line options that don't take a value) can be set to `1` or `0`. Strip the `--no-` prefix in boolean flags, if it exists (`--no-open` in ionic serve can be expressed with `IONIC_CMDOPTS_SERVE_OPEN=0`, for example). - -For example, the command options in `ionic cordova run ios -lc --livereload-port=1234 --host=0.0.0.0` can also be expressed with this series of environment variables: - -```shell -$ export IONIC_CMDOPTS_CORDOVA_RUN_LIVERELOAD=1 -$ export IONIC_CMDOPTS_CORDOVA_RUN_CONSOLELOGS=1 -$ export IONIC_CMDOPTS_CORDOVA_RUN_LIVERELOAD_PORT=1234 -$ export IONIC_CMDOPTS_CORDOVA_RUN_HOST=0.0.0.0 -``` - -If these variables are set in the environment, `ionic cordova build ios` will use new defaults for its options. - -### Telemetry - -The CLI sends usage data to Ionic to create a better experience. To disable this functionality, run `ionic config set -g telemetry false`. diff --git a/versioned_docs/version-v5/cli/configuration.mdx b/versioned_docs/version-v5/cli/configuration.mdx new file mode 100644 index 00000000000..db3e9eb2751 --- /dev/null +++ b/versioned_docs/version-v5/cli/configuration.mdx @@ -0,0 +1,233 @@ +# Configuration + +## Files + +Configuration values are stored in JSON files. The Ionic CLI maintains a global configuration file, usually located at `~/.ionic/config.json`, and project configuration files, usually at the project's root directory as `ionic.config.json`. + +The CLI provides commands for setting and printing config values from project config files and the global CLI config file. See `ionic config --help` or see the documentation for usage of [`ionic config get`](commands/config-get.mdx) and [`ionic config set`](commands/config-set.mdx). + +### Project Configuration File + +Each Ionic project has a project configuration file, usually at the project's root directory. The following is an annotated `ionic.config.json` file. + +```json +{ + // The human-readable name of the app. + "name": "My App", + + // The project type of the app. The CLI uses this value to determine which + // commands and command options are available, what to output for help + // documentation, and what to use for web asset builds and the dev server. + "type": "angular", + + // The App ID for Appflow. + "id": "abc123", + + // Configuration object for integrations such as Cordova and Capacitor. + "integrations": { + "cordova": { + ... + } + }, + + // Hook configuration--see the Hooks section below for details. + "hooks": { + ... + } +} +``` + +## Environment Variables + +The CLI will look for the following environment variables: + +- `IONIC_CONFIG_DIRECTORY`: The directory of the global CLI config. Defaults to `~/.ionic`. +- `IONIC_HTTP_PROXY`: Set a URL for proxying all CLI requests through. See [Using a Proxy](using-a-proxy.mdx). +- `IONIC_TOKEN`: Automatically authenticates with [Appflow](https://ionic.io/appflow). + +## Flags + +CLI flags are global options that alter the behavior of a CLI command. + +- `--help`: Instead of running the command, view its help page. +- `--verbose`: Show all log messages for debugging purposes. +- `--quiet`: Only show `WARN` and `ERROR` log messages. +- `--no-interactive`: Turn off interactive prompts and fancy outputs. If CI or a non-TTY terminal is detected, the CLI is automatically non-interactive. +- `--confirm`: Turn on auto-confirmation of confirmation prompts. Careful: the CLI prompts before doing something potentially harmful. Auto-confirming may have unintended results. + +## Hooks + +The CLI can run scripts during certain events, such as before and after builds. To hook into the CLI, the following [npm scripts](https://docs.npmjs.com/misc/scripts) can be used in `package.json`: + +- `ionic:serve:before`: executed before the dev server starts +- `ionic:serve:after`: executed after the dev server is terminated +- `ionic:build:before`: executed before a web asset build begins +- `ionic:build:after`: executed after a web asset build finishes +- `ionic:capacitor:run:before`: executed during `ionic capacitor run` before capacitor open is executed +- `ionic:capacitor:build:before`: executed during `ionic capacitor build` before capacitor open is executed +- `ionic:capacitor:sync:after`: executed during `ionic capacitor sync` after a sync + +When using a shell script for any of the hooks, hook context is defined in environment variables prefixed with `IONIC_CLI_HOOK_CTX_`. + +The following example shows the environment variables that are set for the `ionic:capacitor:build` hook. + +```shell +IONIC_CLI_HOOK_CTX_NAME=capacitor:build:before +IONIC_CLI_HOOK_CTX_BUILD_CORDOVA_ASSETS=true +IONIC_CLI_HOOK_CTX_BUILD_ENGINE=browser +IONIC_CLI_HOOK_CTX_BUILD_PROJECT=app +IONIC_CLI_HOOK_CTX_BUILD_TYPE=angular +IONIC_CLI_HOOK_CTX_BUILD_VERBOSE=false +IONIC_CLI_HOOK_CTX_CAPACITOR_APP_ID=io.ionic.starter +IONIC_CLI_HOOK_CTX_CAPACITOR_APP_NAME=ionic-starter-app +IONIC_CLI_HOOK_CTX_CAPACITOR_VERBOSE=false +``` + +Hooks can also be defined in `ionic.config.json`. Define a `hooks` object within the project, where each key is the name of the hook (without the `ionic:` prefix), and the value is a path to a JavaScript file or an array of paths. + +In the following example, the file is imported and run during the `ionic:build:before` hook. + +```json +"hooks": { + "build:before": "./scripts/build-before.js" +}, +``` + +JavaScript hook files should export a single function, which is passed a single argument (`ctx`) whenever the hook executes. + +The argument is the context given to the hook file, which differs from hook to hook and with different invocations. + +`./scripts/build-before.js`: + +```javascript +module.exports = function (ctx) { + console.log(ctx); +}; +``` + +## Multi-app Projects + + + Available in CLI 6.2.0+ + + +The Ionic CLI supports a multi-app configuration setup, which involves multiple Ionic apps and shared code within a single repository, or [monorepo](../reference/glossary.mdx#monorepo). + +:::note +These docs give an overview of the multi-app feature of the Ionic CLI, but don't really go into details for each framework. + +If you're using Angular, please see [this article](https://github.com/ionic-team/ionic-cli/wiki/Angular-Monorepo) for examples. +::: + +### Setup Steps + +1. Create a directory and initialize a monorepo (see [Project Structure](#project-structure) for full details). +1. Initialize the monorepo as an Ionic multi-app project. This will create a multi-app `ionic.config.json` file. See [Config File](#config-file) for full details. + + ```shell + $ ionic init --multi-app + ``` + +1. Use `ionic start` to create Ionic apps or `ionic init` to initialize existing apps (see [Adding an App](#adding-an-app) for full details). + +### Project Structure + +In a multi-app project, project structure is flexible. The only requirement is a multi-app `ionic.config.json` file at the root of the repository. + +Below is an example setup, where apps in the `apps/` directory are separated from the shared code in the `lib/` directory. Notice the root `ionic.config.json` file and the monorepo's `package.json` file. + +```bash +apps/ +├── myApp/ +└── myOtherApp/ +lib/ +ionic.config.json +package.json +``` + +### Config File + +In a multi-app project, apps share a single `ionic.config.json` file at the root of the repository instead of each app having their own. The multi-app config file contains the configuration for each app by nesting configuration objects in a `projects` object. A default app can be specified using `defaultProject`. + +Below is an example file, which corresponds to the file structure above. + +```json +{ + "defaultProject": "myApp", + "projects": { + "myApp": { + "name": "My App", + "integrations": {}, + "type": "angular", + "root": "apps/myApp" + }, + "myOtherApp": { + "name": "My Other App", + "integrations": {}, + "type": "angular", + "root": "apps/myOtherApp" + } + } +} +``` + +When a multi-app project is detected, the Ionic CLI will operate under the context of an app configured in the root `ionic.config.json`. Project selection criteria is as follows: + +1. If the global CLI option `--project` is specified, the project is looked up by key in the `projects` object. For example, `--project=myApp` will select the `myApp` project. +1. If the CLI detects it is being run within a project path, configured with the `root` key, it will select the matched project. For example, using the CLI within the `apps/myOtherApp/src` directory will select the `myOtherApp` project. +1. If a `defaultProject` is specified in `ionic.config.json`, it will select the specified project when the above criteria is not met. + +### Adding an App + +Apps can be registered in a multi-app project either by using `ionic start` to create new apps or `ionic init` to initialize existing apps. + +#### Using `ionic start` + +If a multi-app project is detected during `ionic start`, the CLI will add the app configuration to the root `ionic.config.json` file instead of creating a project-specific one. + +Dependency installation can be skipped using `--no-deps` if dependencies are hoisted to the root of the monorepo. + +```shell +$ cd apps/ +$ ionic start "My New App" --no-deps +``` + +#### Using `ionic init` + +If an app was created in a way other than `ionic start`, for example by using a prebuilt template, use `ionic init` to register the existing app with the multi-app project. + +:::note +Make sure the app doesn't have an existing `ionic.config.json`. +::: + +```shell +$ cd apps/existing-app/ +$ ionic init +``` + +## Advanced Configuration + +### Overriding the Build + +Normally, the CLI runs a hard-coded set of commands based on the project type. For example, the standard web asset build for Angular projects is `ng run app:build`. The web asset build can be overridden and `ionic build` can continue to be used by utilizing the `ionic:build` [npm script](https://docs.npmjs.com/misc/scripts). Similarly, the dev server can be overridden by using the `ionic:serve` npm script. + +Pay close attention to the flags supplied to the script by the Ionic CLI. Irregularities may occur if options are not respected, especially for livereload on devices. + +### Command Options + +Command options can be expressed with environment variables. They are normally set with `--opt=value` syntax. The naming of these environment variables follows a pattern: start with `IONIC_CMDOPTS_`, add the command name (replacing any spaces with underscores), add the option name (replacing any hyphens with underscores), and then uppercase everything. Boolean flags (command-line options that don't take a value) can be set to `1` or `0`. Strip the `--no-` prefix in boolean flags, if it exists (`--no-open` in ionic serve can be expressed with `IONIC_CMDOPTS_SERVE_OPEN=0`, for example). + +For example, the command options in `ionic cordova run ios -lc --livereload-port=1234 --host=0.0.0.0` can also be expressed with this series of environment variables: + +```shell +$ export IONIC_CMDOPTS_CORDOVA_RUN_LIVERELOAD=1 +$ export IONIC_CMDOPTS_CORDOVA_RUN_CONSOLELOGS=1 +$ export IONIC_CMDOPTS_CORDOVA_RUN_LIVERELOAD_PORT=1234 +$ export IONIC_CMDOPTS_CORDOVA_RUN_HOST=0.0.0.0 +``` + +If these variables are set in the environment, `ionic cordova build ios` will use new defaults for its options. + +### Telemetry + +The CLI sends usage data to Ionic to create a better experience. To disable this functionality, run `ionic config set -g telemetry false`. diff --git a/versioned_docs/version-v5/cli/livereload.md b/versioned_docs/version-v5/cli/livereload.md deleted file mode 100644 index d43ea298b02..00000000000 --- a/versioned_docs/version-v5/cli/livereload.md +++ /dev/null @@ -1,66 +0,0 @@ -# Live Reload - -One option that can boost productivity when building Ionic apps is **Live Reload** (or **live-reload**). When active, Live Reload will reload the browser or [Web View](../core-concepts/webview.md) when changes in the app are detected. This is particularly useful for developing using hardware devices. - -## Terms - -Live Reload is a conflated term. With `ionic serve`, Live Reload just refers to reloading the browser when changes are made. Live Reload can also be used with Capacitor and Cordova to provide the same experience on virtual and hardware devices, which eliminates the need for re-deploying a native binary. - -## Usage - -Since live-reload requires the Web View to load your app from a URL hosted by your computer instead of just reading files on the device, setting up live-reload for hardware devices can be tricky. - -As with regular device deploys, you will need a cable to connect your device to your computer. The difference is the Ionic CLI configures the Web View to load your app from the dev server on your computer. - -### Capacitor - -Capacitor does not yet have a programmatic build for development (track [this issue](https://github.com/ionic-team/capacitor/issues/324) for progress), so the Ionic CLI does **not** automatically forward ports for iOS and Android. - -To use Live Reload with Capacitor, make sure you're either using a virtual device or a hardware device connected to the same Wi-Fi network as your computer. Then, you'll need to specify that you want to use an external address for the dev server using the `--external` flag. - -```shell -$ ionic capacitor run ios -l --external -$ ionic capacitor run android -l --external -``` - -:::note -Remember, with the `--external` option, others on your Wi-Fi network will be able to access your app. -::: - -### Cordova - -#### Android - -For Android devices, the Ionic CLI will automatically forward the dev server port. This means you can use a `localhost` address and it will refer to your computer when loaded in the Web View, not the device. - -The following all-in-one command will start a live-reload server on `localhost` and deploy the app to an Android device using Cordova: - -```shell -ionic cordova run android -l -``` - -#### iOS - -For iOS devices, port forwarding is not yet an option. This means you'll need to connect your device to the same Wi-Fi network as your computer and use an external address for the dev server. - -:::note -You can track [this issue](https://github.com/ionic-team/native-run/issues/20) for progress on iOS port forwarding with Ionic. -::: - -In some cases, the Ionic CLI won't know the address with which to configure the Web View, so you may be prompted to select one. Be sure to select the address of your computer on your Wi-Fi network. - -The following all-in-one command will start a live-reload server on **all addresses** and deploy the app to an iOS device using Cordova: - -```shell -ionic cordova run ios -l --external -``` - -:::note -Remember, with the `--external` option, others on your Wi-Fi network will be able to access your app. -::: - -## Tips - -- With Cordova, use the `--device`, `--emulator`, and `--target` options to narrow down target devices. Use the `--list` option to list all targets. See usage in the [command docs](commands/cordova-run.md). -- You can separate the dev server process and the deploy process by using `ionic serve` and the `--livereload-url` option of `ionic cordova run` or `ionic capacitor run`. -- For Android, it is possible to configure [adb](https://developer.android.com/studio/command-line/adb) to always forward ports while the adb server is running (see `adb reverse`). With port forwarding set up, an external address would no longer be required. You can also setup the adb bridge over TCP such that subsequent deploys no longer need a USB cable. diff --git a/versioned_docs/version-v5/cli/livereload.mdx b/versioned_docs/version-v5/cli/livereload.mdx new file mode 100644 index 00000000000..81787c9f9de --- /dev/null +++ b/versioned_docs/version-v5/cli/livereload.mdx @@ -0,0 +1,66 @@ +# Live Reload + +One option that can boost productivity when building Ionic apps is **Live Reload** (or **live-reload**). When active, Live Reload will reload the browser or [Web View](../core-concepts/webview.mdx) when changes in the app are detected. This is particularly useful for developing using hardware devices. + +## Terms + +Live Reload is a conflated term. With `ionic serve`, Live Reload just refers to reloading the browser when changes are made. Live Reload can also be used with Capacitor and Cordova to provide the same experience on virtual and hardware devices, which eliminates the need for re-deploying a native binary. + +## Usage + +Since live-reload requires the Web View to load your app from a URL hosted by your computer instead of just reading files on the device, setting up live-reload for hardware devices can be tricky. + +As with regular device deploys, you will need a cable to connect your device to your computer. The difference is the Ionic CLI configures the Web View to load your app from the dev server on your computer. + +### Capacitor + +Capacitor does not yet have a programmatic build for development (track [this issue](https://github.com/ionic-team/capacitor/issues/324) for progress), so the Ionic CLI does **not** automatically forward ports for iOS and Android. + +To use Live Reload with Capacitor, make sure you're either using a virtual device or a hardware device connected to the same Wi-Fi network as your computer. Then, you'll need to specify that you want to use an external address for the dev server using the `--external` flag. + +```shell +$ ionic capacitor run ios -l --external +$ ionic capacitor run android -l --external +``` + +:::note +Remember, with the `--external` option, others on your Wi-Fi network will be able to access your app. +::: + +### Cordova + +#### Android + +For Android devices, the Ionic CLI will automatically forward the dev server port. This means you can use a `localhost` address and it will refer to your computer when loaded in the Web View, not the device. + +The following all-in-one command will start a live-reload server on `localhost` and deploy the app to an Android device using Cordova: + +```shell +ionic cordova run android -l +``` + +#### iOS + +For iOS devices, port forwarding is not yet an option. This means you'll need to connect your device to the same Wi-Fi network as your computer and use an external address for the dev server. + +:::note +You can track [this issue](https://github.com/ionic-team/native-run/issues/20) for progress on iOS port forwarding with Ionic. +::: + +In some cases, the Ionic CLI won't know the address with which to configure the Web View, so you may be prompted to select one. Be sure to select the address of your computer on your Wi-Fi network. + +The following all-in-one command will start a live-reload server on **all addresses** and deploy the app to an iOS device using Cordova: + +```shell +ionic cordova run ios -l --external +``` + +:::note +Remember, with the `--external` option, others on your Wi-Fi network will be able to access your app. +::: + +## Tips + +- With Cordova, use the `--device`, `--emulator`, and `--target` options to narrow down target devices. Use the `--list` option to list all targets. See usage in the [command docs](commands/cordova-run.mdx). +- You can separate the dev server process and the deploy process by using `ionic serve` and the `--livereload-url` option of `ionic cordova run` or `ionic capacitor run`. +- For Android, it is possible to configure [adb](https://developer.android.com/studio/command-line/adb) to always forward ports while the adb server is running (see `adb reverse`). With port forwarding set up, an external address would no longer be required. You can also setup the adb bridge over TCP such that subsequent deploys no longer need a USB cable. diff --git a/versioned_docs/version-v5/cli/using-a-proxy.md b/versioned_docs/version-v5/cli/using-a-proxy.mdx similarity index 100% rename from versioned_docs/version-v5/cli/using-a-proxy.md rename to versioned_docs/version-v5/cli/using-a-proxy.mdx diff --git a/versioned_docs/version-v5/components.md b/versioned_docs/version-v5/components.md deleted file mode 100644 index 0c43dd0b021..00000000000 --- a/versioned_docs/version-v5/components.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: UI Components -description: Ionic Framework comes stock with a number of high-level UI components, including cards, lists, and tabs to quickly and easily build your app's user interface. -hide_table_of_contents: true ---- - - - UI Components | User Interface Application Building Components - - - - -import DocsCard from '@components/global/DocsCard'; -import DocsCards from '@components/global/DocsCards'; - -Ionic apps are made of high-level building blocks called Components, which allow you to quickly construct the UI for your app. Ionic comes stock with a number of components, including cards, lists, and tabs. Once you’re familiar with the basics, refer to the [API Index](api.md) for a complete list of each component and sub-component. - - - - - -

Action Sheets display a set of options with the ability to confirm or cancel an action.

-
- - -

Alerts are a great way to offer the user the ability to choose a specific action or list of actions.

-
- - -

Badges are a small component that typically communicate a numerical value to the user.

-
- - -

Buttons let your users take action. They're an essential way to interact with and navigate through an app.

-
- - - -

Cards are a great way to display an important piece of content, and can contain images, buttons, text, and more.

-
- - -

Checkboxes can be used to let the user know they need to make a binary decision.

-
- - -

Chips are a compact way to display data or actions.

-
- - -

Content is the quintessential way to interact with and navigate through an app.

-
- - -

Date & time pickers are used to present an interface that makes it easy for users to select dates and times.

-
- - -

Floating action buttons are circular buttons that perform a primary action on a screen.

-
- - -

Beautifully designed icons for use in web, iOS, Android, and desktop apps.

-
- - -

The grid is a powerful mobile-first system for building custom layouts.

-
- - -

Infinite scroll allows you to load new data as the user scrolls through your app.

-
- - -

Inputs provides a way for users to enter data in your app.

-
- - -

Items are an all-purpose UI container that can be used as part of a list.

-
- - -

Lists can display rows of information, such as a contact list, playlist, or menu.

-
- - -

Navigation is how users move between different pages in your app.

-
- - -

Menus are a common navigation pattern. They can be permanently on-screen, or revealed when needed.

-
- - -

Modals slide in and off screen to display a temporary UI and are often used for login or sign-up pages.

-
- - -

Popover provides an easy way to present information or options without changing contexts.

-
- - -

Progress indicators visualize the progression of an operation or activity.

-
- - -

Radio inputs allow you to present a set of exclusive options.

-
- - -

Refresher provides pull-to-refresh functionality on a content component.

-
- - -

Searchbar is used to search or filter items, usually from a toolbar.

-
- - -

Reorder lets users drag and drop to reorder a list of items.

-
- - -

Routing allows navigation based on the current path.

-
- - -

Segments provide a set of exclusive buttons that can be used as a filter or view switcher.

-
- - -

Select is similar to the native HTML select, with a few improvements to sorting and selecting.

-
- - -

Slides make it easy to create complex UI such as galleries, tutorials, and page-based layouts.

-
- - -

Tabs enable tabbed navigation, a standard navigation pattern in modern apps.

-
- - -

Toast is used to show a notification over the top of an app's content. It can be temporary or dismissible.

-
- - -

Toggles are an input for binary options, often used for options and switches.

-
- - -

Toolbars are used to house information and actions relating to your app.

-
-
diff --git a/versioned_docs/version-v5/components.mdx b/versioned_docs/version-v5/components.mdx new file mode 100644 index 00000000000..8a9c8a10190 --- /dev/null +++ b/versioned_docs/version-v5/components.mdx @@ -0,0 +1,160 @@ +--- +title: UI Components +description: Ionic Framework comes stock with a number of high-level UI components, including cards, lists, and tabs to quickly and easily build your app's user interface. +hide_table_of_contents: true +--- + + + UI Components | User Interface Application Building Components + + + + +import DocsCard from '@components/global/DocsCard'; +import DocsCards from '@components/global/DocsCards'; + +Ionic apps are made of high-level building blocks called Components, which allow you to quickly construct the UI for your app. Ionic comes stock with a number of components, including cards, lists, and tabs. Once you’re familiar with the basics, refer to the [API Index](api.mdx) for a complete list of each component and sub-component. + + + + + +

Action Sheets display a set of options with the ability to confirm or cancel an action.

+
+ + +

Alerts are a great way to offer the user the ability to choose a specific action or list of actions.

+
+ + +

Badges are a small component that typically communicate a numerical value to the user.

+
+ + +

Buttons let your users take action. They're an essential way to interact with and navigate through an app.

+
+ + + +

Cards are a great way to display an important piece of content, and can contain images, buttons, text, and more.

+
+ + +

Checkboxes can be used to let the user know they need to make a binary decision.

+
+ + +

Chips are a compact way to display data or actions.

+
+ + +

Content is the quintessential way to interact with and navigate through an app.

+
+ + +

Date & time pickers are used to present an interface that makes it easy for users to select dates and times.

+
+ + +

Floating action buttons are circular buttons that perform a primary action on a screen.

+
+ + +

Beautifully designed icons for use in web, iOS, Android, and desktop apps.

+
+ + +

The grid is a powerful mobile-first system for building custom layouts.

+
+ + +

Infinite scroll allows you to load new data as the user scrolls through your app.

+
+ + +

Inputs provides a way for users to enter data in your app.

+
+ + +

Items are an all-purpose UI container that can be used as part of a list.

+
+ + +

Lists can display rows of information, such as a contact list, playlist, or menu.

+
+ + +

Navigation is how users move between different pages in your app.

+
+ + +

Menus are a common navigation pattern. They can be permanently on-screen, or revealed when needed.

+
+ + +

Modals slide in and off screen to display a temporary UI and are often used for login or sign-up pages.

+
+ + +

Popover provides an easy way to present information or options without changing contexts.

+
+ + +

Progress indicators visualize the progression of an operation or activity.

+
+ + +

Radio inputs allow you to present a set of exclusive options.

+
+ + +

Refresher provides pull-to-refresh functionality on a content component.

+
+ + +

Searchbar is used to search or filter items, usually from a toolbar.

+
+ + +

Reorder lets users drag and drop to reorder a list of items.

+
+ + +

Routing allows navigation based on the current path.

+
+ + +

Segments provide a set of exclusive buttons that can be used as a filter or view switcher.

+
+ + +

Select is similar to the native HTML select, with a few improvements to sorting and selecting.

+
+ + +

Slides make it easy to create complex UI such as galleries, tutorials, and page-based layouts.

+
+ + +

Tabs enable tabbed navigation, a standard navigation pattern in modern apps.

+
+ + +

Toast is used to show a notification over the top of an app's content. It can be temporary or dismissible.

+
+ + +

Toggles are an input for binary options, often used for options and switches.

+
+ + +

Toolbars are used to house information and actions relating to your app.

+
+
diff --git a/versioned_docs/version-v5/contributing/coc.md b/versioned_docs/version-v5/contributing/coc.mdx similarity index 100% rename from versioned_docs/version-v5/contributing/coc.md rename to versioned_docs/version-v5/contributing/coc.mdx diff --git a/versioned_docs/version-v5/contributing/how-to-contribute.md b/versioned_docs/version-v5/contributing/how-to-contribute.md deleted file mode 100644 index df5f6efbd23..00000000000 --- a/versioned_docs/version-v5/contributing/how-to-contribute.md +++ /dev/null @@ -1,252 +0,0 @@ ---- -sidebar_label: How to Contribute ---- - -# Contributing to Ionic - -Thanks for the interest in contributing to Ionic Framework! - -## Contributing Etiquette - -Please see the [Contributor Code of Conduct](coc.md) for information on the rules of conduct. - -## Creating an Issue - -- If you have a question about using the framework, please ask on the [Ionic Forum](http://forum.ionicframework.com/). - -- It is required that you clearly describe the steps necessary to reproduce the issue you are running into. Although we would love to help our users as much as possible, diagnosing issues without clear reproduction steps is extremely time-consuming and simply not sustainable. - -- The issue list of the [Ionic](https://github.com/ionic-team/ionic) repository is exclusively for bug reports and feature requests. Non-conforming issues will be closed immediately. - -- Issues with no clear steps to reproduce will not be triaged. If an issue is labeled with "needs: reply" and receives no further replies from the author of the issue for more than 14 days, it will be closed. - -- If you think you have found a bug, or have a new feature idea, please start by making sure it hasn't already been [reported](https://github.com/ionic-team/ionic/issues?utf8=%E2%9C%93&q=is%3Aissue). You can search through existing issues to see if there is a similar one reported. Include closed issues as it may have been closed with a solution. - -- Next, [create a new issue](https://github.com/ionic-team/ionic/issues/new/choose) that thoroughly explains the problem. Please fill out the populated issue form before submitting the issue. - -## Creating a Good Code Reproduction - -### What is a Code Reproduction? - -A code reproduction is a small application that is built to demonstrate a particular issue. The code reproduction should contain the minimum amount of code needed to recreate the issue and should focus on a single issue. - -### Why Should You Create a Reproduction? - -A code reproduction of the issue you are experiencing helps us better isolate the cause of the problem. This is an important first step to getting any bug fixed! - -Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed. In other words, creating a code reproduction of the issue helps us help you. - -### How to Create a Reproduction - -- Create a new Ionic application using one of our starter templates. The `blank` starter application is a great choice for this. You can create one using the following Ionic CLI command: `ionic start myApp blank` -- Add the minimum amount of code needed to recreate the issue you are experiencing. Do not include anything that is not required to reproduce the issue. This includes any 3rd party plugins you have installed. -- Publish the application on GitHub and include a link to it when [creating an issue](#creating-an-issue). -- Be sure to include steps to reproduce the issue. These steps should be clear and easy to follow. - -### Benefits of Creating a Reproduction - -- **Uses the latest version of Ionic:** By creating a new Ionic application, you are ensuring that you are testing against the latest version of the framework. Sometimes the issues you are experiencing have already been resolved in a newer version of the framework! -- **Minimal surface area:** By removing code that is not needed in order to reproduce the issue, it makes it easier to identify the cause of the issue. -- **No secret code needed:** Creating a minimal reproduction of the issue prevents you from having to publish any proprietary code used in your project. -- **Get help fixing the issue:** If we can reliably reproduce an issue, there is a good chance we will be able to address it. - -## Creating a Pull Request - -- We appreciate you taking the time to contribute! Before submitting a pull request, we ask that you please [create an issue](#creating-an-issue) that explains the bug or feature request and let us know that you plan on creating a pull request for it. If an issue already exists, please comment on that issue letting us know you would like to submit a pull request for it. This helps us to keep track of the pull request and make sure there isn't duplicated effort. - -- Looking for an issue to fix? Make sure to look through our issues with the [help wanted](https://github.com/ionic-team/ionic/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) label! - -### Setup - -1. [Download the installer](https://nodejs.org/) for the LTS version of Node.js. This is the best way to also [install npm](https://blog.npmjs.org/post/85484771375/how-to-install-npm#_=_). -2. Fork the [Ionic](https://github.com/ionic-team/ionic) repository. -3. Clone your fork. -4. Create a new branch from master for your change. -5. Navigate into the directory of the package you wish to modify (core, angular, etc.). -6. Run `npm install` to install dependencies for this package. -7. Follow the steps for the specific package below. - -### Core - -#### Modifying Components - -1. Locate the component(s) to modify inside `/core/src/components/`. -2. Take a look at the [Stencil Documentation](https://stenciljs.com/docs/introduction/) and other components to understand the implementation of these components. -3. Make your changes to the component. If the change is overly complex or out of the ordinary, add comments so we can understand the changes. -4. [Preview your changes](#preview-changes) locally. -5. [Modify the documentation](#modifying-documentation) if needed. -6. [Run lint](#lint-changes) on the directory and make sure there are no errors. -7. [Build the project](#building-changes). -8. After the build is finished, commit the changes. Please follow the [commit message format](#commit-message-format) for every commit. -9. [Submit a Pull Request](#submit-pull-request) of your changes. - -#### Preview Changes - -1. Run `npm start` from within the `core` directory. -2. A browser should open at `http://localhost:3333/`. -3. From here, navigate to one of the component's tests to preview your changes. -4. If a test showing your change doesn't exist, [add a new test or update an existing one](#modifying-tests). -5. To test in RTL mode, once you are in the desired component's test, add `?rtl=true` at the end of the url; for example: `http://localhost:3333/src/components/alert/test/basic?rtl=true`. - -#### Lint Changes - -1. Run `npm run lint` to lint the TypeScript and Sass. -2. If there are lint errors, run `npm run lint.fix` to automatically fix any errors. Repeat step 1 to ensure the errors have been fixed, and manually fix them if not. -3. To lint and fix only TypeScript errors, run `npm run lint.ts` and `npm run lint.ts.fix`, respectively. -4. To lint and fix only Sass errors, run `npm run lint.sass` and `npm run lint.sass.fix`, respectively. - -#### Modifying Documentation - -1. Locate the `readme.md` file in the component's directory. -2. Modify the documentation **above** the line that says `` in this file. -3. To update any of the auto generated documentation below that line, make the relevant changes in the following places: - -- `Usage`: update the component's usage examples in the component's `usage/` directory -- `Properties`, `Events`, or `Methods`: update the component's TypeScript file (`*.tsx`) -- `CSS Custom Properties`: update the component's main Sass file (`*.scss`) - -#### Modifying Tests - -1. Locate the test to modify inside the `test/` folder in the component's directory. -2. If a test exists, modify the test by adding an example to reproduce the problem fixed or feature added. -3. If a new test is needed, the easiest way is to copy the `basic/` directory from the component's `test/` directory, rename it, and edit the content in both the `index.html` and `e2e.ts` file (see [Screenshot Tests](#screenshot-tests) for more information on this file). -4. The `preview/` directory is used in the documentation as a demo. Only update this test if there is a bug in the test or if the API has a change that hasn't been updated in the test. - -##### Screenshot Tests - -1. If the test exists in screenshot, there will be a file named `e2e.ts` in the directory of the test. -2. A screenshot test can be added by including this file and adding one or more `test()` calls that include a call to `page.compareScreenshot()`. See [Stencil end-to-end testing](https://stenciljs.com/docs/end-to-end-testing) and existing tests in `core/` for examples. -3. **Important:** each `test()` should have only one screenshot (`page.compareScreenshot()`) call **or** it should check the expect at the end of each test. If there is a mismatch it will fail the test which will prevent the rest of the test from running, i.e. if the first screenshot fails the remaining screenshot calls would not be called _unless_ they are in a separate test or all of the expects are called at the end. -4. To run screenshot locally, use the following command: `npm run test.screenshot`. - - To run screenshot for a specific test, pass the path to the test or a string to search for. - - For example, running all `alert` tests: `npm run test.screenshot alert`. - - Or, running the basic `alert` tests: `npm run test.screenshot src/components/alert/test/basic/e2e.ts`. - -#### Building Changes - -1. Once all changes have been made and the documentation has been updated, run `npm run build` inside of the `core` directory. This will add your changes to any auto-generated files, if necessary. -2. Review the changes and, if everything looks correct, [commit](#commit-message-format) the changes. -3. Make sure the build has finished before committing. If you made changes to the documentation, properties, methods, or anything else that requires an update to a generate file, this needs to be committed. -4. After the changes have been pushed, publish the branch and [create a pull request](#creating-a-pull-request). - -### Submit Pull Request - -1. [Create a new pull request](https://github.com/ionic-team/ionic/compare) with the `master` branch as the `base`. You may need to click on `compare across forks` to find your changes. -2. See the [Creating a pull request from a fork](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) GitHub help article for more information. -3. Please fill out the provided Pull Request template to the best of your ability and include any issues that are related. - -## Commit Message Guidelines - -We have very precise rules over how our git commit messages should be formatted. This leads to readable messages that are easy to follow when looking through the project history. We also use the git commit messages to generate our [changelog](https://github.com/ionic-team/ionic/blob/master/CHANGELOG.md). Our format closely resembles Angular's [commit message guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit). - -### Commit Message Format - -We follow the [Conventional Commits specification](https://www.conventionalcommits.org/). A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**: - -``` -(): - - - -