@scripso-homepad/ui 0.4.7 → 0.4.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scripso-homepad/ui",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "type": "module",
5
5
  "description": "Cross-platform UI components for Homepad (React Web + React Native)",
6
6
  "license": "MIT",
@@ -115,14 +115,21 @@ export function Button({
115
115
  const preset = variantConfig[variant];
116
116
  const metrics = sizeConfig[size];
117
117
 
118
- useApplyWebClassName(containerRef, className);
119
- useApplyWebClassName(textRef, textClassName);
120
-
121
118
  const label = typeof children !== "undefined" ? children : title;
122
119
  const hasCustomChildren = typeof children !== "undefined";
123
120
  const customIcon =
124
121
  icon != null && typeof icon !== "boolean" ? icon : undefined;
125
122
  const hasIcon = showIcon || icon === true || customIcon != null;
123
+ const resolvedContainerClassName = [
124
+ Platform.OS === "web" ? "max-md:px-4!" : "",
125
+ className,
126
+ ]
127
+ .filter(Boolean)
128
+ .join(" ");
129
+
130
+ useApplyWebClassName(containerRef, resolvedContainerClassName || undefined);
131
+ useApplyWebClassName(textRef, textClassName);
132
+
126
133
  const iconNode =
127
134
  customIcon ?? (
128
135
  <ArrowUpRightIcon size={metrics.iconSize} color={preset.iconColor} />
@@ -176,7 +176,7 @@ export function Select({
176
176
  () =>
177
177
  resolveSelectDropdownContentHeight(options.length, optionHeight) >
178
178
  SELECT_DROPDOWN_MAX_HEIGHT - SELECT_DROPDOWN_PADDING * 2,
179
- [compact, optionHeight, options.length],
179
+ [optionHeight, options.length],
180
180
  );
181
181
 
182
182
  useApplyWebClassName(wrapperRef, className);
@@ -12,7 +12,7 @@ interface ArrowUpRightIconProps {
12
12
  /** Native — react-native-svg (peer dependency). */
13
13
  export function ArrowUpRightIcon({
14
14
  size = 20,
15
- color = "#08275d",
15
+ color = "#082640",
16
16
  strokeWidth = 2,
17
17
  }: ArrowUpRightIconProps) {
18
18
  return (
@@ -9,7 +9,7 @@ interface ArrowUpRightIconProps {
9
9
  /** Web / Storybook — plain SVG (no react-native-svg). */
10
10
  export function ArrowUpRightIcon({
11
11
  size = 20,
12
- color = "#08275d",
12
+ color = "#082640",
13
13
  strokeWidth = 2,
14
14
  }: ArrowUpRightIconProps) {
15
15
  return (
@@ -53,8 +53,8 @@ function createOutlineStyle(ringColor: string): ViewStyle {
53
53
  }
54
54
 
55
55
  const defaultOutline: ViewStyle = {
56
- borderRadius: radii.lg,
57
- borderWidth: 0,
56
+ borderRadius: radii.lg + INPUT_OUTLINE_WIDTH,
57
+ borderWidth: INPUT_OUTLINE_WIDTH,
58
58
  borderColor: colors.transparent,
59
59
  padding: 0,
60
60
  backgroundColor: colors.transparent,
@@ -67,8 +67,8 @@ function createOutlineStyle(ringColor: string): ViewStyle {
67
67
  }
68
68
 
69
69
  const defaultOutline: ViewStyle = {
70
- borderRadius: radii.lg,
71
- borderWidth: 0,
70
+ borderRadius: radii.lg + INPUT_OUTLINE_WIDTH,
71
+ borderWidth: INPUT_OUTLINE_WIDTH,
72
72
  borderColor: colors.transparent,
73
73
  padding: 0,
74
74
  backgroundColor: colors.transparent,
@@ -23,18 +23,18 @@ export type StormGrayStep = keyof typeof stormGray;
23
23
 
24
24
  /** Navy scale — Figma steps 0 → 8.5 */
25
25
  export const navy = {
26
- "0": "#f8f9fb",
27
- "0.5": "#e5e9ef",
28
- "1": "#cdd3df",
29
- "1.5": "#b4bece",
30
- "2": "#9ca8be",
31
- "3": "#6a7d9e",
32
- "4": "#39527d",
33
- "5": "#08275d",
34
- "6": "#061f4a",
35
- "7": "#051738",
36
- "8": "#031025",
37
- "8.5": "#020c1c",
26
+ "0": "#f6fafe",
27
+ "0.5": "#dee5eb",
28
+ "1": "#c6d0d8",
29
+ "1.5": "#afbac5",
30
+ "2": "#97a5b2",
31
+ "3": "#677b8c",
32
+ "4": "#385066",
33
+ "5": "#082640",
34
+ "6": "#061e33",
35
+ "7": "#051726",
36
+ "8": "#030f1a",
37
+ "8.5": "#020b13",
38
38
  } as const;
39
39
 
40
40
  export type NavyStep = keyof typeof navy;
@@ -0,0 +1,55 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { fn } from '@storybook/test';
3
+
4
+ import { WebLayoutCanvas } from '../layout/story-helpers';
5
+
6
+ import { ConfirmModal } from './ConfirmModal';
7
+
8
+ const meta = {
9
+ title: 'Web Components/ConfirmModal',
10
+ component: ConfirmModal,
11
+ parameters: {
12
+ layout: 'fullscreen',
13
+ webLayout: true,
14
+ },
15
+ args: {
16
+ open: true,
17
+ title: 'Կասեցնե՞լ շենքի մուտքը',
18
+ description: (
19
+ <>
20
+ Դուք պատրաստվում եք կասեցնել «Կենտրոն» շենքի մուտքը։
21
+ <br />
22
+ Բոլոր օգտատերերը կկորցնեն հասանելիությունը համակարգին։
23
+ </>
24
+ ),
25
+ cancelText: 'Չեղարկել',
26
+ confirmText: 'Կասեցնել',
27
+ onCancel: fn(),
28
+ onConfirm: fn(),
29
+ },
30
+ } satisfies Meta<typeof ConfirmModal>;
31
+
32
+ export default meta;
33
+ type Story = StoryObj<typeof meta>;
34
+
35
+ export const Default: Story = {
36
+ render: (args) => (
37
+ <WebLayoutCanvas className="min-h-screen bg-storm-gray-50 p-6">
38
+ <ConfirmModal {...args} />
39
+ </WebLayoutCanvas>
40
+ ),
41
+ };
42
+
43
+ export const RejectRequest: Story = {
44
+ args: {
45
+ title: 'Մերժե՞լ շենքի հայտը',
46
+ description:' Դուք պատրաստվում եք մերժել «Արաբկիր 12» հասցեի շենքի հայտը։ Կազմակերպությունը կտեղեկացվի մերժման մասին։',
47
+ cancelText: 'Չեղարկել',
48
+ confirmText: 'Մերժել',
49
+ },
50
+ render: (args) => (
51
+ <WebLayoutCanvas className="min-h-screen bg-storm-gray-50 p-6">
52
+ <ConfirmModal {...args} />
53
+ </WebLayoutCanvas>
54
+ ),
55
+ };
@@ -0,0 +1,116 @@
1
+ import { useEffect, type ReactNode } from 'react';
2
+
3
+ import { Button } from '../../components/Button';
4
+ import { cn } from '../utils/cn';
5
+
6
+ export type ConfirmModalProps = {
7
+ open: boolean;
8
+ title: string;
9
+ description: ReactNode;
10
+ cancelText: string;
11
+ confirmText: string;
12
+ onCancel: () => void;
13
+ onConfirm: () => void;
14
+ cancelDisabled?: boolean;
15
+ confirmDisabled?: boolean;
16
+ closeOnBackdrop?: boolean;
17
+ containerClassName?: string;
18
+ buttonClassName?: string;
19
+ };
20
+
21
+ export function ConfirmModal({
22
+ open,
23
+ title,
24
+ description,
25
+ cancelText,
26
+ confirmText,
27
+ onCancel,
28
+ onConfirm,
29
+ cancelDisabled = false,
30
+ confirmDisabled = false,
31
+ closeOnBackdrop = true,
32
+ containerClassName,
33
+ buttonClassName,
34
+ }: ConfirmModalProps) {
35
+ useEffect(() => {
36
+ if (!open) {
37
+ return;
38
+ }
39
+
40
+ const handleKeyDown = (event: KeyboardEvent) => {
41
+ if (event.key === 'Escape') {
42
+ onCancel();
43
+ }
44
+ };
45
+
46
+ window.addEventListener('keydown', handleKeyDown);
47
+
48
+ return () => {
49
+ window.removeEventListener('keydown', handleKeyDown);
50
+ };
51
+ }, [open, onCancel]);
52
+
53
+ if (!open) {
54
+ return null;
55
+ }
56
+
57
+ const sharedButtonClassName = cn('btn h-10 min-w-0 flex-1 justify-center!', buttonClassName);
58
+
59
+ return (
60
+ <div
61
+ className="fixed inset-0 z-50 flex items-center justify-center p-4 backdrop-blur-md bg-storm-gray-850/40"
62
+ onClick={closeOnBackdrop ? onCancel : undefined}
63
+ role="presentation"
64
+ >
65
+ <div
66
+ role="dialog"
67
+ aria-modal="true"
68
+ aria-labelledby="homepad-confirm-modal-title"
69
+ aria-describedby="homepad-confirm-modal-description"
70
+ className={cn(
71
+ 'flex w-full max-w-md flex-col gap-8 rounded-2xl bg-white p-4 opacity-100 md:p-6',
72
+ containerClassName,
73
+ )}
74
+ onClick={(event) => {
75
+ event.stopPropagation();
76
+ }}
77
+ >
78
+ <header className="flex flex-col gap-3 text-center">
79
+ <h2
80
+ id="homepad-confirm-modal-title"
81
+ className="font-sans text-xl font-bold leading-6.75 tracking-normal text-black"
82
+ >
83
+ {title}
84
+ </h2>
85
+ <div
86
+ id="homepad-confirm-modal-description"
87
+ className="text-center font-sans text-sm font-normal leading-4.75 tracking-normal text-storm-gray-400"
88
+ >
89
+ {description}
90
+ </div>
91
+ </header>
92
+
93
+ <footer className="flex w-full gap-4">
94
+ <Button
95
+ title={cancelText}
96
+ onPress={onCancel}
97
+ variant="gray"
98
+ size='sm'
99
+ disabled={cancelDisabled}
100
+ className={sharedButtonClassName}
101
+ textClassName="text-center!"
102
+ />
103
+ <Button
104
+ title={confirmText}
105
+ onPress={onConfirm}
106
+ variant="primary"
107
+ size='sm'
108
+ disabled={confirmDisabled}
109
+ className={sharedButtonClassName}
110
+ textClassName="text-center!"
111
+ />
112
+ </footer>
113
+ </div>
114
+ </div>
115
+ );
116
+ }
@@ -0,0 +1,130 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { fn } from '@storybook/test';
3
+ import { useState } from 'react';
4
+
5
+ import { Input } from '../../components/Input';
6
+ import { TableMenuEditIcon } from '../icons/TableMenuEditIcon';
7
+ import { WebLayoutCanvas } from '../layout/story-helpers';
8
+
9
+ import { Modal, type ModalFooterAlign } from './Modal';
10
+
11
+ const meta = {
12
+ title: 'Web Components/Modal',
13
+ component: Modal,
14
+ parameters: {
15
+ layout: 'fullscreen',
16
+ webLayout: true,
17
+ },
18
+ args: {
19
+ open: true,
20
+ title: 'Նոր շենքի ավելացում',
21
+ subtitle: 'Լրացրեք տվյալները՝ նոր շենք ավելացնելու համար',
22
+ cancelText: 'Չեղարկել',
23
+ confirmText: 'Ավելացնել շենքը',
24
+ onCancel: fn(),
25
+ onConfirm: fn(),
26
+ footerAlign: 'right' as ModalFooterAlign,
27
+ },
28
+ } satisfies Meta<typeof Modal>;
29
+
30
+ export default meta;
31
+ type Story = StoryObj<typeof meta>;
32
+
33
+ function AddBuildingModalBody() {
34
+ return (
35
+ <div className="flex flex-col gap-4">
36
+ <div className="grid gap-4 md:grid-cols-2">
37
+ <Input label="Կազմակերպություն" value="" onChangeText={() => undefined} className="w-full" />
38
+ <Input label="Հասցե" value="" onChangeText={() => undefined} className="w-full" />
39
+ </div>
40
+ <Input label="Կոնտակտային անձ" value="" onChangeText={() => undefined} className="w-full" />
41
+ <div className="grid gap-4 md:grid-cols-2">
42
+ <Input label="Էլ. փոստ" value="" onChangeText={() => undefined} className="w-full" />
43
+ <Input label="Հեռախոսահամար" value="" onChangeText={() => undefined} className="w-full" />
44
+ </div>
45
+ </div>
46
+ );
47
+ }
48
+
49
+ export const Default: Story = {
50
+ args: {
51
+ children: null,
52
+ },
53
+ render: (args) => (
54
+ <WebLayoutCanvas className="min-h-screen bg-storm-gray-50 p-6">
55
+ <Modal {...args}>
56
+ <AddBuildingModalBody />
57
+ </Modal>
58
+ </WebLayoutCanvas>
59
+ ),
60
+ };
61
+
62
+ export const WithIcon: Story = {
63
+ args: {
64
+ children: null,
65
+ title: 'Շենքի խմբագրում',
66
+ subtitle: 'Թարմացրեք շենքի տվյալները',
67
+ icon: <TableMenuEditIcon />,
68
+ },
69
+ render: (args) => (
70
+ <WebLayoutCanvas className="min-h-screen bg-storm-gray-50 p-6">
71
+ <Modal {...args}>
72
+ <AddBuildingModalBody />
73
+ </Modal>
74
+ </WebLayoutCanvas>
75
+ ),
76
+ };
77
+
78
+ export const SplitFooter: Story = {
79
+ args: {
80
+ children: null,
81
+ footerLayout: 'split',
82
+ },
83
+ render: (args) => (
84
+ <WebLayoutCanvas className="min-h-screen bg-storm-gray-50 p-6">
85
+ <Modal {...args}>
86
+ <AddBuildingModalBody />
87
+ </Modal>
88
+ </WebLayoutCanvas>
89
+ ),
90
+ };
91
+
92
+ export const FooterAlignments: Story = {
93
+ args: {
94
+ children: null,
95
+ },
96
+ render: () => <FooterAlignmentsStory />,
97
+ };
98
+
99
+ function FooterAlignmentsStory() {
100
+ const [align, setAlign] = useState<ModalFooterAlign>('right');
101
+
102
+ return (
103
+ <WebLayoutCanvas className="min-h-screen bg-storm-gray-50 p-6">
104
+ <div className="mb-4 flex gap-2">
105
+ {(['left', 'center', 'right'] as const).map((value) => (
106
+ <button
107
+ key={value}
108
+ type="button"
109
+ className="rounded-lg border border-storm-gray-50 px-3 py-1 text-sm"
110
+ onClick={() => setAlign(value)}
111
+ >
112
+ {value}
113
+ </button>
114
+ ))}
115
+ </div>
116
+ <Modal
117
+ open
118
+ title="Նոր շենքի ավելացում"
119
+ subtitle="Լրացրեք տվյալները՝ նոր շենք ավելացնելու համար"
120
+ cancelText="Չեղարկել"
121
+ confirmText="Ավելացնել շենքը"
122
+ footerAlign={align}
123
+ onCancel={fn()}
124
+ onConfirm={fn()}
125
+ >
126
+ <AddBuildingModalBody />
127
+ </Modal>
128
+ </WebLayoutCanvas>
129
+ );
130
+ }
@@ -0,0 +1,162 @@
1
+ import { useEffect, type ReactNode } from 'react';
2
+
3
+ import { Button } from '../../components/Button';
4
+ import { cn } from '../utils/cn';
5
+
6
+ export type ModalFooterAlign = 'left' | 'center' | 'right';
7
+ export type ModalFooterLayout = 'inline' | 'split';
8
+
9
+ export type ModalProps = {
10
+ open: boolean;
11
+ title: string;
12
+ subtitle?: string;
13
+ icon?: ReactNode;
14
+ iconContainerClassName?: string;
15
+ children: ReactNode;
16
+ cancelText: string;
17
+ confirmText: string;
18
+ onCancel: () => void;
19
+ onConfirm: () => void;
20
+ footerAlign?: ModalFooterAlign;
21
+ footerLayout?: ModalFooterLayout;
22
+ cancelDisabled?: boolean;
23
+ confirmDisabled?: boolean;
24
+ closeOnBackdrop?: boolean;
25
+ containerClassName?: string;
26
+ contentClassName?: string;
27
+ buttonClassName?: string;
28
+ };
29
+
30
+ const footerAlignClasses: Record<ModalFooterAlign, string> = {
31
+ left: 'justify-start',
32
+ center: 'justify-center',
33
+ right: 'justify-end',
34
+ };
35
+
36
+ export function Modal({
37
+ open,
38
+ title,
39
+ subtitle,
40
+ icon,
41
+ iconContainerClassName,
42
+ children,
43
+ cancelText,
44
+ confirmText,
45
+ onCancel,
46
+ onConfirm,
47
+ footerAlign = 'right',
48
+ footerLayout = 'inline',
49
+ cancelDisabled = false,
50
+ confirmDisabled = false,
51
+ closeOnBackdrop = true,
52
+ containerClassName,
53
+ contentClassName,
54
+ buttonClassName,
55
+ }: ModalProps) {
56
+ useEffect(() => {
57
+ if (!open) {
58
+ return;
59
+ }
60
+
61
+ const handleKeyDown = (event: KeyboardEvent) => {
62
+ if (event.key === 'Escape') {
63
+ onCancel();
64
+ }
65
+ };
66
+
67
+ window.addEventListener('keydown', handleKeyDown);
68
+
69
+ return () => {
70
+ window.removeEventListener('keydown', handleKeyDown);
71
+ };
72
+ }, [open, onCancel]);
73
+
74
+ if (!open) {
75
+ return null;
76
+ }
77
+
78
+ const sharedButtonClassName = cn(
79
+ 'btn h-13 justify-center!',
80
+ footerLayout === 'split' && 'min-w-0 flex-1',
81
+ buttonClassName,
82
+ );
83
+
84
+ return (
85
+ <div
86
+ className="fixed inset-0 z-50 flex items-center justify-center p-4 backdrop-blur-[12px] bg-storm-gray-850/40"
87
+ onClick={closeOnBackdrop ? onCancel : undefined}
88
+ role="presentation"
89
+ >
90
+ <div
91
+ role="dialog"
92
+ aria-modal="true"
93
+ aria-labelledby="homepad-modal-title"
94
+ {...(subtitle ? { 'aria-describedby': 'homepad-modal-subtitle' } : {})}
95
+ className={cn(
96
+ 'flex w-full max-w-2xl flex-col gap-6 rounded-2xl bg-white p-4 opacity-100 md:p-6',
97
+ containerClassName,
98
+ )}
99
+ onClick={(event) => {
100
+ event.stopPropagation();
101
+ }}
102
+ >
103
+ <header className={cn('flex', icon ? 'items-center gap-2.5' : undefined)}>
104
+ {icon ? (
105
+ <div
106
+ className={cn(
107
+ 'flex size-11 shrink-0 items-center justify-center rounded-lg bg-storm-gray-50 p-3 opacity-100',
108
+ iconContainerClassName,
109
+ )}
110
+ >
111
+ <div className="flex size-5 shrink-0 items-center justify-center [&>*]:size-5 [&_svg]:size-5">
112
+ {icon}
113
+ </div>
114
+ </div>
115
+ ) : null}
116
+ <div className="flex min-w-0 flex-col gap-2">
117
+ <h2
118
+ id="homepad-modal-title"
119
+ className="font-sans text-lg font-bold leading-none tracking-normal text-black"
120
+ >
121
+ {title}
122
+ </h2>
123
+ {subtitle ? (
124
+ <p
125
+ id="homepad-modal-subtitle"
126
+ className="font-sans text-xs font-normal leading-none tracking-normal text-storm-gray-400"
127
+ >
128
+ {subtitle}
129
+ </p>
130
+ ) : null}
131
+ </div>
132
+ </header>
133
+
134
+ <div className={cn('min-w-0', contentClassName)}>{children}</div>
135
+
136
+ <footer
137
+ className={cn(
138
+ 'flex gap-4',
139
+ footerLayout === 'split' ? 'w-full' : footerAlignClasses[footerAlign],
140
+ )}
141
+ >
142
+ <Button
143
+ title={cancelText}
144
+ onPress={onCancel}
145
+ variant="gray"
146
+ disabled={cancelDisabled}
147
+ className={sharedButtonClassName}
148
+ textClassName="text-center!"
149
+ />
150
+ <Button
151
+ title={confirmText}
152
+ onPress={onConfirm}
153
+ variant="primary"
154
+ disabled={confirmDisabled}
155
+ className={sharedButtonClassName}
156
+ textClassName="text-center!"
157
+ />
158
+ </footer>
159
+ </div>
160
+ </div>
161
+ );
162
+ }
@@ -11,7 +11,10 @@ export type TableActionButtonProps = {
11
11
  ariaLabel?: string;
12
12
  className?: string;
13
13
  disabled?: boolean;
14
- } & Pick<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'aria-expanded' | 'aria-haspopup' | 'aria-controls'>;
14
+ } & Pick<
15
+ ButtonHTMLAttributes<HTMLButtonElement>,
16
+ 'onClick' | 'title' | 'aria-expanded' | 'aria-haspopup' | 'aria-controls'
17
+ >;
15
18
 
16
19
  const actionButtonClassName =
17
20
  'inline-flex cursor-pointer items-center gap-1 rounded-lg border border-storm-gray-50 bg-white px-3 py-2 font-sans text-xs font-medium leading-none text-storm-gray-900 transition-colors hover:bg-storm-gray-0';
@@ -40,6 +43,7 @@ export const TableActionButton = forwardRef<HTMLButtonElement, TableActionButton
40
43
  ref,
41
44
  ) {
42
45
  const isInlineAction = variant === 'approve' || variant === 'reject';
46
+ const hasLabel = Boolean(children);
43
47
 
44
48
  return (
45
49
  <button
@@ -50,6 +54,7 @@ export const TableActionButton = forwardRef<HTMLButtonElement, TableActionButton
50
54
  aria-label={ariaLabel}
51
55
  className={cn(
52
56
  variantClasses[variant],
57
+ isInlineAction && !hasLabel && 'px-2',
53
58
  disabled && 'cursor-not-allowed opacity-50',
54
59
  className,
55
60
  )}
@@ -172,13 +172,13 @@ export function TableActionsMenu({
172
172
  item.onSelect();
173
173
  }}
174
174
  className={cn(
175
- 'flex w-full cursor-pointer items-center gap-2.5 px-3 py-4 text-left font-sans text-sm font-medium leading-none text-storm-gray-900 transition-colors hover:bg-storm-gray-0',
175
+ 'flex h-[51px] w-full cursor-pointer items-center gap-2.5 px-3 text-left font-sans text-sm font-medium leading-none text-storm-gray-900 transition-colors hover:bg-storm-gray-0',
176
176
  index > 0 && 'border-t border-storm-gray-50',
177
177
  item.disabled && 'cursor-not-allowed opacity-50',
178
178
  )}
179
179
  >
180
180
  {icon ? (
181
- <span className="inline-flex size-5 shrink-0 items-center justify-center">
181
+ <span className="inline-flex size-5 shrink-0 items-center justify-center text-storm-gray-200">
182
182
  {icon}
183
183
  </span>
184
184
  ) : null}
@@ -16,8 +16,8 @@ export function TableMenuInfoIcon({ className }: TableMenuInfoIconProps) {
16
16
  className={cn('shrink-0', className)}
17
17
  >
18
18
  <path
19
- d="M9.9974 13.3337V10.0003M9.9974 6.66699H10.0057M18.3307 10.0003C18.3307 14.6027 14.5998 18.3337 9.9974 18.3337C5.39502 18.3337 1.66406 14.6027 1.66406 10.0003C1.66406 5.39795 5.39502 1.66699 9.9974 1.66699C14.5998 1.66699 18.3307 5.39795 18.3307 10.0003Z"
20
- stroke="#B5BCC1"
19
+ d="M10.0013 13.3337V10.0003M10.0013 6.66699H10.0096M18.3346 10.0003C18.3346 14.6027 14.6037 18.3337 10.0013 18.3337C5.39893 18.3337 1.66797 14.6027 1.66797 10.0003C1.66797 5.39795 5.39893 1.66699 10.0013 1.66699C14.6037 1.66699 18.3346 5.39795 18.3346 10.0003Z"
20
+ stroke="currentColor"
21
21
  strokeWidth="2"
22
22
  strokeLinecap="round"
23
23
  strokeLinejoin="round"
package/src/web/index.ts CHANGED
@@ -96,6 +96,12 @@ export type { TableActionButtonProps, TableActionButtonVariant } from './compone
96
96
  export { TableIconText } from './components/TableIconText';
97
97
  export type { TableIconTextProps } from './components/TableIconText';
98
98
 
99
+ export { Modal } from './components/Modal';
100
+ export type { ModalFooterAlign, ModalFooterLayout, ModalProps } from './components/Modal';
101
+
102
+ export { ConfirmModal } from './components/ConfirmModal';
103
+ export type { ConfirmModalProps } from './components/ConfirmModal';
104
+
99
105
  export { useMediaQuery } from './hooks/useMediaQuery';
100
106
  export { useOnClickOutside } from './hooks/useOnClickOutside';
101
107
  export { cn } from './utils/cn';