@vetc-miniapp/ui-react 0.0.26 → 0.0.28

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 (60) hide show
  1. package/dist/index.js +1 -41
  2. package/package.json +3 -2
  3. package/dist/bridge.js +0 -20
  4. package/dist/components/app.js +0 -34
  5. package/dist/components/avatar/Avatar.js +0 -33
  6. package/dist/components/avatar/index.js +0 -1
  7. package/dist/components/bottom-sheet/BottomSheet.js +0 -70
  8. package/dist/components/bottom-sheet/index.js +0 -1
  9. package/dist/components/button/Button.js +0 -165
  10. package/dist/components/button/index.js +0 -1
  11. package/dist/components/button-group/ButtonGroup.js +0 -21
  12. package/dist/components/button-group/index.js +0 -1
  13. package/dist/components/card/Card.js +0 -35
  14. package/dist/components/card/index.js +0 -1
  15. package/dist/components/checkbox/Checkbox.js +0 -94
  16. package/dist/components/checkbox/index.js +0 -1
  17. package/dist/components/chip/Chip.js +0 -83
  18. package/dist/components/chip/index.js +0 -1
  19. package/dist/components/dialog/Dialog.js +0 -51
  20. package/dist/components/dialog/index.js +0 -1
  21. package/dist/components/divider/Divider.js +0 -18
  22. package/dist/components/divider/index.js +0 -1
  23. package/dist/components/input/Input.js +0 -51
  24. package/dist/components/input/index.js +0 -1
  25. package/dist/components/list/List.js +0 -72
  26. package/dist/components/list/index.js +0 -1
  27. package/dist/components/loading/Loading.js +0 -33
  28. package/dist/components/loading/index.js +0 -1
  29. package/dist/components/modal/Modal.js +0 -50
  30. package/dist/components/modal/index.js +0 -1
  31. package/dist/components/navigation-bar/NavigationBar.js +0 -70
  32. package/dist/components/navigation-bar/index.js +0 -1
  33. package/dist/components/radio/Radio.js +0 -88
  34. package/dist/components/radio/index.js +0 -1
  35. package/dist/components/select/Select.js +0 -30
  36. package/dist/components/select/index.js +0 -1
  37. package/dist/components/switch/Switch.js +0 -81
  38. package/dist/components/switch/index.js +0 -1
  39. package/dist/components/tab-bar/TabBar.js +0 -60
  40. package/dist/components/tab-bar/index.js +0 -1
  41. package/dist/components/textarea/Textarea.js +0 -33
  42. package/dist/components/textarea/index.js +0 -1
  43. package/dist/components/toast/Toast.js +0 -61
  44. package/dist/components/toast/index.js +0 -1
  45. package/dist/components/typography/Typography.js +0 -143
  46. package/dist/components/typography/index.js +0 -1
  47. package/dist/hooks/use-app-pause.js +0 -25
  48. package/dist/hooks/use-app-resume.js +0 -25
  49. package/dist/hooks/use-app-state.js +0 -1
  50. package/dist/hooks/use-did-hide.js +0 -20
  51. package/dist/hooks/use-did-show.js +0 -20
  52. package/dist/hooks/use-listener-scan-qr.js +0 -25
  53. package/dist/hooks/use-navigate.js +0 -23
  54. package/dist/hooks/use-tap-app-bar.js +0 -20
  55. package/dist/styles/VETCProvider.js +0 -124
  56. package/dist/tokens/colors.js +0 -75
  57. package/dist/tokens/index.js +0 -3
  58. package/dist/tokens/spacing.js +0 -56
  59. package/dist/tokens/typography.js +0 -57
  60. package/dist/types/app.js +0 -1
