Skip to content

Commit 7865386

Browse files
authored
chore: sync with main (#29184)
2 parents acc1042 + d9f97d0 commit 7865386

File tree

123 files changed

+1065
-645
lines changed

Some content is hidden

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

123 files changed

+1065
-645
lines changed

.github/COMPONENT-GUIDE.md

Lines changed: 87 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
- [Button States](#button-states)
44
* [Component Structure](#component-structure)
5-
* [Activated](#activated)
65
* [Disabled](#disabled)
76
* [Focused](#focused)
87
* [Hover](#hover)
8+
* [Activated](#activated)
99
* [Ripple Effect](#ripple-effect)
1010
* [Example Components](#example-components)
1111
* [References](#references)
@@ -21,7 +21,7 @@
2121

2222
## Button States
2323

24-
Any component that renders a button should have the following states: [`activated`](#activated), [`disabled`](#disabled), [`focused`](#focused), [`hover`](#hover). It should also have a [Ripple Effect](#ripple-effect) component added for Material Design.
24+
Any component that renders a button should have the following states: [`disabled`](#disabled), [`focused`](#focused), [`hover`](#hover), [`activated`](#activated). It should also have a [Ripple Effect](#ripple-effect) component added for Material Design.
2525

2626
### Component Structure
2727

@@ -89,78 +89,6 @@ The following styles should be set for the CSS to work properly. Note that the `
8989
```
9090

9191

92-
### Activated
93-
94-
The activated state should be enabled for elements with actions on "press". It usually changes the opacity or background of an element.
95-
96-
> [!WARNING]
97-
>`:active` should not be used here as it is not received on mobile Safari unless the element has a `touchstart` listener (which we don't necessarily want to have to add to every element). From [Safari Web Content Guide](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/AdjustingtheTextSize/AdjustingtheTextSize.html):
98-
>
99-
>> On iOS, mouse events are sent so quickly that the down or active state is never received. Therefore, the `:active` pseudo state is triggered only when there is a touch event set on the HTML element
100-
101-
> Make sure the component has the correct [component structure](#component-structure) before continuing.
102-
103-
#### JavaScript
104-
105-
The `ion-activatable` class needs to be set on an element that can be activated:
106-
107-
```jsx
108-
render() {
109-
return (
110-
<Host class='ion-activatable'>
111-
<slot></slot>
112-
</Host>
113-
);
114-
}
115-
```
116-
117-
Once that is done, the element will get the `ion-activated` class added on press after a small delay. This delay exists so that the active state does not show up when an activatable element is tapped while scrolling.
118-
119-
In addition to setting that class, `ion-activatable-instant` can be set in order to have an instant press with no delay:
120-
121-
```jsx
122-
<Host class='ion-activatable ion-activatable-instant'>
123-
```
124-
125-
#### CSS
126-
127-
```css
128-
/**
129-
* @prop --color-activated: Color of the button when pressed
130-
* @prop --background-activated: Background of the button when pressed
131-
* @prop --background-activated-opacity: Opacity of the background when pressed
132-
*/
133-
```
134-
135-
Style the `ion-activated` class based on the spec for that element:
136-
137-
```scss
138-
:host(.ion-activated) .button-native {
139-
color: var(--color-activated);
140-
141-
&::after {
142-
background: var(--background-activated);
143-
144-
opacity: var(--background-activated-opacity);
145-
}
146-
}
147-
```
148-
149-
> Order is important! Activated should be after the focused & hover states.
150-
151-
152-
#### User Customization
153-
154-
Setting the activated state on the `::after` pseudo-element allows the user to customize the activated state without knowing what the default opacity is set at. A user can customize in the following ways to have a solid red background on press, or they can leave out `--background-activated-opacity` and the button will use the default activated opacity to match the spec.
155-
156-
```css
157-
ion-button {
158-
--background-activated: red;
159-
--background-activated-opacity: 1;
160-
}
161-
```
162-
163-
16492
### Disabled
16593

16694
The disabled state should be set via prop on all components that render a native button. Setting a disabled state will change the opacity or color of the button and remove click events from firing.
@@ -197,7 +125,8 @@ render() {
197125
}
198126
```
199127

200-
> Note: if the class being added was for `ion-back-button` it would be `back-button-disabled`.
128+
> [!NOTE]
129+
> If the class being added was for `ion-back-button` it would be `back-button-disabled`.
201130
202131
#### CSS
203132

@@ -215,16 +144,18 @@ The following CSS _at the bare minimum_ should be added for the disabled class,
215144

216145
TODO
217146

147+
218148
### Focused
219149

220-
The focused state should be enabled for elements with actions when tabbed to via the keyboard. This will only work inside of an `ion-app`. It usually changes the opacity or background of an element.
150+
The focused state should be enabled for elements with actions when tabbed to via the keyboard. This will only work inside of an `ion-app`. It usually changes the opacity or background of an element.
221151

222152
> [!WARNING]
223153
> Do not use `:focus` because that will cause the focus to apply even when an element is tapped (because the element is now focused). Instead, we only want the focus state to be shown when it makes sense which is what the `.ion-focusable` utility mentioned below does.
224154
225155
> [!NOTE]
226156
> The [`:focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible) pseudo-class mostly does the same thing as our JavaScript-driven utility. However, it does not work well with Shadow DOM components as the element that receives focus is typically inside of the Shadow DOM, but we usually want to set the `:focus-visible` state on the host so we can style other parts of the component. Using other combinations such as `:has(:focus-visible)` does not work because `:has` does not pierce the Shadow DOM (as that would leak implementation details about the Shadow DOM contents). `:focus-within` does work with the Shadow DOM, but that has the same problem as `:focus` that was mentioned before. Unfortunately, a [`:focus-visible-within` pseudo-class does not exist yet](https://github.com/WICG/focus-visible/issues/151).
227157
158+
> [!IMPORTANT]
228159
> Make sure the component has the correct [component structure](#component-structure) before continuing.
229160
230161
#### JavaScript
@@ -234,7 +165,7 @@ The `ion-focusable` class needs to be set on an element that can be focused:
234165
```jsx
235166
render() {
236167
return (
237-
<Host class='ion-focusable'>
168+
<Host class="ion-focusable">
238169
<slot></slot>
239170
</Host>
240171
);
@@ -269,7 +200,8 @@ Style the `ion-focused` class based on the spec for that element:
269200
}
270201
```
271202

272-
> Order is important! Focused should be after the activated and before the hover state.
203+
> [!IMPORTANT]
204+
> Order matters! Focused should be **before** the activated and hover states.
273205
274206

275207
#### User Customization
@@ -286,11 +218,12 @@ ion-button {
286218

287219
### Hover
288220

289-
The [hover state](https://developer.mozilla.org/en-US/docs/Web/CSS/:hover) happens when a user moves their cursor on top of an element without pressing on it. It should not happen on mobile, only on desktop devices that support hover.
221+
The [hover state](https://developer.mozilla.org/en-US/docs/Web/CSS/:hover) happens when a user moves their cursor on top of an element without pressing on it. It should not happen on mobile, only on desktop devices that support hover.
290222

291223
> [!NOTE]
292224
> Some Android devices [incorrectly report their inputs](https://issues.chromium.org/issues/40855702) which can result in certain devices receiving hover events when they should not.
293225
226+
> [!IMPORTANT]
294227
> Make sure the component has the correct [component structure](#component-structure) before continuing.
295228
296229
#### CSS
@@ -321,7 +254,8 @@ Style the `:hover` based on the spec for that element:
321254
}
322255
```
323256

324-
> Order is important! Hover should be before the activated state.
257+
> [!IMPORTANT]
258+
> Order matters! Hover should be **before** the activated state.
325259
326260

327261
#### User Customization
@@ -336,6 +270,79 @@ ion-button {
336270
```
337271

338272

273+
### Activated
274+
275+
The activated state should be enabled for elements with actions on "press". It usually changes the opacity or background of an element.
276+
277+
> [!WARNING]
278+
>`:active` should not be used here as it is not received on mobile Safari unless the element has a `touchstart` listener (which we don't necessarily want to have to add to every element). From [Safari Web Content Guide](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/AdjustingtheTextSize/AdjustingtheTextSize.html):
279+
>
280+
>> On iOS, mouse events are sent so quickly that the down or active state is never received. Therefore, the `:active` pseudo state is triggered only when there is a touch event set on the HTML element
281+
282+
> [!IMPORTANT]
283+
> Make sure the component has the correct [component structure](#component-structure) before continuing.
284+
285+
#### JavaScript
286+
287+
The `ion-activatable` class needs to be set on an element that can be activated:
288+
289+
```jsx
290+
render() {
291+
return (
292+
<Host class="ion-activatable">
293+
<slot></slot>
294+
</Host>
295+
);
296+
}
297+
```
298+
299+
Once that is done, the element will get the `ion-activated` class added on press after a small delay. This delay exists so that the active state does not show up when an activatable element is tapped while scrolling.
300+
301+
In addition to setting that class, `ion-activatable-instant` can be set in order to have an instant press with no delay:
302+
303+
```jsx
304+
<Host class="ion-activatable ion-activatable-instant">
305+
```
306+
307+
#### CSS
308+
309+
```css
310+
/**
311+
* @prop --color-activated: Color of the button when pressed
312+
* @prop --background-activated: Background of the button when pressed
313+
* @prop --background-activated-opacity: Opacity of the background when pressed
314+
*/
315+
```
316+
317+
Style the `ion-activated` class based on the spec for that element:
318+
319+
```scss
320+
:host(.ion-activated) .button-native {
321+
color: var(--color-activated);
322+
323+
&::after {
324+
background: var(--background-activated);
325+
326+
opacity: var(--background-activated-opacity);
327+
}
328+
}
329+
```
330+
331+
> [!IMPORTANT]
332+
> Order matters! Activated should be **after** the focused & hover states.
333+
334+
#### User Customization
335+
336+
Setting the activated state on the `::after` pseudo-element allows the user to customize the activated state without knowing what the default opacity is set at. A user can customize in the following ways to have a solid red background on press, or they can leave out `--background-activated-opacity` and the button will use the default activated opacity to match the spec.
337+
338+
```css
339+
ion-button {
340+
--background-activated: red;
341+
--background-activated-opacity: 1;
342+
}
343+
```
344+
345+
339346
### Ripple Effect
340347

341348
The ripple effect should be added to elements for Material Design. It *requires* the `ion-activatable` class to be set on the parent element to work, and relative positioning on the parent.

.github/workflows/actions/test-core-screenshot/action.yml

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,13 @@ runs:
2121
name: ionic-core
2222
path: ./core
2323
filename: CoreBuild.zip
24-
- name: Install Playwright Dependencies
25-
run: npm install && npx playwright install && npx playwright install-deps
24+
- name: Install Dependencies
25+
run: npm install
2626
shell: bash
2727
working-directory: ./core
28-
- id: clean-component-name
29-
name: Clean Component Name
30-
# Remove `ion-` prefix from the `component` variable if it exists.
31-
run: |
32-
echo "component=$(echo ${{ inputs.component }} | sed 's/ion-//g')" >> $GITHUB_OUTPUT
33-
shell: bash
34-
- id: set-test-file
35-
name: Set Test File
36-
# Screenshots can be updated for all components or specified component(s).
37-
# If the `component` variable is set, then the test has the option to
38-
# - run all the file paths that are in a component folder.
39-
# -- For example: if the `component` value is "item", then the test will run all the file paths that are in the "src/components/item" folder.
40-
# -- For example: if the `component` value is "item chip", then the test will run all the file paths that are in the "src/components/item" and "src/components/chip" folders.
41-
run: |
42-
if [ -n "${{ steps.clean-component-name.outputs.component }}" ]; then
43-
echo "testFile=\$(echo '${{ steps.clean-component-name.outputs.component }}' | awk '{for(i=1;i<=NF;i++) \$i=\"src/components/\"\$i}1')" >> $GITHUB_OUTPUT
44-
else
45-
echo "testFile=$(echo '')" >> $GITHUB_OUTPUT
46-
fi
47-
shell: bash
4828
- name: Test
4929
if: inputs.update != 'true'
50-
run: npm run test.e2e ${{ steps.set-test-file.outputs.testFile }} -- --shard=${{ inputs.shard }}/${{ inputs.totalShards }}
30+
run: npm run test.e2e.docker.ci ${{ inputs.component }} -- --shard=${{ inputs.shard }}/${{ inputs.totalShards }}
5131
shell: bash
5232
working-directory: ./core
5333
- name: Test and Update
@@ -69,7 +49,7 @@ runs:
6949
# which is why we not using the upload-archive
7050
# composite step here.
7151
run: |
72-
npm run test.e2e ${{ steps.set-test-file.outputs.testFile }} -- --shard=${{ inputs.shard }}/${{ inputs.totalShards }} --update-snapshots
52+
npm run test.e2e.docker.ci ${{ inputs.component }} -- --shard=${{ inputs.shard }}/${{ inputs.totalShards }} --update-snapshots
7353
git add src/\*.png --force
7454
mkdir updated-screenshots
7555
cd ../ && rsync -R --progress $(git diff --name-only --cached) core/updated-screenshots

.github/workflows/actions/update-reference-screenshots/action.yml

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,17 @@ runs:
2525
# Configure user as Ionitron
2626
# and push only the changed .png snapshots
2727
# to the remote branch.
28-
# Screenshots are in .gitignore
28+
# Non-Linux screenshots are in .gitignore
2929
# to prevent local screenshots from getting
30-
# pushed to Git. As a result, we need --force
31-
# here so that CI generated screenshots can
32-
# get added to git. Screenshot ground truths
33-
# should only be added via this CI process.
30+
# pushed to Git.
3431
run: |
3532
git config user.name ionitron
3633
git config user.email [email protected]
3734
3835
# This adds an empty entry for new
3936
# screenshot files so we can track them with
4037
# git diff
41-
git add src/\*.png --force -N
38+
git add src/\*.png -N
4239
4340
if git diff --exit-code; then
4441
echo -e "\033[1;31m⚠️ Error: No new screenshots generated ⚠️\033[0m"
@@ -48,7 +45,7 @@ runs:
4845
else
4946
# This actually adds the contents
5047
# of the screenshots (including new ones)
51-
git add src/\*.png --force
48+
git add src/\*.png
5249
git commit -m "chore(): add updated snapshots"
5350
git push
5451
fi

.github/workflows/update-screenshots.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@ name: 'Update Reference Screenshots'
33
on:
44
workflow_dispatch:
55
inputs:
6+
# Screenshots can be updated for all components or specified component(s).
7+
# If the `component` variable is set, then the test has the option to
8+
# - run all the instances of the specified component(s) in the `src/components` folder
9+
# -- For example: if the `component` value is "item", then the following command will be: `npm run test.e2e item`
10+
# - run the specified file path
11+
# -- For example: if the `component` value is "src/components/item/test/basic", then the following command will be: `npm run test.e2e src/components/item/test/basic`
12+
# - run multiple specified components based on the space-separated value
13+
# -- For example: if the `component` value is "item basic", then the following command will be: `npm run test.e2e item basic`
14+
# -- For example: if the `component` value is "src/components/item/test/basic src/components/item/test/a11y", then the following command will be: `npm run test.e2e src/components/item/test/basic src/components/item/test/a11y`
15+
#
16+
# If the `component` variable is not set, then the test will run all the instances of the components in the `src/components` folder.
17+
# - For example: `npm run test.e2e`
18+
#
19+
# More common options can be found at the Playwright Command line page: https://playwright.dev/docs/test-cli
620
component:
721
description: 'What component(s) should be updated? (leave blank to update all or use a space-separated list for multiple components)'
822
required: false

.gitignore

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,16 @@ core/www/
6868
# playwright
6969
core/test-results/
7070
core/playwright-report/
71-
core/**/*-snapshots
71+
72+
# ground truths generated outside of docker should not be committed to the repo
73+
core/**/*-snapshots/*
74+
75+
# new ground truths should only be generated inside of docker which will result in -linux.png screenshots
76+
!core/**/*-snapshots/*-linux.png
77+
78+
# these files are going to be different per-developer environment so do not add them to the repo
79+
core/docker-display.txt
80+
core/docker-display-volume.txt
7281

7382
# angular
7483
packages/angular/css/

core/Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Get Playwright
2+
FROM mcr.microsoft.com/playwright:v1.42.1
3+
4+
# Set the working directory
5+
WORKDIR /ionic

0 commit comments

Comments
 (0)