@1024pix/pix-ui 17.2.0 → 18.0.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Pix-UI Changelog
2
2
 
3
+ ## v18.0.1 (02/09/2022)
4
+
5
+
6
+ ### :bug: Correction
7
+ - [#249](https://github.com/1024pix/pix-ui/pull/249) [BUGFIX] Permettre le controle des checkboxs
8
+ - [#248](https://github.com/1024pix/pix-ui/pull/248) [BUGFIX] Prévenir des erreurs à la première ouverture de la sidebar/modal
9
+
10
+ ## v18.0.0 (01/09/2022)
11
+
12
+
13
+ ### :bug: Correction
14
+ - [#246](https://github.com/1024pix/pix-ui/pull/246) [BUGFIX] Mettre le focus sur le premier élement où est utiliser le `trap-focus`.
15
+
16
+ ## v17.2.1 (31/08/2022)
17
+
18
+
19
+ ### :rocket: Amélioration
20
+ - [#247](https://github.com/1024pix/pix-ui/pull/247) [FEATURE] Amélioration couleurs `PixIconButton`
21
+
3
22
  ## v17.2.0 (24/08/2022)
4
23
 
5
24
 
@@ -9,6 +9,7 @@
9
9
  id={{this.id}}
10
10
  type="checkbox"
11
11
  class="pix-checkbox__input {{if @isIndeterminate ' pix-checkbox__input--indeterminate'}}"
12
+ checked={{@checked}}
12
13
  ...attributes
13
14
  />
14
15
  </div>
@@ -1,7 +1,7 @@
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}}
4
+ {{trap-focus @showModal}}
5
5
  {{on-escape-action this.closeAction}}
6
6
  >
7
7
  <div
@@ -1,7 +1,7 @@
1
1
  <div
2
2
  class="pix-sidebar__overlay {{unless @showSidebar ' pix-sidebar__overlay--hidden'}}"
3
3
  {{on "click" this.closeAction}}
4
- {{trap-focus}}
4
+ {{trap-focus @showSidebar}}
5
5
  {{on-escape-action this.closeAction}}
6
6
  >
7
7
  <div
@@ -32,9 +32,9 @@
32
32
  .pix-icon-button {
33
33
  background-color: $pix-primary-5;
34
34
  color: $pix-primary-70;
35
- &:hover,
36
- &:focus,
37
- &:active {
35
+ &:hover:enabled,
36
+ &:focus:enabled,
37
+ &:active:enabled {
38
38
  background-color: $pix-primary-10;
39
39
  color: $pix-primary-70;
40
40
  }
@@ -47,9 +47,9 @@
47
47
  .pix-icon-button {
48
48
  background-color: $pix-warning-5;
49
49
  color: $pix-warning-70;
50
- &:hover,
51
- &:focus,
52
- &:active {
50
+ &:hover:enabled,
51
+ &:focus:enabled,
52
+ &:active:enabled {
53
53
  background-color: $pix-warning-10;
54
54
  color: $pix-warning-70;
55
55
  }
@@ -62,9 +62,9 @@
62
62
  .pix-icon-button {
63
63
  background-color: $pix-error-5;
64
64
  color: $pix-error-70;
65
- &:hover,
66
- &:focus,
67
- &:active {
65
+ &:hover:enabled,
66
+ &:focus:enabled,
67
+ &:active:enabled {
68
68
  background-color: $pix-error-10;
69
69
  color: $pix-error-70;
70
70
  }
@@ -10,35 +10,36 @@
10
10
  align-items: center;
11
11
  justify-content: center;
12
12
  background-color: transparent;
13
+ color: $pix-neutral-60;
13
14
 
14
15
  &:disabled {
15
16
  opacity: 0.5;
16
- cursor: default;
17
+ cursor: not-allowed;
17
18
  }
18
19
 
19
- &:hover,
20
- &:focus {
21
- transition: background-color 0.2s ease;
22
- background-color: $pix-neutral-15;
23
- &:disabled {
24
- background-color: transparent;
25
- }
20
+ &:hover:enabled {
21
+ background-color: $pix-neutral-20;
22
+ box-shadow: none;
23
+ border: 0;
24
+ color: $pix-neutral-60;
26
25
  }
27
26
 
28
- &:active {
29
- transition: background-color 0.2s ease;
30
- background-color: $pix-neutral-20;
27
+ &:focus:enabled {
28
+ background-color: $pix-neutral-60;
29
+ box-shadow: 0 0 0 2px $pix-neutral-60;
30
+ border: 2px solid $pix-neutral-0;
31
+ color: $pix-neutral-0;
32
+ }
33
+
34
+ &:active:enabled {
35
+ background-color: $pix-neutral-22;
36
+ box-shadow: none;
37
+ border: 0;
38
+ color: $pix-neutral-60;
31
39
  }
32
40
 
33
41
  &--background {
34
42
  background-color: $pix-neutral-10;
35
- &:hover,
36
- &:focus,
37
- &:active {
38
- &:disabled {
39
- background-color: $pix-neutral-15;
40
- }
41
- }
42
43
  }
43
44
 
44
45
  &--small {
@@ -52,12 +53,4 @@
52
53
  height: 38px;
53
54
  font-size: 1.25rem;
54
55
  }
55
-
56
- &--dark-grey {
57
- color: $pix-neutral-60;
58
- }
59
-
60
- &--light-grey {
61
- color: $pix-neutral-60;
62
- }
63
56
  }
@@ -7,6 +7,12 @@
7
7
  right: 0;
8
8
  top: 0;
9
9
  z-index: 1000;
10
+ transition: all .3s ease-in-out;
11
+
12
+ &--hidden {
13
+ visibility: hidden;
14
+ opacity: 0;
15
+ }
10
16
  }
11
17
 
12
18
  $modal-padding: 24px;
@@ -1,45 +1,25 @@
1
1
  import { modifier } from 'ember-modifier';
2
2
 
3
- export default modifier(function trapFocus(element) {
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
- function handleBackwardTab() {
19
- if (document.activeElement === firstFocusableElement) {
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
- if (event.shiftKey) {
33
- handleBackwardTab();
34
- } else {
35
- handleForwardTab();
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', handleKeyDown);
15
+ element.addEventListener('keydown', (event) => {
16
+ handleKeyDown(event, element);
17
+ });
40
18
 
41
19
  return () => {
42
- element.removeEventListener('keydown', handleKeyDown);
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
  };
@@ -11,31 +11,42 @@ const Template = (args) => {
11
11
  @triggerAction={{triggerAction}}
12
12
  @withBackground={{withBackground}}
13
13
  @size={{size}}
14
+ disabled={{disabled}}
15
+ aria-disabled={{disabled}}
14
16
  />
15
17
  `,
16
18
  context: args,
17
19
  };
18
20
  };
19
21
 
22
+ const triggerAction = () => Promise.resolve();
23
+
20
24
  export const Default = Template.bind({});
21
25
  Default.args = {
22
26
  ariaLabel: 'Action du bouton',
23
27
  icon: 'xmark',
24
- triggerAction: () => {
25
- return new Promise().resolves();
26
- },
28
+ triggerAction,
27
29
  };
28
30
 
29
31
  export const small = Template.bind({});
30
32
  small.args = {
31
33
  ...Default.args,
32
34
  size: 'small',
35
+ triggerAction,
33
36
  };
34
37
 
35
38
  export const withBackground = Template.bind({});
36
39
  withBackground.args = {
37
40
  ...Default.args,
38
41
  withBackground: true,
42
+ triggerAction,
43
+ };
44
+
45
+ export const disabled = Template.bind({});
46
+ disabled.args = {
47
+ ...Default.args,
48
+ disabled: true,
49
+ triggerAction,
39
50
  };
40
51
 
41
52
  export const argTypes = {
@@ -3,8 +3,8 @@ import centered from '@storybook/addon-centered/ember';
3
3
  import * as stories from './pix-icon-button.stories.js';
4
4
 
5
5
  <Meta
6
- title='Basics/Icon button'
7
- component='PixIconButton'
6
+ title="Basics/Icon button"
7
+ component="PixIconButton"
8
8
  decorators={[centered]}
9
9
  argTypes={stories.argTypes}
10
10
  />
@@ -37,6 +37,14 @@ Le bouton avec le fond grisé.
37
37
  <Story name="With Background" story={stories.withBackground} height={60} />
38
38
  </Canvas>
39
39
 
40
+ ## Disabled
41
+
42
+ Exemple avec le bouton disabled
43
+
44
+ <Canvas>
45
+ <Story name="Disabled" story={stories.disabled} height={60} />
46
+ </Canvas>
47
+
40
48
  ## Accessibilité / aria-label
41
49
 
42
50
  L'attribut `aria-label` étant indispensable pour l'accessibilité de ce composant, la propriété `ariaLabel` a été ajouté.
@@ -48,42 +56,42 @@ L'attribut `aria-label` étant indispensable pour l'accessibilité de ce composa
48
56
  ## Usage
49
57
 
50
58
  Par défaut
59
+
51
60
  ```html
52
- <PixIconButton
53
- @ariaLabel="L'action du bouton"
54
- @icon="icon"
55
- @triggerAction={{triggerAction}}
56
- />
61
+ <PixIconButton @ariaLabel="L'action du bouton" @icon="icon" @triggerAction="{{triggerAction}}" />
57
62
  ```
58
63
 
59
64
  Bouton de fermeture
65
+
60
66
  ```html
61
67
  <PixIconButton
62
- @ariaLabel="L'action du bouton"
63
- @icon="times"
64
- @triggerAction={{triggerAction}}
65
- @withBackground={{true}}
68
+ @ariaLabel="L'action du bouton"
69
+ @icon="times"
70
+ @triggerAction="{{triggerAction}}"
71
+ @withBackground="{{true}}"
66
72
  />
67
73
  ```
68
74
 
69
75
  Bouton d'action
76
+
70
77
  ```html
71
78
  <PixIconButton
72
- @ariaLabel="L'action du bouton"
73
- @icon="arrow-left"
74
- @triggerAction={{triggerAction}}
75
- @size="small"
76
- @withBackground={{true}}
79
+ @ariaLabel="L'action du bouton"
80
+ @icon="arrow-left"
81
+ @triggerAction="{{triggerAction}}"
82
+ @size="small"
83
+ @withBackground="{{true}}"
77
84
  />
78
85
  ```
79
86
 
80
87
  État disabled
88
+
81
89
  ```html
82
90
  <PixIconButton
83
- @ariaLabel="L'action du bouton"
84
- @icon="xmark"
85
- disabled={{true}}
86
- aria-disabled={{true}}
91
+ @ariaLabel="L'action du bouton"
92
+ @icon="xmark"
93
+ disabled="{{true}}"
94
+ aria-disabled="{{true}}"
87
95
  />
88
96
  ```
89
97
 
@@ -3,22 +3,23 @@ import { hbs } from 'ember-cli-htmlbars';
3
3
  export const Template = (args) => {
4
4
  return {
5
5
  template: hbs`
6
- <PixModal @title={{this.title}} @onCloseButtonClick={{onCloseButtonClick}}>
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">Annuler</PixButton>
19
- <PixButton>Valider</PixButton>
20
- </:footer>
21
- </PixModal>
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
  };
@@ -57,4 +57,4 @@ Ce composant possède deux `yield` :
57
57
 
58
58
  ## Arguments
59
59
 
60
- <ArgsTable story="PixModal" />
60
+ <ArgsTable story="Default" />
@@ -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>
@@ -18,6 +17,7 @@ export const Template = (args) => {
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1024pix/pix-ui",
3
- "version": "17.2.0",
3
+ "version": "18.0.1",
4
4
  "description": "Pix-UI is the implementation of Pix design principles and guidelines for its products.",
5
5
  "keywords": [
6
6
  "ember-addon"