diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 09d33bb20d..318db7e5dc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -55,6 +55,7 @@ jobs: - name: Build Angular Proxy run: | + yarn workspace @telekom/scale-components process-angular-proxies yarn workspace @telekom/scale-components-angular build - name: Build React Proxy @@ -123,6 +124,7 @@ jobs: - name: Build Angular Proxy run: | + yarn workspace @telekom/scale-components process-angular-proxies yarn workspace @telekom/scale-components-angular-neutral build - name: Build React Proxy diff --git a/packages/components-angular/src/directives/value-accessor.ts b/packages/components-angular/src/directives/value-accessor.ts index 46ebd057d6..6bb76a6d3c 100644 --- a/packages/components-angular/src/directives/value-accessor.ts +++ b/packages/components-angular/src/directives/value-accessor.ts @@ -1,6 +1,7 @@ -import { ElementRef, HostListener } from '@angular/core'; +import { Directive, ElementRef, HostListener } from '@angular/core'; import { ControlValueAccessor } from '@angular/forms'; +@Directive({}) export class ValueAccessor implements ControlValueAccessor { private onChange: (value: any) => void = () => {/**/}; diff --git a/packages/components/package.json b/packages/components/package.json index 5fd380f0a0..72fec110d8 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -33,14 +33,15 @@ "format": "prettier --write \"*.ts\" \"src/**/*.{html,tsx,ts,css,json}\" \"!src/**/*.d.ts\"", "lint:fix": "yarn lint:style --fix", "lint": "tslint -c tslint.json -p . \"src/**/*.{tsx,ts,css,json}\" \"!src/**/*.d.ts\"", - "generate": "node ./scripts/generate-icons.js" + "generate": "node ./scripts/generate-icons.js", + "process-angular-proxies": "node ./scripts/process-angular-proxies.js" }, "devDependencies": { "@babel/core": "7.10.2", "@babel/plugin-syntax-jsx": "7.10.1", "@babel/plugin-transform-react-jsx": "7.10.1", "@nowseemee/vue-output-target": "0.0.4", - "@stencil/angular-output-target": "^0.0.5", + "@stencil/angular-output-target": "^0.0.7", "@stencil/postcss": "^2.0.0", "@stencil/react-output-target": "^0.0.9", "@types/classnames": "2.2.8", diff --git a/packages/components/scripts/process-angular-proxies.js b/packages/components/scripts/process-angular-proxies.js new file mode 100644 index 0000000000..cf6654b63b --- /dev/null +++ b/packages/components/scripts/process-angular-proxies.js @@ -0,0 +1,15 @@ +const fs = require('fs'); +const angularProxiesFile = '../components-angular/src/directives/proxies.ts'; + +fs.readFile(angularProxiesFile, 'utf8', (err, data) => { + if (err) return console.log(err); + + // regex matches the kebab case event name + const withEscapedKeys = data.replace(/(\w)+(-(\w)+)+!:/g, (match) => { + return `"${match.split('!:')[0]}"!:`; + }); + + fs.writeFile(angularProxiesFile, withEscapedKeys, 'utf8', (err) => { + if (err) return console.log(err); + }); +}); diff --git a/packages/components/src/components/accordion/accordion.tsx b/packages/components/src/components/accordion/accordion.tsx index 19199e0c18..899440d9d4 100644 --- a/packages/components/src/components/accordion/accordion.tsx +++ b/packages/components/src/components/accordion/accordion.tsx @@ -37,7 +37,7 @@ export class Accordion { /** * Handle `dependent` */ - @Listen('scaleExpand') + @Listen('scale-expand') collapsibleHandler(event: CustomEvent) { event.stopPropagation(); const { expanded } = event.detail; diff --git a/packages/components/src/components/checkbox-group/checkbox-group.tsx b/packages/components/src/components/checkbox-group/checkbox-group.tsx index afe9e466be..bde6c5d5d3 100644 --- a/packages/components/src/components/checkbox-group/checkbox-group.tsx +++ b/packages/components/src/components/checkbox-group/checkbox-group.tsx @@ -24,7 +24,7 @@ export class CheckboxGroup { @State() groupStatus: CheckboxState[] = []; - @Listen('scaleChange') + @Listen('scale-change') scaleChangeHandler() { this.createNewState(); } diff --git a/packages/components/src/components/checkbox/checkbox.spec.ts b/packages/components/src/components/checkbox/checkbox.spec.ts index 76508c473c..b922b4b879 100644 --- a/packages/components/src/components/checkbox/checkbox.spec.ts +++ b/packages/components/src/components/checkbox/checkbox.spec.ts @@ -68,11 +68,14 @@ describe('Checkbox', () => { it('should emit on change', async () => { const changeSpy = jest.fn(); - page.doc.addEventListener('scaleChange', changeSpy); + const changeSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-change', changeSpy); + page.doc.addEventListener('scaleChange', changeSpyLegacy); const element = page.root.querySelector('input'); element.dispatchEvent(new Event('change')); await page.waitForChanges(); expect(changeSpy).toHaveBeenCalled(); + expect(changeSpyLegacy).toHaveBeenCalled(); }); it('should handle inputId with value null', async () => { diff --git a/packages/components/src/components/checkbox/checkbox.tsx b/packages/components/src/components/checkbox/checkbox.tsx index 1b77c16642..f9de020907 100644 --- a/packages/components/src/components/checkbox/checkbox.tsx +++ b/packages/components/src/components/checkbox/checkbox.tsx @@ -19,6 +19,7 @@ import { Prop, } from '@stencil/core'; import classNames from 'classnames'; +import { emitEvent } from '../../utils/utils'; let i = 0; @@ -49,8 +50,11 @@ export class Checkbox { @Prop() inputId?: string; /** (optional) Injected CSS styles */ @Prop() styles?: string; + /** Emitted when the value has changed. */ - @Event() scaleChange!: EventEmitter; + @Event({ eventName: 'scale-change' }) scaleChange: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) scaleChangeLegacy: EventEmitter; componentWillLoad() { if (this.inputId == null) { @@ -104,8 +108,7 @@ export class Checkbox { this.indeterminate = false; } this.checked = e.target.checked; - // bubble event through the shadow dom - this.scaleChange.emit({ value: this.checked }); + emitEvent(this, 'scaleChange', { value: this.checked }); }} value={this.value} checked={this.checked} diff --git a/packages/components/src/components/checkbox/readme.md b/packages/components/src/components/checkbox/readme.md index 84b7085685..7b82b4fadc 100644 --- a/packages/components/src/components/checkbox/readme.md +++ b/packages/components/src/components/checkbox/readme.md @@ -23,9 +23,10 @@ ## Events -| Event | Description | Type | -| ------------- | ----------------------------------- | ------------------ | -| `scaleChange` | Emitted when the value has changed. | `CustomEvent` | +| Event | Description | Type | +| -------------- | -------------------------------------------------------------------------------------------------- | ------------------ | +| `scale-change` | Emitted when the value has changed. | `CustomEvent` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Dependencies diff --git a/packages/components/src/components/collapsible/collapsible.spec.ts b/packages/components/src/components/collapsible/collapsible.spec.ts index 1c193c1c5e..ae84f9de80 100644 --- a/packages/components/src/components/collapsible/collapsible.spec.ts +++ b/packages/components/src/components/collapsible/collapsible.spec.ts @@ -25,10 +25,13 @@ describe('TextField', () => { }); it('should emit on click', async () => { const clickSpy = jest.fn(); - page.doc.addEventListener('scaleExpand', clickSpy); + const clickSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-expand', clickSpy); + page.doc.addEventListener('scaleExpand', clickSpyLegacy); const buttonElement = page.root.shadowRoot.querySelector('button'); buttonElement.click(); await page.waitForChanges(); expect(clickSpy).toHaveBeenCalled(); + expect(clickSpyLegacy).toHaveBeenCalled(); }); }); diff --git a/packages/components/src/components/collapsible/collapsible.tsx b/packages/components/src/components/collapsible/collapsible.tsx index 34ff358899..6e2484af66 100644 --- a/packages/components/src/components/collapsible/collapsible.tsx +++ b/packages/components/src/components/collapsible/collapsible.tsx @@ -19,6 +19,7 @@ import { EventEmitter, } from '@stencil/core'; import classNames from 'classnames'; +import { emitEvent } from '../../utils/utils'; export interface CollapsibleEventDetail { expanded: boolean; @@ -46,7 +47,11 @@ export class Collapsible { @Prop() styles?: string; /** Emitted so parent knows about it */ - @Event() scaleExpand: EventEmitter; + @Event({ eventName: 'scale-expand' }) + scaleExpand: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleExpand' }) + scaleExpandLegacy: EventEmitter; componentWillLoad() { const j = i++; @@ -60,7 +65,7 @@ export class Collapsible { handleClick = () => { this.expanded = !this.expanded; - this.scaleExpand.emit({ expanded: this.expanded }); + emitEvent(this, 'scaleExpand', { expanded: this.expanded }); }; /** diff --git a/packages/components/src/components/collapsible/readme.md b/packages/components/src/components/collapsible/readme.md index 86193e62c2..b27b5ecd36 100644 --- a/packages/components/src/components/collapsible/readme.md +++ b/packages/components/src/components/collapsible/readme.md @@ -16,9 +16,10 @@ ## Events -| Event | Description | Type | -| ------------- | -------------------------------------------------- | ------------------------------------- | -| `scaleExpand` | Emitted so parent knows about it | `CustomEvent` | +| Event | Description | Type | +| -------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `scale-expand` | Emitted so parent knows about it | `CustomEvent` | +| `scaleExpand` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Shadow Parts diff --git a/packages/components/src/components/data-grid/data-grid.tsx b/packages/components/src/components/data-grid/data-grid.tsx index 587b19e78c..32e4a68a9d 100644 --- a/packages/components/src/components/data-grid/data-grid.tsx +++ b/packages/components/src/components/data-grid/data-grid.tsx @@ -27,6 +27,7 @@ import { } from './data-grid-cells'; import classNames from 'classnames'; import statusNote from '../../utils/status-note'; +import { emitEvent } from '../../utils/utils'; // [ ] add options to show nested content without the html column // [ ] add options to pre-expand all html content @@ -110,10 +111,17 @@ export class DataGrid { /* 4. Events (alphabetical) */ /** Event triggered every time the editable cells are changed, updating the original rows data */ - @Event() scaleEdit: EventEmitter; + @Event({ eventName: 'scale-edit' }) + scaleEdit: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleEdit' }) + scaleEditLegacy: EventEmitter; /** Event triggered every time the data is sorted, changing original rows data */ - @Event() scaleSort: EventEmitter; - + @Event({ eventName: 'scale-sort' }) + scaleSort: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleSort' }) + scaleSortLegacy: EventEmitter; /* 5. Private Properties (alphabetical) */ /** Used to update column divider during interaction */ private activeDivider: any; @@ -691,7 +699,7 @@ export class DataGrid { sortDirection, columnIndex, } as DataGridSortedEventDetail; - this.scaleSort.emit(data); + emitEvent(this, 'scaleSort', data); } triggerEditEvent(value, rowIndex, columnIndex) { @@ -701,7 +709,7 @@ export class DataGrid { columnIndex, value, } as DataGridEditEventDetail; - this.scaleEdit.emit(data); + emitEvent(this, 'scaleEdit', data); // Force render for checkboxes this.forceRender++; diff --git a/packages/components/src/components/data-grid/readme.md b/packages/components/src/components/data-grid/readme.md index 2d539a6632..cab119fe98 100644 --- a/packages/components/src/components/data-grid/readme.md +++ b/packages/components/src/components/data-grid/readme.md @@ -29,10 +29,12 @@ ## Events -| Event | Description | Type | -| ----------- | ------------------------------------------------------------------------------------------ | ---------------------------------------- | -| `scaleEdit` | Event triggered every time the editable cells are changed, updating the original rows data | `CustomEvent` | -| `scaleSort` | Event triggered every time the data is sorted, changing original rows data | `CustomEvent` | +| Event | Description | Type | +| ------------ | -------------------------------------------------------------------------------------------------- | ---------------------------------------- | +| `scale-edit` | Event triggered every time the editable cells are changed, updating the original rows data | `CustomEvent` | +| `scale-sort` | Event triggered every time the data is sorted, changing original rows data | `CustomEvent` | +| `scaleEdit` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleSort` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Dependencies diff --git a/packages/components/src/components/date-picker/date-picker.tsx b/packages/components/src/components/date-picker/date-picker.tsx index 51081b1d0e..5687338ed3 100644 --- a/packages/components/src/components/date-picker/date-picker.tsx +++ b/packages/components/src/components/date-picker/date-picker.tsx @@ -31,6 +31,7 @@ import { import classNames from 'classnames'; import { DuetLocalizedText } from '@duetds/date-picker/dist/types/components/duet-date-picker/date-localization'; import statusNote from '../../utils/status-note'; +import { emitEvent } from '../../utils/utils'; let i = 0; @@ -151,17 +152,32 @@ export class DatePicker { /** * Event emitted when a date is selected. */ - @Event() scaleChange: EventEmitter; + @Event({ eventName: 'scale-change' }) + scaleChange: EventEmitter; + + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) + scaleChangeLegacy: EventEmitter; /** * Event emitted the date picker input is blurred. */ - @Event() scaleBlur: EventEmitter; + @Event({ eventName: 'scale-blur' }) + scaleBlur: EventEmitter; + + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleBlur' }) + scaleBlurLegacy: EventEmitter; /** * Event emitted the date picker input is focused. */ - @Event() scaleFocus: EventEmitter; + @Event({ eventName: 'scale-focus' }) + scaleFocus: EventEmitter; + + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleFocus' }) + scaleFocusLegacy: EventEmitter; private helperTextId = `helper-message-${i}`; @@ -283,15 +299,15 @@ export class DatePicker { { - this.scaleChange.emit(e.detail); + emitEvent(this, 'scaleChange', e.detail); this.handleKeyPress(e); }} onDuetFocus={(e) => { - this.scaleFocus.emit(e.detail); + emitEvent(this, 'scaleFocus', e.detail); this.hasFocus = true; }} onDuetBlur={(e) => { - this.scaleBlur.emit(e.detail); + emitEvent(this, 'scaleBlur', e.detail); this.hasFocus = false; }} name={this.name} diff --git a/packages/components/src/components/date-picker/readme.md b/packages/components/src/components/date-picker/readme.md index 3abbb76803..b1054d2863 100644 --- a/packages/components/src/components/date-picker/readme.md +++ b/packages/components/src/components/date-picker/readme.md @@ -30,11 +30,14 @@ ## Events -| Event | Description | Type | -| ------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------- | -| `scaleBlur` | Event emitted the date picker input is blurred. | `CustomEvent<{ component: "duet-date-picker"; }>` | -| `scaleChange` | Event emitted when a date is selected. | `CustomEvent<{ component: "duet-date-picker"; valueAsDate: Date; value: string; }>` | -| `scaleFocus` | Event emitted the date picker input is focused. | `CustomEvent<{ component: "duet-date-picker"; }>` | +| Event | Description | Type | +| -------------- | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | +| `scale-blur` | Event emitted the date picker input is blurred. | `CustomEvent<{ component: "duet-date-picker"; }>` | +| `scale-change` | Event emitted when a date is selected. | `CustomEvent<{ component: "duet-date-picker"; valueAsDate: Date; value: string; }>` | +| `scale-focus` | Event emitted the date picker input is focused. | `CustomEvent<{ component: "duet-date-picker"; }>` | +| `scaleBlur` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent<{ component: "duet-date-picker"; }>` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent<{ component: "duet-date-picker"; valueAsDate: Date; value: string; }>` | +| `scaleFocus` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent<{ component: "duet-date-picker"; }>` | ## Methods diff --git a/packages/components/src/components/dropdown/dropdown.tsx b/packages/components/src/components/dropdown/dropdown.tsx index ea85901fc7..60fb246f85 100644 --- a/packages/components/src/components/dropdown/dropdown.tsx +++ b/packages/components/src/components/dropdown/dropdown.tsx @@ -21,6 +21,7 @@ import { } from '@stencil/core'; import classNames from 'classnames'; import { HTMLStencilElement } from '@stencil/core/internal'; +import { emitEvent } from '../../utils/utils'; interface InputChangeEventDetail { value: string | number | boolean | undefined | null; @@ -69,15 +70,30 @@ export class Dropdown { @Prop() styles?: string; /** Emitted when a keyboard input occurred. */ - @Event() scaleInput!: EventEmitter; + @Event({ eventName: 'scale-input' }) scaleInput!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleInput' }) + scaleInputLegacy!: EventEmitter; /** Emitted when the value has changed. */ - @Event() scaleChange!: EventEmitter; + @Event({ eventName: 'scale-change' }) + scaleChange!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) + scaleChangeLegacy!: EventEmitter; /** Emitted when the input has focus. */ - @Event() scaleFocus!: EventEmitter; + @Event({ eventName: 'scale-focus' }) scaleFocus!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleFocus' }) scaleFocusLegacy!: EventEmitter; /** Emitted when the input loses focus. */ - @Event() scaleBlur!: EventEmitter; + @Event({ eventName: 'scale-blur' }) scaleBlur!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleBlur' }) scaleBlurLegacy!: EventEmitter; /** Emitted on keydown. */ - @Event() scaleKeyDown!: EventEmitter; + @Event({ eventName: 'scale-keydown' }) + scaleKeyDown!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleKeydown' }) + scaleKeyDownLegacy!: EventEmitter; /** "forceUpdate" hack, set it to trigger and re-render */ @State() forceUpdate: string; @@ -147,7 +163,7 @@ export class Dropdown { // because how we keep this.value up-to-date for type="select" // `this.value = selectedValue` emitChange() { - this.scaleChange.emit({ + emitEvent(this, 'scaleChange', { value: this.value == null ? this.value : this.value.toString(), }); } @@ -160,7 +176,7 @@ export class Dropdown { const target = event.target as HTMLInputElement | null; if (this.controlled) { - this.scaleChange.emit({ value: target.value }); + emitEvent(this, 'scaleChange', { value: target.value }); this.selectElement.value = String(this.value); this.forceUpdate = String(Date.now()); } else { @@ -175,7 +191,7 @@ export class Dropdown { this.value = target.value || ''; this.emitChange(); } - this.scaleInput.emit(event as KeyboardEvent); + emitEvent(this, 'scaleInput', event as KeyboardEvent); }; handleChange = (event: Event) => { @@ -187,15 +203,15 @@ export class Dropdown { }; handleFocus = () => { - this.scaleFocus.emit(); + emitEvent(this, 'scaleFocus'); }; handleBlur = () => { - this.scaleBlur.emit(); + emitEvent(this, 'scaleBlur'); }; handleKeyDown = (event: KeyboardEvent) => { - this.scaleKeyDown.emit(event); + emitEvent(this, 'scaleKeyDown', event); }; render() { diff --git a/packages/components/src/components/dropdown/readme.md b/packages/components/src/components/dropdown/readme.md index 0e4a7bfdb2..b20d8b9b4b 100644 --- a/packages/components/src/components/dropdown/readme.md +++ b/packages/components/src/components/dropdown/readme.md @@ -27,13 +27,18 @@ ## Events -| Event | Description | Type | -| -------------- | --------------------------------------- | ------------------------------------- | -| `scaleBlur` | Emitted when the input loses focus. | `CustomEvent` | -| `scaleChange` | Emitted when the value has changed. | `CustomEvent` | -| `scaleFocus` | Emitted when the input has focus. | `CustomEvent` | -| `scaleInput` | Emitted when a keyboard input occurred. | `CustomEvent` | -| `scaleKeyDown` | Emitted on keydown. | `CustomEvent` | +| Event | Description | Type | +| --------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `scale-blur` | Emitted when the input loses focus. | `CustomEvent` | +| `scale-change` | Emitted when the value has changed. | `CustomEvent` | +| `scale-focus` | Emitted when the input has focus. | `CustomEvent` | +| `scale-input` | Emitted when a keyboard input occurred. | `CustomEvent` | +| `scale-keydown` | Emitted on keydown. | `CustomEvent` | +| `scaleBlur` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleFocus` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleInput` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleKeydown` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Dependencies diff --git a/packages/components/src/components/input/input.spec.ts b/packages/components/src/components/input/input.spec.ts index 7c142f9019..6066e27e25 100644 --- a/packages/components/src/components/input/input.spec.ts +++ b/packages/components/src/components/input/input.spec.ts @@ -247,38 +247,47 @@ describe('Input', () => { it('onFocus type="select"', async () => { const mock = jest.fn(); + const mockLegacy = jest.fn(); page.root.type = 'select'; - page.root.addEventListener('scaleFocus', mock); + page.root.addEventListener('scale-focus', mock); + page.root.addEventListener('scaleFocus', mockLegacy); await page.waitForChanges(); const select = page.root.querySelector('.input__select'); await page.waitForChanges(); select.dispatchEvent(new Event('focus')); await page.waitForChanges(); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); }); it('onBlur type="select"', async () => { const mock = jest.fn(); + const mockLegacy = jest.fn(); page.root.type = 'select'; - page.root.addEventListener('scaleBlur', mock); + page.root.addEventListener('scale-blur', mock); + page.root.addEventListener('scaleBlur', mockLegacy); await page.waitForChanges(); const select = page.root.querySelector('.input__select'); await page.waitForChanges(); select.dispatchEvent(new Event('blur')); await page.waitForChanges(); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); }); it('onKeyDown type="select"', async () => { const mock = jest.fn(); + const mockLegacy = jest.fn(); page.root.type = 'select'; - page.root.addEventListener('scaleKeyDown', mock); + page.root.addEventListener('scale-keydown', mock); + page.root.addEventListener('scaleKeyDown', mockLegacy); await page.waitForChanges(); const select = page.root.querySelector('.input__select'); await page.waitForChanges(); select.dispatchEvent(new Event('keydown')); await page.waitForChanges(); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); }); it('onChange type="checkbox"', async () => { @@ -297,26 +306,32 @@ describe('Input', () => { page.root.type = 'textarea'; page.root.value = 'value'; const mock = jest.fn(); - page.root.addEventListener('scaleChange', mock); + const mockLegacy = jest.fn(); + page.root.addEventListener('scale-change', mock); + page.root.addEventListener('scaleChange', mockLegacy); await page.waitForChanges(); const select = await page.root.querySelector('textarea.input__textarea'); await select.dispatchEvent(new Event('input')); await page.waitForChanges(); expect(page.rootInstance.value).toBe(''); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); }); it('onChange type="textarea"', async () => { page.root.type = 'textarea'; page.root.value = 'value'; const mock = jest.fn(); - page.root.addEventListener('scaleChange', mock); + const mockLegacy = jest.fn(); + page.root.addEventListener('scale-change', mock); + page.root.addEventListener('scaleChange', mockLegacy); await page.waitForChanges(); const select = await page.root.querySelector('textarea.input__textarea'); await select.dispatchEvent(new Event('change')); await page.waitForChanges(); expect(page.rootInstance.value).toBe(''); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); }); }); }); diff --git a/packages/components/src/components/input/input.tsx b/packages/components/src/components/input/input.tsx index d35e1d09d8..346af2b48d 100644 --- a/packages/components/src/components/input/input.tsx +++ b/packages/components/src/components/input/input.tsx @@ -22,6 +22,7 @@ import { } from '@stencil/core'; import classNames from 'classnames'; import statusNote from '../../utils/status-note'; +import { emitEvent } from '../../utils/utils'; export interface InputChangeEventDetail { value: string | number | boolean | undefined | null; @@ -106,16 +107,30 @@ export class Input { @Prop() styles?: string; /** Emitted when a keyboard input occurred. */ - @Event() scaleInput!: EventEmitter; + @Event({ eventName: 'scale-input' }) scaleInput!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleInput' }) + scaleInputLegacy: EventEmitter; /** Emitted when the value has changed. */ - @Event() scaleChange!: EventEmitter; + @Event({ eventName: 'scale-change' }) + scaleChange: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) + scaleChangeLegacy: EventEmitter; /** Emitted when the input has focus. */ - @Event() scaleFocus!: EventEmitter; + @Event({ eventName: 'scale-focus' }) scaleFocus!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleFocus' }) scaleFocusLegacy!: EventEmitter; /** Emitted when the input loses focus. */ - @Event() scaleBlur!: EventEmitter; + @Event({ eventName: 'scale-blur' }) scaleBlur!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleBlur' }) scaleBlurLegacy!: EventEmitter; /** Emitted on keydown. */ - @Event() scaleKeyDown!: EventEmitter; - + @Event({ eventName: 'scale-keydown' }) + scaleKeyDown!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleKeyDown' }) + scaleKeyDownLegacy!: EventEmitter; /** (optional) Input checkbox checked */ @State() customResize?: any; /** Whether the input element has focus */ @@ -206,14 +221,14 @@ export class Input { // because how we keep this.value up-to-date for type="select" // `this.value = selectedValue` emitChange() { - this.scaleChange.emit({ + emitEvent(this, 'scaleChange', { value: this.value == null ? this.value : this.value.toString(), }); } @Watch('checked') checkedChanged() { - this.scaleChange.emit({ value: this.checked }); + emitEvent(this, 'scaleChange', { value: this.checked }); } // Handle checkbox/radio change (click on label) @@ -236,7 +251,7 @@ export class Input { const target = event.target as HTMLInputElement | null; if (this.controlled) { - this.scaleChange.emit({ value: target.value }); + emitEvent(this, 'scaleChange', { value: target.value }); this.selectElement.value = String(this.value); this.forceUpdate = String(Date.now()); } else { @@ -251,7 +266,7 @@ export class Input { this.value = target.value || ''; this.emitChange(); } - this.scaleInput.emit(event as KeyboardEvent); + emitEvent(this, 'scaleInput', event as KeyboardEvent); }; handleChange = (event: Event) => { @@ -263,17 +278,17 @@ export class Input { }; handleFocus = () => { - this.scaleFocus.emit(); + emitEvent(this, 'scaleFocus'); this.hasFocus = true; }; handleBlur = () => { - this.scaleBlur.emit(); + emitEvent(this, 'scaleBlur'); this.hasFocus = false; }; handleKeyDown = (event: KeyboardEvent) => { - this.scaleKeyDown.emit(event); + emitEvent(this, 'scaleKeyDown', event); }; render() { diff --git a/packages/components/src/components/input/readme.md b/packages/components/src/components/input/readme.md index e4d969bcd9..2a402dd546 100644 --- a/packages/components/src/components/input/readme.md +++ b/packages/components/src/components/input/readme.md @@ -38,13 +38,18 @@ ## Events -| Event | Description | Type | -| -------------- | --------------------------------------- | ------------------------------------- | -| `scaleBlur` | Emitted when the input loses focus. | `CustomEvent` | -| `scaleChange` | Emitted when the value has changed. | `CustomEvent` | -| `scaleFocus` | Emitted when the input has focus. | `CustomEvent` | -| `scaleInput` | Emitted when a keyboard input occurred. | `CustomEvent` | -| `scaleKeyDown` | Emitted on keydown. | `CustomEvent` | +| Event | Description | Type | +| --------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `scale-blur` | Emitted when the input loses focus. | `CustomEvent` | +| `scale-change` | Emitted when the value has changed. | `CustomEvent` | +| `scale-focus` | Emitted when the input has focus. | `CustomEvent` | +| `scale-input` | Emitted when a keyboard input occurred. | `CustomEvent` | +| `scale-keydown` | Emitted on keydown. | `CustomEvent` | +| `scaleBlur` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleFocus` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleInput` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleKeyDown` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Dependencies diff --git a/packages/components/src/components/menu-flyout-list/menu-flyout-list.tsx b/packages/components/src/components/menu-flyout-list/menu-flyout-list.tsx index be88bb217c..7e907c79ec 100644 --- a/packages/components/src/components/menu-flyout-list/menu-flyout-list.tsx +++ b/packages/components/src/components/menu-flyout-list/menu-flyout-list.tsx @@ -23,6 +23,14 @@ import { } from '@stencil/core'; import classNames from 'classnames'; +/* + * Instead of scaleChange.emit() use emitEvent(this, 'scale-change', { whatever payload }); + * This is to transition from scaleChange (camel) to scale-change (kebab). + * Because scaleChange does not work with Vue 3; + * + * import { emitEvent } from '../../utils/utils'; + */ + const name = 'menu-list'; @Component({ tag: 'scale-menu-flyout-list', @@ -43,7 +51,11 @@ export class MenuFlyoutList { /* 4. Events (alphabetical) */ /** Event triggered every time the data is edited, changing original rows data */ - @Event() scaleSelect: EventEmitter<{ + @Event({ eventName: 'scale-select' }) scaleSelect: EventEmitter<{ + item: HTMLElement; + }>; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleSelect' }) scaleSelectLegacy: EventEmitter<{ item: HTMLElement; }>; diff --git a/packages/components/src/components/menu-flyout-list/readme.md b/packages/components/src/components/menu-flyout-list/readme.md index 6c7a327e8c..01fde07467 100644 --- a/packages/components/src/components/menu-flyout-list/readme.md +++ b/packages/components/src/components/menu-flyout-list/readme.md @@ -14,9 +14,10 @@ ## Events -| Event | Description | Type | -| ------------- | -------------------------------------------------------------------------- | ------------------------------------- | -| `scaleSelect` | Event triggered every time the data is edited, changing original rows data | `CustomEvent<{ item: HTMLElement; }>` | +| Event | Description | Type | +| -------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `scale-select` | Event triggered every time the data is edited, changing original rows data | `CustomEvent<{ item: HTMLElement; }>` | +| `scaleSelect` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent<{ item: HTMLElement; }>` | ## Methods diff --git a/packages/components/src/components/menu-flyout/menu-flyout.tsx b/packages/components/src/components/menu-flyout/menu-flyout.tsx index a65ba0caa2..e4e9415bf0 100644 --- a/packages/components/src/components/menu-flyout/menu-flyout.tsx +++ b/packages/components/src/components/menu-flyout/menu-flyout.tsx @@ -23,6 +23,7 @@ import { } from '@stencil/core'; import classNames from 'classnames'; import statusNote from '../../utils/status-note'; +import { emitEvent } from '../../utils/utils'; // [ ] Add keyboard controls // [ ] Hover to open ? @@ -66,17 +67,31 @@ export class MenuFlyout { /* 4. Events (alphabetical) */ /** Event triggered when menu list opened */ - @Event() scaleOpen: EventEmitter<{ + @Event({ eventName: 'scale-open' }) scaleOpen: EventEmitter<{ + id: number; + cascadeLevel: number; + }>; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleOpen' }) scaleOpenLegacy: EventEmitter<{ id: number; cascadeLevel: number; }>; /** Event triggered when menu list closed */ - @Event() scaleClose: EventEmitter<{ + @Event({ eventName: 'scale-close' }) scaleClose: EventEmitter<{ + id: number; + cascadeLevel: number; + }>; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleClose' }) scaleCloseLegacy: EventEmitter<{ id: number; cascadeLevel: number; }>; /** Event triggered when nested menu item selected */ - @Event() scaleSelect: EventEmitter<{ + @Event({ eventName: 'scale-select' }) scaleSelect: EventEmitter<{ + item: HTMLElement; + }>; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleSelect' }) scaleSelectLegacy: EventEmitter<{ item: HTMLElement; }>; @@ -197,7 +212,7 @@ export class MenuFlyout { } // Listen for cascaded menu closes to also close - @Listen('scaleClose') + @Listen('scale-close') childClosedHandler({ detail }) { // Ignore events from self if (detail.id === this.id) { @@ -208,7 +223,7 @@ export class MenuFlyout { } // Listen for cascaded menu closes to also close - @Listen('scaleOpen', { target: 'body' }) + @Listen('scale-open', { target: 'body' }) relativeOpenHandler({ detail }) { // Ignore events from self if (detail.id === this.id) { @@ -397,9 +412,9 @@ export class MenuFlyout { emitOpenState() { const { id, cascadeLevel } = this; if (this.open) { - this.scaleOpen.emit({ id, cascadeLevel }); + emitEvent(this, 'scaleOpen', { id, cascadeLevel }); } else { - this.scaleClose.emit({ id, cascadeLevel }); + emitEvent(this, 'scaleClose', { id, cascadeLevel }); } } @@ -431,7 +446,7 @@ export class MenuFlyout { // Make sure isn't disabled or a cascading menu if (item && !item.disabled && !item.cascade) { // Send event in case developer listening on the menu and not items individually - this.scaleSelect.emit({ item }); + emitEvent(this, 'scaleSelect', { item }); if (this.closeOnSelect) { this.toggleOpenState(); } diff --git a/packages/components/src/components/menu-flyout/readme.md b/packages/components/src/components/menu-flyout/readme.md index 2eb17b0709..38e325e36d 100644 --- a/packages/components/src/components/menu-flyout/readme.md +++ b/packages/components/src/components/menu-flyout/readme.md @@ -17,11 +17,14 @@ ## Events -| Event | Description | Type | -| ------------- | ---------------------------------------------- | ---------------------------------------------------- | -| `scaleClose` | Event triggered when menu list closed | `CustomEvent<{ id: number; cascadeLevel: number; }>` | -| `scaleOpen` | Event triggered when menu list opened | `CustomEvent<{ id: number; cascadeLevel: number; }>` | -| `scaleSelect` | Event triggered when nested menu item selected | `CustomEvent<{ item: HTMLElement; }>` | +| Event | Description | Type | +| -------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| `scale-close` | Event triggered when menu list closed | `CustomEvent<{ id: number; cascadeLevel: number; }>` | +| `scale-open` | Event triggered when menu list opened | `CustomEvent<{ id: number; cascadeLevel: number; }>` | +| `scale-select` | Event triggered when nested menu item selected | `CustomEvent<{ item: HTMLElement; }>` | +| `scaleClose` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent<{ id: number; cascadeLevel: number; }>` | +| `scaleOpen` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent<{ id: number; cascadeLevel: number; }>` | +| `scaleSelect` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent<{ item: HTMLElement; }>` | ## Dependencies diff --git a/packages/components/src/components/modal/modal.tsx b/packages/components/src/components/modal/modal.tsx index f41db98730..75c46cfcf9 100644 --- a/packages/components/src/components/modal/modal.tsx +++ b/packages/components/src/components/modal/modal.tsx @@ -24,6 +24,7 @@ import { import classNames from 'classnames'; import { queryShadowRoot, isHidden, isFocusable } from '../../utils/focus-trap'; import { animateTo, KEYFRAMES } from '../../utils/animate'; +import { emitEvent } from '../../utils/utils'; const supportsResizeObserver = 'ResizeObserver' in window; @@ -74,11 +75,19 @@ export class Modal { @State() hasScroll: boolean = false; /** Fires when the modal has been opened */ - @Event() scaleOpen: EventEmitter; + @Event({ eventName: 'scale-open' }) scaleOpen: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleOpen' }) scaleOpenLegacy: EventEmitter; /** Fires on every close attempt. Calling `event.preventDefault()` will prevent the modal from closing */ - @Event() scaleBeforeClose: EventEmitter; + @Event({ eventName: 'scale-before-close' }) + scaleBeforeClose: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleBeforeClose' }) + scaleBeforeCloseLegacy: EventEmitter; /** Fires when the modal has been closed */ - @Event() scaleClose: EventEmitter; + @Event({ eventName: 'scale-close' }) scaleClose: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleClose' }) scaleCloseLegacy: EventEmitter; private closeButton: HTMLButtonElement | HTMLScaleButtonElement; private modalContainer: HTMLElement; @@ -194,10 +203,10 @@ export class Modal { }); anim.addEventListener('finish', () => { this.attemptFocus(this.getFirstFocusableElement()); - this.scaleOpen.emit(); + emitEvent(this, 'scaleOpen'); }); } catch (err) { - this.scaleOpen.emit(); + emitEvent(this, 'scaleOpen'); } } @@ -208,11 +217,11 @@ export class Modal { }); anim.addEventListener('finish', () => { this.isOpen = false; - this.scaleClose.emit(); + emitEvent(this, 'scaleClose'); }); } catch (err) { this.isOpen = false; - this.scaleClose.emit(); + emitEvent(this, 'scaleClose'); } } diff --git a/packages/components/src/components/modal/readme.md b/packages/components/src/components/modal/readme.md index f32e8d6eb8..ecf67671e5 100644 --- a/packages/components/src/components/modal/readme.md +++ b/packages/components/src/components/modal/readme.md @@ -21,11 +21,14 @@ ## Events -| Event | Description | Type | -| ------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------------- | -| `scaleBeforeClose` | Fires on every close attempt. Calling `event.preventDefault()` will prevent the modal from closing | `CustomEvent` | -| `scaleClose` | Fires when the modal has been closed | `CustomEvent` | -| `scaleOpen` | Fires when the modal has been opened | `CustomEvent` | +| Event | Description | Type | +| -------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `scale-before-close` | Fires on every close attempt. Calling `event.preventDefault()` will prevent the modal from closing | `CustomEvent` | +| `scale-close` | Fires when the modal has been closed | `CustomEvent` | +| `scale-open` | Fires when the modal has been opened | `CustomEvent` | +| `scaleBeforeClose` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleClose` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleOpen` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Shadow Parts diff --git a/packages/components/src/components/pagination/pagination.spec.ts b/packages/components/src/components/pagination/pagination.spec.ts index 032f8a6a9f..5e72c5be5e 100644 --- a/packages/components/src/components/pagination/pagination.spec.ts +++ b/packages/components/src/components/pagination/pagination.spec.ts @@ -41,42 +41,54 @@ describe('pagination', () => { }); it('should emit when clicked goFirstPage()', async () => { const clickSpy = jest.fn(); - page.doc.addEventListener('scalePagination', clickSpy); + const clickSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-pagination', clickSpy); + page.doc.addEventListener('scalePagination', clickSpyLegacy); const buttonElement = page.root.shadowRoot.querySelector( '.pagination__first-prompt' ) as HTMLElement; buttonElement.click(); await page.waitForChanges(); expect(clickSpy).toHaveBeenCalled(); + expect(clickSpyLegacy).toHaveBeenCalled(); }); it('should emit when clicked goPreviousPage()', async () => { const clickSpy = jest.fn(); - page.doc.addEventListener('scalePagination', clickSpy); + const clickSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-pagination', clickSpy); + page.doc.addEventListener('scalePagination', clickSpyLegacy); const buttonElement = page.root.shadowRoot.querySelector( '.pagination__prev-prompt' ) as HTMLElement; buttonElement.click(); await page.waitForChanges(); expect(clickSpy).toHaveBeenCalled(); + expect(clickSpyLegacy).toHaveBeenCalled(); }); it('should emit when clicked goNextPage()', async () => { const clickSpy = jest.fn(); - page.doc.addEventListener('scalePagination', clickSpy); + const clickSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-pagination', clickSpy); + page.doc.addEventListener('scalePagination', clickSpyLegacy); const buttonElement = page.root.shadowRoot.querySelector( '.pagination__next-prompt' ) as HTMLElement; buttonElement.click(); await page.waitForChanges(); expect(clickSpy).toHaveBeenCalled(); + expect(clickSpyLegacy).toHaveBeenCalled(); }); it('should emit when clicked golastPage()', async () => { const clickSpy = jest.fn(); - page.doc.addEventListener('scalePagination', clickSpy); + const clickSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-pagination', clickSpy); + page.doc.addEventListener('scalePagination', clickSpyLegacy); const buttonElement = page.root.shadowRoot.querySelector( '.pagination__last-prompt' ) as HTMLElement; buttonElement.click(); await page.waitForChanges(); expect(clickSpy).toHaveBeenCalled(); + expect(clickSpyLegacy).toHaveBeenCalled(); }); }); diff --git a/packages/components/src/components/pagination/pagination.tsx b/packages/components/src/components/pagination/pagination.tsx index 4b0ad82802..5ddda9da24 100644 --- a/packages/components/src/components/pagination/pagination.tsx +++ b/packages/components/src/components/pagination/pagination.tsx @@ -21,6 +21,7 @@ import { } from '@stencil/core'; import classNames from 'classnames'; import statusNote from '../../utils/status-note'; +import { emitEvent } from '../../utils/utils'; /* TODO @@ -70,11 +71,15 @@ export class Pagination { /* 4. Events (alphabetical) */ /** Event triggered every time the data is edited, changing original rows data */ - @Event() scalePagination: EventEmitter<{ + @Event({ eventName: 'scale-pagination' }) scalePagination: EventEmitter<{ + startElement?: number; + currentPage?: number; + }>; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scalePagination' }) scalePaginationLegacy: EventEmitter<{ startElement?: number; currentPage?: number; }>; - /* 5. Private Properties (alphabetical) */ /** Calculated width of largest text so buttons don't move while changing pages */ maxWidth: number = 100; @@ -130,7 +135,7 @@ export class Pagination { const data = { startElement: this.startElement, }; - this.scalePagination.emit(data); + emitEvent(this, 'scalePagination', data); } /* 10. Render */ diff --git a/packages/components/src/components/pagination/readme.md b/packages/components/src/components/pagination/readme.md index b3ffef2d6e..5108463182 100644 --- a/packages/components/src/components/pagination/readme.md +++ b/packages/components/src/components/pagination/readme.md @@ -23,9 +23,10 @@ ## Events -| Event | Description | Type | -| ----------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------- | -| `scalePagination` | Event triggered every time the data is edited, changing original rows data | `CustomEvent<{ startElement?: number; currentPage?: number; }>` | +| Event | Description | Type | +| ------------------ | -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | +| `scale-pagination` | Event triggered every time the data is edited, changing original rows data | `CustomEvent<{ startElement?: number; currentPage?: number; }>` | +| `scalePagination` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent<{ startElement?: number; currentPage?: number; }>` | ## Shadow Parts diff --git a/packages/components/src/components/radio-button/radio-button.spec.ts b/packages/components/src/components/radio-button/radio-button.spec.ts index 1f686b420a..e7193e0890 100644 --- a/packages/components/src/components/radio-button/radio-button.spec.ts +++ b/packages/components/src/components/radio-button/radio-button.spec.ts @@ -36,11 +36,14 @@ describe('RadioButton', () => { html: ``, }); const changeSpy = jest.fn(); + const changeSpyLegacy = jest.fn(); page.rootInstance.checked = true; - page.doc.addEventListener('scaleChange', changeSpy); + page.doc.addEventListener('scale-change', changeSpy); + page.doc.addEventListener('scaleChange', changeSpyLegacy); const element = page.root.querySelector('input'); element.dispatchEvent(new Event('change')); await page.waitForChanges(); expect(changeSpy).toHaveBeenCalled(); + expect(changeSpyLegacy).toHaveBeenCalled(); }); }); diff --git a/packages/components/src/components/radio-button/radio-button.tsx b/packages/components/src/components/radio-button/radio-button.tsx index 5cae797f88..b7e1b5dfa9 100644 --- a/packages/components/src/components/radio-button/radio-button.tsx +++ b/packages/components/src/components/radio-button/radio-button.tsx @@ -11,6 +11,7 @@ import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core'; import classNames from 'classnames'; +import { emitEvent } from '../../utils/utils'; interface InputChangeEventDetail { value: string | number | boolean | undefined | null; @@ -43,7 +44,11 @@ export class RadioButton { /** (optional) Injected CSS styles */ @Prop() styles?: string; - @Event() scaleChange!: EventEmitter; + @Event({ eventName: 'scale-change' }) + scaleChange!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) + scaleChangeLegacy!: EventEmitter; componentWillLoad() { if (this.inputId == null) { @@ -57,7 +62,7 @@ export class RadioButton { if (this.checked) { this.uncheckSiblings(); } - this.scaleChange.emit({ + emitEvent(this, 'scaleChange', { value: this.value == null ? this.value : this.value.toString(), }); }; diff --git a/packages/components/src/components/radio-button/readme.md b/packages/components/src/components/radio-button/readme.md index 4e844126f8..bd9a6f9d4f 100644 --- a/packages/components/src/components/radio-button/readme.md +++ b/packages/components/src/components/radio-button/readme.md @@ -22,9 +22,10 @@ ## Events -| Event | Description | Type | -| ------------- | ----------- | ------------------------------------- | -| `scaleChange` | | `CustomEvent` | +| Event | Description | Type | +| -------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `scale-change` | | `CustomEvent` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ---------------------------------------------- diff --git a/packages/components/src/components/rating-stars/rating-stars.tsx b/packages/components/src/components/rating-stars/rating-stars.tsx index 0caec8a4f0..7b19d0979f 100644 --- a/packages/components/src/components/rating-stars/rating-stars.tsx +++ b/packages/components/src/components/rating-stars/rating-stars.tsx @@ -18,6 +18,7 @@ import { Event, EventEmitter, } from '@stencil/core'; +import { emitEvent } from '../../utils/utils'; export interface StarInterface extends HTMLDivElement { dataset: { @@ -59,7 +60,9 @@ export class RatingStars { @Prop({ reflect: true }) label?: string; /** Emitted when the rating has changed */ - @Event() scaleChange: EventEmitter; + @Event({ eventName: 'scale-change' }) scaleChange: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) scaleChangeLegacy: EventEmitter; // constructs the aria message for the current rating getRatingText() { @@ -85,7 +88,7 @@ export class RatingStars { this.rating = Number(input.value); - this.scaleChange.emit({ value: this.rating }); + emitEvent(this, 'scaleChange', { value: this.rating }); }; handleStarClick = (ev: MouseEvent) => { @@ -101,7 +104,7 @@ export class RatingStars { } else { this.rating = starValue; } - this.scaleChange.emit({ value: this.rating }); + emitEvent(this, 'scaleChange', { value: this.rating }); }; renderStar(index: number, selected = false, rating: number) { diff --git a/packages/components/src/components/rating-stars/readme.md b/packages/components/src/components/rating-stars/readme.md index b1f58e77f3..c1b10b772a 100644 --- a/packages/components/src/components/rating-stars/readme.md +++ b/packages/components/src/components/rating-stars/readme.md @@ -21,9 +21,10 @@ ## Events -| Event | Description | Type | -| ------------- | ----------------------------------- | ------------------ | -| `scaleChange` | Emitted when the rating has changed | `CustomEvent` | +| Event | Description | Type | +| -------------- | -------------------------------------------------------------------------------------------------- | ------------------ | +| `scale-change` | Emitted when the rating has changed | `CustomEvent` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Shadow Parts diff --git a/packages/components/src/components/slider/readme.md b/packages/components/src/components/slider/readme.md index 8d899c82d2..e4f9af934e 100644 --- a/packages/components/src/components/slider/readme.md +++ b/packages/components/src/components/slider/readme.md @@ -27,10 +27,12 @@ ## Events -| Event | Description | Type | -| ------------- | ----------- | --------------------- | -| `scaleChange` | | `CustomEvent` | -| `scaleInput` | | `CustomEvent` | +| Event | Description | Type | +| -------------- | -------------------------------------------------------------------------------------------------- | --------------------- | +| `scale-change` | | `CustomEvent` | +| `scale-input` | | `CustomEvent` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleInput` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Shadow Parts diff --git a/packages/components/src/components/slider/slider.spec.ts b/packages/components/src/components/slider/slider.spec.ts index 05e09c66a1..171f5dd07f 100644 --- a/packages/components/src/components/slider/slider.spec.ts +++ b/packages/components/src/components/slider/slider.spec.ts @@ -142,6 +142,22 @@ describe('Slider', () => { expect(await page.rootInstance.value).toBe(51); }); + it('input events', async () => { + const page = await newSpecPage({ + components: [Slider], + html: ``, + }); + const inputSpy = jest.fn(); + const inputSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-input', inputSpy); + page.doc.addEventListener('scaleInput', inputSpyLegacy); + const element = page.root.shadowRoot.querySelector('.slider__thumb'); + element.dispatchEvent(new Event('keydown')); + await page.waitForChanges(); + expect(inputSpy).toHaveBeenCalled(); + expect(inputSpyLegacy).toHaveBeenCalled(); + }); + it('keydown .slider__thumb with ArrowUp', async () => { const page = await newSpecPage({ components: [Slider], diff --git a/packages/components/src/components/slider/slider.tsx b/packages/components/src/components/slider/slider.tsx index b5157290ff..d55c264801 100644 --- a/packages/components/src/components/slider/slider.tsx +++ b/packages/components/src/components/slider/slider.tsx @@ -22,6 +22,7 @@ import { EventEmitter, } from '@stencil/core'; import classNames from 'classnames'; +import { emitEvent } from '../../utils/utils'; let i = 0; @@ -65,8 +66,13 @@ export class Slider { // The actual position in % of the slider thumb @State() position: number; - @Event() scaleChange: EventEmitter; - @Event() scaleInput: EventEmitter; + @Event({ eventName: 'scale-change' }) scaleChange: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) scaleChangeLegacy: EventEmitter; + + @Event({ eventName: 'scale-input' }) scaleInput: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleInput' }) scaleInputLegacy: EventEmitter; private dragging: boolean; private offsetLeft: number; @@ -127,7 +133,7 @@ export class Slider { onDragEnd = () => { this.dragging = false; - this.scaleChange.emit(this.value); + emitEvent(this, 'scaleChange', this.value); this.removeGlobalListeners(); }; @@ -137,7 +143,7 @@ export class Slider { setValue = (nextValue: number) => { this.value = this.clamp(nextValue); - this.scaleInput.emit(this.value); + emitEvent(this, 'scaleInput', this.value); }; @Watch('value') diff --git a/packages/components/src/components/switch/readme.md b/packages/components/src/components/switch/readme.md index fb193b09d0..d79a4e50d5 100644 --- a/packages/components/src/components/switch/readme.md +++ b/packages/components/src/components/switch/readme.md @@ -18,9 +18,10 @@ ## Events -| Event | Description | Type | -| ------------- | ----------------------------------- | ------------------ | -| `scaleChange` | Emitted when the switch was clicked | `CustomEvent` | +| Event | Description | Type | +| -------------- | -------------------------------------------------------------------------------------------------- | ------------------ | +| `scale-change` | Emitted when the switch was clicked | `CustomEvent` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Dependencies diff --git a/packages/components/src/components/switch/switch.tsx b/packages/components/src/components/switch/switch.tsx index 348fe14e0e..4b5f3e6633 100644 --- a/packages/components/src/components/switch/switch.tsx +++ b/packages/components/src/components/switch/switch.tsx @@ -12,6 +12,7 @@ import { Component, h, Prop, Host, Event, EventEmitter } from '@stencil/core'; import { isPseudoClassSupported } from '../../utils/utils'; import classNames from 'classnames'; +import { emitEvent } from '../../utils/utils'; let i = 0; @@ -36,7 +37,9 @@ export class Switch { @Prop() styles?: string; /** Emitted when the switch was clicked */ - @Event() scaleChange!: EventEmitter; + @Event({ eventName: 'scale-change' }) scaleChange!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) scaleChangeLegacy!: EventEmitter; componentWillLoad() { if (this.inputId == null) { @@ -59,7 +62,7 @@ export class Switch { onChange={(e: any) => { this.checked = e.target.checked; // bubble event through the shadow dom - this.scaleChange.emit({ value: this.checked }); + emitEvent(this, 'scaleChange', { value: this.checked }); }} />
diff --git a/packages/components/src/components/tag/readme.md b/packages/components/src/components/tag/readme.md index 8db8d043a8..29ba4f64e4 100644 --- a/packages/components/src/components/tag/readme.md +++ b/packages/components/src/components/tag/readme.md @@ -45,9 +45,10 @@ ## Events -| Event | Description | Type | -| ------------ | --------------------------------- | ------------------------- | -| `scaleClose` | (optional) Close icon click event | `CustomEvent` | +| Event | Description | Type | +| ------------- | -------------------------------------------------------------------------------------------------- | ------------------------- | +| `scale-close` | (optional) Close icon click event | `CustomEvent` | +| `scaleClose` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Shadow Parts diff --git a/packages/components/src/components/tag/tag.tsx b/packages/components/src/components/tag/tag.tsx index bc77722164..6d2acac38e 100644 --- a/packages/components/src/components/tag/tag.tsx +++ b/packages/components/src/components/tag/tag.tsx @@ -11,6 +11,7 @@ import { Component, Prop, h, Host, Event, EventEmitter } from '@stencil/core'; import classNames from 'classnames'; +import { emitEvent } from '../../utils/utils'; @Component({ tag: 'scale-tag', styleUrl: './tag.css', @@ -35,7 +36,10 @@ export class Tag { @Prop() styles?: string; /** (optional) Close icon click event */ - @Event() scaleClose: EventEmitter; + @Event({ eventName: 'scale-close' }) scaleClose: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleClose' }) + scaleCloseLegacy: EventEmitter; componentWillUpdate() {} disconnectedCallback() {} @@ -46,7 +50,7 @@ export class Tag { if (this.disabled) { return; } - this.scaleClose.emit(event); + emitEvent(this, 'scaleClose', event); }; render() { diff --git a/packages/components/src/components/text-field/readme.md b/packages/components/src/components/text-field/readme.md index e8b3a0e780..0f10080a25 100644 --- a/packages/components/src/components/text-field/readme.md +++ b/packages/components/src/components/text-field/readme.md @@ -31,13 +31,18 @@ ## Events -| Event | Description | Type | -| -------------- | --------------------------------------- | ------------------------------------- | -| `scaleBlur` | Emitted when the input loses focus. | `CustomEvent` | -| `scaleChange` | Emitted when the value has changed. | `CustomEvent` | -| `scaleFocus` | Emitted when the input has focus. | `CustomEvent` | -| `scaleInput` | Emitted when a keyboard input occurred. | `CustomEvent` | -| `scaleKeyDown` | Emitted on keydown. | `CustomEvent` | +| Event | Description | Type | +| --------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `scale-blur` | Emitted when the input loses focus. | `CustomEvent` | +| `scale-change` | Emitted when the value has changed. | `CustomEvent` | +| `scale-focus` | Emitted when the input has focus. | `CustomEvent` | +| `scale-input` | Emitted when a keyboard input occurred. | `CustomEvent` | +| `scale-keydown` | Emitted on keydown. | `CustomEvent` | +| `scaleBlur` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleFocus` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleInput` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleKeydown` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ## Dependencies diff --git a/packages/components/src/components/text-field/text-field.spec.ts b/packages/components/src/components/text-field/text-field.spec.ts index 63445d3a2c..b8965c480e 100644 --- a/packages/components/src/components/text-field/text-field.spec.ts +++ b/packages/components/src/components/text-field/text-field.spec.ts @@ -102,14 +102,17 @@ describe('TextField', () => { it('should emit on input', async () => { const inputSpy = jest.fn(); - page.doc.addEventListener('scaleInput', inputSpy); + const inputSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-input', inputSpy); + page.doc.addEventListener('scaleInput', inputSpyLegacy); const inputField = page.doc.querySelector('input'); inputField.value = TEST_VALUE; await inputField.dispatchEvent(new Event('input')); await page.waitForChanges(); expect(inputSpy).toHaveBeenCalled(); + expect(inputSpyLegacy).toHaveBeenCalled(); }); - it('should emit on change', async () => { + it('should react on change event', async () => { // const changeSpy = jest.fn(); // page.doc.addEventListener('scaleChange', changeSpy); const inputField = page.doc.querySelector('input'); @@ -123,39 +126,51 @@ describe('TextField', () => { expect(page.rootInstance.value).toBe(''); // expect(changeSpy).toHaveBeenCalled(); }); - it('', async () => { + it('should emit on change', async () => { const emitSpy = jest.fn(); - page.doc.addEventListener('scaleChange', emitSpy); + const emitSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-change', emitSpy); + page.doc.addEventListener('scaleChange', emitSpyLegacy); page.rootInstance.emitChange(); await page.waitForChanges(); expect(emitSpy).toHaveBeenCalled(); + expect(emitSpyLegacy).toHaveBeenCalled(); }); it('should emit on focus', async () => { const focusSpy = jest.fn(); - page.doc.addEventListener('scaleFocus', focusSpy); + const focusSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-focus', focusSpy); + page.doc.addEventListener('scaleFocus', focusSpyLegacy); const inputField = page.doc.querySelector('input'); inputField.value = TEST_VALUE; await inputField.dispatchEvent(new Event('focus')); await page.waitForChanges(); expect(focusSpy).toHaveBeenCalled(); + expect(focusSpyLegacy).toHaveBeenCalled(); }); it('should emit on blur', async () => { const blurSpy = jest.fn(); - page.doc.addEventListener('scaleBlur', blurSpy); + const blurSpyLegacy = jest.fn(); + page.doc.addEventListener('scale-blur', blurSpy); + page.doc.addEventListener('scaleBlur', blurSpyLegacy); const inputField = page.doc.querySelector('input'); inputField.value = TEST_VALUE; await inputField.dispatchEvent(new Event('blur')); await page.waitForChanges(); expect(blurSpy).toHaveBeenCalled(); + expect(blurSpyLegacy).toHaveBeenCalled(); }); it('should emit on keydown', async () => { const keyDownSpy = jest.fn(); - page.doc.addEventListener('scaleKeyDown', keyDownSpy); + const keyDownSpyLegacy = jest.fn(); + page.doc.addEventListener('scaleKeydown', keyDownSpyLegacy); + page.doc.addEventListener('scale-keydown', keyDownSpy); const inputField = page.doc.querySelector('input'); inputField.value = TEST_VALUE; await inputField.dispatchEvent(new Event('keydown')); await page.waitForChanges(); expect(keyDownSpy).toHaveBeenCalled(); + expect(keyDownSpyLegacy).toHaveBeenCalled(); }); it('should handle css classes', () => { @@ -187,17 +202,4 @@ describe('TextField', () => { element.handleBlur(); expect(element.hasFocus).toBeFalsy(); }); - - it('should emit on emitchange', async () => { - const inputSpy = jest.fn(); - const emitSpy = jest.fn(); - page.doc.addEventListener('scaleInput', inputSpy); - page.doc.addEventListener('scaleChange', emitSpy); - const inputField = page.doc.querySelector('input'); - inputField.value = TEST_VALUE; - await inputField.dispatchEvent(new Event('input')); - await page.waitForChanges(); - expect(inputSpy).toHaveBeenCalled(); - expect(emitSpy).toHaveBeenCalled(); - }); }); diff --git a/packages/components/src/components/text-field/text-field.tsx b/packages/components/src/components/text-field/text-field.tsx index c3a60fa39c..a665a864a1 100644 --- a/packages/components/src/components/text-field/text-field.tsx +++ b/packages/components/src/components/text-field/text-field.tsx @@ -19,6 +19,7 @@ import { State, } from '@stencil/core'; import classNames from 'classnames'; +import { emitEvent } from '../../utils/utils'; interface InputChangeEventDetail { value: string | number | boolean | undefined | null; @@ -79,15 +80,30 @@ export class TextField { @Prop() styles?: string; /** Emitted when a keyboard input occurred. */ - @Event() scaleInput!: EventEmitter; + @Event({ eventName: 'scale-input' }) scaleInput!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleInput' }) + scaleInputLegacy!: EventEmitter; /** Emitted when the value has changed. */ - @Event() scaleChange!: EventEmitter; + @Event({ eventName: 'scale-change' }) + scaleChange!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) + scaleChangeLegacy!: EventEmitter; /** Emitted when the input has focus. */ - @Event() scaleFocus!: EventEmitter; + @Event({ eventName: 'scale-focus' }) scaleFocus!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleFocus' }) scaleFocusLegacy!: EventEmitter; /** Emitted when the input loses focus. */ - @Event() scaleBlur!: EventEmitter; + @Event({ eventName: 'scale-blur' }) scaleBlur!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleBlur' }) scaleBlurLegacy!: EventEmitter; /** Emitted on keydown. */ - @Event() scaleKeyDown!: EventEmitter; + @Event({ eventName: 'scale-keydown' }) + scaleKeyDown!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleKeydown' }) + scaleKeyDownLegacy!: EventEmitter; /** Whether the input element has focus */ @State() hasFocus: boolean = false; @@ -104,7 +120,7 @@ export class TextField { // `this.value = selectedValue` emitChange() { - this.scaleChange.emit({ + emitEvent(this, 'scaleChange', { value: this.value == null ? this.value : this.value.toString(), }); } @@ -115,7 +131,7 @@ export class TextField { this.value = target.value || ''; this.emitChange(); } - this.scaleInput.emit(event as KeyboardEvent); + emitEvent(this, 'scaleInput', event as KeyboardEvent); }; handleChange = (event: Event) => { @@ -127,17 +143,17 @@ export class TextField { }; handleFocus = () => { - this.scaleFocus.emit(); + emitEvent(this, 'scaleFocus'); this.hasFocus = true; }; handleBlur = () => { - this.scaleBlur.emit(); + emitEvent(this, 'scaleBlur'); this.hasFocus = false; }; handleKeyDown = (event: KeyboardEvent) => { - this.scaleKeyDown.emit(event); + emitEvent(this, 'scaleKeyDown', event); }; render() { diff --git a/packages/components/src/components/textarea/readme.md b/packages/components/src/components/textarea/readme.md index 25688dd229..7cce549361 100644 --- a/packages/components/src/components/textarea/readme.md +++ b/packages/components/src/components/textarea/readme.md @@ -31,13 +31,18 @@ ## Events -| Event | Description | Type | -| -------------- | --------------------------------------- | ------------------------------------- | -| `scaleBlur` | Emitted when the input loses focus. | `CustomEvent` | -| `scaleChange` | Emitted when the value has changed. | `CustomEvent` | -| `scaleFocus` | Emitted when the input has focus. | `CustomEvent` | -| `scaleInput` | Emitted when a keyboard input occurred. | `CustomEvent` | -| `scaleKeyDown` | Emitted on keydown. | `CustomEvent` | +| Event | Description | Type | +| --------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `scale-blur` | Emitted when the input loses focus. | `CustomEvent` | +| `scale-change` | Emitted when the value has changed. | `CustomEvent` | +| `scale-focus` | Emitted when the input has focus. | `CustomEvent` | +| `scale-input` | Emitted when a keyboard input occurred. | `CustomEvent` | +| `scale-keydown` | Emitted on keydown. | `CustomEvent` | +| `scaleBlur` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleChange` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleFocus` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleInput` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | +| `scaleKeyDown` | **[DEPRECATED]** in v3 in favor of kebab-case event names

| `CustomEvent` | ---------------------------------------------- diff --git a/packages/components/src/components/textarea/textarea.spec.ts b/packages/components/src/components/textarea/textarea.spec.ts index b1745abab5..8c95febb23 100644 --- a/packages/components/src/components/textarea/textarea.spec.ts +++ b/packages/components/src/components/textarea/textarea.spec.ts @@ -145,53 +145,68 @@ describe('Textarea', () => { it('onKeyDown', async () => { const mock = jest.fn(); - page.root.addEventListener('scaleKeyDown', mock); + const mockLegacy = jest.fn(); + page.root.addEventListener('scaleKeyDown', mockLegacy); + page.root.addEventListener('scale-keydown', mock); const target = page.root.querySelector('.textarea__control'); await page.waitForChanges(); - target.dispatchEvent(new KeyboardEvent('keydown')); + await target.dispatchEvent(new KeyboardEvent('keydown')); await page.waitForChanges(); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); }); it('onBlur', async () => { const mock = jest.fn(); - page.root.addEventListener('scaleBlur', mock); + const mockLegacy = jest.fn(); + page.root.addEventListener('scale-blur', mock); + page.root.addEventListener('scaleBlur', mockLegacy); const target = page.root.querySelector('.textarea__control'); await page.waitForChanges(); target.dispatchEvent(new Event('blur')); await page.waitForChanges(); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); }); it('onFocus', async () => { const mock = jest.fn(); - page.root.addEventListener('scaleFocus', mock); + const mockLegacy = jest.fn(); + page.root.addEventListener('scale-focus', mock); + page.root.addEventListener('scaleFocus', mockLegacy); const target = page.root.querySelector('.textarea__control'); await page.waitForChanges(); target.dispatchEvent(new Event('focus')); await page.waitForChanges(); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); }); it('onInput', async () => { const mock = jest.fn(); - page.root.addEventListener('scaleInput', mock); + const mockLegacy = jest.fn(); + page.root.addEventListener('scale-input', mock); + page.root.addEventListener('scaleInput', mockLegacy); const target = page.root.querySelector('.textarea__control'); await page.waitForChanges(); target.dispatchEvent(new Event('input')); await page.waitForChanges(); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); }); it('onChange', async () => { const mock = jest.fn(); + const mockLegacy = jest.fn(); page.root.emitChange = jest.fn(); + page.root.addEventListener('scale-change', mockLegacy); page.root.addEventListener('scaleChange', mock); const target = page.root.querySelector('.textarea__control'); await page.waitForChanges(); target.dispatchEvent(new Event('change')); await page.waitForChanges(); expect(mock).toHaveBeenCalled(); + expect(mockLegacy).toHaveBeenCalled(); expect(page.root.emitChange).not.toHaveBeenCalled(); }); }); diff --git a/packages/components/src/components/textarea/textarea.tsx b/packages/components/src/components/textarea/textarea.tsx index 92cf018f5e..f44b776dfc 100644 --- a/packages/components/src/components/textarea/textarea.tsx +++ b/packages/components/src/components/textarea/textarea.tsx @@ -19,6 +19,7 @@ import { State, } from '@stencil/core'; import classNames from 'classnames'; +import { emitEvent } from '../../utils/utils'; interface InputChangeEventDetail { value: string | number | boolean | undefined | null; @@ -70,15 +71,30 @@ export class Textarea { @Prop() styles?: string; /** Emitted when a keyboard input occurred. */ - @Event() scaleInput!: EventEmitter; + @Event({ eventName: 'scale-input' }) scaleInput!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleInput' }) + scaleInputLegacy!: EventEmitter; /** Emitted when the value has changed. */ - @Event() scaleChange!: EventEmitter; + @Event({ eventName: 'scale-change' }) + scaleChange!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleChange' }) + scaleChangeLegacy!: EventEmitter; /** Emitted when the input has focus. */ - @Event() scaleFocus!: EventEmitter; + @Event({ eventName: 'scale-focus' }) scaleFocus!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleFocus' }) scaleFocusLegacy!: EventEmitter; /** Emitted when the input loses focus. */ - @Event() scaleBlur!: EventEmitter; + @Event({ eventName: 'scale-blur' }) scaleBlur!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleBlur' }) scaleBlurLegacy!: EventEmitter; /** Emitted on keydown. */ - @Event() scaleKeyDown!: EventEmitter; + @Event({ eventName: 'scale-keydown' }) + scaleKeyDown!: EventEmitter; + /** @deprecated in v3 in favor of kebab-case event names */ + @Event({ eventName: 'scaleKeyDown' }) + scaleKeyDownLegacy!: EventEmitter; /** Whether the input element has focus */ @State() hasFocus: boolean = false; @@ -94,7 +110,7 @@ export class Textarea { // because how we keep this.value up-to-date for type="select" // `this.value = selectedValue` emitChange() { - this.scaleChange.emit({ + emitEvent(this, 'scaleChange', { value: this.value == null ? this.value : this.value.toString(), }); } @@ -105,7 +121,7 @@ export class Textarea { this.value = target.value || ''; this.emitChange(); } - this.scaleInput.emit(event as KeyboardEvent); + emitEvent(this, 'scaleInput', event as KeyboardEvent); }; handleChange = (event: Event) => { @@ -117,17 +133,17 @@ export class Textarea { }; handleFocus = () => { - this.scaleFocus.emit(); + emitEvent(this, 'scaleFocus'); this.hasFocus = true; }; handleBlur = () => { - this.scaleBlur.emit(); + emitEvent(this, 'scaleBlur'); this.hasFocus = false; }; handleKeyDown = (event: KeyboardEvent) => { - this.scaleKeyDown.emit(event); + emitEvent(this, 'scaleKeyDown', event); }; render() { diff --git a/packages/components/src/utils/utils.ts b/packages/components/src/utils/utils.ts index fabda72219..f06b4b9a17 100644 --- a/packages/components/src/utils/utils.ts +++ b/packages/components/src/utils/utils.ts @@ -1,3 +1,5 @@ +import { ComponentInterface } from '@stencil/core'; + /** * @license * Scale https://github.com/telekom/scale @@ -43,3 +45,25 @@ export const isPseudoClassSupported = (pseudoClass) => { // Run the test return testPseudo(); }; + +/** + * Call `emit` on component events twice. + * One for the legacy camel-cased event, one for the new kebab-cased. + * e.g. for the event `scaleChange` it will do `instance.scaleChange.emit()` and `instance.scaleChangeLegacy.emit()`. + * It expects both `scaleChange` and `scaleChangeLegacy` event-decorated properties to exist on the component. + * + * @param instance {ComponentInterface} - The component instance, aka `this` + * @param eventKey {string} - The event property, e.g. `scaleChange` + * @param detail {any} - The custom event `detail` + */ +export function emitEvent( + instance: ComponentInterface, + eventKey: string, + detail?: any +) { + const legacyKey = eventKey + 'Legacy'; + if (typeof instance[legacyKey] !== 'undefined') { + instance[legacyKey].emit(detail); + } + instance[eventKey].emit(detail); +} diff --git a/packages/storybook-vue/stories/3_components/checkbox/Checkbox.stories.mdx b/packages/storybook-vue/stories/3_components/checkbox/Checkbox.stories.mdx index 4ee957333e..e9ef3547a3 100644 --- a/packages/storybook-vue/stories/3_components/checkbox/Checkbox.stories.mdx +++ b/packages/storybook-vue/stories/3_components/checkbox/Checkbox.stories.mdx @@ -25,6 +25,7 @@ export const Template = (args, { argTypes }) => ({ :value="value" :input-id="inputId" @scaleChange="action('scaleChange')($event)" + @scale-change="action('scale-change')($event)" > `, methods: { diff --git a/packages/storybook-vue/stories/3_components/data-grid/DataGrid.stories.mdx b/packages/storybook-vue/stories/3_components/data-grid/DataGrid.stories.mdx index b6f8b05026..ba79d4de06 100644 --- a/packages/storybook-vue/stories/3_components/data-grid/DataGrid.stories.mdx +++ b/packages/storybook-vue/stories/3_components/data-grid/DataGrid.stories.mdx @@ -122,7 +122,7 @@ import ScaleDataGrid from './ScaleDataGrid.vue'; description: `Read-only selection array - populated with raw data from selected rows. Note needs selectable set to true`, control: { type: null }, }, - eventScaleEdit: { + eventScaleEditLegacy: { name: '[event] scaleEdit', table: { type: { summary: 'event' }, @@ -130,11 +130,27 @@ import ScaleDataGrid from './ScaleDataGrid.vue'; description: `Event triggered every time the editable cells are changed, updating the original rows data`, control: { type: null } }, - eventScaleSort: { + eventScaleEdit: { + name: '[event] scale-edit', + table: { + type: { summary: 'event' }, + }, + description: `Deprecated!: Event triggered every time the editable cells are changed, updating the original rows data`, + control: { type: null } + }, + eventScaleSortLegacy: { name: '[event] scaleSort', table: { type: { summary: 'event' }, }, + description: `Deprecated!: Event triggered every time the data is sorted, changing original rows data`, + control: { type: null } + }, + eventScaleSort: { + name: '[event] scale-sort', + table: { + type: { summary: 'event' }, + }, description: `Event triggered every time the data is sorted, changing original rows data`, control: { type: null } }, diff --git a/packages/storybook-vue/stories/3_components/date-picker/DatePicker.stories.mdx b/packages/storybook-vue/stories/3_components/date-picker/DatePicker.stories.mdx index e270f2ff9d..0c28461583 100644 --- a/packages/storybook-vue/stories/3_components/date-picker/DatePicker.stories.mdx +++ b/packages/storybook-vue/stories/3_components/date-picker/DatePicker.stories.mdx @@ -32,8 +32,11 @@ export const Template = (args, { argTypes }) => ({ :status="status" :size="size" @scaleChange="scaleChange" + @scale-change="scale-change" @scaleFocus="scaleFocus" + @scale-focus="scale-focus" @scaleBlur="scaleBlur" + @scale-blur="scale-blur" >
`, diff --git a/packages/storybook-vue/stories/3_components/date-picker/ScaleDatePicker.vue b/packages/storybook-vue/stories/3_components/date-picker/ScaleDatePicker.vue index 7abe3601b9..e2752917e2 100644 --- a/packages/storybook-vue/stories/3_components/date-picker/ScaleDatePicker.vue +++ b/packages/storybook-vue/stories/3_components/date-picker/ScaleDatePicker.vue @@ -52,13 +52,25 @@ export default { action("scaleChange"); this.$emit("scaleChange", $event); }, + 'scale-change'($event) { + action("scale-change"); + this.$emit("scale-change", $event); + }, scaleFocus($event) { action("scaleFocus"); this.$emit("scaleFocus", $event); }, + 'scale-focus'($event) { + action("scale-focus"); + this.$emit("scale-focus", $event); + }, scaleBlur($event) { action("scaleBlur"); this.$emit("scaleBlur", $event); + }, + 'scale-blur'($event) { + action("scale-blur"); + this.$emit("scale-blur", $event); } } }; diff --git a/packages/storybook-vue/stories/3_components/dropdown/ScaleDropDown.vue b/packages/storybook-vue/stories/3_components/dropdown/ScaleDropDown.vue index de29589c1d..649de0d97e 100644 --- a/packages/storybook-vue/stories/3_components/dropdown/ScaleDropDown.vue +++ b/packages/storybook-vue/stories/3_components/dropdown/ScaleDropDown.vue @@ -43,17 +43,33 @@ export default { action("scaleChange"); this.$emit("scaleChange", $event); }, + 'scale-change'($event) { + action("scale-change"); + this.$emit("scale-change", $event); + }, scaleFocus($event) { action("scaleFocus"); this.$emit("scaleFocus", $event); }, + 'scale-focus'($event) { + action("scale-focus"); + this.$emit("scale-focus", $event); + }, scaleBlur($event) { action("scaleBlur"); this.$emit("scaleBlur", $event); }, + 'scale-blur'($event) { + action("scale-blur"); + this.$emit("scale-blur", $event); + }, scaleKeyDown($event) { action("scaleKeyDown"); this.$emit("scaleKeyDown", $event); + }, + 'scale-keydown'($event) { + action("scale-keydown"); + this.$emit("scale-keydown", $event); } } }; diff --git a/packages/storybook-vue/stories/3_components/menu-flyout/MenuFlyout.stories.mdx b/packages/storybook-vue/stories/3_components/menu-flyout/MenuFlyout.stories.mdx index 95b99f56a7..d76b39055a 100644 --- a/packages/storybook-vue/stories/3_components/menu-flyout/MenuFlyout.stories.mdx +++ b/packages/storybook-vue/stories/3_components/menu-flyout/MenuFlyout.stories.mdx @@ -39,29 +39,53 @@ import ScaleMenuFlyout from './ScaleMenuFlyout.vue'; control: { type: null }, }, eventScaleOpen: { - name: '[event] scaleOpen', + name: '[event] scale-open', table: { type: { summary: 'event' }, }, description: `Event triggered when menu list opened`, control: { type: null }, }, + eventScaleOpenLegacy: { + name: '[event] scaleOpen', + table: { + type: { summary: 'event' }, + }, + description: `Deprecated!: Event triggered when menu list opened`, + control: { type: null }, + }, eventScaleClose: { - name: '[event] scaleClose', + name: '[event] scale-close', table: { type: { summary: 'event' }, }, description: `Event triggered when menu list closed`, control: { type: null }, }, + eventScaleCloseLegacy: { + name: '[event] scaleClose', + table: { + type: { summary: 'event' }, + }, + description: `Deprecated!: Event triggered when menu list closed`, + control: { type: null }, + }, eventScaleSelect: { - name: '[event] scaleSelect', + name: '[event] scale-select', table: { type: { summary: 'event' }, }, description: `Event triggered when nested menu item selected`, control: { type: null }, }, + eventScaleSelectLegacy: { + name: '[event] scaleSelect', + table: { + type: { summary: 'event' }, + }, + description: `Deprecated!: Event triggered when nested menu item selected`, + control: { type: null }, + }, slotTrigger: { name: '[slot] trigger', table: { diff --git a/packages/storybook-vue/stories/3_components/modal/ScaleModal.vue b/packages/storybook-vue/stories/3_components/modal/ScaleModal.vue index 56a997fcd8..8c17e274e9 100644 --- a/packages/storybook-vue/stories/3_components/modal/ScaleModal.vue +++ b/packages/storybook-vue/stories/3_components/modal/ScaleModal.vue @@ -41,14 +41,26 @@ export default { action("scaleOpen"); this.$emit("scaleOpen", $event); }, + 'scale-open'($event) { + action("scale-open"); + this.$emit("scale-open", $event); + }, scaleBeforeClose($event) { action("scaleBeforeClose"); this.$emit("scaleBeforeClose", $event); }, + 'scale-before-close'($event) { + action("scale-before-close"); + this.$emit("scale-before-close", $event); + }, scaleClose($event) { action("scaleClose"); this.$emit("scaleClose", $event); }, + 'scale-close'($event) { + action("scale-close"); + this.$emit("scale-close", $event); + }, } }; diff --git a/packages/storybook-vue/stories/3_components/pagination/ScalePagination.vue b/packages/storybook-vue/stories/3_components/pagination/ScalePagination.vue index 3ec943064f..9b4bc19801 100644 --- a/packages/storybook-vue/stories/3_components/pagination/ScalePagination.vue +++ b/packages/storybook-vue/stories/3_components/pagination/ScalePagination.vue @@ -10,6 +10,7 @@ :aria-label-previous-page="ariaLabelPreviousPage" :aria-label-next-page="ariaLabelNextPage" :styles="styles" + @scalePagination="scalePagination" > @@ -23,10 +24,20 @@ export default { totalElements: { type: Number, default: 1 }, styles: { type: String }, small: { type: Boolean, default: false }, - ariaLabelFirstPage: { type: String, default: 'Go to first page'}, - ariaLabelLastPage: { type: String, default: 'Go to last page'}, - ariaLabelPreviousPage: { type: String, default: 'Go to previous page'}, - ariaLabelNextPage: { type: String, default: 'Go to next page'}, + ariaLabelFirstPage: { type: String, default: 'Go to first page' }, + ariaLabelLastPage: { type: String, default: 'Go to last page' }, + ariaLabelPreviousPage: { type: String, default: 'Go to previous page' }, + ariaLabelNextPage: { type: String, default: 'Go to next page' }, + }, + methods: { + scalePagination($event) { + action('scalePagination'); + this.$emit('scalePagination', $event); + }, + 'scale-pagination'($event) { + action('scale-pagination'); + this.$emit('scale-pagination', $event); + }, }, }; diff --git a/packages/storybook-vue/stories/3_components/radio-button/ScaleRadioButton.vue b/packages/storybook-vue/stories/3_components/radio-button/ScaleRadioButton.vue index 49a0ce1671..091a2028d7 100644 --- a/packages/storybook-vue/stories/3_components/radio-button/ScaleRadioButton.vue +++ b/packages/storybook-vue/stories/3_components/radio-button/ScaleRadioButton.vue @@ -33,7 +33,11 @@ export default { scaleChange($event) { action("scaleChange"); this.$emit("scaleChange", $event); - } + }, + 'scale-change'($event) { + action("scale-change"); + this.$emit("scale-change", $event); + }, } }; diff --git a/packages/storybook-vue/stories/3_components/rating-stars/ScaleRatingStars.vue b/packages/storybook-vue/stories/3_components/rating-stars/ScaleRatingStars.vue index 66bfc5e7ad..7faf4a61ae 100644 --- a/packages/storybook-vue/stories/3_components/rating-stars/ScaleRatingStars.vue +++ b/packages/storybook-vue/stories/3_components/rating-stars/ScaleRatingStars.vue @@ -8,6 +8,7 @@ :aria-label-translation="ariaLabelTranslation" :label="label" :readonly="readonly" + @scaleChange="scaleChange" > @@ -24,5 +25,15 @@ export default { label: { type: String }, readonly: { type: Boolean, default: false }, }, + methods: { + scaleChange($event) { + action("scaleChange"); + this.$emit("scaleChange", $event); + }, + 'scale-change'($event) { + action("scale-change"); + this.$emit("scale-change", $event); + }, + } }; diff --git a/packages/storybook-vue/stories/3_components/slider/ScaleSlider.vue b/packages/storybook-vue/stories/3_components/slider/ScaleSlider.vue index 022f7d3e04..46e7c987d3 100644 --- a/packages/storybook-vue/stories/3_components/slider/ScaleSlider.vue +++ b/packages/storybook-vue/stories/3_components/slider/ScaleSlider.vue @@ -10,6 +10,8 @@ :thumb-large="thumbLarge" :step="step" :value="value" + @scaleChange="scaleChange" + @scaleInput="scaleInput" > @@ -27,6 +29,24 @@ export default { thumbLarge: { type: Boolean, default: false }, step: { type: Number, default: 1 }, value: Number + }, + methods: { + scaleChange($event) { + action("scaleChange"); + this.$emit("scaleChange", $event); + }, + 'scale-change'($event) { + action("scale-change"); + this.$emit("scale-change", $event); + }, + scaleInput($event) { + action("scaleInput"); + this.$emit("scaleInput", $event); + }, + 'scale-input'($event) { + action("scale-input"); + this.$emit("scale-input", $event); + }, } }; diff --git a/packages/storybook-vue/stories/3_components/switch/ScaleSwitch.vue b/packages/storybook-vue/stories/3_components/switch/ScaleSwitch.vue index f5d2f7eee6..e010827510 100644 --- a/packages/storybook-vue/stories/3_components/switch/ScaleSwitch.vue +++ b/packages/storybook-vue/stories/3_components/switch/ScaleSwitch.vue @@ -25,6 +25,10 @@ export default { action("scaleChange"); this.$emit("scaleChange", $event); }, + 'scale-change'($event) { + action("scale-change"); + this.$emit("scale-change", $event); + }, }, }; diff --git a/packages/storybook-vue/stories/3_components/tag/ScaleTag.vue b/packages/storybook-vue/stories/3_components/tag/ScaleTag.vue index db0bb6caad..4ec683dd4b 100644 --- a/packages/storybook-vue/stories/3_components/tag/ScaleTag.vue +++ b/packages/storybook-vue/stories/3_components/tag/ScaleTag.vue @@ -10,5 +10,15 @@ export default { variant: String, styles: String, }, + methods: { + scaleClose($event) { + action("scaleChange"); + this.$emit("scaleChange", $event); + }, + 'scale-close'($event) { + action("scale-change"); + this.$emit("scale-change", $event); + }, + } }; diff --git a/packages/storybook-vue/stories/3_components/text-area/ScaleTextArea.vue b/packages/storybook-vue/stories/3_components/text-area/ScaleTextArea.vue index 6a54ae05ff..a470cc1228 100644 --- a/packages/storybook-vue/stories/3_components/text-area/ScaleTextArea.vue +++ b/packages/storybook-vue/stories/3_components/text-area/ScaleTextArea.vue @@ -55,18 +55,34 @@ export default { action("scaleChange"); this.$emit("scaleChange", $event); }, + 'scale-change'($event) { + action("scale-change"); + this.$emit("scale-change", $event); + }, scaleFocus($event) { action("scaleFocus"); this.$emit("scaleFocus", $event); }, + 'scale-focus'($event) { + action("scale-focus"); + this.$emit("scale-focus", $event); + }, scaleBlur($event) { action("scaleBlur"); this.$emit("scaleBlur", $event); }, + 'scale-blur'($event) { + action("scale-blur"); + this.$emit("scale-blur", $event); + }, scaleKeyDown($event) { action("scaleKeyDown"); this.$emit("scaleKeyDown", $event); - } + }, + 'scale-keydown'($event) { + action("scale-keydown"); + this.$emit("scale-keydown", $event); + }, } }; diff --git a/packages/storybook-vue/stories/3_components/text-field/ScaleTextField.vue b/packages/storybook-vue/stories/3_components/text-field/ScaleTextField.vue index 954b25e0dc..8aaeedaf62 100644 --- a/packages/storybook-vue/stories/3_components/text-field/ScaleTextField.vue +++ b/packages/storybook-vue/stories/3_components/text-field/ScaleTextField.vue @@ -51,18 +51,34 @@ export default { action("scaleChange"); this.$emit("scaleChange", $event); }, + 'scale-change'($event) { + action("scale-change"); + this.$emit("scale-change", $event); + }, scaleFocus($event) { action("scaleFocus"); this.$emit("scaleFocus", $event); }, + 'scale-focus'($event) { + action("scale-focus"); + this.$emit("scale-focus", $event); + }, scaleBlur($event) { action("scaleBlur"); this.$emit("scaleBlur", $event); }, + 'scale-blur'($event) { + action("scale-blur"); + this.$emit("scale-blur", $event); + }, scaleKeyDown($event) { action("scaleKeyDown"); this.$emit("scaleKeyDown", $event); - } + }, + 'scale-keydown'($event) { + action("scale-keydown"); + this.$emit("scale-keydown", $event); + }, } }; diff --git a/packages/visual-tests/src/__image_snapshots__/accordion-visual-spec-js-accordion-standard-1-snap.png b/packages/visual-tests/src/__image_snapshots__/accordion-visual-spec-js-accordion-standard-1-snap.png index 364d04eea4..652eb2470a 100644 Binary files a/packages/visual-tests/src/__image_snapshots__/accordion-visual-spec-js-accordion-standard-1-snap.png and b/packages/visual-tests/src/__image_snapshots__/accordion-visual-spec-js-accordion-standard-1-snap.png differ diff --git a/packages/visual-tests/src/__image_snapshots__/datagrid-visual-spec-js-data-grid-checkbox-cell-1-snap.png b/packages/visual-tests/src/__image_snapshots__/datagrid-visual-spec-js-data-grid-checkbox-cell-1-snap.png index f7988b6fcc..09fba3543e 100644 Binary files a/packages/visual-tests/src/__image_snapshots__/datagrid-visual-spec-js-data-grid-checkbox-cell-1-snap.png and b/packages/visual-tests/src/__image_snapshots__/datagrid-visual-spec-js-data-grid-checkbox-cell-1-snap.png differ diff --git a/scripts/build.sh b/scripts/build.sh index b8714e4108..3cafbf70c9 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -13,5 +13,8 @@ echo "--------" echo "${GREEN}Building Vue package...${NC}" yarn workspace @telekom/scale-components-vue build; echo "--------" +echo "${GREEN}Processing Angular proxies...${NC}" +yarn workspace @telekom/scale-components process-angular-proxies; +echo "--------" echo "${GREEN}Building Angular package...${NC}" yarn workspace @telekom/scale-components-angular build; diff --git a/yarn.lock b/yarn.lock index c2389c3e5b..47b1a3c594 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3909,10 +3909,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@stencil/angular-output-target@^0.0.5": - version "0.0.5" - resolved "https://registry.yarnpkg.com/@stencil/angular-output-target/-/angular-output-target-0.0.5.tgz" - integrity sha512-00iVf0pMH5NrVc/dUDy6AOEYEwTZ816bXggzNf4gxbhLpX1RAsC+MjC0gs/sJS2gal4gpE4cTVlPCGNy+mtFXg== +"@stencil/angular-output-target@^0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@stencil/angular-output-target/-/angular-output-target-0.0.7.tgz#48a115cc5e0764a8481d9feb6e3e73f0e2ee77ff" + integrity sha512-GM+Sx0KL1cuQ4ysf20iojKBw/Yvuyx3mFWBaqSb3lDxfg4Kg5OHADoaN6L4rMZu3P3G3e2HT5Ut35BuFKIyT+Q== "@stencil/core@^2.3.0": version "2.3.0"