automoby-kit 1.0.71 → 1.0.73
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/dist/cjs/Button.js +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/esm/Button.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/types/Button.js +4 -2
- package/dist/types/components/Button/Button.d.ts +2 -1
- package/dist/types/components/ImageUpload/ImageUpload.d.ts +32 -0
- package/dist/types/components/ImageUpload/ImageUpload.stories.d.ts +92 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +87 -4
- package/package.json +1 -1
package/dist/cjs/Button.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";"use strict";var e=require("react/jsx-runtime"),r=require("react"),t=require("./utils.js"),a=require("./Typography.js");const i={sm:"px-4 py-2",md:"px-4 py-2.5",lg:"px-4 py-3",xl:"px-5 py-3"},n={sm:"body-s-bold",md:"body-m-bold",lg:"body-l-bold",xl:"body-xl-heavy"},l={primary:"\n bg-primary text-white\n hover:bg-primary-dark\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",secondary:"\n bg-primary-lightest text-primary-dark\n hover:bg-primary-lighter\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",tertiary:"\n bg-white border border-primary-light text-primary\n hover:bg-neutral-lighter\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",ghost:"\n bg-transparent text-primary\n hover:bg-primary-lightest\n disabled:bg-neutral-light disabled:text-neutral-darker\n "},s=r.forwardRef(({className:r,variant:s="primary",size:d="md",icon:o,iconPosition:b="right",children:
|
|
1
|
+
"use client";"use strict";var e=require("react/jsx-runtime"),r=require("react"),t=require("./utils.js"),a=require("./Typography.js");const i={sm:"px-4 py-2",md:"px-4 py-2.5",lg:"px-4 py-3",xl:"px-5 py-3"},n={sm:"body-s-bold",md:"body-m-bold",lg:"body-l-bold",xl:"body-xl-heavy"},l={primary:"\n bg-primary text-white\n hover:bg-primary-dark\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",secondary:"\n bg-primary-lightest text-primary-dark\n hover:bg-primary-lighter\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",tertiary:"\n bg-white border border-primary-light text-primary\n hover:bg-neutral-lighter\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",ghost:"\n bg-transparent text-primary\n hover:bg-primary-lightest\n disabled:bg-neutral-light disabled:text-neutral-darker\n "},s=r.forwardRef(({className:r,variant:s="primary",size:d="md",icon:o,iconPosition:b="right",children:p,loading:g=!1,disabled:y,textVariant:m,type:h="button",...u},x)=>{const c=m||n[d];return e.jsxs("button",{ref:x,type:h,className:t("inline-flex items-center justify-center rounded-lg transition-colors duration-200",i[d],l[s],a.getTypographyClasses(c),y&&"opacity-50 pointer-events-none",r),disabled:y||g,...u,children:[o&&"left"===b&&e.jsx("span",{className:"mr-2 flex items-center",children:o}),g?"...":p,o&&"right"===b&&e.jsx("span",{className:"ml-2 flex items-center",children:o})]})});s.displayName="Button",exports.Button=s;
|
package/dist/cjs/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("./Typography.js"),r=require("./Button.js"),
|
|
1
|
+
"use strict";var e=require("./Typography.js"),r=require("./Button.js"),a=require("./Input.js"),s=require("./Tabs.js"),t=require("./Drawer.js"),l=require("./Backdrop.js"),i=require("./Breadcrumb.js"),o=require("./Pagination.js"),n=require("./Accordion.js"),c=require("./Divider.js"),d=require("./RadioGroup.js"),u=require("./chunks/Chips-Ws80QAgh.js"),p=require("./Menu.js"),m=require("react/jsx-runtime"),x=require("react"),h=require("./utils.js"),g=require("./chunks/createLucideIcon-BqJVOzoK.js"),b=require("./contexts.js");require("react-dom"),require("./chunks/chevron-left-Do__K6cA.js");const f=g.createLucideIcon("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);const j=x.forwardRef(({value:r,onChange:a,label:s="ارسال عکس",instruction:t,maxSize:l=10485760,accept:i="image/jpeg,image/jpg,image/png",maxCount:o,onRejected:n,disabled:c=!1,className:d,addButtonText:p="اضافه",removeButtonAriaLabel:g="حذف عکس"},b)=>{const j=x.useMemo(()=>function(e){if(!e||"*"===e)return/.*/;const r=e.split(",").map(e=>e.trim().replace(/^[^/]+\//,"").replace(/^\*\./,"")).filter(Boolean);if(0===r.length)return/.*/;const a=r.map(e=>e.replace(".","\\.")).join("|");return new RegExp(`\\.(${a})$`,"i")}(i),[i]),y=x.useId(),v=x.useMemo(()=>r.map(e=>e.type.startsWith("image/")?URL.createObjectURL(e):null),[r]);x.useEffect(()=>()=>{v.forEach(e=>e&&URL.revokeObjectURL(e))},[v]);const w=x.useCallback(e=>{const s=e.target.files?Array.from(e.target.files):[];e.target.value="";const t=r.length,{rejected:i,valid:c}=s.reduce((e,r)=>null!=o&&t+e.valid.length>=o?(e.rejected.push({file:r,reason:"count"}),e):r.size>l?(e.rejected.push({file:r,reason:"size"}),e):j.test(r.name)?(e.valid.push(r),e):(e.rejected.push({file:r,reason:"type"}),e),{rejected:[],valid:[]});if(c.length>0){const e=null!=o?[...r,...c].slice(0,o):[...r,...c];a(e)}i.length>0&&n?.(i)},[r,a,l,j,o,n]),N=x.useCallback(e=>{if(c)return;const s=r.filter((r,a)=>a!==e);a(s)},[r,a,c]),q=null!=o&&r.length>=o;return m.jsxs("div",{ref:b,className:h("",d),children:[s&&m.jsx(e.Typography,{variant:"body-s-medium",color:"neutral-darker",className:"mb-1",children:s}),null!=t&&m.jsx(e.Typography,{variant:"body-xs-medium",color:"neutral-main",className:"mb-2",children:t}),m.jsxs("div",{className:"flex flex-wrap gap-2 items-center",children:[r.map((r,a)=>m.jsxs("div",{className:"relative w-16 h-16 rounded-lg bg-neutral-light overflow-hidden group",children:[r.type.startsWith("image/")&&v[a]?m.jsx("img",{src:v[a],alt:"",className:"w-full h-full object-cover"}):m.jsx("div",{className:"w-full h-full flex items-center justify-center",children:m.jsx(e.Typography,{variant:"body-xs-medium",children:"فایل"})}),!c&&m.jsx("button",{type:"button",onClick:()=>N(a),className:"absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-neutral-darker/70 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity","aria-label":g,children:m.jsx(u.X,{className:"w-3 h-3"})})]},`${r.name}-${r.size}-${r.lastModified}`)),!c&&!q&&m.jsxs("label",{htmlFor:y,className:"w-16 h-16 rounded-lg border-2 border-dashed border-neutral-main flex items-center justify-center cursor-pointer hover:border-primary-main hover:bg-primary-main/5 transition-colors",children:[m.jsx("input",{id:y,type:"file",accept:i,multiple:!0,className:"sr-only",onChange:w}),m.jsxs("div",{className:"flex flex-col items-center gap-0.5",children:[m.jsx(f,{className:"w-5 h-5 text-neutral-main"}),m.jsx(e.Typography,{variant:"body-xs-medium",color:"neutral-main",children:p})]})]})]})]})});j.displayName="ImageUpload";const y=x.forwardRef(({isOpen:e=!1,onClose:r,title:a,content:s,buttons:t,showCloseButton:i=!0,size:o="md",className:n,children:c},d)=>{const handleClose=()=>{r&&r()},p=h("bg-white rounded-[10px] shadow-lg mx-4",{sm:"max-w-sm",md:"max-w-md",lg:"max-w-lg",xl:"max-w-xl"}[o],n);return m.jsx(l.Backdrop,{isOpen:e,onClick:handleClose,blur:!0,children:m.jsx("div",{ref:d,className:p,onClick:e=>e.stopPropagation(),onKeyDown:e=>{"Escape"===e.key&&r&&r()},role:"dialog","aria-modal":"true","aria-labelledby":a?"dialog-title":void 0,children:m.jsxs("div",{className:"flex flex-col p-6 gap-8",children:[a&&m.jsx("div",{className:"flex flex-col gap-2.5",children:m.jsx("div",{className:"flex items-center justify-between pb-4 border-b border-[#ebeaf0]",children:m.jsxs("div",{className:"flex items-center justify-between gap-3 w-full flex-row-reverse",children:[m.jsx("div",{className:"text-[#590d8b] text-xl font-extrabold leading-8",children:a}),i&&m.jsx("button",{type:"button",onClick:handleClose,className:"p-1 rounded-full hover:bg-gray-100 transition-colors","aria-label":"Close dialog",children:m.jsx(u.X,{className:"w-6 h-6 text-[#a4a2bb]"})})]})})}),s&&m.jsx("div",{className:"flex flex-col gap-4",children:s}),c&&!s&&m.jsx("div",{className:"flex flex-col gap-4",children:c}),t&&m.jsx("div",{className:"flex flex-col gap-1.5",children:t})]})})})});y.displayName="Dialog";const v=x.forwardRef(({variant:e="primary",icon:r,children:a,className:s,...t},l)=>{const i=h("h-14 px-4 py-[13px] rounded-md font-bold text-base leading-[1.8] flex items-center justify-center gap-2 transition-colors",{"bg-[#590d8b] text-white hover:bg-[#4a0a75]":"primary"===e,"bg-white text-[#1a1922] border border-[#ebeaf0] hover:bg-gray-50":"secondary"===e},s);return m.jsxs("button",{type:"button",ref:l,className:i,...t,children:[a,r&&m.jsx("span",{className:"w-5 h-5",children:r})]})});v.displayName="DialogButton";const w=e.Typography,N=r.Button,q=a.Input,k=s.Tabs,B=t.Drawer,C=l.Backdrop,T=i.Breadcrumb,M=o.Pagination,R=n.Accordion,D=c.Divider,I=d.RadioGroup,L=u.Chips,P=p.Menu,U=j;exports.MobileProvider=b.MobileProvider,exports.useMobile=b.useMobile,exports.useTablet=b.useTablet,exports.Accordion=R,exports.Backdrop=C,exports.Breadcrumb=T,exports.Button=N,exports.Chips=L,exports.Dialog=y,exports.DialogButton=v,exports.Divider=D,exports.Drawer=B,exports.ImageUpload=U,exports.Input=q,exports.Menu=P,exports.Pagination=M,exports.RadioGroup=I,exports.Tabs=k,exports.Typography=w;
|
package/dist/esm/Button.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsxs as r,jsx as e}from"react/jsx-runtime";import t from"react";import i from"./utils.js";import{getTypographyClasses as a}from"./Typography.js";const n={sm:"px-4 py-2",md:"px-4 py-2.5",lg:"px-4 py-3",xl:"px-5 py-3"},l={sm:"body-s-bold",md:"body-m-bold",lg:"body-l-bold",xl:"body-xl-heavy"},d={primary:"\n bg-primary text-white\n hover:bg-primary-dark\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",secondary:"\n bg-primary-lightest text-primary-dark\n hover:bg-primary-lighter\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",tertiary:"\n bg-white border border-primary-light text-primary\n hover:bg-neutral-lighter\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",ghost:"\n bg-transparent text-primary\n hover:bg-primary-lightest\n disabled:bg-neutral-light disabled:text-neutral-darker\n "},s=t.forwardRef(({className:t,variant:s="primary",size:o="md",icon:m,iconPosition:
|
|
1
|
+
"use client";import{jsxs as r,jsx as e}from"react/jsx-runtime";import t from"react";import i from"./utils.js";import{getTypographyClasses as a}from"./Typography.js";const n={sm:"px-4 py-2",md:"px-4 py-2.5",lg:"px-4 py-3",xl:"px-5 py-3"},l={sm:"body-s-bold",md:"body-m-bold",lg:"body-l-bold",xl:"body-xl-heavy"},d={primary:"\n bg-primary text-white\n hover:bg-primary-dark\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",secondary:"\n bg-primary-lightest text-primary-dark\n hover:bg-primary-lighter\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",tertiary:"\n bg-white border border-primary-light text-primary\n hover:bg-neutral-lighter\n disabled:bg-neutral-light disabled:text-neutral-darker\n ",ghost:"\n bg-transparent text-primary\n hover:bg-primary-lightest\n disabled:bg-neutral-light disabled:text-neutral-darker\n "},s=t.forwardRef(({className:t,variant:s="primary",size:o="md",icon:m,iconPosition:p="right",children:b,loading:g=!1,disabled:y,textVariant:h,type:c="button",...x},u)=>r("button",{ref:u,type:c,className:i("inline-flex items-center justify-center rounded-lg transition-colors duration-200",n[o],d[s],a(h||l[o]),y&&"opacity-50 pointer-events-none",t),disabled:y||g,...x,children:[m&&"left"===p&&e("span",{className:"mr-2 flex items-center",children:m}),g?"...":b,m&&"right"===p&&e("span",{className:"ml-2 flex items-center",children:m})]}));s.displayName="Button";export{s as Button};
|
package/dist/esm/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Typography as e}from"./Typography.js";import{Button as r}from"./Button.js";import{Input as
|
|
1
|
+
import{Typography as e}from"./Typography.js";import{Button as r}from"./Button.js";import{Input as a}from"./Input.js";import{Tabs as t}from"./Tabs.js";import{Drawer as l}from"./Drawer.js";import{Backdrop as o}from"./Backdrop.js";import{Breadcrumb as i}from"./Breadcrumb.js";import{Pagination as s}from"./Pagination.js";import{Accordion as n}from"./Accordion.js";import{Divider as c}from"./Divider.js";import{RadioGroup as m}from"./RadioGroup.js";import{X as d,C as p}from"./chunks/Chips-Dg1jNlMl.js";import{Menu as u}from"./Menu.js";import{jsxs as f,jsx as h}from"react/jsx-runtime";import b,{useMemo as g,useId as x,useEffect as v,useCallback as y}from"react";import j from"./utils.js";import{c as w}from"./chunks/createLucideIcon-DGp0SoUT.js";export{MobileProvider,useMobile,useTablet}from"./contexts.js";import"react-dom";import"./chunks/chevron-left-4HSuTes3.js";const N=w("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);const k=b.forwardRef(({value:r,onChange:a,label:t="ارسال عکس",instruction:l,maxSize:o=10485760,accept:i="image/jpeg,image/jpg,image/png",maxCount:s,onRejected:n,disabled:c=!1,className:m,addButtonText:p="اضافه",removeButtonAriaLabel:u="حذف عکس"},b)=>{const w=g(()=>function(e){if(!e||"*"===e)return/.*/;const r=e.split(",").map(e=>e.trim().replace(/^[^/]+\//,"").replace(/^\*\./,"")).filter(Boolean);if(0===r.length)return/.*/;const a=r.map(e=>e.replace(".","\\.")).join("|");return new RegExp(`\\.(${a})$`,"i")}(i),[i]),k=x(),C=g(()=>r.map(e=>e.type.startsWith("image/")?URL.createObjectURL(e):null),[r]);v(()=>()=>{C.forEach(e=>e&&URL.revokeObjectURL(e))},[C]);const B=y(e=>{const t=e.target.files?Array.from(e.target.files):[];e.target.value="";const l=r.length,{rejected:i,valid:c}=t.reduce((e,r)=>null!=s&&l+e.valid.length>=s?(e.rejected.push({file:r,reason:"count"}),e):r.size>o?(e.rejected.push({file:r,reason:"size"}),e):w.test(r.name)?(e.valid.push(r),e):(e.rejected.push({file:r,reason:"type"}),e),{rejected:[],valid:[]});if(c.length>0){const e=null!=s?[...r,...c].slice(0,s):[...r,...c];a(e)}i.length>0&&n?.(i)},[r,a,o,w,s,n]),R=y(e=>{if(c)return;const t=r.filter((r,a)=>a!==e);a(t)},[r,a,c]),D=null!=s&&r.length>=s;return f("div",{ref:b,className:j("",m),children:[t&&h(e,{variant:"body-s-medium",color:"neutral-darker",className:"mb-1",children:t}),null!=l&&h(e,{variant:"body-xs-medium",color:"neutral-main",className:"mb-2",children:l}),f("div",{className:"flex flex-wrap gap-2 items-center",children:[r.map((r,a)=>f("div",{className:"relative w-16 h-16 rounded-lg bg-neutral-light overflow-hidden group",children:[r.type.startsWith("image/")&&C[a]?h("img",{src:C[a],alt:"",className:"w-full h-full object-cover"}):h("div",{className:"w-full h-full flex items-center justify-center",children:h(e,{variant:"body-xs-medium",children:"فایل"})}),!c&&h("button",{type:"button",onClick:()=>R(a),className:"absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-neutral-darker/70 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity","aria-label":u,children:h(d,{className:"w-3 h-3"})})]},`${r.name}-${r.size}-${r.lastModified}`)),!c&&!D&&f("label",{htmlFor:k,className:"w-16 h-16 rounded-lg border-2 border-dashed border-neutral-main flex items-center justify-center cursor-pointer hover:border-primary-main hover:bg-primary-main/5 transition-colors",children:[h("input",{id:k,type:"file",accept:i,multiple:!0,className:"sr-only",onChange:B}),f("div",{className:"flex flex-col items-center gap-0.5",children:[h(N,{className:"w-5 h-5 text-neutral-main"}),h(e,{variant:"body-xs-medium",color:"neutral-main",children:p})]})]})]})]})});k.displayName="ImageUpload";const C=b.forwardRef(({isOpen:e=!1,onClose:r,title:a,content:t,buttons:l,showCloseButton:i=!0,size:s="md",className:n,children:c},m)=>{const handleClose=()=>{r&&r()},p=j("bg-white rounded-[10px] shadow-lg mx-4",{sm:"max-w-sm",md:"max-w-md",lg:"max-w-lg",xl:"max-w-xl"}[s],n);return h(o,{isOpen:e,onClick:handleClose,blur:!0,children:h("div",{ref:m,className:p,onClick:e=>e.stopPropagation(),onKeyDown:e=>{"Escape"===e.key&&r&&r()},role:"dialog","aria-modal":"true","aria-labelledby":a?"dialog-title":void 0,children:f("div",{className:"flex flex-col p-6 gap-8",children:[a&&h("div",{className:"flex flex-col gap-2.5",children:h("div",{className:"flex items-center justify-between pb-4 border-b border-[#ebeaf0]",children:f("div",{className:"flex items-center justify-between gap-3 w-full flex-row-reverse",children:[h("div",{className:"text-[#590d8b] text-xl font-extrabold leading-8",children:a}),i&&h("button",{type:"button",onClick:handleClose,className:"p-1 rounded-full hover:bg-gray-100 transition-colors","aria-label":"Close dialog",children:h(d,{className:"w-6 h-6 text-[#a4a2bb]"})})]})})}),t&&h("div",{className:"flex flex-col gap-4",children:t}),c&&!t&&h("div",{className:"flex flex-col gap-4",children:c}),l&&h("div",{className:"flex flex-col gap-1.5",children:l})]})})})});C.displayName="Dialog";const B=b.forwardRef(({variant:e="primary",icon:r,children:a,className:t,...l},o)=>{const i=j("h-14 px-4 py-[13px] rounded-md font-bold text-base leading-[1.8] flex items-center justify-center gap-2 transition-colors",{"bg-[#590d8b] text-white hover:bg-[#4a0a75]":"primary"===e,"bg-white text-[#1a1922] border border-[#ebeaf0] hover:bg-gray-50":"secondary"===e},t);return f("button",{type:"button",ref:o,className:i,...l,children:[a,r&&h("span",{className:"w-5 h-5",children:r})]})});B.displayName="DialogButton";const R=e,D=r,M=a,L=t,T=l,z=o,U=i,$=s,A=n,I=c,O=m,P=p,E=u,G=k;export{A as Accordion,z as Backdrop,U as Breadcrumb,D as Button,P as Chips,C as Dialog,B as DialogButton,I as Divider,T as Drawer,G as ImageUpload,M as Input,E as Menu,$ as Pagination,O as RadioGroup,L as Tabs,R as Typography};
|
package/dist/types/Button.js
CHANGED
|
@@ -37,9 +37,11 @@ const variantClasses = {
|
|
|
37
37
|
disabled:bg-neutral-light disabled:text-neutral-darker
|
|
38
38
|
`,
|
|
39
39
|
};
|
|
40
|
-
const Button = React.forwardRef(({ className, variant = 'primary', size = 'md', icon, iconPosition = 'right', children, loading = false, disabled, textVariant, ...props }, ref) => {
|
|
40
|
+
const Button = React.forwardRef(({ className, variant = 'primary', size = 'md', icon, iconPosition = 'right', children, loading = false, disabled, textVariant, type = 'button', ...props }, ref) => {
|
|
41
41
|
const finalTextVariant = textVariant || defaultTextVariants[size];
|
|
42
|
-
return (jsxs("button", { ref: ref,
|
|
42
|
+
return (jsxs("button", { ref: ref,
|
|
43
|
+
// eslint-disable-next-line react/button-has-type
|
|
44
|
+
type: type, className: cn('inline-flex items-center justify-center rounded-lg transition-colors duration-200', sizeClasses[size], variantClasses[variant], getTypographyClasses(finalTextVariant), disabled && 'opacity-50 pointer-events-none', className), disabled: disabled || loading, ...props, children: [icon && iconPosition === 'left' && (jsx("span", { className: "mr-2 flex items-center", children: icon })), loading ? '...' : children, icon && iconPosition === 'right' && (jsx("span", { className: "ml-2 flex items-center", children: icon }))] }));
|
|
43
45
|
});
|
|
44
46
|
Button.displayName = 'Button';
|
|
45
47
|
|
|
@@ -12,6 +12,7 @@ export interface ButtonProps {
|
|
|
12
12
|
loading?: boolean;
|
|
13
13
|
disabled?: boolean;
|
|
14
14
|
children?: React.ReactNode;
|
|
15
|
-
onClick?:
|
|
15
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
16
|
+
type?: 'button' | 'submit' | 'reset';
|
|
16
17
|
}
|
|
17
18
|
export declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ImageUploadRejected {
|
|
3
|
+
file: File;
|
|
4
|
+
reason: 'size' | 'type' | 'count';
|
|
5
|
+
}
|
|
6
|
+
export interface ImageUploadProps {
|
|
7
|
+
/** Current list of files (controlled). */
|
|
8
|
+
value: File[];
|
|
9
|
+
/** Called when the list of files changes. */
|
|
10
|
+
onChange: (files: File[]) => void;
|
|
11
|
+
/** Label above the upload area. */
|
|
12
|
+
label?: string;
|
|
13
|
+
/** Instruction or hint text below the label. */
|
|
14
|
+
instruction?: string;
|
|
15
|
+
/** Maximum file size in bytes (default: 10MB). */
|
|
16
|
+
maxSize?: number;
|
|
17
|
+
/** Accept attribute for the file input (default: image/jpeg, image/jpg, image/png). */
|
|
18
|
+
accept?: string;
|
|
19
|
+
/** Maximum number of files allowed. New files are ignored when at limit. */
|
|
20
|
+
maxCount?: number;
|
|
21
|
+
/** Called when one or more files are rejected (e.g. too large or wrong type). */
|
|
22
|
+
onRejected?: (rejected: ImageUploadRejected[]) => void;
|
|
23
|
+
/** Disable adding/removing files. */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/** Optional class for the root wrapper. */
|
|
26
|
+
className?: string;
|
|
27
|
+
/** Text for the add button (default: "اضافه" for RTL). */
|
|
28
|
+
addButtonText?: string;
|
|
29
|
+
/** Aria label for the remove button. */
|
|
30
|
+
removeButtonAriaLabel?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare const ImageUpload: React.ForwardRefExoticComponent<ImageUploadProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ImageUploadProps } from './ImageUpload';
|
|
3
|
+
type StoryArgs = ImageUploadProps;
|
|
4
|
+
declare const _default: {
|
|
5
|
+
title: string;
|
|
6
|
+
component: React.ForwardRefExoticComponent<ImageUploadProps & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
argTypes: {
|
|
15
|
+
value: {
|
|
16
|
+
table: {
|
|
17
|
+
disable: boolean;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
onChange: {
|
|
21
|
+
table: {
|
|
22
|
+
disable: boolean;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
label: {
|
|
26
|
+
name: string;
|
|
27
|
+
control: {
|
|
28
|
+
type: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
instruction: {
|
|
32
|
+
name: string;
|
|
33
|
+
control: {
|
|
34
|
+
type: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
maxSize: {
|
|
38
|
+
name: string;
|
|
39
|
+
control: {
|
|
40
|
+
type: string;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
maxCount: {
|
|
44
|
+
name: string;
|
|
45
|
+
control: {
|
|
46
|
+
type: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
disabled: {
|
|
50
|
+
name: string;
|
|
51
|
+
control: {
|
|
52
|
+
type: string;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
addButtonText: {
|
|
56
|
+
name: string;
|
|
57
|
+
control: {
|
|
58
|
+
type: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
onRejected: {
|
|
62
|
+
table: {
|
|
63
|
+
disable: boolean;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
args: {
|
|
68
|
+
label: string;
|
|
69
|
+
instruction: string;
|
|
70
|
+
maxSize: number;
|
|
71
|
+
maxCount: undefined;
|
|
72
|
+
disabled: boolean;
|
|
73
|
+
addButtonText: string;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
export default _default;
|
|
77
|
+
export declare const Default: {
|
|
78
|
+
({ instruction, ...rest }: StoryArgs): import("react/jsx-runtime").JSX.Element;
|
|
79
|
+
storyName: string;
|
|
80
|
+
};
|
|
81
|
+
export declare const WithMaxCount: {
|
|
82
|
+
({ ...args }: StoryArgs): import("react/jsx-runtime").JSX.Element;
|
|
83
|
+
storyName: string;
|
|
84
|
+
};
|
|
85
|
+
export declare const WithRejectedCallback: {
|
|
86
|
+
({ ...args }: StoryArgs): import("react/jsx-runtime").JSX.Element;
|
|
87
|
+
storyName: string;
|
|
88
|
+
};
|
|
89
|
+
export declare const Disabled: {
|
|
90
|
+
({ ...args }: StoryArgs): import("react/jsx-runtime").JSX.Element;
|
|
91
|
+
storyName: string;
|
|
92
|
+
};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare const Divider: import("react").ForwardRefExoticComponent<import("
|
|
|
19
19
|
export declare const RadioGroup: import("react").ForwardRefExoticComponent<import("./components/RadioGroup/RadioGroup").RadioGroupProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
20
20
|
export declare const Chips: import("react").ForwardRefExoticComponent<import("./components/Chips/Chips").ChipsProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
21
21
|
export declare const Menu: import("react").ForwardRefExoticComponent<import("./components/Menu/Menu").MenuProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
22
|
+
export declare const ImageUpload: import("react").ForwardRefExoticComponent<import("./components/ImageUpload/ImageUpload").ImageUploadProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
22
23
|
export type { TypographyProps, TypographyVariant, } from './components/Typography/Typography';
|
|
23
24
|
export type { ButtonProps, ButtonVariant, ButtonSize, } from './components/Button/Button';
|
|
24
25
|
export type { InputProps } from './components/Input/Input';
|
|
@@ -33,6 +34,7 @@ export type { DividerProps } from './components/Divider/Divider';
|
|
|
33
34
|
export type { RadioGroupProps, RadioOption, } from './components/RadioGroup/RadioGroup';
|
|
34
35
|
export type { ChipsProps } from './components/Chips/Chips';
|
|
35
36
|
export type { MenuProps, MenuItem } from './components/Menu/Menu';
|
|
37
|
+
export type { ImageUploadProps, ImageUploadRejected, } from './components/ImageUpload/ImageUpload';
|
|
36
38
|
export { MobileProvider } from './contexts/MobileContext';
|
|
37
39
|
export { useMobile } from './contexts/MobileContext';
|
|
38
40
|
export { useTablet } from './contexts/MobileContext';
|
package/dist/types/index.js
CHANGED
|
@@ -11,13 +11,95 @@ import { Divider as Divider$1 } from './Divider.js';
|
|
|
11
11
|
import { RadioGroup as RadioGroup$1 } from './RadioGroup.js';
|
|
12
12
|
import { X, C as Chips$1 } from './Chips-DfvV08WT.js';
|
|
13
13
|
import { Menu as Menu$1 } from './Menu.js';
|
|
14
|
-
import {
|
|
15
|
-
import React from 'react';
|
|
14
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
15
|
+
import React, { useMemo, useId, useEffect, useCallback } from 'react';
|
|
16
16
|
import cn from './utils.js';
|
|
17
|
+
import { c as createLucideIcon } from './createLucideIcon-D-q73LTT.js';
|
|
17
18
|
export { MobileProvider, useMobile, useTablet } from './contexts.js';
|
|
18
19
|
import 'react-dom';
|
|
19
20
|
import './chevron-left-Ck6O99eF.js';
|
|
20
|
-
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @license lucide-react v0.522.0 - ISC
|
|
24
|
+
*
|
|
25
|
+
* This source code is licensed under the ISC license.
|
|
26
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
const __iconNode = [
|
|
31
|
+
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
32
|
+
["path", { d: "M12 5v14", key: "s699le" }]
|
|
33
|
+
];
|
|
34
|
+
const Plus = createLucideIcon("plus", __iconNode);
|
|
35
|
+
|
|
36
|
+
const DEFAULT_MAX_SIZE_BYTES = 10 * 1024 * 1024; // 10MB
|
|
37
|
+
const DEFAULT_ACCEPT = 'image/jpeg,image/jpg,image/png';
|
|
38
|
+
function getAcceptRegex(accept) {
|
|
39
|
+
if (!accept || accept === '*')
|
|
40
|
+
return /.*/;
|
|
41
|
+
const extensions = accept
|
|
42
|
+
.split(',')
|
|
43
|
+
.map((s) => s
|
|
44
|
+
.trim()
|
|
45
|
+
.replace(/^[^/]+\//, '')
|
|
46
|
+
.replace(/^\*\./, ''))
|
|
47
|
+
.filter(Boolean);
|
|
48
|
+
if (extensions.length === 0)
|
|
49
|
+
return /.*/;
|
|
50
|
+
const pattern = extensions.map((ext) => ext.replace('.', '\\.')).join('|');
|
|
51
|
+
return new RegExp(`\\.(${pattern})$`, 'i');
|
|
52
|
+
}
|
|
53
|
+
const ImageUpload$1 = React.forwardRef(({ value, onChange, label = 'ارسال عکس', instruction, maxSize = DEFAULT_MAX_SIZE_BYTES, accept = DEFAULT_ACCEPT, maxCount, onRejected, disabled = false, className, addButtonText = 'اضافه', removeButtonAriaLabel = 'حذف عکس', }, ref) => {
|
|
54
|
+
const acceptRegex = useMemo(() => getAcceptRegex(accept), [accept]);
|
|
55
|
+
const inputId = useId();
|
|
56
|
+
const objectUrls = useMemo(() => value.map((file) => file.type.startsWith('image/') ? URL.createObjectURL(file) : null), [value]);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
return () => {
|
|
59
|
+
objectUrls.forEach((url) => url && URL.revokeObjectURL(url));
|
|
60
|
+
};
|
|
61
|
+
}, [objectUrls]);
|
|
62
|
+
const handleFileChange = useCallback((e) => {
|
|
63
|
+
const files = e.target.files ? Array.from(e.target.files) : [];
|
|
64
|
+
e.target.value = '';
|
|
65
|
+
const currentCount = value.length;
|
|
66
|
+
const { rejected, valid } = files.reduce((acc, file) => {
|
|
67
|
+
if (maxCount != null &&
|
|
68
|
+
currentCount + acc.valid.length >= maxCount) {
|
|
69
|
+
acc.rejected.push({ file, reason: 'count' });
|
|
70
|
+
return acc;
|
|
71
|
+
}
|
|
72
|
+
if (file.size > maxSize) {
|
|
73
|
+
acc.rejected.push({ file, reason: 'size' });
|
|
74
|
+
return acc;
|
|
75
|
+
}
|
|
76
|
+
if (!acceptRegex.test(file.name)) {
|
|
77
|
+
acc.rejected.push({ file, reason: 'type' });
|
|
78
|
+
return acc;
|
|
79
|
+
}
|
|
80
|
+
acc.valid.push(file);
|
|
81
|
+
return acc;
|
|
82
|
+
}, { rejected: [], valid: [] });
|
|
83
|
+
if (valid.length > 0) {
|
|
84
|
+
const next = maxCount != null
|
|
85
|
+
? [...value, ...valid].slice(0, maxCount)
|
|
86
|
+
: [...value, ...valid];
|
|
87
|
+
onChange(next);
|
|
88
|
+
}
|
|
89
|
+
if (rejected.length > 0) {
|
|
90
|
+
onRejected?.(rejected);
|
|
91
|
+
}
|
|
92
|
+
}, [value, onChange, maxSize, acceptRegex, maxCount, onRejected]);
|
|
93
|
+
const removeImage = useCallback((index) => {
|
|
94
|
+
if (disabled)
|
|
95
|
+
return;
|
|
96
|
+
const next = value.filter((_, i) => i !== index);
|
|
97
|
+
onChange(next);
|
|
98
|
+
}, [value, onChange, disabled]);
|
|
99
|
+
const atLimit = maxCount != null && value.length >= maxCount;
|
|
100
|
+
return (jsxs("div", { ref: ref, className: cn('', className), children: [label && (jsx(Typography$1, { variant: "body-s-medium", color: "neutral-darker", className: "mb-1", children: label })), instruction != null && (jsx(Typography$1, { variant: "body-xs-medium", color: "neutral-main", className: "mb-2", children: instruction })), jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [value.map((file, index) => (jsxs("div", { className: "relative w-16 h-16 rounded-lg bg-neutral-light overflow-hidden group", children: [file.type.startsWith('image/') && objectUrls[index] ? (jsx("img", { src: objectUrls[index], alt: "", className: "w-full h-full object-cover" })) : (jsx("div", { className: "w-full h-full flex items-center justify-center", children: jsx(Typography$1, { variant: "body-xs-medium", children: "\u0641\u0627\u06CC\u0644" }) })), !disabled && (jsx("button", { type: "button", onClick: () => removeImage(index), className: "absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-neutral-darker/70 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity", "aria-label": removeButtonAriaLabel, children: jsx(X, { className: "w-3 h-3" }) }))] }, `${file.name}-${file.size}-${file.lastModified}`))), !disabled && !atLimit && (jsxs("label", { htmlFor: inputId, className: "w-16 h-16 rounded-lg border-2 border-dashed border-neutral-main flex items-center justify-center cursor-pointer hover:border-primary-main hover:bg-primary-main/5 transition-colors", children: [jsx("input", { id: inputId, type: "file", accept: accept, multiple: true, className: "sr-only", onChange: handleFileChange }), jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [jsx(Plus, { className: "w-5 h-5 text-neutral-main" }), jsx(Typography$1, { variant: "body-xs-medium", color: "neutral-main", children: addButtonText })] })] }))] })] }));
|
|
101
|
+
});
|
|
102
|
+
ImageUpload$1.displayName = 'ImageUpload';
|
|
21
103
|
|
|
22
104
|
const Dialog = React.forwardRef(({ isOpen = false, onClose, title, content, buttons, showCloseButton = true, size = 'md', className, children, }, ref) => {
|
|
23
105
|
const handleClose = () => {
|
|
@@ -64,5 +146,6 @@ const Divider = Divider$1;
|
|
|
64
146
|
const RadioGroup = RadioGroup$1;
|
|
65
147
|
const Chips = Chips$1;
|
|
66
148
|
const Menu = Menu$1;
|
|
149
|
+
const ImageUpload = ImageUpload$1;
|
|
67
150
|
|
|
68
|
-
export { Accordion, Backdrop, Breadcrumb, Button, Chips, Dialog, DialogButton, Divider, Drawer, Input, Menu, Pagination, RadioGroup, Tabs, Typography };
|
|
151
|
+
export { Accordion, Backdrop, Breadcrumb, Button, Chips, Dialog, DialogButton, Divider, Drawer, ImageUpload, Input, Menu, Pagination, RadioGroup, Tabs, Typography };
|