Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
360fce73d4 | ||
|
|
8c21980a70 | ||
|
|
3c6bb9fb00 | ||
|
|
a130a4a63a | ||
|
|
e5ed8a10ed | ||
|
|
8b0769ce75 | ||
|
|
2229c24bf5 | ||
|
|
a6b19f40b2 | ||
|
|
d91edcffdf | ||
|
|
4c1d0127b6 | ||
|
|
7075808ba8 | ||
|
|
67a1800094 | ||
|
|
895ef4798e | ||
|
|
f1e6a4bb71 | ||
|
|
a671b74756 | ||
|
|
b9013c9457 | ||
|
|
dc764e45e9 | ||
|
|
1cd81b9230 | ||
|
|
05026c5a48 | ||
|
|
a2e803a553 | ||
|
|
56265e35d1 | ||
|
|
95a7d710e7 | ||
|
|
a00a389df7 | ||
|
|
a62d382171 | ||
|
|
8d39ea0c6e | ||
|
|
e4c042834c | ||
|
|
6203b88b9f | ||
|
|
fdb77960ad | ||
|
|
227d637998 | ||
|
|
cbb4ad5683 | ||
|
|
75f6c05fb9 | ||
|
|
d5627c7368 | ||
|
|
74cd71af24 | ||
|
|
30d1910d6e | ||
|
|
b154f4ed09 | ||
|
|
d25b8a34f2 | ||
|
|
244f9a1dd6 | ||
|
|
ffcf5d0268 | ||
|
|
759147fab6 | ||
|
|
dc713167f9 | ||
|
|
0f7dd51767 | ||
|
|
31c5416a51 | ||
|
|
baed34722b | ||
|
|
708d5845b9 | ||
|
|
5780a95a9c | ||
|
|
dd68369338 |
@@ -8,7 +8,7 @@ inputs:
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22.x
|
||||
|
||||
@@ -8,7 +8,7 @@ inputs:
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22.x
|
||||
@@ -31,4 +31,6 @@ runs:
|
||||
with:
|
||||
name: ionic-core
|
||||
output: core/CoreBuild.zip
|
||||
paths: core/dist core/components core/css core/hydrate core/loader core/src/components.d.ts core/api.txt
|
||||
# Include generated proxy files from Stencil output targets so
|
||||
# framework builds can detect when they need to be updated
|
||||
paths: core/dist core/components core/css core/hydrate core/loader core/src/components.d.ts core/api.txt packages/angular/src/directives/proxies.ts packages/angular/src/directives/proxies-list.ts packages/angular/standalone/src/directives/proxies.ts packages/vue/src/proxies.ts packages/react/src/components/proxies.ts packages/react/src/components/inner-proxies.ts packages/react/src/components/routing-proxies.ts
|
||||
|
||||
@@ -10,7 +10,7 @@ inputs:
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: ${{ inputs.name }}
|
||||
path: ${{ inputs.path }}
|
||||
|
||||
@@ -32,6 +32,10 @@ runs:
|
||||
run: npm install
|
||||
shell: bash
|
||||
working-directory: ./packages/angular/test/build/${{ inputs.app }}
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install
|
||||
shell: bash
|
||||
working-directory: ./packages/angular/test/build/${{ inputs.app }}
|
||||
- name: Sync Built Changes
|
||||
run: npm run sync
|
||||
shell: bash
|
||||
|
||||
@@ -10,7 +10,7 @@ runs:
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22.x
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: ./artifacts
|
||||
- name: Extract Archives
|
||||
|
||||
30
.github/workflows/build.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
build-core:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-core
|
||||
with:
|
||||
ionicons-version: ${{ inputs.ionicons_npm_release_tag }}
|
||||
@@ -31,21 +31,21 @@ jobs:
|
||||
needs: [build-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-core-clean-build
|
||||
|
||||
test-core-lint:
|
||||
needs: [build-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-core-lint
|
||||
|
||||
test-core-spec:
|
||||
needs: [build-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-core-spec
|
||||
|
||||
test-core-screenshot:
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
needs: [build-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-core-screenshot
|
||||
with:
|
||||
shard: ${{ matrix.shard }}
|
||||
@@ -90,14 +90,14 @@ jobs:
|
||||
needs: [build-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-vue
|
||||
|
||||
build-vue-router:
|
||||
needs: [build-vue]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-vue-router
|
||||
|
||||
test-vue-e2e:
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
needs: [build-vue, build-vue-router]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-vue-e2e
|
||||
with:
|
||||
app: ${{ matrix.apps }}
|
||||
@@ -126,14 +126,14 @@ jobs:
|
||||
needs: [build-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-angular
|
||||
|
||||
build-angular-server:
|
||||
needs: [build-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-angular-server
|
||||
|
||||
test-angular-e2e:
|
||||
@@ -144,7 +144,7 @@ jobs:
|
||||
needs: [build-angular, build-angular-server]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-angular-e2e
|
||||
with:
|
||||
app: ${{ matrix.apps }}
|
||||
@@ -162,14 +162,14 @@ jobs:
|
||||
needs: [build-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-react
|
||||
|
||||
build-react-router:
|
||||
needs: [build-react]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-react-router
|
||||
|
||||
test-react-router-e2e:
|
||||
@@ -180,7 +180,7 @@ jobs:
|
||||
needs: [build-react, build-react-router]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-react-router-e2e
|
||||
with:
|
||||
app: ${{ matrix.apps }}
|
||||
@@ -202,7 +202,7 @@ jobs:
|
||||
needs: [build-react, build-react-router]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-react-e2e
|
||||
with:
|
||||
app: ${{ matrix.apps }}
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
permissions:
|
||||
security-events: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: javascript
|
||||
|
||||
2
.github/workflows/dev-build.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
outputs:
|
||||
dev-hash: ${{ steps.create-dev-hash.outputs.DEV_HASH }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
# A 1 is required before the timestamp
|
||||
# as lerna will fail when there is a leading 0
|
||||
# See https://github.com/lerna/lerna/issues/2840
|
||||
|
||||
2
.github/workflows/nightly.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
outputs:
|
||||
nightly-hash: ${{ steps.create-nightly-hash.outputs.NIGHTLY_HASH }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
# A 1 is required before the timestamp
|
||||
# as lerna will fail when there is a leading 0
|
||||
# See https://github.com/lerna/lerna/issues/2840
|
||||
|
||||
16
.github/workflows/release-ionic.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
release-core:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/publish-npm
|
||||
with:
|
||||
scope: '@ionic/core'
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
needs: [release-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Restore @ionic/docs built cache
|
||||
uses: ./.github/workflows/actions/download-archive
|
||||
with:
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
needs: [release-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Restore @ionic/core built cache
|
||||
uses: ./.github/workflows/actions/download-archive
|
||||
with:
|
||||
@@ -95,7 +95,7 @@ jobs:
|
||||
needs: [release-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Restore @ionic/core built cache
|
||||
uses: ./.github/workflows/actions/download-archive
|
||||
with:
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
needs: [release-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Restore @ionic/core built cache
|
||||
uses: ./.github/workflows/actions/download-archive
|
||||
with:
|
||||
@@ -147,7 +147,7 @@ jobs:
|
||||
needs: [release-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Restore @ionic/core built cache
|
||||
uses: ./.github/workflows/actions/download-archive
|
||||
with:
|
||||
@@ -168,7 +168,7 @@ jobs:
|
||||
needs: [release-react]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Restore @ionic/core built cache
|
||||
uses: ./.github/workflows/actions/download-archive
|
||||
with:
|
||||
@@ -194,7 +194,7 @@ jobs:
|
||||
needs: [release-vue]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Restore @ionic/core built cache
|
||||
uses: ./.github/workflows/actions/download-archive
|
||||
with:
|
||||
|
||||
4
.github/workflows/release.yml
vendored
@@ -48,7 +48,7 @@ jobs:
|
||||
needs: [release-ionic]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
token: ${{ secrets.IONITRON_TOKEN }}
|
||||
fetch-depth: 0
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
needs: [finalize-release]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
# Pull the latest version of the reference
|
||||
# branch instead of the revision that triggered
|
||||
# the workflow otherwise we won't get the commit
|
||||
|
||||
30
.github/workflows/stencil-nightly.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
build-core-with-stencil-nightly:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-core-stencil-prerelease
|
||||
with:
|
||||
stencil-version: ${{ inputs.npm_release_tag || 'nightly' }}
|
||||
@@ -35,21 +35,21 @@ jobs:
|
||||
needs: [build-core-with-stencil-nightly]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-core-clean-build
|
||||
|
||||
test-core-lint:
|
||||
needs: [build-core-with-stencil-nightly]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-core-lint
|
||||
|
||||
test-core-spec:
|
||||
needs: [build-core-with-stencil-nightly]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-core-spec
|
||||
with:
|
||||
stencil-version: ${{ inputs.npm_release_tag || 'nightly' }}
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
needs: [build-core-with-stencil-nightly]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-core-screenshot
|
||||
with:
|
||||
shard: ${{ matrix.shard }}
|
||||
@@ -100,14 +100,14 @@ jobs:
|
||||
needs: [build-core-with-stencil-nightly]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-vue
|
||||
|
||||
build-vue-router:
|
||||
needs: [build-vue]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-vue-router
|
||||
|
||||
test-vue-e2e:
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
needs: [build-vue, build-vue-router]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-vue-e2e
|
||||
with:
|
||||
app: ${{ matrix.apps }}
|
||||
@@ -136,14 +136,14 @@ jobs:
|
||||
needs: [build-core-with-stencil-nightly]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-angular
|
||||
|
||||
build-angular-server:
|
||||
needs: [build-core-with-stencil-nightly]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-angular-server
|
||||
|
||||
test-angular-e2e:
|
||||
@@ -154,7 +154,7 @@ jobs:
|
||||
needs: [build-angular, build-angular-server]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-angular-e2e
|
||||
with:
|
||||
app: ${{ matrix.apps }}
|
||||
@@ -172,14 +172,14 @@ jobs:
|
||||
needs: [build-core-with-stencil-nightly]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-react
|
||||
|
||||
build-react-router:
|
||||
needs: [build-react]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-react-router
|
||||
|
||||
test-react-router-e2e:
|
||||
@@ -190,7 +190,7 @@ jobs:
|
||||
needs: [build-react, build-react-router]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-react-router-e2e
|
||||
with:
|
||||
app: ${{ matrix.apps }}
|
||||
@@ -212,7 +212,7 @@ jobs:
|
||||
needs: [build-react, build-react-router]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-react-e2e
|
||||
with:
|
||||
app: ${{ matrix.apps }}
|
||||
|
||||
6
.github/workflows/update-screenshots.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
build-core:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/build-core
|
||||
|
||||
test-core-screenshot:
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
needs: [build-core]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/workflows/actions/test-core-screenshot
|
||||
with:
|
||||
shard: ${{ matrix.shard }}
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test-core-screenshot]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
# Normally, we could just push with the
|
||||
# default GITHUB_TOKEN, but that will
|
||||
# not cause the build workflow
|
||||
|
||||
59
CHANGELOG.md
@@ -3,6 +3,65 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [8.7.2](https://github.com/ionic-team/ionic-framework/compare/v8.7.1...v8.7.2) (2025-08-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reorder-group:** add children fallback for framework compatibility ([#30593](https://github.com/ionic-team/ionic-framework/issues/30593)) ([1cd81b9](https://github.com/ionic-team/ionic-framework/commit/1cd81b92301378d55bce63a01dfcf95a91c92652)), closes [#30592](https://github.com/ionic-team/ionic-framework/issues/30592)
|
||||
* **tabs:** add fallback to select tab if router integration fails ([#30599](https://github.com/ionic-team/ionic-framework/issues/30599)) ([a2e803a](https://github.com/ionic-team/ionic-framework/commit/a2e803a553dc58fc0e1599e515a56180a7ab263a)), closes [#30552](https://github.com/ionic-team/ionic-framework/issues/30552)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.7.1](https://github.com/ionic-team/ionic-framework/compare/v8.7.0...v8.7.1) (2025-07-31)
|
||||
|
||||
### Dependencies
|
||||
|
||||
* **stencil:** upgrade `@stencil/core` to version 4.36.2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.7.0](https://github.com/ionic-team/ionic-framework/compare/v8.6.7...v8.7.0) (2025-07-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **css:** add new css utility classes for display and flex utils ([#30567](https://github.com/ionic-team/ionic-framework/issues/30567)) ([75f6c05](https://github.com/ionic-team/ionic-framework/commit/75f6c05fb96313ef890cc80a229a3a3ed3d57460)), closes [#22469](https://github.com/ionic-team/ionic-framework/issues/22469)
|
||||
* **datetime:** add border property to highlightedDates ([#30534](https://github.com/ionic-team/ionic-framework/issues/30534)) ([d5627c7](https://github.com/ionic-team/ionic-framework/commit/d5627c73681faf658ea3b869f3fb04d708391eb9)), closes [#29833](https://github.com/ionic-team/ionic-framework/issues/29833)
|
||||
* **deps:** update ionicons to v8 ([#30390](https://github.com/ionic-team/ionic-framework/issues/30390)) ([74cd71a](https://github.com/ionic-team/ionic-framework/commit/74cd71af243183aa738d11b280e155bdfd652126)), closes [#30445](https://github.com/ionic-team/ionic-framework/issues/30445)
|
||||
* **modal:** add IonModalToken for injecting modal elements in Angular components ([#30474](https://github.com/ionic-team/ionic-framework/issues/30474)) ([30d1910](https://github.com/ionic-team/ionic-framework/commit/30d1910d6ea5428b414d0e127e7681f59426c538))
|
||||
* **reorder-group:** add ionReorderStart, ionReorderMove, ionReorderEnd events ([#30471](https://github.com/ionic-team/ionic-framework/issues/30471)) ([b154f4e](https://github.com/ionic-team/ionic-framework/commit/b154f4ed095890f57ccab539fd9217976a5466e5)), closes [#23148](https://github.com/ionic-team/ionic-framework/issues/23148) [#27614](https://github.com/ionic-team/ionic-framework/issues/27614)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.7](https://github.com/ionic-team/ionic-framework/compare/v8.6.6...v8.6.7) (2025-07-30)
|
||||
|
||||
### Dependencies
|
||||
|
||||
* **stencil:** downgrade `@stencil/core` to version 4.33.1
|
||||
|
||||
_Stencil has been downgraded due to an uncaught regression in Reorder._
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.6](https://github.com/ionic-team/ionic-framework/compare/v8.6.5...v8.6.6) (2025-07-30)
|
||||
|
||||
### Dependencies
|
||||
|
||||
* **stencil:** upgrade `@stencil/core` to version 4.36.2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.5](https://github.com/ionic-team/ionic-framework/compare/v8.6.4...v8.6.5) (2025-07-16)
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,64 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [8.7.2](https://github.com/ionic-team/ionic-framework/compare/v8.7.1...v8.7.2) (2025-08-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reorder-group:** add children fallback for framework compatibility ([#30593](https://github.com/ionic-team/ionic-framework/issues/30593)) ([1cd81b9](https://github.com/ionic-team/ionic-framework/commit/1cd81b92301378d55bce63a01dfcf95a91c92652)), closes [#30592](https://github.com/ionic-team/ionic-framework/issues/30592)
|
||||
* **tabs:** add fallback to select tab if router integration fails ([#30599](https://github.com/ionic-team/ionic-framework/issues/30599)) ([a2e803a](https://github.com/ionic-team/ionic-framework/commit/a2e803a553dc58fc0e1599e515a56180a7ab263a)), closes [#30552](https://github.com/ionic-team/ionic-framework/issues/30552)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.7.1](https://github.com/ionic-team/ionic-framework/compare/v8.7.0...v8.7.1) (2025-07-31)
|
||||
|
||||
### Dependencies
|
||||
|
||||
* **stencil:** upgrade `@stencil/core` to version 4.36.2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.7.0](https://github.com/ionic-team/ionic-framework/compare/v8.6.7...v8.7.0) (2025-07-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **css:** add new css utility classes for display and flex utils ([#30567](https://github.com/ionic-team/ionic-framework/issues/30567)) ([75f6c05](https://github.com/ionic-team/ionic-framework/commit/75f6c05fb96313ef890cc80a229a3a3ed3d57460)), closes [#22469](https://github.com/ionic-team/ionic-framework/issues/22469)
|
||||
* **datetime:** add border property to highlightedDates ([#30534](https://github.com/ionic-team/ionic-framework/issues/30534)) ([d5627c7](https://github.com/ionic-team/ionic-framework/commit/d5627c73681faf658ea3b869f3fb04d708391eb9)), closes [#29833](https://github.com/ionic-team/ionic-framework/issues/29833)
|
||||
* **deps:** update ionicons to v8 ([#30390](https://github.com/ionic-team/ionic-framework/issues/30390)) ([74cd71a](https://github.com/ionic-team/ionic-framework/commit/74cd71af243183aa738d11b280e155bdfd652126)), closes [#30445](https://github.com/ionic-team/ionic-framework/issues/30445)
|
||||
* **reorder-group:** add ionReorderStart, ionReorderMove, ionReorderEnd events ([#30471](https://github.com/ionic-team/ionic-framework/issues/30471)) ([b154f4e](https://github.com/ionic-team/ionic-framework/commit/b154f4ed095890f57ccab539fd9217976a5466e5)), closes [#23148](https://github.com/ionic-team/ionic-framework/issues/23148) [#27614](https://github.com/ionic-team/ionic-framework/issues/27614)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.7](https://github.com/ionic-team/ionic-framework/compare/v8.6.6...v8.6.7) (2025-07-30)
|
||||
|
||||
### Dependencies
|
||||
|
||||
* **stencil:** downgrade `@stencil/core` to version 4.33.1
|
||||
|
||||
_Stencil has been downgraded due to an uncaught regression in Reorder._
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.6](https://github.com/ionic-team/ionic-framework/compare/v8.6.5...v8.6.6) (2025-07-30)
|
||||
|
||||
### Dependencies
|
||||
|
||||
* **stencil:** upgrade `@stencil/core` to version 4.36.2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.5](https://github.com/ionic-team/ionic-framework/compare/v8.6.4...v8.6.5) (2025-07-16)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Get Playwright
|
||||
FROM mcr.microsoft.com/playwright:v1.54.1
|
||||
FROM mcr.microsoft.com/playwright:v1.54.2
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /ionic
|
||||
|
||||
35
core/api.txt
@@ -1205,6 +1205,37 @@ ion-modal,part,backdrop
|
||||
ion-modal,part,content
|
||||
ion-modal,part,handle
|
||||
|
||||
ion-my-chip,shadow
|
||||
ion-my-chip,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
|
||||
ion-my-chip,prop,disabled,boolean,false,false,false
|
||||
ion-my-chip,prop,hue,"bold" | "subtle" | undefined,'subtle',false,false
|
||||
ion-my-chip,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-my-chip,prop,outline,boolean,false,false,false
|
||||
ion-my-chip,prop,shape,"rectangular" | "round" | "soft" | undefined,'soft',false,false
|
||||
ion-my-chip,prop,size,"large" | "small" | undefined,'small',false,false
|
||||
ion-my-chip,prop,theme,"ios" | "md" | "ionic",undefined,false,false
|
||||
ion-my-chip,css-prop,--ion-chip-border-width
|
||||
ion-my-chip,css-prop,--ion-chip-focus-ring-color
|
||||
ion-my-chip,css-prop,--ion-chip-focus-ring-width
|
||||
ion-my-chip,css-prop,--ion-chip-font-weight
|
||||
ion-my-chip,css-prop,--ion-chip-gap
|
||||
ion-my-chip,css-prop,--ion-chip-hue-bold-bg
|
||||
ion-my-chip,css-prop,--ion-chip-hue-bold-border-color
|
||||
ion-my-chip,css-prop,--ion-chip-hue-bold-color
|
||||
ion-my-chip,css-prop,--ion-chip-hue-subtle-bg
|
||||
ion-my-chip,css-prop,--ion-chip-hue-subtle-border-color
|
||||
ion-my-chip,css-prop,--ion-chip-hue-subtle-color
|
||||
ion-my-chip,css-prop,--ion-chip-line-height
|
||||
ion-my-chip,css-prop,--ion-chip-padding-horizontal
|
||||
ion-my-chip,css-prop,--ion-chip-padding-vertical
|
||||
ion-my-chip,css-prop,--ion-chip-shape-rectangular-border-radius
|
||||
ion-my-chip,css-prop,--ion-chip-shape-round-border-radius
|
||||
ion-my-chip,css-prop,--ion-chip-shape-soft-border-radius
|
||||
ion-my-chip,css-prop,--ion-chip-size-large-font-size
|
||||
ion-my-chip,css-prop,--ion-chip-size-large-min-height
|
||||
ion-my-chip,css-prop,--ion-chip-size-small-font-size
|
||||
ion-my-chip,css-prop,--ion-chip-size-small-min-height
|
||||
|
||||
ion-nav,shadow
|
||||
ion-nav,prop,animated,boolean,true,false,false
|
||||
ion-nav,prop,animation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
@@ -1231,6 +1262,7 @@ ion-nav,event,ionNavWillChange,void,false
|
||||
ion-nav-link,none
|
||||
ion-nav-link,prop,component,Function | HTMLElement | ViewController | null | string | undefined,undefined,false,false
|
||||
ion-nav-link,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false
|
||||
ion-nav-link,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-nav-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-nav-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
|
||||
|
||||
@@ -1508,6 +1540,9 @@ ion-reorder-group,none
|
||||
ion-reorder-group,prop,disabled,boolean,true,false,false
|
||||
ion-reorder-group,method,complete,complete(listOrReorder?: boolean | any[]) => Promise<any>
|
||||
ion-reorder-group,event,ionItemReorder,ItemReorderEventDetail,true
|
||||
ion-reorder-group,event,ionReorderEnd,ReorderEndEventDetail,true
|
||||
ion-reorder-group,event,ionReorderMove,ReorderMoveEventDetail,true
|
||||
ion-reorder-group,event,ionReorderStart,void,true
|
||||
|
||||
ion-ripple-effect,shadow
|
||||
ion-ripple-effect,prop,type,"bounded" | "unbounded",'bounded',false,false
|
||||
|
||||
131
core/package-lock.json
generated
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.6.5",
|
||||
"version": "8.7.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/core",
|
||||
"version": "8.6.5",
|
||||
"version": "8.7.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
"@stencil/core": "4.36.2",
|
||||
"ionicons": "^8.0.13",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -22,7 +22,7 @@
|
||||
"@clack/prompts": "^0.11.0",
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
"@ionic/prettier-config": "^2.0.0",
|
||||
"@playwright/test": "^1.54.1",
|
||||
"@playwright/test": "^1.54.2",
|
||||
"@rollup/plugin-node-resolve": "^8.4.0",
|
||||
"@rollup/plugin-virtual": "^2.0.3",
|
||||
"@stencil/angular-output-target": "^0.10.0",
|
||||
@@ -672,27 +672,27 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/haptics": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-7.0.1.tgz",
|
||||
"integrity": "sha512-ewZmspE5krgDUj5ZvUDcfNZvgerAIr+3bDSk6DLzyvBZ/dYmr/tMLu5H6WtYaaKYZJ32aZAudGpIal5epDyBYA==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-7.0.2.tgz",
|
||||
"integrity": "sha512-vqfeEM6s2zMgLjpITCTUIy7P/hadq/Gr5E/RClFgMJPB41Y5FsqOKD+j85/uwh8N2cf/aWaPeXUmjnTzJbEB2g==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/keyboard": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.1.tgz",
|
||||
"integrity": "sha512-Gi064vOARMac+x9/DmEFeywN9oAETMf3OYsMuYm9gA8SvdsDJ3QJqMoFnSEIORYXe21Jzt2SIEdLlpT65P/b2g==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.2.tgz",
|
||||
"integrity": "sha512-9We5BY1mu+QWOReDukr+6HxA4Bh0mKBU0txFtwXJdjBohttMYWJzB+dQf4oHrX8odiU2Cm/BfDdAU2wV06Cyig==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@capacitor/status-bar": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-7.0.1.tgz",
|
||||
"integrity": "sha512-iDv3mXYo9CdxYRVwt3/pRyuk25p7Sn4GfaS/zMZyVIqTzsvKLCIIH3GdKK+ta+nsNcAVpCw/t5jFEBt1D18ctA==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-7.0.2.tgz",
|
||||
"integrity": "sha512-fYYkkdzCbQV+MjZVnaQTFl5I4bddnFW8ZrPVxDjNoGVPTUG7H58Ij1+NcuNxHLXjJvZOoZeYJ3w3I16Wb2zssw==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=7.0.0"
|
||||
@@ -1715,12 +1715,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.54.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.1.tgz",
|
||||
"integrity": "sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw==",
|
||||
"version": "1.54.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.2.tgz",
|
||||
"integrity": "sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"playwright": "1.54.1"
|
||||
"playwright": "1.54.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -1914,9 +1914,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "4.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.33.1.tgz",
|
||||
"integrity": "sha512-12k9xhAJBkpg598it+NRmaYIdEe6TSnsL/v6/KRXDcUyTK11VYwZQej2eHnMWtqot+znJ+GNTqb5YbiXi+5Low==",
|
||||
"version": "4.36.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.36.2.tgz",
|
||||
"integrity": "sha512-PRFSpxNzX9Oi0Wfh02asztN9Sgev/MacfZwmd+VVyE6ZxW+a/kEpAYZhzGAmE+/aKVOGYuug7R9SulanYGxiDQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
@@ -3474,9 +3474,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
|
||||
"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz",
|
||||
"integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
@@ -5711,11 +5711,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ionicons": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.2.2.tgz",
|
||||
"integrity": "sha512-I3iYIfc9Q9FRifWyFSwTAvbEABWlWY32i0sAVDDPGYnaIZVugkLCZFbEcrphW6ixVPg8tt1oLwalo/JJwbEqnA==",
|
||||
"version": "8.0.13",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-8.0.13.tgz",
|
||||
"integrity": "sha512-2QQVyG2P4wszne79jemMjWYLp0DBbDhr4/yFroPCxvPP1wtMxgdIV3l5n+XZ5E9mgoXU79w7yTWpm2XzJsISxQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.0.3"
|
||||
"@stencil/core": "^4.35.3"
|
||||
}
|
||||
},
|
||||
"node_modules/is-alphabetical": {
|
||||
@@ -8592,12 +8593,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.54.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.1.tgz",
|
||||
"integrity": "sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==",
|
||||
"version": "1.54.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.2.tgz",
|
||||
"integrity": "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"playwright-core": "1.54.1"
|
||||
"playwright-core": "1.54.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -8610,9 +8611,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.54.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.1.tgz",
|
||||
"integrity": "sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==",
|
||||
"version": "1.54.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.2.tgz",
|
||||
"integrity": "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
@@ -11110,23 +11111,23 @@
|
||||
}
|
||||
},
|
||||
"@capacitor/haptics": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-7.0.1.tgz",
|
||||
"integrity": "sha512-ewZmspE5krgDUj5ZvUDcfNZvgerAIr+3bDSk6DLzyvBZ/dYmr/tMLu5H6WtYaaKYZJ32aZAudGpIal5epDyBYA==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-7.0.2.tgz",
|
||||
"integrity": "sha512-vqfeEM6s2zMgLjpITCTUIy7P/hadq/Gr5E/RClFgMJPB41Y5FsqOKD+j85/uwh8N2cf/aWaPeXUmjnTzJbEB2g==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"@capacitor/keyboard": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.1.tgz",
|
||||
"integrity": "sha512-Gi064vOARMac+x9/DmEFeywN9oAETMf3OYsMuYm9gA8SvdsDJ3QJqMoFnSEIORYXe21Jzt2SIEdLlpT65P/b2g==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.2.tgz",
|
||||
"integrity": "sha512-9We5BY1mu+QWOReDukr+6HxA4Bh0mKBU0txFtwXJdjBohttMYWJzB+dQf4oHrX8odiU2Cm/BfDdAU2wV06Cyig==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"@capacitor/status-bar": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-7.0.1.tgz",
|
||||
"integrity": "sha512-iDv3mXYo9CdxYRVwt3/pRyuk25p7Sn4GfaS/zMZyVIqTzsvKLCIIH3GdKK+ta+nsNcAVpCw/t5jFEBt1D18ctA==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-7.0.2.tgz",
|
||||
"integrity": "sha512-fYYkkdzCbQV+MjZVnaQTFl5I4bddnFW8ZrPVxDjNoGVPTUG7H58Ij1+NcuNxHLXjJvZOoZeYJ3w3I16Wb2zssw==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
@@ -11862,12 +11863,12 @@
|
||||
}
|
||||
},
|
||||
"@playwright/test": {
|
||||
"version": "1.54.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.1.tgz",
|
||||
"integrity": "sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw==",
|
||||
"version": "1.54.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.2.tgz",
|
||||
"integrity": "sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"playwright": "1.54.1"
|
||||
"playwright": "1.54.2"
|
||||
}
|
||||
},
|
||||
"@rollup/plugin-node-resolve": {
|
||||
@@ -11983,9 +11984,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@stencil/core": {
|
||||
"version": "4.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.33.1.tgz",
|
||||
"integrity": "sha512-12k9xhAJBkpg598it+NRmaYIdEe6TSnsL/v6/KRXDcUyTK11VYwZQej2eHnMWtqot+znJ+GNTqb5YbiXi+5Low==",
|
||||
"version": "4.36.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.36.2.tgz",
|
||||
"integrity": "sha512-PRFSpxNzX9Oi0Wfh02asztN9Sgev/MacfZwmd+VVyE6ZxW+a/kEpAYZhzGAmE+/aKVOGYuug7R9SulanYGxiDQ==",
|
||||
"requires": {
|
||||
"@rollup/rollup-darwin-arm64": "4.34.9",
|
||||
"@rollup/rollup-darwin-x64": "4.34.9",
|
||||
@@ -13075,9 +13076,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
|
||||
"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz",
|
||||
"integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk-template": {
|
||||
@@ -14744,11 +14745,11 @@
|
||||
}
|
||||
},
|
||||
"ionicons": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.2.2.tgz",
|
||||
"integrity": "sha512-I3iYIfc9Q9FRifWyFSwTAvbEABWlWY32i0sAVDDPGYnaIZVugkLCZFbEcrphW6ixVPg8tt1oLwalo/JJwbEqnA==",
|
||||
"version": "8.0.13",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-8.0.13.tgz",
|
||||
"integrity": "sha512-2QQVyG2P4wszne79jemMjWYLp0DBbDhr4/yFroPCxvPP1wtMxgdIV3l5n+XZ5E9mgoXU79w7yTWpm2XzJsISxQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "^4.0.3"
|
||||
"@stencil/core": "^4.35.3"
|
||||
}
|
||||
},
|
||||
"is-alphabetical": {
|
||||
@@ -16811,19 +16812,19 @@
|
||||
}
|
||||
},
|
||||
"playwright": {
|
||||
"version": "1.54.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.1.tgz",
|
||||
"integrity": "sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==",
|
||||
"version": "1.54.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.2.tgz",
|
||||
"integrity": "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fsevents": "2.3.2",
|
||||
"playwright-core": "1.54.1"
|
||||
"playwright-core": "1.54.2"
|
||||
}
|
||||
},
|
||||
"playwright-core": {
|
||||
"version": "1.54.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.1.tgz",
|
||||
"integrity": "sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==",
|
||||
"version": "1.54.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.2.tgz",
|
||||
"integrity": "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==",
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.6.5",
|
||||
"version": "8.7.2",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -31,8 +31,8 @@
|
||||
"loader/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
"@stencil/core": "4.36.2",
|
||||
"ionicons": "^8.0.13",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -44,7 +44,7 @@
|
||||
"@clack/prompts": "^0.11.0",
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
"@ionic/prettier-config": "^2.0.0",
|
||||
"@playwright/test": "^1.54.1",
|
||||
"@playwright/test": "^1.54.2",
|
||||
"@rollup/plugin-node-resolve": "^8.4.0",
|
||||
"@rollup/plugin-virtual": "^2.0.3",
|
||||
"@stencil/angular-output-target": "^0.10.0",
|
||||
|
||||
119
core/src/components.d.ts
vendored
@@ -30,7 +30,7 @@ import { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAct
|
||||
import { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
|
||||
import { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
|
||||
import { RefresherEventDetail } from "./components/refresher/refresher-interface";
|
||||
import { ItemReorderEventDetail } from "./components/reorder-group/reorder-group-interface";
|
||||
import { ItemReorderEventDetail, ReorderEndEventDetail, ReorderMoveEventDetail } from "./components/reorder-group/reorder-group-interface";
|
||||
import { NavigationHookCallback } from "./components/route/route-interface";
|
||||
import { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./components/searchbar/searchbar-interface";
|
||||
import { SegmentChangeEventDetail, SegmentValue } from "./components/segment/segment-interface";
|
||||
@@ -68,7 +68,7 @@ export { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAct
|
||||
export { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
|
||||
export { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
|
||||
export { RefresherEventDetail } from "./components/refresher/refresher-interface";
|
||||
export { ItemReorderEventDetail } from "./components/reorder-group/reorder-group-interface";
|
||||
export { ItemReorderEventDetail, ReorderEndEventDetail, ReorderMoveEventDetail } from "./components/reorder-group/reorder-group-interface";
|
||||
export { NavigationHookCallback } from "./components/route/route-interface";
|
||||
export { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./components/searchbar/searchbar-interface";
|
||||
export { SegmentChangeEventDetail, SegmentValue } from "./components/segment/segment-interface";
|
||||
@@ -2072,6 +2072,45 @@ export namespace Components {
|
||||
*/
|
||||
"trigger": string | undefined;
|
||||
}
|
||||
interface IonMyChip {
|
||||
/**
|
||||
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
|
||||
*/
|
||||
"color"?: Color;
|
||||
/**
|
||||
* If `true`, the user cannot interact with the chip.
|
||||
* @default false
|
||||
*/
|
||||
"disabled": boolean;
|
||||
/**
|
||||
* Set to `"bold"` for a chip with vibrant, bold colors or to `"subtle"` for a chip with muted, subtle colors. Only applies to the `ionic` theme.
|
||||
* @default 'subtle'
|
||||
*/
|
||||
"hue"?: 'bold' | 'subtle';
|
||||
/**
|
||||
* The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* Display an outline style button.
|
||||
* @default false
|
||||
*/
|
||||
"outline": boolean;
|
||||
/**
|
||||
* Set to `"soft"` for a chip with slightly rounded corners, `"round"` for a chip with fully rounded corners, or `"rectangular"` for a chip without rounded corners. Defaults to `"round"` for the `"ionic"` theme and `"soft"` for all other themes.
|
||||
* @default 'soft'
|
||||
*/
|
||||
"shape"?: 'soft' | 'round' | 'rectangular';
|
||||
/**
|
||||
* Set to `"small"` for a chip with less height and padding. Defaults to `"large"` for the ionic theme, and undefined for all other themes.
|
||||
* @default 'small'
|
||||
*/
|
||||
"size"?: 'small' | 'large';
|
||||
/**
|
||||
* The theme determines the visual appearance of the component.
|
||||
*/
|
||||
"theme"?: "ios" | "md" | "ionic";
|
||||
}
|
||||
interface IonNav {
|
||||
/**
|
||||
* If `true`, the nav should animate the transition of components.
|
||||
@@ -2208,6 +2247,10 @@ export namespace Components {
|
||||
* Data you want to pass to the component as props. Only used if the `"routerDirection"` is `"forward"` or `"root"`.
|
||||
*/
|
||||
"componentProps"?: ComponentProps;
|
||||
/**
|
||||
* The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* The transition animation when navigating to another page.
|
||||
*/
|
||||
@@ -2783,7 +2826,7 @@ export namespace Components {
|
||||
}
|
||||
interface IonReorderGroup {
|
||||
/**
|
||||
* Completes the reorder operation. Must be called by the `ionItemReorder` event. If a list of items is passed, the list will be reordered and returned in the proper order. If no parameters are passed or if `true` is passed in, the reorder will complete and the item will remain in the position it was dragged to. If `false` is passed, the reorder will complete and the item will bounce back to its original position.
|
||||
* Completes the reorder operation. Must be called by the `ionReorderEnd` event. If a list of items is passed, the list will be reordered and returned in the proper order. If no parameters are passed or if `true` is passed in, the reorder will complete and the item will remain in the position it was dragged to. If `false` is passed, the reorder will complete and the item will bounce back to its original position.
|
||||
* @param listOrReorder A list of items to be sorted and returned in the new order or a boolean of whether or not the reorder should reposition the item.
|
||||
*/
|
||||
"complete": (listOrReorder?: boolean | any[]) => Promise<any>;
|
||||
@@ -4535,6 +4578,12 @@ declare global {
|
||||
prototype: HTMLIonModalElement;
|
||||
new (): HTMLIonModalElement;
|
||||
};
|
||||
interface HTMLIonMyChipElement extends Components.IonMyChip, HTMLStencilElement {
|
||||
}
|
||||
var HTMLIonMyChipElement: {
|
||||
prototype: HTMLIonMyChipElement;
|
||||
new (): HTMLIonMyChipElement;
|
||||
};
|
||||
interface HTMLIonNavElementEventMap {
|
||||
"ionNavWillLoad": void;
|
||||
"ionNavWillChange": void;
|
||||
@@ -4769,6 +4818,9 @@ declare global {
|
||||
};
|
||||
interface HTMLIonReorderGroupElementEventMap {
|
||||
"ionItemReorder": ItemReorderEventDetail;
|
||||
"ionReorderStart": void;
|
||||
"ionReorderMove": ReorderMoveEventDetail;
|
||||
"ionReorderEnd": ReorderEndEventDetail;
|
||||
}
|
||||
interface HTMLIonReorderGroupElement extends Components.IonReorderGroup, HTMLStencilElement {
|
||||
addEventListener<K extends keyof HTMLIonReorderGroupElementEventMap>(type: K, listener: (this: HTMLIonReorderGroupElement, ev: IonReorderGroupCustomEvent<HTMLIonReorderGroupElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
@@ -5233,6 +5285,7 @@ declare global {
|
||||
"ion-menu-button": HTMLIonMenuButtonElement;
|
||||
"ion-menu-toggle": HTMLIonMenuToggleElement;
|
||||
"ion-modal": HTMLIonModalElement;
|
||||
"ion-my-chip": HTMLIonMyChipElement;
|
||||
"ion-nav": HTMLIonNavElement;
|
||||
"ion-nav-link": HTMLIonNavLinkElement;
|
||||
"ion-note": HTMLIonNoteElement;
|
||||
@@ -7372,6 +7425,45 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"trigger"?: string | undefined;
|
||||
}
|
||||
interface IonMyChip {
|
||||
/**
|
||||
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
|
||||
*/
|
||||
"color"?: Color;
|
||||
/**
|
||||
* If `true`, the user cannot interact with the chip.
|
||||
* @default false
|
||||
*/
|
||||
"disabled"?: boolean;
|
||||
/**
|
||||
* Set to `"bold"` for a chip with vibrant, bold colors or to `"subtle"` for a chip with muted, subtle colors. Only applies to the `ionic` theme.
|
||||
* @default 'subtle'
|
||||
*/
|
||||
"hue"?: 'bold' | 'subtle';
|
||||
/**
|
||||
* The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* Display an outline style button.
|
||||
* @default false
|
||||
*/
|
||||
"outline"?: boolean;
|
||||
/**
|
||||
* Set to `"soft"` for a chip with slightly rounded corners, `"round"` for a chip with fully rounded corners, or `"rectangular"` for a chip without rounded corners. Defaults to `"round"` for the `"ionic"` theme and `"soft"` for all other themes.
|
||||
* @default 'soft'
|
||||
*/
|
||||
"shape"?: 'soft' | 'round' | 'rectangular';
|
||||
/**
|
||||
* Set to `"small"` for a chip with less height and padding. Defaults to `"large"` for the ionic theme, and undefined for all other themes.
|
||||
* @default 'small'
|
||||
*/
|
||||
"size"?: 'small' | 'large';
|
||||
/**
|
||||
* The theme determines the visual appearance of the component.
|
||||
*/
|
||||
"theme"?: "ios" | "md" | "ionic";
|
||||
}
|
||||
interface IonNav {
|
||||
/**
|
||||
* If `true`, the nav should animate the transition of components.
|
||||
@@ -7417,6 +7509,10 @@ declare namespace LocalJSX {
|
||||
* Data you want to pass to the component as props. Only used if the `"routerDirection"` is `"forward"` or `"root"`.
|
||||
*/
|
||||
"componentProps"?: ComponentProps;
|
||||
/**
|
||||
* The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* The transition animation when navigating to another page.
|
||||
*/
|
||||
@@ -8053,9 +8149,22 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"disabled"?: boolean;
|
||||
/**
|
||||
* Event that needs to be listened to in order to complete the reorder action. Once the event has been emitted, the `complete()` method then needs to be called in order to finalize the reorder action.
|
||||
* Event that needs to be listened to in order to complete the reorder action.
|
||||
* @deprecated Use `ionReorderEnd` instead. If you are accessing `event.detail.from` or `event.detail.to` and relying on them being different you should now add checks as they are always emitted in `ionReorderEnd`, even when they are the same.
|
||||
*/
|
||||
"onIonItemReorder"?: (event: IonReorderGroupCustomEvent<ItemReorderEventDetail>) => void;
|
||||
/**
|
||||
* Event that is emitted when the reorder gesture ends. The from and to properties are always available, regardless of if the reorder gesture moved the item. If the item did not change from its start position, the from and to properties will be the same. Once the event has been emitted, the `complete()` method then needs to be called in order to finalize the reorder action.
|
||||
*/
|
||||
"onIonReorderEnd"?: (event: IonReorderGroupCustomEvent<ReorderEndEventDetail>) => void;
|
||||
/**
|
||||
* Event that is emitted as the reorder gesture moves.
|
||||
*/
|
||||
"onIonReorderMove"?: (event: IonReorderGroupCustomEvent<ReorderMoveEventDetail>) => void;
|
||||
/**
|
||||
* Event that is emitted when the reorder gesture starts.
|
||||
*/
|
||||
"onIonReorderStart"?: (event: IonReorderGroupCustomEvent<void>) => void;
|
||||
}
|
||||
interface IonRippleEffect {
|
||||
/**
|
||||
@@ -9150,6 +9259,7 @@ declare namespace LocalJSX {
|
||||
"ion-menu-button": IonMenuButton;
|
||||
"ion-menu-toggle": IonMenuToggle;
|
||||
"ion-modal": IonModal;
|
||||
"ion-my-chip": IonMyChip;
|
||||
"ion-nav": IonNav;
|
||||
"ion-nav-link": IonNavLink;
|
||||
"ion-note": IonNote;
|
||||
@@ -9253,6 +9363,7 @@ declare module "@stencil/core" {
|
||||
"ion-menu-button": LocalJSX.IonMenuButton & JSXBase.HTMLAttributes<HTMLIonMenuButtonElement>;
|
||||
"ion-menu-toggle": LocalJSX.IonMenuToggle & JSXBase.HTMLAttributes<HTMLIonMenuToggleElement>;
|
||||
"ion-modal": LocalJSX.IonModal & JSXBase.HTMLAttributes<HTMLIonModalElement>;
|
||||
"ion-my-chip": LocalJSX.IonMyChip & JSXBase.HTMLAttributes<HTMLIonMyChipElement>;
|
||||
"ion-nav": LocalJSX.IonNav & JSXBase.HTMLAttributes<HTMLIonNavElement>;
|
||||
"ion-nav-link": LocalJSX.IonNavLink & JSXBase.HTMLAttributes<HTMLIonNavLinkElement>;
|
||||
"ion-note": LocalJSX.IonNote & JSXBase.HTMLAttributes<HTMLIonNoteElement>;
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
|
||||
<ion-toolbar color="dark">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button class="ion-hide"></ion-back-button>
|
||||
<ion-back-button class="ion-display-none"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Hidden</ion-title>
|
||||
</ion-toolbar>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -22,15 +22,15 @@ export type DatetimePresentation = 'date-time' | 'time-date' | 'date' | 'time' |
|
||||
|
||||
export type TitleSelectedDatesFormatter = (selectedDates: string[]) => string;
|
||||
|
||||
export type DatetimeHighlightStyle =
|
||||
| {
|
||||
textColor: string;
|
||||
backgroundColor?: string;
|
||||
}
|
||||
| {
|
||||
textColor?: string;
|
||||
backgroundColor: string;
|
||||
};
|
||||
/**
|
||||
* DatetimeHighlightStyle must include textColor, backgroundColor, or border.
|
||||
* It cannot be an empty object.
|
||||
*/
|
||||
export type DatetimeHighlightStyle = {
|
||||
textColor?: string;
|
||||
backgroundColor?: string;
|
||||
border?: string;
|
||||
} & ({ textColor: string } | { backgroundColor: string } | { border: string });
|
||||
|
||||
export type DatetimeHighlight = { date: string } & DatetimeHighlightStyle;
|
||||
|
||||
|
||||
@@ -2335,6 +2335,7 @@ export class Datetime implements ComponentInterface {
|
||||
`${dateStyle ? dateStyle.backgroundColor : ''}`,
|
||||
'important'
|
||||
);
|
||||
el.style.setProperty('border', `${dateStyle ? dateStyle.border : ''}`, 'important');
|
||||
}
|
||||
}}
|
||||
tabindex="-1"
|
||||
|
||||
@@ -5,6 +5,8 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('datetime: custom'), () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(`/src/components/datetime/test/custom`, config);
|
||||
|
||||
await page.locator('.datetime-ready').last().waitFor();
|
||||
});
|
||||
|
||||
test('should allow styling wheel style datetimes', async ({ page }) => {
|
||||
@@ -30,6 +32,13 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test('should allow styling calendar days in grid style datetimes', async ({ page }) => {
|
||||
const datetime = page.locator('#custom-calendar-days');
|
||||
|
||||
// Wait for calendar days to be rendered
|
||||
await page.waitForFunction(() => {
|
||||
const datetime = document.querySelector('#custom-calendar-days');
|
||||
const calendarDays = datetime?.shadowRoot?.querySelectorAll('.calendar-day');
|
||||
return calendarDays && calendarDays.length > 0;
|
||||
});
|
||||
|
||||
await expect(datetime).toHaveScreenshot(screenshot(`datetime-custom-calendar-days`));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
const customDatetime = document.querySelector('#custom-calendar-days');
|
||||
|
||||
// Mock the current day to always have the same screenshots
|
||||
const mockToday = '2023-06-10T16:22';
|
||||
const mockToday = '2023-06-10T16:22:00.000Z';
|
||||
Date = class extends Date {
|
||||
constructor(...args) {
|
||||
if (args.length === 0) {
|
||||
|
||||
@@ -22,11 +22,23 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await expect(monthYearToggle).toContainText('January 2022');
|
||||
|
||||
// Click to open the picker
|
||||
await monthYearToggle.click();
|
||||
await page.waitForChanges();
|
||||
|
||||
// February
|
||||
await monthColumnItems.nth(1).click();
|
||||
// Wait for the picker to be open
|
||||
await page.locator('.month-year-picker-open').waitFor();
|
||||
|
||||
// Wait a bit for the picker to fully load
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
|
||||
// Click on February
|
||||
await monthColumnItems.filter({ hasText: 'February' }).click();
|
||||
|
||||
// Wait for changes
|
||||
await ionChange.next();
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(monthYearToggle).toContainText('February 2022');
|
||||
@@ -38,13 +50,23 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
const datetime = page.locator('ion-datetime');
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
|
||||
// Click to open the picker
|
||||
await monthYearToggle.click();
|
||||
await page.waitForChanges();
|
||||
|
||||
// February
|
||||
await monthColumnItems.nth(1).click();
|
||||
// Wait for the picker to be open
|
||||
await page.locator('.month-year-picker-open').waitFor();
|
||||
|
||||
// Wait a bit for the picker to fully load
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
// Click on February
|
||||
await monthColumnItems.filter({ hasText: 'February' }).click();
|
||||
|
||||
// Wait for changes
|
||||
await ionChange.next();
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionChange).toHaveReceivedEventTimes(1);
|
||||
await expect(datetime).toHaveJSProperty('value', '2022-02-28');
|
||||
});
|
||||
|
||||
@@ -21,16 +21,19 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
date: '2023-01-01', // ensure selected date style overrides highlight
|
||||
textColor: '#800080',
|
||||
backgroundColor: '#ffc0cb',
|
||||
border: '2px solid purple',
|
||||
},
|
||||
{
|
||||
date: '2023-01-02',
|
||||
textColor: '#b22222',
|
||||
backgroundColor: '#fa8072',
|
||||
border: '2px solid purple',
|
||||
},
|
||||
{
|
||||
date: '2023-01-03',
|
||||
textColor: '#0000ff',
|
||||
backgroundColor: '#add8e6',
|
||||
border: '2px solid purple',
|
||||
},
|
||||
];
|
||||
});
|
||||
@@ -52,6 +55,7 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
return {
|
||||
textColor: '#b22222',
|
||||
backgroundColor: '#fa8072',
|
||||
border: '2px solid purple',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -59,6 +63,7 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
return {
|
||||
textColor: '#800080',
|
||||
backgroundColor: '#ffc0cb',
|
||||
border: '2px solid purple',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,6 +71,7 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
return {
|
||||
textColor: '#0000ff',
|
||||
backgroundColor: '#add8e6',
|
||||
border: '2px solid purple',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -77,7 +83,7 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
await expect(datetime).toHaveScreenshot(screenshot(`datetime-highlightedDates-callback`));
|
||||
});
|
||||
|
||||
test('should render highlights correctly when only using one color or the other', async ({ page }) => {
|
||||
test('should render highlights correctly when only using only one color property', async ({ page }) => {
|
||||
const datetime = page.locator('ion-datetime');
|
||||
|
||||
await datetime.evaluate((el: HTMLIonDatetimeElement) => {
|
||||
@@ -90,6 +96,10 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
date: '2023-01-03',
|
||||
textColor: '#0000ff',
|
||||
},
|
||||
{
|
||||
date: '2023-01-04',
|
||||
border: '2px solid purple',
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 20 KiB |
@@ -78,6 +78,10 @@
|
||||
textColor: 'blue',
|
||||
backgroundColor: 'lightblue',
|
||||
},
|
||||
{
|
||||
date: '2023-01-07',
|
||||
border: '2px dotted red',
|
||||
},
|
||||
];
|
||||
|
||||
document.querySelector('#withCallback').highlightedDates = (isoString) => {
|
||||
@@ -103,6 +107,7 @@
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
textColor: 'purple',
|
||||
backgroundColor: 'pink',
|
||||
border: '2px solid purple',
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
@@ -207,6 +207,7 @@ export const getHighlightStyles = (
|
||||
return {
|
||||
textColor: matchingHighlight.textColor,
|
||||
backgroundColor: matchingHighlight.backgroundColor,
|
||||
border: matchingHighlight.border,
|
||||
} as DatetimeHighlightStyle;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Infinite Scroll - Basic</title>
|
||||
<title>Infinite Scroll - Top</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
@@ -18,7 +18,7 @@
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Infinite Scroll - Basic</ion-title>
|
||||
<ion-title>Infinite Scroll - Top</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
</ion-infinite-scroll-content>
|
||||
</ion-infinite-scroll>
|
||||
|
||||
<button onclick="toggleInfiniteScroll()" class="expand">Toggle InfiniteScroll</button>
|
||||
<div id="list"></div>
|
||||
|
||||
<ion-list id="list"></ion-list>
|
||||
<button onclick="toggleInfiniteScroll()" class="expand">Toggle InfiniteScroll</button>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
|
||||
@@ -46,17 +46,26 @@
|
||||
console.log('Loading data...');
|
||||
await wait(500);
|
||||
infiniteScroll.complete();
|
||||
appendItems();
|
||||
appendItems(true);
|
||||
// Custom event consumed in the e2e tests
|
||||
window.dispatchEvent(new CustomEvent('ionInfiniteComplete'));
|
||||
|
||||
console.log('Done');
|
||||
});
|
||||
|
||||
function appendItems() {
|
||||
function appendItems(newItems = false) {
|
||||
const randomColor =
|
||||
'#' +
|
||||
Math.floor(Math.random() * 16777215)
|
||||
.toString(16)
|
||||
.padStart(6, '0');
|
||||
|
||||
for (var i = 0; i < 30; i++) {
|
||||
const el = document.createElement('ion-item');
|
||||
el.textContent = `${1 + i}`;
|
||||
el.textContent = `Item ${1 + i}`;
|
||||
if (newItems) {
|
||||
el.style.borderLeft = `4px solid ${randomColor}`;
|
||||
}
|
||||
list.prepend(el);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,8 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
el.separators = [2, 3];
|
||||
});
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(await hasSeparatorAfter(page, 0)).toBe(false);
|
||||
await expect(await hasSeparatorAfter(page, 1)).toBe(true);
|
||||
await expect(await hasSeparatorAfter(page, 2)).toBe(true);
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
}
|
||||
function initGroup(group) {
|
||||
var groupEl = document.getElementById(group.id);
|
||||
groupEl.addEventListener('ionItemReorder', function (ev) {
|
||||
groupEl.addEventListener('ionReorderEnd', function (ev) {
|
||||
ev.detail.complete();
|
||||
});
|
||||
var groupItems = [];
|
||||
|
||||
@@ -18,7 +18,13 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
const heading = page.locator('ion-menu h1');
|
||||
await expect(heading).toHaveText('Open Menu');
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
/**
|
||||
* Disable the 'scrollable-region-focusable' rule because this test
|
||||
* is missing the required `ion-app` wrapper component. The `ion-app`
|
||||
* wrapper provides the necessary focus management that allows the
|
||||
* menu content to be focusable.
|
||||
*/
|
||||
const results = await new AxeBuilder({ page }).disableRules('scrollable-region-focusable').analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
187
core/src/components/my-chip/my-chip.base.scss
Normal file
@@ -0,0 +1,187 @@
|
||||
@import "../../themes/ionic.functions.color";
|
||||
@import "../../themes/ionic.mixins";
|
||||
|
||||
:host {
|
||||
/**
|
||||
* @prop --ion-chip-focus-ring-color: Color of the focus ring
|
||||
* @prop --ion-chip-focus-ring-width: Width of the focus ring
|
||||
* @prop --ion-chip-padding-horizontal: Padding top and bottom of the chip
|
||||
* @prop --ion-chip-padding-vertical: Padding start and end of the chip
|
||||
* @prop --ion-chip-font-weight: Font weight of the chip
|
||||
* @prop --ion-chip-line-height: Line height of the chip
|
||||
* @prop --ion-chip-gap: Gap between the chip and the text
|
||||
* @prop --ion-chip-border-width: Border width of the chip
|
||||
*
|
||||
* @prop --ion-chip-shape-soft-border-radius: Border radius of the chip for the soft shape
|
||||
* @prop --ion-chip-shape-round-border-radius: Border radius of the chip for the round shape
|
||||
* @prop --ion-chip-shape-rectangular-border-radius: Border radius of the chip for the rectangular shape
|
||||
*
|
||||
* @prop --ion-chip-size-small-min-height: Minimum height of the chip for the small size
|
||||
* @prop --ion-chip-size-large-min-height: Minimum height of the chip for the large size
|
||||
* @prop --ion-chip-size-small-font-size: Font size of the chip for the small size
|
||||
* @prop --ion-chip-size-large-font-size: Font size of the chip for the large size
|
||||
*
|
||||
* @prop --ion-chip-hue-subtle-bg: Background of the chip for the subtle hue
|
||||
* @prop --ion-chip-hue-subtle-color: Color of the chip for the subtle hue
|
||||
* @prop --ion-chip-hue-subtle-border-color: Border color of the chip for the subtle hue
|
||||
* @prop --ion-chip-hue-bold-bg: Background of the chip for the bold hue
|
||||
* @prop --ion-chip-hue-bold-color: Color of the chip for the bold hue
|
||||
* @prop --ion-chip-hue-bold-border-color: Border color of the chip for the bold hue
|
||||
*/
|
||||
--ion-chip-focus-ring-color: var(--ion-color-blue-50);
|
||||
--ion-chip-focus-ring-width: var(--ion-spacing-xs);
|
||||
--ion-chip-padding-horizontal: var(--ion-spacing-xs);
|
||||
--ion-chip-padding-vertical: var(--ion-spacing-sm);
|
||||
--ion-chip-font-weight: var(--ion-font-weights-normal);
|
||||
--ion-chip-line-height: var(--ion-line-heights-md);
|
||||
--ion-chip-gap: var(--ion-spacing-xs);
|
||||
--ion-chip-border-width: var(--ion-spacing-xxs);
|
||||
|
||||
--ion-chip-shape-soft-border-radius: var(--ion-radii-lg);
|
||||
--ion-chip-shape-round-border-radius: var(--ion-radii-xxl);
|
||||
--ion-chip-shape-rectangular-border-radius: var(--ion-radii-none);
|
||||
|
||||
--ion-chip-size-small-min-height: var(--ion-scaling-600);
|
||||
--ion-chip-size-large-min-height: var(--ion-scaling-900);
|
||||
--ion-chip-size-small-font-size: var(--ion-font-sizes-sm-rem);
|
||||
--ion-chip-size-large-font-size: var(--ion-font-sizes-lg-rem);
|
||||
|
||||
--ion-chip-hue-subtle-bg: var(--ion-color-gray-100);
|
||||
--ion-chip-hue-subtle-color: var(--ion-color-gray-800);
|
||||
--ion-chip-hue-subtle-border-color: var(--ion-color-gray-300);
|
||||
--ion-chip-hue-bold-bg: var(--ion-color-gray-700);
|
||||
--ion-chip-hue-bold-color: var(--ion-color-white);
|
||||
--ion-chip-hue-bold-border-color: var(--ion-color-gray-800);
|
||||
|
||||
@include font-smoothing();
|
||||
@include padding(var(--ion-chip-padding-horizontal), var(--ion-chip-padding-vertical));
|
||||
@include border-radius(var(--ion-chip-border-radius));
|
||||
|
||||
display: inline-flex;
|
||||
|
||||
position: relative;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background: var(--ion-chip-background);
|
||||
color: var(--ion-chip-color);
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
font-weight: var(--ion-chip-font-weight);
|
||||
line-height: var(--ion-chip-line-height);
|
||||
|
||||
gap: var(--ion-chip-gap);
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
:host(.chip-disabled) {
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Outline Chip
|
||||
// ---------------------------------------------
|
||||
|
||||
:host(.chip-outline) {
|
||||
border-width: var(--ion-chip-border-width);
|
||||
border-style: solid; // Do we need to use a variable here? ionic uses tokens but all themes use solid so it's not really necessary
|
||||
}
|
||||
|
||||
// Chip Shapes
|
||||
// ---------------------------------------------
|
||||
|
||||
:host(.chip-soft) {
|
||||
--ion-chip-border-radius: var(--ion-chip-shape-soft-border-radius);
|
||||
}
|
||||
|
||||
:host(.chip-round) {
|
||||
--ion-chip-border-radius: var(--ion-chip-shape-round-border-radius);
|
||||
}
|
||||
|
||||
:host(.chip-rectangular) {
|
||||
--ion-chip-border-radius: var(--ion-chip-shape-rectangular-border-radius);
|
||||
}
|
||||
|
||||
// Size
|
||||
// ---------------------------------------------
|
||||
|
||||
:host(.chip-small) {
|
||||
min-height: var(--ion-chip-size-small-min-height);
|
||||
|
||||
font-size: var(--ion-chip-size-small-font-size);
|
||||
}
|
||||
|
||||
:host(.chip-large) {
|
||||
min-height: var(--ion-chip-size-large-min-height);
|
||||
|
||||
font-size: var(--ion-chip-size-large-font-size);
|
||||
}
|
||||
|
||||
// Subtle Chip
|
||||
// ---------------------------------------------
|
||||
|
||||
:host(.chip-subtle) {
|
||||
--ion-chip-background: var(--ion-chip-hue-subtle-bg);
|
||||
--ion-chip-color: var(--ion-chip-hue-subtle-color);
|
||||
}
|
||||
|
||||
:host(.chip-outline.chip-subtle) {
|
||||
border-color: var(--ion-chip-hue-subtle-border-color);
|
||||
}
|
||||
|
||||
// Bold Chip
|
||||
// ---------------------------------------------
|
||||
|
||||
:host(.chip-bold) {
|
||||
--ion-chip-background: var(--ion-chip-hue-bold-bg);
|
||||
--ion-chip-color: var(--ion-chip-hue-bold-color);
|
||||
}
|
||||
|
||||
:host(.chip-outline.chip-bold) {
|
||||
border-color: var(--ion-chip-hue-bold-border-color);
|
||||
}
|
||||
|
||||
// Chip Colors
|
||||
// ---------------------------------------------
|
||||
|
||||
// Subtle
|
||||
:host(.chip-subtle.ion-color) {
|
||||
background: current-color(
|
||||
base,
|
||||
$subtle: true
|
||||
); // these don't work because we need to update the function to use the new color system
|
||||
color: current-color(
|
||||
contrast,
|
||||
$subtle: true
|
||||
); // these don't work because we need to update the function to use the new color system
|
||||
}
|
||||
|
||||
:host(.chip-subtle.chip-outline.ion-color) {
|
||||
border-color: current-color(
|
||||
shade,
|
||||
$subtle: true
|
||||
); // these don't work because we need to update the function to use the new color system
|
||||
}
|
||||
|
||||
// Bold
|
||||
:host(.chip-bold.ion-color) {
|
||||
background: current-color(
|
||||
base
|
||||
); // these don't work because we need to update the function to use the new color system
|
||||
color: current-color(
|
||||
contrast
|
||||
); // these don't work because we need to update the function to use the new color system
|
||||
}
|
||||
|
||||
:host(.chip-bold.chip-outline.ion-color) {
|
||||
border-color: current-color(
|
||||
shade
|
||||
); // these don't work because we need to update the function to use the new color system
|
||||
}
|
||||
113
core/src/components/my-chip/my-chip.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { ComponentInterface } from '@stencil/core';
|
||||
import { Component, Host, Prop, h, Element } from '@stencil/core';
|
||||
import { createColorClasses } from '@utils/theme';
|
||||
|
||||
import { getIonMode, getIonCustomTheme } from '../../global/ionic-global';
|
||||
import type { Color } from '../../interface';
|
||||
import { generateCSSVars } from '../../themes/base/generate-css-vars';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
|
||||
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-my-chip',
|
||||
styleUrl: 'my-chip.base.scss',
|
||||
shadow: true,
|
||||
})
|
||||
export class MyChip implements ComponentInterface {
|
||||
private isThemed = false;
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
/**
|
||||
* The color to use from your application's color palette.
|
||||
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
|
||||
* For more information on colors, see [theming](/docs/theming/basics).
|
||||
*/
|
||||
@Prop({ reflect: true }) color?: Color;
|
||||
|
||||
/**
|
||||
* Display an outline style button.
|
||||
*/
|
||||
@Prop() outline = false;
|
||||
|
||||
/**
|
||||
* If `true`, the user cannot interact with the chip.
|
||||
*/
|
||||
@Prop() disabled = false;
|
||||
|
||||
/**
|
||||
* Set to `"bold"` for a chip with vibrant, bold colors or to `"subtle"` for
|
||||
* a chip with muted, subtle colors.
|
||||
*
|
||||
* Only applies to the `ionic` theme.
|
||||
*/
|
||||
// THOUGHT: Comparing to ChakraUI, they use variants (aka fills) for this
|
||||
// maybe we should consider using variants: solid, outline, subtle
|
||||
// they use solid for bold solid background, no outline, has states
|
||||
// subtle for light background, no outline, has states
|
||||
// outline for outline style, no background, has states
|
||||
// surface for light background, with outline, has states
|
||||
// ghost for no background, no outline, has states
|
||||
// plain for no background, no outline, no states
|
||||
@Prop() hue?: 'bold' | 'subtle' = 'subtle';
|
||||
|
||||
/**
|
||||
* Set to `"soft"` for a chip with slightly rounded corners, `"round"` for a chip with fully
|
||||
* rounded corners, or `"rectangular"` for a chip without rounded corners.
|
||||
* Defaults to `"round"` for the `"ionic"` theme and `"soft"` for all other themes.
|
||||
*/
|
||||
@Prop() shape?: 'soft' | 'round' | 'rectangular' = 'soft';
|
||||
|
||||
/**
|
||||
* Set to `"small"` for a chip with less height and padding.
|
||||
*
|
||||
* Defaults to `"large"` for the ionic theme, and undefined for all other themes.
|
||||
*/
|
||||
@Prop() size?: 'small' | 'large' = 'small';
|
||||
|
||||
componentWillLoad() {
|
||||
const myCustomTheme = getIonCustomTheme();
|
||||
const componentTheme = myCustomTheme.components['IonChip'];
|
||||
|
||||
// check if componentTheme is not an empty object or undefined
|
||||
if (componentTheme !== undefined || Object.keys(componentTheme).length > 0) {
|
||||
this.isThemed = true;
|
||||
|
||||
// apply a style tag to this component
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = [generateCSSVars(componentTheme, '--ion-chip-', ':host(.chip-themed)')].join('\n\n');
|
||||
|
||||
// Attach to Shadow Root if available, otherwise Light DOM
|
||||
const root = this.el.shadowRoot ?? this.el;
|
||||
root.appendChild(style);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { hue, shape, size } = this;
|
||||
const mode = getIonMode(this);
|
||||
|
||||
return (
|
||||
<Host
|
||||
aria-disabled={this.disabled ? 'true' : null}
|
||||
class={createColorClasses(this.color, {
|
||||
// Needed to properly add the custom styles else
|
||||
// the styles would be ignored due to styling order
|
||||
'chip-themed': this.isThemed,
|
||||
[`chip-${shape}`]: shape !== undefined,
|
||||
'chip-outline': this.outline,
|
||||
'chip-disabled': this.disabled,
|
||||
'ion-activatable': true,
|
||||
'ion-focusable': !this.disabled,
|
||||
[`chip-${size}`]: size !== undefined,
|
||||
[`chip-${hue}`]: hue !== undefined,
|
||||
})}
|
||||
>
|
||||
<slot></slot>
|
||||
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
}
|
||||
95
core/src/components/my-chip/test/basic/index.html
Normal file
@@ -0,0 +1,95 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>MyChip - Basic</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>MyChip - Basic</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding" id="content" style="text-align: center">
|
||||
<h2>My Chip</h2>
|
||||
<p>
|
||||
This is a POC, not all the features are working as expected. For example, the color property still needs to be
|
||||
worked on.
|
||||
</p>
|
||||
<p>You can verify that the variables are being generated correctly by inspecting the root element.</p>
|
||||
|
||||
<ion-my-chip>default</ion-my-chip>
|
||||
|
||||
<ion-my-chip outline>outline</ion-my-chip>
|
||||
|
||||
<ion-my-chip size="large">large</ion-my-chip>
|
||||
|
||||
<ion-my-chip hue="bold">bold</ion-my-chip>
|
||||
<ion-my-chip hue="bold" outline>bold with outline</ion-my-chip>
|
||||
|
||||
<ion-my-chip color="primary">primary, subtle hue</ion-my-chip>
|
||||
<ion-my-chip color="primary" hue="bold">primary, bold hue</ion-my-chip>
|
||||
|
||||
<ion-my-chip color="secondary">secondary, subtle hue</ion-my-chip>
|
||||
<ion-my-chip color="secondary" hue="bold">secondary, bold hue</ion-my-chip>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
window.Ionic = {
|
||||
config: {
|
||||
customTheme: {
|
||||
palette: {
|
||||
light: {
|
||||
color: {
|
||||
primary: {
|
||||
bold: {
|
||||
base: 'pink',
|
||||
constrast: 'black',
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
bold: {
|
||||
base: '#510aa8',
|
||||
},
|
||||
},
|
||||
// gray: {
|
||||
// 800: 'pink',
|
||||
// }
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
IonChip: {
|
||||
hue: {
|
||||
subtle: {
|
||||
bg: 'red',
|
||||
color: 'white',
|
||||
borderColor: 'black'
|
||||
},
|
||||
bold: {
|
||||
bg: 'blue',
|
||||
color: 'white',
|
||||
borderColor: 'black'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -7,6 +7,9 @@ import type { RouterDirection } from '../router/utils/interface';
|
||||
|
||||
import { navLink } from './nav-link-utils';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-nav-link',
|
||||
})
|
||||
|
||||
@@ -107,6 +107,7 @@ const renderProgress = (value: number, buffer: number) => {
|
||||
* When finalBuffer === 1, we use display: none
|
||||
* instead of removing the element to avoid flickering.
|
||||
*/
|
||||
// TODO(FW-6697): change `ion-hide` class to `ion-display-none` or another class
|
||||
<div
|
||||
class={{ 'buffer-circles-container': true, 'ion-hide': finalBuffer === 1 }}
|
||||
style={{ transform: `translateX(${finalBuffer * 100}%)` }}
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
// TODO(FW-6590): Remove this once the deprecated event is removed
|
||||
export interface ItemReorderEventDetail {
|
||||
from: number;
|
||||
to: number;
|
||||
complete: (data?: boolean | any[]) => any;
|
||||
}
|
||||
|
||||
// TODO(FW-6590): Remove this once the deprecated event is removed
|
||||
export interface ItemReorderCustomEvent extends CustomEvent {
|
||||
detail: ItemReorderEventDetail;
|
||||
target: HTMLIonReorderGroupElement;
|
||||
}
|
||||
|
||||
export interface ReorderMoveEventDetail {
|
||||
from: number;
|
||||
to: number;
|
||||
}
|
||||
|
||||
export interface ReorderEndEventDetail {
|
||||
from: number;
|
||||
to: number;
|
||||
complete: (data?: boolean | any[]) => any;
|
||||
}
|
||||
|
||||
export interface ReorderMoveCustomEvent extends CustomEvent {
|
||||
detail: ReorderMoveEventDetail;
|
||||
target: HTMLIonReorderGroupElement;
|
||||
}
|
||||
|
||||
export interface ReorderEndCustomEvent extends CustomEvent {
|
||||
detail: ReorderEndEventDetail;
|
||||
target: HTMLIonReorderGroupElement;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@ import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart } from
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import type { Gesture, GestureDetail } from '../../interface';
|
||||
import type { HTMLStencilElement } from '../../utils/element-interface';
|
||||
|
||||
import type { ItemReorderEventDetail } from './reorder-group-interface';
|
||||
import type { ItemReorderEventDetail, ReorderMoveEventDetail, ReorderEndEventDetail } from './reorder-group-interface';
|
||||
|
||||
// TODO(FW-2832): types
|
||||
|
||||
@@ -38,7 +39,7 @@ export class ReorderGroup implements ComponentInterface {
|
||||
|
||||
@State() state = ReorderGroupState.Idle;
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
@Element() el!: HTMLStencilElement;
|
||||
|
||||
/**
|
||||
* If `true`, the reorder will be hidden.
|
||||
@@ -51,12 +52,35 @@ export class ReorderGroup implements ComponentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(FW-6590): Remove this in a major release.
|
||||
/**
|
||||
* Event that needs to be listened to in order to complete the reorder action.
|
||||
* @deprecated Use `ionReorderEnd` instead. If you are accessing
|
||||
* `event.detail.from` or `event.detail.to` and relying on them
|
||||
* being different you should now add checks as they are always emitted
|
||||
* in `ionReorderEnd`, even when they are the same.
|
||||
*/
|
||||
@Event() ionItemReorder!: EventEmitter<ItemReorderEventDetail>;
|
||||
|
||||
/**
|
||||
* Event that is emitted when the reorder gesture starts.
|
||||
*/
|
||||
@Event() ionReorderStart!: EventEmitter<void>;
|
||||
|
||||
/**
|
||||
* Event that is emitted as the reorder gesture moves.
|
||||
*/
|
||||
@Event() ionReorderMove!: EventEmitter<ReorderMoveEventDetail>;
|
||||
|
||||
/**
|
||||
* Event that is emitted when the reorder gesture ends.
|
||||
* The from and to properties are always available, regardless of
|
||||
* if the reorder gesture moved the item. If the item did not change
|
||||
* from its start position, the from and to properties will be the same.
|
||||
* Once the event has been emitted, the `complete()` method then needs
|
||||
* to be called in order to finalize the reorder action.
|
||||
*/
|
||||
@Event() ionItemReorder!: EventEmitter<ItemReorderEventDetail>;
|
||||
@Event() ionReorderEnd!: EventEmitter<ReorderEndEventDetail>;
|
||||
|
||||
async connectedCallback() {
|
||||
const contentEl = findClosestIonContent(this.el);
|
||||
@@ -88,7 +112,8 @@ export class ReorderGroup implements ComponentInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the reorder operation. Must be called by the `ionItemReorder` event.
|
||||
* Completes the reorder operation. Must be called by the `ionReorderEnd` event.
|
||||
*
|
||||
* If a list of items is passed, the list will be reordered and returned in the
|
||||
* proper order.
|
||||
*
|
||||
@@ -128,7 +153,7 @@ export class ReorderGroup implements ComponentInterface {
|
||||
const heights = this.cachedHeights;
|
||||
heights.length = 0;
|
||||
const el = this.el;
|
||||
const children: any = el.children;
|
||||
const children: any = el.__children || el.children;
|
||||
if (!children || children.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -163,6 +188,8 @@ export class ReorderGroup implements ComponentInterface {
|
||||
item.classList.add(ITEM_REORDER_SELECTED);
|
||||
|
||||
hapticSelectionStart();
|
||||
|
||||
this.ionReorderStart.emit();
|
||||
}
|
||||
|
||||
private onMove(ev: GestureDetail) {
|
||||
@@ -179,6 +206,7 @@ export class ReorderGroup implements ComponentInterface {
|
||||
const currentY = Math.max(top, Math.min(ev.currentY, bottom));
|
||||
const deltaY = scroll + currentY - ev.startY;
|
||||
const normalizedY = currentY - top;
|
||||
const fromIndex = this.lastToIndex;
|
||||
const toIndex = this.itemIndexForTop(normalizedY);
|
||||
if (toIndex !== this.lastToIndex) {
|
||||
const fromIndex = indexForItem(selectedItem);
|
||||
@@ -190,6 +218,11 @@ export class ReorderGroup implements ComponentInterface {
|
||||
|
||||
// Update selected item position
|
||||
selectedItem.style.transform = `translateY(${deltaY}px)`;
|
||||
|
||||
this.ionReorderMove.emit({
|
||||
from: fromIndex,
|
||||
to: toIndex,
|
||||
});
|
||||
}
|
||||
|
||||
private onEnd() {
|
||||
@@ -206,6 +239,7 @@ export class ReorderGroup implements ComponentInterface {
|
||||
if (toIndex === fromIndex) {
|
||||
this.completeReorder();
|
||||
} else {
|
||||
// TODO(FW-6590): Remove this once the deprecated event is removed
|
||||
this.ionItemReorder.emit({
|
||||
from: fromIndex,
|
||||
to: toIndex,
|
||||
@@ -214,12 +248,18 @@ export class ReorderGroup implements ComponentInterface {
|
||||
}
|
||||
|
||||
hapticSelectionEnd();
|
||||
|
||||
this.ionReorderEnd.emit({
|
||||
from: fromIndex,
|
||||
to: toIndex,
|
||||
complete: this.completeReorder.bind(this),
|
||||
});
|
||||
}
|
||||
|
||||
private completeReorder(listOrReorder?: boolean | any[]): any {
|
||||
const selectedItemEl = this.selectedItemEl;
|
||||
if (selectedItemEl && this.state === ReorderGroupState.Complete) {
|
||||
const children = this.el.children as any;
|
||||
const children: any = this.el.__children || this.el.children;
|
||||
const len = children.length;
|
||||
const toIndex = this.lastToIndex;
|
||||
const fromIndex = indexForItem(selectedItemEl);
|
||||
@@ -269,7 +309,7 @@ export class ReorderGroup implements ComponentInterface {
|
||||
/********* DOM WRITE ********* */
|
||||
private reorderMove(fromIndex: number, toIndex: number) {
|
||||
const itemHeight = this.selectedItemHeight;
|
||||
const children = this.el.children;
|
||||
const children: any = this.el.__children || this.el.children;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const style = (children[i] as any).style;
|
||||
let value = '';
|
||||
|
||||
@@ -122,8 +122,25 @@
|
||||
const reorderGroup = document.getElementById('reorder');
|
||||
reorderGroup.disabled = !reorderGroup.disabled;
|
||||
|
||||
// TODO(FW-6590): Remove this once the deprecated event is removed
|
||||
reorderGroup.addEventListener('ionItemReorder', ({ detail }) => {
|
||||
console.log('Dragged from index', detail.from, 'to', detail.to);
|
||||
console.log('ionItemReorder: Dragged from index', detail.from, 'to', detail.to);
|
||||
});
|
||||
|
||||
reorderGroup.addEventListener('ionReorderStart', () => {
|
||||
console.log('ionReorderStart');
|
||||
});
|
||||
|
||||
reorderGroup.addEventListener('ionReorderMove', ({ detail }) => {
|
||||
console.log('ionReorderMove: Dragged from index', detail.from, 'to', detail.to);
|
||||
});
|
||||
|
||||
reorderGroup.addEventListener('ionReorderEnd', ({ detail }) => {
|
||||
if (detail.from !== detail.to) {
|
||||
console.log('ionReorderEnd: Dragged from index', detail.from, 'to', detail.to);
|
||||
} else {
|
||||
console.log('ionReorderEnd: No position change occurred');
|
||||
}
|
||||
|
||||
detail.complete();
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body onLoad="render()">
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
<ion-content id="content">
|
||||
<ion-list>
|
||||
<ion-reorder-group id="reorderGroup" disabled="false">
|
||||
<ion-reorder-group disabled="false">
|
||||
<!-- items will be inserted here -->
|
||||
</ion-reorder-group>
|
||||
</ion-list>
|
||||
@@ -36,27 +36,44 @@
|
||||
for (var i = 0; i < 30; i++) {
|
||||
items.push(i + 1);
|
||||
}
|
||||
const reorderGroup = document.getElementById('reorderGroup');
|
||||
|
||||
function render() {
|
||||
let html = '';
|
||||
for (let item of items) {
|
||||
html += `
|
||||
<ion-item>
|
||||
<ion-label>${item}</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>`;
|
||||
}
|
||||
reorderGroup.innerHTML = html;
|
||||
}
|
||||
|
||||
reorderGroup.addEventListener('ionItemReorder', ({ detail }) => {
|
||||
console.log('Dragged from index', detail.from, 'to', detail.to);
|
||||
const reorderGroup = document.querySelector('ion-reorder-group');
|
||||
reorderItems(items);
|
||||
|
||||
reorderGroup.addEventListener('ionReorderEnd', ({ detail }) => {
|
||||
// Before complete is called with the items they will remain in the
|
||||
// order before the drag
|
||||
console.log('Before complete', items);
|
||||
|
||||
// Finish the reorder and position the item in the DOM based on
|
||||
// where the gesture ended. Update the items variable to the
|
||||
// new order of items
|
||||
items = detail.complete(items);
|
||||
|
||||
// Reorder the items in the DOM
|
||||
reorderItems(items);
|
||||
|
||||
// After complete is called the items will be in the new order
|
||||
console.log('After complete', items);
|
||||
});
|
||||
|
||||
function reorderItems(items) {
|
||||
reorderGroup.replaceChildren();
|
||||
|
||||
let reordered = '';
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
reordered += `
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
Item ${items[i]}
|
||||
</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
`;
|
||||
}
|
||||
|
||||
reorderGroup.innerHTML = reordered;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
</ion-reorder-group>
|
||||
<script>
|
||||
const group = document.querySelector('ion-reorder-group');
|
||||
group.addEventListener('ionItemReorder', (ev) => {
|
||||
group.addEventListener('ionReorderEnd', (ev) => {
|
||||
ev.detail.complete();
|
||||
window.dispatchEvent(new CustomEvent('ionItemReorderComplete'));
|
||||
window.dispatchEvent(new CustomEvent('ionReorderComplete'));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -11,24 +11,24 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
});
|
||||
test('should drag and drop when ion-reorder wraps ion-item', async ({ page }) => {
|
||||
const items = page.locator('ion-item');
|
||||
const ionItemReorderComplete = await page.spyOnEvent('ionItemReorderComplete');
|
||||
const ionReorderComplete = await page.spyOnEvent('ionReorderComplete');
|
||||
|
||||
await expect(items).toContainText(['Item 1', 'Item 2', 'Item 3', 'Item 4']);
|
||||
|
||||
await dragElementBy(items.nth(1), page, 0, 300);
|
||||
await ionItemReorderComplete.next();
|
||||
await ionReorderComplete.next();
|
||||
|
||||
await expect(items).toContainText(['Item 1', 'Item 3', 'Item 4', 'Item 2']);
|
||||
});
|
||||
test('should drag and drop when ion-item wraps ion-reorder', async ({ page }) => {
|
||||
const reorderHandle = page.locator('ion-reorder');
|
||||
const items = page.locator('ion-item');
|
||||
const ionItemReorderComplete = await page.spyOnEvent('ionItemReorderComplete');
|
||||
const ionReorderComplete = await page.spyOnEvent('ionReorderComplete');
|
||||
|
||||
await expect(items).toContainText(['Item 1', 'Item 2', 'Item 3', 'Item 4']);
|
||||
|
||||
await dragElementBy(reorderHandle.nth(0), page, 0, 300);
|
||||
await ionItemReorderComplete.next();
|
||||
await ionReorderComplete.next();
|
||||
|
||||
await expect(items).toContainText(['Item 2', 'Item 3', 'Item 4', 'Item 1']);
|
||||
});
|
||||
|
||||
@@ -68,9 +68,9 @@
|
||||
customElements.define('app-reorder', AppReorder);
|
||||
|
||||
const group = document.querySelector('ion-reorder-group');
|
||||
group.addEventListener('ionItemReorder', (ev) => {
|
||||
group.addEventListener('ionReorderEnd', (ev) => {
|
||||
ev.detail.complete();
|
||||
window.dispatchEvent(new CustomEvent('ionItemReorderComplete'));
|
||||
window.dispatchEvent(new CustomEvent('ionReorderComplete'));
|
||||
});
|
||||
</script>
|
||||
</ion-app>
|
||||
|
||||
@@ -11,24 +11,24 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
});
|
||||
test('should drag and drop when ion-reorder wraps ion-item', async ({ page }) => {
|
||||
const items = page.locator('app-reorder');
|
||||
const ionItemReorderComplete = await page.spyOnEvent('ionItemReorderComplete');
|
||||
const ionReorderComplete = await page.spyOnEvent('ionReorderComplete');
|
||||
|
||||
await expect(items).toContainText(['Item 1', 'Item 2', 'Item 3', 'Item 4']);
|
||||
|
||||
await dragElementBy(items.nth(1), page, 0, 300);
|
||||
await ionItemReorderComplete.next();
|
||||
await ionReorderComplete.next();
|
||||
|
||||
await expect(items).toContainText(['Item 1', 'Item 3', 'Item 4', 'Item 2']);
|
||||
});
|
||||
test('should drag and drop when ion-item wraps ion-reorder', async ({ page }) => {
|
||||
const reorderHandle = page.locator('app-reorder ion-reorder');
|
||||
const items = page.locator('app-reorder');
|
||||
const ionItemReorderComplete = await page.spyOnEvent('ionItemReorderComplete');
|
||||
const ionReorderComplete = await page.spyOnEvent('ionReorderComplete');
|
||||
|
||||
await expect(items).toContainText(['Item 1', 'Item 2', 'Item 3', 'Item 4']);
|
||||
|
||||
await dragElementBy(reorderHandle.nth(0), page, 0, 300);
|
||||
await ionItemReorderComplete.next();
|
||||
await ionReorderComplete.next();
|
||||
|
||||
await expect(items).toContainText(['Item 2', 'Item 3', 'Item 4', 'Item 1']);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, dragElementBy, test } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* This behavior does not vary across modes/directions.
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('reorder-group: events:'), () => {
|
||||
test.describe('ionReorderStart', () => {
|
||||
test('should emit when the reorder operation starts', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-reorder-group disabled="false">
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
</ion-reorder-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const reorderGroup = page.locator('ion-reorder-group');
|
||||
const ionReorderStart = await page.spyOnEvent('ionReorderStart');
|
||||
|
||||
await expect(ionReorderStart).toHaveReceivedEventTimes(0);
|
||||
|
||||
// Start the drag to verify it emits the event without having to
|
||||
// actually move the item. Do not release the drag here.
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 0, undefined, undefined, false);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionReorderStart).toHaveReceivedEventTimes(1);
|
||||
|
||||
// Drag the reorder item further to verify it does
|
||||
// not emit the event again
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 300);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionReorderStart).toHaveReceivedEventTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('ionReorderMove', () => {
|
||||
test('should emit when the reorder operation does not move the item position', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-reorder-group disabled="false">
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
</ion-reorder-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const reorderGroup = page.locator('ion-reorder-group');
|
||||
const ionReorderMove = await page.spyOnEvent('ionReorderMove');
|
||||
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 0);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
expect(ionReorderMove.events.length).toBeGreaterThan(0);
|
||||
|
||||
// Grab the last event to verify that it is emitting
|
||||
// the correct from and to positions
|
||||
const lastEvent = ionReorderMove.events[ionReorderMove.events.length - 1];
|
||||
expect(lastEvent?.detail.from).toBe(0);
|
||||
expect(lastEvent?.detail.to).toBe(0);
|
||||
});
|
||||
|
||||
test('should emit when the reorder operation moves the item by multiple positions', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-reorder-group disabled="false">
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
</ion-reorder-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const reorderGroup = page.locator('ion-reorder-group');
|
||||
const ionReorderMove = await page.spyOnEvent('ionReorderMove');
|
||||
|
||||
// Drag the reorder item by a lot to verify it emits the event
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 300);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
expect(ionReorderMove.events.length).toBeGreaterThan(0);
|
||||
|
||||
// Grab the last event where the from and to are different to
|
||||
// verify that it is not using the gesture start position as the from
|
||||
const lastDifferentEvent = ionReorderMove.events
|
||||
.reverse()
|
||||
.find((event) => event.detail.from !== event.detail.to);
|
||||
expect(lastDifferentEvent?.detail.from).toBe(1);
|
||||
expect(lastDifferentEvent?.detail.to).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('ionReorderEnd', () => {
|
||||
test('should emit without details when the reorder operation ends without moving the item position', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-reorder-group disabled="false">
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
</ion-reorder-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const reorderGroup = page.locator('ion-reorder-group');
|
||||
const ionReorderEnd = await page.spyOnEvent('ionReorderEnd');
|
||||
|
||||
// Drag the reorder item a little bit but not enough to
|
||||
// make it switch to a different position
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 20);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionReorderEnd).toHaveReceivedEventTimes(1);
|
||||
await expect(ionReorderEnd).toHaveReceivedEventDetail({ from: 0, to: 0, complete: undefined });
|
||||
});
|
||||
|
||||
test('should emit with details when the reorder operation ends and the item has moved', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-reorder-group disabled="false">
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
</ion-reorder-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const reorderGroup = page.locator('ion-reorder-group');
|
||||
const ionReorderEnd = await page.spyOnEvent('ionReorderEnd');
|
||||
|
||||
// Start the drag to verify it does not emit the event at the start
|
||||
// of the drag or during the drag. Do not release the drag here.
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 100, undefined, undefined, false);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionReorderEnd).toHaveReceivedEventTimes(0);
|
||||
|
||||
// Drag the reorder item further and release the drag to verify it emits the event
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 300);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionReorderEnd).toHaveReceivedEventTimes(1);
|
||||
await expect(ionReorderEnd).toHaveReceivedEventDetail({ from: 0, to: 2, complete: undefined });
|
||||
});
|
||||
});
|
||||
|
||||
// TODO(FW-6590): Remove this once the deprecated event is removed
|
||||
test.describe('ionItemReorder', () => {
|
||||
test('should not emit when the reorder operation ends without moving the item position', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-reorder-group disabled="false">
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
</ion-reorder-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const reorderGroup = page.locator('ion-reorder-group');
|
||||
const ionItemReorder = await page.spyOnEvent('ionItemReorder');
|
||||
|
||||
// Drag the reorder item a little bit but not enough to
|
||||
// make it switch to a different position
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 20);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionItemReorder).toHaveReceivedEventTimes(0);
|
||||
});
|
||||
|
||||
test('should emit when the reorder operation ends and the item has moved', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-reorder-group disabled="false">
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-reorder slot="end"></ion-reorder>
|
||||
</ion-item>
|
||||
</ion-reorder-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const reorderGroup = page.locator('ion-reorder-group');
|
||||
const ionItemReorder = await page.spyOnEvent('ionItemReorder');
|
||||
|
||||
// Start the drag to verify it does not emit the event at the start
|
||||
// of the drag or during the drag. Do not release the drag here.
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 100, undefined, undefined, false);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionItemReorder).toHaveReceivedEventTimes(0);
|
||||
|
||||
// Drag the reorder item further and release the drag to verify it emits the event
|
||||
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 300);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionItemReorder).toHaveReceivedEventTimes(1);
|
||||
await expect(ionItemReorder).toHaveReceivedEventDetail({ from: 0, to: 2, complete: undefined });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -57,9 +57,9 @@
|
||||
|
||||
<script>
|
||||
const group = document.querySelector('ion-reorder-group');
|
||||
group.addEventListener('ionItemReorder', (ev) => {
|
||||
group.addEventListener('ionReorderEnd', (ev) => {
|
||||
ev.detail.complete();
|
||||
window.dispatchEvent(new CustomEvent('ionItemReorderComplete'));
|
||||
window.dispatchEvent(new CustomEvent('ionReorderComplete'));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -11,24 +11,24 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
});
|
||||
test('should drag and drop when ion-reorder wraps ion-item', async ({ page }) => {
|
||||
const items = page.locator('ion-item');
|
||||
const ionItemReorderComplete = await page.spyOnEvent('ionItemReorderComplete');
|
||||
const ionReorderComplete = await page.spyOnEvent('ionReorderComplete');
|
||||
|
||||
await expect(items).toContainText(['Item 1', 'Item 2', 'Item 3', 'Item 4']);
|
||||
|
||||
await dragElementBy(items.nth(1), page, 0, 300);
|
||||
await ionItemReorderComplete.next();
|
||||
await ionReorderComplete.next();
|
||||
|
||||
await expect(items).toContainText(['Item 1', 'Item 3', 'Item 4', 'Item 2']);
|
||||
});
|
||||
test('should drag and drop when ion-item wraps ion-reorder', async ({ page }) => {
|
||||
const reorderHandle = page.locator('ion-reorder');
|
||||
const items = page.locator('ion-item');
|
||||
const ionItemReorderComplete = await page.spyOnEvent('ionItemReorderComplete');
|
||||
const ionReorderComplete = await page.spyOnEvent('ionReorderComplete');
|
||||
|
||||
await expect(items).toContainText(['Item 1', 'Item 2', 'Item 3', 'Item 4']);
|
||||
|
||||
await dragElementBy(reorderHandle.nth(0), page, 0, 300);
|
||||
await ionItemReorderComplete.next();
|
||||
await ionReorderComplete.next();
|
||||
|
||||
await expect(items).toContainText(['Item 2', 'Item 3', 'Item 4', 'Item 1']);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import type { AnimationBuilder, ComponentProps } from '../../../interface';
|
||||
import type { AnimationBuilder, ComponentProps, HTMLStencilElement } from '../../../interface';
|
||||
import type { NavigationHookCallback } from '../../route/route-interface';
|
||||
|
||||
export interface HTMLStencilElement extends HTMLElement {
|
||||
componentOnReady(): Promise<this>;
|
||||
}
|
||||
|
||||
export interface NavOutlet {
|
||||
setRouteId(
|
||||
id: string,
|
||||
|
||||
@@ -68,7 +68,27 @@ export class Tabs implements NavOutlet {
|
||||
componentWillRender() {
|
||||
const tabBar = this.el.querySelector('ion-tab-bar');
|
||||
if (tabBar) {
|
||||
const tab = this.selectedTab ? this.selectedTab.tab : undefined;
|
||||
let tab = this.selectedTab ? this.selectedTab.tab : undefined;
|
||||
|
||||
// Fallback: if no selectedTab is set but we're using router mode,
|
||||
// determine the active tab from the current URL. This works around
|
||||
// timing issues in React Router integration where setRouteId may not
|
||||
// be called in time for the initial render.
|
||||
// TODO(FW-6724): Remove this with React Router upgrade
|
||||
if (!tab && this.useRouter && typeof window !== 'undefined') {
|
||||
const currentPath = window.location.pathname;
|
||||
const tabButtons = this.el.querySelectorAll('ion-tab-button');
|
||||
|
||||
// Look for a tab button that matches the current path pattern
|
||||
for (const tabButton of tabButtons) {
|
||||
const tabId = tabButton.getAttribute('tab');
|
||||
if (tabId && currentPath.includes(tabId)) {
|
||||
tab = tabId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tabBar.selectedTab = tab;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
@import "../themes/ionic.mixins";
|
||||
|
||||
// Display
|
||||
// --------------------------------------------------
|
||||
// Modifies display of a particular element based on the given classes
|
||||
// ------------------------------------------------------------------
|
||||
// Provides utility classes to control the CSS display property
|
||||
// of elements. Includes responsive variants for toggling between
|
||||
// block, inline, flex, grid, and other display values at different
|
||||
// breakpoints.
|
||||
|
||||
// TODO(FW-6697): remove ion-hide-* classes in favor of the new
|
||||
// ion-display-* classes
|
||||
.ion-hide {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -29,3 +34,29 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$display-values: (
|
||||
none,
|
||||
inline,
|
||||
inline-block,
|
||||
block,
|
||||
flex,
|
||||
inline-flex,
|
||||
grid,
|
||||
inline-grid,
|
||||
table,
|
||||
table-cell,
|
||||
table-row
|
||||
);
|
||||
|
||||
@each $display in $display-values {
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
.ion-display#{$infix}-#{$display} {
|
||||
display: #{$display} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,99 +1,211 @@
|
||||
@import "../themes/ionic.globals";
|
||||
@import "../themes/ionic.mixins";
|
||||
|
||||
// Flex Utilities
|
||||
// --------------------------------------------------
|
||||
// Creates flex classes to align flex containers
|
||||
// and items
|
||||
// ------------------------------------------------------------------
|
||||
// Provides utility classes to control flexbox layout, alignment,
|
||||
// and sizing of elements. Includes responsive variants for managing
|
||||
// flex direction, alignment, justification, wrapping, growth,
|
||||
// shrinking, and ordering at different breakpoints.
|
||||
|
||||
// Align Self
|
||||
// --------------------------------------------------
|
||||
// Align Content
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
.ion-align-self-start {
|
||||
align-self: flex-start !important;
|
||||
$align-content-values: (
|
||||
start: flex-start,
|
||||
end: flex-end,
|
||||
center: center,
|
||||
between: space-between,
|
||||
around: space-around,
|
||||
stretch: stretch
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $key, $value in $align-content-values {
|
||||
.ion-align-content#{$infix}-#{$key} {
|
||||
align-content: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-self-end {
|
||||
align-self: flex-end !important;
|
||||
}
|
||||
|
||||
.ion-align-self-center {
|
||||
align-self: center !important;
|
||||
}
|
||||
|
||||
.ion-align-self-stretch {
|
||||
align-self: stretch !important;
|
||||
}
|
||||
|
||||
.ion-align-self-baseline {
|
||||
align-self: baseline !important;
|
||||
}
|
||||
|
||||
.ion-align-self-auto {
|
||||
align-self: auto !important;
|
||||
}
|
||||
|
||||
|
||||
// Flex Wrap
|
||||
// --------------------------------------------------
|
||||
|
||||
.ion-wrap {
|
||||
flex-wrap: wrap !important;
|
||||
}
|
||||
|
||||
.ion-nowrap {
|
||||
flex-wrap: nowrap !important;
|
||||
}
|
||||
|
||||
.ion-wrap-reverse {
|
||||
flex-wrap: wrap-reverse !important;
|
||||
}
|
||||
|
||||
|
||||
// Justify Content
|
||||
// --------------------------------------------------
|
||||
|
||||
.ion-justify-content-start {
|
||||
justify-content: flex-start !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-center {
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-end {
|
||||
justify-content: flex-end !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-around {
|
||||
justify-content: space-around !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-between {
|
||||
justify-content: space-between !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-evenly {
|
||||
justify-content: space-evenly !important;
|
||||
}
|
||||
|
||||
|
||||
// Align Items
|
||||
// --------------------------------------------------
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
.ion-align-items-start {
|
||||
align-items: flex-start !important;
|
||||
$align-items-values: (
|
||||
start,
|
||||
end,
|
||||
center,
|
||||
stretch,
|
||||
baseline
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $align-items-values {
|
||||
.ion-align-items#{$infix}-#{$value} {
|
||||
align-items: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-items-center {
|
||||
align-items: center !important;
|
||||
// Align Self
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$align-self-values: (
|
||||
start,
|
||||
end,
|
||||
center,
|
||||
stretch,
|
||||
baseline,
|
||||
auto
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $align-self-values {
|
||||
.ion-align-self#{$infix}-#{$value} {
|
||||
align-self: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-items-end {
|
||||
align-items: flex-end !important;
|
||||
// Justify Content
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$justify-content-values: (
|
||||
start: flex-start,
|
||||
end: flex-end,
|
||||
center: center,
|
||||
between: space-between,
|
||||
around: space-around,
|
||||
evenly: space-evenly
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $key, $value in $justify-content-values {
|
||||
.ion-justify-content#{$infix}-#{$key} {
|
||||
justify-content: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-items-stretch {
|
||||
align-items: stretch !important;
|
||||
// Flex Direction
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$flex-direction-values: (
|
||||
row,
|
||||
row-reverse,
|
||||
column,
|
||||
column-reverse
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $flex-direction-values {
|
||||
.ion-flex#{$infix}-#{$value} {
|
||||
flex-direction: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-items-baseline {
|
||||
align-items: baseline !important;
|
||||
// Flex Wrap
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$flex-wrap-values: (
|
||||
wrap,
|
||||
nowrap,
|
||||
wrap-reverse
|
||||
);
|
||||
|
||||
@each $value in $flex-wrap-values {
|
||||
// TODO(FW-6697): remove ion-wrap, ion-nowrap, ion-wrap-reverse
|
||||
// in favor of the new ion-flex-wrap, ion-flex-nowrap, and
|
||||
// ion-flex-wrap-reverse classes
|
||||
.ion-#{$value} {
|
||||
flex-wrap: #{$value} !important;
|
||||
}
|
||||
}
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $flex-wrap-values {
|
||||
.ion-flex#{$infix}-#{$value} {
|
||||
flex-wrap: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flex Fill
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$flex-fill-values: (
|
||||
1,
|
||||
auto,
|
||||
initial,
|
||||
none
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $flex-fill-values {
|
||||
.ion-flex#{$infix}-#{$value} {
|
||||
flex: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flex Grow and Shrink
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
.ion-flex#{$infix}-grow-0 {
|
||||
flex-grow: 0 !important;
|
||||
}
|
||||
|
||||
.ion-flex#{$infix}-grow-1 {
|
||||
flex-grow: 1 !important;
|
||||
}
|
||||
|
||||
.ion-flex#{$infix}-shrink-0 {
|
||||
flex-shrink: 0 !important;
|
||||
}
|
||||
|
||||
.ion-flex#{$infix}-shrink-1 {
|
||||
flex-shrink: 1 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flex Order
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
.ion-order#{$infix}-first { order: -1 !important; }
|
||||
|
||||
@for $i from 0 through 12 {
|
||||
.ion-order#{$infix}-#{$i} { order: #{$i} !important; }
|
||||
}
|
||||
|
||||
.ion-order#{$infix}-last { order: 13 !important; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,61 +11,70 @@ $light: #222428;
|
||||
$medium: #989aa2;
|
||||
$dark: #f4f5f8;
|
||||
|
||||
$colors: (
|
||||
$colors: (
|
||||
primary: (
|
||||
base: $primary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($primary),
|
||||
tint: get-color-tint($primary)
|
||||
base: $primary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($primary),
|
||||
tint: get-color-tint($primary),
|
||||
foreground: $primary,
|
||||
),
|
||||
secondary: (
|
||||
base: $secondary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($secondary),
|
||||
tint: get-color-tint($secondary)
|
||||
base: $secondary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($secondary),
|
||||
tint: get-color-tint($secondary),
|
||||
foreground: $secondary,
|
||||
),
|
||||
tertiary: (
|
||||
base: $tertiary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($tertiary),
|
||||
tint: get-color-tint($tertiary)
|
||||
base: $tertiary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($tertiary),
|
||||
tint: get-color-tint($tertiary),
|
||||
foreground: $tertiary,
|
||||
),
|
||||
success: (
|
||||
base: $success,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($success),
|
||||
tint: get-color-tint($success)
|
||||
base: $success,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($success),
|
||||
tint: get-color-tint($success),
|
||||
foreground: $success,
|
||||
),
|
||||
warning: (
|
||||
base: $warning,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($warning),
|
||||
tint: get-color-tint($warning)
|
||||
base: $warning,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($warning),
|
||||
tint: get-color-tint($warning),
|
||||
foreground: $warning,
|
||||
),
|
||||
danger: (
|
||||
base: $danger,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($danger),
|
||||
tint: get-color-tint($danger)
|
||||
base: $danger,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($danger),
|
||||
tint: get-color-tint($danger),
|
||||
foreground: $danger,
|
||||
),
|
||||
light: (
|
||||
base: $light,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($light),
|
||||
tint: get-color-tint($light)
|
||||
base: $light,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($light),
|
||||
tint: get-color-tint($light),
|
||||
foreground: $light,
|
||||
),
|
||||
medium: (
|
||||
base: $medium,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($medium),
|
||||
tint: get-color-tint($medium)
|
||||
base: $medium,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($medium),
|
||||
tint: get-color-tint($medium),
|
||||
foreground: $medium,
|
||||
),
|
||||
dark: (
|
||||
base: $dark,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($dark),
|
||||
tint: get-color-tint($dark)
|
||||
)
|
||||
base: $dark,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($dark),
|
||||
tint: get-color-tint($dark),
|
||||
foreground: $dark,
|
||||
),
|
||||
);
|
||||
|
||||
@mixin dark-base-palette() {
|
||||
|
||||
@@ -1,71 +1,80 @@
|
||||
@use "sass:map";
|
||||
@import "../../themes/ionic.functions.color";
|
||||
|
||||
$primary: #7cabff;
|
||||
$secondary: #62bdff;
|
||||
$tertiary: #b6b9f9;
|
||||
$success: #4ada71;
|
||||
$warning: #ffce31;
|
||||
$danger: #fc9aa2;
|
||||
$light: #222428;
|
||||
$medium: #a8aab3;
|
||||
$dark: #f4f5f8;
|
||||
$primary: #7cabff;
|
||||
$secondary: #62bdff;
|
||||
$tertiary: #b6b9f9;
|
||||
$success: #4ada71;
|
||||
$warning: #ffce31;
|
||||
$danger: #fc9aa2;
|
||||
$light: #222428;
|
||||
$medium: #a8aab3;
|
||||
$dark: #f4f5f8;
|
||||
|
||||
$colors: (
|
||||
$colors: (
|
||||
primary: (
|
||||
base: $primary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($primary),
|
||||
tint: get-color-tint($primary)
|
||||
base: $primary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($primary),
|
||||
tint: get-color-tint($primary),
|
||||
foreground: $primary,
|
||||
),
|
||||
secondary: (
|
||||
base: $secondary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($secondary),
|
||||
tint: get-color-tint($secondary)
|
||||
base: $secondary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($secondary),
|
||||
tint: get-color-tint($secondary),
|
||||
foreground: $secondary,
|
||||
),
|
||||
tertiary: (
|
||||
base: $tertiary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($tertiary),
|
||||
tint: get-color-tint($tertiary)
|
||||
base: $tertiary,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($tertiary),
|
||||
tint: get-color-tint($tertiary),
|
||||
foreground: $tertiary,
|
||||
),
|
||||
success: (
|
||||
base: $success,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($success),
|
||||
tint: get-color-tint($success)
|
||||
base: $success,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($success),
|
||||
tint: get-color-tint($success),
|
||||
foreground: $success,
|
||||
),
|
||||
warning: (
|
||||
base: $warning,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($warning),
|
||||
tint: get-color-tint($warning)
|
||||
base: $warning,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($warning),
|
||||
tint: get-color-tint($warning),
|
||||
foreground: $warning,
|
||||
),
|
||||
danger: (
|
||||
base: $danger,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($danger),
|
||||
tint: get-color-tint($danger)
|
||||
base: $danger,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($danger),
|
||||
tint: get-color-tint($danger),
|
||||
foreground: $danger,
|
||||
),
|
||||
light: (
|
||||
base: $light,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($light),
|
||||
tint: get-color-tint($light)
|
||||
base: $light,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($light),
|
||||
tint: get-color-tint($light),
|
||||
foreground: $light,
|
||||
),
|
||||
medium: (
|
||||
base: $medium,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($medium),
|
||||
tint: get-color-tint($medium)
|
||||
base: $medium,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($medium),
|
||||
tint: get-color-tint($medium),
|
||||
foreground: $medium,
|
||||
),
|
||||
dark: (
|
||||
base: $dark,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($dark),
|
||||
tint: get-color-tint($dark)
|
||||
)
|
||||
base: $dark,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($dark),
|
||||
tint: get-color-tint($dark),
|
||||
foreground: $dark,
|
||||
),
|
||||
);
|
||||
|
||||
/// Text step colors are generated based on
|
||||
@@ -105,13 +114,12 @@ $lightest-text-color: $text-color;
|
||||
--ion-color-#{$color-name}-shade: #{map.get($value, shade)};
|
||||
--ion-color-#{$color-name}-tint: #{map.get($value, tint)};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@mixin high-contrast-dark-ios-palette() {
|
||||
$background-color: #000000;
|
||||
|
||||
|
||||
& {
|
||||
--ion-background-color: #{$background-color};
|
||||
--ion-background-color-rgb: #{color-to-rgb-list($background-color)};
|
||||
@@ -175,7 +183,7 @@ $lightest-text-color: $text-color;
|
||||
|
||||
@mixin high-contrast-dark-md-palette() {
|
||||
$background-color: #121212;
|
||||
|
||||
|
||||
& {
|
||||
--ion-background-color: #{$background-color};
|
||||
--ion-background-color-rgb: #{color-to-rgb-list($background-color)};
|
||||
|
||||
@@ -1,71 +1,80 @@
|
||||
@use "sass:map";
|
||||
@import "../../themes/ionic.functions.color";
|
||||
|
||||
$primary: #003fae;
|
||||
$secondary: #01487b;
|
||||
$tertiary: #3400e6;
|
||||
$success: #004314;
|
||||
$warning: #5f4100;
|
||||
$danger: #9c000c;
|
||||
$light: #f4f5f8;
|
||||
$medium: #444446;
|
||||
$dark: #222428;
|
||||
$primary: #003fae;
|
||||
$secondary: #01487b;
|
||||
$tertiary: #3400e6;
|
||||
$success: #004314;
|
||||
$warning: #5f4100;
|
||||
$danger: #9c000c;
|
||||
$light: #f4f5f8;
|
||||
$medium: #444446;
|
||||
$dark: #222428;
|
||||
|
||||
$colors: (
|
||||
$colors: (
|
||||
primary: (
|
||||
base: $primary,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($primary),
|
||||
tint: get-color-tint($primary)
|
||||
base: $primary,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($primary),
|
||||
tint: get-color-tint($primary),
|
||||
foreground: $primary,
|
||||
),
|
||||
secondary: (
|
||||
base: $secondary,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($secondary),
|
||||
tint: get-color-tint($secondary)
|
||||
base: $secondary,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($secondary),
|
||||
tint: get-color-tint($secondary),
|
||||
foreground: $secondary,
|
||||
),
|
||||
tertiary: (
|
||||
base: $tertiary,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($tertiary),
|
||||
tint: get-color-tint($tertiary)
|
||||
base: $tertiary,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($tertiary),
|
||||
tint: get-color-tint($tertiary),
|
||||
foreground: $tertiary,
|
||||
),
|
||||
success: (
|
||||
base: $success,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($success),
|
||||
tint: get-color-tint($success)
|
||||
base: $success,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($success),
|
||||
tint: get-color-tint($success),
|
||||
foreground: $success,
|
||||
),
|
||||
warning: (
|
||||
base: $warning,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($warning),
|
||||
tint: get-color-tint($warning)
|
||||
base: $warning,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($warning),
|
||||
tint: get-color-tint($warning),
|
||||
foreground: $warning,
|
||||
),
|
||||
danger: (
|
||||
base: $danger,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($danger),
|
||||
tint: get-color-tint($danger)
|
||||
base: $danger,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($danger),
|
||||
tint: get-color-tint($danger),
|
||||
foreground: $danger,
|
||||
),
|
||||
light: (
|
||||
base: $light,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($light),
|
||||
tint: get-color-tint($light)
|
||||
base: $light,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($light),
|
||||
tint: get-color-tint($light),
|
||||
foreground: $light,
|
||||
),
|
||||
medium: (
|
||||
base: $medium,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($medium),
|
||||
tint: get-color-tint($medium)
|
||||
base: $medium,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($medium),
|
||||
tint: get-color-tint($medium),
|
||||
foreground: $medium,
|
||||
),
|
||||
dark: (
|
||||
base: $dark,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($dark),
|
||||
tint: get-color-tint($dark)
|
||||
)
|
||||
base: $dark,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($dark),
|
||||
tint: get-color-tint($dark),
|
||||
foreground: $dark,
|
||||
),
|
||||
);
|
||||
|
||||
/// Text step colors are generated based on
|
||||
|
||||
48
core/src/css/test/display.e2e.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
test.describe('display css utility classes', () => {
|
||||
let css: string;
|
||||
|
||||
test.beforeAll(() => {
|
||||
css = fs.readFileSync(path.resolve(__dirname, '../../../css/display.css'), 'utf8');
|
||||
});
|
||||
|
||||
const INFIXES = ['', '-sm', '-md', '-lg', '-xl'];
|
||||
|
||||
// TODO(FW-6697): remove `ion-hide classes` test
|
||||
test('ion-hide classes', () => {
|
||||
expect(css).toContain('.ion-hide');
|
||||
|
||||
const values = ['up', 'down'];
|
||||
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-hide${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('ion-display classes', () => {
|
||||
const values = [
|
||||
'none',
|
||||
'inline',
|
||||
'inline-block',
|
||||
'block',
|
||||
'flex',
|
||||
'inline-flex',
|
||||
'grid',
|
||||
'inline-grid',
|
||||
'table',
|
||||
'table-cell',
|
||||
'table-row',
|
||||
];
|
||||
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-display${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
100
core/src/css/test/flex-utils.e2e.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
test.describe('flex-utils css utility classes', () => {
|
||||
let css: string;
|
||||
|
||||
test.beforeAll(() => {
|
||||
css = fs.readFileSync(path.resolve(__dirname, '../../../css/flex-utils.css'), 'utf8');
|
||||
});
|
||||
|
||||
const INFIXES = ['', '-sm', '-md', '-lg', '-xl'];
|
||||
|
||||
test('align-content classes', () => {
|
||||
const values = ['start', 'end', 'center', 'between', 'around', 'stretch'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-align-content${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('align-items classes', () => {
|
||||
const values = ['start', 'center', 'end', 'stretch', 'baseline'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-align-items${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('align-self classes', () => {
|
||||
const values = ['start', 'end', 'center', 'stretch', 'baseline', 'auto'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-align-self${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('justify-content classes', () => {
|
||||
const values = ['start', 'center', 'end', 'around', 'between', 'evenly'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-justify-content${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-direction classes', () => {
|
||||
const values = ['row', 'row-reverse', 'column', 'column-reverse'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-wrap classes', () => {
|
||||
const values = ['wrap', 'nowrap', 'wrap-reverse'];
|
||||
// TODO(FW-6697): remove all `ion-wrap-*` expects
|
||||
for (const value of values) {
|
||||
expect(css).toContain(`.ion-${value}`);
|
||||
}
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-fill classes', () => {
|
||||
const values = ['1', 'auto', 'initial', 'none'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-grow and flex-shrink classes', () => {
|
||||
const values = ['grow', 'shrink'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}-0`);
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}-1`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-order classes', () => {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-order${infix}-first`);
|
||||
expect(css).toContain(`.ion-order${infix}-last`);
|
||||
for (let i = 0; i <= 12; i++) {
|
||||
expect(css).toContain(`.ion-order${infix}-${i}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -41,7 +41,10 @@ html {
|
||||
/**
|
||||
* Includes fallback if Dynamic Type is not enabled.
|
||||
*/
|
||||
font: var(--ion-dynamic-font, 16px var(--ion-font-family));
|
||||
// ion-font-sizes-root needs a fallback since the new theming isn't fully
|
||||
// implemented in the framework yet.
|
||||
font: var(--ion-dynamic-font, var(--ion-font-sizes-root, 16px) var(--ion-font-family));
|
||||
// font: var(--ion-dynamic-font, var(--ion-font-sizes-root) var(--ion-font-family));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { getMode, setMode } from '@stencil/core';
|
||||
import { printIonWarning } from '@utils/logging';
|
||||
|
||||
import type { IonicConfig, Mode } from '../interface';
|
||||
import { defaultTheme as baseTheme } from '../themes/base/base.tokens';
|
||||
import type { Theme as BaseTheme } from '../themes/base/base.tokens';
|
||||
import { deepMerge, generateCSSVars } from '../themes/base/generate-css-vars';
|
||||
import { printIonWarning } from '../utils/logging';
|
||||
import { isPlatform, setupPlatforms } from '../utils/platform';
|
||||
|
||||
import { config, configFromSession, configFromURL, saveConfig } from './config';
|
||||
@@ -10,8 +13,183 @@ import { config, configFromSession, configFromURL, saveConfig } from './config';
|
||||
|
||||
let defaultMode: Mode;
|
||||
|
||||
export const getIonMode = (ref?: any): Mode => {
|
||||
return (ref && getMode(ref)) || defaultMode;
|
||||
type Theme = 'ios' | 'md' | 'ionic';
|
||||
|
||||
const getElement = (ref: any): HTMLElement => {
|
||||
if (ref && typeof ref === 'object' && ref.tagName) {
|
||||
return ref;
|
||||
}
|
||||
return document.documentElement;
|
||||
};
|
||||
|
||||
/**
|
||||
* Prints a warning message to the developer to inform them of
|
||||
* an invalid configuration of mode and theme.
|
||||
* @param mode The invalid mode configuration.
|
||||
* @param theme The invalid theme configuration.
|
||||
*/
|
||||
const printInvalidModeWarning = (mode: Mode, theme: Theme, ref?: any) => {
|
||||
printIonWarning(
|
||||
`Invalid mode and theme combination provided: mode: ${mode}, theme: ${theme}. Fallback mode ${getDefaultModeForTheme(
|
||||
theme
|
||||
)} will be used.`,
|
||||
ref
|
||||
);
|
||||
};
|
||||
|
||||
const applyTheme = (userTheme: BaseTheme, prefix?: string) => {
|
||||
const mergedTheme = deepMerge(baseTheme, userTheme);
|
||||
const { palette, components, ...restTokens } = mergedTheme;
|
||||
const { enabled, ...restDarkTokens } = palette.dark;
|
||||
|
||||
config.set('customTheme', mergedTheme);
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = [generateCSSVars(restTokens, prefix), generateCSSVars(palette.light, prefix)].join('\n\n');
|
||||
|
||||
if (enabled === 'system') {
|
||||
style.innerHTML += `@media (prefers-color-scheme: dark) {\n${generateCSSVars(restDarkTokens, prefix)}\n}`;
|
||||
}
|
||||
|
||||
document.head.appendChild(style);
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates if a mode is accepted for a theme configuration.
|
||||
* @param mode The mode to validate.
|
||||
* @param theme The theme the mode is being used with.
|
||||
* @returns `true` if the mode is valid for the theme, `false` if invalid.
|
||||
*/
|
||||
export const isModeValidForTheme = (mode: Mode, theme: Theme) => {
|
||||
if (mode === 'md') {
|
||||
return theme === 'md' || theme === 'ionic';
|
||||
} else if (mode === 'ios') {
|
||||
return theme === 'ios' || theme === 'ionic';
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the default mode for a specified theme.
|
||||
* @param theme The theme to return a default mode for.
|
||||
* @returns The default mode, either `ios` or `md`.
|
||||
*/
|
||||
const getDefaultModeForTheme = (theme: Theme): Mode => {
|
||||
if (theme === 'ios') {
|
||||
return 'ios';
|
||||
}
|
||||
return 'md';
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the default theme for a specified mode.
|
||||
* @param mode The mode to return a default theme for.
|
||||
* @returns The default theme.
|
||||
*/
|
||||
const getDefaultThemeForMode = (mode: Mode): Theme => {
|
||||
if (mode === 'ios') {
|
||||
return 'ios';
|
||||
}
|
||||
return 'md';
|
||||
};
|
||||
|
||||
// const isModeSupported = (elmMode: string) => ['ios', 'md'].includes(elmMode);
|
||||
|
||||
// const isThemeSupported = (theme: string) => ['ios', 'md', 'ionic'].includes(theme);
|
||||
|
||||
// const isIonicElement = (elm: HTMLElement) => elm.tagName?.startsWith('ION-');
|
||||
|
||||
/**
|
||||
* Returns the mode value of the element reference or the closest
|
||||
* parent with a valid mode.
|
||||
* @param ref The element reference to look up the mode for.
|
||||
* @param theme Optionally can provide the theme to avoid an additional look-up.
|
||||
* @returns The mode value for the element reference.
|
||||
*/
|
||||
export const getIonMode = (ref?: any, theme = getIonTheme(ref)): Mode => {
|
||||
if (ref?.mode && isModeValidForTheme(ref?.mode, theme)) {
|
||||
/**
|
||||
* If the reference already has a mode configuration,
|
||||
* use it instead of performing a look-up.
|
||||
*/
|
||||
return ref.mode;
|
||||
} else {
|
||||
const el = getElement(ref);
|
||||
const mode = (el.closest('[mode]')?.getAttribute('mode') as Mode) || defaultMode;
|
||||
|
||||
if (isModeValidForTheme(mode, theme)) {
|
||||
/**
|
||||
* The mode configuration is supported for the configured theme.
|
||||
*/
|
||||
return mode;
|
||||
} else {
|
||||
printInvalidModeWarning(mode, theme, ref);
|
||||
}
|
||||
}
|
||||
return getDefaultModeForTheme(theme);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the theme value of the element reference or the closest
|
||||
* parent with a valid theme.
|
||||
*
|
||||
* @param ref The element reference to look up the theme for.
|
||||
* @returns The theme value for the element reference, defaults to
|
||||
* the default theme if it cannot be determined.
|
||||
*/
|
||||
export const getIonTheme = (ref?: any): Theme => {
|
||||
const theme: Theme = ref && getMode<Theme>(ref);
|
||||
if (theme) {
|
||||
return theme;
|
||||
}
|
||||
|
||||
const el = getElement(ref);
|
||||
const mode = ref?.mode ?? (el.closest('[mode]')?.getAttribute('mode') as Mode);
|
||||
|
||||
if (mode) {
|
||||
return getDefaultThemeForMode(mode);
|
||||
}
|
||||
|
||||
// Return a default theme string, not the baseTheme object
|
||||
return 'md'; // or 'ionic' as your default
|
||||
};
|
||||
|
||||
export const getIonCustomTheme = (): any => {
|
||||
const customTheme = config.get('customTheme');
|
||||
if (customTheme) {
|
||||
return customTheme;
|
||||
}
|
||||
return baseTheme;
|
||||
};
|
||||
|
||||
export const rIC = (callback: () => void) => {
|
||||
if ('requestIdleCallback' in window) {
|
||||
(window as any).requestIdleCallback(callback);
|
||||
} else {
|
||||
setTimeout(callback, 32);
|
||||
}
|
||||
};
|
||||
|
||||
export const needInputShims = () => {
|
||||
/**
|
||||
* iOS always needs input shims
|
||||
*/
|
||||
const needsShimsIOS = isPlatform(window, 'ios') && isPlatform(window, 'mobile');
|
||||
if (needsShimsIOS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Android only needs input shims when running
|
||||
* in the browser and only if the browser is using the
|
||||
* new Chrome 108+ resize behavior: https://developer.chrome.com/blog/viewport-resize-behavior/
|
||||
*/
|
||||
const isAndroidMobileWeb = isPlatform(window, 'android') && isPlatform(window, 'mobileweb');
|
||||
if (isAndroidMobileWeb) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export const initialize = (userConfig: IonicConfig = {}) => {
|
||||
@@ -53,6 +231,17 @@ export const initialize = (userConfig: IonicConfig = {}) => {
|
||||
doc.documentElement.setAttribute('mode', defaultMode);
|
||||
doc.documentElement.classList.add(defaultMode);
|
||||
|
||||
// Remove this line as 'theme' is not a valid IonicConfig key
|
||||
// config.set('theme', defaultTheme);
|
||||
// doc.documentElement.setAttribute('theme', defaultTheme);
|
||||
// doc.documentElement.classList.add(defaultTheme);
|
||||
|
||||
const customTheme: BaseTheme | undefined = configObj.customTheme;
|
||||
|
||||
if (customTheme) {
|
||||
applyTheme(customTheme);
|
||||
}
|
||||
|
||||
if (config.getBoolean('_testing')) {
|
||||
config.set('animated', false);
|
||||
}
|
||||
|
||||
9
core/src/interface.d.ts
vendored
@@ -23,9 +23,13 @@ export { PickerOptions, PickerColumnOption } from './components/picker-legacy/pi
|
||||
export { PopoverOptions } from './components/popover/popover-interface';
|
||||
export { RadioGroupCustomEvent } from './components/radio-group/radio-group-interface';
|
||||
export { RangeCustomEvent, PinFormatter } from './components/range/range-interface';
|
||||
export { HTMLStencilElement, RouterCustomEvent } from './components/router/utils/interface';
|
||||
export { RouterCustomEvent } from './components/router/utils/interface';
|
||||
export { RefresherCustomEvent } from './components/refresher/refresher-interface';
|
||||
export { ItemReorderCustomEvent } from './components/reorder-group/reorder-group-interface';
|
||||
export {
|
||||
ItemReorderCustomEvent,
|
||||
ReorderEndCustomEvent,
|
||||
ReorderMoveCustomEvent,
|
||||
} from './components/reorder-group/reorder-group-interface';
|
||||
export { SearchbarCustomEvent } from './components/searchbar/searchbar-interface';
|
||||
export { SegmentCustomEvent } from './components/segment/segment-interface';
|
||||
export { SelectCustomEvent, SelectCompareFn } from './components/select/select-interface';
|
||||
@@ -45,6 +49,7 @@ export {
|
||||
AnimationKeyFrames,
|
||||
AnimationLifecycle,
|
||||
} from './utils/animation/animation-interface';
|
||||
export { HTMLStencilElement } from './utils/element-interface';
|
||||
export { TransitionOptions } from './utils/transition';
|
||||
export { HTMLIonOverlayElement, OverlayController, OverlayInterface } from './utils/overlays-interface';
|
||||
export { Config, config } from './global/config';
|
||||
|
||||
86
core/src/themes/base/base.tokens.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { defaultDarkTheme } from './dark.tokens';
|
||||
import { defaultLightTheme } from './light.tokens';
|
||||
|
||||
export const defaultTheme = {
|
||||
palette: {
|
||||
light: defaultLightTheme,
|
||||
dark: defaultDarkTheme,
|
||||
},
|
||||
// so far spacing is being used for
|
||||
// padding, margin, gap, border-width, height, width
|
||||
spacing: {
|
||||
none: '0',
|
||||
xxs: '2px',
|
||||
xs: '4px',
|
||||
sm: '8px',
|
||||
md: '16px',
|
||||
lg: '24px',
|
||||
xl: '32px',
|
||||
xxl: '40px',
|
||||
},
|
||||
// scaling is used for width and height
|
||||
scaling: {
|
||||
0: '0',
|
||||
100: '4px',
|
||||
150: '6px',
|
||||
200: '8px',
|
||||
250: '10px',
|
||||
300: '12px',
|
||||
350: '14px',
|
||||
400: '16px',
|
||||
450: '18px',
|
||||
500: '20px',
|
||||
550: '22px',
|
||||
600: '24px',
|
||||
650: '26px',
|
||||
700: '28px',
|
||||
750: '30px',
|
||||
800: '32px',
|
||||
850: '34px',
|
||||
900: '36px',
|
||||
},
|
||||
radii: {
|
||||
none: '0',
|
||||
xs: '1px',
|
||||
sm: '2px',
|
||||
md: '4px',
|
||||
lg: '8px',
|
||||
xl: '16px',
|
||||
xxl: '32px',
|
||||
},
|
||||
dynamicFont: '-apple-system-body',
|
||||
fontFamily: 'Roboto, "Helvetica Neue", sans-serif',
|
||||
fontWeights: {
|
||||
thin: '100',
|
||||
extraLight: '200',
|
||||
light: '300',
|
||||
normal: '400',
|
||||
medium: '500',
|
||||
semiBold: '600',
|
||||
bold: '700',
|
||||
extraBold: '800',
|
||||
black: '900',
|
||||
},
|
||||
fontSizes: {
|
||||
root: '16px',
|
||||
xxs: '10px',
|
||||
xs: '12px',
|
||||
sm: '14px',
|
||||
md: '16px',
|
||||
lg: '18px',
|
||||
xl: '20px',
|
||||
xxl: '24px',
|
||||
},
|
||||
lineHeights: {
|
||||
xxs: '1',
|
||||
xs: '1.2',
|
||||
sm: '1.4',
|
||||
md: '1.6',
|
||||
lg: '1.8',
|
||||
xl: '2',
|
||||
xxl: '2.4',
|
||||
},
|
||||
components: {},
|
||||
};
|
||||
|
||||
export type Theme = typeof defaultTheme;
|
||||
58
core/src/themes/base/dark.tokens.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
export const defaultDarkTheme = {
|
||||
enabled: 'never', // 'always' | 'system' | 'class' | 'never'
|
||||
color: {
|
||||
primary: {
|
||||
bold: {
|
||||
base: '#0054e9',
|
||||
constrast: '#ffffff',
|
||||
shade: '#0041c4', // darker version
|
||||
tint: '#0065ff', // lighter version
|
||||
},
|
||||
subtle: {
|
||||
base: '#0054e9',
|
||||
constrast: '#ffffff',
|
||||
shade: '#0041c4', // darker version
|
||||
tint: '#0065ff', // lighter version
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
bold: {
|
||||
base: '#0163aa',
|
||||
constrast: '#ffffff',
|
||||
shade: '#015a9e',
|
||||
tint: '#0176c4',
|
||||
},
|
||||
subtle: {
|
||||
base: '#0163aa',
|
||||
constrast: '#ffffff',
|
||||
shade: '#015a9e',
|
||||
tint: '#0176c4',
|
||||
},
|
||||
},
|
||||
red: {
|
||||
50: '#ffebee',
|
||||
100: '#ffcdd2',
|
||||
200: '#ef9a9a',
|
||||
},
|
||||
blue: {
|
||||
50: '#e3f2fd',
|
||||
100: '#bbdefb',
|
||||
200: '#90caf9',
|
||||
},
|
||||
gray: {
|
||||
50: '#f5f5f5',
|
||||
100: '#eeeeee',
|
||||
200: '#e0e0e0',
|
||||
300: '#bdbdbd',
|
||||
400: '#9e9e9e',
|
||||
500: '#757575',
|
||||
600: '#616161',
|
||||
700: '#424242',
|
||||
800: '#212121',
|
||||
},
|
||||
white: 'green',
|
||||
black: '#000000',
|
||||
},
|
||||
};
|
||||
|
||||
export type Theme = typeof defaultDarkTheme;
|
||||
45
core/src/themes/base/generate-css-vars.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// import type { Theme } from './base.tokens';
|
||||
|
||||
export function generateCSSVars(theme: any, themePrefix = '--ion-', selector = ':root'): string {
|
||||
const flatten = (obj: any, prefix = themePrefix): string =>
|
||||
Object.entries(obj)
|
||||
.flatMap(([key, val]) => {
|
||||
// if key is camelCase, convert to kebab-case
|
||||
if (key.match(/([a-z])([A-Z])/g)) {
|
||||
key = key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
|
||||
// If it's a font-sizes key, create rem version
|
||||
// This is necessary to support the dynamic font size feature
|
||||
if (key === 'font-sizes' && typeof val === 'object' && val !== null) {
|
||||
const fontSizeBase = parseFloat(theme.fontSizes.root);
|
||||
return Object.entries(val).map(([sizeKey, sizeValue]) => {
|
||||
const remValue = `${parseFloat(sizeValue) / fontSizeBase}rem`;
|
||||
// Need a check to determine if the value is already in rem
|
||||
return [
|
||||
`${prefix}${key}-${sizeKey}: ${sizeValue};`, // original px value
|
||||
`${prefix}${key}-${sizeKey}-rem: ${remValue};` // rem value
|
||||
].join('\n');
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
return typeof val === 'object' && val !== null
|
||||
? flatten(val, `${prefix}${key}-`)
|
||||
: [`${prefix}${key}: ${val};`];
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
return `${selector} {\n${flatten(theme)}\n}`;
|
||||
}
|
||||
|
||||
// Simple deep merge function
|
||||
export function deepMerge(target: any, source: any): any {
|
||||
for (const key in source) {
|
||||
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
||||
target[key] = deepMerge(target[key] ?? {}, source[key]);
|
||||
} else {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
57
core/src/themes/base/light.tokens.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
export const defaultLightTheme = {
|
||||
color: {
|
||||
primary: {
|
||||
bold: {
|
||||
base: '#0054e9',
|
||||
constrast: '#ffffff',
|
||||
shade: '#0041c4', // darker version
|
||||
tint: '#0065ff', // lighter version
|
||||
},
|
||||
subtle: {
|
||||
base: '#0054e9',
|
||||
constrast: '#ffffff',
|
||||
shade: '#0041c4', // darker version
|
||||
tint: '#0065ff', // lighter version
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
bold: {
|
||||
base: '#0163aa',
|
||||
constrast: '#ffffff',
|
||||
shade: '#015a9e',
|
||||
tint: '#0176c4',
|
||||
},
|
||||
subtle: {
|
||||
base: '#0163aa',
|
||||
constrast: '#ffffff',
|
||||
shade: '#015a9e',
|
||||
tint: '#0176c4',
|
||||
},
|
||||
},
|
||||
red: {
|
||||
50: '#ffebee',
|
||||
100: '#ffcdd2',
|
||||
200: '#ef9a9a',
|
||||
},
|
||||
blue: {
|
||||
50: '#e3f2fd',
|
||||
100: '#bbdefb',
|
||||
200: '#90caf9',
|
||||
},
|
||||
gray: {
|
||||
50: '#f5f5f5',
|
||||
100: '#eeeeee',
|
||||
200: '#e0e0e0',
|
||||
300: '#bdbdbd',
|
||||
400: '#9e9e9e',
|
||||
500: '#757575',
|
||||
600: '#616161',
|
||||
700: '#424242',
|
||||
800: '#212121',
|
||||
},
|
||||
white: '#ffffff',
|
||||
black: '#000000',
|
||||
},
|
||||
};
|
||||
|
||||
export type Theme = typeof defaultLightTheme;
|
||||
@@ -1,14 +1,18 @@
|
||||
@use "sass:map";
|
||||
|
||||
// Gets the active color's css variable from a variation. Alpha is optional.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Example usage:
|
||||
// current-color(base) => var(--ion-color-base)
|
||||
// current-color(contrast, 0.1) => rgba(var(--ion-color-contrast-rgb), 0.1)
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@function current-color($variation, $alpha: null) {
|
||||
@function current-color($variation, $alpha: null, $subtle: false) {
|
||||
$variable: if($subtle, "--ion-color-subtle-#{$variation}", "--ion-color-#{$variation}");
|
||||
|
||||
@if $alpha == null {
|
||||
@return var(--ion-color-#{$variation});
|
||||
@return var(#{$variable});
|
||||
} @else {
|
||||
@return rgba(var(--ion-color-#{$variation}-rgb), #{$alpha});
|
||||
@return rgba(var(#{$variable}-rgb), #{$alpha});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,19 +23,36 @@
|
||||
// ion-color(secondary, contrast) => var(--ion-color-secondary-contrast)
|
||||
// ion-color(primary, base, 0.5) => rgba(var(--ion-color-primary-rgb, 56, 128, 255), 0.5)
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@function ion-color($name, $variation, $alpha: null, $rgb: null) {
|
||||
$values: map-get($colors, $name);
|
||||
$value: map-get($values, $variation);
|
||||
$variable: --ion-color-#{$name}-#{$variation};
|
||||
@function ion-color($name, $variation, $alpha: null, $rgb: null, $subtle: false) {
|
||||
$values: map.get($colors, $name);
|
||||
$values: map.get($values, if($subtle, subtle, bold));
|
||||
|
||||
$value: map.get($values, $variation);
|
||||
|
||||
// TODO(FW-6417): this can be removed when foreground is required
|
||||
// Fallback to "base" variant when "foreground" variant is undefined
|
||||
@if ($variation == foreground and $value == null) {
|
||||
$variation: base;
|
||||
$value: map.get($values, $variation);
|
||||
}
|
||||
|
||||
// If the color requested is subtle we return `--ion-color-{color}-subtle-contrast`,
|
||||
// otherwise we return `--ion-color-{color}-contrast`.
|
||||
$variable: if($subtle, "--ion-color-#{$name}-subtle-#{$variation}", "--ion-color-#{$name}-#{$variation}");
|
||||
|
||||
// If the variation being used is "base", we do not include the variant.
|
||||
// If the color requested is subtle we return `--ion-color-{color}-subtle`,
|
||||
// otherwise we return `--ion-color-{color}`.
|
||||
@if ($variation == base) {
|
||||
$variable: --ion-color-#{$name};
|
||||
$variable: if($subtle, "--ion-color-#{$name}-subtle", "--ion-color-#{$name}");
|
||||
}
|
||||
|
||||
@if ($alpha) {
|
||||
$value: color-to-rgb-list($value);
|
||||
|
||||
@return rgba(var(#{$variable}-rgb, $value), $alpha);
|
||||
}
|
||||
|
||||
@if ($rgb) {
|
||||
$value: color-to-rgb-list($value);
|
||||
$variable: #{$variable}-rgb;
|
||||
@@ -43,17 +64,181 @@
|
||||
// Mixes a color with black to create its shade.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@function get-color-shade($color) {
|
||||
@if (type-of($color) != color) {
|
||||
@return $color;
|
||||
}
|
||||
@return mix(#000, $color, 12%);
|
||||
}
|
||||
|
||||
// Mixes a color with white to create its tint.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@function get-color-tint($color) {
|
||||
@if (type-of($color) != color) {
|
||||
@return $color;
|
||||
}
|
||||
@return mix(#fff, $color, 10%);
|
||||
}
|
||||
|
||||
// Converts a color to a comma separated rgb.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@function color-to-rgb-list($color) {
|
||||
@return #{red($color)},#{green($color)},#{blue($color)};
|
||||
@if (type-of($color) != color) {
|
||||
@return $color;
|
||||
}
|
||||
@return #{red($color)}, #{green($color)}, #{blue($color)};
|
||||
}
|
||||
|
||||
// Generates color variants for the specified color based on the
|
||||
// colors map for whichever hue is passed (bold, subtle).
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Example usage (bold):
|
||||
// .ion-color-primary {
|
||||
// @include generate-color-variants("primary");
|
||||
// }
|
||||
//
|
||||
// Example output (bold):
|
||||
// .ion-color-primary {
|
||||
// --ion-color-base: var(--ion-color-primary-base, #105cef) !important;
|
||||
// --ion-color-base-rgb: var(--ion-color-primary-base-rgb, 16, 92, 239) !important;
|
||||
// --ion-color-contrast: var(--ion-color-primary-contrast, #fff) !important;
|
||||
// --ion-color-contrast-rgb: var(--ion-color-primary-contrast-rgb, 255, 255, 255) !important;
|
||||
// --ion-color-shade: var(--ion-color-primary-shade, #0f54da) !important;
|
||||
// --ion-color-tint: var(--ion-color-primary-tint, #94a5f4) !important;
|
||||
// }
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Example usage (subtle):
|
||||
// .ion-color-primary {
|
||||
// @include generate-color-variants("primary", "subtle")
|
||||
// }
|
||||
//
|
||||
// Example output (subtle):
|
||||
// .ion-color-primary {
|
||||
// --ion-color-subtle-base: var(--ion-color-primary-subtle-base, #f2f4fd) !important;
|
||||
// --ion-color-subtle-base-rgb: var(--ion-color-primary-subtle-base-rgb, 242, 244, 253) !important;
|
||||
// --ion-color-subtle-contrast: var(--ion-color-primary-subtle-contrast, #105cef) !important;
|
||||
// --ion-color-subtle-contrast-rgb: var(--ion-color-primary-subtle-contrast-rgb, 16, 92, 239) !important;
|
||||
// --ion-color-subtle-shade: var(--ion-color-primary-subtle-shade, #d0d7fa) !important;
|
||||
// --ion-color-subtle-tint: var(--ion-color-primary-subtle-tint, #e9ecfc) !important;
|
||||
// }
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@mixin generate-color-variants($color-name, $hue: "bold") {
|
||||
@if not($colors) {
|
||||
@error 'No theme colors set. Please make sure to call set-theme-colors($colorsMap) before using ion-color()';
|
||||
}
|
||||
|
||||
// Grab the different hue color maps for the
|
||||
// specified color and then grab the map of color variants
|
||||
$hue-colors: map.get($colors, $color-name);
|
||||
$color-variants: map.get($hue-colors, $hue);
|
||||
|
||||
$prefix: if($hue == "subtle", "-subtle", "");
|
||||
|
||||
// TODO(FW-6417) this @if can be removed if we add subtle colors for ios and md
|
||||
// Only proceed if the color variants exist
|
||||
@if $color-variants {
|
||||
// Grab the individual color variants
|
||||
$base: map.get($color-variants, base);
|
||||
$base-rgb: map.get($color-variants, base-rgb);
|
||||
$contrast: map.get($color-variants, contrast);
|
||||
$contrast-rgb: map.get($color-variants, contrast-rgb);
|
||||
$shade: map.get($color-variants, shade);
|
||||
$tint: map.get($color-variants, tint);
|
||||
$foreground: map.get($color-variants, foreground);
|
||||
|
||||
// Generate CSS variables dynamically
|
||||
--ion-color#{$prefix}-base: var(--ion-color-#{$color-name}#{$prefix}, #{$base}) !important;
|
||||
--ion-color#{$prefix}-base-rgb: var(--ion-color-#{$color-name}#{$prefix}-rgb, #{$base-rgb}) !important;
|
||||
--ion-color#{$prefix}-contrast: var(--ion-color-#{$color-name}#{$prefix}-contrast, #{$contrast}) !important;
|
||||
--ion-color#{$prefix}-contrast-rgb: var(
|
||||
--ion-color-#{$color-name}#{$prefix}-contrast-rgb,
|
||||
#{$contrast-rgb}
|
||||
) !important;
|
||||
--ion-color#{$prefix}-shade: var(--ion-color-#{$color-name}#{$prefix}-shade, #{$shade}) !important;
|
||||
--ion-color#{$prefix}-tint: var(--ion-color-#{$color-name}#{$prefix}-tint, #{$tint}) !important;
|
||||
// TODO(FW-6417): remove the fallback variable when the foreground variable is
|
||||
// required by all palettes for all themes:
|
||||
// --ion-color#{$prefix}-foreground: var(--ion-color-#{$color-name}#{$prefix}-foreground, #{$foreground}) !important;
|
||||
--ion-color#{$prefix}-foreground: var(
|
||||
--ion-color-#{$color-name}#{$prefix}-foreground,
|
||||
var(--ion-color-#{$color-name}#{$prefix}, #{$foreground})
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Generates both bold and subtle color variables
|
||||
// for the specified color in the colors map.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@mixin generate-color($color-name) {
|
||||
@include generate-color-variants($color-name);
|
||||
@include generate-color-variants($color-name, "subtle");
|
||||
}
|
||||
|
||||
// Generates color variables for all colors in the colors map for both hues (bold, subtle).
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Example usage:
|
||||
// :root {
|
||||
// generate-color-variables()
|
||||
// }
|
||||
//
|
||||
// Example output:
|
||||
// :root {
|
||||
// --ion-color-primary: #105cef;
|
||||
// --ion-color-primary-rgb: 16, 92, 239;
|
||||
// --ion-color-primary-contrast: #ffffff;
|
||||
// --ion-color-primary-contrast-rgb: 255, 255, 255;
|
||||
// --ion-color-primary-shade: #0f54da;
|
||||
// --ion-color-primary-tint: #94a5f4;
|
||||
// --ion-color-primary-foreground: #105cef;
|
||||
// --ion-color-primary-subtle: #f2f4fd;
|
||||
// --ion-color-primary-subtle-rgb: 242, 244, 253;
|
||||
// --ion-color-primary-subtle-contrast: #105cef;
|
||||
// --ion-color-primary-subtle-contrast-rgb: 16, 92, 239;
|
||||
// --ion-color-primary-subtle-shade: #d0d7fa;
|
||||
// --ion-color-primary-subtle-tint: #e9ecfc;
|
||||
// --ion-color-primary-foreground: #105cef;
|
||||
// ...
|
||||
// --ion-color-dark: #292929;
|
||||
// --ion-color-dark-rgb: 41, 41, 41;
|
||||
// --ion-color-dark-contrast: #ffffff;
|
||||
// --ion-color-dark-contrast-rgb: 255, 255, 255;
|
||||
// --ion-color-dark-shade: #242424;
|
||||
// --ion-color-dark-tint: #4e4e4e;
|
||||
// --ion-color-dark-foreground: #242424;
|
||||
// --ion-color-dark-subtle: #f5f5f5;
|
||||
// --ion-color-dark-subtle-rgb: 245, 245, 245;
|
||||
// --ion-color-dark-subtle-contrast: #292929;
|
||||
// --ion-color-dark-subtle-contrast-rgb: 41, 41, 41;
|
||||
// --ion-color-dark-subtle-shade: #e0e0e0;
|
||||
// --ion-color-dark-subtle-tint: #efefef;
|
||||
// --ion-color-dark-subtle-foreground: #242424;
|
||||
// }
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@mixin generate-color-variables() {
|
||||
@if not($colors) {
|
||||
@error 'No theme colors set. Please make sure to call set-theme-colors($colorsMap) before using ion-color().';
|
||||
}
|
||||
|
||||
@each $color-name, $value in $colors {
|
||||
@each $hue in (bold, subtle) {
|
||||
$colors: map.get($value, $hue);
|
||||
|
||||
@if $colors != null {
|
||||
$prefix: if($hue == subtle, "-subtle", "");
|
||||
|
||||
--ion-color-#{$color-name}#{$prefix}: #{map.get($colors, base)};
|
||||
--ion-color-#{$color-name}#{$prefix}-rgb: #{map.get($colors, base-rgb)};
|
||||
--ion-color-#{$color-name}#{$prefix}-contrast: #{map.get($colors, contrast)};
|
||||
--ion-color-#{$color-name}#{$prefix}-contrast-rgb: #{map.get($colors, contrast-rgb)};
|
||||
--ion-color-#{$color-name}#{$prefix}-shade: #{map.get($colors, shade)};
|
||||
--ion-color-#{$color-name}#{$prefix}-tint: #{map.get($colors, tint)};
|
||||
// TODO(FW-6417): this "if" can be removed when foreground is defined for ios/md
|
||||
// themes. It should not be added until we want foreground to be required for
|
||||
// ios and md because this will be a breaking change, requiring users to add
|
||||
// `--ion-color-{color}-foreground` in order to override the default colors
|
||||
@if (map.get($colors, foreground)) {
|
||||
--ion-color-#{$color-name}#{$prefix}-foreground: #{map.get($colors, foreground)};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,92 +7,130 @@
|
||||
// Default Ionic Colors
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Color map should provide
|
||||
// - base: main color to be used.
|
||||
// - contrast: Color that will provide readable text against the base color
|
||||
// - shade: 12% darker version of the base color (mix with black)
|
||||
// - tint: 10% lighter version of the base color (mix with white)
|
||||
// - base: The main color used for backgrounds
|
||||
// - base-rgb: The base color in RGB format
|
||||
// - contrast: A color that ensures readable text on the base color
|
||||
// - contrast-rgb: The contrast color in RGB format
|
||||
// - shade: 12% darker version of the base color (mix with black), used for pressed/active states
|
||||
// - tint: 10% lighter version of the base color (mix with white), used for focused/hover states
|
||||
|
||||
$primary: #0054e9;
|
||||
$secondary: #0163aa;
|
||||
$tertiary: #6030ff;
|
||||
$success: #2dd55b;
|
||||
$warning: #ffc409;
|
||||
$danger: #c5000f;
|
||||
$light: #f4f5f8;
|
||||
$medium: #636469;
|
||||
$dark: #222428;
|
||||
$primary: #0054e9;
|
||||
$secondary: #0163aa;
|
||||
$tertiary: #6030ff;
|
||||
$success: #2dd55b;
|
||||
$warning: #ffc409;
|
||||
$danger: #c5000f;
|
||||
$light: #f4f5f8;
|
||||
$medium: #636469;
|
||||
$dark: #222428;
|
||||
|
||||
$colors: (
|
||||
$colors: (
|
||||
primary: (
|
||||
base: $primary,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($primary),
|
||||
tint: get-color-tint($primary)
|
||||
bold: (
|
||||
base: $primary,
|
||||
base-rgb: color-to-rgb-list($primary),
|
||||
contrast: #fff,
|
||||
contrast-rgb: color-to-rgb-list(#fff),
|
||||
shade: get-color-shade($primary),
|
||||
tint: get-color-tint($primary),
|
||||
),
|
||||
),
|
||||
secondary: (
|
||||
base: $secondary,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($secondary),
|
||||
tint: get-color-tint($secondary)
|
||||
bold: (
|
||||
base: $secondary,
|
||||
base-rgb: color-to-rgb-list($secondary),
|
||||
contrast: #fff,
|
||||
contrast-rgb: color-to-rgb-list(#fff),
|
||||
shade: get-color-shade($secondary),
|
||||
tint: get-color-tint($secondary),
|
||||
),
|
||||
),
|
||||
tertiary: (
|
||||
base: $tertiary,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($tertiary),
|
||||
tint: get-color-tint($tertiary)
|
||||
bold: (
|
||||
base: $tertiary,
|
||||
base-rgb: color-to-rgb-list($tertiary),
|
||||
contrast: #fff,
|
||||
contrast-rgb: color-to-rgb-list(#fff),
|
||||
shade: get-color-shade($tertiary),
|
||||
tint: get-color-tint($tertiary),
|
||||
),
|
||||
),
|
||||
success: (
|
||||
base: $success,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($success),
|
||||
tint: get-color-tint($success)
|
||||
bold: (
|
||||
base: $success,
|
||||
base-rgb: color-to-rgb-list($success),
|
||||
contrast: #000,
|
||||
contrast-rgb: color-to-rgb-list(#000),
|
||||
shade: get-color-shade($success),
|
||||
tint: get-color-tint($success),
|
||||
),
|
||||
),
|
||||
warning: (
|
||||
base: $warning,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($warning),
|
||||
tint: get-color-tint($warning)
|
||||
bold: (
|
||||
base: $warning,
|
||||
base-rgb: color-to-rgb-list($warning),
|
||||
contrast: #000,
|
||||
contrast-rgb: color-to-rgb-list(#000),
|
||||
shade: get-color-shade($warning),
|
||||
tint: get-color-tint($warning),
|
||||
),
|
||||
),
|
||||
danger: (
|
||||
base: $danger,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($danger),
|
||||
tint: get-color-tint($danger)
|
||||
bold: (
|
||||
base: $danger,
|
||||
base-rgb: color-to-rgb-list($danger),
|
||||
contrast: #fff,
|
||||
contrast-rgb: color-to-rgb-list(#fff),
|
||||
shade: get-color-shade($danger),
|
||||
tint: get-color-tint($danger),
|
||||
),
|
||||
),
|
||||
light: (
|
||||
base: $light,
|
||||
contrast: #000,
|
||||
shade: get-color-shade($light),
|
||||
tint: get-color-tint($light)
|
||||
bold: (
|
||||
base: $light,
|
||||
base-rgb: color-to-rgb-list($light),
|
||||
contrast: #000,
|
||||
contrast-rgb: color-to-rgb-list(#000),
|
||||
shade: get-color-shade($light),
|
||||
tint: get-color-tint($light),
|
||||
),
|
||||
),
|
||||
medium: (
|
||||
base: $medium,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($medium),
|
||||
tint: get-color-tint($medium)
|
||||
bold: (
|
||||
base: $medium,
|
||||
base-rgb: color-to-rgb-list($medium),
|
||||
contrast: #fff,
|
||||
contrast-rgb: color-to-rgb-list(#fff),
|
||||
shade: get-color-shade($medium),
|
||||
tint: get-color-tint($medium),
|
||||
),
|
||||
),
|
||||
dark: (
|
||||
base: $dark,
|
||||
contrast: #fff,
|
||||
shade: get-color-shade($dark),
|
||||
tint: get-color-tint($dark)
|
||||
)
|
||||
bold: (
|
||||
base: $dark,
|
||||
base-rgb: color-to-rgb-list($dark),
|
||||
contrast: #fff,
|
||||
contrast-rgb: color-to-rgb-list(#fff),
|
||||
shade: get-color-shade($dark),
|
||||
tint: get-color-tint($dark),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Default Foreground and Background Colors
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Used internally to calculate the default steps
|
||||
|
||||
$background-color-value: #fff;
|
||||
$background-color-rgb-value: 255, 255, 255;
|
||||
$background-color-value: #fff;
|
||||
$background-color-rgb-value: 255, 255, 255;
|
||||
|
||||
$text-color-value: #000;
|
||||
$text-color-rgb-value: 0, 0, 0;
|
||||
$text-color-value: #000;
|
||||
$text-color-rgb-value: 0, 0, 0;
|
||||
|
||||
$background-color: var(--ion-background-color, $background-color-value);
|
||||
$background-color-rgb: var(--ion-background-color-rgb, $background-color-rgb-value);
|
||||
$text-color: var(--ion-text-color, $text-color-value);
|
||||
$text-color-rgb: var(--ion-text-color-rgb, $text-color-rgb-value);
|
||||
$background-color: var(--ion-background-color, $background-color-value);
|
||||
$background-color-rgb: var(--ion-background-color-rgb, $background-color-rgb-value);
|
||||
$text-color: var(--ion-text-color, $text-color-value);
|
||||
$text-color-rgb: var(--ion-text-color-rgb, $text-color-rgb-value);
|
||||
|
||||
// Default Foreground and Background Step Colors
|
||||
// -------------------------------------------------------------------------------------------
|
||||
@@ -101,45 +139,159 @@ $text-color-rgb: var(--ion-text-color-rgb, $text-color-rgb-va
|
||||
// For example, $text-color-step-XXX will be $text-color stepping towards $background-color,
|
||||
// but a $background-color-step-XXX will be $background-color stepping towards $text-color.
|
||||
|
||||
$background-color-step-50: var(--ion-color-step-50, var(--ion-background-color-step-50, mix($text-color-value, $background-color-value, 5%)));
|
||||
$background-color-step-100: var(--ion-color-step-100, var(--ion-background-color-step-100, mix($text-color-value, $background-color-value, 10%)));
|
||||
$background-color-step-150: var(--ion-color-step-150, var(--ion-background-color-step-150, mix($text-color-value, $background-color-value, 15%)));
|
||||
$background-color-step-200: var(--ion-color-step-200, var(--ion-background-color-step-200, mix($text-color-value, $background-color-value, 20%)));
|
||||
$background-color-step-250: var(--ion-color-step-250, var(--ion-background-color-step-250, mix($text-color-value, $background-color-value, 25%)));
|
||||
$background-color-step-300: var(--ion-color-step-300, var(--ion-background-color-step-300, mix($text-color-value, $background-color-value, 30%)));
|
||||
$background-color-step-350: var(--ion-color-step-350, var(--ion-background-color-step-350, mix($text-color-value, $background-color-value, 35%)));
|
||||
$background-color-step-400: var(--ion-color-step-400, var(--ion-background-color-step-400, mix($text-color-value, $background-color-value, 40%)));
|
||||
$background-color-step-450: var(--ion-color-step-450, var(--ion-background-color-step-450, mix($text-color-value, $background-color-value, 45%)));
|
||||
$background-color-step-500: var(--ion-color-step-500, var(--ion-background-color-step-500, mix($text-color-value, $background-color-value, 50%)));
|
||||
$background-color-step-550: var(--ion-color-step-550, var(--ion-background-color-step-550, mix($text-color-value, $background-color-value, 55%)));
|
||||
$background-color-step-600: var(--ion-color-step-600, var(--ion-background-color-step-600, mix($text-color-value, $background-color-value, 60%)));
|
||||
$background-color-step-650: var(--ion-color-step-650, var(--ion-background-color-step-650, mix($text-color-value, $background-color-value, 65%)));
|
||||
$background-color-step-700: var(--ion-color-step-700, var(--ion-background-color-step-700, mix($text-color-value, $background-color-value, 70%)));
|
||||
$background-color-step-750: var(--ion-color-step-750, var(--ion-background-color-step-750, mix($text-color-value, $background-color-value, 75%)));
|
||||
$background-color-step-800: var(--ion-color-step-800, var(--ion-background-color-step-800, mix($text-color-value, $background-color-value, 80%)));
|
||||
$background-color-step-850: var(--ion-color-step-850, var(--ion-background-color-step-850, mix($text-color-value, $background-color-value, 85%)));
|
||||
$background-color-step-900: var(--ion-color-step-900, var(--ion-background-color-step-900, mix($text-color-value, $background-color-value, 90%)));
|
||||
$background-color-step-950: var(--ion-color-step-950, var(--ion-background-color-step-950, mix($text-color-value, $background-color-value, 95%)));
|
||||
$text-color-step-50: var(--ion-color-step-950, var(--ion-text-color-step-50, mix($background-color-value, $text-color-value, 5%)));
|
||||
$text-color-step-100: var(--ion-color-step-900, var(--ion-text-color-step-100, mix($background-color-value, $text-color-value, 10%)));
|
||||
$text-color-step-150: var(--ion-color-step-850, var(--ion-text-color-step-150, mix($background-color-value, $text-color-value, 15%)));
|
||||
$text-color-step-200: var(--ion-color-step-800, var(--ion-text-color-step-200, mix($background-color-value, $text-color-value, 20%)));
|
||||
$text-color-step-250: var(--ion-color-step-750, var(--ion-text-color-step-250, mix($background-color-value, $text-color-value, 25%)));
|
||||
$text-color-step-300: var(--ion-color-step-700, var(--ion-text-color-step-300, mix($background-color-value, $text-color-value, 30%)));
|
||||
$text-color-step-350: var(--ion-color-step-650, var(--ion-text-color-step-350, mix($background-color-value, $text-color-value, 35%)));
|
||||
$text-color-step-400: var(--ion-color-step-600, var(--ion-text-color-step-400, mix($background-color-value, $text-color-value, 40%)));
|
||||
$text-color-step-450: var(--ion-color-step-550, var(--ion-text-color-step-450, mix($background-color-value, $text-color-value, 45%)));
|
||||
$text-color-step-500: var(--ion-color-step-500, var(--ion-text-color-step-500, mix($background-color-value, $text-color-value, 50%)));
|
||||
$text-color-step-550: var(--ion-color-step-450, var(--ion-text-color-step-550, mix($background-color-value, $text-color-value, 55%)));
|
||||
$text-color-step-600: var(--ion-color-step-400, var(--ion-text-color-step-600, mix($background-color-value, $text-color-value, 60%)));
|
||||
$text-color-step-650: var(--ion-color-step-350, var(--ion-text-color-step-650, mix($background-color-value, $text-color-value, 65%)));
|
||||
$text-color-step-700: var(--ion-color-step-300, var(--ion-text-color-step-700, mix($background-color-value, $text-color-value, 70%)));
|
||||
$text-color-step-750: var(--ion-color-step-250, var(--ion-text-color-step-750, mix($background-color-value, $text-color-value, 75%)));
|
||||
$text-color-step-800: var(--ion-color-step-200, var(--ion-text-color-step-800, mix($background-color-value, $text-color-value, 80%)));
|
||||
$text-color-step-850: var(--ion-color-step-150, var(--ion-text-color-step-850, mix($background-color-value, $text-color-value, 85%)));
|
||||
$text-color-step-900: var(--ion-color-step-100, var(--ion-text-color-step-900, mix($background-color-value, $text-color-value, 90%)));
|
||||
$text-color-step-950: var(--ion-color-step-50, var(--ion-text-color-step-950, mix($background-color-value, $text-color-value, 95%)));
|
||||
$background-color-step-50: var(
|
||||
--ion-color-step-50,
|
||||
var(--ion-background-color-step-50, mix($text-color-value, $background-color-value, 5%))
|
||||
);
|
||||
$background-color-step-100: var(
|
||||
--ion-color-step-100,
|
||||
var(--ion-background-color-step-100, mix($text-color-value, $background-color-value, 10%))
|
||||
);
|
||||
$background-color-step-150: var(
|
||||
--ion-color-step-150,
|
||||
var(--ion-background-color-step-150, mix($text-color-value, $background-color-value, 15%))
|
||||
);
|
||||
$background-color-step-200: var(
|
||||
--ion-color-step-200,
|
||||
var(--ion-background-color-step-200, mix($text-color-value, $background-color-value, 20%))
|
||||
);
|
||||
$background-color-step-250: var(
|
||||
--ion-color-step-250,
|
||||
var(--ion-background-color-step-250, mix($text-color-value, $background-color-value, 25%))
|
||||
);
|
||||
$background-color-step-300: var(
|
||||
--ion-color-step-300,
|
||||
var(--ion-background-color-step-300, mix($text-color-value, $background-color-value, 30%))
|
||||
);
|
||||
$background-color-step-350: var(
|
||||
--ion-color-step-350,
|
||||
var(--ion-background-color-step-350, mix($text-color-value, $background-color-value, 35%))
|
||||
);
|
||||
$background-color-step-400: var(
|
||||
--ion-color-step-400,
|
||||
var(--ion-background-color-step-400, mix($text-color-value, $background-color-value, 40%))
|
||||
);
|
||||
$background-color-step-450: var(
|
||||
--ion-color-step-450,
|
||||
var(--ion-background-color-step-450, mix($text-color-value, $background-color-value, 45%))
|
||||
);
|
||||
$background-color-step-500: var(
|
||||
--ion-color-step-500,
|
||||
var(--ion-background-color-step-500, mix($text-color-value, $background-color-value, 50%))
|
||||
);
|
||||
$background-color-step-550: var(
|
||||
--ion-color-step-550,
|
||||
var(--ion-background-color-step-550, mix($text-color-value, $background-color-value, 55%))
|
||||
);
|
||||
$background-color-step-600: var(
|
||||
--ion-color-step-600,
|
||||
var(--ion-background-color-step-600, mix($text-color-value, $background-color-value, 60%))
|
||||
);
|
||||
$background-color-step-650: var(
|
||||
--ion-color-step-650,
|
||||
var(--ion-background-color-step-650, mix($text-color-value, $background-color-value, 65%))
|
||||
);
|
||||
$background-color-step-700: var(
|
||||
--ion-color-step-700,
|
||||
var(--ion-background-color-step-700, mix($text-color-value, $background-color-value, 70%))
|
||||
);
|
||||
$background-color-step-750: var(
|
||||
--ion-color-step-750,
|
||||
var(--ion-background-color-step-750, mix($text-color-value, $background-color-value, 75%))
|
||||
);
|
||||
$background-color-step-800: var(
|
||||
--ion-color-step-800,
|
||||
var(--ion-background-color-step-800, mix($text-color-value, $background-color-value, 80%))
|
||||
);
|
||||
$background-color-step-850: var(
|
||||
--ion-color-step-850,
|
||||
var(--ion-background-color-step-850, mix($text-color-value, $background-color-value, 85%))
|
||||
);
|
||||
$background-color-step-900: var(
|
||||
--ion-color-step-900,
|
||||
var(--ion-background-color-step-900, mix($text-color-value, $background-color-value, 90%))
|
||||
);
|
||||
$background-color-step-950: var(
|
||||
--ion-color-step-950,
|
||||
var(--ion-background-color-step-950, mix($text-color-value, $background-color-value, 95%))
|
||||
);
|
||||
$text-color-step-50: var(
|
||||
--ion-color-step-950,
|
||||
var(--ion-text-color-step-50, mix($background-color-value, $text-color-value, 5%))
|
||||
);
|
||||
$text-color-step-100: var(
|
||||
--ion-color-step-900,
|
||||
var(--ion-text-color-step-100, mix($background-color-value, $text-color-value, 10%))
|
||||
);
|
||||
$text-color-step-150: var(
|
||||
--ion-color-step-850,
|
||||
var(--ion-text-color-step-150, mix($background-color-value, $text-color-value, 15%))
|
||||
);
|
||||
$text-color-step-200: var(
|
||||
--ion-color-step-800,
|
||||
var(--ion-text-color-step-200, mix($background-color-value, $text-color-value, 20%))
|
||||
);
|
||||
$text-color-step-250: var(
|
||||
--ion-color-step-750,
|
||||
var(--ion-text-color-step-250, mix($background-color-value, $text-color-value, 25%))
|
||||
);
|
||||
$text-color-step-300: var(
|
||||
--ion-color-step-700,
|
||||
var(--ion-text-color-step-300, mix($background-color-value, $text-color-value, 30%))
|
||||
);
|
||||
$text-color-step-350: var(
|
||||
--ion-color-step-650,
|
||||
var(--ion-text-color-step-350, mix($background-color-value, $text-color-value, 35%))
|
||||
);
|
||||
$text-color-step-400: var(
|
||||
--ion-color-step-600,
|
||||
var(--ion-text-color-step-400, mix($background-color-value, $text-color-value, 40%))
|
||||
);
|
||||
$text-color-step-450: var(
|
||||
--ion-color-step-550,
|
||||
var(--ion-text-color-step-450, mix($background-color-value, $text-color-value, 45%))
|
||||
);
|
||||
$text-color-step-500: var(
|
||||
--ion-color-step-500,
|
||||
var(--ion-text-color-step-500, mix($background-color-value, $text-color-value, 50%))
|
||||
);
|
||||
$text-color-step-550: var(
|
||||
--ion-color-step-450,
|
||||
var(--ion-text-color-step-550, mix($background-color-value, $text-color-value, 55%))
|
||||
);
|
||||
$text-color-step-600: var(
|
||||
--ion-color-step-400,
|
||||
var(--ion-text-color-step-600, mix($background-color-value, $text-color-value, 60%))
|
||||
);
|
||||
$text-color-step-650: var(
|
||||
--ion-color-step-350,
|
||||
var(--ion-text-color-step-650, mix($background-color-value, $text-color-value, 65%))
|
||||
);
|
||||
$text-color-step-700: var(
|
||||
--ion-color-step-300,
|
||||
var(--ion-text-color-step-700, mix($background-color-value, $text-color-value, 70%))
|
||||
);
|
||||
$text-color-step-750: var(
|
||||
--ion-color-step-250,
|
||||
var(--ion-text-color-step-750, mix($background-color-value, $text-color-value, 75%))
|
||||
);
|
||||
$text-color-step-800: var(
|
||||
--ion-color-step-200,
|
||||
var(--ion-text-color-step-800, mix($background-color-value, $text-color-value, 80%))
|
||||
);
|
||||
$text-color-step-850: var(
|
||||
--ion-color-step-150,
|
||||
var(--ion-text-color-step-850, mix($background-color-value, $text-color-value, 85%))
|
||||
);
|
||||
$text-color-step-900: var(
|
||||
--ion-color-step-100,
|
||||
var(--ion-text-color-step-900, mix($background-color-value, $text-color-value, 90%))
|
||||
);
|
||||
$text-color-step-950: var(
|
||||
--ion-color-step-50,
|
||||
var(--ion-text-color-step-950, mix($background-color-value, $text-color-value, 95%))
|
||||
);
|
||||
|
||||
// Default General Colors
|
||||
// --------------------------------------------------
|
||||
$placeholder-text-color: var(--ion-placeholder-color, $text-color-step-600);
|
||||
$placeholder-text-color: var(--ion-placeholder-color, $text-color-step-600);
|
||||
|
||||
@@ -238,6 +238,8 @@ export interface IonicConfig {
|
||||
scrollAssist?: boolean;
|
||||
hideCaretOnScroll?: boolean;
|
||||
|
||||
customTheme?: any;
|
||||
|
||||
// INTERNAL configs
|
||||
// TODO(FW-2832): types
|
||||
persistConfig?: boolean;
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
// The interfaces in this file are used to make sure our components
|
||||
// have the correct properties defined that are needed to pass to
|
||||
// the native HTML elements they render
|
||||
// the native HTML elements they render. The HTMLStencilElement interface
|
||||
// extends HTMLElement to provide Stencil-specific functionality like
|
||||
// componentOnReady() and proper children handling.
|
||||
|
||||
export interface HTMLStencilElement extends HTMLElement {
|
||||
componentOnReady(): Promise<this>;
|
||||
/**
|
||||
* Stencil patches `el.children` to behave like calling `el.children` on an
|
||||
* element with shadow DOM even though the component is not a shadow DOM element.
|
||||
* To allow components to work properly we need to access the original accessor
|
||||
* for this property which is `__children`.
|
||||
*/
|
||||
__children?: HTMLCollection;
|
||||
}
|
||||
|
||||
export interface AnchorInterface {
|
||||
href: string | undefined;
|
||||
|
||||
@@ -216,7 +216,7 @@ export const config: Config = {
|
||||
},
|
||||
{
|
||||
type: 'dist',
|
||||
esmLoaderPath: '../loader'
|
||||
esmLoaderPath: '../loader',
|
||||
},
|
||||
{
|
||||
type: 'dist-custom-elements',
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"core",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "8.6.5"
|
||||
"version": "8.7.2"
|
||||
}
|
||||
@@ -3,6 +3,46 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [8.7.2](https://github.com/ionic-team/ionic-framework/compare/v8.7.1...v8.7.2) (2025-08-06)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.7.1](https://github.com/ionic-team/ionic-framework/compare/v8.7.0...v8.7.1) (2025-07-31)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.7.0](https://github.com/ionic-team/ionic-framework/compare/v8.6.7...v8.7.0) (2025-07-30)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.7](https://github.com/ionic-team/ionic-framework/compare/v8.6.6...v8.6.7) (2025-07-30)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.6](https://github.com/ionic-team/ionic-framework/compare/v8.6.5...v8.6.6) (2025-07-30)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.5](https://github.com/ionic-team/ionic-framework/compare/v8.6.4...v8.6.5) (2025-07-16)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
55
packages/angular-server/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "8.6.5",
|
||||
"version": "8.7.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "8.6.5",
|
||||
"version": "8.7.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.5"
|
||||
"@ionic/core": "^8.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-eslint/eslint-plugin": "^16.0.0",
|
||||
@@ -1031,13 +1031,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "8.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.5.tgz",
|
||||
"integrity": "sha512-HN+6/Q67fEEpRA86QzXSrCahuHwaTPBsa910RuvY0pIYuoY4rpzGPU9ZOQ5q2wBsrln921rroEPU1xdpPKIH8Q==",
|
||||
"version": "8.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.2.tgz",
|
||||
"integrity": "sha512-u1xTJHltvcwiHkwGowQ/uywiUmvszNeR4mXT5JSp1RH6npe8e9doIY9KSzKRrzpWu1T+H0bUwGbhaYg/I/poRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
"@stencil/core": "4.36.2",
|
||||
"ionicons": "^8.0.13",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
@@ -1386,9 +1386,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "4.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.33.1.tgz",
|
||||
"integrity": "sha512-12k9xhAJBkpg598it+NRmaYIdEe6TSnsL/v6/KRXDcUyTK11VYwZQej2eHnMWtqot+znJ+GNTqb5YbiXi+5Low==",
|
||||
"version": "4.36.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.36.2.tgz",
|
||||
"integrity": "sha512-PRFSpxNzX9Oi0Wfh02asztN9Sgev/MacfZwmd+VVyE6ZxW+a/kEpAYZhzGAmE+/aKVOGYuug7R9SulanYGxiDQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
@@ -3818,11 +3818,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ionicons": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.4.0.tgz",
|
||||
"integrity": "sha512-ZK94MMqgzMCPPMhmk8Ouu6goyVHFIlw/ACP6oe3FrikcI0N7CX0xcwVaEbUc0G/v3W0shI93vo+9ve/KpvcNhQ==",
|
||||
"version": "8.0.13",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-8.0.13.tgz",
|
||||
"integrity": "sha512-2QQVyG2P4wszne79jemMjWYLp0DBbDhr4/yFroPCxvPP1wtMxgdIV3l5n+XZ5E9mgoXU79w7yTWpm2XzJsISxQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.0.3"
|
||||
"@stencil/core": "^4.35.3"
|
||||
}
|
||||
},
|
||||
"node_modules/is-array-buffer": {
|
||||
@@ -7305,12 +7306,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "8.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.6.5.tgz",
|
||||
"integrity": "sha512-HN+6/Q67fEEpRA86QzXSrCahuHwaTPBsa910RuvY0pIYuoY4rpzGPU9ZOQ5q2wBsrln921rroEPU1xdpPKIH8Q==",
|
||||
"version": "8.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.2.tgz",
|
||||
"integrity": "sha512-u1xTJHltvcwiHkwGowQ/uywiUmvszNeR4mXT5JSp1RH6npe8e9doIY9KSzKRrzpWu1T+H0bUwGbhaYg/I/poRA==",
|
||||
"requires": {
|
||||
"@stencil/core": "4.33.1",
|
||||
"ionicons": "^7.2.2",
|
||||
"@stencil/core": "4.36.2",
|
||||
"ionicons": "^8.0.13",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
@@ -7528,9 +7529,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"@stencil/core": {
|
||||
"version": "4.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.33.1.tgz",
|
||||
"integrity": "sha512-12k9xhAJBkpg598it+NRmaYIdEe6TSnsL/v6/KRXDcUyTK11VYwZQej2eHnMWtqot+znJ+GNTqb5YbiXi+5Low==",
|
||||
"version": "4.36.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.36.2.tgz",
|
||||
"integrity": "sha512-PRFSpxNzX9Oi0Wfh02asztN9Sgev/MacfZwmd+VVyE6ZxW+a/kEpAYZhzGAmE+/aKVOGYuug7R9SulanYGxiDQ==",
|
||||
"requires": {
|
||||
"@rollup/rollup-darwin-arm64": "4.34.9",
|
||||
"@rollup/rollup-darwin-x64": "4.34.9",
|
||||
@@ -9239,11 +9240,11 @@
|
||||
}
|
||||
},
|
||||
"ionicons": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.4.0.tgz",
|
||||
"integrity": "sha512-ZK94MMqgzMCPPMhmk8Ouu6goyVHFIlw/ACP6oe3FrikcI0N7CX0xcwVaEbUc0G/v3W0shI93vo+9ve/KpvcNhQ==",
|
||||
"version": "8.0.13",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-8.0.13.tgz",
|
||||
"integrity": "sha512-2QQVyG2P4wszne79jemMjWYLp0DBbDhr4/yFroPCxvPP1wtMxgdIV3l5n+XZ5E9mgoXU79w7yTWpm2XzJsISxQ==",
|
||||
"requires": {
|
||||
"@stencil/core": "^4.0.3"
|
||||
"@stencil/core": "^4.35.3"
|
||||
}
|
||||
},
|
||||
"is-array-buffer": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "8.6.5",
|
||||
"version": "8.7.2",
|
||||
"description": "Angular SSR Module for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -62,6 +62,6 @@
|
||||
},
|
||||
"prettier": "@ionic/prettier-config",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^8.6.5"
|
||||
"@ionic/core": "^8.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,54 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [8.7.2](https://github.com/ionic-team/ionic-framework/compare/v8.7.1...v8.7.2) (2025-08-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reorder-group:** add children fallback for framework compatibility ([#30593](https://github.com/ionic-team/ionic-framework/issues/30593)) ([1cd81b9](https://github.com/ionic-team/ionic-framework/commit/1cd81b92301378d55bce63a01dfcf95a91c92652)), closes [#30592](https://github.com/ionic-team/ionic-framework/issues/30592)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.7.1](https://github.com/ionic-team/ionic-framework/compare/v8.7.0...v8.7.1) (2025-07-31)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.7.0](https://github.com/ionic-team/ionic-framework/compare/v8.6.7...v8.7.0) (2025-07-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **deps:** update ionicons to v8 ([#30390](https://github.com/ionic-team/ionic-framework/issues/30390)) ([74cd71a](https://github.com/ionic-team/ionic-framework/commit/74cd71af243183aa738d11b280e155bdfd652126)), closes [#30445](https://github.com/ionic-team/ionic-framework/issues/30445)
|
||||
* **modal:** add IonModalToken for injecting modal elements in Angular components ([#30474](https://github.com/ionic-team/ionic-framework/issues/30474)) ([30d1910](https://github.com/ionic-team/ionic-framework/commit/30d1910d6ea5428b414d0e127e7681f59426c538))
|
||||
* **reorder-group:** add ionReorderStart, ionReorderMove, ionReorderEnd events ([#30471](https://github.com/ionic-team/ionic-framework/issues/30471)) ([b154f4e](https://github.com/ionic-team/ionic-framework/commit/b154f4ed095890f57ccab539fd9217976a5466e5)), closes [#23148](https://github.com/ionic-team/ionic-framework/issues/23148) [#27614](https://github.com/ionic-team/ionic-framework/issues/27614)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.7](https://github.com/ionic-team/ionic-framework/compare/v8.6.6...v8.6.7) (2025-07-30)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.6](https://github.com/ionic-team/ionic-framework/compare/v8.6.5...v8.6.6) (2025-07-30)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.6.5](https://github.com/ionic-team/ionic-framework/compare/v8.6.4...v8.6.5) (2025-07-16)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
export { MenuController } from './providers/menu-controller';
|
||||
export { DomController } from './providers/dom-controller';
|
||||
export { MenuController } from './providers/menu-controller';
|
||||
export { NavController } from './providers/nav-controller';
|
||||
|
||||
export { Config, ConfigToken } from './providers/config';
|
||||
export { Platform } from './providers/platform';
|
||||
|
||||
export { bindLifecycleEvents, AngularDelegate } from './providers/angular-delegate';
|
||||
export { AngularDelegate, bindLifecycleEvents, IonModalToken } from './providers/angular-delegate';
|
||||
|
||||
export type { IonicWindow } from './types/interfaces';
|
||||
export type { ViewWillEnter, ViewWillLeave, ViewDidEnter, ViewDidLeave } from './types/ionic-lifecycle-hooks';
|
||||
export type { ViewDidEnter, ViewDidLeave, ViewWillEnter, ViewWillLeave } from './types/ionic-lifecycle-hooks';
|
||||
|
||||
export { NavParams } from './directives/navigation/nav-params';
|
||||
|
||||
export { IonPopover } from './overlays/popover';
|
||||
export { IonModal } from './overlays/modal';
|
||||
export { IonPopover } from './overlays/popover';
|
||||
|
||||
export { IonRouterOutlet, provideComponentInputBinding } from './directives/navigation/router-outlet';
|
||||
|
||||
export * from './directives/control-value-accessors';
|
||||
export { IonBackButton } from './directives/navigation/back-button';
|
||||
export { IonNav } from './directives/navigation/nav';
|
||||
export {
|
||||
RouterLinkDelegateDirective,
|
||||
RouterLinkWithHrefDelegateDirective,
|
||||
} from './directives/navigation/router-link-delegate';
|
||||
export { IonNav } from './directives/navigation/nav';
|
||||
export { IonTabs } from './directives/navigation/tabs';
|
||||
export * from './directives/control-value-accessors';
|
||||
|
||||
export { ProxyCmp } from './utils/proxy';
|
||||
|
||||
export { IonicRouteStrategy } from './utils/routing';
|
||||
export { OverlayBaseController } from './utils/overlay';
|
||||
export { IonicRouteStrategy } from './utils/routing';
|
||||
|
||||
export { raf } from './utils/util';
|
||||
|
||||