@vaadin/date-picker 25.3.0-alpha9 → 25.3.0-beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,7 +23,7 @@
23
23
  "declarations": [
24
24
  {
25
25
  "kind": "class",
26
- "description": "A reactive controller that resolves the metadata (currently the disabled state)\nfor the dates shown by the date-picker's `dateMetadataProvider`.\n\nThe provider is called for a range of months and may return an array\nsynchronously or a `Promise`, so results from a server (Flow) or a remote\navailability service can be awaited. Each returned entry is a `DatePickerDate`\nextended with metadata fields, e.g. `{ year, month, day, disabled: true }`.\n\n`ARCHITECTURE.md` in this package records the reasoning behind the request,\ncaching, notification and failure behavior.",
26
+ "description": "A reactive controller that resolves the metadata (currently the disabled state)\nfor the dates shown by the date-picker's `dateMetadataProvider`.\n\nThe provider is called for a range of months and may return an array\nsynchronously or a `Promise`, so results from a server (Flow) or a remote\navailability service can be awaited. The range and each returned entry identify\na date by an ISO 8601 string, e.g. `{ date: '2026-01-01', disabled: true }`.\n\n`ARCHITECTURE.md` in this package records the reasoning behind the request,\ncaching, notification and failure behavior.",
27
27
  "name": "DateMetadataController",
28
28
  "members": [
29
29
  {
@@ -616,7 +616,7 @@
616
616
  }
617
617
  }
618
618
  ],
619
- "description": "Parse date string of one of the following date formats:\n- ISO 8601 `\"YYYY-MM-DD\"`\n- 6-digit extended ISO 8601 `\"+YYYYYY-MM-DD\"`, `\"-YYYYYY-MM-DD\"`",
619
+ "description": "Parse date string of one of the following date formats:\n- ISO 8601 `\"YYYY-MM-DD\"`\n- Extended ISO 8601 with a signed year, e.g. `\"+012026-MM-DD\"` or `\"-0001-MM-DD\"`\n\nA date that does not exist, such as `\"2026-02-30\"`, is not parsed. Building it would carry the\nsurplus into the next month or year and answer with a date that was never asked for.",
620
620
  "return": {
621
621
  "type": {
622
622
  "text": "Date"
@@ -635,7 +635,7 @@
635
635
  }
636
636
  }
637
637
  ],
