TimeInput: add confirmation text

This commit is contained in:
Elijah Duffy
2025-05-20 10:49:44 -07:00
parent 9a820794a2
commit 72bc7e23b4
5 changed files with 25 additions and 48 deletions

View File

@@ -34,15 +34,15 @@
} }
}, },
"peerDependencies": { "peerDependencies": {
"svelte": "^5.25.3", "@sveltejs/kit": "^2.16.0",
"@sveltejs/kit": "^2.16.0" "svelte": "^5.25.3"
}, },
"devDependencies": { "devDependencies": {
"@eslint/compat": "^1.2.5", "@eslint/compat": "^1.2.5",
"@eslint/js": "^9.18.0", "@eslint/js": "^9.18.0",
"@jsrob/svelte-portal": "^0.2.1",
"@repo/tailwindcss-config": "workspace:*", "@repo/tailwindcss-config": "workspace:*",
"@repo/validate": "workspace:*", "@repo/validate": "workspace:*",
"@jsrob/svelte-portal": "^0.2.1",
"@sveltejs/adapter-auto": "^4.0.0", "@sveltejs/adapter-auto": "^4.0.0",
"@sveltejs/package": "^2.0.0", "@sveltejs/package": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0", "@sveltejs/vite-plugin-svelte": "^5.0.0",
@@ -56,6 +56,7 @@
"libphonenumber-js": "^1.12.6", "libphonenumber-js": "^1.12.6",
"match-sorter": "^8.0.0", "match-sorter": "^8.0.0",
"melt": "^0.12.0", "melt": "^0.12.0",
"moment": "^2.30.1",
"phosphor-svelte": "^3.0.1", "phosphor-svelte": "^3.0.1",
"prettier": "^3.4.2", "prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.3", "prettier-plugin-svelte": "^3.3.3",

View File

@@ -1,10 +0,0 @@
import type { Snippet } from 'svelte';
type $$ComponentProps = {
for: string;
error?: boolean;
bigError?: boolean;
children: Snippet;
};
declare const Label: import("svelte").Component<$$ComponentProps, {}, "">;
type Label = ReturnType<typeof Label>;
export default Label;

View File

@@ -1,12 +0,0 @@
import type { HTMLInputAttributes } from 'svelte/elements';
import { type InputValidatorEvent, type ValidatorOptions } from '@repo/validate';
type $Props = Omit<HTMLInputAttributes, 'name' | 'value'> & {
name: string;
value?: string;
validate?: ValidatorOptions;
ref?: HTMLInputElement | null;
onvalidate?: (e: InputValidatorEvent) => void;
};
declare const StyledRawInput: import("svelte").Component<$Props, {}, "value" | "ref">;
type StyledRawInput = ReturnType<typeof StyledRawInput>;
export default StyledRawInput;

View File

@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { inputValidator, keydownValidator, liveValidator, validate } from '@repo/validate'; import { liveValidator, validate } from '@repo/validate';
import Label from './Label.svelte'; import Label from './Label.svelte';
import StyledRawInput from './StyledRawInput.svelte'; import StyledRawInput from './StyledRawInput.svelte';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
@@ -12,7 +12,7 @@
formattedValue = $bindable(''), formattedValue = $bindable(''),
required, required,
invalidMessage = 'Please select a time', invalidMessage = 'Please select a time',
showText = false showConfirm = false
}: { }: {
name: string; name: string;
label?: string; label?: string;
@@ -20,7 +20,7 @@
formattedValue?: string; formattedValue?: string;
required?: boolean; required?: boolean;
invalidMessage?: string; invalidMessage?: string;
showText?: boolean; showConfirm?: boolean;
} = $props(); } = $props();
let ampm: 'AM' | 'PM' = $state('AM'); let ampm: 'AM' | 'PM' = $state('AM');
@@ -145,6 +145,7 @@
if (isNaN(hourValue)) { if (isNaN(hourValue)) {
value = ''; value = '';
formattedValue = '';
updateHiddenInput(); updateHiddenInput();
return; return;
} }
@@ -162,6 +163,8 @@
updateHiddenInput(); updateHiddenInput();
// update formatted value // update formatted value
const date = moment(value, 'HH:mm');
formattedValue = date.format('h:mm A');
}; };
/** /**
@@ -214,6 +217,11 @@
onkeydown={(e) => { onkeydown={(e) => {
if (!hourInput) return; if (!hourInput) return;
if (e.key === ':' && hourInput.value.length !== 0) {
minuteInput?.focus();
e.preventDefault();
}
if (e.key === 'ArrowRight' && hourInput.selectionEnd === hourInput.value.length) { if (e.key === 'ArrowRight' && hourInput.selectionEnd === hourInput.value.length) {
minuteInput?.focus(); minuteInput?.focus();
} }
@@ -230,7 +238,6 @@
} }
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') { if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
e.preventDefault(); e.preventDefault();
return;
} }
}} }}
oninput={() => { oninput={() => {
@@ -305,7 +312,7 @@
<div class="flex flex-col"> <div class="flex flex-col">
<!-- AM Button --> <!-- AM Button -->
<button <button
class={['ampm rounded-t-sm border', ampm === 'AM' && 'selected ring-1 ring-blue-300']} class={['ampm rounded-t-sm border', ampm === 'AM' && 'selected']}
onclick={() => { onclick={() => {
ampm = 'AM'; ampm = 'AM';
updateValue(); updateValue();
@@ -321,10 +328,7 @@
<!-- PM Button --> <!-- PM Button -->
<button <button
class={[ class={['ampm rounded-b-sm border-r border-b border-l', ampm === 'PM' && 'selected']}
'ampm rounded-b-sm border-r border-b border-l',
ampm === 'PM' && 'selected ring-1 ring-blue-300'
]}
onclick={() => { onclick={() => {
ampm = 'PM'; ampm = 'PM';
updateValue(); updateValue();
@@ -339,9 +343,13 @@
</div> </div>
</div> </div>
<div class={['opacity-0 transition-opacity', !valid && 'opacity-100']}> <div class={['opacity-0 transition-opacity', (!valid || showConfirm) && 'opacity-100']}>
<Label for={name} error> <Label for={name} error={!valid}>
{#if !valid}
{invalidMessage} {invalidMessage}
{:else if showConfirm}
{formattedValue !== '' ? `See you at ${formattedValue}!` : ''}
{/if}
</Label> </Label>
</div> </div>
</div> </div>
@@ -367,7 +375,7 @@
@apply border-accent dark:border-accent/50 cursor-pointer px-3 py-1 font-medium; @apply border-accent dark:border-accent/50 cursor-pointer px-3 py-1 font-medium;
&.selected { &.selected {
@apply bg-accent text-background dark:bg-accent/30 dark:text-background/90 ring-1 ring-blue-600 dark:ring-blue-300; @apply bg-accent text-background dark:bg-accent/30 dark:text-background/90 ring-1 ring-black dark:ring-blue-300;
} }
} }
</style> </style>

View File

@@ -1,10 +0,0 @@
type $$ComponentProps = {
name: string;
label?: string;
value?: string;
required?: boolean;
invalidMessage?: string;
};
declare const TimeInput: import("svelte").Component<$$ComponentProps, {}, "value">;
type TimeInput = ReturnType<typeof TimeInput>;
export default TimeInput;