Skip to content

Commit

Permalink
feat(TextArea): added floating action buttons, inset action items, ti…
Browse files Browse the repository at this point in the history
…tle, and description
  • Loading branch information
N00nDay committed May 10, 2023
1 parent 0b20c66 commit 9c8d240
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 26 deletions.
22 changes: 22 additions & 0 deletions src/lib/components/textarea/Actions.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script lang="ts">
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());
const defaultClass =
'flex items-center justify-between space-x-3 border-t border-border px-2 py-2 sm:px-3';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<div
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot />
</div>
21 changes: 21 additions & 0 deletions src/lib/components/textarea/Pills.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script lang="ts">
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());
const defaultClass = 'flex flex-nowrap justify-end space-x-2 px-2 py-2 sm:px-3';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<div
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<slot />
</div>
115 changes: 91 additions & 24 deletions src/lib/components/textarea/TextArea.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
export let autocomplete: string | undefined = undefined;
export let autocapitalize: 'off' | 'none' | 'sentences' | 'words' | 'characters' = 'off';
export let readonly = false;
export let disabled = true;
export let disabled = false;
let textarea: HTMLTextAreaElement;
let currentError: Writable<string | undefined> = writable(error);
Expand All @@ -22,32 +22,99 @@
// TODO: add action buttons/pills
</script>

