bootstrap-time 0.1.4-beta → 0.1.6-beta

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
@@ -33,8 +33,8 @@ Or load the published files from jsDelivr:
33
33
  ```html
34
34
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@6.0.0-alpha.1/dist/css/bootstrap.min.css">
35
35
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.2/font/bootstrap-icons.min.css">
36
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-time@0.1.4-beta/dist/css/bootstrap-time.min.css">
37
- <script src="https://cdn.jsdelivr.net/npm/bootstrap-time@0.1.4-beta/dist/js/bootstrap-time.min.js"></script>
36
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-time@0.1.6-beta/dist/css/bootstrap-time.min.css">
37
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap-time@0.1.6-beta/dist/js/bootstrap-time.min.js"></script>
38
38
  ```
39
39
 
40
40
  Local builds use the same paths under `dist/`:
@@ -44,10 +44,21 @@ Local builds use the same paths under `dist/`:
44
44
  <script src="dist/js/bootstrap-time.min.js"></script>
45
45
  ```
46
46
 
47
- The script initializes the clock when `.clock-picker`, `#clock`, `#time-input`, `#hour-arrow` and `#minute-arrow` are present. The widget overlays the form under the time input. See `examples/bootstrap-time.html`.
47
+ The script initializes the clock when `.clock-picker`, `#clock`, `#time-input`, `#hour-arrow` and `#minute-arrow` are present. The widget overlays the form under the time input. Minute selection follows the input `step`, including when `step` changes: `60` allows every minute by clicking between the numbers, `900` enables only 00, 15, 30 and 45. See `examples/bootstrap-time.html`.
48
48
 
49
49
  ## Changelog
50
50
 
51
+ ### 0.1.6-beta
52
+
53
+ - The example starts on the current time.
54
+ - Minute selection follows the input `step`, including when it changes.
55
+ - `step="60"` selects any minute by clicking between the numbers.
56
+ - `step="900"` enables only 00, 15, 30 and 45.
57
+
58
+ ### 0.1.5-beta
59
+
60
+ - Release title uses `<version>-beta`.
61
+
51
62
  ### 0.1.4-beta
52
63
 
53
64
  - Bootstrap 6 is a dependency.
@@ -76,6 +76,8 @@
76
76
  width: 16rem;
77
77
  height: 16rem;
78
78
  border-radius: 50%;
79
+ touch-action: none;
80
+ cursor: pointer;
79
81
  }
80
82
 