638
- "description": "Parse date string of one of the following date formats:\n- ISO 8601 `\"YYYY-MM-DD\"`\n- 6-digit extended ISO 8601 `\"+YYYYYY-MM-DD\"`, `\"-YYYYYY-MM-DD\"`\n\nUses UTC date components to allow handling date instances independently of\nthe system time-zone.",
638
+ "description": "Parse date string of one of the following date formats:\n- ISO 8601 `\"YYYY-MM-DD\"`\n- Extended ISO 8601 with a signed year, e.g. `\"+012026-MM-DD\"` or `\"-0001-MM-DD\"`\n\nUses UTC date components to allow handling date instances independently of\nthe system time-zone.\n\nA date that does not exist, such as `\"2026-02-30\"`, is not parsed, as in `parseDate`.",
639
639
  "return": {
640
640
  "type": {
641
641
  "text": "Date"
@@ -921,7 +921,7 @@
921
921
  "type": {
922
922
  "text": "DatePickerDateMetadataProvider | null | undefined"
923
923
  },
924
- "description": "A batch function that fetches metadata for a range of dates the calendar is about to\nrender. It receives a `DatePickerDateRange` and returns, or resolves with, an array of\n`DatePickerDateMetadata` objects — a `DatePickerDate` extended with metadata such as\n`disabled`, e.g. `{ year, month, day, disabled: true }` for the dates that have metadata\nwithin that range. Dates it does not mention have no metadata. `month` is 0-based: 0 is\nJanuary and 11 is December.\n\nUnlike `isDateDisabled`, which is called once per date, this function is called for a\nrange of dates at a time, and again as the calendar renders further dates. The size of the\nrange is decided by the calendar and may span several months, and may include months it\nalready has metadata for, whose entries are then ignored.\n\nIt may return a `Promise`, so the answer can come from a server. Until it resolves, the\naffected dates render with the `loading` part but stay selectable, and a loading spinner\nis shown. Nothing is disabled before the provider has actually reported it, so a slow\nprovider does not make the calendar unusable. If it throws or rejects, the error is logged\nand the affected months are requested again the next time the user navigates.\n\n`disabled` from the metadata is combined with `min`, `max` and `isDateDisabled`: a date is\ndisabled if it is out of the min/max range, or `isDateDisabled` returns `true`, or its\nmetadata marks it disabled. That decides what the calendar renders as disabled, what can be\nselected, and whether the field is valid.\n\nA value is checked against the provider even if the overlay is never opened, which loads the\nmonth holding it. Until that month answers the value is valid, and it is re-validated once\nthe answer arrives, so `checkValidity()` can report a value as valid and then invalid.\n\n`part` from the metadata adds part names to the date, so a theme can style specific dates\nwith `::part()` e.g. `{ year, month, day, part: 'busy' }`. Give a single name or several\nseparated by spaces. Do not use built-in names like `disabled` and `selected`.\n\nKeep a stable reference to the function. Assigning a new function clears the cache and\nre-fetches every visible range. To re-fetch while keeping the same function, because the\ndata behind it changed, call `clearCache()`.",
924
+ "description": "A function that provides metadata for the dates the calendar is about to render: whether they\nare disabled, and CSS `part` names for styling from outside using the `::part()` selector.\nUnlike `isDateDisabled`, which is called once per date, the metadata provider is called for\na range of dates at a time, and again as the calendar renders further dates.\n\nIt receives a `DatePickerDateRange` and returns an array of `DatePickerDateMetadata` objects\nfor the dates in that range that have metadata. It can return a `Promise` to load the metadata\nasynchronously, and `null` or `undefined` when no date in the range has metadata.\n\nThe returned array has the following structure:\n\n```js\n[\n // The date is an ISO 8601 string.\n { date: '2026-01-01', disabled: true },\n\n // Adds a custom part name to the date.\n { date: '2026-01-02', part: 'busy' },\n]\n```\n\nA date is disabled if its metadata marks it disabled, or `isDateDisabled` returns `true`, or\nit is outside `min` and `max`. Disabled dates are not selectable, and typing a disabled date in\nthe field makes it invalid. The provider does not affect which date is focused when opening the\noverlay. Use `initialPosition` property to provide a selectable date.\n\nWhile a returned `Promise` is pending, the dates it covers are not disabled yet and render with\nthe `loading` part. If the function throws or rejects, corresponding dates are requested again\nthe next time the user navigates.\n\nThe provider is used for validation also when the overlay is closed. Date is considered valid\nwhile the provider is pending, and is re-validated again after the metadata is loaded.\n\nKeep a stable reference to the function: assigning a new one clears the cache and re-fetches\nvisible range. Call `clearCache()` to re-fetch when the data behind the same function changed.",
925
925
  "attribute": "date-metadata-provider"
926
926
  },
927
927
  {
@@ -983,7 +983,7 @@
983
983
  "type": {
984
984
  "text": "function(DatePickerDate): boolean | undefined"
985
985
  },
986
- "description": "A function to be used to determine whether the user can select a given date.\nReceives a `DatePickerDate` object of the date to be selected and should return a\nboolean.",
986
+ "description": "A function to be used to determine whether the user can select a given date.\nReceives a `DatePickerDate` object of the date to be selected and should return a\nboolean.\n\nThe function is called once per date and has to answer synchronously. Use\n`dateMetadataProvider` when the answer has to be loaded first, or when dates also need\ncustom part names. A date is disabled when either of the two disables it.",
987
987
  "attribute": "is-date-disabled"
988
988
  },
989
989
  {
@@ -1142,7 +1142,7 @@
1142
1142
  "type": {
1143
1143
  "text": "DatePickerDateMetadataProvider | null | undefined"
1144
1144
  },
1145
- "description": "A batch function that fetches metadata for a range of dates the calendar is about to\nrender. It receives a `DatePickerDateRange` and returns, or resolves with, an array of\n`DatePickerDateMetadata` objects — a `DatePickerDate` extended with metadata such as\n`disabled`, e.g. `{ year, month, day, disabled: true }` for the dates that have metadata\nwithin that range. Dates it does not mention have no metadata. `month` is 0-based: 0 is\nJanuary and 11 is December.\n\nUnlike `isDateDisabled`, which is called once per date, this function is called for a\nrange of dates at a time, and again as the calendar renders further dates. The size of the\nrange is decided by the calendar and may span several months, and may include months it\nalready has metadata for, whose entries are then ignored.\n\nIt may return a `Promise`, so the answer can come from a server. Until it resolves, the\naffected dates render with the `loading` part but stay selectable, and a loading spinner\nis shown. Nothing is disabled before the provider has actually reported it, so a slow\nprovider does not make the calendar unusable. If it throws or rejects, the error is logged\nand the affected months are requested again the next time the user navigates.\n\n`disabled` from the metadata is combined with `min`, `max` and `isDateDisabled`: a date is\ndisabled if it is out of the min/max range, or `isDateDisabled` returns `true`, or its\nmetadata marks it disabled. That decides what the calendar renders as disabled, what can be\nselected, and whether the field is valid.\n\nA value is checked against the provider even if the overlay is never opened, which loads the\nmonth holding it. Until that month answers the value is valid, and it is re-validated once\nthe answer arrives, so `checkValidity()` can report a value as valid and then invalid.\n\n`part` from the metadata adds part names to the date, so a theme can style specific dates\nwith `::part()` e.g. `{ year, month, day, part: 'busy' }`. Give a single name or several\nseparated by spaces. Do not use built-in names like `disabled` and `selected`.\n\nKeep a stable reference to the function. Assigning a new function clears the cache and\nre-fetches every visible range. To re-fetch while keeping the same function, because the\ndata behind it changed, call `clearCache()`.",
1145
+ "description": "A function that provides metadata for the dates the calendar is about to render: whether they\nare disabled, and CSS `part` names for styling from outside using the `::part()` selector.\nUnlike `isDateDisabled`, which is called once per date, the metadata provider is called for\na range of dates at a time, and again as the calendar renders further dates.\n\nIt receives a `DatePickerDateRange` and returns an array of `DatePickerDateMetadata` objects\nfor the dates in that range that have metadata. It can return a `Promise` to load the metadata\nasynchronously, and `null` or `undefined` when no date in the range has metadata.\n\nThe returned array has the following structure:\n\n```js\n[\n // The date is an ISO 8601 string.\n { date: '2026-01-01', disabled: true },\n\n // Adds a custom part name to the date.\n { date: '2026-01-02', part: 'busy' },\n]\n```\n\nA date is disabled if its metadata marks it disabled, or `isDateDisabled` returns `true`, or\nit is outside `min` and `max`. Disabled dates are not selectable, and typing a disabled date in\nthe field makes it invalid. The provider does not affect which date is focused when opening the\noverlay. Use `initialPosition` property to provide a selectable date.\n\nWhile a returned `Promise` is pending, the dates it covers are not disabled yet and render with\nthe `loading` part. If the function throws or rejects, corresponding dates are requested again\nthe next time the user navigates.\n\nThe provider is used for validation also when the overlay is closed. Date is considered valid\nwhile the provider is pending, and is re-validated again after the metadata is loaded.\n\nKeep a stable reference to the function: assigning a new one clears the cache and re-fetches\nvisible range. Call `clearCache()` to re-fetch when the data behind the same function changed.",
1146
1146
  "fieldName": "dateMetadataProvider"
1147
1147
  },
1148
1148
  {
@@ -1194,7 +1194,7 @@
1194
1194
  "type": {
1195
1195
  "text": "function(DatePickerDate): boolean | undefined"
1196
1196
  },
1197
- "description": "A function to be used to determine whether the user can select a given date.\nReceives a `DatePickerDate` object of the date to be selected and should return a\nboolean.",
1197
+ "description": "A function to be used to determine whether the user can select a given date.\nReceives a `DatePickerDate` object of the date to be selected and should return a\nboolean.\n\nThe function is called once per date and has to answer synchronously. Use\n`dateMetadataProvider` when the answer has to be loaded first, or when dates also need\ncustom part names. A date is disabled when either of the two disables it.",
1198
1198
  "fieldName": "isDateDisabled"
1199
1199
  },
1200
1200
  {
@@ -2157,7 +2157,7 @@
2157
2157
  "declarations": [
2158
2158
  {
2159
2159
  "kind": "class",
2160
- "description": "`<vaadin-date-picker>` is an input field that allows to enter a date by typing or by selecting from a calendar overlay.\n\n```html\n<vaadin-date-picker label=\"Birthday\"></vaadin-date-picker>\n```\n\n```js\ndatePicker.value = '2016-03-02';\n```\n\nWhen the selected `value` is changed, a `value-changed` event is triggered.\n\n### Styling\n\nThe following custom properties are available for styling:\n\nCustom property | Description | Default\n-------------------------------|----------------------------|---------\n`--vaadin-field-default-width` | Default width of the field | `12em`\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|----------------\n`label` | The label element\n`input-field` | The element that wraps prefix, value and buttons\n`field-button` | Set on both clear and toggle buttons\n`clear-button` | The clear button\n`error-message` | The error message element\n`helper-text` | The helper text element wrapper\n`required-indicator` | The `required` state indicator element\n`toggle-button` | The toggle button\n`backdrop` | Backdrop of the overlay\n`overlay` | The overlay container\n`content` | The overlay content\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------------|---------------------------------\n`disabled` | Set when the element is disabled\n`has-value` | Set when the element has a value\n`has-label` | Set when the element has a label\n`has-helper` | Set when the element has helper text or slot\n`has-error-message` | Set when the element has an error message\n`has-tooltip` | Set when the element has a slotted tooltip\n`invalid` | Set when the element is invalid\n`focused` | Set when the element is focused\n`focus-ring` | Set when the element is keyboard focused\n`readonly` | Set when the element is readonly\n`opened` | Set when the overlay is opened\n`week-numbers` | Set when week numbers are shown in the calendar\n\n### Internal components\n\nIn addition to `<vaadin-date-picker>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-date-picker-overlay-content>`\n- `<vaadin-date-picker-month-scroller>`\n- `<vaadin-date-picker-year-scroller>`\n- `<vaadin-date-picker-year>`\n- `<vaadin-month-calendar>`\n\nIn order to style the overlay content, use `<vaadin-date-picker-overlay-content>` shadow DOM parts:\n\nPart name | Description\n----------------------|--------------------\n`years-toggle-button` | Fullscreen mode years scroller toggle\n`toolbar` | Toolbar with slotted buttons\n`loader` | Loading spinner shown while the date metadata provider is resolving\n\nThe following state attributes are available on the `<vaadin-date-picker-overlay-content>` element:\n\nAttribute | Description\n----------------|-------------------------------------------------\n`desktop` | Set when the overlay content is in desktop mode\n`fullscreen` | Set when the overlay content is in fullscreen mode\n`years-visible` | Set when the year scroller is visible in fullscreen mode\n`loading` | Set while the date metadata provider is resolving\n\nIn order to style the month calendar, use `<vaadin-month-calendar>` shadow DOM parts:\n\nPart name | Description\n----------------------|--------------------\n`month-header` | Month title\n`weekdays` | Weekday container\n`weekday` | Weekday element\n`week-numbers` | Week numbers container\n`week-number` | Week number element\n`date` | Date element\n`disabled` | Disabled date element\n`loading` | Date element in a month whose metadata is currently being fetched\n`focused` | Focused date element\n`selected` | Selected date element\n`today` | Date element corresponding to the current day\n`past` | Date element corresponding to the date in the past\n`future` | Date element corresponding to the date in the future\n\nIn order to style year scroller elements, use `<vaadin-date-picker-year>` shadow DOM parts:\n\nPart name | Description\n----------------------|--------------------\n`year-number` | Year number\n`year-separator` | Year separator\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Change events\n\nDepending on the nature of the value change that the user attempts to commit e.g. by pressing Enter,\nthe component can fire either a `change` event or an `unparsable-change` event:\n\nValue change | Event\n:------------------------|:------------------\nempty => parsable | change\nempty => unparsable | unparsable-change\nparsable => empty | change\nparsable => parsable | change\nparsable => unparsable | change\nunparsable => empty | unparsable-change\nunparsable => parsable | change\nunparsable => unparsable | unparsable-change",
2160
+ "description": "`<vaadin-date-picker>` is an input field that allows to enter a date by typing or by selecting from a calendar overlay.\n\n```html\n<vaadin-date-picker label=\"Birthday\"></vaadin-date-picker>\n```\n\n```js\ndatePicker.value = '2016-03-02';\n```\n\nWhen the selected `value` is changed, a `value-changed` event is triggered.\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|----------------\n`label` | The label element\n`input-field` | The element that wraps prefix, value and buttons\n`field-button` | Set on both clear and toggle buttons\n`clear-button` | The clear button\n`error-message` | The error message element\n`helper-text` | The helper text element wrapper\n`required-indicator` | The `required` state indicator element\n`toggle-button` | The toggle button\n`backdrop` | Backdrop of the overlay\n`overlay` | The overlay container\n`content` | The overlay content\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------------|---------------------------------\n`disabled` | Set when the element is disabled\n`has-value` | Set when the element has a value\n`has-label` | Set when the element has a label\n`has-helper` | Set when the element has helper text or slot\n`has-error-message` | Set when the element has an error message\n`has-tooltip` | Set when the element has a slotted tooltip\n`invalid` | Set when the element is invalid\n`focused` | Set when the element is focused\n`focus-ring` | Set when the element is keyboard focused\n`readonly` | Set when the element is readonly\n`opened` | Set when the overlay is opened\n`week-numbers` | Set when week numbers are shown in the calendar\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property |\n:----------------------------------------------------------|\n| `--vaadin-date-picker-date-border-radius` |\n| `--vaadin-date-picker-date-disabled-color` |\n| `--vaadin-date-picker-date-height` |\n| `--vaadin-date-picker-date-selected-background` |\n| `--vaadin-date-picker-date-selected-color` |\n| `--vaadin-date-picker-date-today-color` |\n| `--vaadin-date-picker-date-width` |\n| `--vaadin-date-picker-month-header-color` |\n| `--vaadin-date-picker-month-header-font-size` |\n| `--vaadin-date-picker-month-header-font-weight` |\n| `--vaadin-date-picker-month-padding` |\n| `--vaadin-date-picker-overlay-max-height` |\n| `--vaadin-date-picker-overlay-width` |\n| `--vaadin-date-picker-toolbar-padding` |\n| `--vaadin-date-picker-week-divider-color` |\n| `--vaadin-date-picker-week-number-color` |\n| `--vaadin-date-picker-week-number-font-size` |\n| `--vaadin-date-picker-weekday-color` |\n| `--vaadin-date-picker-weekday-font-size` |\n| `--vaadin-date-picker-weekday-font-weight` |\n| `--vaadin-date-picker-year-scroller-background` |\n| `--vaadin-date-picker-year-scroller-border-color` |\n| `--vaadin-date-picker-year-scroller-current-year-color` |\n| `--vaadin-date-picker-year-scroller-width` |\n| `--vaadin-field-default-width` |\n| `--vaadin-input-field-background` |\n| `--vaadin-input-field-border-color` |\n| `--vaadin-input-field-border-radius` |\n| `--vaadin-input-field-border-width` |\n| `--vaadin-input-field-bottom-end-radius` |\n| `--vaadin-input-field-bottom-start-radius` |\n| `--vaadin-input-field-button-text-color` |\n| `--vaadin-input-field-container-gap` |\n| `--vaadin-input-field-disabled-background` |\n| `--vaadin-input-field-disabled-text-color` |\n| `--vaadin-input-field-error-color` |\n| `--vaadin-input-field-error-font-size` |\n| `--vaadin-input-field-error-font-weight` |\n| `--vaadin-input-field-error-line-height` |\n| `--vaadin-input-field-gap` |\n| `--vaadin-input-field-helper-color` |\n| `--vaadin-input-field-helper-font-size` |\n| `--vaadin-input-field-helper-font-weight` |\n| `--vaadin-input-field-helper-line-height` |\n| `--vaadin-input-field-label-color` |\n| `--vaadin-input-field-label-font-size` |\n| `--vaadin-input-field-label-font-weight` |\n| `--vaadin-input-field-label-line-height` |\n| `--vaadin-input-field-padding` |\n| `--vaadin-input-field-placeholder-color` |\n| `--vaadin-input-field-required-indicator` |\n| `--vaadin-input-field-required-indicator-color` |\n| `--vaadin-input-field-top-end-radius` |\n| `--vaadin-input-field-top-start-radius` |\n| `--vaadin-input-field-value-color` |\n| `--vaadin-input-field-value-font-size` |\n| `--vaadin-input-field-value-font-weight` |\n| `--vaadin-input-field-value-line-height` |\n\n### Internal components\n\nIn addition to `<vaadin-date-picker>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-date-picker-overlay-content>`\n- `<vaadin-date-picker-month-scroller>`\n- `<vaadin-date-picker-year-scroller>`\n- `<vaadin-date-picker-year>`\n- `<vaadin-month-calendar>`\n\nIn order to style the overlay content, use `<vaadin-date-picker-overlay-content>` shadow DOM parts:\n\nPart name | Description\n----------------------|--------------------\n`years-toggle-button` | Fullscreen mode years scroller toggle\n`toolbar` | Toolbar with slotted buttons\n`loader` | Loading spinner shown while the date metadata provider is resolving\n\nThe following state attributes are available on the `<vaadin-date-picker-overlay-content>` element:\n\nAttribute | Description\n----------------|-------------------------------------------------\n`desktop` | Set when the overlay content is in desktop mode\n`fullscreen` | Set when the overlay content is in fullscreen mode\n`years-visible` | Set when the year scroller is visible in fullscreen mode\n`loading` | Set while the date metadata provider is resolving\n\nIn order to style the month calendar, use `<vaadin-month-calendar>` shadow DOM parts:\n\nPart name | Description\n----------------------|--------------------\n`month-header` | Month title\n`weekdays` | Weekday container\n`weekday` | Weekday element\n`week-numbers` | Week numbers container\n`week-number` | Week number element\n`date` | Date element\n`disabled` | Disabled date element\n`loading` | Date element in a month whose metadata is currently being fetched\n`focused` | Focused date element\n`selected` | Selected date element\n`today` | Date element corresponding to the current day\n`past` | Date element corresponding to the date in the past\n`future` | Date element corresponding to the date in the future\n\nIn order to style year scroller elements, use `<vaadin-date-picker-year>` shadow DOM parts:\n\nPart name | Description\n----------------------|--------------------\n`year-number` | Year number\n`year-separator` | Year separator\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.\n\n### Change events\n\nDepending on the nature of the value change that the user attempts to commit e.g. by pressing Enter,\nthe component can fire either a `change` event or an `unparsable-change` event:\n\nValue change | Event\n:------------------------|:------------------\nempty => parsable | change\nempty => unparsable | unparsable-change\nparsable => empty | change\nparsable => parsable | change\nparsable => unparsable | change\nunparsable => empty | unparsable-change\nunparsable => parsable | change\nunparsable => unparsable | unparsable-change",
2161
2161
  "name": "DatePicker",
2162
2162
  "members": [
2163
2163
  {
@@ -2320,7 +2320,7 @@
2320
2320
  "type": {
2321
2321
  "text": "DatePickerDateMetadataProvider | null | undefined"
2322
2322
  },
2323
- "description": "A batch function that fetches metadata for a range of dates the calendar is about to\nrender. It receives a `DatePickerDateRange` and returns, or resolves with, an array of\n`DatePickerDateMetadata` objects — a `DatePickerDate` extended with metadata such as\n`disabled`, e.g. `{ year, month, day, disabled: true }` for the dates that have metadata\nwithin that range. Dates it does not mention have no metadata. `month` is 0-based: 0 is\nJanuary and 11 is December.\n\nUnlike `isDateDisabled`, which is called once per date, this function is called for a\nrange of dates at a time, and again as the calendar renders further dates. The size of the\nrange is decided by the calendar and may span several months, and may include months it\nalready has metadata for, whose entries are then ignored.\n\nIt may return a `Promise`, so the answer can come from a server. Until it resolves, the\naffected dates render with the `loading` part but stay selectable, and a loading spinner\nis shown. Nothing is disabled before the provider has actually reported it, so a slow\nprovider does not make the calendar unusable. If it throws or rejects, the error is logged\nand the affected months are requested again the next time the user navigates.\n\n`disabled` from the metadata is combined with `min`, `max` and `isDateDisabled`: a date is\ndisabled if it is out of the min/max range, or `isDateDisabled` returns `true`, or its\nmetadata marks it disabled. That decides what the calendar renders as disabled, what can be\nselected, and whether the field is valid.\n\nA value is checked against the provider even if the overlay is never opened, which loads the\nmonth holding it. Until that month answers the value is valid, and it is re-validated once\nthe answer arrives, so `checkValidity()` can report a value as valid and then invalid.\n\n`part` from the metadata adds part names to the date, so a theme can style specific dates\nwith `::part()` e.g. `{ year, month, day, part: 'busy' }`. Give a single name or several\nseparated by spaces. Do not use built-in names like `disabled` and `selected`.\n\nKeep a stable reference to the function. Assigning a new function clears the cache and\nre-fetches every visible range. To re-fetch while keeping the same function, because the\ndata behind it changed, call `clearCache()`.",
2323
+ "description": "A function that provides metadata for the dates the calendar is about to render: whether they\nare disabled, and CSS `part` names for styling from outside using the `::part()` selector.\nUnlike `isDateDisabled`, which is called once per date, the metadata provider is called for\na range of dates at a time, and again as the calendar renders further dates.\n\nIt receives a `DatePickerDateRange` and returns an array of `DatePickerDateMetadata` objects\nfor the dates in that range that have metadata. It can return a `Promise` to load the metadata\nasynchronously, and `null` or `undefined` when no date in the range has metadata.\n\nThe returned array has the following structure:\n\n```js\n[\n // The date is an ISO 8601 string.\n { date: '2026-01-01', disabled: true },\n\n // Adds a custom part name to the date.\n { date: '2026-01-02', part: 'busy' },\n]\n```\n\nA date is disabled if its metadata marks it disabled, or `isDateDisabled` returns `true`, or\nit is outside `min` and `max`. Disabled dates are not selectable, and typing a disabled date in\nthe field makes it invalid. The provider does not affect which date is focused when opening the\noverlay. Use `initialPosition` property to provide a selectable date.\n\nWhile a returned `Promise` is pending, the dates it covers are not disabled yet and render with\nthe `loading` part. If the function throws or rejects, corresponding dates are requested again\nthe next time the user navigates.\n\nThe provider is used for validation also when the overlay is closed. Date is considered valid\nwhile the provider is pending, and is re-validated again after the metadata is loaded.\n\nKeep a stable reference to the function: assigning a new one clears the cache and re-fetches\nvisible range. Call `clearCache()` to re-fetch when the data behind the same function changed.",
2324
2324
  "attribute": "date-metadata-provider",
2325
2325
  "inheritedFrom": {
2326
2326
  "name": "DatePickerMixin",
@@ -2418,7 +2418,7 @@
2418
2418
  "type": {
2419
2419
  "text": "function(DatePickerDate): boolean | undefined"
2420
2420
  },
2421
- "description": "A function to be used to determine whether the user can select a given date.\nReceives a `DatePickerDate` object of the date to be selected and should return a\nboolean.",
2421
+ "description": "A function to be used to determine whether the user can select a given date.\nReceives a `DatePickerDate` object of the date to be selected and should return a\nboolean.\n\nThe function is called once per date and has to answer synchronously. Use\n`dateMetadataProvider` when the answer has to be loaded first, or when dates also need\ncustom part names. A date is disabled when either of the two disables it.",
2422
2422
  "attribute": "is-date-disabled",
2423
2423
  "inheritedFrom": {
2424
2424
  "name": "DatePickerMixin",
@@ -2771,7 +2771,7 @@
2771
2771
  "type": {
2772
2772
  "text": "DatePickerDateMetadataProvider | null | undefined"
2773
2773
  },
2774
- "description": "A batch function that fetches metadata for a range of dates the calendar is about to\nrender. It receives a `DatePickerDateRange` and returns, or resolves with, an array of\n`DatePickerDateMetadata` objects — a `DatePickerDate` extended with metadata such as\n`disabled`, e.g. `{ year, month, day, disabled: true }` for the dates that have metadata\nwithin that range. Dates it does not mention have no metadata. `month` is 0-based: 0 is\nJanuary and 11 is December.\n\nUnlike `isDateDisabled`, which is called once per date, this function is called for a\nrange of dates at a time, and again as the calendar renders further dates. The size of the\nrange is decided by the calendar and may span several months, and may include months it\nalready has metadata for, whose entries are then ignored.\n\nIt may return a `Promise`, so the answer can come from a server. Until it resolves, the\naffected dates render with the `loading` part but stay selectable, and a loading spinner\nis shown. Nothing is disabled before the provider has actually reported it, so a slow\nprovider does not make the calendar unusable. If it throws or rejects, the error is logged\nand the affected months are requested again the next time the user navigates.\n\n`disabled` from the metadata is combined with `min`, `max` and `isDateDisabled`: a date is\ndisabled if it is out of the min/max range, or `isDateDisabled` returns `true`, or its\nmetadata marks it disabled. That decides what the calendar renders as disabled, what can be\nselected, and whether the field is valid.\n\nA value is checked against the provider even if the overlay is never opened, which loads the\nmonth holding it. Until that month answers the value is valid, and it is re-validated once\nthe answer arrives, so `checkValidity()` can report a value as valid and then invalid.\n\n`part` from the metadata adds part names to the date, so a theme can style specific dates\nwith `::part()` e.g. `{ year, month, day, part: 'busy' }`. Give a single name or several\nseparated by spaces. Do not use built-in names like `disabled` and `selected`.\n\nKeep a stable reference to the function. Assigning a new function clears the cache and\nre-fetches every visible range. To re-fetch while keeping the same function, because the\ndata behind it changed, call `clearCache()`.",
2774
+ "description": "A function that provides metadata for the dates the calendar is about to render: whether they\nare disabled, and CSS `part` names for styling from outside using the `::part()` selector.\nUnlike `isDateDisabled`, which is called once per date, the metadata provider is called for\na range of dates at a time, and again as the calendar renders further dates.\n\nIt receives a `DatePickerDateRange` and returns an array of `DatePickerDateMetadata` objects\nfor the dates in that range that have metadata. It can return a `Promise` to load the metadata\nasynchronously, and `null` or `undefined` when no date in the range has metadata.\n\nThe returned array has the following structure:\n\n```js\n[\n // The date is an ISO 8601 string.\n { date: '2026-01-01', disabled: true },\n\n // Adds a custom part name to the date.\n { date: '2026-01-02', part: 'busy' },\n]\n```\n\nA date is disabled if its metadata marks it disabled, or `isDateDisabled` returns `true`, or\nit is outside `min` and `max`. Disabled dates are not selectable, and typing a disabled date in\nthe field makes it invalid. The provider does not affect which date is focused when opening the\noverlay. Use `initialPosition` property to provide a selectable date.\n\nWhile a returned `Promise` is pending, the dates it covers are not disabled yet and render with\nthe `loading` part. If the function throws or rejects, corresponding dates are requested again\nthe next time the user navigates.\n\nThe provider is used for validation also when the overlay is closed. Date is considered valid\nwhile the provider is pending, and is re-validated again after the metadata is loaded.\n\nKeep a stable reference to the function: assigning a new one clears the cache and re-fetches\nvisible range. Call `clearCache()` to re-fetch when the data behind the same function changed.",
2775
2775
  "fieldName": "dateMetadataProvider",
2776
2776
  "inheritedFrom": {
2777
2777
  "name": "DatePickerMixin",
@@ -2855,7 +2855,7 @@
2855
2855
  "type": {
2856
2856
  "text": "function(DatePickerDate): boolean | undefined"
2857
2857
  },
2858
- "description": "A function to be used to determine whether the user can select a given date.\nReceives a `DatePickerDate` object of the date to be selected and should return a\nboolean.",
2858
+ "description": "A function to be used to determine whether the user can select a given date.\nReceives a `DatePickerDate` object of the date to be selected and should return a\nboolean.\n\nThe function is called once per date and has to answer synchronously. Use\n`dateMetadataProvider` when the answer has to be loaded first, or when dates also need\ncustom part names. A date is disabled when either of the two disables it.",
2859
2859
  "fieldName": "isDateDisabled",
2860
2860
  "inheritedFrom": {
2861
2861
  "name": "DatePickerMixin",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/date-picker",
3
- "version": "25.3.0-alpha9",
3
+ "version": "25.3.0-beta2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -35,21 +35,21 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "@open-wc/dedupe-mixin": "^1.3.0",
38
- "@vaadin/a11y-base": "25.3.0-alpha9",
39
- "@vaadin/button": "25.3.0-alpha9",
40
- "@vaadin/component-base": "25.3.0-alpha9",
41
- "@vaadin/field-base": "25.3.0-alpha9",
42
- "@vaadin/input-container": "25.3.0-alpha9",
43
- "@vaadin/overlay": "25.3.0-alpha9",
44
- "@vaadin/vaadin-themable-mixin": "25.3.0-alpha9",
38
+ "@vaadin/a11y-base": "25.3.0-beta2",
39
+ "@vaadin/button": "25.3.0-beta2",
40
+ "@vaadin/component-base": "25.3.0-beta2",
41
+ "@vaadin/field-base": "25.3.0-beta2",
42
+ "@vaadin/input-container": "25.3.0-beta2",
43
+ "@vaadin/overlay": "25.3.0-beta2",
44
+ "@vaadin/vaadin-themable-mixin": "25.3.0-beta2",
45
45
  "lit": "^3.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@vaadin/aura": "25.3.0-alpha9",
49
- "@vaadin/chai-plugins": "25.3.0-alpha9",
50
- "@vaadin/test-runner-commands": "25.3.0-alpha9",
48
+ "@vaadin/aura": "25.3.0-beta2",
49
+ "@vaadin/chai-plugins": "25.3.0-beta2",
50
+ "@vaadin/test-runner-commands": "25.3.0-beta2",
51
51
  "@vaadin/testing-helpers": "^2.0.0",
52
- "@vaadin/vaadin-lumo-styles": "25.3.0-alpha9",
52
+ "@vaadin/vaadin-lumo-styles": "25.3.0-beta2",
53
53
  "sinon": "^22.0.0"
54
54
  },
55
55
  "customElements": "custom-elements.json",
@@ -57,5 +57,5 @@
57
57
  "web-types.json",
58
58
  "web-types.lit.json"
59
59
  ],
60
- "gitHead": "cb915ebde095ec5b94a87af93dd4530f51984c52"
60
+ "gitHead": "d97ccbec217b60c39f3c8b2dd52473c79a48c8c1"
61
61
  }
@@ -10,6 +10,9 @@ export const monthCalendarStyles = css`
10
10
  :host {
11
11
  display: block;
12
12
  padding: var(--vaadin-date-picker-month-padding, var(--vaadin-padding-s));
13
+ -webkit-tap-highlight-color: transparent;
14
+ -webkit-user-select: none;
15
+ user-select: none;
13
16
  }
14
17
 
15
18
  [part='month-header'] {
@@ -12,8 +12,8 @@ import type { DatePickerDateMetadata, DatePickerDateMetadataProvider } from './v
12
12
  *
13
13
  * The provider is called for a range of months and may return an array
14
14
  * synchronously or a `Promise`, so results from a server (Flow) or a remote
15
- * availability service can be awaited. Each returned entry is a `DatePickerDate`
16
- * extended with metadata fields, e.g. `{ year, month, day, disabled: true }`.
15
+ * availability service can be awaited. The range and each returned entry identify
16
+ * a date by an ISO 8601 string, e.g. `{ date: '2026-01-01', disabled: true }`.
17
17
  *
18
18
  * `ARCHITECTURE.md` in this package records the reasoning behind the request,
19
19
  * caching, notification and failure behavior.
@@ -6,14 +6,7 @@
6
6
  import { microTask } from '@vaadin/component-base/src/async.js';
7
7
  import { Debouncer } from '@vaadin/component-base/src/debounce.js';
8
8
  import { issueWarning } from '@vaadin/component-base/src/warnings.js';
9
- import {
10
- createDate,
11
- extractDateParts,
12
- lastOfMonth,
13
- monthDate,
14
- monthIndex,
15
- monthIndexOf,
16
- } from './vaadin-date-picker-helper.js';
9
+ import { formatISODate, lastOfMonth, monthDate, monthIndex, parseDate } from './vaadin-date-picker-helper.js';
17
10
 
18
11
  // Counted from January of year 0, so a block is one calendar year.
19
12
  const BLOCK_MONTHS = 12;
@@ -24,12 +17,10 @@ function blockStart(month) {
24
17
 
25
18
  const PENDING_MONTH = Object.freeze({ pending: true });
26
19
 
27
- function isValidEntry(entry) {
28
- if (!entry || !Number.isInteger(entry.year) || !Number.isInteger(entry.month) || !Number.isInteger(entry.day)) {
29
- return false;
30
- }
31
- const date = createDate(entry.year, entry.month, entry.day);
32
- return date.getFullYear() === entry.year && date.getMonth() === entry.month && date.getDate() === entry.day;
20
+ // The date of an entry, or `undefined` when its `date` is not one. Checked for being a string first,
21
+ // since coercing another type to one can throw, and an entry comes from outside.
22
+ function entryDate(entry) {
23
+ return typeof entry?.date === 'string' ? parseDate(entry.date) : undefined;
33
24
  }
34
25
 
35
26
  function groupEntriesByMonth(months, entries) {
@@ -37,10 +28,11 @@ function groupEntriesByMonth(months, entries) {
37
28
 
38
29
  if (Array.isArray(entries)) {
39
30
  entries.forEach((entry) => {
40
- if (isValidEntry(entry)) {
41
- result.get(monthIndexOf(entry.year, entry.month))?.set(entry.day, entry);
31
+ const date = entryDate(entry);
32
+ if (date) {
33
+ result.get(monthIndex(date))?.set(date.getDate(), entry);
42
34
  } else {
43
- issueWarning('Ignored `dateMetadataProvider` entries with an invalid year, month (0-11) or day.');
35
+ issueWarning('Ignored `dateMetadataProvider` entries whose `date` is not an ISO 8601 date.');
44
36
  }
45
37
  });
46
38
  } else if (entries != null) {
@@ -56,8 +48,8 @@ function groupEntriesByMonth(months, entries) {
56
48
  *
57
49
  * The provider is called for a range of months and may return an array
58
50
  * synchronously or a `Promise`, so results from a server (Flow) or a remote
59
- * availability service can be awaited. Each returned entry is a `DatePickerDate`
60
- * extended with metadata fields, e.g. `{ year, month, day, disabled: true }`.
51
+ * availability service can be awaited. The range and each returned entry identify
52
+ * a date by an ISO 8601 string, e.g. `{ date: '2026-01-01', disabled: true }`.
61
53
  *
62
54
  * `ARCHITECTURE.md` in this package records the reasoning behind the request,
63
55
  * caching, notification and failure behavior.
@@ -235,8 +227,8 @@ export class DateMetadataController {
235
227
  this.#notify();
236
228
 
237
229
  const range = {
238
- start: extractDateParts(monthDate(months[0])),
239
- end: extractDateParts(lastOfMonth(monthDate(months.at(-1)))),
230
+ start: formatISODate(monthDate(months[0])),
231
+ end: formatISODate(lastOfMonth(monthDate(months.at(-1)))),
240
232
  };
241
233
 
242
234
  let entries;
@@ -6,19 +6,85 @@
6
6
  import type { DateMetadataController } from './vaadin-date-metadata-controller.js';
7
7
  import type { DatePickerDate } from './vaadin-date-picker-mixin.js';
8
8
 
9
+ /**
10
+ * Create a date at midnight in local time. Unlike `new Date(year, month, day)`,
11
+ * this supports years below 100, which the constructor maps into the 20th
12
+ * century. The month is assigned before the day so that the initial day of month
13
+ * (1) always exists in the target month.
14
+ *
15
+ * @param month Zero-based month, may be out of range to shift the year
16
+ * @param day May be `0` to select the last day of the previous month
17
+ */
18
+ declare function createDate(year: number, month: number, day: number): Date;
19
+
20
+ /**
21
+ * Get the first day of the month the given date is in.
22
+ */
23
+ declare function firstOfMonth(date: Date): Date;
24
+
25
+ /**
26
+ * Get the last day of the month the given date is in.
27
+ */
28
+ declare function lastOfMonth(date: Date): Date;
29
+
30
+ /**
31
+ * Get the index of a month, counted from January of year 0. Reduces a month to a single
32
+ * integer, so a lookup builds no key and two months are adjacent when their indexes are.
33
+ *
34
+ * @param month Zero-based month
35
+ */
36
+ declare function monthIndexOf(year: number, month: number): number;
37
+
38
+ /**
39
+ * Get the index of the month the given date is in.
40
+ */
41
+ declare function monthIndex(date: Date): number;
42
+
43
+ /**
44
+ * Get the first day of the month with the given index, inverting `monthIndexOf`. Counting from
45
+ * January of year 0 also inverts negative indexes, since `createDate` normalizes a month outside
46
+ * 0-11 into the year.
47
+ */
48
+ declare function monthDate(index: number): Date;
49
+
9
50
  /**
10
51
  * Get ISO 8601 week number for the given date.
11
52
  *
12
53
  * @returns Week number
13
54
  */
14
- declare function getISOWeekNumber(Date: Date): number;
55
+ declare function getISOWeekNumber(date: Date): number;
56
+
57
+ /**
58
+ * Creates a new object with the same date, but sets the hours, minutes, seconds and milliseconds to 0.
59
+ *
60
+ * @param date in system timezone
61
+ * @returns The same date with time elements set to 0, in system timezone.
62
+ */
63
+ declare function normalizeDate(date: Date): Date;
64
+
65
+ /**
66
+ * Creates a new object with the same date, but sets the hours, minutes, seconds and milliseconds to 0.
67
+ *
68
+ * Uses UTC date components to allow handling date instances independently of
69
+ * the system time-zone.
70
+ *
71
+ * @param date in UTC timezone
72
+ * @returns The same date with time elements set to 0, in UTC timezone.
73
+ */
74
+ declare function normalizeUTCDate(date: Date): Date;
15
75
 
16
76
  /**
17
77
  * Check if two dates are equal.
18
78
  *
19
79
  * @returns True if the given date objects refer to the same date
20
80
  */
21
- declare function dateEquals(date1: Date | null, date2: Date | null): boolean;
81
+ declare function dateEquals(date1: Date | null, date2: Date | null, normalizer?: (date: Date) => Date): boolean;
82
+
83
+ /**
84
+ * Extracts the basic component parts of a date (day, month and year)
85
+ * to the expected format.
86
+ */
87
+ declare function extractDateParts(date: Date): { day: number; month: number; year: number };
22
88
 
23
89
  /**
24
90
  * Check if the given date is in the range of allowed dates.
@@ -55,37 +121,85 @@ declare function dateSelectable(
55
121
  declare function getClosestDate(date: Date, dates: Date[]): Date;
56
122
 
57
123
  /**
58
- * Extracts the basic component parts of a date (day, month and year)
59
- * to the expected format.
124
+ * Get difference in months between today and given months value.
60
125
  */
61
- declare function extractDateParts(date: Date): { day: number; month: number; year: number };
126
+ declare function dateAfterXMonths(months: number): Date;
62
127
 
63
128
  /**
64
- * Get difference in months between today and given months value.
129
+ * Calculate the year of the date based on the provided reference date.
130
+ * Gets a two-digit year and returns a full year.
131
+ *
132
+ * @param year Should be in the range of [0, 99]
133
+ * @returns Adjusted year value
65
134
  */
66
- declare function dateAfterXMonths(months: number): number;
135
+ declare function getAdjustedYear(referenceDate: Date, year: number, month?: number, day?: number): number;
67
136
 
68
137
  /**
69
- * Calculate the year of the date based on the provided reference date
70
- * Gets a two-digit year and returns a full year.
138
+ * Parse date string of one of the following date formats:
139
+ * - ISO 8601 `"YYYY-MM-DD"`
140
+ * - Extended ISO 8601 with a signed year, e.g. `"+012026-MM-DD"` or `"-0001-MM-DD"`
141
+ *
142
+ * A date that does not exist, such as `"2026-02-30"`, is not parsed. Building it would carry the
143
+ * surplus into the next month or year and answer with a date that was never asked for.
144
+ *
145
+ * @param str Date string to parse
146
+ * @returns Parsed date in system timezone, or `undefined` when the string is not a date
71
147
  */
72
- declare function getAdjustedYear(referenceDate: Date, year: number, month?: number, day?: number): Date;
148
+ declare function parseDate(str: string): Date | undefined;
73
149
 
74
150
  /**
75
151
  * Parse date string of one of the following date formats:
76
152
  * - ISO 8601 `"YYYY-MM-DD"`
77
- * - 6-digit extended ISO 8601 `"+YYYYYY-MM-DD"`, `"-YYYYYY-MM-DD"`
153
+ * - Extended ISO 8601 with a signed year, e.g. `"+012026-MM-DD"` or `"-0001-MM-DD"`
154
+ *
155
+ * Uses UTC date components to allow handling date instances independently of
156
+ * the system time-zone.
157
+ *
158
+ * A date that does not exist, such as `"2026-02-30"`, is not parsed, as in `parseDate`.
159
+ *
160
+ * @param str Date string to parse
161
+ * @returns Parsed date in UTC timezone, or `undefined` when the string is not a date
162
+ */
163
+ declare function parseUTCDate(str: string): Date | undefined;
164
+
165
+ /**
166
+ * Format a date instance in ISO 8601 (`"YYYY-MM-DD"`) or 6-digit extended ISO
167
+ * 8601 (`"+YYYYYY-MM-DD"`, `"-YYYYYY-MM-DD"`) format.
168
+ *
169
+ * @param date in system timezone
78
170
  */
79
- declare function parseDate(str: string): Date;
171
+ declare function formatISODate(date: Date): string;
172
+
173
+ /**
174
+ * Format a date instance in ISO 8601 (`"YYYY-MM-DD"`) or 6-digit extended ISO
175
+ * 8601 (`"+YYYYYY-MM-DD"`, `"-YYYYYY-MM-DD"`) format.
176
+ *
177
+ * Uses UTC date components to allow handling date instances independently of
178
+ * the system time-zone.
179
+ *
180
+ * @param date in UTC timezone
181
+ */
182
+ declare function formatUTCISODate(date: Date): string;
80
183
 
81
184
  export {
185
+ createDate,
186
+ firstOfMonth,
187
+ lastOfMonth,
188
+ monthIndexOf,
189
+ monthIndex,
190
+ monthDate,
82
191
  getISOWeekNumber,
192
+ normalizeDate,
193
+ normalizeUTCDate,
83
194
  dateEquals,
195
+ extractDateParts,
84
196
  dateAllowed,
85
197
  dateSelectable,
86
198
  getClosestDate,
87
- extractDateParts,
88
199
  dateAfterXMonths,
89
200
  getAdjustedYear,
90
201
  parseDate,
202
+ parseUTCDate,
203
+ formatISODate,
204
+ formatUTCISODate,
91
205
  };
@@ -260,47 +260,66 @@ export function getAdjustedYear(referenceDate, year, month = 0, day = 1) {
260
260
  return adjustedYear;
261
261
  }
262
262
 
263
+ const ISO_DATE = /^([-+]\d{1,6}|\d{2,4})-(\d{1,2})-(\d{1,2})$/u;
264
+
265
+ // The parts of a date string in a format the parsers accept, as written.
266
+ function parseParts(str) {
267
+ // Parsing with RegExp to ensure correct format
268
+ const parts = ISO_DATE.exec(str);
269
+ if (!parts) {
270
+ return undefined;
271
+ }
272
+
273
+ return { year: parseInt(parts[1], 10), month: parseInt(parts[2], 10) - 1, day: parseInt(parts[3], 10) };
274
+ }
275
+
263
276
  /**
264
277
  * Parse date string of one of the following date formats:
265
278
  * - ISO 8601 `"YYYY-MM-DD"`
266
- * - 6-digit extended ISO 8601 `"+YYYYYY-MM-DD"`, `"-YYYYYY-MM-DD"`
279
+ * - Extended ISO 8601 with a signed year, e.g. `"+012026-MM-DD"` or `"-0001-MM-DD"`
280
+ *
281
+ * A date that does not exist, such as `"2026-02-30"`, is not parsed. Building it would carry the
282
+ * surplus into the next month or year and answer with a date that was never asked for.
283
+ *
267
284
  * @param {!string} str Date string to parse
268
285
  * @return {Date} Parsed date in system timezone
269
286
  */
270
287
  export function parseDate(str) {
271
- // Parsing with RegExp to ensure correct format
272
- const parts = /^([-+]\d{1}|\d{2,4}|[-+]\d{6})-(\d{1,2})-(\d{1,2})$/u.exec(str);
288
+ const parts = parseParts(str);
273
289
  if (!parts) {
274
290
  return undefined;
275
291
  }
276
292
 
277
- return createDate(parseInt(parts[1], 10), parseInt(parts[2], 10) - 1, parseInt(parts[3], 10));
293
+ const date = createDate(parts.year, parts.month, parts.day);
294
+
295
+ return date.getMonth() === parts.month && date.getDate() === parts.day ? date : undefined;
278
296
  }
279
297
 
280
298
  /**
281
299
  * Parse date string of one of the following date formats:
282
300
  * - ISO 8601 `"YYYY-MM-DD"`
283
- * - 6-digit extended ISO 8601 `"+YYYYYY-MM-DD"`, `"-YYYYYY-MM-DD"`
301
+ * - Extended ISO 8601 with a signed year, e.g. `"+012026-MM-DD"` or `"-0001-MM-DD"`
284
302
  *
285
303
  * Uses UTC date components to allow handling date instances independently of
286
304
  * the system time-zone.
287
305
  *
306
+ * A date that does not exist, such as `"2026-02-30"`, is not parsed, as in `parseDate`.
307
+ *
288
308
  * @param {!string} str Date string to parse
289
309
  * @return {Date} Parsed date in UTC timezone
290
310
  */
291
311
  export function parseUTCDate(str) {
292
- // Parsing with RegExp to ensure correct format
293
- const parts = /^([-+]\d{1}|\d{2,4}|[-+]\d{6})-(\d{1,2})-(\d{1,2})$/u.exec(str);
312
+ const parts = parseParts(str);
294
313
  if (!parts) {
295
314
  return undefined;
296
315
  }
297
316
 
298
317
  const date = new Date(Date.UTC(0, 0)); // Wrong date (1900-01-01), but with midnight in UTC
299
- date.setUTCFullYear(parseInt(parts[1], 10));
300
- date.setUTCMonth(parseInt(parts[2], 10) - 1);
301
- date.setUTCDate(parseInt(parts[3], 10));
318
+ date.setUTCFullYear(parts.year);
319
+ date.setUTCMonth(parts.month);
320
+ date.setUTCDate(parts.day);
302
321
 
303
- return date;
322
+ return date.getUTCMonth() === parts.month && date.getUTCDate() === parts.day ? date : undefined;
304
323
  }
305
324
 
306
325
  function formatISODateBase(dateParts) {