cisse-vue-ui 0.8.3 → 0.9.0

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.
Files changed (174) hide show
  1. package/README.md +666 -4
  2. package/dist/{CheckboxGroup.vue_vue_type_script_setup_true_lang-DuJr8cz3.cjs → CheckboxGroup.vue_vue_type_script_setup_true_lang-BC86pBlY.cjs} +70 -70
  3. package/dist/CheckboxGroup.vue_vue_type_script_setup_true_lang-BC86pBlY.cjs.map +1 -0
  4. package/dist/{CheckboxGroup.vue_vue_type_script_setup_true_lang-N4oS_DJD.js → CheckboxGroup.vue_vue_type_script_setup_true_lang-ZP02bMgY.js} +72 -72
  5. package/dist/CheckboxGroup.vue_vue_type_script_setup_true_lang-ZP02bMgY.js.map +1 -0
  6. package/dist/{ConfirmDialog.vue_vue_type_script_setup_true_lang-DWs2V7xX.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-C5KHLMvx.js} +37 -184
  7. package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-C5KHLMvx.js.map +1 -0
  8. package/dist/{ConfirmDialog.vue_vue_type_script_setup_true_lang-BGUoa5fT.cjs → ConfirmDialog.vue_vue_type_script_setup_true_lang-CLfy0-Wb.cjs} +33 -180
  9. package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-CLfy0-Wb.cjs.map +1 -0
  10. package/dist/{Dropdown.vue_vue_type_script_setup_true_lang-DoJKvn30.cjs → Dropdown.vue_vue_type_script_setup_true_lang-BAKGRZIb.cjs} +2 -2
  11. package/dist/{Dropdown.vue_vue_type_script_setup_true_lang-DoJKvn30.cjs.map → Dropdown.vue_vue_type_script_setup_true_lang-BAKGRZIb.cjs.map} +1 -1
  12. package/dist/{Dropdown.vue_vue_type_script_setup_true_lang-A9Ax6iob.js → Dropdown.vue_vue_type_script_setup_true_lang-GLCX7E3C.js} +2 -2
  13. package/dist/{Dropdown.vue_vue_type_script_setup_true_lang-A9Ax6iob.js.map → Dropdown.vue_vue_type_script_setup_true_lang-GLCX7E3C.js.map} +1 -1
  14. package/dist/{FilterTabs.vue_vue_type_script_setup_true_lang-jW6Ikbvy.cjs → FilterTabs.vue_vue_type_script_setup_true_lang-COkZbeGG.cjs} +1260 -209
  15. package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-COkZbeGG.cjs.map +1 -0
  16. package/dist/{FilterTabs.vue_vue_type_script_setup_true_lang-CcOgc2Y_.js → FilterTabs.vue_vue_type_script_setup_true_lang-CzpYHtc5.js} +1269 -218
  17. package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-CzpYHtc5.js.map +1 -0
  18. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-BHopJ9RG.js +298 -0
  19. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-BHopJ9RG.js.map +1 -0
  20. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-Bo3HqgX0.cjs +297 -0
  21. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-Bo3HqgX0.cjs.map +1 -0
  22. package/dist/{PageHero.vue_vue_type_script_setup_true_lang-rbvfGvll.cjs → PageHero.vue_vue_type_script_setup_true_lang-BqwBJlv0.cjs} +2 -2
  23. package/dist/{PageHero.vue_vue_type_script_setup_true_lang-rbvfGvll.cjs.map → PageHero.vue_vue_type_script_setup_true_lang-BqwBJlv0.cjs.map} +1 -1
  24. package/dist/{PageHero.vue_vue_type_script_setup_true_lang-Gvocjdqh.js → PageHero.vue_vue_type_script_setup_true_lang-by-P5wIB.js} +2 -2
  25. package/dist/{PageHero.vue_vue_type_script_setup_true_lang-Gvocjdqh.js.map → PageHero.vue_vue_type_script_setup_true_lang-by-P5wIB.js.map} +1 -1
  26. package/dist/cisse-vue-ui.css +4 -4
  27. package/dist/components/core/AccordionItem.test.d.ts +1 -0
  28. package/dist/components/core/Breadcrumb.stories.d.ts +5 -0
  29. package/dist/components/core/CardWrapper.stories.d.ts +32 -0
  30. package/dist/components/core/CardWrapper.test.d.ts +1 -0
  31. package/dist/components/core/CardWrapper.vue.d.ts +129 -0
  32. package/dist/components/core/CollapsibleCard.vue.d.ts +1 -1
  33. package/dist/components/core/DataTable.stories.d.ts +38 -0
  34. package/dist/components/core/Dropdown.vue.d.ts +1 -1
  35. package/dist/components/core/Popover.vue.d.ts +2 -2
  36. package/dist/components/core/Tooltip.stories.d.ts +3 -0
  37. package/dist/components/core/index.cjs +40 -23
  38. package/dist/components/core/index.cjs.map +1 -1
  39. package/dist/components/core/index.d.ts +4 -1
  40. package/dist/components/core/index.js +40 -23
  41. package/dist/components/core/table/DataTable.test.d.ts +1 -0
  42. package/dist/components/core/{TableComponent.vue.d.ts → table/DataTable.vue.d.ts} +60 -7
  43. package/dist/components/core/table/Table.stories.d.ts +27 -0
  44. package/dist/components/core/table/atoms/Caption.test.d.ts +1 -0
  45. package/dist/components/core/table/atoms/Caption.vue.d.ts +26 -0
  46. package/dist/components/core/table/atoms/Col.test.d.ts +1 -0
  47. package/dist/components/core/table/atoms/Col.vue.d.ts +8 -0
  48. package/dist/components/core/table/atoms/Colgroup.test.d.ts +1 -0
  49. package/dist/components/core/table/atoms/Colgroup.vue.d.ts +17 -0
  50. package/dist/components/core/table/atoms/Table.test.d.ts +1 -0
  51. package/dist/components/core/table/atoms/Table.vue.d.ts +46 -0
  52. package/dist/components/core/table/atoms/Tbody.test.d.ts +1 -0
  53. package/dist/components/core/table/atoms/Tbody.vue.d.ts +17 -0
  54. package/dist/components/core/table/atoms/Td.test.d.ts +1 -0
  55. package/dist/components/core/table/atoms/Td.vue.d.ts +43 -0
  56. package/dist/components/core/table/atoms/Tfoot.test.d.ts +1 -0
  57. package/dist/components/core/table/atoms/Tfoot.vue.d.ts +17 -0
  58. package/dist/components/core/table/atoms/Th.test.d.ts +1 -0
  59. package/dist/components/core/table/atoms/Th.vue.d.ts +64 -0
  60. package/dist/components/core/table/atoms/Thead.test.d.ts +1 -0
  61. package/dist/components/core/table/atoms/Thead.vue.d.ts +17 -0
  62. package/dist/components/core/table/atoms/Tr.test.d.ts +1 -0
  63. package/dist/components/core/table/atoms/Tr.vue.d.ts +35 -0
  64. package/dist/components/core/table/atoms/index.d.ts +10 -0
  65. package/dist/components/core/table/index.d.ts +3 -0
  66. package/dist/components/core/table/molecules/ExpandableRow.test.d.ts +1 -0
  67. package/dist/components/core/table/molecules/ExpandableRow.vue.d.ts +47 -0
  68. package/dist/components/core/table/molecules/TableFooter.test.d.ts +1 -0
  69. package/dist/components/core/table/molecules/TableFooter.vue.d.ts +21 -0
  70. package/dist/components/core/table/molecules/TableHeader.test.d.ts +1 -0
  71. package/dist/components/core/table/molecules/TableHeader.vue.d.ts +49 -0
  72. package/dist/components/core/table/molecules/TableRow.test.d.ts +1 -0
  73. package/dist/components/core/table/molecules/TableRow.vue.d.ts +59 -0
  74. package/dist/components/core/table/molecules/index.d.ts +4 -0
  75. package/dist/components/feedback/Progress.vue.d.ts +1 -1
  76. package/dist/components/feedback/TableSkeleton.vue.d.ts +1 -1
  77. package/dist/components/feedback/index.cjs +14 -14
  78. package/dist/components/feedback/index.js +14 -14
  79. package/dist/components/form/Combobox.stories.d.ts +2 -0
  80. package/dist/components/form/Combobox.vue.d.ts +4 -0
  81. package/dist/components/form/DatePicker.stories.d.ts +2 -0
  82. package/dist/components/form/DatePicker.vue.d.ts +4 -0
  83. package/dist/components/form/FormSection.vue.d.ts +1 -1
  84. package/dist/components/form/FormSelect.stories.d.ts +2 -0
  85. package/dist/components/form/FormSelect.vue.d.ts +4 -0
  86. package/dist/components/form/IconPicker.stories.d.ts +19 -0
  87. package/dist/components/form/IconPicker.test.d.ts +1 -0
  88. package/dist/components/form/InputWrapper.stories.d.ts +1 -5
  89. package/dist/components/form/InputWrapper.vue.d.ts +6 -3
  90. package/dist/components/form/Rating.vue.d.ts +1 -1
  91. package/dist/components/form/SearchInput.vue.d.ts +1 -1
  92. package/dist/components/form/TagsInput.stories.d.ts +1 -0
  93. package/dist/components/form/TagsInput.vue.d.ts +3 -3
  94. package/dist/components/form/TextArea.stories.d.ts +3 -1
  95. package/dist/components/form/TextArea.vue.d.ts +4 -0
  96. package/dist/components/form/index.cjs +1 -1
  97. package/dist/components/form/index.js +2 -2
  98. package/dist/components/index.cjs +56 -39
  99. package/dist/components/index.cjs.map +1 -1
  100. package/dist/components/index.js +66 -49
  101. package/dist/components/layout/index.cjs +1 -1
  102. package/dist/components/layout/index.js +1 -1
  103. package/dist/composables/index.cjs +18 -9
  104. package/dist/composables/index.cjs.map +1 -1
  105. package/dist/composables/index.d.ts +8 -0
  106. package/dist/composables/index.js +15 -6
  107. package/dist/composables/index.js.map +1 -1
  108. package/dist/composables/useColumnResize.d.ts +38 -0
  109. package/dist/composables/useColumnResize.test.d.ts +1 -0
  110. package/dist/composables/useColumnVisibility.d.ts +44 -0
  111. package/dist/composables/useColumnVisibility.test.d.ts +1 -0
  112. package/dist/composables/useEditableCell.d.ts +51 -0
  113. package/dist/composables/useEditableCell.test.d.ts +1 -0
  114. package/dist/composables/useInputStyles.d.ts +32 -0
  115. package/dist/composables/useInputStyles.test.d.ts +1 -0
  116. package/dist/composables/usePagination.d.ts +44 -0
  117. package/dist/composables/usePagination.test.d.ts +1 -0
  118. package/dist/composables/usePinnedRows.d.ts +41 -0
  119. package/dist/composables/usePinnedRows.test.d.ts +1 -0
  120. package/dist/composables/useTableKeyboardNavigation.d.ts +52 -0
  121. package/dist/composables/useTableKeyboardNavigation.test.d.ts +1 -0
  122. package/dist/composables/useVirtualScroll.d.ts +32 -0
  123. package/dist/composables/useVirtualScroll.test.d.ts +1 -0
  124. package/dist/index-0kwQORZJ.js +114 -0
  125. package/dist/index-0kwQORZJ.js.map +1 -0
  126. package/dist/{index-5dQNEzd8.cjs → index-BMSH4AOz.cjs} +57 -40
  127. package/dist/{index-5dQNEzd8.cjs.map → index-BMSH4AOz.cjs.map} +1 -1
  128. package/dist/{index-SNefWfX0.js → index-BaWpldIJ.js} +3 -3
  129. package/dist/{index-SNefWfX0.js.map → index-BaWpldIJ.js.map} +1 -1
  130. package/dist/index.cjs +75 -49
  131. package/dist/index.cjs.map +1 -1
  132. package/dist/index.js +83 -57
  133. package/dist/index.js.map +1 -1
  134. package/dist/style.css +1 -1
  135. package/dist/types/components.d.ts +1 -1
  136. package/dist/types/property.d.ts +8 -0
  137. package/dist/{useDropdown-DK4c5JGL.cjs → useDropdown-HI7ABBLe.cjs} +5 -4
  138. package/dist/{useDropdown-DK4c5JGL.cjs.map → useDropdown-HI7ABBLe.cjs.map} +1 -1
  139. package/dist/{useDropdown-De0cKI83.js → useDropdown-XITCE_SM.js} +5 -4
  140. package/dist/{useDropdown-De0cKI83.js.map → useDropdown-XITCE_SM.js.map} +1 -1
  141. package/dist/useInputStyles-BFTJdXHL.js +127 -0
  142. package/dist/useInputStyles-BFTJdXHL.js.map +1 -0
  143. package/dist/useInputStyles-DMfvW6N5.cjs +126 -0
  144. package/dist/useInputStyles-DMfvW6N5.cjs.map +1 -0
  145. package/dist/usePagination-BGwbICFC.js +135 -0
  146. package/dist/usePagination-BGwbICFC.js.map +1 -0
  147. package/dist/usePagination-gvvh1zqA.cjs +134 -0
  148. package/dist/usePagination-gvvh1zqA.cjs.map +1 -0
  149. package/dist/useVirtualScroll-BivP86fA.cjs +869 -0
  150. package/dist/useVirtualScroll-BivP86fA.cjs.map +1 -0
  151. package/dist/useVirtualScroll-YeZru2Eo.js +870 -0
  152. package/dist/useVirtualScroll-YeZru2Eo.js.map +1 -0
  153. package/package.json +1 -1
  154. package/dist/CheckboxGroup.vue_vue_type_script_setup_true_lang-DuJr8cz3.cjs.map +0 -1
  155. package/dist/CheckboxGroup.vue_vue_type_script_setup_true_lang-N4oS_DJD.js.map +0 -1
  156. package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-BGUoa5fT.cjs.map +0 -1
  157. package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-DWs2V7xX.js.map +0 -1
  158. package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-CcOgc2Y_.js.map +0 -1
  159. package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-jW6Ikbvy.cjs.map +0 -1
  160. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-BwtEbaiT.js +0 -150
  161. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-BwtEbaiT.js.map +0 -1
  162. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-DtwwmfWr.cjs +0 -149
  163. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-DtwwmfWr.cjs.map +0 -1
  164. package/dist/components/core/TableComponent.stories.d.ts +0 -16
  165. package/dist/index-CDDUEkXf.js +0 -97
  166. package/dist/index-CDDUEkXf.js.map +0 -1
  167. package/dist/useDarkMode-Cl5QWTlC.js +0 -53
  168. package/dist/useDarkMode-Cl5QWTlC.js.map +0 -1
  169. package/dist/useDarkMode-DLZcJEUQ.cjs +0 -52
  170. package/dist/useDarkMode-DLZcJEUQ.cjs.map +0 -1
  171. package/dist/useToast-Bk60GArg.cjs +0 -176
  172. package/dist/useToast-Bk60GArg.cjs.map +0 -1
  173. package/dist/useToast-ina5g3mj.js +0 -177
  174. package/dist/useToast-ina5g3mj.js.map +0 -1
