/*
 * MyTh Ahmed Faiz Copyright © 2016-2024 All rights reserved.
 * Email: mythpe@gmail.com
 * Mobile: +966590470092
 * Website: https://www.4myth.com
 * Github: https://github.com/mythpe
 */

import { AxiosRequestConfig } from 'axios'
import {
  QAvatarProps,
  QAvatarSlots,
  QBtnProps,
  QBtnSlots,
  QCheckboxProps,
  QDateProps,
  QEditorProps,
  QEditorSlots,
  QFieldSlots,
  QFileProps,
  QFileSlots,
  QImgProps,
  QInputProps,
  QInputSlots,
  QOptionGroupProps,
  QOptionGroupSlots,
  QRadioProps,
  QSelectProps,
  QTimeProps,
  QToggleProps,
  QUploaderProps,
  QUploaderSlots
} from 'quasar'
import { FieldContext, FieldOptions, FormContext, FormOptions, FormState } from 'vee-validate'
import { MaybeRefOrGetter, UnwrapNestedRefs, VNode, ComputedRef, Ref, ShallowRef, WritableComputedRef } from 'vue'
import { MColProps, ViewModeProps } from '../grid/models'
import { EditorConfig } from 'ckeditor5'
import { HelpersStubSchema } from '../../types'

export type BaseInputFieldPropContext = FieldContext<any>;
export type BaseInputFieldProps = {
  /**
   * Context of field input.
   */
  field: UnwrapNestedRefs<BaseInputFieldPropContext>;
  readonly label?: string | undefined;
}

export type InputRulesContext = string | string[] | Record<string, any> | undefined;
export type InputErrorsContext = string[];
export type InputFormErrorsContext = Record<string, InputErrorsContext> | undefined;

export type InputHelpProps = {
  /**
   * Information text with Icon.
   */
  readonly help?: string;
}
export type InputHelpSlots = {
  /**
   * VNode bottom of input & before 'bottom-input slot'.
   */
  help: () => VNode[];
}

export type BaseInputFormProps = {
  /**
   * Input name.
   */
  readonly name: string;
  /**
   * Input model value.
   * can be used instead of initialValue.
   */
  modelValue?: any;
  /**
   * Input Label.
   */
  readonly label?: string | undefined;
  /**
   * Caption under label.
   */
  readonly caption?: string | undefined;
  /**
   * Input Hint.
   */
  readonly hint?: string | undefined;
  /**
   * Input Placeholder.
   */
  readonly placeholder?: string | undefined;
  /**
   * Input Required validation.
   */
  readonly required?: boolean;
  /**
   * Input Validation Rules.
   */
  readonly rules?: InputRulesContext;
  /**
   * Input Error Messages.
   */
  // errors?: InputErrorsContext;
  /**
   * Form Error Messages.
   */
  // formErrors?: InputFormErrorsContext;
  /**
   * Input autocomplete attribute.
   * if true, will set from input name.
   * if false, will set 'off'.
   * else, will set the attribute value.
   * Default: undefined.
   */
  readonly autocomplete?: boolean | string | undefined;
  /**
   * Inputs Top Label.
   */
  readonly topLabel?: boolean;
  /**
   * Mobile Rule.
   */
  readonly mobile?: boolean | string | number | undefined;
  /**
   * Email Rule.
   */
  readonly email?: boolean;
  /**
   * Number Rule.
   */
  readonly float?: boolean;
  /**
   * vee-validate Field Options.
   */
  readonly fieldOptions?: Partial<FieldOptions> | MaybeRefOrGetter<Partial<FieldOptions>>;
}
export type BaseInputsProps = ViewModeProps & InputHelpProps & Omit<MColProps, 'name'> & BaseInputFormProps;

export type BaseInputsSlots = InputHelpSlots & {
  /**
   * VNode top of input & top of 'top label slot'.
   */
  'top-input': () => VNode[];
  /**
   * The label top on input
   */
  'top-label': () => VNode[];
  /**
   * VNode top of input & after top label.
   */
  caption: () => VNode[];
  /**
   * Field main content
   */
  default: () => VNode[];
  /**
   * VNode bottom of input.
   */
  'bottom-input': () => VNode[];
}

export declare type GenericFormValues = Record<any, any>;

export interface MBtnProps extends QBtnProps {
  color?: string | undefined
  noCaps?: boolean | undefined
}

