TimeInput: add confirmation text
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
10
src/lib/Label.svelte.d.ts
vendored
10
src/lib/Label.svelte.d.ts
vendored
@@ -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;
|
|
||||||
12
src/lib/StyledRawInput.svelte.d.ts
vendored
12
src/lib/StyledRawInput.svelte.d.ts
vendored
@@ -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;
|
|
||||||
@@ -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>
|
||||||
|
|||||||
10
src/lib/TimeInput.svelte.d.ts
vendored
10
src/lib/TimeInput.svelte.d.ts
vendored
@@ -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;
|
|
||||||
Reference in New Issue
Block a user