pillardash-ui-react 0.1.142 → 0.1.144
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/components/Form/Input/Input.js +1 -1
- package/dist/cjs/components/Form/Input/Input.js.map +1 -1
- package/dist/cjs/components/Form/Input/InputWithPrefix.js +1 -1
- package/dist/cjs/components/Form/Input/InputWithPrefix.js.map +1 -1
- package/dist/cjs/components/Form/Input/TagInput.js +1 -1
- package/dist/cjs/components/Form/Input/TagInput.js.map +1 -1
- package/dist/cjs/components/Form/Search/Search.js +1 -1
- package/dist/cjs/components/Form/Search/Search.js.map +1 -1
- package/dist/cjs/components/Form/Select/Select.js +1 -1
- package/dist/cjs/components/Form/Select/Select.js.map +1 -1
- package/dist/cjs/components/Form/Select/SelectButton.js +1 -1
- package/dist/cjs/components/Form/Select/SelectButton.js.map +1 -1
- package/dist/cjs/components/Modal/Modal.js +1 -1
- package/dist/cjs/components/Modal/Modal.js.map +1 -1
- package/dist/cjs/components/Table/Pagination.js +1 -1
- package/dist/cjs/components/Table/Pagination.js.map +1 -1
- package/dist/cjs/components/Table/Table.js +1 -1
- package/dist/cjs/components/Table/Table.js.map +1 -1
- package/dist/cjs/components/Table/TableDropdown.js +1 -1
- package/dist/cjs/components/Table/TableDropdown.js.map +1 -1
- package/dist/cjs/components/Table/TableSkeleton.js +1 -1
- package/dist/cjs/components/Table/TableSkeleton.js.map +1 -1
- package/dist/esm/components/Form/Input/Input.mjs +1 -1
- package/dist/esm/components/Form/Input/Input.mjs.map +1 -1
- package/dist/esm/components/Form/Input/InputWithPrefix.mjs +1 -1
- package/dist/esm/components/Form/Input/InputWithPrefix.mjs.map +1 -1
- package/dist/esm/components/Form/Input/TagInput.mjs +1 -1
- package/dist/esm/components/Form/Input/TagInput.mjs.map +1 -1
- package/dist/esm/components/Form/Search/Search.mjs +1 -1
- package/dist/esm/components/Form/Search/Search.mjs.map +1 -1
- package/dist/esm/components/Form/Select/Select.mjs +1 -1
- package/dist/esm/components/Form/Select/Select.mjs.map +1 -1
- package/dist/esm/components/Form/Select/SelectButton.mjs +1 -1
- package/dist/esm/components/Form/Select/SelectButton.mjs.map +1 -1
- package/dist/esm/components/Modal/Modal.mjs +1 -1
- package/dist/esm/components/Modal/Modal.mjs.map +1 -1
- package/dist/esm/components/Table/Pagination.mjs +1 -1
- package/dist/esm/components/Table/Pagination.mjs.map +1 -1
- package/dist/esm/components/Table/Table.mjs +1 -1
- package/dist/esm/components/Table/Table.mjs.map +1 -1
- package/dist/esm/components/Table/TableDropdown.mjs +1 -1
- package/dist/esm/components/Table/TableDropdown.mjs.map +1 -1
- package/dist/esm/components/Table/TableSkeleton.mjs +1 -1
- package/dist/esm/components/Table/TableSkeleton.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsxs as
|
|
1
|
+
import{jsxs as r,jsx as e}from"react/jsx-runtime";import{useState as a}from"react";function t(t){var o=t.placeholder,l=void 0===o?"Search...":o,n=t.onSearch,c=t.className,i=void 0===c?"":c,d=a(""),s=d[0],u=d[1];return r("div",{className:"relative ".concat(i),children:[e("input",{type:"text",value:s,onChange:function(r){r.preventDefault(),u(r.target.value),n(s)},placeholder:l,className:"w-full rounded-lg border border-gray-200 bg-white py-2 pl-8 pr-4 text-sm focus:outline-none focus:ring-1 focus:ring-primary dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-500"}),r("svg",{className:"absolute left-2 top-1/2 -translate-y-1/2 transform text-gray-400 dark:text-gray-500",width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e("circle",{cx:"11",cy:"11",r:"8"}),e("line",{x1:"21",y1:"21",x2:"16.65",y2:"16.65"})]})]})}export{t as default};
|
|
2
2
|
//# sourceMappingURL=Search.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Search.mjs","sources":["../../../../../src/components/Form/Search/Search.tsx"],"sourcesContent":["import { ChangeEvent, useState } from \"react\";\n\nexport interface SearchProps {\n placeholder?: string;\n onSearch: (query: string) => void;\n className?: string;\n disabled?: boolean;\n}\n\nexport default function Search({\n placeholder = \"Search...\",\n onSearch,\n className = \"\",\n}: SearchProps) {\n const [query, setQuery] = useState(\"\");\n\n function handleSearch(e: ChangeEvent<HTMLInputElement>) {\n e.preventDefault();\n setQuery(e.target.value);\n onSearch(query);\n }\n\n return (\n <div className={`relative ${className}`}>\n <input\n type='text'\n value={query}\n onChange={handleSearch}\n placeholder={placeholder}\n className='w-full rounded-lg border border-gray-200 bg-white py-2 pl-8 pr-4 text-sm focus:outline-none focus:ring-1 focus:ring-primary'\n />\n <svg\n className='absolute left-2 top-1/2 -translate-y-1/2 transform text-gray-400'\n width='16'\n height='16'\n viewBox='0 0 24 24'\n fill='none'\n stroke='currentColor'\n strokeWidth='2'\n >\n <circle cx='11' cy='11' r='8' />\n <line x1='21' y1='21' x2='16.65' y2='16.65' />\n </svg>\n </div>\n );\n}\n"],"names":["Search","_a","_b","placeholder","onSearch","_c","className","_d","useState","query","setQuery","_jsxs","_jsx","type","value","onChange","e","preventDefault","target","width","height","viewBox","fill","stroke","strokeWidth","cx","cy","r","x1","y1","x2","y2"],"mappings":"mFASc,SAAUA,EAAOC,GAC3B,IAAAC,EAAAD,EAAAE,YAAAA,OAAW,IAAAD,EAAG,cACdE,EAAQH,EAAAG,SACRC,EAAAJ,EAAAK,UAAAA,OAAS,IAAAD,EAAG,GAAEA,EAERE,EAAoBC,EAAS,IAA5BC,EAAKF,EAAA,GAAEG,EAAQH,EAAA,GAQtB,OACII,SAAKL,UAAW,mBAAYA,aACxBM,EAAA,QAAA,CACIC,KAAK,OACLC,MAAOL,EACPM,SAXZ,SAAsBC,GAClBA,EAAEC,iBACFP,EAASM,EAAEE,OAAOJ,OAClBV,EAASK,EACb,EAQYN,YAAaA,EACbG,UAAU,
|
|
1
|
+
{"version":3,"file":"Search.mjs","sources":["../../../../../src/components/Form/Search/Search.tsx"],"sourcesContent":["import { ChangeEvent, useState } from \"react\";\n\nexport interface SearchProps {\n placeholder?: string;\n onSearch: (query: string) => void;\n className?: string;\n disabled?: boolean;\n}\n\nexport default function Search({\n placeholder = \"Search...\",\n onSearch,\n className = \"\",\n}: SearchProps) {\n const [query, setQuery] = useState(\"\");\n\n function handleSearch(e: ChangeEvent<HTMLInputElement>) {\n e.preventDefault();\n setQuery(e.target.value);\n onSearch(query);\n }\n\n return (\n <div className={`relative ${className}`}>\n <input\n type='text'\n value={query}\n onChange={handleSearch}\n placeholder={placeholder}\n className='w-full rounded-lg border border-gray-200 bg-white py-2 pl-8 pr-4 text-sm focus:outline-none focus:ring-1 focus:ring-primary dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-500'\n />\n <svg\n className='absolute left-2 top-1/2 -translate-y-1/2 transform text-gray-400 dark:text-gray-500'\n width='16'\n height='16'\n viewBox='0 0 24 24'\n fill='none'\n stroke='currentColor'\n strokeWidth='2'\n >\n <circle cx='11' cy='11' r='8' />\n <line x1='21' y1='21' x2='16.65' y2='16.65' />\n </svg>\n </div>\n );\n}\n"],"names":["Search","_a","_b","placeholder","onSearch","_c","className","_d","useState","query","setQuery","_jsxs","_jsx","type","value","onChange","e","preventDefault","target","width","height","viewBox","fill","stroke","strokeWidth","cx","cy","r","x1","y1","x2","y2"],"mappings":"mFASc,SAAUA,EAAOC,GAC3B,IAAAC,EAAAD,EAAAE,YAAAA,OAAW,IAAAD,EAAG,cACdE,EAAQH,EAAAG,SACRC,EAAAJ,EAAAK,UAAAA,OAAS,IAAAD,EAAG,GAAEA,EAERE,EAAoBC,EAAS,IAA5BC,EAAKF,EAAA,GAAEG,EAAQH,EAAA,GAQtB,OACII,SAAKL,UAAW,mBAAYA,aACxBM,EAAA,QAAA,CACIC,KAAK,OACLC,MAAOL,EACPM,SAXZ,SAAsBC,GAClBA,EAAEC,iBACFP,EAASM,EAAEE,OAAOJ,OAClBV,EAASK,EACb,EAQYN,YAAaA,EACbG,UAAU,mNAEdK,EAAA,MAAA,CACIL,UAAU,sFACVa,MAAM,KACNC,OAAO,KACPC,QAAQ,YACRC,KAAK,OACLC,OAAO,eACPC,YAAY,cAEZZ,EAAA,SAAA,CAAQa,GAAG,KAAKC,GAAG,KAAKC,EAAE,MAC1Bf,UAAMgB,GAAG,KAAKC,GAAG,KAAKC,GAAG,QAAQC,GAAG,eAIpD"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{__spreadArray as e}from"../../../node_modules/tslib/tslib.es6.mjs";import{jsxs as t,jsx as r,Fragment as
|
|
1
|
+
import{__spreadArray as e}from"../../../node_modules/tslib/tslib.es6.mjs";import{jsxs as t,jsx as r,Fragment as a}from"react/jsx-runtime";import{useState as n,useRef as l,useEffect as i}from"react";import{X as o,ChevronDown as u,Loader2 as c}from"lucide-react";function d(d){var s,m=d.options,f=d.placeholder,v=void 0===f?"Select an option":f,g=d.onChange,p=d.value,x=d.size,h=void 0===x?"md":x,y=d.className,b=void 0===y?"":y,k=d.name,N=d.id,w=d.disabled,C=void 0!==w&&w,S=d.label,A=d.required,j=d.error,z=d.helpText,L=d.fullWidth,B=void 0===L||L,T=d.searchable,F=void 0!==T&&T,R=d.onSearch,D=d.isSearching,E=void 0!==D&&D,M=d.searchDebounceMs,q=void 0===M?300:M,H=d.multiple,I=void 0!==H&&H,O=d.maxSelected,P=d.showSelectedCount,W=void 0!==P&&P,_=d.closeOnSelect,G=d.showSelectAll,J=void 0===G||G,K=n(!1),Q=K[0],U=K[1],V=n(""),X=V[0],Y=V[1],Z=n("bottom"),$=Z[0],ee=Z[1],te=void 0!==_?_:!I,re=n((function(){if(!p)return[];if(I&&Array.isArray(p))return p.map((function(e){return m.find((function(t){return t.value==e}))})).filter(Boolean);if(!I){var e=m.find((function(e){return e.value==p}));return e?[e]:[]}return[]})),ae=re[0],ne=re[1],le=l(null),ie=l(null),oe=l(null);i((function(){if(I&&Array.isArray(p))ne(p.map((function(e){return m.find((function(t){return t.value==e}))})).filter(Boolean));else if(I)""!==p&&null!==p&&null!=p||ne([]);else{var e=m.find((function(e){return e.value==p}));ne(e?[e]:[])}}),[p,m,I]),i((function(){if(Q&&le.current){var e=le.current.getBoundingClientRect(),t=window.innerHeight-e.bottom,r=e.top;ee(t<250&&r>250?"top":"bottom")}}),[Q]),i((function(){if(R&&X)return oe.current&&clearTimeout(oe.current),oe.current=setTimeout((function(){R(X)}),q),function(){oe.current&&clearTimeout(oe.current)}}),[X,R,q]);var ue=F&&!R?m.filter((function(e){return(e.label||e.value).toLowerCase().includes(X.toLowerCase())})):m;i((function(){var e=function(e){le.current&&!le.current.contains(e.target)&&(U(!1),Y(""))};return document.addEventListener("mousedown",e),function(){document.removeEventListener("mousedown",e)}}),[]);var ce="top"===$?"bottom-full mb-1":"top-full mt-1";return t("div",{ref:le,className:"".concat(B?"w-full":"w-fit"," mb-4"),children:[S&&t("label",{htmlFor:N,className:"mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300",children:[S,A&&r("span",{className:"ml-1 text-red-500",children:"*"})]}),t("div",{className:"relative",children:[t("button",{type:"button",className:"flex items-center justify-between rounded-lg border ".concat(j?"border-red-500":"border-gray-200 dark:border-gray-700"," bg-gray-100 shadow-sm dark:bg-gray-800 ").concat({sm:"text-xs px-3 py-1.5 text-sm min-h-[32px]",md:"text-sm px-4 py-2 text-base min-h-[40px]",lg:"text-base px-4 py-3 text-lg min-h-[48px]"}[h]," text-gray-700 hover:border-gray-300 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 dark:text-gray-200 dark:hover:border-gray-600 ").concat(C?"cursor-not-allowed bg-gray-50 opacity-50 dark:bg-gray-700":""," ").concat(b," ").concat(B?"w-full":""," transition-all duration-200"),onClick:function(){return!C&&U(!Q)},disabled:C,id:N,"aria-haspopup":"listbox","aria-expanded":Q,children:[r("div",{className:"flex-1 flex items-center gap-1 min-w-0",children:I&&ae.length>0?t("div",{className:"flex flex-wrap gap-1 flex-1",children:[ae.slice(0,3).map((function(e){return t("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 bg-primary-100 text-primary-800 text-sm rounded-md",children:[r("span",{className:"truncate max-w-[120px]",children:e.label||e.value}),r(o,{className:"h-3 w-3 cursor-pointer hover:text-primary-900",onClick:function(t){return function(e,t){t.stopPropagation();var r=ae.filter((function(t){return t.value!==e.value}));ne(r);var a=I?r.map((function(e){return e.value})):"";g({target:{id:N||"",value:a}})}(e,t)}})]},e.value)})),ae.length>3&&t("span",{className:"px-1 text-sm text-gray-500 dark:text-gray-400",children:["+",ae.length-3," more"]})]}):r("span",{className:"truncate ".concat(0===ae.length?"text-gray-400 dark:text-gray-500":"text-gray-700 dark:text-gray-200"),children:function(){var e,t,r,a;return 0===ae.length?v:I?W&&ae.length>2?"".concat(ae.length," items selected"):ae.length<=2?ae.map((function(e){return e.label||e.value})).join(", "):"".concat((null===(r=ae[0])||void 0===r?void 0:r.label)||(null===(a=ae[0])||void 0===a?void 0:a.value)," +").concat(ae.length-1," more"):(null===(e=ae[0])||void 0===e?void 0:e.label)||(null===(t=ae[0])||void 0===t?void 0:t.value)}()})}),r(u,{className:"ml-2 h-4 w-4 flex-shrink-0 text-gray-400 transition-transform dark:text-gray-500 ".concat(Q?"rotate-180 transform":"")})]}),Q&&t("div",{ref:ie,className:"absolute z-[9999] w-full rounded-lg border border-gray-200 bg-white shadow-xl dark:border-gray-700 dark:bg-gray-800 ".concat(ce),role:"listbox",style:{zIndex:9999,position:"absolute"},children:[F&&r("div",{className:"sticky top-0 z-[10000] border-b border-gray-100 bg-white p-3 dark:border-gray-700 dark:bg-gray-800",children:t("div",{className:"relative",children:[r("input",{type:"text",className:"w-full rounded-md border border-gray-200 bg-white px-3 py-2 pr-8 text-sm transition-all duration-200 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:placeholder-gray-500",placeholder:R?"Search...":"Filter...",value:X,onChange:function(e){return Y(e.target.value)},autoFocus:!0}),E&&r(c,{className:"absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-gray-400 dark:text-gray-500"})]})}),r("div",{className:"max-h-60 overflow-auto py-1",children:E?t("div",{className:"px-3 py-8 text-center",children:[r(c,{className:"h-6 w-6 animate-spin text-primary-500 mx-auto mb-2"}),r("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:"Searching..."})]}):ue.length>0?t(a,{children:[I&&J&&t("div",{className:"border-b border-gray-100 dark:border-gray-700",children:[t("div",{className:"px-3 py-2 flex items-center justify-between",children:[r("button",{type:"button",onClick:function(){if(I){var t,r=ue.filter((function(e){return!e.disabled}));if(r.every((function(e){return ae.some((function(t){return t.value===e.value}))})))t=ae.filter((function(e){return!r.some((function(t){return t.value===e.value}))}));else{var a=r.filter((function(e){return!ae.some((function(t){return t.value===e.value}))}));if(void 0!==O){var n=O-ae.length;t=e(e([],ae,!0),a.slice(0,n),!0)}else t=e(e([],ae,!0),a,!0)}ne(t);var l=t.map((function(e){return e.value}));g({target:{id:N||"",value:l}})}},className:"text-sm font-medium text-primary-600 hover:text-primary-700 transition-colors",children:function(){if(!I||0===ue.length)return!1;var e=ue.filter((function(e){return!e.disabled}));return e.length>0&&e.every((function(e){return ae.some((function(t){return t.value===e.value}))}))}()?"Deselect All":"Select All"}),ae.length>0&&r("button",{type:"button",onClick:function(){I&&(ne([]),g({target:{id:N||"",value:[]}}))},className:"text-sm font-medium text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200",children:"Clear All"})]}),ae.length>0&&t("div",{className:"px-3 pb-2 text-xs text-gray-500 dark:text-gray-400",children:[ae.length," selected",O&&" of ".concat(O," max")]})]}),ue.map((function(a){var n=function(e){return ae.some((function(t){return t.value===e.value}))}(a),l=a.disabled||void 0!==O&&!n&&ae.length>=O;return t("div",{className:"cursor-pointer px-3 py-2 flex items-center justify-between transition-colors duration-150 ".concat(n?"bg-primary-50 text-primary-700":"text-gray-700 hover:bg-gray-50 dark:text-gray-200 dark:hover:bg-gray-700"," ").concat(l?"cursor-not-allowed text-gray-400 opacity-50 hover:bg-white dark:text-gray-500 dark:hover:bg-gray-800":""),onClick:function(){return!l&&function(t){var r;if(!t.disabled){var a;if(I)if(ae.some((function(e){return e.value===t.value})))a=ae.filter((function(e){return e.value!==t.value}));else{if(O&&ae.length>=O)return;a=e(e([],ae,!0),[t],!1)}else a=[t];ne(a);var n=I?a.map((function(e){return e.value})):(null===(r=a[0])||void 0===r?void 0:r.value)||"";g({target:{id:N||"",value:n}}),te&&(U(!1),Y(""))}}(a)},role:"option","aria-selected":n,"aria-disabled":l,children:[r("span",{className:"flex-1 text-sm font-medium",children:a.label||a.value}),I&&n&&r("div",{className:"w-4 h-4 bg-primary-500 rounded-sm flex items-center justify-center",children:r("svg",{className:"w-3 h-3 text-white",fill:"currentColor",viewBox:"0 0 20 20",children:r("path",{fillRule:"evenodd",d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",clipRule:"evenodd"})})})]},a.value)}))]}):r("div",{className:"px-3 py-8 text-center",children:r("p",{className:"text-sm text-gray-500 dark:text-gray-400",children:X?"No results found":"No options available"})})})]})]}),j&&r("p",{className:"mt-1 text-sm text-red-600",children:j}),z&&!j&&r("p",{className:"mt-1 text-sm text-gray-500 dark:text-gray-400",children:z}),k&&r(a,{children:I?ae.map((function(e,t){return r("input",{type:"hidden",name:"".concat(k,"[]"),value:e.value},"".concat(e.value,"-").concat(t))})):r("input",{type:"hidden",name:k,value:(null===(s=ae[0])||void 0===s?void 0:s.value)||""})})]})}export{d as default};
|
|
2
2
|
//# sourceMappingURL=Select.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.mjs","sources":["../../../../../src/components/Form/Select/Select.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport { ChevronDown, X, Loader2 } from \"lucide-react\";\n\nexport interface SelectOption {\n value: string;\n label?: string;\n disabled?: boolean;\n}\n\nexport type SelectProps = {\n options: SelectOption[];\n placeholder?: string;\n onChange: (value: React.ChangeEvent<HTMLSelectElement>) => void;\n value?: string | string[];\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n name?: string;\n id?: string;\n disabled?: boolean;\n label?: string;\n required?: boolean;\n error?: string;\n helpText?: string;\n fullWidth?: boolean;\n searchable?: boolean;\n\n // NEW: Backend search props\n onSearch?: (searchTerm: string) => void | Promise<void>;\n isSearching?: boolean;\n searchDebounceMs?: number;\n\n multiple?: boolean;\n maxSelected?: number;\n showSelectedCount?: boolean;\n closeOnSelect?: boolean;\n showSelectAll?: boolean;\n};\n\nexport default function Select({\n options,\n placeholder = \"Select an option\",\n onChange,\n value,\n size = \"md\",\n className = \"\",\n name,\n id,\n disabled = false,\n label,\n required,\n error,\n helpText,\n fullWidth = true,\n searchable = false,\n onSearch,\n isSearching = false,\n searchDebounceMs = 300,\n multiple = false,\n maxSelected,\n showSelectedCount = false,\n closeOnSelect,\n showSelectAll = true,\n}: SelectProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [searchTerm, setSearchTerm] = useState(\"\");\n const [dropdownPosition, setDropdownPosition] = useState<\"bottom\" | \"top\">(\n \"bottom\",\n );\n\n const shouldCloseOnSelect =\n closeOnSelect !== undefined ? closeOnSelect : !multiple;\n\n const [selectedOptions, setSelectedOptions] = useState<SelectOption[]>(() => {\n if (!value) return [];\n\n if (multiple && Array.isArray(value)) {\n return value\n .map((val) => options.find((option) => option.value == val))\n .filter(Boolean) as SelectOption[];\n } else if (!multiple) {\n const option = options.find((option) => option.value == value);\n return option ? [option] : [];\n }\n return [];\n });\n\n const selectRef = useRef<HTMLDivElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const searchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (multiple && Array.isArray(value)) {\n setSelectedOptions(\n value\n .map((val) => options.find((option) => option.value == val))\n .filter(Boolean) as SelectOption[],\n );\n } else if (!multiple) {\n const option = options.find((option) => option.value == value);\n setSelectedOptions(option ? [option] : []);\n } else if (value === \"\" || value === null || value == undefined) {\n setSelectedOptions([]);\n }\n }, [value, options, multiple]);\n\n useEffect(() => {\n if (isOpen && selectRef.current) {\n const selectRect = selectRef.current.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const dropdownHeight = 250;\n const spaceBelow = viewportHeight - selectRect.bottom;\n const spaceAbove = selectRect.top;\n\n if (spaceBelow < dropdownHeight && spaceAbove > dropdownHeight) {\n setDropdownPosition(\"top\");\n } else {\n setDropdownPosition(\"bottom\");\n }\n }\n }, [isOpen]);\n\n // Handle search with debouncing\n useEffect(() => {\n if (!onSearch || !searchTerm) return;\n\n if (searchTimeoutRef.current) {\n clearTimeout(searchTimeoutRef.current);\n }\n\n searchTimeoutRef.current = setTimeout(() => {\n onSearch(searchTerm);\n }, searchDebounceMs);\n\n return () => {\n if (searchTimeoutRef.current) {\n clearTimeout(searchTimeoutRef.current);\n }\n };\n }, [searchTerm, onSearch, searchDebounceMs]);\n\n // Filter options based on search term if using client-side search\n const filteredOptions =\n searchable && !onSearch\n ? options.filter((option) =>\n (option.label || option.value)\n .toLowerCase()\n .includes(searchTerm.toLowerCase()),\n )\n : options;\n\n const handleSelect = (option: SelectOption) => {\n if (option.disabled) return;\n\n let newSelectedOptions: SelectOption[];\n\n if (multiple) {\n const isAlreadySelected = selectedOptions.some(\n (selected) => selected.value === option.value,\n );\n\n if (isAlreadySelected) {\n newSelectedOptions = selectedOptions.filter(\n (selected) => selected.value !== option.value,\n );\n } else {\n if (maxSelected && selectedOptions.length >= maxSelected) {\n return;\n }\n newSelectedOptions = [...selectedOptions, option];\n }\n } else {\n newSelectedOptions = [option];\n }\n\n setSelectedOptions(newSelectedOptions);\n\n const eventValue = multiple\n ? newSelectedOptions.map((opt) => opt.value)\n : newSelectedOptions[0]?.value || \"\";\n\n onChange({\n target: {\n id: id || \"\",\n value: eventValue,\n },\n } as React.ChangeEvent<HTMLSelectElement>);\n\n if (shouldCloseOnSelect) {\n setIsOpen(false);\n setSearchTerm(\"\");\n }\n };\n\n const handleSelectAll = () => {\n if (!multiple) return;\n\n const selectableOptions = filteredOptions.filter((opt) => !opt.disabled);\n const allSelected = selectableOptions.every((option) =>\n selectedOptions.some((selected) => selected.value === option.value),\n );\n\n let newSelectedOptions: SelectOption[];\n\n if (allSelected) {\n newSelectedOptions = selectedOptions.filter(\n (selected) =>\n !selectableOptions.some((option) => option.value === selected.value),\n );\n } else {\n const optionsToAdd = selectableOptions.filter(\n (option) =>\n !selectedOptions.some((selected) => selected.value === option.value),\n );\n\n if (maxSelected !== undefined) {\n const remainingSlots = maxSelected - selectedOptions.length;\n newSelectedOptions = [\n ...selectedOptions,\n ...optionsToAdd.slice(0, remainingSlots),\n ];\n } else {\n newSelectedOptions = [...selectedOptions, ...optionsToAdd];\n }\n }\n\n setSelectedOptions(newSelectedOptions);\n\n const eventValue = newSelectedOptions.map((opt) => opt.value);\n\n onChange({\n target: {\n id: id || \"\",\n value: eventValue,\n },\n } as unknown as React.ChangeEvent<HTMLSelectElement>);\n };\n\n const handleClearAll = () => {\n if (!multiple) return;\n\n setSelectedOptions([]);\n\n onChange({\n target: {\n id: id || \"\",\n value: [],\n },\n } as unknown as React.ChangeEvent<HTMLSelectElement>);\n };\n\n const removeOption = (optionToRemove: SelectOption, e: React.MouseEvent) => {\n e.stopPropagation();\n const newSelectedOptions = selectedOptions.filter(\n (option) => option.value !== optionToRemove.value,\n );\n setSelectedOptions(newSelectedOptions);\n\n const eventValue = multiple\n ? newSelectedOptions.map((opt) => opt.value)\n : \"\";\n\n onChange({\n target: {\n id: id || \"\",\n value: eventValue,\n },\n } as React.ChangeEvent<HTMLSelectElement>);\n };\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n selectRef.current &&\n !selectRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n setSearchTerm(\"\");\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }, []);\n\n const sizeClasses = {\n sm: \"text-xs px-3 py-1.5 text-sm min-h-[32px]\",\n md: \"text-sm px-4 py-2 text-base min-h-[40px]\",\n lg: \"text-base px-4 py-3 text-lg min-h-[48px]\",\n };\n\n const getDisplayText = () => {\n if (selectedOptions.length === 0) return placeholder;\n\n if (!multiple) {\n return selectedOptions[0]?.label || selectedOptions[0]?.value;\n }\n\n if (showSelectedCount && selectedOptions.length > 2) {\n return `${selectedOptions.length} items selected`;\n }\n\n if (selectedOptions.length <= 2) {\n return selectedOptions.map((opt) => opt.label || opt.value).join(\", \");\n }\n\n return `${selectedOptions[0]?.label || selectedOptions[0]?.value} +${selectedOptions.length - 1} more`;\n };\n\n const isOptionSelected = (option: SelectOption) => {\n return selectedOptions.some((selected) => selected.value === option.value);\n };\n\n const areAllFilteredSelected = () => {\n if (!multiple || filteredOptions.length === 0) return false;\n const selectableOptions = filteredOptions.filter((opt) => !opt.disabled);\n return (\n selectableOptions.length > 0 &&\n selectableOptions.every((option) =>\n selectedOptions.some((selected) => selected.value === option.value),\n )\n );\n };\n\n const areSomeFilteredSelected = () => {\n if (!multiple || filteredOptions.length === 0) return false;\n const selectableOptions = filteredOptions.filter((opt) => !opt.disabled);\n return (\n selectableOptions.some((option) =>\n selectedOptions.some((selected) => selected.value === option.value),\n ) && !areAllFilteredSelected()\n );\n };\n\n const dropdownPositionClasses =\n dropdownPosition === \"top\" ? \"bottom-full mb-1\" : \"top-full mt-1\";\n\n return (\n <div ref={selectRef} className={`${fullWidth ? \"w-full\" : \"w-fit\"} mb-4`}>\n {label && (\n <label\n htmlFor={id}\n className=\"mb-1 block text-sm font-medium text-gray-700\"\n >\n {label}\n {required && <span className=\"ml-1 text-red-500\">*</span>}\n </label>\n )}\n\n <div className=\"relative\">\n <button\n type=\"button\"\n className={`flex items-center justify-between rounded-lg border ${\n error ? \"border-red-500\" : \"border-gray-200\"\n } bg-gray-100 shadow-sm ${\n sizeClasses[size]\n } text-gray-700 hover:border-gray-300 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 ${\n disabled ? \"cursor-not-allowed bg-gray-50 opacity-50\" : \"\"\n } ${className} ${fullWidth ? \"w-full\" : \"\"} transition-all duration-200`}\n onClick={() => !disabled && setIsOpen(!isOpen)}\n disabled={disabled}\n id={id}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n >\n <div className=\"flex-1 flex items-center gap-1 min-w-0\">\n {multiple && selectedOptions.length > 0 ? (\n <div className=\"flex flex-wrap gap-1 flex-1\">\n {selectedOptions.slice(0, 3).map((option) => (\n <span\n key={option.value}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 bg-primary-100 text-primary-800 text-sm rounded-md\"\n >\n <span className=\"truncate max-w-[120px]\">\n {option.label || option.value}\n </span>\n <X\n className=\"h-3 w-3 cursor-pointer hover:text-primary-900\"\n onClick={(e) => removeOption(option, e)}\n />\n </span>\n ))}\n {selectedOptions.length > 3 && (\n <span className=\"text-sm text-gray-500 px-1\">\n +{selectedOptions.length - 3} more\n </span>\n )}\n </div>\n ) : (\n <span\n className={`truncate ${selectedOptions.length === 0 ? \"text-gray-400\" : \"text-gray-700\"}`}\n >\n {getDisplayText()}\n </span>\n )}\n </div>\n <ChevronDown\n className={`ml-2 h-4 w-4 text-gray-400 transition-transform flex-shrink-0 ${\n isOpen ? \"rotate-180 transform\" : \"\"\n }`}\n />\n </button>\n\n {isOpen && (\n <div\n ref={dropdownRef}\n className={`absolute z-[9999] w-full rounded-lg border border-gray-200 bg-white shadow-xl ${dropdownPositionClasses}`}\n role=\"listbox\"\n style={{\n zIndex: 9999,\n position: \"absolute\",\n }}\n >\n {searchable && (\n <div className=\"sticky top-0 border-b border-gray-100 bg-white p-3 z-[10000]\">\n <div className=\"relative\">\n <input\n type=\"text\"\n className=\"w-full rounded-md border border-gray-200 px-3 py-2 pr-8 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200\"\n placeholder={onSearch ? \"Search...\" : \"Filter...\"}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n autoFocus\n />\n {isSearching && (\n <Loader2 className=\"absolute right-2 top-1/2 -translate-y-1/2 h-4 w-4 animate-spin text-gray-400\" />\n )}\n </div>\n </div>\n )}\n\n <div className=\"max-h-60 overflow-auto py-1\">\n {isSearching ? (\n <div className=\"px-3 py-8 text-center\">\n <Loader2 className=\"h-6 w-6 animate-spin text-primary-500 mx-auto mb-2\" />\n <p className=\"text-sm text-gray-500\">Searching...</p>\n </div>\n ) : filteredOptions.length > 0 ? (\n <>\n {multiple && showSelectAll && (\n <div className=\"border-b border-gray-100\">\n <div className=\"px-3 py-2 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={handleSelectAll}\n className=\"text-sm font-medium text-primary-600 hover:text-primary-700 transition-colors\"\n >\n {areAllFilteredSelected()\n ? \"Deselect All\"\n : \"Select All\"}\n </button>\n {selectedOptions.length > 0 && (\n <button\n type=\"button\"\n onClick={handleClearAll}\n className=\"text-sm font-medium text-gray-500 hover:text-gray-700 transition-colors\"\n >\n Clear All\n </button>\n )}\n </div>\n {selectedOptions.length > 0 && (\n <div className=\"px-3 pb-2 text-xs text-gray-500\">\n {selectedOptions.length} selected\n {maxSelected && ` of ${maxSelected} max`}\n </div>\n )}\n </div>\n )}\n {filteredOptions.map((option) => {\n const isSelected = isOptionSelected(option);\n const isDisabled =\n option.disabled ||\n (maxSelected !== undefined &&\n !isSelected &&\n selectedOptions.length >= maxSelected);\n\n return (\n <div\n key={option.value}\n className={`cursor-pointer px-3 py-2 flex items-center justify-between transition-colors duration-150 ${\n isSelected\n ? \"bg-primary-50 text-primary-700\"\n : \"text-gray-700 hover:bg-gray-50\"\n } ${\n isDisabled\n ? \"cursor-not-allowed text-gray-400 hover:bg-white opacity-50\"\n : \"\"\n }`}\n onClick={() => !isDisabled && handleSelect(option)}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={isDisabled}\n >\n <span className=\"flex-1 text-sm font-medium\">\n {option.label || option.value}\n </span>\n {multiple && isSelected && (\n <div className=\"w-4 h-4 bg-primary-500 rounded-sm flex items-center justify-center\">\n <svg\n className=\"w-3 h-3 text-white\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n )}\n </div>\n );\n })}\n </>\n ) : (\n <div className=\"px-3 py-8 text-center\">\n <p className=\"text-sm text-gray-500\">\n {searchTerm ? \"No results found\" : \"No options available\"}\n </p>\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n\n {error && <p className=\"mt-1 text-sm text-red-600\">{error}</p>}\n {helpText && !error && (\n <p className=\"mt-1 text-sm text-gray-500\">{helpText}</p>\n )}\n\n {name && (\n <>\n {multiple ? (\n selectedOptions.map((option, index) => (\n <input\n key={`${option.value}-${index}`}\n type=\"hidden\"\n name={`${name}[]`}\n value={option.value}\n />\n ))\n ) : (\n <input\n type=\"hidden\"\n name={name}\n value={selectedOptions[0]?.value || \"\"}\n />\n )}\n </>\n )}\n </div>\n );\n}\n\n// Demo Component\nfunction Demo() {\n const [selectedValue, setSelectedValue] = useState(\"\");\n const [options, setOptions] = useState([\n { value: \"1\", label: \"Apple\" },\n { value: \"2\", label: \"Banana\" },\n { value: \"3\", label: \"Cherry\" },\n ]);\n const [isSearching, setIsSearching] = useState(false);\n\n const handleBackendSearch = async (searchTerm: string) => {\n console.log(\"Searching backend for:\", searchTerm);\n setIsSearching(true);\n\n // Simulate API call\n await new Promise((resolve) => setTimeout(resolve, 800));\n\n // Mock backend filtering\n const allFruits = [\n { value: \"1\", label: \"Apple\" },\n { value: \"2\", label: \"Banana\" },\n { value: \"3\", label: \"Cherry\" },\n { value: \"4\", label: \"Date\" },\n { value: \"5\", label: \"Elderberry\" },\n { value: \"6\", label: \"Fig\" },\n { value: \"7\", label: \"Grape\" },\n { value: \"8\", label: \"Honeydew\" },\n ];\n\n const filtered = searchTerm\n ? allFruits.filter((fruit) =>\n fruit.label.toLowerCase().includes(searchTerm.toLowerCase()),\n )\n : allFruits;\n\n setOptions(filtered);\n setIsSearching(false);\n };\n\n return (\n <div className=\"max-w-2xl mx-auto p-8 space-y-8\">\n <div>\n <h1 className=\"text-3xl font-bold mb-2\">Select with Backend Search</h1>\n <p className=\"text-gray-600\">\n Type in the search box to trigger backend filtering (simulated with\n 800ms delay)\n </p>\n </div>\n\n <Select\n label=\"Choose a fruit\"\n placeholder=\"Select or search for a fruit\"\n options={options}\n value={selectedValue}\n onChange={(e) => setSelectedValue(e.target.value as string)}\n searchable={true}\n onSearch={handleBackendSearch}\n isSearching={isSearching}\n searchDebounceMs={300}\n />\n\n {selectedValue && (\n <div className=\"p-4 bg-blue-50 rounded-lg\">\n <p className=\"text-sm font-medium text-blue-900\">\n Selected value: {selectedValue}\n </p>\n </div>\n )}\n </div>\n );\n}\n"],"names":["Select","_a","options","_c","placeholder","onChange","value","_d","size","_e","className","name","id","_f","disabled","label","required","error","helpText","_g","fullWidth","_h","searchable","onSearch","_j","isSearching","_k","searchDebounceMs","_l","multiple","maxSelected","_m","showSelectedCount","closeOnSelect","_o","showSelectAll","_p","useState","isOpen","setIsOpen","_q","searchTerm","setSearchTerm","_r","dropdownPosition","setDropdownPosition","shouldCloseOnSelect","undefined","_s","Array","isArray","map","val","find","option","filter","Boolean","selectedOptions","setSelectedOptions","selectRef","useRef","dropdownRef","searchTimeoutRef","useEffect","current","selectRect","getBoundingClientRect","spaceBelow","window","innerHeight","bottom","spaceAbove","top","clearTimeout","setTimeout","filteredOptions","toLowerCase","includes","handleClickOutside","event","contains","target","document","addEventListener","removeEventListener","dropdownPositionClasses","_jsxs","ref","concat","children","htmlFor","_jsx","type","sm","md","lg","onClick","length","slice","X","e","optionToRemove","stopPropagation","newSelectedOptions","eventValue","opt","removeOption","join","_b","getDisplayText","ChevronDown","role","style","zIndex","position","autoFocus","Loader2","selectableOptions","every","some","selected","optionsToAdd","remainingSlots","__spreadArray","areAllFilteredSelected","isSelected","isOptionSelected","isDisabled","handleSelect","fill","viewBox","fillRule","d","clipRule","_Fragment","index"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Select.mjs","sources":["../../../../../src/components/Form/Select/Select.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport { ChevronDown, X, Loader2 } from \"lucide-react\";\n\nexport interface SelectOption {\n value: string;\n label?: string;\n disabled?: boolean;\n}\n\nexport type SelectProps = {\n options: SelectOption[];\n placeholder?: string;\n onChange: (value: React.ChangeEvent<HTMLSelectElement>) => void;\n value?: string | string[];\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n name?: string;\n id?: string;\n disabled?: boolean;\n label?: string;\n required?: boolean;\n error?: string;\n helpText?: string;\n fullWidth?: boolean;\n searchable?: boolean;\n\n // NEW: Backend search props\n onSearch?: (searchTerm: string) => void | Promise<void>;\n isSearching?: boolean;\n searchDebounceMs?: number;\n\n multiple?: boolean;\n maxSelected?: number;\n showSelectedCount?: boolean;\n closeOnSelect?: boolean;\n showSelectAll?: boolean;\n};\n\nexport default function Select({\n options,\n placeholder = \"Select an option\",\n onChange,\n value,\n size = \"md\",\n className = \"\",\n name,\n id,\n disabled = false,\n label,\n required,\n error,\n helpText,\n fullWidth = true,\n searchable = false,\n onSearch,\n isSearching = false,\n searchDebounceMs = 300,\n multiple = false,\n maxSelected,\n showSelectedCount = false,\n closeOnSelect,\n showSelectAll = true,\n}: SelectProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [searchTerm, setSearchTerm] = useState(\"\");\n const [dropdownPosition, setDropdownPosition] = useState<\"bottom\" | \"top\">(\n \"bottom\",\n );\n\n const shouldCloseOnSelect =\n closeOnSelect !== undefined ? closeOnSelect : !multiple;\n\n const [selectedOptions, setSelectedOptions] = useState<SelectOption[]>(() => {\n if (!value) return [];\n\n if (multiple && Array.isArray(value)) {\n return value\n .map((val) => options.find((option) => option.value == val))\n .filter(Boolean) as SelectOption[];\n } else if (!multiple) {\n const option = options.find((option) => option.value == value);\n return option ? [option] : [];\n }\n return [];\n });\n\n const selectRef = useRef<HTMLDivElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const searchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (multiple && Array.isArray(value)) {\n setSelectedOptions(\n value\n .map((val) => options.find((option) => option.value == val))\n .filter(Boolean) as SelectOption[],\n );\n } else if (!multiple) {\n const option = options.find((option) => option.value == value);\n setSelectedOptions(option ? [option] : []);\n } else if (value === \"\" || value === null || value == undefined) {\n setSelectedOptions([]);\n }\n }, [value, options, multiple]);\n\n useEffect(() => {\n if (isOpen && selectRef.current) {\n const selectRect = selectRef.current.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const dropdownHeight = 250;\n const spaceBelow = viewportHeight - selectRect.bottom;\n const spaceAbove = selectRect.top;\n\n if (spaceBelow < dropdownHeight && spaceAbove > dropdownHeight) {\n setDropdownPosition(\"top\");\n } else {\n setDropdownPosition(\"bottom\");\n }\n }\n }, [isOpen]);\n\n // Handle search with debouncing\n useEffect(() => {\n if (!onSearch || !searchTerm) return;\n\n if (searchTimeoutRef.current) {\n clearTimeout(searchTimeoutRef.current);\n }\n\n searchTimeoutRef.current = setTimeout(() => {\n onSearch(searchTerm);\n }, searchDebounceMs);\n\n return () => {\n if (searchTimeoutRef.current) {\n clearTimeout(searchTimeoutRef.current);\n }\n };\n }, [searchTerm, onSearch, searchDebounceMs]);\n\n // Filter options based on search term if using client-side search\n const filteredOptions =\n searchable && !onSearch\n ? options.filter((option) =>\n (option.label || option.value)\n .toLowerCase()\n .includes(searchTerm.toLowerCase()),\n )\n : options;\n\n const handleSelect = (option: SelectOption) => {\n if (option.disabled) return;\n\n let newSelectedOptions: SelectOption[];\n\n if (multiple) {\n const isAlreadySelected = selectedOptions.some(\n (selected) => selected.value === option.value,\n );\n\n if (isAlreadySelected) {\n newSelectedOptions = selectedOptions.filter(\n (selected) => selected.value !== option.value,\n );\n } else {\n if (maxSelected && selectedOptions.length >= maxSelected) {\n return;\n }\n newSelectedOptions = [...selectedOptions, option];\n }\n } else {\n newSelectedOptions = [option];\n }\n\n setSelectedOptions(newSelectedOptions);\n\n const eventValue = multiple\n ? newSelectedOptions.map((opt) => opt.value)\n : newSelectedOptions[0]?.value || \"\";\n\n onChange({\n target: {\n id: id || \"\",\n value: eventValue,\n },\n } as React.ChangeEvent<HTMLSelectElement>);\n\n if (shouldCloseOnSelect) {\n setIsOpen(false);\n setSearchTerm(\"\");\n }\n };\n\n const handleSelectAll = () => {\n if (!multiple) return;\n\n const selectableOptions = filteredOptions.filter((opt) => !opt.disabled);\n const allSelected = selectableOptions.every((option) =>\n selectedOptions.some((selected) => selected.value === option.value),\n );\n\n let newSelectedOptions: SelectOption[];\n\n if (allSelected) {\n newSelectedOptions = selectedOptions.filter(\n (selected) =>\n !selectableOptions.some((option) => option.value === selected.value),\n );\n } else {\n const optionsToAdd = selectableOptions.filter(\n (option) =>\n !selectedOptions.some((selected) => selected.value === option.value),\n );\n\n if (maxSelected !== undefined) {\n const remainingSlots = maxSelected - selectedOptions.length;\n newSelectedOptions = [\n ...selectedOptions,\n ...optionsToAdd.slice(0, remainingSlots),\n ];\n } else {\n newSelectedOptions = [...selectedOptions, ...optionsToAdd];\n }\n }\n\n setSelectedOptions(newSelectedOptions);\n\n const eventValue = newSelectedOptions.map((opt) => opt.value);\n\n onChange({\n target: {\n id: id || \"\",\n value: eventValue,\n },\n } as unknown as React.ChangeEvent<HTMLSelectElement>);\n };\n\n const handleClearAll = () => {\n if (!multiple) return;\n\n setSelectedOptions([]);\n\n onChange({\n target: {\n id: id || \"\",\n value: [],\n },\n } as unknown as React.ChangeEvent<HTMLSelectElement>);\n };\n\n const removeOption = (optionToRemove: SelectOption, e: React.MouseEvent) => {\n e.stopPropagation();\n const newSelectedOptions = selectedOptions.filter(\n (option) => option.value !== optionToRemove.value,\n );\n setSelectedOptions(newSelectedOptions);\n\n const eventValue = multiple\n ? newSelectedOptions.map((opt) => opt.value)\n : \"\";\n\n onChange({\n target: {\n id: id || \"\",\n value: eventValue,\n },\n } as React.ChangeEvent<HTMLSelectElement>);\n };\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n selectRef.current &&\n !selectRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n setSearchTerm(\"\");\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }, []);\n\n const sizeClasses = {\n sm: \"text-xs px-3 py-1.5 text-sm min-h-[32px]\",\n md: \"text-sm px-4 py-2 text-base min-h-[40px]\",\n lg: \"text-base px-4 py-3 text-lg min-h-[48px]\",\n };\n\n const getDisplayText = () => {\n if (selectedOptions.length === 0) return placeholder;\n\n if (!multiple) {\n return selectedOptions[0]?.label || selectedOptions[0]?.value;\n }\n\n if (showSelectedCount && selectedOptions.length > 2) {\n return `${selectedOptions.length} items selected`;\n }\n\n if (selectedOptions.length <= 2) {\n return selectedOptions.map((opt) => opt.label || opt.value).join(\", \");\n }\n\n return `${selectedOptions[0]?.label || selectedOptions[0]?.value} +${selectedOptions.length - 1} more`;\n };\n\n const isOptionSelected = (option: SelectOption) => {\n return selectedOptions.some((selected) => selected.value === option.value);\n };\n\n const areAllFilteredSelected = () => {\n if (!multiple || filteredOptions.length === 0) return false;\n const selectableOptions = filteredOptions.filter((opt) => !opt.disabled);\n return (\n selectableOptions.length > 0 &&\n selectableOptions.every((option) =>\n selectedOptions.some((selected) => selected.value === option.value),\n )\n );\n };\n\n const areSomeFilteredSelected = () => {\n if (!multiple || filteredOptions.length === 0) return false;\n const selectableOptions = filteredOptions.filter((opt) => !opt.disabled);\n return (\n selectableOptions.some((option) =>\n selectedOptions.some((selected) => selected.value === option.value),\n ) && !areAllFilteredSelected()\n );\n };\n\n const dropdownPositionClasses =\n dropdownPosition === \"top\" ? \"bottom-full mb-1\" : \"top-full mt-1\";\n\n return (\n <div ref={selectRef} className={`${fullWidth ? \"w-full\" : \"w-fit\"} mb-4`}>\n {label && (\n <label\n htmlFor={id}\n className=\"mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {label}\n {required && <span className=\"ml-1 text-red-500\">*</span>}\n </label>\n )}\n\n <div className=\"relative\">\n <button\n type=\"button\"\n className={`flex items-center justify-between rounded-lg border ${\n error ? \"border-red-500\" : \"border-gray-200 dark:border-gray-700\"\n } bg-gray-100 shadow-sm dark:bg-gray-800 ${\n sizeClasses[size]\n } text-gray-700 hover:border-gray-300 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 dark:text-gray-200 dark:hover:border-gray-600 ${\n disabled ? \"cursor-not-allowed bg-gray-50 opacity-50 dark:bg-gray-700\" : \"\"\n } ${className} ${fullWidth ? \"w-full\" : \"\"} transition-all duration-200`}\n onClick={() => !disabled && setIsOpen(!isOpen)}\n disabled={disabled}\n id={id}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n >\n <div className=\"flex-1 flex items-center gap-1 min-w-0\">\n {multiple && selectedOptions.length > 0 ? (\n <div className=\"flex flex-wrap gap-1 flex-1\">\n {selectedOptions.slice(0, 3).map((option) => (\n <span\n key={option.value}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 bg-primary-100 text-primary-800 text-sm rounded-md\"\n >\n <span className=\"truncate max-w-[120px]\">\n {option.label || option.value}\n </span>\n <X\n className=\"h-3 w-3 cursor-pointer hover:text-primary-900\"\n onClick={(e) => removeOption(option, e)}\n />\n </span>\n ))}\n {selectedOptions.length > 3 && (\n <span className=\"px-1 text-sm text-gray-500 dark:text-gray-400\">\n +{selectedOptions.length - 3} more\n </span>\n )}\n </div>\n ) : (\n <span\n className={`truncate ${selectedOptions.length === 0 ? \"text-gray-400 dark:text-gray-500\" : \"text-gray-700 dark:text-gray-200\"}`}\n >\n {getDisplayText()}\n </span>\n )}\n </div>\n <ChevronDown\n className={`ml-2 h-4 w-4 flex-shrink-0 text-gray-400 transition-transform dark:text-gray-500 ${\n isOpen ? \"rotate-180 transform\" : \"\"\n }`}\n />\n </button>\n\n {isOpen && (\n <div\n ref={dropdownRef}\n className={`absolute z-[9999] w-full rounded-lg border border-gray-200 bg-white shadow-xl dark:border-gray-700 dark:bg-gray-800 ${dropdownPositionClasses}`}\n role=\"listbox\"\n style={{\n zIndex: 9999,\n position: \"absolute\",\n }}\n >\n {searchable && (\n <div className=\"sticky top-0 z-[10000] border-b border-gray-100 bg-white p-3 dark:border-gray-700 dark:bg-gray-800\">\n <div className=\"relative\">\n <input\n type=\"text\"\n className=\"w-full rounded-md border border-gray-200 bg-white px-3 py-2 pr-8 text-sm transition-all duration-200 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:placeholder-gray-500\"\n placeholder={onSearch ? \"Search...\" : \"Filter...\"}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n autoFocus\n />\n {isSearching && (\n <Loader2 className=\"absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-gray-400 dark:text-gray-500\" />\n )}\n </div>\n </div>\n )}\n\n <div className=\"max-h-60 overflow-auto py-1\">\n {isSearching ? (\n <div className=\"px-3 py-8 text-center\">\n <Loader2 className=\"h-6 w-6 animate-spin text-primary-500 mx-auto mb-2\" />\n <p className=\"text-sm text-gray-500 dark:text-gray-400\">Searching...</p>\n </div>\n ) : filteredOptions.length > 0 ? (\n <>\n {multiple && showSelectAll && (\n <div className=\"border-b border-gray-100 dark:border-gray-700\">\n <div className=\"px-3 py-2 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={handleSelectAll}\n className=\"text-sm font-medium text-primary-600 hover:text-primary-700 transition-colors\"\n >\n {areAllFilteredSelected()\n ? \"Deselect All\"\n : \"Select All\"}\n </button>\n {selectedOptions.length > 0 && (\n <button\n type=\"button\"\n onClick={handleClearAll}\n className=\"text-sm font-medium text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Clear All\n </button>\n )}\n </div>\n {selectedOptions.length > 0 && (\n <div className=\"px-3 pb-2 text-xs text-gray-500 dark:text-gray-400\">\n {selectedOptions.length} selected\n {maxSelected && ` of ${maxSelected} max`}\n </div>\n )}\n </div>\n )}\n {filteredOptions.map((option) => {\n const isSelected = isOptionSelected(option);\n const isDisabled =\n option.disabled ||\n (maxSelected !== undefined &&\n !isSelected &&\n selectedOptions.length >= maxSelected);\n\n return (\n <div\n key={option.value}\n className={`cursor-pointer px-3 py-2 flex items-center justify-between transition-colors duration-150 ${\n isSelected\n ? \"bg-primary-50 text-primary-700\"\n : \"text-gray-700 hover:bg-gray-50 dark:text-gray-200 dark:hover:bg-gray-700\"\n } ${\n isDisabled\n ? \"cursor-not-allowed text-gray-400 opacity-50 hover:bg-white dark:text-gray-500 dark:hover:bg-gray-800\"\n : \"\"\n }`}\n onClick={() => !isDisabled && handleSelect(option)}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={isDisabled}\n >\n <span className=\"flex-1 text-sm font-medium\">\n {option.label || option.value}\n </span>\n {multiple && isSelected && (\n <div className=\"w-4 h-4 bg-primary-500 rounded-sm flex items-center justify-center\">\n <svg\n className=\"w-3 h-3 text-white\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n )}\n </div>\n );\n })}\n </>\n ) : (\n <div className=\"px-3 py-8 text-center\">\n <p className=\"text-sm text-gray-500 dark:text-gray-400\">\n {searchTerm ? \"No results found\" : \"No options available\"}\n </p>\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n\n {error && <p className=\"mt-1 text-sm text-red-600\">{error}</p>}\n {helpText && !error && (\n <p className=\"mt-1 text-sm text-gray-500 dark:text-gray-400\">{helpText}</p>\n )}\n\n {name && (\n <>\n {multiple ? (\n selectedOptions.map((option, index) => (\n <input\n key={`${option.value}-${index}`}\n type=\"hidden\"\n name={`${name}[]`}\n value={option.value}\n />\n ))\n ) : (\n <input\n type=\"hidden\"\n name={name}\n value={selectedOptions[0]?.value || \"\"}\n />\n )}\n </>\n )}\n </div>\n );\n}\n\n// Demo Component\nfunction Demo() {\n const [selectedValue, setSelectedValue] = useState(\"\");\n const [options, setOptions] = useState([\n { value: \"1\", label: \"Apple\" },\n { value: \"2\", label: \"Banana\" },\n { value: \"3\", label: \"Cherry\" },\n ]);\n const [isSearching, setIsSearching] = useState(false);\n\n const handleBackendSearch = async (searchTerm: string) => {\n console.log(\"Searching backend for:\", searchTerm);\n setIsSearching(true);\n\n // Simulate API call\n await new Promise((resolve) => setTimeout(resolve, 800));\n\n // Mock backend filtering\n const allFruits = [\n { value: \"1\", label: \"Apple\" },\n { value: \"2\", label: \"Banana\" },\n { value: \"3\", label: \"Cherry\" },\n { value: \"4\", label: \"Date\" },\n { value: \"5\", label: \"Elderberry\" },\n { value: \"6\", label: \"Fig\" },\n { value: \"7\", label: \"Grape\" },\n { value: \"8\", label: \"Honeydew\" },\n ];\n\n const filtered = searchTerm\n ? allFruits.filter((fruit) =>\n fruit.label.toLowerCase().includes(searchTerm.toLowerCase()),\n )\n : allFruits;\n\n setOptions(filtered);\n setIsSearching(false);\n };\n\n return (\n <div className=\"max-w-2xl mx-auto p-8 space-y-8\">\n <div>\n <h1 className=\"text-3xl font-bold mb-2\">Select with Backend Search</h1>\n <p className=\"text-gray-600\">\n Type in the search box to trigger backend filtering (simulated with\n 800ms delay)\n </p>\n </div>\n\n <Select\n label=\"Choose a fruit\"\n placeholder=\"Select or search for a fruit\"\n options={options}\n value={selectedValue}\n onChange={(e) => setSelectedValue(e.target.value as string)}\n searchable={true}\n onSearch={handleBackendSearch}\n isSearching={isSearching}\n searchDebounceMs={300}\n />\n\n {selectedValue && (\n <div className=\"p-4 bg-blue-50 rounded-lg\">\n <p className=\"text-sm font-medium text-blue-900\">\n Selected value: {selectedValue}\n </p>\n </div>\n )}\n </div>\n );\n}\n"],"names":["Select","_a","options","_c","placeholder","onChange","value","_d","size","_e","className","name","id","_f","disabled","label","required","error","helpText","_g","fullWidth","_h","searchable","onSearch","_j","isSearching","_k","searchDebounceMs","_l","multiple","maxSelected","_m","showSelectedCount","closeOnSelect","_o","showSelectAll","_p","useState","isOpen","setIsOpen","_q","searchTerm","setSearchTerm","_r","dropdownPosition","setDropdownPosition","shouldCloseOnSelect","undefined","_s","Array","isArray","map","val","find","option","filter","Boolean","selectedOptions","setSelectedOptions","selectRef","useRef","dropdownRef","searchTimeoutRef","useEffect","current","selectRect","getBoundingClientRect","spaceBelow","window","innerHeight","bottom","spaceAbove","top","clearTimeout","setTimeout","filteredOptions","toLowerCase","includes","handleClickOutside","event","contains","target","document","addEventListener","removeEventListener","dropdownPositionClasses","_jsxs","ref","concat","children","htmlFor","_jsx","type","sm","md","lg","onClick","length","slice","X","e","optionToRemove","stopPropagation","newSelectedOptions","eventValue","opt","removeOption","join","_b","getDisplayText","ChevronDown","role","style","zIndex","position","autoFocus","Loader2","selectableOptions","every","some","selected","optionsToAdd","remainingSlots","__spreadArray","areAllFilteredSelected","isSelected","isOptionSelected","isDisabled","handleSelect","fill","viewBox","fillRule","d","clipRule","_Fragment","index"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsxs as e,jsx as
|
|
1
|
+
import{jsxs as e,jsx as a}from"react/jsx-runtime";import{useState as r}from"react";import{ChevronDown as t,Check as l}from"lucide-react";function n(n){var o=n.options,d=n.placeholder,i=void 0===d?"Select an option":d,c=n.onChange,u=n.value,s=n.size,m=void 0===s?"md":s,v=n.className,g=void 0===v?"":v,b=n.name,x=n.id,y=n.disabled,h=void 0!==y&&y,p=n.label,f=n.required,k=r(!1),w=k[0],N=k[1],j=r(u&&o.find((function(e){return e.value===u}))||null),z=j[0],C=j[1];return e("div",{className:"relative ".concat(g),children:[p&&e("label",{htmlFor:x,className:"mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300",children:[p,f&&a("span",{className:"ml-1 text-red-500",children:"*"})]}),e("button",{type:"button",className:"flex w-full items-center justify-between rounded-md border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800 ".concat({sm:"px-3 py-2 text-sm",md:"px-4 py-2.5 text-base"}[m]," text-gray-700 hover:bg-gray-50 focus:outline-none dark:text-gray-200 dark:hover:bg-gray-700 ").concat(h?"cursor-not-allowed opacity-50":""),onClick:function(){return!h&&N(!w)},disabled:h,id:x,children:[a("span",{className:"truncate",children:z?(null==z?void 0:z.label)||z.value:i}),a(t,{className:"ml-2 h-4 w-4 ".concat(w?"rotate-180 transform":"")})]}),w&&a("div",{className:"absolute z-10 mt-1 max-h-60 w-full min-w-[200px] overflow-auto rounded-lg bg-white p-1 text-sm font-medium shadow-xl dark:bg-gray-800 dark:ring-1 dark:ring-gray-700",children:o.map((function(r){return e("div",{className:"cursor-pointer px-3 py-2 hover:bg-gray-100 rounded-lg flex justify-between item-center ".concat((null==z?void 0:z.value)===r.value?"bg-gray-50 text-black dark:bg-gray-700 dark:text-white":"text-gray-900 dark:text-gray-200"),onClick:function(){return function(e){C(e),c(e.value),N(!1)}(r)},children:[a("div",{children:r.label||r.value}),(null==z?void 0:z.value)===r.value&&a("div",{children:a(l,{size:15,className:"text-blue-600"})})]},r.value)}))}),b&&a("input",{type:"hidden",name:b,value:(null==z?void 0:z.value)||""})]})}export{n as default};
|
|
2
2
|
//# sourceMappingURL=SelectButton.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectButton.mjs","sources":["../../../../../src/components/Form/Select/SelectButton.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { Check, ChevronDown } from \"lucide-react\";\n\nexport type SelectButtonOption = {\n value: string;\n label?: string;\n};\n\nexport type SelectButtonProps = {\n options: SelectButtonOption[];\n placeholder?: string;\n onChange: (value: string) => void;\n value?: string;\n size?: \"sm\" | \"md\";\n className?: string;\n name?: string;\n id?: string;\n disabled?: boolean;\n label?: string;\n required?: boolean;\n};\n\nexport default function SelectButton({\n options,\n placeholder = \"Select an option\",\n onChange,\n value,\n size = \"md\",\n className = \"\",\n name,\n id,\n disabled = false,\n label,\n required,\n}: SelectButtonProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [selectedOption, setSelectedOption] =\n useState<SelectButtonOption | null>(\n value ? options.find((option) => option.value === value) || null : null,\n );\n\n const handleSelect = (option: SelectButtonOption) => {\n setSelectedOption(option);\n onChange(option.value);\n setIsOpen(false);\n };\n\n // Size classes for the button\n const sizeClasses = {\n sm: \"px-3 py-2 text-sm\",\n md: \"px-4 py-2.5 text-base\",\n };\n\n return (\n <div className={`relative ${className}`}>\n {label && (\n <label\n htmlFor={id}\n className=\"mb-1 block text-sm font-medium text-gray-700\"\n >\n {label}\n {required && <span className=\"ml-1 text-red-500\">*</span>}\n </label>\n )}\n <button\n type=\"button\"\n className={`flex w-full items-center justify-between rounded-md border border-gray-200 bg-white shadow-sm ${\n sizeClasses[size]\n } text-gray-700 hover:bg-gray-50 focus:outline-none ${disabled ? \"cursor-not-allowed opacity-50\" : \"\"}`}\n onClick={() => !disabled && setIsOpen(!isOpen)}\n disabled={disabled}\n id={id}\n >\n <span className=\"truncate\">\n {selectedOption\n ? selectedOption?.label || selectedOption.value\n : placeholder}\n </span>\n <ChevronDown\n className={`ml-2 h-4 w-4 ${isOpen ? \"rotate-180 transform\" : \"\"}`}\n />\n </button>\n {isOpen && (\n <div className=\"absolute z-10 mt-1 max-h-60 w-full min-w-[200px] p-1
|
|
1
|
+
{"version":3,"file":"SelectButton.mjs","sources":["../../../../../src/components/Form/Select/SelectButton.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { Check, ChevronDown } from \"lucide-react\";\n\nexport type SelectButtonOption = {\n value: string;\n label?: string;\n};\n\nexport type SelectButtonProps = {\n options: SelectButtonOption[];\n placeholder?: string;\n onChange: (value: string) => void;\n value?: string;\n size?: \"sm\" | \"md\";\n className?: string;\n name?: string;\n id?: string;\n disabled?: boolean;\n label?: string;\n required?: boolean;\n};\n\nexport default function SelectButton({\n options,\n placeholder = \"Select an option\",\n onChange,\n value,\n size = \"md\",\n className = \"\",\n name,\n id,\n disabled = false,\n label,\n required,\n}: SelectButtonProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [selectedOption, setSelectedOption] =\n useState<SelectButtonOption | null>(\n value ? options.find((option) => option.value === value) || null : null,\n );\n\n const handleSelect = (option: SelectButtonOption) => {\n setSelectedOption(option);\n onChange(option.value);\n setIsOpen(false);\n };\n\n // Size classes for the button\n const sizeClasses = {\n sm: \"px-3 py-2 text-sm\",\n md: \"px-4 py-2.5 text-base\",\n };\n\n return (\n <div className={`relative ${className}`}>\n {label && (\n <label\n htmlFor={id}\n className=\"mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {label}\n {required && <span className=\"ml-1 text-red-500\">*</span>}\n </label>\n )}\n <button\n type=\"button\"\n className={`flex w-full items-center justify-between rounded-md border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800 ${\n sizeClasses[size]\n } text-gray-700 hover:bg-gray-50 focus:outline-none dark:text-gray-200 dark:hover:bg-gray-700 ${disabled ? \"cursor-not-allowed opacity-50\" : \"\"}`}\n onClick={() => !disabled && setIsOpen(!isOpen)}\n disabled={disabled}\n id={id}\n >\n <span className=\"truncate\">\n {selectedOption\n ? selectedOption?.label || selectedOption.value\n : placeholder}\n </span>\n <ChevronDown\n className={`ml-2 h-4 w-4 ${isOpen ? \"rotate-180 transform\" : \"\"}`}\n />\n </button>\n {isOpen && (\n <div className=\"absolute z-10 mt-1 max-h-60 w-full min-w-[200px] overflow-auto rounded-lg bg-white p-1 text-sm font-medium shadow-xl dark:bg-gray-800 dark:ring-1 dark:ring-gray-700\">\n {options.map((option) => (\n <div\n key={option.value}\n className={`cursor-pointer px-3 py-2 hover:bg-gray-100 rounded-lg flex justify-between item-center ${\n selectedOption?.value === option.value\n ? \"bg-gray-50 text-black dark:bg-gray-700 dark:text-white\"\n : \"text-gray-900 dark:text-gray-200\"\n }`}\n onClick={() => handleSelect(option)}\n >\n <div>{option.label || option.value}</div>\n {selectedOption?.value === option.value && (\n <div>\n <Check size={15} className=\"text-blue-600\" />\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n {name && (\n <input type=\"hidden\" name={name} value={selectedOption?.value || \"\"} />\n )}\n </div>\n );\n}\n\n// Demo\nfunction Demo() {\n const [value1, setValue1] = useState(\"\");\n const [value2, setValue2] = useState(\"\");\n const [value3, setValue3] = useState(\"\");\n\n const options = [\n { value: \"option1\", label: \"Option 1\" },\n { value: \"option2\", label: \"Option 2\" },\n { value: \"option3\", label: \"Option 3\" },\n ];\n\n return (\n <div className=\"p-8 space-y-6\">\n <h1 className=\"text-2xl font-bold mb-6\">Resizable Select Button</h1>\n\n <div>\n <p className=\"mb-2 text-sm text-gray-600\">Default (no width class):</p>\n <SelectButton\n options={options}\n onChange={setValue1}\n value={value1}\n placeholder=\"Select...\"\n />\n </div>\n\n <div>\n <p className=\"mb-2 text-sm text-gray-600\">With w-64 class:</p>\n <SelectButton\n options={options}\n onChange={setValue2}\n value={value2}\n placeholder=\"Select...\"\n className=\"w-64\"\n />\n </div>\n\n <div>\n <p className=\"mb-2 text-sm text-gray-600\">With w-96 class:</p>\n <SelectButton\n options={options}\n onChange={setValue3}\n value={value3}\n placeholder=\"Select...\"\n className=\"w-96\"\n />\n </div>\n </div>\n );\n}\n"],"names":["SelectButton","_a","options","_b","placeholder","onChange","value","_c","size","_d","className","name","id","_e","disabled","label","required","_f","useState","isOpen","setIsOpen","_g","find","option","selectedOption","setSelectedOption","_jsxs","concat","children","htmlFor","_jsx","type","sm","md","onClick","ChevronDown","map","handleSelect","Check"],"mappings":"yIAsBc,SAAUA,EAAaC,OACnCC,EAAOD,EAAAC,QACPC,EAAAF,EAAAG,YAAAA,OAAW,IAAAD,EAAG,qBACdE,aACAC,UACAC,EAAAN,EAAAO,KAAAA,OAAI,IAAAD,EAAG,KAAIA,EACXE,EAAAR,EAAAS,UAAAA,OAAS,IAAAD,EAAG,GAAEA,EACdE,EAAIV,EAAAU,KACJC,EAAEX,EAAAW,GACFC,aAAAC,cAAgBD,EAChBE,EAAKd,EAAAc,MACLC,EAAQf,EAAAe,SAEFC,EAAsBC,GAAS,GAA9BC,EAAMF,EAAA,GAAEG,EAASH,EAAA,GAClBI,EACJH,EACEZ,GAAQJ,EAAQoB,MAAK,SAACC,GAAW,OAAAA,EAAOjB,QAAUA,CAAjB,KAAkC,MAFhEkB,EAAcH,EAAA,GAAEI,OAiBvB,OACEC,EAAA,MAAA,CAAKhB,UAAW,YAAAiB,OAAYjB,GAAWkB,SAAA,CACpCb,GACCW,WACEG,QAASjB,EACTF,UAAU,kEAAiEkB,SAAA,CAE1Eb,EACAC,GAAYc,EAAA,OAAA,CAAMpB,UAAU,sCAGjCgB,EAAA,SAAA,CACEK,KAAK,SACLrB,UAAW,8IAlBG,CAClBsB,GAAI,oBACJC,GAAI,yBAiBczB,2GACkFM,EAAW,gCAAkC,IAC7IoB,QAAS,WAAM,OAACpB,GAAYM,GAAWD,EAAxB,EACfL,SAAUA,EACVF,GAAIA,EAAEgB,SAAA,CAENE,EAAA,OAAA,CAAMpB,UAAU,oBACbc,GACGA,aAAc,EAAdA,EAAgBT,QAASS,EAAelB,MACxCF,IAEN0B,EAACK,EAAW,CACVzB,UAAW,gBAAAiB,OAAgBR,EAAS,uBAAyB,SAGhEA,GACCW,EAAA,MAAA,CAAKpB,UAAU,uKAAsKkB,SAClL1B,EAAQkC,KAAI,SAACb,GAAW,OACvBG,EAAA,MAAA,CAEEhB,UAAW,0FAAAiB,QACTH,aAAc,EAAdA,EAAgBlB,SAAUiB,EAAOjB,MAC7B,yDACA,oCAEN4B,QAAS,WAAM,OAnDN,SAACX,GACpBE,EAAkBF,GAClBlB,EAASkB,EAAOjB,OAChBc,GAAU,EACZ,CA+C2BiB,CAAad,EAAb,EAAoBK,SAAA,CAEnCE,EAAA,MAAA,CAAAF,SAAML,EAAOR,OAASQ,EAAOjB,SAC5BkB,aAAc,EAAdA,EAAgBlB,SAAUiB,EAAOjB,OAChCwB,EAAA,MAAA,CAAAF,SACEE,EAACQ,EAAK,CAAC9B,KAAM,GAAIE,UAAU,sBAX1Ba,EAAOjB,MAFS,MAoB5BK,GACCmB,EAAA,QAAA,CAAOC,KAAK,SAASpB,KAAMA,EAAML,OAAOkB,aAAc,EAAdA,EAAgBlB,QAAS,OAIzE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsxs as e,jsx as t}from"react/jsx-runtime";import n,{useRef as l,useEffect as
|
|
1
|
+
import{jsxs as e,jsx as t}from"react/jsx-runtime";import n,{useRef as l,useEffect as r}from"react";import{X as i}from"lucide-react";var o=function(n){var o=n.isOpen,a=n.onClose,s=n.title,c=n.children,d=n.size,u=void 0===d?"md":d,m=n.position,f=void 0===m?"right":m,h=n.showCloseButton,g=void 0===h||h,x=n.closeOnOverlayClick,v=void 0!==x&&x,p=n.closeOnEscape,b=void 0===p||p,y=n.className,N=void 0===y?"":y,w=n.overlayClassName,k=void 0===w?"":w,C=n.contentClassName,z=void 0===C?"":C,S=n.headerClassName,j=void 0===S?"":S,E=n.footer,O=n.footerClassName,L=void 0===O?"":O,M=n.maxHeight,T=void 0!==M&&M,F=l(null),H=l(null);r((function(){var e;return o?(H.current=document.activeElement,null===(e=F.current)||void 0===e||e.focus(),document.body.style.overflow="hidden"):(document.body.style.overflow="unset",H.current&&H.current.focus()),function(){document.body.style.overflow="unset"}}),[o]),r((function(){var e=function(e){"Escape"===e.key&&b&&a()};return o&&document.addEventListener("keydown",e),function(){document.removeEventListener("keydown",e)}}),[o,b,a]);var I=function(e){e.target===e.currentTarget&&v&&"full"!==u&&a()};return o?e("div",{className:"fixed inset-0 z-50 ".concat(k),role:"dialog","aria-modal":"true","aria-labelledby":s?"modal-title":void 0,children:["full"!==u&&t("div",{className:"fixed inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-700",onClick:I}),t("div",{className:"fixed inset-0 flex ".concat("p-0"," ").concat(function(){if("full"===u)return"items-start justify-start";return{left:"items-start justify-start",right:"items-start justify-end",center:"items-center justify-center"}[f]}()),onClick:I,children:e("div",{ref:F,tabIndex:-1,className:"\n relative w-full ".concat({xs:"max-w-xs",sm:"max-w-sm",md:"max-w-md",lg:"max-w-lg",xl:"max-w-xl","2xl":"max-w-2xl",full:"w-full h-full"}[u]," bg-white shadow-2xl transform transition-all duration-700 ease-out flex flex-col dark:bg-gray-900\n ").concat("full"===u?"h-full max-h-screen overflow-hidden":"left"===f||"right"===f?"h-full ".concat(T?"max-h-screen":""):"".concat(T?"max-h-[90vh] overflow-hidden":""),"\n ").concat("full"===u?"animate-in fade-in-0":"center"===f?"animate-in fade-in-0 zoom-in-95":"left"===f?"animate-in slide-in-from-left-full":"animate-in slide-in-from-right-full","\n ").concat(N,"\n "),onClick:function(e){return e.stopPropagation()},children:[(s||g)&&e("div",{className:"flex flex-shrink-0 items-center justify-between border-b border-gray-200 px-6 py-3 dark:border-gray-700 ".concat(j),children:[s&&t("h2",{id:"modal-title",className:"truncate pr-4 text-xl font-semibold text-gray-900 dark:text-gray-100",children:s}),g&&t("button",{onClick:a,className:"flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors duration-200 hover:bg-gray-100 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:text-gray-500 dark:hover:bg-gray-800 dark:hover:text-gray-300 dark:focus:ring-offset-gray-900","aria-label":"Close modal",children:t(i,{size:20})})]}),t("div",{className:"flex-1 min-h-0 overflow-y-auto ".concat(z),children:t("div",T&&("left"===f||"right"===f)||"full"===u?{className:"p-6 min-h-0 flex-1",children:c}:{className:"p-6",children:c})}),E&&t("div",{className:"flex-shrink-0 border-t border-gray-200 px-6 py-4 dark:border-gray-700 ".concat(""," ").concat(L),children:E})]})})]}):null},a=function(){var l=n.useState(!1),r=l[0],i=l[1],a=n.useState("left"),s=a[0],c=a[1],d=n.useState("md"),u=d[0],m=d[1],f=e("div",{className:"flex justify-end space-x-3",children:[t("button",{onClick:function(){return i(!1)},className:"px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors duration-200",children:"Cancel"}),t("button",{onClick:function(){return i(!1)},className:"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors duration-200",children:"Save Changes"})]});return e("div",{className:"p-8 space-y-4",children:[e("div",{className:"flex flex-wrap gap-4 mb-6",children:[e("div",{children:[t("label",{className:"block text-sm font-medium text-gray-700 mb-2",children:"Position"}),e("select",{value:s,onChange:function(e){return c(e.target.value)},className:"border border-gray-300 rounded-md px-3 py-2 text-sm",disabled:"full"===u,children:[t("option",{value:"left",children:"Left"}),t("option",{value:"right",children:"Right"}),t("option",{value:"center",children:"Center"})]})]}),e("div",{children:[t("label",{className:"block text-sm font-medium text-gray-700 mb-2",children:"Size"}),e("select",{value:u,onChange:function(e){return m(e.target.value)},className:"border border-gray-300 rounded-md px-3 py-2 text-sm",children:[t("option",{value:"xs",children:"Extra Small"}),t("option",{value:"sm",children:"Small"}),t("option",{value:"md",children:"Medium"}),t("option",{value:"lg",children:"Large"}),t("option",{value:"xl",children:"Extra Large"}),t("option",{value:"2xl",children:"2X Large"}),t("option",{value:"full",children:"Full Screen"})]})]})]}),t("button",{onClick:function(){return i(!0)},className:"px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200 font-medium",children:"Open Modal"}),t(o,{isOpen:r,onClose:function(){return i(!1)},title:"Example Modal",size:u,position:s,footer:f,maxHeight:"center"!==s,children:e("div",{className:"space-y-4",children:[t("p",{className:"text-gray-600",children:"This is an example of the multipurpose modal component. It supports different sizes, positions, and configurations."}),e("div",{className:"bg-gray-50 p-4 rounded-lg",children:[t("h4",{className:"font-medium text-gray-900 mb-2",children:"Features:"}),e("ul",{className:"text-sm text-gray-600 space-y-1 list-disc list-inside",children:[t("li",{children:"Multiple sizes (xs, sm, md, lg, xl, 2xl, full screen)"}),t("li",{children:"Three positions (left, right, center)"}),t("li",{children:"Customizable styling with className props"}),t("li",{children:"Keyboard navigation and accessibility"}),t("li",{children:"Click outside to close (disabled for full screen)"}),t("li",{children:"Smooth animations"}),t("li",{children:"Optional footer with actions"}),t("li",{children:"Full screen mode without margins or border radius"})]})]}),("left"===s||"right"===s||"full"===u)&&t("div",{className:"space-y-2",children:Array.from({length:20},(function(t,n){return e("p",{className:"text-gray-600",children:["This is paragraph ",n+1," to demonstrate scrolling in side panels","full"===u?" and full screen mode":"","."]},n)}))})]})})]})};export{a as ModalExample,o as default};
|
|
2
2
|
//# sourceMappingURL=Modal.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.mjs","sources":["../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["import React, { useEffect, useRef } from \"react\";\nimport { X } from \"lucide-react\";\n\ntype ModalSize = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"full\";\ntype ModalPosition = \"left\" | \"right\" | \"center\";\n\nexport interface ModalProps {\n isOpen: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n size?: ModalSize;\n position?: ModalPosition;\n showCloseButton?: boolean;\n closeOnOverlayClick?: boolean;\n closeOnEscape?: boolean;\n className?: string;\n overlayClassName?: string;\n contentClassName?: string;\n headerClassName?: string;\n footer?: React.ReactNode;\n footerClassName?: string;\n maxHeight?: boolean;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n isOpen,\n onClose,\n title,\n children,\n size = \"md\",\n position = \"right\",\n showCloseButton = true,\n closeOnOverlayClick = false,\n closeOnEscape = true,\n className = \"\",\n overlayClassName = \"\",\n contentClassName = \"\",\n headerClassName = \"\",\n footer,\n footerClassName = \"\",\n maxHeight = false,\n}) => {\n const modalRef = useRef<HTMLDivElement>(null);\n const previousFocusRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (isOpen) {\n // Store the previously focused element\n previousFocusRef.current = document.activeElement as HTMLElement;\n\n // Focus the modal\n modalRef.current?.focus();\n\n // Prevent body scroll\n document.body.style.overflow = \"hidden\";\n } else {\n // Restore body scroll\n document.body.style.overflow = \"unset\";\n\n // Restore focus to previously focused element\n if (previousFocusRef.current) {\n previousFocusRef.current.focus();\n }\n }\n\n return () => {\n document.body.style.overflow = \"unset\";\n };\n }, [isOpen]);\n\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && closeOnEscape) {\n onClose();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"keydown\", handleEscape);\n }\n\n return () => {\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }, [isOpen, closeOnEscape, onClose]);\n\n const handleOverlayClick = (event: React.MouseEvent) => {\n if (\n event.target === event.currentTarget &&\n closeOnOverlayClick &&\n size !== \"full\"\n ) {\n onClose();\n }\n };\n\n const getSizeClasses = (): string => {\n const sizeMap: Record<ModalSize, string> = {\n xs: \"max-w-xs\",\n sm: \"max-w-sm\",\n md: \"max-w-md\",\n lg: \"max-w-lg\",\n xl: \"max-w-xl\",\n \"2xl\": \"max-w-2xl\",\n full: \"w-full h-full\",\n };\n return sizeMap[size];\n };\n\n const getPositionClasses = (): string => {\n if (size === \"full\") {\n return \"items-start justify-start\";\n }\n\n const positionMap: Record<ModalPosition, string> = {\n left: \"items-start justify-start\",\n right: \"items-start justify-end\",\n center: \"items-center justify-center\",\n };\n return positionMap[position];\n };\n\n const getModalPositionClasses = (): string => {\n if (size === \"full\") {\n return \"h-full max-h-screen overflow-hidden\";\n }\n\n if (position === \"left\" || position === \"right\") {\n return `h-full ${maxHeight ? \"max-h-screen\" : \"\"}`;\n }\n return `${maxHeight ? \"max-h-[90vh] overflow-hidden\" : \"\"}`;\n };\n\n const getContainerPadding = (): string => {\n return size === \"full\" ? \"p-0\" : \"p-0\";\n };\n\n if (!isOpen) return null;\n\n return (\n <div\n className={`fixed inset-0 z-50 ${overlayClassName}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? \"modal-title\" : undefined}\n >\n {/* Backdrop - Hidden for full screen */}\n {size !== \"full\" && (\n <div\n className=\"fixed inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-700\"\n onClick={handleOverlayClick}\n />\n )}\n\n {/* Modal Container */}\n <div\n className={`fixed inset-0 flex ${getContainerPadding()} ${getPositionClasses()}`}\n onClick={handleOverlayClick}\n >\n {/* Modal Content */}\n <div\n ref={modalRef}\n tabIndex={-1}\n className={`\n relative w-full ${getSizeClasses()} bg-white shadow-2xl transform transition-all duration-700 ease-out flex flex-col\n ${getModalPositionClasses()}\n ${\n size === \"full\"\n ? \"animate-in fade-in-0\"\n : position === \"center\"\n ? \"animate-in fade-in-0 zoom-in-95\"\n : position === \"left\"\n ? \"animate-in slide-in-from-left-full\"\n : \"animate-in slide-in-from-right-full\"\n }\n ${className}\n `}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n {(title || showCloseButton) && (\n <div\n className={`flex items-center justify-between px-6 py-3 border-b border-gray-200 flex-shrink-0 ${headerClassName}`}\n >\n {title && (\n <h2\n id=\"modal-title\"\n className=\"text-xl font-semibold text-gray-900 truncate pr-4\"\n >\n {title}\n </h2>\n )}\n {showCloseButton && (\n <button\n onClick={onClose}\n className=\"flex items-center justify-center w-8 h-8 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2\"\n aria-label=\"Close modal\"\n >\n <X size={20} />\n </button>\n )}\n </div>\n )}\n\n {/* Content */}\n <div className={`flex-1 min-h-0 overflow-y-auto ${contentClassName}`}>\n {(maxHeight && (position === \"left\" || position === \"right\")) ||\n size === \"full\" ? (\n <div className=\"p-6 min-h-0 flex-1\">{children}</div>\n ) : (\n <div className=\"p-6\">{children}</div>\n )}\n </div>\n\n {/* Footer */}\n {footer && (\n <div\n className={`px-6 py-4 border-t border-gray-200 flex-shrink-0 ${size === \"full\" ? \"\" : \"\"} ${footerClassName}`}\n >\n {footer}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\nexport default Modal;\n\nexport const ModalExample: React.FC = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n const [position, setPosition] = React.useState<ModalPosition>(\"left\");\n const [size, setSize] = React.useState<ModalSize>(\"md\");\n\n const footer = (\n <div className=\"flex justify-end space-x-3\">\n <button\n onClick={() => setIsOpen(false)}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors duration-200\"\n >\n Cancel\n </button>\n <button\n onClick={() => setIsOpen(false)}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors duration-200\"\n >\n Save Changes\n </button>\n </div>\n );\n\n return (\n <div className=\"p-8 space-y-4\">\n <div className=\"flex flex-wrap gap-4 mb-6\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n Position\n </label>\n <select\n value={position}\n onChange={(e) => setPosition(e.target.value as ModalPosition)}\n className=\"border border-gray-300 rounded-md px-3 py-2 text-sm\"\n disabled={size === \"full\"}\n >\n <option value=\"left\">Left</option>\n <option value=\"right\">Right</option>\n <option value=\"center\">Center</option>\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n Size\n </label>\n <select\n value={size}\n onChange={(e) => setSize(e.target.value as ModalSize)}\n className=\"border border-gray-300 rounded-md px-3 py-2 text-sm\"\n >\n <option value=\"xs\">Extra Small</option>\n <option value=\"sm\">Small</option>\n <option value=\"md\">Medium</option>\n <option value=\"lg\">Large</option>\n <option value=\"xl\">Extra Large</option>\n <option value=\"2xl\">2X Large</option>\n <option value=\"full\">Full Screen</option>\n </select>\n </div>\n </div>\n\n <button\n onClick={() => setIsOpen(true)}\n className=\"px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200 font-medium\"\n >\n Open Modal\n </button>\n\n <Modal\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n title=\"Example Modal\"\n size={size}\n position={position}\n footer={footer}\n maxHeight={position !== \"center\"}\n >\n <div className=\"space-y-4\">\n <p className=\"text-gray-600\">\n This is an example of the multipurpose modal component. It supports\n different sizes, positions, and configurations.\n </p>\n\n <div className=\"bg-gray-50 p-4 rounded-lg\">\n <h4 className=\"font-medium text-gray-900 mb-2\">Features:</h4>\n <ul className=\"text-sm text-gray-600 space-y-1 list-disc list-inside\">\n <li>Multiple sizes (xs, sm, md, lg, xl, 2xl, full screen)</li>\n <li>Three positions (left, right, center)</li>\n <li>Customizable styling with className props</li>\n <li>Keyboard navigation and accessibility</li>\n <li>Click outside to close (disabled for full screen)</li>\n <li>Smooth animations</li>\n <li>Optional footer with actions</li>\n <li>Full screen mode without margins or border radius</li>\n </ul>\n </div>\n\n {(position === \"left\" || position === \"right\" || size === \"full\") && (\n <div className=\"space-y-2\">\n {Array.from({ length: 20 }, (_, i) => (\n <p key={i} className=\"text-gray-600\">\n This is paragraph {i + 1} to demonstrate scrolling in side\n panels{size === \"full\" ? \" and full screen mode\" : \"\"}.\n </p>\n ))}\n </div>\n )}\n </div>\n </Modal>\n </div>\n );\n};\n"],"names":["Modal","_a","isOpen","onClose","title","children","_b","size","_c","position","_d","showCloseButton","_e","closeOnOverlayClick","_f","closeOnEscape","_g","className","_h","overlayClassName","_j","contentClassName","_k","headerClassName","footer","_l","footerClassName","_m","maxHeight","modalRef","useRef","previousFocusRef","useEffect","current","document","activeElement","focus","body","style","overflow","handleEscape","event","key","addEventListener","removeEventListener","handleOverlayClick","target","currentTarget","_jsxs","concat","role","undefined","_jsx","onClick","left","right","center","getPositionClasses","ref","tabIndex","xs","sm","md","lg","xl","full","e","stopPropagation","id","X","ModalExample","React","useState","setIsOpen","setPosition","setSize","value","onChange","disabled","Array","from","length","_","i"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Modal.mjs","sources":["../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["import React, { useEffect, useRef } from \"react\";\nimport { X } from \"lucide-react\";\n\ntype ModalSize = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"full\";\ntype ModalPosition = \"left\" | \"right\" | \"center\";\n\nexport interface ModalProps {\n isOpen: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n size?: ModalSize;\n position?: ModalPosition;\n showCloseButton?: boolean;\n closeOnOverlayClick?: boolean;\n closeOnEscape?: boolean;\n className?: string;\n overlayClassName?: string;\n contentClassName?: string;\n headerClassName?: string;\n footer?: React.ReactNode;\n footerClassName?: string;\n maxHeight?: boolean;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n isOpen,\n onClose,\n title,\n children,\n size = \"md\",\n position = \"right\",\n showCloseButton = true,\n closeOnOverlayClick = false,\n closeOnEscape = true,\n className = \"\",\n overlayClassName = \"\",\n contentClassName = \"\",\n headerClassName = \"\",\n footer,\n footerClassName = \"\",\n maxHeight = false,\n}) => {\n const modalRef = useRef<HTMLDivElement>(null);\n const previousFocusRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (isOpen) {\n // Store the previously focused element\n previousFocusRef.current = document.activeElement as HTMLElement;\n\n // Focus the modal\n modalRef.current?.focus();\n\n // Prevent body scroll\n document.body.style.overflow = \"hidden\";\n } else {\n // Restore body scroll\n document.body.style.overflow = \"unset\";\n\n // Restore focus to previously focused element\n if (previousFocusRef.current) {\n previousFocusRef.current.focus();\n }\n }\n\n return () => {\n document.body.style.overflow = \"unset\";\n };\n }, [isOpen]);\n\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && closeOnEscape) {\n onClose();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"keydown\", handleEscape);\n }\n\n return () => {\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }, [isOpen, closeOnEscape, onClose]);\n\n const handleOverlayClick = (event: React.MouseEvent) => {\n if (\n event.target === event.currentTarget &&\n closeOnOverlayClick &&\n size !== \"full\"\n ) {\n onClose();\n }\n };\n\n const getSizeClasses = (): string => {\n const sizeMap: Record<ModalSize, string> = {\n xs: \"max-w-xs\",\n sm: \"max-w-sm\",\n md: \"max-w-md\",\n lg: \"max-w-lg\",\n xl: \"max-w-xl\",\n \"2xl\": \"max-w-2xl\",\n full: \"w-full h-full\",\n };\n return sizeMap[size];\n };\n\n const getPositionClasses = (): string => {\n if (size === \"full\") {\n return \"items-start justify-start\";\n }\n\n const positionMap: Record<ModalPosition, string> = {\n left: \"items-start justify-start\",\n right: \"items-start justify-end\",\n center: \"items-center justify-center\",\n };\n return positionMap[position];\n };\n\n const getModalPositionClasses = (): string => {\n if (size === \"full\") {\n return \"h-full max-h-screen overflow-hidden\";\n }\n\n if (position === \"left\" || position === \"right\") {\n return `h-full ${maxHeight ? \"max-h-screen\" : \"\"}`;\n }\n return `${maxHeight ? \"max-h-[90vh] overflow-hidden\" : \"\"}`;\n };\n\n const getContainerPadding = (): string => {\n return size === \"full\" ? \"p-0\" : \"p-0\";\n };\n\n if (!isOpen) return null;\n\n return (\n <div\n className={`fixed inset-0 z-50 ${overlayClassName}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? \"modal-title\" : undefined}\n >\n {/* Backdrop - Hidden for full screen */}\n {size !== \"full\" && (\n <div\n className=\"fixed inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-700\"\n onClick={handleOverlayClick}\n />\n )}\n\n {/* Modal Container */}\n <div\n className={`fixed inset-0 flex ${getContainerPadding()} ${getPositionClasses()}`}\n onClick={handleOverlayClick}\n >\n {/* Modal Content */}\n <div\n ref={modalRef}\n tabIndex={-1}\n className={`\n relative w-full ${getSizeClasses()} bg-white shadow-2xl transform transition-all duration-700 ease-out flex flex-col dark:bg-gray-900\n ${getModalPositionClasses()}\n ${\n size === \"full\"\n ? \"animate-in fade-in-0\"\n : position === \"center\"\n ? \"animate-in fade-in-0 zoom-in-95\"\n : position === \"left\"\n ? \"animate-in slide-in-from-left-full\"\n : \"animate-in slide-in-from-right-full\"\n }\n ${className}\n `}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n {(title || showCloseButton) && (\n <div\n className={`flex flex-shrink-0 items-center justify-between border-b border-gray-200 px-6 py-3 dark:border-gray-700 ${headerClassName}`}\n >\n {title && (\n <h2\n id=\"modal-title\"\n className=\"truncate pr-4 text-xl font-semibold text-gray-900 dark:text-gray-100\"\n >\n {title}\n </h2>\n )}\n {showCloseButton && (\n <button\n onClick={onClose}\n className=\"flex h-8 w-8 items-center justify-center rounded-full text-gray-400 transition-colors duration-200 hover:bg-gray-100 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:text-gray-500 dark:hover:bg-gray-800 dark:hover:text-gray-300 dark:focus:ring-offset-gray-900\"\n aria-label=\"Close modal\"\n >\n <X size={20} />\n </button>\n )}\n </div>\n )}\n\n {/* Content */}\n <div className={`flex-1 min-h-0 overflow-y-auto ${contentClassName}`}>\n {(maxHeight && (position === \"left\" || position === \"right\")) ||\n size === \"full\" ? (\n <div className=\"p-6 min-h-0 flex-1\">{children}</div>\n ) : (\n <div className=\"p-6\">{children}</div>\n )}\n </div>\n\n {/* Footer */}\n {footer && (\n <div\n className={`flex-shrink-0 border-t border-gray-200 px-6 py-4 dark:border-gray-700 ${size === \"full\" ? \"\" : \"\"} ${footerClassName}`}\n >\n {footer}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\nexport default Modal;\n\nexport const ModalExample: React.FC = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n const [position, setPosition] = React.useState<ModalPosition>(\"left\");\n const [size, setSize] = React.useState<ModalSize>(\"md\");\n\n const footer = (\n <div className=\"flex justify-end space-x-3\">\n <button\n onClick={() => setIsOpen(false)}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors duration-200\"\n >\n Cancel\n </button>\n <button\n onClick={() => setIsOpen(false)}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors duration-200\"\n >\n Save Changes\n </button>\n </div>\n );\n\n return (\n <div className=\"p-8 space-y-4\">\n <div className=\"flex flex-wrap gap-4 mb-6\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n Position\n </label>\n <select\n value={position}\n onChange={(e) => setPosition(e.target.value as ModalPosition)}\n className=\"border border-gray-300 rounded-md px-3 py-2 text-sm\"\n disabled={size === \"full\"}\n >\n <option value=\"left\">Left</option>\n <option value=\"right\">Right</option>\n <option value=\"center\">Center</option>\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n Size\n </label>\n <select\n value={size}\n onChange={(e) => setSize(e.target.value as ModalSize)}\n className=\"border border-gray-300 rounded-md px-3 py-2 text-sm\"\n >\n <option value=\"xs\">Extra Small</option>\n <option value=\"sm\">Small</option>\n <option value=\"md\">Medium</option>\n <option value=\"lg\">Large</option>\n <option value=\"xl\">Extra Large</option>\n <option value=\"2xl\">2X Large</option>\n <option value=\"full\">Full Screen</option>\n </select>\n </div>\n </div>\n\n <button\n onClick={() => setIsOpen(true)}\n className=\"px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200 font-medium\"\n >\n Open Modal\n </button>\n\n <Modal\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n title=\"Example Modal\"\n size={size}\n position={position}\n footer={footer}\n maxHeight={position !== \"center\"}\n >\n <div className=\"space-y-4\">\n <p className=\"text-gray-600\">\n This is an example of the multipurpose modal component. It supports\n different sizes, positions, and configurations.\n </p>\n\n <div className=\"bg-gray-50 p-4 rounded-lg\">\n <h4 className=\"font-medium text-gray-900 mb-2\">Features:</h4>\n <ul className=\"text-sm text-gray-600 space-y-1 list-disc list-inside\">\n <li>Multiple sizes (xs, sm, md, lg, xl, 2xl, full screen)</li>\n <li>Three positions (left, right, center)</li>\n <li>Customizable styling with className props</li>\n <li>Keyboard navigation and accessibility</li>\n <li>Click outside to close (disabled for full screen)</li>\n <li>Smooth animations</li>\n <li>Optional footer with actions</li>\n <li>Full screen mode without margins or border radius</li>\n </ul>\n </div>\n\n {(position === \"left\" || position === \"right\" || size === \"full\") && (\n <div className=\"space-y-2\">\n {Array.from({ length: 20 }, (_, i) => (\n <p key={i} className=\"text-gray-600\">\n This is paragraph {i + 1} to demonstrate scrolling in side\n panels{size === \"full\" ? \" and full screen mode\" : \"\"}.\n </p>\n ))}\n </div>\n )}\n </div>\n </Modal>\n </div>\n );\n};\n"],"names":["Modal","_a","isOpen","onClose","title","children","_b","size","_c","position","_d","showCloseButton","_e","closeOnOverlayClick","_f","closeOnEscape","_g","className","_h","overlayClassName","_j","contentClassName","_k","headerClassName","footer","_l","footerClassName","_m","maxHeight","modalRef","useRef","previousFocusRef","useEffect","current","document","activeElement","focus","body","style","overflow","handleEscape","event","key","addEventListener","removeEventListener","handleOverlayClick","target","currentTarget","_jsxs","concat","role","undefined","_jsx","onClick","left","right","center","getPositionClasses","ref","tabIndex","xs","sm","md","lg","xl","full","e","stopPropagation","id","X","ModalExample","React","useState","setIsOpen","setPosition","setSize","value","onChange","disabled","Array","from","length","_","i"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsxs as e,jsx as r}from"react/jsx-runtime";import
|
|
1
|
+
import{jsxs as e,jsx as r}from"react/jsx-runtime";import a from"../Button/Button.mjs";import"../Button/ExportButton.mjs";function t(t){var n=t.currentPage,i=t.totalPages,d=t.totalItems,l=t.itemsPerPage,o=t.onPageChange,s=t.onViewChange,c=t.loading,g=void 0!==c&&c,m=function(e){e>0&&e<=i&&!g&&o&&o(e)},u=(n-1)*l,h=Math.min(u+l,d);return e("div",{className:"flex items-center justify-between border-t border-gray-200 bg-white p-3 dark:border-gray-700 dark:bg-gray-900",children:[r("div",{className:"block flex-1 sm:hidden",children:e("div",{className:"flex justify-between",children:[r("button",{onClick:function(){return m(n-1)},disabled:1===n||g,className:"relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700 ".concat(1===n||g?"cursor-not-allowed opacity-50":""),children:"Previous"}),r("button",{onClick:function(){return m(n+1)},disabled:n===i||g,className:"relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700 ".concat(n===i||g?"cursor-not-allowed opacity-50":""),children:"Next"})]})}),e("div",{className:"hidden sm:flex sm:flex-1 sm:items-center sm:justify-between",children:[e("div",{className:"flex items-center justify-center gap-2",children:[e("div",{className:"relative",children:[r("select",{value:l,onChange:function(e){return s&&s(e.target.value)},disabled:g,className:"appearance-none rounded-md border border-gray-300 bg-white py-2 pl-3 pr-8 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200",children:[10,20,30,50,100].map((function(e){return r("option",{value:e,children:e},e)}))}),r("div",{className:"pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700 dark:text-gray-300",children:r("svg",{className:"h-4 w-4",fill:"currentColor",viewBox:"0 0 20 20",children:r("path",{fillRule:"evenodd",d:"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z",clipRule:"evenodd"})})})]}),e("p",{className:"text-sm text-gray-700 dark:text-gray-300",children:[e("span",{children:[d," Entries"]}),e("span",{className:"ml-1",children:["(Showing ",u+1,"-",h," of ",d,")"]})]})]}),r("div",{children:e("nav",{className:"relative z-0 inline-flex gap-2 -space-x-px rounded-md shadow-sm","aria-label":"Pagination",children:[e("button",{onClick:function(){return m(n-1)},disabled:1===n||g,className:"relative inline-flex items-center rounded-md border border-gray-300 bg-white px-2 py-2 text-sm font-medium text-gray-500 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 ".concat(1===n||g?"cursor-not-allowed opacity-50":""),children:[r("span",{className:"sr-only",children:"Previous"}),r("svg",{className:"h-5 w-5",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor","aria-hidden":"true",children:r("path",{fillRule:"evenodd",d:"M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z",clipRule:"evenodd"})})]}),function(){var e=[];if(i<=5)for(var r=1;r<=i;r++)e.push(r);else{var a=Math.max(1,n-2),t=Math.min(i,a+5-1);t-a<4&&(a=Math.max(1,t-5+1));for(r=a;r<=t;r++)e.push(r)}return e}().map((function(e){return r("button",{onClick:function(){return m(e)},disabled:g,"aria-current":n===e?"page":void 0,className:"relative inline-flex items-center rounded-md border px-4 py-2 text-sm font-semibold ".concat(n===e?"z-10 border-primary-100 bg-primary-50 text-primary":"border-gray-300 bg-white text-gray-500 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"," ").concat(g?"cursor-not-allowed opacity-50":""),children:e},e)})),e(a,{onClick:function(){return m(n+1)},disabled:n===i||g,type:"button",variant:"primary",size:"sm",outline:!0,children:["Next Page",r("svg",{className:"h-5 w-5",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor","aria-hidden":"true",children:r("path",{fillRule:"evenodd",d:"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z",clipRule:"evenodd"})})]})]})})]})]})}export{t as Pagination};
|
|
2
2
|
//# sourceMappingURL=Pagination.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.mjs","sources":["../../../../src/components/Table/Pagination.tsx"],"sourcesContent":["import { PaginationProps } from \"./types\";\nimport { Button } from \"../Button\";\n\nexport function Pagination({\n currentPage,\n totalPages,\n totalItems,\n itemsPerPage,\n onPageChange,\n onViewChange,\n loading = false,\n}: PaginationProps) {\n const perPageOptions = [10, 20, 30, 50, 100];\n const goToPage = (page: number) => {\n if (page > 0 && page <= totalPages && !loading && onPageChange) {\n onPageChange(page);\n }\n };\n\n const getPageNumbers = () => {\n const pageNumbers = [];\n const maxPagesToShow = 5;\n\n if (totalPages <= maxPagesToShow) {\n for (let i = 1; i <= totalPages; i++) {\n pageNumbers.push(i);\n }\n } else {\n let startPage = Math.max(1, currentPage - 2);\n const endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);\n\n if (endPage - startPage < maxPagesToShow - 1) {\n startPage = Math.max(1, endPage - maxPagesToShow + 1);\n }\n\n for (let i = startPage; i <= endPage; i++) {\n pageNumbers.push(i);\n }\n }\n\n return pageNumbers;\n };\n\n const startIndex = (currentPage - 1) * itemsPerPage;\n const endIndex = Math.min(startIndex + itemsPerPage, totalItems);\n\n return (\n <div className=\"flex items-center justify-between border-t border-gray-200 bg-white py-3\">\n <div className=\"flex flex-1 justify-between sm:hidden\">\n <button\n onClick={() => goToPage(currentPage - 1)}\n disabled={currentPage === 1 || loading}\n className={`relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 ${\n currentPage === 1 || loading ? \"cursor-not-allowed opacity-50\" : \"\"\n }`}\n >\n Previous\n </button>\n <button\n onClick={() => goToPage(currentPage + 1)}\n disabled={currentPage === totalPages || loading}\n className={`relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 ${\n currentPage === totalPages || loading\n ? \"cursor-not-allowed opacity-50\"\n : \"\"\n }`}\n >\n Next\n </button>\n </div>\n\n <div className=\"hidden sm:flex sm:flex-1 sm:items-center sm:justify-between\">\n <div className=\"flex items-center justify-center gap-2\">\n {/*{onViewChange && (*/}\n <div className=\"relative\">\n <select\n value={itemsPerPage}\n onChange={(e) => onViewChange && onViewChange(e.target.value)}\n disabled={loading}\n className=\"appearance-none rounded-md border border-gray-300 bg-white py-2 pl-3 pr-8 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500\"\n >\n {perPageOptions.map((option) => (\n <option key={option} value={option}>\n {option}\n </option>\n ))}\n </select>\n <div className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700\">\n <svg className=\"h-4 w-4\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path\n fillRule=\"evenodd\"\n d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n {/*)}*/}\n <p className=\"text-sm text-gray-700\">\n <span>{totalItems} Entries</span>\n <span className=\"ml-1\">\n (Showing {startIndex + 1}-{endIndex} of {totalItems})\n </span>\n </p>\n </div>\n <div>\n <nav\n className=\"relative z-0 inline-flex gap-2 -space-x-px rounded-md shadow-sm\"\n aria-label=\"Pagination\"\n >\n <button\n onClick={() => goToPage(currentPage - 1)}\n disabled={currentPage === 1 || loading}\n className={`relative inline-flex items-center rounded-md border border-gray-300 bg-white px-2 py-2 text-sm font-medium text-gray-500 hover:bg-gray-50 ${\n currentPage === 1 || loading\n ? \"cursor-not-allowed opacity-50\"\n : \"\"\n }`}\n >\n <span className=\"sr-only\">Previous</span>\n <svg\n className=\"h-5 w-5\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n\n {getPageNumbers().map((number) => (\n <button\n key={number}\n onClick={() => goToPage(number)}\n disabled={loading}\n aria-current={currentPage === number ? \"page\" : undefined}\n className={`relative inline-flex items-center rounded-md border px-4 py-2 text-sm font-semibold ${\n currentPage === number\n ? \"z-10 border-primary-100 bg-primary-50 text-primary\"\n : \"border-gray-300 bg-white text-gray-500 hover:bg-gray-50\"\n } ${loading ? \"cursor-not-allowed opacity-50\" : \"\"}`}\n >\n {number}\n </button>\n ))}\n\n <Button\n onClick={() => goToPage(currentPage + 1)}\n disabled={currentPage === totalPages || loading}\n type=\"button\"\n variant=\"primary\"\n size=\"sm\"\n outline\n >\n Next Page\n <svg\n className=\"h-5 w-5\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </Button>\n </nav>\n </div>\n </div>\n </div>\n );\n}\n"],"names":["Pagination","_a","currentPage","totalPages","totalItems","itemsPerPage","onPageChange","onViewChange","_b","loading","goToPage","page","startIndex","endIndex","Math","min","_jsxs","className","_jsx","onClick","disabled","concat","children","value","onChange","e","target","map","option","fill","viewBox","fillRule","d","clipRule","xmlns","pageNumbers","i","push","startPage","max","endPage","maxPagesToShow","getPageNumbers","number","undefined","Button","type","variant","size","outline"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Pagination.mjs","sources":["../../../../src/components/Table/Pagination.tsx"],"sourcesContent":["import { PaginationProps } from \"./types\";\nimport { Button } from \"../Button\";\n\nexport function Pagination({\n currentPage,\n totalPages,\n totalItems,\n itemsPerPage,\n onPageChange,\n onViewChange,\n loading = false,\n}: PaginationProps) {\n const perPageOptions = [10, 20, 30, 50, 100];\n const goToPage = (page: number) => {\n if (page > 0 && page <= totalPages && !loading && onPageChange) {\n onPageChange(page);\n }\n };\n\n const getPageNumbers = () => {\n const pageNumbers = [];\n const maxPagesToShow = 5;\n\n if (totalPages <= maxPagesToShow) {\n for (let i = 1; i <= totalPages; i++) {\n pageNumbers.push(i);\n }\n } else {\n let startPage = Math.max(1, currentPage - 2);\n const endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);\n\n if (endPage - startPage < maxPagesToShow - 1) {\n startPage = Math.max(1, endPage - maxPagesToShow + 1);\n }\n\n for (let i = startPage; i <= endPage; i++) {\n pageNumbers.push(i);\n }\n }\n\n return pageNumbers;\n };\n\n const startIndex = (currentPage - 1) * itemsPerPage;\n const endIndex = Math.min(startIndex + itemsPerPage, totalItems);\n\n return (\n <div className=\"flex items-center justify-between border-t border-gray-200 bg-white p-3 dark:border-gray-700 dark:bg-gray-900\">\n <div className=\"block flex-1 sm:hidden\">\n <div className=\"flex justify-between\">\n <button\n onClick={() => goToPage(currentPage - 1)}\n disabled={currentPage === 1 || loading}\n className={`relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700 ${\n currentPage === 1 || loading\n ? \"cursor-not-allowed opacity-50\"\n : \"\"\n }`}\n >\n Previous\n </button>\n <button\n onClick={() => goToPage(currentPage + 1)}\n disabled={currentPage === totalPages || loading}\n className={`relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700 ${\n currentPage === totalPages || loading\n ? \"cursor-not-allowed opacity-50\"\n : \"\"\n }`}\n >\n Next\n </button>\n </div>\n </div>\n\n <div className=\"hidden sm:flex sm:flex-1 sm:items-center sm:justify-between\">\n <div className=\"flex items-center justify-center gap-2\">\n {/*{onViewChange && (*/}\n <div className=\"relative\">\n <select\n value={itemsPerPage}\n onChange={(e) => onViewChange && onViewChange(e.target.value)}\n disabled={loading}\n className=\"appearance-none rounded-md border border-gray-300 bg-white py-2 pl-3 pr-8 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200\"\n >\n {perPageOptions.map((option) => (\n <option key={option} value={option}>\n {option}\n </option>\n ))}\n </select>\n <div className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700 dark:text-gray-300\">\n <svg className=\"h-4 w-4\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path\n fillRule=\"evenodd\"\n d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n {/*)}*/}\n <p className=\"text-sm text-gray-700 dark:text-gray-300\">\n <span>{totalItems} Entries</span>\n <span className=\"ml-1\">\n (Showing {startIndex + 1}-{endIndex} of {totalItems})\n </span>\n </p>\n </div>\n <div>\n <nav\n className=\"relative z-0 inline-flex gap-2 -space-x-px rounded-md shadow-sm\"\n aria-label=\"Pagination\"\n >\n <button\n onClick={() => goToPage(currentPage - 1)}\n disabled={currentPage === 1 || loading}\n className={`relative inline-flex items-center rounded-md border border-gray-300 bg-white px-2 py-2 text-sm font-medium text-gray-500 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 ${\n currentPage === 1 || loading\n ? \"cursor-not-allowed opacity-50\"\n : \"\"\n }`}\n >\n <span className=\"sr-only\">Previous</span>\n <svg\n className=\"h-5 w-5\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n\n {getPageNumbers().map((number) => (\n <button\n key={number}\n onClick={() => goToPage(number)}\n disabled={loading}\n aria-current={currentPage === number ? \"page\" : undefined}\n className={`relative inline-flex items-center rounded-md border px-4 py-2 text-sm font-semibold ${\n currentPage === number\n ? \"z-10 border-primary-100 bg-primary-50 text-primary\"\n : \"border-gray-300 bg-white text-gray-500 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700\"\n } ${loading ? \"cursor-not-allowed opacity-50\" : \"\"}`}\n >\n {number}\n </button>\n ))}\n\n <Button\n onClick={() => goToPage(currentPage + 1)}\n disabled={currentPage === totalPages || loading}\n type=\"button\"\n variant=\"primary\"\n size=\"sm\"\n outline\n >\n Next Page\n <svg\n className=\"h-5 w-5\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </Button>\n </nav>\n </div>\n </div>\n </div>\n );\n}\n"],"names":["Pagination","_a","currentPage","totalPages","totalItems","itemsPerPage","onPageChange","onViewChange","_b","loading","goToPage","page","startIndex","endIndex","Math","min","_jsxs","className","children","_jsx","onClick","disabled","concat","value","onChange","e","target","map","option","fill","viewBox","fillRule","d","clipRule","xmlns","pageNumbers","i","push","startPage","max","endPage","maxPagesToShow","getPageNumbers","number","undefined","Button","type","variant","size","outline"],"mappings":"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"}
|