{"version":3,"file":"AutoSaveField.mjs","sources":["../../../../src/components/AutoSaveField/AutoSaveField.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport { debounce } from 'lodash';\nimport { useCallback, useMemo, useRef } from 'react';\nimport * as React from 'react';\n\nimport { Trans } from '@grafana/i18n';\n\nimport { useStyles2 } from '../../themes/ThemeContext';\nimport { Field, FieldProps } from '../Forms/Field';\nimport { InlineToast } from '../InlineToast/InlineToast';\n\nimport { EllipsisAnimated } from './EllipsisAnimated';\n\nconst SHOW_SUCCESS_DURATION = 2 * 1000;\n\nexport interface Props<T = string> extends Omit<FieldProps, 'children'> {\n  /** Saving request that will be triggered 600ms after changing the value */\n  onFinishChange: (inputValue: T) => Promise<void>;\n  /** Custom error message to display on saving */\n  saveErrorMessage?: string;\n  /** Input that will save its value on change  */\n  children: (onChange: (newValue: T) => void) => React.ReactElement<Record<string, unknown>>;\n}\n\n/**\n * Used for form inputs that should save its content automatically.\n *\n * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-autosavefield--docs\n */\nexport function AutoSaveField<T = string>(props: Props<T>) {\n  const {\n    invalid,\n    loading,\n    onFinishChange,\n    saveErrorMessage = 'Error saving this value',\n    error,\n    children,\n    disabled,\n    ...restProps\n  } = props;\n\n  const [fieldState, setFieldState] = React.useState({\n    isLoading: false,\n    showSuccess: false,\n    showError: invalid,\n  });\n\n  const fieldRef = useRef<HTMLDivElement>(null);\n\n  React.useEffect(() => {\n    let timeoutId: ReturnType<typeof setTimeout>;\n    if (fieldState.showSuccess) {\n      const time = fieldState.showError ? 0 : SHOW_SUCCESS_DURATION;\n      timeoutId = setTimeout(() => {\n        setFieldState({ ...fieldState, showSuccess: false });\n      }, time);\n    }\n\n    return () => {\n      window.clearTimeout(timeoutId);\n    };\n  }, [fieldState]);\n\n  const handleChange = useCallback(\n    (nextValue: T) => {\n      if (invalid) {\n        return;\n      }\n      setFieldState({ ...fieldState, isLoading: true, showSuccess: false });\n      onFinishChange(nextValue)\n        .then(() => {\n          setFieldState({\n            isLoading: false,\n            showSuccess: true,\n            showError: false,\n          });\n        })\n        .catch(() => {\n          setFieldState({\n            ...fieldState,\n            isLoading: false,\n            showError: true,\n          });\n        });\n    },\n    [invalid, fieldState, onFinishChange]\n  );\n\n  const lodashDebounce = useMemo(() => debounce(handleChange, 600, { leading: false }), [handleChange]);\n  //We never want to pass false to field, because it won't be deleted with deleteUndefinedProps() being false\n  const isInvalid = invalid || fieldState.showError || undefined;\n  /**\n   * use Field around input to pass the error message\n   * use InlineToast.tsx to show the save message\n   */\n  const styles = useStyles2(getStyles);\n\n  return (\n    <>\n      <Field\n        {...restProps}\n        loading={loading || undefined}\n        invalid={isInvalid}\n        disabled={disabled}\n        error={error || (fieldState.showError && saveErrorMessage)}\n        ref={fieldRef}\n        className={styles.widthFitContent}\n      >\n        {React.cloneElement(\n          children((newValue) => {\n            lodashDebounce(newValue);\n          })\n        )}\n      </Field>\n      {fieldState.isLoading && (\n        <InlineToast referenceElement={fieldRef.current} placement=\"right\">\n          <Trans i18nKey=\"grafana-ui.auto-save-field.saving\">\n            Saving <EllipsisAnimated />\n          </Trans>\n        </InlineToast>\n      )}\n      {fieldState.showSuccess && (\n        <InlineToast suffixIcon={'check'} referenceElement={fieldRef.current} placement=\"right\">\n          <Trans i18nKey=\"grafana-ui.auto-save-field.saved\">Saved!</Trans>\n        </InlineToast>\n      )}\n    </>\n  );\n}\n\nAutoSaveField.displayName = 'AutoSaveField';\n\nconst getStyles = () => {\n  return {\n    widthFitContent: css({\n      width: 'fit-content',\n    }),\n  };\n};\n"],"names":[],"mappings":"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"}