From 6b63120b65c845b49288e4e1436c94e97f16fe5f Mon Sep 17 00:00:00 2001 From: Sam Van Campenhout Date: Wed, 13 Sep 2023 15:07:26 +0200 Subject: [PATCH 1/2] Deprecate some functionality in the AuInput component This deprecates the 2-way-binding and the masking feature in the AuInput component. We were using `Input` internally, but this wasn't always usefull requiring some projects to create new components based on the native input instead. By deprecating the `Input` usage, all projects can now use `AuInput`, even for more advanced use-cases. The masking functionality is now replaced by the `{{au-inputmask}}` modifier. Projects can apply the modifier instead of passing arguments. This makes the implementation a lot easier to maintain and projects that don't use the masking feature (and the AuDateInput component) won't ship the inputmask library if they are using Embroider "optimized". --- addon/components/au-input.hbs | 48 ++++++++--- addon/components/au-input.js | 44 +++++++++- tests/integration/components/au-input-test.js | 85 ++++++++++++++++++- 3 files changed, 161 insertions(+), 16 deletions(-) diff --git a/addon/components/au-input.hbs b/addon/components/au-input.hbs index d08cc981f..8389a74c9 100644 --- a/addon/components/au-input.hbs +++ b/addon/components/au-input.hbs @@ -11,13 +11,23 @@ {{this.inputmaskModifier options=this.inputmaskOptions}} /> {{else}} - + {{#if this.useDeprecatedInput}} + + {{else}} + + {{/if}} {{/if}} {{#if (eq @iconAlignment "right")}} @@ -37,12 +47,22 @@ {{this.inputmaskModifier options=this.inputmaskOptions}} /> {{else}} - + {{#if this.useDeprecatedInput}} + + {{else}} + + {{/if}} {{/if}} {{/if}} \ No newline at end of file diff --git a/addon/components/au-input.js b/addon/components/au-input.js index 0a2ccc016..0523099a0 100644 --- a/addon/components/au-input.js +++ b/addon/components/au-input.js @@ -1,6 +1,6 @@ import { action } from '@ember/object'; import Component from '@glimmer/component'; -import { assert } from '@ember/debug'; +import { assert, deprecate } from '@ember/debug'; import auInputmask from '@appuniversum/ember-appuniversum/modifiers/au-inputmask'; export default class AuInput extends Component { @@ -12,6 +12,23 @@ export default class AuInput extends Component { !this.args.onChange || (typeof this.args.onChange === 'function' && this.isMasked), ); + + deprecate( + '[AuInput] The `@value` argument is deprecated. Use the `value` attribute and the `{{on}}` modifier instead.', + !('value' in this.args), + { + id: '@appuniversum/ember-appuniversum.au-input', + until: '3.0.0', + for: '@appuniversum/ember-appuniversum', + since: { + enabled: '2.13.0', + }, + }, + ); + } + + get useDeprecatedInput() { + return 'value' in this.args || 'type' in this.args; } get width() { @@ -41,6 +58,18 @@ export default class AuInput extends Component { } get type() { + deprecate( + '[AuInput] The `@type` argument is deprecated. Use the `type` attribute instead.', + !('type' in this.args), + { + id: '@appuniversum/ember-appuniversum.au-input', + until: '3.0.0', + for: '@appuniversum/ember-appuniversum', + since: { + enabled: '2.13.0', + }, + }, + ); return this.args.type || 'text'; } @@ -70,6 +99,19 @@ export default class AuInput extends Component { return {}; } + deprecate( + '[AuInput] The masking feature is deprecated. Use the `{{au-inputmask}}` modifier instead.', + false, + { + id: '@appuniversum/ember-appuniversum.au-input', + until: '3.0.0', + for: '@appuniversum/ember-appuniversum', + since: { + enabled: '2.13.0', + }, + }, + ); + let { mask, maskPlaceholder, maskOptions = {} } = this.args; let options = { diff --git a/tests/integration/components/au-input-test.js b/tests/integration/components/au-input-test.js index d4a1848ef..c66b5f61b 100644 --- a/tests/integration/components/au-input-test.js +++ b/tests/integration/components/au-input-test.js @@ -1,7 +1,8 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; +import { fillIn, find, render } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; +import { hasDeprecationStartingWith } from '../../helpers/deprecations'; module('Integration | Component | au-input', function (hooks) { setupRenderingTest(hooks); @@ -14,5 +15,87 @@ module('Integration | Component | au-input', function (hooks) { this.set('type', 'number'); assert.dom('input').hasAttribute('type', 'number'); + + assert.true( + hasDeprecationStartingWith( + '[AuInput] The `@type` argument is deprecated. Use the `type` attribute instead.', + ), + '@type throws a deprecation warning', + ); + }); + + test("it's possible to set the value", async function (assert) { + this.value = 'hello'; + await render(hbs``); + assert.dom('input').hasValue('hello'); + + await fillIn('input', 'hello world'); + assert.strictEqual( + this.value, + 'hello world', + 'the value is updated through 2-way-binding', + ); + + assert.true( + hasDeprecationStartingWith( + '[AuInput] The `@value` argument is deprecated. Use the `value` attribute and the `{{on}}` modifier instead.', + ), + '@value throws a deprecation warning', + ); + }); + + test('it shows deprecation warnings even if the values are undefined', async function (assert) { + await render(hbs``); + + assert.true( + hasDeprecationStartingWith( + '[AuInput] The `@value` argument is deprecated. Use the `value` attribute and the `{{on}}` modifier instead.', + ), + '@value throws a deprecation warning', + ); + + assert.true( + hasDeprecationStartingWith( + '[AuInput] The `@type` argument is deprecated. Use the `type` attribute instead.', + ), + '@type throws a deprecation warning', + ); + }); + + test("it's possible to pass attributes to the input element", async function (assert) { + await render(hbs``); + assert.dom('input[data-test-hello]').exists(); + }); + + test("it's possible to mask the input", async function (assert) { + this.value = '12'; + await render( + hbs``, + ); + + const input = find('input'); + assert.ok( + input.inputmask, + 'an inputmask instance is attached to the `inputmask` property on the element', + ); + assert.strictEqual( + input.value, + '1.2._', + '.value returns the mask and placeholder', + ); + + this.set('value', '321'); + assert.strictEqual( + input.value, + '3.2.1', + '.value returns the mask and placeholder', + ); + + assert.true( + hasDeprecationStartingWith( + '[AuInput] The masking feature is deprecated. Use the `{{au-inputmask}}` modifier instead.', + ), + '@mask throws a deprecation warning', + ); }); }); From 66178645c0ded25a9982e2073b3107e99022b75b Mon Sep 17 00:00:00 2001 From: Sam Van Campenhout Date: Wed, 13 Sep 2023 15:22:12 +0200 Subject: [PATCH 2/2] Update the `AuInput` documentation This updates the docs so only the non-deprecated options are shown. --- stories/5-components/Forms/AuInput.stories.js | 100 ------------------ .../Forms/Input/AuInput.stories.js | 62 +++++++++++ .../Forms/Input/Inputmask.stories.js | 45 ++++++++ 3 files changed, 107 insertions(+), 100 deletions(-) delete mode 100644 stories/5-components/Forms/AuInput.stories.js create mode 100644 stories/5-components/Forms/Input/AuInput.stories.js create mode 100644 stories/5-components/Forms/Input/Inputmask.stories.js diff --git a/stories/5-components/Forms/AuInput.stories.js b/stories/5-components/Forms/AuInput.stories.js deleted file mode 100644 index cb2af8314..000000000 --- a/stories/5-components/Forms/AuInput.stories.js +++ /dev/null @@ -1,100 +0,0 @@ -import { hbs } from 'ember-cli-htmlbars'; -import { icons } from '../../assets/icons'; - -export default { - title: 'Components/Forms/AuInput', - argTypes: { - error: { control: 'boolean', description: 'Add an error state' }, - warning: { control: 'boolean', description: 'Add an warning state' }, - disabled: { - control: 'boolean', - description: 'Adds a disabled state to the input', - }, - width: { - control: 'select', - options: ['default', 'block'], - description: 'Display the input as a block element', - }, - icon: { - control: 'select', - options: icons, - description: - 'Adds an icon (using an icon implies the use @width="block")', - }, - iconAlignment: { - control: 'select', - options: ['left', 'right'], - description: 'Choose the position of the icon', - }, - mask: { - control: 'text', - description: - 'Define the input mask you want to add. See https://github.com/RobinHerbots/Inputmask for more options.', - }, - maskPlaceholder: { - control: 'text', - description: 'Define the input mask placeholder', - }, - maskOptions: { - description: - 'A more flexible alternative to the `@mask` and `@maskPlaceholder` arguments. This object will be passed into the InputMask instance. See https://github.com/RobinHerbots/Inputmask for more options.', - }, - onChange: { - action: 'change', - description: - 'This action will be called when the value changes and will be passed to the unmasked value and the masked value.', - }, - type: { - control: 'select', - options: ['text', 'number'], - }, - }, - parameters: { - layout: 'padded', - }, -}; - -const Template = (args) => ({ - template: hbs` - `, - context: args, -}); - -export const Component = Template.bind({}); -Component.args = { - error: false, - warning: false, - disabled: false, - width: '', - icon: '', - iconAlignment: 'left', - mask: '', - maskPlaceholder: '', -}; - -export const InputMask = Template.bind({}); -InputMask.args = { - value: '', - error: false, - warning: false, - disabled: false, - width: '', - icon: '', - iconAlignment: 'left', - maskOptions: { - mask: '99.99.99-999.99', - placeholder: '__.__.__-___.__', - }, -}; diff --git a/stories/5-components/Forms/Input/AuInput.stories.js b/stories/5-components/Forms/Input/AuInput.stories.js new file mode 100644 index 000000000..3a8a6ff07 --- /dev/null +++ b/stories/5-components/Forms/Input/AuInput.stories.js @@ -0,0 +1,62 @@ +import { hbs } from 'ember-cli-htmlbars'; +import { icons } from '../../../assets/icons'; + +export default { + title: 'Components/Forms/Input/AuInput', + argTypes: { + error: { control: 'boolean', description: 'Add an error state' }, + warning: { control: 'boolean', description: 'Add an warning state' }, + disabled: { + control: 'boolean', + description: 'Adds a disabled state to the input', + }, + width: { + control: 'select', + options: ['default', 'block'], + description: 'Display the input as a block element', + }, + icon: { + control: 'select', + options: icons, + description: + 'Adds an icon (using an icon implies the use @width="block")', + }, + iconAlignment: { + control: 'select', + options: ['left', 'right'], + description: 'Choose the position of the icon', + }, + value: { + control: 'text', + }, + }, + parameters: { + layout: 'padded', + }, +}; + +const Template = (args) => ({ + template: hbs` + Input + `, + context: args, +}); + +export const Component = Template.bind({}); +Component.args = { + error: false, + warning: false, + disabled: false, + width: '', + icon: '', + iconAlignment: 'left', +}; diff --git a/stories/5-components/Forms/Input/Inputmask.stories.js b/stories/5-components/Forms/Input/Inputmask.stories.js new file mode 100644 index 000000000..f954f87a8 --- /dev/null +++ b/stories/5-components/Forms/Input/Inputmask.stories.js @@ -0,0 +1,45 @@ +import { hbs } from 'ember-cli-htmlbars'; + +export default { + title: 'Components/Forms/Input/Inputmasking', + argTypes: { + value: { + control: 'text', + }, + mask: { + control: 'text', + }, + placeholder: { + control: 'text', + }, + }, + parameters: { + layout: 'padded', + }, +}; + +const Template = (args) => ({ + template: hbs` + +

+ You can add input masking to the AuInput by applying the {{"{{au-inputmask}}"}} modifier. It is a simple wrapper around the inputmask library. Usage instructions can be found in the inputmask repo. +

+
+
+ Masked input + `, + context: args, +}); + +export const Component = Template.bind({}); +Component.args = { + mask: '99.99.99-999.99', + placeholder: '_', +};