export interface MBtnSlots extends QBtnSlots {
  /**
   * Use for custom content, instead of relying on 'icon' and 'label' props
   */
  default: () => VNode[];
  /**
   * Override the default QSpinner when in 'loading' state
   */
  loading: () => VNode[];
}

export interface MInputProps extends Omit<QInputProps, 'rules' | 'name' | 'modelValue' | 'label' | 'hint'>, BaseInputsProps {
  //
}

export type MPasswordProps = MInputProps & {
  /**
   * icon prepend it to password input.
   */
  icon?: boolean | undefined;
  /**
   * toggle password append icon.
   */
  noToggle?: boolean | undefined;
}

export type MInputSlots = QInputSlots & QFieldSlots & BaseInputsSlots

export type MFieldProps = Omit<MInputProps, 'viewMode' | 'viewModeValue' | 'fieldOptions'>
export type MFieldSlots = MInputSlots

export type MHiddenInputSlots = object
export type MHiddenInputProps = Pick<BaseInputFormProps, 'rules' | 'required'> & {
  /**
   * Input name.
   */
  name: string;
  /**
   * Input model value.
   */
  modelValue?: any;
}

export type MHiddenProps = MHiddenInputProps & Pick<ViewModeProps, 'viewMode'> & Omit<MColProps, 'name'>
export type MHiddenSlots = {
  /**
   * Field main content
   */
  default: () => VNode[];
}

export type MOptionsOptionContext = Omit<QToggleProps, 'modelValue'> & Omit<QRadioProps, 'modelValue'> & Omit<QCheckboxProps, 'modelValue'> & {
  /**
   * Label to display along the component
   */
  label: string;
  /**
   * Value of the option that will be used by the component model
   */
  value: any;
  /**
   * If true, the option will be disabled
   */
  disable?: boolean;
  /**
   * Any other props from QToggle, QCheckbox, or QRadio
   */
}
export type MOptionsProps = Omit<QOptionGroupProps, 'name' | 'modelValue' | 'options'> & Omit<BaseInputsProps, 'autocomplete', 'modelValue'> & {
  modelValue?: any;
  /**
   * Array of objects with value, label, and disable (optional) props. The binary components will be created according to this array; Props from QToggle, QCheckbox or QRadio can also be added as key/value pairs to control the components singularly
   */
  options?: MOptionsOptionContext[];
  /**
   * Get options by function. any send the current value to this function to get options.
   */
  service?: ((value: any) => Promise<void>) | undefined;
  /**
   * Service loading.
   */
  loading?: boolean | undefined;
  /**
   * Set content to be full width.
   */
  fullWidth?: boolean;
  /**
   * Set width of content to be equals.
   * Default is: 33.33333333%
   */
  fitWidth?: boolean;
}
export type MOptionsSlots = QOptionGroupSlots & QFieldSlots & BaseInputsSlots

export type MFileProps =
  Omit<QFileProps, 'modelValue' | 'rules' | 'name' | 'label' | 'hint'>
  & Omit<BaseInputsProps, 'autocomplete'>
  & {
  accept?: string | undefined;
  images?: boolean;
  svg?: boolean;
  video?: boolean;
  pdf?: boolean;
  excel?: boolean;
}

export type MFileSlots = QFileSlots & BaseInputsSlots

export type MPickerProps =
  Omit<MInputProps, 'modelValue' | 'type'>
  & Omit<QDateProps, 'modelValue' | 'options'>
  & Omit<QTimeProps, 'modelValue'>
  & {
  /**
   * Initial value of the picker.
   * Default is: null.
   */
  modelValue?: any;
  /**
   * Type of picker. 'date' or 'time'.
   * Default is: 'date'.
   */
  type?: 'date' | 'time';
  /**
   *  QBtn props for append button.
   */
  btnProps?: QBtnProps;
  /**
   * Value of separator for range picker.
   * Default is: ' - '.
   */
  rangeSeparator?: string;
}

export type MPickerSlots = MInputSlots

export type MDateProps = Omit<MPickerProps, 'type'>
export type MDateSlots = MPickerSlots

