@eml-payments/ui-kit 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/index.css +2 -2
  2. package/dist/src/components/Button/ButtonVariants.d.ts +1 -1
  3. package/dist/src/components/Button/ButtonVariants.js +1 -0
  4. package/dist/src/components/Combobox/Combobox.d.ts +28 -0
  5. package/dist/src/components/Combobox/Combobox.js +58 -0
  6. package/dist/src/components/Combobox/Combobox.stories.d.ts +12 -0
  7. package/dist/src/components/Combobox/Combobox.stories.js +86 -0
  8. package/dist/src/components/Combobox/index.d.ts +1 -0
  9. package/dist/src/components/Combobox/index.js +1 -0
  10. package/dist/src/components/Input/Input.js +12 -8
  11. package/dist/src/components/Input/Input.stories.d.ts +3 -2
  12. package/dist/src/components/Input/Input.stories.js +9 -2
  13. package/dist/src/components/InputGroup/InputGroup.d.ts +16 -0
  14. package/dist/src/components/InputGroup/InputGroup.js +58 -0
  15. package/dist/src/components/InputGroup/InputGroup.stories.d.ts +19 -0
  16. package/dist/src/components/InputGroup/InputGroup.stories.js +62 -0
  17. package/dist/src/components/InputGroup/index.d.ts +1 -0
  18. package/dist/src/components/InputGroup/index.js +1 -0
  19. package/dist/src/components/Select/Select.js +1 -1
  20. package/dist/src/components/Stepper/Stepper.js +1 -1
  21. package/dist/src/components/Table/StandardTable/StandardTable.stories.js +5 -1
  22. package/dist/src/components/Table/hooks/useInfiniteScrolling.js +1 -0
  23. package/dist/src/components/Table/hooks/useTableController.js +4 -14
  24. package/dist/src/components/Textarea/Textarea.js +12 -7
  25. package/dist/src/components/Textarea/Textarea.stories.d.ts +2 -1
  26. package/dist/src/components/Textarea/Textarea.stories.js +6 -2
  27. package/dist/src/components/index.d.ts +2 -0
  28. package/dist/src/components/index.js +2 -0
  29. package/package.json +11 -5
  30. package/dist/index.d.cts +0 -488
  31. package/dist/index.d.ts +0 -488
  32. package/dist/src/components/Table/BaseTable/index.d.ts +0 -1
  33. package/dist/src/components/Table/BaseTable/index.js +0 -1
