@1024pix/pix-ui 11.1.0

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.
Files changed (196) hide show
  1. package/.buildpacks +2 -0
  2. package/.circleci/config.yml +22 -0
  3. package/.gitattributes +7 -0
  4. package/.github/workflows/auto-merge.yml +26 -0
  5. package/.github/workflows/deploy-storybook.yml +21 -0
  6. package/.github/workflows/npm-publish.yml +23 -0
  7. package/.github/workflows/on-dev-merge.yml +33 -0
  8. package/.nvmrc +1 -0
  9. package/.prettierignore +1 -0
  10. package/.prettierrc.json +12 -0
  11. package/.storybook/fonts.css +1 -0
  12. package/.storybook/main.js +10 -0
  13. package/.storybook/manager.js +6 -0
  14. package/.storybook/preview.js +37 -0
  15. package/.storybook/storybook-custom-theme.js +37 -0
  16. package/CHANGELOG.md +469 -0
  17. package/CNAME +1 -0
  18. package/LICENSE.md +9 -0
  19. package/README.md +58 -0
  20. package/addon/components/pix-background-header.hbs +7 -0
  21. package/addon/components/pix-background-header.js +5 -0
  22. package/addon/components/pix-banner.hbs +16 -0
  23. package/addon/components/pix-banner.js +43 -0
  24. package/addon/components/pix-block.hbs +5 -0
  25. package/addon/components/pix-block.js +11 -0
  26. package/addon/components/pix-button-base.js +27 -0
  27. package/addon/components/pix-button-link.hbs +16 -0
  28. package/addon/components/pix-button-link.js +10 -0
  29. package/addon/components/pix-button-upload.hbs +11 -0
  30. package/addon/components/pix-button-upload.js +20 -0
  31. package/addon/components/pix-button.hbs +43 -0
  32. package/addon/components/pix-button.js +54 -0
  33. package/addon/components/pix-collapsible.hbs +29 -0
  34. package/addon/components/pix-collapsible.js +27 -0
  35. package/addon/components/pix-filter-banner.hbs +28 -0
  36. package/addon/components/pix-filter-banner.js +13 -0
  37. package/addon/components/pix-icon-button.hbs +11 -0
  38. package/addon/components/pix-icon-button.js +33 -0
  39. package/addon/components/pix-input-code.hbs +24 -0
  40. package/addon/components/pix-input-code.js +133 -0
  41. package/addon/components/pix-input-password.hbs +43 -0
  42. package/addon/components/pix-input-password.js +34 -0
  43. package/addon/components/pix-input.hbs +30 -0
  44. package/addon/components/pix-input.js +26 -0
  45. package/addon/components/pix-message.hbs +8 -0
  46. package/addon/components/pix-message.js +30 -0
  47. package/addon/components/pix-multi-select.hbs +70 -0
  48. package/addon/components/pix-multi-select.js +162 -0
  49. package/addon/components/pix-progress-gauge.hbs +19 -0
  50. package/addon/components/pix-progress-gauge.js +29 -0
  51. package/addon/components/pix-radio-button.hbs +12 -0
  52. package/addon/components/pix-radio-button.js +5 -0
  53. package/addon/components/pix-return-to.hbs +15 -0
  54. package/addon/components/pix-return-to.js +20 -0
  55. package/addon/components/pix-select.hbs +55 -0
  56. package/addon/components/pix-select.js +58 -0
  57. package/addon/components/pix-selectable-tag.hbs +10 -0
  58. package/addon/components/pix-selectable-tag.js +13 -0
  59. package/addon/components/pix-stars.hbs +16 -0
  60. package/addon/components/pix-stars.js +27 -0
  61. package/addon/components/pix-tag.hbs +3 -0
  62. package/addon/components/pix-tag.js +11 -0
  63. package/addon/components/pix-textarea.hbs +21 -0
  64. package/addon/components/pix-textarea.js +17 -0
  65. package/addon/components/pix-tooltip-deprecated.hbs +18 -0
  66. package/addon/components/pix-tooltip-deprecated.js +26 -0
  67. package/addon/components/pix-tooltip.hbs +18 -0
  68. package/addon/components/pix-tooltip.js +17 -0
  69. package/addon/styles/_breakpoints.scss +17 -0
  70. package/addon/styles/_colors.scss +87 -0
  71. package/addon/styles/_fonts.scss +10 -0
  72. package/addon/styles/_form.scss +68 -0
  73. package/addon/styles/_pix-background-header.scss +20 -0
  74. package/addon/styles/_pix-banner.scss +67 -0
  75. package/addon/styles/_pix-block.scss +29 -0
  76. package/addon/styles/_pix-button-base.scss +137 -0
  77. package/addon/styles/_pix-button-link.scss +4 -0
  78. package/addon/styles/_pix-button-upload.scss +5 -0
  79. package/addon/styles/_pix-button.scss +40 -0
  80. package/addon/styles/_pix-collapsible.scss +82 -0
  81. package/addon/styles/_pix-filter-banner.scss +74 -0
  82. package/addon/styles/_pix-icon-button.scss +60 -0
  83. package/addon/styles/_pix-input-code.scss +71 -0
  84. package/addon/styles/_pix-input-password.scss +68 -0
  85. package/addon/styles/_pix-input.scss +93 -0
  86. package/addon/styles/_pix-message.scss +35 -0
  87. package/addon/styles/_pix-multi-select.scss +182 -0
  88. package/addon/styles/_pix-progress-gauge.scss +119 -0
  89. package/addon/styles/_pix-radio-button.scss +72 -0
  90. package/addon/styles/_pix-return-to.scss +64 -0
  91. package/addon/styles/_pix-select.scss +71 -0
  92. package/addon/styles/_pix-selectable-tag.scss +86 -0
  93. package/addon/styles/_pix-stars.scss +43 -0
  94. package/addon/styles/_pix-tag.scss +69 -0
  95. package/addon/styles/_pix-textarea.scss +39 -0
  96. package/addon/styles/_pix-tooltip.scss +196 -0
  97. package/addon/styles/_reset-css.scss +36 -0
  98. package/addon/styles/_spacing.scss +9 -0
  99. package/addon/styles/addon.scss +41 -0
  100. package/app/components/pix-background-header.js +1 -0
  101. package/app/components/pix-banner.js +1 -0
  102. package/app/components/pix-block.js +1 -0
  103. package/app/components/pix-button-link.js +1 -0
  104. package/app/components/pix-button-upload.js +1 -0
  105. package/app/components/pix-button.js +1 -0
  106. package/app/components/pix-collapsible.js +1 -0
  107. package/app/components/pix-filter-banner.js +1 -0
  108. package/app/components/pix-icon-button.js +1 -0
  109. package/app/components/pix-input-code.js +1 -0
  110. package/app/components/pix-input-password.js +1 -0
  111. package/app/components/pix-input.js +1 -0
  112. package/app/components/pix-message.js +1 -0
  113. package/app/components/pix-multi-select.js +1 -0
  114. package/app/components/pix-progress-gauge.js +1 -0
  115. package/app/components/pix-radio-button.js +1 -0
  116. package/app/components/pix-return-to.js +1 -0
  117. package/app/components/pix-select.js +1 -0
  118. package/app/components/pix-selectable-tag.js +1 -0
  119. package/app/components/pix-stars.js +1 -0
  120. package/app/components/pix-tag.js +1 -0
  121. package/app/components/pix-textarea.js +1 -0
  122. package/app/components/pix-tooltip-deprecated.js +1 -0
  123. package/app/components/pix-tooltip.js +1 -0
  124. package/app/stories/form.stories.js +91 -0
  125. package/app/stories/form.stories.mdx +16 -0
  126. package/app/stories/pix-background-header.stories.js +19 -0
  127. package/app/stories/pix-background-header.stories.mdx +36 -0
  128. package/app/stories/pix-banner.stories.js +89 -0
  129. package/app/stories/pix-banner.stories.mdx +107 -0
  130. package/app/stories/pix-block.stories.js +20 -0
  131. package/app/stories/pix-block.stories.mdx +44 -0
  132. package/app/stories/pix-button-link.stories.js +125 -0
  133. package/app/stories/pix-button-link.stories.mdx +57 -0
  134. package/app/stories/pix-button-upload.stories.js +85 -0
  135. package/app/stories/pix-button-upload.stories.mdx +39 -0
  136. package/app/stories/pix-button.stories.js +253 -0
  137. package/app/stories/pix-button.stories.mdx +99 -0
  138. package/app/stories/pix-collapsible.stories.js +56 -0
  139. package/app/stories/pix-collapsible.stories.mdx +39 -0
  140. package/app/stories/pix-filter-banner.stories.js +51 -0
  141. package/app/stories/pix-filter-banner.stories.mdx +33 -0
  142. package/app/stories/pix-icon-button.stories.js +95 -0
  143. package/app/stories/pix-icon-button.stories.mdx +90 -0
  144. package/app/stories/pix-input-code.stories.js +74 -0
  145. package/app/stories/pix-input-code.stories.mdx +46 -0
  146. package/app/stories/pix-input-password.stories.js +89 -0
  147. package/app/stories/pix-input-password.stories.mdx +69 -0
  148. package/app/stories/pix-input.stories.js +94 -0
  149. package/app/stories/pix-input.stories.mdx +57 -0
  150. package/app/stories/pix-message.stories.js +57 -0
  151. package/app/stories/pix-message.stories.mdx +71 -0
  152. package/app/stories/pix-multi-select.stories.js +199 -0
  153. package/app/stories/pix-multi-select.stories.mdx +55 -0
  154. package/app/stories/pix-progress-gauge.stories.js +78 -0
  155. package/app/stories/pix-progress-gauge.stories.mdx +43 -0
  156. package/app/stories/pix-radio-button.stories.js +71 -0
  157. package/app/stories/pix-radio-button.stories.mdx +49 -0
  158. package/app/stories/pix-return-to.stories.js +45 -0
  159. package/app/stories/pix-return-to.stories.mdx +41 -0
  160. package/app/stories/pix-select.stories.js +140 -0
  161. package/app/stories/pix-select.stories.mdx +57 -0
  162. package/app/stories/pix-selectable-tag.stories.js +91 -0
  163. package/app/stories/pix-selectable-tag.stories.mdx +55 -0
  164. package/app/stories/pix-stars.stories.js +43 -0
  165. package/app/stories/pix-stars.stories.mdx +35 -0
  166. package/app/stories/pix-tag.stories.js +56 -0
  167. package/app/stories/pix-tag.stories.mdx +46 -0
  168. package/app/stories/pix-textarea.stories.js +59 -0
  169. package/app/stories/pix-textarea.stories.mdx +36 -0
  170. package/app/stories/pix-tooltip-deprecated.stories.js +136 -0
  171. package/app/stories/pix-tooltip-deprecated.stories.mdx +143 -0
  172. package/app/stories/pix-tooltip.stories.js +157 -0
  173. package/app/stories/pix-tooltip.stories.mdx +183 -0
  174. package/app/styles/app.scss +0 -0
  175. package/config/environment.js +5 -0
  176. package/docs/architecture.stories.mdx +106 -0
  177. package/docs/assets/accessibility-storybook.png +0 -0
  178. package/docs/assets/screen-pix-storybook.png +0 -0
  179. package/docs/breaking-changes.stories.mdx +90 -0
  180. package/docs/changelog.stories.mdx +6 -0
  181. package/docs/create-component.stories.mdx +118 -0
  182. package/docs/design-system.stories.mdx +20 -0
  183. package/docs/good-practices-a11y.stories.mdx +48 -0
  184. package/docs/good-practices-design.stories.mdx +71 -0
  185. package/docs/good-practices-responsive.stories.mdx +51 -0
  186. package/docs/good-practices-style-css.stories.mdx +40 -0
  187. package/docs/good-practices-tests.stories.mdx +9 -0
  188. package/docs/make-a-release.stories.mdx +66 -0
  189. package/docs/pull_request_template.md +14 -0
  190. package/docs/storybook.stories.mdx +44 -0
  191. package/docs/use-component.stories.mdx +89 -0
  192. package/docs/use-install.stories.mdx +37 -0
  193. package/index.js +5 -0
  194. package/package.json +121 -0
  195. package/scalingo.json +17 -0
  196. package/servers.conf.erb +30 -0
