@aurora-ds/components 0.23.6 → 0.24.0

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.
Files changed (29) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/forms/file-picker/FilePicker.d.ts +24 -0
  3. package/dist/cjs/components/forms/file-picker/FilePicker.props.d.ts +99 -0
  4. package/dist/cjs/components/forms/file-picker/FilePicker.styles.d.ts +18 -0
  5. package/dist/cjs/components/forms/file-picker/index.d.ts +2 -0
  6. package/dist/cjs/components/forms/image-picker/ImagePicker.d.ts +18 -0
  7. package/dist/cjs/components/forms/image-picker/ImagePicker.props.d.ts +76 -0
  8. package/dist/cjs/components/forms/image-picker/index.d.ts +2 -0
  9. package/dist/cjs/components/index.d.ts +2 -0
  10. package/dist/cjs/index.js +150 -0
  11. package/dist/cjs/index.js.map +1 -1
  12. package/dist/cjs/resources/Icons.d.ts +3 -1
  13. package/dist/cjs/resources/icons/PlusIcon.d.ts +2 -0
  14. package/dist/cjs/resources/icons/TrashIcon.d.ts +2 -0
  15. package/dist/esm/components/forms/file-picker/FilePicker.d.ts +24 -0
  16. package/dist/esm/components/forms/file-picker/FilePicker.props.d.ts +99 -0
  17. package/dist/esm/components/forms/file-picker/FilePicker.styles.d.ts +18 -0
  18. package/dist/esm/components/forms/file-picker/index.d.ts +2 -0
  19. package/dist/esm/components/forms/image-picker/ImagePicker.d.ts +18 -0
  20. package/dist/esm/components/forms/image-picker/ImagePicker.props.d.ts +76 -0
  21. package/dist/esm/components/forms/image-picker/index.d.ts +2 -0
  22. package/dist/esm/components/index.d.ts +2 -0
  23. package/dist/esm/index.js +149 -1
  24. package/dist/esm/index.js.map +1 -1
  25. package/dist/esm/resources/Icons.d.ts +3 -1
  26. package/dist/esm/resources/icons/PlusIcon.d.ts +2 -0
  27. package/dist/esm/resources/icons/TrashIcon.d.ts +2 -0
  28. package/dist/index.d.ts +216 -3
  29. package/package.json +1 -1
package/README.md CHANGED
@@ -211,7 +211,7 @@ The `defaultTheme` includes these token categories:
211
211
  **Buttons:** Button, IconButton
212
212
  **Layout:** Box, Card, Stack, Grid, Page, PageSection, Separator
213
213
  **Typography:** Text
214
- **Forms:** Input, TextArea, Select, DatePicker, Form
214
+ **Forms:** Input, TextArea, Select, DatePicker, Form, FilePicker, ImagePicker
215
215
  **Data Display:** Status, Avatar, AvatarGroup, Icon
216
216
  **Navigation:** Breadcrumb, Tabs, DrawerItem, Menu, Pagination
217
217
  **Feedback:** Alert, Accordion
