Skip to content

Commit

Permalink
feat(datepicker): date picker component
Browse files Browse the repository at this point in the history
  • Loading branch information
Leotheluck authored and dpellier committed Oct 4, 2023
1 parent ed6cdb7 commit acc5b28
Show file tree
Hide file tree
Showing 9 changed files with 498 additions and 46 deletions.
191 changes: 191 additions & 0 deletions packages/common/core/src/utils/typedoc/typedoc-json-to-md.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
"use strict";
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
exports.__esModule = true;
exports.convertJsonToMarkdown = void 0;
var tableSeparator = '|';
function convertJsonToMarkdown(jsonItems, filter) {
var result = [];
var filteredItems = jsonItems.filter(function (_a) {
var name = _a.name;
return name.match(filter);
});
var displaySection = function (stringArray, sectionString) {
var res = stringArray;
if (res.length) {
result.push(sectionString);
result.push.apply(result, res);
}
};
var interfaces = getInterfaces(filteredItems), types = getTypes(filteredItems), classes = getClass(filteredItems), typeAlias = getTypeAlias(filteredItems), variables = getVariables(filteredItems);
// Create Table
result.push.apply(result, __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], ((interfaces === null || interfaces === void 0 ? void 0 : interfaces.length) ? ["* [**Interfaces**](#interfaces)"] : []), false), ((types === null || types === void 0 ? void 0 : types.length) ? ["* [**Types**](#types)"] : []), false), ((classes === null || classes === void 0 ? void 0 : classes.length) ? ["* [**Classes**](#classes)"] : []), false), ((typeAlias === null || typeAlias === void 0 ? void 0 : typeAlias.length) ? ["* [**Type alias**](#type-alias)"] : []), false), ((variables === null || variables === void 0 ? void 0 : variables.length) ? ["* [**Variables**](#variables)"] : []), false));
displaySection(interfaces, "\n## Interfaces");
displaySection(types, "\n## Types");
displaySection(classes, "\n## Classes");
displaySection(typeAlias, "\n## Type alias");
displaySection(variables, "\n## Variables");
return result.join('\n');
}
exports.convertJsonToMarkdown = convertJsonToMarkdown;
function getInterfaces(filteredJSON) {
var res = [];
filteredJSON.filter(function (_a) {
var filteredString = _a.kindString, filteredChildren = _a.children;
return filteredString === 'Interface'
&& typeof filteredChildren !== 'undefined';
}).forEach(function (_a) {
var _b, _c, _d, _e;
var name = _a.name, children = _a.children;
res.push("\n### ".concat(name));
// Find default values
var defaultValues = {};
(_e = (_d = (_c = (_b = filteredJSON.find(function (_a) {
var defaultString = _a.kindString, defaultName = _a.name;
return defaultString === 'Variable'
&& defaultName.toLowerCase() === "".concat(name.toLowerCase(), "defaultdoc");
})) === null || _b === void 0 ? void 0 : _b.type) === null || _c === void 0 ? void 0 : _c.declaration) === null || _d === void 0 ? void 0 : _d.children) === null || _e === void 0 ? void 0 : _e.forEach(function (_a) {
var name = _a.name, defaultValue = _a.defaultValue;
defaultValues[name] = defaultValue;
});
res.push(tableSeparator + ['name', 'Type', 'Required', 'Default', 'Description'].join(" ".concat(tableSeparator, " ")) + tableSeparator);
res.push(tableSeparator + ['---', '---', ':---:', '---', '---'].join("".concat(tableSeparator)) + tableSeparator);
children.forEach(function (_a) {
var _b, _c, _d;
var name = _a.name, type = _a.type, signatures = _a.signatures, flags = _a.flags, comment = _a.comment;
var commentString = ((_c = (comment || (signatures && ((_b = signatures[0]) === null || _b === void 0 ? void 0 : _b.comment)))) === null || _c === void 0 ? void 0 : _c.shortText) || '';
res.push(tableSeparator + [
"**`".concat(name, "`**"),
type ? printType(type) : printType((_d = signatures[0]) === null || _d === void 0 ? void 0 : _d.type),
!flags.isOptional ? '✴️' : '',
defaultValues[name] ? "`".concat(defaultValues[name], "`") : '',
commentString.replace(/\n/g, '')
].join(" ".concat(tableSeparator, " ")) + tableSeparator);
});
});
return res;
}
function getTypes(filteredJSON) {
var res = [];
filteredJSON.filter(function (item) { return item.kindString === 'Enumeration'; }).forEach(function (enumeration) {
res.push("\n### ".concat(enumeration.name));
res.push("| |\n|:---:|");
if (enumeration.children) {
res.push(enumeration.children.map(function (property) { return "| `".concat(property.name, "` |"); }).join('\n'));
}
});
return res;
}
function getClass(filteredJSON) {
var res = [];
filteredJSON.filter(function (item) { return item.kindString === 'Class'; }).forEach(function (_a) {
var className = _a.name, classComment = _a.comment, classChildren = _a.children;
res.push("\n### ".concat(className));
var comments = classComment === null || classComment === void 0 ? void 0 : classComment.shortText;
if (comments) {
res.push("_".concat(comments.replace(/\n/gmi, '_\n_'), "_\n"));
}
// Methods
var methods = classChildren === null || classChildren === void 0 ? void 0 : classChildren.filter(function (item) { return item.kindString === 'Method'; });
if (typeof methods !== 'undefined' && methods.length) {
res.push("#### Methods");
methods.forEach(function (_a) {
var methodSignatures = _a.signatures, methodName = _a.name;
var _b = methodSignatures[0], signatureParameters = _b.signatureParameters, signatureType = _b.signatureType, signatureComment = _b.signatureComment;
var params = [];
var parameterSection = [];
if (signatureParameters && signatureParameters.length) {
parameterSection.push("Name | Type | Description \n---|---|---");
signatureParameters === null || signatureParameters === void 0 ? void 0 : signatureParameters.map(function (_a) {
var paramName = _a.name, paramType = _a.type, paramComment = _a.comment;
params.push("`".concat(paramName, "`: ").concat(printType(paramType)));
parameterSection.push("**".concat(paramName, "** | ").concat(printType(paramType), " | ").concat(paramComment === null || paramComment === void 0 ? void 0 : paramComment.shortText));
});
}
res.push("> **".concat(methodName, "**(").concat((params || ['']).join(','), ") => ").concat(printType(signatureType), "\n"));
var comments = signatureComment === null || signatureComment === void 0 ? void 0 : signatureComment.shortText;
if (comments) {
res.push("_".concat(comments.replace(/\n/gmi, '_\n_'), "_\n"));
}
res.push("".concat((parameterSection || ['']).join('\n')));
});
}
});
return res;
}
function getTypeAlias(filteredJSON) {
var res = [];
filteredJSON.filter(function (_a) {
var itemString = _a.kindString, itemType = _a.type;
return itemString === 'Type alias'
&& itemType.type !== 'template-literal';
}).forEach(function (_a) {
var _b;
var typeAliasName = _a.name, typeAliasComment = _a.comment, typeAliasType = _a.type, typeAliasTypeParameter = _a.typeParameter;
res.push("\n### ".concat(typeAliasName));
if (typeAliasComment) {
res.push("\n".concat(typeAliasComment === null || typeAliasComment === void 0 ? void 0 : typeAliasComment.shortText));
}
switch (typeAliasType.type) {
case 'reference':
(_b = ((typeAliasTypeParameter || typeAliasType.typeArguments))) === null || _b === void 0 ? void 0 : _b.map(function (typeParameter) {
res.push("\n> - ".concat(printType(typeParameter) !== '_unknown_' ?
printType(typeParameter) :
printType(typeParameter.type)));
});
break;
case 'union':
typeAliasType.types.forEach(function (typeVariant) {
res.push("\n> - ".concat(printType(typeVariant)));
});
break;
}
});
filteredJSON.filter(function (item) {
var _a;
return item.kindString === 'Interface'
&& typeof item.extendedTypes !== 'undefined'
&& ((_a = item.extendedTypes[0]) === null || _a === void 0 ? void 0 : _a.type) === 'reference';
}).forEach(function (_a) {
var typeAliasName = _a.name, typeAliasExtendedTypes = _a.extendedTypes;
res.push("\n### ".concat(typeAliasName));
res.push("\n> _Based on ".concat(printType(typeAliasExtendedTypes[0]), "_"));
});
return res;
}
function getVariables(filteredJSON) {
var res = [];
filteredJSON
.filter(function (_a) {
var itemString = _a.kindString, itemType = _a.type;
return itemString === 'Variable' && itemType.type !== 'array' && itemType.type !== 'reflection';
})
.forEach(function (_a) {
var variableName = _a.name, variableType = _a.type;
res.push("\n### ".concat(variableName));
res.push("".concat(printType(variableType)));
});
return res;
}
function printType(typeObject) {
var getTypeValue = function (tObj) { return typeof tObj.name !== 'undefined' ? "".concat(tObj.name) : "".concat(tObj.value); };
if (typeObject && typeObject.type) {
switch (typeObject.type) {
case 'intrinsic':
case 'literal':
return "_".concat(getTypeValue(typeObject), "_");
case 'reference':
return "`".concat(typeObject.name, "`");
case 'union':
return typeObject.types.map(function (tObj) { return "`".concat(getTypeValue(tObj), "`"); }).join(' \\| ');
}
}
return '_unknown_';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
* [**Interfaces**](#interfaces)
* [**Classes**](#classes)

## Interfaces

### OdsDatepickerAttribute
|Name | Type | Required | Default | Description|
|---|---|:---:|---|---|
|**`clearable`** | _boolean_ | | | Defines if the Datepicker should be clearable or not (displays a clear button)|
|**`color`** | `ODS_THEME_COLOR_INTENT` | | | Defines the Datepicker's color (see component principles)|
|**`datesDisabled`** | Date[] | | | Defines the Datepicker's disabled dates|
|**`daysOfWeekDisabled`** | ODS_DATEPICKER_DAY[] | | | Defines the Datepicker's disabled days of the week (monday, tuesday...)|
|**`disabled`** | _boolean_ | | | Defines if the Datepicker should be disabled or not (lower opacity and not interactable)|
|**`error`** | _boolean_ | | | Defines if the Datepicker should display an error message|
|**`format`** | _string_ | | | Defines which format the Datepicker should be applying (supported formats: https://mymth.github.io/vanillajs-datepicker/#/date-string+format?id=date-format)|
|**`inline`** | _boolean_ | | | Defines if the Datepicker should be displayed inline or not|
|**`maxDate`** | `undefined` \| `Date` | | | Defines the Datepicker's maximum selectable date|
|**`minDate`** | `undefined` \| `Date` | | | Defines the Datepicker's minimum selectable date|
|**`placeholder`** | _string_ | | | Defines if the Datepicker should display a placeholder message|
|**`value`** | `undefined` \| `Date` | | | Defines the Datepicker's value (Date object)|

## Classes

### OsdsDatepicker
17 changes: 9 additions & 8 deletions packages/components/datepicker/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ovhcloud/ods-component-datepicker",
"version": "16.0.1",
"version": "16.1.1",
"description": "ODS Datepicker component",
"author": "OVH SAS",
"license": "Apache-2.0",
Expand All @@ -22,6 +22,7 @@
"ignore:rm": "git clean -Xdf",
"generate": "stencil generate",
"doc:api": "typedoc",
"doc": "typedoc --json ./docs-api/typedoc.json --pretty && node ../../../scripts/generate-typedoc-md.js",
"generate:licence": "npx generate-license-file --input package.json --output THIRD-PARTY-LICENCES --overwrite",
"test": "yarn run test:spec && yarn run test:e2e",
"test:spec": "stencil test --spec --config stencil.config.ts --coverage",
Expand All @@ -34,16 +35,16 @@
"test:e2e:ci:screenshot:update": "stencil test --config stencil.config.ts --e2e --ci --screenshot --update-screenshot --passWithNoTests"
},
"dependencies": {
"@ovhcloud/ods-common-core": "16.0.1",
"@ovhcloud/ods-common-stencil": "16.0.1",
"@ovhcloud/ods-common-theming": "16.0.1",
"@ovhcloud/ods-component-icon": "16.0.1",
"@ovhcloud/ods-component-input": "16.0.1",
"@ovhcloud/ods-common-core": "16.1.1",
"@ovhcloud/ods-common-stencil": "16.1.1",
"@ovhcloud/ods-common-theming": "16.1.1",
"@ovhcloud/ods-component-icon": "16.1.1",
"@ovhcloud/ods-component-input": "16.1.1",
"vanillajs-datepicker": "1.3.3"
},
"devDependencies": {
"@ovhcloud/ods-common-testing": "16.0.1",
"@ovhcloud/ods-stencil-dev": "16.0.1",
"@ovhcloud/ods-common-testing": "16.1.1",
"@ovhcloud/ods-stencil-dev": "16.1.1",
"@types/vanillajs-datepicker": "1.2.2"
}
}
6 changes: 3 additions & 3 deletions packages/components/datepicker/react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ovhcloud/ods-component-datepicker-react",
"version": "16.0.1",
"version": "16.1.1",
"private": true,
"description": "React specific wrapper for ods",
"keywords": [],
Expand All @@ -20,13 +20,13 @@
"dist/"
],
"dependencies": {
"@ovhcloud/ods-component-datepicker": "16.0.1"
"@ovhcloud/ods-component-datepicker": "16.1.1"
},
"peerDependencies": {
"react": ">=16.8.6",
"react-dom": ">=16.8.6"
},
"devDependencies": {
"@ovhcloud/ods-react-dev": "16.0.1"
"@ovhcloud/ods-react-dev": "16.1.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { OdsDatepickerController } from './controller';
import { OsdsDatepicker } from '../osds-datepicker';

class OsdsDatepickerMock extends OsdsDatepicker {
constructor(attribute: Partial<OsdsDatepicker>) {
super();
Object.assign(this, attribute);
}
emitFocus = jest.fn();
emitBlur = jest.fn();
emitDatepickerValueChange = jest.fn();
}

describe('spec:ods-datepicker-controller', () => {
let controller: OdsDatepickerController;
let component: OsdsDatepicker;

function setup(attributes: Partial<OsdsDatepicker> = {}) {
component = new OsdsDatepickerMock(attributes);
controller = new OdsDatepickerController(component);
}

afterEach(() => {
jest.clearAllMocks();
});

describe('methods', () => {
describe('methods:onFocus', () => {
it('should set hasFocus to true and call emitFocus if component is not disabled', () => {
setup();
controller.onFocus();
expect(component.hasFocus).toBe(true);
expect(component.emitFocus).toHaveBeenCalledTimes(1);
});

it('should not change hasFocus and not call emitFocus if component is disabled', () => {
setup({ disabled: true });
controller.onFocus();
expect(component.hasFocus).toBeFalsy();
expect(component.emitFocus).not.toHaveBeenCalled();
});
});

describe('methods:onBlur', () => {
it('should set hasFocus to false and call emitBlur', () => {
setup();
controller.onBlur();
expect(component.hasFocus).toBe(false);
expect(component.emitBlur).toHaveBeenCalledTimes(1);
});
});

describe('methods:onChange', () => {
it('should reset value and call emitDatepickerValueChange with null if value is not valid', () => {
setup();
const oldValue = new Date('2022-01-01');
const newValue = new Date(NaN);
controller.onChange(newValue, oldValue);
expect(component.value).toBeNull();
expect(component.emitDatepickerValueChange).toHaveBeenCalledWith(null, oldValue);
});

it('should set new value and call emitDatepickerValueChange with new value if value is valid', () => {
setup();
const oldValue = new Date('2022-01-01');
const newValue = new Date('2023-01-01');
controller.onChange(newValue, oldValue);
expect(component.value).toEqual(newValue);
expect(component.emitDatepickerValueChange).toHaveBeenCalledWith(newValue, oldValue);
});

it('should reset value if date is disabled', () => {
const disabledDate = new Date('2023-05-05');
setup({ datesDisabled: [disabledDate] });
controller.onChange(disabledDate);
expect(component.value).toBeNull();
expect(component.emitDatepickerValueChange).toHaveBeenCalledWith(null, null);
});

it('should reset value if day of the week is disabled', () => {
const sunday = new Date('2023-10-01'); // 1st of October 2023 is a sunday
setup({ daysOfWeekDisabled: [0] });
controller.onChange(sunday);
expect(component.value).toBeNull();
expect(component.emitDatepickerValueChange).toHaveBeenCalledWith(null, null);
});

it('should reset value if date is greater than maxDate', () => {
const maxDate = new Date('2023-05-05');
const dateAboveMax = new Date('2023-05-06');
setup({ maxDate: maxDate });
controller.onChange(dateAboveMax);
expect(component.value).toBeNull();
expect(component.emitDatepickerValueChange).toHaveBeenCalledWith(null, null);
});

it('should reset value if date is less than minDate', () => {
const minDate = new Date('2023-05-05');
const dateBelowMin = new Date('2023-05-04');
setup({ minDate: minDate });
controller.onChange(dateBelowMin);
expect(component.value).toBeNull();
expect(component.emitDatepickerValueChange).toHaveBeenCalledWith(null, null);
});
});
});
});
Loading

0 comments on commit acc5b28

Please sign in to comment.