package/README.md CHANGED
@@ -94,7 +94,18 @@ app.use(VueTailwindUI, { components: ['Button', 'CardComponent'] })
94
94
  |-----------|-------------|
95
95
  | `Button` | Button with variants (primary, secondary, outline, ghost, danger, success), sizes, icons, loading state |
96
96
  | `CardComponent` | Card container with header, content, and footer slots |
97
- | `TableComponent` | Data table with sorting, selection, actions, and custom column rendering |
97
+ | `CardWrapper` | Advanced card with shadow/border/padding variants, image positions, clickable/selected states, loading skeleton |
98
+ | `DataTable` | Full-featured data table with sorting, selection, pagination, error states, striped/bordered/compact options |
99
+ | `Table` | Atomic table wrapper with context provider for styling (striped, bordered, hover, compact, stickyHeader) |
100
+ | `Colgroup` / `Col` | Column grouping and column styling |
101
+ | `Thead` / `Tbody` / `Tfoot` | Table section wrappers (support multiple sections) |
102
+ | `Tr` | Table row with selected, clickable, disabled states |
103
+ | `Th` | Header cell with sortable, colspan/rowspan, scope, alignment, and sticky column support |
104
+ | `Td` | Data cell with colspan/rowspan, alignment, main column styling, truncate, and custom classes |
105
+ | `TableHeader` | Composed header row with sort and select-all functionality |
106
+ | `TableRow` | Composed data row with selection and type rendering |
107
+ | `TableFooter` | Composed footer row for summary/pagination |
108
+ | `TableComponent` | Alias for DataTable (backwards compatibility) |
98
109
  | `MobileList` | Mobile-optimized card-based list with selection support |