@@ -0,0 +1,24 @@
1
+ import { FC } from 'react';
2
+ import { FilePickerProps } from '@components/forms/file-picker/FilePicker.props.ts';
3
+ /**
4
+ * Generic file picker component with drag-and-drop style interface.
5
+ * Supports custom preview, icons, and styling for use in external libraries.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * // Basic usage with image
10
+ * <FilePicker
11
+ * label="Upload Image"
12
+ * accept="image/*"
13
+ * preview={imagePreview}
14
+ * placeholder="Click to upload"
15
+ * hint="JPEG, PNG or WebP"
16
+ * icon={PlusIcon}
17
+ * clearIcon={TrashIcon}
18
+ * onSelect={handleSelect}
19
+ * onClear={handleClear}
20
+ * />
21
+ * ```
22
+ */
23
+ declare const FilePicker: FC<FilePickerProps>;
24
+ export default FilePicker;
@@ -0,0 +1,99 @@
1
+ import { ComponentType, CSSProperties, ReactNode, SVGProps } from 'react';
2
+ /**
3
+ * SVG icon component type (compatible with Aurora-DS Icon)
4
+ */
5
+ export type SvgIconComponent = ComponentType<SVGProps<SVGSVGElement>>;
6
+ export type FilePickerProps = {
7
+ /**
8
+ * Label for the input
9
+ */
10
+ label?: string;
11
+ /**
12
+ * Accepted file types (MIME types)
13
+ * @example 'image/jpeg,image/png,image/webp'
14
+ * @example 'application/pdf'
15
+ * @example '.jpg,.png,.pdf'
16
+ */
17
+ accept?: string;
18
+ /**
19
+ * Preview content to display when a file is selected
20
+ * Can be a URL string for images or a ReactNode for custom preview
21
+ */
22
+ preview?: string | ReactNode | null;
23
+ /**
24
+ * Whether the preview is an image URL
25
+ * @default true when preview is a string
26
+ */
27
+ previewIsImage?: boolean;
28
+ /**
29
+ * Alt text for image preview
30
+ */
31
+ previewAlt?: string;
32
+ /**
33
+ * Error message to display
34
+ */
35
+ error?: string | null;
36
+ /**
37
+ * Callback when a file is selected
38
+ */
39
+ onSelect: (file: File | null) => void;
40
+ /**
41
+ * Callback when the file is cleared
42
+ */
43
+ onClear: () => void;
44
+ /**
45
+ * Whether the input is disabled
46
+ */
47
+ disabled?: boolean;
48
+ /**
49
+ * Placeholder text shown in the dropzone
50
+ */
51
+ placeholder?: string;
52
+ /**
53
+ * Hint text shown below the placeholder (e.g., accepted formats)
54
+ */
55
+ hint?: string;
56
+ /**
57
+ * Icon component to display in the dropzone
58
+ * Should be an SVG component (e.g., from @resources/Icons)
59
+ */
60
+ icon?: SvgIconComponent;
61
+ /**
62
+ * Icon component to display on the clear button
63
+ * Should be an SVG component (e.g., from @resources/Icons)
64
+ */
65
+ clearIcon?: SvgIconComponent;
66
+ /**
67
+ * Aria label for the clear button
68
+ */
69
+ clearAriaLabel?: string;
70
+ /**
71
+ * Width of the FilePicker container
72
+ * @example '400px'
73
+ * @example '100%'
74
+ */
75
+ width?: CSSProperties['width'];
76
+ /**
77
+ * Height of the dropzone (when no preview)
78
+ * @example '200px'
79
+ * @default '120px'
80
+ */
81
+ dropzoneHeight?: CSSProperties['height'];
82
+ /**
83
+ * Max height of the preview image
84
+ * @example '300px'
85
+ * @default '200px'
86
+ */
87
+ previewMaxHeight?: CSSProperties['maxHeight'];
88
+ /**
89
+ * Max width of the preview image
90
+ * @example '400px'
91
+ * @default '100%'
92
+ */
93
+ previewMaxWidth?: CSSProperties['maxWidth'];
94
+ /**
95
+ * Object fit for the preview image
96
+ * @default 'cover'
97
+ */
98
+ previewObjectFit?: CSSProperties['objectFit'];
99
+ };
@@ -0,0 +1,18 @@
1
+ import { CSSProperties } from 'react';
2
+ type StyleParams = {
3
+ width?: CSSProperties['width'];
4
+ dropzoneHeight?: CSSProperties['height'];
5
+ previewMaxHeight?: CSSProperties['maxHeight'];
6
+ previewMaxWidth?: CSSProperties['maxWidth'];
7
+ previewObjectFit?: CSSProperties['objectFit'];
8
+ };
9
+ export declare const FILE_PICKER_STYLES: {
10
+ root: (params?: StyleParams | undefined) => string;
11
+ dropzone: (params?: StyleParams | undefined) => string;
12
+ dropzoneDisabled: string;
13
+ hiddenInput: string;
14
+ previewContainer: string;
15
+ preview: (params?: StyleParams | undefined) => string;
16
+ clearButton: string;
17
+ };
18
+ export {};
@@ -0,0 +1,2 @@
1
+ export { default as FilePicker } from '@components/forms/file-picker/FilePicker.tsx';
2
+ export type { FilePickerProps } from '@components/forms/file-picker/FilePicker.props.ts';
@@ -0,0 +1,18 @@
1
+ import { FC } from 'react';
2
+ import { ImagePickerProps } from '@components/forms/image-picker/ImagePicker.props.ts';
3
+ /**
4
+ * Image picker component built on top of the generic FilePicker.
5
+ * Pre-configured for image uploads with JPEG, PNG, and WebP support.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <ImagePicker
10
+ * label="Profile Picture"
11
+ * preview={imageUrl}
12
+ * onSelect={handleImageSelect}
13
+ * onClear={handleImageClear}
14
+ * />
15
+ * ```
16
+ */
17
+ declare const ImagePicker: FC<ImagePickerProps>;
18
+ export default ImagePicker;
@@ -0,0 +1,76 @@
1
+ import { CSSProperties } from 'react';
2
+ export type ImagePickerProps = {
3
+ /**
4
+ * Label for the input
5
+ */
6
+ label?: string;
7
+ /**
8
+ * Preview URL of the selected image
9
+ */
10
+ preview: string | null;
11
+ /**
12
+ * Error message to display
13
+ */
14
+ error?: string | null;
15
+ /**
16
+ * Callback when a file is selected
17
+ */
18
+ onSelect: (file: File | null) => void;
19
+ /**
20
+ * Callback when the image is cleared
21
+ */
22
+ onClear: () => void;
23
+ /**
24
+ * Whether the input is disabled
25
+ */
26
+ disabled?: boolean;
27
+ /**
28
+ * Placeholder text shown in the dropzone
29
+ * @default 'Click to upload an image'
30
+ */
31
+ placeholder?: string;
32
+ /**
33
+ * Hint text shown below the placeholder
34
+ * @default 'JPEG, PNG or WebP'
35
+ */
36
+ hint?: string;
37
+ /**
38
+ * Alt text for image preview
39
+ * @default 'Image preview'
40
+ */
41
+ previewAlt?: string;
42
+ /**
43
+ * Aria label for the clear button
44
+ * @default 'Remove image'
45
+ */
46
+ clearAriaLabel?: string;
47
+ /**
48
+ * Width of the ImagePicker container
49
+ * @example '400px'
50
+ * @example '100%'
51
+ */
52
+ width?: CSSProperties['width'];
53
+ /**
54
+ * Height of the dropzone (when no preview)
55
+ * @example '200px'
56
+ * @default '120px'
57
+ */
58
+ dropzoneHeight?: CSSProperties['height'];
59
+ /**
60
+ * Max height of the preview image
61
+ * @example '300px'
62
+ * @default '200px'
63
+ */
64
+ previewMaxHeight?: CSSProperties['maxHeight'];
65
+ /**
66
+ * Max width of the preview image
67
+ * @example '400px'
68
+ * @default '100%'
69
+ */
70
+ previewMaxWidth?: CSSProperties['maxWidth'];
71
+ /**
72
+ * Object fit for the preview image
73
+ * @default 'cover'
74
+ */
75
+ previewObjectFit?: CSSProperties['objectFit'];
76
+ };
@@ -0,0 +1,2 @@
1
+ export { default as ImagePicker } from '@components/forms/image-picker/ImagePicker.tsx';
2
+ export type { ImagePickerProps } from '@components/forms/image-picker/ImagePicker.props.ts';
@@ -11,6 +11,8 @@ export * from '@components/forms/input';
11
11
  export * from '@components/forms/textarea';
