@axzydev/axzy_ui_system 1.4.8 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -11
- package/dist/index.cjs +1826 -1351
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +115 -14
- package/dist/index.d.ts +115 -14
- package/dist/index.js +1481 -1010
- package/dist/index.js.map +1 -1
- package/dist/layered.css +1 -1
- package/package.json +3 -16
- package/src/App.tsx +90 -73
- package/src/components/atoms/badget/badget.tsx +23 -5
- package/src/components/atoms/chip/chip.tsx +3 -1
- package/src/components/atoms/image/image.tsx +3 -1
- package/src/components/atoms/input/input.tsx +8 -5
- package/src/components/atoms/loader/loader.tsx +3 -1
- package/src/components/atoms/slide/slide.props.ts +12 -0
- package/src/components/atoms/slide/slide.tsx +3 -0
- package/src/components/molecules/alert/alert.tsx +3 -1
- package/src/components/molecules/breadcrumbs/breadcrumbs.tsx +3 -1
- package/src/components/molecules/calendar/calendar.tsx +9 -6
- package/src/components/molecules/card/card.tsx +5 -2
- package/src/components/molecules/chip-input/chip-input.tsx +9 -7
- package/src/components/molecules/date-picker/datePicker.tsx +9 -9
- package/src/components/molecules/dropdown-menu/dropdown-menu.props.ts +1 -1
- package/src/components/molecules/dropdown-menu/dropdown-menu.tsx +6 -3
- package/src/components/molecules/field/field.tsx +3 -1
- package/src/components/molecules/form-header/form-header.tsx +3 -1
- package/src/components/molecules/line-bar-chart/line-bar-chart.props.ts +2 -2
- package/src/components/molecules/line-bar-chart/line-bar-chart.tsx +20 -15
- package/src/components/molecules/masked-input/masked-input.tsx +3 -1
- package/src/components/molecules/multi-select/multi-select.tsx +12 -9
- package/src/components/molecules/pagination/pagination.tsx +11 -5
- package/src/components/molecules/search-select/search-select.tsx +11 -9
- package/src/components/molecules/select/select.tsx +6 -4
- package/src/components/molecules/stepper/stepper.tsx +6 -4
- package/src/components/molecules/table/table.tsx +30 -28
- package/src/components/molecules/time-picker/timePicker.tsx +8 -6
- package/src/components/molecules/wysiwyg/wysiwyg.tsx +23 -12
- package/src/components/organisms/confirm-dialog/confirm-dialog.props.ts +4 -4
- package/src/components/organisms/confirm-dialog/confirm-dialog.tsx +16 -8
- package/src/components/organisms/data-table/dataTable.tsx +31 -25
- package/src/components/organisms/dialog/dialog.tsx +3 -0
- package/src/components/organisms/drawer/drawer.tsx +3 -0
- package/src/components/organisms/dropfile/dropfile.tsx +19 -17
- package/src/components/organisms/form-builder/fieldRenderer.tsx +4 -2
- package/src/components/organisms/navbar/navbar.tsx +4 -2
- package/src/components/organisms/page-header/page-header.tsx +3 -1
- package/src/components/organisms/searchTable/components/PaginationControls.tsx +8 -6
- package/src/components/organisms/searchTable/components/PaginationInfo.tsx +3 -1
- package/src/components/organisms/searchTable/components/SearchAndSortBar.tsx +7 -5
- package/src/components/organisms/searchTable/components/SearchInput.tsx +4 -2
- package/src/components/organisms/searchTable/components/SortButton.tsx +13 -11
- package/src/components/organisms/searchTable/components/TableEmptyState.tsx +4 -2
- package/src/components/organisms/searchTable/components/TableRow.tsx +6 -4
- package/src/components/organisms/searchTable/searchTable.tsx +4 -2
- package/src/components/organisms/sidebar/sidebar.props.ts +1 -1
- package/src/components/organisms/sidebar/sidebar.tsx +9 -4
- package/src/components/organisms/toast/toast.tsx +3 -1
- package/src/components/organisms/topbar/topbar.tsx +4 -2
- package/src/components/templates/page/page.props.ts +4 -4
- package/src/components/templates/page/page.tsx +6 -4
- package/src/components/theme-provider/themeProvider.tsx +28 -17
- package/src/dev.css +61 -2
- package/src/global.d.ts +10 -0
- package/src/i18n/context.ts +9 -0
- package/src/i18n/index.ts +22 -0
- package/src/i18n/locales/en.ts +163 -0
- package/src/i18n/locales/es.ts +165 -0
- package/src/i18n/provider.tsx +44 -0
- package/src/i18n/translator.ts +82 -0
- package/src/i18n/types.ts +54 -0
- package/src/i18n/useITTranslation.ts +20 -0
- package/src/index.css +0 -1
- package/src/index.ts +7 -1
- package/src/sandbox/LandingShowcase.tsx +224 -580
- package/src/sandbox/NotFoundShowcase.tsx +51 -36
- package/src/sandbox/TopbarSearch.tsx +6 -4
- package/src/sandbox/controls.tsx +180 -0
- package/src/sandbox/i18n.ts +1939 -0
- package/src/sandbox/icons.tsx +25 -0
- package/src/sandbox/locale.tsx +72 -0
- package/src/sandbox/ui.tsx +474 -0
- package/src/sandbox/useHashRoute.ts +46 -10
- package/src/showcases/DataShowcases.tsx +103 -87
- package/src/showcases/FeedbackShowcases.tsx +37 -30
- package/src/showcases/FormShowcases.tsx +303 -215
- package/src/showcases/GettingStartedShowcase.tsx +151 -145
- package/src/showcases/HelpShowcase.tsx +126 -128
- package/src/showcases/HomeShowcase.tsx +678 -482
- package/src/showcases/LayoutPrimitivesShowcases.tsx +129 -114
- package/src/showcases/NavigationShowcases.tsx +45 -37
- package/src/showcases/PageShowcases.tsx +171 -152
- package/src/showcases/ProductoDetalle.tsx +272 -129
- package/src/showcases/ShowcaseLayout.tsx +256 -219
- package/src/showcases/SizesShowcase.tsx +123 -64
- package/src/showcases/StructureShowcases.tsx +203 -138
- package/src/showcases/portfolioUi.tsx +153 -0
- package/src/showcases/techIcons.ts +3 -0
- package/src/utils/table.utils.ts +10 -2
- package/src/components/atoms/avatar/avatar.doc.mdx +0 -48
- package/src/components/atoms/avatar/avatar.stories.tsx +0 -64
- package/src/components/atoms/badget/badget.doc.mdx +0 -46
- package/src/components/atoms/badget/badget.stories.tsx +0 -75
- package/src/components/atoms/button/button.doc.mdx +0 -59
- package/src/components/atoms/button/button.stories.tsx +0 -173
- package/src/components/atoms/checkbox/checkbox.doc.mdx +0 -54
- package/src/components/atoms/checkbox/checkbox.stories.tsx +0 -53
- package/src/components/atoms/chip/chip.doc.mdx +0 -47
- package/src/components/atoms/chip/chip.stories.tsx +0 -64
- package/src/components/atoms/divider/divider.doc.mdx +0 -42
- package/src/components/atoms/divider/divider.stories.tsx +0 -33
- package/src/components/atoms/flex/flex.doc.mdx +0 -59
- package/src/components/atoms/flex/flex.stories.tsx +0 -70
- package/src/components/atoms/grid/grid.doc.mdx +0 -54
- package/src/components/atoms/grid/grid.stories.tsx +0 -71
- package/src/components/atoms/image/image.doc.mdx +0 -44
- package/src/components/atoms/image/image.stories.tsx +0 -48
- package/src/components/atoms/input/input.doc.mdx +0 -70
- package/src/components/atoms/input/input.stories.tsx +0 -113
- package/src/components/atoms/input-number/input-number.doc.mdx +0 -74
- package/src/components/atoms/input-number/input-number.stories.tsx +0 -111
- package/src/components/atoms/loader/loader.doc.mdx +0 -43
- package/src/components/atoms/loader/loader.stories.tsx +0 -104
- package/src/components/atoms/popover/popover.doc.mdx +0 -53
- package/src/components/atoms/popover/popover.stories.tsx +0 -24
- package/src/components/atoms/progress/progress.doc.mdx +0 -48
- package/src/components/atoms/progress/progress.stories.tsx +0 -39
- package/src/components/atoms/radio/radio.doc.mdx +0 -62
- package/src/components/atoms/radio/radio.stories.tsx +0 -48
- package/src/components/atoms/segmented-control/segmented-control.doc.mdx +0 -60
- package/src/components/atoms/segmented-control/segmented-control.stories.tsx +0 -62
- package/src/components/atoms/skeleton/skeleton.doc.mdx +0 -43
- package/src/components/atoms/skeleton/skeleton.stories.tsx +0 -29
- package/src/components/atoms/slide/slide.doc.mdx +0 -46
- package/src/components/atoms/slide/slide.stories.tsx +0 -120
- package/src/components/atoms/slider/slider.doc.mdx +0 -49
- package/src/components/atoms/slider/slider.stories.tsx +0 -29
- package/src/components/atoms/stack/stack.doc.mdx +0 -126
- package/src/components/atoms/stack/stack.stories.tsx +0 -283
- package/src/components/atoms/text/text.doc.mdx +0 -41
- package/src/components/atoms/text/text.stories.tsx +0 -66
- package/src/components/atoms/textarea/textarea.doc.mdx +0 -64
- package/src/components/atoms/textarea/textarea.stories.tsx +0 -26
- package/src/components/atoms/tooltip/tooltip.doc.mdx +0 -47
- package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -19
- package/src/components/isolation/isolation.stories.tsx +0 -202
- package/src/components/molecules/accordion/accordion.doc.mdx +0 -47
- package/src/components/molecules/accordion/accordion.stories.tsx +0 -68
- package/src/components/molecules/alert/alert.doc.mdx +0 -48
- package/src/components/molecules/alert/alert.stories.tsx +0 -40
- package/src/components/molecules/breadcrumbs/breadcrumbs.doc.mdx +0 -57
- package/src/components/molecules/breadcrumbs/breadcrumbs.stories.tsx +0 -20
- package/src/components/molecules/calendar/calendar.doc.mdx +0 -76
- package/src/components/molecules/calendar/calendar.stories.tsx +0 -90
- package/src/components/molecules/card/card.doc.mdx +0 -54
- package/src/components/molecules/card/card.stories.tsx +0 -57
- package/src/components/molecules/chip-input/chip-input.doc.mdx +0 -44
- package/src/components/molecules/chip-input/chip-input.stories.tsx +0 -52
- package/src/components/molecules/date-picker/date-picker.doc.mdx +0 -65
- package/src/components/molecules/date-picker/date-picker.stories.tsx +0 -88
- package/src/components/molecules/dropdown-menu/dropdown-menu.doc.mdx +0 -46
- package/src/components/molecules/dropdown-menu/dropdown-menu.stories.tsx +0 -41
- package/src/components/molecules/empty-state/empty-state.doc.mdx +0 -50
- package/src/components/molecules/empty-state/empty-state.stories.tsx +0 -19
- package/src/components/molecules/field/field.doc.mdx +0 -43
- package/src/components/molecules/field/field.stories.tsx +0 -42
- package/src/components/molecules/form-header/form-header.doc.mdx +0 -38
- package/src/components/molecules/form-header/form-header.stories.tsx +0 -52
- package/src/components/molecules/masked-input/masked-input.doc.mdx +0 -78
- package/src/components/molecules/masked-input/masked-input.stories.tsx +0 -126
- package/src/components/molecules/multi-select/multi-select.doc.mdx +0 -55
- package/src/components/molecules/multi-select/multi-select.stories.tsx +0 -59
- package/src/components/molecules/pagination/pagination.doc.mdx +0 -62
- package/src/components/molecules/pagination/pagination.stories.tsx +0 -110
- package/src/components/molecules/search-select/search-select.doc.mdx +0 -77
- package/src/components/molecules/search-select/search-select.stories.tsx +0 -146
- package/src/components/molecules/select/select.doc.mdx +0 -75
- package/src/components/molecules/select/select.stories.tsx +0 -85
- package/src/components/molecules/stat-card/stat-card.doc.mdx +0 -48
- package/src/components/molecules/stat-card/stat-card.stories.tsx +0 -40
- package/src/components/molecules/stepper/stepper.doc.mdx +0 -54
- package/src/components/molecules/stepper/stepper.stories.tsx +0 -154
- package/src/components/molecules/table/table.doc.mdx +0 -140
- package/src/components/molecules/table/table.stories.tsx +0 -402
- package/src/components/molecules/tabs/tabs.doc.mdx +0 -52
- package/src/components/molecules/tabs/tabs.stories.tsx +0 -31
- package/src/components/molecules/time-picker/timePicker.doc.mdx +0 -68
- package/src/components/molecules/time-picker/timePicker.stories.tsx +0 -130
- package/src/components/molecules/wysiwyg/wysiwyg.stories.tsx +0 -95
- package/src/components/organisms/confirm-dialog/confirm-dialog.doc.mdx +0 -60
- package/src/components/organisms/confirm-dialog/confirm-dialog.stories.tsx +0 -32
- package/src/components/organisms/data-table/ITDataTable.doc.mdx +0 -132
- package/src/components/organisms/data-table/ITDataTable.stories.tsx +0 -353
- package/src/components/organisms/dialog/dialog.doc.mdx +0 -54
- package/src/components/organisms/dialog/dialog.stories.tsx +0 -126
- package/src/components/organisms/drawer/drawer.doc.mdx +0 -59
- package/src/components/organisms/drawer/drawer.stories.tsx +0 -40
- package/src/components/organisms/dropfile/dropfile.doc.mdx +0 -74
- package/src/components/organisms/dropfile/dropfile.stories.tsx +0 -93
- package/src/components/organisms/form-builder/formBuilder.doc.mdx +0 -251
- package/src/components/organisms/form-builder/formBuilder.stories.tsx +0 -914
- package/src/components/organisms/navbar/navbar.doc.mdx +0 -77
- package/src/components/organisms/navbar/navbar.stories.tsx +0 -83
- package/src/components/organisms/page-header/page-header.doc.mdx +0 -54
- package/src/components/organisms/page-header/page-header.stories.tsx +0 -74
- package/src/components/organisms/searchTable/searchTable.doc.mdx +0 -79
- package/src/components/organisms/searchTable/searchTable.stories.tsx +0 -73
- package/src/components/organisms/sidebar/sidebar.doc.mdx +0 -176
- package/src/components/organisms/sidebar/sidebar.stories.tsx +0 -234
- package/src/components/organisms/toast/toast.doc.mdx +0 -50
- package/src/components/organisms/toast/toast.stories.tsx +0 -137
- package/src/components/organisms/topbar/topbar.doc.mdx +0 -72
- package/src/components/organisms/topbar/topbar.stories.tsx +0 -79
- package/src/components/organisms/triple-filter/tripleFilter.doc.mdx +0 -62
- package/src/components/organisms/triple-filter/tripleFilter.stories.tsx +0 -31
- package/src/components/templates/layout/layout.doc.mdx +0 -53
- package/src/components/templates/layout/layout.stories.tsx +0 -113
- package/src/components/templates/page/page.doc.mdx +0 -86
- package/src/components/templates/page/page.stories.tsx +0 -97
- package/src/components/theme-provider/themeProvider.doc.mdx +0 -85
- package/src/components/theme-provider/themeProvider.stories.tsx +0 -58
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
-
import * as StoriesData from './table.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={StoriesData} />
|
|
5
|
-
|
|
6
|
-
# ITTable
|
|
7
|
-
|
|
8
|
-
Basic data table with column definitions, sorting, and configurable visual variants.
|
|
9
|
-
|
|
10
|
-
## Props
|
|
11
|
-
|
|
12
|
-
| Prop | Type | Default | Description |
|
|
13
|
-
|------|------|---------|-------------|
|
|
14
|
-
| `columns` | `Column<T>[]` | — | Column definitions: key, label, type, sortable, filter, render, actions, plus layout fields `width` (`number` px or CSS `string`), `minWidth` (px), `align` (`"left" \| "center" \| "right"`), `truncate` (ellipsis + native `title`), and `pinned` (`"left" \| "right"`). |
|
|
15
|
-
| `data` | `T[]` | `[]` | Row data array. |
|
|
16
|
-
| `variant` | `"default" \| "striped" \| "bordered"` | `"default"` | Visual style variant. |
|
|
17
|
-
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Font-size preset (does not change padding). |
|
|
18
|
-
| `containerClassName` | `string` | — | CSS classes for the outermost container. |
|
|
19
|
-
| `className` | `string` | — | Declared for API compatibility but **currently not applied** by ITTable. Use `containerClassName` for the outer wrapper. |
|
|
20
|
-
| `itemsPerPageOptions` | `number[]` | `[5, 10, 20]` | Page-size options shown in the paginator. |
|
|
21
|
-
| `defaultItemsPerPage` | `number` | `10` | Initial rows per page. |
|
|
22
|
-
| `title` | `string` | — | Optional heading rendered above the table. |
|
|
23
|
-
| `renderCard` | `(row: T) => ReactNode` | — | Custom card renderer for the cards view. |
|
|
24
|
-
| `defaultView` | `"table" \| "cards"` | `"table"` | Initial view mode. |
|
|
25
|
-
| `showVerticalBorder` | `boolean` | `true` | Show vertical borders between columns. |
|
|
26
|
-
| `verticalBorderClassname` | `string` | — | Custom class for the vertical borders. |
|
|
27
|
-
| `onRowClick` | `(row: T, event: MouseEvent<HTMLElement> \| KeyboardEvent<HTMLElement>) => void` | — | Row/card activation. `MouseEvent` for pointer, `KeyboardEvent` for Enter/Space. Skipped when the interaction starts inside an interactive child. |
|
|
28
|
-
| `layout` | `"auto" \| "fixed"` | `"auto"` | Table layout algorithm. `"fixed"` honors column `width` values and drops the `min-w-max` / `min-w-[150px]` floors so content no longer forces horizontal scrolling. |
|
|
29
|
-
| `density` | `"compact" \| "normal" \| "comfortable"` | `"normal"` | Cell padding / row-height preset. Independent of `size`, which only controls font-size. |
|
|
30
|
-
| `autoCardBreakpoint` | `number` | `0` | Container width (px) below which the table automatically falls back to the cards view. `0` disables the fallback. |
|
|
31
|
-
| `virtualized` | `boolean` | `false` | Renders only the visible row window with spacer rows preserving scroll height. Table view only; cards view is never virtualized. |
|
|
32
|
-
| `virtualizedMaxHeight` | `number` | `400` | Max height (px) of the virtualized scroll container. Only used when `virtualized` is true. |
|
|
33
|
-
| `rowHeight` | `number` | `getRowHeight(size, density)` | Assumed uniform row height (px). Size-aware: `size="md"` baseline is 33 / 45 / 53 for compact / normal / comfortable; `size` shifts it by the font-size line box (sm 16px / md 20px / lg 28px). |
|
|
34
|
-
| `overscan` | `number` | `5` | Extra rows rendered above and below the viewport to avoid blank gaps. |
|
|
35
|
-
| `stickyHeader` | `boolean` | `false` | Keeps header cells sticky while the virtualized body scrolls. Only effective when `virtualized` is true. |
|
|
36
|
-
| `showViewToggle` | `boolean` | `true` | Renders the Table\|Cards switcher in the toolbar. Hiding it does not disable `defaultView` or `autoCardBreakpoint`. |
|
|
37
|
-
| `colors` | `TableColors` | — | Per-instance color overrides (`headerBg`, `headerText`, `rowBg`, `rowText`, `rowHover`). Written as local `--color-table-*` variables, so they beat the global theme for this instance only. |
|
|
38
|
-
| `design` | `TableDesign` | — | Per-region overrides. Each region (`container`, `card`, `toolbar`, `header`, `headerCell`, `row`, `cell`, `cards`, `footer`) accepts `className` and `style`. |
|
|
39
|
-
| `containerStyle` | `CSSProperties` | — | Inline styles for the outermost wrapper. |
|
|
40
|
-
| `cardClassName` / `cardStyle` | `string` / `CSSProperties` | — | The rounded card surface that wraps toolbar, table and footer. |
|
|
41
|
-
| `toolbarClassName` / `toolbarStyle` | `string` / `CSSProperties` | — | The toolbar strip holding the title and/or the view toggle. |
|
|
42
|
-
| `headerClassName` / `headerStyle` | `string` / `CSSProperties` | — | The `<thead>` row. |
|
|
43
|
-
| `headerCellClassName` / `headerCellStyle` | `string` / `CSSProperties` | — | Every `<th>` header cell. |
|
|
44
|
-
| `rowClassName` / `rowStyle` | `string` / `CSSProperties` | — | Every body `<tr>`. |
|
|
45
|
-
| `cellClassName` / `cellStyle` | `string` / `CSSProperties` | — | Every body `<td>`. |
|
|
46
|
-
| `cardsClassName` / `cardsStyle` | `string` / `CSSProperties` | — | The cards-view scroll wrapper. |
|
|
47
|
-
| `footerClassName` / `footerStyle` | `string` / `CSSProperties` | — | The pagination footer strip. |
|
|
48
|
-
|
|
49
|
-
> When both `design.<region>` and its flat shortcut are passed, the flat shortcut wins.
|
|
50
|
-
|
|
51
|
-
### Column fields
|
|
52
|
-
|
|
53
|
-
| Field | Type | Default | Description |
|
|
54
|
-
|-------|------|---------|-------------|
|
|
55
|
-
| `width` | `number \| string` | — | Fixed column width. `number` = px, `string` = any CSS length (e.g. `"20%"`). A `<colgroup>` is only emitted when at least one column sets it. |
|
|
56
|
-
| `minWidth` | `number` | — | Minimum column width in px, applied to header and body cells via inline style. |
|
|
57
|
-
| `align` | `"left" \| "center" \| "right"` | `"left"` | Horizontal alignment of the column's header and cells. |
|
|
58
|
-
| `truncate` | `boolean` | `false` | Truncates overflowing cell content with an ellipsis and exposes the raw string/number via the native `title` attribute. |
|
|
59
|
-
| `pinned` | `"left" \| "right"` | `undefined` | Freezes the column to the given horizontal edge while the table scrolls sideways. `"left"` keeps it flush to the left edge, `"right"` to the right edge. Omit to leave the column unpinned (identical to the previous behavior). Offsets accumulate from each preceding pinned column's pixel `width` / `minWidth`, so give every pinned column of a side a pixel `width`. The pinned cell gets an opaque background (row background + row hover) and a 1px separator shadow on its frozen edge. One pinned column per side is the supported contract. |
|
|
60
|
-
| `headerClassName` / `headerStyle` | `string` / `CSSProperties` | — | Extra classes / inline styles for this column's `<th>` only (merged after `design.headerCell`). |
|
|
61
|
-
| `cellClassName` / `cellStyle` | `string` / `CSSProperties` | — | Extra classes / inline styles for this column's `<td>` only (merged after `design.cell`). |
|
|
62
|
-
| `filter` | `true \| "catalog" \| "search" \| "date" \| "date-range"` | `false` | Filter control rendered in the header. `true` = text/number input (or boolean toggle when `type: "boolean"`); `"catalog"` = `ITSelect` fed by `catalogOptions.data`; `"search"` = `ITSearchSelect` typeahead fed by `catalogOptions.data` (optional `catalogOptions.onSearch` for server-side search); `"date"` / `"date-range"` = `ITDatePicker` single/range, bounded by `dateFilterOptions`. |
|
|
63
|
-
|
|
64
|
-
## Usage
|
|
65
|
-
|
|
66
|
-
```tsx
|
|
67
|
-
import { ITTable } from '@axzydev/axzy_ui_system';
|
|
68
|
-
|
|
69
|
-
const columns = [
|
|
70
|
-
{ key: 'name', label: 'Name', type: 'string', sortable: true, filter: true },
|
|
71
|
-
{ key: 'role', label: 'Role', type: 'string', filter: 'catalog', catalogOptions: { data: roles } },
|
|
72
|
-
{ key: 'status', label: 'Status', type: 'boolean', filter: true },
|
|
73
|
-
];
|
|
74
|
-
const data = [
|
|
75
|
-
{ name: 'Alice', role: 'ADMIN', status: true },
|
|
76
|
-
{ name: 'Bob', role: 'EDITOR', status: false },
|
|
77
|
-
];
|
|
78
|
-
|
|
79
|
-
<ITTable columns={columns} data={data} title="Users" />
|
|
80
|
-
<ITTable columns={columns} data={data} variant="striped" size="sm" defaultItemsPerPage={5} />
|
|
81
|
-
<ITTable
|
|
82
|
-
columns={columns}
|
|
83
|
-
data={data}
|
|
84
|
-
defaultView="cards"
|
|
85
|
-
onRowClick={(row, event) => console.log(row, event.type)}
|
|
86
|
-
/>
|
|
87
|
-
|
|
88
|
-
// Filter modes: ITSearchSelect typeahead + ITDatePicker single / range
|
|
89
|
-
const filterColumns = [
|
|
90
|
-
{ key: 'role', label: 'Role', type: 'string', filter: 'search', catalogOptions: { data: roles } },
|
|
91
|
-
{ key: 'lastLogin', label: 'Last login', type: 'date', filter: 'date', dateFilterOptions: { maxDate: new Date() } },
|
|
92
|
-
{ key: 'hiredAt', label: 'Hired', type: 'date', filter: 'date-range', dateFilterOptions: { maxDate: new Date() } },
|
|
93
|
-
];
|
|
94
|
-
|
|
95
|
-
<ITTable columns={filterColumns} data={data} />
|
|
96
|
-
|
|
97
|
-
// No horizontal scroll: fixed layout + per-column widths + truncation
|
|
98
|
-
const fixedColumns = [
|
|
99
|
-
{ key: 'name', label: 'Name', type: 'string', width: '30%', truncate: true },
|
|
100
|
-
{ key: 'email', label: 'Email', type: 'string', width: 220, truncate: true },
|
|
101
|
-
{ key: 'role', label: 'Role', type: 'string', width: 140, align: 'center' },
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
<ITTable columns={fixedColumns} data={data} layout="fixed" density="compact" />
|
|
105
|
-
|
|
106
|
-
// Pinned columns: freeze the first column left and the last one right
|
|
107
|
-
const pinnedColumns = [
|
|
108
|
-
{ key: 'id', label: 'ID', type: 'number', width: 72, pinned: 'left' },
|
|
109
|
-
{ key: 'name', label: 'Name', type: 'string', width: 240, truncate: true },
|
|
110
|
-
{ key: 'actions', label: 'Actions', type: 'actions', width: 104, pinned: 'right' },
|
|
111
|
-
];
|
|
112
|
-
|
|
113
|
-
<ITTable columns={pinnedColumns} data={data} layout="fixed" density="compact" />
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## Notes
|
|
117
|
-
|
|
118
|
-
- `columns[].render` provides custom cell rendering via render function
|
|
119
|
-
- `columns[].sortable` enables column header sort toggles
|
|
120
|
-
- `columns[].filter` supports `true` (text/number input, or boolean toggle for `type: "boolean"`), `"catalog"` (`ITSelect`), `"search"` (`ITSearchSelect` typeahead; add `catalogOptions.onSearch` for server-side search), and `"date"` / `"date-range"` (`ITDatePicker`; bound with `dateFilterOptions: { minDate, maxDate }`). Filtering is client-side: `"date"` matches the whole day, `"date-range"` includes both ends (`startOfDay` / `endOfDay`).
|
|
121
|
-
- `onRowClick` fires in **both** the table and cards views. The event is a `MouseEvent` for pointer interaction and a `KeyboardEvent` for Enter/Space activation.
|
|
122
|
-
- Clicks/keys that start inside an interactive child (`button`, `a`, `input`, `select`, `textarea`, `[role="button"]`, `[role="link"]`, `[data-row-click-ignore]`) do **not** trigger `onRowClick`.
|
|
123
|
-
- When `onRowClick` is omitted no `cursor-pointer`, focus ring, `tabIndex`, or `role` is added.
|
|
124
|
-
- `density` controls padding/row height (`compact` 33px / `normal` 45px / `comfortable` 53px at `size="md"`); `size` changes font-size and shifts the row height by the line box (sm 16px / md 20px / lg 28px).
|
|
125
|
-
- **Anti horizontal scroll recipe:** `layout="fixed"` + a `width` on every column + `truncate` on long text + `density="compact"`. `width` accepts a `number` (px) or any CSS length string (`"20%"`, `"12rem"`). A `<colgroup>` is only emitted when at least one column defines a `width`.
|
|
126
|
-
- **Pinned columns:** set `columns[].pinned: "left" | "right"` to freeze a column to that edge during horizontal scroll (`position: sticky`; the wrapper needs no `relative`). Omitting `pinned` renders exactly as before. Sticky offsets accumulate from each preceding pinned column's pixel `width` / `minWidth`; a non-px width contributes `minWidth ?? 0`, so give every pinned column of a side a pixel `width`. The pinned cell gets an opaque background (`--color-table-rowBg`, row hover `--color-table-rowHover`) and a 1px separator shadow on its frozen edge. Z-layering: pinned body cell `z-[1]` < sticky header `z-10` < pinned header `z-[15]`; it composes with `stickyHeader` and `virtualized`. One pinned column per side is the supported contract. Known limitation: with `variant="striped"` the opaque pinned background covers that column's stripe tint.
|
|
127
|
-
- With the default `layout="auto"`, `min-w-max` stays active so column widths can still reflow as different cell content enters the window during vertical scroll. Use `layout="fixed"` + column `width` for stable widths.
|
|
128
|
-
- `autoCardBreakpoint` swaps to the cards view when the container (not the viewport) is narrower than the given px value; the Table toggle is disabled while forced, the Cards toggle stays enabled. It is measured in px in both directions.
|
|
129
|
-
- **Design props:** `design` (or the flat `<slot>ClassName` / `<slot>Style` shortcuts, which win when both are passed) styles `container`, `card`, `toolbar`, `header`, `headerCell`, `row`, `cell`, `cards` and `footer`; `columns[]` adds `headerClassName` / `cellClassName` (+ their `*Style`). `colors` writes local `--color-table-*` variables and overrides the global `ITThemeProvider` palette for that instance only. Because the theme pins its table colors with `!important` on `thead tr` / `tbody tr` / `th span` / `td div`, use `colors` (not `style`) to change colors, and `showViewToggle={false}` to hide the Table\|Cards switch.
|
|
130
|
-
- **Virtualization** applies to the **table view only** — the cards view is never virtualized. It only pays off with a large page size: raise `defaultItemsPerPage` and `itemsPerPageOptions` (defaults are `10` and `[5, 10, 20]`). Rows are assumed to have a uniform `rowHeight`; use `truncate` + `layout="fixed"` for predictable heights.
|
|
131
|
-
- Scroll resets to the top on page or items-per-page change, but **not** on filter change (known limitation). `aria-rowcount` reflects the current page (+1), not the whole dataset, because pagination is independent.
|
|
132
|
-
- `virtualizedMaxHeight`, `rowHeight`, `overscan`, and `stickyHeader` only take effect when `virtualized` is true. `stickyHeader` makes each `<th>` sticky using the `--color-table-headerBg` token (fallback `#f8fafc`).
|
|
133
|
-
- `TableDensity` is exported from the package. `ITSearchTable` does **not** support `layout`, `density`, `autoCardBreakpoint`, `virtualized`, or per-column `width` — do not assume parity.
|
|
134
|
-
- Three visual variants: default (no borders), striped (alternating rows), bordered (full grid)
|
|
135
|
-
|
|
136
|
-
## Stories
|
|
137
|
-
|
|
138
|
-
<Primary />
|
|
139
|
-
<Controls />
|
|
140
|
-
<Stories />
|
|
@@ -1,402 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
-
import ITTable from "@/components/molecules/table/table";
|
|
3
|
-
import { Column } from "./table.props";
|
|
4
|
-
import ITBadget from "@/components/atoms/badget/badget";
|
|
5
|
-
import ITButton from "@/components/atoms/button/button";
|
|
6
|
-
import { FaTrash } from "react-icons/fa";
|
|
7
|
-
import { useState } from "react";
|
|
8
|
-
|
|
9
|
-
const meta: Meta<typeof ITTable> = {
|
|
10
|
-
title: "Components/Data Display/ITTable",
|
|
11
|
-
component: ITTable,
|
|
12
|
-
parameters: {
|
|
13
|
-
layout: "padded", // Tables need more space
|
|
14
|
-
},
|
|
15
|
-
argTypes: {
|
|
16
|
-
variant: {
|
|
17
|
-
control: "select",
|
|
18
|
-
options: ["default", "striped", "bordered"],
|
|
19
|
-
},
|
|
20
|
-
size: {
|
|
21
|
-
control: "select",
|
|
22
|
-
options: ["sm", "md", "lg"],
|
|
23
|
-
},
|
|
24
|
-
density: {
|
|
25
|
-
control: "select",
|
|
26
|
-
options: ["compact", "normal", "comfortable"],
|
|
27
|
-
},
|
|
28
|
-
layout: {
|
|
29
|
-
control: "select",
|
|
30
|
-
options: ["auto", "fixed"],
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export default meta;
|
|
36
|
-
type Story = StoryObj<typeof ITTable>;
|
|
37
|
-
|
|
38
|
-
// --- MOCK DATA & COLUMNS ---
|
|
39
|
-
|
|
40
|
-
interface User {
|
|
41
|
-
id: number;
|
|
42
|
-
name: string;
|
|
43
|
-
email: string;
|
|
44
|
-
roleId: number;
|
|
45
|
-
balance: number;
|
|
46
|
-
isActive: boolean;
|
|
47
|
-
lastLogin: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const mockRoles = [
|
|
51
|
-
{ id: 1, name: "Administrator" },
|
|
52
|
-
{ id: 2, name: "Editor" },
|
|
53
|
-
{ id: 3, name: "Viewer" },
|
|
54
|
-
];
|
|
55
|
-
|
|
56
|
-
const generateMockData = (count: number): User[] => {
|
|
57
|
-
return Array.from({ length: count }, (_, i) => ({
|
|
58
|
-
id: i + 1,
|
|
59
|
-
name: `User ${i + 1}`,
|
|
60
|
-
email: `user${i + 1}@example.com`,
|
|
61
|
-
roleId: (i % 3) + 1,
|
|
62
|
-
balance: Math.random() * 10000,
|
|
63
|
-
isActive: i % 4 !== 0,
|
|
64
|
-
lastLogin: new Date(Date.now() - Math.random() * 10000000000).toISOString(),
|
|
65
|
-
}));
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const mockData = generateMockData(25);
|
|
69
|
-
|
|
70
|
-
const basicColumns: Column<User>[] = [
|
|
71
|
-
{ key: "id", label: "ID", type: "number" },
|
|
72
|
-
{ key: "name", label: "Name", type: "string" },
|
|
73
|
-
{ key: "email", label: "Email", type: "string" },
|
|
74
|
-
];
|
|
75
|
-
|
|
76
|
-
const advancedColumns: Column<User>[] = [
|
|
77
|
-
{ key: "id", label: "ID", type: "number", sortable: true, filter: true },
|
|
78
|
-
{ key: "name", label: "Name", type: "string", sortable: true, filter: true },
|
|
79
|
-
{ key: "email", label: "Email", type: "string", sortable: true, filter: true },
|
|
80
|
-
{
|
|
81
|
-
key: "roleId",
|
|
82
|
-
label: "Role",
|
|
83
|
-
type: "catalog",
|
|
84
|
-
sortable: true,
|
|
85
|
-
filter: "catalog",
|
|
86
|
-
catalogOptions: { data: mockRoles }
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
key: "balance",
|
|
90
|
-
label: "Balance",
|
|
91
|
-
type: "number",
|
|
92
|
-
sortable: true,
|
|
93
|
-
currencyMX: true
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
key: "isActive",
|
|
97
|
-
label: "Status",
|
|
98
|
-
type: "boolean",
|
|
99
|
-
sortable: true,
|
|
100
|
-
filter: true,
|
|
101
|
-
render: (row) => (
|
|
102
|
-
<ITBadget
|
|
103
|
-
label={row.isActive ? "Active" : "Inactive"}
|
|
104
|
-
color={row.isActive ? "success" : "danger"}
|
|
105
|
-
/>
|
|
106
|
-
)
|
|
107
|
-
},
|
|
108
|
-
];
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// --- STORIES ---
|
|
112
|
-
|
|
113
|
-
export const Default: Story = {
|
|
114
|
-
args: {
|
|
115
|
-
columns: basicColumns,
|
|
116
|
-
data: mockData.slice(0, 5), // Just a few
|
|
117
|
-
title: "Basic Users Table",
|
|
118
|
-
} as any,
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
export const WithPagination: Story = {
|
|
122
|
-
args: {
|
|
123
|
-
columns: basicColumns,
|
|
124
|
-
data: mockData,
|
|
125
|
-
title: "Paginated Table",
|
|
126
|
-
defaultItemsPerPage: 5,
|
|
127
|
-
itemsPerPageOptions: [5, 10, 20],
|
|
128
|
-
} as any,
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
export const WithSortingAndFiltering: Story = {
|
|
132
|
-
args: {
|
|
133
|
-
columns: advancedColumns.map(col => ({ ...col, render: undefined })), // Remove custom render to show raw formatting
|
|
134
|
-
data: mockData,
|
|
135
|
-
title: "Data Management (Sort & Filter)",
|
|
136
|
-
} as any,
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
export const CustomRendering: Story = {
|
|
140
|
-
args: {
|
|
141
|
-
columns: advancedColumns,
|
|
142
|
-
data: mockData,
|
|
143
|
-
title: "Custom Rendering (Badges & Catalogs)",
|
|
144
|
-
} as any,
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// Wrapper for interactive actions
|
|
148
|
-
const ActionsTableWrapper = (args: any) => {
|
|
149
|
-
const [data, setData] = useState(mockData.slice(0, 5));
|
|
150
|
-
|
|
151
|
-
const actions: Column<User> = {
|
|
152
|
-
key: "actions",
|
|
153
|
-
label: "Actions",
|
|
154
|
-
type: "actions",
|
|
155
|
-
actions: (row) => (
|
|
156
|
-
<>
|
|
157
|
-
<ITButton size="sm" variant="text" color="danger" ariaLabel="Delete" onClick={() => setData(d => d.filter(item => item.id !== row.id))}>
|
|
158
|
-
<FaTrash />
|
|
159
|
-
</ITButton>
|
|
160
|
-
</>
|
|
161
|
-
),
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
return <ITTable {...args} data={data} columns={[...basicColumns, actions]} />;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
export const WithActions: Story = {
|
|
168
|
-
render: (args) => <ActionsTableWrapper {...args} />,
|
|
169
|
-
args: {
|
|
170
|
-
title: "Table with Actions",
|
|
171
|
-
} as any,
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
export const EmptyState: Story = {
|
|
175
|
-
args: {
|
|
176
|
-
columns: basicColumns,
|
|
177
|
-
data: [],
|
|
178
|
-
title: "No Data Available",
|
|
179
|
-
} as any,
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
// Wrapper for clickable rows/cards
|
|
183
|
-
const RowClickWrapper = (args: any) => {
|
|
184
|
-
const [selected, setSelected] = useState<User | null>(null);
|
|
185
|
-
|
|
186
|
-
return (
|
|
187
|
-
<div className="space-y-3">
|
|
188
|
-
<p className="text-sm font-medium text-slate-500">
|
|
189
|
-
{selected
|
|
190
|
-
? `Selected: ${selected.name} (id ${selected.id})`
|
|
191
|
-
: "Click a row/card or press Enter/Space while focused"}
|
|
192
|
-
</p>
|
|
193
|
-
<ITTable
|
|
194
|
-
{...args}
|
|
195
|
-
onRowClick={(row: User) => setSelected(row)}
|
|
196
|
-
/>
|
|
197
|
-
</div>
|
|
198
|
-
);
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
export const WithRowClick: Story = {
|
|
202
|
-
render: (args) => <RowClickWrapper {...args} />,
|
|
203
|
-
args: {
|
|
204
|
-
columns: basicColumns,
|
|
205
|
-
data: mockData.slice(0, 5),
|
|
206
|
-
title: "Clickable Rows",
|
|
207
|
-
} as any,
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
export const WithRowClickCards: Story = {
|
|
211
|
-
render: (args) => <RowClickWrapper {...args} />,
|
|
212
|
-
args: {
|
|
213
|
-
columns: basicColumns,
|
|
214
|
-
data: mockData.slice(0, 5),
|
|
215
|
-
title: "Clickable Cards",
|
|
216
|
-
defaultView: "cards",
|
|
217
|
-
} as any,
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
// --- CONFIGURABLE LAYOUT / DENSITY ---
|
|
221
|
-
|
|
222
|
-
const longCellData: User[] = [
|
|
223
|
-
{
|
|
224
|
-
id: 1,
|
|
225
|
-
name: "Extraordinariamente Largo Nombre de Usuario Que No Cabe",
|
|
226
|
-
email: "usuario.con.un.correo.extremadamente.largo@example-enterprise-domain.com",
|
|
227
|
-
roleId: 1,
|
|
228
|
-
balance: 28400,
|
|
229
|
-
isActive: true,
|
|
230
|
-
lastLogin: "2026-07-18T09:30:00",
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
id: 2,
|
|
234
|
-
name: "Otra Persona Con Un Nombre Bastante Extenso Para Probar",
|
|
235
|
-
email: "otra.persona.con.correo.extenso@example-enterprise-domain.com",
|
|
236
|
-
roleId: 2,
|
|
237
|
-
balance: 15200,
|
|
238
|
-
isActive: false,
|
|
239
|
-
lastLogin: "2026-07-17T14:22:00",
|
|
240
|
-
},
|
|
241
|
-
];
|
|
242
|
-
|
|
243
|
-
const fixedColumns: Column<User>[] = [
|
|
244
|
-
{ key: "id", label: "ID", type: "number", width: 64, minWidth: 48, align: "center" },
|
|
245
|
-
{ key: "name", label: "Name", type: "string", width: "35%", truncate: true },
|
|
246
|
-
{ key: "email", label: "Email", type: "string", width: "45%", truncate: true },
|
|
247
|
-
];
|
|
248
|
-
|
|
249
|
-
export const CompactDensity: Story = {
|
|
250
|
-
args: {
|
|
251
|
-
columns: advancedColumns.map(col => ({ ...col, render: undefined })),
|
|
252
|
-
data: mockData,
|
|
253
|
-
title: "Compact Density",
|
|
254
|
-
density: "compact",
|
|
255
|
-
defaultItemsPerPage: 8,
|
|
256
|
-
} as any,
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
export const FixedLayoutWithWidths: Story = {
|
|
260
|
-
render: (args: any) => (
|
|
261
|
-
<div style={{ width: 480 }} className="rounded-lg border border-dashed border-slate-300">
|
|
262
|
-
<ITTable {...args} />
|
|
263
|
-
</div>
|
|
264
|
-
),
|
|
265
|
-
args: {
|
|
266
|
-
columns: fixedColumns,
|
|
267
|
-
data: longCellData,
|
|
268
|
-
title: "Fixed layout · no horizontal scroll",
|
|
269
|
-
layout: "fixed",
|
|
270
|
-
density: "compact",
|
|
271
|
-
defaultItemsPerPage: 5,
|
|
272
|
-
} as any,
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
// Pixel widths force the total past the 520px wrapper, so the ID (left) and
|
|
276
|
-
// Actions (right) columns stay frozen while the middle scrolls sideways.
|
|
277
|
-
const pinnedColumns: Column<User>[] = [
|
|
278
|
-
{ key: "id", label: "ID", type: "number", width: 72, minWidth: 56, align: "center", pinned: "left" },
|
|
279
|
-
{ key: "name", label: "Name", type: "string", width: 240, truncate: true },
|
|
280
|
-
{ key: "email", label: "Email", type: "string", width: 280, truncate: true },
|
|
281
|
-
{ key: "balance", label: "Balance", type: "number", width: 160, currencyMX: true },
|
|
282
|
-
{ key: "lastLogin", label: "Last login", type: "string", width: 160, truncate: true },
|
|
283
|
-
{
|
|
284
|
-
key: "isActive",
|
|
285
|
-
label: "Status",
|
|
286
|
-
type: "boolean",
|
|
287
|
-
width: 104,
|
|
288
|
-
align: "center",
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
key: "actions",
|
|
292
|
-
label: "Actions",
|
|
293
|
-
type: "actions",
|
|
294
|
-
width: 104,
|
|
295
|
-
pinned: "right",
|
|
296
|
-
actions: () => (
|
|
297
|
-
<ITButton size="sm" variant="text" color="danger" ariaLabel="Delete">
|
|
298
|
-
<FaTrash />
|
|
299
|
-
</ITButton>
|
|
300
|
-
),
|
|
301
|
-
},
|
|
302
|
-
];
|
|
303
|
-
|
|
304
|
-
export const PinnedColumns: Story = {
|
|
305
|
-
render: (args: any) => (
|
|
306
|
-
<div style={{ width: 520 }} className="rounded-lg border border-dashed border-slate-300">
|
|
307
|
-
<ITTable {...args} />
|
|
308
|
-
</div>
|
|
309
|
-
),
|
|
310
|
-
args: {
|
|
311
|
-
columns: pinnedColumns,
|
|
312
|
-
data: mockData.slice(0, 6),
|
|
313
|
-
title: "Pinned left (ID) & right (Actions)",
|
|
314
|
-
layout: "fixed",
|
|
315
|
-
density: "compact",
|
|
316
|
-
defaultItemsPerPage: 6,
|
|
317
|
-
} as any,
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
export const AutoCardsNarrowContainer: Story = {
|
|
321
|
-
render: (args: any) => (
|
|
322
|
-
<div style={{ width: 420 }} className="rounded-lg border border-dashed border-slate-300">
|
|
323
|
-
<ITTable {...args} />
|
|
324
|
-
</div>
|
|
325
|
-
),
|
|
326
|
-
args: {
|
|
327
|
-
columns: basicColumns,
|
|
328
|
-
data: mockData.slice(0, 6),
|
|
329
|
-
title: "Auto cards under 640px",
|
|
330
|
-
autoCardBreakpoint: 640,
|
|
331
|
-
defaultItemsPerPage: 6,
|
|
332
|
-
} as any,
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
// --- VIRTUALIZATION ---
|
|
336
|
-
|
|
337
|
-
const virtualColumns: Column<User>[] = [
|
|
338
|
-
{ key: "id", label: "ID", type: "number", width: 72, minWidth: 56, align: "center" },
|
|
339
|
-
{ key: "name", label: "Name", type: "string", width: "30%", truncate: true },
|
|
340
|
-
{ key: "email", label: "Email", type: "string", width: "40%", truncate: true },
|
|
341
|
-
{
|
|
342
|
-
key: "roleId",
|
|
343
|
-
label: "Role",
|
|
344
|
-
type: "catalog",
|
|
345
|
-
width: "30%",
|
|
346
|
-
truncate: true,
|
|
347
|
-
catalogOptions: { data: mockRoles },
|
|
348
|
-
},
|
|
349
|
-
];
|
|
350
|
-
|
|
351
|
-
export const VirtualizedLargeDataset: Story = {
|
|
352
|
-
render: (args: any) => (
|
|
353
|
-
<div className="space-y-2">
|
|
354
|
-
<p className="text-xs text-slate-500">
|
|
355
|
-
250 rows · only the visible window is mounted (~10–20 <tr> + at most 2 spacer rows)
|
|
356
|
-
</p>
|
|
357
|
-
<ITTable {...args} />
|
|
358
|
-
</div>
|
|
359
|
-
),
|
|
360
|
-
args: {
|
|
361
|
-
columns: virtualColumns,
|
|
362
|
-
data: generateMockData(250),
|
|
363
|
-
title: "Virtualized · 250 rows",
|
|
364
|
-
virtualized: true,
|
|
365
|
-
stickyHeader: true,
|
|
366
|
-
layout: "fixed",
|
|
367
|
-
density: "compact",
|
|
368
|
-
virtualizedMaxHeight: 360,
|
|
369
|
-
defaultItemsPerPage: 250,
|
|
370
|
-
itemsPerPageOptions: [50, 100, 250],
|
|
371
|
-
} as any,
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
// --- COLUMN FILTER MODES ---
|
|
375
|
-
|
|
376
|
-
const filterModeColumns: Column<User>[] = [
|
|
377
|
-
{ key: "name", label: "Name", type: "string", filter: true },
|
|
378
|
-
{
|
|
379
|
-
key: "roleId",
|
|
380
|
-
label: "Role (ITSearchSelect)",
|
|
381
|
-
type: "catalog",
|
|
382
|
-
filter: "search",
|
|
383
|
-
catalogOptions: { data: mockRoles },
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
key: "lastLogin",
|
|
387
|
-
label: "Last login (ITDatePicker range)",
|
|
388
|
-
type: "date",
|
|
389
|
-
filter: "date-range",
|
|
390
|
-
dateFilterOptions: { maxDate: new Date() },
|
|
391
|
-
render: (row) => new Date(row.lastLogin).toLocaleDateString("es-MX"),
|
|
392
|
-
},
|
|
393
|
-
];
|
|
394
|
-
|
|
395
|
-
export const WithSearchAndDateFilters: Story = {
|
|
396
|
-
args: {
|
|
397
|
-
columns: filterModeColumns,
|
|
398
|
-
data: generateMockData(25),
|
|
399
|
-
title: "Filtros: ITSearchSelect + ITDatePicker (rango)",
|
|
400
|
-
defaultItemsPerPage: 8,
|
|
401
|
-
} as any,
|
|
402
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
-
import * as StoriesData from './tabs.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={StoriesData} />
|
|
5
|
-
|
|
6
|
-
# ITTabs
|
|
7
|
-
|
|
8
|
-
Tab navigation component with multiple visual variants, orientation options, and color themes.
|
|
9
|
-
|
|
10
|
-
## Props
|
|
11
|
-
|
|
12
|
-
| Prop | Type | Default | Description |
|
|
13
|
-
|------|------|---------|-------------|
|
|
14
|
-
| `tabs` | `{ label: string; icon?: ReactNode; disabled?: boolean }[]` | — | Tab definitions |
|
|
15
|
-
| `activeTab` | `number` | `0` | Zero-indexed active tab |
|
|
16
|
-
| `onChange` | `(index: number) => void` | — | Tab change handler |
|
|
17
|
-
| `variant` | `'default' \| 'pills' \| 'underline' \| 'enclosed'` | `'default'` | Visual style variant |
|
|
18
|
-
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Tab layout orientation |
|
|
19
|
-
| `fullWidth` | `boolean` | `false` | Stretch tabs to fill container |
|
|
20
|
-
| `color` | `'primary' \| 'secondary' \| 'success' \| 'warning' \| 'danger' \| 'info' \| 'neutral'` | `'primary'` | Color theme |
|
|
21
|
-
|
|
22
|
-
## Usage
|
|
23
|
-
|
|
24
|
-
```tsx
|
|
25
|
-
import { ITTabs } from '@axzydev/axzy_ui_system';
|
|
26
|
-
|
|
27
|
-
const tabs = [
|
|
28
|
-
{ label: 'General' },
|
|
29
|
-
{ label: 'Security', icon: <LockIcon /> },
|
|
30
|
-
{ label: 'Billing', disabled: true },
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
<ITTabs tabs={tabs} activeTab={0} onChange={(i) => console.log(i)} />
|
|
34
|
-
<ITTabs tabs={tabs} variant="pills" fullWidth />
|
|
35
|
-
<ITTabs tabs={tabs} variant="underline" orientation="vertical" color="success" />
|
|
36
|
-
<ITTabs tabs={tabs} variant="enclosed" />
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Notes
|
|
40
|
-
|
|
41
|
-
- Four visual variants: default, pills, underline, enclosed
|
|
42
|
-
- Horizontal or vertical tab layout
|
|
43
|
-
- `fullWidth` makes tabs span the full container width
|
|
44
|
-
- Icons rendered alongside tab labels via the `icon` prop
|
|
45
|
-
- Individual tabs can be disabled
|
|
46
|
-
- Seven color themes available
|
|
47
|
-
|
|
48
|
-
## Stories
|
|
49
|
-
|
|
50
|
-
<Primary />
|
|
51
|
-
<Controls />
|
|
52
|
-
<Stories />
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import ITTabs from '@/components/molecules/tabs/tabs';
|
|
3
|
-
|
|
4
|
-
const meta: Meta<typeof ITTabs> = {
|
|
5
|
-
title: 'Components/ITTabs',
|
|
6
|
-
component: ITTabs,
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export default meta;
|
|
10
|
-
type Story = StoryObj<typeof ITTabs>;
|
|
11
|
-
|
|
12
|
-
export const Line: Story = {
|
|
13
|
-
args: {
|
|
14
|
-
variant: 'line',
|
|
15
|
-
items: [
|
|
16
|
-
{ id: '1', label: 'Tab 1', content: <div className="p-4">Content 1</div> },
|
|
17
|
-
{ id: '2', label: 'Tab 2', content: <div className="p-4">Content 2</div> },
|
|
18
|
-
{ id: '3', label: 'Disabled', content: <div>X</div>, disabled: true },
|
|
19
|
-
],
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export const Pill: Story = {
|
|
24
|
-
args: {
|
|
25
|
-
variant: 'pill',
|
|
26
|
-
items: [
|
|
27
|
-
{ id: '1', label: 'Overview', content: <div className="p-4">Dashboard Overview</div> },
|
|
28
|
-
{ id: '2', label: 'Settings', content: <div className="p-4">Account Settings</div> },
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
};
|