81
83
  .clock-hand {
@@ -118,3 +120,7 @@
118
120
  .clock-number[aria-pressed=true] {
119
121
  color: var(--bs-white, #fff);
120
122
  }
123
+ .clock-number:disabled {
124
+ opacity: 0.35;
125
+ cursor: default;
126
+ }
@@ -1 +1 @@
1
- .clock-picker{position:relative;width:20rem}.clock-picker input[type=time]::-webkit-calendar-picker-indicator{display:none;appearance:none}.clock-toggle{pointer-events:auto;width:2.25rem;height:2.25rem;margin:-0.25rem;border:0;border-radius:50%;background:rgba(0,0,0,0);color:var(--bs-form-adorn-icon-color, var(--bs-secondary-color))}.clock-toggle .bi{font-size:1rem;line-height:1}.clock-toggle:hover,.clock-toggle:focus-visible{background-color:var(--bs-bg-3);color:var(--bs-body-color)}.clock-widget{position:absolute;top:100%;left:0;z-index:5;width:20rem;margin-top:.25rem;padding:.25rem .5rem 1rem;background-color:var(--bs-secondary-bg-subtle);color:var(--bs-secondary-fg)}.clock-arrows{display:flex;justify-content:flex-end;gap:.25rem}.btn.clock-arrow{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;min-height:0;padding:0;border-radius:50%;background-color:rgba(0,0,0,0);color:var(--bs-body-color);text-decoration:none}.btn.clock-arrow svg{width:1.5rem;height:1.5rem;fill:currentColor}.btn.clock-arrow:hover,.btn.clock-arrow:focus-visible{background-color:var(--bs-bg-3);color:var(--bs-body-color)}.btn.clock-arrow:disabled,.btn.clock-arrow:disabled:hover{background-color:rgba(0,0,0,0);color:var(--bs-secondary-color);opacity:.45}.clock{width:16rem;height:16rem;border-radius:50%}.clock-hand{position:absolute;left:50%;bottom:50%;width:2px;height:var(--hand);transform-origin:center bottom;transform:translateX(-50%) rotate(var(--angle));transition:transform .3s ease,height .3s ease;border-radius:1px;pointer-events:none}.clock-knob{position:absolute;left:50%;top:0;width:2.25rem;height:2.25rem;border-radius:50%;transform:translate(-50%, -50%)}.clock-number{position:absolute;left:50%;top:50%;z-index:1;width:2.25rem;height:2.25rem;margin:-1.125rem;border:0;border-radius:50%;background:rgba(0,0,0,0);color:inherit;transform:rotate(var(--angle)) translateY(calc(var(--radius) * -1)) rotate(calc(var(--angle) * -1))}.clock-number[aria-pressed=true]{color:var(--bs-white, #fff)}
1
+ .clock-picker{position:relative;width:20rem}.clock-picker input[type=time]::-webkit-calendar-picker-indicator{display:none;appearance:none}.clock-toggle{pointer-events:auto;width:2.25rem;height:2.25rem;margin:-0.25rem;border:0;border-radius:50%;background:rgba(0,0,0,0);color:var(--bs-form-adorn-icon-color, var(--bs-secondary-color))}.clock-toggle .bi{font-size:1rem;line-height:1}.clock-toggle:hover,.clock-toggle:focus-visible{background-color:var(--bs-bg-3);color:var(--bs-body-color)}.clock-widget{position:absolute;top:100%;left:0;z-index:5;width:20rem;margin-top:.25rem;padding:.25rem .5rem 1rem;background-color:var(--bs-secondary-bg-subtle);color:var(--bs-secondary-fg)}.clock-arrows{display:flex;justify-content:flex-end;gap:.25rem}.btn.clock-arrow{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;min-height:0;padding:0;border-radius:50%;background-color:rgba(0,0,0,0);color:var(--bs-body-color);text-decoration:none}.btn.clock-arrow svg{width:1.5rem;height:1.5rem;fill:currentColor}.btn.clock-arrow:hover,.btn.clock-arrow:focus-visible{background-color:var(--bs-bg-3);color:var(--bs-body-color)}.btn.clock-arrow:disabled,.btn.clock-arrow:disabled:hover{background-color:rgba(0,0,0,0);color:var(--bs-secondary-color);opacity:.45}.clock{width:16rem;height:16rem;border-radius:50%;touch-action:none;cursor:pointer}.clock-hand{position:absolute;left:50%;bottom:50%;width:2px;height:var(--hand);transform-origin:center bottom;transform:translateX(-50%) rotate(var(--angle));transition:transform .3s ease,height .3s ease;border-radius:1px;pointer-events:none}.clock-knob{position:absolute;left:50%;top:0;width:2.25rem;height:2.25rem;border-radius:50%;transform:translate(-50%, -50%)}.clock-number{position:absolute;left:50%;top:50%;z-index:1;width:2.25rem;height:2.25rem;margin:-1.125rem;border:0;border-radius:50%;background:rgba(0,0,0,0);color:inherit;transform:rotate(var(--angle)) translateY(calc(var(--radius) * -1)) rotate(calc(var(--angle) * -1))}.clock-number[aria-pressed=true]{color:var(--bs-white, #fff)}.clock-number:disabled{opacity:.35;cursor:default}
@@ -18,9 +18,12 @@
18
18
  var clockToggle = document.querySelector("#clock-toggle");
19
19
  if (!clock || !timeInput || !hourArrow || !minuteArrow) return;
20
20
 
21
- var initial = (timeInput.value || "17:00").split(":");
21
+ var now = new Date();
22
+ var initial = timeInput.value
23
+ ? timeInput.value.split(":")
24
+ : [now.getHours(), now.getMinutes()];
22
25
  var hour = Number(initial[0]) || 0;
23
- var minute = Number(initial[1]) || 0;
26
+ var minute = snapMinute(Number(initial[1]) || 0);
24
27
  var mode = "hour";
25
28
  var handAngle = 150;
26
29
  var hand = document.createElement("div");
@@ -36,6 +39,22 @@
36
39
  return String(value).padStart(2, "0");
37
40
  }
38
41
 
42
+ function minuteStep() {
43
+ var step = Number(timeInput.getAttribute("step") || timeInput.step);
44
+ if (!step || step < 60) step = 60;
45
+ return Math.max(1, Math.round(step / 60));
46
+ }
47
+
48
+ function snapMinute(value) {
49
+ var step = minuteStep();
50
+ var snapped = Math.round(value / step) * step;
51
+ return ((snapped % 60) + 60) % 60;
52
+ }
53
+
54
+ function allowedMinute(value) {
55
+ return value % minuteStep() === 0;
56
+ }
57
+
39
58
  function targetAngle() {
40
59
  return mode === "hour" ? (hour % 12) * 30 : minute * 6;
41
60
  }
@@ -85,14 +104,18 @@
85
104
  var button = document.createElement("button");
86
105
  var inner = mode === "hour" && index >= 12;
87
106
  var angle = (mode === "hour" ? index % 12 : index) * 30;
107
+ var disabled = mode === "minute" && !allowedMinute(value);
88
108
 
89
109
  button.type = "button";
90
110
  button.className = "clock-number";
91
- button.textContent = mode === "hour" && value === 0 ? "00" : String(value);
92
- button.setAttribute("aria-pressed", value === selected ? "true" : "false");
111
+ button.textContent = value === 0 ? "00" : String(value);
112
+ button.dataset.value = String(value);
113
+ button.disabled = disabled;
114
+ button.setAttribute("aria-pressed", !disabled && value === selected ? "true" : "false");
93
115
  button.style.setProperty("--angle", angle + "deg");
94
116
  button.style.setProperty("--radius", inner ? INNER_RADIUS : OUTER_RADIUS);
95
117
  button.addEventListener("click", function () {
118
+ if (button.disabled) return;
96
119
  if (mode === "hour") {
97
120
  hour = value;
98
121
  mode = "minute";
@@ -124,6 +147,31 @@
124
147
  else hideWidget();
125
148
  }
126
149
 
150
+ function valueFromPoint(event) {
151
+ var rect = clock.getBoundingClientRect();
152
+ var dx = event.clientX - (rect.left + rect.width / 2);
153
+ var dy = event.clientY - (rect.top + rect.height / 2);
154
+ var angle = (Math.atan2(dx, -dy) * 180 / Math.PI + 360) % 360;
155
+ if (mode === "minute") return snapMinute(Math.round(angle / 6) % 60);
156
+ var hour12 = Math.round(angle / 30) % 12;
157
+ var inner = Math.hypot(dx, dy) < rect.width * 0.32;
158
+ if (inner) return hour12 === 0 ? 0 : hour12 + 12;
159
+ return hour12 === 0 ? 12 : hour12;
160
+ }
161
+
162
+ clock.addEventListener("click", function (event) {
163
+ if (event.target.closest(".clock-number")) return;
164
+ var value = valueFromPoint(event);
165
+ if (mode === "minute") minute = value;
166
+ else {
167
+ hour = value;
168
+ mode = "minute";
169
+ }
170
+ writeInput();
171
+ updateArrows();
172
+ renderClock();
173
+ });
174
+
127
175
  hourArrow.addEventListener("click", function () {
128
176
  showMode("hour");
129
177
  });
@@ -158,6 +206,30 @@
158
206
  hideWidget();
159
207
  });
160
208
 
209
+ function applyStep() {
210
+ minute = snapMinute(minute);
211
+ writeInput();
212
+ renderClock();
213
+ }
214
+
215
+ var stepDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "step");
216
+ if (stepDescriptor && stepDescriptor.set) {
217
+ Object.defineProperty(timeInput, "step", {
218
+ configurable: true,
219
+ get: function () {
220
+ return stepDescriptor.get.call(timeInput);
221
+ },
222
+ set: function (value) {
223
+ stepDescriptor.set.call(timeInput, value);
224
+ applyStep();
225
+ }
226
+ });
227
+ }
228
+ new MutationObserver(applyStep).observe(timeInput, {
229
+ attributes: true,
230
+ attributeFilter: ["step"]
231
+ });
232
+
161
233
  updateArrows();
162
234
  writeInput();
163
235
  renderClock();
@@ -1 +1 @@
1
- !function(){"use strict";var e="4.6rem",t="6.4rem";function n(){var n=document.querySelector(".clock-picker"),r=document.querySelector("#clock"),u=document.querySelector("#clock-widget"),o=document.querySelector("#time-input"),c=document.querySelector("#hour-arrow"),i=document.querySelector("#minute-arrow"),a=document.querySelector("#clock-toggle");if(r&&o&&c&&i){var d=(o.value||"17:00").split(":"),s=Number(d[0])||0,l=Number(d[1])||0,m="hour",f=150,p=document.createElement("div"),h=document.createElement("span");p.className="clock-hand bg-primary",h.className="clock-knob bg-primary",h.setAttribute("aria-hidden","true"),p.append(h),r.append(p),c.addEventListener("click",function(){k("hour")}),i.addEventListener("click",function(){k("minute")}),a&&a.addEventListener("click",function(){u&&u.hidden?S():L()}),o.addEventListener("focus",S),o.addEventListener("input",function(){if(o.value){var e=o.value.split(":"),t=Number(e[0]),n=Number(e[1]);n!==l?m="minute":t!==s&&(m="hour"),s=t,l=n,b(),E()}}),n&&n.addEventListener("mousedown",function(e){e.target!==o&&(a&&a.contains(e.target)||e.preventDefault())}),document.addEventListener("mousedown",function(e){n&&!n.contains(e.target)&&L()}),b(),g(),E(),L()}function v(e){return String(e).padStart(2,"0")}function y(){f+=((("hour"===m?s%12*30:6*l)-f)%360+540)%360-180,p.style.setProperty("--angle",f+"deg"),p.style.setProperty("--hand","hour"===m&&(0===s||s>12)?e:t)}function b(){c.disabled="hour"===m,i.disabled="minute"===m}function g(){o.value=v(s)+":"+v(l)}function k(e){m!==e&&(m=e,b(),E())}function E(){r.querySelectorAll(".clock-number").forEach(function(e){e.remove()}),r.setAttribute("aria-label","hour"===m?"Kies een uur":"Kies de minuten");var n="hour"===m?[12,1,2,3,4,5,6,7,8,9,10,11,0,13,14,15,16,17,18,19,20,21,22,23]:[0,5,10,15,20,25,30,35,40,45,50,55],u="hour"===m?s:l;y(),n.forEach(function(n,o){var c=document.createElement("button"),i="hour"===m&&o>=12,a=30*("hour"===m?o%12:o);c.type="button",c.className="clock-number",c.textContent="hour"===m&&0===n?"00":String(n),c.setAttribute("aria-pressed",n===u?"true":"false"),c.style.setProperty("--angle",a+"deg"),c.style.setProperty("--radius",i?e:t),c.addEventListener("click",function(){"hour"===m?(s=n,m="minute"):l=n,g(),b(),E()}),r.append(c)})}function S(){u&&(u.hidden=!1,a&&a.setAttribute("aria-pressed","true"))}function L(){u&&(u.hidden=!0,a&&a.setAttribute("aria-pressed","false"))}}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",n):n()}();
1
+ !function(){"use strict";var e="4.6rem",t="6.4rem";function n(){var n=document.querySelector(".clock-picker"),r=document.querySelector("#clock"),u=document.querySelector("#clock-widget"),o=document.querySelector("#time-input"),i=document.querySelector("#hour-arrow"),a=document.querySelector("#minute-arrow"),c=document.querySelector("#clock-toggle");if(r&&o&&i&&a){var d=new Date,s=o.value?o.value.split(":"):[d.getHours(),d.getMinutes()],l=Number(s[0])||0,m=k(Number(s[1])||0),f="hour",p=150,h=document.createElement("div"),v=document.createElement("span");h.className="clock-hand bg-primary",v.className="clock-knob bg-primary",v.setAttribute("aria-hidden","true"),h.append(v),r.append(h),r.addEventListener("click",function(e){if(!e.target.closest(".clock-number")){var t=function(e){var t=r.getBoundingClientRect(),n=e.clientX-(t.left+t.width/2),u=e.clientY-(t.top+t.height/2),o=(180*Math.atan2(n,-u)/Math.PI+360)%360;if("minute"===f)return k(Math.round(o/6)%60);var i=Math.round(o/30)%12;return Math.hypot(n,u)<.32*t.width?0===i?0:i+12:0===i?12:i}(e);"minute"===f?m=t:(l=t,f="minute"),L(),S(),w()}}),i.addEventListener("click",function(){M("hour")}),a.addEventListener("click",function(){M("minute")}),c&&c.addEventListener("click",function(){u&&u.hidden?q():N()}),o.addEventListener("focus",q),o.addEventListener("input",function(){if(o.value){var e=o.value.split(":"),t=Number(e[0]),n=Number(e[1]);n!==m?f="minute":t!==l&&(f="hour"),l=t,m=n,S(),w()}}),n&&n.addEventListener("mousedown",function(e){e.target!==o&&(c&&c.contains(e.target)||e.preventDefault())}),document.addEventListener("mousedown",function(e){n&&!n.contains(e.target)&&N()});var b=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,"step");b&&b.set&&Object.defineProperty(o,"step",{configurable:!0,get:function(){return b.get.call(o)},set:function(e){b.set.call(o,e),A()}}),new MutationObserver(A).observe(o,{attributes:!0,attributeFilter:["step"]}),S(),L(),w(),N()}function g(e){return String(e).padStart(2,"0")}function y(){var e=Number(o.getAttribute("step")||o.step);return(!e||e<60)&&(e=60),Math.max(1,Math.round(e/60))}function k(e){var t=y();return(Math.round(e/t)*t%60+60)%60}function E(){p+=((("hour"===f?l%12*30:6*m)-p)%360+540)%360-180,h.style.setProperty("--angle",p+"deg"),h.style.setProperty("--hand","hour"===f&&(0===l||l>12)?e:t)}function S(){i.disabled="hour"===f,a.disabled="minute"===f}function L(){o.value=g(l)+":"+g(m)}function M(e){f!==e&&(f=e,S(),w())}function w(){r.querySelectorAll(".clock-number").forEach(function(e){e.remove()}),r.setAttribute("aria-label","hour"===f?"Kies een uur":"Kies de minuten");var n="hour"===f?[12,1,2,3,4,5,6,7,8,9,10,11,0,13,14,15,16,17,18,19,20,21,22,23]:[0,5,10,15,20,25,30,35,40,45,50,55],u="hour"===f?l:m;E(),n.forEach(function(n,o){var i=document.createElement("button"),a="hour"===f&&o>=12,c=30*("hour"===f?o%12:o),d="minute"===f&&!function(e){return e%y()===0}(n);i.type="button",i.className="clock-number",i.textContent=0===n?"00":String(n),i.dataset.value=String(n),i.disabled=d,i.setAttribute("aria-pressed",d||n!==u?"false":"true"),i.style.setProperty("--angle",c+"deg"),i.style.setProperty("--radius",a?e:t),i.addEventListener("click",function(){i.disabled||("hour"===f?(l=n,f="minute"):m=n,L(),S(),w())}),r.append(i)})}function q(){u&&(u.hidden=!1,c&&c.setAttribute("aria-pressed","true"))}function N(){u&&(u.hidden=!0,c&&c.setAttribute("aria-pressed","false"))}function A(){m=k(m),L(),w()}}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",n):n()}();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bootstrap-time",
3
- "version": "0.1.4-beta",
3
+ "version": "0.1.6-beta",
4
4
  "description": "Time picker based on Bootstrap.",
5
5
  "author": "M. de Ridder",
6
6
  "license": "MIT",
@@ -18,9 +18,12 @@
18
18
  var clockToggle = document.querySelector("#clock-toggle");
19
19
  if (!clock || !timeInput || !hourArrow || !minuteArrow) return;
20
20
 
21
- var initial = (timeInput.value || "17:00").split(":");
21
+ var now = new Date();
22
+ var initial = timeInput.value
23
+ ? timeInput.value.split(":")
24
+ : [now.getHours(), now.getMinutes()];
22
25
  var hour = Number(initial[0]) || 0;
23
- var minute = Number(initial[1]) || 0;
26
+ var minute = snapMinute(Number(initial[1]) || 0);
24
27
  var mode = "hour";
25
28
  var handAngle = 150;
26
29
  var hand = document.createElement("div");
@@ -36,6 +39,22 @@
36
39
  return String(value).padStart(2, "0");
37
40
  }
38
41
 
42
+ function minuteStep() {
43
+ var step = Number(timeInput.getAttribute("step") || timeInput.step);
44
+ if (!step || step < 60) step = 60;
45
+ return Math.max(1, Math.round(step / 60));
46
+ }
47
+
48
+ function snapMinute(value) {
49
+ var step = minuteStep();
50
+ var snapped = Math.round(value / step) * step;
51
+ return ((snapped % 60) + 60) % 60;
52
+ }
53
+
54
+ function allowedMinute(value) {
55
+ return value % minuteStep() === 0;
56
+ }
57
+
39
58
  function targetAngle() {
40
59
  return mode === "hour" ? (hour % 12) * 30 : minute * 6;
41
60
  }
@@ -85,14 +104,18 @@
85
104
  var button = document.createElement("button");
86
105
  var inner = mode === "hour" && index >= 12;
87
106
  var angle = (mode === "hour" ? index % 12 : index) * 30;
107
+ var disabled = mode === "minute" && !allowedMinute(value);
88
108
 
89
109
  button.type = "button";
90
110
  button.className = "clock-number";
91
- button.textContent = mode === "hour" && value === 0 ? "00" : String(value);
92
- button.setAttribute("aria-pressed", value === selected ? "true" : "false");
111
+ button.textContent = value === 0 ? "00" : String(value);
112
+ button.dataset.value = String(value);
113
+ button.disabled = disabled;
114
+ button.setAttribute("aria-pressed", !disabled && value === selected ? "true" : "false");
93
115
  button.style.setProperty("--angle", angle + "deg");
94
116
  button.style.setProperty("--radius", inner ? INNER_RADIUS : OUTER_RADIUS);
95
117
  button.addEventListener("click", function () {
118
+ if (button.disabled) return;
96
119
  if (mode === "hour") {
97
120
  hour = value;
98
121
  mode = "minute";
@@ -124,6 +147,31 @@
124
147
  else hideWidget();
125
148
  }
126
149
 
150
+ function valueFromPoint(event) {
151
+ var rect = clock.getBoundingClientRect();
152
+ var dx = event.clientX - (rect.left + rect.width / 2);
153
+ var dy = event.clientY - (rect.top + rect.height / 2);
154
+ var angle = (Math.atan2(dx, -dy) * 180 / Math.PI + 360) % 360;
155
+ if (mode === "minute") return snapMinute(Math.round(angle / 6) % 60);
156
+ var hour12 = Math.round(angle / 30) % 12;
157
+ var inner = Math.hypot(dx, dy) < rect.width * 0.32;
158
+ if (inner) return hour12 === 0 ? 0 : hour12 + 12;
159
+ return hour12 === 0 ? 12 : hour12;
160
+ }
161
+
162
+ clock.addEventListener("click", function (event) {
163
+ if (event.target.closest(".clock-number")) return;
164
+ var value = valueFromPoint(event);
165
+ if (mode === "minute") minute = value;
166
+ else {
167
+ hour = value;
168
+ mode = "minute";
169
+ }
170
+ writeInput();
171
+ updateArrows();
172
+ renderClock();
173
+ });
174
+
127
175
  hourArrow.addEventListener("click", function () {
128
176
  showMode("hour");
129
177
  });
@@ -158,6 +206,30 @@
158
206
  hideWidget();
159
207
  });
160
208
 
209
+ function applyStep() {
210
+ minute = snapMinute(minute);
211
+ writeInput();
212
+ renderClock();
213
+ }
214
+
215
+ var stepDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "step");
216
+ if (stepDescriptor && stepDescriptor.set) {
217
+ Object.defineProperty(timeInput, "step", {
218
+ configurable: true,
219
+ get: function () {
220
+ return stepDescriptor.get.call(timeInput);
221
+ },
222
+ set: function (value) {
223
+ stepDescriptor.set.call(timeInput, value);
224
+ applyStep();
225
+ }
226
+ });
227
+ }
228
+ new MutationObserver(applyStep).observe(timeInput, {
229
+ attributes: true,
230
+ attributeFilter: ["step"]
231
+ });
232
+
161
233
  updateArrows();
162
234
  writeInput();
163
235
  renderClock();
@@ -89,6 +89,8 @@
89
89
  width: 16rem;
90
90
  height: 16rem;
91
91
  border-radius: 50%;
92
+ touch-action: none;
93
+ cursor: pointer;
92
94
  }
93
95
 
94
96
  .clock-hand {
@@ -131,4 +133,9 @@
131
133
  &[aria-pressed="true"] {
132
134
  color: var(--bs-white, #fff);
133
135
  }
136
+
137
+ &:disabled {
138
+ opacity: 0.35;
139
+ cursor: default;
140
+ }
134
141
  }