diff --git a/src/lib/TimeInput.svelte b/src/lib/TimeInput.svelte
index 974ce40..0fc43df 100644
--- a/src/lib/TimeInput.svelte
+++ b/src/lib/TimeInput.svelte
@@ -23,17 +23,31 @@
import { generateIdentifier, prefixZero, targetMust } from './util';
import { FocusManager } from './focus';
import { Time } from '@internationalized/date';
+ import { incrementValue, decrementValue } from './numeric-utils';
interface Props {
+ /**
+ * Name of the input for form integration, form will receive ISO 8601
+ * formatted string.
+ */
name?: string;
+ /** Label for the input */
label?: string;
+ /** Bindable Time value */
value?: Time | null;
+ /** Bindable formatted time string, always matches current value and cannot be set */
formattedValue?: string;
+ /** Whether the input is required */
required?: boolean;
+ /** Message to show when the input is invalid */
invalidMessage?: string;
+ /** Controls visibility for a confirmation text below the input */
showConfirm?: boolean;
+ /** Whether to use compact styling */
compact?: boolean;
+ /** Class is applied to the root container (div element) */
class?: ClassValue | null | undefined;
+ /** Triggered whenever the time value is changed by the user */
onchange?: (details: { time: Time | null; formattedTime: string }) => void;
}
@@ -95,55 +109,6 @@
}
};
- /**
- * incrementValue increments the value of the input by 1
- * @param input The input element to increment
- * @param max The maximum value of the input
- * @param start The starting value of the input
- * @returns true if the value was incremented, false if it looped back to 0
- */
- const incrementValue = (input: HTMLInputElement, max: number, start: number): boolean => {
- if (input.value.length === 0) {
- input.value = start.toString();
- return true;
- }
-
- const value = parseInt(input.value);
- if (value === max) {
- input.value = start.toString();
- return false;
- } else if (value > max) {
- input.value = (value - max).toString();
- return false;
- } else {
- input.value = (value + 1).toString();
- return true;
- }
- };
-
- /**
- * decrementValue decrements the value of the input by 1
- * @param input The input element to decrement
- * @param max The maximum value of the input
- * @param start The starting value of the input
- * @returns true if the value was decremented, false if it looped back to max
- */
- const decrementValue = (input: HTMLInputElement, max: number, start: number): boolean => {
- if (input.value.length === 0) {
- input.value = max.toString();
- return true;
- }
-
- const value = parseInt(input.value);
- if (value <= start) {
- input.value = max.toString();
- return false;
- } else {
- input.value = (value - 1).toString();
- return true;
- }
- };
-
/**
* updateValue updates `value` with the current time in 24-hour format.
* If any component is invalid or blank, it sets `value` to an empty string.
@@ -216,10 +181,10 @@
}
if (e.key === 'ArrowUp') {
- incrementValue(target, 12, 1);
+ incrementValue(target, { max: 12, start: 1 });
if (target.value === '12') toggleAMPM();
} else if (e.key === 'ArrowDown') {
- decrementValue(target, 12, 1);
+ decrementValue(target, { max: 12, start: 1 });
if (target.value === '11') toggleAMPM();
} else {
return;
@@ -248,9 +213,9 @@
const target = targetMust(e);
if (e.key === 'ArrowUp') {
- incrementValue(target, 59, 0);
+ incrementValue(target, { max: 59, start: 0 });
} else if (e.key === 'ArrowDown') {
- decrementValue(target, 59, 0);
+ decrementValue(target, { max: 59, start: 0 });
} else {
return;
}
diff --git a/src/lib/index.ts b/src/lib/index.ts
index 96a2fac..461f10f 100644
--- a/src/lib/index.ts
+++ b/src/lib/index.ts
@@ -6,6 +6,12 @@ export { default as Checkbox, type CheckboxState } from './Checkbox.svelte';
export { default as Combobox, type ComboboxOption } from './Combobox.svelte';
export { default as DateInput } from './DateInput.svelte';
export { default as Dialog, type DialogAPI, type DialogControlOpts } from './Dialog.svelte';
+export {
+ default as DurationInput,
+ formatDuration,
+ durationToISO8601,
+ iso8601ToDuration
+} from './DurationInput.svelte';
export { default as ErrorBox } from './ErrorBox.svelte';
export { default as FramelessButton } from './FramelessButton.svelte';
export { default as InjectGoogleMaps } from './InjectGoogleMaps.svelte';
diff --git a/src/lib/numeric-utils.ts b/src/lib/numeric-utils.ts
new file mode 100644
index 0000000..5a5e3b8
--- /dev/null
+++ b/src/lib/numeric-utils.ts
@@ -0,0 +1,67 @@
+/**
+ * numeric-utils.ts
+ * Utility functions for numeric input manipulation.
+ */
+
+/**
+ * incrementValue increments the value of the input by 1
+ * @param input The input element to increment
+ * @param max The maximum value of the input
+ * @param start The starting value of the input
+ * @returns true if the value was incremented, false if it looped back to 0
+ */
+export const incrementValue = (
+ input: HTMLInputElement,
+ opts: { max?: number; start: number }
+): boolean => {
+ if (input.value.length === 0) {
+ input.value = opts.start.toString();
+ return true;
+ }
+
+ const value = parseInt(input.value);
+ if (value === opts.max) {
+ input.value = opts.start.toString();
+ return false;
+ } else if (opts.max && value > opts.max) {
+ input.value = (value - opts.max).toString();
+ return false;
+ } else {
+ input.value = (value + 1).toString();
+ return true;
+ }
+};
+
+/**
+ * decrementValue decrements the value of the input by 1
+ * @param input The input element to decrement
+ * @param max The maximum value of the input
+ * @param start The starting value of the input
+ * @returns true if the value was decremented, false if it looped back to max
+ */
+export const decrementValue = (
+ input: HTMLInputElement,
+ opts: { max?: number; start: number }
+): boolean => {
+ const setToMax = (): boolean => {
+ if (opts.max) {
+ input.value = opts.max.toString();
+ return true;
+ } else {
+ input.value = '0';
+ return false;
+ }
+ };
+
+ if (input.value.length === 0) {
+ return setToMax();
+ }
+
+ const value = parseInt(input.value);
+ if (value <= opts.start) {
+ return !setToMax();
+ } else {
+ input.value = (value - 1).toString();
+ return true;
+ }
+};
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 51b01f8..c905127 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -1,5 +1,10 @@