@1024pix/pix-ui 17.2.1 → 18.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/auto-merge.yml +7 -10
- package/CHANGELOG.md +22 -0
- package/addon/components/pix-checkbox.hbs +1 -0
- package/addon/components/pix-modal.hbs +4 -5
- package/addon/components/pix-modal.js +6 -7
- package/addon/components/pix-sidebar.hbs +3 -4
- package/addon/components/pix-sidebar.js +6 -7
- package/addon/styles/_pix-modal.scss +6 -0
- package/app/modifiers/trap-focus.js +84 -34
- package/app/stories/pix-checkbox.stories.js +10 -0
- package/app/stories/pix-modal.stories.js +29 -19
- package/app/stories/pix-modal.stories.mdx +1 -1
- package/app/stories/pix-sidebar.stories.js +3 -3
- package/package.json +1 -1
|
@@ -4,9 +4,13 @@ on:
|
|
|
4
4
|
pull_request:
|
|
5
5
|
types:
|
|
6
6
|
- labeled
|
|
7
|
+
- unlabeled
|
|
7
8
|
check_suite:
|
|
8
9
|
types:
|
|
9
10
|
- completed
|
|
11
|
+
status:
|
|
12
|
+
types:
|
|
13
|
+
- success
|
|
10
14
|
|
|
11
15
|
permissions: write-all
|
|
12
16
|
|
|
@@ -14,13 +18,6 @@ jobs:
|
|
|
14
18
|
automerge:
|
|
15
19
|
runs-on: ubuntu-latest
|
|
16
20
|
steps:
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
GITHUB_TOKEN: "${{ github.token }}"
|
|
21
|
-
MERGE_LABELS: ":rocket: Ready to Merge"
|
|
22
|
-
MERGE_COMMIT_MESSAGE: "pull-request-title"
|
|
23
|
-
UPDATE_LABELS: ":rocket: Ready to Merge"
|
|
24
|
-
UPDATE_METHOD: "rebase"
|
|
25
|
-
MERGE_FORKS: "false"
|
|
26
|
-
LOG: "TRACE"
|
|
21
|
+
- uses: 1024pix/pix-actions/auto-merge@v0
|
|
22
|
+
with:
|
|
23
|
+
auto_merge_token: "${{ github.token }}"
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Pix-UI Changelog
|
|
2
2
|
|
|
3
|
+
## v18.0.2 (06/09/2022)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### :bug: Correction
|
|
7
|
+
- [#251](https://github.com/1024pix/pix-ui/pull/251) [BUGFIX] Évite de casser les tests d'acceptance des applis (PIX-5619)
|
|
8
|
+
|
|
9
|
+
### :coffee: Autre
|
|
10
|
+
- [#250](https://github.com/1024pix/pix-ui/pull/250) [CLEANUP] Utilise l'action commune d'automerge
|
|
11
|
+
|
|
12
|
+
## v18.0.1 (02/09/2022)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### :bug: Correction
|
|
16
|
+
- [#249](https://github.com/1024pix/pix-ui/pull/249) [BUGFIX] Permettre le controle des checkboxs
|
|
17
|
+
- [#248](https://github.com/1024pix/pix-ui/pull/248) [BUGFIX] Prévenir des erreurs à la première ouverture de la sidebar/modal
|
|
18
|
+
|
|
19
|
+
## v18.0.0 (01/09/2022)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### :bug: Correction
|
|
23
|
+
- [#246](https://github.com/1024pix/pix-ui/pull/246) [BUGFIX] Mettre le focus sur le premier élement où est utiliser le `trap-focus`.
|
|
24
|
+
|
|
3
25
|
## v17.2.1 (31/08/2022)
|
|
4
26
|
|
|
5
27
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div
|
|
2
|
-
class="pix-modal__overlay"
|
|
2
|
+
class="pix-modal__overlay {{unless @showModal ' pix-modal__overlay--hidden'}}"
|
|
3
3
|
{{on "click" this.closeAction}}
|
|
4
|
-
{{trap-focus}}
|
|
5
|
-
{{on-escape-action
|
|
4
|
+
{{trap-focus @showModal}}
|
|
5
|
+
{{on-escape-action @onCloseButtonClick}}
|
|
6
6
|
>
|
|
7
7
|
<div
|
|
8
8
|
class="pix-modal"
|
|
@@ -10,14 +10,13 @@
|
|
|
10
10
|
aria-labelledby="modal-title"
|
|
11
11
|
aria-describedby="modal-content"
|
|
12
12
|
aria-modal="true"
|
|
13
|
-
{{on "click" this.stopPropagation}}
|
|
14
13
|
...attributes
|
|
15
14
|
>
|
|
16
15
|
<header class="pix-modal__header">
|
|
17
16
|
<h1 id="modal-title" class="pix-modal__title">{{@title}}</h1>
|
|
18
17
|
<PixIconButton
|
|
19
18
|
@icon="xmark"
|
|
20
|
-
@triggerAction={{
|
|
19
|
+
@triggerAction={{@onCloseButtonClick}}
|
|
21
20
|
@ariaLabel="Fermer"
|
|
22
21
|
@size="small"
|
|
23
22
|
@withBackground={{true}}
|
|
@@ -11,14 +11,13 @@ export default class PixModal extends Component {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
@action
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
closeAction(event) {
|
|
15
|
+
if (this.args.onCloseButtonClick && this.isClickOnOverlay(event)) {
|
|
16
|
+
this.args.onCloseButtonClick(event);
|
|
17
|
+
}
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (this.args.onCloseButtonClick) {
|
|
21
|
-
this.args.onCloseButtonClick(params);
|
|
22
|
-
}
|
|
20
|
+
isClickOnOverlay(event) {
|
|
21
|
+
return event.target.classList.contains('pix-modal__overlay');
|
|
23
22
|
}
|
|
24
23
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div
|
|
2
2
|
class="pix-sidebar__overlay {{unless @showSidebar ' pix-sidebar__overlay--hidden'}}"
|
|
3
3
|
{{on "click" this.closeAction}}
|
|
4
|
-
{{trap-focus}}
|
|
5
|
-
{{on-escape-action
|
|
4
|
+
{{trap-focus @showSidebar}}
|
|
5
|
+
{{on-escape-action @onClose}}
|
|
6
6
|
>
|
|
7
7
|
<div
|
|
8
8
|
class="pix-sidebar {{unless @showSidebar ' pix-sidebar--hidden'}}"
|
|
@@ -10,14 +10,13 @@
|
|
|
10
10
|
aria-labelledby="sidebar-title"
|
|
11
11
|
aria-describedby="sidebar-content"
|
|
12
12
|
aria-modal="true"
|
|
13
|
-
{{on "click" this.stopPropagation}}
|
|
14
13
|
...attributes
|
|
15
14
|
>
|
|
16
15
|
<header class="pix-sidebar__header">
|
|
17
16
|
<h1 id="sidebar-title" class="pix-sidebar__title">{{@title}}</h1>
|
|
18
17
|
<PixIconButton
|
|
19
18
|
@icon="xmark"
|
|
20
|
-
@triggerAction={{
|
|
19
|
+
@triggerAction={{@onClose}}
|
|
21
20
|
@ariaLabel="Fermer"
|
|
22
21
|
@size="small"
|
|
23
22
|
@withBackground={{true}}
|
|
@@ -11,14 +11,13 @@ export default class PixSidebar extends Component {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
@action
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
closeAction(event) {
|
|
15
|
+
if (this.args.onClose && this.isClickOnOverlay(event)) {
|
|
16
|
+
this.args.onClose(event);
|
|
17
|
+
}
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (this.args.onClose) {
|
|
21
|
-
this.args.onClose(params);
|
|
22
|
-
}
|
|
20
|
+
isClickOnOverlay(event) {
|
|
21
|
+
return event.target.classList.contains('pix-sidebar__overlay');
|
|
23
22
|
}
|
|
24
23
|
}
|
|
@@ -1,45 +1,25 @@
|
|
|
1
1
|
import { modifier } from 'ember-modifier';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const [firstFocusableElement] = findFocusableElements(element);
|
|
5
|
-
|
|
6
|
-
firstFocusableElement.focus();
|
|
7
|
-
|
|
8
|
-
function handleKeyDown(event) {
|
|
9
|
-
const TAB_KEY = 9;
|
|
10
|
-
const focusableElements = findFocusableElements(element);
|
|
11
|
-
const [firstFocusableElement] = focusableElements;
|
|
12
|
-
const lastFocusableElement = focusableElements[focusableElements.length - 1];
|
|
13
|
-
|
|
14
|
-
if (event.keyCode !== TAB_KEY) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
3
|
+
let sourceActiveElement = null;
|
|
17
4
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
event.preventDefault();
|
|
21
|
-
lastFocusableElement.focus();
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function handleForwardTab() {
|
|
26
|
-
if (document.activeElement === lastFocusableElement) {
|
|
27
|
-
event.preventDefault();
|
|
28
|
-
firstFocusableElement.focus();
|
|
29
|
-
}
|
|
30
|
-
}
|
|
5
|
+
export default modifier(function trapFocus(element, [isOpen]) {
|
|
6
|
+
const [firstFocusableElement] = findFocusableElements(element);
|
|
31
7
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
8
|
+
if (isOpen) {
|
|
9
|
+
sourceActiveElement = document.activeElement;
|
|
10
|
+
focusElement(firstFocusableElement, element);
|
|
11
|
+
} else if (sourceActiveElement) {
|
|
12
|
+
focusElement(sourceActiveElement, element);
|
|
37
13
|
}
|
|
38
14
|
|
|
39
|
-
element.addEventListener('keydown',
|
|
15
|
+
element.addEventListener('keydown', (event) => {
|
|
16
|
+
handleKeyDown(event, element);
|
|
17
|
+
});
|
|
40
18
|
|
|
41
19
|
return () => {
|
|
42
|
-
element.removeEventListener('keydown',
|
|
20
|
+
element.removeEventListener('keydown', (event) => {
|
|
21
|
+
handleKeyDown(event, element);
|
|
22
|
+
});
|
|
43
23
|
};
|
|
44
24
|
});
|
|
45
25
|
|
|
@@ -50,3 +30,73 @@ function findFocusableElements(element) {
|
|
|
50
30
|
),
|
|
51
31
|
].filter((el) => !el.hasAttribute('disabled') && !el.getAttribute('aria-hidden'));
|
|
52
32
|
}
|
|
33
|
+
|
|
34
|
+
function focusElement(elementToFocus, element) {
|
|
35
|
+
let focusOnce = false;
|
|
36
|
+
|
|
37
|
+
const handleTransitionEnd = () => {
|
|
38
|
+
if (!focusOnce) {
|
|
39
|
+
elementToFocus.focus();
|
|
40
|
+
focusOnce = true;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
if (hasTransitionDuration(element)) {
|
|
45
|
+
element.addEventListener('transitionend', handleTransitionEnd);
|
|
46
|
+
} else if (hasAnimationDuration(element)) {
|
|
47
|
+
element.addEventListener('animationend', handleTransitionEnd);
|
|
48
|
+
} else {
|
|
49
|
+
elementToFocus.focus();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
if (hasTransitionDuration(element)) {
|
|
54
|
+
element.removeEventListener('transitionend', handleTransitionEnd);
|
|
55
|
+
} else if (hasAnimationDuration(element)) {
|
|
56
|
+
element.removeEventListener('animationend', handleTransitionEnd);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function hasTransitionDuration(element) {
|
|
62
|
+
return hasDurationByKey(element, 'transition-duration');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function hasAnimationDuration(element) {
|
|
66
|
+
return hasDurationByKey(element, 'animation-duration');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function hasDurationByKey(element, key) {
|
|
70
|
+
return !['', '0s'].includes(getComputedStyle(element, null).getPropertyValue(key));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function handleKeyDown(event, element) {
|
|
74
|
+
const TAB_KEY = 9;
|
|
75
|
+
const focusableElements = findFocusableElements(element);
|
|
76
|
+
const [firstFocusableElement] = focusableElements;
|
|
77
|
+
const lastFocusableElement = focusableElements[focusableElements.length - 1];
|
|
78
|
+
|
|
79
|
+
if (event.keyCode !== TAB_KEY) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const handleBackwardTab = () => {
|
|
84
|
+
if (document.activeElement === firstFocusableElement) {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
lastFocusableElement.focus();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const handleForwardTab = () => {
|
|
91
|
+
if (document.activeElement === lastFocusableElement) {
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
firstFocusableElement.focus();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
if (event.shiftKey) {
|
|
98
|
+
handleBackwardTab();
|
|
99
|
+
} else {
|
|
100
|
+
handleForwardTab();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -9,6 +9,7 @@ export const Template = (args) => {
|
|
|
9
9
|
@screenReaderOnly={{screenReaderOnly}}
|
|
10
10
|
@isIndeterminate={{isIndeterminate}}
|
|
11
11
|
@labelSize={{labelSize}}
|
|
12
|
+
@checked={{checked}}
|
|
12
13
|
/>
|
|
13
14
|
`,
|
|
14
15
|
context: args,
|
|
@@ -85,4 +86,13 @@ export const argTypes = {
|
|
|
85
86
|
options: ['small', 'default', 'large'],
|
|
86
87
|
},
|
|
87
88
|
},
|
|
89
|
+
checked: {
|
|
90
|
+
name: 'checked',
|
|
91
|
+
description: 'Permet de cocher la checkbox',
|
|
92
|
+
type: { name: 'boolean', required: false },
|
|
93
|
+
table: {
|
|
94
|
+
type: { summary: 'boolean' },
|
|
95
|
+
defaultValue: { summary: false },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
88
98
|
};
|
|
@@ -3,22 +3,23 @@ import { hbs } from 'ember-cli-htmlbars';
|
|
|
3
3
|
export const Template = (args) => {
|
|
4
4
|
return {
|
|
5
5
|
template: hbs`
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
6
|
+
<PixModal @showModal={{showModal}} @title={{this.title}} @onCloseButtonClick={{fn (mut showModal) (not showModal)}} >
|
|
7
|
+
<:content>
|
|
8
|
+
<p>
|
|
9
|
+
Une fenêtre modale est, dans une interface graphique, une fenêtre qui prend le contrôle total du clavier et
|
|
10
|
+
de l'écran. Elle est en général associée à une question à laquelle il est impératif que l'utilisateur
|
|
11
|
+
réponde avant de poursuivre, ou de modifier quoi que ce soit. La fenêtre modale a pour propos : d'obtenir
|
|
12
|
+
des informations de l'utilisateur (ces informations sont nécessaires pour réaliser une opération) ; de
|
|
13
|
+
fournir une information à l'utilisateur (ce dernier doit en prendre connaissance avant de pouvoir continuer
|
|
14
|
+
à utiliser l'application).
|
|
15
|
+
</p>
|
|
16
|
+
</:content>
|
|
17
|
+
<:footer>
|
|
18
|
+
<PixButton @backgroundColor="transparent-light" @isBorderVisible="true" @triggerAction={{fn (mut showModal) (not showModal)}}>Annuler</PixButton>
|
|
19
|
+
<PixButton @triggerAction={{fn (mut showModal) (not showModal)}}>Valider</PixButton>
|
|
20
|
+
</:footer>
|
|
21
|
+
</PixModal>
|
|
22
|
+
<PixButton @triggerAction={{fn (mut showModal) (not showModal)}}>Ouvrir la modale</PixButton>
|
|
22
23
|
`,
|
|
23
24
|
context: args,
|
|
24
25
|
};
|
|
@@ -26,10 +27,9 @@ export const Template = (args) => {
|
|
|
26
27
|
|
|
27
28
|
export const Default = Template.bind({});
|
|
28
29
|
Default.args = {
|
|
30
|
+
showModal: true,
|
|
29
31
|
title: "Qu'est-ce qu'une modale ?",
|
|
30
|
-
onCloseButtonClick: () => {
|
|
31
|
-
alert('Action : fermer modale');
|
|
32
|
-
},
|
|
32
|
+
onCloseButtonClick: () => {},
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export const argTypes = {
|
|
@@ -45,4 +45,14 @@ export const argTypes = {
|
|
|
45
45
|
type: { name: 'function', required: true },
|
|
46
46
|
defaultValue: null,
|
|
47
47
|
},
|
|
48
|
+
showModal: {
|
|
49
|
+
name: 'showModal',
|
|
50
|
+
description: "Gérer l'ouverture de la modale",
|
|
51
|
+
type: { name: 'boolean', required: false },
|
|
52
|
+
control: { type: 'boolean' },
|
|
53
|
+
table: {
|
|
54
|
+
type: { summary: 'boolean' },
|
|
55
|
+
defaultValue: { summary: false },
|
|
56
|
+
},
|
|
57
|
+
},
|
|
48
58
|
};
|
|
@@ -3,7 +3,6 @@ import { hbs } from 'ember-cli-htmlbars';
|
|
|
3
3
|
export const Template = (args) => {
|
|
4
4
|
return {
|
|
5
5
|
template: hbs`
|
|
6
|
-
<PixButton @triggerAction={{fn (mut showSidebar) (not showSidebar)}}>Ouvrir la sidebar</PixButton>
|
|
7
6
|
<PixSidebar @showSidebar={{showSidebar}} @title={{title}} @onClose={{fn (mut showSidebar) (not showSidebar)}}>
|
|
8
7
|
<:content>
|
|
9
8
|
<p>
|
|
@@ -13,11 +12,12 @@ export const Template = (args) => {
|
|
|
13
12
|
</:content>
|
|
14
13
|
<:footer>
|
|
15
14
|
<div style="display: flex; gap: 8px">
|
|
16
|
-
<PixButton @backgroundColor="transparent-light" @isBorderVisible="true">Annuler</PixButton>
|
|
17
|
-
<PixButton>Valider</PixButton>
|
|
15
|
+
<PixButton @backgroundColor="transparent-light" @isBorderVisible="true" @triggerAction={{fn (mut showSidebar) (not showSidebar)}}>Annuler</PixButton>
|
|
16
|
+
<PixButton @triggerAction={{fn (mut showSidebar) (not showSidebar)}}>Valider</PixButton>
|
|
18
17
|
</div>
|
|
19
18
|
</:footer>
|
|
20
19
|
</PixSidebar>
|
|
20
|
+
<PixButton @triggerAction={{fn (mut showSidebar) (not showSidebar)}}>Ouvrir la sidebar</PixButton>
|
|
21
21
|
`,
|
|
22
22
|
context: args,
|
|
23
23
|
};
|