-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(date-picker): add pf-date-picker #2599
Draft
ArathyKumar
wants to merge
19
commits into
patternfly:main
Choose a base branch
from
ArathyKumar:feature/pf-date-picker
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
ad5106e
feat: add pf-date-picker
2b0ff7d
chore: added date picker component
690a889
Merge branch 'main' into feature/pf-date-picker
ArathyKumar 832d1f6
Merge branch 'main' into feature/pf-date-picker
549822b
fix: code updated to work with pf-3
36f9aca
Merge branch 'patternfly:main' into feature/pf-date-picker
ArathyKumar 08820f3
fix: translation and popover fixes updated
19e0e11
chore: split large demo files to individual files
1ae65c5
fix: css fixes
52456d7
fix: button css fix on focus
0c94f75
chore: component image added
dde0275
fix: removed the date-picker child components from package.json
988447d
fix: added constants in the helper file
412b41d
fix: removed the constructor
543394f
fix: changed the format of DOM properties from camelCase to dash-case
80615e4
Merge remote-tracking branch 'origin/main' into feature/pf-date-picker
c04282e
chore: readme updated
9580ff1
fix: changed extend composedevent to event
e9e9833
fix: added ecmascript private variables
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Date Picker | ||
Add a description of the component here. | ||
|
||
## Usage | ||
Describe how best to use this web component along with best practices. | ||
|
||
```html | ||
<pf-date-picker> | ||
|
||
</pf-date-picker> | ||
``` |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note to future self and other reviewers: see if / how many of these functions can be replaced with Intl built-ins. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,344 @@ | ||
export interface DateFormatDetails { | ||
dateParts: string[]; | ||
literal: string | undefined; | ||
} | ||
|
||
export interface InputDate { | ||
day: number; | ||
month: number; | ||
year: number; | ||
literal: string; | ||
} | ||
|
||
export const days: string[] = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; | ||
export const defaultWeekdays: number[] = [0, 1, 2, 3, 4, 5, 6]; // S, M, T, W, T, F, S | ||
export const defaultWeeks: number[] = [0, 1, 2, 3, 4, 5]; // 1 previous month week, 4 current month weeks, 1 next month week | ||
|
||
// Function to return date object | ||
export const getFormattedDate = (date: Date) => { | ||
const focusDate = { | ||
day: date.getDate(), | ||
month: date.getMonth(), | ||
year: date.getFullYear() | ||
}; | ||
|
||
return focusDate; | ||
}; | ||
|
||
|
||
// Function to get the date format locale parts | ||
export const getLocaleParts = (language?: string) => { | ||
// Get the browser user locale - Commented for reference | ||
// const userLocale: string = navigator.languages && navigator.languages.length ? | ||
// navigator.languages[0] : navigator.language; | ||
|
||
const { timeZone } = Intl.DateTimeFormat().resolvedOptions(); | ||
let formatter: Intl.DateTimeFormatPart[] = []; | ||
|
||
// Set date format options | ||
const options: Intl.DateTimeFormatOptions = { | ||
timeZone: timeZone, | ||
dateStyle: 'short', | ||
localeMatcher: 'lookup' | ||
}; | ||
|
||
// If there is locale passed from parent, pass locale else use "default" | ||
const locale: string = language ? language : 'default'; | ||
|
||
// Try - Catch block is used to catch error and format date using default locale if invalid locale is passed from parent | ||
try { | ||
// Get the date components breakdown array | ||
formatter = new Intl.DateTimeFormat(locale, options).formatToParts(new Date()); | ||
} catch (error) { | ||
if (error) { // Get the date components breakdown array with default locale | ||
formatter = new Intl.DateTimeFormat('default', options).formatToParts(new Date()); | ||
} | ||
} | ||
|
||
return formatter; | ||
}; | ||
|
||
|
||
// Function to return the date values from user input | ||
export const getDateValues = (dateString: string, languageCode?: string, dateFormatInput?: string) => { | ||
let parseDay!: number; | ||
let parseMonth!: number; | ||
let parseYear!: number; | ||
let splitWith!: string; | ||
|
||
// If there is a dateFormat input from parent, the input format will be applied | ||
// else date format will be generated and applied from languageCode input or default locale | ||
if (dateFormatInput && isInputDateFormatValid(dateFormatInput)) { | ||
const dateFormatDetails: DateFormatDetails = parseDateFormat(dateFormatInput); | ||
let index = 0; | ||
|
||
dateFormatDetails.dateParts.map((part: string) => { // Generate the date format | ||
switch (part) { | ||
case 'MM': | ||
parseMonth = index; | ||
index++; | ||
break; | ||
case 'DD': | ||
parseDay = index; | ||
index++; | ||
break; | ||
case 'YYYY': | ||
parseYear = index; | ||
index++; | ||
break; | ||
default: | ||
break; | ||
} | ||
}); | ||
splitWith = dateFormatDetails.literal ? dateFormatDetails.literal : '/'; | ||
} else { | ||
const formatter: Intl.DateTimeFormatPart[] = getLocaleParts(languageCode); | ||
let index = 0; | ||
|
||
formatter.map((part: Intl.DateTimeFormatPart) => { // Generate the date format | ||
switch (part.type) { | ||
case 'month': | ||
parseMonth = index; | ||
index++; | ||
break; | ||
case 'day': | ||
parseDay = index; | ||
index++; | ||
break; | ||
case 'year': | ||
parseYear = index; | ||
index++; | ||
break; | ||
default: | ||
splitWith = part.value; | ||
} | ||
}); | ||
} | ||
|
||
const dateStringArray: string[] = dateString.split(splitWith); | ||
const selectedDayInput: number = parseInt(dateStringArray[parseDay], 10); | ||
const selectedMonthInput: number = parseInt(dateStringArray[parseMonth], 10); | ||
const selectedYearInput: number = parseInt(dateStringArray[parseYear], 10); | ||
const inputDate: InputDate = { | ||
day: selectedDayInput, | ||
month: selectedMonthInput, | ||
year: selectedYearInput, | ||
literal: splitWith | ||
}; | ||
|
||
return inputDate; | ||
}; | ||
|
||
// Function to return the fomatted date string | ||
export const getDateFormat = (day: string, month: string, year: string, languageCode?: string, dateFormatInput?: string) => { | ||
let formattedDate = ``; | ||
const dd: string = day; | ||
const mm: string = month; | ||
const yyyy: string = year; | ||
|
||
// If there is a dateFormat input from parent, the input format will be applied | ||
// else date format will be generated and applied from languageCode input or default locale | ||
if (dateFormatInput && isInputDateFormatValid(dateFormatInput)) { | ||
const dateFormatDetails: DateFormatDetails = parseDateFormat(dateFormatInput); | ||
|
||
dateFormatDetails.dateParts.map((part: string, index: number) => { // Generate the date format | ||
switch (part) { | ||
case 'MM': | ||
formattedDate += `${mm}`; | ||
break; | ||
case 'DD': | ||
formattedDate += `${dd}`; | ||
break; | ||
case 'YYYY': | ||
formattedDate += `${yyyy}`; | ||
break; | ||
default: | ||
break; | ||
} | ||
if (index < 2) { | ||
formattedDate += dateFormatDetails.literal ? dateFormatDetails.literal : '/'; | ||
} | ||
}); | ||
} else { | ||
const formatter: Intl.DateTimeFormatPart[] = getLocaleParts(languageCode); | ||
|
||
formatter.map((part: Intl.DateTimeFormatPart) => { // Generate the date format | ||
switch (part.type) { | ||
case 'month': | ||
formattedDate += `${mm}`; | ||
break; | ||
case 'day': | ||
formattedDate += `${dd}`; | ||
break; | ||
case 'year': | ||
formattedDate += `${yyyy}`; | ||
break; | ||
default: | ||
formattedDate += part.value; | ||
} | ||
}); | ||
} | ||
|
||
return formattedDate; | ||
}; | ||
|
||
// Function to return date format based on date format input or locale | ||
export const getDatePatternFromLocale = (languageCode?: string, dateFormatInput?: string) => { | ||
let localeDateFormat = ''; | ||
|
||
// If there is a dateFormat input from parent, the input format will be applied | ||
// else date format will be generated and applied from languageCode input or default locale | ||
if (dateFormatInput && isInputDateFormatValid(dateFormatInput)) { | ||
localeDateFormat = dateFormatInput; | ||
} else { | ||
const formatter: Intl.DateTimeFormatPart[] = getLocaleParts(languageCode); | ||
|
||
formatter.map((part: Intl.DateTimeFormatPart) => { // Generate the date format | ||
switch (part.type) { | ||
case 'month': | ||
localeDateFormat += 'MM'; | ||
break; | ||
case 'day': | ||
localeDateFormat += 'DD'; | ||
break; | ||
case 'year': | ||
localeDateFormat += 'YYYY'; | ||
break; | ||
default: | ||
localeDateFormat += part.value; | ||
} | ||
}); | ||
} | ||
|
||
return localeDateFormat; | ||
}; | ||
|
||
// Function to generate regex pattern based on date format input or locale | ||
export const getRegexPattern = (languageCode?: string, dateFormatInput?: string) => { | ||
const regDay = '[0-9]{1,2}'; | ||
const regMonth = '[0-9]{1,2}'; | ||
const regYear = '[0-9]{2,4}'; | ||
let regex = '^'; | ||
|
||
// If there is a dateFormat input from parent, the input format will be applied | ||
// else date format will be generated and applied from languageCode input or default locale | ||
if (dateFormatInput && isInputDateFormatValid(dateFormatInput)) { | ||
const dateFormatDetails: DateFormatDetails = parseDateFormat(dateFormatInput); | ||
|
||
dateFormatDetails.dateParts.map((part: string, index: number) => { // Generate the date format | ||
switch (part) { | ||
case 'MM': | ||
regex += regMonth; | ||
break; | ||
case 'DD': | ||
regex += regDay; | ||
break; | ||
case 'YYYY': | ||
regex += regYear; | ||
break; | ||
default: | ||
break; | ||
} | ||
if (index < 2) { | ||
regex += dateFormatDetails.literal ? dateFormatDetails.literal : '/'; | ||
} | ||
}); | ||
} else { | ||
const formatter: Intl.DateTimeFormatPart[] = getLocaleParts(languageCode); | ||
|
||
formatter.map((part: Intl.DateTimeFormatPart) => { // Generate the regex for the date format according to locale | ||
switch (part.type) { | ||
case 'month': | ||
regex += regMonth; | ||
break; | ||
case 'day': | ||
regex += regDay; | ||
break; | ||
case 'year': | ||
regex += regYear; | ||
break; | ||
default: | ||
regex += part.value; // Will append the part literal '/' or '.' or '-' to the regex | ||
break; | ||
} | ||
}); | ||
} | ||
regex += '$'; | ||
|
||
return regex; | ||
}; | ||
|
||
// Function to generate date parts array from date format input | ||
export const parseDateFormat = (dateFormatInput: string) => { | ||
const literals: string[] = ['/', '-', '.']; // Supported date format literals | ||
let datePartsArray: string[] = []; | ||
|
||
const literal = literals.find((literal: string) => { // Find the literal in the format | ||
if (dateFormatInput.includes(literal)) { | ||
return literal; | ||
} | ||
}); | ||
|
||
if (literal) { | ||
datePartsArray = dateFormatInput.split(literal); // Split the format to date parts | ||
} | ||
|
||
const dateFormatParts = { | ||
dateParts: datePartsArray, | ||
literal: literal | ||
}; | ||
|
||
return dateFormatParts; | ||
}; | ||
|
||
// Function to check validity of the date format input | ||
export const isInputDateFormatValid = (dateFormatInput: string) => { | ||
let isDateFormatValid = false; | ||
const supportedDateFormats: string[] = [ // Supported date formats from parent | ||
'DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY/MM/DD', 'YYYY/DD/MM', 'DD-MM-YYYY', 'MM-DD-YYYY', | ||
'YYYY-MM-DD', 'YYYY-DD-MM', 'DD.MM.YYYY', 'MM.DD.YYYY', 'YYYY.MM.DD', 'YYYY.DD.MM' | ||
]; | ||
|
||
if (supportedDateFormats.includes(dateFormatInput)) { | ||
isDateFormatValid = true; | ||
} else { | ||
isDateFormatValid = false; | ||
} | ||
|
||
return isDateFormatValid; | ||
}; | ||
|
||
export const getMonthNamesFromLocale = (languageCode?: string) => { | ||
const monthNames: string[] = [ | ||
'January', | ||
'February', | ||
'March', | ||
'April', | ||
'May', | ||
'June', | ||
'July', | ||
'August', | ||
'September', | ||
'October', | ||
'November', | ||
'December' | ||
]; | ||
|
||
if (languageCode) { | ||
const date: Date = new Date(); | ||
try { | ||
const translatedMonthNames: string[] = []; | ||
for (let i = 0; i < 12; i++) { | ||
date.setMonth(i); | ||
const monthName: string = new Intl.DateTimeFormat(languageCode, { month: 'long' }).format(new Date(date.getFullYear(), i, date.getDate())); | ||
translatedMonthNames.push(monthName); | ||
} | ||
return translatedMonthNames; | ||
} catch (error) { | ||
if (error) { | ||
return monthNames; | ||
} | ||
} | ||
} | ||
return monthNames; | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be updated with prose from v4-archive.patternfly.org
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated README file