Skip to content

Commit

Permalink
feat(datepicker): addressing changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Leotheluck authored and dpellier committed Oct 4, 2023
1 parent e7e80c1 commit bd4dc48
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 97 deletions.
9 changes: 5 additions & 4 deletions packages/components/datepicker/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { getStencilJestConfig } from '@ovhcloud/ods-common-testing';

const config = getStencilJestConfig({
args: process.argv.slice(2),
options: {
moduleNameMapper: {
'vanillajs-datepicker': '<rootDir>/src/jestStub.js',
}
}
});

config.moduleNameMapper = {
'vanillajs-datepicker': '<rootDir>/src/jestStub.js',
}

export default config;
11 changes: 4 additions & 7 deletions packages/components/datepicker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,13 @@
"@ovhcloud/ods-common-core": "16.0.1",
"@ovhcloud/ods-common-stencil": "16.0.1",
"@ovhcloud/ods-common-theming": "16.0.1",
"@ovhcloud/ods-component-text": "16.0.1",
"@types/vanillajs-datepicker": "^1.2.2",
"vanillajs-datepicker": "^1.3.3"
"@ovhcloud/ods-component-input": "16.0.1",
"@ovhcloud/ods-component-icon": "16.0.1",
"vanillajs-datepicker": "1.3.3"
},
"devDependencies": {
"@ovhcloud/ods-common-testing": "16.0.1",
"@ovhcloud/ods-component-input": "16.0.1",
"@ovhcloud/ods-component-link": "16.0.1",
"@ovhcloud/ods-component-textarea": "16.0.1",
"@ovhcloud/ods-component-tooltip": "16.0.1",
"@types/vanillajs-datepicker": "1.2.2",
"@ovhcloud/ods-stencil-dev": "16.0.1"
}
}
4 changes: 2 additions & 2 deletions packages/components/datepicker/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
"dist/"
],
"dependencies": {
"@ovhcloud/ods-component-datepicker": "^16.0.1"
"@ovhcloud/ods-component-datepicker": "16.0.1"
},
"peerDependencies": {
"react": ">=16.8.6",
"react-dom": ">=16.8.6"
},
"devDependencies": {
"@ovhcloud/ods-react-dev": "^16.0.1"
"@ovhcloud/ods-react-dev": "16.0.1"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { OdsDatepickerAttribute } from '../interfaces/attributes';
const DEFAULT_ATTRIBUTE: OdsDatepickerAttribute = Object.freeze({
clearable: false,
disabled: false,
error: '',
error: false,
format: 'dd/mm/yyyy',
placeholder: '',
value: null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,29 @@
import type { OsdsDatepicker } from '../osds-datepicker';
import { OdsLogger } from '@ovhcloud/ods-common-core';

/**
* common controller logic for input component used by the different implementations.
* it contains all the glue between framework implementation and the third party service.
*/
class OdsDatepickerController {
private readonly component: OsdsDatepicker;
private readonly logger = new OdsLogger('OdsDatepickerController');

constructor(component: OsdsDatepicker) {
this.component = component;
}

beforeInit(): void {
this.logger.debug('[datepicker]', 'beforeInit', this.component.value);
this.onChange(this.component.value);
}

onFocus() {
this.component.hasFocus = true;
this.component.emitFocus();
}

onChange(newValue: Date | undefined | null, value?: Date | null) {
this.logger.debug(`[datepicker=${newValue}]`, 'value changed', { newValue, value });
onChange(newValue: Date | undefined | null, oldValue?: Date | undefined | null) {
if(!this.component.disabled) {
if (newValue === undefined || newValue === null || isNaN(newValue.getTime())) {
this.component.value = null;
} else {
this.component.value = newValue;
this.component.datepickerInstance?.setDate(newValue);
this.component.emitValueChange(newValue, oldValue);
}
}
}
Expand All @@ -39,15 +32,6 @@ class OdsDatepickerController {
this.component.hasFocus = false;
this.component.emitBlur();
}

onValueChange(value: Date, oldValue?: Date): void {
this.logger.debug(`[datepicker=${this.component.value}]`, 'value changed', { value, oldValue });
this.validateValue();
}

private validateValue() {
return true
}
}

export {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface OdsDatepickerAttribute {
/**
* Defines if the Datepicker should display an error message
*/
error?: string;
error?: boolean;
/**
* Defines which format the Datepicker should be applying (supported formats: https://mymth.github.io/vanillajs-datepicker/#/date-string+format?id=date-format)
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type { EventEmitter } from '@stencil/core';
import type { OdsValidityState } from '@ovhcloud/ods-common-core';

interface OdsDatepickerValueChangeEventDetail {
validity: OdsValidityState;
value: Date | undefined | null;
oldValue?: Date | undefined | null;
}
Expand All @@ -15,7 +13,7 @@ interface OdsDatepickerEvent {
/** Triggered on focus */
odsDatepickerFocus: EventEmitter<void>;
/** Triggered on value change */
odsValueChange: EventEmitter<OdsDatepickerValueChangeEventDetail>;
odsDatepickerValueChange: EventEmitter<OdsDatepickerValueChangeEventDetail>;
}

export {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,25 @@
// CSS targeted only for this component
// /!\ for theming purposes, it has to be done in theming files
// (i.e. packages/libraries/theming/...)
:host {
:host(.osds-datepicker) {
display: flex;
flex-direction: column;
}

:host([inline]) {
width: fit-content;
}

:host .osds-datepicker__hidden-input {
display: none;
}

:host .datepicker {
display: none;
.osds-datepicker {
&__hidden-input {
display: none;
}
}

:host([hasFocus]) {
:host {
.datepicker {
display: none;
width: 50%;
max-width: clamp(36rem, 50%, 50%);
margin-top: var(--ods-size-04);
height: 0;
position: relative;
display: flex;

.datepicker-picker {
width: 100%;
Expand All @@ -43,6 +37,12 @@
}
}

:host([hasFocus]) {
.datepicker {
display: flex;
}
}

// apply the theme template for the component
@include ods-theme-component() {
@include osds-datepicker-theme-color();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ describe('spec:osds-datepicker', () => {
odsUnitTestAttribute<OdsDatepickerAttribute, 'error'>({
name: 'error',
defaultValue: DEFAULT_ATTRIBUTE.error,
newValue: 'Bip bop, we encountered a problem.',
value: '',
newValue: true,
value: false,
setup: (value) => setup({ attributes: { ['error']: value } }),
...config,
});
Expand Down Expand Up @@ -134,16 +134,5 @@ describe('spec:osds-datepicker', () => {
expect(controller.onFocus).toHaveBeenCalledWith();
});
});

describe('watchers', () => {
it('should call onValueChange on value change', async () => {
const value = new Date('1999-11-02');
await setup({ });
instance.value = value;

expect(controller.onValueChange).toHaveBeenCalledTimes(1);
expect(controller.onValueChange).toHaveBeenCalledWith(value, null);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { EventEmitter } from '@stencil/core';
import type { OdsDatepickerAttribute } from './interfaces/attributes';
import type { OdsDatepickerEvent, OdsDatepickerValueChangeEventDetail } from './interfaces/events';
import { Component, Element, Event, Host, h, Listen, Prop, State, Watch } from '@stencil/core';
import { Component, Element, Event, Host, h, Listen, Prop, State } from '@stencil/core';
import { ODS_INPUT_TYPE } from '@ovhcloud/ods-component-input';
import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import { ODS_ICON_NAME } from '@ovhcloud/ods-component-icon';
Expand Down Expand Up @@ -34,7 +34,7 @@ export class OsdsDatepicker implements OdsDatepickerAttribute, OdsDatepickerEven
@Prop({ reflect: true }) disabled?: boolean = DEFAULT_ATTRIBUTE.disabled;

/** @see OdsDatepickerAttribute.error */
@Prop({ reflect: true }) error?: string = DEFAULT_ATTRIBUTE.error;
@Prop({ reflect: true }) error?: boolean = DEFAULT_ATTRIBUTE.error;

/** @see OdsDatepickerAttribute.format */
@Prop({ reflect: true }) format?: string = DEFAULT_ATTRIBUTE.format;
Expand All @@ -47,22 +47,16 @@ export class OsdsDatepicker implements OdsDatepickerAttribute, OdsDatepickerEven

/** Events */

/** @see OdsDatepickerEvents.odsValueChange */
@Event() odsValueChange!: EventEmitter<OdsDatepickerValueChangeEventDetail>;

/** @see OdsDatepickerEvents.odsDatepickerBlur */
/** @see OdsDatepickerEvent.odsDatepickerBlur */
@Event() odsDatepickerBlur!: EventEmitter<void>;

/** @see OdsDatepickerEvents.odsDatepickerFocus */
/** @see OdsDatepickerEvent.odsDatepickerFocus */
@Event() odsDatepickerFocus!: EventEmitter<void>;

/** Watchers */

@Watch('value')
onValueChange(value: Date, oldValue?: Date) {
this.controller.onValueChange(value, oldValue);
}
/** @see OdsDatepickerEvent.odsDatepickerValueChange */
@Event() odsDatepickerValueChange!: EventEmitter<OdsDatepickerValueChangeEventDetail>;

/** Listening to user's manual input */
@Listen('odsValueChange')
handleInputValueChange(event: CustomEvent) {
if (this.format && event.detail.value.length === this.format.length) {
Expand All @@ -86,6 +80,13 @@ export class OsdsDatepicker implements OdsDatepickerAttribute, OdsDatepickerEven
this.odsDatepickerFocus.emit();
}

/**
* @see OdsDatepickerBehavior.emitValueChange
*/
emitValueChange(newValue: Date | undefined | null, oldValue?: Date | undefined | null): void {
this.odsDatepickerValueChange.emit({ value: newValue, oldValue: oldValue });
}

/**
* @see OdsDatepickerBehavior.onBlur
*/
Expand All @@ -107,29 +108,18 @@ export class OsdsDatepicker implements OdsDatepickerAttribute, OdsDatepickerEven
this.controller.onFocus();
}

/**
* @see OdsInputBehavior.beforeInit
*/
beforeInit() {
this.controller.beforeInit();
}

componentWillLoad() {
this.beforeInit();
}

componentDidLoad() {
if(!this.el.shadowRoot) {
return;
}

const hiddenInput = this.el.shadowRoot.querySelector('.osds-datepicker__hidden-input') as HTMLInputElement;
const hiddenInput = this.el.shadowRoot.querySelector('#hidden-input') as HTMLInputElement;

if (!hiddenInput.getAttribute('initialized')) {
this.datepickerInstance = new Datepicker(hiddenInput, {
format: this.format,
nextArrow: `<osds-icon name="triangle-right" size="sm" color="primary"></osds-icon>`,
prevArrow: `<osds-icon name="triangle-left" size="sm" color="primary"></osds-icon>`,
nextArrow: `<osds-icon name="triangle-right" size="sm" color="${ODS_THEME_COLOR_INTENT.primary}"></osds-icon>`,
prevArrow: `<osds-icon name="triangle-left" size="sm" color="${ODS_THEME_COLOR_INTENT.primary}"></osds-icon>`,
maxView: 2,
});

Expand All @@ -143,7 +133,7 @@ export class OsdsDatepicker implements OdsDatepickerAttribute, OdsDatepickerEven
}

formatDate(date?: Date | undefined | null) {
if (this.format && date && this.el.shadowRoot) {
if (this.format && date) {
return Datepicker.formatDate(date, this.format);
} else {
return '';
Expand All @@ -162,25 +152,22 @@ export class OsdsDatepicker implements OdsDatepickerAttribute, OdsDatepickerEven

return (
<Host {...{
class: 'osds-datepicker',
disabled,
error,
hasFocus,
onBlur: () => this.onBlur(),
onFocus: () => this.onFocus(),
}}>
<osds-input
clearable={clearable}
error={error && error.length > 0 ? true : false }
error={error}
icon={ODS_ICON_NAME.CALENDAR}
placeholder={placeholder}
type={ODS_INPUT_TYPE.text}
value={this.formatDate(value)}
></osds-input>
<input tabindex={-1} class="osds-datepicker__hidden-input"></input>
{
error
&& error.length > 0
&& <osds-text color={ODS_THEME_COLOR_INTENT.error}>{error}</osds-text>
}
<input tabindex={-1} id="hidden-input" class="osds-datepicker__hidden-input"></input>
</Host>
);
}
Expand Down

0 comments on commit bd4dc48

Please sign in to comment.