Skip to content

Commit cbe8f5c

Browse files
committed
Add Glint support to the {{au-date-input}} modifier
1 parent c1a2384 commit cbe8f5c

File tree

7 files changed

+153
-91
lines changed

7 files changed

+153
-91
lines changed

addon/modifiers/au-date-input.js addon/modifiers/au-date-input.ts

+38-20
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,52 @@
1+
import { assert } from '@ember/debug';
2+
import { registerDestructor } from '@ember/destroyable';
3+
import type Owner from '@ember/owner';
4+
import Modifier, { type ArgsFor } from 'ember-modifier';
5+
import Inputmask from 'inputmask';
16
import {
27
toIsoDateString,
38
isIsoDateString,
49
isoDateToBelgianFormat,
5-
} from '@appuniversum/ember-appuniversum/utils/date';
6-
import { assert } from '@ember/debug';
7-
import { registerDestructor } from '@ember/destroyable';
8-
import Modifier from 'ember-modifier';
9-
import Inputmask from 'inputmask';
10+
} from '../utils/date';
11+
12+
export interface AuDateInputModifierSignature {
13+
Args: {
14+
Named: {
15+
value?: string | Date;
16+
prefillYear?: boolean;
17+
onChange?: (isoDate: string | null, date: Date | null) => void;
18+
};
19+
};
20+
Element: HTMLInputElement;
21+
}
22+
23+
type Signature = AuDateInputModifierSignature;
1024