export type MTimeProps = Omit<MPickerProps, 'type'>
export type MTimeSlots = MPickerSlots
export type MSelectModelEmit = { value: any | null; model: object | null }
export type MSelectProps = Omit<QSelectProps, 'rules' | 'name' | 'modelValue' | 'label' | 'hint' | 'autocomplete'> & BaseInputsProps & {
  /**
   * Input search functionality. useInput prop for this feature.
   */
  search?: string | null | undefined;
  /**
   * Minimum characters to start searching. Default is 1.
   */
  searchLength?: string | number;
  /**
   * hide the default empty list message.
   */
  hideEmptyList?: boolean | undefined;
  /**
   * Disable filter functionality.
   */
  noFilter?: boolean | undefined;
  /**
   * Set mode of component to axios of filter & search.
   * if set to true, component will fetch data from api and don't do filter functionality.
   */
  axiosMode?: boolean | undefined;
  /**
   * Fetch Data on mounted
   */
  // iniData?: boolean;
}
export type MSelectSlots = QInputSlots & QFieldSlots & BaseInputsSlots
type ParamsReq = Record<string, any>;
export type MAxiosProps = Omit<MSelectProps, 'options' | 'axiosMode'> & {
  /**
   * Request method. Default is GET.
   */
  service: ((config?: AxiosRequestConfig) => Promise<any>) | string;
  /**
   * Send request as guest request. If false, send request as authenticated user. Default is true.
   */
  guest?: boolean | MaybeRefOrGetter<boolean>;
  /**
   * Request params.
   */
  params?: Ref<ParamsReq> | ShallowRef<ParamsReq> | WritableComputedRef<ParamsReq> | ComputedRef<ParamsReq> | (() => ParamsReq);
  /**
   * Request relations.
   */
  requestWith?: MaybeRefOrGetter<string> | undefined;
  /**
   * Component items.
   */
  items?: any[];
  /**
   *  The name of the attribute to be used as a label
   */
  attributeName?: string;
  /**
   * Do fetch asynchronous
   */
  lazy?: boolean;
  /**
   * emit model as Object value.
   * @param value
   */
  // 'on:model': (value: MSelectModelEmit) => void;
}
export type MAxiosSlots = MSelectSlots
export type BaseCheckboxProps = Omit<BaseInputsProps, 'topLabel'> & {
  /**
   * Input row props.
   */
  rowProps?: Record<string, any>;
  /**
   * Input column props.
   */
  colProps?: Record<string, any>;
}
export type MCheckboxProps = Omit<QCheckboxProps, 'name' | 'modelValue' | 'label'> & BaseCheckboxProps
export type MCheckboxSlots = Omit<BaseInputsSlots, 'top-label'> & {
  /**
   * VNode before field main content.
   */
  before: () => VNode[];
  /**
   * VNode after field main content.
   */
  after: () => VNode[];
}

export type MRadioProps = Omit<QRadioProps, 'name' | 'modelValue' | 'label'> & BaseCheckboxProps
export type MRadioSlots = MCheckboxSlots

export type MToggleProps =
  Omit<BaseInputsProps, 'placeholder' | 'topLabel' | 'autocomplete'>
  & Omit<QToggleProps, 'modelValue' | 'label' | 'name'>
  & {
  /**
   * Customize the label when the toggle is true.
   * Default is: Yes.
   */
  activeLabel?: string;
  /**
   * Customize the label when the toggle is false.
   * Default is: No.
   */
  inactiveLabel?: string;
  /**
   * Set labels of toggle to status, Active & Inactive.
   */
  status?: boolean;
  /**
   * Input row props.
   */
  rowProps?: Record<string, any>;
  /**
   * Input column props.
   */
  colProps?: Record<string, any>;
}
export type MToggleSlots = MCheckboxSlots & Pick<BaseInputsProps, 'topLabel'>;

export interface MFormProps {
  /**
   * Form HTML element attributes.
   */
  formProps?: Record<string, any>;
  /**
   * Default options of useForm.
   */
  opts?: FormOptions<Record<string, any>>;
  /**
   * The target to which the page will be scrolled.
   * Default is: Window.
   */
  target?: HTMLElement | string | undefined;
  /**
   * Emit values instead controlled values.
   * Default is: false.
   */
  emitValues?: boolean;
  /**
   * Watch to reset form values.
   */
  readonly state?: MaybeRefOrGetter<Partial<FormState<Record<string, any>>>>;
  /**
   * Watch to reset form values.
   */
  readonly form?: MaybeRefOrGetter<Record<string, any>>;
  /**
   * Watch to set form values.
   */
  readonly values?: MaybeRefOrGetter<Record<string, any>>;
  /**
   * Watch to set form errors.
   */
  readonly errors?: MaybeRefOrGetter<Record<string, string | string[]>>;
  /**
   * Apply padding to form.
   */
  readonly padding?: boolean;
}