12
12
  export * from '@components/forms/select';
13
13
  export * from '@components/forms/date-picker';
14
+ export * from '@components/forms/file-picker';
15
+ export * from '@components/forms/image-picker';
14
16
  export * from '@components/layout/box';
15
17
  export * from '@components/layout/stack';
16
18
  export * from '@components/layout/card';
package/dist/cjs/index.js CHANGED
@@ -1227,6 +1227,10 @@ const MoreHorizontalIcon = () => {
1227
1227
  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' })] }));
1228
1228
  };
1229
1229
 
1230
+ 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' }) }));
1231
+
1232
+ 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' })] }));
1233
+
1230
1234
  /**
1231
1235
  * Input component
1232
1236
  */
@@ -2109,6 +2113,150 @@ const DatePicker = ({ value, onChange, label, mandatory = false, placeholder, di
2109
2113
  DatePicker.displayName = 'DatePicker';
2110
2114
  var DatePicker_default = React.memo(DatePicker);
2111
2115
 
2116
+ const FILE_PICKER_STYLES = theme.createStyles((theme) => ({
2117
+ root: (params) => ({
2118
+ display: 'flex',
2119
+ flexDirection: 'column',
2120
+ gap: theme.spacing.xs,
2121
+ width: params?.width ?? '100%',
2122
+ }),
2123
+ dropzone: (params) => ({
2124
+ position: 'relative',
2125
+ display: 'flex',
2126
+ flexDirection: 'column',
2127
+ alignItems: 'center',
2128
+ justifyContent: 'center',
2129
+ gap: theme.spacing.sm,
2130
+ padding: theme.spacing.lg,
2131
+ border: `2px dashed ${theme.colors.border}`,
2132
+ borderRadius: theme.radius.md,
2133
+ backgroundColor: theme.colors.surface,
2134
+ cursor: 'pointer',
2135
+ transition: `all ${theme.transition.fast}`,
2136
+ minHeight: params?.dropzoneHeight ?? '120px',
2137
+ '&:hover': {
2138
+ borderColor: theme.colors.primary,
2139
+ backgroundColor: theme.colors.surfaceHover,
2140
+ },
2141
+ }),
2142
+ dropzoneDisabled: {
2143
+ opacity: 0.5,
2144
+ cursor: 'not-allowed',
2145
+ '&:hover': {
2146
+ borderColor: theme.colors.border,
2147
+ backgroundColor: theme.colors.surface,
2148
+ },
2149
+ },
2150
+ hiddenInput: {
2151
+ display: 'none',
2152
+ },
2153
+ previewContainer: {
2154
+ position: 'relative',
2155
+ width: '100%',
2156
+ borderRadius: theme.radius.md,
2157
+ overflow: 'hidden',
2158
+ },
2159
+ preview: (params) => ({
2160
+ width: '100%',
2161
+ maxHeight: params?.previewMaxHeight ?? '200px',
2162
+ maxWidth: params?.previewMaxWidth ?? '100%',
2163
+ objectFit: params?.previewObjectFit ?? 'cover',
2164
+ borderRadius: theme.radius.md,
2165
+ }),
2166
+ clearButton: {
2167
+ position: 'absolute',
2168
+ top: theme.spacing.xs,
2169
+ right: theme.spacing.xs,
2170
+ '& button': {
2171
+ backgroundColor: 'rgba(0, 0, 0, 0.6)',
2172
+ '&:hover': {
2173
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
2174
+ },
2175
+ },
2176
+ },
2177
+ }));
2178
+
2179
+ /**
2180
+ * Generic file picker component with drag-and-drop style interface.
2181
+ * Supports custom preview, icons, and styling for use in external libraries.
2182
+ *
2183
+ * @example
2184
+ * ```tsx
2185
+ * // Basic usage with image
2186
+ * <FilePicker
2187
+ * label="Upload Image"
2188
+ * accept="image/*"
2189
+ * preview={imagePreview}
2190
+ * placeholder="Click to upload"
2191
+ * hint="JPEG, PNG or WebP"
2192
+ * icon={PlusIcon}
2193
+ * clearIcon={TrashIcon}
2194
+ * onSelect={handleSelect}
2195
+ * onClear={handleClear}
2196
+ * />
2197
+ * ```
2198
+ */
2199
+ 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, }) => {
2200
+ // refs
2201
+ const inputRef = React.useRef(null);
2202
+ // handlers
2203
+ const handleClick = () => {
2204
+ if (!disabled && inputRef.current) {
2205
+ inputRef.current.click();
2206
+ }
2207
+ };
2208
+ const handleChange = (e) => {
2209
+ const file = e.target.files?.[0] || null;
2210
+ onSelect(file);
2211
+ // Reset input to allow selecting the same file again
2212
+ if (inputRef.current) {
2213
+ inputRef.current.value = '';
2214
+ }
2215
+ };
2216
+ const handleClear = (e) => {
2217
+ e.stopPropagation();
2218
+ onClear();
2219
+ };
2220
+ const handleKeyDown = (e) => {
2221
+ if (e.key === 'Enter' || e.key === ' ') {
2222
+ e.preventDefault();
2223
+ handleClick();
2224
+ }
2225
+ };
2226
+ // Determine if preview is a string (image URL) or ReactNode
2227
+ const isImagePreview = typeof preview === 'string' && previewIsImage;
2228
+ const hasPreview = preview !== null && preview !== undefined;
2229
+ // Style parameters
2230
+ const styleParams = {
2231
+ width,
2232
+ dropzoneHeight,
2233
+ previewMaxHeight,
2234
+ previewMaxWidth,
2235
+ previewObjectFit,
2236
+ };
2237
+ 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 }))] }));
2238
+ };
2239
+ FilePicker.displayName = 'FilePicker';
2240
+
2241
+ /**
2242
+ * Image picker component built on top of the generic FilePicker.
2243
+ * Pre-configured for image uploads with JPEG, PNG, and WebP support.
2244
+ *
2245
+ * @example
2246
+ * ```tsx
2247
+ * <ImagePicker
2248
+ * label="Profile Picture"
2249
+ * preview={imageUrl}
2250
+ * onSelect={handleImageSelect}
2251
+ * onClear={handleImageClear}
2252
+ * />
2253
+ * ```
2254
+ */
2255
+ 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, }) => {
2256
+ 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 }));
2257
+ };
2258
+ ImagePicker.displayName = 'ImagePicker';
2259
+
2112
2260
  /**
2113
2261
  * Box styles using createStyles from @aurora-ds/theme
2114
2262
  */
@@ -3574,10 +3722,12 @@ exports.ButtonToggleGroup = ButtonToggleGroup;
3574
3722
  exports.Card = Card;
3575
3723
  exports.DatePicker = DatePicker_default;
3576
3724
  exports.DrawerItem = DrawerItem;
3725
+ exports.FilePicker = FilePicker;
3577
3726
  exports.Form = Form$1;
3578
3727
  exports.Grid = Grid;
3579
3728
  exports.Icon = Icon;
3580
3729
  exports.IconButton = IconButton;
3730
+ exports.ImagePicker = ImagePicker;
3581
3731
  exports.Input = Input_default;
3582
3732
  exports.Menu = Menu;
3583
3733
  exports.MenuGroup = MenuGroup;