Skip to content

Commit 12cda19

Browse files
committed
feat(input): adds first draft of pin input
1 parent 7a73cf2 commit 12cda19

File tree

4 files changed

+540
-44
lines changed

4 files changed

+540
-44
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Neomorphic ui library for svelte 5
88
- [x] Card
99
- [x] Inputs
1010
- [x] Password
11+
- [ ] Pin
1112
- [ ] Color picker
1213
- [x] Text Area
1314
- [ ] @ / # tags
@@ -91,4 +92,3 @@ Neomorphic ui library for svelte 5
9192

9293
# TODO (work in progress)
9394

94-
- Re-name all modifier to be prefixed with `neo-` to avoid conflicts with other libraries

demo/components/DemoInputs.svelte

Lines changed: 187 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<script lang="ts">
2+
import { fade } from 'svelte/transition';
3+
24
import DemoElevationPicker from '../utils/DemoElevationPicker.svelte';
35
import SphereBackdrop from '../utils/SphereBackdrop.svelte';
46
@@ -11,6 +13,7 @@
1113
import NeoInput from '~/inputs/NeoInput.svelte';
1214
import NeoNumberStep from '~/inputs/NeoNumberStep.svelte';
1315
import NeoPassword from '~/inputs/NeoPassword.svelte';
16+
import NeoPin from '~/inputs/NeoPin.svelte';
1417
import NeoTextArea from '~/inputs/NeoTextarea.svelte';
1518
import { DefaultShadowElevation, MaxShadowElevation, MinShadowElevation } from '~/utils/shadow.utils';
1619
@@ -26,7 +29,24 @@
2629
touched = $state(false);
2730
dirty = $state(false);
2831
valid = $state(undefined);
29-
value = $state('');
32+
value = $state<string | number>('');
33+
34+
constructor({
35+
touched = false,
36+
dirty = false,
37+
valid = undefined,
38+
value = '',
39+
}: {
40+
touched?: boolean;
41+
dirty?: boolean;
42+
valid?: boolean;
43+
value?: string | number;
44+
} = {}) {
45+
this.touched = touched;
46+
this.dirty = dirty;
47+
this.valid = valid;
48+
this.value = value;
49+
}
3050
3151
clear() {
3252
this.touched = false;
@@ -64,10 +84,21 @@
6484
const invalidState = new ValidationState();
6585
const customState = new ValidationState();
6686
87+
const numberState = new ValidationState({ value: 0 });
88+
89+
const pinState = new ValidationState();
90+
const pinStateSeparator = new ValidationState();
91+
const pinPasswordState = new ValidationState();
92+
6793
const onClear = () => {
6894
validation.clear();
6995
validState.clear();
7096
invalidState.clear();
97+
customState.clear();
98+
99+
pinState.clear();
100+
pinStateSeparator.clear();
101+
pinPasswordState.clear();
71102
};
72103
73104
const onclick = (e: MouseEvent) => console.info('suffix click', e);
@@ -329,11 +360,14 @@
329360
{/if}
330361
{/snippet}
331362

332-
{#snippet validationState({ touched, dirty, valid }: ValidationState)}
363+
{#snippet validationState({ touched, dirty, valid, value }: ValidationState, show = false)}
333364
<div class="row">
334365
<div class="label">Touched: {touched}</div>
335366
<div class="label">Dirty: {dirty}</div>
336367
<div class="label">Valid: {valid}</div>
368+
{#if show}
369+
<div class="label">Value: {value}</div>
370+
{/if}
337371
</div>
338372
{/snippet}
339373

@@ -348,54 +382,153 @@
348382
</div>
349383
{/each}
350384
</div>
385+
</form>
351386

352-
<div class="row">
353-
{#each validationColumns as column}
354-
<div class="column content">
355-
<span class="label">{column.label}</span>
356-
{@render validationState(column.state)}
357-
{@render group(column)}
358-
</div>
359-
{/each}
360-
</div>
361-
362-
<div class="row">
387+
<!-- Password -->
388+
<div class="row">
389+
{#each validationColumns as column}
363390
<div class="column content">
364-
<span class="label">Password</span>
365-
{#if options.glass}
366-
<SphereBackdrop>
367-
<NeoPassword label="Password" auto-complete="current-password" {...options} />
368-
</SphereBackdrop>
369-
{:else}
370-
<NeoPassword label="Password" auto-complete="current-password" {...options} />
371-
{/if}
391+
<span class="label">{column.label}</span>
392+
{@render validationState(column.state)}
393+
{@render group(column)}
372394
</div>
395+
{/each}
396+
</div>
397+
398+
<div class="row">
399+
<div class="column content">
400+
<span class="label">Password</span>
401+
{#if options.glass}
402+
<SphereBackdrop>
403+
<NeoPassword label="Password" autocomplete="current-password" {...options} />
404+
</SphereBackdrop>
405+
{:else}
406+
<NeoPassword in={fade} label="Password" autocomplete="current-password" {...options} />
407+
{/if}
373408
</div>
409+
</div>
374410

375-
<div class="row">
376-
<div class="column content">
377-
<span class="label">Number</span>
378-
{#if options.glass}
379-
<SphereBackdrop>
380-
<NeoNumberStep {...options} />
381-
</SphereBackdrop>
382-
{:else}
383-
<NeoNumberStep {...options} />
384-
{/if}
385-
</div>
411+
<!-- Number inputs -->
412+
<div class="row">
413+
<div class="column content">
414+
<span class="label">Number</span>
415+
{@render validationState(numberState)}
416+
{#if options.glass}
417+
<SphereBackdrop>
418+
<NeoNumberStep
419+
bind:touched={numberState.touched}
420+
bind:dirty={numberState.dirty}
421+
bind:valid={numberState.valid}
422+
bind:value={numberState.value}
423+
{...options}
424+
/>
425+
</SphereBackdrop>
426+
{:else}
427+
<NeoNumberStep
428+
bind:touched={numberState.touched}
429+
bind:dirty={numberState.dirty}
430+
bind:valid={numberState.valid}
431+
bind:value={numberState.value}
432+
{...options}
433+
/>
434+
{/if}
435+
</div>
386436

387-
<div class="column content">
388-
<span class="label">Min Max</span>
389-
{#if options.glass}
390-
<SphereBackdrop>
391-
<NeoNumberStep min="-5" max="5" {...options} />
392-
</SphereBackdrop>
393-
{:else}
394-
<NeoNumberStep min="-5" max="5" {...options} />
395-
{/if}
396-
</div>
437+
<div class="column content">
438+
<span class="label">Min Max</span>
439+
{@render validationState(numberState)}
440+
{#if options.glass}
441+
<SphereBackdrop>
442+
<NeoNumberStep
443+
bind:touched={numberState.touched}
444+
bind:dirty={numberState.dirty}
445+
bind:valid={numberState.valid}
446+
bind:value={numberState.value}
447+
min="-5"
448+
max="5"
449+
{...options}
450+
/>
451+
</SphereBackdrop>
452+
{:else}
453+
<NeoNumberStep
454+
bind:touched={numberState.touched}
455+
bind:dirty={numberState.dirty}
456+
bind:valid={numberState.valid}
457+
bind:value={numberState.value}
458+
min="-5"
459+
max="5"
460+
{...options}
461+
/>
462+
{/if}
397463
</div>
398-
</form>
464+
</div>
465+
466+
<!-- Number inputs -->
467+
<div class="row">
468+
<div class="column content">
469+
<span class="label">Pin</span>
470+
{@render validationState(pinState, true)}
471+
{#if options.glass}
472+
<SphereBackdrop>
473+
<NeoPin bind:touched={pinState.touched} bind:dirty={pinState.dirty} bind:valid={pinState.valid} bind:value={pinState.value} {...options} />
474+
</SphereBackdrop>
475+
{:else}
476+
<NeoPin bind:touched={pinState.touched} bind:dirty={pinState.dirty} bind:valid={pinState.valid} bind:value={pinState.value} {...options} />
477+
{/if}
478+
</div>
479+
480+
<div class="column content">
481+
<span class="label">Pin Groups</span>
482+
{@render validationState(pinStateSeparator, true)}
483+
{#if options.glass}
484+
<SphereBackdrop>
485+
<NeoPin
486+
groups={2}
487+
bind:touched={pinStateSeparator.touched}
488+
bind:dirty={pinStateSeparator.dirty}
489+
bind:valid={pinStateSeparator.valid}
490+
bind:value={pinStateSeparator.value}
491+
{...options}
492+
/>
493+
</SphereBackdrop>
494+
{:else}
495+
<NeoPin
496+
groups={2}
497+
bind:touched={pinStateSeparator.touched}
498+
bind:dirty={pinStateSeparator.dirty}
499+
bind:valid={pinStateSeparator.valid}
500+
bind:value={pinStateSeparator.value}
501+
{...options}
502+
/>
503+
{/if}
504+
</div>
505+
506+
<div class="column content">
507+
<span class="label">Pin Password</span>
508+
{@render validationState(pinPasswordState, true)}
509+
{#if options.glass}
510+
<SphereBackdrop>
511+
<NeoPin
512+
bind:touched={pinPasswordState.touched}
513+
bind:dirty={pinPasswordState.dirty}
514+
bind:valid={pinPasswordState.valid}
515+
bind:value={pinPasswordState.value}
516+
type="password"
517+
{...options}
518+
/>
519+
</SphereBackdrop>
520+
{:else}
521+
<NeoPin
522+
bind:touched={pinPasswordState.touched}
523+
bind:dirty={pinPasswordState.dirty}
524+
bind:valid={pinPasswordState.valid}
525+
bind:value={pinPasswordState.value}
526+
type="password"
527+
{...options}
528+
/>
529+
{/if}
530+
</div>
531+
</div>
399532

400533
<style lang="scss">
401534
@use 'src/lib/styles/common/flex' as flex;
@@ -417,6 +550,17 @@
417550
&.content {
418551
flex: 1 0 20%;
419552
max-width: 25%;
553+
554+
:global(.neo-pin-container) {
555+
container-type: inline-size;
556+
width: 100%;
557+
}
558+
559+
:global(.neo-pin-separator) {
560+
@container (width > 500px) {
561+
width: 100%;
562+
}
563+
}
420564
}
421565
}
422566

0 commit comments

Comments
 (0)