@nccirtu/tablefy 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7327,12 +7327,12 @@ var DropdownMenuItemIndicator = React__namespace.forwardRef((props, forwardedRef
7327
7327
  });
7328
7328
  DropdownMenuItemIndicator.displayName = INDICATOR_NAME$1;
7329
7329
  var SEPARATOR_NAME$1 = "DropdownMenuSeparator";
7330
- var DropdownMenuSeparator = React__namespace.forwardRef((props, forwardedRef) => {
7330
+ var DropdownMenuSeparator$1 = React__namespace.forwardRef((props, forwardedRef) => {
7331
7331
  const { __scopeDropdownMenu, ...separatorProps } = props;
7332
7332
  const menuScope = useMenuScope(__scopeDropdownMenu);
7333
7333
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Separator, { ...menuScope, ...separatorProps, ref: forwardedRef });
7334
7334
  });
7335
- DropdownMenuSeparator.displayName = SEPARATOR_NAME$1;
7335
+ DropdownMenuSeparator$1.displayName = SEPARATOR_NAME$1;
7336
7336
  var ARROW_NAME$2 = "DropdownMenuArrow";
7337
7337
  var DropdownMenuArrow = React__namespace.forwardRef(
7338
7338
  (props, forwardedRef) => {
@@ -7379,6 +7379,7 @@ var Trigger$2 = DropdownMenuTrigger$1;
7379
7379
  var Portal2 = DropdownMenuPortal;
7380
7380
  var Content2$2 = DropdownMenuContent$1;
7381
7381
  var Item2 = DropdownMenuItem$1;
7382
+ var Separator2 = DropdownMenuSeparator$1;
7382
7383
 
7383
7384
  // packages/core/number/src/number.ts
7384
7385
  function clamp(value, [min, max]) {
@@ -9123,6 +9124,9 @@ function DropdownMenuContent({ className, align = "start", sideOffset = 4, ...pr
9123
9124
  function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
9124
9125
  return (jsxRuntimeExports.jsx(Item2, { "data-slot": "dropdown-menu-item", "data-inset": inset, "data-variant": variant, className: className, ...props }));
9125
9126
  }
9127
+ function DropdownMenuSeparator({ className, ...props }) {
9128
+ return (jsxRuntimeExports.jsx(Separator2, { "data-slot": "dropdown-menu-separator", className: className, ...props }));
9129
+ }
9126
9130
 
9127
9131
  function DataTableHeader({ title, description, actions = [], search, searchValue = "", onSearchChange, table, selectedCount = 0, className, }) {
9128
9132
  // Actions aufteilen in normale und Bulk-Actions
@@ -10044,6 +10048,68 @@ class IconColumn extends BaseColumn {
10044
10048
  }
10045
10049
  }
10046
10050
 
10051
+ class ImageColumn extends BaseColumn {
10052
+ constructor(accessor) {
10053
+ super(accessor);
10054
+ this.config.size = 'md';
10055
+ this.config.rounded = 'md';
10056
+ }
10057
+ static make(accessor) {
10058
+ return new ImageColumn(accessor);
10059
+ }
10060
+ size(size) {
10061
+ this.config.size = size;
10062
+ return this;
10063
+ }
10064
+ rounded(rounded) {
10065
+ this.config.rounded = rounded;
10066
+ return this;
10067
+ }
10068
+ circular() {
10069
+ return this.rounded('full');
10070
+ }
10071
+ square() {
10072
+ return this.rounded('none');
10073
+ }
10074
+ fallback(url) {
10075
+ this.config.fallback = url;
10076
+ return this;
10077
+ }
10078
+ alt(fn) {
10079
+ this.config.alt = fn;
10080
+ return this;
10081
+ }
10082
+ build() {
10083
+ const config = this.config;
10084
+ const { accessor, label, size, rounded, fallback, alt } = config;
10085
+ const sizeClasses = {
10086
+ sm: 'h-8 w-8',
10087
+ md: 'h-10 w-10',
10088
+ lg: 'h-12 w-12',
10089
+ };
10090
+ const roundedClasses = {
10091
+ none: 'rounded-none',
10092
+ sm: 'rounded-sm',
10093
+ md: 'rounded-md',
10094
+ lg: 'rounded-lg',
10095
+ full: 'rounded-full',
10096
+ };
10097
+ return {
10098
+ accessorKey: accessor,
10099
+ header: () => jsxRuntimeExports.jsx("span", { className: cn('text-muted-foreground font-medium', this.config.headerClassName), children: label || '' }),
10100
+ cell: ({ getValue, row }) => {
10101
+ const src = getValue();
10102
+ const altText = alt ? alt(row.original) : 'Bild';
10103
+ return (jsxRuntimeExports.jsx("img", { src: src || fallback || '/placeholder.png', alt: altText, className: cn('object-cover', sizeClasses[size || 'md'], roundedClasses[rounded || 'md'], this.config.cellClassName), onError: (e) => {
10104
+ if (fallback) {
10105
+ e.target.src = fallback;
10106
+ }
10107
+ } }));
10108
+ },
10109
+ };
10110
+ }
10111
+ }
10112
+
10047
10113
  const InputColumn = (config) => {
10048
10114
  const accessorKey = config.accessorKey || "input";
10049
10115
  return {
@@ -10056,6 +10122,182 @@ const InputColumn = (config) => {
10056
10122
  };
10057
10123
  };
10058
10124
 
10125
+ class LinkColumn extends BaseColumn {
10126
+ constructor(accessor) {
10127
+ super(accessor);
10128
+ const config = this.config;
10129
+ config.external = false;
10130
+ config.showExternalIcon = false;
10131
+ config.underline = 'hover';
10132
+ config.openInNewTab = false;
10133
+ }
10134
+ static make(accessor) {
10135
+ return new LinkColumn(accessor);
10136
+ }
10137
+ // URL setzen (statisch oder dynamisch)
10138
+ href(href) {
10139
+ this.config.href = href;
10140
+ return this;
10141
+ }
10142
+ // URL aus einem anderen Feld nehmen
10143
+ urlFromField(field) {
10144
+ this.config.href = (row) => String(row[field]);
10145
+ return this;
10146
+ }
10147
+ // Externer Link (zeigt Icon)
10148
+ external(external = true) {
10149
+ const config = this.config;
10150
+ config.external = external;
10151
+ config.showExternalIcon = external;
10152
+ config.openInNewTab = external;
10153
+ return this;
10154
+ }
10155
+ // Icon vor dem Text
10156
+ icon(icon) {
10157
+ this.config.icon = icon;
10158
+ return this;
10159
+ }
10160
+ // External-Icon anzeigen
10161
+ showExternalIcon(show = true) {
10162
+ this.config.showExternalIcon = show;
10163
+ return this;
10164
+ }
10165
+ // Unterstreichung
10166
+ underline(style) {
10167
+ this.config.underline = style;
10168
+ return this;
10169
+ }
10170
+ // In neuem Tab öffnen
10171
+ openInNewTab(open = true) {
10172
+ this.config.openInNewTab = open;
10173
+ return this;
10174
+ }
10175
+ // Click-Handler (für programmatische Navigation)
10176
+ onClick(handler) {
10177
+ this.config.onClick = handler;
10178
+ return this;
10179
+ }
10180
+ build() {
10181
+ const config = this.config;
10182
+ const { accessor, label, sortable, href, icon, showExternalIcon, underline, openInNewTab, onClick } = config;
10183
+ const underlineClasses = {
10184
+ always: 'underline',
10185
+ hover: 'hover:underline',
10186
+ never: 'no-underline',
10187
+ };
10188
+ return {
10189
+ accessorKey: accessor,
10190
+ header: ({ column }) => {
10191
+ const displayLabel = label || String(accessor);
10192
+ if (!sortable) {
10193
+ return (jsxRuntimeExports.jsx("span", { className: cn('text-muted-foreground font-medium', this.getAlignmentClass(), this.config.headerClassName), children: displayLabel }));
10194
+ }
10195
+ return (jsxRuntimeExports.jsxs(Button, { variant: "table_header", size: "table_header", onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), className: cn('text-muted-foreground font-medium', this.getAlignmentClass(), this.config.headerClassName), children: [displayLabel, jsxRuntimeExports.jsx(lucideReact.ArrowUpDown, { className: "ml-2 h-4 w-4" })] }));
10196
+ },
10197
+ cell: ({ getValue, row }) => {
10198
+ const value = getValue();
10199
+ if (!value) {
10200
+ return jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: "\u2014" });
10201
+ }
10202
+ // URL berechnen
10203
+ const url = typeof href === 'function' ? href(row.original) : href || value;
10204
+ const handleClick = (e) => {
10205
+ if (onClick) {
10206
+ e.preventDefault();
10207
+ onClick(row.original);
10208
+ }
10209
+ };
10210
+ // Alignment ohne text-muted-foreground für Links
10211
+ const alignmentClass = this.config.align === 'center' ? 'text-center' : this.config.align === 'right' ? 'text-right' : 'text-left';
10212
+ return (jsxRuntimeExports.jsxs("a", { href: url, target: openInNewTab ? '_blank' : undefined, rel: openInNewTab ? 'noopener noreferrer' : undefined, onClick: onClick ? handleClick : undefined, className: cn('inline-flex items-center gap-1.5 text-sm text-blue-500', underlineClasses[underline || 'hover'], 'hover:text-blue-500/80', alignmentClass, this.config.cellClassName), children: [icon, jsxRuntimeExports.jsx("span", { children: value }), showExternalIcon && jsxRuntimeExports.jsx(lucideReact.ExternalLink, { className: "text-muted-foreground h-3 w-3" })] }));
10213
+ },
10214
+ };
10215
+ }
10216
+ }
10217
+
10218
+ class NumberColumn extends BaseColumn {
10219
+ constructor(accessor) {
10220
+ super(accessor);
10221
+ this.config.align = 'right'; // Zahlen standardmäßig rechtsbündig
10222
+ this.config.decimals = 0;
10223
+ this.config.locale = 'de-DE';
10224
+ }
10225
+ static make(accessor) {
10226
+ return new NumberColumn(accessor);
10227
+ }
10228
+ decimals(decimals) {
10229
+ this.config.decimals = decimals;
10230
+ return this;
10231
+ }
10232
+ locale(locale) {
10233
+ this.config.locale = locale;
10234
+ return this;
10235
+ }
10236
+ // Währungsformatierung
10237
+ money(currency = 'EUR') {
10238
+ this.config.currency = currency;
10239
+ this.config.decimals = 2;
10240
+ return this;
10241
+ }
10242
+ // Prozentformatierung
10243
+ percent() {
10244
+ this.config.percent = true;
10245
+ return this;
10246
+ }
10247
+ prefix(prefix) {
10248
+ this.config.prefix = prefix;
10249
+ return this;
10250
+ }
10251
+ suffix(suffix) {
10252
+ this.config.suffix = suffix;
10253
+ return this;
10254
+ }
10255
+ build() {
10256
+ const config = this.config;
10257
+ const { accessor, label, sortable, decimals, locale, currency, percent, prefix, suffix } = config;
10258
+ return {
10259
+ accessorKey: accessor,
10260
+ header: ({ column }) => {
10261
+ const displayLabel = label || String(accessor);
10262
+ if (!sortable) {
10263
+ return (jsxRuntimeExports.jsx("span", { className: cn('text-muted-foreground font-medium', this.getAlignmentClass(), this.config.headerClassName), children: displayLabel }));
10264
+ }
10265
+ return (jsxRuntimeExports.jsxs(Button, { variant: "table_header", size: "table_header", onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), className: cn('text-muted-foreground font-medium', this.getAlignmentClass(), this.config.headerClassName), children: [displayLabel, jsxRuntimeExports.jsx(lucideReact.ArrowUpDown, { className: "ml-2 h-4 w-4" })] }));
10266
+ },
10267
+ cell: ({ getValue }) => {
10268
+ const value = getValue();
10269
+ if (value === null || value === undefined) {
10270
+ return jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: "\u2014" });
10271
+ }
10272
+ let formatted;
10273
+ if (currency) {
10274
+ formatted = new Intl.NumberFormat(locale, {
10275
+ style: 'currency',
10276
+ currency,
10277
+ minimumFractionDigits: decimals,
10278
+ maximumFractionDigits: decimals,
10279
+ }).format(value);
10280
+ }
10281
+ else if (percent) {
10282
+ formatted = new Intl.NumberFormat(locale, {
10283
+ style: 'percent',
10284
+ minimumFractionDigits: decimals,
10285
+ maximumFractionDigits: decimals,
10286
+ }).format(value / 100);
10287
+ }
10288
+ else {
10289
+ formatted = new Intl.NumberFormat(locale, {
10290
+ minimumFractionDigits: decimals,
10291
+ maximumFractionDigits: decimals,
10292
+ }).format(value);
10293
+ }
10294
+ const displayValue = `${prefix || ''}${formatted}${suffix || ''}`;
10295
+ return jsxRuntimeExports.jsx("span", { className: cn('tabular-nums', this.getAlignmentClass(), this.config.cellClassName), children: displayValue });
10296
+ },
10297
+ };
10298
+ }
10299
+ }
10300
+
10059
10301
  function Progress({ className, value, ...props }) {
10060
10302
  return (jsxRuntimeExports.jsx(Root, { "data-slot": "progress", className: className, ...props, children: jsxRuntimeExports.jsx(Indicator, { "data-slot": "progress-indicator", className: "bg-primary size-full flex-1 transition-all", style: { transform: `translateX(-${100 - (value || 0)}%)` } }) }));
10061
10303
  }
