Skip to content

Commit

Permalink
feat(b-calendar, b-form-datepicker): add prop weekday-header-format
Browse files Browse the repository at this point in the history
… to specify weekday header length (closes #5171) (#5175)

Co-authored-by: Jacob Müller
  • Loading branch information
tmorehouse committed Apr 18, 2020
1 parent 203e669 commit 8241644
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 24 deletions.
19 changes: 19 additions & 0 deletions src/components/calendar/README.md
Expand Up @@ -282,6 +282,23 @@ Notes:
- `year`, `month` and `day` will always be shown. If you need to leave out a value, set the property
to `undefined`, although this is highly discouraged for accessibility reasons

### Weekday name header format

<span class="badge badge-info small">2.12.0+</span>

The calendar weekday name header format defaults to `'short'`, which is typically a three-character
abbreviation of the weekday, although some [locales](#internationalization) may override this. The
format can be controlled via the prop `weekday-header-format` and accepts one of three values:

- `'long'` the full weekday name (e.g. <samp>Tuesday</samp>). Handy when using a full width
calendar. Avoid using with the default calendar width.
- `'short'` typically is a 2 or 3 letter abbreviation of the weekday name, depending on the selected
locale (e.g. "Tue").
- `'narrow'` is typically a single character abbreviation (e.g., <samp>T</samp>). Two weekdays may
have the same narrow style for some locales (e.g. Tuesday and Thursday's narrow style are both
<samp>T</samp>). This can be handy for those locales that do not support the `'short'` format,
such as locales `'ar'` and `'fa'`.

### Hiding the top selected date header

By default, the current selected date will be displayed at the top of the calendar component,
Expand Down Expand Up @@ -592,6 +609,7 @@ the same locale as requested, depending on the supported locales of `Intl`).
labelHelp: 'Mit den Pfeiltasten durch den Kalender navigieren'
},
'ar-EG': {
weekdayHeaderFormat: 'narrow',
labelPrevDecade: 'العقد السابق',
labelPrevYear: 'العام السابق',
labelPrevMonth: 'الشهر السابق',
Expand All @@ -607,6 +625,7 @@ the same locale as requested, depending on the supported locales of `Intl`).
labelHelp: 'استخدم مفاتيح المؤشر للتنقل في التواريخ'
},
zh: {
weekdayHeaderFormat: 'narrow',
labelPrevDecade: '过去十年',
labelPrevYear: '上一年',
labelPrevMonth: '上个月',
Expand Down
67 changes: 49 additions & 18 deletions src/components/calendar/calendar.js
Expand Up @@ -42,6 +42,14 @@ const NAME = 'BCalendar'
// Key Codes
const { UP, DOWN, LEFT, RIGHT, PAGEUP, PAGEDOWN, HOME, END, ENTER, SPACE } = KeyCodes

// Common calendar option value strings
export const STR_GREGORY = 'gregory'
export const STR_NUMERIC = 'numeric'
export const STR_2_DIGIT = '2-digit'
export const STR_LONG = 'long'
export const STR_SHORT = 'short'
export const STR_NARROW = 'narrow'

// --- BCalendar component ---

// @vue/component
Expand Down Expand Up @@ -224,13 +232,25 @@ export const BCalendar = Vue.extend({
},
dateFormatOptions: {
// `Intl.DateTimeFormat` object
// Note: This value is *not* to be placed in the global config
type: Object,
default: () => ({
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
year: STR_NUMERIC,
month: STR_LONG,
day: STR_NUMERIC,
weekday: STR_LONG
})
},
weekdayHeaderFormat: {
// Format of the weekday names at the top of the calendar
// Note: This value is *not* to be placed in the global config
type: String,
// `short` is typically a 3 letter abbreviation,
// `narrow` is typically a single letter
// `long` is the full week day name
// Although some locales may override this (i.e `ar`, etc)
default: STR_SHORT,
validator: value => arrayIncludes([STR_LONG, STR_SHORT, STR_NARROW], value)
}
},
data() {
Expand Down Expand Up @@ -271,18 +291,18 @@ export const BCalendar = Vue.extend({
},
computedLocale() {
// Returns the resolved locale used by the calendar
return resolveLocale(concat(this.locale).filter(identity), 'gregory')
return resolveLocale(concat(this.locale).filter(identity), STR_GREGORY)
},
calendarLocale() {
// This locale enforces the gregorian calendar (for use in formatter functions)
// Needed because IE 11 resolves `ar-IR` as islamic-civil calendar
// and IE 11 (and some other browsers) do not support the `calendar` option
// And we currently only support the gregorian calendar
const fmt = new Intl.DateTimeFormat(this.computedLocale, { calendar: 'gregory' })
const fmt = new Intl.DateTimeFormat(this.computedLocale, { calendar: STR_GREGORY })
const calendar = fmt.resolvedOptions().calendar
let locale = fmt.resolvedOptions().locale
/* istanbul ignore if: mainly for IE 11 and a few other browsers, hard to test in JSDOM */
if (calendar !== 'gregory') {
if (calendar !== STR_GREGORY) {
// Ensure the locale requests the gregorian calendar
// Mainly for IE 11, and currently we can't handle non-gregorian calendars
// TODO: Should we always return this value?
Expand Down Expand Up @@ -384,9 +404,9 @@ export const BCalendar = Vue.extend({
// Ensure we have year, month, day shown for screen readers/ARIA
// If users really want to leave one of these out, they can
// pass `undefined` for the property value
year: 'numeric',
month: '2-digit',
day: '2-digit',
year: STR_NUMERIC,
month: STR_2_DIGIT,
day: STR_2_DIGIT,
// Merge in user supplied options
...this.dateFormatOptions,
// Ensure hours/minutes/seconds are not shown
Expand All @@ -395,26 +415,37 @@ export const BCalendar = Vue.extend({
minute: undefined,
second: undefined,
// Ensure calendar is gregorian
calendar: 'gregory'
calendar: STR_GREGORY
})
},
formatYearMonth() {
// Returns a date formatter function
return createDateFormatter(this.calendarLocale, {
year: 'numeric',
month: 'long',
calendar: 'gregory'
year: STR_NUMERIC,
month: STR_LONG,
calendar: STR_GREGORY
})
},
formatWeekdayName() {
return createDateFormatter(this.calendarLocale, { weekday: 'long', calendar: 'gregory' })
// Long weekday name for weekday header aria-label
return createDateFormatter(this.calendarLocale, {
weekday: STR_LONG,
calendar: STR_GREGORY
})
},
formatWeekdayNameShort() {
// Used as the header cells
return createDateFormatter(this.calendarLocale, { weekday: 'short', calendar: 'gregory' })
// Weekday header cell format
// defaults to 'short' 3 letter days, where possible
return createDateFormatter(this.calendarLocale, {
weekday: this.weekdayHeaderFormat || STR_SHORT,
calendar: STR_GREGORY
})
},
formatDay() {
return createDateFormatter(this.calendarLocale, { day: 'numeric', calendar: 'gregory' })
return createDateFormatter(this.calendarLocale, {
day: STR_NUMERIC,
calendar: STR_GREGORY
})
},
// Disabled states for the nav buttons
prevDecadeDisabled() {
Expand Down
5 changes: 5 additions & 0 deletions src/components/calendar/package.json
Expand Up @@ -172,6 +172,11 @@
"prop": "dateFormatOptions",
"version": "2.6.0",
"description": "Format object for displayed text string that is passed to `Intl.DateTimeFormat`"
},
{
"prop": "weekdayHeaderFormat",
"version": "2.12.0",
"description": "Format to use for the calendar weekday headings. Possible values are `long`, `short` (default), or `narrow`"
}
],
"events": [
Expand Down
19 changes: 19 additions & 0 deletions src/components/form-datepicker/README.md
Expand Up @@ -439,6 +439,23 @@ Notes:
- `year`, `month` and `day` will always be shown. If you need to leave out a value, set the property
to `undefined`, although this is highly discouraged for accessibility reasons

### Weekday name header format

<span class="badge badge-info small">2.12.0+</span>

The calendar weekday name header format defaults to `'short'`, which is typically a three-character
abbreviation of the weekday, although some [locales](#internationalization) may override this. The
format can be controlled via the prop `weekday-header-format` and accepts one of three values:

- `'long'` the full weekday name (e.g. <samp>Tuesday</samp>). Handy when using a full width
calendar. Avoid using with the default calendar width.
- `'short'` typically is a 2 or 3 letter abbreviation of the weekday name, depending on the selected
locale (e.g. "Tue").
- `'narrow'` is typically a single character abbreviation (e.g., <samp>T</samp>). Two weekdays may
have the same narrow style for some locales (e.g. Tuesday and Thursday's narrow style are both
<samp>T</samp>). This can be handy for those locales that do not support the `'short'` format,
such as locales `'ar'` and `'fa'`.

### Date navigation button slots

<span class="badge badge-info small">2.12.0+</span>
Expand Down Expand Up @@ -551,6 +568,7 @@ Saturday.
labelHelp: 'Mit den Pfeiltasten durch den Kalender navigieren'
},
'ar-EG': {
weekdayHeaderFormat: 'narrow',
labelPrevDecade: 'العقد السابق',
labelPrevYear: 'العام السابق',
labelPrevMonth: 'الشهر السابق',
Expand All @@ -566,6 +584,7 @@ Saturday.
labelHelp: 'استخدم مفاتيح المؤشر للتنقل في التواريخ'
},
zh: {
weekdayHeaderFormat: 'narrow',
labelPrevDecade: '过去十年',
labelPrevYear: '上一年',
labelPrevMonth: '上个月',
Expand Down
26 changes: 20 additions & 6 deletions src/components/form-datepicker/form-datepicker.js
@@ -1,12 +1,13 @@
import Vue from '../../utils/vue'
import { arrayIncludes } from '../../utils/array'
import { BVFormBtnLabelControl, dropdownProps } from '../../utils/bv-form-btn-label-control'
import { getComponentConfig } from '../../utils/config'
import { createDate, constrainDate, formatYMD, parseYMD } from '../../utils/date'
import { isUndefinedOrNull } from '../../utils/inspect'
import { pick } from '../../utils/object'
import idMixin from '../../mixins/id'
import { BButton } from '../button/button'
import { BCalendar } from '../calendar/calendar'
import { BCalendar, STR_LONG, STR_NARROW, STR_NUMERIC, STR_SHORT } from '../calendar/calendar'
import { BIconCalendar, BIconCalendarFill } from '../../icons/icons'

const NAME = 'BFormDatepicker'
Expand Down Expand Up @@ -240,14 +241,26 @@ const propsMixin = {
},
dateFormatOptions: {
// `Intl.DateTimeFormat` object
// Note: This value is *not* to be placed in the global config
type: Object,
default: () => ({
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
year: STR_NUMERIC,
month: STR_LONG,
day: STR_NUMERIC,
weekday: STR_LONG
})
},
weekdayHeaderFormat: {
// Format of the weekday names at the top of the calendar
// Note: This value is *not* to be placed in the global config
type: String,
// `short` is typically a 3 letter abbreviation,
// `narrow` is typically a single letter
// `long` is the full week day name
// Although some locales may override this (i.e `ar`, etc)
default: STR_SHORT,
validator: value => arrayIncludes([STR_LONG, STR_SHORT, STR_NARROW], value)
},
// Dark mode
dark: {
type: Boolean,
Expand Down Expand Up @@ -328,7 +341,8 @@ export const BFormDatepicker = /*#__PURE__*/ Vue.extend({
labelCalendar: self.labelCalendar,
labelNav: self.labelNav,
labelHelp: self.labelHelp,
dateFormatOptions: self.dateFormatOptions
dateFormatOptions: self.dateFormatOptions,
weekdayHeaderFormat: self.weekdayHeaderFormat
}
},
computedLang() {
Expand Down
5 changes: 5 additions & 0 deletions src/components/form-datepicker/package.json
Expand Up @@ -268,6 +268,11 @@
"prop": "dateFormatOptions",
"version": "2.6.0",
"description": "Format object for displayed text string that is passed to `Intl.DateTimeFormat`"
},
{
"prop": "weekdayHeaderFormat",
"version": "2.12.0",
"description": "Format to use for the calendar weekday headings. Possible values are `long`, `short` (default), or `narrow`"
}
],
"events": [
Expand Down

0 comments on commit 8241644

Please sign in to comment.