@khoangd/ui 0.1.0
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/README.md +54 -0
- package/dist/ErrorView.d.ts +18 -0
- package/dist/ErrorView.d.ts.map +1 -0
- package/dist/ErrorView.js +17 -0
- package/dist/ErrorView.js.map +1 -0
- package/dist/ImageWithFallback.d.ts +12 -0
- package/dist/ImageWithFallback.d.ts.map +1 -0
- package/dist/ImageWithFallback.js +13 -0
- package/dist/ImageWithFallback.js.map +1 -0
- package/dist/VirtualizedList.d.ts +18 -0
- package/dist/VirtualizedList.d.ts.map +1 -0
- package/dist/VirtualizedList.js +36 -0
- package/dist/VirtualizedList.js.map +1 -0
- package/dist/dataDisplay.d.ts +8 -0
- package/dist/dataDisplay.d.ts.map +1 -0
- package/dist/dataDisplay.js +6 -0
- package/dist/dataDisplay.js.map +1 -0
- package/dist/feedback.d.ts +31 -0
- package/dist/feedback.d.ts.map +1 -0
- package/dist/feedback.js +20 -0
- package/dist/feedback.js.map +1 -0
- package/dist/forms.d.ts +82 -0
- package/dist/forms.d.ts.map +1 -0
- package/dist/forms.js +44 -0
- package/dist/forms.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +23 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +30 -0
- package/dist/layout.js.map +1 -0
- package/dist/primitives.d.ts +23 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +10 -0
- package/dist/primitives.js.map +1 -0
- package/package.json +75 -0
- package/src/styles.css +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @khoangd/ui
|
|
2
|
+
|
|
3
|
+
Accessible, props-driven React primitives. Import `@khoangd/ui/styles.css` once in the consumer entry point.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Button, Grid, Input, InputSelect, Stack, Switch, Textarea } from '@khoangd/ui';
|
|
7
|
+
import '@khoangd/ui/styles.css';
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
The package has no WTS store, API, socket, router or trading workflow dependency.
|
|
11
|
+
|
|
12
|
+
Stable subpaths are available when a resource only needs one layer:
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Button, Input } from '@khoangd/ui/primitives';
|
|
16
|
+
import {
|
|
17
|
+
Checkbox,
|
|
18
|
+
DatePicker,
|
|
19
|
+
FormField,
|
|
20
|
+
InputSelect,
|
|
21
|
+
RadioGroup,
|
|
22
|
+
SegmentedControl,
|
|
23
|
+
Switch,
|
|
24
|
+
Textarea,
|
|
25
|
+
} from '@khoangd/ui/forms';
|
|
26
|
+
import { Grid, Stack, Wrapper } from '@khoangd/ui/layout';
|
|
27
|
+
import { ErrorBoundary, Loading, Overlay, Skeleton } from '@khoangd/ui/feedback';
|
|
28
|
+
import { Badge } from '@khoangd/ui/data-display';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`InputSelect` is a native select intended for local option lists. Search, remote data,
|
|
32
|
+
translations and Ant Design adapters remain in the consuming application.
|
|
33
|
+
|
|
34
|
+
`IconButton` requires an accessible `label`. `Badge` and `EmptyState` accept icon nodes so
|
|
35
|
+
consumers can use `@khoangd/icons` without coupling the UI package to a specific icon set.
|
|
36
|
+
|
|
37
|
+
## Shared display components
|
|
38
|
+
|
|
39
|
+
`ImageWithFallback` and `ErrorView` now live here; `@khoangd/trading-ui` keeps compatibility re-exports. Image fallback recovers when `src` changes. Load the stylesheet for the image's default aspect ratio/fit/radius without Tailwind.
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { VirtualizedList } from '@khoangd/ui/virtualized-list';
|
|
43
|
+
|
|
44
|
+
<VirtualizedList
|
|
45
|
+
items={rows}
|
|
46
|
+
itemHeight={32}
|
|
47
|
+
containerHeight={320}
|
|
48
|
+
getItemKey={(row) => row.id}
|
|
49
|
+
renderItem={(row) => <div style={{ height: 32 }}>{row.label}</div>}
|
|
50
|
+
emptyContent={<span>No data</span>}
|
|
51
|
+
/>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`VirtualizedList` supports either `renderItem(item, absoluteIndex)` or `renderContent(visibleItems)`. Rows must have the specified fixed height; viewport height is controlled by `containerHeight`. `onScroll` receives the native scroll event. Routing, data fetching, translations and empty-state assets belong to the consumer. Stable `getItemKey` values preserve row identity when sorting/filtering.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ErrorViewProps {
|
|
3
|
+
/** Optional icon (e.g. SVG component) */
|
|
4
|
+
icon?: React.ReactNode;
|
|
5
|
+
/** Message or description */
|
|
6
|
+
description?: React.ReactNode;
|
|
7
|
+
/** Retry / refresh handler */
|
|
8
|
+
onRefresh?: () => void;
|
|
9
|
+
/** Additional class name */
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generic error state with optional icon, description, and retry.
|
|
14
|
+
* App can wrap with antd Empty, i18n, and custom icon.
|
|
15
|
+
*/
|
|
16
|
+
export declare function ErrorView({ icon, description, onRefresh, className, }: ErrorViewProps): React.ReactElement;
|
|
17
|
+
export default ErrorView;
|
|
18
|
+
//# sourceMappingURL=ErrorView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorView.d.ts","sourceRoot":"","sources":["../src/ErrorView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,WAAW,EACX,SAAS,EACT,SAAc,GACf,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CA2BrC;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Generic error state with optional icon, description, and retry.
|
|
4
|
+
* App can wrap with antd Empty, i18n, and custom icon.
|
|
5
|
+
*/
|
|
6
|
+
export function ErrorView({ icon, description, onRefresh, className = '', }) {
|
|
7
|
+
return (_jsxs("div", { className: className, style: {
|
|
8
|
+
display: 'flex',
|
|
9
|
+
flexDirection: 'column',
|
|
10
|
+
alignItems: 'center',
|
|
11
|
+
justifyContent: 'center',
|
|
12
|
+
padding: 24,
|
|
13
|
+
textAlign: 'center',
|
|
14
|
+
}, children: [icon && (_jsx("div", { onClick: onRefresh, onKeyDown: (e) => e.key === 'Enter' && onRefresh?.(), role: "button", tabIndex: 0, style: { cursor: onRefresh ? 'pointer' : 'default', marginBottom: 8 }, children: icon })), description != null && _jsx("div", { style: { color: 'var(--TEXT__2, #666)' }, children: description })] }));
|
|
15
|
+
}
|
|
16
|
+
export default ErrorView;
|
|
17
|
+
//# sourceMappingURL=ErrorView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorView.js","sourceRoot":"","sources":["../src/ErrorView.tsx"],"names":[],"mappings":";AAaA;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,EACxB,IAAI,EACJ,WAAW,EACX,SAAS,EACT,SAAS,GAAG,EAAE,GACC;IACf,OAAO,CACL,eACE,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE;YACL,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,QAAQ;YACvB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,QAAQ;SACpB,aAEA,IAAI,IAAI,CACP,cACE,OAAO,EAAE,SAAS,EAClB,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,SAAS,EAAE,EAAE,EACpD,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,CAAC,EACX,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,YAAY,EAAE,CAAC,EAAE,YAEpE,IAAI,GACD,CACP,EACA,WAAW,IAAI,IAAI,IAAI,cAAK,KAAK,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE,YAAG,WAAW,GAAO,IACtF,CACP,CAAC;AACJ,CAAC;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ImageWithFallbackProps {
|
|
3
|
+
src?: string;
|
|
4
|
+
alt?: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
style?: React.CSSProperties;
|
|
7
|
+
/** Fallback image URL when src fails to load. If not provided, a placeholder is used. */
|
|
8
|
+
fallbackSrc?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function ImageWithFallback({ src, alt, className, style, fallbackSrc, }: ImageWithFallbackProps): React.ReactElement | null;
|
|
11
|
+
export default ImageWithFallback;
|
|
12
|
+
//# sourceMappingURL=ImageWithFallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageWithFallback.d.ts","sourceRoot":"","sources":["../src/ImageWithFallback.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,MAAM,WAAW,sBAAsB;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,yFAAyF;IACzF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAKD,wBAAgB,iBAAiB,CAAC,EAChC,GAAQ,EACR,GAAQ,EACR,SAAc,EACd,KAAsB,EACtB,WAAyB,GAC1B,EAAE,sBAAsB,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAgBpD;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
const PLACEHOLDER = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"%3E%3Crect fill="%23f0f0f0" width="100" height="100"/%3E%3C/svg%3E';
|
|
4
|
+
export function ImageWithFallback({ src = '', alt = '', className = '', style = { width: 100 }, fallbackSrc = PLACEHOLDER, }) {
|
|
5
|
+
const [failedSrc, setFailedSrc] = useState(null);
|
|
6
|
+
const imgSrc = failedSrc === src ? fallbackSrc : src;
|
|
7
|
+
if (!src)
|
|
8
|
+
return null;
|
|
9
|
+
return (_jsx("img", { style: style, className: `shinhan-image aspect-video object-contain rounded-[4px] ${className}`.trim(), src: imgSrc, alt: alt, onError: () => { if (imgSrc !== fallbackSrc)
|
|
10
|
+
setFailedSrc(src); }, loading: "lazy" }));
|
|
11
|
+
}
|
|
12
|
+
export default ImageWithFallback;
|
|
13
|
+
//# sourceMappingURL=ImageWithFallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageWithFallback.js","sourceRoot":"","sources":["../src/ImageWithFallback.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAWxC,MAAM,WAAW,GACf,+KAA+K,CAAC;AAElL,MAAM,UAAU,iBAAiB,CAAC,EAChC,GAAG,GAAG,EAAE,EACR,GAAG,GAAG,EAAE,EACR,SAAS,GAAG,EAAE,EACd,KAAK,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,EACtB,WAAW,GAAG,WAAW,GACF;IACvB,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC;IAErD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IAEtB,OAAO,CACL,cACE,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,2DAA2D,SAAS,EAAE,CAAC,IAAI,EAAE,EACxF,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,MAAM,KAAK,WAAW;YAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EACjE,OAAO,EAAC,MAAM,GACd,CACH,CAAC;AACJ,CAAC;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CSSProperties, type Key, type ReactNode } from 'react';
|
|
2
|
+
export interface VirtualizedListProps<T> {
|
|
3
|
+
items?: readonly T[];
|
|
4
|
+
itemHeight?: number;
|
|
5
|
+
containerHeight?: number;
|
|
6
|
+
className?: string;
|
|
7
|
+
classNameChild?: string;
|
|
8
|
+
style?: CSSProperties;
|
|
9
|
+
tabIndex?: number;
|
|
10
|
+
renderItem?: (item: T, index: number) => ReactNode;
|
|
11
|
+
renderContent?: (items: T[]) => ReactNode;
|
|
12
|
+
getItemKey?: (item: T, index: number) => Key;
|
|
13
|
+
emptyContent?: ReactNode;
|
|
14
|
+
onScroll?: (event: Event) => void;
|
|
15
|
+
}
|
|
16
|
+
/** Fixed-height list with no routing, app state, stylesheet or translation dependency. */
|
|
17
|
+
export declare function VirtualizedList<T>({ items, itemHeight, containerHeight, className, classNameChild, style, tabIndex, renderItem, renderContent, getItemKey, emptyContent, onScroll, }: VirtualizedListProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=VirtualizedList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualizedList.d.ts","sourceRoot":"","sources":["../src/VirtualizedList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,aAAa,EAAE,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlG,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IACnD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC;IAC7C,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACnC;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,CAAC,EAAE,EACjC,KAAU,EAAE,UAAe,EAAE,eAAqB,EAAE,SAAc,EAAE,cAAmB,EACvF,KAAK,EAAE,QAAY,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,YAAmB,EAAE,QAAQ,GAC1F,EAAE,oBAAoB,CAAC,CAAC,CAAC,2CAqCzB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, useEffect, useRef } from 'react';
|
|
3
|
+
import { useVirtualScroll } from '@khoangd/react-utils';
|
|
4
|
+
/** Fixed-height list with no routing, app state, stylesheet or translation dependency. */
|
|
5
|
+
export function VirtualizedList({ items = [], itemHeight = 30, containerHeight = 100, className = '', classNameChild = '', style, tabIndex = 0, renderItem, renderContent, getItemKey, emptyContent = null, onScroll, }) {
|
|
6
|
+
const container = useRef(null);
|
|
7
|
+
const { range, updateRange } = useVirtualScroll(items.length, itemHeight, containerHeight);
|
|
8
|
+
const hasItems = items.length > 0;
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const element = container.current;
|
|
11
|
+
if (!element)
|
|
12
|
+
return;
|
|
13
|
+
let frame;
|
|
14
|
+
const handleScroll = (event) => {
|
|
15
|
+
onScroll?.(event);
|
|
16
|
+
if (frame !== undefined)
|
|
17
|
+
cancelAnimationFrame(frame);
|
|
18
|
+
frame = requestAnimationFrame(() => updateRange(element.scrollTop));
|
|
19
|
+
};
|
|
20
|
+
updateRange(element.scrollTop);
|
|
21
|
+
element.addEventListener('scroll', handleScroll, { passive: true });
|
|
22
|
+
return () => {
|
|
23
|
+
element.removeEventListener('scroll', handleScroll);
|
|
24
|
+
if (frame !== undefined)
|
|
25
|
+
cancelAnimationFrame(frame);
|
|
26
|
+
};
|
|
27
|
+
}, [hasItems, onScroll, updateRange]);
|
|
28
|
+
if (!hasItems)
|
|
29
|
+
return _jsx(_Fragment, { children: emptyContent });
|
|
30
|
+
const visibleItems = items.slice(range.start, range.end);
|
|
31
|
+
return (_jsx("div", { ref: container, className: className, tabIndex: tabIndex, style: { position: 'relative', overflowY: 'auto', ...style, height: containerHeight }, children: _jsx("div", { style: { height: items.length * itemHeight, position: 'relative' }, children: _jsx("div", { className: classNameChild, style: { transform: `translateY(${range.start * itemHeight}px)` }, children: renderItem ? visibleItems.map((item, index) => {
|
|
32
|
+
const absoluteIndex = range.start + index;
|
|
33
|
+
return _jsx(Fragment, { children: renderItem(item, absoluteIndex) }, getItemKey?.(item, absoluteIndex) ?? absoluteIndex);
|
|
34
|
+
}) : renderContent?.(visibleItems) }) }) }));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=VirtualizedList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualizedList.js","sourceRoot":"","sources":["../src/VirtualizedList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
3
|
+
variant?: 'neutral' | 'success' | 'warning' | 'danger' | 'info';
|
|
4
|
+
icon?: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
/** Semantic status label. Product icons and tooltip behavior are supplied by consumers. */
|
|
7
|
+
export declare function Badge({ variant, icon, className, children, ...props }: BadgeProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=dataDisplay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataDisplay.d.ts","sourceRoot":"","sources":["../src/dataDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvD,MAAM,WAAW,UAAW,SAAQ,cAAc,CAAC,eAAe,CAAC;IACjE,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IAChE,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,2FAA2F;AAC3F,wBAAgB,KAAK,CAAC,EAAE,OAAmB,EAAE,IAAI,EAAE,SAAc,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,2CAOlG"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/** Semantic status label. Product icons and tooltip behavior are supplied by consumers. */
|
|
3
|
+
export function Badge({ variant = 'neutral', icon, className = '', children, ...props }) {
|
|
4
|
+
return (_jsxs("span", { className: `shinhan-badge shinhan-badge--${variant} ${className}`.trim(), ...props, children: [icon == null ? null : _jsx("span", { className: "shinhan-badge__icon", "aria-hidden": "true", children: icon }), _jsx("span", { children: children })] }));
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=dataDisplay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataDisplay.js","sourceRoot":"","sources":["../src/dataDisplay.tsx"],"names":[],"mappings":";AAOA,2FAA2F;AAC3F,MAAM,UAAU,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,EAAE,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAc;IACjG,OAAO,CACL,gBAAM,SAAS,EAAE,gCAAgC,OAAO,IAAI,SAAS,EAAE,CAAC,IAAI,EAAE,KAAM,KAAK,aACtF,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,qBAAqB,iBAAa,MAAM,YAAE,IAAI,GAAQ,EAC7F,yBAAO,QAAQ,GAAQ,IAClB,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Component, type ErrorInfo, type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
export declare function Loading({ label, ...props }: HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
label?: string;
|
|
4
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function Skeleton(props: HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function Overlay(props: HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
8
|
+
title: ReactNode;
|
|
9
|
+
description?: ReactNode;
|
|
10
|
+
icon?: ReactNode;
|
|
11
|
+
action?: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
export declare function EmptyState({ title, description, icon, action, className, ...props }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export type ErrorBoundaryProps = {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
fallback?: ReactNode;
|
|
17
|
+
onError?: (error: Error, info: ErrorInfo) => void;
|
|
18
|
+
};
|
|
19
|
+
type ErrorBoundaryState = {
|
|
20
|
+
error: Error | null;
|
|
21
|
+
};
|
|
22
|
+
export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
23
|
+
state: ErrorBoundaryState;
|
|
24
|
+
static getDerivedStateFromError(error: Error): {
|
|
25
|
+
error: Error;
|
|
26
|
+
};
|
|
27
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
28
|
+
render(): string | number | boolean | Iterable<ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=feedback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../src/feedback.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvF,wBAAgB,OAAO,CAAC,EAAE,KAAiB,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,2CAE3G;AACD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,cAAc,CAAC,2CAAkH;AAChL,wBAAgB,OAAO,CAAC,KAAK,EAAE,cAAc,CAAC,cAAc,CAAC,2CAA8F;AAE3J,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACpF,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,SAAc,EAAE,GAAG,KAAK,EAAE,EAAE,eAAe,2CASzG;AAED,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;CAAE,CAAC;AAClI,KAAK,kBAAkB,GAAG;IAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CAAE,CAAC;AAClD,qBAAa,aAAc,SAAQ,SAAS,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;IAClF,KAAK,EAAE,kBAAkB,CAAmB;IAC5C,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK;;;IAC5C,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS;IAC/C,MAAM;CACP"}
|
package/dist/feedback.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Component } from 'react';
|
|
3
|
+
export function Loading({ label = 'Loading', ...props }) {
|
|
4
|
+
return _jsx("div", { role: "status", "aria-label": label, ...props, children: _jsx("span", { className: "shinhan-spinner", "aria-hidden": "true" }) });
|
|
5
|
+
}
|
|
6
|
+
export function Skeleton(props) { return _jsx("div", { "aria-hidden": "true", ...props, className: `shinhan-skeleton ${props.className ?? ''}`.trim() }); }
|
|
7
|
+
export function Overlay(props) { return _jsx("div", { ...props, className: `shinhan-overlay ${props.className ?? ''}`.trim() }); }
|
|
8
|
+
export function EmptyState({ title, description, icon, action, className = '', ...props }) {
|
|
9
|
+
return (_jsxs("div", { className: `shinhan-empty-state ${className}`.trim(), ...props, children: [icon == null ? null : _jsx("div", { className: "shinhan-empty-state__icon", "aria-hidden": "true", children: icon }), _jsx("strong", { className: "shinhan-empty-state__title", children: title }), description == null ? null : _jsx("div", { className: "shinhan-empty-state__description", children: description }), action == null ? null : _jsx("div", { className: "shinhan-empty-state__action", children: action })] }));
|
|
10
|
+
}
|
|
11
|
+
export class ErrorBoundary extends Component {
|
|
12
|
+
constructor() {
|
|
13
|
+
super(...arguments);
|
|
14
|
+
this.state = { error: null };
|
|
15
|
+
}
|
|
16
|
+
static getDerivedStateFromError(error) { return { error }; }
|
|
17
|
+
componentDidCatch(error, info) { this.props.onError?.(error, info); }
|
|
18
|
+
render() { return this.state.error ? (this.props.fallback ?? _jsx("div", { role: "alert", children: "Something went wrong." })) : this.props.children; }
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.js","sourceRoot":"","sources":["../src/feedback.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAuD,MAAM,OAAO,CAAC;AAEvF,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,GAAG,SAAS,EAAE,GAAG,KAAK,EAAuD;IAC1G,OAAO,cAAK,IAAI,EAAC,QAAQ,gBAAa,KAAK,KAAM,KAAK,YAAE,eAAM,SAAS,EAAC,iBAAiB,iBAAa,MAAM,GAAG,GAAM,CAAC;AACxH,CAAC;AACD,MAAM,UAAU,QAAQ,CAAC,KAAqC,IAAI,OAAO,6BAAiB,MAAM,KAAK,KAAK,EAAE,SAAS,EAAE,oBAAoB,KAAK,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,GAAI,CAAC,CAAC,CAAC;AAChL,MAAM,UAAU,OAAO,CAAC,KAAqC,IAAI,OAAO,iBAAS,KAAK,EAAE,SAAS,EAAE,mBAAmB,KAAK,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,GAAI,CAAC,CAAC,CAAC;AAS3J,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,GAAG,EAAE,EAAE,GAAG,KAAK,EAAmB;IACxG,OAAO,CACL,eAAK,SAAS,EAAE,uBAAuB,SAAS,EAAE,CAAC,IAAI,EAAE,KAAM,KAAK,aACjE,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,2BAA2B,iBAAa,MAAM,YAAE,IAAI,GAAO,EACjG,iBAAQ,SAAS,EAAC,4BAA4B,YAAE,KAAK,GAAU,EAC9D,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,kCAAkC,YAAE,WAAW,GAAO,EAClG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,6BAA6B,YAAE,MAAM,GAAO,IAChF,CACP,CAAC;AACJ,CAAC;AAID,MAAM,OAAO,aAAc,SAAQ,SAAiD;IAApF;;QACE,UAAK,GAAuB,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAI9C,CAAC;IAHC,MAAM,CAAC,wBAAwB,CAAC,KAAY,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACnE,iBAAiB,CAAC,KAAY,EAAE,IAAe,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACvF,MAAM,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,cAAK,IAAI,EAAC,OAAO,sCAA4B,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;CACrI"}
|
package/dist/forms.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type InputHTMLAttributes, type LabelHTMLAttributes, type ReactNode, type SelectHTMLAttributes, type TextareaHTMLAttributes } from 'react';
|
|
2
|
+
export interface SwitchProps {
|
|
3
|
+
checked?: boolean;
|
|
4
|
+
onChange?: (checked: boolean) => void;
|
|
5
|
+
checkedChildren?: ReactNode;
|
|
6
|
+
unCheckedChildren?: ReactNode;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
className?: string;
|
|
9
|
+
'aria-label'?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Controlled, keyboard-accessible switch with no application state dependency. */
|
|
12
|
+
export declare const Switch: import("react").ForwardRefExoticComponent<SwitchProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
13
|
+
export interface InputSelectOption {
|
|
14
|
+
value: string;
|
|
15
|
+
label: ReactNode;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface InputSelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, 'onChange' | 'value'> {
|
|
19
|
+
value?: string;
|
|
20
|
+
onChange?: (value: string, option: InputSelectOption) => void;
|
|
21
|
+
options?: readonly InputSelectOption[];
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
allowClear?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Native select primitive. Searchable or remote-data selects stay in app adapters. */
|
|
26
|
+
export declare const InputSelect: import("react").ForwardRefExoticComponent<InputSelectProps & import("react").RefAttributes<HTMLSelectElement>>;
|
|
27
|
+
/** Preferred product-neutral name. InputSelect remains for compatibility. */
|
|
28
|
+
export declare const Select: import("react").ForwardRefExoticComponent<InputSelectProps & import("react").RefAttributes<HTMLSelectElement>>;
|
|
29
|
+
export type SelectOption = InputSelectOption;
|
|
30
|
+
export type SelectProps = InputSelectProps;
|
|
31
|
+
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
32
|
+
minRows?: number;
|
|
33
|
+
maxRows?: number;
|
|
34
|
+
}
|
|
35
|
+
export declare const Textarea: import("react").ForwardRefExoticComponent<TextareaProps & import("react").RefAttributes<HTMLTextAreaElement>>;
|
|
36
|
+
export interface DatePickerProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'value' | 'onChange'> {
|
|
37
|
+
value?: string;
|
|
38
|
+
onChange?: (value: string) => void;
|
|
39
|
+
}
|
|
40
|
+
/** Native date input using an explicit YYYY-MM-DD value contract. */
|
|
41
|
+
export declare const DatePicker: import("react").ForwardRefExoticComponent<DatePickerProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
42
|
+
export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'checked' | 'onChange'> {
|
|
43
|
+
checked?: boolean;
|
|
44
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
45
|
+
label?: ReactNode;
|
|
46
|
+
}
|
|
47
|
+
export declare const Checkbox: import("react").ForwardRefExoticComponent<CheckboxProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
48
|
+
export interface RadioOption {
|
|
49
|
+
value: string;
|
|
50
|
+
label: ReactNode;
|
|
51
|
+
disabled?: boolean;
|
|
52
|
+
}
|
|
53
|
+
export interface RadioGroupProps {
|
|
54
|
+
name: string;
|
|
55
|
+
value?: string;
|
|
56
|
+
options: readonly RadioOption[];
|
|
57
|
+
onChange?: (value: string, option: RadioOption) => void;
|
|
58
|
+
disabled?: boolean;
|
|
59
|
+
direction?: 'row' | 'column';
|
|
60
|
+
className?: string;
|
|
61
|
+
'aria-label'?: string;
|
|
62
|
+
}
|
|
63
|
+
export declare function RadioGroup({ name, value, options, onChange, disabled, direction, className, 'aria-label': ariaLabel, }: RadioGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
64
|
+
export interface SegmentedControlProps {
|
|
65
|
+
value?: string;
|
|
66
|
+
options: readonly RadioOption[];
|
|
67
|
+
onChange?: (value: string, option: RadioOption) => void;
|
|
68
|
+
disabled?: boolean;
|
|
69
|
+
className?: string;
|
|
70
|
+
'aria-label'?: string;
|
|
71
|
+
}
|
|
72
|
+
export declare function SegmentedControl({ value, options, onChange, disabled, className, 'aria-label': ariaLabel, }: SegmentedControlProps): import("react/jsx-runtime").JSX.Element;
|
|
73
|
+
export interface FormFieldProps extends LabelHTMLAttributes<HTMLLabelElement> {
|
|
74
|
+
label: ReactNode;
|
|
75
|
+
htmlFor?: string;
|
|
76
|
+
hint?: ReactNode;
|
|
77
|
+
error?: ReactNode;
|
|
78
|
+
required?: boolean;
|
|
79
|
+
children: ReactNode;
|
|
80
|
+
}
|
|
81
|
+
export declare function FormField({ label, htmlFor, hint, error, required, children, className, ...props }: FormFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
82
|
+
//# sourceMappingURL=forms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../src/forms.tsx"],"names":[],"mappings":"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"}
|
package/dist/forms.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, } from 'react';
|
|
3
|
+
/** Controlled, keyboard-accessible switch with no application state dependency. */
|
|
4
|
+
export const Switch = forwardRef(function Switch({ checked = false, onChange, checkedChildren, unCheckedChildren, disabled = false, className = '', 'aria-label': ariaLabel, }, ref) {
|
|
5
|
+
return (_jsxs("button", { ref: ref, type: "button", role: "switch", "aria-checked": checked, "aria-label": ariaLabel, disabled: disabled, className: `shinhan-switch ${className}`.trim(), onClick: () => onChange?.(!checked), children: [_jsx("span", { className: "shinhan-switch__content", children: checked ? checkedChildren : unCheckedChildren }), _jsx("span", { className: "shinhan-switch__thumb", "aria-hidden": "true" })] }));
|
|
6
|
+
});
|
|
7
|
+
/** Native select primitive. Searchable or remote-data selects stay in app adapters. */
|
|
8
|
+
export const InputSelect = forwardRef(function InputSelect({ value = '', onChange, options = [], placeholder = '', allowClear = false, className = '', ...props }, ref) {
|
|
9
|
+
const handleChange = (event) => {
|
|
10
|
+
const nextValue = event.target.value;
|
|
11
|
+
const option = options.find((item) => item.value === nextValue);
|
|
12
|
+
onChange?.(nextValue, option ?? { value: nextValue, label: nextValue });
|
|
13
|
+
};
|
|
14
|
+
return (_jsxs("select", { ref: ref, value: value, onChange: handleChange, className: `shinhan-select ${className}`.trim(), ...props, children: [placeholder || allowClear ? _jsx("option", { value: "", children: placeholder || '—' }) : null, options.map((option) => (_jsx("option", { value: option.value, disabled: option.disabled, children: typeof option.label === 'string' || typeof option.label === 'number'
|
|
15
|
+
? option.label
|
|
16
|
+
: option.value }, option.value)))] }));
|
|
17
|
+
});
|
|
18
|
+
/** Preferred product-neutral name. InputSelect remains for compatibility. */
|
|
19
|
+
export const Select = InputSelect;
|
|
20
|
+
export const Textarea = forwardRef(function Textarea({ value, defaultValue, minRows = 2, maxRows = 6, className = '', ...props }, ref) {
|
|
21
|
+
const content = value ?? defaultValue ?? '';
|
|
22
|
+
const rows = Math.min(Math.max(minRows, String(content).split('\n').length), maxRows);
|
|
23
|
+
return (_jsx("textarea", { ref: ref, value: value, defaultValue: defaultValue, rows: rows, className: `shinhan-textarea ${className}`.trim(), ...props }));
|
|
24
|
+
});
|
|
25
|
+
/** Native date input using an explicit YYYY-MM-DD value contract. */
|
|
26
|
+
export const DatePicker = forwardRef(function DatePicker({ value = '', onChange, className = '', ...props }, ref) {
|
|
27
|
+
return (_jsx("input", { ref: ref, type: "date", value: value, onChange: (event) => onChange?.(event.target.value), className: `shinhan-datepicker ${className}`.trim(), ...props }));
|
|
28
|
+
});
|
|
29
|
+
export const Checkbox = forwardRef(function Checkbox({ checked = false, onCheckedChange, label, className = '', disabled, ...props }, ref) {
|
|
30
|
+
return (_jsxs("label", { className: `shinhan-checkbox ${disabled ? 'shinhan-checkbox--disabled' : ''} ${className}`.trim(), children: [_jsx("input", { ref: ref, type: "checkbox", checked: checked, disabled: disabled, onChange: (event) => onCheckedChange?.(event.target.checked), ...props }), label == null ? null : _jsx("span", { children: label })] }));
|
|
31
|
+
});
|
|
32
|
+
export function RadioGroup({ name, value, options, onChange, disabled = false, direction = 'row', className = '', 'aria-label': ariaLabel, }) {
|
|
33
|
+
return (_jsx("div", { role: "radiogroup", "aria-label": ariaLabel, className: `shinhan-radio-group shinhan-radio-group--${direction} ${className}`.trim(), children: options.map((option) => (_jsxs("label", { className: `shinhan-radio ${disabled || option.disabled ? 'shinhan-radio--disabled' : ''}`, children: [_jsx("input", { type: "radio", name: name, value: option.value, checked: value === option.value, disabled: disabled || option.disabled, onChange: () => onChange?.(option.value, option) }), _jsx("span", { children: option.label })] }, option.value))) }));
|
|
34
|
+
}
|
|
35
|
+
export function SegmentedControl({ value, options, onChange, disabled = false, className = '', 'aria-label': ariaLabel, }) {
|
|
36
|
+
return (_jsx("div", { role: "radiogroup", "aria-label": ariaLabel, className: `shinhan-segmented ${className}`.trim(), children: options.map((option) => {
|
|
37
|
+
const selected = value === option.value;
|
|
38
|
+
return (_jsx("button", { type: "button", role: "radio", "aria-checked": selected, disabled: disabled || option.disabled, className: "shinhan-segmented__item", onClick: () => onChange?.(option.value, option), children: option.label }, option.value));
|
|
39
|
+
}) }));
|
|
40
|
+
}
|
|
41
|
+
export function FormField({ label, htmlFor, hint, error, required = false, children, className = '', ...props }) {
|
|
42
|
+
return (_jsxs("label", { htmlFor: htmlFor, className: `shinhan-field ${className}`.trim(), ...props, children: [_jsxs("span", { className: "shinhan-field__label", children: [label, required ? _jsx("span", { "aria-hidden": "true", children: " *" }) : null] }), children, error == null ? null : _jsx("span", { className: "shinhan-field__error", children: error }), error != null || hint == null ? null : _jsx("span", { className: "shinhan-field__hint", children: hint })] }));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=forms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms.js","sourceRoot":"","sources":["../src/forms.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './primitives.js';
|
|
2
|
+
export * from './forms.js';
|
|
3
|
+
export * from './layout.js';
|
|
4
|
+
export * from './feedback.js';
|
|
5
|
+
export * from './dataDisplay.js';
|
|
6
|
+
export { ImageWithFallback } from './ImageWithFallback.js';
|
|
7
|
+
export type { ImageWithFallbackProps } from './ImageWithFallback.js';
|
|
8
|
+
export { ErrorView } from './ErrorView.js';
|
|
9
|
+
export type { ErrorViewProps } from './ErrorView.js';
|
|
10
|
+
export { VirtualizedList } from './VirtualizedList.js';
|
|
11
|
+
export type { VirtualizedListProps } from './VirtualizedList.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './primitives.js';
|
|
2
|
+
export * from './forms.js';
|
|
3
|
+
export * from './layout.js';
|
|
4
|
+
export * from './feedback.js';
|
|
5
|
+
export * from './dataDisplay.js';
|
|
6
|
+
export { ImageWithFallback } from './ImageWithFallback.js';
|
|
7
|
+
export { ErrorView } from './ErrorView.js';
|
|
8
|
+
export { VirtualizedList } from './VirtualizedList.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CSSProperties, HTMLAttributes, PropsWithChildren } from 'react';
|
|
2
|
+
type StackProps = PropsWithChildren<HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
direction?: 'row' | 'column';
|
|
4
|
+
gap?: CSSProperties['gap'];
|
|
5
|
+
align?: CSSProperties['alignItems'];
|
|
6
|
+
justify?: CSSProperties['justifyContent'];
|
|
7
|
+
wrap?: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function Stack({ direction, gap, align, justify, wrap, style, ...props }: StackProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
type GridProps = PropsWithChildren<HTMLAttributes<HTMLDivElement> & {
|
|
11
|
+
columns?: number | string;
|
|
12
|
+
gap?: CSSProperties['gap'];
|
|
13
|
+
}>;
|
|
14
|
+
export declare function Grid({ columns, gap, style, ...props }: GridProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export interface WrapperProps extends HTMLAttributes<HTMLDivElement> {
|
|
16
|
+
padding?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8;
|
|
17
|
+
gap?: 0 | 1 | 2 | 3 | 4 | 6 | 8;
|
|
18
|
+
direction?: 'row' | 'column';
|
|
19
|
+
}
|
|
20
|
+
/** Token-aligned container used by products that do not need a layout framework. */
|
|
21
|
+
export declare function Wrapper({ padding, gap, direction, className, style, ...props }: WrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAE9E,KAAK,UAAU,GAAG,iBAAiB,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAAE,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAAC,GAAG,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AACnO,wBAAgB,KAAK,CAAC,EAAE,SAAoB,EAAE,GAA8B,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,2CAEhI;AAED,KAAK,SAAS,GAAG,iBAAiB,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;CAAE,CAAC,CAAC;AAC/H,wBAAgB,IAAI,CAAC,EAAE,OAAW,EAAE,GAA8B,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,SAAS,2CAE/F;AAED,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,cAAc,CAAC;IAClE,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC9B;AAaD,oFAAoF;AACpF,wBAAgB,OAAO,CAAC,EACtB,OAAW,EACX,GAAO,EACP,SAAoB,EACpB,SAAc,EACd,KAAK,EACL,GAAG,KAAK,EACT,EAAE,YAAY,2CAgBd"}
|
package/dist/layout.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function Stack({ direction = 'column', gap = 'var(--shinhan-space-2)', align, justify, wrap, style, ...props }) {
|
|
3
|
+
return _jsx("div", { ...props, style: { display: 'flex', flexDirection: direction, gap, alignItems: align, justifyContent: justify, flexWrap: wrap ? 'wrap' : undefined, ...style } });
|
|
4
|
+
}
|
|
5
|
+
export function Grid({ columns = 1, gap = 'var(--shinhan-space-2)', style, ...props }) {
|
|
6
|
+
return _jsx("div", { ...props, style: { display: 'grid', gridTemplateColumns: typeof columns === 'number' ? `repeat(${columns}, minmax(0, 1fr))` : columns, gap, ...style } });
|
|
7
|
+
}
|
|
8
|
+
const SPACE_PX = {
|
|
9
|
+
0: 0,
|
|
10
|
+
1: 4,
|
|
11
|
+
2: 8,
|
|
12
|
+
3: 12,
|
|
13
|
+
4: 16,
|
|
14
|
+
5: 20,
|
|
15
|
+
6: 24,
|
|
16
|
+
8: 32,
|
|
17
|
+
};
|
|
18
|
+
/** Token-aligned container used by products that do not need a layout framework. */
|
|
19
|
+
export function Wrapper({ padding = 2, gap = 0, direction = 'column', className = '', style, ...props }) {
|
|
20
|
+
const gapPx = SPACE_PX[gap] ?? 0;
|
|
21
|
+
return (_jsx("div", { className: `shinhan-wrapper ${className}`.trim(), style: {
|
|
22
|
+
boxSizing: 'border-box',
|
|
23
|
+
padding: SPACE_PX[padding] ?? 8,
|
|
24
|
+
display: gapPx > 0 ? 'flex' : 'block',
|
|
25
|
+
flexDirection: direction,
|
|
26
|
+
gap: gapPx,
|
|
27
|
+
...style,
|
|
28
|
+
}, ...props }));
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.tsx"],"names":[],"mappings":";AAGA,MAAM,UAAU,KAAK,CAAC,EAAE,SAAS,GAAG,QAAQ,EAAE,GAAG,GAAG,wBAAwB,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,EAAc;IAC/H,OAAO,iBAAS,KAAK,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,GAAG,KAAK,EAAE,GAAI,CAAC;AAClL,CAAC;AAGD,MAAM,UAAU,IAAI,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,GAAG,GAAG,wBAAwB,EAAE,KAAK,EAAE,GAAG,KAAK,EAAa;IAC9F,OAAO,iBAAS,KAAK,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,OAAO,mBAAmB,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,GAAI,CAAC;AAC1K,CAAC;AAQD,MAAM,QAAQ,GAA2B;IACvC,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;CACN,CAAC;AAEF,oFAAoF;AACpF,MAAM,UAAU,OAAO,CAAC,EACtB,OAAO,GAAG,CAAC,EACX,GAAG,GAAG,CAAC,EACP,SAAS,GAAG,QAAQ,EACpB,SAAS,GAAG,EAAE,EACd,KAAK,EACL,GAAG,KAAK,EACK;IACb,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,CACL,cACE,SAAS,EAAE,mBAAmB,SAAS,EAAE,CAAC,IAAI,EAAE,EAChD,KAAK,EAAE;YACL,SAAS,EAAE,YAAY;YACvB,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;YAC/B,OAAO,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;YACrC,aAAa,EAAE,SAAS;YACxB,GAAG,EAAE,KAAK;YACV,GAAG,KAAK;SACT,KACG,KAAK,GACT,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes, type InputHTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
3
|
+
variant?: 'primary' | 'secondary' | 'ghost';
|
|
4
|
+
loading?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare const Button: import("react").ForwardRefExoticComponent<ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
7
|
+
variant?: "primary" | "secondary" | "ghost" | undefined;
|
|
8
|
+
loading?: boolean | undefined;
|
|
9
|
+
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
10
|
+
export type InputProps = InputHTMLAttributes<HTMLInputElement> & {
|
|
11
|
+
invalid?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare const Input: import("react").ForwardRefExoticComponent<InputHTMLAttributes<HTMLInputElement> & {
|
|
14
|
+
invalid?: boolean | undefined;
|
|
15
|
+
} & import("react").RefAttributes<HTMLInputElement>>;
|
|
16
|
+
export interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'aria-label'> {
|
|
17
|
+
label: string;
|
|
18
|
+
size?: 'small' | 'medium' | 'large';
|
|
19
|
+
variant?: 'ghost' | 'subtle';
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
export declare const IconButton: import("react").ForwardRefExoticComponent<IconButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
23
|
+
//# sourceMappingURL=primitives.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAExG,MAAM,MAAM,WAAW,GAAG,oBAAoB,CAAC,iBAAiB,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AACvI,eAAO,MAAM,MAAM;;;qDAIjB,CAAC;AAGH,MAAM,MAAM,UAAU,GAAG,mBAAmB,CAAC,gBAAgB,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AACvF,eAAO,MAAM,KAAK;;oDAEhB,CAAC;AAGH,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,YAAY,CAAC;IAClG,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,UAAU,+GAerB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
export const Button = forwardRef(({ variant = 'primary', loading, disabled, className = '', children, ...props }, ref) => (_jsxs("button", { ref: ref, className: `shinhan-button shinhan-button--${variant} ${className}`.trim(), disabled: disabled || loading, "aria-busy": loading || undefined, ...props, children: [loading ? _jsx("span", { className: "shinhan-spinner", "aria-hidden": "true" }) : null, children] })));
|
|
4
|
+
Button.displayName = 'Button';
|
|
5
|
+
export const Input = forwardRef(({ invalid, className = '', ...props }, ref) => (_jsx("input", { ref: ref, className: `shinhan-input ${className}`.trim(), "aria-invalid": invalid || undefined, ...props })));
|
|
6
|
+
Input.displayName = 'Input';
|
|
7
|
+
export const IconButton = forwardRef(function IconButton({ label, size = 'medium', variant = 'ghost', className = '', children, type = 'button', ...props }, ref) {
|
|
8
|
+
return (_jsx("button", { ref: ref, type: type, "aria-label": label, className: `shinhan-icon-button shinhan-icon-button--${size} shinhan-icon-button--${variant} ${className}`.trim(), ...props, children: children }));
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=primitives.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitives.js","sourceRoot":"","sources":["../src/primitives.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAuE,MAAM,OAAO,CAAC;AAGxG,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAiC,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,GAAG,EAAE,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CACxJ,kBAAQ,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,kCAAkC,OAAO,IAAI,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,IAAI,OAAO,eAAa,OAAO,IAAI,SAAS,KAAM,KAAK,aACpK,OAAO,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,iBAAiB,iBAAa,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,IAC5E,CACV,CAAC,CAAC;AACH,MAAM,CAAC,WAAW,GAAG,QAAQ,CAAC;AAG9B,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,CAAC,EAAE,OAAO,EAAE,SAAS,GAAG,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAC5G,gBAAO,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,SAAS,EAAE,CAAC,IAAI,EAAE,kBAAgB,OAAO,IAAI,SAAS,KAAM,KAAK,GAAI,CACnH,CAAC,CAAC;AACH,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC;AAS5B,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAqC,SAAS,UAAU,CAC1F,EAAE,KAAK,EAAE,IAAI,GAAG,QAAQ,EAAE,OAAO,GAAG,OAAO,EAAE,SAAS,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,EAClG,GAAG;IAEH,OAAO,CACL,iBACE,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,IAAI,gBACE,KAAK,EACjB,SAAS,EAAE,4CAA4C,IAAI,yBAAyB,OAAO,IAAI,SAAS,EAAE,CAAC,IAAI,EAAE,KAC7G,KAAK,YAER,QAAQ,GACF,CACV,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@khoangd/ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Accessible React UI primitives for Shinhan frontend products",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": [
|
|
7
|
+
"**/*.css"
|
|
8
|
+
],
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"src/styles.css",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"module": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./primitives": {
|
|
24
|
+
"types": "./dist/primitives.d.ts",
|
|
25
|
+
"import": "./dist/primitives.js"
|
|
26
|
+
},
|
|
27
|
+
"./forms": {
|
|
28
|
+
"types": "./dist/forms.d.ts",
|
|
29
|
+
"import": "./dist/forms.js"
|
|
30
|
+
},
|
|
31
|
+
"./layout": {
|
|
32
|
+
"types": "./dist/layout.d.ts",
|
|
33
|
+
"import": "./dist/layout.js"
|
|
34
|
+
},
|
|
35
|
+
"./feedback": {
|
|
36
|
+
"types": "./dist/feedback.d.ts",
|
|
37
|
+
"import": "./dist/feedback.js"
|
|
38
|
+
},
|
|
39
|
+
"./data-display": {
|
|
40
|
+
"types": "./dist/dataDisplay.d.ts",
|
|
41
|
+
"import": "./dist/dataDisplay.js"
|
|
42
|
+
},
|
|
43
|
+
"./styles.css": "./src/styles.css",
|
|
44
|
+
"./package.json": "./package.json",
|
|
45
|
+
"./virtualized-list": {
|
|
46
|
+
"types": "./dist/VirtualizedList.d.ts",
|
|
47
|
+
"import": "./dist/VirtualizedList.js",
|
|
48
|
+
"default": "./dist/VirtualizedList.js"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsc -p tsconfig.json",
|
|
53
|
+
"clean": "rm -rf dist",
|
|
54
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@khoangd/tokens": "workspace:*",
|
|
58
|
+
"@khoangd/react-utils": "workspace:*"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"react": ">=17 <20",
|
|
62
|
+
"react-dom": ">=17 <20"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@types/react": "^18.0.0",
|
|
66
|
+
"@types/react-dom": "^18.0.0",
|
|
67
|
+
"react": "^18.2.0",
|
|
68
|
+
"react-dom": "^18.2.0",
|
|
69
|
+
"typescript": "^4.7.4"
|
|
70
|
+
},
|
|
71
|
+
"publishConfig": {
|
|
72
|
+
"access": "public",
|
|
73
|
+
"registry": "https://registry.npmjs.org/"
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
@import '@khoangd/tokens/styles.css';
|
|
2
|
+
.shinhan-image { aspect-ratio: 16 / 9; object-fit: contain; border-radius: 4px; }
|
|
3
|
+
.shinhan-button { align-items: center; border: 1px solid transparent; border-radius: var(--shinhan-radius-md); cursor: pointer; display: inline-flex; font: 500 14px/1 var(--shinhan-font-sans); gap: var(--shinhan-space-2); justify-content: center; min-height: 36px; padding: 0 var(--shinhan-space-4); transition: background var(--shinhan-motion-fast); }
|
|
4
|
+
.shinhan-button:disabled { cursor: not-allowed; opacity: .55; }
|
|
5
|
+
.shinhan-button--primary { background: var(--shinhan-color-brand-primary); color: var(--shinhan-color-text-inverse); }
|
|
6
|
+
.shinhan-button--primary:hover:not(:disabled) { background: var(--shinhan-color-brand-primary-hover); }
|
|
7
|
+
.shinhan-button--secondary { background: var(--shinhan-color-surface); border-color: var(--shinhan-color-border); color: var(--shinhan-color-text-primary); }
|
|
8
|
+
.shinhan-button--ghost { background: transparent; color: var(--shinhan-color-text-primary); }
|
|
9
|
+
.shinhan-icon-button { align-items: center; border: 0; border-radius: 50%; color: inherit; cursor: pointer; display: inline-flex; justify-content: center; padding: 0; }
|
|
10
|
+
.shinhan-icon-button--small { height: 24px; width: 24px; }
|
|
11
|
+
.shinhan-icon-button--medium { height: 32px; width: 32px; }
|
|
12
|
+
.shinhan-icon-button--large { height: 40px; width: 40px; }
|
|
13
|
+
.shinhan-icon-button--ghost { background: transparent; }
|
|
14
|
+
.shinhan-icon-button--subtle { background: var(--shinhan-color-surface-subtle); }
|
|
15
|
+
.shinhan-icon-button:hover:not(:disabled) { background: var(--shinhan-color-border); }
|
|
16
|
+
.shinhan-icon-button:disabled { cursor: not-allowed; opacity: .55; }
|
|
17
|
+
.shinhan-input { background: var(--shinhan-color-surface); border: 1px solid var(--shinhan-color-border); border-radius: var(--shinhan-radius-md); box-sizing: border-box; color: var(--shinhan-color-text-primary); font: 400 14px/1.4 var(--shinhan-font-sans); min-height: 36px; padding: 0 var(--shinhan-space-3); }
|
|
18
|
+
.shinhan-input:focus-visible { border-color: var(--shinhan-color-brand-primary); outline: 2px solid rgba(0, 91, 172, .25); }
|
|
19
|
+
.shinhan-input[aria-invalid='true'] { border-color: #d32f2f; }
|
|
20
|
+
.shinhan-select, .shinhan-textarea, .shinhan-datepicker { background: var(--shinhan-color-surface); border: 1px solid var(--shinhan-color-border); border-radius: var(--shinhan-radius-md); box-sizing: border-box; color: var(--shinhan-color-text-primary); font: 400 14px/1.4 var(--shinhan-font-sans); min-height: 36px; padding: var(--shinhan-space-2) var(--shinhan-space-3); width: 100%; }
|
|
21
|
+
.shinhan-textarea { resize: vertical; }
|
|
22
|
+
.shinhan-select:focus-visible, .shinhan-textarea:focus-visible, .shinhan-datepicker:focus-visible { border-color: var(--shinhan-color-brand-primary); outline: 2px solid rgba(0, 91, 172, .25); }
|
|
23
|
+
.shinhan-switch { align-items: center; background: var(--shinhan-color-border); border: 0; border-radius: 9999px; color: var(--shinhan-color-text-primary); cursor: pointer; display: inline-flex; gap: var(--shinhan-space-1); justify-content: space-between; min-height: 24px; min-width: 44px; padding: 2px; position: relative; transition: background var(--shinhan-motion-fast); }
|
|
24
|
+
.shinhan-switch[aria-checked='true'] { background: var(--shinhan-color-brand-primary); color: var(--shinhan-color-text-inverse); }
|
|
25
|
+
.shinhan-switch:disabled { cursor: not-allowed; opacity: .55; }
|
|
26
|
+
.shinhan-switch__content { font: 500 11px/1 var(--shinhan-font-sans); padding: 0 var(--shinhan-space-1); }
|
|
27
|
+
.shinhan-switch__thumb { background: var(--shinhan-color-surface); border-radius: 50%; box-shadow: 0 1px 2px rgba(0, 0, 0, .2); height: 20px; order: -1; transition: transform var(--shinhan-motion-fast); width: 20px; }
|
|
28
|
+
.shinhan-switch[aria-checked='true'] .shinhan-switch__thumb { order: 1; }
|
|
29
|
+
.shinhan-checkbox, .shinhan-radio { align-items: center; color: var(--shinhan-color-text-primary); cursor: pointer; display: inline-flex; font: 400 14px/1.4 var(--shinhan-font-sans); gap: var(--shinhan-space-2); }
|
|
30
|
+
.shinhan-checkbox--disabled, .shinhan-radio--disabled { cursor: not-allowed; opacity: .55; }
|
|
31
|
+
.shinhan-checkbox input, .shinhan-radio input { accent-color: var(--shinhan-color-brand-primary); height: 16px; margin: 0; width: 16px; }
|
|
32
|
+
.shinhan-radio-group { display: flex; gap: var(--shinhan-space-3); }
|
|
33
|
+
.shinhan-radio-group--column { align-items: flex-start; flex-direction: column; }
|
|
34
|
+
.shinhan-segmented { background: var(--shinhan-color-surface-subtle); border-radius: var(--shinhan-radius-md); display: inline-flex; gap: 2px; padding: 2px; }
|
|
35
|
+
.shinhan-segmented__item { background: transparent; border: 0; border-radius: var(--shinhan-radius-sm); color: var(--shinhan-color-text-secondary); cursor: pointer; font: 500 13px/1 var(--shinhan-font-sans); min-height: 28px; padding: 0 var(--shinhan-space-3); }
|
|
36
|
+
.shinhan-segmented__item[aria-checked='true'] { background: var(--shinhan-color-surface); color: var(--shinhan-color-brand-primary); }
|
|
37
|
+
.shinhan-segmented__item:disabled { cursor: not-allowed; opacity: .55; }
|
|
38
|
+
.shinhan-field { color: var(--shinhan-color-text-primary); display: grid; font-family: var(--shinhan-font-sans); gap: var(--shinhan-space-2); }
|
|
39
|
+
.shinhan-field__label { font-size: 13px; font-weight: 600; }
|
|
40
|
+
.shinhan-field__hint, .shinhan-field__error { font-size: 12px; }
|
|
41
|
+
.shinhan-field__hint { color: var(--shinhan-color-text-secondary); }
|
|
42
|
+
.shinhan-field__error { color: #d32f2f; }
|
|
43
|
+
.shinhan-badge { align-items: center; border-radius: 9999px; display: inline-flex; font: 500 12px/1 var(--shinhan-font-sans); gap: var(--shinhan-space-1); min-height: 22px; padding: 0 var(--shinhan-space-2); white-space: nowrap; }
|
|
44
|
+
.shinhan-badge--neutral { background: var(--shinhan-color-surface-subtle); color: var(--shinhan-color-text-secondary); }
|
|
45
|
+
.shinhan-badge--success { background: #def7e7; color: #16803c; }
|
|
46
|
+
.shinhan-badge--warning { background: #fff3d1; color: #8a5700; }
|
|
47
|
+
.shinhan-badge--danger { background: #ffe5e5; color: #b42318; }
|
|
48
|
+
.shinhan-badge--info { background: #e5f1ff; color: #0568c5; }
|
|
49
|
+
.shinhan-badge__icon { display: inline-flex; }
|
|
50
|
+
.shinhan-empty-state { align-items: center; color: var(--shinhan-color-text-primary); display: flex; flex-direction: column; font-family: var(--shinhan-font-sans); gap: var(--shinhan-space-2); justify-content: center; padding: var(--shinhan-space-6); text-align: center; }
|
|
51
|
+
.shinhan-empty-state__icon { color: var(--shinhan-color-text-secondary); display: inline-flex; }
|
|
52
|
+
.shinhan-empty-state__title { font-size: 14px; }
|
|
53
|
+
.shinhan-empty-state__description { color: var(--shinhan-color-text-secondary); font-size: 13px; }
|
|
54
|
+
.shinhan-empty-state__action { margin-top: var(--shinhan-space-2); }
|
|
55
|
+
.shinhan-spinner { animation: shinhan-spin .7s linear infinite; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; display: inline-block; height: 1em; width: 1em; }
|
|
56
|
+
.shinhan-skeleton { animation: shinhan-pulse 1.4s ease-in-out infinite; background: var(--shinhan-color-surface-subtle); border-radius: var(--shinhan-radius-md); min-height: 1em; }
|
|
57
|
+
.shinhan-overlay { background: var(--shinhan-color-overlay); inset: 0; position: fixed; z-index: 1200; }
|
|
58
|
+
@keyframes shinhan-spin { to { transform: rotate(360deg); } }
|
|
59
|
+
@keyframes shinhan-pulse { 50% { opacity: .55; } }
|
|
60
|
+
@media (prefers-reduced-motion: reduce) { .shinhan-spinner, .shinhan-skeleton { animation: none; } }
|