@@ -10276,10 +10518,93 @@ class TextColumn extends BaseColumn {
10276
10518
  }
10277
10519
  }
10278
10520
 
10521
+ class ActionsColumn {
10522
+ config = {
10523
+ actions: [],
10524
+ label: 'Aktionen',
10525
+ };
10526
+ static make() {
10527
+ return new ActionsColumn();
10528
+ }
10529
+ label(label) {
10530
+ this.config.label = label;
10531
+ return this;
10532
+ }
10533
+ triggerIcon(icon) {
10534
+ this.config.triggerIcon = icon;
10535
+ return this;
10536
+ }
10537
+ // Action hinzufügen
10538
+ action(action) {
10539
+ this.config.actions.push(action);
10540
+ return this;
10541
+ }
10542
+ // Shortcuts für gängige Actions
10543
+ view(onClick) {
10544
+ return this.action({ label: 'Anzeigen', onClick });
10545
+ }
10546
+ edit(onClick) {
10547
+ return this.action({ label: 'Bearbeiten', onClick });
10548
+ }
10549
+ delete(onClick) {
10550
+ return this.action({
10551
+ label: 'Löschen',
10552
+ onClick,
10553
+ variant: 'destructive',
10554
+ separator: true,
10555
+ });
10556
+ }
10557
+ link(label, href) {
10558
+ return this.action({ label, href });
10559
+ }
10560
+ separator() {
10561
+ if (this.config.actions.length > 0) {
10562
+ this.config.actions[this.config.actions.length - 1].separator = true;
10563
+ }
10564
+ return this;
10565
+ }
10566
+ build() {
10567
+ const { actions, label, triggerIcon } = this.config;
10568
+ return {
10569
+ id: 'actions',
10570
+ header: () => jsxRuntimeExports.jsx("span", { className: "sr-only", children: label }),
10571
+ cell: ({ row }) => {
10572
+ const data = row.original;
10573
+ const visibleActions = actions.filter((action) => !action.hidden || !action.hidden(data));
10574
+ if (visibleActions.length === 0)
10575
+ return null;
10576
+ return (jsxRuntimeExports.jsxs(DropdownMenu, { children: [jsxRuntimeExports.jsx(DropdownMenuTrigger, { asChild: true, children: jsxRuntimeExports.jsxs(Button, { variant: "ghost", className: "h-10 w-10 p-0", children: [jsxRuntimeExports.jsx("span", { className: "sr-only", children: label }), triggerIcon || jsxRuntimeExports.jsx(lucideReact.MoreHorizontal, { className: "h-8 w-8" })] }) }), jsxRuntimeExports.jsx(DropdownMenuContent, { align: "end", children: visibleActions.map((action, index) => (jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsxs(DropdownMenuItem, { disabled: action.disabled?.(data), className: cn(action.variant === 'destructive' && 'text-destructive focus:text-destructive'), onClick: () => {
10577
+ if (action.href) {
10578
+ window.location.href = action.href(data);
10579
+ }
10580
+ else if (action.onClick) {
10581
+ action.onClick(data);
10582
+ }
10583
+ }, children: [action.icon && jsxRuntimeExports.jsx("span", { className: "mr-2", children: action.icon }), action.label] }), action.separator && index < visibleActions.length - 1 && jsxRuntimeExports.jsx(DropdownMenuSeparator, {})] }, index))) })] }));
10584
+ },
10585
+ };
10586
+ }
10587
+ }
10588
+
10589
+ exports.ActionsColumn = ActionsColumn;
10590
+ exports.AvatarGroupColumn = AvatarGroupColumn;
10591
+ exports.BadgeColumn = BadgeColumn;
10592
+ exports.ButtonColumn = ButtonColumn;
10593
+ exports.CheckboxColumn = CheckboxColumn;
10279
10594
  exports.DataTable = DataTable;
10280
10595
  exports.DataTableSchema = DataTableSchema;
10596
+ exports.DateColumn = DateColumn;
10597
+ exports.DropdownColumn = DropdownColumn;
10281
10598
  exports.EmptyStateBuilder = EmptyStateBuilder;
10599
+ exports.IconColumn = IconColumn;
10600
+ exports.ImageColumn = ImageColumn;
10601
+ exports.InputColumn = InputColumn;
10602
+ exports.LinkColumn = LinkColumn;
10603
+ exports.NumberColumn = NumberColumn;
10604
+ exports.ProgressColumn = ProgressColumn;
10605
+ exports.SelectColumn = SelectColumn;
10282
10606
  exports.TableSchema = TableSchema;
10607
+ exports.TextColumn = TextColumn;
10283
10608
  exports.avatarGroupColumn = AvatarGroupColumn;
10284
10609
  exports.badgeColumn = BadgeColumn;
10285
10610
  exports.buttonColumn = ButtonColumn;