zaravand-ui 5.0.1 → 5.1.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.
@@ -0,0 +1,5 @@
1
+ import type { AvatarGroupProps, AvatarProps } from "./Avatar.interface";
2
+ declare function Avatar({ src, alt, name, fallback, size: sizeProp, shape: shapeProp, status, showTooltip, previewable, previewSrc, onClick, onImageSelect, onImageRemove, accept, maxSizeKb, onReject, className, }: AvatarProps): import("react/jsx-runtime").JSX.Element;
3
+ declare function AvatarGroup({ items, children, max, size, shape, showTooltip, className, }: AvatarGroupProps): import("react/jsx-runtime").JSX.Element;
4
+ export { AvatarGroup };
5
+ export default Avatar;
@@ -0,0 +1,65 @@
1
+ import type * as React from "react";
2
+ import type { UploaderRejection } from "../Uploader/Uploader.interface";
3
+ export type AvatarSize = "xs" | "sm" | "default" | "lg" | "xl";
4
+ export type AvatarShape = "circle" | "square";
5
+ export type AvatarStatus = "online" | "offline" | "busy" | "away";
6
+ export interface AvatarProps {
7
+ /** Image URL. When missing or failing to load, the fallback is shown. */
8
+ src?: string;
9
+ /** Image alt text. Defaults to `name`. */
10
+ alt?: string;
11
+ /** Person/entity name — used for the initials fallback, accessible label and tooltip. */
12
+ name?: string;
13
+ /** Custom fallback content. Replaces the initials/icon fallback. */
14
+ fallback?: React.ReactNode;
15
+ /** @default "default" (or the surrounding `AvatarGroup`'s size) */
16
+ size?: AvatarSize;
17
+ /** @default "circle" (or the surrounding `AvatarGroup`'s shape) */
18
+ shape?: AvatarShape;
19
+ /** Presence dot at the bottom corner. */
20
+ status?: AvatarStatus;
21
+ /** Shows `name` in a tooltip on hover/focus. */
22
+ showTooltip?: boolean;
23
+ /**
24
+ * When the image has loaded: shows a magnifier on hover and opens the image in a full-screen preview on click.
25
+ * @default true when `onClick` is not set
26
+ */
27
+ previewable?: boolean;
28
+ /** Larger image used in the preview. Defaults to `src`. */
29
+ previewSrc?: string;
30
+ /** Makes the avatar a button. Takes precedence over the preview click unless `previewable` is set explicitly. */
31
+ onClick?: React.MouseEventHandler<HTMLButtonElement>;
32
+ /** Enables editing: shows a camera button that picks a new image. The consumer updates `src`. */
33
+ onImageSelect?: (file: File) => void;
34
+ /** Shows a "remove image" action in the preview. */
35
+ onImageRemove?: () => void;
36
+ /** @default "image/*" */
37
+ accept?: string;
38
+ /** Max size of the picked image in kilobytes. */
39
+ maxSizeKb?: number;
40
+ /** Called with a rejected image. When omitted, an error toast is shown. */
41
+ onReject?: (rejection: UploaderRejection) => void;
42
+ className?: string;
43
+ }
44
+ export type AvatarGroupItem = Omit<AvatarProps, "size" | "shape"> & {
45
+ /** React key. Defaults to `name`/index. */
46
+ key?: string;
47
+ };
48
+ export interface AvatarGroupProps {
49
+ /** Data-driven usage. When provided, `children` is ignored. */
50
+ items?: AvatarGroupItem[];
51
+ /** Manual composition with `<Avatar>` children. */
52
+ children?: React.ReactNode;
53
+ /** Maximum avatars shown before collapsing the rest into a "+N" chip. */
54
+ max?: number;
55
+ /** @default "default" */
56
+ size?: AvatarSize;
57
+ /** @default "circle" */
58
+ shape?: AvatarShape;
59
+ /**
60
+ * Tooltip with the name on each avatar (items mode) and the hidden names on the "+N" chip.
61
+ * @default true
62
+ */
63
+ showTooltip?: boolean;
64
+ className?: string;
65
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * First letter of the first and last word. Persian/Arabic letters are joined with a ZWNJ so
3
+ * they render as two separate letters ("م‌ط") instead of connecting into one word ("مط").
4
+ */
5
+ declare function getInitials(name: string | undefined): string;
6
+ export { getInitials };
@@ -0,0 +1,22 @@
1
+ declare const avatarVariants: (props?: ({
2
+ size?: "xs" | "sm" | "default" | "lg" | "xl" | null | undefined;
3
+ shape?: "circle" | "square" | null | undefined;
4
+ interactive?: boolean | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ declare const avatarStatusVariants: (props?: ({
7
+ status?: "online" | "offline" | "busy" | "away" | null | undefined;
8
+ size?: "xs" | "sm" | "default" | "lg" | "xl" | null | undefined;
9
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
10
+ declare const avatarEditButtonVariants: (props?: ({
11
+ size?: "xs" | "sm" | "default" | "lg" | "xl" | null | undefined;
12
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
13
+ /** Overlap for `AvatarGroup` children (RTL-aware via margin-inline-start on every item but the first). */
14
+ declare const avatarGroupOverlapBySize: {
15
+ readonly xs: "zui:[&>*:not(:first-child)]:-ms-1.5";
16
+ readonly sm: "zui:[&>*:not(:first-child)]:-ms-2";
17
+ readonly default: "zui:[&>*:not(:first-child)]:-ms-2.5";
18
+ readonly lg: "zui:[&>*:not(:first-child)]:-ms-3";
19
+ readonly xl: "zui:[&>*:not(:first-child)]:-ms-4";
20
+ };
21
+ declare const avatarPreviewContentClassName = "zui:relative zui:z-[110] zui:flex zui:max-w-[92vw] zui:flex-col zui:items-center zui:gap-3 zui:outline-none zui:duration-300 zui:ease-out zui:data-[state=open]:animate-in zui:data-[state=open]:fade-in-0 zui:data-[state=open]:zoom-in-75 zui:data-[state=closed]:animate-out zui:data-[state=closed]:fade-out-0 zui:data-[state=closed]:zoom-out-90";
22
+ export { avatarEditButtonVariants, avatarGroupOverlapBySize, avatarPreviewContentClassName, avatarStatusVariants, avatarVariants, };
@@ -1,6 +1,6 @@
1
1
  declare const toastViewportVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
2
2
  declare const toastVariants: (props?: ({
3
- variant?: "success" | "warning" | "default" | "error" | "info" | "destructive" | null | undefined;
3
+ variant?: "success" | "warning" | "default" | "info" | "error" | "destructive" | null | undefined;
4
4
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
5
5
  declare const toastActionVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
6
6
  declare const toastCloseVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
@@ -0,0 +1,3 @@
1
+ import type { UploaderProps } from "./Uploader.interface";
2
+ declare function Uploader({ type, size, title, required, showRequiredMessage, placeholder, id, name, form, disabled, readOnly, className, accept, maxSizeKb, files, defaultFiles, onFilesChange, attachments, onAttachmentsChange, onAttachmentDelete, onPreview, onDownload, onReject, open, defaultOpen, onOpenChange, onInvalid, }: UploaderProps): import("react/jsx-runtime").JSX.Element;
3
+ export default Uploader;
@@ -0,0 +1,78 @@
1
+ import type * as React from "react";
2
+ import type { VariantProps } from "class-variance-authority";
3
+ import { uploaderFieldVariants } from "./Uploader.variant";
4
+ /** A file that already lives on the server (e.g. loaded with the entity being edited). */
5
+ export interface UploaderAttachment {
6
+ /** Stable identity (storage key, id, ...). Used as the React key and for delete. */
7
+ key: string;
8
+ /** Display name. */
9
+ name: string;
10
+ /** Direct URL used by the built-in preview/download actions. */
11
+ url?: string;
12
+ /** Size in bytes, shown next to the name when provided. */
13
+ size?: number;
14
+ }
15
+ /** One row of the uploader: either a freshly picked local file or an existing server attachment. */
16
+ export type UploaderItem = {
17
+ kind: "local";
18
+ file: File;
19
+ } | {
20
+ kind: "attachment";
21
+ attachment: UploaderAttachment;
22
+ };
23
+ export type UploaderRejectReason = "size" | "type";
24
+ export interface UploaderRejection {
25
+ file: File;
26
+ reason: UploaderRejectReason;
27
+ }
28
+ export interface UploaderProps extends VariantProps<typeof uploaderFieldVariants> {
29
+ /**
30
+ * `"single"` keeps at most one file; `"multi"` collects a list shown in a dropdown.
31
+ * @default "single"
32
+ */
33
+ type?: "single" | "multi";
34
+ title?: string;
35
+ required?: boolean;
36
+ /**
37
+ * When true and `required` is true, shows a "این فیلد اجباری است" hint next to the required star.
38
+ * @default false
39
+ */
40
+ showRequiredMessage?: boolean;
41
+ placeholder?: string;
42
+ id?: string;
43
+ /** When set, the picked local files are also submitted with a native `<form>` under this name. */
44
+ name?: string;
45
+ form?: string;
46
+ disabled?: boolean;
47
+ /** Shows the files with preview/download only — no picking, dropping or deleting. */
48
+ readOnly?: boolean;
49
+ className?: string;
50
+ /** Same syntax as the native `accept` attribute. Also enforced on picked and dropped files. */
51
+ accept?: string;
52
+ /** Maximum size of a single file in kilobytes. */
53
+ maxSizeKb?: number;
54
+ /** Controlled local files. */
55
+ files?: File[];
56
+ /** Initial local files (uncontrolled). */
57
+ defaultFiles?: File[];
58
+ onFilesChange?: (files: File[]) => void;
59
+ /** Existing server files. Always controlled. */
60
+ attachments?: UploaderAttachment[];
61
+ onAttachmentsChange?: (attachments: UploaderAttachment[]) => void;
62
+ /**
63
+ * Called before an attachment is removed (e.g. to send the DELETE request).
64
+ * Returning / resolving `false` keeps the attachment.
65
+ */
66
+ onAttachmentDelete?: (attachment: UploaderAttachment) => boolean | void | Promise<boolean | void>;
67
+ /** Replaces the built-in preview (open in a new tab). Also enables preview for attachments without `url`. */
68
+ onPreview?: (item: UploaderItem) => void;
69
+ /** Replaces the built-in download. Also enables download for attachments without `url`. */
70
+ onDownload?: (item: UploaderItem) => void;
71
+ /** Called with files rejected by `accept`/`maxSizeKb`. When omitted, an error toast is shown instead. */
72
+ onReject?: (rejections: UploaderRejection[]) => void;
73
+ /** Controlled open state of the multi-mode file list. */
74
+ open?: boolean;
75
+ defaultOpen?: boolean;
76
+ onOpenChange?: (open: boolean) => void;
77
+ onInvalid?: React.FormEventHandler<HTMLInputElement>;
78
+ }
@@ -0,0 +1,17 @@
1
+ import type { UploaderItem, UploaderRejection } from "./Uploader.interface";
2
+ declare function dedupeFiles(files: File[]): File[];
3
+ /** Mirrors the native `accept` attribute: `.ext`, `type/*` and exact MIME tokens. */
4
+ declare function matchesAccept(file: File, accept: string | undefined): boolean;
5
+ declare function splitAcceptedFiles(files: File[], accept: string | undefined, maxSizeKb: number | undefined): {
6
+ accepted: File[];
7
+ rejected: UploaderRejection[];
8
+ };
9
+ declare function toPersianNumber(value: number, fractionDigits?: number): string;
10
+ declare function formatFileSize(bytes: number): string;
11
+ declare function describeRejection({ file, reason }: UploaderRejection, maxSizeKb: number | undefined): string;
12
+ declare function getItemName(item: UploaderItem): string;
13
+ declare function getItemSize(item: UploaderItem): number | undefined;
14
+ declare function getItemKey(item: UploaderItem): string;
15
+ declare function previewItemInNewTab(item: UploaderItem): void;
16
+ declare function downloadItem(item: UploaderItem): void;
17
+ export { dedupeFiles, describeRejection, downloadItem, formatFileSize, getItemKey, getItemName, getItemSize, matchesAccept, previewItemInNewTab, splitAcceptedFiles, toPersianNumber, };
@@ -0,0 +1,8 @@
1
+ declare const uploaderFieldVariants: (props?: ({
2
+ size?: "sm" | "default" | "lg" | null | undefined;
3
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
4
+ declare const uploaderIconButtonClassName = "zui:inline-flex zui:size-7 zui:shrink-0 zui:cursor-pointer zui:items-center zui:justify-center zui:rounded-md zui:border-0 zui:bg-transparent zui:p-0 zui:text-[var(--zui-color-text)] zui:outline-none zui:transition-[background-color,opacity,transform] zui:duration-200 zui:hover:bg-[var(--zui-theme-bg-muted)] zui:focus-visible:bg-[var(--zui-theme-bg-muted)] zui:focus-visible:shadow-[0_0_0_1px_var(--zui-theme-action-primary)] zui:disabled:pointer-events-none zui:disabled:cursor-not-allowed zui:disabled:opacity-40 zui:[&>svg]:size-4 zui:[&>svg]:transition-transform zui:[&>svg]:duration-200 zui:hover:[&>svg]:scale-110";
5
+ declare const uploaderDangerIconClassName = "zui:text-[var(--zui-theme-status-danger)]";
6
+ declare const uploaderContentVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
7
+ declare const uploaderRowClassName = "zui:flex zui:min-h-11 zui:items-center zui:gap-2 zui:border-b zui:border-[var(--zui-color-border)] zui:px-2 zui:py-1.5 zui:transition-colors zui:duration-150 zui:last:border-b-0 zui:hover:bg-[var(--zui-theme-bg-muted)]";
8
+ export { uploaderContentVariants, uploaderDangerIconClassName, uploaderFieldVariants, uploaderIconButtonClassName, uploaderRowClassName, };