@@ -0,0 +1,27 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ export default class PixButtonBase extends Component {
4
+ get shape() {
5
+ return this.args.shape || 'squircle';
6
+ }
7
+
8
+ get backgroundColor() {
9
+ return this.args.backgroundColor || 'blue';
10
+ }
11
+
12
+ get size() {
13
+ return this.args.size || 'big';
14
+ }
15
+
16
+ get baseClassNames() {
17
+ const classNames = [
18
+ 'pix-button',
19
+ `pix-button--shape-${this.shape}`,
20
+ `pix-button--size-${this.size}`,
21
+ `pix-button--background-${this.backgroundColor}`,
22
+ ];
23
+ this.args.isBorderVisible && classNames.push('pix-button--border');
24
+ this.args.isDisabled && classNames.push('pix-button--disabled');
25
+ return classNames;
26
+ }
27
+ }
@@ -0,0 +1,16 @@
1
+ {{#if @route}}
2
+ <LinkTo
3
+ @route={{@route}}
4
+ @models={{if @model (array @model) this.defaultModel}}
5
+ @disabled={{@isDisabled}}
6
+ @query={{if @query @query this.defaultParams}}
7
+ class={{this.className}}
8
+ ...attributes
9
+ >
10
+ {{yield}}
11
+ </LinkTo>
12
+ {{else}}
13
+ <a href={{@href}} class={{this.className}} ...attributes>
14
+ {{yield}}
15
+ </a>
16
+ {{/if}}
@@ -0,0 +1,10 @@
1
+ import PixButtonBase from './pix-button-base';
2
+
3
+ export default class PixButtonLink extends PixButtonBase {
4
+ defaultModel = [];
5
+ defaultParams = {};
6
+
7
+ get className() {
8
+ return super.baseClassNames.join(' ');
9
+ }
10
+ }
@@ -0,0 +1,11 @@
1
+ <label for={{@id}} class={{this.className}} role="button">
2
+ {{yield}}
3
+ </label>
4
+ <input
5
+ id={{@id}}
6
+ type="file"
7
+ class="pix-button-upload__input"
8
+ value={{this.files}}
9
+ {{on "change" this.handleChange}}
10
+ ...attributes
11
+ />
@@ -0,0 +1,20 @@
1
+ import PixButtonBase from './pix-button-base';
2
+ import { action } from '@ember/object';
3
+ import { tracked } from '@glimmer/tracking';
4
+
5
+ export default class PixButtonUpload extends PixButtonBase {
6
+ @tracked
7
+ files = [];
8
+
9
+ get className() {
10
+ return super.baseClassNames.join(' ');
11
+ }
12
+
13
+ @action
14
+ async handleChange(e) {
15
+ if (e.target?.files?.length) {
16
+ await this.args.onChange(e.target.files);
17
+ }
18
+ this.files = [];
19
+ }
20
+ }
@@ -0,0 +1,43 @@
1
+ {{#if @route}}
2
+ <LinkTo
3
+ @route={{@route}}
4
+ @models={{if @model (array @model) this.defaultModel}}
5
+ class={{this.className}}
6
+ ...attributes
7
+ >
8
+ {{yield}}
9
+ </LinkTo>
10
+ {{else}}
11
+ {{#if this.enableTriggerAction}}
12
+ <button
13
+ type={{this.type}}
14
+ class={{this.className}}
15
+ {{on "click" this.triggerAction}}
16
+ ...attributes
17
+ disabled={{this.isButtonLoadingOrDisabled}}
18
+ aria-disabled="{{this.ariaDisabled}}"
19
+ >
20
+ {{#if this.isLoading}}
21
+ <div class="loader loader--{{this.loadingColor}}">
22
+ <div class="bounce1"></div>
23
+ <div class="bounce2"></div>
24
+ <div class="bounce3"></div>
25
+ </div>
26
+ <span class="loader__not-visible-text">{{yield}}</span>
27
+ {{else}}
28
+ {{yield}}
29
+ {{/if}}
30
+ </button>
31
+ {{else}}
32
+ <button
33
+ type={{this.type}}
34
+ class={{this.className}}
35
+ ...attributes
36
+ disabled={{this.isButtonLoadingOrDisabled}}
37
+ aria-disabled="{{this.ariaDisabled}}"
38
+ >
39
+ {{yield}}
40
+ </button>
41
+ {{/if}}
42
+
43
+ {{/if}}
@@ -0,0 +1,54 @@
1
+ import { action } from '@ember/object';
2
+ import { tracked } from '@glimmer/tracking';
3
+
4
+ import PixButtonBase from './pix-button-base';
5
+
6
+ export default class PixButton extends PixButtonBase {
7
+ text = 'pix-button';
8
+ defaultModel = [];
9
+
10
+ @tracked isTriggering = false;
11
+
12
+ get isLoading() {
13
+ return this.args.isLoading || this.isTriggering;
14
+ }
15
+
16
+ get type() {
17
+ return this.args.type || 'button';
18
+ }
19
+
20
+ get loadingColor() {
21
+ return this.args.loadingColor || this.args['loading-color'] || 'white';
22
+ }
23
+
24
+ get isButtonLoadingOrDisabled() {
25
+ return this.isLoading || this.args.isDisabled;
26
+ }
27
+
28
+ get ariaDisabled() {
29
+ return this.isButtonLoadingOrDisabled;
30
+ }
31
+
32
+ get className() {
33
+ return super.baseClassNames.join(' ');
34
+ }
35
+
36
+ get enableTriggerAction() {
37
+ return !(this.type === 'submit' && !this.args.triggerAction);
38
+ }
39
+
40
+ @action
41
+ async triggerAction(params) {
42
+ try {
43
+ this.isTriggering = true;
44
+ await this.args.triggerAction(params);
45
+ this.isTriggering = false;
46
+ } catch (e) {
47
+ this.isTriggering = false;
48
+ if (!this.args.triggerAction) {
49
+ throw new Error('@triggerAction params is required for PixButton !');
50
+ }
51
+ throw new Error(e);
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,29 @@
1
+ <div class="pix-collapsible {{if this.isUnCollapsed "pix-collapsible--uncollapsed"}}">
2
+
3
+ <button
4
+ type="button"
5
+ {{on "click" this.toggleCollapsible}}
6
+ class="pix-collapsible__title {{if this.isUnCollapsed "pix-collapsible__title--uncollapsed"}}"
7
+ aria-controls={{this.contentId}}
8
+ aria-expanded={{if this.isUnCollapsed "true" "false"}}
9
+ ...attributes
10
+ >
11
+ <span>
12
+ {{#if @titleIcon}}
13
+ <FaIcon @icon={{@titleIcon}} class="pix-collapsible-title__icon" />
14
+ {{/if}}
15
+ {{this.title}}
16
+ </span>
17
+
18
+ <FaIcon @icon="{{if this.isCollapsed "plus" "minus"}}" class="pix-collapsible-title__icon" />
19
+ </button>
20
+
21
+ <div
22
+ id={{this.contentId}}
23
+ aria-hidden={{if this.isCollapsed "true" "false"}}
24
+ class="pix-collapsible__content
25
+ {{if this.isUnCollapsed " pix-collapsible__content--uncollapse"}}"
26
+ >
27
+ {{yield}}
28
+ </div>
29
+ </div>
@@ -0,0 +1,27 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { action } from '@ember/object';
4
+ import { guidFor } from '@ember/object/internals';
5
+
6
+ export default class PixCollapsible extends Component {
7
+ text = 'pix-collapsible';
8
+ contentId = 'pix-collapsible-' + guidFor(this);
9
+
10
+ @tracked isCollapsed = true;
11
+
12
+ get isUnCollapsed() {
13
+ return !this.isCollapsed;
14
+ }
15
+
16
+ get title() {
17
+ if (!this.args.title || !this.args.title.trim()) {
18
+ throw new Error('ERROR in PixCollapsible component, @title param is not provided');
19
+ }
20
+ return this.args.title;
21
+ }
22
+
23
+ @action
24
+ toggleCollapsible() {
25
+ this.isCollapsed = !this.isCollapsed;
26
+ }
27
+ }
@@ -0,0 +1,28 @@
1
+ <div class="pix-filter-banner" ...attributes>
2
+ <div class="pix-filter-banner__container-left">
3
+ {{#if this.displayTitle}}
4
+ <p class="pix-filter-banner__title">{{@title}}</p>
5
+ {{/if}}
6
+ <div class="pix-filter-banner__content">
7
+ {{yield}}
8
+ </div>
9
+ </div>
10
+ <div class="pix-filter-banner__container-right">
11
+ {{#if this.displayDetails}}
12
+ <p class="pix-filter-banner__details">{{@details}}</p>
13
+ {{/if}}
14
+ {{#if this.displayClearFilters}}
15
+ <div class="pix-filter-banner__button-container">
16
+ <PixButton
17
+ class="pix-filter-banner__button"
18
+ @shape="squircle"
19
+ @size="small"
20
+ @triggerAction={{@onClearFilters}}
21
+ >
22
+ <FaIcon class="pix-filter-banner-button__icon" @icon="trash-alt" @prefix="far" />
23
+ {{@clearFiltersLabel}}
24
+ </PixButton>
25
+ </div>
26
+ {{/if}}
27
+ </div>
28
+ </div>
@@ -0,0 +1,13 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ export default class PixFilterBanner extends Component {
4
+ get displayTitle() {
5
+ return Boolean(this.args.title);
6
+ }
7
+ get displayDetails() {
8
+ return Boolean(this.args.details);
9
+ }
10
+ get displayClearFilters() {
11
+ return Boolean(this.args.clearFiltersLabel);
12
+ }
13
+ }
@@ -0,0 +1,11 @@
1
+ <button
2
+ type="button"
3
+ aria-label={{this.ariaLabel}}
4
+ class="pix-icon-button pix-icon-button--{{this.size}}
5
+ pix-icon-button--{{this.color}}
6
+ {{if @withBackground " pix-icon-button--background"}}"
7
+ {{on "click" this.triggerAction}}
8
+ ...attributes
9
+ >
10
+ <FaIcon @icon={{this.icon}} @prefix={{@iconPrefix}} />
11
+ </button>
@@ -0,0 +1,33 @@
1
+ import Component from '@glimmer/component';
2
+ import { action } from '@ember/object';
3
+
4
+ export default class PixIconButton extends Component {
5
+ text = 'pix-icon-button';
6
+
7
+ get icon() {
8
+ const defaultIcon = 'plus';
9
+ return this.args.icon ? this.args.icon : defaultIcon;
10
+ }
11
+
12
+ get size() {
13
+ return this.args.size || 'big';
14
+ }
15
+
16
+ get color() {
17
+ return this.args.color || 'light-grey';
18
+ }
19
+
20
+ get ariaLabel() {
21
+ if (!this.args.ariaLabel || !this.args.ariaLabel.trim()) {
22
+ throw new Error('ERROR in PixIconButton component, @ariaLabel param is not provided.');
23
+ }
24
+ return this.args.ariaLabel;
25
+ }
26
+
27
+ @action
28
+ triggerAction() {
29
+ if (this.args.triggerAction) {
30
+ this.args.triggerAction();
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,24 @@
1
+ {{! template-lint-disable no-down-event-binding }}
2
+ <div class="pix-input-code">
3
+ <fieldset aria-describedby="pix-input-code__details-of-use">
4
+ <p id="pix-input-code__details-of-use">{{this.explanationOfUse}}</p>
5
+ <legend>{{this.legend}}</legend>
6
+ {{#each this.numberOfIterations as |i|}}
7
+ <input
8
+ ...attributes
9
+ id="code-input-{{i}}"
10
+ type="{{this.inputType}}"
11
+ aria-label="{{this.ariaLabel}} {{i}}"
12
+ class="pix-input-code__input"
13
+ min="1"
14
+ max="9"
15
+ autocomplete="off"
16
+ placeholder="{{this.placeholder}}"
17
+ {{on "keydown" this.handleArrowUpOrDown}}
18
+ {{on "keyup" (fn this.handleKeyUp i)}}
19
+ {{on "input" (fn this.handleCodeInput i)}}
20
+ {{on "paste" (fn this.handlePaste i)}}
21
+ />
22
+ {{/each}}
23
+ </fieldset>
24
+ </div>
@@ -0,0 +1,133 @@
1
+ import Component from '@glimmer/component';
2
+ import { action } from '@ember/object';
3
+
4
+ const ERROR_MESSAGE =
5
+ 'ERROR in PixInputCode component, you must provide an @ariaLabel and a @legend';
6
+ const NAVIGATION_EXPLANATION =
7
+ 'Pour se déplacer de champ en champ vous pouvez utiliser la tabulation ou bien les flèches gauche et droite de votre clavier.';
8
+ const NUMBER_INPUT_EXPLANATION =
9
+ 'Pour remplir un champ vous pouvez utiliser des chiffres de 1 à 9 ou bien les flèches haut et bas de votre clavier pour incrémenter de 1 la valeur du champ.';
10
+ const TEXT_INPUT_EXPLANATION =
11
+ 'Pour remplir un champ vous pouvez utiliser les caractères alphanumériques de votre clavier.';
12
+
13
+ export default class PixInputCode extends Component {
14
+ moveFocus = true;
15
+ numInputs = this.args.numInputs || 6;
16
+
17
+ get numberOfIterations() {
18
+ return Array.from({ length: this.numInputs }, (_, i) => i + 1);
19
+ }
20
+
21
+ get ariaLabel() {
22
+ if (!this.args.ariaLabel) {
23
+ throw new Error(ERROR_MESSAGE);
24
+ }
25
+ return this.args.ariaLabel;
26
+ }
27
+
28
+ get explanationOfUse() {
29
+ const defaultFillingExplanation =
30
+ this.inputType === 'number' ? NUMBER_INPUT_EXPLANATION : TEXT_INPUT_EXPLANATION;
31
+ const defaultExplanationOfUseMessage = NAVIGATION_EXPLANATION + ' ' + defaultFillingExplanation;
32
+
33
+ return this.args.explanationOfUse ? this.args.explanationOfUse : defaultExplanationOfUseMessage;
34
+ }
35
+
36
+ get legend() {
37
+ if (!this.args.legend) {
38
+ throw new Error(ERROR_MESSAGE);
39
+ }
40
+ return this.args.legend;
41
+ }
42
+
43
+ get inputType() {
44
+ return this.args.inputType || 'number';
45
+ }
46
+
47
+ get placeholder() {
48
+ return this.inputType === 'number' ? '0' : null;
49
+ }
50
+
51
+ focusElement(index) {
52
+ const nextElem = document.getElementById(`code-input-${index}`);
53
+ nextElem && nextElem.focus();
54
+ }
55
+
56
+ validateInput(elem) {
57
+ if (this.inputType === 'number') {
58
+ const startsWithDigit = elem.value.match(/^[1-9]/);
59
+ if (!startsWithDigit) elem.value = '';
60
+ }
61
+ if (elem.value.length > 1) elem.value = [...elem.value][0];
62
+ }
63
+
64
+ triggerAction() {
65
+ if (!this.args.onAllInputsFilled) return;
66
+
67
+ const code = [];
68
+ for (let i = 1; i <= this.numInputs; i++) {
69
+ const elem = document.getElementById(`code-input-${i}`);
70
+ elem.value.length > 0 && code.push(elem.value);
71
+ }
72
+ if (code.length === this.numInputs) {
73
+ this.args.onAllInputsFilled(code.join(''));
74
+ }
75
+ }
76
+
77
+ @action
78
+ handleCodeInput(index) {
79
+ const elem = document.getElementById(`code-input-${index}`);
80
+ this.validateInput(elem);
81
+ if (elem.value.length > 0) {
82
+ elem.classList.add('filled');
83
+ this.moveFocus && this.focusElement(index + 1);
84
+ this.triggerAction();
85
+ } else {
86
+ elem.classList.remove('filled');
87
+ }
88
+ }
89
+
90
+ @action
91
+ handleKeyUp(index, event) {
92
+ const eventMap = {
93
+ Backspace: index - 1,
94
+ ArrowLeft: index - 1,
95
+ ArrowRight: index + 1,
96
+ };
97
+ const newIndex = eventMap[event.code || event.key];
98
+ this.focusElement(newIndex);
99
+ }
100
+
101
+ @action
102
+ handleArrowUpOrDown(event) {
103
+ this.moveFocus = true;
104
+ const eventCode = event.code || event.key;
105
+ if (['ArrowUp', 'ArrowDown'].includes(eventCode)) this.moveFocus = false;
106
+ }
107
+
108
+ @action
109
+ handlePaste(index, event) {
110
+ event.preventDefault();
111
+ event.stopPropagation();
112
+
113
+ const pastedText = (event.clipboardData || window.clipboardData).getData('text');
114
+ const pastedTextWithOnlyValidCharacters = _extractValidCharacters(pastedText);
115
+
116
+ pastedTextWithOnlyValidCharacters.forEach((char) => {
117
+ const input = document.getElementById(`code-input-${index}`);
118
+ if (input) {
119
+ this.focusElement(index);
120
+ input.value = char;
121
+ input.classList.add('filled');
122
+ index++;
123
+ }
124
+ });
125
+ this.focusElement(index);
126
+ this.triggerAction();
127
+ }
128
+ }
129
+
130
+ function _extractValidCharacters(pastedText) {
131
+ const alphanumericCharacters = /^[a-zA-Z0-9_]*$/;
132
+ return [...pastedText].filter((char) => alphanumericCharacters.test(char));
133
+ }
@@ -0,0 +1,43 @@
1
+ <div class="pix-input-password">
2
+ {{#if this.label}}
3
+ <label for={{this.id}} class="pix-input__label">{{this.label}}</label>
4
+ {{/if}}
5
+ {{#if @information}}
6
+ <label for={{this.id}} class="pix-input__information">{{@information}}</label>
7
+ {{/if}}
8
+ <div
9
+ class="pix-input-password__container
10
+ {{if @errorMessage "pix-input-password__error-container"}}
11
+ {{if @prefix "pix-input-password__with-prefix"}}"
12
+ >
13
+
14
+ {{#if @prefix}}
15
+ <span class="pix-input-password__prefix">{{@prefix}}</span>
16
+ {{/if}}
17
+
18
+ <input
19
+ id={{this.id}}
20
+ type={{if this.isPasswordVisible "text" "password"}}
21
+ value={{@value}}
22
+ aria-label={{this.ariaLabel}}
23
+ {{on "change" this.onChange}}
24
+ ...attributes
25
+ />
26
+
27
+ <PixIconButton
28
+ class="pix-input-password__button {{if @errorMessage " pix-input-password__error-button"}}"
29
+ @icon={{if this.isPasswordVisible "eye" "eye-slash"}}
30
+ @ariaLabel={{if this.isPasswordVisible "Masquer le mot de passe" "Afficher le mot de passe"}}
31
+ @triggerAction={{this.togglePasswordVisibility}}
32
+ @size="small"
33
+ />
34
+
35
+ {{#if @errorMessage}}
36
+ <FaIcon @icon="times" class="pix-input-password__error-icon" />
37
+ {{/if}}
38
+ </div>
39
+
40
+ {{#if @errorMessage}}
41
+ <label for={{this.id}} class="pix-input__error-message">{{@errorMessage}}</label>
42
+ {{/if}}
43
+ </div>
@@ -0,0 +1,34 @@
1
+ import PixInput from './pix-input';
2
+ import { action } from '@ember/object';
3
+ import { tracked } from '@glimmer/tracking';
4
+
5
+ const ERROR_MESSAGE =
6
+ 'ERROR in PixInputPassword component, you must provide @label or @ariaLabel params';
7
+
8
+ export default class PixInputPassword extends PixInput {
9
+ @tracked isPasswordVisible = false;
10
+
11
+ get label() {
12
+ if (!this.args.label && !this.args.ariaLabel) {
13
+ throw new Error(ERROR_MESSAGE);
14
+ }
15
+ return this.args.label;
16
+ }
17
+
18
+ get ariaLabel() {
19
+ if (!this.args.label && !this.args.ariaLabel) {
20
+ throw new Error(ERROR_MESSAGE);
21
+ }
22
+ return this.args.label ? null : this.args.ariaLabel;
23
+ }
24
+
25
+ @action
26
+ togglePasswordVisibility() {
27
+ this.isPasswordVisible = !this.isPasswordVisible;
28
+ }
29
+
30
+ @action
31
+ onChange() {
32
+ if (typeof this.args.onChange === 'function') this.args.onChange();
33
+ }
34
+ }
@@ -0,0 +1,30 @@
1
+ <div class="pix-input">
2
+ {{#if @label}}
3
+ <label for={{this.id}} class="pix-input__label">{{@label}}</label>
4
+ {{/if}}
5
+ {{#if @information}}
6
+ <label for={{this.id}} class="pix-input__information">{{@information}}</label>
7
+ {{/if}}
8
+
9
+ <div class="pix-input__container">
10
+ <input
11
+ id={{this.id}}
12
+ class={{this.className}}
13
+ value={{@value}}
14
+ {{on "change" this.onChange}}
15
+ ...attributes
16
+ />
17
+
18
+ {{#if @errorMessage}}
19
+ <FaIcon @icon="times" class="pix-input__error-icon" />
20
+ {{/if}}
21
+
22
+ {{#if @icon}}
23
+ <FaIcon @icon={{@icon}} class="pix-input__icon {{if @isIconLeft "pix-input__icon--left"}}" />
24
+ {{/if}}
25
+ </div>
26
+
27
+ {{#if @errorMessage}}
28
+ <label for={{this.id}} class="pix-input__error-message">{{@errorMessage}}</label>
29
+ {{/if}}
30
+ </div>
@@ -0,0 +1,26 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ import { action } from '@ember/object';
4
+ export default class PixInput extends Component {
5
+ text = 'pix-input';
6
+
7
+ get id() {
8
+ if (!this.args.id || !this.args.id.toString().trim()) {
9
+ throw new Error('ERROR in PixInput component, @id param is not provided');
10
+ }
11
+ return this.args.id;
12
+ }
13
+
14
+ get className() {
15
+ const classNames = [];
16
+ this.args.errorMessage && classNames.push('pix-input__input--error');
17
+ this.args.icon && classNames.push('pix-input__input--icon');
18
+ this.args.isIconLeft && classNames.push('pix-input__input--icon-left');
19
+ return classNames.join(' ');
20
+ }
21
+
22
+ @action
23
+ onChange() {
24
+ if (typeof this.args.onChange === 'function') this.args.onChange();
25
+ }
26
+ }
@@ -0,0 +1,8 @@
1
+ <p class="pix-message {{concat "pix-message--" this.type}}" ...attributes>
2
+ {{#if @withIcon}}
3
+ <FaIcon @icon={{this.iconClass}} />
4
+ {{/if}}
5
+ <span class="pix-message__content">
6
+ {{yield}}
7
+ </span>
8
+ </p>
@@ -0,0 +1,30 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ const TYPE_INFO = 'info';
4
+ const TYPE_SUCCESS = 'success';
5
+ const TYPE_WARNING = 'warning';
6
+ const TYPE_ALERT = 'alert';
7
+ const TYPE_ERROR = 'error';
8
+
9
+ export default class PixMessage extends Component {
10
+ get type() {
11
+ const correctTypes = [TYPE_INFO, TYPE_SUCCESS, TYPE_WARNING, TYPE_ALERT, TYPE_ERROR];
12
+ if (this.args.type === 'alert') {
13
+ console.warn(
14
+ 'ERROR in PixMessage component, "alert" type is deprecated. Use "error" type instead.'
15
+ );
16
+ }
17
+ return correctTypes.includes(this.args.type) ? this.args.type : 'info';
18
+ }
19
+
20
+ get iconClass() {
21
+ const classes = {
22
+ [TYPE_INFO]: 'info-circle',
23
+ [TYPE_SUCCESS]: 'check-circle',
24
+ [TYPE_WARNING]: 'exclamation-circle',
25
+ [TYPE_ALERT]: 'exclamation-triangle',
26
+ [TYPE_ERROR]: 'exclamation-triangle',
27
+ };
28
+ return classes[this.type];
29
+ }
30
+ }