99
110
  | `ResponsiveList` | Combines MobileList (mobile) and TableComponent (desktop) with automatic breakpoint switching |
100
111
  | `Tabs` | Tab navigation with variants (underline, pills, boxed) |
@@ -102,37 +113,58 @@ app.use(VueTailwindUI, { components: ['Button', 'CardComponent'] })
102
113
  | `Dropdown` | Dropdown menu with items, icons, and dividers |
103
114
  | `Avatar` | User avatar with image, initials, or icon fallback |
104
115
  | `AutocompleteComponent` | Searchable select with keyboard navigation |
105
- | `MenuItem` | Navigation menu item with icon, active state detection, and route support |
116
+ | `MenuItem` | Navigation menu item with icon, active state detection, flyout submenus, and route support |
106
117
  | `StatusBadge` | Colored status indicator badge |
107
118
  | `TableAction` | Icon button for table row actions |
108
119
  | `Stepper` | Multi-step progress indicator with horizontal/vertical orientation |
109
120
  | `CollapsibleCard` | Card that can expand/collapse its content |
110
121
  | `Accordion` | Expandable content sections with single/multiple mode |
122
+ | `AccordionItem` | Individual accordion panel (use with Accordion) |
111
123
  | `Breadcrumb` | Navigation breadcrumb trail |
