import {animateTo} from "../../internal/animate";
import {classMap} from "lit/directives/class-map.js";
import {type CSSResultGroup, html, type HTMLTemplateResult, unsafeCSS} from 'lit';
import {defaultValue} from "../../internal/default-value";
import {FormControlController} from "../../internal/form";
import {getAnimation, setDefaultAnimation} from "../../utilities/animation-registry";
import {HasSlotController} from "../../internal/slot";
import {ifDefined} from "lit/directives/if-defined.js";
import {LocalizeController} from "../../utilities/localize";
import {property, query, state} from 'lit/decorators.js';
import {repeat} from 'lit/directives/repeat.js';
import {watch} from "../../internal/watch";
import ZincElement, {type ZincFormControl} from '../../internal/zinc-element';
import ZnDialog from "../dialog";
import type ZnButton from "../button";
import styles from './file.scss';
/**
* @summary File controls allow selecting an arbitrary number of files for uploading.
* @documentation https://zinc.style/components/drag-upload
* @status experimental
* @since 1.0
*
* @dependency zn-button
* @dependency zn-icon
* @dependency zn-dialog
*
* @slot label - The file control's label. Alternatively, you can use the `label` attribute.
* @slot help-text - Text that describes how to use the file control.
* Alternatively, you can use the `help-text` attribute.
* @slot trigger - Optional content to be used as trigger instead of the default content.
* Opening the file dialog on click and as well as drag and drop will work for this content.
* Following attributes will no longer work: *label*, *droparea*, *help-text*, *size*,
* *hide-value*. Also if using the disabled attribute, the disabled styling will not be
* applied and must be taken care of yourself.
*
* @event zn-blur - Emitted when the control loses focus.
* @event zn-change - Emitted when an alteration to the control's value is committed by the user.
* @event zn-clear - Emitted when the user confirms clearing the selected file or `src`.
* @event zn-error - Emitted when multiple files are selected via drag and drop, without
* the `multiple` property being set.
* @event zn-focus - Emitted when the control gains focus.
* @event zn-input - Emitted when the control receives input.
*
* @csspart form-control - The form control that wraps the label, input, and help text.
* @csspart form-control-label - The label's wrapper.
* @csspart form-control-input - The input's wrapper.
* @csspart form-control-help-text - The help text's wrapper.
* @csspart button-wrapper - The wrapper around the button and text value.
* @csspart button - The zn-button acting as a file input.
* @csspart button__base - The zn-button's exported `base` part.
* @csspart value - The chosen files or placeholder text for the file input.
* @csspart droparea - The element wrapping the drop zone.
* @csspart droparea-background - The background of the drop zone.
* @csspart upload - The upload button shown in the droparea when no file is selected.
* @csspart preview - The image preview rendered in the droparea for previewable files.
* @csspart filename - The filename label rendered in the droparea for non-previewable files.
* @csspart clear - The clear button rendered in the droparea when a file is present.
* @csspart clear-confirm - The confirmation dialog shown before clearing the file.
* @csspart link - The current link anchor rendered when `show-link` is enabled.
* @csspart trigger - The container that wraps the trigger.
*
* @animation file.iconDrop - The animation to use for the file icon
* when a file is dropped
* @animation file.text.disappear - The disappear animation to use for the file placeholder text
* when a file is dropped
* @animation file.text.appear - The appear animation to use for the file placeholder text
* when a file is dropped
*/
export default class ZnFile extends ZincElement implements ZincFormControl {
static styles: CSSResultGroup = unsafeCSS(styles);
static dependencies = {
'zn-dialog': ZnDialog
};
private readonly formControlController = new FormControlController(this, {
assumeInteractionOn: ['zn-change'],
value: (el: ZnFile) => el.files
})
private readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
private readonly localize = new LocalizeController(this);
@state() private userIsDragging = false;
@state() private fileObjectUrl: string | null = null;
@query('.input__control') input: HTMLInputElement;
@query('.button') button: ZnButton;
@query('.droparea') dropareaWrapper: HTMLDivElement;
@query('.droparea__icon') dropareaIcon: HTMLSpanElement;
@query('.input__value') inputChosen: HTMLSpanElement;
@query('.clear-confirm') clearConfirmDialog: HTMLElement & { show: () => void; hide: () => void };
/**
* The selected files as a FileList object containing a list of File objects.
* The FileList behaves like an array, so you can get the number of selected files
* via its length property.
* [see MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#getting_information_on_selected_files)
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#getting_information_on_selected_files
*/
@property({type: Object})
set files(v: FileList | null) {
if (this.input) {
this.input.files = v;
this.updatePreview();
}
}
get files() {
return this.input?.files;
}
/** The name of the file control, submitted as a name/value pair with form data. */
@property({type: String}) name = '';
/**
* The current value of the input, submitted as a name/value pair with form data.
* Beware that the only valid value when setting a file input is an empty string!
*/
/**
* The value of the file control contains a string that represents the path of the selected file.
* If multiple files are selected, the value represents the first file in the list.
* If no file is selected, the value is an empty string.
* Beware that the only valid value when setting a file control is an empty string!
* [see MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#value)
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#value
*/
@property({type: String})
set value(v: string) {
if (this.input) {
this.input.value = v;
}
}
get value() {
return this.input?.value;
}
/** The default value of the form control. Primarily used for resetting the form control. */
@defaultValue() defaultValue: string = '';
/** The file control's size. */
@property({reflect: true}) size: 'small' | 'medium' | 'large' = 'medium';
/** The file control's label. If you need to display HTML, use the `label` slot instead. */
@property() label = '';
/** If this is set, then the only way to remove files is to click the cross next to them. */
@property({type: Boolean}) clearable = false;
/**
* The file control's help text.
* If you need to display HTML, use the `help-text` slot instead.
*/
@property({attribute: 'help-text'}) helpText = '';
/** Disables the file control. */
@property({reflect: true, type: Boolean}) disabled = false;
/** Draw the file control as a drop area */
@property({type: Boolean}) droparea = false;
/**
* Comma separated list of supported file types
* [see MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept)
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept
* @example