@vetc-miniapp/ui-react 0.0.24 → 0.0.25

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 (172) hide show
  1. package/dist/bridge.d.ts +11 -0
  2. package/dist/bridge.js +20 -0
  3. package/dist/components/app.d.ts +6 -0
  4. package/dist/components/app.js +34 -0
  5. package/dist/components/avatar/Avatar.d.ts +21 -0
  6. package/dist/components/avatar/Avatar.js +33 -0
  7. package/dist/components/avatar/index.js +1 -0
  8. package/dist/components/bottom-sheet/BottomSheet.d.ts +19 -0
  9. package/dist/components/bottom-sheet/BottomSheet.js +70 -0
  10. package/dist/components/bottom-sheet/index.js +1 -0
  11. package/dist/components/button/Button.d.ts +32 -0
  12. package/dist/components/button/Button.js +165 -0
  13. package/dist/components/button/index.js +1 -0
  14. package/dist/components/button-group/ButtonGroup.d.ts +28 -0
  15. package/dist/components/button-group/ButtonGroup.js +21 -0
  16. package/dist/components/button-group/index.js +1 -0
  17. package/dist/components/card/Card.d.ts +18 -0
  18. package/dist/components/card/Card.js +35 -0
  19. package/dist/components/card/index.js +1 -0
  20. package/dist/components/checkbox/Checkbox.d.ts +41 -0
  21. package/dist/components/checkbox/Checkbox.js +94 -0
  22. package/dist/components/checkbox/index.js +1 -0
  23. package/dist/components/chip/Chip.d.ts +24 -0
  24. package/dist/components/chip/Chip.js +83 -0
  25. package/dist/components/chip/index.js +1 -0
  26. package/dist/components/dialog/Dialog.d.ts +19 -0
  27. package/dist/components/dialog/Dialog.js +51 -0
  28. package/dist/components/dialog/index.js +1 -0
  29. package/dist/components/divider/Divider.d.ts +16 -0
  30. package/dist/components/divider/Divider.js +18 -0
  31. package/dist/components/divider/index.js +1 -0
  32. package/dist/components/input/Input.d.ts +40 -0
  33. package/dist/components/input/Input.js +51 -0
  34. package/dist/components/input/index.js +1 -0
  35. package/dist/components/list/List.d.ts +31 -0
  36. package/dist/components/list/List.js +72 -0
  37. package/dist/components/list/index.js +1 -0
  38. package/dist/components/loading/Loading.d.ts +28 -0
  39. package/dist/components/loading/Loading.js +33 -0
  40. package/dist/components/loading/index.js +1 -0
  41. package/dist/components/modal/Modal.d.ts +38 -0
  42. package/dist/components/modal/Modal.js +50 -0
  43. package/dist/components/modal/index.js +1 -0
  44. package/dist/components/navigation-bar/NavigationBar.d.ts +44 -0
  45. package/dist/components/navigation-bar/NavigationBar.js +70 -0
  46. package/dist/components/navigation-bar/index.js +1 -0
  47. package/dist/components/radio/Radio.d.ts +40 -0
  48. package/dist/components/radio/Radio.js +88 -0
  49. package/dist/components/radio/index.js +1 -0
  50. package/dist/components/select/Select.d.ts +29 -0
  51. package/dist/components/select/Select.js +30 -0
  52. package/dist/components/select/index.js +1 -0
  53. package/dist/components/switch/Switch.d.ts +23 -0
  54. package/dist/components/switch/Switch.js +81 -0
  55. package/dist/components/switch/index.js +1 -0
  56. package/dist/components/tab-bar/TabBar.d.ts +28 -0
  57. package/dist/components/tab-bar/TabBar.js +60 -0
  58. package/dist/components/tab-bar/index.js +1 -0
  59. package/dist/components/textarea/Textarea.d.ts +31 -0
  60. package/dist/components/textarea/Textarea.js +33 -0
  61. package/dist/components/textarea/index.js +1 -0
  62. package/dist/components/toast/Toast.d.ts +41 -0
  63. package/dist/components/toast/Toast.js +61 -0
  64. package/dist/components/toast/index.js +1 -0
  65. package/dist/components/typography/Typography.d.ts +45 -0
  66. package/dist/components/typography/Typography.js +143 -0
  67. package/dist/components/typography/index.js +1 -0
  68. package/dist/hooks/use-app-pause.d.ts +6 -0
  69. package/dist/hooks/use-app-pause.js +29 -0
  70. package/dist/hooks/use-app-resume.d.ts +6 -0
  71. package/dist/hooks/use-app-resume.js +28 -0
  72. package/{src/ui-react/hooks/use-app-state.ts → dist/hooks/use-app-state.d.ts} +0 -1
  73. package/dist/hooks/use-app-state.js +1 -0
  74. package/dist/hooks/use-did-hide.d.ts +6 -0
  75. package/dist/hooks/use-did-hide.js +21 -0
  76. package/dist/hooks/use-did-show.d.ts +6 -0
  77. package/dist/hooks/use-did-show.js +21 -0
  78. package/dist/hooks/use-listener-scan-qr.d.ts +21 -0
  79. package/dist/hooks/use-listener-scan-qr.js +29 -0
  80. package/dist/hooks/use-navigate.d.ts +8 -0
  81. package/dist/hooks/use-navigate.js +23 -0
  82. package/dist/hooks/use-tap-app-bar.d.ts +6 -0
  83. package/dist/hooks/use-tap-app-bar.js +21 -0
  84. package/{src/ui-react/index.ts → dist/index.d.ts} +1 -30
  85. package/dist/index.js +41 -0
  86. package/dist/styles/VETCProvider.d.ts +114 -0
  87. package/dist/styles/VETCProvider.js +124 -0
  88. package/{src/ui-react → dist}/styles/tokens.css +22 -1
  89. package/dist/tokens/colors.d.ts +127 -0
  90. package/dist/tokens/colors.js +75 -0
  91. package/dist/tokens/index.js +3 -0
  92. package/dist/tokens/spacing.d.ts +56 -0
  93. package/dist/tokens/spacing.js +56 -0
  94. package/dist/tokens/typography.d.ts +121 -0
  95. package/dist/tokens/typography.js +57 -0
  96. package/dist/types/app.d.ts +21 -0
  97. package/dist/types/app.js +1 -0
  98. package/package.json +13 -7
  99. package/src/dist/ui-react/index.js +0 -2
  100. package/src/dist/ui-react/index.js.LICENSE.txt +0 -11
  101. package/src/ui-react/bridge.js +0 -36
  102. package/src/ui-react/bridge.ts +0 -48
  103. package/src/ui-react/components/app.d.ts +0 -7
  104. package/src/ui-react/components/app.jsx +0 -80
  105. package/src/ui-react/components/app.tsx +0 -42
  106. package/src/ui-react/components/app1.js +0 -101
  107. package/src/ui-react/components/avatar/Avatar.tsx +0 -88
  108. package/src/ui-react/components/bottom-sheet/BottomSheet.tsx +0 -149
  109. package/src/ui-react/components/button/Button.tsx +0 -246
  110. package/src/ui-react/components/button-group/ButtonGroup.tsx +0 -108
  111. package/src/ui-react/components/card/Card.tsx +0 -77
  112. package/src/ui-react/components/checkbox/Checkbox.tsx +0 -232
  113. package/src/ui-react/components/chip/Chip.tsx +0 -137
  114. package/src/ui-react/components/dialog/Dialog.tsx +0 -135
  115. package/src/ui-react/components/divider/Divider.tsx +0 -54
  116. package/src/ui-react/components/input/Input.tsx +0 -195
  117. package/src/ui-react/components/list/List.tsx +0 -180
  118. package/src/ui-react/components/loading/Loading.tsx +0 -121
  119. package/src/ui-react/components/modal/Modal.tsx +0 -116
  120. package/src/ui-react/components/navigation-bar/NavigationBar.tsx +0 -188
  121. package/src/ui-react/components/radio/Radio.tsx +0 -216
  122. package/src/ui-react/components/select/Select.tsx +0 -109
  123. package/src/ui-react/components/switch/Switch.tsx +0 -164
  124. package/src/ui-react/components/tab-bar/TabBar.tsx +0 -137
  125. package/src/ui-react/components/textarea/Textarea.tsx +0 -109
  126. package/src/ui-react/components/toast/Toast.ts +0 -98
  127. package/src/ui-react/components/typography/Typography.tsx +0 -201
  128. package/src/ui-react/hooks/use-app-pause.js +0 -35
  129. package/src/ui-react/hooks/use-app-pause.ts +0 -33
  130. package/src/ui-react/hooks/use-app-resume.js +0 -37
  131. package/src/ui-react/hooks/use-app-resume.ts +0 -32
  132. package/src/ui-react/hooks/use-app-state.js +0 -35
  133. package/src/ui-react/hooks/use-did-hide.js +0 -25
  134. package/src/ui-react/hooks/use-did-hide.ts +0 -34
  135. package/src/ui-react/hooks/use-did-show.js +0 -26
  136. package/src/ui-react/hooks/use-did-show.ts +0 -34
  137. package/src/ui-react/hooks/use-listener-scan-qr.js +0 -33
  138. package/src/ui-react/hooks/use-listener-scan-qr.ts +0 -52
  139. package/src/ui-react/hooks/use-navigate.js +0 -15
  140. package/src/ui-react/hooks/use-navigate.ts +0 -41
  141. package/src/ui-react/hooks/use-tap-app-bar.js +0 -26
  142. package/src/ui-react/hooks/use-tap-app-bar.ts +0 -34
  143. package/src/ui-react/index.js +0 -9
  144. package/src/ui-react/styles/VETCProvider.tsx +0 -152
  145. package/src/ui-react/tokens/colors.ts +0 -91
  146. package/src/ui-react/tokens/spacing.ts +0 -59
  147. package/src/ui-react/tokens/typography.ts +0 -63
  148. package/src/ui-react/tokens_vetc.json +0 -1517
  149. package/src/ui-react/types/app.js +0 -30
  150. package/src/ui-react/types/app.ts +0 -32
  151. /package/{src/ui-react/components/avatar/index.ts → dist/components/avatar/index.d.ts} +0 -0
  152. /package/{src/ui-react/components/bottom-sheet/index.ts → dist/components/bottom-sheet/index.d.ts} +0 -0
  153. /package/{src/ui-react/components/button/index.ts → dist/components/button/index.d.ts} +0 -0
  154. /package/{src/ui-react/components/button-group/index.ts → dist/components/button-group/index.d.ts} +0 -0
  155. /package/{src/ui-react/components/card/index.ts → dist/components/card/index.d.ts} +0 -0
  156. /package/{src/ui-react/components/checkbox/index.ts → dist/components/checkbox/index.d.ts} +0 -0
  157. /package/{src/ui-react/components/chip/index.ts → dist/components/chip/index.d.ts} +0 -0
  158. /package/{src/ui-react/components/dialog/index.ts → dist/components/dialog/index.d.ts} +0 -0
  159. /package/{src/ui-react/components/divider/index.ts → dist/components/divider/index.d.ts} +0 -0
  160. /package/{src/ui-react/components/input/index.ts → dist/components/input/index.d.ts} +0 -0
  161. /package/{src/ui-react/components/list/index.ts → dist/components/list/index.d.ts} +0 -0
  162. /package/{src/ui-react/components/loading/index.ts → dist/components/loading/index.d.ts} +0 -0
  163. /package/{src/ui-react/components/modal/index.ts → dist/components/modal/index.d.ts} +0 -0
  164. /package/{src/ui-react/components/navigation-bar/index.ts → dist/components/navigation-bar/index.d.ts} +0 -0
  165. /package/{src/ui-react/components/radio/index.ts → dist/components/radio/index.d.ts} +0 -0
  166. /package/{src/ui-react/components/select/index.ts → dist/components/select/index.d.ts} +0 -0
  167. /package/{src/ui-react/components/switch/index.ts → dist/components/switch/index.d.ts} +0 -0
  168. /package/{src/ui-react/components/tab-bar/index.ts → dist/components/tab-bar/index.d.ts} +0 -0
  169. /package/{src/ui-react/components/textarea/index.ts → dist/components/textarea/index.d.ts} +0 -0
  170. /package/{src/ui-react/components/toast/index.ts → dist/components/toast/index.d.ts} +0 -0
  171. /package/{src/ui-react/components/typography/index.ts → dist/components/typography/index.d.ts} +0 -0
  172. /package/{src/ui-react/tokens/index.ts → dist/tokens/index.d.ts} +0 -0