<div class={$$props.class} style={$$props.style}>
<slot name="label" />
<div class="mt-1 opacity-75={disabled}">
<textarea
bind:this={textarea}
rows="4"
{autocapitalize}
{autocomplete}
{name}
{readonly}
{disabled}
id={name}
class="block w-full outline-none focus:outline-none sm:text-sm rounded-md placeholder-secondary-content placeholder-opacity-80"
{#if $$slots.title || $$slots.pills || $$slots.actions}
<div class="relative">
<slot name="label" />
<div
class="mt-1 overflow-hidden rounded-md border w-full outline-none focus:outline-none sm:text-sm opacity-75={disabled}"
class:border-danger={error}
class:text-danger={error}
class:placeholder-red-300={error}
class:focus:border-red-500={error}
class:focus:border-primary={!error}
class:focus-within:border-red-500={error}
class:focus-within:border-primary={!error}
class:border-border={!error}
class:bg-surface={!disabled}
class:bg-default={disabled}
{placeholder}
bind:value
/>
>
<slot name="title" />
<label for="description" class="sr-only">Description</label>
<textarea
bind:this={textarea}
rows="2"
{placeholder}
{autocapitalize}
{autocomplete}
{name}
{readonly}
{disabled}
id={name}
bind:value
class="block bg-surface w-full resize-none border-0 py-0 focus:ring-0 sm:text-sm sm:leading-6 placeholder-secondary-content placeholder-opacity-80"
class:mb-2.5={!$$slots.actions && !$$slots.pills}
class:mt-2.5={!$$slots.title}
class:placeholder-red-300={error}
/>

{#if $$slots.pills || $$slots.actions}
<div aria-hidden="true">
{#if $$slots.pills}
<div class="py-2">
<div class="h-9" />
</div>
{/if}
{#if $$slots.actions}
<div class="h-px" />
<div class="py-2">
<div class="py-px">
<div class="h-9" />
</div>
</div>
{/if}
</div>
{/if}
</div>

{#if $$slots.pills || $$slots.actions}
<div class="absolute inset-x-px bottom-0">
{#if $$slots.pills}
<slot name="pills" />
{/if}
{#if $$slots.actions}
<slot name="actions" />
{/if}
</div>
{/if}
{#if error}
<p transition:slide|local class="mt-2 text-sm text-danger" id="{name}-error">{error}</p>
{/if}
</div>
{:else}
<div class={$$props.class} style={$$props.style}>
<slot name="label" />
<div class="mt-1 opacity-75={disabled}">
<textarea
bind:this={textarea}
rows="4"
{autocapitalize}
{autocomplete}
{name}
{readonly}
{disabled}
id={name}
class="block w-full outline-none focus:outline-none sm:text-sm rounded-md placeholder-secondary-content placeholder-opacity-80"
class:border-danger={error}
class:text-danger={error}
class:placeholder-red-300={error}
class:focus:border-red-500={error}
class:focus:border-primary={!error}
class:border-border={!error}
class:bg-surface={!disabled}
class:bg-default={disabled}
{placeholder}
bind:value
/>
</div>
{#if error}
<p transition:slide|local class="mt-2 text-sm text-danger" id="{name}-error">{error}</p>
{/if}
</div>
{#if error}
<p transition:slide|local class="mt-2 text-sm text-danger" id="{name}-error">{error}</p>
{/if}
</div>
{/if}
44 changes: 44 additions & 0 deletions src/lib/components/textarea/Title.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script lang="ts">
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());
export let name: string;
export let placeholder: string | undefined = undefined;
export let value: string | undefined = undefined;
export let autocomplete: 'on' | 'off' | undefined = undefined;
export let autocapitalize: 'off' | 'none' | 'sentences' | 'words' | 'characters' = 'off';
export let readonly: true | undefined = undefined;
export let tabindex: string | undefined = undefined;
export let disabled = false;
const defaultClass =
'block w-full bg-surface border-0 pt-2.5 text-lg font-medium placeholder-secondary-content placeholder-opacity-80 focus:ring-0';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<div>
<slot />
</div>

<label for={name} class="sr-only">Title</label>
<input
type="text"
{name}
id={name}
{placeholder}
{autocapitalize}
{autocomplete}
{readonly}
{tabindex}
{disabled}
bind:value
class={finalClass}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
/>
9 changes: 9 additions & 0 deletions src/lib/components/textarea/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import OriginalTextArea from './TextArea.svelte';
import Label from './Label.svelte';
import Title from './Title.svelte';
import Pills from './Pills.svelte';
import Actions from './Actions.svelte';

const TextArea = OriginalTextArea as TextAreaStatic;
TextArea.Label = Label;
TextArea.Title = Title;
TextArea.Pills = Pills;
TextArea.Actions = Actions;

export default TextArea;

export interface TextAreaStatic {
new (...args: ConstructorParameters<typeof OriginalTextArea>): OriginalTextArea;
Label: typeof Label;
Title: typeof Title;
Pills: typeof Pills;
Actions: typeof Actions;
}
88 changes: 86 additions & 2 deletions src/routes/text-area/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
<script lang="ts">
import { Card, Col, TextArea } from '../../lib';
import { example, props, slots, labelSlots } from './examples';
import { Card, Col, TextArea, Dropdown, Button } from '../../lib';
import { example, kitchenExample, props, slots, labelSlots } from './examples';
import { PropsTable, SlotsTable, CodeBlock, BetaComponent } from '../../docs';
import { account, calendar } from '$lib/icons';
let value: string | undefined;
let error: string | undefined = "You're doing it wrong!";
let dropdown1 = false;
let dropdown2 = false;
let dropdown3 = false;
function toggleDropdown1() {
dropdown1 = !dropdown1;
}
function toggleDropdown2() {
dropdown2 = !dropdown2;
}
function toggleDropdown3() {
dropdown3 = !dropdown3;
}
$: if (value && value.length > 0) {
error = undefined;
} else {
Expand Down Expand Up @@ -36,6 +53,73 @@
</Card>
</Col>

<Col class="col-24 md:col-12">
<Card bordered={false}>
<Card.Content slot="content" class="p-4">
<TextArea name="input-4" placeholder="Description">
<TextArea.Label slot="label">Label</TextArea.Label>
<TextArea.Title slot="title" name="title" placeholder="Title" />
<TextArea.Pills slot="pills">
<Dropdown bind:visible={dropdown1}>
<Button
slot="trigger"
type="default"
shape="pill"
size="xs"
class="shadow-none"
on:click={toggleDropdown1}
>
<Button.Leading slot="leading" data={account} />
Assign</Button
>
<Dropdown.Items slot="items">
<Dropdown.Items.Item on:click={toggleDropdown1} label="Person One">
<Dropdown.Items.Item.Icon slot="icon" data={account} />
</Dropdown.Items.Item>
<Dropdown.Items.Item on:click={toggleDropdown1} label="Person Two">
<Dropdown.Items.Item.Icon slot="icon" data={account} />
</Dropdown.Items.Item>
<Dropdown.Items.Item on:click={toggleDropdown1} label="Person Three">
<Dropdown.Items.Item.Icon slot="icon" data={account} />
</Dropdown.Items.Item>
</Dropdown.Items>
</Dropdown>

<Dropdown bind:visible={dropdown2}>
<Button
slot="trigger"
type="default"
shape="pill"
size="xs"
class="shadow-none"
on:click={toggleDropdown2}
>
<Button.Leading slot="leading" data={calendar} />
Due Date</Button
>
<Dropdown.Items slot="items">
<Dropdown.Items.Item on:click={toggleDropdown1} label="Today">
<Dropdown.Items.Item.Icon slot="icon" data={calendar} />
</Dropdown.Items.Item>
<Dropdown.Items.Item on:click={toggleDropdown1} label="Tomorrow">
<Dropdown.Items.Item.Icon slot="icon" data={calendar} />
</Dropdown.Items.Item>
</Dropdown.Items>
</Dropdown>
</TextArea.Pills>
<TextArea.Actions slot="actions">
<div />
<Button type="primary">Submit</Button>
</TextArea.Actions>
</TextArea>

<br />

<CodeBlock language="svelte" code={kitchenExample} />
</Card.Content>
</Card>
</Col>

<Col class="col-24">
<PropsTable component="TextArea" {props} />
</Col>
Expand Down
Loading

0 comments on commit 9c8d240

Please sign in to comment.