Skip to content

Commit

Permalink
fix(Input): replaced label, leading, trailing props with slots
Browse files Browse the repository at this point in the history
fix(Input): added Input.Label
fix(Input): added Input.Leading
fix(Input): added Input.Trailing
docs(icons): added phone and lock
docs(Navigation): added updated flag to input
fix(icons): added eye and eye_off
docs(input): updated examples, props, and slots table
docs(input): added updated component banner
  • Loading branch information
N00nDay committed Oct 17, 2022
1 parent 3f38e5a commit 2c0c024
Show file tree
Hide file tree
Showing 10 changed files with 296 additions and 176 deletions.
2 changes: 1 addition & 1 deletion src/docs/components/navigation/Navigation.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
{
title: 'Input',
href: '/input',
beta: true
updated: true
},
{
title: 'InputNumber',
Expand Down
4 changes: 4 additions & 0 deletions src/docs/icons.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export const email =
'M20,8L12,13L4,8V6L12,11L20,6M20,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V6C22,4.89 21.1,4 20,4Z';
export const phone =
'M6.62,10.79C8.06,13.62 10.38,15.94 13.21,17.38L15.41,15.18C15.69,14.9 16.08,14.82 16.43,14.93C17.55,15.3 18.75,15.5 20,15.5A1,1 0 0,1 21,16.5V20A1,1 0 0,1 20,21A17,17 0 0,1 3,4A1,1 0 0,1 4,3H7.5A1,1 0 0,1 8.5,4C8.5,5.25 8.7,6.45 9.07,7.57C9.18,7.92 9.1,8.31 8.82,8.59L6.62,10.79Z';
export const lock =
'M12,17A2,2 0 0,0 14,15C14,13.89 13.1,13 12,13A2,2 0 0,0 10,15A2,2 0 0,0 12,17M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V10C4,8.89 4.9,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z';
130 changes: 34 additions & 96 deletions src/lib/components/input/Input.svelte
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
<script lang="ts">
import { current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
import { exclude } from '../../utils/exclude';
export let use: ActionArray = [];
const forwardEvents = forwardEventsBuilder(current_component);
<script lang="ts" context="module">
export const INPUT_CONTEXT_ID = 'input-context-id';
</script>

import type { MaterialIcon } from '../../types';
<script lang="ts">
import { setContext } from 'svelte/internal';
import { slide, scale } from 'svelte/transition';
import Swap from '../swap';
import { twMerge } from 'tailwind-merge';
import Icon from '../icon';
import { error as errorIcon, close, eye, eye_off } from '../../icons';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
export let leading: MaterialIcon | undefined = undefined;
export let trailing: MaterialIcon | undefined = undefined;
export let name: string;
export let type: 'text' | 'email' | 'password' = 'text';
export let label: string | undefined = undefined;
export let srOnly = false;
export let error: string | undefined = undefined;
export let placeholder: string | undefined = undefined;
export let value: string | undefined = undefined;
Expand All @@ -24,12 +25,8 @@
export let autofocus: true | undefined = undefined;
export let readonly: true | undefined = undefined;
export let tabindex: string | undefined = undefined;
export let handleLeadingClick: (() => void) | undefined = undefined;
export let handleTrailingClick: (() => void) | undefined = undefined;
export let showPasswordToggle = false;
export let allowClear = false;
export let leadingAriaLabel = 'input leading';
export let trailingAriaLabel = 'input trailing';
let input: HTMLInputElement;
Expand All @@ -53,20 +50,18 @@
value = undefined;
}
setContext(INPUT_CONTEXT_ID, {
input: true,
name,
error
});
const defaultClass = 'group';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<div class={finalClass} style={$$props.style}>
{#if label}
<label
for={name}
class="block text-sm font-medium{srOnly ? ' sr-only' : ''}"
class:text-light-secondary-content={!error}
class:dark:text-dark-secondary-content={!error}
class:text-danger={error}>{label}</label
>
{/if}
<slot name="label" />
<div class="mt-1 relative rounded-md shadow-sm h-[2.5rem] dark:shadow-black">
<input
bind:this={input}
Expand Down Expand Up @@ -94,51 +89,27 @@
class:group-active:border-red-500={error}
class:group-active:border-primary={!error}
class:dark:group-active:border-primary={!error}
class:pl-10={leading}
class:pr-10={trailing || error || allowClear}
class:pl-10={$$slots.leading}
class:pr-10={$$slots.trailing || error || allowClear}
{placeholder}
bind:value
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
/>

{#if leading}
{#if handleLeadingClick}
<button
aria-label={leadingAriaLabel}
on:click={handleLeadingClick}
class="absolute inset-y-0 left-0 pl-3"
>
<span
transition:scale|local
class="material-icons flex items-center"
class:text-light-secondary-content={!error}
class:dark:text-dark-secondary-content={!error}
class:text-danger={error}>{leading}</span
>
</button>
{:else}
<span
transition:scale|local
class="material-icons flex items-center pointer-events-none absolute inset-y-0 left-0 pl-3"
class:text-light-secondary-content={!error}
class:dark:text-dark-secondary-content={!error}
class:text-danger={error}>{leading}</span
>
{/if}
{/if}
<slot name="leading" />

{#if allowClear && value && value.length > 0}
<button
aria-label="clear"
on:click={handleClear}
class="absolute inset-y-0 hidden group-focus-within:flex active:flex items-center"
class:right-10={showPasswordToggle || trailing || error}
class:right-3={!showPasswordToggle && !trailing && !error}
class:right-10={showPasswordToggle || $$slots.trailing || error}
class:right-3={!showPasswordToggle && !$$slots.trailing && !error}
>
<span transition:scale|local class="items-center flex">
<span class="material-icons text-light-icon dark:text-dark-icon text-base"> clear </span>
<span transition:scale|local class="items-center flex text-light-icon dark:text-dark-icon">
<Icon path={close} />
</span>
</button>
{/if}
Expand All @@ -148,52 +119,19 @@
on:click={togglePasswordVisibility}
swapped={passwordVisible}
type="flip"
class="inset-y-0 right-0 pr-3 flex items-center z-10 w-9"
style="position: absolute;left: unset;"
class="absolute left-[unset] inset-y-0 right-1 flex items-center w-9 text-light-secondary-content dark:text-dark-secondary-content"
>
<span
slot="on"
class="material-icons pr-3 text-light-secondary-content dark:text-dark-secondary-content"
>
visibility
</span>
<span
slot="off"
class="material-icons pr-3 text-light-secondary-content dark:text-dark-secondary-content"
>
visibility_off
</span>
<Icon slot="on" path={eye} />
<Icon slot="off" path={eye_off} />
</Swap>
{:else if trailing && !error}
{#if handleTrailingClick}
<button
aria-label={trailingAriaLabel}
on:click={handleTrailingClick}
class="absolute inset-y-0 right-0 pr-3"
>
<span
transition:scale|local
class="material-icons flex items-center"
class:text-light-secondary-content={!error}
class:dark:text-dark-secondary-content={!error}
class:text-danger={error}>{trailing}</span
>
</button>
{:else}
<span
transition:scale|local
class="material-icons absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none"
class:text-light-secondary-content={!error}
class:dark:text-dark-secondary-content={!error}
class:text-danger={error}>{trailing}</span
>
{/if}
{:else if $$slots.trailing && !error}
<slot name="trailing" />
{:else if error}
<span
transition:scale|local
class="material-icons absolute inset-y-0 right-3 flex items-center pointer-events-none text-danger"
>error</span
class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none text-danger"
>
<Icon path={errorIcon} />
</span>
{/if}
</div>
{#if error}
Expand Down
35 changes: 35 additions & 0 deletions src/lib/components/input/Label.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script lang="ts">
import { getContext } from 'svelte';
import { twMerge } from 'tailwind-merge';
import { useContext } from '../../utils/useContext';
import { INPUT_CONTEXT_ID } from './Input.svelte';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
useContext({
context_id: INPUT_CONTEXT_ID,
parent: 'Input',
component: 'Input.Label'
});
const { name, error }: { name: string; error: string } = getContext(INPUT_CONTEXT_ID);
let defaultClass = 'block text-sm font-medium';
if (error) {
defaultClass = defaultClass + ' text-danger';
} else {
defaultClass = defaultClass + ' text-light-secondary-content dark:text-dark-secondary-content';
}
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<label
for={name}
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}><slot /></label
>
36 changes: 36 additions & 0 deletions src/lib/components/input/Leading.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
import { INPUT_CONTEXT_ID } from './Input.svelte';
import { getContext } from 'svelte';
import { useContext } from '../../utils/useContext';
import { twMerge } from 'tailwind-merge';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
useContext({
context_id: INPUT_CONTEXT_ID,
parent: 'Input',
component: 'Input.Leading'
});
const { error }: { error: string } = getContext(INPUT_CONTEXT_ID);
let defaultClass = 'absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none';
if (error) {
defaultClass = defaultClass + ' text-danger';
} else {
defaultClass = defaultClass + ' text-light-secondary-content dark:text-dark-secondary-content';
}
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<span
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot />
</span>
36 changes: 36 additions & 0 deletions src/lib/components/input/Trailing.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
import { INPUT_CONTEXT_ID } from './Input.svelte';
import { getContext } from 'svelte';
import { useContext } from '../../utils/useContext';
import { twMerge } from 'tailwind-merge';
import { get_current_component } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
const forwardEvents = forwardEventsBuilder(get_current_component());
useContext({
context_id: INPUT_CONTEXT_ID,
parent: 'Input',
component: 'Input.Leading'
});
const { error }: { error: string } = getContext(INPUT_CONTEXT_ID);
let defaultClass = 'absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none';
if (error) {
defaultClass = defaultClass + ' text-danger';
} else {
defaultClass = defaultClass + ' text-light-secondary-content dark:text-dark-secondary-content';
}
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<span
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot />
</span>
17 changes: 16 additions & 1 deletion src/lib/components/input/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
import Input from './Input.svelte';
import OriginalInput from './Input.svelte';
import Label from './Label.svelte';
import Leading from './Leading.svelte';
import Trailing from './Trailing.svelte';

const Input = OriginalInput as InputStatic;
Input.Label = Label;
Input.Leading = Leading;
Input.Trailing = Trailing;

export default Input;

export interface InputStatic {
new (...args: ConstructorParameters<typeof OriginalInput>): OriginalInput;
Label: typeof Label;
Leading: typeof Leading;
Trailing: typeof Trailing;
}
4 changes: 4 additions & 0 deletions src/lib/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ export const check =
'M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z';
export const close =
'M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z';
export const eye =
'M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17M12,4.5C7,4.5 2.73,7.61 1,12C2.73,16.39 7,19.5 12,19.5C17,19.5 21.27,16.39 23,12C21.27,7.61 17,4.5 12,4.5Z';
export const eye_off =
'M11.83,9L15,12.16C15,12.11 15,12.05 15,12A3,3 0 0,0 12,9C11.94,9 11.89,9 11.83,9M7.53,9.8L9.08,11.35C9.03,11.56 9,11.77 9,12A3,3 0 0,0 12,15C12.22,15 12.44,14.97 12.65,14.92L14.2,16.47C13.53,16.8 12.79,17 12,17A5,5 0 0,1 7,12C7,11.21 7.2,10.47 7.53,9.8M2,4.27L4.28,6.55L4.73,7C3.08,8.3 1.78,10 1,12C2.73,16.39 7,19.5 12,19.5C13.55,19.5 15.03,19.2 16.38,18.66L16.81,19.08L19.73,22L21,20.73L3.27,3M12,7A5,5 0 0,1 17,12C17,12.64 16.87,13.26 16.64,13.82L19.57,16.75C21.07,15.5 22.27,13.86 23,12C21.27,7.61 17,4.5 12,4.5C10.6,4.5 9.26,4.75 8,5.2L10.17,7.35C10.74,7.13 11.35,7 12,7Z';
Loading

0 comments on commit 2c0c024

Please sign in to comment.