• 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

91.53
/packages/web-react/src/components/FileUploader/useFileUploaderStyleProps.ts
1
import classNames from 'classnames';
174✔
2
import { type CSSProperties } from 'react';
3
import { type ObjectFit } from '../../constants';
4
import { useClassNamePrefix } from '../../hooks';
174✔
5
import { type FileMetadata, type FileUploaderQueueLimitBehaviorType, type Validation } from '../../types';
6
import { FileUploaderCropCSS, IMAGE_DIMENSION } from './constants';
174✔
7

8
export interface FileUploaderStyleProps extends Validation {
9
  imageObjectFit?: (typeof ObjectFit)[keyof typeof ObjectFit];
10
  isDisabled?: boolean;
11
  isDisabledByQueueLimitBehavior?: boolean;
12
  isDragAndDropSupported?: boolean;
13
  isDragging?: boolean;
14
  isDropZoneHidden?: boolean;
15
  isLabelHidden?: boolean;
16
  meta?: FileMetadata;
17
  queueLimitBehavior?: FileUploaderQueueLimitBehaviorType;
18
}
19

20
type ImageCropCSS = {
21
  [FileUploaderCropCSS.TOP]?: string;
22
  [FileUploaderCropCSS.LEFT]?: string;
23
  [FileUploaderCropCSS.WIDTH]?: string;
24
  [FileUploaderCropCSS.HEIGHT]?: string;
25
} & CSSProperties;
26

27
type ImageObjectFit = {
28
  '--file-uploader-attachment-image-object-fit': string;
29
};
30

31
type ImageCropMeta = {
32
  x: number;
33
  y: number;
34
  cropWidth: number;
35
  cropHeight: number;
36
  originalWidth: number;
37
  originalHeight: number;
38
};
39

40
export interface FileUploaderStyleReturn {
41
  /** className props */
42
  classProps: {
43
    root: string;
44
    input: {
45
      root: string;
46
      input: string;
47
      dropLabel: string;
48
      link: string;
49
      dropZone: {
50
        root: string;
51
        label: string;
52
      };
53
    };
54
    list: string;
55
    attachment: {
56
      root: string;
57
      button: string;
58
      name: string;
59
      image: string;
60
      slot: string;
61
    };
62
    imageCropStyles?: ImageCropCSS;
63
    attachmentStyles?: ImageObjectFit;
64
  };
65
}
66