11-
export default class AuDateInputModifier extends Modifier {
12-
input;
13-
argValue;
14-
argOnChange;
15-
currentIsoDate;
25+
export default class AuDateInputModifier extends Modifier<Signature> {
26+
input!: Signature['Element'];
27+
argValue?: Signature['Args']['Named']['value'];
28+
argOnChange?: Signature['Args']['Named']['onChange'];
29+
currentIsoDate?: string | null;
1630

17-
constructor() {
18-
super(...arguments);
31+
constructor(owner: Owner, args: ArgsFor<Signature>) {
32+
super(owner, args);
1933
registerDestructor(this, this.removeInputmask);
2034
}
2135

2236
get isInitialized() {
2337
return Boolean(this.input);
2438
}
2539

26-
modify(input, positional, { value, onChange, prefillYear = false }) {
27-
let valueHasChanged = this.argValue !== value;
40+
modify(
41+
input: Signature['Element'],
42+
_positional: never,
43+
{ value, onChange, prefillYear = false }: Signature['Args']['Named'],
44+
) {
45+
const valueHasChanged = this.argValue !== value;
2846

2947
if (valueHasChanged || !this.isInitialized) {
3048
this.argValue = value;
31-
let isoDate = ensureIsoDate(value);
49+
const isoDate = ensureIsoDate(value);
3250
this.currentIsoDate = isoDate;
3351
input.value = isoDate ? isoDateToBelgianFormat(isoDate) : '';
3452
}
@@ -42,17 +60,17 @@ export default class AuDateInputModifier extends Modifier {
4260
}
4361
}
4462

45-
initialize(input, prefillYear) {
63+
initialize(input: Signature['Element'], prefillYear?: boolean) {
4664
this.input = input;
4765

48-
let inputmask = new Inputmask({
66+
const inputmask = new Inputmask({
4967
alias: 'datetime',
5068
inputFormat: 'dd-mm-yyyy',
5169
outputFormat: 'yyyy-mm-dd',
5270
placeholder: 'DD-MM-JJJJ',
5371
prefillYear,
5472
oncomplete: () => {
55-
let isoDate = this.input.inputmask.unmaskedvalue();
73+
const isoDate = this.input.inputmask!.unmaskedvalue();
5674

5775
if (isoDate !== this.currentIsoDate) {
5876
this.currentIsoDate = isoDate;
@@ -70,7 +88,7 @@ export default class AuDateInputModifier extends Modifier {
7088
inputmask.mask(input);
7189
}
7290

73-
onChange(isoDate, date) {
91+
onChange(isoDate: string | null, date: Date | null) {
7492
this.argOnChange?.(isoDate, date);
7593
}
7694

@@ -79,7 +97,7 @@ export default class AuDateInputModifier extends Modifier {
7997
};
8098
}
8199

82-
function ensureIsoDate(argValue) {
100+
function ensureIsoDate(argValue?: unknown): string | undefined {
83101
if (!argValue) {
84102
return;
85103
}

addon/template-registry.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Components
12
import type AuAlert from '@appuniversum/ember-appuniversum/components/au-alert';
23
import type AuApp from '@appuniversum/ember-appuniversum/components/au-app';
34
import type AuBadge from '@appuniversum/ember-appuniversum/components/au-badge';
@@ -17,7 +18,11 @@ import type AuLink from '@appuniversum/ember-appuniversum/components/au-link';
1718
import type AuList from '@appuniversum/ember-appuniversum/components/au-list';
1819
import type AuLoader from '@appuniversum/ember-appuniversum/components/au-loader';
1920

21+
// Modifiers
22+
import type AuDateInputModifier from '@appuniversum/ember-appuniversum/modifiers/au-date-input';
23+
2024
export default interface AppuniversumRegistry {
25+
// Components
2126
AuAlert: typeof AuAlert;
2227
AuApp: typeof AuApp;
2328
AuBadge: typeof AuBadge;
@@ -36,4 +41,7 @@ export default interface AppuniversumRegistry {
3641
AuLink: typeof AuLink;
3742
AuList: typeof AuList;
3843
AuLoader: typeof AuLoader;
44+
45+
// Modifiers
46+
'au-date-input': typeof AuDateInputModifier;
3947
}

package-lock.json

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
"@storybook/theming": "^6.5.7",
128128
"@testing-library/dom": "^9.3.1",
129129
"@tsconfig/ember": "^3.0.2",
130+
"@types/inputmask": "^5.0.7",
130131
"@types/qunit": "^2.19.9",
131132
"@types/rsvp": "^4.0.8",
132133
"@typescript-eslint/eslint-plugin": "^6.14.0",

tests/integration/components/loose-mode-test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,15 @@ module('Integration | Component | Loose mode', function (hooks) {
133133
assert.dom('[data-test-loader]').exists();
134134
});
135135
});
136+
137+
module('Integration | Modifier | Loose mode', function (hooks) {
138+
setupRenderingTest(hooks);
139+
140+
test('`{{au-date-input}}` resolves in loose mode', async function (assert) {
141+
await render(hbs`
142+
<AuInput data-test-date-input {{au-date-input value="2023-02-02"}} />
143+
`);
144+
145+
assert.dom('[data-test-date-input]').hasValue('02-02-2023');
146+
});
147+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import auDateInput from '@appuniversum/ember-appuniversum/modifiers/au-date-input';
2+
import { find } from '@ember/test-helpers';
3+
import {
4+
typeIn,
5+
fillIn,
6+
render,
7+
settled,
8+
triggerKeyEvent,
9+
} from '@ember/test-helpers';
10+
import { tracked } from '@glimmer/tracking';
11+
import { setupRenderingTest } from 'ember-qunit';
12+
import { module, test } from 'qunit';
13+
14+
module('Integration | Modifier | au-date-input', function (hooks) {
15+
setupRenderingTest(hooks);
16+
17+
test('it accepts an iso date string or date object as a value', async function (assert) {
18+
class TestState {
19+
@tracked value?: string | Date;
20+
}
21+
const state = new TestState();
22+
state.value = '2023-02-02';
23+
24+
await render(
25+
<template><input {{auDateInput value=state.value}} /></template>,
26+
);
27+
28+
assert.dom('input').hasValue('02-02-2023');
29+
30+
state.value = new Date(2024, 5, 3);
31+
await settled();
32+
assert.dom('input').hasValue('03-06-2024');
33+
34+
state.value = undefined;
35+
await settled();
36+
assert.dom('input').hasNoValue();
37+
});
38+
39+
test('it calls @onChange with the correct date', async function (assert) {
40+
const onChange = (isoDate: string | null, date: Date | null) => {
41+
assert.step(isoDate!);
42+
assert.step((date instanceof Date).toString());
43+
};
44+
45+
await render(
46+
<template><input {{auDateInput onChange=onChange}} /></template>,
47+
);
48+
49+
await fillIn('input', '0202202');
50+
await typeIn('input', '3'); // fillIn alone doesn't do the trick, but typeIn has issues when typing all the characters..
51+
52+
assert.verifySteps(
53+
['2023-02-02', 'true'],
54+
'@onChange returns an iso string and date instance',
55+
);
56+
});
57+
58+
test('it calls @onChange with `null` if the input is cleared', async function (assert) {
59+
const onChange = (isoDate: string | null, date: Date | null) => {
60+
assert.step((isoDate === null).toString());
61+
assert.step((date === null).toString());
62+
};
63+
64+
await render(
65+
<template>
66+
<input {{auDateInput value="2023-02-02" onChange=onChange}} />
67+
</template>,
68+
);
69+
70+
const input = find('input');
71+
72+
await clearInput(input!);
73+
assert.verifySteps(
74+
['true', 'true'],
75+
'`@onChange` returns `null` if the input is cleared',
76+
);
77+
});
78+
});
79+
80+
async function clearInput(input: HTMLInputElement) {
81+
// Focus seems to be needed to make the backspace work
82+
input.focus();
83+
84+
while (input.value.length > 0) {
85+
await triggerKeyEvent(input, 'keydown', 'Backspace');
86+
}
87+
}

tests/integration/modifiers/au-date-input-test.js

-71
This file was deleted.

0 commit comments

Comments
 (0)