@aurora-ds/components 0.24.5 → 0.24.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,7 @@ type StyleParams = {
5
5
  previewMaxHeight?: CSSProperties['maxHeight'];
6
6
  previewMaxWidth?: CSSProperties['maxWidth'];
7
7
  previewObjectFit?: CSSProperties['objectFit'];
8
+ isDragOver?: boolean;
8
9
  };
9
10
  export declare const FILE_PICKER_STYLES: {
10
11
  root: (params?: StyleParams | undefined) => string;
package/dist/cjs/index.js CHANGED
@@ -1211,10 +1211,10 @@ const MoreHorizontalIcon = () => {
1211
1211
  return (jsxRuntime.jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round', className: 'lucide lucide-ellipsis-icon lucide-ellipsis', children: [jsxRuntime.jsx("circle", { cx: '12', cy: '12', r: '1' }), jsxRuntime.jsx("circle", { cx: '19', cy: '12', r: '1' }), jsxRuntime.jsx("circle", { cx: '5', cy: '12', r: '1' })] }));
1212
1212
  };
1213
1213
 
1214
- const PlusIcon = () => (jsxRuntime.jsx("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', children: jsxRuntime.jsx("path", { d: 'M8 3.33337V12.6667M3.33333 8H12.6667', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' }) }));
1215
-
1216
1214
  const TrashIcon = () => (jsxRuntime.jsxs("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', children: [jsxRuntime.jsx("path", { d: 'M2 4H3.33333H14', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' }), jsxRuntime.jsx("path", { d: 'M5.33325 4.00004V2.66671C5.33325 2.31309 5.47373 1.97395 5.72378 1.7239C5.97382 1.47385 6.31296 1.33337 6.66659 1.33337H9.33325C9.68687 1.33337 10.026 1.47385 10.276 1.7239C10.5261 1.97395 10.6666 2.31309 10.6666 2.66671V4.00004M12.6666 4.00004V13.3334C12.6666 13.687 12.5261 14.0261 12.276 14.2762C12.026 14.5262 11.6868 14.6667 11.3333 14.6667H4.66659C4.31296 14.6667 3.97382 14.5262 3.72378 14.2762C3.47373 14.0261 3.33325 13.687 3.33325 13.3334V4.00004H12.6666Z', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' })] }));
1217
1215
 
1216
+ const UploadIcon = () => (jsxRuntime.jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', "stroke-width": '2', "stroke-linecap": 'round', "stroke-linejoin": 'round', className: 'lucide lucide-upload-icon lucide-upload', children: [jsxRuntime.jsx("path", { d: 'M12 3v12' }), jsxRuntime.jsx("path", { d: 'm17 8-5-5-5 5' }), jsxRuntime.jsx("path", { d: 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4' })] }));
1217
+
1218
1218
  /**
1219
1219
  * Input component
1220
1220
  */
@@ -2111,17 +2111,20 @@ const FILE_PICKER_STYLES = theme.createStyles((theme) => ({
2111
2111
  alignItems: 'center',
2112
2112
  justifyContent: 'center',
2113
2113
  gap: theme.spacing.sm,
2114
- padding: theme.spacing.lg,
2115
- border: `2px dashed ${theme.colors.border}`,
2114
+ padding: theme.spacing.md,
2115
+ border: `2px dashed ${params?.isDragOver ? theme.colors.primary : theme.colors.border}`,
2116
2116
  borderRadius: theme.radius.md,
2117
- backgroundColor: theme.colors.surface,
2117
+ backgroundColor: params?.isDragOver ? theme.colors.surfaceHover : theme.colors.surface,
2118
2118
  cursor: 'pointer',
2119
2119
  transition: `all ${theme.transition.fast}`,
2120
- minHeight: params?.dropzoneHeight ?? '120px',
2120
+ minHeight: params?.dropzoneHeight ?? undefined,
2121
2121
  '&:hover': {
2122
2122
  borderColor: theme.colors.primary,
2123
2123
  backgroundColor: theme.colors.surfaceHover,
2124
2124
  },
2125
+ '& > *': {
2126
+ pointerEvents: 'none',
2127
+ },
2125
2128
  }),
2126
2129
  dropzoneDisabled: {
2127
2130
  opacity: 0.5,
@@ -2183,6 +2186,8 @@ const FILE_PICKER_STYLES = theme.createStyles((theme) => ({
2183
2186
  const FilePicker = ({ label, accept, preview, previewIsImage = true, previewAlt = 'Preview', error, onSelect, onClear, disabled = false, placeholder = 'Click to upload a file', hint, icon: IconComponent, clearIcon: ClearIconComponent, clearAriaLabel = 'Remove file', width, dropzoneHeight, previewMaxHeight, previewMaxWidth, previewObjectFit, }) => {
2184
2187
  // refs
2185
2188
  const inputRef = React.useRef(null);
2189
+ // state
2190
+ const [isDragOver, setIsDragOver] = React.useState(false);
2186
2191
  // handlers
2187
2192
  const handleClick = () => {
2188
2193
  if (!disabled && inputRef.current) {
@@ -2207,6 +2212,56 @@ const FilePicker = ({ label, accept, preview, previewIsImage = true, previewAlt
2207
2212
  handleClick();
2208
2213
  }
2209
2214
  };
2215
+ const handleDragEnter = (e) => {
2216
+ e.preventDefault();
2217
+ e.stopPropagation();
2218
+ if (!disabled) {
2219
+ setIsDragOver(true);
2220
+ }
2221
+ };
2222
+ const handleDragOver = (e) => {
2223
+ e.preventDefault();
2224
+ e.stopPropagation();
2225
+ };
2226
+ const handleDragLeave = (e) => {
2227
+ e.preventDefault();
2228
+ e.stopPropagation();
2229
+ // Only set isDragOver to false if we're actually leaving the dropzone
2230
+ // (not just entering a child element)
2231
+ if (e.currentTarget === e.target || !e.currentTarget.contains(e.relatedTarget)) {
2232
+ setIsDragOver(false);
2233
+ }
2234
+ };
2235
+ const handleDrop = (e) => {
2236
+ e.preventDefault();
2237
+ e.stopPropagation();
2238
+ setIsDragOver(false);
2239
+ if (!disabled) {
2240
+ const file = e.dataTransfer.files?.[0] || null;
2241
+ if (file) {
2242
+ // Validate file type if accept is specified
2243
+ if (accept) {
2244
+ const acceptedTypes = accept.split(',').map(type => type.trim());
2245
+ const isAccepted = acceptedTypes.some(type => {
2246
+ if (type.startsWith('.')) {
2247
+ // Extension check
2248
+ return file.name.toLowerCase().endsWith(type.toLowerCase());
2249
+ }
2250
+ else {
2251
+ // MIME type check
2252
+ return file.type === type || file.type.match(new RegExp(type.replace('*', '.*')));
2253
+ }
2254
+ });
2255
+ if (isAccepted) {
2256
+ onSelect(file);
2257
+ }
2258
+ }
2259
+ else {
2260
+ onSelect(file);
2261
+ }
2262
+ }
2263
+ }
2264
+ };
2210
2265
  // Determine if preview is a string (image URL) or ReactNode
2211
2266
  const isImagePreview = typeof preview === 'string' && previewIsImage;
2212
2267
  const hasPreview = preview !== null && preview !== undefined;
@@ -2217,8 +2272,9 @@ const FilePicker = ({ label, accept, preview, previewIsImage = true, previewAlt
2217
2272
  previewMaxHeight,
2218
2273
  previewMaxWidth,
2219
2274
  previewObjectFit,
2275
+ isDragOver,
2220
2276
  };
2221
- return (jsxRuntime.jsxs("div", { className: FILE_PICKER_STYLES.root(styleParams), children: [label && (jsxRuntime.jsx(Text, { fontSize: 'sm', variant: 'label', children: label })), jsxRuntime.jsx("input", { ref: inputRef, type: 'file', accept: accept, className: FILE_PICKER_STYLES.hiddenInput, onChange: handleChange, disabled: disabled }), hasPreview ? (jsxRuntime.jsxs("div", { className: FILE_PICKER_STYLES.previewContainer, children: [isImagePreview ? (jsxRuntime.jsx("img", { src: preview, alt: previewAlt, className: FILE_PICKER_STYLES.preview(styleParams) })) : (preview), !disabled && ClearIconComponent && (jsxRuntime.jsx("div", { className: FILE_PICKER_STYLES.clearButton, children: jsxRuntime.jsx(IconButton, { icon: jsxRuntime.jsx(ClearIconComponent, {}), onClick: handleClear, ariaLabel: clearAriaLabel, variant: 'contained', size: 'small', textColor: 'surface' }) }))] })) : (jsxRuntime.jsxs("div", { className: `${FILE_PICKER_STYLES.dropzone(styleParams)} ${disabled ? FILE_PICKER_STYLES.dropzoneDisabled : ''}`, onClick: handleClick, role: 'button', tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown, children: [IconComponent && (jsxRuntime.jsx(Icon, { size: 'lg', color: 'text', children: jsxRuntime.jsx(IconComponent, {}) })), jsxRuntime.jsx(Text, { children: placeholder }), hint && (jsxRuntime.jsx(Text, { fontSize: 'xs', color: 'textSecondary', children: hint }))] })), error && (jsxRuntime.jsx(Text, { fontSize: 'sm', color: 'error', children: error }))] }));
2277
+ return (jsxRuntime.jsxs("div", { className: FILE_PICKER_STYLES.root(styleParams), children: [label && (jsxRuntime.jsx(Text, { fontSize: 'sm', variant: 'label', children: label })), jsxRuntime.jsx("input", { ref: inputRef, type: 'file', accept: accept, className: FILE_PICKER_STYLES.hiddenInput, onChange: handleChange, disabled: disabled }), hasPreview ? (jsxRuntime.jsxs("div", { className: FILE_PICKER_STYLES.previewContainer, children: [isImagePreview ? (jsxRuntime.jsx("img", { src: preview, alt: previewAlt, className: FILE_PICKER_STYLES.preview(styleParams) })) : (preview), !disabled && ClearIconComponent && (jsxRuntime.jsx("div", { className: FILE_PICKER_STYLES.clearButton, children: jsxRuntime.jsx(IconButton, { icon: jsxRuntime.jsx(ClearIconComponent, {}), onClick: handleClear, ariaLabel: clearAriaLabel, variant: 'contained', size: 'small', textColor: 'surface' }) }))] })) : (jsxRuntime.jsxs("div", { className: `${FILE_PICKER_STYLES.dropzone(styleParams)} ${disabled ? FILE_PICKER_STYLES.dropzoneDisabled : ''}`, onClick: handleClick, role: 'button', tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown, onDragEnter: handleDragEnter, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [jsxRuntime.jsxs(Stack, { children: [IconComponent && (jsxRuntime.jsx(Icon, { size: 'md', color: 'text', children: jsxRuntime.jsx(IconComponent, {}) })), jsxRuntime.jsx(Text, { children: placeholder })] }), hint && (jsxRuntime.jsx(Text, { fontSize: 'xs', color: 'textSecondary', children: hint }))] })), error && (jsxRuntime.jsx(Text, { fontSize: 'sm', color: 'error', children: error }))] }));
2222
2278
  };
2223
2279
  FilePicker.displayName = 'FilePicker';
2224
2280
 
@@ -2237,7 +2293,7 @@ FilePicker.displayName = 'FilePicker';
2237
2293
  * ```
2238
2294
  */
2239
2295
  const ImagePicker = ({ label, preview, error, onSelect, onClear, disabled = false, placeholder = 'Click to upload an image', hint = 'JPEG, PNG or WebP', previewAlt = 'Image preview', clearAriaLabel = 'Remove image', width, dropzoneHeight, previewMaxHeight, previewMaxWidth, previewObjectFit, }) => {
2240
- return (jsxRuntime.jsx(FilePicker, { label: label, accept: 'image/jpeg,image/png,image/webp', preview: preview, previewIsImage: true, previewAlt: previewAlt, error: error, onSelect: onSelect, onClear: onClear, disabled: disabled, placeholder: placeholder, hint: hint, icon: PlusIcon, clearIcon: TrashIcon, clearAriaLabel: clearAriaLabel, width: width, dropzoneHeight: dropzoneHeight, previewMaxHeight: previewMaxHeight, previewMaxWidth: previewMaxWidth, previewObjectFit: previewObjectFit }));
2296
+ return (jsxRuntime.jsx(FilePicker, { label: label, accept: 'image/jpeg,image/png,image/webp', preview: preview, previewIsImage: true, previewAlt: previewAlt, error: error, onSelect: onSelect, onClear: onClear, disabled: disabled, placeholder: placeholder, hint: hint, icon: UploadIcon, clearIcon: TrashIcon, clearAriaLabel: clearAriaLabel, width: width, dropzoneHeight: dropzoneHeight, previewMaxHeight: previewMaxHeight, previewMaxWidth: previewMaxWidth, previewObjectFit: previewObjectFit }));
2241
2297
  };
2242
2298
  ImagePicker.displayName = 'ImagePicker';
2243
2299