Skip to content

Commit

Permalink
fix: #i390 add clearable to FileUpload
Browse files Browse the repository at this point in the history
  • Loading branch information
shinokada committed Oct 30, 2024
1 parent 9055d8f commit f35c890
Show file tree
Hide file tree
Showing 21 changed files with 81 additions and 70 deletions.
1 change: 1 addition & 0 deletions src/lib/accordion/AccordionItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
let inactiveCls = twMerge(inactiveClass, classInactive);
// make a custom transition function that returns the desired transition
/* eslint-disable @typescript-eslint/no-explicit-any */
const multiple = (node: HTMLElement, params: any) => {
switch (transitionType) {
case 'blur':
Expand Down
1 change: 1 addition & 0 deletions src/lib/badge/Badge.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import type { HTMLAttributes } from 'svelte/elements';
import { fade, type TransitionConfig } from 'svelte/transition';
/* eslint-disable @typescript-eslint/no-explicit-any */
type TransitionFunc = (node: HTMLElement, params: any) => TransitionConfig;
const dispatcher = createEventDispatcher();
Expand Down
3 changes: 2 additions & 1 deletion src/lib/banner/Banner.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import CloseButton from '../utils/CloseButton.svelte';
import type { HTMLAttributes } from 'svelte/elements';
import { fade, type TransitionConfig } from 'svelte/transition';
import type { ParamsType } from '../types'
type TransitionFunc = (node: HTMLElement, params: any) => TransitionConfig;
type TransitionFunc = (node: HTMLElement, params: ParamsType) => TransitionConfig;
interface $$Props extends HTMLAttributes<HTMLDivElement> {
position?: 'static' | 'fixed' | 'absolute' | 'relative' | 'sticky';
Expand Down
6 changes: 4 additions & 2 deletions src/lib/carousel/Carousel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
import Indicators from './Indicators.svelte';
import Slide from './Slide.svelte';
import { canChangeSlide } from './CarouselSlide';
import type { ParamsType } from '../types'
type TransitionFunc = (node: HTMLElement, params: any) => TransitionConfig;
type TransitionFunc = (node: HTMLElement, params: ParamsType) => TransitionConfig;
const SLIDE_DURATION_RATIO = 0.25; // TODO: Expose one day?
export let images: HTMLImgAttributes[];
Expand Down Expand Up @@ -78,6 +79,7 @@
carouselDiv = node; // used by DragStart
// loop timer
/* eslint-disable @typescript-eslint/no-explicit-any */
let intervalId: any;
if (duration > 0) intervalId = setInterval(nextSlide, duration);
Expand Down Expand Up @@ -116,7 +118,7 @@
const onDragStart = (evt: MouseEvent | TouchEvent) => {
if (disableSwipe) return;
/* eslint-disable @typescript-eslint/no-unused-expressions */
touchEvent = evt;
evt.cancelable && evt.preventDefault();
const start = getPositionFromEvent(evt);
Expand Down
3 changes: 2 additions & 1 deletion src/lib/carousel/Slide.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import type { State } from './Carousel.svelte';
import type { ParamsType } from '../types'
const state = getContext<Writable<State>>('state');
type TransitionFunc = (node: HTMLElement, params: any) => TransitionConfig;
type TransitionFunc = (node: HTMLElement, params: ParamsType) => TransitionConfig;
export let image: HTMLImgAttributes;
export let transition: TransitionFunc | null = null; // Optional transition function, overrides default slide transition
Expand Down
1 change: 0 additions & 1 deletion src/lib/carousel/Thumbnails.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
<div class={twMerge('flex flex-row justify-center bg-gray-100 w-full', $$props.class)}>
{#each images as image, idx}
{@const selected = index === idx}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<button on:click={() => btnClick(idx)} aria-label={ariaLabel}>
<slot {Thumbnail} {image} {selected} {imgClass}>
<Thumbnail {...image} {selected} class={imgClass} />
Expand Down
2 changes: 1 addition & 1 deletion src/lib/drawer/Drawer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
export let divClass: $$Props['divClass'] = 'overflow-y-auto z-50 p-4 bg-white dark:bg-gray-800';
export let transitionParams: $$Props['transitionParams'] = {};
export let transitionType: $$Props['transitionType'] = 'fly';
/* eslint-disable @typescript-eslint/no-explicit-any */
function multiple(node: HTMLElement, params: any) {
switch (transitionType) {
case 'slide':
Expand Down
39 changes: 36 additions & 3 deletions src/lib/forms/Fileupload.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,52 @@
import type { ComponentProps } from 'svelte';
import { twMerge } from 'tailwind-merge';
import Input from './Input.svelte';
import { CloseButton } from "$lib";
interface $$Props extends ComponentProps<Input> {
files?: FileList | undefined;
inputClass?: string;
clearable?: boolean;
size?: 'sm' | 'md' | 'lg';
}
export let files: $$Props['files'] = undefined;
export let inputClass: $$Props['inputClass'] = 'border !p-0 dark:text-gray-400';
export let clearable: $$Props['clearable'] = false;
export let size: $$Props['size'] = 'md';
const base: string= "block w-full disabled:cursor-not-allowed disabled:opacity-50 rtl:text-right p-2.5 focus:border-primary-500 focus:ring-primary-500 dark:focus:border-primary-500 dark:focus:ring-primary-500 bg-gray-50 text-gray-900 dark:bg-gray-700 dark:placeholder-gray-400 border-gray-300 dark:border-gray-600 text-sm rounded-lg border !p-0 dark:text-gray-400";
const wrapper: string = "relative w-full";
const right: string = "flex absolute inset-y-0 items-center text-gray-500 dark:text-gray-400 end-0 p-2.5"
const sizes: Record<string, string> = {
sm: "text-xs ps-9 pe-9 p-2",
md: "text-sm ps-10 pe-10 p-2.5",
lg: "sm:text-base ps-11 pe-11 p-3"
}
let fileInputRef: HTMLInputElement | undefined;
const clearAll = () => {
if (fileInputRef) {
fileInputRef.value = "";
files = undefined;
}
};
$: hasFiles = files && files.length > 0;
let inputCls = twMerge(base, sizes[size ?? 'md'], inputClass);
</script>

<Input {...$$restProps} class={twMerge(inputClass, $$props.class)} let:props>
<input type="file" on:change on:keyup on:keydown on:keypress on:focus on:blur on:click on:mouseover on:mouseenter on:mouseleave on:paste bind:files {...props} />
</Input>
{#if clearable}
<div class={wrapper}>
<input type="file" on:change on:keyup on:keydown on:keypress on:focus on:blur on:click on:mouseover on:mouseenter on:mouseleave on:paste bind:files {...$$restProps} class={inputCls} bind:this={fileInputRef} />
{#if hasFiles}
<CloseButton on:click={clearAll} class={right} />
{/if}
</div>
{:else}
<Input {...$$restProps} class={twMerge(inputClass, $$props.class)} let:props>
<input type="file" on:change on:keyup on:keydown on:keypress on:focus on:blur on:click on:mouseover on:mouseenter on:mouseleave on:paste bind:files {...props} />
</Input>
{/if}

<!--
@component
Expand Down
2 changes: 1 addition & 1 deletion src/lib/forms/FloatingLabelInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
type?: InputType;
size?: 'small' | 'default';
color?: 'base' | 'green' | 'red';
value?: any;
value?: string | number | readonly string[] | undefined;
classDiv?: string;
classInput?: string;
classLabel?: string;
Expand Down
1 change: 0 additions & 1 deletion src/lib/forms/Label.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
</script>

{#if show}
<!-- svelte-ignore a11y-label-has-associated-control -->
<label bind:this={node} {...$$restProps} class={labelClass}><slot /></label>
{:else}
<slot />
Expand Down
2 changes: 0 additions & 2 deletions src/lib/forms/MultiSelect.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@
<option {value} {disabled}>{name}</option>
{/each}
</select>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div on:click={() => !disabled && (show = !show)} on:focusout={() => !disabled && (show = false)} on:keydown={handleKeyDown} tabindex="0" role="listbox" class={twMerge(multiSelectClass, sizes[size], $$props.class, !disabled && "focus-within:ring-1 focus-within:border-primary-500 dark:focus-within:border-primary-500", disabled && "opacity-50 cursor-not-allowed")}>
{#if !selectItems.length}
<span class="text-gray-400">{placeholder}</span>
Expand Down Expand Up @@ -175,7 +174,6 @@
{#if show}
<div on:click|stopPropagation role="presentation" class={multiSelectDropdown}>
{#each items as item (item.name)}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div on:click={() => selectOption(item)} role="presentation" class={twMerge(itemsClass, selectItems.includes(item) && itemsSelectClass, activeItem === item && activeItemClass, disabled && "pointer-events-none", item.disabled && "opacity-50 cursor-not-allowed")}>
{item.name}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/lib/forms/Textarea.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import Wrapper from '../utils/Wrapper.svelte';
interface $$Props extends HTMLTextareaAttributes {
value?: any;
value?: string;
wrappedClass?: string;
unWrappedClass?: string;
innerWrappedClass?: string;
Expand Down
1 change: 0 additions & 1 deletion src/lib/pagination/PaginationItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
);
</script>

<!-- svelte-ignore a11y-click-events-have-key-events -->
<svelte:element this={href ? 'a' : 'button'} {href} class={defaultClass} on:blur on:change on:click on:focus on:keydown on:keypress on:keyup on:mouseenter on:mouseleave on:mouseover role={href ? 'button' : undefined}>
<slot />
</svelte:element>
Expand Down
29 changes: 17 additions & 12 deletions src/lib/steps/StepIndicator.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,27 @@
import type { HTMLAttributes } from 'svelte/elements';
import { twMerge, twJoin } from 'tailwind-merge';
type ColorType = 'primary' | 'secondary' | 'gray' | 'red' | 'yellow' | 'green' | 'indigo' | 'purple' | 'pink' | 'blue' | 'custom';
interface $$Props extends HTMLAttributes<HTMLElement> {
steps?: string[];
currentStep?: number;
steps: string[];
currentStep: number;
size?: string;
color?: 'primary' | 'secondary' | 'gray' | 'red' | 'yellow' | 'green' | 'indigo' | 'purple' | 'pink' | 'blue' | 'custom';
color?: ColorType;
glow?: boolean;
hideLabel?: boolean;
completedCustom?: string;
currentCustom?: string;
}
export let steps: $$Props['steps'] = ['Step 1', 'Step 2', 'Step 3', 'Step 4', 'Step 5'];
export let currentStep: $$Props['currentStep'] = 1;
export let size: $$Props['size'] = 'h-2.5';
export let color: $$Props['color'] = 'primary';
export let glow: $$Props['glow'] = false;
export let hideLabel: $$Props['hideLabel'] = false;
export let completedCustom: $$Props['completedCustom'] = '';
export let currentCustom: $$Props['currentCustom'] = '';
export let steps = ['Step 1', 'Step 2', 'Step 3', 'Step 4', 'Step 5'];
export let currentStep = 1;
export let size = 'h-2.5';
export let color: ColorType = 'primary';
export let glow = false;
export let hideLabel = false;
export let completedCustom = '';
export let currentCustom = '';
const completedStepColors = {
primary: 'bg-primary-500 dark:bg-primary-900',
Expand Down Expand Up @@ -48,11 +50,14 @@
blue: 'bg-blue-800 dark:bg-blue-400',
custom: currentCustom
};
// Ensure currentStep is within bounds
$: safeCurrentStep = Math.max(1, Math.min(currentStep, steps.length));
$: currentStepLabel = steps[safeCurrentStep - 1] ?? 'Unknown Step';
</script>

<div {...$$restProps} class={twMerge('space-y-2 dark:text-white', $$props.class)}>
{#if !hideLabel}
<h3 class="text-base font-semibold">{steps[currentStep - 1]}</h3>
<h3 class="text-base font-semibold">{currentStepLabel}</h3>
{/if}
<div class={twJoin('flex justify-between gap-2 w-full', size)}>
{#each steps as step, i}
Expand Down
3 changes: 3 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
import type { TransitionConfig, FadeParams, BlurParams, FlyParams, SlideParams, ScaleParams } from 'svelte/transition';

export type BlockQuoteType = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl' | '8xl' | '9xl';

Expand Down Expand Up @@ -27,6 +28,8 @@ export type FormColorType = 'blue' | 'red' | 'green' | 'purple' | 'teal' | 'yell

export type ModalPlacementType = 'top-left' | 'top-center' | 'top-right' | 'center-left' | 'center' | 'center-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';

export type ParamsType = FadeParams | BlurParams | FlyParams | SlideParams | ScaleParams;

export type PsizeType = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl' | '8xl' | '9xl';

export type PweightType = 'thin' | 'extralight' | 'light' | 'normal' | 'medium' | 'semibold' | 'bold' | 'extrabold' | 'black';
Expand Down
1 change: 1 addition & 0 deletions src/lib/utils/Popper.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
$: hoverable = trigger === 'hover';
$: dispatch('show', open);
/* eslint-disable @typescript-eslint/no-unused-expressions */
$: placement && (referenceEl = referenceEl);
let referenceEl: Element;
Expand Down
11 changes: 1 addition & 10 deletions src/lib/utils/backdrop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,10 @@ export let open = false;

const backdropClasses = 'bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40';
export let placement: string;
// const placement:
// | 'top-left'
// | 'top-center'
// | 'top-right'
// | 'center-left'
// | 'center'
// | 'center-right'
// | 'bottom-left'
// | 'bottom-center'
// | 'bottom-right'='center';

export const init = (node: HTMLElement, _open: boolean) => {
getPlacementClasses().map((c) => node.classList.add(c));
/* eslint-disable @typescript-eslint/no-unused-expressions */
_open && createBackdrop(node);

return {
Expand Down
2 changes: 1 addition & 1 deletion src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
siteName: 'Flowbite Svelte'
}}
twitter={{
creator: '@shinokada',
handle: '@shinokada',
cardType: 'summary_large_image',
title: `${title}`,
description: `${description}`,
Expand Down
37 changes: 7 additions & 30 deletions src/routes/docs/forms/file-input.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,6 @@ The file input component can be used to upload one or more files from the device
</script>
```

## File upload example

```svelte example
<script>
import { Fileupload, Label } from 'flowbite-svelte';
let value;
</script>
<Label class="space-y-2 mb-2">
<span>Upload file</span>
<Fileupload bind:value />
</Label>
<Label>File: {value}</Label>
```

## Helper text

```svelte example
Expand All @@ -51,25 +36,17 @@ The file input component can be used to upload one or more files from the device
<Helper>SVG, PNG, JPG or GIF (MAX. 800x400px).</Helper>
```

## Multiple files

When the user selected multiple files, the `value` represents the first file in the list of files they selected. The other files can be identified using the `files` property.
## Clearable and multiple files

```svelte example
<script>
import { Fileupload, Label, Listgroup, ListgroupItem } from 'flowbite-svelte';
let files; // FileList type
<script lang="ts">
import { Fileupload, Helper } from 'flowbite-svelte';
let selectedFiles: FileList | undefined;
$: fileNames = selectedFiles ? Array.from(selectedFiles).map((file) => file.name).join(", "): "No files selected";
</script>
<Label class="pb-2" for="multiple_files">Upload multiple files</Label>
<Fileupload id="multiple_files" multiple bind:files />
<Listgroup items={files} let:item class="mt-2">
{#if item}
{item.name}
{:else}
<ListgroupItem>No files</ListgroupItem>
{/if}
</Listgroup>
<Fileupload clearable bind:files={selectedFiles} multiple />
<Helper color="emerald" class="mt-2">Selected files: {fileNames}</Helper>
```

## Sizes
Expand Down
2 changes: 1 addition & 1 deletion src/routes/icons/utils/MetaTag.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
siteName: 'Flowbite Svelte Icons'
}}
twitter={{
creator: '@shinokada',
handle: '@shinokada',
cardType: 'summary_large_image',
title: `${title}`,
description: `${description}`,
Expand Down
2 changes: 1 addition & 1 deletion src/routes/utils/MetaTag.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
siteName: 'Flowbite Svelte'
}}
twitter={{
creator: '@shinokada',
handle: '@shinokada',
cardType: 'summary_large_image',
title: `${title}`,
description: `${description}`,
Expand Down

0 comments on commit f35c890

Please sign in to comment.