• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alma-oss / spirit-design-system / 27762221325

18 Jun 2026 01:17PM UTC coverage: 84.677% (+0.1%) from 84.533%
27762221325

Pull #2724

github

crishpeen
feat(codemods): introduce codemod to transfer Item to new structure #DS-2586
Pull Request #2724: refactor(web,web-react)!: compose Item content with slots #DS-2586

2575 of 3504 branches covered (73.49%)

Branch coverage included in aggregate %.

157 of 177 new or added lines in 4 files covered. (88.7%)

117 existing lines in 11 files now uncovered.

7383 of 8256 relevant lines covered (89.43%)

198.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.53
/packages/web-react/src/components/UNSTABLE_FileUpload/UNSTABLE_FileUpload.tsx
1
'use client';
2

3
import classNames from 'classnames';
173✔
4
import React, { type DragEvent, type DragEventHandler, useEffect, useState } from 'react';
173✔
5
import { PropsProvider } from '../../context';
173✔
6
import { useAriaDescribedBy, useStyleProps } from '../../hooks';
173✔
7
import { Button } from '../Button';
173✔
8
import { HelperText } from '../HelperText';
173✔
9
import { Icon } from '../Icon';
173✔
10
import { Label } from '../Label';
173✔
11
import { ValidationText, useValidationTextRole } from '../ValidationText';
173✔
12
import { type UnstableFileUploadProps } from './types';
13
import { useFileUploadState } from './useFileUploadState';
173✔
14
import { useFileUploadStyleProps } from './useFileUploadStyleProps';
173✔
15