export type MFormScope = FormContext<Record<string, any>>;

export interface MFormSlots {
  default: (scope: MFormScope) => VNode[];
}

export type MAvatarViewerModelValue = File | null | undefined;

export type MAvatarViewerProps = QAvatarProps & MColProps & {
  /**
   * Comma separated list of unique file type specifiers. Maps to 'accept' attribute of native input type=file element
   */
  accept?: string;
  /**
   * Add accept file type.
   */
  images?: boolean;
  /**
   * Add accept svg type.
   */
  svg?: boolean;
  /**
   * Add accept video type.
   */
  video?: boolean;
  /**
   * Add accept pdf type.
   */
  pdf?: boolean;
  /**
   * Add accept excel type.
   */
  excel?: boolean;
  /**
   * Show text if no image
   */
  avatarText?: string;
  /**
   * How the image will fit into the container; Equivalent of the object-fit prop; Can be coordinated with 'position' prop
   * Default value: cover
   */
  fit?: QImgProps['fit'];
  /**
   * Can clear the input & not required
   */
  clearable?: boolean;
  /**
   * The label that will appear above the image
   */
  label?: string;
  /**
   * List of error messages.
   */
  errors?: InputErrorsContext;
  /**
   * List of form errors.
   */
  formErrors?: InputFormErrorsContext;
  /**
   * Model of the component;
   * Must be FileList or Array if using 'multiple' prop;
   * Either use this property (along with a listener for 'update:modelValue' event) OR use v-model directive
   */
  modelValue?: MAvatarViewerModelValue;
  /**
   * The name of the file for the image used and the field.
   * Example: name='avatar' { avatar: https://4myth.com, avatarBlob: Blob, avatarRemoved: !0 | !1 }
   */
  name?: string;
  /**
   * Avatar url.
   * (along with a listener for 'update:url' event) OR use v-model directive
   */
  url?: string;
  /**
   * value if user remove the image
   * (along with a listener for 'update:removed' event) OR use v-model directive
   */
  removed?: boolean;
  /**
   * Input hint.
   */
  hint?: string;
  hintProps?: Record<string, any>;

  caption?: string;
  captionProps?: Record<string, any>;
  /**
   * Help text after label.
   */
  help?: string;
  /**
   * Set input to readonly.
   */
  readonly?: boolean;
  /**
   * Loading for skeleton.
   */
  loading?: boolean;
}

export interface MAvatarViewerSlots extends QAvatarSlots {
  /**
   * Field main content
   */
  default: () => VNode[];
  hint: () => VNode[];
}

export type MUploaderMediaItem = {
  id: number;
  value: number;
  name: string;
  file_name: string;
  type: string;
  size: number;
  size_to_string: string;
  url: string;
  download_url: string;
  icon: string;
  description: string;
  attachment_type: string;
  attachment_type_id: number;
  attachment_type_id_to_string: string;
  user_id: number | null;
  user_id_to_string: string;
  order_column: number;
  [k: string]: any;
};

export type MUploaderServiceType = Pick<HelpersStubSchema, 'getUploadAttachmentsUrl' | 'updateAttachment' | 'uploadAttachments' | 'deleteAttachment'>

export interface MUploaderProps extends Omit<QUploaderProps, 'formFields' | 'headers' | 'url'>, MColProps, Pick<BaseInputsProps, 'fieldOptions'> {
  /**
   * Name fo field input, Attachments key name.
   * Default is: 'attachments'
   */
  name?: string;
  /**
   * Put component in disabled mode
   */
  disable?: boolean;
  /**
   * Put component in readonly mode
   */
  readonly?: boolean;
  /**
   * Comma separated list of unique file type specifiers. Maps to 'accept' attribute of native input type=file element
   */
  accept?: string;
  /**
   *  Support for uploading images
   */
  images?: boolean;
  /**
   * Support for uploading svg
   */
  svg?: boolean;
  /**
   * Support for uploading videos
   */
  video?: boolean;
  /**
   * Support for uploading pdf
   */
  pdf?: boolean;
  /**
   * Support for uploading excel
   */
  excel?: boolean;
  /**
   * Upload files immediately when added
   */
  autoUpload?: boolean;
  /**
   * Field name for each file upload; This goes into the following header: 'Content-Disposition: form-data; name="__HERE__"; filename="somefile.png"; If using a function then for best performance, reference it from your scope and do not define it inline
   * Default value: (file) => file.name
   * @param files The current file being processed
   * @returns Field name for the current file upload
   */
  fieldName?: string | ((files: File) => string);
  /**
   * Collection send to API
   */
  collection?: string | number | symbol;
  /**
   * Field Attachment Type
   */
  attachmentType?: any;
  /**
   * return attachments after upload;
   * Default current collection name;
   */
  returnType?: 'all' | 'current' | undefined;
  /**
   * Object with additional fields definitions (used by Form to be uploaded);
   */
  formFields?: Record<string, any>;
  /**
   * Extra headers
   */
  headers?: Record<string, any>;
  /**
   * Label for the uploader
   */
  label?: string | null | undefined;
  /**
   * The Attachments list.
   */
  modelValue?: MUploaderMediaItem[];
  /**
   *  Hide delete media items from uploader, no delete media For API
   */
  hideDeleteMedia?: boolean;
  /**
   *  Show update button of media.
   */
  updateBtn?: boolean;
  /**
   * User APi service for upload & delete
   */
  service: string | MUploaderServiceType;
  /**
   * The ID of model will use in attachments
   */
  modelId?: string | number | undefined;
  uploading?: boolean | undefined;
  defaultFileIcon?: string | undefined;
  deleteMediaIcon?: string | undefined;
  uploadFilesIcon?: string | undefined;
  pickFilesIcon?: string | undefined;
  removeUploadedIcon?: string | undefined;
  removeQueuedIcon?: string | undefined;
  abortUploadIcon?: string | undefined;
  downloadFileIcon?: string | undefined;
  errorsIcon?: string | undefined;
  iconsSize?: string | undefined;
  displayMode?: 'list' | 'card' | undefined;
  shadow?: string | undefined;
  /**
   * Media Item Label Field.
   * Default is: name.
   */
  mediaLabel?: string | undefined;
}

export interface MUploaderSlots extends QUploaderSlots {
  /**
   * Field main content
   */
  default: () => VNode[];
  /**
   * list of item will be display
   */
  // list: (scope: { item: MUploaderMediaItem, index: number }) => VNode[];
  /**
   * list of item will be display
   */
  'item-list': (scope: { item: MUploaderMediaItem, index: number }) => VNode[];
}

export type MUploaderXhrInfo = { files: readonly any[]; xhr: any; }

export type MEditorProps = Omit<QEditorProps, 'modelValue' | 'placeholder'> & BaseInputsProps
export type MEditorSlots = QEditorSlots & BaseInputsSlots

export type MCkeditorProps = Omit<BaseInputsProps, 'hint' | 'topLabel' | 'placeholder' | 'autocomplete'> & {
  /**
   * Editor language.
   * Default value: ar.
   */
  lang: 'ar' | 'en';
  /**
   * Specifies the configuration of the editor.
   * https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig-EditorConfig.html
   */
  config?: ((config: EditorConfig) => EditorConfig) | undefined;
  /**
   * By default, the editor component creates a <div> container which is used as an element passed to the editor (for example, ClassicEditor#element).
   * The element can be configured, so for example to create a <textarea>, use the following directive:
   * tag-name="textarea"
   * Default value: div.
   */
  tagName?: string;
  /**
   * This directive controls the isReadOnly property of the editor.
   * Default value: false.
   */
  disabled?: boolean;
  /**
   * Allows disabling the two-way data binding mechanism.
   * Default value: false.
   */
  disableTwoWayDataBinding?: boolean;
}
export type MCkeditorSlots = BaseInputsSlots

export interface MOtpProps extends Omit<QInputProps, 'modelValue'> {
  modelValue?: string | number;
  inputLength?: string | number;
  numeric?: boolean;
  time?: string | number;
  hideTime?: boolean;
  hideSendAgain?: boolean;
  topLabel?: string | undefined;
  topLabelProps?: any | undefined;
  errors?: string[];
}

export interface MOtpSlots extends QInputSlots {
  default: () => VNode[];
  'before-all': () => VNode[];
  'after-all': () => VNode[];
  'after-input': () => VNode[];
}

