v-calendar-3 1.0.1 → 1.1.0

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.
package/README.md CHANGED
@@ -4,7 +4,7 @@ A maintained Vue 3 calendar and date picker with TypeScript declarations,
4
4
  timezone support, keyboard navigation, touch interaction, and responsive theme
5
5
  handling.
6
6
 
7
- Current version: `1.0.1`
7
+ Current version: `1.1.0`
8
8
 
9
9
  ## Features
10
10
 
@@ -112,7 +112,7 @@ const attributes = [
112
112
  <template>
113
113
  <Calendar :attributes="attributes" />
114
114
  <DatePicker v-model="selectedDate" />
115
- <DatePicker v-model.range="range" />
115
+ <DatePicker v-model.range="range" :rows="2" />
116
116
  </template>
117
117
  ```
118
118
 
@@ -139,6 +139,13 @@ ranges and the `mode` prop when time selection is required.
139
139
  <DatePicker v-model="time" mode="time" is24hr />
140
140
  ```
141
141
 
142
+ `rows="2"` with the default `columns="1"` is the two-month period layout. It
143
+ renders both months horizontally with a complete navigation header and a
144
+ month/year picker on each pane. The displayed months remain consecutive, and
145
+ each pane includes muted leading and trailing dates from adjacent months so its
146
+ week rows are complete. With `trim-weeks`, both period panes are balanced to the
147
+ larger visible week count.
148
+
142
149
  The `string` and `number` model modifiers are also supported. Numeric values use
143
150
  JavaScript timestamp milliseconds.
144
151
 
@@ -234,6 +241,7 @@ styles to internal selectors.
234
241
  --vc-day-min-height: 1.75rem;
235
242
  --vc-day-content-width: 1.75rem;
236
243
  --vc-day-content-height: 1.75rem;
244
+ --vc-day-content-outside-month-opacity: 0.6;
237
245
  --vc-highlight-width: 1.75rem;
238
246
  --vc-highlight-height: 1.75rem;
239
247
  --vc-header-margin-top: 0;
@@ -163,6 +163,8 @@
163
163
 
164
164
  .vc-header {
165
165
  display: grid;
166
+ width: 100%;
167
+ min-width: 0;
166
168
  grid-gap: var(--vc-header-gap);
167
169
  align-items: center;
168
170
  height: var(--vc-header-height);
@@ -181,6 +183,8 @@
181
183
  .vc-header .vc-title-wrapper {
182
184
  grid-row: 1;
183
185
  grid-column: title;
186
+ min-width: 0;
187
+ justify-self: center;
184
188
  }
185
189
  .vc-header .vc-prev {
186
190
  grid-row: 1;
@@ -208,6 +212,9 @@
208
212
  font-weight: var(--vc-font-semibold);
209
213
  text-transform: var(--vc-header-title-text-transform);
210
214
  white-space: nowrap;
215
+ max-width: 100%;
216
+ overflow: hidden;
217
+ text-overflow: ellipsis;
211
218
  padding: var(--vc-header-title-padding);
212
219
  margin: 0;
213
220
  line-height: var(--vc-header-title-line-height);
@@ -303,15 +310,13 @@
303
310
  position: relative;
304
311
  min-height: var(--vc-day-min-height);
305
312
  z-index: 1;
306
- /* &.is-not-in-month * {
307
- opacity: 0;
308
- pointer-events: none;
309
- } */
310
313
  }
311
314
  .vc-monthly .is-not-in-month * {
312
- opacity: 0;
313
315
  pointer-events: none;
314
316
  }
317
+ .vc-monthly .is-not-in-month .vc-day-content {
318
+ opacity: var(--vc-day-content-outside-month-opacity);
319
+ }
315
320
  .vc-day-layer {
316
321
  position: absolute;
317
322
  left: 0;
@@ -855,6 +860,7 @@
855
860
  --vc-day-content-width: 28px;
856
861
  --vc-day-content-height: 28px;
857
862
  --vc-day-content-line-height: 28px;
863
+ --vc-day-content-outside-month-opacity: 0.6;
858
864
  --vc-highlight-width: var(--vc-day-content-width);
859
865
  --vc-highlight-height: var(--vc-day-content-height);
860
866
 
package/dist/cjs/index.js CHANGED
@@ -8007,6 +8007,9 @@ function createCalendar(props, { slots, emit }) {
8007
8007
  provideSlots(slots);
8008
8008
  const { theme, color, displayMode, locale, masks, minDate, maxDate, normalizedMinDate, normalizedMaxDate, disabledAttribute, disabledDates } = useOrCreateBase(props);
8009
8009
  const count = (0, vue.computed)(() => props.rows * props.columns);
8010
+ const isPeriodLayout = (0, vue.computed)(() => props.rows === 2 && props.columns === 1);
8011
+ const layoutRows = (0, vue.computed)(() => isPeriodLayout.value ? 1 : props.rows);
8012
+ const layoutColumns = (0, vue.computed)(() => isPeriodLayout.value ? 2 : props.columns);
8010
8013
  const step = (0, vue.computed)(() => props.step || count.value);
8011
8014
  const firstPage = (0, vue.computed)(() => (0, import_head.default)(_pages.value) ?? null);
8012
8015
  const lastPage = (0, vue.computed)(() => (0, import_last.default)(_pages.value) ?? null);
@@ -8139,10 +8142,10 @@ function createCalendar(props, { slots, emit }) {
8139
8142
  for (let i = 0; i < count.value; i++) {
8140
8143
  const newPage = addPages$1(fromPage, i);
8141
8144
  const position = i + 1;
8142
- const row = Math.ceil(position / props.columns);
8143
- const rowFromEnd = props.rows - row + 1;
8144
- const column = position % props.columns || props.columns;
8145
- const columnFromEnd = props.columns - column + 1;
8145
+ const row = Math.ceil(position / layoutColumns.value);
8146
+ const rowFromEnd = layoutRows.value - row + 1;
8147
+ const column = position % layoutColumns.value || layoutColumns.value;
8148
+ const columnFromEnd = layoutColumns.value - column + 1;
8146
8149
  const weeknumberPosition = getWeeknumberPosition(column, columnFromEnd);
8147
8150
  pages.push(locale.value.getPage({
8148
8151
  ...newPage,
@@ -8159,6 +8162,12 @@ function createCalendar(props, { slots, emit }) {
8159
8162
  weeknumberPosition
8160
8163
  }));
8161
8164
  }
8165
+ if (isPeriodLayout.value && isMonthly.value) {
8166
+ const weekCount = Math.max(...pages.map((currentPage) => currentPage.viewWeeks.length));
8167
+ pages.forEach((currentPage) => {
8168
+ currentPage.viewWeeks = currentPage.weeks.slice(0, weekCount);
8169
+ });
8170
+ }
8162
8171
  transitionName.value = getPageTransition(_pages.value[0], pages[0], transition);
8163
8172
  _pages.value = pages;
8164
8173
  if (transitionName.value && transitionName.value !== "none") transitionPromise = {
@@ -8216,6 +8225,14 @@ function createCalendar(props, { slots, emit }) {
8216
8225
  const moveNext = () => {
8217
8226
  return moveBy(step.value);
8218
8227
  };
8228
+ const canMovePeriodPrev = (0, vue.computed)(() => canMoveBy(-1));
8229
+ const canMovePeriodNext = (0, vue.computed)(() => canMoveBy(1));
8230
+ const movePeriodPrev = () => {
8231
+ return moveBy(-1);
8232
+ };
8233
+ const movePeriodNext = () => {
8234
+ return moveBy(1);
8235
+ };
8219
8236
  const tryFocusDate = (date) => {
8220
8237
  const inMonth = isMonthly.value ? ".in-month" : "";
8221
8238
  const daySelector = `.id-${locale.value.getDayId(date)}${inMonth}`;
@@ -8317,7 +8334,11 @@ function createCalendar(props, { slots, emit }) {
8317
8334
  (0, vue.watch)(() => locale.value, () => {
8318
8335
  refreshPages();
8319
8336
  });
8320
- (0, vue.watch)(() => count.value, () => refreshPages());
8337
+ (0, vue.watch)([
8338
+ count,
8339
+ layoutRows,
8340
+ layoutColumns
8341
+ ], () => refreshPages());
8321
8342
  (0, vue.watch)(() => props.view, () => _view.value = props.view);
8322
8343
  (0, vue.watch)(() => _view.value, () => {
8323
8344
  handleWatcher("view", () => {
@@ -8358,6 +8379,9 @@ function createCalendar(props, { slots, emit }) {
8358
8379
  dayCells,
8359
8380
  count,
8360
8381
  step,
8382
+ isPeriodLayout,
8383
+ layoutRows,
8384
+ layoutColumns,
8361
8385
  firstPage,
8362
8386
  lastPage,
8363
8387
  canMovePrev,
@@ -8377,6 +8401,10 @@ function createCalendar(props, { slots, emit }) {
8377
8401
  moveBy,
8378
8402
  movePrev,
8379
8403
  moveNext,
8404
+ canMovePeriodPrev,
8405
+ canMovePeriodNext,
8406
+ movePeriodPrev,
8407
+ movePeriodNext,
8380
8408
  onTransitionBeforeEnter,
8381
8409
  onTransitionAfterEnter,
8382
8410
  tryFocusDate,
@@ -8940,11 +8968,16 @@ var CalendarHeader_default = /* @__PURE__ */ (0, vue.defineComponent)({
8940
8968
  isXl: { type: Boolean },
8941
8969
  is2xl: { type: Boolean },
8942
8970
  hideTitle: { type: Boolean },
8943
- hideArrows: { type: Boolean }
8971
+ hideArrows: { type: Boolean },
8972
+ periodNavigation: { type: Boolean }
8944
8973
  },
8945
8974
  setup(__props) {
8946
8975
  const props = __props;
8947
- const { navPopoverId, navVisibility, canMovePrev, movePrev, canMoveNext, moveNext } = useCalendar();
8976
+ const { navPopoverId, navVisibility, canMovePrev, movePrev, canMoveNext, moveNext, canMovePeriodPrev, canMovePeriodNext, movePeriodPrev, movePeriodNext } = useCalendar();
8977
+ const canMovePrev_ = (0, vue.computed)(() => props.periodNavigation ? canMovePeriodPrev.value : canMovePrev.value);
8978
+ const canMoveNext_ = (0, vue.computed)(() => props.periodNavigation ? canMovePeriodNext.value : canMoveNext.value);
8979
+ const movePrev_ = () => props.periodNavigation ? movePeriodPrev() : movePrev();
8980
+ const moveNext_ = () => props.periodNavigation ? movePeriodNext() : moveNext();
8948
8981
  const navPlacement = (0, vue.computed)(() => {
8949
8982
  switch (props.page.titlePosition) {
8950
8983
  case "left": return "bottom-start";
@@ -8982,6 +9015,7 @@ var CalendarHeader_default = /* @__PURE__ */ (0, vue.defineComponent)({
8982
9015
  };
8983
9016
  });
8984
9017
  const gridStyle = (0, vue.computed)(() => {
9018
+ if (props.periodNavigation && !props.layout) return { gridTemplateColumns: "[prev] auto [title] minmax(0, 1fr) [next] auto" };
8985
9019
  return { gridTemplateColumns: layout_.value.split("").map((l) => {
8986
9020
  switch (l) {
8987
9021
  case "p": return "[prev] auto";
@@ -9005,12 +9039,12 @@ var CalendarHeader_default = /* @__PURE__ */ (0, vue.defineComponent)({
9005
9039
  key: 0,
9006
9040
  type: "button",
9007
9041
  class: "vc-arrow vc-prev vc-focus",
9008
- disabled: !(0, vue.unref)(canMovePrev),
9009
- onClick: _cache[0] || (_cache[0] = (...args) => (0, vue.unref)(movePrev) && (0, vue.unref)(movePrev)(...args)),
9010
- onKeydown: _cache[1] || (_cache[1] = (0, vue.withKeys)((...args) => (0, vue.unref)(movePrev) && (0, vue.unref)(movePrev)(...args), ["space", "enter"]))
9042
+ disabled: !canMovePrev_.value,
9043
+ onClick: movePrev_,
9044
+ onKeydown: (0, vue.withKeys)(movePrev_, ["space", "enter"])
9011
9045
  }, [(0, vue.createVNode)(CalendarSlot_default, {
9012
9046
  name: "header-prev-button",
9013
- disabled: !(0, vue.unref)(canMovePrev)
9047
+ disabled: !canMovePrev_.value
9014
9048
  }, {
9015
9049
  default: (0, vue.withCtx)(() => [(0, vue.createVNode)(BaseIcon_default, {
9016
9050
  name: "ChevronLeft",
@@ -9032,12 +9066,12 @@ var CalendarHeader_default = /* @__PURE__ */ (0, vue.defineComponent)({
9032
9066
  key: 2,
9033
9067
  type: "button",
9034
9068
  class: "vc-arrow vc-next vc-focus",
9035
- disabled: !(0, vue.unref)(canMoveNext),
9036
- onClick: _cache[2] || (_cache[2] = (...args) => (0, vue.unref)(moveNext) && (0, vue.unref)(moveNext)(...args)),
9037
- onKeydown: _cache[3] || (_cache[3] = (0, vue.withKeys)((...args) => (0, vue.unref)(moveNext) && (0, vue.unref)(moveNext)(...args), ["space", "enter"]))
9069
+ disabled: !canMoveNext_.value,
9070
+ onClick: moveNext_,
9071
+ onKeydown: (0, vue.withKeys)(moveNext_, ["space", "enter"])
9038
9072
  }, [(0, vue.createVNode)(CalendarSlot_default, {
9039
9073
  name: "header-next-button",
9040
- disabled: !(0, vue.unref)(canMoveNext)
9074
+ disabled: !canMoveNext_.value
9041
9075
  }, {
9042
9076
  default: (0, vue.withCtx)(() => [(0, vue.createVNode)(BaseIcon_default, {
9043
9077
  name: "ChevronRight",
@@ -9524,7 +9558,7 @@ var CalendarPage_default = /* @__PURE__ */ (0, vue.defineComponent)({
9524
9558
  __name: "CalendarPage",
9525
9559
  setup(__props) {
9526
9560
  const { page } = usePage();
9527
- const { onWeeknumberClick } = useCalendar();
9561
+ const { isPeriodLayout, onWeeknumberClick } = useCalendar();
9528
9562
  return (_ctx, _cache) => {
9529
9563
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
9530
9564
  class: (0, vue.normalizeClass)([
@@ -9538,8 +9572,13 @@ var CalendarPage_default = /* @__PURE__ */ (0, vue.defineComponent)({
9538
9572
  }, [(0, vue.createVNode)(CalendarHeader_default, {
9539
9573
  page: (0, vue.unref)(page),
9540
9574
  "is-lg": "",
9541
- "hide-arrows": ""
9542
- }, null, 8, ["page"]), (0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)(["vc-weeks", { [`vc-show-weeknumbers-${(0, vue.unref)(page).weeknumberPosition}`]: (0, vue.unref)(page).weeknumberPosition }]) }, [(0, vue.createElementVNode)("div", _hoisted_1$3, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)((0, vue.unref)(page).weekdays, ({ weekday, label }, i) => {
9575
+ "hide-arrows": !(0, vue.unref)(isPeriodLayout),
9576
+ "period-navigation": (0, vue.unref)(isPeriodLayout)
9577
+ }, null, 8, [
9578
+ "page",
9579
+ "hide-arrows",
9580
+ "period-navigation"
9581
+ ]), (0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)(["vc-weeks", { [`vc-show-weeknumbers-${(0, vue.unref)(page).weeknumberPosition}`]: (0, vue.unref)(page).weeknumberPosition }]) }, [(0, vue.createElementVNode)("div", _hoisted_1$3, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)((0, vue.unref)(page).weekdays, ({ weekday, label }, i) => {
9543
9582
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
9544
9583
  key: i,
9545
9584
  class: (0, vue.normalizeClass)(`vc-weekday vc-weekday-${weekday}`)
@@ -9586,7 +9625,10 @@ var Calendar_vue_vue_type_script_lang_default = (0, vue.defineComponent)({
9586
9625
  });
9587
9626
  //#endregion
9588
9627
  //#region src/components/Calendar/Calendar.vue
9589
- var _hoisted_1$2 = { class: "vc-pane-header-wrapper" };
9628
+ var _hoisted_1$2 = {
9629
+ key: 0,
9630
+ class: "vc-pane-header-wrapper"
9631
+ };
9590
9632
  function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
9591
9633
  const _component_CalendarHeader = (0, vue.resolveComponent)("CalendarHeader");
9592
9634
  const _component_CalendarPage = (0, vue.resolveComponent)("CalendarPage");
@@ -9610,12 +9652,12 @@ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
9610
9652
  onMouseup: _cache[0] || (_cache[0] = (0, vue.withModifiers)(() => {}, ["prevent"])),
9611
9653
  ref: "containerRef"
9612
9654
  }), [(0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)(["vc-pane-container", { "in-transition": _ctx.inTransition }]) }, [
9613
- (0, vue.createElementVNode)("div", _hoisted_1$2, [_ctx.firstPage ? ((0, vue.openBlock)(), (0, vue.createBlock)(_component_CalendarHeader, {
9655
+ !_ctx.isPeriodLayout ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$2, [_ctx.firstPage ? ((0, vue.openBlock)(), (0, vue.createBlock)(_component_CalendarHeader, {
9614
9656
  key: 0,
9615
9657
  page: _ctx.firstPage,
9616
9658
  "is-lg": "",
9617
9659
  "hide-title": ""
9618
- }, null, 8, ["page"])) : (0, vue.createCommentVNode)("", true)]),
9660
+ }, null, 8, ["page"])) : (0, vue.createCommentVNode)("", true)])) : (0, vue.createCommentVNode)("", true),
9619
9661
  (0, vue.createVNode)(vue.Transition, {
9620
9662
  name: `vc-${_ctx.transitionName}`,
9621
9663
  onBeforeEnter: _ctx.onTransitionBeforeEnter,
@@ -9624,7 +9666,7 @@ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
9624
9666
  default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
9625
9667
  key: _ctx.pages[0].id,
9626
9668
  class: "vc-pane-layout",
9627
- style: (0, vue.normalizeStyle)({ gridTemplateColumns: `repeat(${_ctx.columns}, 1fr)` })
9669
+ style: (0, vue.normalizeStyle)({ gridTemplateColumns: `repeat(${_ctx.layoutColumns}, 1fr)` })
9628
9670
  }, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(_ctx.pages, (page) => {
9629
9671
  return (0, vue.openBlock)(), (0, vue.createBlock)(_component_CalendarPageProvider, {
9630
9672
  key: page.id,