From edfcf5123a717237fa55c733b922e80f46ee69d5 Mon Sep 17 00:00:00 2001 From: Bartek Date: Mon, 28 Sep 2026 13:24:13 +0200 Subject: [PATCH] Fix `Datepicker` throwing with two months on Vanilla Calendar Pro 3.4 --- ...-datepicker-vanilla-calendar-extensions.md | 5 ++++ core/js/src/datepicker.ts | 22 ++++++++++++++++ core/js/tests/unit/datepicker.spec.ts | 25 +++++++++++++++++++ core/package.json | 2 +- pnpm-lock.yaml | 10 ++++---- 5 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 .changeset/fix-datepicker-vanilla-calendar-extensions.md diff --git a/.changeset/fix-datepicker-vanilla-calendar-extensions.md b/.changeset/fix-datepicker-vanilla-calendar-extensions.md new file mode 100644 index 000000000..9ef0b9483 --- /dev/null +++ b/.changeset/fix-datepicker-vanilla-calendar-extensions.md @@ -0,0 +1,5 @@ +--- +"@tabler/core": patch +--- + +Fixed `Datepicker` with Vanilla Calendar Pro 3.4 throwing on `data-bs-display-months-count="2"` and extension options. diff --git a/core/js/src/datepicker.ts b/core/js/src/datepicker.ts index 082850e55..f25b040b3 100644 --- a/core/js/src/datepicker.ts +++ b/core/js/src/datepicker.ts @@ -40,6 +40,9 @@ const HIDE_DELAY = 100 // ms delay before hiding after selection const DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/ +// Vanilla Calendar Pro 3.4+ throws on an option whose extension is not registered +const PLUGIN_EXTENSIONS = ['annotations', 'months', 'motion', 'time', 'weeks'] as const + // The public API is typed with local copies of the Vanilla Calendar Pro types. // `vanilla-calendar-pro` is an optional peer dependency, so the published // `dist/types` must not import it: a project that never loads the datepicker @@ -590,6 +593,11 @@ class Datepicker extends BaseComponent { calendarOptions.selectedYear = firstDate.getFullYear() } + const extensions = this._getPluginExtensions() + if (extensions.length > 0) { + calendarOptions.extensions = extensions + } + if (this._config.dateMin) { calendarOptions.dateMin = this._config.dateMin as Options['dateMin'] } @@ -601,6 +609,20 @@ class Datepicker extends BaseComponent { return calendarOptions } + /** @internal */ + _getPluginExtensions(): NonNullable { + const extensions = [...((this._config.vcpOptions as Options).extensions ?? [])] + + for (const name of PLUGIN_EXTENSIONS) { + const extension = window.VanillaCalendarPro?.[name] + if (extension && !extensions.includes(extension)) { + extensions.push(extension) + } + } + + return extensions + } + /** @internal */ _handleDateClick(self: Calendar, event: MouseEvent): void { const selectedDates = [...self.context.selectedDates] diff --git a/core/js/tests/unit/datepicker.spec.ts b/core/js/tests/unit/datepicker.spec.ts index 9ab21b6d3..bf0ad5414 100644 --- a/core/js/tests/unit/datepicker.spec.ts +++ b/core/js/tests/unit/datepicker.spec.ts @@ -137,6 +137,31 @@ describe('Datepicker', () => { expect(input().isConnected).toBe(true) expect(input().value).toBe('2026-03-04') }) + + it('should show two months side by side', () => { + fixtureEl.innerHTML = '
' + + new Datepicker(fixtureEl.querySelector('div')!) + + expect(fixtureEl.querySelectorAll('[data-vc="column"]')).toHaveLength(2) + }) + + it('should enable an option that needs a plugin extension', () => { + fixtureEl.innerHTML = '
' + + new Datepicker(fixtureEl.querySelector('div')!, { vcpOptions: { selectionTimeMode: 24 } }) + + expect(fixtureEl.querySelector('[data-vc="time"]')).not.toBeNull() + }) + + it('should keep extensions passed through vcpOptions', () => { + fixtureEl.innerHTML = '' + + const instance = new Datepicker(input(), { vcpOptions: { extensions: [VanillaCalendarPro.time] } }) + + expect(instance.calendar!.extensions).toContain(VanillaCalendarPro.time) + expect(instance.calendar!.extensions).toContain(VanillaCalendarPro.months) + }) }) describe('show and hide', () => { diff --git a/core/package.json b/core/package.json index 8add9cc8e..e1a5a4d75 100644 --- a/core/package.json +++ b/core/package.json @@ -287,7 +287,7 @@ "tom-select": "^2.6.2", "typed.js": "^3.0.0", "typescript": "^7.0.2", - "vanilla-calendar-pro": "^3.3.2", + "vanilla-calendar-pro": "^3.4.0", "vitest": "4.1.11" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5d87b3c0..0d91c2786 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -214,8 +214,8 @@ importers: specifier: ^7.0.2 version: 7.0.2 vanilla-calendar-pro: - specifier: ^3.3.2 - version: 3.3.2 + specifier: ^3.4.0 + version: 3.4.0 vitest: specifier: 4.1.11 version: 4.1.11(@types/node@26.4.0)(@vitest/browser-playwright@4.1.11)(@vitest/coverage-istanbul@4.1.11)(esbuild@0.28.1)(sass@1.103.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.0) @@ -4601,8 +4601,8 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - vanilla-calendar-pro@3.3.2: - resolution: {integrity: sha512-RaLpDtvQFeKi0ajOpGBedLNrr0YoiYAF+0sppk4XZV/U57AuihJIhw8h2whUvIG1ZSR3LrdSXk3lHLkCPGlHvg==} + vanilla-calendar-pro@3.4.0: + resolution: {integrity: sha512-HLWjzHOWvMIrjI77tXK5bYzp0s5TeBSrZC247STjcTAdWI7kqEwWT6Xvu20vqdwzF498H1Da8l4WpdgVIGtc1Q==} vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -9590,7 +9590,7 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vanilla-calendar-pro@3.3.2: {} + vanilla-calendar-pro@3.4.0: {} vfile-location@5.0.3: dependencies: