@rolldate/mcp 1.1.0 → 1.3.1

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.
@@ -454,49 +454,55 @@ var RollDate = (function () {
454
454
  ? options.weekDays
455
455
  : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
456
456
  this.enableTime = Boolean(options.enableTime);
457
- this.hasFooter = Boolean(options.enableTime || (options.footerButtons && options.footerButtons.length));
457
+ this.hasFooter = Boolean(options.footerButtons && options.footerButtons.length);
458
458
 
459
459
  this.init();
460
460
  }
461
461
 
462
462
  init() {
463
+ const timePanelHtml = this.enableTime
464
+ ? '<div class="RollDate__time-separator" aria-hidden="true"></div><div class="RollDate__time-panel"><div class="RollDate__time"></div></div>'
465
+ : '';
466
+
463
467
  const footerHtml = this.hasFooter ? `
464
468
  <div class="RollDate__footer">
465
- ${this.enableTime ? '<div class="RollDate__time"></div>' : ''}
466
469
  <div class="RollDate__footer__buttons"></div>
467
470
  </div>
468
471
  ` : '';
469
472
 
470
473
  this.$container.innerHTML = `
471
- <div class="RollDate__header">
472
- <div class="RollDate__calendar__switcher">
473
- <div class="RollDate__header__year"></div>
474
- <div class="RollDate__header__month"></div>
474
+ <div class="RollDate__content">
475
+ <div class="RollDate__calendar">
476
+ <div class="RollDate__header">
477
+ <div class="RollDate__calendar__switcher">
478
+ <div class="RollDate__header__year"></div>
479
+ <div class="RollDate__header__month"></div>
480
+ </div>
481
+ <div class="RollDate__calendar__buttons">
482
+ <button class="RollDate__calendar__button" data-direction="prev">
483
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 61 55" width="55" height="50">
484
+ <path id="Форма 2" fill-rule="evenodd" class="s0" d="m52.76 54.67l-44.73 0.12c-6.16 0.02-10.02-6.64-6.96-11.98l22.26-38.79c3.07-5.35 10.76-5.37 13.86-0.04l22.47 38.67c3.09 5.33-0.74 12.01-6.9 12.02z"/>
485
+ </svg>
486
+ </button>
487
+ <button class="RollDate__calendar__button" data-direction="next">
488
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 61 55" width="55" height="50">
489
+ <path id="Форма 2" fill-rule="evenodd" class="s0" d="m52.76 54.67l-44.73 0.12c-6.16 0.02-10.02-6.64-6.96-11.98l22.26-38.79c3.07-5.35 10.76-5.37 13.86-0.04l22.47 38.67c3.09 5.33-0.74 12.01-6.9 12.02z" />
490
+ </svg>
491
+ </button>
492
+ </div>
475
493
  </div>
476
- <div class="RollDate__calendar__buttons">
477
- <button class="RollDate__calendar__button" data-direction="prev">
478
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 61 55" width="55" height="50">
479
- <path id="Форма 2" fill-rule="evenodd" class="s0" d="m52.76 54.67l-44.73 0.12c-6.16 0.02-10.02-6.64-6.96-11.98l22.26-38.79c3.07-5.35 10.76-5.37 13.86-0.04l22.47 38.67c3.09 5.33-0.74 12.01-6.9 12.02z"/>
480
- </svg>
481
- </button>
482
- <button class="RollDate__calendar__button" data-direction="next">
483
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 61 55" width="55" height="50">
484
- <path id="Форма 2" fill-rule="evenodd" class="s0" d="m52.76 54.67l-44.73 0.12c-6.16 0.02-10.02-6.64-6.96-11.98l22.26-38.79c3.07-5.35 10.76-5.37 13.86-0.04l22.47 38.67c3.09 5.33-0.74 12.01-6.9 12.02z" />
485
- </svg>
486
- </button>
494
+ <div class="RollDate__calendar__header">
495
+ ${this.#dayHeaders()}
487
496
  </div>
488
- </div>
489
- <div class="RollDate__calendar">
490
- <div class="RollDate__calendar__header">
491
- ${this.#dayHeaders()}
492
- </div>
493
- <div class="RollDate__calendar__body">
494
- <div class="RollDate__calendar__scrollblock">
495
- <div class="RollDate__calendar__days"></div>
496
- <div class="RollDate__calendar__months"></div>
497
- <div class="RollDate__calendar__years"></div>
497
+ <div class="RollDate__calendar__body">
498
+ <div class="RollDate__calendar__scrollblock">
499
+ <div class="RollDate__calendar__days"></div>
500
+ <div class="RollDate__calendar__months"></div>
501
+ <div class="RollDate__calendar__years"></div>
502
+ </div>
498
503
  </div>
499
504
  </div>
505
+ ${timePanelHtml}
500
506
  </div>
501
507
  ${footerHtml}
502
508
  `;
@@ -655,6 +661,10 @@ var RollDate = (function () {
655
661
  #lastEdgeTriggerAt = 0
656
662
  #isTouchDragging = false
657
663
  #touchLastY = 0
664
+ #touchLastTime = 0
665
+ #touchVelocity = 0
666
+ #momentumId = 0
667
+ #animId = 0
658
668
 
659
669
  constructor(body, methods = {
660
670
  dominant: () => console.error('Function "dominant" is not found'),
@@ -684,6 +694,7 @@ var RollDate = (function () {
684
694
  wheelHandler(e) {
685
695
  e.preventDefault();
686
696
  e.stopPropagation();
697
+ this.#cancelMomentum();
687
698
 
688
699
  const rawDelta = e.deltaY * 0.85;
689
700
  const steps = Math.abs(rawDelta) > 50 ? 20 : 1;
@@ -715,8 +726,11 @@ var RollDate = (function () {
715
726
 
716
727
  touchStartHandler(e) {
717
728
  if (!e.touches || e.touches.length !== 1) return
729
+ this.#cancelMomentum();
718
730
  this.#isTouchDragging = true;
719
731
  this.#touchLastY = e.touches[0].clientY;
732
+ this.#touchLastTime = performance.now();
733
+ this.#touchVelocity = 0;
720
734
  this.#edgeTriggeredInCurrentWheel = false;
721
735
  }
722
736
 
@@ -726,7 +740,13 @@ var RollDate = (function () {
726
740
 
727
741
  const currentY = e.touches[0].clientY;
728
742
  const deltaY = currentY - this.#touchLastY;
743
+ const now = performance.now();
744
+ const dt = now - this.#touchLastTime;
745
+ if (dt > 0 && dt < 120) {
746
+ this.#touchVelocity = this.#touchVelocity * 0.65 + (deltaY / dt) * 0.35;
747
+ }
729
748
  this.#touchLastY = currentY;
749
+ this.#touchLastTime = now;
730
750
 
731
751
  if (Math.abs(deltaY) < 1) return
732
752
 
@@ -740,6 +760,86 @@ var RollDate = (function () {
740
760
  touchEndHandler() {
741
761
  this.#isTouchDragging = false;
742
762
  this.#edgeTriggeredInCurrentWheel = false;
763
+
764
+ const v = this.#touchVelocity * 16;
765
+ if (Math.abs(v) < 0.4) return
766
+
767
+ let velocity = v;
768
+ const step = () => {
769
+ if (Math.abs(velocity) < 0.35) {
770
+ this.#momentumId = 0;
771
+ return
772
+ }
773
+
774
+ const prevOffset = this.#offset;
775
+ this.offset += velocity;
776
+ if (this.#offset === prevOffset) {
777
+ this.#momentumId = 0;
778
+ return
779
+ }
780
+
781
+ this.dominant();
782
+ const direction = velocity < 0 ? 'down' : 'up';
783
+ this.checkEdge(direction);
784
+
785
+ velocity *= 0.92;
786
+ this.#momentumId = requestAnimationFrame(step);
787
+ };
788
+ this.#momentumId = requestAnimationFrame(step);
789
+ }
790
+
791
+ #cancelMomentum() {
792
+ if (!this.#momentumId) return
793
+ cancelAnimationFrame(this.#momentumId);
794
+ this.#momentumId = 0;
795
+ }
796
+
797
+ #cancelAnimate() {
798
+ if (!this.#animId) return
799
+ cancelAnimationFrame(this.#animId);
800
+ this.#animId = 0;
801
+ this.blocked = false;
802
+ }
803
+
804
+ animateTo(targetOffset, opts = {}) {
805
+ this.#cancelMomentum();
806
+ this.#cancelAnimate();
807
+
808
+ const duration = opts.duration ?? 220;
809
+ const start = this.#offset;
810
+ const min = this.minScroll;
811
+ const target = Math.max(Math.min(targetOffset, 0), min);
812
+
813
+ if (Math.abs(target - start) < 1) {
814
+ this.offset = target;
815
+ this.dominant();
816
+ opts.onComplete?.();
817
+ return Promise.resolve()
818
+ }
819
+
820
+ this.blocked = true;
821
+ const startTime = performance.now();
822
+
823
+ return new Promise(resolve => {
824
+ const step = (now) => {
825
+ const t = Math.min(1, (now - startTime) / duration);
826
+ const eased = 1 - Math.pow(1 - t, 3);
827
+ this.offset = start + (target - start) * eased;
828
+
829
+ if (t < 1) {
830
+ this.#animId = requestAnimationFrame(step);
831
+ return
832
+ }
833
+
834
+ this.offset = target;
835
+ this.blocked = false;
836
+ this.dominant();
837
+ this.#animId = 0;
838
+ opts.onComplete?.();
839
+ resolve();
840
+ };
841
+ this.#animId = requestAnimationFrame(step);
842
+ })
743
843
  }
744
844
 
745
845
  apply() {
@@ -810,6 +910,8 @@ var RollDate = (function () {
810
910
  }
811
911
 
812
912
  destroy() {
913
+ this.#cancelMomentum();
914
+ this.#cancelAnimate();
813
915
  if (this.#boundWheelHandler) {
814
916
  this.$body.removeEventListener('wheel', this.#boundWheelHandler);
815
917
  }
@@ -1066,11 +1168,8 @@ var RollDate = (function () {
1066
1168
  }
1067
1169
  }
1068
1170
 
1069
- const ITEM_HEIGHT = 28;
1070
-
1071
- const ARROW_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 61 55" width="55" height="50" aria-hidden="true">
1072
- <path fill-rule="evenodd" d="m52.76 54.67l-44.73 0.12c-6.16 0.02-10.02-6.64-6.96-11.98l22.26-38.79c3.07-5.35 10.76-5.37 13.86-0.04l22.47 38.67c3.09 5.33-0.74 12.01-6.9 12.02z"/>
1073
- </svg>`;
1171
+ const DEFAULT_ITEM_HEIGHT = 28;
1172
+ const DEFAULT_VISIBLE = 3;
1074
1173
 
1075
1174
  class TimePicker {
1076
1175
  #hours = 0
@@ -1079,7 +1178,6 @@ var RollDate = (function () {
1079
1178
  #period = 'AM'
1080
1179
  #minuteStep = 1
1081
1180
  #columns = []
1082
- #displayEl = null
1083
1181
 
1084
1182
  constructor(root, options = {}) {
1085
1183
  this.root = root;
@@ -1113,7 +1211,83 @@ var RollDate = (function () {
1113
1211
  return Math.min(59, Math.max(0, Number.isNaN(m) ? 0 : m))
1114
1212
  }
1115
1213
 
1214
+ #readMetrics(viewport) {
1215
+ const container = viewport.closest('.RollDate__container');
1216
+ const cs = container ? getComputedStyle(container) : getComputedStyle(viewport);
1217
+ const itemH = parseFloat(cs.getPropertyValue('--rd-time-item-h')) || DEFAULT_ITEM_HEIGHT;
1218
+ const visible = parseInt(cs.getPropertyValue('--rd-time-visible'), 10) || DEFAULT_VISIBLE;
1219
+ const pad = Math.floor((visible - 1) / 2) * itemH;
1220
+ return { itemH, visible, pad }
1221
+ }
1222
+
1116
1223
  #build() {
1224
+ this.root.innerHTML = `
1225
+ <div class="RollDate__time__picker"></div>
1226
+ <div class="RollDate__time__period">
1227
+ <div class="RollDate__time__segmented RollDate__time__segmented--period" data-role="period">
1228
+ <button type="button" class="RollDate__time__segment-btn" data-period="AM">AM</button>
1229
+ <button type="button" class="RollDate__time__segment-btn" data-period="PM">PM</button>
1230
+ </div>
1231
+ </div>
1232
+ `;
1233
+
1234
+ if (this.#use12Hour) {
1235
+ this.root.classList.add('RollDate__time--12h');
1236
+ }
1237
+ this.#bindToolbar();
1238
+ this.#buildPickerColumns();
1239
+ this.#syncToolbar();
1240
+ }
1241
+
1242
+ #bindToolbar() {
1243
+ this.root.querySelector('[data-role="period"]')?.addEventListener('click', (e) => {
1244
+ const btn = e.target.closest('[data-period]');
1245
+ if (!btn || !this.#use12Hour) return
1246
+ this.#setPeriod(btn.dataset.period);
1247
+ });
1248
+ }
1249
+
1250
+ #setPeriod(period) {
1251
+ if (period !== 'AM' && period !== 'PM') return
1252
+ if (this.#period === period) return
1253
+
1254
+ this.#readColumns();
1255
+ const was = this.#period;
1256
+ this.#period = period;
1257
+
1258
+ if (was === 'AM' && period === 'PM' && this.#hours < 12) {
1259
+ this.#hours += 12;
1260
+ } else if (was === 'PM' && period === 'AM' && this.#hours >= 12) {
1261
+ this.#hours -= 12;
1262
+ }
1263
+
1264
+ this.#columns.find(c => c.unit === 'hour')?.scrollToValue(this.#displayHour(), true);
1265
+ this.#syncToolbar();
1266
+ hapticTick(this.hapticFeedback);
1267
+ this.#commitTime();
1268
+ }
1269
+
1270
+ #syncToolbar() {
1271
+ this.root.classList.toggle('RollDate__time--12h', this.#use12Hour);
1272
+
1273
+ this.root.querySelectorAll('[data-period]').forEach((btn) => {
1274
+ const active = btn.dataset.period === this.#period;
1275
+ btn.classList.toggle('RollDate__time__segment-btn--active', active);
1276
+ btn.setAttribute('aria-pressed', active ? 'true' : 'false');
1277
+ });
1278
+ }
1279
+
1280
+ #destroyColumns() {
1281
+ this.#columns.forEach((column) => column._resizeObserver?.disconnect());
1282
+ this.#columns = [];
1283
+ }
1284
+
1285
+ #buildPickerColumns() {
1286
+ this.#destroyColumns();
1287
+
1288
+ const picker = this.root.querySelector('.RollDate__time__picker');
1289
+ if (!picker) return
1290
+
1117
1291
  const hourValues = this.#use12Hour
1118
1292
  ? Array.from({ length: 12 }, (_, i) => i + 1)
1119
1293
  : Array.from({ length: 24 }, (_, i) => i);
@@ -1123,76 +1297,38 @@ var RollDate = (function () {
1123
1297
  minuteValues.push(m);
1124
1298
  }
1125
1299
 
1126
- this.root.innerHTML = `
1127
- <div class="RollDate__time__picker">
1300
+ picker.innerHTML = `
1128
1301
  <div class="RollDate__time__field" data-unit="hour">
1129
1302
  <div class="RollDate__time__column">
1130
- <button type="button" class="RollDate__time__arrow RollDate__time__arrow--prev" data-dir="prev" aria-label="Earlier hour">${ARROW_SVG}</button>
1131
1303
  <div class="RollDate__time__viewport">
1132
1304
  <div class="RollDate__time__list"></div>
1133
1305
  </div>
1134
- <button type="button" class="RollDate__time__arrow RollDate__time__arrow--next" data-dir="next" aria-label="Later hour">${ARROW_SVG}</button>
1135
1306
  </div>
1136
1307
  </div>
1137
1308
  <span class="RollDate__time__sep">:</span>
1138
1309
  <div class="RollDate__time__field" data-unit="minute">
1139
1310
  <div class="RollDate__time__column">
1140
- <button type="button" class="RollDate__time__arrow RollDate__time__arrow--prev" data-dir="prev" aria-label="Earlier minute">${ARROW_SVG}</button>
1141
1311
  <div class="RollDate__time__viewport">
1142
1312
  <div class="RollDate__time__list"></div>
1143
1313
  </div>
1144
- <button type="button" class="RollDate__time__arrow RollDate__time__arrow--next" data-dir="next" aria-label="Later minute">${ARROW_SVG}</button>
1145
1314
  </div>
1146
1315
  </div>
1147
- ${this.#use12Hour ? `
1148
- <div class="RollDate__time__field RollDate__time__field--period" data-unit="period">
1149
- <div class="RollDate__time__column">
1150
- <button type="button" class="RollDate__time__arrow RollDate__time__arrow--prev" data-dir="prev" aria-label="Earlier period">${ARROW_SVG}</button>
1151
- <div class="RollDate__time__viewport">
1152
- <div class="RollDate__time__list"></div>
1153
- </div>
1154
- <button type="button" class="RollDate__time__arrow RollDate__time__arrow--next" data-dir="next" aria-label="Later period">${ARROW_SVG}</button>
1155
- </div>
1156
- </div>` : ''}
1157
- </div>
1158
- <div class="RollDate__time__display" aria-live="polite"></div>
1159
1316
  `;
1160
1317
 
1161
- this.#displayEl = this.root.querySelector('.RollDate__time__display');
1162
- if (this.#use12Hour) {
1163
- this.root.classList.add('RollDate__time--12h');
1164
- }
1165
-
1166
- this.#columns.push(this.#createColumn('hour', hourValues, this.#displayHour()));
1318
+ this.#columns.push(this.#createColumn('hour', hourValues, this.#use12Hour ? this.#displayHour() : this.#hours));
1167
1319
  this.#columns.push(this.#createColumn('minute', minuteValues, this.#minutes));
1168
- if (this.#use12Hour) {
1169
- this.#columns.push(this.#createColumn('period', ['AM', 'PM'], this.#period));
1170
- }
1171
-
1172
- this.#updateDisplay();
1173
- }
1174
-
1175
- #formatDisplay() {
1176
- const hours = String(this.#hours).padStart(2, '0');
1177
- const minutes = String(this.#minutes).padStart(2, '0');
1178
- if (this.#use12Hour) {
1179
- return `${String(this.#displayHour()).padStart(2, '0')}:${minutes} ${this.#period}`
1180
- }
1181
- return `${hours}:${minutes}`
1182
- }
1183
-
1184
- #updateDisplay() {
1185
- if (this.#displayEl) {
1186
- this.#displayEl.textContent = this.#formatDisplay();
1187
- }
1188
1320
  }
1189
1321
 
1190
1322
  #commitTime() {
1191
1323
  this.#readColumns();
1192
- this.#updateDisplay();
1193
1324
  this.onChange(this.getTime());
1194
1325
  }
1195
1326
 
1327
+ #parseItemValue(unit, raw) {
1328
+ if (unit === 'period') return raw
1329
+ return Number(raw)
1330
+ }
1331
+
1196
1332
  #createColumn(unit, values, initial) {
1197
1333
  const field = this.root.querySelector(`[data-unit="${unit}"]`);
1198
1334
  const viewport = field.querySelector('.RollDate__time__viewport');
@@ -1205,17 +1341,22 @@ var RollDate = (function () {
1205
1341
  return `<div class="RollDate__time__item" data-value="${value}">${label}</div>`
1206
1342
  }).join('');
1207
1343
 
1208
- list.style.paddingTop = `${ITEM_HEIGHT}px`;
1209
- list.style.paddingBottom = `${ITEM_HEIGHT}px`;
1210
-
1211
1344
  const column = {
1212
1345
  unit,
1213
1346
  viewport,
1214
1347
  list,
1215
1348
  values,
1216
- offset: 0
1349
+ offset: 0,
1350
+ getMetrics: () => this.#readMetrics(viewport)
1217
1351
  };
1218
1352
 
1353
+ const applyPadding = () => {
1354
+ const { pad } = column.getMetrics();
1355
+ list.style.paddingTop = `${pad}px`;
1356
+ list.style.paddingBottom = `${pad}px`;
1357
+ };
1358
+ applyPadding();
1359
+
1219
1360
  column.updateActive = () => {
1220
1361
  const index = column.indexFromOffset();
1221
1362
  if (column._lastIndex !== index) {
@@ -1231,7 +1372,8 @@ var RollDate = (function () {
1231
1372
  };
1232
1373
 
1233
1374
  column.indexFromOffset = () => {
1234
- const raw = Math.round(-column.offset / ITEM_HEIGHT);
1375
+ const { itemH } = column.getMetrics();
1376
+ const raw = Math.round(-column.offset / itemH);
1235
1377
  return Math.min(values.length - 1, Math.max(0, raw))
1236
1378
  };
1237
1379
 
@@ -1244,42 +1386,51 @@ var RollDate = (function () {
1244
1386
  };
1245
1387
 
1246
1388
  column.snap = () => {
1389
+ const { itemH } = column.getMetrics();
1247
1390
  const index = column.indexFromOffset();
1248
- column.offset = -index * ITEM_HEIGHT;
1391
+ column.offset = -index * itemH;
1249
1392
  column._lastIndex = index;
1250
1393
  column.apply(true);
1251
1394
  this.#commitTime();
1252
1395
  };
1253
1396
 
1254
1397
  column.scrollToValue = (value, animate = true) => {
1398
+ const { itemH } = column.getMetrics();
1255
1399
  const index = values.indexOf(value);
1256
1400
  if (index < 0) return
1257
- column.offset = -index * ITEM_HEIGHT;
1401
+ column.offset = -index * itemH;
1402
+ column._lastIndex = index;
1258
1403
  column.apply(animate);
1259
1404
  };
1260
1405
 
1261
- column.stepBy = (delta) => {
1262
- const index = Math.min(values.length - 1, Math.max(0, column.indexFromOffset() + delta));
1263
- column.offset = -index * ITEM_HEIGHT;
1264
- column.apply(true);
1406
+ column.scrollToIndex = (index, animate = true) => {
1407
+ const { itemH } = column.getMetrics();
1408
+ const clamped = Math.min(values.length - 1, Math.max(0, index));
1409
+ column.offset = -clamped * itemH;
1410
+ column._lastIndex = clamped;
1411
+ column.apply(animate);
1265
1412
  };
1266
1413
 
1267
1414
  column.scrollToValue(initial, false);
1268
1415
  this.#bindWheel(column);
1269
1416
  this.#bindTouch(column);
1270
- this.#bindArrows(field, column);
1417
+ this.#bindItemClick(column);
1418
+ column._resizeObserver = new ResizeObserver(() => {
1419
+ applyPadding();
1420
+ column.scrollToIndex(column.indexFromOffset(), false);
1421
+ });
1422
+ column._resizeObserver.observe(viewport);
1271
1423
 
1272
1424
  return column
1273
1425
  }
1274
1426
 
1275
- #bindArrows(field, column) {
1276
- field.querySelector('[data-dir="prev"]')?.addEventListener('click', (e) => {
1277
- e.preventDefault();
1278
- column.stepBy(-1);
1279
- });
1280
- field.querySelector('[data-dir="next"]')?.addEventListener('click', (e) => {
1281
- e.preventDefault();
1282
- column.stepBy(1);
1427
+ #bindItemClick(column) {
1428
+ column.list.addEventListener('click', (e) => {
1429
+ const item = e.target.closest('.RollDate__time__item');
1430
+ if (!item) return
1431
+ const value = this.#parseItemValue(column.unit, item.dataset.value);
1432
+ column.scrollToValue(value, true);
1433
+ this.#commitTime();
1283
1434
  });
1284
1435
  }
1285
1436
 
@@ -1287,9 +1438,10 @@ var RollDate = (function () {
1287
1438
  column.viewport.addEventListener('wheel', (e) => {
1288
1439
  e.preventDefault();
1289
1440
  e.stopPropagation();
1441
+ const { itemH } = column.getMetrics();
1290
1442
  column.list.style.transition = 'none';
1291
1443
  column.offset -= e.deltaY * 0.35;
1292
- const min = -(column.values.length - 1) * ITEM_HEIGHT;
1444
+ const min = -(column.values.length - 1) * itemH;
1293
1445
  column.offset = Math.max(min, Math.min(0, column.offset));
1294
1446
  column.list.style.transform = `translateY(${column.offset}px)`;
1295
1447
  column.updateActive();
@@ -1312,8 +1464,9 @@ var RollDate = (function () {
1312
1464
  column.viewport.addEventListener('touchmove', (e) => {
1313
1465
  if (!e.touches || e.touches.length !== 1) return
1314
1466
  e.preventDefault();
1467
+ const { itemH } = column.getMetrics();
1315
1468
  column.offset = startOffset + (e.touches[0].clientY - startY);
1316
- const min = -(column.values.length - 1) * ITEM_HEIGHT;
1469
+ const min = -(column.values.length - 1) * itemH;
1317
1470
  column.offset = Math.max(min, Math.min(0, column.offset));
1318
1471
  column.list.style.transform = `translateY(${column.offset}px)`;
1319
1472
  column.updateActive();
@@ -1325,13 +1478,12 @@ var RollDate = (function () {
1325
1478
  #readColumns() {
1326
1479
  const hourCol = this.#columns.find(c => c.unit === 'hour');
1327
1480
  const minuteCol = this.#columns.find(c => c.unit === 'minute');
1328
- const periodCol = this.#columns.find(c => c.unit === 'period');
1481
+ if (!hourCol || !minuteCol) return
1329
1482
 
1330
1483
  const hourValue = hourCol.getValue();
1331
1484
  this.#minutes = minuteCol.getValue();
1332
1485
 
1333
- if (this.#use12Hour && periodCol) {
1334
- this.#period = periodCol.getValue();
1486
+ if (this.#use12Hour) {
1335
1487
  if (this.#period === 'AM') {
1336
1488
  this.#hours = hourValue === 12 ? 0 : hourValue;
1337
1489
  } else {
@@ -1352,16 +1504,15 @@ var RollDate = (function () {
1352
1504
  if (this.#use12Hour) {
1353
1505
  this.#period = this.#hours >= 12 ? 'PM' : 'AM';
1354
1506
  this.#columns.find(c => c.unit === 'hour')?.scrollToValue(this.#displayHour());
1355
- this.#columns.find(c => c.unit === 'period')?.scrollToValue(this.#period);
1356
1507
  } else {
1357
1508
  this.#columns.find(c => c.unit === 'hour')?.scrollToValue(this.#hours);
1358
1509
  }
1359
1510
  this.#columns.find(c => c.unit === 'minute')?.scrollToValue(this.#minutes);
1360
- this.#updateDisplay();
1511
+ this.#syncToolbar();
1361
1512
  }
1362
1513
 
1363
1514
  destroy() {
1364
- this.#columns = [];
1515
+ this.#destroyColumns();
1365
1516
  this.root.innerHTML = '';
1366
1517
  }
1367
1518
  }
@@ -1371,6 +1522,7 @@ var RollDate = (function () {
1371
1522
 
1372
1523
  #wheelHandler
1373
1524
  #viewNumber = 0
1525
+ #arrowAnimating = false
1374
1526
  #viewPeriodNames = ['day', 'month', 'year']
1375
1527
  #selectedDates = []
1376
1528
  #firstOpen = true
@@ -1581,6 +1733,11 @@ var RollDate = (function () {
1581
1733
  const btn = document.createElement('button');
1582
1734
  btn.type = 'button';
1583
1735
  btn.className = 'RollDate__footer__button';
1736
+ if (cfg.variant === 'primary') {
1737
+ btn.classList.add('RollDate__footer__button--primary');
1738
+ } else if (cfg.variant === 'secondary') {
1739
+ btn.classList.add('RollDate__footer__button--secondary');
1740
+ }
1584
1741
  btn.textContent = cfg.text;
1585
1742
  btn.addEventListener('click', (e) => {
1586
1743
  e.preventDefault();
@@ -1712,7 +1869,7 @@ var RollDate = (function () {
1712
1869
 
1713
1870
  const baseOptions = {
1714
1871
  mode: 'auto',
1715
- theme: 'dark',
1872
+ theme: 'main',
1716
1873
  startWeekFromMonday: true,
1717
1874
  selectType: 'single',
1718
1875
  monthsNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
@@ -1729,6 +1886,7 @@ var RollDate = (function () {
1729
1886
  enableTime: false,
1730
1887
  use12Hour: false,
1731
1888
  timeStep: 1,
1889
+ timePosition: 'right',
1732
1890
  footerButtons: [],
1733
1891
  rangePresets: [],
1734
1892
  hapticFeedback: true,
@@ -1736,7 +1894,7 @@ var RollDate = (function () {
1736
1894
  };
1737
1895
 
1738
1896
  if (baseOptions.theme === 'default') {
1739
- baseOptions.theme = 'dark';
1897
+ baseOptions.theme = 'main';
1740
1898
  }
1741
1899
 
1742
1900
  const resolvedLocale = baseOptions.locale ||
@@ -1816,8 +1974,10 @@ var RollDate = (function () {
1816
1974
 
1817
1975
  if (this.options.enableTime) {
1818
1976
  this.$container.classList.add('RollDate__has-time');
1977
+ const timePosition = this.options.timePosition === 'bottom' ? 'bottom' : 'right';
1978
+ this.$container.classList.add(`RollDate__time-position_${timePosition}`);
1819
1979
  }
1820
- if (this.options.footerButtons?.length || this.options.enableTime) {
1980
+ if (this.options.footerButtons?.length) {
1821
1981
  this.$container.classList.add('RollDate__has-footer');
1822
1982
  }
1823
1983
 
@@ -1923,6 +2083,13 @@ var RollDate = (function () {
1923
2083
 
1924
2084
  const preserveScroll = options.preserveScroll === true;
1925
2085
  const savedOffset = preserveScroll ? this.scroll.offset : null;
2086
+ const animateScroll = options.animate === true && Number(options.shift);
2087
+ const onScrollComplete = typeof options.onScrollComplete === 'function'
2088
+ ? options.onScrollComplete
2089
+ : null;
2090
+ const finishScroll = () => {
2091
+ onScrollComplete?.();
2092
+ };
1926
2093
 
1927
2094
  this.#updateHeader();
1928
2095
  this.scroll.blocked = false;
@@ -1953,6 +2120,7 @@ var RollDate = (function () {
1953
2120
  if (blockHeight <= bodyHeight) {
1954
2121
  this.scroll.setBaseOffset(bodyHeight - blockHeight);
1955
2122
  this.scroll.offset = 0;
2123
+ finishScroll();
1956
2124
  return
1957
2125
  }
1958
2126
 
@@ -1961,6 +2129,7 @@ var RollDate = (function () {
1961
2129
 
1962
2130
  if (preserveScroll && savedOffset != null) {
1963
2131
  this.scroll.offset = Math.max(savedOffset, this.scroll.minScroll);
2132
+ finishScroll();
1964
2133
  return
1965
2134
  }
1966
2135
 
@@ -1979,12 +2148,29 @@ var RollDate = (function () {
1979
2148
  $firstEl = this.$container.querySelector(fallbacks[this.period]);
1980
2149
  }
1981
2150
 
1982
- if (!$firstEl) return
2151
+ if (!$firstEl) {
2152
+ finishScroll();
2153
+ return
2154
+ }
1983
2155
 
1984
2156
  const containerRect = $scrollBlock.getBoundingClientRect();
1985
2157
  const firstRect = $firstEl.getBoundingClientRect();
1986
2158
  const firstRectOffset = -(firstRect.top - containerRect.top);
1987
- this.scroll.offset = Math.max(firstRectOffset, this.scroll.minScroll);
2159
+ const targetOffset = Math.max(firstRectOffset, this.scroll.minScroll);
2160
+
2161
+ if (animateScroll) {
2162
+ const slide = Math.min(bodyHeight * 0.38, 140);
2163
+ const startOffset = Math.max(
2164
+ Math.min(targetOffset + (options.shift > 0 ? slide : -slide), 0),
2165
+ this.scroll.minScroll
2166
+ );
2167
+ this.scroll.offset = startOffset;
2168
+ this.scroll.animateTo(targetOffset, { onComplete: finishScroll });
2169
+ return
2170
+ }
2171
+
2172
+ this.scroll.offset = targetOffset;
2173
+ finishScroll();
1988
2174
  };
1989
2175
 
1990
2176
  setTimeout(applyScroll, 0);
@@ -2245,6 +2431,8 @@ var RollDate = (function () {
2245
2431
  e.preventDefault();
2246
2432
  e.stopPropagation();
2247
2433
 
2434
+ if (this.#arrowAnimating) return
2435
+
2248
2436
  const direction = e.currentTarget?.dataset?.direction;
2249
2437
  if (direction !== 'prev' && direction !== 'next') return
2250
2438
  const shift = direction === 'prev' ? -1 : 1;
@@ -2281,8 +2469,15 @@ var RollDate = (function () {
2281
2469
  this.data.current_decade = targetDecade;
2282
2470
  }
2283
2471
 
2472
+ this.#arrowAnimating = true;
2284
2473
  hapticTick(this.options.hapticFeedback !== false);
2285
- this.#updateView(this.#viewNumber);
2474
+ this.#updateView(this.#viewNumber, {
2475
+ animate: true,
2476
+ shift,
2477
+ onScrollComplete: () => {
2478
+ this.#arrowAnimating = false;
2479
+ }
2480
+ });
2286
2481
  });
2287
2482
  });
2288
2483
  }
@@ -2807,6 +3002,10 @@ var RollDate = (function () {
2807
3002
  this.data.current_month = now.getMonth();
2808
3003
  this.data.current_decade = getDecade(now.getFullYear());
2809
3004
 
3005
+ if (this.options.enableTime && this.timePicker) {
3006
+ this.timePicker.setTime(now.getHours(), now.getMinutes());
3007
+ }
3008
+
2810
3009
  const selected = this.#applyTimeToDate(now);
2811
3010
 
2812
3011
  if (this.options.selectType === 'single') {