@eml-payments/ui-kit 1.5.3 → 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.
@@ -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';
@@ -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,
@@ -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.3",
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",
@@ -49,6 +49,7 @@
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",