@@ -1,88 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /**
3
- * VETC Radio & RadioGroup
4
- * Figma: size=20px, states: default/hover/selected/disabled
5
- * variant: neutral (gray-90) | brand (green-40)
6
- */
7
- import { useState } from 'react';
8
- export function Radio({ label, description, checked, defaultChecked = false, disabled = false, variant = 'brand', onChange, value, id, className = '', style, }) {
9
- const [internalChecked, setInternalChecked] = useState(defaultChecked);
10
- const [hovered, setHovered] = useState(false);
11
- const isControlled = checked !== undefined;
12
- const isChecked = isControlled ? checked : internalChecked;
13
- const handleChange = () => {
14
- if (disabled || isChecked)
15
- return;
16
- if (!isControlled)
17
- setInternalChecked(true);
18
- onChange?.(true);
19
- };
20
- const accentColor = variant === 'brand'
21
- ? 'var(--vetc-color-brand)'
22
- : 'var(--vetc-gray-90)';
23
- const accentHover = variant === 'brand'
24
- ? 'var(--vetc-color-brand-hover)'
25
- : 'var(--vetc-gray-70)';
26
- const ringColor = disabled
27
- ? 'var(--vetc-color-border-disabled)'
28
- : isChecked
29
- ? (hovered ? accentHover : accentColor)
30
- : (hovered ? accentColor : 'var(--vetc-color-border)');
31
- const dotColor = disabled ? 'var(--vetc-color-text-disabled)' : accentColor;
32
- return (_jsxs("label", { htmlFor: id, className: `vetc-radio ${className}`, onMouseEnter: () => !disabled && setHovered(true), onMouseLeave: () => setHovered(false), style: {
33
- display: 'inline-flex',
34
- alignItems: description ? 'flex-start' : 'center',
35
- gap: 'var(--vetc-space-12)',
36
- cursor: disabled ? 'not-allowed' : 'pointer',
37
- userSelect: 'none',
38
- fontFamily: 'var(--vetc-font-family)',
39
- ...style,
40
- }, children: [_jsx("input", { id: id, type: "radio", checked: isChecked, disabled: disabled, value: value, onChange: handleChange, style: { position: 'absolute', opacity: 0, width: 0, height: 0, pointerEvents: 'none' } }), _jsx("span", { "aria-hidden": "true", style: {
41
- width: '20px',
42
- height: '20px',
43
- flexShrink: 0,
44
- borderRadius: '50%',
45
- border: `1.5px solid ${ringColor}`,
46
- backgroundColor: 'transparent',
47
- display: 'flex',
48
- alignItems: 'center',
49
- justifyContent: 'center',
50
- transition: 'border-color var(--vetc-transition-fast)',
51
- marginTop: description ? '2px' : 0,
52
- }, children: isChecked && (_jsx("span", { style: {
53
- width: '8px',
54
- height: '8px',
55
- borderRadius: '50%',
56
- backgroundColor: dotColor,
57
- flexShrink: 0,
58
- } })) }), (label || description) && (_jsxs("span", { style: { display: 'flex', flexDirection: 'column', gap: 'var(--vetc-space-2)' }, children: [label && (_jsx("span", { style: {
59
- fontSize: 'var(--vetc-font-size-base)',
60
- fontWeight: 'var(--vetc-font-weight-regular)',
61
- lineHeight: 'var(--vetc-line-height-relaxed)',
62
- color: disabled ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-color-text-primary)',
63
- }, children: label })), description && (_jsx("span", { style: {
64
- fontSize: 'var(--vetc-font-size-sm)',
65
- fontWeight: 'var(--vetc-font-weight-regular)',
66
- lineHeight: 'var(--vetc-line-height-relaxed)',
67
- color: disabled ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-color-text-secondary)',
68
- }, children: description }))] }))] }));
69
- }
70
- export function RadioGroup({ options, value, defaultValue, direction = 'vertical', disabled = false, variant = 'brand', onChange, className = '', style, }) {
71
- const [internalValue, setInternalValue] = useState(defaultValue);
72
- const isControlled = value !== undefined;
73
- const currentValue = isControlled ? value : internalValue;
74
- const handleChange = (optValue) => {
75
- if (!isControlled)
76
- setInternalValue(optValue);
77
- onChange?.(optValue);
78
- };
79
- return (_jsx("div", { role: "radiogroup", className: `vetc-radio-group ${className}`, style: {
80
- display: 'flex',
81
- flexDirection: direction === 'vertical' ? 'column' : 'row',
82
- flexWrap: direction === 'horizontal' ? 'wrap' : undefined,
83
- gap: direction === 'vertical' ? 'var(--vetc-space-12)' : 'var(--vetc-space-16)',
84
- fontFamily: 'var(--vetc-font-family)',
85
- ...style,
86
- }, children: options.map((opt) => (_jsx(Radio, { label: opt.label, description: opt.description, checked: currentValue === opt.value, disabled: opt.disabled ?? disabled, variant: variant, value: opt.value, onChange: () => handleChange(opt.value) }, String(opt.value)))) }));
87
- }
88
- export default Radio;
@@ -1 +0,0 @@
1
- export { Radio, RadioGroup } from './Radio';
@@ -1,30 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Select as AntSelect } from 'antd';
3
- export function Select({ label, placeholder, value, defaultValue, options = [], helperText, error, disabled = false, multiple = false, searchable = false, allowClear = false, loading = false, onChange, onSearch, id, className = '', style, required = false, popupMatchSelectWidth = true, }) {
4
- const hasError = !!error;
5
- const helperMsg = error ?? helperText;
6
- const helperColor = hasError
7
- ? 'var(--vetc-input-helper-color-error)'
8
- : 'var(--vetc-input-helper-color)';
9
- return (_jsxs("div", { className: `vetc-select-wrapper ${className}`, style: { display: 'flex', flexDirection: 'column', gap: 'var(--vetc-input-gap)', ...style }, children: [label && (_jsxs("label", { htmlFor: id, style: {
10
- fontFamily: 'var(--vetc-font-family)',
11
- fontSize: 'var(--vetc-input-label-font-size)',
12
- fontWeight: 'var(--vetc-input-label-font-weight)',
13
- lineHeight: 'var(--vetc-line-height-relaxed)',
14
- color: disabled
15
- ? 'var(--vetc-color-text-disabled)'
16
- : 'var(--vetc-input-label-color)',
17
- display: 'block',
18
- }, children: [label, required && (_jsx("span", { style: { color: 'var(--vetc-color-negative)', marginLeft: 'var(--vetc-space-2)' }, children: "*" }))] })), _jsx(AntSelect, { id: id, value: value, defaultValue: defaultValue, placeholder: placeholder, options: options, disabled: disabled, mode: multiple ? 'multiple' : undefined, showSearch: searchable, allowClear: allowClear, loading: loading, status: hasError ? 'error' : undefined, onChange: onChange, onSearch: onSearch, popupMatchSelectWidth: popupMatchSelectWidth, style: {
19
- height: 'var(--vetc-input-height)',
20
- width: '100%',
21
- fontFamily: 'var(--vetc-font-family)',
22
- fontSize: 'var(--vetc-input-font-size)',
23
- } }), helperMsg && (_jsx("span", { style: {
24
- fontFamily: 'var(--vetc-font-family)',
25
- fontSize: 'var(--vetc-input-helper-font-size)',
26
- lineHeight: 'var(--vetc-line-height-relaxed)',
27
- color: helperColor,
28
- }, children: helperMsg }))] }));
29
- }
30
- export default Select;
@@ -1 +0,0 @@
1
- export { Select } from './Select';
@@ -1,81 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- /**
3
- * VETC Switch
4
- * Figma: w=52px h=32px, thumb=28px, ON=brand-green, OFF=gray-30
5
- * variant: neutral (gray-90 on) | brand (green-40 on)
6
- */
7
- import { useState } from 'react';
8
- export function Switch({ label, description, labelPosition = 'right', checked, defaultChecked = false, disabled = false, loading = false, variant = 'brand', onChange, id, className = '', style, }) {
9
- const [internalChecked, setInternalChecked] = useState(defaultChecked);
10
- const isControlled = checked !== undefined;
11
- const isChecked = isControlled ? checked : internalChecked;
12
- const isDisabled = disabled || loading;
13
- const handleToggle = () => {
14
- if (isDisabled)
15
- return;
16
- const next = !isChecked;
17
- if (!isControlled)
18
- setInternalChecked(next);
19
- onChange?.(next);
20
- };
21
- const onColor = variant === 'brand'
22
- ? 'var(--vetc-switch-on-bg)'
23
- : 'var(--vetc-gray-90)';
24
- const trackBg = isDisabled
25
- ? 'var(--vetc-color-bg-disabled)'
26
- : isChecked
27
- ? onColor
28
- : 'var(--vetc-switch-off-bg)';
29
- const thumbLeft = isChecked ? 'calc(100% - 30px)' : '2px';
30
- const switchEl = (_jsxs("button", { id: id, type: "button", role: "switch", "aria-checked": isChecked, disabled: isDisabled, onClick: handleToggle, className: `vetc-switch ${className}`, style: {
31
- position: 'relative',
32
- display: 'inline-flex',
33
- alignItems: 'center',
34
- width: 'var(--vetc-switch-width)',
35
- height: 'var(--vetc-switch-height)',
36
- borderRadius: 'var(--vetc-radius-pill)',
37
- backgroundColor: trackBg,
38
- border: 'none',
39
- cursor: isDisabled ? 'not-allowed' : 'pointer',
40
- padding: 0,
41
- flexShrink: 0,
42
- transition: 'background-color var(--vetc-transition-fast)',
43
- outline: 'none',
44
- ...(label || description ? {} : style),
45
- }, children: [_jsx("span", { style: {
46
- position: 'absolute',
47
- left: thumbLeft,
48
- width: 'var(--vetc-switch-thumb-size)',
49
- height: 'var(--vetc-switch-thumb-size)',
50
- borderRadius: '50%',
51
- backgroundColor: isDisabled ? 'var(--vetc-gray-20)' : 'var(--vetc-white)',
52
- boxShadow: '0 1px 4px rgba(0,0,0,0.25)',
53
- transition: 'left var(--vetc-transition-fast)',
54
- display: 'flex',
55
- alignItems: 'center',
56
- justifyContent: 'center',
57
- }, children: loading && (_jsxs("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { animation: 'vetc-btn-spin 0.6s linear infinite' }, "aria-hidden": "true", children: [_jsx("circle", { cx: "6", cy: "6", r: "4", stroke: "var(--vetc-gray-30)", strokeWidth: "1.5" }), _jsx("path", { d: "M6 2a4 4 0 014 4", stroke: "var(--vetc-color-brand)", strokeWidth: "1.5", strokeLinecap: "round" })] })) }), _jsx("style", { children: `@keyframes vetc-btn-spin { to { transform: rotate(360deg); } }` })] }));
58
- if (!label && !description)
59
- return switchEl;
60
- const labelBlock = (_jsxs("span", { style: { display: 'flex', flexDirection: 'column', gap: 'var(--vetc-space-2)', flex: 1 }, children: [label && (_jsx("span", { style: {
61
- fontSize: 'var(--vetc-font-size-base)',
62
- fontWeight: 'var(--vetc-font-weight-regular)',
63
- lineHeight: 'var(--vetc-line-height-relaxed)',
64
- color: isDisabled ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-color-text-primary)',
65
- }, children: label })), description && (_jsx("span", { style: {
66
- fontSize: 'var(--vetc-font-size-sm)',
67
- fontWeight: 'var(--vetc-font-weight-regular)',
68
- lineHeight: 'var(--vetc-line-height-relaxed)',
69
- color: isDisabled ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-color-text-secondary)',
70
- }, children: description }))] }));
71
- return (_jsx("div", { style: {
72
- display: 'flex',
73
- alignItems: 'center',
74
- gap: 'var(--vetc-space-12)',
75
- flexDirection: labelPosition === 'left' ? 'row-reverse' : 'row',
76
- fontFamily: 'var(--vetc-font-family)',
77
- cursor: isDisabled ? 'not-allowed' : 'pointer',
78
- ...style,
79
- }, onClick: handleToggle, children: labelPosition === 'right' ? (_jsxs(_Fragment, { children: [switchEl, labelBlock] })) : (_jsxs(_Fragment, { children: [labelBlock, switchEl] })) }));
80
- }
81
- export default Switch;
@@ -1 +0,0 @@
1
- export { Switch } from './Switch';
@@ -1,60 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export function TabBar({ items, activeKey, onChange, variant = 'brand', backgroundColor, divider = true, className = '', style, id, }) {
3
- const activeColor = variant === 'brand'
4
- ? 'var(--vetc-tab-color-active)'
5
- : 'var(--vetc-color-text-primary)';
6
- return (_jsx("nav", { id: id, className: `vetc-tab-bar ${className}`, style: {
7
- display: 'flex',
8
- alignItems: 'stretch',
9
- height: 'var(--vetc-tab-height)',
10
- backgroundColor: backgroundColor ?? 'var(--vetc-tab-bg)',
11
- borderTop: divider ? `1px solid var(--vetc-tab-border)` : 'none',
12
- fontFamily: 'var(--vetc-font-family)',
13
- ...style,
14
- }, children: items.map((item) => {
15
- const isActive = item.key === activeKey;
16
- const color = item.disabled
17
- ? 'var(--vetc-tab-color-disabled)'
18
- : isActive
19
- ? activeColor
20
- : 'var(--vetc-tab-color-inactive)';
21
- return (_jsxs("button", { disabled: item.disabled, onClick: () => !item.disabled && onChange?.(item.key), "aria-current": isActive ? 'page' : undefined, "aria-label": item.label, className: `vetc-tab-bar__item${isActive ? ' vetc-tab-bar__item--active' : ''}`, style: {
22
- flex: 1,
23
- display: 'flex',
24
- flexDirection: 'column',
25
- alignItems: 'center',
26
- justifyContent: 'center',
27
- gap: 'var(--vetc-space-2)',
28
- background: 'none',
29
- border: 'none',
30
- cursor: item.disabled ? 'not-allowed' : 'pointer',
31
- padding: `var(--vetc-space-6) 0`,
32
- position: 'relative',
33
- opacity: item.disabled ? 0.5 : 1,
34
- transition: `color var(--vetc-transition-fast)`,
35
- color,
36
- }, children: [_jsxs("div", { style: { position: 'relative', display: 'inline-flex' }, children: [_jsx("span", { style: { color, display: 'flex', fontSize: '24px', lineHeight: 1 }, children: isActive && item.activeIcon ? item.activeIcon : item.icon }), item.badge !== undefined && (_jsx("span", { style: {
37
- position: 'absolute',
38
- top: 'calc(-1 * var(--vetc-space-4))',
39
- right: 'calc(-1 * var(--vetc-space-8))',
40
- minWidth: 'var(--vetc-tab-badge-size)',
41
- height: 'var(--vetc-tab-badge-size)',
42
- backgroundColor: 'var(--vetc-tab-badge-bg)',
43
- borderRadius: 'var(--vetc-radius-pill)',
44
- fontSize: 'var(--vetc-tab-badge-font-size)',
45
- fontWeight: 'var(--vetc-font-weight-semibold)',
46
- color: 'var(--vetc-tab-badge-text)',
47
- display: 'flex',
48
- alignItems: 'center',
49
- justifyContent: 'center',
50
- padding: `0 var(--vetc-space-4)`,
51
- lineHeight: 1,
52
- }, children: item.badge }))] }), _jsx("span", { style: {
53
- fontSize: 'var(--vetc-tab-label-size)',
54
- fontWeight: 'var(--vetc-tab-label-weight)',
55
- color,
56
- lineHeight: 'var(--vetc-line-height-relaxed)',
57
- }, children: item.label })] }, item.key));
58
- }) }));
59
- }
60
- export default TabBar;
@@ -1 +0,0 @@
1
- export { TabBar } from './TabBar';
@@ -1,33 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Input as AntInput } from 'antd';
3
- const { TextArea: AntTextArea } = AntInput;
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 ? 'var(--vetc-color-text-disabled)' : 'var(--vetc-input-label-color)',
11
- display: 'block',
12
- }, children: [children, required && _jsx("span", { style: { color: 'var(--vetc-color-negative)', marginLeft: 'var(--vetc-space-2)' }, children: "*" })] }));
13
- }
14
- export function Textarea({ label, placeholder, value, defaultValue, helperText, error, disabled = false, readOnly = false, maxLength, showCount = false, rows = 4, autoSize, onChange, onFocus, onBlur, id, name, className = '', style, required = false, }) {
15
- const hasError = !!error;
16
- const helperMsg = error ?? helperText;
17
- const helperColor = hasError
18
- ? 'var(--vetc-input-helper-color-error)'
19
- : 'var(--vetc-input-helper-color)';
20
- return (_jsxs("div", { className: `vetc-textarea-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(AntTextArea, { id: id, name: name, value: value, defaultValue: defaultValue, placeholder: placeholder, disabled: disabled, readOnly: readOnly, maxLength: maxLength, showCount: showCount, rows: rows, autoSize: autoSize, status: hasError ? 'error' : undefined, onChange: (e) => onChange?.(e.target.value), onFocus: onFocus, onBlur: onBlur, style: {
21
- borderRadius: 'var(--vetc-input-radius)',
22
- padding: 'var(--vetc-input-padding-x)',
23
- fontSize: 'var(--vetc-input-font-size)',
24
- fontFamily: 'var(--vetc-font-family)',
25
- resize: 'vertical',
26
- } }), helperMsg && (_jsx("span", { style: {
27
- fontFamily: 'var(--vetc-font-family)',
28
- fontSize: 'var(--vetc-input-helper-font-size)',
29
- lineHeight: 'var(--vetc-line-height-relaxed)',
30
- color: helperColor,
31
- }, children: helperMsg }))] }));
32
- }
33
- export default Textarea;
@@ -1 +0,0 @@
1
- export { Textarea } from './Textarea';
@@ -1,61 +0,0 @@
1
- import { notification, message } from 'antd';
2
- /** Shared notification style — references CSS vars */
3
- const toastStyle = {
4
- borderRadius: 'var(--vetc-toast-radius)',
5
- fontFamily: 'var(--vetc-font-family)',
6
- };
7
- /**
8
- * Static programmatic toast API
9
- * Usage: toast.success('Message')
10
- */
11
- export const toast = {
12
- show(opts) {
13
- const { type = 'default', message: msg, description, duration = 3, placement = 'top', icon, onClose, } = opts;
14
- if (type === 'default') {
15
- message.open({ type: 'info', content: msg, duration, onClose });
16
- return;
17
- }
18
- notification[type]({
19
- message: msg,
20
- description,
21
- duration,
22
- placement,
23
- icon,
24
- onClose,
25
- style: toastStyle,
26
- });
27
- },
28
- success: (msg, description) => toast.show({ message: msg, description, type: 'success' }),
29
- error: (msg, description) => toast.show({ message: msg, description, type: 'error' }),
30
- warning: (msg, description) => toast.show({ message: msg, description, type: 'warning' }),
31
- info: (msg, description) => toast.show({ message: msg, description, type: 'info' }),
32
- };
33
- /**
34
- * Hook-based toast — requires VETCProvider (antd App wrapper)
35
- */
36
- export function useToast() {
37
- const [api, contextHolder] = notification.useNotification();
38
- const show = (opts) => {
39
- const { type = 'info', message: msg, description, duration = 3, placement = 'top', icon, onClose, } = opts;
40
- api[type === 'default' ? 'info' : type]({
41
- message: msg,
42
- description,
43
- duration,
44
- placement,
45
- icon,
46
- onClose,
47
- style: toastStyle,
48
- });
49
- };
50
- return {
51
- contextHolder,
52
- toast: {
53
- show,
54
- success: (msg, description) => show({ message: msg, description, type: 'success' }),
55
- error: (msg, description) => show({ message: msg, description, type: 'error' }),
56
- warning: (msg, description) => show({ message: msg, description, type: 'warning' }),
57
- info: (msg, description) => show({ message: msg, description, type: 'info' }),
58
- },
59
- };
60
- }
61
- export default toast;
@@ -1 +0,0 @@
1
- export { toast, useToast } from './Toast';
@@ -1,143 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- // ── Typography style map — dùng CSS vars thay vì hardcode ──────────────────
3
- const styles = {
4
- display4xl: {
5
- fontSize: 'var(--vetc-font-size-4xl)',
6
- fontWeight: 'var(--vetc-font-weight-bold)',
7
- lineHeight: 'var(--vetc-line-height-tight)',
8
- },
9
- display3xl: {
10
- fontSize: 'var(--vetc-font-size-3xl)',
11
- fontWeight: 'var(--vetc-font-weight-bold)',
12
- lineHeight: 'var(--vetc-line-height-tight)',
13
- },
14
- display2xl: {
15
- fontSize: 'var(--vetc-font-size-2xl)',
16
- fontWeight: 'var(--vetc-font-weight-bold)',
17
- lineHeight: 'var(--vetc-line-height-tight)',
18
- },
19
- headlineXl: {
20
- fontSize: 'var(--vetc-font-size-xl)',
21
- fontWeight: 'var(--vetc-font-weight-bold)',
22
- lineHeight: 'var(--vetc-line-height-normal)',
23
- },
24
- headlineLg: {
25
- fontSize: 'var(--vetc-font-size-lg)',
26
- fontWeight: 'var(--vetc-font-weight-semibold)',
27
- lineHeight: 'var(--vetc-line-height-normal)',
28
- },
29
- titleBase: {
30
- fontSize: 'var(--vetc-font-size-base)',
31
- fontWeight: 'var(--vetc-font-weight-semibold)',
32
- lineHeight: 'var(--vetc-line-height-relaxed)',
33
- letterSpacing: 'var(--vetc-letter-spacing-sm)',
34
- },
35
- titleSm: {
36
- fontSize: 'var(--vetc-font-size-sm)',
37
- fontWeight: 'var(--vetc-font-weight-semibold)',
38
- lineHeight: 'var(--vetc-line-height-relaxed)',
39
- letterSpacing: 'var(--vetc-letter-spacing-sm)',
40
- },
41
- labelBase: {
42
- fontSize: 'var(--vetc-font-size-base)',
43
- fontWeight: 'var(--vetc-font-weight-semibold)',
44
- lineHeight: 'var(--vetc-line-height-relaxed)',
45
- },
46
- labelSm: {
47
- fontSize: 'var(--vetc-font-size-sm)',
48
- fontWeight: 'var(--vetc-font-weight-semibold)',
49
- lineHeight: 'var(--vetc-line-height-relaxed)',
50
- letterSpacing: 'var(--vetc-letter-spacing-lg)',
51
- },
52
- labelXs: {
53
- fontSize: 'var(--vetc-font-size-xs)',
54
- fontWeight: 'var(--vetc-font-weight-semibold)',
55
- lineHeight: 'var(--vetc-line-height-relaxed)',
56
- letterSpacing: 'var(--vetc-letter-spacing-lg)',
57
- },
58
- labelXxs: {
59
- fontSize: 'var(--vetc-font-size-2xs)',
60
- fontWeight: 'var(--vetc-font-weight-semibold)',
61
- lineHeight: 'var(--vetc-line-height-relaxed)',
62
- letterSpacing: 'var(--vetc-letter-spacing-lg)',
63
- },
64
- bodyBase: {
65
- fontSize: 'var(--vetc-font-size-base)',
66
- fontWeight: 'var(--vetc-font-weight-regular)',
67
- lineHeight: 'var(--vetc-line-height-relaxed)',
68
- letterSpacing: 'var(--vetc-letter-spacing-sm)',
69
- },
70
- bodySm: {
71
- fontSize: 'var(--vetc-font-size-sm)',
72
- fontWeight: 'var(--vetc-font-weight-regular)',
73
- lineHeight: 'var(--vetc-line-height-relaxed)',
74
- letterSpacing: 'var(--vetc-letter-spacing-md)',
75
- },
76
- bodyXs: {
77
- fontSize: 'var(--vetc-font-size-xs)',
78
- fontWeight: 'var(--vetc-font-weight-regular)',
79
- lineHeight: 'var(--vetc-line-height-relaxed)',
80
- letterSpacing: 'var(--vetc-letter-spacing-lg)',
81
- },
82
- body2xs: {
83
- fontSize: 'var(--vetc-font-size-2xs)',
84
- fontWeight: 'var(--vetc-font-weight-regular)',
85
- lineHeight: 'var(--vetc-line-height-relaxed)',
86
- letterSpacing: 'var(--vetc-letter-spacing-lg)',
87
- },
88
- };
89
- const colorMap = {
90
- primary: 'var(--vetc-color-text-primary)',
91
- secondary: 'var(--vetc-color-text-secondary)',
92
- tertiary: 'var(--vetc-color-text-tertiary)',
93
- disabled: 'var(--vetc-color-text-disabled)',
94
- brand: 'var(--vetc-color-brand)',
95
- error: 'var(--vetc-color-text-error)',
96
- warning: 'var(--vetc-color-warning)',
97
- success: 'var(--vetc-color-positive)',
98
- inherit: 'inherit',
99
- };
100
- export function Typography({ variant = 'bodyBase', color = 'primary', strikethrough = false, underline = false, truncate = false, lines, as: Tag = 'span', children, className = '', style, id, }) {
101
- const variantStyle = styles[variant] ?? styles.bodyBase;
102
- const colorValue = colorMap[color];
103
- const combinedStyle = {
104
- fontFamily: 'var(--vetc-font-family)',
105
- margin: 0,
106
- padding: 0,
107
- ...variantStyle,
108
- color: colorValue,
109
- textDecoration: strikethrough ? 'line-through' : underline ? 'underline' : 'none',
110
- ...(truncate && !lines
111
- ? { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }
112
- : {}),
113
- ...(lines
114
- ? {
115
- display: '-webkit-box',
116
- WebkitLineClamp: lines,
117
- WebkitBoxOrient: 'vertical',
118
- overflow: 'hidden',
119
- }
120
- : {}),
121
- ...style,
122
- };
123
- return (_jsx(Tag, { id: id, className: `vetc-text vetc-text--${variant} ${className}`, style: combinedStyle, children: children }));
124
- }
125
- // ── Convenience shorthands ──────────────────────────────────────────────────
126
- export function Display({ level = '2xl', ...props }) {
127
- return _jsx(Typography, { ...props, variant: `display${level}`, as: props.as ?? 'h1' });
128
- }
129
- export function Headline({ level = 'xl', ...props }) {
130
- return _jsx(Typography, { ...props, variant: level === 'xl' ? 'headlineXl' : 'headlineLg', as: props.as ?? 'h2' });
131
- }
132
- export function Title({ size = 'base', ...props }) {
133
- return _jsx(Typography, { ...props, variant: size === 'base' ? 'titleBase' : 'titleSm', as: props.as ?? 'h3' });
134
- }
135
- export function Label({ size = 'base', ...props }) {
136
- const variantMap = { base: 'labelBase', sm: 'labelSm', xs: 'labelXs', xxs: 'labelXxs' };
137
- return _jsx(Typography, { ...props, variant: variantMap[size], as: props.as ?? 'span' });
138
- }
139
- export function Body({ size = 'base', ...props }) {
140
- const variantMap = { base: 'bodyBase', sm: 'bodySm', xs: 'bodyXs', '2xs': 'body2xs' };
141
- return _jsx(Typography, { ...props, variant: variantMap[size], as: props.as ?? 'p' });
142
- }
143
- export default Typography;
@@ -1 +0,0 @@
1
- export { Typography, Display, Headline, Title, Label, Body } from './Typography';
@@ -1,25 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- /**
3
- * useAppPause — trigger khi Native App đi vào background.
4
- */
5
- export function useAppPause(callback) {
6
- const savedCallback = useRef(callback);
7
- useEffect(() => {
8
- savedCallback.current = callback;
9
- }, [callback]);
10
- useEffect(() => {
11
- if (typeof window === "undefined" || !window.MiniApp)
12
- return;
13
- const bridge = window.MiniApp;
14
- const handler = () => {
15
- try {
16
- savedCallback.current?.();
17
- }
18
- catch (err) {
19
- console.error("[useAppPause error]", err);
20
- }
21
- };
22
- bridge.on("appPause", handler);
23
- return () => bridge.off("appPause", handler);
24
- }, []);
25
- }
@@ -1,25 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- /**
3
- * useAppResume — trigger khi Native App quay lại foreground.
4
- */
5
- export function useAppResume(callback) {
6
- const savedCallback = useRef(callback);
7
- useEffect(() => {
8
- savedCallback.current = callback;
9
- }, [callback]);
10
- useEffect(() => {
11
- if (typeof window === "undefined" || !window.MiniApp)
12
- return;
13
- const bridge = window.MiniApp;
14
- const handler = () => {
15
- try {
16
- savedCallback.current?.();
17
- }
18
- catch (err) {
19
- console.error("[useAppResume error]", err);
20
- }
21
- };
22
- bridge.on("appResume", handler);
23
- return () => bridge.off("appResume", handler);
24
- }, []);
25
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,20 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- export function useDidHide(route, callback) {
3
- const saved = useRef(callback);
4
- // luôn giữ callback mới nhất
5
- useEffect(() => {
6
- saved.current = callback;
7
- }, [callback]);
8
- useEffect(() => {
9
- if (typeof window === "undefined" || !window.MiniApp)
10
- return;
11
- const bridge = window.MiniApp;
12
- const handler = (data) => {
13
- if (data?.route === route) {
14
- saved.current?.(data);
15
- }
16
- };
17
- bridge.on("didHide", handler);
18
- return () => bridge.off("didHide", handler);
19
- }, [route]);
20
- }
@@ -1,20 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- export function useDidShow(route, callback) {
3
- const saved = useRef(callback);
4
- // luôn giữ callback mới nhất
5
- useEffect(() => {
6
- saved.current = callback;
7
- }, [callback]);
8
- useEffect(() => {
9
- if (typeof window === "undefined" || !window.MiniApp)
10
- return;
11
- const bridge = window.MiniApp;
12
- const handler = (data) => {
13
- if (data?.route === route) {
14
- saved.current?.(data);
15
- }
16
- };
17
- bridge.on("didShow", handler);
18
- return () => bridge.off("didShow", handler);
19
- }, [route]);
20
- }
@@ -1,25 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- /**
3
- * useListenerScanQr — lắng nghe kết quả scan QR từ Native.
4
- */
5
- export function useListenerScanQr(callback) {
6
- const savedCallback = useRef(callback);
7
- useEffect(() => {
8
- savedCallback.current = callback;
9
- }, [callback]);
10
- useEffect(() => {
11
- if (typeof window === "undefined" || !window.MiniApp)
12
- return;
13
- const bridge = window.MiniApp;
14
- const handler = (data) => {
15
- try {
16
- savedCallback.current?.(data);
17
- }
18
- catch (err) {
19
- console.error("[useListenerScanQr error]", err);
20
- }
21
- };
22
- bridge.on("scanQrResult", handler);
23
- return () => bridge.off("scanQrResult", handler);
24
- }, []);
25
- }