112
124
  | `Drawer` | Slide-out panel from any edge (left, right, top, bottom) |
113
125
  | `Popover` | Floating content panel triggered by click or hover |
114
126
  | `Timeline` | Vertical timeline for events/history display |
115
127
  | `Tooltip` | Hover tooltip with customizable position |
128
+ | `DarkModeToggle` | Dark mode toggle button with icon variants |
129
+ | `StatsCard` | Statistics display card with icon, value, and trend |
130
+ | `StatsGrid` | Grid layout for multiple StatsCard components |
131
+ | `FilterTabs` | Tabbed filter buttons with counts |
116
132
 
117
133
  ### Form
118
134
 
119
135
  | Component | Description |
120
136
  |-----------|-------------|
121
- | `FormInput` | Text input with validation states and ARIA support |
137
+ | `FormInput` | Text input with validation states, sizes (sm/md/lg), and ARIA support |
122
138
  | `FormSelect` | Select dropdown with search, multi-select, and validation |
123
139
  | `FormGroup` | Form field wrapper with label, help text, and error states |
124
140
  | `FormLabel` | Styled form label with required indicator |
125
141
  | `FormHelp` | Help/error text for form fields |
142
+ | `FormSection` | Grouped form section with title and description |
143
+ | `FormActions` | Form button container with alignment options |
144
+ | `InputWrapper` | Wrapper for consistent input styling |
126
145
  | `SearchInput` | Search input with icon and clear button |
127
146
  | `Switch` | Toggle switch with label and description |
128
147
  | `Checkbox` | Checkbox with label, description, and indeterminate state |
148
+ | `CheckboxGroup` | Group of related checkboxes with select all |
129
149
  | `Combobox` | Multi-select combobox with search and tags |
150
+ | `TagsInput` | Tag input with add/remove functionality |
151
+ | `TextArea` | Multi-line text input with auto-resize |
130
152
  | `DatePicker` | Calendar date picker with min/max dates |
131
153
  | `ColorPicker` | Color selection with swatches and custom input |
154
+ | `IconPicker` | Icon selection from Iconify with search |
132
155
  | `FileUpload` | Drag-and-drop file upload with preview |
133
156
  | `Rating` | Star rating input with half-star support |
134
157
  | `Slider` | Single value slider input |
135
158
  | `RangeSlider` | Dual-handle range slider |
159
+ | `EmailInput` | Email input with validation |
160
+ | `PasswordInput` | Password input with visibility toggle |
161
+ | `PhoneInput` | Phone number input with formatting |
162
+ | `NumberInput` | Numeric input with increment/decrement |
163
+ | `MoneyInput` | Currency input with formatting |
164
+ | `PercentInput` | Percentage input with formatting |
165
+ | `QuantityInput` | Quantity input with +/- buttons |
166
+ | `URLInput` | URL input with validation |
167
+ | `OTPInput` | One-time password input with multiple digits |
136
168
 
137
169
  ### Feedback
138
170
 
@@ -161,6 +193,7 @@ app.use(VueTailwindUI, { components: ['Button', 'CardComponent'] })
161
193
  | `AuthLayout` | Split-panel authentication layout with branding and form sections |
162
194
  | `BaseLayout` | App shell with sidebar, header, main content area, and route-aware menu |
163
195
  | `PageLayout` | Page wrapper with breadcrumbs |
196
+ | `PageHero` | Hero section with title, description, and action slots |
164
197
 
165
198
  ### Type Display
166
199
 
@@ -172,6 +205,111 @@ app.use(VueTailwindUI, { components: ['Button', 'CardComponent'] })
172
205
  | `BooleanType` | Boolean value display (check/cross icons) |
173
206
  | `BadgeType` | Badge value display with colors |
174
207
 
208
+ ## Atomic Table Usage
209
+
210
+ Build custom tables with granular control using atomic components:
211
+
212
+ ```vue
213
+ <script setup lang="ts">
214
+ import { Table, Thead, Tbody, Tfoot, Tr, Th, Td, Colgroup, Col } from 'cisse-vue-ui'
215
+
216
+ const data = [
217
+ { id: 1, name: 'John Doe', amount: 1250.00 },
218
+ { id: 2, name: 'Jane Smith', amount: 890.50 },
219
+ ]
220
+ const total = data.reduce((sum, row) => sum + row.amount, 0)
221
+ </script>
222
+
223
+ <template>
224
+ <Table striped bordered>
225
+ <Colgroup>
226
+ <Col width="200px" />
227
+ <Col width="150px" />
228
+ </Colgroup>
229
+ <Thead>
230
+ <Tr>
231
+ <Th sortable>Name</Th>
232
+ <Th align="right">Amount</Th>
233
+ </Tr>
234
+ </Thead>
235
+ <Tbody>
236
+ <Tr v-for="row in data" :key="row.id" clickable @click="select(row)">
237
+ <Td main>{{ row.name }}</Td>
238
+ <Td align="right">{{ row.amount.toFixed(2) }}</Td>
239
+ </Tr>
240
+ </Tbody>
241
+ <Tfoot>
242
+ <Tr>
243
+ <Td>Total</Td>
244
+ <Td align="right">{{ total.toFixed(2) }}</Td>
245
+ </Tr>
246
+ </Tfoot>
247
+ </Table>
248
+ </template>
249
+ ```
250
+
251
+ ### Advanced: Colspan, Rowspan & Row Grouping
252
+
253
+ ```vue
254
+ <Table bordered>
255
+ <Thead>
256
+ <Tr>
257
+ <Th rowspan="2">Product</Th>
258
+ <Th colspan="2" align="center">Sales</Th>
259
+ </Tr>
260
+ <Tr>
261
+ <Th align="right">Q1</Th>
262
+ <Th align="right">Q2</Th>
263
+ </Tr>
264
+ </Thead>
265
+ <Tbody>
266
+ <!-- Row grouping with scope="rowgroup" -->
267
+ <Tr>
268
+ <Th rowspan="2" scope="rowgroup">Electronics</Th>
269
+ <Td align="right">$45,000</Td>
270
+ <Td align="right">$52,000</Td>
271
+ </Tr>
272
+ <Tr>
273
+ <Td align="right">$38,000</Td>
274
+ <Td align="right">$41,000</Td>
275
+ </Tr>
276
+ </Tbody>
277
+ </Table>
278
+ ```
279
+
280
+ All atomic components support `v-bind="$attrs"` for full customization.
281
+
282
+ Or use the full-featured DataTable for common use cases:
283
+
284
+ ```vue
285
+ <script setup lang="ts">
286
+ import { DataTable } from 'cisse-vue-ui'
287
+ import type { Property } from 'cisse-vue-ui/types'
288
+
289
+ const properties: Property[] = [
290
+ { name: 'name', label: 'Name', main: true, sortable: true },
291
+ { name: 'email', label: 'Email' },
292
+ { name: 'status', label: 'Active', type: 'boolean' },
293
+ ]
294
+ </script>
295
+
296
+ <template>
297
+ <DataTable
298
+ :items="users"
299
+ :properties="properties"
300
+ selectable
301
+ striped
302
+ bordered
303
+ @select="handleSelect"
304
+ @sort="handleSort"
305
+ >
306
+ <template #action="{ item }">
307
+ <Button variant="ghost" size="sm" icon="lucide:edit" />
308
+ </template>
309
+ </DataTable>
310
+ </template>
311
+ ```
312
+
175
313
  ## Composables
176
314
 
177
315
  ```typescript
@@ -183,7 +321,8 @@ import {
183
321
  useModal,
184
322
  useToast,
185
323
  useFocusTrap,
186
- useId
324
+ useId,
325
+ useInputStyles
187
326
  } from 'cisse-vue-ui/composables'
188
327
  ```
189
328
 
@@ -350,6 +489,436 @@ const { id, related } = useId({ prefix: 'modal' })
350
489
  </template>
351
490
  ```
352
491
 
492
+ ### useInputStyles
493
+
494
+ Centralized input styling for form components with consistent sizing, states, and dark mode:
495
+
496
+ ```typescript
497
+ import { useInputStyles } from 'cisse-vue-ui/composables'
498
+ import { ref, computed } from 'vue'
499
+
500
+ const size = ref<'sm' | 'md' | 'lg'>('md')
501
+ const disabled = ref(false)
502
+ const invalid = ref(false)
503
+
504
+ const {
505
+ inputClasses, // Classes for input elements
506
+ triggerClasses, // Classes for dropdown triggers
507
+ wrapperClasses, // Classes for input wrappers
508
+ iconClasses, // Classes for input icons
509
+ } = useInputStyles({
510
+ size,
511
+ disabled,
512
+ invalid,
513
+ focused: computed(() => false)
514
+ })
515
+ ```
516
+
517
+ Size variants:
518
+ - `sm`: Smaller text (text-sm), reduced padding (px-2.5 py-1.5)
519
+ - `md`: Default size (text-sm), standard padding (px-3 py-2)
520
+ - `lg`: Larger text (text-base), increased padding (px-4 py-2.5)
521
+
522
+ ## Table Composables
523
+
524
+ Powerful composables for building advanced data tables:
525
+
526
+ ```typescript
527
+ import {
528
+ usePagination,
529
+ useTableKeyboardNavigation,
530
+ useColumnVisibility,
531
+ useColumnResize,
532
+ usePinnedRows,
533
+ useEditableCell,
534
+ useVirtualScroll
535
+ } from 'cisse-vue-ui/composables'
536
+ ```
537
+
538
+ ### usePagination
539
+
540
+ Client-side pagination with page size selector support:
541
+
542
+ ```typescript
543
+ import { usePagination } from 'cisse-vue-ui/composables'
544
+ import { ref } from 'vue'
545
+
546
+ const items = ref([/* your data */])
547
+
548
+ const {
549
+ currentPage, // Current page (1-indexed)
550
+ pageSize, // Items per page
551
+ totalPages, // Total number of pages
552
+ paginatedItems, // Items for current page
553
+ startIndex, // First item index (0-indexed)
554
+ endIndex, // Last item index (0-indexed)
555
+ hasNextPage, // Can go forward?
556
+ hasPreviousPage, // Can go back?
557
+ goToPage, // Navigate to specific page
558
+ nextPage, // Go to next page
559
+ previousPage, // Go to previous page
560
+ setPageSize, // Change items per page
561
+ } = usePagination(items, {
562
+ initialPage: 1,
563
+ initialPageSize: 10,
564
+ pageSizes: [10, 25, 50, 100]
565
+ })
566
+ ```
567
+
568
+ ```vue
569
+ <template>
570
+ <DataTable
571
+ :items="items"
572
+ :properties="properties"
573
+ paginated
574
+ :page-size="25"
575
+ :page-sizes="[10, 25, 50, 100]"
576
+ @page-change="handlePageChange"
577
+ />
578
+ </template>
579
+ ```
580
+
581
+ ### useTableKeyboardNavigation
582
+
583
+ Keyboard navigation for accessible tables:
584
+
585
+ ```typescript
586
+ import { useTableKeyboardNavigation } from 'cisse-vue-ui/composables'
587
+ import { ref } from 'vue'
588
+
589
+ const tableRef = ref<HTMLElement>()
590
+ const items = ref([/* your data */])
591
+
592
+ const {
593
+ focusedRowIndex, // Currently focused row
594
+ focusedCellIndex, // Currently focused cell
595
+ handleKeydown, // Keyboard event handler
596
+ focusRow, // Focus specific row
597
+ focusCell, // Focus specific cell
598
+ } = useTableKeyboardNavigation({
599
+ tableRef,
600
+ items,
601
+ onSelect: (index) => console.log('Selected row:', index),
602
+ onActivate: (index) => console.log('Activated row:', index),
603
+ })
604
+ ```
605
+
606
+ ```vue
607
+ <template>
608
+ <Table ref="tableRef" @keydown="handleKeydown">
609
+ <Tbody>
610
+ <Tr
611
+ v-for="(item, index) in items"
612
+ :key="item.id"
613
+ :tabindex="focusedRowIndex === index ? 0 : -1"
614
+ :class="{ 'ring-2 ring-primary-500': focusedRowIndex === index }"
615
+ >
616
+ <Td>{{ item.name }}</Td>
617
+ </Tr>
618
+ </Tbody>
619
+ </Table>
620
+ </template>
621
+ ```
622
+
623
+ ### useColumnVisibility
624
+
625
+ Toggle column visibility with persistence:
626
+
627
+ ```typescript
628
+ import { useColumnVisibility, type Column } from 'cisse-vue-ui/composables'
629
+
630
+ const columns: Column[] = [
631
+ { key: 'name', label: 'Name', visible: true, required: true },
632
+ { key: 'email', label: 'Email', visible: true },
633
+ { key: 'phone', label: 'Phone', visible: false },
634
+ { key: 'address', label: 'Address', visible: false },
635
+ ]
636
+
637
+ const {
638
+ visibleColumns, // Columns with visible: true
639
+ hiddenColumns, // Columns with visible: false
640
+ toggleColumn, // Toggle single column visibility
641
+ showColumn, // Show a column
642
+ hideColumn, // Hide a column
643
+ showAllColumns, // Show all columns
644
+ hideAllColumns, // Hide all except required
645
+ resetColumns, // Reset to initial state
646
+ isColumnVisible, // Check if column is visible
647
+ } = useColumnVisibility({
648
+ columns,
649
+ storageKey: 'my-table-columns' // Optional: persist to localStorage
650
+ })
651
+ ```
652
+
653
+ ```vue
654
+ <template>
655
+ <div class="mb-4 flex gap-2">
656
+ <Checkbox
657
+ v-for="col in columns"
658
+ :key="col.key"
659
+ :model-value="isColumnVisible(col.key)"
660
+ :disabled="col.required"
661
+ :label="col.label"
662
+ @update:model-value="toggleColumn(col.key)"
663
+ />
664
+ </div>
665
+
666
+ <Table>
667
+ <Thead>
668
+ <Tr>
669
+ <Th v-for="col in visibleColumns" :key="col.key">{{ col.label }}</Th>
670
+ </Tr>
671
+ </Thead>
672
+ <Tbody>
673
+ <Tr v-for="item in items" :key="item.id">
674
+ <Td v-for="col in visibleColumns" :key="col.key">
675
+ {{ item[col.key] }}
676
+ </Td>
677
+ </Tr>
678
+ </Tbody>
679
+ </Table>
680
+ </template>
681
+ ```
682
+
683
+ ### useColumnResize
684
+
685
+ Drag-to-resize columns with constraints:
686
+
687
+ ```typescript
688
+ import { useColumnResize } from 'cisse-vue-ui/composables'
689
+
690
+ const {
691
+ columnWidths, // Map of column key to width
692
+ isResizing, // Currently resizing?
693
+ resizingColumn, // Which column is being resized
694
+ startResize, // Begin resize operation
695
+ getColumnWidth, // Get width for column
696
+ setColumnWidth, // Set width for column
697
+ resetColumnWidth, // Reset column to default
698
+ resetAllWidths, // Reset all columns
699
+ } = useColumnResize({
700
+ defaultWidth: 150,
701
+ minWidth: 80,
702
+ maxWidth: 500,
703
+ storageKey: 'my-table-widths' // Optional: persist to localStorage
704
+ })
705
+ ```
706
+
707
+ ```vue
708
+ <template>
709
+ <Table>
710
+ <Thead>
711
+ <Tr>
712
+ <Th
713
+ v-for="col in columns"
714
+ :key="col.key"
715
+ :style="{ width: getColumnWidth(col.key) + 'px' }"
716
+ resizable
717
+ :resizing="resizingColumn === col.key"
718
+ @resize-start="(e) => startResize(col.key, e)"
719
+ >
720
+ {{ col.label }}
721
+ </Th>
722
+ </Tr>
723
+ </Thead>
724
+ </Table>
725
+ </template>
726
+ ```
727
+
728
+ ### usePinnedRows
729
+
730
+ Pin rows to top or bottom of table:
731
+
732
+ ```typescript
733
+ import { usePinnedRows } from 'cisse-vue-ui/composables'
734
+
735
+ interface User {
736
+ id: number
737
+ name: string
738
+ email: string
739
+ }
740
+
741
+ const items = ref<User[]>([/* your data */])
742
+
743
+ const {
744
+ pinnedTop, // Items pinned to top
745
+ pinnedBottom, // Items pinned to bottom
746
+ unpinnedItems, // Items not pinned
747
+ isPinned, // Check if item is pinned
748
+ getPinPosition, // Get pin position ('top' | 'bottom' | null)
749
+ pinToTop, // Pin item to top
750
+ pinToBottom, // Pin item to bottom
751
+ unpin, // Unpin item
752
+ togglePin, // Toggle pin state
753
+ clearPinned, // Clear all pinned items
754
+ } = usePinnedRows<User>({
755
+ items,
756
+ keyField: 'id',
757
+ maxPinned: 5 // Optional: limit pinned rows
758
+ })
759
+ ```
760
+
761
+ ```vue
762
+ <template>
763
+ <Table>
764
+ <Tbody>
765
+ <!-- Pinned top rows -->
766
+ <Tr
767
+ v-for="item in pinnedTop"
768
+ :key="item.id"
769
+ class="bg-yellow-50 dark:bg-yellow-900/20"
770
+ >
771
+ <Td>
772
+ <Button size="sm" @click="unpin(String(item.id))">Unpin</Button>
773
+ </Td>
774
+ <Td>{{ item.name }}</Td>
775
+ </Tr>
776
+
777
+ <!-- Regular rows -->
778
+ <Tr v-for="item in unpinnedItems" :key="item.id">
779
+ <Td>
780
+ <Button size="sm" @click="pinToTop(String(item.id), item)">Pin</Button>
781
+ </Td>
782
+ <Td>{{ item.name }}</Td>
783
+ </Tr>
784
+
785
+ <!-- Pinned bottom rows -->
786
+ <Tr
787
+ v-for="item in pinnedBottom"
788
+ :key="item.id"
789
+ class="bg-blue-50 dark:bg-blue-900/20"
790
+ >
791
+ <Td>
792
+ <Button size="sm" @click="unpin(String(item.id))">Unpin</Button>
793
+ </Td>
794
+ <Td>{{ item.name }}</Td>
795
+ </Tr>
796
+ </Tbody>
797
+ </Table>
798
+ </template>
799
+ ```
800
+
801
+ ### useEditableCell
802
+
803
+ Inline cell editing with validation:
804
+
805
+ ```typescript
806
+ import { useEditableCell } from 'cisse-vue-ui/composables'
807
+
808
+ interface User {
809
+ id: number
810
+ name: string
811
+ email: string
812
+ }
813
+
814
+ const {
815
+ editingCell, // Current cell being edited { rowKey, field }
816
+ editingValue, // Current edit value
817
+ isEditing, // Is any cell being edited?
818
+ isSaving, // Is save in progress?
819
+ startEditing, // Start editing a cell
820
+ saveEdit, // Save current edit
821
+ cancelEdit, // Cancel current edit
822
+ getCellValue, // Get original value for cell
823
+ } = useEditableCell<User>({
824
+ onSave: async ({ rowKey, field, oldValue, newValue }) => {
825
+ // Save to backend
826
+ await api.updateUser(rowKey, { [field]: newValue })
827
+ },
828
+ validate: ({ field, newValue }) => {
829
+ if (field === 'email' && !newValue.includes('@')) {
830
+ return 'Invalid email address'
831
+ }
832
+ return true
833
+ }
834
+ })
835
+ ```
836
+
837
+ ```vue
838
+ <template>
839
+ <Table>
840
+ <Tbody>
841
+ <Tr v-for="item in items" :key="item.id">
842
+ <Td @dblclick="startEditing(String(item.id), 'name', item.name)">
843
+ <template v-if="editingCell?.rowKey === String(item.id) && editingCell?.field === 'name'">
844
+ <input
845
+ v-model="editingValue"
846
+ @keydown.enter="saveEdit"
847
+ @keydown.escape="cancelEdit"
848
+ @blur="saveEdit"
849
+ class="border rounded px-2 py-1"
850
+ />
851
+ </template>
852
+ <template v-else>
853
+ {{ item.name }}
854
+ </template>
855
+ </Td>
856
+ </Tr>
857
+ </Tbody>
858
+ </Table>
859
+ </template>
860
+ ```
861
+
862
+ ### useVirtualScroll
863
+
864
+ Virtual scrolling for large datasets:
865
+
866
+ ```typescript
867
+ import { useVirtualScroll } from 'cisse-vue-ui/composables'
868
+
869
+ const items = ref([/* 10,000+ items */])
870
+
871
+ const {
872
+ visibleItems, // Items to render
873
+ totalHeight, // Total scroll height
874
+ offsetY, // Top offset for positioning
875
+ startIndex, // First visible item index
876
+ endIndex, // Last visible item index
877
+ scrollTop, // Current scroll position
878
+ onScroll, // Scroll event handler
879
+ scrollToIndex, // Scroll to specific item
880
+ containerRef, // Ref for scroll container
881
+ } = useVirtualScroll({
882
+ items,
883
+ rowHeight: 48, // Height of each row in px
884
+ containerHeight: 500, // Visible container height
885
+ overscan: 5 // Extra rows to render (buffer)
886
+ })
887
+ ```
888
+
889
+ ```vue
890
+ <template>
891
+ <div
892
+ ref="containerRef"
893
+ class="overflow-auto"
894
+ :style="{ height: '500px' }"
895
+ @scroll="onScroll"
896
+ >
897
+ <!-- Spacer for total height -->
898
+ <div :style="{ height: totalHeight + 'px', position: 'relative' }">
899
+ <!-- Positioned visible items -->
900
+ <div :style="{ transform: `translateY(${offsetY}px)` }">
901
+ <Table>
902
+ <Tbody>
903
+ <Tr
904
+ v-for="(item, index) in visibleItems"
905
+ :key="item.id"
906
+ :style="{ height: '48px' }"
907
+ >
908
+ <Td>{{ startIndex + index + 1 }}</Td>
909
+ <Td>{{ item.name }}</Td>
910
+ </Tr>
911
+ </Tbody>
912
+ </Table>
913
+ </div>
914
+ </div>
915
+ </div>
916
+
917
+ <!-- Jump to row -->
918
+ <Button @click="scrollToIndex(5000)">Jump to row 5000</Button>
919
+ </template>
920
+ ```
921
+
353
922
  ## Types
354
923
 
355
924
  ```typescript