16
const UNSTABLE_FileUpload = (props: UnstableFileUploadProps) => {
173✔
17
  const [isDragAndDropDetected, setIsDragAndDropDetected] = useState(false);
74✔
18
  const {
19
    'aria-describedby': ariaDescribedBy = '',
74✔
20
    accept,
21
    buttonText = 'Browse',
74✔
22
    children,
23
    dropZoneRef,
24
    hasValidationIcon,
25
    helperText,
26
    iconName = 'upload',
74✔
27
    id,
28
    inputRef,
29
    isCompact,
30
    isDisabled,
31
    isDragAndDropSupported: isDragAndDropSupportedProp,
32
    isLabelHidden,
33
    isMultiple,
34
    isRequired,
35
    isUploadDisabled,
36
    label,
37
    labelText,
38
    linkText,
39
    name,
40
    onFilesSelected,
41
    rootId,
42
    validationState,
43
    validationText,
44
    ...restProps
45
  } = props;
74✔
46

47
  const hasInput = name !== undefined;
74✔
48
  const isUploadInteractionDisabled = isDisabled || isUploadDisabled;
74✔
49

50
  const isDragAndDropSupported = isDragAndDropSupportedProp ?? isDragAndDropDetected;
74✔
51

52
  const { isDragging, onChange, onDragEnter, onDragLeave, onDragOver, onDrop } = useFileUploadState({
74✔
53
    onFilesSelected: hasInput ? onFilesSelected : undefined,
74✔
54
  });
55

56
  const { classProps } = useFileUploadStyleProps({
74✔
57
    hasValidationIcon,
58
    isCompact,
59
    isDisabled,
60
    isDragAndDropSupported,
61
    isDragging,
62
    isLabelHidden,
63
    isRequired,
64
    isUploadDisabled,
65
    validationState,
66
  });
67

68
  const { styleProps, props: transferProps } = useStyleProps(restProps);
74✔
69

70
  const [ariaDescribedByProp, register] = useAriaDescribedBy(ariaDescribedBy);
74✔
71
  const validationTextRole = useValidationTextRole({
74✔
72
    validationState,
73
    validationText,
74
  });
75
  const inputId = `${id}-input`;
74✔
76
  const rootDomId = rootId != null && rootId !== '' ? rootId : id;
74✔
77
  const onDisabledDropGuard = (event: DragEvent<HTMLDivElement>) => {
74✔
78
    const { dataTransfer } = event;
2✔
79

80
    if (dataTransfer) {
2!
UNCOV
81
      dataTransfer.dropEffect = 'none';
×
82
    }
83

84
    event.preventDefault();
2✔
85
    event.stopPropagation();
2✔
86
  };
87
  let onDragOverHandler: DragEventHandler<HTMLDivElement> | undefined;
88
  let onDropHandler: DragEventHandler<HTMLDivElement> | undefined;
89

90
  if (isUploadInteractionDisabled) {
74✔
91
    onDragOverHandler = onDisabledDropGuard;
10✔
92
    onDropHandler = onDisabledDropGuard;
10✔
93
  } else if (isDragAndDropSupported) {
64✔
94
    onDragOverHandler = onDragOver;
31✔
95
    onDropHandler = onDrop;
31✔
96
  }
97

98
  useEffect(() => {
74✔
99
    if (isDragAndDropSupportedProp !== undefined) {
37✔
100
      return;
1✔
101
    }
102
    setIsDragAndDropDetected('draggable' in document.createElement('span'));
36✔
103
  }, [isDragAndDropSupportedProp]);
104

105
  return (
74✔
106
    <PropsProvider
107
      value={{
108
        isDisabled,
109
        isLabelHidden,
110
        isRequired,
111
        validationState,
112
      }}
113
    >
114
      <div
115
        {...transferProps}
116
        {...styleProps}
117
        id={rootDomId}
118
        className={classNames(classProps.root, styleProps.className)}
119
      >
120
        {hasInput && (
116✔
121
          <div
122
            onDragOver={onDragOverHandler}
123
            onDragEnter={!isUploadInteractionDisabled && isDragAndDropSupported ? onDragEnter : undefined}
116✔
124
            onDragLeave={!isUploadInteractionDisabled && isDragAndDropSupported ? onDragLeave : undefined}
116✔
125
            onDrop={onDropHandler}
126
            className={classProps.input.root}
127
          >
128
            <Label htmlFor={inputId}>{label}</Label>
129
            <input
130
              {...ariaDescribedByProp}
131
              type="file"
132
              accept={accept}
133
              id={inputId}
134
              ref={inputRef}
135
              name={name}
136
              className={classProps.input.input}
137
              onChange={onChange}
138
              multiple={isMultiple}
139
              disabled={isUploadInteractionDisabled}
140
            />
141
            <div ref={dropZoneRef} className={classProps.input.dropZone.root}>
142
              {!isCompact && <Icon name={iconName} boxSize={28} aria-hidden="true" />}
84✔
143
              <div className={classProps.input.dropZone.content}>
144
                <label htmlFor={inputId} className={classProps.input.dropZone.label}>
145
                  <span className={classProps.input.link}>{linkText}</span>
146
                  &nbsp;
147
                  <span className={classProps.input.dropLabel}>{labelText}</span>
148
                </label>
149
                <HelperText
150
                  id={`${inputId}-helper-text`}
151
                  registerAria={register}
152
                  helperText={helperText}
153
                  isDisabled={isUploadInteractionDisabled}
154
                />
155
              </div>
156
              <Button aria-hidden="true" isDisabled={isUploadInteractionDisabled} elementType="div">
157
                {buttonText}
158
              </Button>
159
            </div>
160
            {validationState && (
56✔
161
              <ValidationText
162
                elementType="span"
163
                id={`${inputId}-validation-text`}
164
                {...(hasValidationIcon && { validationStateIcon: validationState })}
16✔
165
                validationText={validationText}
166
                registerAria={register}
167
                role={validationTextRole}
168
              />
169
            )}
170
          </div>
171
        )}
172
        {children}
173
      </div>
174
    </PropsProvider>
175
  );
176
};
177

178
UNSTABLE_FileUpload.spiritComponent = 'UNSTABLE_FileUpload';
173✔
179
UNSTABLE_FileUpload.displayName = 'UNSTABLE_FileUpload';
173✔
180

181
export default UNSTABLE_FileUpload;
173✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc