@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.
- package/.buildpacks +2 -0
- package/.circleci/config.yml +22 -0
- package/.gitattributes +7 -0
- package/.github/workflows/auto-merge.yml +26 -0
- package/.github/workflows/deploy-storybook.yml +21 -0
- package/.github/workflows/npm-publish.yml +23 -0
- package/.github/workflows/on-dev-merge.yml +33 -0
- package/.nvmrc +1 -0
- package/.prettierignore +1 -0
- package/.prettierrc.json +12 -0
- package/.storybook/fonts.css +1 -0
- package/.storybook/main.js +10 -0
- package/.storybook/manager.js +6 -0
- package/.storybook/preview.js +37 -0
- package/.storybook/storybook-custom-theme.js +37 -0
- package/CHANGELOG.md +469 -0
- package/CNAME +1 -0
- package/LICENSE.md +9 -0
- package/README.md +58 -0
- package/addon/components/pix-background-header.hbs +7 -0
- package/addon/components/pix-background-header.js +5 -0
- package/addon/components/pix-banner.hbs +16 -0
- package/addon/components/pix-banner.js +43 -0
- package/addon/components/pix-block.hbs +5 -0
- package/addon/components/pix-block.js +11 -0
- package/addon/components/pix-button-base.js +27 -0
- package/addon/components/pix-button-link.hbs +16 -0
- package/addon/components/pix-button-link.js +10 -0
- package/addon/components/pix-button-upload.hbs +11 -0
- package/addon/components/pix-button-upload.js +20 -0
- package/addon/components/pix-button.hbs +43 -0
- package/addon/components/pix-button.js +54 -0
- package/addon/components/pix-collapsible.hbs +29 -0
- package/addon/components/pix-collapsible.js +27 -0
- package/addon/components/pix-filter-banner.hbs +28 -0
- package/addon/components/pix-filter-banner.js +13 -0
- package/addon/components/pix-icon-button.hbs +11 -0
- package/addon/components/pix-icon-button.js +33 -0
- package/addon/components/pix-input-code.hbs +24 -0
- package/addon/components/pix-input-code.js +133 -0
- package/addon/components/pix-input-password.hbs +43 -0
- package/addon/components/pix-input-password.js +34 -0
- package/addon/components/pix-input.hbs +30 -0
- package/addon/components/pix-input.js +26 -0
- package/addon/components/pix-message.hbs +8 -0
- package/addon/components/pix-message.js +30 -0
- package/addon/components/pix-multi-select.hbs +70 -0
- package/addon/components/pix-multi-select.js +162 -0
- package/addon/components/pix-progress-gauge.hbs +19 -0
- package/addon/components/pix-progress-gauge.js +29 -0
- package/addon/components/pix-radio-button.hbs +12 -0
- package/addon/components/pix-radio-button.js +5 -0
- package/addon/components/pix-return-to.hbs +15 -0
- package/addon/components/pix-return-to.js +20 -0
- package/addon/components/pix-select.hbs +55 -0
- package/addon/components/pix-select.js +58 -0
- package/addon/components/pix-selectable-tag.hbs +10 -0
- package/addon/components/pix-selectable-tag.js +13 -0
- package/addon/components/pix-stars.hbs +16 -0
- package/addon/components/pix-stars.js +27 -0
- package/addon/components/pix-tag.hbs +3 -0
- package/addon/components/pix-tag.js +11 -0
- package/addon/components/pix-textarea.hbs +21 -0
- package/addon/components/pix-textarea.js +17 -0
- package/addon/components/pix-tooltip-deprecated.hbs +18 -0
- package/addon/components/pix-tooltip-deprecated.js +26 -0
- package/addon/components/pix-tooltip.hbs +18 -0
- package/addon/components/pix-tooltip.js +17 -0
- package/addon/styles/_breakpoints.scss +17 -0
- package/addon/styles/_colors.scss +87 -0
- package/addon/styles/_fonts.scss +10 -0
- package/addon/styles/_form.scss +68 -0
- package/addon/styles/_pix-background-header.scss +20 -0
- package/addon/styles/_pix-banner.scss +67 -0
- package/addon/styles/_pix-block.scss +29 -0
- package/addon/styles/_pix-button-base.scss +137 -0
- package/addon/styles/_pix-button-link.scss +4 -0
- package/addon/styles/_pix-button-upload.scss +5 -0
- package/addon/styles/_pix-button.scss +40 -0
- package/addon/styles/_pix-collapsible.scss +82 -0
- package/addon/styles/_pix-filter-banner.scss +74 -0
- package/addon/styles/_pix-icon-button.scss +60 -0
- package/addon/styles/_pix-input-code.scss +71 -0
- package/addon/styles/_pix-input-password.scss +68 -0
- package/addon/styles/_pix-input.scss +93 -0
- package/addon/styles/_pix-message.scss +35 -0
- package/addon/styles/_pix-multi-select.scss +182 -0
- package/addon/styles/_pix-progress-gauge.scss +119 -0
- package/addon/styles/_pix-radio-button.scss +72 -0
- package/addon/styles/_pix-return-to.scss +64 -0
- package/addon/styles/_pix-select.scss +71 -0
- package/addon/styles/_pix-selectable-tag.scss +86 -0
- package/addon/styles/_pix-stars.scss +43 -0
- package/addon/styles/_pix-tag.scss +69 -0
- package/addon/styles/_pix-textarea.scss +39 -0
- package/addon/styles/_pix-tooltip.scss +196 -0
- package/addon/styles/_reset-css.scss +36 -0
- package/addon/styles/_spacing.scss +9 -0
- package/addon/styles/addon.scss +41 -0
- package/app/components/pix-background-header.js +1 -0
- package/app/components/pix-banner.js +1 -0
- package/app/components/pix-block.js +1 -0
- package/app/components/pix-button-link.js +1 -0
- package/app/components/pix-button-upload.js +1 -0
- package/app/components/pix-button.js +1 -0
- package/app/components/pix-collapsible.js +1 -0
- package/app/components/pix-filter-banner.js +1 -0
- package/app/components/pix-icon-button.js +1 -0
- package/app/components/pix-input-code.js +1 -0
- package/app/components/pix-input-password.js +1 -0
- package/app/components/pix-input.js +1 -0
- package/app/components/pix-message.js +1 -0
- package/app/components/pix-multi-select.js +1 -0
- package/app/components/pix-progress-gauge.js +1 -0
- package/app/components/pix-radio-button.js +1 -0
- package/app/components/pix-return-to.js +1 -0
- package/app/components/pix-select.js +1 -0
- package/app/components/pix-selectable-tag.js +1 -0
- package/app/components/pix-stars.js +1 -0
- package/app/components/pix-tag.js +1 -0
- package/app/components/pix-textarea.js +1 -0
- package/app/components/pix-tooltip-deprecated.js +1 -0
- package/app/components/pix-tooltip.js +1 -0
- package/app/stories/form.stories.js +91 -0
- package/app/stories/form.stories.mdx +16 -0
- package/app/stories/pix-background-header.stories.js +19 -0
- package/app/stories/pix-background-header.stories.mdx +36 -0
- package/app/stories/pix-banner.stories.js +89 -0
- package/app/stories/pix-banner.stories.mdx +107 -0
- package/app/stories/pix-block.stories.js +20 -0
- package/app/stories/pix-block.stories.mdx +44 -0
- package/app/stories/pix-button-link.stories.js +125 -0
- package/app/stories/pix-button-link.stories.mdx +57 -0
- package/app/stories/pix-button-upload.stories.js +85 -0
- package/app/stories/pix-button-upload.stories.mdx +39 -0
- package/app/stories/pix-button.stories.js +253 -0
- package/app/stories/pix-button.stories.mdx +99 -0
- package/app/stories/pix-collapsible.stories.js +56 -0
- package/app/stories/pix-collapsible.stories.mdx +39 -0
- package/app/stories/pix-filter-banner.stories.js +51 -0
- package/app/stories/pix-filter-banner.stories.mdx +33 -0
- package/app/stories/pix-icon-button.stories.js +95 -0
- package/app/stories/pix-icon-button.stories.mdx +90 -0
- package/app/stories/pix-input-code.stories.js +74 -0
- package/app/stories/pix-input-code.stories.mdx +46 -0
- package/app/stories/pix-input-password.stories.js +89 -0
- package/app/stories/pix-input-password.stories.mdx +69 -0
- package/app/stories/pix-input.stories.js +94 -0
- package/app/stories/pix-input.stories.mdx +57 -0
- package/app/stories/pix-message.stories.js +57 -0
- package/app/stories/pix-message.stories.mdx +71 -0
- package/app/stories/pix-multi-select.stories.js +199 -0
- package/app/stories/pix-multi-select.stories.mdx +55 -0
- package/app/stories/pix-progress-gauge.stories.js +78 -0
- package/app/stories/pix-progress-gauge.stories.mdx +43 -0
- package/app/stories/pix-radio-button.stories.js +71 -0
- package/app/stories/pix-radio-button.stories.mdx +49 -0
- package/app/stories/pix-return-to.stories.js +45 -0
- package/app/stories/pix-return-to.stories.mdx +41 -0
- package/app/stories/pix-select.stories.js +140 -0
- package/app/stories/pix-select.stories.mdx +57 -0
- package/app/stories/pix-selectable-tag.stories.js +91 -0
- package/app/stories/pix-selectable-tag.stories.mdx +55 -0
- package/app/stories/pix-stars.stories.js +43 -0
- package/app/stories/pix-stars.stories.mdx +35 -0
- package/app/stories/pix-tag.stories.js +56 -0
- package/app/stories/pix-tag.stories.mdx +46 -0
- package/app/stories/pix-textarea.stories.js +59 -0
- package/app/stories/pix-textarea.stories.mdx +36 -0
- package/app/stories/pix-tooltip-deprecated.stories.js +136 -0
- package/app/stories/pix-tooltip-deprecated.stories.mdx +143 -0
- package/app/stories/pix-tooltip.stories.js +157 -0
- package/app/stories/pix-tooltip.stories.mdx +183 -0
- package/app/styles/app.scss +0 -0
- package/config/environment.js +5 -0
- package/docs/architecture.stories.mdx +106 -0
- package/docs/assets/accessibility-storybook.png +0 -0
- package/docs/assets/screen-pix-storybook.png +0 -0
- package/docs/breaking-changes.stories.mdx +90 -0
- package/docs/changelog.stories.mdx +6 -0
- package/docs/create-component.stories.mdx +118 -0
- package/docs/design-system.stories.mdx +20 -0
- package/docs/good-practices-a11y.stories.mdx +48 -0
- package/docs/good-practices-design.stories.mdx +71 -0
- package/docs/good-practices-responsive.stories.mdx +51 -0
- package/docs/good-practices-style-css.stories.mdx +40 -0
- package/docs/good-practices-tests.stories.mdx +9 -0
- package/docs/make-a-release.stories.mdx +66 -0
- package/docs/pull_request_template.md +14 -0
- package/docs/storybook.stories.mdx +44 -0
- package/docs/use-component.stories.mdx +89 -0
- package/docs/use-install.stories.mdx +37 -0
- package/index.js +5 -0
- package/package.json +121 -0
- package/scalingo.json +17 -0
- 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,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,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
|
+
}
|