@@ -0,0 +1,94 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * VETC Checkbox & CheckboxGroup
4
+ * Figma: size=20px, touch-area=48px, states: default/hover/pressed/selected/indeterminate/disabled
5
+ * variant: neutral (gray-90) | brand (green-40)
6
+ */
7
+ import { useState } from 'react';
8
+ const CheckIcon = () => (_jsx("svg", { width: "12", height: "9", viewBox: "0 0 12 9", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M1 4L4.5 7.5L11 1", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
9
+ const IndeterminateIcon = () => (_jsx("svg", { width: "10", height: "2", viewBox: "0 0 10 2", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M1 1H9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
10
+ export function Checkbox({ label, description, checked, defaultChecked = false, indeterminate = false, disabled = false, variant = 'brand', onChange, value, id, className = '', style, }) {
11
+ const [internalChecked, setInternalChecked] = useState(defaultChecked);
12
+ const [hovered, setHovered] = useState(false);
13
+ const isControlled = checked !== undefined;
14
+ const isChecked = isControlled ? checked : internalChecked;
15
+ const isActive = isChecked || indeterminate;
16
+ const handleChange = () => {
17
+ if (disabled)
18
+ return;
19
+ const next = !isChecked;
20
+ if (!isControlled)
21
+ setInternalChecked(next);
22
+ onChange?.(next);
23
+ };
24
+ const accentColor = variant === 'brand'
25
+ ? 'var(--vetc-color-brand)'
26
+ : 'var(--vetc-gray-90)';
27
+ const accentHover = variant === 'brand'
28
+ ? 'var(--vetc-color-brand-hover)'
29
+ : 'var(--vetc-gray-70)';
30
+ let boxBg = 'transparent';
31
+ let boxBorder = disabled ? 'var(--vetc-color-border-disabled)' : hovered ? accentColor : 'var(--vetc-color-border)';
32
+ let iconColor = 'var(--vetc-white)';
33
+ if (isActive) {
34
+ boxBg = disabled ? 'var(--vetc-color-bg-disabled)' : accentColor;
35
+ boxBorder = disabled ? 'var(--vetc-color-border-disabled)' : hovered ? accentHover : accentColor;
36
+ iconColor = disabled ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-white)';
37
+ if (disabled)
38
+ boxBg = 'var(--vetc-color-bg-disabled)';
39
+ }
40
+ return (_jsxs("label", { htmlFor: id, className: `vetc-checkbox ${className}`, onMouseEnter: () => !disabled && setHovered(true), onMouseLeave: () => setHovered(false), style: {
41
+ display: 'inline-flex',
42
+ alignItems: description ? 'flex-start' : 'center',
43
+ gap: 'var(--vetc-space-12)',
44
+ cursor: disabled ? 'not-allowed' : 'pointer',
45
+ userSelect: 'none',
46
+ fontFamily: 'var(--vetc-font-family)',
47
+ ...style,
48
+ }, children: [_jsx("input", { id: id, type: "checkbox", checked: isChecked, disabled: disabled, value: value, onChange: handleChange, style: { position: 'absolute', opacity: 0, width: 0, height: 0, pointerEvents: 'none' }, "aria-checked": indeterminate ? 'mixed' : isChecked }), _jsxs("span", { "aria-hidden": "true", style: {
49
+ width: '20px',
50
+ height: '20px',
51
+ flexShrink: 0,
52
+ borderRadius: 'var(--vetc-radius-xs)',
53
+ border: `1.5px solid ${boxBorder}`,
54
+ backgroundColor: boxBg,
55
+ display: 'flex',
56
+ alignItems: 'center',
57
+ justifyContent: 'center',
58
+ transition: 'background-color var(--vetc-transition-fast), border-color var(--vetc-transition-fast)',
59
+ color: iconColor,
60
+ marginTop: description ? '2px' : 0,
61
+ }, children: [isChecked && !indeterminate && _jsx(CheckIcon, {}), indeterminate && _jsx(IndeterminateIcon, {})] }), (label || description) && (_jsxs("span", { style: { display: 'flex', flexDirection: 'column', gap: 'var(--vetc-space-2)' }, children: [label && (_jsx("span", { style: {
62
+ fontSize: 'var(--vetc-font-size-base)',
63
+ fontWeight: 'var(--vetc-font-weight-regular)',
64
+ lineHeight: 'var(--vetc-line-height-relaxed)',
65
+ color: disabled ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-color-text-primary)',
66
+ }, children: label })), description && (_jsx("span", { style: {
67
+ fontSize: 'var(--vetc-font-size-sm)',
68
+ fontWeight: 'var(--vetc-font-weight-regular)',
69
+ lineHeight: 'var(--vetc-line-height-relaxed)',
70
+ color: disabled ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-color-text-secondary)',
71
+ }, children: description }))] }))] }));
72
+ }
73
+ export function CheckboxGroup({ options, value, defaultValue = [], direction = 'vertical', disabled = false, variant = 'brand', onChange, className = '', style, }) {
74
+ const [internalValue, setInternalValue] = useState(defaultValue);
75
+ const isControlled = value !== undefined;
76
+ const currentValue = isControlled ? value : internalValue;
77
+ const handleChange = (optValue, checked) => {
78
+ const next = checked
79
+ ? [...currentValue, optValue]
80
+ : currentValue.filter((v) => v !== optValue);
81
+ if (!isControlled)
82
+ setInternalValue(next);
83
+ onChange?.(next);
84
+ };
85
+ return (_jsx("div", { className: `vetc-checkbox-group ${className}`, style: {
86
+ display: 'flex',
87
+ flexDirection: direction === 'vertical' ? 'column' : 'row',
88
+ flexWrap: direction === 'horizontal' ? 'wrap' : undefined,
89
+ gap: direction === 'vertical' ? 'var(--vetc-space-12)' : 'var(--vetc-space-16)',
90
+ fontFamily: 'var(--vetc-font-family)',
91
+ ...style,
92
+ }, children: options.map((opt) => (_jsx(Checkbox, { label: opt.label, description: opt.description, checked: currentValue.includes(opt.value), disabled: opt.disabled ?? disabled, variant: variant, value: opt.value, onChange: (chk) => handleChange(opt.value, chk) }, String(opt.value)))) }));
93
+ }
94
+ export default Checkbox;
@@ -0,0 +1 @@
1
+ export { Checkbox, CheckboxGroup } from './Checkbox';
@@ -0,0 +1,24 @@
1
+ /**
2
+ * VETC Chip / Tag — tokenized
3
+ * Figma: Chip page (7 types × 3 styles)
4
+ */
5
+ import React from 'react';
6
+ export type ChipStyle = 'filled' | 'outlined' | 'tinted';
7
+ export type ChipType = 'default' | 'brand' | 'positive' | 'negative' | 'warning' | 'info';
8
+ export type ChipShape = 'pill' | 'rounded';
9
+ export interface ChipProps {
10
+ style?: ChipStyle;
11
+ type?: ChipType;
12
+ shape?: ChipShape;
13
+ size?: 'md' | 'sm';
14
+ icon?: React.ReactNode;
15
+ closable?: boolean;
16
+ onClose?: () => void;
17
+ onClick?: () => void;
18
+ children?: React.ReactNode;
19
+ className?: string;
20
+ css?: React.CSSProperties;
21
+ id?: string;
22
+ }
23
+ export declare function Chip({ style, type, shape, size, icon, closable, onClose, onClick, children, className, css, id, }: ChipProps): import("react/jsx-runtime").JSX.Element;
24
+ export default Chip;
@@ -0,0 +1,83 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Tag as AntTag } from 'antd';
3
+ // Map type → CSS vars (from tokens.css --vetc-chip-*)
4
+ const typeVarMap = {
5
+ default: {
6
+ bg: 'var(--vetc-chip-default-bg)',
7
+ border: 'var(--vetc-chip-default-border)',
8
+ text: 'var(--vetc-chip-default-text)',
9
+ filledBg: 'var(--vetc-chip-default-filled-bg)',
10
+ },
11
+ brand: {
12
+ bg: 'var(--vetc-chip-brand-bg)',
13
+ border: 'var(--vetc-chip-brand-border)',
14
+ text: 'var(--vetc-chip-brand-text)',
15
+ filledBg: 'var(--vetc-chip-brand-filled-bg)',
16
+ },
17
+ positive: {
18
+ bg: 'var(--vetc-chip-positive-bg)',
19
+ border: 'var(--vetc-chip-positive-border)',
20
+ text: 'var(--vetc-chip-positive-text)',
21
+ filledBg: 'var(--vetc-chip-positive-filled-bg)',
22
+ },
23
+ negative: {
24
+ bg: 'var(--vetc-chip-negative-bg)',
25
+ border: 'var(--vetc-chip-negative-border)',
26
+ text: 'var(--vetc-chip-negative-text)',
27
+ filledBg: 'var(--vetc-chip-negative-filled-bg)',
28
+ },
29
+ warning: {
30
+ bg: 'var(--vetc-chip-warning-bg)',
31
+ border: 'var(--vetc-chip-warning-border)',
32
+ text: 'var(--vetc-chip-warning-text)',
33
+ filledBg: 'var(--vetc-chip-warning-filled-bg)',
34
+ },
35
+ info: {
36
+ bg: 'var(--vetc-chip-info-bg)',
37
+ border: 'var(--vetc-chip-info-border)',
38
+ text: 'var(--vetc-chip-info-text)',
39
+ filledBg: 'var(--vetc-chip-info-filled-bg)',
40
+ },
41
+ };
42
+ export function Chip({ style = 'tinted', type = 'default', shape = 'pill', size = 'md', icon, closable = false, onClose, onClick, children, className = '', css, id, }) {
43
+ const vars = typeVarMap[type];
44
+ const height = size === 'md' ? 'var(--vetc-chip-height-md)' : 'var(--vetc-chip-height-sm)';
45
+ const paddingX = size === 'md' ? 'var(--vetc-chip-padding-x-md)' : 'var(--vetc-chip-padding-x-sm)';
46
+ const fontSize = size === 'md' ? 'var(--vetc-chip-font-size-md)' : 'var(--vetc-chip-font-size-sm)';
47
+ const fontWeight = 'var(--vetc-chip-font-weight)';
48
+ const borderRadius = shape === 'pill' ? 'var(--vetc-chip-radius-pill)' : 'var(--vetc-chip-radius-rounded)';
49
+ let bg = vars.bg;
50
+ let border = `1px solid ${vars.border}`;
51
+ let textColor = vars.text;
52
+ if (style === 'filled') {
53
+ bg = vars.filledBg;
54
+ border = 'none';
55
+ textColor = 'var(--vetc-white)';
56
+ }
57
+ else if (style === 'outlined') {
58
+ bg = 'transparent';
59
+ border = `1px solid ${vars.border}`;
60
+ textColor = vars.text;
61
+ }
62
+ // tinted: bg + border (default)
63
+ return (_jsx(AntTag, { id: id, closable: closable, onClose: (e) => { e.preventDefault(); onClose?.(); }, onClick: onClick, icon: icon, className: `vetc-chip vetc-chip--${style} vetc-chip--${type} ${className}`, style: {
64
+ display: 'inline-flex',
65
+ alignItems: 'center',
66
+ height,
67
+ padding: `0 ${paddingX}`,
68
+ borderRadius,
69
+ background: bg,
70
+ border,
71
+ color: textColor,
72
+ fontSize,
73
+ fontWeight: fontWeight,
74
+ fontFamily: 'var(--vetc-font-family)',
75
+ cursor: onClick ? 'pointer' : 'default',
76
+ userSelect: 'none',
77
+ lineHeight: 1,
78
+ gap: 'var(--vetc-space-4)',
79
+ transition: 'var(--vetc-transition-fast)',
80
+ ...css,
81
+ }, children: children }));
82
+ }
83
+ export default Chip;
@@ -0,0 +1 @@
1
+ export { Chip } from './Chip';
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ export interface DialogProps {
3
+ open: boolean;
4
+ /** Optional image URL shown at the top of the dialog */
5
+ image?: string;
6
+ title?: React.ReactNode;
7
+ description?: React.ReactNode;
8
+ okText?: string;
9
+ cancelText?: string;
10
+ okDisabled?: boolean;
11
+ okLoading?: boolean;
12
+ okDanger?: boolean;
13
+ onOk?: () => void;
14
+ onCancel?: () => void;
15
+ /** Close dialog when clicking outside (default: true) */
16
+ maskClosable?: boolean;
17
+ }
18
+ export declare function Dialog({ open, image, title, description, okText, cancelText, okDisabled, okLoading, okDanger, onOk, onCancel, maskClosable, }: DialogProps): React.ReactPortal;
19
+ export default Dialog;
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { Button } from '../button';
5
+ export function Dialog({ open, image, title, description, okText = 'Xác nhận', cancelText = 'Hủy', okDisabled = false, okLoading = false, okDanger = false, onOk, onCancel, maskClosable = true, }) {
6
+ useEffect(() => {
7
+ if (open)
8
+ document.body.style.overflow = 'hidden';
9
+ else
10
+ document.body.style.overflow = '';
11
+ return () => { document.body.style.overflow = ''; };
12
+ }, [open]);
13
+ if (!open)
14
+ return null;
15
+ const hasContent = title || description;
16
+ return createPortal(_jsx("div", { style: {
17
+ position: 'fixed',
18
+ inset: 0,
19
+ backgroundColor: 'var(--vetc-dialog-overlay)',
20
+ display: 'flex',
21
+ alignItems: 'center',
22
+ justifyContent: 'center',
23
+ zIndex: 1000,
24
+ padding: '0 var(--vetc-space-24)',
25
+ }, onClick: maskClosable ? onCancel : undefined, children: _jsxs("div", { style: {
26
+ width: '100%',
27
+ maxWidth: 'var(--vetc-dialog-width)',
28
+ backgroundColor: 'var(--vetc-dialog-bg)',
29
+ borderRadius: 'var(--vetc-dialog-radius)',
30
+ overflow: 'hidden',
31
+ boxShadow: 'var(--vetc-shadow-lg)',
32
+ fontFamily: 'var(--vetc-font-family)',
33
+ }, onClick: e => e.stopPropagation(), children: [image && (_jsx("div", { style: { width: '100%', height: 'var(--vetc-dialog-image-height)', overflow: 'hidden', flexShrink: 0 }, children: _jsx("img", { src: image, alt: "", style: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' } }) })), hasContent && (_jsxs("div", { style: { padding: 'var(--vetc-dialog-padding)' }, children: [title && (_jsx("div", { style: {
34
+ fontSize: 'var(--vetc-dialog-title-size)',
35
+ fontWeight: 'var(--vetc-dialog-title-weight)',
36
+ color: 'var(--vetc-color-text-primary)',
37
+ lineHeight: 'var(--vetc-line-height-relaxed)',
38
+ marginBottom: description ? 'var(--vetc-space-8)' : 0,
39
+ }, children: title })), description && (_jsx("div", { style: {
40
+ fontSize: 'var(--vetc-dialog-desc-size)',
41
+ color: 'var(--vetc-dialog-desc-color)',
42
+ lineHeight: 'var(--vetc-line-height-relaxed)',
43
+ }, children: description }))] })), _jsxs("div", { style: {
44
+ display: 'flex',
45
+ gap: 'var(--vetc-dialog-btn-gap)',
46
+ padding: hasContent
47
+ ? `0 var(--vetc-dialog-padding) var(--vetc-dialog-padding)`
48
+ : 'var(--vetc-dialog-padding)',
49
+ }, children: [onCancel && (_jsx(Button, { block: true, style: "outlined", variant: "neutral", onClick: onCancel, children: cancelText })), _jsx(Button, { block: true, style: okDanger ? 'danger' : 'filled', loading: okLoading, disabled: okDisabled, onClick: onOk, children: okText })] })] }) }), document.body);
50
+ }
51
+ export default Dialog;
@@ -0,0 +1 @@
1
+ export { Dialog } from './Dialog';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * VETC Divider — tokenized
3
+ */
4
+ import React from 'react';
5
+ export interface DividerProps {
6
+ orientation?: 'horizontal' | 'vertical';
7
+ label?: React.ReactNode;
8
+ labelAlign?: 'left' | 'center' | 'right';
9
+ thickness?: number;
10
+ color?: string;
11
+ margin?: string;
12
+ className?: string;
13
+ style?: React.CSSProperties;
14
+ }
15
+ export declare function Divider({ orientation, label, labelAlign, thickness, color, margin, className, style, }: DividerProps): import("react/jsx-runtime").JSX.Element;
16
+ export default Divider;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Divider as AntDivider } from 'antd';
3
+ export function Divider({ orientation = 'horizontal', label, labelAlign = 'center', thickness = 1, color, margin, className = '', style, }) {
4
+ const isVertical = orientation === 'vertical';
5
+ return (_jsx(AntDivider, { type: isVertical ? 'vertical' : 'horizontal', orientationMargin: labelAlign !== 'center' ? 0 : undefined, orientation: labelAlign !== 'center' ? labelAlign : undefined, className: `vetc-divider ${className}`, style: {
6
+ borderColor: color ?? 'var(--vetc-divider-color)',
7
+ borderTopWidth: !isVertical ? thickness : undefined,
8
+ borderLeftWidth: isVertical ? thickness : undefined,
9
+ margin: margin ?? (isVertical
10
+ ? `0 var(--vetc-divider-margin-v)`
11
+ : `var(--vetc-divider-margin-h) 0`),
12
+ fontFamily: 'var(--vetc-font-family)',
13
+ fontSize: 'var(--vetc-divider-label-size)',
14
+ color: 'var(--vetc-divider-label-color)',
15
+ ...style,
16
+ }, children: label }));
17
+ }
18
+ export default Divider;
@@ -0,0 +1 @@
1
+ export { Divider } from './Divider';
@@ -0,0 +1,40 @@
1
+ /**
2
+ * VETC Input / TextField & PasswordInput Components
3
+ * All style values use CSS custom properties from tokens.css
4
+ * Figma: Text field page — height 48px, radius 8px, padding-x 12px
5
+ */
6
+ import React from 'react';
7
+ export type InputStatus = 'default' | 'error' | 'success';
8
+ export interface InputProps {
9
+ label?: string;
10
+ placeholder?: string;
11
+ value?: string;
12
+ defaultValue?: string;
13
+ helperText?: string;
14
+ /** Status affecting border color */
15
+ status?: InputStatus;
16
+ /** Error message — sets status=error automatically */
17
+ error?: string;
18
+ disabled?: boolean;
19
+ readOnly?: boolean;
20
+ maxLength?: number;
21
+ showCount?: boolean;
22
+ prefix?: React.ReactNode;
23
+ suffix?: React.ReactNode;
24
+ allowClear?: boolean;
25
+ onChange?: (value: string, event: React.ChangeEvent<HTMLInputElement>) => void;
26
+ onFocus?: React.FocusEventHandler<HTMLInputElement>;
27
+ onBlur?: React.FocusEventHandler<HTMLInputElement>;
28
+ onPressEnter?: React.KeyboardEventHandler<HTMLInputElement>;
29
+ type?: string;
30
+ id?: string;
31
+ name?: string;
32
+ className?: string;
33
+ style?: React.CSSProperties;
34
+ required?: boolean;
35
+ }
36
+ export declare function Input({ label, placeholder, value, defaultValue, helperText, status, error, disabled, readOnly, maxLength, showCount, prefix, suffix, allowClear, onChange, onFocus, onBlur, onPressEnter, type, id, name, className, style, required, }: InputProps): import("react/jsx-runtime").JSX.Element;
37
+ export interface PasswordInputProps extends Omit<InputProps, 'type' | 'suffix' | 'allowClear'> {
38
+ }
39
+ export declare function PasswordInput({ label, placeholder, value, defaultValue, helperText, status, error, disabled, readOnly, maxLength, onChange, onFocus, onBlur, id, name, className, style, required, }: PasswordInputProps): import("react/jsx-runtime").JSX.Element;
40
+ export default Input;
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Input as AntInput } from 'antd';
3
+ // ── Shared label/helper sub-components ───────────────────────────────────────
4
+ function FieldLabel({ htmlFor, required, disabled, children }) {
5
+ return (_jsxs("label", { htmlFor: htmlFor, style: {
6
+ fontFamily: 'var(--vetc-font-family)',
7
+ fontSize: 'var(--vetc-input-label-font-size)',
8
+ fontWeight: 'var(--vetc-input-label-font-weight)',
9
+ lineHeight: 'var(--vetc-line-height-relaxed)',
10
+ color: disabled
11
+ ? 'var(--vetc-color-text-disabled)'
12
+ : 'var(--vetc-input-label-color)',
13
+ display: 'block',
14
+ }, children: [children, required && (_jsx("span", { style: { color: 'var(--vetc-color-negative)', marginLeft: 'var(--vetc-space-2)' }, children: "*" }))] }));
15
+ }
16
+ function HelperText({ color, children }) {
17
+ return (_jsx("span", { style: {
18
+ fontFamily: 'var(--vetc-font-family)',
19
+ fontSize: 'var(--vetc-input-helper-font-size)',
20
+ lineHeight: 'var(--vetc-line-height-relaxed)',
21
+ color,
22
+ }, children: children }));
23
+ }
24
+ const inputFieldStyle = {
25
+ height: 'var(--vetc-input-height)',
26
+ borderRadius: 'var(--vetc-input-radius)',
27
+ paddingInline: 'var(--vetc-input-padding-x)',
28
+ fontSize: 'var(--vetc-input-font-size)',
29
+ fontFamily: 'var(--vetc-font-family)',
30
+ };
31
+ export function Input({ label, placeholder, value, defaultValue, helperText, status = 'default', error, disabled = false, readOnly = false, maxLength, showCount = false, prefix, suffix, allowClear = false, onChange, onFocus, onBlur, onPressEnter, type = 'text', id, name, className = '', style, required = false, }) {
32
+ const hasError = !!error;
33
+ const resolvedStatus = hasError ? 'error' : status;
34
+ const antStatus = resolvedStatus === 'error' ? 'error' : undefined;
35
+ const helperMsg = error ?? helperText;
36
+ const helperColor = resolvedStatus === 'error'
37
+ ? 'var(--vetc-input-helper-color-error)'
38
+ : 'var(--vetc-input-helper-color)';
39
+ return (_jsxs("div", { className: `vetc-input-wrapper ${className}`, style: { display: 'flex', flexDirection: 'column', gap: 'var(--vetc-input-gap)', ...style }, children: [label && _jsx(FieldLabel, { htmlFor: id, required: required, disabled: disabled, children: label }), _jsx(AntInput, { id: id, name: name, type: type, value: value, defaultValue: defaultValue, placeholder: placeholder, disabled: disabled, readOnly: readOnly, maxLength: maxLength, showCount: showCount, prefix: prefix, suffix: suffix, allowClear: allowClear, status: antStatus, onChange: (e) => onChange?.(e.target.value, e), onFocus: onFocus, onBlur: onBlur, onPressEnter: onPressEnter, style: inputFieldStyle }), helperMsg && _jsx(HelperText, { color: helperColor, children: helperMsg })] }));
40
+ }
41
+ export function PasswordInput({ label, placeholder, value, defaultValue, helperText, status = 'default', error, disabled = false, readOnly = false, maxLength, onChange, onFocus, onBlur, id, name, className = '', style, required = false, }) {
42
+ const hasError = !!error;
43
+ const resolvedStatus = hasError ? 'error' : status;
44
+ const antStatus = resolvedStatus === 'error' ? 'error' : undefined;
45
+ const helperMsg = error ?? helperText;
46
+ const helperColor = hasError
47
+ ? 'var(--vetc-input-helper-color-error)'
48
+ : 'var(--vetc-input-helper-color)';
49
+ return (_jsxs("div", { className: `vetc-input-wrapper ${className ?? ''}`, style: { display: 'flex', flexDirection: 'column', gap: 'var(--vetc-input-gap)', ...style }, children: [label && _jsx(FieldLabel, { htmlFor: id, required: required, disabled: disabled, children: label }), _jsx(AntInput.Password, { id: id, name: name, value: value, defaultValue: defaultValue, placeholder: placeholder, disabled: disabled, readOnly: readOnly, maxLength: maxLength, status: antStatus, onChange: (e) => onChange?.(e.target.value, e), onFocus: onFocus, onBlur: onBlur, style: inputFieldStyle }), helperMsg && _jsx(HelperText, { color: helperColor, children: helperMsg })] }));
50
+ }
51
+ export default Input;
@@ -0,0 +1 @@
1
+ export { Input, PasswordInput } from './Input';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * VETC List & ListItem — tokenized
3
+ * Figma: List item page — height 56px, padding-x 16px
4
+ */
5
+ import React from 'react';
6
+ export interface ListItemProps {
7
+ leading?: React.ReactNode;
8
+ title: React.ReactNode;
9
+ description?: React.ReactNode;
10
+ trailing?: React.ReactNode;
11
+ /** Show right chevron */
12
+ arrow?: boolean;
13
+ /** Bottom divider line */
14
+ divider?: boolean;
15
+ onClick?: () => void;
16
+ disabled?: boolean;
17
+ className?: string;
18
+ style?: React.CSSProperties;
19
+ id?: string;
20
+ }
21
+ export declare function ListItem({ leading, title, description, trailing, arrow, divider, onClick, disabled, className, style, id, }: ListItemProps): import("react/jsx-runtime").JSX.Element;
22
+ export interface ListProps<T = any> {
23
+ items: T[];
24
+ renderItem: (item: T, index: number) => React.ReactNode;
25
+ bordered?: boolean;
26
+ className?: string;
27
+ style?: React.CSSProperties;
28
+ id?: string;
29
+ }
30
+ export declare function List<T = any>({ items, renderItem, bordered, className, style, id, }: ListProps<T>): import("react/jsx-runtime").JSX.Element;
31
+ export default ListItem;
@@ -0,0 +1,72 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * VETC List & ListItem — tokenized
4
+ * Figma: List item page — height 56px, padding-x 16px
5
+ */
6
+ import React from 'react';
7
+ // ── ChevronRight Icon ─────────────────────────────────────────────────────────
8
+ function ChevronRightIcon({ disabled }) {
9
+ return (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M7.5 5L12.5 10L7.5 15", stroke: disabled ? 'var(--vetc-color-icon-disabled)' : 'var(--vetc-color-icon-muted)', strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
10
+ }
11
+ export function ListItem({ leading, title, description, trailing, arrow = false, divider = true, onClick, disabled = false, className = '', style, id, }) {
12
+ const isClickable = !!onClick && !disabled;
13
+ return (_jsxs("div", { id: id, role: isClickable ? 'button' : undefined, tabIndex: isClickable ? 0 : undefined, className: `vetc-list-item ${className}`, onClick: !disabled ? onClick : undefined, onKeyDown: isClickable ? (e) => { if (e.key === 'Enter' || e.key === ' ')
14
+ onClick?.(); } : undefined, style: {
15
+ display: 'flex',
16
+ alignItems: 'center',
17
+ minHeight: 'var(--vetc-list-item-height)',
18
+ padding: `0 var(--vetc-list-item-padding-x)`,
19
+ gap: 'var(--vetc-list-item-gap)',
20
+ cursor: isClickable ? 'pointer' : 'default',
21
+ borderBottom: divider ? `1px solid var(--vetc-list-item-border)` : 'none',
22
+ backgroundColor: 'var(--vetc-list-item-bg)',
23
+ opacity: disabled ? 0.5 : 1,
24
+ fontFamily: 'var(--vetc-font-family)',
25
+ transition: `background-color var(--vetc-transition-fast)`,
26
+ outline: 'none',
27
+ ...style,
28
+ }, onMouseEnter: (e) => {
29
+ if (isClickable)
30
+ e.currentTarget.style.backgroundColor = 'var(--vetc-list-item-bg-hover)';
31
+ }, onMouseLeave: (e) => {
32
+ if (isClickable)
33
+ e.currentTarget.style.backgroundColor = 'var(--vetc-list-item-bg)';
34
+ }, children: [leading && (_jsx("div", { style: {
35
+ flexShrink: 0,
36
+ display: 'flex',
37
+ alignItems: 'center',
38
+ color: 'var(--vetc-list-item-icon-color)',
39
+ }, children: leading })), _jsxs("div", { style: { flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 'var(--vetc-space-2)' }, children: [_jsx("span", { style: {
40
+ fontSize: 'var(--vetc-list-item-title-size)',
41
+ fontWeight: 'var(--vetc-list-item-title-weight)',
42
+ color: disabled ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-list-item-title-color)',
43
+ lineHeight: 'var(--vetc-line-height-relaxed)',
44
+ overflow: 'hidden',
45
+ textOverflow: 'ellipsis',
46
+ whiteSpace: 'nowrap',
47
+ }, children: title }), description && (_jsx("span", { style: {
48
+ fontSize: 'var(--vetc-list-item-desc-size)',
49
+ fontWeight: 'var(--vetc-font-weight-regular)',
50
+ color: disabled ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-list-item-desc-color)',
51
+ lineHeight: 'var(--vetc-line-height-relaxed)',
52
+ overflow: 'hidden',
53
+ textOverflow: 'ellipsis',
54
+ whiteSpace: 'nowrap',
55
+ }, children: description }))] }), (trailing || arrow) && (_jsxs("div", { style: {
56
+ flexShrink: 0,
57
+ display: 'flex',
58
+ alignItems: 'center',
59
+ gap: 'var(--vetc-space-8)',
60
+ color: 'var(--vetc-list-item-icon-color)',
61
+ }, children: [trailing, arrow && _jsx(ChevronRightIcon, { disabled: disabled })] }))] }));
62
+ }
63
+ export function List({ items, renderItem, bordered = false, className = '', style, id, }) {
64
+ return (_jsx("div", { id: id, className: `vetc-list ${className}`, style: {
65
+ border: bordered ? `1px solid var(--vetc-color-border-variant)` : 'none',
66
+ borderRadius: bordered ? 'var(--vetc-card-radius)' : 0,
67
+ overflow: 'hidden',
68
+ backgroundColor: 'var(--vetc-color-bg)',
69
+ ...style,
70
+ }, children: items.map((item, index) => (_jsx(React.Fragment, { children: renderItem(item, index) }, index))) }));
71
+ }
72
+ export default ListItem;
@@ -0,0 +1 @@
1
+ export { List, ListItem } from './List';
@@ -0,0 +1,28 @@
1
+ /**
2
+ * VETC Loading — tokenized
3
+ */
4
+ import React from 'react';
5
+ export type SpinnerSize = 'sm' | 'md' | 'lg';
6
+ export interface SpinnerProps {
7
+ size?: SpinnerSize;
8
+ color?: string;
9
+ fullscreen?: boolean;
10
+ tip?: string;
11
+ children?: React.ReactNode;
12
+ spinning?: boolean;
13
+ className?: string;
14
+ style?: React.CSSProperties;
15
+ }
16
+ export declare function Spinner({ size, color, fullscreen, tip, children, spinning, className, style, }: SpinnerProps): import("react/jsx-runtime").JSX.Element;
17
+ export interface SkeletonProps {
18
+ rows?: number;
19
+ avatar?: boolean;
20
+ avatarSize?: number;
21
+ title?: boolean;
22
+ loading?: boolean;
23
+ className?: string;
24
+ style?: React.CSSProperties;
25
+ children?: React.ReactNode;
26
+ }
27
+ export declare function SkeletonLoader({ rows, avatar, avatarSize, title, loading, className, style, children, }: SkeletonProps): import("react/jsx-runtime").JSX.Element;
28
+ export default Spinner;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Spin, Skeleton } from 'antd';
3
+ import { LoadingOutlined } from '@ant-design/icons';
4
+ const spinnerSizeVarMap = {
5
+ sm: 'var(--vetc-spinner-size-sm)',
6
+ md: 'var(--vetc-spinner-size-md)',
7
+ lg: 'var(--vetc-spinner-size-lg)',
8
+ };
9
+ // antd icon needs numeric fontSize — CSS var won't work directly
10
+ const spinnerPxMap = { sm: 16, md: 24, lg: 40 };
11
+ export function Spinner({ size = 'md', color, fullscreen = false, tip, children, spinning = true, className = '', style, }) {
12
+ const icon = (_jsx(LoadingOutlined, { style: { fontSize: spinnerPxMap[size], color: color ?? 'var(--vetc-spinner-color)' }, spin: true }));
13
+ if (children) {
14
+ return (_jsx(Spin, { spinning: spinning, indicator: icon, tip: tip, className: `vetc-spinner ${className}`, style: style, children: children }));
15
+ }
16
+ if (fullscreen) {
17
+ return (_jsx("div", { className: `vetc-spinner-overlay ${className}`, style: {
18
+ position: 'fixed',
19
+ inset: 0,
20
+ display: 'flex',
21
+ alignItems: 'center',
22
+ justifyContent: 'center',
23
+ backgroundColor: 'var(--vetc-color-overlay)',
24
+ zIndex: 9999,
25
+ ...style,
26
+ }, children: _jsx(Spin, { spinning: spinning, indicator: icon, tip: tip }) }));
27
+ }
28
+ return (_jsx("div", { className: `vetc-spinner ${className}`, style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', ...style }, children: _jsx(Spin, { spinning: spinning, indicator: icon, tip: tip }) }));
29
+ }
30
+ export function SkeletonLoader({ rows = 3, avatar = false, avatarSize = 40, title = true, loading = true, className = '', style, children, }) {
31
+ return (_jsx(Skeleton, { active: true, loading: loading, avatar: avatar ? { size: avatarSize, shape: 'circle' } : false, title: title, paragraph: { rows }, className: `vetc-skeleton ${className}`, style: style, children: children }));
32
+ }
33
+ export default Spinner;
@@ -0,0 +1 @@
1
+ export { Spinner, SkeletonLoader } from './Loading';
@@ -0,0 +1,38 @@
1
+ /**
2
+ * VETC Modal / Dialog — tokenized
3
+ * Figma: Dialog page — width 344px, radius 16px, overlay rgba(0,0,0,0.4)
4
+ */
5
+ import React from 'react';
6
+ export interface ModalProps {
7
+ open: boolean;
8
+ title?: React.ReactNode;
9
+ children?: React.ReactNode;
10
+ /** null = hide footer, undefined = default buttons, ReactNode = custom */
11
+ footer?: React.ReactNode | null;
12
+ okText?: string;
13
+ cancelText?: string;
14
+ okDisabled?: boolean;
15
+ okLoading?: boolean;
16
+ okDanger?: boolean;
17
+ onOk?: () => void;
18
+ onCancel?: () => void;
19
+ maskClosable?: boolean;
20
+ closable?: boolean;
21
+ width?: number | string;
22
+ className?: string;
23
+ style?: React.CSSProperties;
24
+ id?: string;
25
+ }
26
+ export declare function Modal({ open, title, children, footer, okText, cancelText, okDisabled, okLoading, okDanger, onOk, onCancel, maskClosable, closable, width, className, style, id, }: ModalProps): import("react/jsx-runtime").JSX.Element;
27
+ export declare function useConfirm(): {
28
+ confirm: (opts: {
29
+ title: string;
30
+ content?: React.ReactNode;
31
+ okText?: string;
32
+ cancelText?: string;
33
+ okDanger?: boolean;
34
+ onOk?: () => void | Promise<void>;
35
+ onCancel?: () => void;
36
+ }) => void;
37
+ };
38
+ export default Modal;