@@ -21,7 +21,7 @@ const ControlledLengthIndicator = (args) => {
21
21
  export const Text = {
22
22
  args: { type: 'text', placeholder: 'Enter text...' },
23
23
  };
24
- export const Number = {
24
+ export const NumberInput = {
25
25
  args: { type: 'number', placeholder: 'Enter number...' },
26
26
  };
27
27
  export const WithValue = {
@@ -36,9 +36,16 @@ export const PasswordInput = {
36
36
  export const WithHelperText = {
37
37
  args: { helperText: 'This is a helper text', placeholder: 'Enter text...' },
38
38
  };
39
- export const WithTextLengthIndicator = {
39
+ export const WithControlledLengthIndicator = {
40
40
  render: (args) => _jsx(ControlledLengthIndicator, { ...args }),
41
41
  };
42
+ export const WithMaxLengthIndicator = {
43
+ args: {
44
+ maxLength: 50,
45
+ helperText: 'This is a helper text',
46
+ placeholder: 'Type here to see counter...',
47
+ },
48
+ };
42
49
  export const Disabled = {
43
50
  args: { disabled: true, placeholder: 'Disabled input' },
44
51
  };
@@ -0,0 +1,16 @@
1
+ import * as React from 'react';
2
+ import { type VariantProps } from 'class-variance-authority';
3
+ import { Button } from '../../components/Button';
4
+ declare function InputGroup({ className, ...props }: React.ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
5
+ declare const inputGroupAddonVariants: (props?: ({
6
+ align?: "block-end" | "block-start" | "inline-end" | "inline-start" | null | undefined;
7
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
+ declare function InputGroupAddon({ className, align, ...props }: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>): import("react/jsx-runtime").JSX.Element;
9
+ declare const inputGroupButtonVariants: (props?: ({
10
+ size?: "sm" | "xs" | "icon-xs" | "icon-sm" | null | undefined;
11
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
12
+ declare function InputGroupButton({ className, type, variant, size, ...props }: Omit<React.ComponentProps<typeof Button>, 'size'> & VariantProps<typeof inputGroupButtonVariants>): import("react/jsx-runtime").JSX.Element;
13
+ declare function InputGroupText({ className, ...props }: React.ComponentProps<'span'>): import("react/jsx-runtime").JSX.Element;
14
+ declare function InputGroupInput({ className, ...props }: React.ComponentProps<'input'>): import("react/jsx-runtime").JSX.Element;
15
+ declare function InputGroupTextarea({ className, ...props }: React.ComponentProps<'textarea'>): import("react/jsx-runtime").JSX.Element;
16
+ export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupInput, InputGroupTextarea };
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { cva } from 'class-variance-authority';
4
+ import { cn } from '../../lib/utils';
5
+ import { Button } from '../../components/Button';
6
+ import { Input } from '../../components/Input';
7
+ import { Textarea } from '../../components/Textarea';
8
+ function InputGroup({ className, ...props }) {
9
+ return (_jsx("div", { "data-slot": "input-group", role: "group", className: cn('border-input dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-disabled:bg-input/50 dark:has-disabled:bg-input/80 h-8 rounded-lg border transition-colors in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-3 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 group/input-group relative flex w-full min-w-0 items-center outline-none has-[>textarea]:h-auto', className), ...props }));
10
+ }
11
+ const inputGroupAddonVariants = cva("text-muted-foreground h-auto gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4 flex cursor-text items-center justify-center select-none", {
12
+ variants: {
13
+ align: {
14
+ 'inline-start': 'pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem] order-first',
15
+ 'inline-end': 'pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem] order-last',
16
+ 'block-start': 'px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2 order-first w-full justify-start',
17
+ 'block-end': 'px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2 order-last w-full justify-start',
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ align: 'inline-start',
22
+ },
23
+ });
24
+ function InputGroupAddon({ className, align = 'inline-start', ...props }) {
25
+ return (_jsx("div", { role: "group", "data-slot": "input-group-addon", "data-align": align, className: cn(inputGroupAddonVariants({ align }), className), onClick: (e) => {
26
+ var _a, _b;
27
+ if (e.target.closest('button')) {
28
+ return;
29
+ }
30
+ (_b = (_a = e.currentTarget.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector('input')) === null || _b === void 0 ? void 0 : _b.focus();
31
+ }, ...props }));
32
+ }
33
+ const inputGroupButtonVariants = cva('gap-2 text-sm flex items-center shadow-none', {
34
+ variants: {
35
+ size: {
36
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
37
+ sm: '',
38
+ 'icon-xs': 'size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0',
39
+ 'icon-sm': 'size-8 p-0 has-[>svg]:p-0',
40
+ },
41
+ },
42
+ defaultVariants: {
43
+ size: 'xs',
44
+ },
45
+ });
46
+ function InputGroupButton({ className, type = 'button', variant = 'ghost', size = 'xs', ...props }) {
47
+ return (_jsx(Button, { type: type, "data-size": size, variant: variant, className: cn(inputGroupButtonVariants({ size }), className), ...props }));
48
+ }
49
+ function InputGroupText({ className, ...props }) {
50
+ return (_jsx("span", { className: cn("text-muted-foreground gap-2 text-sm [&_svg:not([class*='size-'])]:size-4 flex items-center [&_svg]:pointer-events-none", className), ...props }));
51
+ }
52
+ function InputGroupInput({ className, ...props }) {
53
+ return (_jsx(Input, { "data-slot": "input-group-control", className: cn('rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent flex-1', className), ...props }));
54
+ }
55
+ function InputGroupTextarea({ className, ...props }) {
56
+ return (_jsx(Textarea, { "data-slot": "input-group-control", className: cn('rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent flex-1 resize-none', className), ...props }));
57
+ }
58
+ export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupInput, InputGroupTextarea };
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { InputGroup } from './InputGroup';
3
+ declare const meta: Meta<typeof InputGroup>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof InputGroup>;
6
+ export declare const Basic: Story;
7
+ export declare const WithInlineStartAddon: Story;
8
+ export declare const WithInlineEndAddon: Story;
9
+ export declare const WithBothInlineAddons: Story;
10
+ export declare const WithBlockStartAddon: Story;
11
+ export declare const WithBlockEndAddon: Story;
12
+ export declare const WithInlineStartButton: Story;
13
+ export declare const WithInlineEndButton: Story;
14
+ export declare const WithPassword: Story;
15
+ export declare const WithMultipleButtons: Story;
16
+ export declare const WithTextAndIcon: Story;
17
+ export declare const WithTextarea: Story;
18
+ export declare const Disabled: Story;
19
+ export declare const Invalid: Story;
@@ -0,0 +1,62 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { SearchIcon, CalendarIcon, UserIcon, MailIcon, XIcon, EyeIcon, EyeOffIcon } from 'lucide-react';
3
+ import { useState } from 'react';
4
+ import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupInput, InputGroupTextarea, } from './InputGroup';
5
+ const meta = {
6
+ title: 'UIKit/InputGroup',
7
+ component: InputGroup,
8
+ tags: ['autodocs'],
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component: 'A versatile input group component that allows combining inputs with addons, buttons, and text.',
13
+ },
14
+ },
15
+ },
16
+ };
17
+ export default meta;
18
+ export const Basic = {
19
+ render: () => (_jsx(InputGroup, { children: _jsx(InputGroupInput, { placeholder: "Enter text..." }) })),
20
+ };
21
+ export const WithInlineStartAddon = {
22
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupAddon, { align: "inline-start", children: _jsx(SearchIcon, {}) }), _jsx(InputGroupInput, { placeholder: "Search..." })] })),
23
+ };
24
+ export const WithInlineEndAddon = {
25
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupInput, { placeholder: "Enter email..." }), _jsx(InputGroupAddon, { align: "inline-end", children: _jsx(MailIcon, {}) })] })),
26
+ };
27
+ export const WithBothInlineAddons = {
28
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupAddon, { align: "inline-start", children: _jsx(UserIcon, {}) }), _jsx(InputGroupInput, { placeholder: "Username" }), _jsx(InputGroupAddon, { align: "inline-end", children: _jsx("span", { className: "text-xs", children: "@domain.com" }) })] })),
29
+ };
30
+ export const WithBlockStartAddon = {
31
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupAddon, { align: "block-start", children: _jsx(InputGroupText, { children: "Email Address" }) }), _jsx(InputGroupInput, { placeholder: "john@example.com" })] })),
32
+ };
33
+ export const WithBlockEndAddon = {
34
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupInput, { placeholder: "Enter your message..." }), _jsx(InputGroupAddon, { align: "block-end", children: _jsx(InputGroupText, { children: "Additional information" }) })] })),
35
+ };
36
+ export const WithInlineStartButton = {
37
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupAddon, { align: "inline-start", children: _jsx(InputGroupButton, { size: "icon-xs", children: _jsx(SearchIcon, {}) }) }), _jsx(InputGroupInput, { placeholder: "Search..." })] })),
38
+ };
39
+ export const WithInlineEndButton = {
40
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupInput, { placeholder: "Enter text..." }), _jsx(InputGroupAddon, { align: "inline-end", children: _jsx(InputGroupButton, { size: "icon-xs", variant: "ghost", children: _jsx(XIcon, {}) }) })] })),
41
+ };
42
+ export const WithPassword = {
43
+ render: () => {
44
+ const [showPassword, setShowPassword] = useState(false);
45
+ return (_jsxs(InputGroup, { children: [_jsx(InputGroupInput, { type: showPassword ? 'text' : 'password', placeholder: "Enter password..." }), _jsx(InputGroupAddon, { align: "inline-end", children: _jsx(InputGroupButton, { size: "icon-xs", variant: "ghost", onClick: () => setShowPassword(!showPassword), children: showPassword ? _jsx(EyeOffIcon, {}) : _jsx(EyeIcon, {}) }) })] }));
46
+ },
47
+ };
48
+ export const WithMultipleButtons = {
49
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupAddon, { align: "inline-start", children: _jsx(InputGroupButton, { size: "xs", children: "Copy" }) }), _jsx(InputGroupInput, { placeholder: "Enter value..." }), _jsxs(InputGroupAddon, { align: "inline-end", children: [_jsx(InputGroupButton, { size: "xs", variant: "primary", children: "Save" }), _jsx(InputGroupButton, { size: "icon-xs", variant: "ghost", children: _jsx(XIcon, {}) })] })] })),
50
+ };
51
+ export const WithTextAndIcon = {
52
+ render: () => (_jsxs(InputGroup, { children: [_jsxs(InputGroupAddon, { align: "inline-start", children: [_jsx(CalendarIcon, {}), _jsx(InputGroupText, { children: "Date" })] }), _jsx(InputGroupInput, { placeholder: "Select date..." })] })),
53
+ };
54
+ export const WithTextarea = {
55
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupAddon, { align: "block-start", children: _jsx(InputGroupText, { children: "Description" }) }), _jsx(InputGroupTextarea, { placeholder: "Enter your description...", rows: 4 }), _jsx(InputGroupAddon, { align: "block-end", children: _jsx(InputGroupText, { children: "Max 500 characters" }) })] })),
56
+ };
57
+ export const Disabled = {
58
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupAddon, { align: "inline-start", children: _jsx(UserIcon, {}) }), _jsx(InputGroupInput, { placeholder: "Disabled input...", disabled: true }), _jsx(InputGroupAddon, { align: "inline-end", children: _jsx(InputGroupButton, { size: "icon-xs", disabled: true, children: _jsx(XIcon, {}) }) })] })),
59
+ };
60
+ export const Invalid = {
61
+ render: () => (_jsxs(InputGroup, { children: [_jsx(InputGroupAddon, { align: "inline-start", children: _jsx(MailIcon, {}) }), _jsx(InputGroupInput, { placeholder: "Enter email...", "aria-invalid": "true", defaultValue: "Invalid email" })] })),
62
+ };
@@ -0,0 +1 @@
1
+ export * from './InputGroup';
@@ -0,0 +1 @@
1
+ export * from './InputGroup';
@@ -116,7 +116,7 @@ const SelectContent = React.forwardRef(({ className, children, position = 'poppe
116
116
  const filteredItemsCount = React.useMemo(() => {
117
117
  return countSelectItems(filteredChildren);
118
118
  }, [filteredChildren]);
119
- const noResultsContent = (_jsxs("div", { className: "px-2 py-1.5 flex flex-col items-start gap-1", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: noResultsText }), noResultsButtonText && onNoResultsButtonClick && (_jsx(Button, { variant: "primaryText", onMouseDown: (event) => event.preventDefault(), onClick: onNoResultsButtonClick, className: "h-auto p-0 text-sm", children: noResultsButtonText }))] }));
119
+ const noResultsContent = (_jsxs("div", { className: "px-2 py-1.5 flex flex-col items-start gap-1", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: noResultsText }), noResultsButtonText && onNoResultsButtonClick && (_jsx(Button, { variant: "secondaryText", onMouseDown: (event) => event.preventDefault(), onClick: onNoResultsButtonClick, className: "h-auto p-0 text-sm", children: noResultsButtonText }))] }));
120
120
  return (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, { ref: ref, className: cn('relative z-50 max-h-(--radix-select-content-available-height) min-w-32 overflow-y-auto overflow-x-hidden rounded-(--uikit-radius) border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-select-content-transform-origin)', position === 'popper' &&
121
121
  'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1', className), position: position, onCloseAutoFocus: () => {
122
122
  if (shouldShowSearch) {
@@ -19,7 +19,7 @@ export function Stepper({ steps, currentStep, onStepChange, contentProps, classN
19
19
  onStepChange === null || onStepChange === void 0 ? void 0 : onStepChange(step.id);
20
20
  }, children: [_jsx("div", { className: cn('w-9 h-9 rounded-full flex items-center justify-center', isPastStep && 'bg-(--uikit-success)/10 text-(--uikit-success)', isActive &&
21
21
  !isPastStep &&
22
- 'bg-(--uikit-primary)/10 text-[var(--uikit-primary)]', !isPastStep && !isActive && 'bg-muted/50 text-muted-foreground'), children: isPastStep ? _jsx(Check, { size: 16, strokeWidth: 3 }) : ((_a = step.icon) !== null && _a !== void 0 ? _a : index + 1) }), _jsx("span", { className: cn('text-sm font-normal not-italic', isPastStep && 'text-(--uikit-success)', isActive && 'text-[var(--uikit-primary)]', !isPastStep && !isActive && 'text-muted-foreground'), children: step.label })] }), index < steps.length - 1 && (_jsx("div", { className: cn(isVertical ? 'w-[3px] h-14 my-2' : 'h-[3px] flex-1 mx-3 mt-4', isPastStep ? 'bg-(--uikit-success)' : 'bg-muted') }))] }, step.id));
22
+ 'bg-(--uikit-secondary)/10 text-[var(--uikit-secondary)]', !isPastStep && !isActive && 'bg-muted/50 text-muted-foreground'), children: isPastStep ? _jsx(Check, { size: 16, strokeWidth: 3 }) : ((_a = step.icon) !== null && _a !== void 0 ? _a : index + 1) }), _jsx("span", { className: cn('text-sm font-normal not-italic', isPastStep && 'text-(--uikit-success)', isActive && 'text-[var(--uikit-secondary)]', !isPastStep && !isActive && 'text-muted-foreground'), children: step.label })] }), index < steps.length - 1 && (_jsx("div", { className: cn(isVertical ? 'w-[3px] h-14 my-2' : 'h-[3px] flex-1 mx-3 mt-4', isPastStep ? 'bg-(--uikit-success)' : 'bg-muted') }))] }, step.id));
23
23
  }) })), _jsx("div", { className: "flex-1", children: (() => {
24
24
  if (React.isValidElement(currentContent)) {
25
25
  return currentContent;
@@ -56,7 +56,11 @@ export const EmptyState = {
56
56
  render: () => (_jsx(StandardTable, { id: "empty-table", data: [], columns: columns, customNoRows: { message: 'No users found' }, paginationMode: "client" })),
57
57
  };
58
58
  export const EmptyStateWithIcon = {
59
- render: () => (_jsx(StandardTable, { id: "empty-table-with-icon", data: [], columns: columns, paginationMode: "none", customNoRows: { message: 'No transactions', icon: _jsx(MdReceiptLong, { size: 56 }), messageClassName: 'text-xl font-bold' } })),
59
+ render: () => (_jsx(StandardTable, { id: "empty-table-with-icon", data: [], columns: columns, paginationMode: "none", customNoRows: {
60
+ message: 'No transactions',
61
+ icon: _jsx(MdReceiptLong, { size: 56 }),
62
+ messageClassName: 'text-xl font-bold',
63
+ } })),
60
64
  };
61
65
  export const Loading = {
62
66
  render: () => _jsx(StandardTable, { id: "loading-table", data: [], columns: columns, isLoading: true, paginationMode: "client" }),
@@ -24,6 +24,7 @@ export function useInfiniteScrolling(params) {
24
24
  count: allRows.length + (isInfinite && hasNextPage ? 1 : 0),
25
25
  getScrollElement: () => parentScrollRef.current,
26
26
  estimateSize: () => { var _a; return (_a = virtualization === null || virtualization === void 0 ? void 0 : virtualization.rowEstimate) !== null && _a !== void 0 ? _a : 48; },
27
+ measureElement: (el) => { var _a; return (_a = el === null || el === void 0 ? void 0 : el.getBoundingClientRect().height) !== null && _a !== void 0 ? _a : 48; },
27
28
  overscan: (_a = virtualization === null || virtualization === void 0 ? void 0 : virtualization.overscan) !== null && _a !== void 0 ? _a : 6,
28
29
  });
29
30
  const loadLockRef = useRef(false);
@@ -1,4 +1,4 @@
1
- import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
1
+ import { useEffect, useMemo, useRef, useState } from 'react';
2
2
  import { useReactTable, getCoreRowModel, getSortedRowModel, getPaginationRowModel, getGroupedRowModel, getExpandedRowModel, } from '@tanstack/react-table';
3
3
  import { applyFlexSizes, getCheckboxSelectionColumn } from '../table.helpers';
4
4
  import { usePaginationController } from './usePaginationController';
@@ -12,17 +12,7 @@ export function useTableController({ id, height, data, columns, checkboxSelectio
12
12
  const columnVisibility = useMemo(() => {
13
13
  return Object.fromEntries(stableGrouping.map((columnId) => [columnId, false]));
14
14
  }, [stableGrouping]);
15
- const [containerWidth, setContainerWidth] = useState(0);
16
- useLayoutEffect(() => {
17
- if (!parentScrollRef.current)
18
- return;
19
- const ro = new ResizeObserver(([entry]) => {
20
- setContainerWidth(entry.contentRect.width);
21
- });
22
- ro.observe(parentScrollRef.current);
23
- return () => ro.disconnect();
24
- }, []);
25
- const [tableColumns, setTableColumns] = useState(() => applyFlexSizes(columns !== null && columns !== void 0 ? columns : [], containerWidth, !!(virtualization === null || virtualization === void 0 ? void 0 : virtualization.enabled)));
15
+ const [tableColumns, setTableColumns] = useState(() => applyFlexSizes(columns !== null && columns !== void 0 ? columns : []));
26
16
  const [internalSorting, setInternalSorting] = useState(sorting !== null && sorting !== void 0 ? sorting : []);
27
17
  const [internalRowSelection, setInternalRowSelection] = useState(() => {
28
18
  if (selectedRowIds) {
@@ -108,7 +98,7 @@ export function useTableController({ id, height, data, columns, checkboxSelectio
108
98
  return checkboxSelection ? getCheckboxSelectionColumn(table) : null;
109
99
  }, [checkboxSelection, table]);
110
100
  useEffect(() => {
111
- const normalized = applyFlexSizes(columns !== null && columns !== void 0 ? columns : [], containerWidth, !!(virtualization === null || virtualization === void 0 ? void 0 : virtualization.enabled));
101
+ const normalized = applyFlexSizes(columns !== null && columns !== void 0 ? columns : []);
112
102
  let finalColumns;
113
103
  if (checkboxSelection && selectionColumn) {
114
104
  if (checkboxPosition === 'start') {
@@ -125,7 +115,7 @@ export function useTableController({ id, height, data, columns, checkboxSelectio
125
115
  finalColumns = normalized;
126
116
  }
127
117
  setTableColumns(finalColumns);
128
- }, [columns, checkboxSelection, checkboxPosition, containerWidth, virtualization === null || virtualization === void 0 ? void 0 : virtualization.enabled]);
118
+ }, [columns, checkboxSelection, checkboxPosition]);
129
119
  return {
130
120
  table,
131
121
  height,
@@ -2,20 +2,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { cn } from '../../lib/utils';
4
4
  import { useUIKitTheme } from '../../context/useUIKitTheme';
5
- export const Textarea = React.forwardRef(({ label, error, helperText, className, maxLength, 'aria-describedby': ariaDescribedBy, 'aria-invalid': ariaInvalid, ...props }, ref) => {
6
- var _a, _b;
5
+ export const Textarea = React.forwardRef(({ label, error, helperText, className, value, defaultValue, onChange, maxLength, 'aria-describedby': ariaDescribedBy, 'aria-invalid': ariaInvalid, ...props }, ref) => {
6
+ var _a;
7
7
  const theme = useUIKitTheme();
8
8
  const generatedId = React.useId();
9
9
  const textareaId = (_a = props.id) !== null && _a !== void 0 ? _a : generatedId;
10
10
  const isInvalid = Boolean(error) || (ariaInvalid !== undefined && ariaInvalid !== false && ariaInvalid !== 'false');
11
- const isControlled = props.value !== undefined;
12
- const currentValue = isControlled ? String((_b = props.value) !== null && _b !== void 0 ? _b : '') : '';
13
- const currentLength = currentValue.length;
14
- const showLengthIndicator = isControlled && typeof maxLength === 'number' && !error;
11
+ const isControlled = value !== undefined;
12
+ const [uncontrolledLength, setUncontrolledLength] = React.useState(() => String(defaultValue !== null && defaultValue !== void 0 ? defaultValue : '').length);
13
+ const currentLength = isControlled ? String(value !== null && value !== void 0 ? value : '').length : uncontrolledLength;
14
+ const showLengthIndicator = typeof maxLength === 'number' && !error;
15
15
  const showHelperRow = !error && (helperText || showLengthIndicator);
16
16
  const errorId = error ? `${textareaId}-error` : undefined;
17
17
  const helperId = showHelperRow ? `${textareaId}-helper` : undefined;
18
18
  const describedBy = [ariaDescribedBy, errorId, helperId].filter(Boolean).join(' ') || undefined;
19
- return (_jsxs("div", { className: cn(className), children: [label && (_jsx("label", { htmlFor: textareaId, className: "text-sm font-medium text-foreground", children: label })), _jsx("textarea", { id: textareaId, "aria-invalid": isInvalid, "aria-describedby": describedBy, maxLength: maxLength, style: { fontFamily: theme.fontFamily }, className: cn('flex min-h-[80px] w-full text-(--uikit-textSecondary) rounded-(--uikit-radius) border border-(--uikit-inputEnabledBorder) bg-background hover:border-(--uikit-inputHoverBorder) px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 md:text-sm transition focus-visible:outline-none focus-visible:border-(--uikit-primary) focus-visible:ring-2 focus-visible:ring-(--uikit-primary) aria-invalid:border-(--uikit-error) aria-invalid:focus-visible:ring-(--uikit-error)'), ref: ref, ...props }), error && (_jsx("p", { id: errorId, className: "text-sm font-medium text-error", children: error })), showHelperRow && (_jsxs("div", { id: helperId, className: "mt-1 flex items-center justify-between gap-2", children: [helperText ? _jsx("p", { className: "text-sm font-medium text-foreground", children: helperText }) : _jsx("span", {}), showLengthIndicator && (_jsxs("span", { className: "text-sm font-medium text-foreground", children: [currentLength, "/", maxLength] }))] }))] }));
19
+ return (_jsxs("div", { className: cn(className), children: [label && (_jsx("label", { htmlFor: textareaId, className: "text-xs font-normal text-muted-foreground", children: label })), _jsx("textarea", { id: textareaId, "aria-invalid": isInvalid, "aria-describedby": describedBy, value: value, defaultValue: defaultValue, onChange: (event) => {
20
+ if (!isControlled) {
21
+ setUncontrolledLength(event.target.value.length);
22
+ }
23
+ onChange === null || onChange === void 0 ? void 0 : onChange(event);
24
+ }, maxLength: maxLength, style: { fontFamily: theme.fontFamily }, className: cn('flex min-h-[80px] w-full text-(--uikit-textSecondary) rounded-(--uikit-radius) border border-(--uikit-inputEnabledBorder) bg-background hover:border-(--uikit-inputHoverBorder) px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 md:text-sm transition focus-visible:outline-none focus-visible:border-(--uikit-primary) focus-visible:ring-2 focus-visible:ring-(--uikit-primary) aria-invalid:border-(--uikit-error) aria-invalid:focus-visible:ring-(--uikit-error)'), ref: ref, ...props }), error && (_jsx("p", { id: errorId, className: "text-sm font-medium text-error", children: error })), showHelperRow && (_jsxs("div", { id: helperId, className: "mt-1 flex items-center justify-between gap-2", children: [helperText ? (_jsx("p", { className: "text-xs font-normal text-muted-foreground", children: helperText })) : (_jsx("span", {})), showLengthIndicator && (_jsxs("span", { className: "text-xs font-normal text-muted-foreground", children: [currentLength, "/", maxLength] }))] }))] }));
20
25
  });
21
26
  Textarea.displayName = 'Textarea';
@@ -5,6 +5,7 @@ export default meta;
5
5
  type Story = StoryObj<TextareaProps>;
6
6
  export declare const Default: Story;
7
7
  export declare const WithHelperText: Story;
8
- export declare const WithTextLengthIndicator: Story;
8
+ export declare const WithMaxLengthIndicator: Story;
9
+ export declare const WithMaxLengthIndicatorControlled: Story;
9
10
  export declare const WithError: Story;
10
11
  export declare const Disabled: Story;
@@ -21,12 +21,16 @@ export const WithHelperText = {
21
21
  helperText: 'This is a helper text',
22
22
  },
23
23
  };
24
- export const WithTextLengthIndicator = {
25
- render: (args) => _jsx(ControlledLengthIndicator, { ...args }),
24
+ export const WithMaxLengthIndicator = {
26
25
  args: {
26
+ maxLength: 50,
27
27
  helperText: 'This is a helper text',
28
+ placeholder: 'Type here to see counter...',
28
29
  },
29
30
  };
31
+ export const WithMaxLengthIndicatorControlled = {
32
+ render: (args) => _jsx(ControlledLengthIndicator, { ...args }),
33
+ };
30
34
  export const WithError = {
31
35
  args: {
32
36
  error: 'Something went wrong',
@@ -31,3 +31,5 @@ export * from './Popover';
31
31
  export * from './DatePicker';
32
32
  export * from './Calendar';
33
33
  export * from './Textarea';
34
+ export * from './Combobox';
35
+ export * from './InputGroup';
@@ -31,3 +31,5 @@ export * from './Popover';
31
31
  export * from './DatePicker';
32
32
  export * from './Calendar';
33
33
  export * from './Textarea';
34
+ export * from './Combobox';
35
+ export * from './InputGroup';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eml-payments/ui-kit",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "private": false,
5
5
  "description": "ARLO UIKit",
6
6
  "homepage": "https://github.com/EML-Payments/arlo.npm.uikit#readme",
@@ -43,12 +43,13 @@
43
43
  "format:fix": "prettier --write \"**/*.{js,jsx,ts,tsx,json,htm,html,yml,yaml}\"",
44
44
  "task:prettier": "prettier \"./src/**/*.{ts,tsx}\" --check --log-level error",
45
45
  "task:prettier:fix": "prettier --write \"./src/**/*.{ts,tsx}\" --check --log-level error",
46
- "task:eslint": "eslint \"./src/**/*\" --ext .ts,.tsx --cache",
47
- "task:eslint:fix": "eslint \"./src/**/*.tsx\" --fix --cache && eslint \"src/**/*.ts\" --fix --cache",
46
+ "task:eslint": "eslint \"src/**/*.{ts,tsx}\" --cache",
47
+ "task:eslint:fix": "eslint \"src/**/*.{ts,tsx}\" --fix --cache",
48
48
  "task:typecheck": "tsc",
49
49
  "formatx": "npm run task:prettier:fix && npm run task:eslint:fix && npm run task:typecheck"
50
50
  },
51
51
  "dependencies": {
52
+ "@base-ui/react": "^1.3.0",
52
53
  "@radix-ui/react-avatar": "^1.1.10",
53
54
  "@radix-ui/react-checkbox": "^1.3.2",
54
55
  "@radix-ui/react-dialog": "^1.1.14",
@@ -67,7 +68,7 @@
67
68
  "class-variance-authority": "^0.7.1",
68
69
  "clsx": "^2.1.1",
69
70
  "dayjs": "^1.11.19",
70
- "lucide-react": "^0.575.0",
71
+ "lucide-react": "^0.577.0",
71
72
  "prettier": "^3.6.2",
72
73
  "react": ">=18.0.0",
73
74
  "react-day-picker": "^9.13.0",
@@ -87,6 +88,7 @@
87
88
  "@storybook/react-vite": "^10.0.6",
88
89
  "@tailwindcss/cli": "^4.1.12",
89
90
  "@typescript-eslint/eslint-plugin": "^8.35.1",
91
+ "baseline-browser-mapping": "^2.10.0",
90
92
  "eslint": "^9.31.0",
91
93
  "eslint-config-prettier": "^10.1.5",
92
94
  "eslint-plugin-import": "^2.32.0",
@@ -113,6 +115,10 @@
113
115
  ]
114
116
  },
115
117
  "lint-staged": {
116
- "*.{js,ts,tsx}": "eslint --fix"
118
+ "*.{js,ts,tsx}": [
119
+ "prettier --write",
120
+ "eslint --fix"
121
+ ],
122
+ "*.{json,md,css}": "prettier --write"
117
123
  }
118
124
  }