-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Eric Lim <[email protected]>
- Loading branch information
1 parent
3259c60
commit 1d9fc35
Showing
9 changed files
with
339 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<div> | ||
{{#if (has-block "label")}} | ||
<PixLabel | ||
@for={{this.id}} | ||
@requiredLabel={{@requiredLabel}} | ||
@subLabel={{@subLabel}} | ||
@size={{@size}} | ||
@screenReaderOnly={{@screenReaderOnly}} | ||
> | ||
{{yield to="label"}} | ||
</PixLabel> | ||
{{/if}} | ||
<div> | ||
<input | ||
id={{this.id}} | ||
class="pix-code" | ||
style={{this.style}} | ||
value={{@value}} | ||
aria-required="{{if @requiredLabel true false}}" | ||
required={{if @requiredLabel true false}} | ||
maxlength={{this.length}} | ||
minlength={{this.length}} | ||
aria-describedby={{this.ariaDescribedBy}} | ||
...attributes | ||
/> | ||
|
||
{{#if this.hasErrorMessage}} | ||
<p id={{this.ariaDescribedBy}} class="pix-code__error-message">{{@errorMessage}}</p> | ||
{{/if}} | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { warn } from '@ember/debug'; | ||
import { htmlSafe } from '@ember/template'; | ||
|
||
import PixInputBase from './pix-input-base'; | ||
|
||
export default class PixCode extends PixInputBase { | ||
constructor() { | ||
super(...arguments); | ||
|
||
this.prefix = 'pix-code'; | ||
} | ||
|
||
get length() { | ||
warn('PixCode: @length is required.', !['', null, undefined].includes(this.args.length), { | ||
id: 'pix-ui.code.length.required', | ||
}); | ||
|
||
return this.args.length || 1; | ||
} | ||
|
||
get style() { | ||
return htmlSafe('--nb-characters:' + this.length); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
@use "pix-design-tokens/typography"; | ||
@use "component-state/form"; | ||
|
||
.pix-code { | ||
@extend %pix-monospace; | ||
@extend %pix-form-element-state; | ||
|
||
$space-between-dashes: 0.6ch; | ||
$total-width: calc(var(--nb-characters) * (1ch + $space-between-dashes)); | ||
|
||
display: inline-block; | ||
box-sizing: content-box; | ||
width: $total-width; | ||
height: 3.125rem; | ||
padding: 0 0.2ch 1px 0.5ch; | ||
color: var(--pix-neutral-900); | ||
font-size: 1.875rem; | ||
letter-spacing: $space-between-dashes; | ||
text-transform: uppercase; | ||
background: repeating-linear-gradient( | ||
90deg, | ||
var(--pix-neutral-500) 0, | ||
var(--pix-neutral-500) 1ch, | ||
transparent 0, | ||
transparent 1ch + $space-between-dashes | ||
) | ||
0 100% / calc($total-width - $space-between-dashes) 1px no-repeat; | ||
background-position-x: 0.5ch; | ||
background-position-y: 2.5ch; | ||
border: solid 1px var(--pix-neutral-500); | ||
border-radius: var(--pix-spacing-1x); | ||
outline: none; | ||
} | ||
|
||
.pix-code__error-message { | ||
@extend %pix-input-error-message; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from '@1024pix/pix-ui/components/pix-code'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { Meta, Story, ArgTypes } from '@storybook/blocks'; | ||
|
||
import * as ComponentStories from './pix-code.stories.js'; | ||
|
||
<Meta of={ComponentStories} /> | ||
|
||
# Pix Code | ||
|
||
Une `PixCode` est un champ permettant de renseigner un code. Le nombre de caractères attendu est visible par le nombre de traits dans le champ. | ||
|
||
|
||
## Without label | ||
|
||
<Story of={ComponentStories.WithoutLabel} height={200} /> | ||
|
||
## With label (and subLabel) | ||
|
||
<Story of={ComponentStories.WithLabel} height={200} /> | ||
|
||
## Error state (with error message) | ||
|
||
<Story of={ComponentStories.Error} height={200} /> | ||
|
||
## Usage | ||
|
||
```html | ||
<PixCode | ||
@length=6 | ||
@errorMessage="Une erreur est survenue" | ||
@validationStatus="error" | ||
> | ||
<:label>Code campagne</:label> | ||
</PixCode> | ||
``` | ||
|
||
## Arguments | ||
|
||
<ArgTypes story="Default" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { hbs } from 'ember-cli-htmlbars'; | ||
|
||
export default { | ||
title: 'Forms/Code', | ||
argTypes: { | ||
id: { | ||
name: 'id', | ||
description: 'Identifiant du champ permettant de lui attacher un label', | ||
type: { name: 'string', required: true }, | ||
}, | ||
length: { | ||
name: 'length', | ||
description: 'Correspond au nombre de caractères attendu dans le champ', | ||
type: { name: 'number', required: true }, | ||
table: { | ||
defaultValue: { summary: 1 }, | ||
}, | ||
}, | ||
validationStatus: { | ||
name: 'validationStatus', | ||
description: | ||
"Définit l'état du champ, neutre par défaut ou en erreur selon l'action de l'utilisateur", | ||
type: { name: 'string', required: false }, | ||
options: ['default', 'error'], | ||
control: { type: 'select' }, | ||
}, | ||
errorMessage: { | ||
name: 'errorMessage', | ||
description: | ||
"Affiche le message d'erreur donné. Doit s'accompagner du paramètre validationStatus en 'error'", | ||
type: { name: 'string', required: false }, | ||
}, | ||
label: { | ||
name: 'label', | ||
description: 'Le label du champ', | ||
type: { name: 'string', required: false }, | ||
table: { | ||
type: { summary: 'string' }, | ||
}, | ||
}, | ||
subLabel: { | ||
name: 'subLabel', | ||
description: 'Un descriptif complétant le label', | ||
type: { name: 'string', required: false }, | ||
}, | ||
requiredLabel: { | ||
name: 'requiredLabel', | ||
description: 'Label indiquant que le champ est requis.', | ||
type: { name: 'string', required: false }, | ||
table: { | ||
type: { summary: 'string' }, | ||
}, | ||
}, | ||
screenReaderOnly: { | ||
name: 'screenReaderOnly', | ||
description: "Permet de rendre le label lisible uniquement par les lecteurs d'écran", | ||
control: { type: 'boolean' }, | ||
type: { name: 'boolean', required: false }, | ||
table: { | ||
type: { summary: 'boolean' }, | ||
defaultValue: { summary: false }, | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
const Template = (args) => { | ||
return { | ||
template: hbs`<PixCode | ||
@length={{this.length}} | ||
@errorMessage={{this.errorMessage}} | ||
@validationStatus={{this.validationStatus}} | ||
@label={{this.label}} | ||
@requiredLabel={{this.requiredLabel}} | ||
@subLabel={{this.subLabel}} | ||
@screenReaderOnly={{this.screenReaderOnly}} | ||
> | ||
<:label>{{this.label}}</:label> | ||
</PixCode>`, | ||
context: args, | ||
}; | ||
}; | ||
|
||
export const WithoutLabel = Template.bind({}); | ||
WithoutLabel.args = { | ||
length: 10, | ||
}; | ||
|
||
export const WithLabel = Template.bind({}); | ||
WithLabel.args = { | ||
length: 8, | ||
label: 'Code de vérification', | ||
subLabel: 'Exemple: P-XXXXXXXX', | ||
}; | ||
|
||
export const Error = Template.bind({}); | ||
Error.args = { | ||
length: 6, | ||
label: 'Code de certification', | ||
errorMessage: "un message d'erreur", | ||
validationStatus: 'error', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { clickByName, render } from '@1024pix/ember-testing-library'; | ||
import { fillIn } from '@ember/test-helpers'; | ||
import { hbs } from 'ember-cli-htmlbars'; | ||
import { setupRenderingTest } from 'ember-qunit'; | ||
import { module, test } from 'qunit'; | ||
|
||
module('Integration | Component | PixCode', function (hooks) { | ||
setupRenderingTest(hooks); | ||
|
||
test('it renders the default PixCode', async function (assert) { | ||
// given | ||
const screen = await render( | ||
hbs`<PixCode @length={{10}}><:label>Code de vérification</:label></PixCode>`, | ||
); | ||
|
||
// when | ||
await fillIn(screen.getByRole('textbox', { name: 'Code de vérification' }), 'P-123VALID'); | ||
|
||
// then | ||
assert.contains('P-123VALID'); | ||
}); | ||
|
||
test('it should be possible to provide the expected number of length in the field', async function (assert) { | ||
// given | ||
const screen = await render( | ||
hbs`<PixCode @length={{14}}><:label>Code de vérification</:label></PixCode>`, | ||
); | ||
|
||
// when | ||
await fillIn(screen.getByRole('textbox', { name: 'Code de vérification' }), 'P-123VALID'); | ||
|
||
// then | ||
assert | ||
.dom(screen.getByRole('textbox', { name: 'Code de vérification' })) | ||
.hasAttribute('maxLength', '14'); | ||
assert | ||
.dom(screen.getByRole('textbox', { name: 'Code de vérification' })) | ||
.hasAttribute('minLength', '14'); | ||
}); | ||
|
||
test('it should be possible to give an extra information to input', async function (assert) { | ||
// given & when | ||
const screen = await render( | ||
hbs`<PixCode @length={{10}} @subLabel='exemple: P-1234'><:label>Code de vérification</:label></PixCode>`, | ||
); | ||
|
||
// then | ||
assert.ok(screen.getByRole('textbox', { name: 'Code de vérification exemple: P-1234' })); | ||
}); | ||
|
||
test('it should be possible to give an error message to input', async function (assert) { | ||
// given & when | ||
const screen = await render( | ||
hbs`<PixCode | ||
@errorMessage='Seul les caractères alphanumériques sont autorisés' | ||
@validationStatus='error' | ||
><:label>Code de vérification</:label></PixCode>`, | ||
); | ||
|
||
// then | ||
assert.dom(screen.getByText('Seul les caractères alphanumériques sont autorisés')).exists(); | ||
}); | ||
|
||
test('it should be possible to make "pixCode" required', async function (assert) { | ||
// given & when | ||
const screen = await render( | ||
hbs`<PixCode @length={{10}} @requiredLabel='Champ obligatoire'><:label>Code de vérification</:label></PixCode>`, | ||
); | ||
|
||
// then | ||
const requiredInput = screen.getByLabelText('Code de vérification *'); | ||
assert.dom(requiredInput).isRequired(); | ||
}); | ||
|
||
module('@length', function (hooks) { | ||
let warnStub; | ||
|
||
hooks.beforeEach(function () { | ||
warnStub = sinon.stub(console, 'warn'); | ||
}); | ||
|
||
hooks.afterEach(function () { | ||
warnStub.restore(); | ||
}); | ||
|
||
['', null, undefined].forEach(function (testCase) { | ||
test(`it should warn when @length="${testCase}"`, async function (assert) { | ||
// given | ||
this.set('length', testCase); | ||
const screen = await render( | ||
hbs`<PixCode @length={{this.length}} @requiredLabel='Champ obligatoire'><:label>Code de vérification</:label></PixCode>`, | ||
); | ||
|
||
|
||
assert.ok( | ||
warnStub.calledWithExactly( | ||
'WARNING: PixCode: @length is required.', | ||
), | ||
); | ||
}); | ||
}); | ||
}); | ||
|
||
}); |