export type MInputFieldControlProps = any;
export type MInputFieldControlSlots = {
  default: () => VNode[];
}

export type MInputLabelProps = BaseInputFieldProps;
export type MInputLabelSlots = {
  default: () => VNode[];
}

export type SignaturePadWaterMark = {
  /**
   * Watermark text. default is: ''
   * e.g. "Your Name", "Your Company", "Date"
   */
  text: string;
  /**
   * Mark font. Default is: '20px sans-serif'
   */
  font: string;
  /**
   * Fill Text and Stroke Text,  'all' | 'stroke' | 'fill'.
   * Default is: 'fill'.
   */
  style: 'all' | 'stroke' | 'fill';
  /**
   *  Fill color.
   *  Default is: '#333'
   */
  fillStyle: CSSStyleDeclaration['color'];
  /**
   * Stroke Color.
   * Default is: '#333'.
   */
  strokeStyle: CSSStyleDeclaration['color'];
  /**
   * Fill positionX.
   * Default is: 20
   */
  x: number;
  /**
   * fill positionY.
   * Default is: 20
   */
  y: number;
  /**
   * Stroke positionX.
   * Default is: 40
   */
  sx: number;
  /**
   * Stroke positionY.
   * Default is: 40
   */
  sy: number;
}
export type MSignaturePadProps = Omit<MColProps, 'name'> & Pick<BaseInputsProps, 'fieldOptions'> & {
  /**
   * Base64 data of the signature.
   */
  modelValue?: string | null | undefined;
  /**
   * Name of field.
   * Default is: signature.
   */
  name?: string;
  /**
   * Signature pen color.
   * Default is: 'rgb(0, 0, 0)'
   */
  color?: CSSStyleDeclaration['color'];
  /**
   * Signature pad background color.
   * Default is: 'rgb(255,255,255)'
   */
  bg?: CSSStyleDeclaration['backgroundColor'];
  /**
   * Parent container width.
   * Need units like 100px or 100%
   * Default is: '100%'
   */
  width?: string;
  /**
   * Parent container height.
   * Need units like 100px or 100%
   * Default is: '200px'
   */
  height?: string;
  /**
   * Canvas is cleared on window resize.
   * Default is: false.
   */
  clearOnResize?: boolean;
  /**
   * Disable Signature pad.
   * Default is: false.
   */
  disabled?: boolean;
  /**
   * Add Required validation.
   * Default is: false.
   */
  required?: boolean;
  /**
   * Signature pad label.
   * Default is: undefined.
   */
  label?: string | undefined | null;
  /**
   * Props of signature pad label.
   * Default is: undefined.
   */
  labelProps?: Record<string, any>;
  /**
   * Signature pad center label.
   * Default is: false.
   */
  center?: boolean | undefined;
  /**
   * Default value for signature url.
   * Default is: undefined.
   */
  url?: string | undefined;
  /**
   * Hide control buttons.
   * Default is: false.
   */
  noBtn?: boolean;
  /**
   * Size of signature pad label.
   * Default is: false.
   */
  large?: boolean;
  /**
   * Signature pad watermark text.
   * Default is: undefined.
   */
  waterMark?: SignaturePadWaterMark;
}
export type MSignaturePadMethods = {
  /**
   * Save image as PNG/JPEG/SVG
   * @param type
   */
  save: (type: 'image/jpeg' | 'image/svg+xml') => string;
  /**
   * Clear canvas
   */
  clear: () => void;
  /**
   * Returns true if canvas is empty.
   * otherwise returns false
   */
  isEmpty: () => boolean;
  /**
   * Remove the last step of pen.
   */
  undo: () => void;
  /**
   * Reset Pad state.
   */
  reset: () => void;
  /**
   * Add Text Watermark.
   */
  addWaterMark: (opt: SignaturePadWaterMark) => void;
  /**
   * Draws signature image from data URL.
   */
  fromDataURL: (url: string) => void;
}
export type MSignaturePadSlots = {
  'top-input': () => VNode[];
  default: () => VNode[];
  pad: (scope: {
    width: MSignaturePadProps['width'];
    height: MSignaturePadProps['height'];
    reset: MSignaturePadMethods['reset'];
    save: MSignaturePadMethods['save'];
    clear: MSignaturePadMethods['clear'];
    undo: MSignaturePadMethods['undo']
  }) => VNode[];
  'bottom-input': () => VNode[];
}

export {}