67
export const useFileUploaderStyleProps = (props?: FileUploaderStyleProps): FileUploaderStyleReturn => {
174✔
68
  const fileUploaderClass = useClassNamePrefix('FileUploader');
68✔
69
  const fileUploaderHasDragAndDropClass = 'has-drag-and-drop';
68✔
70
  const fileUploaderInputClass = `${fileUploaderClass}Input`;
68✔
71
  const fileUploaderInputDisabledClass = `${fileUploaderInputClass}--disabled`;
68✔
72
  const fileUploaderInputValidationClass = `${fileUploaderInputClass}--${props?.validationState}`;
68✔
73
  const fileUploaderInputDraggingClass = 'is-dragging';
68✔
74
  const fileUploaderInputDropLabelClass = `${fileUploaderInputClass}__dragAndDropLabel`;
68✔
75
  const fileUploaderInputDropZoneClass = `${fileUploaderInputClass}__dropZone`;
68✔
76
  const fileUploaderInputDropZoneLabelClass = `${fileUploaderInputDropZoneClass}Label`;
68✔
77
  const fileUploaderInputHiddenClass = 'd-none';
68✔
78
  const fileUploaderInputInputClass = `${fileUploaderInputClass}__input`;
68✔
79
  const fileUploaderInputLinkClass = `${fileUploaderInputClass}__link`;
68✔
80
  const fileUploaderInputLinkUtilityClasses = ['link-primary', 'link-underlined'];
68✔
81
  const fileUploaderListClass = `${fileUploaderClass}List`;
68✔
82
  const fileUploaderAttachmentClass = `${fileUploaderClass}Attachment`;
68✔
83
  const fileUploaderAttachmentNameClass = `${fileUploaderAttachmentClass}__name`;
68✔
84
  const fileUploaderAttachmentButtonClass = `${fileUploaderAttachmentClass}__action`;
68✔
85
  const fileUploaderAttachmentImageClass = `${fileUploaderAttachmentClass}__image`;
68✔
86
  const fileUploaderAttachmentSlotClass = `${fileUploaderAttachmentClass}__slot`;
68✔
87

88
  const { meta, imageObjectFit } = props || {};
68✔
89
  let imageCropCSS: ImageCropCSS | undefined;
90
  let imageObjectFitCSS: ImageObjectFit | undefined;
91
  const hasCoordsInMeta =
92
    meta != null &&
68✔
93
    ['x', 'y', 'cropWidth', 'cropHeight', 'originalWidth', 'originalHeight'].every((coord) => meta[coord] != null);
6✔
94

95
  if (hasCoordsInMeta) {
68✔
96
    const { x, y, cropWidth, cropHeight, originalWidth, originalHeight } = meta as ImageCropMeta;
1✔
97
    const previewHeight = IMAGE_DIMENSION;
1✔
98
    let scale;
99
    if (cropHeight > cropWidth) {
1!
100
      // scale for portrait images
UNCOV
101
      scale = previewHeight / cropWidth;
×
102
    } else {
103
      // scale for landscape images
104
      scale = previewHeight / cropHeight;
1✔
105
    }
106

107
    const cropX = Math.round(x * scale);
1✔
108
    const cropY = Math.round(y * scale);
1✔
109
    const imageWidth = Math.round(originalWidth * scale);
1✔
110
    const imageHeight = Math.round(originalHeight * scale);
1✔
111

112
    imageCropCSS = {
1✔
113
      [FileUploaderCropCSS.TOP]: `-${cropY}px`,
114
      [FileUploaderCropCSS.LEFT]: `-${cropX}px`,
115
      [FileUploaderCropCSS.WIDTH]: `${imageWidth}px`,
116
      [FileUploaderCropCSS.HEIGHT]: `${imageHeight}px`,
117
    };
118
  }
119

120
  if (imageObjectFit) {
68!
UNCOV
121
    imageObjectFitCSS = {
×
122
      '--file-uploader-attachment-image-object-fit': imageObjectFit,
123
    };
124
  }
125

126
  return {
68✔
127
    classProps: {
128
      root: fileUploaderClass,
129
      input: {
130
        root: classNames(fileUploaderInputClass, {
131
          [fileUploaderHasDragAndDropClass]: props?.isDragAndDropSupported,
132
          [fileUploaderInputDisabledClass]:
133
            props?.isDisabled || (props?.isDisabledByQueueLimitBehavior && props?.queueLimitBehavior === 'disable'),
130✔
134
          [fileUploaderInputDraggingClass]: props?.isDragging,
135
          [fileUploaderInputHiddenClass]: props?.isDropZoneHidden && props.queueLimitBehavior === 'hide',
69✔
136
          [fileUploaderInputValidationClass]: props?.validationState,
137
        }),
138
        input: fileUploaderInputInputClass,
139
        dropLabel: fileUploaderInputDropLabelClass,
140
        link: classNames(fileUploaderInputLinkClass, ...fileUploaderInputLinkUtilityClasses),
141
        dropZone: {
142
          root: fileUploaderInputDropZoneClass,
143
          label: fileUploaderInputDropZoneLabelClass,
144
        },
145
      },
146
      list: fileUploaderListClass,
147
      attachment: {
148
        root: fileUploaderAttachmentClass,
149
        button: fileUploaderAttachmentButtonClass,
150
        name: fileUploaderAttachmentNameClass,
151
        image: fileUploaderAttachmentImageClass,
152
        slot: fileUploaderAttachmentSlotClass,
153
      },
154
      ...(hasCoordsInMeta && { imageCropStyles: imageCropCSS }),
69✔
155
      ...(imageObjectFit && { attachmentStyles: imageObjectFitCSS }),
68!
156
    },
157
  };
158
};
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