@adamosuiteservices/ui 2.18.6 → 2.19.1
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.
- package/README.md +1 -1
- package/dist/accordion-rounded.cjs +8 -8
- package/dist/accordion-rounded.js +12 -12
- package/dist/accordion.cjs +1 -1
- package/dist/accordion.js +1 -1
- package/dist/alert.cjs +32 -23
- package/dist/alert.js +53 -43
- package/dist/amount-input.cjs +8 -0
- package/dist/amount-input.js +191 -0
- package/dist/avatar.cjs +7 -7
- package/dist/avatar.js +18 -18
- package/dist/badge.cjs +24 -28
- package/dist/badge.js +45 -42
- package/dist/breadcrumb.cjs +3 -4
- package/dist/breadcrumb.js +17 -18
- package/dist/button-CPm4-98H.cjs +87 -0
- package/dist/button-D4ddrxyp.js +156 -0
- package/dist/button-group.cjs +1 -1
- package/dist/button-group.js +1 -1
- package/dist/button.cjs +1 -1
- package/dist/button.js +1 -1
- package/dist/{calendar-Dorq3-wv.cjs → calendar-DXq90PYV.cjs} +20 -22
- package/dist/{calendar-xBaFu2sB.js → calendar-DgfO9zab.js} +239 -240
- package/dist/calendar.cjs +1 -1
- package/dist/calendar.js +1 -1
- package/dist/card.cjs +3 -3
- package/dist/card.js +4 -4
- package/dist/checkbox-CIzBdqN7.cjs +24 -0
- package/dist/{checkbox-DL_jFvgl.js → checkbox-DPlUjwLi.js} +54 -52
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/colors.css +1 -1
- package/dist/combobox-DG9u4g84.js +692 -0
- package/dist/combobox-DylTjGrw.cjs +57 -0
- package/dist/combobox.cjs +1 -1
- package/dist/combobox.js +1 -1
- package/dist/components/layout/sidebar/sidebar.d.ts +2 -1
- package/dist/components/layout/toaster/toaster.d.ts +1 -1
- package/dist/components/ui/alert/alert.d.ts +1 -1
- package/dist/components/ui/amount-input/amount-input.d.ts +32 -0
- package/dist/components/ui/amount-input/index.d.ts +1 -0
- package/dist/components/ui/badge/badge.d.ts +3 -2
- package/dist/components/ui/calendar/calendar.d.ts +1 -1
- package/dist/components/ui/combobox/combobox.d.ts +3 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts +3 -1
- package/dist/components/ui/selectable-card/index.d.ts +1 -0
- package/dist/components/ui/selectable-card/selectable-card.d.ts +22 -0
- package/dist/components/ui/timeline/index.d.ts +1 -0
- package/dist/components/ui/timeline/timeline.d.ts +30 -0
- package/dist/components/ui/typography/typography.d.ts +1 -1
- package/dist/context-menu.cjs +18 -19
- package/dist/context-menu.js +37 -38
- package/dist/date-picker-selector.cjs +1 -1
- package/dist/date-picker-selector.js +3 -3
- package/dist/dialog.cjs +7 -9
- package/dist/dialog.js +36 -38
- package/dist/dropdown-menu.cjs +57 -36
- package/dist/dropdown-menu.js +206 -173
- package/dist/field.cjs +12 -7
- package/dist/field.js +51 -45
- package/dist/file-upload-v2.cjs +11 -5
- package/dist/file-upload-v2.js +75 -60
- package/dist/file-upload.cjs +11 -5
- package/dist/file-upload.js +118 -110
- package/dist/full-screen-loader.cjs +1 -1
- package/dist/full-screen-loader.js +1 -1
- package/dist/{icon-B7joBr0A.cjs → icon-C5Q2b1Am.cjs} +1 -1
- package/dist/{icon-BFQz1tQC.js → icon-t4jt1Z2h.js} +1 -1
- package/dist/icon.cjs +1 -1
- package/dist/icon.js +1 -1
- package/dist/index-BBT2EGq8.js +18 -0
- package/dist/index-DCsgSkBj.cjs +1 -0
- package/dist/input-8sEO5zwD.js +44 -0
- package/dist/input-AONeSXcs.cjs +22 -0
- package/dist/input-group-BLffLxyg.cjs +86 -0
- package/dist/input-group-DmevJAqa.js +240 -0
- package/dist/input-group.cjs +1 -84
- package/dist/input-group.js +7 -234
- package/dist/input-otp.cjs +5 -7
- package/dist/input-otp.js +58 -60
- package/dist/input.cjs +1 -1
- package/dist/input.js +1 -1
- package/dist/kbd.cjs +6 -7
- package/dist/kbd.js +14 -15
- package/dist/{label-DqfX9cHc.cjs → label-B7Z1D5-Q.cjs} +5 -4
- package/dist/{label-C6zVnc3d.js → label-_BWRIH7C.js} +14 -13
- package/dist/label.cjs +1 -1
- package/dist/label.js +1 -1
- package/dist/pagination.cjs +5 -5
- package/dist/pagination.js +18 -18
- package/dist/radio-group.cjs +12 -9
- package/dist/radio-group.js +66 -63
- package/dist/select.cjs +18 -16
- package/dist/select.js +18 -16
- package/dist/selectable-card.cjs +29 -0
- package/dist/selectable-card.js +129 -0
- package/dist/separator-DXdc7LcC.cjs +7 -0
- package/dist/{separator-CsaqP20m.js → separator-DZfXXbNt.js} +1 -1
- package/dist/separator.cjs +1 -1
- package/dist/separator.js +1 -1
- package/dist/{sheet-Cnq7TCzu.cjs → sheet-Cp6JGhWC.cjs} +10 -10
- package/dist/{sheet-C9vce0ut.js → sheet-hWerE8S1.js} +9 -6
- package/dist/sheet.cjs +1 -1
- package/dist/sheet.js +1 -1
- package/dist/sidebar.cjs +10 -10
- package/dist/sidebar.js +83 -92
- package/dist/slider.cjs +1 -1
- package/dist/slider.js +1 -1
- package/dist/{spinner-C7q7NthY.cjs → spinner-DUZ2vcus.cjs} +1 -1
- package/dist/{spinner-DQ5JLL3U.js → spinner-_-J3zJ_g.js} +1 -1
- package/dist/spinner.cjs +1 -1
- package/dist/spinner.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/switch.cjs +2 -4
- package/dist/switch.js +71 -73
- package/dist/table.cjs +14 -14
- package/dist/table.js +12 -12
- package/dist/tabs-underline.cjs +11 -15
- package/dist/tabs-underline.js +20 -24
- package/dist/tabs.cjs +10 -14
- package/dist/tabs.js +20 -24
- package/dist/tailwind-colors.css +1 -1
- package/dist/tailwind-theme.css +1 -1
- package/dist/textarea-BSooGyp-.cjs +18 -0
- package/dist/textarea-D_sj6ivo.js +39 -0
- package/dist/textarea.cjs +1 -1
- package/dist/textarea.js +1 -1
- package/dist/themes.css +1 -1
- package/dist/timeline.cjs +4 -0
- package/dist/timeline.js +189 -0
- package/dist/toaster.cjs +5 -4
- package/dist/toaster.js +33 -32
- package/dist/toggle.cjs +4 -4
- package/dist/toggle.js +17 -17
- package/dist/tooltip.cjs +5 -6
- package/dist/tooltip.js +4 -5
- package/docs/components/layout/sidebar.md +81 -53
- package/docs/components/layout/toaster.md +35 -55
- package/docs/components/ui/accordion-rounded.md +12 -11
- package/docs/components/ui/alert.md +66 -36
- package/docs/components/ui/amount-input.md +229 -0
- package/docs/components/ui/avatar.md +28 -32
- package/docs/components/ui/badge.md +85 -32
- package/docs/components/ui/breadcrumb.md +5 -7
- package/docs/components/ui/button-group.md +16 -16
- package/docs/components/ui/button.md +23 -36
- package/docs/components/ui/calendar.md +54 -27
- package/docs/components/ui/card.md +5 -4
- package/docs/components/ui/checkbox.md +3 -3
- package/docs/components/ui/combobox.md +35 -1
- package/docs/components/ui/command.md +7 -7
- package/docs/components/ui/context-menu.md +14 -15
- package/docs/components/ui/date-picker-selector.md +31 -31
- package/docs/components/ui/dialog.md +47 -49
- package/docs/components/ui/dropdown-menu.md +34 -37
- package/docs/components/ui/field.md +25 -31
- package/docs/components/ui/file-upload-v2.md +11 -0
- package/docs/components/ui/file-upload.md +105 -108
- package/docs/components/ui/hover-card.md +28 -6
- package/docs/components/ui/icon.md +10 -9
- package/docs/components/ui/input-group.md +9 -9
- package/docs/components/ui/input.md +30 -33
- package/docs/components/ui/kbd.md +10 -9
- package/docs/components/ui/label.md +6 -6
- package/docs/components/ui/pagination.md +3 -3
- package/docs/components/ui/popover.md +1 -0
- package/docs/components/ui/progress.md +3 -3
- package/docs/components/ui/radio-group.md +18 -6
- package/docs/components/ui/scroll-area.md +4 -4
- package/docs/components/ui/select.md +14 -12
- package/docs/components/ui/selectable-card.md +204 -0
- package/docs/components/ui/separator.md +4 -4
- package/docs/components/ui/sheet.md +21 -3
- package/docs/components/ui/slider.md +3 -3
- package/docs/components/ui/switch.md +7 -7
- package/docs/components/ui/table.md +7 -4
- package/docs/components/ui/tabs-underline.md +36 -36
- package/docs/components/ui/tabs.md +6 -4
- package/docs/components/ui/textarea.md +6 -4
- package/docs/components/ui/timeline.md +214 -0
- package/docs/components/ui/toggle.md +1 -1
- package/docs/components/ui/tooltip.md +3 -3
- package/llm.txt +7 -4
- package/package.json +13 -1
- package/dist/button-BnUlAtuD.js +0 -132
- package/dist/button-CFJs0esR.cjs +0 -63
- package/dist/checkbox-3RIZX2HF.cjs +0 -22
- package/dist/combobox-MkeJiTXj.js +0 -637
- package/dist/combobox-jJRxvUsB.cjs +0 -40
- package/dist/input-BCiOr4Fy.js +0 -44
- package/dist/input-Bz5k4w94.cjs +0 -22
- package/dist/separator-CCGaTo09.cjs +0 -7
- package/dist/textarea-BRCnIxdB.js +0 -33
- package/dist/textarea-DkFUS_oS.cjs +0 -14
|
@@ -50,18 +50,7 @@ function MyForm() {
|
|
|
50
50
|
}
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
###
|
|
54
|
-
|
|
55
|
-
```tsx
|
|
56
|
-
import { useState } from "react";
|
|
57
|
-
import { FileUpload } from "@adamosuiteservices/ui/file-upload";
|
|
58
|
-
|
|
59
|
-
function MyForm() {
|
|
60
|
-
const [files, setFiles] = useState<File[]>([]);
|
|
61
|
-
|
|
62
|
-
return <FileUpload selectedFiles={files} onFilesSelect={setFiles} multiple />;
|
|
63
|
-
}
|
|
64
|
-
```
|
|
53
|
+
### Multiple files
|
|
65
54
|
|
|
66
55
|
**Default configuration**:
|
|
67
56
|
|
|
@@ -448,75 +437,55 @@ Position where selected files appear in multiple mode:
|
|
|
448
437
|
### With Field components
|
|
449
438
|
|
|
450
439
|
```tsx
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
selectedFile={file}
|
|
461
|
-
onFileSelect={setFile}
|
|
462
|
-
acceptedExtensions={[".pdf", ".doc", ".docx"]}
|
|
463
|
-
/>
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
### maxSizeInMB
|
|
467
|
-
|
|
468
|
-
```tsx
|
|
469
|
-
maxSizeInMB?: number
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
Maximum file size in megabytes. Default: `50`
|
|
473
|
-
|
|
474
|
-
**Example**:
|
|
475
|
-
|
|
476
|
-
```tsx
|
|
477
|
-
<FileUpload selectedFile={file} onFileSelect={setFile} maxSizeInMB={10} />
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
## Examples
|
|
440
|
+
import { useState } from "react";
|
|
441
|
+
import { FileUpload } from "@adamosuiteservices/ui/file-upload";
|
|
442
|
+
import {
|
|
443
|
+
Field,
|
|
444
|
+
FieldLabel,
|
|
445
|
+
FieldDescription,
|
|
446
|
+
FieldError,
|
|
447
|
+
FieldGroup,
|
|
448
|
+
} from "@adamosuiteservices/ui/field";
|
|
481
449
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
setError(
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
450
|
+
function DocumentUpload() {
|
|
451
|
+
const [file, setFile] = useState<File | null>(null);
|
|
452
|
+
const [error, setError] = useState("");
|
|
453
|
+
|
|
454
|
+
const handleInvalidFile = (f: File, reason: "extension" | "size") => {
|
|
455
|
+
setError(
|
|
456
|
+
reason === "extension"
|
|
457
|
+
? `File "${f.name}" has an invalid extension.`
|
|
458
|
+
: `File "${f.name}" exceeds the maximum size limit.`,
|
|
459
|
+
);
|
|
460
|
+
};
|
|
489
461
|
|
|
490
|
-
return (
|
|
491
|
-
<FieldGroup className="adm:max-w-xl">
|
|
492
|
-
<Field>
|
|
493
|
-
<FieldLabel>Upload document (PDF or DOCX only, max
|
|
494
|
-
<FileUpload
|
|
495
|
-
selectedFile={file}
|
|
496
|
-
onFileSelect={(newFile) => {
|
|
497
|
-
setFile(newFile);
|
|
498
|
-
if (newFile) setError("");
|
|
499
|
-
}}
|
|
500
|
-
onInvalidFile={handleInvalidFile}
|
|
501
|
-
aria-invalid={!!error}
|
|
502
|
-
acceptedExtensions={[".pdf", ".docx"]}
|
|
503
|
-
maxSizeInMB={2}
|
|
504
|
-
/>
|
|
505
|
-
{error ? (
|
|
506
|
-
<FieldError>{error}</FieldError>
|
|
507
|
-
) : (
|
|
508
|
-
<FieldDescription>
|
|
509
|
-
Supported formats: PDF, DOCX. Maximum
|
|
510
|
-
</FieldDescription>
|
|
511
|
-
)}
|
|
512
|
-
</Field>
|
|
513
|
-
</FieldGroup>
|
|
514
|
-
);
|
|
462
|
+
return (
|
|
463
|
+
<FieldGroup className="adm:max-w-xl">
|
|
464
|
+
<Field data-invalid={!!error}>
|
|
465
|
+
<FieldLabel>Upload document (PDF or DOCX only, max 2 MB)</FieldLabel>
|
|
466
|
+
<FileUpload
|
|
467
|
+
selectedFile={file}
|
|
468
|
+
onFileSelect={(newFile) => {
|
|
469
|
+
setFile(newFile);
|
|
470
|
+
if (newFile) setError("");
|
|
471
|
+
}}
|
|
472
|
+
onInvalidFile={handleInvalidFile}
|
|
473
|
+
aria-invalid={!!error}
|
|
474
|
+
acceptedExtensions={[".pdf", ".docx"]}
|
|
475
|
+
maxSizeInMB={2}
|
|
476
|
+
/>
|
|
477
|
+
{error ? (
|
|
478
|
+
<FieldError>{error}</FieldError>
|
|
479
|
+
) : (
|
|
480
|
+
<FieldDescription>
|
|
481
|
+
Supported formats: PDF, DOCX. Maximum 2 MB.
|
|
482
|
+
</FieldDescription>
|
|
483
|
+
)}
|
|
484
|
+
</Field>
|
|
485
|
+
</FieldGroup>
|
|
486
|
+
);
|
|
515
487
|
}
|
|
516
|
-
|
|
517
|
-
````
|
|
518
|
-
|
|
519
|
-
### Estado Deshabilitado
|
|
488
|
+
```
|
|
520
489
|
|
|
521
490
|
```tsx
|
|
522
491
|
import {
|
|
@@ -559,7 +528,7 @@ function DisabledWithFileExample() {
|
|
|
559
528
|
</FieldGroup>
|
|
560
529
|
);
|
|
561
530
|
}
|
|
562
|
-
|
|
531
|
+
```
|
|
563
532
|
|
|
564
533
|
### Inside fieldset disabled
|
|
565
534
|
|
|
@@ -733,12 +702,17 @@ function MultipleFilesWithCallbacks() {
|
|
|
733
702
|
|
|
734
703
|
### Excel files (default)
|
|
735
704
|
|
|
736
|
-
|
|
705
|
+
```tsx
|
|
737
706
|
const [file, setFile] = useState<File | null>(null);
|
|
738
707
|
|
|
739
708
|
<FileUpload
|
|
740
709
|
selectedFile={file}
|
|
741
|
-
|
|
710
|
+
onFileSelect={setFile}
|
|
711
|
+
// Default: .xls, .xlsx, .numbers; max 50 MB
|
|
712
|
+
/>;
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
### Multiple files with labels
|
|
742
716
|
|
|
743
717
|
```tsx
|
|
744
718
|
const [files, setFiles] = useState<File[]>([]);
|
|
@@ -750,10 +724,10 @@ const [files, setFiles] = useState<File[]>([]);
|
|
|
750
724
|
maxFiles={5}
|
|
751
725
|
labels={{
|
|
752
726
|
dragDrop: "Drag and drop your files here or",
|
|
753
|
-
selectFile: "Select files"
|
|
727
|
+
selectFile: "Select files",
|
|
754
728
|
}}
|
|
755
|
-
|
|
756
|
-
|
|
729
|
+
/>;
|
|
730
|
+
```
|
|
757
731
|
|
|
758
732
|
### Multiple images
|
|
759
733
|
|
|
@@ -793,13 +767,24 @@ const [files, setFiles] = useState<File[]>([]);
|
|
|
793
767
|
/>;
|
|
794
768
|
```
|
|
795
769
|
|
|
796
|
-
/>
|
|
797
|
-
|
|
798
770
|
### Images
|
|
799
771
|
|
|
800
|
-
|
|
772
|
+
```tsx
|
|
801
773
|
const [image, setImage] = useState<File | null>(null);
|
|
802
774
|
|
|
775
|
+
<FileUpload
|
|
776
|
+
selectedFile={image}
|
|
777
|
+
onFileSelect={setImage}
|
|
778
|
+
acceptedExtensions={[".jpg", ".jpeg", ".png", ".gif", ".webp"]}
|
|
779
|
+
maxSizeInMB={5}
|
|
780
|
+
labels={{
|
|
781
|
+
dragDrop: "Drag and drop your image here or",
|
|
782
|
+
selectFile: "Select image",
|
|
783
|
+
fileRequirements: "Supported: JPG, PNG, GIF, WebP. Max 5 MB.",
|
|
784
|
+
}}
|
|
785
|
+
/>;
|
|
786
|
+
```
|
|
787
|
+
|
|
803
788
|
## Visual states
|
|
804
789
|
|
|
805
790
|
### Simple mode
|
|
@@ -807,6 +792,7 @@ const [image, setImage] = useState<File | null>(null);
|
|
|
807
792
|
#### Without selected file
|
|
808
793
|
|
|
809
794
|
The component shows:
|
|
795
|
+
|
|
810
796
|
- Drag & drop area with dashed border
|
|
811
797
|
- Document icon on light blue background
|
|
812
798
|
- Instructional text and link to select file
|
|
@@ -815,6 +801,7 @@ The component shows:
|
|
|
815
801
|
#### With selected file
|
|
816
802
|
|
|
817
803
|
The drag & drop area is hidden and shows:
|
|
804
|
+
|
|
818
805
|
- Card with `bg-muted` background and border
|
|
819
806
|
- Document icon on `bg-primary-50` background
|
|
820
807
|
- File name (with truncate if long)
|
|
@@ -830,12 +817,15 @@ Only the drag & drop area is shown.
|
|
|
830
817
|
### During drag over
|
|
831
818
|
|
|
832
819
|
When the user drags files over the area:
|
|
833
|
-
|
|
820
|
+
|
|
821
|
+
- Border changes to `border-strong-border`
|
|
822
|
+
- Background changes to `bg-muted`
|
|
834
823
|
- Smooth transition with `transition-colors`
|
|
835
824
|
|
|
836
825
|
### Invalid state
|
|
837
826
|
|
|
838
827
|
When `invalid={true}` or `aria-invalid={true}`:
|
|
828
|
+
|
|
839
829
|
- Border: `border-destructive`
|
|
840
830
|
- Background: `bg-destructive/5`
|
|
841
831
|
- Document icon: `text-destructive` with `bg-destructive/10` background
|
|
@@ -848,11 +838,13 @@ When `invalid={true}` or `aria-invalid={true}`:
|
|
|
848
838
|
When `disabled={true}` or inside `<fieldset disabled>`:
|
|
849
839
|
|
|
850
840
|
**Drag & drop area**:
|
|
841
|
+
|
|
851
842
|
- Opacity: `opacity-50`
|
|
852
843
|
- Cursor: `cursor-not-allowed`
|
|
853
844
|
- Visual error states are not applied
|
|
854
845
|
|
|
855
846
|
**Selected files**:
|
|
847
|
+
|
|
856
848
|
- Opacity: `opacity-50`
|
|
857
849
|
- Cursor: `cursor-not-allowed`
|
|
858
850
|
- Remove button disabled
|
|
@@ -868,6 +860,7 @@ The component automatically validates:
|
|
|
868
860
|
3. **Count** (multiple mode): Limits to `maxFiles` number of files
|
|
869
861
|
|
|
870
862
|
If a file does not meet these validations:
|
|
863
|
+
|
|
871
864
|
- It is not selected
|
|
872
865
|
- The `onFileSelect`/`onFilesSelect` callbacks are not invoked
|
|
873
866
|
- The `onInvalidFile` callback is invoked (if defined) with the file and reason
|
|
@@ -898,16 +891,18 @@ const handleInvalidFile = (file: File, reason: "extension" | "size") => {
|
|
|
898
891
|
invalid={!!error}
|
|
899
892
|
acceptedExtensions={[".pdf", ".docx"]}
|
|
900
893
|
maxSizeInMB={2}
|
|
901
|
-
|
|
894
|
+
/>;
|
|
902
895
|
|
|
903
|
-
{
|
|
904
|
-
|
|
905
|
-
<
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
896
|
+
{
|
|
897
|
+
error && (
|
|
898
|
+
<div className="adm:rounded-lg adm:border adm:border-destructive adm:bg-destructive/5 adm:p-4">
|
|
899
|
+
<Typography color="destructive" className="adm:text-sm adm:font-medium">
|
|
900
|
+
{error}
|
|
901
|
+
</Typography>
|
|
902
|
+
</div>
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
```
|
|
911
906
|
|
|
912
907
|
## Behavior by mode
|
|
913
908
|
|
|
@@ -930,26 +925,28 @@ const handleInvalidFile = (file: File, reason: "extension" | "size") => {
|
|
|
930
925
|
**Drag & drop area:**
|
|
931
926
|
|
|
932
927
|
- Padding: `p-6` (24px)
|
|
933
|
-
- Border radius: `rounded-
|
|
934
|
-
- Border: `border
|
|
928
|
+
- Border radius: `rounded-3xl` (24px)
|
|
929
|
+
- Border: `border border-dashed`
|
|
935
930
|
- Normal state: `border-input bg-background`
|
|
936
|
-
-
|
|
931
|
+
- Hover: `border-strong-border bg-muted`
|
|
932
|
+
- Dragging: `border-strong-border`
|
|
937
933
|
- Transitions: `transition-colors`
|
|
934
|
+
- Drop icon: `upload` from Material Symbols on `bg-primary-50` background (`rounded-full size-11`)
|
|
938
935
|
|
|
939
936
|
**Selected file card:**
|
|
940
937
|
|
|
941
|
-
- Padding: `p-
|
|
942
|
-
- Border radius: `rounded-
|
|
938
|
+
- Padding: `p-4` (16px)
|
|
939
|
+
- Border radius: `rounded-3xl` (24px)
|
|
943
940
|
- Background: `bg-muted`
|
|
944
|
-
-
|
|
945
|
-
- Horizontal gap: `gap-
|
|
946
|
-
- Icon: `
|
|
941
|
+
- No border
|
|
942
|
+
- Horizontal gap: `gap-6` (24px)
|
|
943
|
+
- Icon: `article` from Material Symbols on `bg-background` background (`rounded-full size-11`)
|
|
947
944
|
|
|
948
945
|
**Remove button:**
|
|
949
946
|
|
|
950
|
-
- Variant: `
|
|
951
|
-
- Icon: `
|
|
952
|
-
- Icon color: `text-destructive`
|
|
947
|
+
- Variant: `ghost`, size: `icon`
|
|
948
|
+
- Icon: `cancel` from Material Symbols
|
|
949
|
+
- Icon color: `text-destructive` (automatically inherits `text-disabled-foreground` when disabled)
|
|
953
950
|
|
|
954
951
|
**Clear all button (multiple mode):**
|
|
955
952
|
|
|
@@ -60,10 +60,32 @@ import {
|
|
|
60
60
|
|
|
61
61
|
## Props
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
|
63
|
+
### HoverCard (root)
|
|
64
|
+
|
|
65
|
+
| Prop | Type | Default | Description |
|
|
66
|
+
| -------------- | ------------------------- | ------- | --------------------------- |
|
|
67
|
+
| `open` | `boolean` | - | Controlled open state |
|
|
68
|
+
| `onOpenChange` | `(open: boolean) => void` | - | Callback when state changes |
|
|
69
|
+
| `openDelay` | `number` | `200` | Delay before opening (ms) |
|
|
70
|
+
| `closeDelay` | `number` | `300` | Delay before closing (ms) |
|
|
71
|
+
|
|
72
|
+
### HoverCardTrigger
|
|
73
|
+
|
|
74
|
+
| Prop | Type | Description |
|
|
75
|
+
| --------- | --------- | ---------------------------------------- |
|
|
76
|
+
| `asChild` | `boolean` | Pass props to child instead of a wrapper |
|
|
77
|
+
|
|
78
|
+
### HoverCardContent
|
|
79
|
+
|
|
80
|
+
| Prop | Type | Default | Description |
|
|
81
|
+
| ------------- | ---------------------------------------- | ---------- | ---------------------------------------- |
|
|
82
|
+
| `align` | `"start" \| "center" \| "end"` | `"center"` | Horizontal alignment relative to trigger |
|
|
83
|
+
| `side` | `"top" \| "right" \| "bottom" \| "left"` | `"bottom"` | Side where the card appears |
|
|
84
|
+
| `sideOffset` | `number` | `4` | Distance from trigger (px) |
|
|
85
|
+
| `alignOffset` | `number` | `0` | Alignment offset |
|
|
86
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
87
|
+
|
|
88
|
+
**Default styles**: `w-64`, `p-4`, `rounded-md`, `shadow-xs`, `bg-popover`, `z-50`
|
|
67
89
|
|
|
68
90
|
## References
|
|
69
91
|
|
|
@@ -90,7 +112,7 @@ import {
|
|
|
90
112
|
</HoverCard>
|
|
91
113
|
```
|
|
92
114
|
|
|
93
|
-
###
|
|
115
|
+
### With avatar (user preview)
|
|
94
116
|
|
|
95
117
|
```tsx
|
|
96
118
|
import {
|
|
@@ -152,7 +174,7 @@ import { Icon } from "@adamosuiteservices/ui/icon";
|
|
|
152
174
|
<p className="text-sm">Building design systems and web apps.</p>
|
|
153
175
|
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
|
154
176
|
<div className="flex items-center gap-1">
|
|
155
|
-
<
|
|
177
|
+
<Icon symbol="group" className="text-lg" />
|
|
156
178
|
<span>2.1k followers</span>
|
|
157
179
|
</div>
|
|
158
180
|
<div>Following 180</div>
|
|
@@ -31,7 +31,7 @@ import { Icon, type IconProps } from "@adamosuiteservices/ui/icon";
|
|
|
31
31
|
```tsx
|
|
32
32
|
import { type IconProps } from "@adamosuiteservices/ui/icon";
|
|
33
33
|
|
|
34
|
-
//
|
|
34
|
+
// To create custom components
|
|
35
35
|
function CustomIcon(props: IconProps) {
|
|
36
36
|
return <Icon {...props} className="custom-icon-styles" />;
|
|
37
37
|
}
|
|
@@ -386,21 +386,21 @@ const commonIcons = [
|
|
|
386
386
|
<Icon symbol="star" className="adm:text-5xl" /> {/* ~48px */}
|
|
387
387
|
```
|
|
388
388
|
|
|
389
|
-
###
|
|
389
|
+
### Appropriate weight by context
|
|
390
390
|
|
|
391
391
|
```tsx
|
|
392
392
|
{
|
|
393
|
-
/* ✅
|
|
393
|
+
/* ✅ Correct - Light weight for modern interfaces */
|
|
394
394
|
}
|
|
395
395
|
<Icon symbol="menu" weight={300} />;
|
|
396
396
|
|
|
397
397
|
{
|
|
398
|
-
/* ✅
|
|
398
|
+
/* ✅ Correct - Heavier weight for emphasis */
|
|
399
399
|
}
|
|
400
400
|
<Icon symbol="warning" weight={500} fill={1} className="adm:text-warning" />;
|
|
401
401
|
|
|
402
402
|
{
|
|
403
|
-
/* ❌
|
|
403
|
+
/* ❌ Avoid - Too heavy without purpose */
|
|
404
404
|
}
|
|
405
405
|
<Icon symbol="home" weight={700} />;
|
|
406
406
|
```
|
|
@@ -417,18 +417,18 @@ const commonIcons = [
|
|
|
417
417
|
<Icon symbol="favorite" fill={liked ? 1 : 0} />
|
|
418
418
|
```
|
|
419
419
|
|
|
420
|
-
###
|
|
420
|
+
### Accessibility
|
|
421
421
|
|
|
422
422
|
```tsx
|
|
423
423
|
{
|
|
424
|
-
/* ✅
|
|
424
|
+
/* ✅ Correct - Buttons with labels */
|
|
425
425
|
}
|
|
426
426
|
<Button variant="ghost" size="icon" aria-label="Close dialog">
|
|
427
427
|
<Icon symbol="close" className="adm:text-2xl" />
|
|
428
428
|
</Button>;
|
|
429
429
|
|
|
430
430
|
{
|
|
431
|
-
/* ✅
|
|
431
|
+
/* ✅ Correct - Decorative icons */
|
|
432
432
|
}
|
|
433
433
|
<div className="adm:flex adm:items-center adm:gap-2">
|
|
434
434
|
<Icon symbol="folder" className="adm:text-xl" aria-hidden="true" />
|
|
@@ -513,8 +513,9 @@ The component renders a `<span>` with the following characteristics:
|
|
|
513
513
|
|
|
514
514
|
```tsx
|
|
515
515
|
<span
|
|
516
|
+
translate="no"
|
|
516
517
|
data-slot="icon"
|
|
517
|
-
className="material-symbols-outlined adm:inline-block adm:text-2xl"
|
|
518
|
+
className="material-symbols-outlined adm:inline-block adm:text-2xl adm:select-none"
|
|
518
519
|
style={{ fontVariationSettings: "..." }}
|
|
519
520
|
>
|
|
520
521
|
{symbol}
|
|
@@ -79,12 +79,12 @@ import {
|
|
|
79
79
|
|
|
80
80
|
### InputGroupButton
|
|
81
81
|
|
|
82
|
-
| Prop | Type | Default
|
|
83
|
-
| --------- | ---------------------------------------- |
|
|
84
|
-
| `size` | `"xs" \| "sm" \| "icon-xs" \| "icon-sm"` | `"xs"`
|
|
85
|
-
| `variant` | Button variants | `"
|
|
86
|
-
| `type` | `string` | `"button"`
|
|
87
|
-
| ...rest | - | -
|
|
82
|
+
| Prop | Type | Default | Description |
|
|
83
|
+
| --------- | ---------------------------------------- | ---------------- | ------------------------------ |
|
|
84
|
+
| `size` | `"xs" \| "sm" \| "icon-xs" \| "icon-sm"` | `"xs"` | Button size |
|
|
85
|
+
| `variant` | Button variants | `"link-neutral"` | Button variant |
|
|
86
|
+
| `type` | `string` | `"button"` | HTML button type |
|
|
87
|
+
| ...rest | - | - | All Button props except `size` |
|
|
88
88
|
|
|
89
89
|
**Sizes**:
|
|
90
90
|
|
|
@@ -448,9 +448,9 @@ function App() {
|
|
|
448
448
|
|
|
449
449
|
### InputGroup States
|
|
450
450
|
|
|
451
|
-
- **Disabled**: `data-disabled` → `opacity-50`
|
|
452
|
-
- **Focus**: `has-[input:focus-visible]` → ring
|
|
453
|
-
- **Invalid**: `has-[input[aria-invalid=true]]` → ring
|
|
451
|
+
- **Disabled**: `data-disabled` → `opacity-50` on addons
|
|
452
|
+
- **Focus**: `has-[input:focus-visible]` → ring and border applied to the group
|
|
453
|
+
- **Invalid**: `has-[input[aria-invalid=true]]` → destructive ring and border
|
|
454
454
|
|
|
455
455
|
### Focus behavior
|
|
456
456
|
|
|
@@ -128,20 +128,20 @@ import { Input } from "@adamosuiteservices/ui/input";
|
|
|
128
128
|
|
|
129
129
|
```tsx
|
|
130
130
|
{
|
|
131
|
-
/*
|
|
131
|
+
/* Small */
|
|
132
132
|
}
|
|
133
133
|
<Input type="text" placeholder="Small input" className="h-9 text-sm" />;
|
|
134
134
|
|
|
135
135
|
{
|
|
136
|
-
/*
|
|
136
|
+
/* Default */
|
|
137
137
|
}
|
|
138
138
|
<Input type="text" placeholder="Default input" />;
|
|
139
139
|
{
|
|
140
|
-
/* h-10
|
|
140
|
+
/* h-10 by default */
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
{
|
|
144
|
-
/*
|
|
144
|
+
/* Large */
|
|
145
145
|
}
|
|
146
146
|
<Input type="text" placeholder="Large input" className="h-11" />;
|
|
147
147
|
```
|
|
@@ -179,32 +179,28 @@ import { Input } from "@adamosuiteservices/ui/input";
|
|
|
179
179
|
|
|
180
180
|
### Focus
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
The input has a visible focus ring:
|
|
183
183
|
|
|
184
184
|
```css
|
|
185
|
-
focus-visible:
|
|
186
|
-
focus-visible:ring-
|
|
185
|
+
focus-visible:border-primary-300
|
|
186
|
+
focus-visible:ring-4
|
|
187
|
+
focus-visible:ring-primary/10
|
|
187
188
|
```
|
|
188
189
|
|
|
189
190
|
### Validation states
|
|
190
191
|
|
|
191
192
|
- Normal border: `border-input`
|
|
192
|
-
- Invalid: `aria-invalid:border-destructive`
|
|
193
|
-
|
|
194
|
-
### Dark mode
|
|
195
|
-
|
|
196
|
-
```css
|
|
197
|
-
dark: bg-input/30;
|
|
198
|
-
```
|
|
193
|
+
- Invalid: `aria-invalid:border-destructive` + red ring on focus `ring-4 ring-destructive/10`
|
|
199
194
|
|
|
200
195
|
### File input
|
|
201
196
|
|
|
202
197
|
File inputs have special styles for the button:
|
|
203
198
|
|
|
204
199
|
```css
|
|
205
|
-
file:h-
|
|
200
|
+
file:h-full
|
|
206
201
|
file:text-sm
|
|
207
202
|
file:font-medium
|
|
203
|
+
file:text-foreground
|
|
208
204
|
```
|
|
209
205
|
|
|
210
206
|
## Common use cases
|
|
@@ -265,7 +261,7 @@ const maxLength = 100;
|
|
|
265
261
|
|
|
266
262
|
## Implementation notes
|
|
267
263
|
|
|
268
|
-
- Uses the
|
|
264
|
+
- Uses the `adm:` prefix in all styles
|
|
269
265
|
- Based on the native HTML `<input>` element
|
|
270
266
|
- Supports all native HTML input props
|
|
271
267
|
- Internal SVG icons are automatically resized
|
|
@@ -273,32 +269,32 @@ const maxLength = 100;
|
|
|
273
269
|
|
|
274
270
|
## References
|
|
275
271
|
|
|
276
|
-
-
|
|
272
|
+
- shadcn/ui documentation: <https://ui.shadcn.com/docs/components/input>
|
|
277
273
|
- MDN Input: <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input>
|
|
278
274
|
|
|
279
275
|
## Advanced features
|
|
280
276
|
|
|
281
|
-
**Forms**: Inputs
|
|
282
|
-
**Search**:
|
|
283
|
-
**File upload**:
|
|
284
|
-
**Numbers**:
|
|
285
|
-
**Dates**:
|
|
286
|
-
**Validation**:
|
|
277
|
+
**Forms**: Inputs in registration, login, and contact forms
|
|
278
|
+
**Search**: Search bars with `type="search"`
|
|
279
|
+
**File upload**: File selection with `type="file"`
|
|
280
|
+
**Numbers**: Quantities, prices, ages with `type="number"`
|
|
281
|
+
**Dates**: Date selection with `type="date"`
|
|
282
|
+
**Validation**: Fields with visual validation via `aria-invalid`
|
|
287
283
|
|
|
288
284
|
## States and data attributes
|
|
289
285
|
|
|
290
286
|
### Focus
|
|
291
287
|
|
|
292
|
-
- **Focused**: `focus-visible:
|
|
288
|
+
- **Focused**: `focus-visible:border-primary-300`, `focus-visible:ring-4`, `focus-visible:ring-primary/10`
|
|
293
289
|
|
|
294
290
|
### Validation
|
|
295
291
|
|
|
296
|
-
- **Invalid**: `aria-invalid:border-destructive`, `aria-invalid:ring-destructive/
|
|
292
|
+
- **Invalid**: `aria-invalid:border-destructive`, `aria-invalid:focus-visible:border-destructive`, `aria-invalid:focus-visible:ring-destructive/10`
|
|
297
293
|
- **Valid**: Border normal `border-input`
|
|
298
294
|
|
|
299
295
|
### Disabled state
|
|
300
296
|
|
|
301
|
-
- **Disabled**: `opacity-
|
|
297
|
+
- **Disabled**: `disabled:opacity-100`, `disabled:pointer-events-none`, `disabled:cursor-not-allowed`, `disabled:bg-input-disabled`, `disabled:text-input-foreground-disabled`, `disabled:placeholder:text-disabled-foreground`
|
|
302
298
|
|
|
303
299
|
### File input styles
|
|
304
300
|
|
|
@@ -309,9 +305,10 @@ const maxLength = 100;
|
|
|
309
305
|
- **Height**: `h-10` (~40px) default
|
|
310
306
|
- **Border**: `border`, `border-input`, `rounded-md`
|
|
311
307
|
- **Padding**: `px-3` (no vertical padding, height defines the height)
|
|
312
|
-
- **Font**: `text-
|
|
308
|
+
- **Font**: `text-sm`
|
|
313
309
|
- **Shadow**: `shadow-xs`
|
|
314
|
-
- **Background**: `bg-
|
|
310
|
+
- **Background**: `bg-background`
|
|
311
|
+
- **Hover**: `hover:bg-muted`
|
|
315
312
|
- **Transitions**: `transition-[color,box-shadow]`
|
|
316
313
|
- **Selection**: `selection:bg-primary selection:text-primary-foreground`
|
|
317
314
|
|
|
@@ -332,17 +329,17 @@ const maxLength = 100;
|
|
|
332
329
|
- **Props forwarding**: Accepts all native HTML props
|
|
333
330
|
- **Validation**: Uses native attributes (`required`, `pattern`, `min`, `max`) + `aria-invalid`
|
|
334
331
|
- **File input**: Special styles for "Choose file" button
|
|
335
|
-
- **Focus ring**:
|
|
332
|
+
- **Focus ring**: `ring-4` with `ring-primary/10` for visibility without being invasive
|
|
336
333
|
- **Shadow**: Subtle `shadow-xs` for depth
|
|
337
|
-
- **
|
|
338
|
-
- **
|
|
334
|
+
- **Font size**: `text-sm` on all screen sizes
|
|
335
|
+
- **Background**: Solid `bg-background`, `hover:bg-muted`
|
|
339
336
|
|
|
340
337
|
## Differences with Textarea
|
|
341
338
|
|
|
342
339
|
| Aspect | Input | Textarea |
|
|
343
340
|
| ---------- | -------------------------------- | ------------------------- |
|
|
344
341
|
| **Lines** | Single-line | Multi-line |
|
|
345
|
-
| **Height** | Fixed (h-
|
|
342
|
+
| **Height** | Fixed (h-10) | Variable (min-h-20) |
|
|
346
343
|
| **Resize** | No | Yes (vertical by default) |
|
|
347
344
|
| **Types** | Multiple (email, password, etc.) | Text only |
|
|
348
345
|
| **Usage** | Short data | Long text |
|
|
@@ -354,7 +351,7 @@ const maxLength = 100;
|
|
|
354
351
|
**Styles don't apply**: Verify you're using `className` with valid Tailwind
|
|
355
352
|
**File input doesn't look good**: Use `file:*` classes to style button
|
|
356
353
|
**Invalid state doesn't work**: Make sure to use `aria-invalid` not just `invalid`
|
|
357
|
-
**Inconsistent height**: Input has `h-
|
|
354
|
+
**Inconsistent height**: Input has `h-10` default, use `className` to override
|
|
358
355
|
**Dark mode doesn't work**: Verify theme configured and `dark:` class applying
|
|
359
356
|
**Number input allows text**: Browser validates, but use additional JS validation
|
|
360
357
|
|