@@ -503,6 +1072,99 @@ const steps = [
503
1072
  />
504
1073
  ```
505
1074
 
1075
+ ### CardWrapper
1076
+
1077
+ ```vue
1078
+ <script setup>
1079
+ import { CardWrapper, Button } from 'cisse-vue-ui'
1080
+ </script>
1081
+
1082
+ <template>
1083
+ <!-- Basic card with title and icon -->
1084
+ <CardWrapper
1085
+ title="Dashboard"
1086
+ description="Overview of your account"
1087
+ icon="lucide:layout-dashboard"
1088
+ >
1089
+ <div class="p-5">
1090
+ <p>Card content goes here.</p>
1091
+ </div>
1092
+ </CardWrapper>
1093
+
1094
+ <!-- Card with image -->
1095
+ <CardWrapper
1096
+ title="Product"
1097
+ image="/product.jpg"
1098
+ image-position="top"
1099
+ image-height="200px"
1100
+ >
1101
+ <div class="p-5">Product description</div>
1102
+ </CardWrapper>
1103
+
1104
+ <!-- Clickable card with accent -->
1105
+ <CardWrapper
1106
+ title="Clickable Card"
1107
+ accent="primary"
1108
+ clickable
1109
+ @click="handleClick"
1110
+ >
1111
+ <div class="p-5">Click me!</div>
1112
+ </CardWrapper>
1113
+
1114
+ <!-- Card with actions -->
1115
+ <CardWrapper title="Settings" icon="lucide:settings">
1116
+ <template #actions>
1117
+ <Button size="sm" variant="outline">Cancel</Button>
1118
+ <Button size="sm">Save</Button>
1119
+ </template>
1120
+ <div class="p-5">Settings content</div>
1121
+ <template #footer>
1122
+ <p class="text-sm text-gray-500">Last updated: Today</p>
1123
+ </template>
1124
+ </CardWrapper>
1125
+ </template>
1126
+ ```
1127
+
1128
+ #### CardWrapper Props
1129
+
1130
+ | Prop | Type | Default | Description |
1131
+ |------|------|---------|-------------|
1132
+ | `title` | `string` | - | Card title |
1133
+ | `description` | `string` | - | Card description |
1134
+ | `icon` | `string` | - | Header icon (Iconify format) |
1135
+ | `shadow` | `'none' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Shadow level |
1136
+ | `rounded` | `'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | `'lg'` | Border radius |
1137
+ | `padding` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'none'` | Content padding |
1138
+ | `border` | `'none' \| 'default' \| 'primary' \| 'secondary'` | `'none'` | Border style |
1139
+ | `variant` | `'default' \| 'glass' \| 'outline' \| 'flat'` | `'default'` | Visual variant |
1140
+ | `accent` | `'none' \| 'primary' \| 'secondary' \| 'success' \| 'warning' \| 'danger' \| 'info'` | `'none'` | Colored accent border |
1141
+ | `clickable` | `boolean` | `false` | Make card clickable with hover effects |
1142
+ | `selected` | `boolean` | `false` | Selected state with ring indicator |
1143
+ | `disabled` | `boolean` | `false` | Disabled state |
1144
+ | `image` | `string` | - | Image URL |
1145
+ | `imagePosition` | `'top' \| 'bottom' \| 'left' \| 'right' \| 'background'` | `'top'` | Image position |
1146
+ | `loading` | `boolean` | `false` | Show loading skeleton |
1147
+
1148
+ ### IconPicker
1149
+
1150
+ ```vue
1151
+ <script setup>
1152
+ import { ref } from 'vue'
1153
+ import { IconPicker } from 'cisse-vue-ui'
1154
+
1155
+ const selectedIcon = ref('mdi:heart')
1156
+ </script>
1157
+
1158
+ <template>
1159
+ <IconPicker
1160
+ v-model="selectedIcon"
1161
+ label="Select Icon"
1162
+ help="Choose an icon for your item"
1163
+ :collections="['mdi', 'heroicons', 'lucide']"
1164
+ />
1165
+ </template>
1166
+ ```
1167
+
506
1168
  ### TableComponent
507
1169
 
508
1170
  ```vue