alope-ui 1.1.3 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2393
- package/dist/components/Avatar/Avatar.d.ts +38 -0
- package/dist/components/Avatar/AvatarGroup.d.ts +10 -0
- package/dist/components/FileUpload/FIleUpload.d.ts +14 -0
- package/dist/components/Pagination/Pagination.d.ts +22 -0
- package/dist/components/Skeleton/Skeleton.d.ts +10 -0
- package/dist/components/Spinner/Spinner.d.ts +23 -0
- package/dist/components/Table/Table.d.ts +34 -0
- package/dist/components/Tabs/Tabs.d.ts +57 -0
- package/dist/components/Textarea/Textarea.d.ts +8 -0
- package/dist/components/Toggle/Toggle.d.ts +27 -0
- package/dist/components/Tooltip/Tooltip.d.ts +14 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/index.css +1 -1
- package/dist/main.cjs +339 -287
- package/dist/main.d.ts +11 -0
- package/package.json +14 -1
package/README.md
CHANGED
|
@@ -96,23 +96,16 @@ export default App;
|
|
|
96
96
|
|
|
97
97
|
- [🪗 Accordion](#accordion) - Collapsible content panels
|
|
98
98
|
- [🍞 Breadcrumb](#breadcrumb) - Navigation trail
|
|
99
|
-
- [📑 Tabs](#tabs) - Tabbed navigation interface
|
|
100
|
-
- [📄 Pagination](#pagination) - Page navigation controls
|
|
101
99
|
|
|
102
100
|
### Feedback Components
|
|
103
101
|
|
|
104
102
|
- [⚠️ Alert](#alert) - Status messages and notifications
|
|
105
103
|
- [🍞 Toast](#toast) - Temporary notification messages
|
|
106
|
-
- [💡 Tooltip](#tooltip) - Contextual information on hover
|
|
107
|
-
- [⏳ Spinner](#spinner) - Loading indicators
|
|
108
|
-
- [💀 Skeleton](#skeleton) - Content loading placeholders
|
|
109
104
|
|
|
110
105
|
### Data Display
|
|
111
106
|
|
|
112
107
|
- [🏷️ Badge](#badge) - Status indicators and labels
|
|
113
108
|
- [🃏 Card](#card) - Content containers
|
|
114
|
-
- [📊 Table](#table) - Tabular data display
|
|
115
|
-
- [👤 Avatar](#avatar) - User profile images
|
|
116
109
|
|
|
117
110
|
### Form Controls
|
|
118
111
|
|
|
@@ -120,9 +113,6 @@ export default App;
|
|
|
120
113
|
- [🔘 Radio Input](#radio-input) - Single choice selections
|
|
121
114
|
- [📝 Select Input](#select-input) - Dropdown selections
|
|
122
115
|
- [⌨️ Text Input](#text-input) - Text input fields
|
|
123
|
-
- [📝 Textarea](#textarea) - Multi-line text input
|
|
124
|
-
- [🔄 Toggle](#toggle) - Switch controls
|
|
125
|
-
- [📁 File Upload](#file-upload) - File selection and upload
|
|
126
116
|
|
|
127
117
|
### Interactive Elements
|
|
128
118
|
|
|
@@ -1713,2388 +1703,6 @@ const BasicExample = () => {
|
|
|
1713
1703
|
/>
|
|
1714
1704
|
```
|
|
1715
1705
|
|
|
1716
|
-
---
|
|
1717
|
-
|
|
1718
|
-
## Pagination
|
|
1719
|
-
|
|
1720
|
-
The Pagination component provides navigation controls for paginated content, supporting both simplified and full pagination modes with customizable appearance.
|
|
1721
|
-
|
|
1722
|
-
### Import
|
|
1723
|
-
|
|
1724
|
-
```jsx
|
|
1725
|
-
import { Pagination } from "alope-ui";
|
|
1726
|
-
```
|
|
1727
|
-
|
|
1728
|
-
### Props
|
|
1729
|
-
|
|
1730
|
-
| Prop | Type | Default | Description |
|
|
1731
|
-
| --------------- | --------------------------------- | --------- | ----------------------------------------------------- |
|
|
1732
|
-
| `currentPage` | `number` | `required`| Current active page number |
|
|
1733
|
-
| `onPageChange` | `(page: number) => void` | `required`| Callback function when page changes |
|
|
1734
|
-
| `count` | `number` | `undefined` | Total number of items |
|
|
1735
|
-
| `pageSize` | `number` | `undefined` | Number of items per page |
|
|
1736
|
-
| `totalPages` | `number` | `undefined` | Total number of pages (deprecated, use count + pageSize) |
|
|
1737
|
-
| `format` | `'none' \| 'long'` | `'none'` | Format for displaying page info |
|
|
1738
|
-
| `simplified` | `boolean` | `false` | Show simplified pagination (prev/next only) |
|
|
1739
|
-
| `asLink` | `boolean` | `false` | Render pagination buttons as links |
|
|
1740
|
-
| `getPageHref` | `(page: number) => string` | `undefined` | Custom href generator for pagination links |
|
|
1741
|
-
| `siblingCount` | `number` | `1` | Number of page buttons to show on each side |
|
|
1742
|
-
| `prevIcon` | `React.ReactNode` | `'<'` | Custom icon for previous button |
|
|
1743
|
-
| `nextIcon` | `React.ReactNode` | `'>'` | Custom icon for next button |
|
|
1744
|
-
| `size` | `'sm' \| 'md' \| 'lg'` | `'sm'` | Size variant of pagination buttons |
|
|
1745
|
-
|
|
1746
|
-
### Basic Pagination
|
|
1747
|
-
|
|
1748
|
-
```jsx
|
|
1749
|
-
import { useState } from "react";
|
|
1750
|
-
import { Pagination } from "alope-ui";
|
|
1751
|
-
|
|
1752
|
-
const BasicExample = () => {
|
|
1753
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
1754
|
-
|
|
1755
|
-
return (
|
|
1756
|
-
<Pagination
|
|
1757
|
-
currentPage={currentPage}
|
|
1758
|
-
count={100}
|
|
1759
|
-
pageSize={10}
|
|
1760
|
-
onPageChange={setCurrentPage}
|
|
1761
|
-
/>
|
|
1762
|
-
);
|
|
1763
|
-
};
|
|
1764
|
-
```
|
|
1765
|
-
|
|
1766
|
-
### Simplified Pagination
|
|
1767
|
-
|
|
1768
|
-
```jsx
|
|
1769
|
-
const SimplifiedExample = () => {
|
|
1770
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
1771
|
-
|
|
1772
|
-
return (
|
|
1773
|
-
<Pagination
|
|
1774
|
-
currentPage={currentPage}
|
|
1775
|
-
count={100}
|
|
1776
|
-
pageSize={10}
|
|
1777
|
-
onPageChange={setCurrentPage}
|
|
1778
|
-
simplified
|
|
1779
|
-
/>
|
|
1780
|
-
);
|
|
1781
|
-
};
|
|
1782
|
-
```
|
|
1783
|
-
|
|
1784
|
-
### Pagination with Format
|
|
1785
|
-
|
|
1786
|
-
```jsx
|
|
1787
|
-
{/* None Format - Shows page numbers */}
|
|
1788
|
-
<Pagination
|
|
1789
|
-
currentPage={currentPage}
|
|
1790
|
-
count={100}
|
|
1791
|
-
pageSize={10}
|
|
1792
|
-
onPageChange={setCurrentPage}
|
|
1793
|
-
format="none"
|
|
1794
|
-
simplified
|
|
1795
|
-
/>
|
|
1796
|
-
|
|
1797
|
-
{/* Long Format - Shows item range */}
|
|
1798
|
-
<Pagination
|
|
1799
|
-
currentPage={currentPage}
|
|
1800
|
-
count={100}
|
|
1801
|
-
pageSize={10}
|
|
1802
|
-
onPageChange={setCurrentPage}
|
|
1803
|
-
format="long"
|
|
1804
|
-
simplified
|
|
1805
|
-
/>
|
|
1806
|
-
```
|
|
1807
|
-
|
|
1808
|
-
### Sizes
|
|
1809
|
-
|
|
1810
|
-
```jsx
|
|
1811
|
-
{/* Small Size */}
|
|
1812
|
-
<Pagination
|
|
1813
|
-
currentPage={currentPage}
|
|
1814
|
-
count={100}
|
|
1815
|
-
pageSize={10}
|
|
1816
|
-
onPageChange={setCurrentPage}
|
|
1817
|
-
size="sm"
|
|
1818
|
-
/>
|
|
1819
|
-
|
|
1820
|
-
{/* Medium Size */}
|
|
1821
|
-
<Pagination
|
|
1822
|
-
currentPage={currentPage}
|
|
1823
|
-
count={100}
|
|
1824
|
-
pageSize={10}
|
|
1825
|
-
onPageChange={setCurrentPage}
|
|
1826
|
-
size="md"
|
|
1827
|
-
/>
|
|
1828
|
-
|
|
1829
|
-
{/* Large Size */}
|
|
1830
|
-
<Pagination
|
|
1831
|
-
currentPage={currentPage}
|
|
1832
|
-
count={100}
|
|
1833
|
-
pageSize={10}
|
|
1834
|
-
onPageChange={setCurrentPage}
|
|
1835
|
-
size="lg"
|
|
1836
|
-
/>
|
|
1837
|
-
```
|
|
1838
|
-
|
|
1839
|
-
### Custom Sibling Count
|
|
1840
|
-
|
|
1841
|
-
```jsx
|
|
1842
|
-
{/* Show 2 page buttons on each side */}
|
|
1843
|
-
<Pagination
|
|
1844
|
-
currentPage={currentPage}
|
|
1845
|
-
count={100}
|
|
1846
|
-
pageSize={10}
|
|
1847
|
-
onPageChange={setCurrentPage}
|
|
1848
|
-
siblingCount={2}
|
|
1849
|
-
/>
|
|
1850
|
-
```
|
|
1851
|
-
|
|
1852
|
-
### Custom Icons
|
|
1853
|
-
|
|
1854
|
-
```jsx
|
|
1855
|
-
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
1856
|
-
|
|
1857
|
-
<Pagination
|
|
1858
|
-
currentPage={currentPage}
|
|
1859
|
-
count={100}
|
|
1860
|
-
pageSize={10}
|
|
1861
|
-
onPageChange={setCurrentPage}
|
|
1862
|
-
prevIcon={<ChevronLeft size={16} />}
|
|
1863
|
-
nextIcon={<ChevronRight size={16} />}
|
|
1864
|
-
/>
|
|
1865
|
-
```
|
|
1866
|
-
|
|
1867
|
-
### As Links
|
|
1868
|
-
|
|
1869
|
-
```jsx
|
|
1870
|
-
<Pagination
|
|
1871
|
-
currentPage={currentPage}
|
|
1872
|
-
count={100}
|
|
1873
|
-
pageSize={10}
|
|
1874
|
-
onPageChange={setCurrentPage}
|
|
1875
|
-
asLink
|
|
1876
|
-
getPageHref={(page) => `/products?page=${page}`}
|
|
1877
|
-
/>
|
|
1878
|
-
```
|
|
1879
|
-
|
|
1880
|
-
### Using TotalPages (Legacy)
|
|
1881
|
-
|
|
1882
|
-
```jsx
|
|
1883
|
-
{/* This approach is deprecated, prefer using count + pageSize */}
|
|
1884
|
-
<Pagination
|
|
1885
|
-
currentPage={currentPage}
|
|
1886
|
-
totalPages={10}
|
|
1887
|
-
onPageChange={setCurrentPage}
|
|
1888
|
-
/>
|
|
1889
|
-
```
|
|
1890
|
-
|
|
1891
|
-
---
|
|
1892
|
-
|
|
1893
|
-
## Table
|
|
1894
|
-
|
|
1895
|
-
The Table component provides a flexible and feature-rich data table with support for custom rendering, row selection, striping, sticky headers, and responsive design.
|
|
1896
|
-
|
|
1897
|
-
### Import
|
|
1898
|
-
|
|
1899
|
-
```jsx
|
|
1900
|
-
import { Table } from "alope-ui";
|
|
1901
|
-
import type { Column } from "alope-ui";
|
|
1902
|
-
```
|
|
1903
|
-
|
|
1904
|
-
### Props
|
|
1905
|
-
|
|
1906
|
-
| Prop | Type | Default | Description |
|
|
1907
|
-
| ---------------------- | --------------------------------- | ---------- | ---------------------------------------------- |
|
|
1908
|
-
| `columns` | `Column<T>[]` | `required` | Array of column configurations |
|
|
1909
|
-
| `data` | `T[]` | `required` | Array of data objects to display |
|
|
1910
|
-
| `striped` | `boolean` | `false` | Enable alternating row colors |
|
|
1911
|
-
| `stripeColor` | `string` | `undefined`| Custom color for striped rows |
|
|
1912
|
-
| `headerClassName` | `string` | `""` | CSS class for table header |
|
|
1913
|
-
| `dataColumnClassName` | `string` | `""` | CSS class for data cells |
|
|
1914
|
-
| `dataRowClassName` | `string` | `""` | CSS class for data rows |
|
|
1915
|
-
| `tableClassName` | `string` | `""` | CSS class for table element |
|
|
1916
|
-
| `captionClassName` | `string` | `""` | CSS class for caption |
|
|
1917
|
-
| `containerClassName` | `string` | `""` | CSS class for container |
|
|
1918
|
-
| `customEmptyData` | `React.ReactNode` | `undefined`| Custom message when no data |
|
|
1919
|
-
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size variant of table |
|
|
1920
|
-
| `caption` | `string` | `undefined`| Table caption text |
|
|
1921
|
-
| `captionPosition` | `'top' \| 'bottom'` | `'bottom'` | Position of caption |
|
|
1922
|
-
| `stickyHeader` | `boolean` | `false` | Make header sticky on scroll |
|
|
1923
|
-
| `selectable` | `boolean` | `false` | Enable row selection with checkboxes |
|
|
1924
|
-
| `onSelectionChange` | `(selected: T[]) => void` | `undefined`| Callback when selection changes |
|
|
1925
|
-
| `selectedRows` | `T[]` | `[]` | Array of selected rows |
|
|
1926
|
-
|
|
1927
|
-
### Column Type
|
|
1928
|
-
|
|
1929
|
-
```typescript
|
|
1930
|
-
type Column<T> = {
|
|
1931
|
-
header: string;
|
|
1932
|
-
accessor: keyof T;
|
|
1933
|
-
render?: (value: T[keyof T], row: T) => React.ReactNode;
|
|
1934
|
-
};
|
|
1935
|
-
```
|
|
1936
|
-
|
|
1937
|
-
### Basic Table
|
|
1938
|
-
|
|
1939
|
-
```jsx
|
|
1940
|
-
import { Table } from "alope-ui";
|
|
1941
|
-
import type { Column } from "alope-ui";
|
|
1942
|
-
|
|
1943
|
-
type User = {
|
|
1944
|
-
id: number;
|
|
1945
|
-
name: string;
|
|
1946
|
-
email: string;
|
|
1947
|
-
role: string;
|
|
1948
|
-
};
|
|
1949
|
-
|
|
1950
|
-
const columns: Column<User>[] = [
|
|
1951
|
-
{ header: "Name", accessor: "name" },
|
|
1952
|
-
{ header: "Email", accessor: "email" },
|
|
1953
|
-
{ header: "Role", accessor: "role" },
|
|
1954
|
-
];
|
|
1955
|
-
|
|
1956
|
-
const data: User[] = [
|
|
1957
|
-
{ id: 1, name: "John Doe", email: "john@example.com", role: "Admin" },
|
|
1958
|
-
{ id: 2, name: "Jane Smith", email: "jane@example.com", role: "User" },
|
|
1959
|
-
{ id: 3, name: "Bob Johnson", email: "bob@example.com", role: "Manager" },
|
|
1960
|
-
];
|
|
1961
|
-
|
|
1962
|
-
const BasicExample = () => {
|
|
1963
|
-
return <Table columns={columns} data={data} />;
|
|
1964
|
-
};
|
|
1965
|
-
```
|
|
1966
|
-
|
|
1967
|
-
### Striped Table
|
|
1968
|
-
|
|
1969
|
-
```jsx
|
|
1970
|
-
<Table columns={columns} data={data} striped />
|
|
1971
|
-
|
|
1972
|
-
{/* With custom stripe color */}
|
|
1973
|
-
<Table
|
|
1974
|
-
columns={columns}
|
|
1975
|
-
data={data}
|
|
1976
|
-
striped
|
|
1977
|
-
stripeColor="bg-blue-50 dark:bg-blue-900"
|
|
1978
|
-
/>
|
|
1979
|
-
```
|
|
1980
|
-
|
|
1981
|
-
### Sizes
|
|
1982
|
-
|
|
1983
|
-
```jsx
|
|
1984
|
-
{/* Small Size */}
|
|
1985
|
-
<Table columns={columns} data={data} size="sm" />
|
|
1986
|
-
|
|
1987
|
-
{/* Medium Size */}
|
|
1988
|
-
<Table columns={columns} data={data} size="md" />
|
|
1989
|
-
|
|
1990
|
-
{/* Large Size */}
|
|
1991
|
-
<Table columns={columns} data={data} size="lg" />
|
|
1992
|
-
```
|
|
1993
|
-
|
|
1994
|
-
### Custom Rendering
|
|
1995
|
-
|
|
1996
|
-
```jsx
|
|
1997
|
-
const columns: Column<User>[] = [
|
|
1998
|
-
{ header: "Name", accessor: "name" },
|
|
1999
|
-
{ header: "Email", accessor: "email" },
|
|
2000
|
-
{
|
|
2001
|
-
header: "Role",
|
|
2002
|
-
accessor: "role",
|
|
2003
|
-
render: (value, row) => (
|
|
2004
|
-
<span
|
|
2005
|
-
className={
|
|
2006
|
-
value === "Admin"
|
|
2007
|
-
? "bg-red-100 text-red-800 px-2 py-1 rounded"
|
|
2008
|
-
: "bg-blue-100 text-blue-800 px-2 py-1 rounded"
|
|
2009
|
-
}
|
|
2010
|
-
>
|
|
2011
|
-
{value}
|
|
2012
|
-
</span>
|
|
2013
|
-
),
|
|
2014
|
-
},
|
|
2015
|
-
];
|
|
2016
|
-
|
|
2017
|
-
<Table columns={columns} data={data} />;
|
|
2018
|
-
```
|
|
2019
|
-
|
|
2020
|
-
### Selectable Rows
|
|
2021
|
-
|
|
2022
|
-
```jsx
|
|
2023
|
-
import { useState } from "react";
|
|
2024
|
-
|
|
2025
|
-
const SelectableExample = () => {
|
|
2026
|
-
const [selectedRows, setSelectedRows] = useState<User[]>([]);
|
|
2027
|
-
|
|
2028
|
-
return (
|
|
2029
|
-
<Table
|
|
2030
|
-
columns={columns}
|
|
2031
|
-
data={data}
|
|
2032
|
-
selectable
|
|
2033
|
-
selectedRows={selectedRows}
|
|
2034
|
-
onSelectionChange={setSelectedRows}
|
|
2035
|
-
/>
|
|
2036
|
-
);
|
|
2037
|
-
};
|
|
2038
|
-
```
|
|
2039
|
-
|
|
2040
|
-
### Sticky Header
|
|
2041
|
-
|
|
2042
|
-
```jsx
|
|
2043
|
-
<Table columns={columns} data={data} stickyHeader />
|
|
2044
|
-
```
|
|
2045
|
-
|
|
2046
|
-
### With Caption
|
|
2047
|
-
|
|
2048
|
-
```jsx
|
|
2049
|
-
{/* Caption at bottom */}
|
|
2050
|
-
<Table
|
|
2051
|
-
columns={columns}
|
|
2052
|
-
data={data}
|
|
2053
|
-
caption="User Management Table"
|
|
2054
|
-
captionPosition="bottom"
|
|
2055
|
-
/>
|
|
2056
|
-
|
|
2057
|
-
{/* Caption at top */}
|
|
2058
|
-
<Table
|
|
2059
|
-
columns={columns}
|
|
2060
|
-
data={data}
|
|
2061
|
-
caption="User Management Table"
|
|
2062
|
-
captionPosition="top"
|
|
2063
|
-
/>
|
|
2064
|
-
```
|
|
2065
|
-
|
|
2066
|
-
### Custom Empty State
|
|
2067
|
-
|
|
2068
|
-
```jsx
|
|
2069
|
-
<Table
|
|
2070
|
-
columns={columns}
|
|
2071
|
-
data={[]}
|
|
2072
|
-
customEmptyData={
|
|
2073
|
-
<div className="flex flex-col items-center gap-2">
|
|
2074
|
-
<span className="text-gray-500">No users found</span>
|
|
2075
|
-
<button className="px-4 py-2 bg-blue-500 text-white rounded">
|
|
2076
|
-
Add User
|
|
2077
|
-
</button>
|
|
2078
|
-
</div>
|
|
2079
|
-
}
|
|
2080
|
-
/>
|
|
2081
|
-
```
|
|
2082
|
-
|
|
2083
|
-
### Custom Styling
|
|
2084
|
-
|
|
2085
|
-
```jsx
|
|
2086
|
-
<Table
|
|
2087
|
-
columns={columns}
|
|
2088
|
-
data={data}
|
|
2089
|
-
containerClassName="shadow-lg rounded-lg"
|
|
2090
|
-
tableClassName="border-2 border-blue-500"
|
|
2091
|
-
headerClassName="bg-blue-600 text-white"
|
|
2092
|
-
dataRowClassName="hover:bg-blue-50"
|
|
2093
|
-
dataColumnClassName="text-gray-700"
|
|
2094
|
-
/>
|
|
2095
|
-
```
|
|
2096
|
-
|
|
2097
|
-
### Complete Example
|
|
2098
|
-
|
|
2099
|
-
```jsx
|
|
2100
|
-
import { useState } from "react";
|
|
2101
|
-
import { Table } from "alope-ui";
|
|
2102
|
-
import type { Column } from "alope-ui";
|
|
2103
|
-
|
|
2104
|
-
type Product = {
|
|
2105
|
-
id: number;
|
|
2106
|
-
name: string;
|
|
2107
|
-
price: number;
|
|
2108
|
-
stock: number;
|
|
2109
|
-
status: string;
|
|
2110
|
-
};
|
|
2111
|
-
|
|
2112
|
-
const ProductTable = () => {
|
|
2113
|
-
const [selectedRows, setSelectedRows] = useState<Product[]>([]);
|
|
2114
|
-
|
|
2115
|
-
const columns: Column<Product>[] = [
|
|
2116
|
-
{ header: "Product Name", accessor: "name" },
|
|
2117
|
-
{
|
|
2118
|
-
header: "Price",
|
|
2119
|
-
accessor: "price",
|
|
2120
|
-
render: (value) => `$${value.toFixed(2)}`,
|
|
2121
|
-
},
|
|
2122
|
-
{ header: "Stock", accessor: "stock" },
|
|
2123
|
-
{
|
|
2124
|
-
header: "Status",
|
|
2125
|
-
accessor: "status",
|
|
2126
|
-
render: (value) => (
|
|
2127
|
-
<span
|
|
2128
|
-
className={
|
|
2129
|
-
value === "Available"
|
|
2130
|
-
? "bg-green-100 text-green-800 px-2 py-1 rounded"
|
|
2131
|
-
: "bg-gray-100 text-gray-800 px-2 py-1 rounded"
|
|
2132
|
-
}
|
|
2133
|
-
>
|
|
2134
|
-
{value}
|
|
2135
|
-
</span>
|
|
2136
|
-
),
|
|
2137
|
-
},
|
|
2138
|
-
];
|
|
2139
|
-
|
|
2140
|
-
const data: Product[] = [
|
|
2141
|
-
{ id: 1, name: "Laptop", price: 999.99, stock: 15, status: "Available" },
|
|
2142
|
-
{ id: 2, name: "Mouse", price: 29.99, stock: 0, status: "Out of Stock" },
|
|
2143
|
-
{ id: 3, name: "Keyboard", price: 79.99, stock: 23, status: "Available" },
|
|
2144
|
-
];
|
|
2145
|
-
|
|
2146
|
-
return (
|
|
2147
|
-
<Table
|
|
2148
|
-
columns={columns}
|
|
2149
|
-
data={data}
|
|
2150
|
-
striped
|
|
2151
|
-
selectable
|
|
2152
|
-
selectedRows={selectedRows}
|
|
2153
|
-
onSelectionChange={setSelectedRows}
|
|
2154
|
-
stickyHeader
|
|
2155
|
-
caption="Product Inventory"
|
|
2156
|
-
size="md"
|
|
2157
|
-
/>
|
|
2158
|
-
);
|
|
2159
|
-
};
|
|
2160
|
-
```
|
|
2161
|
-
|
|
2162
|
-
---
|
|
2163
|
-
|
|
2164
|
-
## Tooltip
|
|
2165
|
-
|
|
2166
|
-
The Tooltip component displays informative text when hovering over an element, with customizable placement, styling, and animation options.
|
|
2167
|
-
|
|
2168
|
-
### Import
|
|
2169
|
-
|
|
2170
|
-
```jsx
|
|
2171
|
-
import { Tooltip } from "alope-ui";
|
|
2172
|
-
```
|
|
2173
|
-
|
|
2174
|
-
### Props
|
|
2175
|
-
|
|
2176
|
-
| Prop | Type | Default | Description |
|
|
2177
|
-
| ------------------- | ----------------------------------------- | --------------------------------- | ---------------------------------------- |
|
|
2178
|
-
| `children` | `React.ReactNode` | `required` | Element that triggers the tooltip |
|
|
2179
|
-
| `text` | `string` | `required` | Text content of the tooltip |
|
|
2180
|
-
| `showArrow` | `boolean` | `true` | Show arrow pointing to trigger element |
|
|
2181
|
-
| `placement` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | Position of tooltip relative to trigger |
|
|
2182
|
-
| `offset` | `number` | `8` | Distance from trigger element (in px) |
|
|
2183
|
-
| `bgColor` | `string` | `'bg-gray-800 dark:bg-gray-600'` | Background color class |
|
|
2184
|
-
| `isOpen` | `boolean` | `undefined` | Controlled visibility state |
|
|
2185
|
-
| `onOpenChange` | `(open: boolean) => void` | `undefined` | Callback when visibility changes |
|
|
2186
|
-
| `disabled` | `boolean` | `false` | Disable tooltip functionality |
|
|
2187
|
-
| `animationDuration` | `number` | `300` | Animation duration (in ms) |
|
|
2188
|
-
| `delay` | `number` | `700` | Delay before showing tooltip (in ms) |
|
|
2189
|
-
|
|
2190
|
-
### Basic Tooltip
|
|
2191
|
-
|
|
2192
|
-
```jsx
|
|
2193
|
-
import { Tooltip } from "alope-ui";
|
|
2194
|
-
|
|
2195
|
-
const BasicExample = () => {
|
|
2196
|
-
return (
|
|
2197
|
-
<Tooltip text="This is a helpful tooltip">
|
|
2198
|
-
<button className="px-4 py-2 bg-blue-500 text-white rounded">
|
|
2199
|
-
Hover me
|
|
2200
|
-
</button>
|
|
2201
|
-
</Tooltip>
|
|
2202
|
-
);
|
|
2203
|
-
};
|
|
2204
|
-
```
|
|
2205
|
-
|
|
2206
|
-
### Placement
|
|
2207
|
-
|
|
2208
|
-
```jsx
|
|
2209
|
-
{/* Top Placement */}
|
|
2210
|
-
<Tooltip text="Tooltip on top" placement="top">
|
|
2211
|
-
<button>Top</button>
|
|
2212
|
-
</Tooltip>
|
|
2213
|
-
|
|
2214
|
-
{/* Bottom Placement */}
|
|
2215
|
-
<Tooltip text="Tooltip on bottom" placement="bottom">
|
|
2216
|
-
<button>Bottom</button>
|
|
2217
|
-
</Tooltip>
|
|
2218
|
-
|
|
2219
|
-
{/* Left Placement */}
|
|
2220
|
-
<Tooltip text="Tooltip on left" placement="left">
|
|
2221
|
-
<button>Left</button>
|
|
2222
|
-
</Tooltip>
|
|
2223
|
-
|
|
2224
|
-
{/* Right Placement */}
|
|
2225
|
-
<Tooltip text="Tooltip on right" placement="right">
|
|
2226
|
-
<button>Right</button>
|
|
2227
|
-
</Tooltip>
|
|
2228
|
-
```
|
|
2229
|
-
|
|
2230
|
-
### Without Arrow
|
|
2231
|
-
|
|
2232
|
-
```jsx
|
|
2233
|
-
<Tooltip text="Tooltip without arrow" showArrow={false}>
|
|
2234
|
-
<button>No Arrow</button>
|
|
2235
|
-
</Tooltip>
|
|
2236
|
-
```
|
|
2237
|
-
|
|
2238
|
-
### Custom Offset
|
|
2239
|
-
|
|
2240
|
-
```jsx
|
|
2241
|
-
{/* Small offset */}
|
|
2242
|
-
<Tooltip text="Close to element" offset={4}>
|
|
2243
|
-
<button>Small Offset</button>
|
|
2244
|
-
</Tooltip>
|
|
2245
|
-
|
|
2246
|
-
{/* Large offset */}
|
|
2247
|
-
<Tooltip text="Far from element" offset={16}>
|
|
2248
|
-
<button>Large Offset</button>
|
|
2249
|
-
</Tooltip>
|
|
2250
|
-
```
|
|
2251
|
-
|
|
2252
|
-
### Custom Background Color
|
|
2253
|
-
|
|
2254
|
-
```jsx
|
|
2255
|
-
<Tooltip text="Blue tooltip" bgColor="bg-blue-600">
|
|
2256
|
-
<button>Blue Tooltip</button>
|
|
2257
|
-
</Tooltip>
|
|
2258
|
-
|
|
2259
|
-
<Tooltip text="Red tooltip" bgColor="bg-red-600">
|
|
2260
|
-
<button>Red Tooltip</button>
|
|
2261
|
-
</Tooltip>
|
|
2262
|
-
|
|
2263
|
-
<Tooltip text="Green tooltip" bgColor="bg-green-600">
|
|
2264
|
-
<button>Green Tooltip</button>
|
|
2265
|
-
</Tooltip>
|
|
2266
|
-
```
|
|
2267
|
-
|
|
2268
|
-
### Controlled Tooltip
|
|
2269
|
-
|
|
2270
|
-
```jsx
|
|
2271
|
-
import { useState } from "react";
|
|
2272
|
-
|
|
2273
|
-
const ControlledExample = () => {
|
|
2274
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
2275
|
-
|
|
2276
|
-
return (
|
|
2277
|
-
<div>
|
|
2278
|
-
<Tooltip
|
|
2279
|
-
text="Controlled tooltip"
|
|
2280
|
-
isOpen={isOpen}
|
|
2281
|
-
onOpenChange={setIsOpen}
|
|
2282
|
-
>
|
|
2283
|
-
<button onClick={() => setIsOpen(!isOpen)}>
|
|
2284
|
-
Click to toggle
|
|
2285
|
-
</button>
|
|
2286
|
-
</Tooltip>
|
|
2287
|
-
</div>
|
|
2288
|
-
);
|
|
2289
|
-
};
|
|
2290
|
-
```
|
|
2291
|
-
|
|
2292
|
-
### Custom Animation
|
|
2293
|
-
|
|
2294
|
-
```jsx
|
|
2295
|
-
{/* Fast animation */}
|
|
2296
|
-
<Tooltip text="Fast animation" animationDuration={150}>
|
|
2297
|
-
<button>Fast</button>
|
|
2298
|
-
</Tooltip>
|
|
2299
|
-
|
|
2300
|
-
{/* Slow animation */}
|
|
2301
|
-
<Tooltip text="Slow animation" animationDuration={600}>
|
|
2302
|
-
<button>Slow</button>
|
|
2303
|
-
</Tooltip>
|
|
2304
|
-
```
|
|
2305
|
-
|
|
2306
|
-
### Custom Delay
|
|
2307
|
-
|
|
2308
|
-
```jsx
|
|
2309
|
-
{/* No delay */}
|
|
2310
|
-
<Tooltip text="Instant tooltip" delay={0}>
|
|
2311
|
-
<button>No Delay</button>
|
|
2312
|
-
</Tooltip>
|
|
2313
|
-
|
|
2314
|
-
{/* Long delay */}
|
|
2315
|
-
<Tooltip text="Patient tooltip" delay={1500}>
|
|
2316
|
-
<button>Long Delay</button>
|
|
2317
|
-
</Tooltip>
|
|
2318
|
-
```
|
|
2319
|
-
|
|
2320
|
-
### Disabled Tooltip
|
|
2321
|
-
|
|
2322
|
-
```jsx
|
|
2323
|
-
<Tooltip text="This won't show" disabled>
|
|
2324
|
-
<button>Disabled Tooltip</button>
|
|
2325
|
-
</Tooltip>
|
|
2326
|
-
```
|
|
2327
|
-
|
|
2328
|
-
### With Icons
|
|
2329
|
-
|
|
2330
|
-
```jsx
|
|
2331
|
-
import { Info, HelpCircle } from "lucide-react";
|
|
2332
|
-
|
|
2333
|
-
<Tooltip text="Additional information about this feature">
|
|
2334
|
-
<Info className="w-4 h-4 text-gray-500 cursor-help" />
|
|
2335
|
-
</Tooltip>
|
|
2336
|
-
|
|
2337
|
-
<Tooltip text="Click for help documentation" placement="right">
|
|
2338
|
-
<HelpCircle className="w-5 h-5 text-blue-500 cursor-pointer" />
|
|
2339
|
-
</Tooltip>
|
|
2340
|
-
```
|
|
2341
|
-
|
|
2342
|
-
### Complete Example
|
|
2343
|
-
|
|
2344
|
-
```jsx
|
|
2345
|
-
import { Tooltip } from "alope-ui";
|
|
2346
|
-
import { Info } from "lucide-react";
|
|
2347
|
-
|
|
2348
|
-
const UserProfile = () => {
|
|
2349
|
-
return (
|
|
2350
|
-
<div className="flex items-center gap-4">
|
|
2351
|
-
<div className="flex items-center gap-2">
|
|
2352
|
-
<span>Username</span>
|
|
2353
|
-
<Tooltip
|
|
2354
|
-
text="Your username is visible to all users"
|
|
2355
|
-
placement="top"
|
|
2356
|
-
bgColor="bg-blue-600"
|
|
2357
|
-
delay={500}
|
|
2358
|
-
>
|
|
2359
|
-
<Info className="w-4 h-4 text-gray-400 cursor-help" />
|
|
2360
|
-
</Tooltip>
|
|
2361
|
-
</div>
|
|
2362
|
-
|
|
2363
|
-
<div className="flex items-center gap-2">
|
|
2364
|
-
<span>Email</span>
|
|
2365
|
-
<Tooltip
|
|
2366
|
-
text="Your email is kept private and secure"
|
|
2367
|
-
placement="right"
|
|
2368
|
-
showArrow={false}
|
|
2369
|
-
offset={12}
|
|
2370
|
-
>
|
|
2371
|
-
<Info className="w-4 h-4 text-gray-400 cursor-help" />
|
|
2372
|
-
</Tooltip>
|
|
2373
|
-
</div>
|
|
2374
|
-
|
|
2375
|
-
<Tooltip text="Click to edit your profile" placement="bottom">
|
|
2376
|
-
<button className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
|
|
2377
|
-
Edit Profile
|
|
2378
|
-
</button>
|
|
2379
|
-
</Tooltip>
|
|
2380
|
-
</div>
|
|
2381
|
-
);
|
|
2382
|
-
};
|
|
2383
|
-
```
|
|
2384
|
-
|
|
2385
|
-
---
|
|
2386
|
-
|
|
2387
|
-
## Spinner
|
|
2388
|
-
|
|
2389
|
-
The Spinner component displays an animated loading indicator with customizable size, color, duration, and thickness.
|
|
2390
|
-
|
|
2391
|
-
### Import
|
|
2392
|
-
|
|
2393
|
-
```jsx
|
|
2394
|
-
import { Spinner } from "alope-ui";
|
|
2395
|
-
```
|
|
2396
|
-
|
|
2397
|
-
### Props
|
|
2398
|
-
|
|
2399
|
-
| Prop | Type | Default | Description |
|
|
2400
|
-
| ----------- | --------------------------------------------------------------- | --------- | ------------------------------------- |
|
|
2401
|
-
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the spinner |
|
|
2402
|
-
| `color` | `'primary' \| 'error' \| 'warning' \| 'success' \| 'info' \| 'secondary'` | `'primary'` | Color variant of the spinner |
|
|
2403
|
-
| `className` | `string` | `""` | Additional CSS classes |
|
|
2404
|
-
| `duration` | `number` | `1000` | Animation duration (in ms) |
|
|
2405
|
-
| `thickness` | `number` | `undefined` | Custom border thickness (in px) |
|
|
2406
|
-
|
|
2407
|
-
### Basic Spinner
|
|
2408
|
-
|
|
2409
|
-
```jsx
|
|
2410
|
-
import { Spinner } from "alope-ui";
|
|
2411
|
-
|
|
2412
|
-
const BasicExample = () => {
|
|
2413
|
-
return <Spinner />;
|
|
2414
|
-
};
|
|
2415
|
-
```
|
|
2416
|
-
|
|
2417
|
-
### Sizes
|
|
2418
|
-
|
|
2419
|
-
```jsx
|
|
2420
|
-
{/* Small Size */}
|
|
2421
|
-
<Spinner size="sm" />
|
|
2422
|
-
|
|
2423
|
-
{/* Medium Size */}
|
|
2424
|
-
<Spinner size="md" />
|
|
2425
|
-
|
|
2426
|
-
{/* Large Size */}
|
|
2427
|
-
<Spinner size="lg" />
|
|
2428
|
-
```
|
|
2429
|
-
|
|
2430
|
-
### Colors
|
|
2431
|
-
|
|
2432
|
-
```jsx
|
|
2433
|
-
{/* Primary Color */}
|
|
2434
|
-
<Spinner color="primary" />
|
|
2435
|
-
|
|
2436
|
-
{/* Error Color */}
|
|
2437
|
-
<Spinner color="error" />
|
|
2438
|
-
|
|
2439
|
-
{/* Warning Color */}
|
|
2440
|
-
<Spinner color="warning" />
|
|
2441
|
-
|
|
2442
|
-
{/* Success Color */}
|
|
2443
|
-
<Spinner color="success" />
|
|
2444
|
-
|
|
2445
|
-
{/* Info Color */}
|
|
2446
|
-
<Spinner color="info" />
|
|
2447
|
-
|
|
2448
|
-
{/* Secondary Color */}
|
|
2449
|
-
<Spinner color="secondary" />
|
|
2450
|
-
```
|
|
2451
|
-
|
|
2452
|
-
### Custom Duration
|
|
2453
|
-
|
|
2454
|
-
```jsx
|
|
2455
|
-
{/* Fast animation */}
|
|
2456
|
-
<Spinner duration={500} />
|
|
2457
|
-
|
|
2458
|
-
{/* Slow animation */}
|
|
2459
|
-
<Spinner duration={2000} />
|
|
2460
|
-
```
|
|
2461
|
-
|
|
2462
|
-
### Custom Thickness
|
|
2463
|
-
|
|
2464
|
-
```jsx
|
|
2465
|
-
{/* Thin spinner */}
|
|
2466
|
-
<Spinner thickness={1} />
|
|
2467
|
-
|
|
2468
|
-
{/* Thick spinner */}
|
|
2469
|
-
<Spinner thickness={6} />
|
|
2470
|
-
```
|
|
2471
|
-
|
|
2472
|
-
### Combined Customization
|
|
2473
|
-
|
|
2474
|
-
```jsx
|
|
2475
|
-
<Spinner size="lg" color="success" duration={1500} thickness={5} />
|
|
2476
|
-
```
|
|
2477
|
-
|
|
2478
|
-
### With Custom Styling
|
|
2479
|
-
|
|
2480
|
-
```jsx
|
|
2481
|
-
<Spinner className="mx-auto my-4" />
|
|
2482
|
-
|
|
2483
|
-
<Spinner className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" />
|
|
2484
|
-
```
|
|
2485
|
-
|
|
2486
|
-
### Loading States
|
|
2487
|
-
|
|
2488
|
-
```jsx
|
|
2489
|
-
import { useState } from "react";
|
|
2490
|
-
|
|
2491
|
-
const LoadingButton = () => {
|
|
2492
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
2493
|
-
|
|
2494
|
-
const handleClick = async () => {
|
|
2495
|
-
setIsLoading(true);
|
|
2496
|
-
// Simulate API call
|
|
2497
|
-
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2498
|
-
setIsLoading(false);
|
|
2499
|
-
};
|
|
2500
|
-
|
|
2501
|
-
return (
|
|
2502
|
-
<button
|
|
2503
|
-
onClick={handleClick}
|
|
2504
|
-
disabled={isLoading}
|
|
2505
|
-
className="px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50 flex items-center gap-2"
|
|
2506
|
-
>
|
|
2507
|
-
{isLoading && <Spinner size="sm" className="border-white" />}
|
|
2508
|
-
{isLoading ? "Loading..." : "Submit"}
|
|
2509
|
-
</button>
|
|
2510
|
-
);
|
|
2511
|
-
};
|
|
2512
|
-
```
|
|
2513
|
-
|
|
2514
|
-
### Centered Loading
|
|
2515
|
-
|
|
2516
|
-
```jsx
|
|
2517
|
-
const CenteredLoading = () => {
|
|
2518
|
-
return (
|
|
2519
|
-
<div className="flex items-center justify-center h-64">
|
|
2520
|
-
<Spinner size="lg" color="primary" />
|
|
2521
|
-
</div>
|
|
2522
|
-
);
|
|
2523
|
-
};
|
|
2524
|
-
```
|
|
2525
|
-
|
|
2526
|
-
### With Text
|
|
2527
|
-
|
|
2528
|
-
```jsx
|
|
2529
|
-
const LoadingWithText = () => {
|
|
2530
|
-
return (
|
|
2531
|
-
<div className="flex flex-col items-center gap-3">
|
|
2532
|
-
<Spinner size="lg" color="info" />
|
|
2533
|
-
<p className="text-gray-600 dark:text-gray-400">Loading data...</p>
|
|
2534
|
-
</div>
|
|
2535
|
-
);
|
|
2536
|
-
};
|
|
2537
|
-
```
|
|
2538
|
-
|
|
2539
|
-
### Complete Example
|
|
2540
|
-
|
|
2541
|
-
```jsx
|
|
2542
|
-
import { useState, useEffect } from "react";
|
|
2543
|
-
import { Spinner } from "alope-ui";
|
|
2544
|
-
|
|
2545
|
-
const DataFetcher = () => {
|
|
2546
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
2547
|
-
const [data, setData] = useState(null);
|
|
2548
|
-
|
|
2549
|
-
useEffect(() => {
|
|
2550
|
-
const fetchData = async () => {
|
|
2551
|
-
setIsLoading(true);
|
|
2552
|
-
try {
|
|
2553
|
-
// Simulate API call
|
|
2554
|
-
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2555
|
-
setData({ message: "Data loaded successfully!" });
|
|
2556
|
-
} catch (error) {
|
|
2557
|
-
console.error(error);
|
|
2558
|
-
} finally {
|
|
2559
|
-
setIsLoading(false);
|
|
2560
|
-
}
|
|
2561
|
-
};
|
|
2562
|
-
|
|
2563
|
-
fetchData();
|
|
2564
|
-
}, []);
|
|
2565
|
-
|
|
2566
|
-
if (isLoading) {
|
|
2567
|
-
return (
|
|
2568
|
-
<div className="flex flex-col items-center justify-center h-96 gap-4">
|
|
2569
|
-
<Spinner size="lg" color="primary" duration={800} />
|
|
2570
|
-
<p className="text-gray-600 dark:text-gray-400">
|
|
2571
|
-
Fetching your data...
|
|
2572
|
-
</p>
|
|
2573
|
-
</div>
|
|
2574
|
-
);
|
|
2575
|
-
}
|
|
2576
|
-
|
|
2577
|
-
return (
|
|
2578
|
-
<div className="p-4">
|
|
2579
|
-
<h2 className="text-xl font-bold">{data?.message}</h2>
|
|
2580
|
-
</div>
|
|
2581
|
-
);
|
|
2582
|
-
};
|
|
2583
|
-
```
|
|
2584
|
-
|
|
2585
|
-
---
|
|
2586
|
-
|
|
2587
|
-
## Skeleton
|
|
2588
|
-
|
|
2589
|
-
The Skeleton component displays a placeholder preview of content before the actual data is loaded, improving perceived performance and user experience.
|
|
2590
|
-
|
|
2591
|
-
### Import
|
|
2592
|
-
|
|
2593
|
-
```jsx
|
|
2594
|
-
import { Skeleton } from "alope-ui";
|
|
2595
|
-
```
|
|
2596
|
-
|
|
2597
|
-
### Props
|
|
2598
|
-
|
|
2599
|
-
| Prop | Type | Default | Description |
|
|
2600
|
-
| ----------- | ------------------------- | ------------ | ---------------------------------------------- |
|
|
2601
|
-
| `width` | `string` | `undefined` | Width of the skeleton (CSS value) |
|
|
2602
|
-
| `height` | `string` | `undefined` | Height of the skeleton (CSS value) |
|
|
2603
|
-
| `rounded` | `boolean` | `false` | Apply rounded shape (full circle/pill) |
|
|
2604
|
-
| `isLoading` | `boolean` | `true` | Show skeleton or actual content |
|
|
2605
|
-
| `children` | `React.ReactNode` | `undefined` | Content to render when not loading |
|
|
2606
|
-
| `animode` | `'shimmer' \| 'flash'` | `'flash'` | Animation mode for the skeleton |
|
|
2607
|
-
|
|
2608
|
-
### Basic Skeleton
|
|
2609
|
-
|
|
2610
|
-
```jsx
|
|
2611
|
-
import { Skeleton } from "alope-ui";
|
|
2612
|
-
|
|
2613
|
-
const BasicExample = () => {
|
|
2614
|
-
return <Skeleton width="200px" height="20px" />;
|
|
2615
|
-
};
|
|
2616
|
-
```
|
|
2617
|
-
|
|
2618
|
-
### With Children
|
|
2619
|
-
|
|
2620
|
-
```jsx
|
|
2621
|
-
import { useState, useEffect } from "react";
|
|
2622
|
-
|
|
2623
|
-
const SkeletonWithChildren = () => {
|
|
2624
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
2625
|
-
|
|
2626
|
-
useEffect(() => {
|
|
2627
|
-
setTimeout(() => setIsLoading(false), 2000);
|
|
2628
|
-
}, []);
|
|
2629
|
-
|
|
2630
|
-
return (
|
|
2631
|
-
<Skeleton isLoading={isLoading}>
|
|
2632
|
-
<p>This content will show after loading</p>
|
|
2633
|
-
</Skeleton>
|
|
2634
|
-
);
|
|
2635
|
-
};
|
|
2636
|
-
```
|
|
2637
|
-
|
|
2638
|
-
### Animation Modes
|
|
2639
|
-
|
|
2640
|
-
```jsx
|
|
2641
|
-
{/* Flash animation */}
|
|
2642
|
-
<Skeleton width="200px" height="20px" animode="flash" />
|
|
2643
|
-
|
|
2644
|
-
{/* Shimmer animation */}
|
|
2645
|
-
<Skeleton width="200px" height="20px" animode="shimmer" />
|
|
2646
|
-
```
|
|
2647
|
-
|
|
2648
|
-
### Rounded Skeleton
|
|
2649
|
-
|
|
2650
|
-
```jsx
|
|
2651
|
-
{/* Rounded rectangle */}
|
|
2652
|
-
<Skeleton width="100px" height="100px" rounded />
|
|
2653
|
-
|
|
2654
|
-
{/* Avatar skeleton */}
|
|
2655
|
-
<Skeleton width="48px" height="48px" rounded />
|
|
2656
|
-
```
|
|
2657
|
-
|
|
2658
|
-
### Different Sizes
|
|
2659
|
-
|
|
2660
|
-
```jsx
|
|
2661
|
-
{/* Small */}
|
|
2662
|
-
<Skeleton width="100px" height="16px" />
|
|
2663
|
-
|
|
2664
|
-
{/* Medium */}
|
|
2665
|
-
<Skeleton width="200px" height="20px" />
|
|
2666
|
-
|
|
2667
|
-
{/* Large */}
|
|
2668
|
-
<Skeleton width="300px" height="24px" />
|
|
2669
|
-
|
|
2670
|
-
{/* Full width */}
|
|
2671
|
-
<Skeleton width="100%" height="20px" />
|
|
2672
|
-
```
|
|
2673
|
-
|
|
2674
|
-
### Text Skeleton
|
|
2675
|
-
|
|
2676
|
-
```jsx
|
|
2677
|
-
const TextSkeleton = () => {
|
|
2678
|
-
return (
|
|
2679
|
-
<div className="space-y-2">
|
|
2680
|
-
<Skeleton width="100%" height="20px" />
|
|
2681
|
-
<Skeleton width="90%" height="20px" />
|
|
2682
|
-
<Skeleton width="95%" height="20px" />
|
|
2683
|
-
<Skeleton width="85%" height="20px" />
|
|
2684
|
-
</div>
|
|
2685
|
-
);
|
|
2686
|
-
};
|
|
2687
|
-
```
|
|
2688
|
-
|
|
2689
|
-
### Card Skeleton
|
|
2690
|
-
|
|
2691
|
-
```jsx
|
|
2692
|
-
const CardSkeleton = () => {
|
|
2693
|
-
return (
|
|
2694
|
-
<div className="border rounded-lg p-4 space-y-4">
|
|
2695
|
-
{/* Image skeleton */}
|
|
2696
|
-
<Skeleton width="100%" height="200px" />
|
|
2697
|
-
|
|
2698
|
-
{/* Title skeleton */}
|
|
2699
|
-
<Skeleton width="70%" height="24px" />
|
|
2700
|
-
|
|
2701
|
-
{/* Description skeleton */}
|
|
2702
|
-
<div className="space-y-2">
|
|
2703
|
-
<Skeleton width="100%" height="16px" />
|
|
2704
|
-
<Skeleton width="95%" height="16px" />
|
|
2705
|
-
<Skeleton width="90%" height="16px" />
|
|
2706
|
-
</div>
|
|
2707
|
-
|
|
2708
|
-
{/* Button skeleton */}
|
|
2709
|
-
<Skeleton width="120px" height="40px" />
|
|
2710
|
-
</div>
|
|
2711
|
-
);
|
|
2712
|
-
};
|
|
2713
|
-
```
|
|
2714
|
-
|
|
2715
|
-
### Avatar Skeleton
|
|
2716
|
-
|
|
2717
|
-
```jsx
|
|
2718
|
-
const AvatarSkeleton = () => {
|
|
2719
|
-
return (
|
|
2720
|
-
<div className="flex items-center gap-3">
|
|
2721
|
-
<Skeleton width="48px" height="48px" rounded />
|
|
2722
|
-
<div className="space-y-2 flex-1">
|
|
2723
|
-
<Skeleton width="150px" height="16px" />
|
|
2724
|
-
<Skeleton width="100px" height="14px" />
|
|
2725
|
-
</div>
|
|
2726
|
-
</div>
|
|
2727
|
-
);
|
|
2728
|
-
};
|
|
2729
|
-
```
|
|
2730
|
-
|
|
2731
|
-
### List Skeleton
|
|
2732
|
-
|
|
2733
|
-
```jsx
|
|
2734
|
-
const ListSkeleton = () => {
|
|
2735
|
-
return (
|
|
2736
|
-
<div className="space-y-4">
|
|
2737
|
-
{[...Array(5)].map((_, i) => (
|
|
2738
|
-
<div key={i} className="flex items-center gap-3">
|
|
2739
|
-
<Skeleton width="40px" height="40px" rounded />
|
|
2740
|
-
<div className="space-y-2 flex-1">
|
|
2741
|
-
<Skeleton width="60%" height="16px" />
|
|
2742
|
-
<Skeleton width="40%" height="14px" />
|
|
2743
|
-
</div>
|
|
2744
|
-
</div>
|
|
2745
|
-
))}
|
|
2746
|
-
</div>
|
|
2747
|
-
);
|
|
2748
|
-
};
|
|
2749
|
-
```
|
|
2750
|
-
|
|
2751
|
-
### Table Skeleton
|
|
2752
|
-
|
|
2753
|
-
```jsx
|
|
2754
|
-
const TableSkeleton = () => {
|
|
2755
|
-
return (
|
|
2756
|
-
<div className="space-y-3">
|
|
2757
|
-
{/* Header */}
|
|
2758
|
-
<div className="grid grid-cols-4 gap-4">
|
|
2759
|
-
<Skeleton width="100%" height="20px" />
|
|
2760
|
-
<Skeleton width="100%" height="20px" />
|
|
2761
|
-
<Skeleton width="100%" height="20px" />
|
|
2762
|
-
<Skeleton width="100%" height="20px" />
|
|
2763
|
-
</div>
|
|
2764
|
-
|
|
2765
|
-
{/* Rows */}
|
|
2766
|
-
{[...Array(5)].map((_, i) => (
|
|
2767
|
-
<div key={i} className="grid grid-cols-4 gap-4">
|
|
2768
|
-
<Skeleton width="100%" height="16px" />
|
|
2769
|
-
<Skeleton width="100%" height="16px" />
|
|
2770
|
-
<Skeleton width="100%" height="16px" />
|
|
2771
|
-
<Skeleton width="100%" height="16px" />
|
|
2772
|
-
</div>
|
|
2773
|
-
))}
|
|
2774
|
-
</div>
|
|
2775
|
-
);
|
|
2776
|
-
};
|
|
2777
|
-
```
|
|
2778
|
-
|
|
2779
|
-
### Complete Example
|
|
2780
|
-
|
|
2781
|
-
```jsx
|
|
2782
|
-
import { useState, useEffect } from "react";
|
|
2783
|
-
import { Skeleton } from "alope-ui";
|
|
2784
|
-
|
|
2785
|
-
type User = {
|
|
2786
|
-
id: number;
|
|
2787
|
-
name: string;
|
|
2788
|
-
email: string;
|
|
2789
|
-
avatar: string;
|
|
2790
|
-
};
|
|
2791
|
-
|
|
2792
|
-
const UserProfile = () => {
|
|
2793
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
2794
|
-
const [user, setUser] = useState<User | null>(null);
|
|
2795
|
-
|
|
2796
|
-
useEffect(() => {
|
|
2797
|
-
const fetchUser = async () => {
|
|
2798
|
-
setIsLoading(true);
|
|
2799
|
-
// Simulate API call
|
|
2800
|
-
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2801
|
-
setUser({
|
|
2802
|
-
id: 1,
|
|
2803
|
-
name: "John Doe",
|
|
2804
|
-
email: "john@example.com",
|
|
2805
|
-
avatar: "/avatar.jpg",
|
|
2806
|
-
});
|
|
2807
|
-
setIsLoading(false);
|
|
2808
|
-
};
|
|
2809
|
-
|
|
2810
|
-
fetchUser();
|
|
2811
|
-
}, []);
|
|
2812
|
-
|
|
2813
|
-
if (isLoading) {
|
|
2814
|
-
return (
|
|
2815
|
-
<div className="max-w-md border rounded-lg p-6 space-y-4">
|
|
2816
|
-
{/* Avatar and name skeleton */}
|
|
2817
|
-
<div className="flex items-center gap-4">
|
|
2818
|
-
<Skeleton width="64px" height="64px" rounded />
|
|
2819
|
-
<div className="space-y-2 flex-1">
|
|
2820
|
-
<Skeleton width="150px" height="20px" />
|
|
2821
|
-
<Skeleton width="200px" height="16px" />
|
|
2822
|
-
</div>
|
|
2823
|
-
</div>
|
|
2824
|
-
|
|
2825
|
-
{/* Bio skeleton */}
|
|
2826
|
-
<div className="space-y-2">
|
|
2827
|
-
<Skeleton width="100%" height="16px" />
|
|
2828
|
-
<Skeleton width="95%" height="16px" />
|
|
2829
|
-
<Skeleton width="90%" height="16px" />
|
|
2830
|
-
</div>
|
|
2831
|
-
|
|
2832
|
-
{/* Stats skeleton */}
|
|
2833
|
-
<div className="flex gap-4">
|
|
2834
|
-
<Skeleton width="80px" height="40px" />
|
|
2835
|
-
<Skeleton width="80px" height="40px" />
|
|
2836
|
-
<Skeleton width="80px" height="40px" />
|
|
2837
|
-
</div>
|
|
2838
|
-
|
|
2839
|
-
{/* Button skeleton */}
|
|
2840
|
-
<Skeleton width="100%" height="44px" />
|
|
2841
|
-
</div>
|
|
2842
|
-
);
|
|
2843
|
-
}
|
|
2844
|
-
|
|
2845
|
-
return (
|
|
2846
|
-
<div className="max-w-md border rounded-lg p-6">
|
|
2847
|
-
<div className="flex items-center gap-4 mb-4">
|
|
2848
|
-
<img
|
|
2849
|
-
src={user?.avatar}
|
|
2850
|
-
alt={user?.name}
|
|
2851
|
-
className="w-16 h-16 rounded-full"
|
|
2852
|
-
/>
|
|
2853
|
-
<div>
|
|
2854
|
-
<h2 className="text-xl font-bold">{user?.name}</h2>
|
|
2855
|
-
<p className="text-gray-600">{user?.email}</p>
|
|
2856
|
-
</div>
|
|
2857
|
-
</div>
|
|
2858
|
-
{/* Rest of the content */}
|
|
2859
|
-
</div>
|
|
2860
|
-
);
|
|
2861
|
-
};
|
|
2862
|
-
```
|
|
2863
|
-
|
|
2864
|
-
---
|
|
2865
|
-
|
|
2866
|
-
## Toggle
|
|
2867
|
-
|
|
2868
|
-
The Toggle component provides an animated switch control for toggling between on/off states with various visual styles and sizes.
|
|
2869
|
-
|
|
2870
|
-
### Import
|
|
2871
|
-
|
|
2872
|
-
```jsx
|
|
2873
|
-
import { Toggle } from "alope-ui";
|
|
2874
|
-
```
|
|
2875
|
-
|
|
2876
|
-
### Props
|
|
2877
|
-
|
|
2878
|
-
| Prop | Type | Default | Description |
|
|
2879
|
-
| ------------------- | -------------------------------------------------------------- | ----------- | ---------------------------------------- |
|
|
2880
|
-
| `variant` | `'primary' \| 'error' \| 'warning' \| 'success' \| 'info' \| 'secondary'` | `'primary'` | Color variant of the toggle |
|
|
2881
|
-
| `customSize` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the toggle switch |
|
|
2882
|
-
| `thumbShape` | `'stadium' \| 'rounded'` | `'stadium'` | Shape of the toggle thumb |
|
|
2883
|
-
| `label` | `string` | `undefined` | Label text displayed next to toggle |
|
|
2884
|
-
| `wrapperClassName` | `string` | `""` | CSS class for wrapper element |
|
|
2885
|
-
| `labelClassName` | `string` | `""` | CSS class for label text |
|
|
2886
|
-
| `...props` | `InputHTMLAttributes<HTMLInputElement>` | - | All standard HTML input attributes |
|
|
2887
|
-
|
|
2888
|
-
### Basic Toggle
|
|
2889
|
-
|
|
2890
|
-
```jsx
|
|
2891
|
-
import { useState } from "react";
|
|
2892
|
-
import { Toggle } from "alope-ui";
|
|
2893
|
-
|
|
2894
|
-
const BasicExample = () => {
|
|
2895
|
-
const [isChecked, setIsChecked] = useState(false);
|
|
2896
|
-
|
|
2897
|
-
return (
|
|
2898
|
-
<Toggle
|
|
2899
|
-
checked={isChecked}
|
|
2900
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2901
|
-
/>
|
|
2902
|
-
);
|
|
2903
|
-
};
|
|
2904
|
-
```
|
|
2905
|
-
|
|
2906
|
-
### With Label
|
|
2907
|
-
|
|
2908
|
-
```jsx
|
|
2909
|
-
<Toggle
|
|
2910
|
-
checked={isChecked}
|
|
2911
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2912
|
-
label="Enable notifications"
|
|
2913
|
-
/>
|
|
2914
|
-
```
|
|
2915
|
-
|
|
2916
|
-
### Variants
|
|
2917
|
-
|
|
2918
|
-
```jsx
|
|
2919
|
-
{/* Primary Variant */}
|
|
2920
|
-
<Toggle
|
|
2921
|
-
checked={isChecked}
|
|
2922
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2923
|
-
variant="primary"
|
|
2924
|
-
label="Primary"
|
|
2925
|
-
/>
|
|
2926
|
-
|
|
2927
|
-
{/* Error Variant */}
|
|
2928
|
-
<Toggle
|
|
2929
|
-
checked={isChecked}
|
|
2930
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2931
|
-
variant="error"
|
|
2932
|
-
label="Error"
|
|
2933
|
-
/>
|
|
2934
|
-
|
|
2935
|
-
{/* Warning Variant */}
|
|
2936
|
-
<Toggle
|
|
2937
|
-
checked={isChecked}
|
|
2938
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2939
|
-
variant="warning"
|
|
2940
|
-
label="Warning"
|
|
2941
|
-
/>
|
|
2942
|
-
|
|
2943
|
-
{/* Success Variant */}
|
|
2944
|
-
<Toggle
|
|
2945
|
-
checked={isChecked}
|
|
2946
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2947
|
-
variant="success"
|
|
2948
|
-
label="Success"
|
|
2949
|
-
/>
|
|
2950
|
-
|
|
2951
|
-
{/* Info Variant */}
|
|
2952
|
-
<Toggle
|
|
2953
|
-
checked={isChecked}
|
|
2954
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2955
|
-
variant="info"
|
|
2956
|
-
label="Info"
|
|
2957
|
-
/>
|
|
2958
|
-
|
|
2959
|
-
{/* Secondary Variant */}
|
|
2960
|
-
<Toggle
|
|
2961
|
-
checked={isChecked}
|
|
2962
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2963
|
-
variant="secondary"
|
|
2964
|
-
label="Secondary"
|
|
2965
|
-
/>
|
|
2966
|
-
```
|
|
2967
|
-
|
|
2968
|
-
### Sizes
|
|
2969
|
-
|
|
2970
|
-
```jsx
|
|
2971
|
-
{/* Small Size */}
|
|
2972
|
-
<Toggle
|
|
2973
|
-
checked={isChecked}
|
|
2974
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2975
|
-
customSize="sm"
|
|
2976
|
-
label="Small"
|
|
2977
|
-
/>
|
|
2978
|
-
|
|
2979
|
-
{/* Medium Size */}
|
|
2980
|
-
<Toggle
|
|
2981
|
-
checked={isChecked}
|
|
2982
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2983
|
-
customSize="md"
|
|
2984
|
-
label="Medium"
|
|
2985
|
-
/>
|
|
2986
|
-
|
|
2987
|
-
{/* Large Size */}
|
|
2988
|
-
<Toggle
|
|
2989
|
-
checked={isChecked}
|
|
2990
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
2991
|
-
customSize="lg"
|
|
2992
|
-
label="Large"
|
|
2993
|
-
/>
|
|
2994
|
-
```
|
|
2995
|
-
|
|
2996
|
-
### Thumb Shapes
|
|
2997
|
-
|
|
2998
|
-
```jsx
|
|
2999
|
-
{/* Stadium Shape (Fully Rounded) */}
|
|
3000
|
-
<Toggle
|
|
3001
|
-
checked={isChecked}
|
|
3002
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
3003
|
-
thumbShape="stadium"
|
|
3004
|
-
label="Stadium"
|
|
3005
|
-
/>
|
|
3006
|
-
|
|
3007
|
-
{/* Rounded Shape (Slightly Rounded) */}
|
|
3008
|
-
<Toggle
|
|
3009
|
-
checked={isChecked}
|
|
3010
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
3011
|
-
thumbShape="rounded"
|
|
3012
|
-
label="Rounded"
|
|
3013
|
-
/>
|
|
3014
|
-
```
|
|
3015
|
-
|
|
3016
|
-
### Disabled State
|
|
3017
|
-
|
|
3018
|
-
```jsx
|
|
3019
|
-
<Toggle
|
|
3020
|
-
checked={isChecked}
|
|
3021
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
3022
|
-
disabled
|
|
3023
|
-
label="Disabled toggle"
|
|
3024
|
-
/>
|
|
3025
|
-
```
|
|
3026
|
-
|
|
3027
|
-
### Custom Styling
|
|
3028
|
-
|
|
3029
|
-
```jsx
|
|
3030
|
-
<Toggle
|
|
3031
|
-
checked={isChecked}
|
|
3032
|
-
onChange={(e) => setIsChecked(e.target.checked)}
|
|
3033
|
-
label="Custom styled toggle"
|
|
3034
|
-
wrapperClassName="bg-gray-100 p-4 rounded-lg"
|
|
3035
|
-
labelClassName="text-lg font-bold text-blue-600"
|
|
3036
|
-
/>
|
|
3037
|
-
```
|
|
3038
|
-
|
|
3039
|
-
### Complete Example
|
|
3040
|
-
|
|
3041
|
-
```jsx
|
|
3042
|
-
import { useState } from "react";
|
|
3043
|
-
import { Toggle } from "alope-ui";
|
|
3044
|
-
|
|
3045
|
-
const CompleteExample = () => {
|
|
3046
|
-
const [settings, setSettings] = useState({
|
|
3047
|
-
notifications: false,
|
|
3048
|
-
darkMode: true,
|
|
3049
|
-
autoSave: false,
|
|
3050
|
-
});
|
|
3051
|
-
|
|
3052
|
-
const handleToggle = (key: string) => (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
3053
|
-
setSettings(prev => ({
|
|
3054
|
-
...prev,
|
|
3055
|
-
[key]: e.target.checked
|
|
3056
|
-
}));
|
|
3057
|
-
};
|
|
3058
|
-
|
|
3059
|
-
return (
|
|
3060
|
-
<div className="space-y-4">
|
|
3061
|
-
<Toggle
|
|
3062
|
-
checked={settings.notifications}
|
|
3063
|
-
onChange={handleToggle('notifications')}
|
|
3064
|
-
variant="primary"
|
|
3065
|
-
customSize="md"
|
|
3066
|
-
label="Enable notifications"
|
|
3067
|
-
/>
|
|
3068
|
-
|
|
3069
|
-
<Toggle
|
|
3070
|
-
checked={settings.darkMode}
|
|
3071
|
-
onChange={handleToggle('darkMode')}
|
|
3072
|
-
variant="secondary"
|
|
3073
|
-
customSize="md"
|
|
3074
|
-
label="Dark mode"
|
|
3075
|
-
/>
|
|
3076
|
-
|
|
3077
|
-
<Toggle
|
|
3078
|
-
checked={settings.autoSave}
|
|
3079
|
-
onChange={handleToggle('autoSave')}
|
|
3080
|
-
variant="success"
|
|
3081
|
-
customSize="md"
|
|
3082
|
-
label="Auto-save documents"
|
|
3083
|
-
/>
|
|
3084
|
-
</div>
|
|
3085
|
-
);
|
|
3086
|
-
};
|
|
3087
|
-
```
|
|
3088
|
-
|
|
3089
|
-
---
|
|
3090
|
-
|
|
3091
|
-
## FileUpload
|
|
3092
|
-
|
|
3093
|
-
The FileUpload component provides a flexible file upload interface with support for drag-and-drop, file validation, preview, and two display modes (dropzone and text input).
|
|
3094
|
-
|
|
3095
|
-
### Import
|
|
3096
|
-
|
|
3097
|
-
```jsx
|
|
3098
|
-
import { FileUpload } from "alope-ui";
|
|
3099
|
-
```
|
|
3100
|
-
|
|
3101
|
-
### Props
|
|
3102
|
-
|
|
3103
|
-
| Prop | Type | Default | Description |
|
|
3104
|
-
| ---------------- | ------------------------------ | ------------ | ------------------------------------------------ |
|
|
3105
|
-
| `onFilesChange` | `(files: File[]) => void` | `required` | Callback fired when files change |
|
|
3106
|
-
| `acceptedFiles` | `string` | `'image/*'` | Accepted file types (MIME types or extensions) |
|
|
3107
|
-
| `maxFiles` | `number` | `1` | Maximum number of files allowed |
|
|
3108
|
-
| `maxKiloByte` | `number` | `2048` | Maximum file size in kilobytes |
|
|
3109
|
-
| `mode` | `'dropzone' \| 'textinput'` | `'dropzone'` | Display mode of the file upload |
|
|
3110
|
-
| `clearable` | `boolean` | `true` | Show clear button on file previews |
|
|
3111
|
-
| `inputLabel` | `string` | `undefined` | Label for text input mode button |
|
|
3112
|
-
| `helperText` | `string` | `undefined` | Helper text displayed below the input |
|
|
3113
|
-
| `mediaCapture` | `'user' \| 'environment'` | `undefined` | Camera capture mode (for mobile devices) |
|
|
3114
|
-
|
|
3115
|
-
### Basic FileUpload (Dropzone Mode)
|
|
3116
|
-
|
|
3117
|
-
```jsx
|
|
3118
|
-
import { useState } from "react";
|
|
3119
|
-
import { FileUpload } from "alope-ui";
|
|
3120
|
-
|
|
3121
|
-
const BasicExample = () => {
|
|
3122
|
-
const [files, setFiles] = useState<File[]>([]);
|
|
3123
|
-
|
|
3124
|
-
return (
|
|
3125
|
-
<FileUpload
|
|
3126
|
-
onFilesChange={setFiles}
|
|
3127
|
-
/>
|
|
3128
|
-
);
|
|
3129
|
-
};
|
|
3130
|
-
```
|
|
3131
|
-
|
|
3132
|
-
### Text Input Mode
|
|
3133
|
-
|
|
3134
|
-
```jsx
|
|
3135
|
-
<FileUpload
|
|
3136
|
-
mode="textinput"
|
|
3137
|
-
onFilesChange={setFiles}
|
|
3138
|
-
inputLabel="Upload File"
|
|
3139
|
-
/>
|
|
3140
|
-
```
|
|
3141
|
-
|
|
3142
|
-
### Multiple Files
|
|
3143
|
-
|
|
3144
|
-
```jsx
|
|
3145
|
-
<FileUpload
|
|
3146
|
-
maxFiles={5}
|
|
3147
|
-
onFilesChange={setFiles}
|
|
3148
|
-
helperText="You can upload up to 5 files"
|
|
3149
|
-
/>
|
|
3150
|
-
```
|
|
3151
|
-
|
|
3152
|
-
### Custom File Types
|
|
3153
|
-
|
|
3154
|
-
```jsx
|
|
3155
|
-
{/* Accept only images */}
|
|
3156
|
-
<FileUpload
|
|
3157
|
-
acceptedFiles="image/*"
|
|
3158
|
-
onFilesChange={setFiles}
|
|
3159
|
-
/>
|
|
3160
|
-
|
|
3161
|
-
{/* Accept specific image types */}
|
|
3162
|
-
<FileUpload
|
|
3163
|
-
acceptedFiles="image/png, image/jpeg, image/jpg"
|
|
3164
|
-
onFilesChange={setFiles}
|
|
3165
|
-
/>
|
|
3166
|
-
|
|
3167
|
-
{/* Accept PDFs */}
|
|
3168
|
-
<FileUpload
|
|
3169
|
-
acceptedFiles="application/pdf"
|
|
3170
|
-
onFilesChange={setFiles}
|
|
3171
|
-
/>
|
|
3172
|
-
|
|
3173
|
-
{/* Accept by file extension */}
|
|
3174
|
-
<FileUpload
|
|
3175
|
-
acceptedFiles=".pdf, .doc, .docx"
|
|
3176
|
-
onFilesChange={setFiles}
|
|
3177
|
-
/>
|
|
3178
|
-
|
|
3179
|
-
{/* Accept multiple types */}
|
|
3180
|
-
<FileUpload
|
|
3181
|
-
acceptedFiles="image/*, .pdf, .doc"
|
|
3182
|
-
onFilesChange={setFiles}
|
|
3183
|
-
/>
|
|
3184
|
-
```
|
|
3185
|
-
|
|
3186
|
-
### File Size Limit
|
|
3187
|
-
|
|
3188
|
-
```jsx
|
|
3189
|
-
{/* 5MB limit */}
|
|
3190
|
-
<FileUpload
|
|
3191
|
-
maxKiloByte={5120}
|
|
3192
|
-
onFilesChange={setFiles}
|
|
3193
|
-
helperText="Maximum file size: 5MB"
|
|
3194
|
-
/>
|
|
3195
|
-
|
|
3196
|
-
{/* 500KB limit */}
|
|
3197
|
-
<FileUpload
|
|
3198
|
-
maxKiloByte={512}
|
|
3199
|
-
onFilesChange={setFiles}
|
|
3200
|
-
helperText="Maximum file size: 500KB"
|
|
3201
|
-
/>
|
|
3202
|
-
```
|
|
3203
|
-
|
|
3204
|
-
### With Helper Text
|
|
3205
|
-
|
|
3206
|
-
```jsx
|
|
3207
|
-
<FileUpload
|
|
3208
|
-
onFilesChange={setFiles}
|
|
3209
|
-
helperText="Accepted formats: PNG, JPG, JPEG. Max size: 2MB"
|
|
3210
|
-
/>
|
|
3211
|
-
```
|
|
3212
|
-
|
|
3213
|
-
### Camera Capture (Mobile)
|
|
3214
|
-
|
|
3215
|
-
```jsx
|
|
3216
|
-
{/* Use front camera */}
|
|
3217
|
-
<FileUpload
|
|
3218
|
-
acceptedFiles="image/*"
|
|
3219
|
-
mediaCapture="user"
|
|
3220
|
-
onFilesChange={setFiles}
|
|
3221
|
-
/>
|
|
3222
|
-
|
|
3223
|
-
{/* Use back camera */}
|
|
3224
|
-
<FileUpload
|
|
3225
|
-
acceptedFiles="image/*"
|
|
3226
|
-
mediaCapture="environment"
|
|
3227
|
-
onFilesChange={setFiles}
|
|
3228
|
-
/>
|
|
3229
|
-
```
|
|
3230
|
-
|
|
3231
|
-
### Non-clearable Files
|
|
3232
|
-
|
|
3233
|
-
```jsx
|
|
3234
|
-
<FileUpload
|
|
3235
|
-
onFilesChange={setFiles}
|
|
3236
|
-
clearable={false}
|
|
3237
|
-
/>
|
|
3238
|
-
```
|
|
3239
|
-
|
|
3240
|
-
### Complete Example with Dropzone Mode
|
|
3241
|
-
|
|
3242
|
-
```jsx
|
|
3243
|
-
import { useState } from "react";
|
|
3244
|
-
import { FileUpload } from "alope-ui";
|
|
3245
|
-
|
|
3246
|
-
const DropzoneExample = () => {
|
|
3247
|
-
const [uploadedFiles, setUploadedFiles] = useState<File[]>([]);
|
|
3248
|
-
|
|
3249
|
-
const handleFilesChange = (files: File[]) => {
|
|
3250
|
-
setUploadedFiles(files);
|
|
3251
|
-
console.log('Uploaded files:', files);
|
|
3252
|
-
};
|
|
3253
|
-
|
|
3254
|
-
return (
|
|
3255
|
-
<div className="max-w-2xl mx-auto p-6">
|
|
3256
|
-
<h2 className="text-xl font-bold mb-4">Upload Your Images</h2>
|
|
3257
|
-
|
|
3258
|
-
<FileUpload
|
|
3259
|
-
mode="dropzone"
|
|
3260
|
-
acceptedFiles="image/png, image/jpeg, image/jpg"
|
|
3261
|
-
maxFiles={3}
|
|
3262
|
-
maxKiloByte={5120}
|
|
3263
|
-
onFilesChange={handleFilesChange}
|
|
3264
|
-
helperText="Upload up to 3 images. Max 5MB per file."
|
|
3265
|
-
/>
|
|
3266
|
-
|
|
3267
|
-
{uploadedFiles.length > 0 && (
|
|
3268
|
-
<div className="mt-4">
|
|
3269
|
-
<p className="font-medium">Selected files:</p>
|
|
3270
|
-
<ul className="list-disc list-inside">
|
|
3271
|
-
{uploadedFiles.map((file, index) => (
|
|
3272
|
-
<li key={index}>{file.name}</li>
|
|
3273
|
-
))}
|
|
3274
|
-
</ul>
|
|
3275
|
-
</div>
|
|
3276
|
-
)}
|
|
3277
|
-
</div>
|
|
3278
|
-
);
|
|
3279
|
-
};
|
|
3280
|
-
```
|
|
3281
|
-
|
|
3282
|
-
### Complete Example with Text Input Mode
|
|
3283
|
-
|
|
3284
|
-
```jsx
|
|
3285
|
-
import { useState } from "react";
|
|
3286
|
-
import { FileUpload } from "alope-ui";
|
|
3287
|
-
|
|
3288
|
-
const TextInputExample = () => {
|
|
3289
|
-
const [documents, setDocuments] = useState<File[]>([]);
|
|
3290
|
-
|
|
3291
|
-
return (
|
|
3292
|
-
<div className="max-w-2xl mx-auto p-6">
|
|
3293
|
-
<h2 className="text-xl font-bold mb-4">Upload Documents</h2>
|
|
3294
|
-
|
|
3295
|
-
<FileUpload
|
|
3296
|
-
mode="textinput"
|
|
3297
|
-
acceptedFiles=".pdf, .doc, .docx"
|
|
3298
|
-
maxFiles={5}
|
|
3299
|
-
maxKiloByte={10240}
|
|
3300
|
-
inputLabel="Choose Documents"
|
|
3301
|
-
onFilesChange={setDocuments}
|
|
3302
|
-
helperText="Accepted: PDF, DOC, DOCX. Max 10MB per file."
|
|
3303
|
-
/>
|
|
3304
|
-
</div>
|
|
3305
|
-
);
|
|
3306
|
-
};
|
|
3307
|
-
```
|
|
3308
|
-
|
|
3309
|
-
---
|
|
3310
|
-
|
|
3311
|
-
## Textarea
|
|
3312
|
-
|
|
3313
|
-
The Textarea component provides a multi-line text input with optional auto-resize functionality, label, error messages, and dark mode support.
|
|
3314
|
-
|
|
3315
|
-
### Import
|
|
3316
|
-
|
|
3317
|
-
```jsx
|
|
3318
|
-
import { Textarea } from "alope-ui";
|
|
3319
|
-
import type { TextareaType } from "alope-ui";
|
|
3320
|
-
```
|
|
3321
|
-
|
|
3322
|
-
### Props
|
|
3323
|
-
|
|
3324
|
-
| Prop | Type | Default | Description |
|
|
3325
|
-
| ----------------- | --------------------------------------------- | ------- | ------------------------------------------------ |
|
|
3326
|
-
| `label` | `string` | `undefined` | Label text displayed above textarea |
|
|
3327
|
-
| `error` | `string` | `undefined` | Error message displayed below textarea |
|
|
3328
|
-
| `autoResize` | `boolean` | `false` | Enable auto-resize based on content |
|
|
3329
|
-
| `customClassName` | `string` | `""` | Custom CSS class for textarea element |
|
|
3330
|
-
| `...props` | `InputHTMLAttributes<HTMLTextAreaElement>` | - | All standard HTML textarea attributes |
|
|
3331
|
-
|
|
3332
|
-
### Basic Textarea
|
|
3333
|
-
|
|
3334
|
-
```jsx
|
|
3335
|
-
import { useState } from "react";
|
|
3336
|
-
import { Textarea } from "alope-ui";
|
|
3337
|
-
|
|
3338
|
-
const BasicExample = () => {
|
|
3339
|
-
const [value, setValue] = useState("");
|
|
3340
|
-
|
|
3341
|
-
return (
|
|
3342
|
-
<Textarea
|
|
3343
|
-
value={value}
|
|
3344
|
-
onChange={(e) => setValue(e.target.value)}
|
|
3345
|
-
placeholder="Enter your text here..."
|
|
3346
|
-
/>
|
|
3347
|
-
);
|
|
3348
|
-
};
|
|
3349
|
-
```
|
|
3350
|
-
|
|
3351
|
-
### With Label
|
|
3352
|
-
|
|
3353
|
-
```jsx
|
|
3354
|
-
<Textarea
|
|
3355
|
-
label="Description"
|
|
3356
|
-
name="description"
|
|
3357
|
-
value={value}
|
|
3358
|
-
onChange={(e) => setValue(e.target.value)}
|
|
3359
|
-
placeholder="Enter description..."
|
|
3360
|
-
/>
|
|
3361
|
-
```
|
|
3362
|
-
|
|
3363
|
-
### With Error Message
|
|
3364
|
-
|
|
3365
|
-
```jsx
|
|
3366
|
-
const [description, setDescription] = useState("");
|
|
3367
|
-
const [error, setError] = useState("");
|
|
3368
|
-
|
|
3369
|
-
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
3370
|
-
setDescription(e.target.value);
|
|
3371
|
-
if (e.target.value.length < 10) {
|
|
3372
|
-
setError("Description must be at least 10 characters");
|
|
3373
|
-
} else {
|
|
3374
|
-
setError("");
|
|
3375
|
-
}
|
|
3376
|
-
};
|
|
3377
|
-
|
|
3378
|
-
<Textarea
|
|
3379
|
-
label="Description"
|
|
3380
|
-
value={description}
|
|
3381
|
-
onChange={handleChange}
|
|
3382
|
-
error={error}
|
|
3383
|
-
placeholder="Enter at least 10 characters..."
|
|
3384
|
-
/>
|
|
3385
|
-
```
|
|
3386
|
-
|
|
3387
|
-
### Auto-Resize Textarea
|
|
3388
|
-
|
|
3389
|
-
```jsx
|
|
3390
|
-
<Textarea
|
|
3391
|
-
label="Auto-resizing textarea"
|
|
3392
|
-
autoResize
|
|
3393
|
-
value={value}
|
|
3394
|
-
onChange={(e) => setValue(e.target.value)}
|
|
3395
|
-
placeholder="This textarea grows as you type..."
|
|
3396
|
-
/>
|
|
3397
|
-
```
|
|
3398
|
-
|
|
3399
|
-
### Disabled State
|
|
3400
|
-
|
|
3401
|
-
```jsx
|
|
3402
|
-
<Textarea
|
|
3403
|
-
label="Disabled textarea"
|
|
3404
|
-
value="This textarea is disabled"
|
|
3405
|
-
disabled
|
|
3406
|
-
/>
|
|
3407
|
-
```
|
|
3408
|
-
|
|
3409
|
-
### Custom Styling
|
|
3410
|
-
|
|
3411
|
-
```jsx
|
|
3412
|
-
<Textarea
|
|
3413
|
-
label="Custom styled textarea"
|
|
3414
|
-
value={value}
|
|
3415
|
-
onChange={(e) => setValue(e.target.value)}
|
|
3416
|
-
customClassName="border-2 border-blue-500 focus:ring-blue-600 rounded-lg"
|
|
3417
|
-
placeholder="Custom styled..."
|
|
3418
|
-
/>
|
|
3419
|
-
```
|
|
3420
|
-
|
|
3421
|
-
### With Rows
|
|
3422
|
-
|
|
3423
|
-
```jsx
|
|
3424
|
-
<Textarea
|
|
3425
|
-
label="Fixed height textarea"
|
|
3426
|
-
rows={8}
|
|
3427
|
-
value={value}
|
|
3428
|
-
onChange={(e) => setValue(e.target.value)}
|
|
3429
|
-
placeholder="8 rows high..."
|
|
3430
|
-
/>
|
|
3431
|
-
```
|
|
3432
|
-
|
|
3433
|
-
### Complete Example
|
|
3434
|
-
|
|
3435
|
-
```jsx
|
|
3436
|
-
import { useState } from "react";
|
|
3437
|
-
import { Textarea } from "alope-ui";
|
|
3438
|
-
|
|
3439
|
-
const CompleteExample = () => {
|
|
3440
|
-
const [feedback, setFeedback] = useState("");
|
|
3441
|
-
const [error, setError] = useState("");
|
|
3442
|
-
|
|
3443
|
-
const handleSubmit = (e: React.FormEvent) => {
|
|
3444
|
-
e.preventDefault();
|
|
3445
|
-
|
|
3446
|
-
if (feedback.length < 20) {
|
|
3447
|
-
setError("Feedback must be at least 20 characters");
|
|
3448
|
-
return;
|
|
3449
|
-
}
|
|
3450
|
-
|
|
3451
|
-
console.log("Feedback submitted:", feedback);
|
|
3452
|
-
setFeedback("");
|
|
3453
|
-
setError("");
|
|
3454
|
-
};
|
|
3455
|
-
|
|
3456
|
-
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
3457
|
-
setFeedback(e.target.value);
|
|
3458
|
-
if (error && e.target.value.length >= 20) {
|
|
3459
|
-
setError("");
|
|
3460
|
-
}
|
|
3461
|
-
};
|
|
3462
|
-
|
|
3463
|
-
return (
|
|
3464
|
-
<form onSubmit={handleSubmit} className="max-w-lg mx-auto p-6">
|
|
3465
|
-
<h2 className="text-xl font-bold mb-4">Share Your Feedback</h2>
|
|
3466
|
-
|
|
3467
|
-
<Textarea
|
|
3468
|
-
label="Feedback"
|
|
3469
|
-
name="feedback"
|
|
3470
|
-
value={feedback}
|
|
3471
|
-
onChange={handleChange}
|
|
3472
|
-
error={error}
|
|
3473
|
-
autoResize
|
|
3474
|
-
placeholder="Tell us what you think... (minimum 20 characters)"
|
|
3475
|
-
customClassName="mb-4"
|
|
3476
|
-
/>
|
|
3477
|
-
|
|
3478
|
-
<p className="text-sm text-gray-500 mb-4">
|
|
3479
|
-
Character count: {feedback.length}
|
|
3480
|
-
</p>
|
|
3481
|
-
|
|
3482
|
-
<button
|
|
3483
|
-
type="submit"
|
|
3484
|
-
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
|
|
3485
|
-
>
|
|
3486
|
-
Submit Feedback
|
|
3487
|
-
</button>
|
|
3488
|
-
</form>
|
|
3489
|
-
);
|
|
3490
|
-
};
|
|
3491
|
-
```
|
|
3492
|
-
|
|
3493
|
-
### Form Integration Example
|
|
3494
|
-
|
|
3495
|
-
```jsx
|
|
3496
|
-
import { useState } from "react";
|
|
3497
|
-
import { Textarea } from "alope-ui";
|
|
3498
|
-
|
|
3499
|
-
const FormExample = () => {
|
|
3500
|
-
const [formData, setFormData] = useState({
|
|
3501
|
-
name: "",
|
|
3502
|
-
message: "",
|
|
3503
|
-
comments: ""
|
|
3504
|
-
});
|
|
3505
|
-
|
|
3506
|
-
const handleChange = (field: string) => (
|
|
3507
|
-
e: React.ChangeEvent<HTMLTextAreaElement>
|
|
3508
|
-
) => {
|
|
3509
|
-
setFormData(prev => ({
|
|
3510
|
-
...prev,
|
|
3511
|
-
[field]: e.target.value
|
|
3512
|
-
}));
|
|
3513
|
-
};
|
|
3514
|
-
|
|
3515
|
-
return (
|
|
3516
|
-
<div className="space-y-4 max-w-lg mx-auto p-6">
|
|
3517
|
-
<Textarea
|
|
3518
|
-
label="Message"
|
|
3519
|
-
name="message"
|
|
3520
|
-
value={formData.message}
|
|
3521
|
-
onChange={handleChange('message')}
|
|
3522
|
-
placeholder="Your message..."
|
|
3523
|
-
rows={4}
|
|
3524
|
-
/>
|
|
3525
|
-
|
|
3526
|
-
<Textarea
|
|
3527
|
-
label="Additional Comments"
|
|
3528
|
-
name="comments"
|
|
3529
|
-
value={formData.comments}
|
|
3530
|
-
onChange={handleChange('comments')}
|
|
3531
|
-
placeholder="Any additional comments..."
|
|
3532
|
-
autoResize
|
|
3533
|
-
/>
|
|
3534
|
-
</div>
|
|
3535
|
-
);
|
|
3536
|
-
};
|
|
3537
|
-
```
|
|
3538
|
-
|
|
3539
|
-
---
|
|
3540
|
-
|
|
3541
|
-
## Tabs
|
|
3542
|
-
|
|
3543
|
-
The Tabs component provides a tabbed navigation interface for organizing and displaying content in separate panels.
|
|
3544
|
-
|
|
3545
|
-
### Import
|
|
3546
|
-
|
|
3547
|
-
```jsx
|
|
3548
|
-
import { Tabs } from "alope-ui";
|
|
3549
|
-
import type { Tabs as TabType } from "alope-ui";
|
|
3550
|
-
```
|
|
3551
|
-
|
|
3552
|
-
### Props
|
|
3553
|
-
|
|
3554
|
-
| Prop | Type | Default | Description |
|
|
3555
|
-
| -------------------- | --------------------------------------------------- | -------- | ---------------------------------------- |
|
|
3556
|
-
| `tabs` | `TabType[]` | `required` | Array of tab objects |
|
|
3557
|
-
| `variant` | `'line' \| 'solid' \| 'subtle' \| 'inline' \| 'outline' \| 'plain'` | `'line'` | Visual variant style |
|
|
3558
|
-
| `fitted` | `boolean` | `false` | Make tabs fill available width |
|
|
3559
|
-
| `wrapperClassName` | `string` | `""` | Wrapper container CSS class |
|
|
3560
|
-
| `buttonClassName` | `string` | `""` | Tab button CSS class |
|
|
3561
|
-
| `activeClassName` | `string` | `""` | Active tab CSS class |
|
|
3562
|
-
| `inactiveClassName` | `string` | `""` | Inactive tab CSS class |
|
|
3563
|
-
| `activeTab` | `number` | `undefined` | Controlled active tab index |
|
|
3564
|
-
| `onTabChange` | `(index: number) => void` | `undefined` | Callback when tab changes |
|
|
3565
|
-
|
|
3566
|
-
### Tab Object Type
|
|
3567
|
-
|
|
3568
|
-
```typescript
|
|
3569
|
-
type Tabs = {
|
|
3570
|
-
label: string;
|
|
3571
|
-
content: React.ReactNode;
|
|
3572
|
-
disabled?: boolean;
|
|
3573
|
-
link?: string;
|
|
3574
|
-
}
|
|
3575
|
-
```
|
|
3576
|
-
|
|
3577
|
-
### Basic Tabs
|
|
3578
|
-
|
|
3579
|
-
```jsx
|
|
3580
|
-
import { Tabs } from "alope-ui";
|
|
3581
|
-
|
|
3582
|
-
const BasicExample = () => {
|
|
3583
|
-
const tabs = [
|
|
3584
|
-
{
|
|
3585
|
-
label: "Profile",
|
|
3586
|
-
content: <div>Profile content here</div>,
|
|
3587
|
-
},
|
|
3588
|
-
{
|
|
3589
|
-
label: "Settings",
|
|
3590
|
-
content: <div>Settings content here</div>,
|
|
3591
|
-
},
|
|
3592
|
-
{
|
|
3593
|
-
label: "Notifications",
|
|
3594
|
-
content: <div>Notifications content here</div>,
|
|
3595
|
-
},
|
|
3596
|
-
];
|
|
3597
|
-
|
|
3598
|
-
return <Tabs tabs={tabs} />;
|
|
3599
|
-
};
|
|
3600
|
-
```
|
|
3601
|
-
|
|
3602
|
-
### Variants
|
|
3603
|
-
|
|
3604
|
-
```jsx
|
|
3605
|
-
{/* Line Variant */}
|
|
3606
|
-
<Tabs tabs={tabs} variant="line" />
|
|
3607
|
-
|
|
3608
|
-
{/* Solid Variant */}
|
|
3609
|
-
<Tabs tabs={tabs} variant="solid" />
|
|
3610
|
-
|
|
3611
|
-
{/* Subtle Variant */}
|
|
3612
|
-
<Tabs tabs={tabs} variant="subtle" />
|
|
3613
|
-
|
|
3614
|
-
{/* Inline Variant */}
|
|
3615
|
-
<Tabs tabs={tabs} variant="inline" />
|
|
3616
|
-
|
|
3617
|
-
{/* Outline Variant */}
|
|
3618
|
-
<Tabs tabs={tabs} variant="outline" />
|
|
3619
|
-
|
|
3620
|
-
{/* Plain Variant */}
|
|
3621
|
-
<Tabs tabs={tabs} variant="plain" />
|
|
3622
|
-
```
|
|
3623
|
-
|
|
3624
|
-
### Fitted Tabs
|
|
3625
|
-
|
|
3626
|
-
```jsx
|
|
3627
|
-
{/* Tabs will fill the available width equally */}
|
|
3628
|
-
<Tabs tabs={tabs} fitted />
|
|
3629
|
-
```
|
|
3630
|
-
|
|
3631
|
-
### Controlled Tabs
|
|
3632
|
-
|
|
3633
|
-
```jsx
|
|
3634
|
-
import { useState } from "react";
|
|
3635
|
-
import { Tabs } from "alope-ui";
|
|
3636
|
-
|
|
3637
|
-
const ControlledExample = () => {
|
|
3638
|
-
const [activeTab, setActiveTab] = useState(0);
|
|
3639
|
-
|
|
3640
|
-
const tabs = [
|
|
3641
|
-
{
|
|
3642
|
-
label: "Tab 1",
|
|
3643
|
-
content: <div>Content 1</div>,
|
|
3644
|
-
},
|
|
3645
|
-
{
|
|
3646
|
-
label: "Tab 2",
|
|
3647
|
-
content: <div>Content 2</div>,
|
|
3648
|
-
},
|
|
3649
|
-
];
|
|
3650
|
-
|
|
3651
|
-
return (
|
|
3652
|
-
<Tabs
|
|
3653
|
-
tabs={tabs}
|
|
3654
|
-
activeTab={activeTab}
|
|
3655
|
-
onTabChange={setActiveTab}
|
|
3656
|
-
/>
|
|
3657
|
-
);
|
|
3658
|
-
};
|
|
3659
|
-
```
|
|
3660
|
-
|
|
3661
|
-
### Disabled Tabs
|
|
3662
|
-
|
|
3663
|
-
```jsx
|
|
3664
|
-
const tabs = [
|
|
3665
|
-
{
|
|
3666
|
-
label: "Active Tab",
|
|
3667
|
-
content: <div>Active content</div>,
|
|
3668
|
-
},
|
|
3669
|
-
{
|
|
3670
|
-
label: "Disabled Tab",
|
|
3671
|
-
content: <div>This content won't show</div>,
|
|
3672
|
-
disabled: true,
|
|
3673
|
-
},
|
|
3674
|
-
];
|
|
3675
|
-
|
|
3676
|
-
<Tabs tabs={tabs} />
|
|
3677
|
-
```
|
|
3678
|
-
|
|
3679
|
-
### Tabs with Links
|
|
3680
|
-
|
|
3681
|
-
```jsx
|
|
3682
|
-
const tabs = [
|
|
3683
|
-
{
|
|
3684
|
-
label: "Dashboard",
|
|
3685
|
-
content: <div>Dashboard content</div>,
|
|
3686
|
-
link: "/dashboard",
|
|
3687
|
-
},
|
|
3688
|
-
{
|
|
3689
|
-
label: "Profile",
|
|
3690
|
-
content: <div>Profile content</div>,
|
|
3691
|
-
link: "/profile",
|
|
3692
|
-
},
|
|
3693
|
-
];
|
|
3694
|
-
|
|
3695
|
-
<Tabs tabs={tabs} />
|
|
3696
|
-
```
|
|
3697
|
-
|
|
3698
|
-
### Custom Styling
|
|
3699
|
-
|
|
3700
|
-
```jsx
|
|
3701
|
-
<Tabs
|
|
3702
|
-
tabs={tabs}
|
|
3703
|
-
variant="solid"
|
|
3704
|
-
wrapperClassName="bg-gray-100 dark:bg-gray-800"
|
|
3705
|
-
buttonClassName="text-base"
|
|
3706
|
-
activeClassName="font-bold"
|
|
3707
|
-
inactiveClassName="opacity-70"
|
|
3708
|
-
/>
|
|
3709
|
-
```
|
|
3710
|
-
|
|
3711
|
-
### Complete Example
|
|
3712
|
-
|
|
3713
|
-
```jsx
|
|
3714
|
-
import { useState } from "react";
|
|
3715
|
-
import { Tabs } from "alope-ui";
|
|
3716
|
-
|
|
3717
|
-
const CompleteExample = () => {
|
|
3718
|
-
const [activeTab, setActiveTab] = useState(0);
|
|
3719
|
-
|
|
3720
|
-
const tabs = [
|
|
3721
|
-
{
|
|
3722
|
-
label: "Overview",
|
|
3723
|
-
content: (
|
|
3724
|
-
<div className="p-4">
|
|
3725
|
-
<h2 className="text-xl font-bold mb-2">Overview</h2>
|
|
3726
|
-
<p>Dashboard overview content goes here.</p>
|
|
3727
|
-
</div>
|
|
3728
|
-
),
|
|
3729
|
-
},
|
|
3730
|
-
{
|
|
3731
|
-
label: "Analytics",
|
|
3732
|
-
content: (
|
|
3733
|
-
<div className="p-4">
|
|
3734
|
-
<h2 className="text-xl font-bold mb-2">Analytics</h2>
|
|
3735
|
-
<p>Analytics and statistics content.</p>
|
|
3736
|
-
</div>
|
|
3737
|
-
),
|
|
3738
|
-
},
|
|
3739
|
-
{
|
|
3740
|
-
label: "Reports",
|
|
3741
|
-
content: (
|
|
3742
|
-
<div className="p-4">
|
|
3743
|
-
<h2 className="text-xl font-bold mb-2">Reports</h2>
|
|
3744
|
-
<p>Reports and data visualization.</p>
|
|
3745
|
-
</div>
|
|
3746
|
-
),
|
|
3747
|
-
},
|
|
3748
|
-
{
|
|
3749
|
-
label: "Settings",
|
|
3750
|
-
content: (
|
|
3751
|
-
<div className="p-4">
|
|
3752
|
-
<h2 className="text-xl font-bold mb-2">Settings</h2>
|
|
3753
|
-
<p>Configuration and preferences.</p>
|
|
3754
|
-
</div>
|
|
3755
|
-
),
|
|
3756
|
-
disabled: true,
|
|
3757
|
-
},
|
|
3758
|
-
];
|
|
3759
|
-
|
|
3760
|
-
return (
|
|
3761
|
-
<Tabs
|
|
3762
|
-
tabs={tabs}
|
|
3763
|
-
variant="subtle"
|
|
3764
|
-
fitted
|
|
3765
|
-
activeTab={activeTab}
|
|
3766
|
-
onTabChange={setActiveTab}
|
|
3767
|
-
/>
|
|
3768
|
-
);
|
|
3769
|
-
};
|
|
3770
|
-
```
|
|
3771
|
-
|
|
3772
|
-
---
|
|
3773
|
-
|
|
3774
|
-
## Avatar
|
|
3775
|
-
|
|
3776
|
-
The Avatar component displays user profile images with fallback initials, status indicators, and various styling options.
|
|
3777
|
-
|
|
3778
|
-
### Import
|
|
3779
|
-
|
|
3780
|
-
```jsx
|
|
3781
|
-
import { Avatar } from "alope-ui";
|
|
3782
|
-
```
|
|
3783
|
-
|
|
3784
|
-
### Props
|
|
3785
|
-
|
|
3786
|
-
| Prop | Type | Default | Description |
|
|
3787
|
-
| ----------------- | --------------------------------------------------------- | ----------- | ------------------------------------- |
|
|
3788
|
-
| `imageSrc` | `string` | `undefined` | URL of the avatar image |
|
|
3789
|
-
| `fallbackName` | `string` | `undefined` | Name to generate initials from |
|
|
3790
|
-
| `fallbackColor` | `'primary' \| 'error' \| 'warning' \| 'success' \| 'info' \| 'secondary'` | `'primary'` | Background color for fallback |
|
|
3791
|
-
| `shape` | `'sharp' \| 'cornered' \| 'rounded'` | `'rounded'` | Shape of the avatar |
|
|
3792
|
-
| `variant` | `'solid' \| 'outline'` | `'solid'` | Visual variant style |
|
|
3793
|
-
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the avatar |
|
|
3794
|
-
| `ring` | `boolean` | `false` | Show ring around avatar |
|
|
3795
|
-
| `ringClassName` | `string` | `""` | Custom ring CSS class |
|
|
3796
|
-
| `alt` | `string` | `'avatar'` | Alt text for image |
|
|
3797
|
-
| `status` | `'online' \| 'offline'` | `undefined` | Status indicator |
|
|
3798
|
-
| `className` | `string` | `""` | Additional CSS class |
|
|
3799
|
-
|
|
3800
|
-
### Basic Avatar
|
|
3801
|
-
|
|
3802
|
-
```jsx
|
|
3803
|
-
import { Avatar } from "alope-ui";
|
|
3804
|
-
|
|
3805
|
-
const BasicExample = () => {
|
|
3806
|
-
return (
|
|
3807
|
-
<Avatar
|
|
3808
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3809
|
-
alt="User Avatar"
|
|
3810
|
-
/>
|
|
3811
|
-
);
|
|
3812
|
-
};
|
|
3813
|
-
```
|
|
3814
|
-
|
|
3815
|
-
### Fallback with Initials
|
|
3816
|
-
|
|
3817
|
-
```jsx
|
|
3818
|
-
{/* Avatar with fallback name */}
|
|
3819
|
-
<Avatar fallbackName="John Doe" />
|
|
3820
|
-
|
|
3821
|
-
{/* Avatar with no image (shows initials) */}
|
|
3822
|
-
<Avatar
|
|
3823
|
-
imageSrc="invalid-url.jpg"
|
|
3824
|
-
fallbackName="Jane Smith"
|
|
3825
|
-
/>
|
|
3826
|
-
```
|
|
3827
|
-
|
|
3828
|
-
### Sizes
|
|
3829
|
-
|
|
3830
|
-
```jsx
|
|
3831
|
-
{/* Small */}
|
|
3832
|
-
<Avatar
|
|
3833
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3834
|
-
size="sm"
|
|
3835
|
-
/>
|
|
3836
|
-
|
|
3837
|
-
{/* Medium */}
|
|
3838
|
-
<Avatar
|
|
3839
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3840
|
-
size="md"
|
|
3841
|
-
/>
|
|
3842
|
-
|
|
3843
|
-
{/* Large */}
|
|
3844
|
-
<Avatar
|
|
3845
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3846
|
-
size="lg"
|
|
3847
|
-
/>
|
|
3848
|
-
```
|
|
3849
|
-
|
|
3850
|
-
### Shapes
|
|
3851
|
-
|
|
3852
|
-
```jsx
|
|
3853
|
-
{/* Sharp corners */}
|
|
3854
|
-
<Avatar
|
|
3855
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3856
|
-
shape="sharp"
|
|
3857
|
-
/>
|
|
3858
|
-
|
|
3859
|
-
{/* Cornered (slightly rounded) */}
|
|
3860
|
-
<Avatar
|
|
3861
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3862
|
-
shape="cornered"
|
|
3863
|
-
/>
|
|
3864
|
-
|
|
3865
|
-
{/* Rounded (circular) */}
|
|
3866
|
-
<Avatar
|
|
3867
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3868
|
-
shape="rounded"
|
|
3869
|
-
/>
|
|
3870
|
-
```
|
|
3871
|
-
|
|
3872
|
-
### Variants
|
|
3873
|
-
|
|
3874
|
-
```jsx
|
|
3875
|
-
{/* Solid variant */}
|
|
3876
|
-
<Avatar
|
|
3877
|
-
fallbackName="John Doe"
|
|
3878
|
-
variant="solid"
|
|
3879
|
-
/>
|
|
3880
|
-
|
|
3881
|
-
{/* Outline variant */}
|
|
3882
|
-
<Avatar
|
|
3883
|
-
fallbackName="John Doe"
|
|
3884
|
-
variant="outline"
|
|
3885
|
-
/>
|
|
3886
|
-
```
|
|
3887
|
-
|
|
3888
|
-
### Fallback Colors
|
|
3889
|
-
|
|
3890
|
-
```jsx
|
|
3891
|
-
{/* Primary color */}
|
|
3892
|
-
<Avatar fallbackName="John Doe" fallbackColor="primary" />
|
|
3893
|
-
|
|
3894
|
-
{/* Error color */}
|
|
3895
|
-
<Avatar fallbackName="John Doe" fallbackColor="error" />
|
|
3896
|
-
|
|
3897
|
-
{/* Warning color */}
|
|
3898
|
-
<Avatar fallbackName="John Doe" fallbackColor="warning" />
|
|
3899
|
-
|
|
3900
|
-
{/* Success color */}
|
|
3901
|
-
<Avatar fallbackName="John Doe" fallbackColor="success" />
|
|
3902
|
-
|
|
3903
|
-
{/* Info color */}
|
|
3904
|
-
<Avatar fallbackName="John Doe" fallbackColor="info" />
|
|
3905
|
-
|
|
3906
|
-
{/* Secondary color */}
|
|
3907
|
-
<Avatar fallbackName="John Doe" fallbackColor="secondary" />
|
|
3908
|
-
```
|
|
3909
|
-
|
|
3910
|
-
### With Ring
|
|
3911
|
-
|
|
3912
|
-
```jsx
|
|
3913
|
-
{/* Default ring */}
|
|
3914
|
-
<Avatar
|
|
3915
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3916
|
-
ring
|
|
3917
|
-
/>
|
|
3918
|
-
|
|
3919
|
-
{/* Custom ring color */}
|
|
3920
|
-
<Avatar
|
|
3921
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3922
|
-
ring
|
|
3923
|
-
ringClassName="ring-success dark:ring-success-dark"
|
|
3924
|
-
/>
|
|
3925
|
-
```
|
|
3926
|
-
|
|
3927
|
-
### Status Indicator
|
|
3928
|
-
|
|
3929
|
-
```jsx
|
|
3930
|
-
{/* Online status */}
|
|
3931
|
-
<Avatar
|
|
3932
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3933
|
-
status="online"
|
|
3934
|
-
/>
|
|
3935
|
-
|
|
3936
|
-
{/* Offline status */}
|
|
3937
|
-
<Avatar
|
|
3938
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3939
|
-
status="offline"
|
|
3940
|
-
/>
|
|
3941
|
-
```
|
|
3942
|
-
|
|
3943
|
-
### Complete Example
|
|
3944
|
-
|
|
3945
|
-
```jsx
|
|
3946
|
-
import { Avatar } from "alope-ui";
|
|
3947
|
-
|
|
3948
|
-
const CompleteExample = () => {
|
|
3949
|
-
return (
|
|
3950
|
-
<div className="flex gap-4">
|
|
3951
|
-
<Avatar
|
|
3952
|
-
imageSrc="https://i.pravatar.cc/150?img=1"
|
|
3953
|
-
fallbackName="John Doe"
|
|
3954
|
-
size="lg"
|
|
3955
|
-
shape="rounded"
|
|
3956
|
-
ring
|
|
3957
|
-
status="online"
|
|
3958
|
-
alt="John Doe Avatar"
|
|
3959
|
-
/>
|
|
3960
|
-
|
|
3961
|
-
<Avatar
|
|
3962
|
-
imageSrc="https://i.pravatar.cc/150?img=2"
|
|
3963
|
-
fallbackName="Jane Smith"
|
|
3964
|
-
size="lg"
|
|
3965
|
-
shape="rounded"
|
|
3966
|
-
ring
|
|
3967
|
-
status="offline"
|
|
3968
|
-
alt="Jane Smith Avatar"
|
|
3969
|
-
/>
|
|
3970
|
-
</div>
|
|
3971
|
-
);
|
|
3972
|
-
};
|
|
3973
|
-
```
|
|
3974
|
-
|
|
3975
|
-
## AvatarGroup
|
|
3976
|
-
|
|
3977
|
-
The AvatarGroup component displays multiple avatars in an overlapping stack with a counter for additional avatars.
|
|
3978
|
-
|
|
3979
|
-
### Import
|
|
3980
|
-
|
|
3981
|
-
```jsx
|
|
3982
|
-
import { AvatarGroup } from "alope-ui";
|
|
3983
|
-
import type { AvatarGroupProps } from "alope-ui";
|
|
3984
|
-
```
|
|
3985
|
-
|
|
3986
|
-
### Props
|
|
3987
|
-
|
|
3988
|
-
| Prop | Type | Default | Description |
|
|
3989
|
-
| ------------- | ----------------- | -------- | ---------------------------------------- |
|
|
3990
|
-
| `avatars` | `AvatarProps[]` | `required` | Array of avatar configurations |
|
|
3991
|
-
| `maxVisible` | `number` | `3` | Maximum number of visible avatars |
|
|
3992
|
-
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of all avatars in the group |
|
|
3993
|
-
| `overlap` | `string` | `'-ml-3'` | CSS class for overlap spacing |
|
|
3994
|
-
| `className` | `string` | `""` | Additional CSS class |
|
|
3995
|
-
|
|
3996
|
-
### Basic AvatarGroup
|
|
3997
|
-
|
|
3998
|
-
```jsx
|
|
3999
|
-
import { AvatarGroup } from "alope-ui";
|
|
4000
|
-
|
|
4001
|
-
const BasicGroupExample = () => {
|
|
4002
|
-
const avatars = [
|
|
4003
|
-
{ imageSrc: "https://i.pravatar.cc/150?img=1", fallbackName: "John Doe" },
|
|
4004
|
-
{ imageSrc: "https://i.pravatar.cc/150?img=2", fallbackName: "Jane Smith" },
|
|
4005
|
-
{ imageSrc: "https://i.pravatar.cc/150?img=3", fallbackName: "Bob Wilson" },
|
|
4006
|
-
];
|
|
4007
|
-
|
|
4008
|
-
return <AvatarGroup avatars={avatars} />;
|
|
4009
|
-
};
|
|
4010
|
-
```
|
|
4011
|
-
|
|
4012
|
-
### With Max Visible Limit
|
|
4013
|
-
|
|
4014
|
-
```jsx
|
|
4015
|
-
const avatars = [
|
|
4016
|
-
{ imageSrc: "https://i.pravatar.cc/150?img=1", fallbackName: "User 1" },
|
|
4017
|
-
{ imageSrc: "https://i.pravatar.cc/150?img=2", fallbackName: "User 2" },
|
|
4018
|
-
{ imageSrc: "https://i.pravatar.cc/150?img=3", fallbackName: "User 3" },
|
|
4019
|
-
{ imageSrc: "https://i.pravatar.cc/150?img=4", fallbackName: "User 4" },
|
|
4020
|
-
{ imageSrc: "https://i.pravatar.cc/150?img=5", fallbackName: "User 5" },
|
|
4021
|
-
];
|
|
4022
|
-
|
|
4023
|
-
{/* Show only 3 avatars, rest shown as "+2" */}
|
|
4024
|
-
<AvatarGroup avatars={avatars} maxVisible={3} />
|
|
4025
|
-
```
|
|
4026
|
-
|
|
4027
|
-
### Different Sizes
|
|
4028
|
-
|
|
4029
|
-
```jsx
|
|
4030
|
-
{/* Small size */}
|
|
4031
|
-
<AvatarGroup avatars={avatars} size="sm" />
|
|
4032
|
-
|
|
4033
|
-
{/* Medium size */}
|
|
4034
|
-
<AvatarGroup avatars={avatars} size="md" />
|
|
4035
|
-
|
|
4036
|
-
{/* Large size */}
|
|
4037
|
-
<AvatarGroup avatars={avatars} size="lg" />
|
|
4038
|
-
```
|
|
4039
|
-
|
|
4040
|
-
### Custom Overlap
|
|
4041
|
-
|
|
4042
|
-
```jsx
|
|
4043
|
-
{/* More overlap */}
|
|
4044
|
-
<AvatarGroup avatars={avatars} overlap="-ml-4" />
|
|
4045
|
-
|
|
4046
|
-
{/* Less overlap */}
|
|
4047
|
-
<AvatarGroup avatars={avatars} overlap="-ml-2" />
|
|
4048
|
-
|
|
4049
|
-
{/* No overlap */}
|
|
4050
|
-
<AvatarGroup avatars={avatars} overlap="" />
|
|
4051
|
-
```
|
|
4052
|
-
|
|
4053
|
-
### Complete AvatarGroup Example
|
|
4054
|
-
|
|
4055
|
-
```jsx
|
|
4056
|
-
import { AvatarGroup } from "alope-ui";
|
|
4057
|
-
|
|
4058
|
-
const CompleteGroupExample = () => {
|
|
4059
|
-
const teamMembers = [
|
|
4060
|
-
{
|
|
4061
|
-
imageSrc: "https://i.pravatar.cc/150?img=1",
|
|
4062
|
-
fallbackName: "John Doe",
|
|
4063
|
-
status: "online"
|
|
4064
|
-
},
|
|
4065
|
-
{
|
|
4066
|
-
imageSrc: "https://i.pravatar.cc/150?img=2",
|
|
4067
|
-
fallbackName: "Jane Smith",
|
|
4068
|
-
status: "online"
|
|
4069
|
-
},
|
|
4070
|
-
{
|
|
4071
|
-
imageSrc: "https://i.pravatar.cc/150?img=3",
|
|
4072
|
-
fallbackName: "Bob Wilson",
|
|
4073
|
-
status: "offline"
|
|
4074
|
-
},
|
|
4075
|
-
{
|
|
4076
|
-
fallbackName: "Alice Brown",
|
|
4077
|
-
fallbackColor: "success"
|
|
4078
|
-
},
|
|
4079
|
-
{
|
|
4080
|
-
fallbackName: "Charlie Davis",
|
|
4081
|
-
fallbackColor: "info"
|
|
4082
|
-
},
|
|
4083
|
-
];
|
|
4084
|
-
|
|
4085
|
-
return (
|
|
4086
|
-
<AvatarGroup
|
|
4087
|
-
avatars={teamMembers}
|
|
4088
|
-
maxVisible={3}
|
|
4089
|
-
size="md"
|
|
4090
|
-
overlap="-ml-3"
|
|
4091
|
-
/>
|
|
4092
|
-
);
|
|
4093
|
-
};
|
|
4094
|
-
```
|
|
4095
|
-
|
|
4096
|
-
---
|
|
4097
|
-
|
|
4098
1706
|
## 💡 Contributing
|
|
4099
1707
|
|
|
4100
1708
|
We welcome contributions! If you want to add features, fix bugs, or improve documentation, feel free to fork this project and submit a pull request.
|
|
@@ -4109,4 +1717,4 @@ MIT License – Free to use, modify, and distribute.
|
|
|
4109
1717
|
|
|
4110
1718
|
## 🙌 Thank You
|
|
4111
1719
|
|
|
4112
|
-
Thank you for using **ALOPE UI Library**. We hope this helps you build beautiful and functional user interfaces with ease.
|
|
1720
|
+
Thank you for using **ALOPE UI Library**. We hope this helps you build beautiful and functional user interfaces with ease.
|