@xfilecom/front-core 0.2.2 → 0.2.5

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 (35) hide show
  1. package/dist/base.css +225 -1
  2. package/dist/components/InlineErrorList.d.ts +12 -0
  3. package/dist/components/InlineErrorList.js +11 -0
  4. package/dist/components/LoadingOverlay.d.ts +8 -0
  5. package/dist/components/LoadingOverlay.js +11 -0
  6. package/dist/components/Toast.d.ts +25 -0
  7. package/dist/components/Toast.js +42 -0
  8. package/dist/components/atoms/Badge.d.ts +6 -0
  9. package/dist/components/atoms/Badge.js +8 -0
  10. package/dist/components/atoms/Box.d.ts +6 -0
  11. package/dist/components/atoms/Box.js +9 -0
  12. package/dist/components/atoms/Button.d.ts +5 -0
  13. package/dist/components/atoms/Button.js +8 -0
  14. package/dist/components/atoms/Card.d.ts +5 -0
  15. package/dist/components/atoms/Card.js +8 -0
  16. package/dist/components/atoms/InlineErrorList.d.ts +12 -0
  17. package/dist/components/atoms/InlineErrorList.js +11 -0
  18. package/dist/components/atoms/Input.d.ts +3 -0
  19. package/dist/components/atoms/Input.js +9 -0
  20. package/dist/components/atoms/LoadingOverlay.d.ts +8 -0
  21. package/dist/components/atoms/LoadingOverlay.js +11 -0
  22. package/dist/components/atoms/Stack.d.ts +8 -0
  23. package/dist/components/atoms/Stack.js +16 -0
  24. package/dist/components/atoms/Text.d.ts +22 -0
  25. package/dist/components/atoms/Text.js +20 -0
  26. package/dist/components/atoms/Toast.d.ts +25 -0
  27. package/dist/components/atoms/Toast.js +42 -0
  28. package/dist/components/atoms/index.d.ts +14 -0
  29. package/dist/components/atoms/index.js +29 -0
  30. package/dist/components/index.d.ts +1 -7
  31. package/dist/components/index.js +15 -15
  32. package/dist/index.d.ts +11 -3
  33. package/dist/index.js +16 -3
  34. package/dist/tokens.css +8 -0
  35. package/package.json +6 -2
package/dist/base.css CHANGED
@@ -1,6 +1,13 @@
1
1
  /**
2
2
  * Global base + atomic classes for @xfilecom/front-core components.
3
- * Import after tokens.css.
3
+ *
4
+ * 권장 로드 순서 (xframe web/shared 와 함께 쓸 때):
5
+ * 1. @xfilecom/front-core/tokens.css
6
+ * 2. web/shared/src/styles/xfc-theme.css — 앱별 :root --xfc-* 덮어쓰기(선택)
7
+ * 3. 이 파일 (base.css) — atoms(.xfc-*)
8
+ * 4. web/shared/src/styles/app.css — 레이아웃 + atoms 클래스 오버라이드(선택)
9
+ *
10
+ * CSS 변수는 사용 시점에 계산되므로, (2)에서 바꾼 --xfc-* 는 (3)의 atoms 규칙에 반영됩니다.
4
11
  */
5
12
 
6
13
  *,
@@ -292,3 +299,220 @@ a:hover {
292
299
  background: color-mix(in srgb, var(--xfc-danger) 15%, transparent);
293
300
  color: var(--xfc-danger);
294
301
  }
302
+
303
+ /* —— Global loading overlay (business-promotion global-indicator) —— */
304
+
305
+ .xfc-loading-overlay {
306
+ position: fixed;
307
+ inset: 0;
308
+ z-index: 9999;
309
+ display: flex;
310
+ flex-direction: column;
311
+ align-items: center;
312
+ justify-content: center;
313
+ gap: var(--xfc-space-md);
314
+ padding: var(--xfc-space-lg);
315
+ box-sizing: border-box;
316
+ background: transparent;
317
+ pointer-events: auto;
318
+ animation: xfc-loading-overlay-enter 0.2s ease-out;
319
+ }
320
+
321
+ .xfc-loading-overlay-spinner {
322
+ width: 48px;
323
+ height: 48px;
324
+ border: 4px solid color-mix(in srgb, var(--xfc-accent) 22%, transparent);
325
+ border-top-color: var(--xfc-accent);
326
+ border-radius: 50%;
327
+ animation: xfc-loading-overlay-spin 0.68s linear infinite;
328
+ flex-shrink: 0;
329
+ box-shadow:
330
+ 0 0 0 2px rgba(255, 255, 255, 0.95),
331
+ 0 6px 24px rgba(0, 0, 0, 0.14);
332
+ filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.08));
333
+ }
334
+
335
+ .xfc-loading-overlay-message {
336
+ margin: 0;
337
+ max-width: min(280px, 100%);
338
+ font-size: var(--xfc-text-small);
339
+ font-weight: 600;
340
+ line-height: 1.4;
341
+ color: var(--xfc-fg);
342
+ text-align: center;
343
+ text-shadow:
344
+ 0 0 10px rgba(255, 255, 255, 1),
345
+ 0 0 3px rgba(255, 255, 255, 1),
346
+ 0 1px 2px rgba(0, 0, 0, 0.08);
347
+ }
348
+
349
+ @keyframes xfc-loading-overlay-enter {
350
+ from {
351
+ opacity: 0;
352
+ }
353
+ to {
354
+ opacity: 1;
355
+ }
356
+ }
357
+
358
+ @keyframes xfc-loading-overlay-spin {
359
+ to {
360
+ transform: rotate(360deg);
361
+ }
362
+ }
363
+
364
+ @media (prefers-reduced-motion: reduce) {
365
+ .xfc-loading-overlay {
366
+ animation: none;
367
+ }
368
+
369
+ .xfc-loading-overlay-spinner {
370
+ animation-duration: 1.4s;
371
+ }
372
+ }
373
+
374
+ /* —— Toasts (business-promotion toast-list) —— */
375
+
376
+ .xfc-toast-list {
377
+ position: fixed;
378
+ bottom: var(--xfc-space-md);
379
+ right: var(--xfc-space-md);
380
+ z-index: 9998;
381
+ display: flex;
382
+ flex-direction: column;
383
+ gap: var(--xfc-space-sm);
384
+ max-width: 360px;
385
+ }
386
+
387
+ .xfc-toast {
388
+ display: inline-flex;
389
+ width: 100%;
390
+ box-sizing: border-box;
391
+ align-items: flex-start;
392
+ justify-content: flex-start;
393
+ gap: var(--xfc-space-lg);
394
+ padding: var(--xfc-space-lg);
395
+ border-radius: var(--xfc-toast-radius);
396
+ color: #fff;
397
+ font-family: var(--xfc-font-sans);
398
+ font-size: var(--xfc-text-body);
399
+ font-weight: 400;
400
+ line-height: 1.25;
401
+ box-shadow: var(--xfc-toast-shadow);
402
+ transition: opacity 0.2s ease;
403
+ }
404
+
405
+ .xfc-toast--info {
406
+ background: var(--xfc-toast-info-bg);
407
+ }
408
+
409
+ .xfc-toast--success {
410
+ background: var(--xfc-toast-success-bg);
411
+ }
412
+
413
+ .xfc-toast--warn {
414
+ background: var(--xfc-toast-warn-bg);
415
+ }
416
+
417
+ .xfc-toast--error {
418
+ background: var(--xfc-toast-error-bg);
419
+ }
420
+
421
+ .xfc-toast__icon {
422
+ flex-shrink: 0;
423
+ width: 20px;
424
+ height: 20px;
425
+ display: flex;
426
+ align-items: center;
427
+ justify-content: center;
428
+ color: #fff;
429
+ }
430
+
431
+ .xfc-toast__icon svg {
432
+ display: block;
433
+ }
434
+
435
+ .xfc-toast__message {
436
+ flex: 1 1 0;
437
+ min-width: 0;
438
+ overflow-wrap: break-word;
439
+ word-wrap: break-word;
440
+ }
441
+
442
+ .xfc-toast-dismiss {
443
+ flex-shrink: 0;
444
+ width: 20px;
445
+ height: 20px;
446
+ padding: 0;
447
+ margin: 0;
448
+ border: none;
449
+ background: none;
450
+ color: #fff;
451
+ cursor: pointer;
452
+ display: flex;
453
+ align-items: center;
454
+ justify-content: center;
455
+ opacity: 0.85;
456
+ }
457
+
458
+ .xfc-toast-dismiss svg {
459
+ display: block;
460
+ }
461
+
462
+ .xfc-toast-dismiss:hover {
463
+ opacity: 1;
464
+ }
465
+
466
+ .xfc-toast-dismiss:focus-visible {
467
+ outline: none;
468
+ box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85);
469
+ border-radius: 2px;
470
+ }
471
+
472
+ /* —— Inline error banners (business-promotion error-list) —— */
473
+
474
+ .xfc-inline-error-list {
475
+ position: fixed;
476
+ top: var(--xfc-space-md);
477
+ left: 50%;
478
+ transform: translateX(-50%);
479
+ z-index: 9998;
480
+ display: flex;
481
+ flex-direction: column;
482
+ gap: var(--xfc-space-sm);
483
+ max-width: 400px;
484
+ }
485
+
486
+ .xfc-inline-error-item {
487
+ display: flex;
488
+ align-items: center;
489
+ justify-content: space-between;
490
+ gap: var(--xfc-space-sm);
491
+ padding: var(--xfc-space-md) var(--xfc-space-lg);
492
+ background: var(--xfc-danger);
493
+ color: var(--xfc-accent-fg);
494
+ border-radius: var(--xfc-radius-md);
495
+ font-size: var(--xfc-text-small);
496
+ box-shadow: var(--xfc-toast-shadow);
497
+ }
498
+
499
+ .xfc-inline-error-dismiss {
500
+ background: none;
501
+ border: none;
502
+ color: inherit;
503
+ cursor: pointer;
504
+ font-size: 1.25rem;
505
+ line-height: 1;
506
+ opacity: 0.8;
507
+ padding: 0 var(--xfc-space-xs);
508
+ }
509
+
510
+ .xfc-inline-error-dismiss:hover {
511
+ opacity: 1;
512
+ }
513
+
514
+ .xfc-inline-error-dismiss:focus-visible {
515
+ outline: none;
516
+ box-shadow: var(--xfc-focus-ring);
517
+ border-radius: var(--xfc-radius-xs);
518
+ }
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from 'react';
2
+ export type InlineErrorEntry = {
3
+ id: string;
4
+ message: ReactNode;
5
+ };
6
+ export type InlineErrorListProps = {
7
+ errors: InlineErrorEntry[];
8
+ onDismiss: (id: string) => void;
9
+ className?: string;
10
+ };
11
+ /** 상단 고정 에러 배너 목록 (business-promotion `ErrorList` UI, MobX 없음). */
12
+ export declare function InlineErrorList({ errors, onDismiss, className }: InlineErrorListProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InlineErrorList = InlineErrorList;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /** 상단 고정 에러 배너 목록 (business-promotion `ErrorList` UI, MobX 없음). */
6
+ function InlineErrorList({ errors, onDismiss, className = '' }) {
7
+ if (!errors.length)
8
+ return null;
9
+ const listCls = ['xfc-inline-error-list', className].filter(Boolean).join(' ');
10
+ return ((0, jsx_runtime_1.jsx)("div", { className: listCls, "aria-live": "assertive", role: "alert", children: errors.map((e) => ((0, jsx_runtime_1.jsxs)("div", { className: "xfc-inline-error-item", children: [(0, jsx_runtime_1.jsx)("span", { children: e.message }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "xfc-inline-error-dismiss", onClick: () => onDismiss(e.id), "aria-label": "\uB2EB\uAE30", children: "\u00D7" })] }, e.id))) }));
11
+ }
@@ -0,0 +1,8 @@
1
+ import type { ReactNode } from 'react';
2
+ export type LoadingOverlayProps = {
3
+ active: boolean;
4
+ message?: ReactNode;
5
+ className?: string;
6
+ };
7
+ /** 전역 로딩 오버레이 (business-promotion `GlobalIndicator` UI, 상태는 부모에서 주입). */
8
+ export declare function LoadingOverlay({ active, message, className }: LoadingOverlayProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoadingOverlay = LoadingOverlay;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /** 전역 로딩 오버레이 (business-promotion `GlobalIndicator` UI, 상태는 부모에서 주입). */
6
+ function LoadingOverlay({ active, message, className = '' }) {
7
+ if (!active)
8
+ return null;
9
+ const root = ['xfc-loading-overlay', className].filter(Boolean).join(' ');
10
+ return ((0, jsx_runtime_1.jsxs)("div", { className: root, role: "status", "aria-live": "polite", "aria-busy": "true", children: [(0, jsx_runtime_1.jsx)("span", { className: "xfc-loading-overlay-spinner", "aria-hidden": true }), message ? (0, jsx_runtime_1.jsx)("p", { className: "xfc-loading-overlay-message", children: message }) : null] }));
11
+ }
@@ -0,0 +1,25 @@
1
+ import type { ReactNode } from 'react';
2
+ export type ToastSeverity = 'info' | 'success' | 'warn' | 'error';
3
+ export declare function ToastSeverityIcon({ severity }: {
4
+ severity: ToastSeverity;
5
+ }): import("react/jsx-runtime").JSX.Element;
6
+ export type ToastProps = {
7
+ severity: ToastSeverity;
8
+ message: ReactNode;
9
+ onDismiss?: () => void;
10
+ className?: string;
11
+ };
12
+ /** 단일 토스트 행 (목록·커스텀 레이아웃용). */
13
+ export declare function Toast({ severity, message, onDismiss, className }: ToastProps): import("react/jsx-runtime").JSX.Element;
14
+ export type ToastEntry = {
15
+ id: string;
16
+ severity: ToastSeverity;
17
+ message: ReactNode;
18
+ };
19
+ export type ToastListProps = {
20
+ toasts: ToastEntry[];
21
+ onDismiss: (id: string) => void;
22
+ className?: string;
23
+ };
24
+ /** 하단 고정 토스트 스택 (business-promotion `ToastList` UI, 상태는 부모에서 주입). */
25
+ export declare function ToastList({ toasts, onDismiss, className }: ToastListProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToastSeverityIcon = ToastSeverityIcon;
4
+ exports.Toast = Toast;
5
+ exports.ToastList = ToastList;
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const iconSvgProps = {
8
+ width: 20,
9
+ height: 20,
10
+ viewBox: '0 0 20 20',
11
+ fill: 'none',
12
+ xmlns: 'http://www.w3.org/2000/svg',
13
+ 'aria-hidden': true,
14
+ };
15
+ function ToastSeverityIcon({ severity }) {
16
+ switch (severity) {
17
+ case 'success':
18
+ return ((0, jsx_runtime_1.jsxs)("svg", { ...iconSvgProps, children: [(0, jsx_runtime_1.jsx)("path", { d: "M10 18.5a8.5 8.5 0 100-17 8.5 8.5 0 000 17z", stroke: "currentColor", strokeWidth: "1.33" }), (0, jsx_runtime_1.jsx)("path", { d: "M6.2 10.1l2.4 2.4 5.2-5.2", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round", strokeLinejoin: "round" })] }));
19
+ case 'error':
20
+ return ((0, jsx_runtime_1.jsxs)("svg", { ...iconSvgProps, children: [(0, jsx_runtime_1.jsx)("path", { d: "M10 18.5a8.5 8.5 0 100-17 8.5 8.5 0 000 17z", stroke: "currentColor", strokeWidth: "1.33" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 6.2v5.2M10 13.7v.1", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round" })] }));
21
+ case 'warn':
22
+ return ((0, jsx_runtime_1.jsxs)("svg", { ...iconSvgProps, children: [(0, jsx_runtime_1.jsx)("path", { d: "M10 3.2L17.3 16H2.7L10 3.2z", stroke: "currentColor", strokeWidth: "1.33", strokeLinejoin: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 8v3.2M10 13.5v.1", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round" })] }));
23
+ case 'info':
24
+ default:
25
+ return ((0, jsx_runtime_1.jsxs)("svg", { ...iconSvgProps, children: [(0, jsx_runtime_1.jsx)("path", { d: "M10 18.5a8.5 8.5 0 100-17 8.5 8.5 0 000 17z", stroke: "currentColor", strokeWidth: "1.33" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 8.8V14M10 5.8v.1", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round" })] }));
26
+ }
27
+ }
28
+ function ToastCloseIcon() {
29
+ return ((0, jsx_runtime_1.jsx)("svg", { width: 20, height: 20, viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M5 5l10 10M15 5L5 15", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round" }) }));
30
+ }
31
+ /** 단일 토스트 행 (목록·커스텀 레이아웃용). */
32
+ function Toast({ severity, message, onDismiss, className = '' }) {
33
+ const root = ['xfc-toast', `xfc-toast--${severity}`, className].filter(Boolean).join(' ');
34
+ return ((0, jsx_runtime_1.jsxs)("div", { className: root, role: "alert", children: [(0, jsx_runtime_1.jsx)("span", { className: "xfc-toast__icon", children: (0, jsx_runtime_1.jsx)(ToastSeverityIcon, { severity: severity }) }), (0, jsx_runtime_1.jsx)("div", { className: "xfc-toast__message", children: message }), onDismiss ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "xfc-toast-dismiss", onClick: onDismiss, "aria-label": "\uB2EB\uAE30", children: (0, jsx_runtime_1.jsx)(ToastCloseIcon, {}) })) : null] }));
35
+ }
36
+ /** 하단 고정 토스트 스택 (business-promotion `ToastList` UI, 상태는 부모에서 주입). */
37
+ function ToastList({ toasts, onDismiss, className = '' }) {
38
+ if (!toasts.length)
39
+ return null;
40
+ const listCls = ['xfc-toast-list', className].filter(Boolean).join(' ');
41
+ return ((0, jsx_runtime_1.jsx)("div", { className: listCls, "aria-live": "polite", children: toasts.map((t) => ((0, jsx_runtime_1.jsx)(Toast, { severity: t.severity, message: t.message, onDismiss: () => onDismiss(t.id) }, t.id))) }));
42
+ }
@@ -0,0 +1,6 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react';
2
+ export type BadgeProps = HTMLAttributes<HTMLSpanElement> & {
3
+ tone?: 'neutral' | 'accent' | 'success' | 'danger';
4
+ children?: ReactNode;
5
+ };
6
+ export declare function Badge({ tone, className, children, ...rest }: BadgeProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Badge = Badge;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ function Badge({ tone = 'neutral', className = '', children, ...rest }) {
6
+ const cls = ['xfc-badge', `xfc-badge--${tone}`, className].filter(Boolean).join(' ');
7
+ return ((0, jsx_runtime_1.jsx)("span", { className: cls, ...rest, children: children }));
8
+ }
@@ -0,0 +1,6 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react';
2
+ export type BoxProps = HTMLAttributes<HTMLDivElement> & {
3
+ padding?: 'none' | 'sm' | 'md' | 'lg';
4
+ children?: ReactNode;
5
+ };
6
+ export declare function Box({ padding, className, children, ...rest }: BoxProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Box = Box;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ function Box({ padding = 'none', className = '', children, ...rest }) {
6
+ const padClass = padding === 'none' ? '' : padding === 'sm' ? 'xfc-box--p-sm' : padding === 'md' ? 'xfc-box--p-md' : 'xfc-box--p-lg';
7
+ const cls = ['xfc-box', padClass, className].filter(Boolean).join(' ');
8
+ return ((0, jsx_runtime_1.jsx)("div", { className: cls, ...rest, children: children }));
9
+ }
@@ -0,0 +1,5 @@
1
+ import type { ButtonHTMLAttributes } from 'react';
2
+ export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
3
+ variant?: 'primary' | 'secondary' | 'outline' | 'muted' | 'ghost';
4
+ };
5
+ export declare function Button({ variant, className, type, ...rest }: ButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Button = Button;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ function Button({ variant = 'primary', className = '', type = 'button', ...rest }) {
6
+ const cls = ['xfc-btn', `xfc-btn--${variant}`, className].filter(Boolean).join(' ');
7
+ return (0, jsx_runtime_1.jsx)("button", { type: type, className: cls, ...rest });
8
+ }
@@ -0,0 +1,5 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react';
2
+ export type CardProps = HTMLAttributes<HTMLDivElement> & {
3
+ children?: ReactNode;
4
+ };
5
+ export declare function Card({ className, children, ...rest }: CardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Card = Card;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ function Card({ className = '', children, ...rest }) {
6
+ const cls = ['xfc-card', className].filter(Boolean).join(' ');
7
+ return ((0, jsx_runtime_1.jsx)("div", { className: cls, ...rest, children: children }));
8
+ }
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from 'react';
2
+ export type InlineErrorEntry = {
3
+ id: string;
4
+ message: ReactNode;
5
+ };
6
+ export type InlineErrorListProps = {
7
+ errors: InlineErrorEntry[];
8
+ onDismiss: (id: string) => void;
9
+ className?: string;
10
+ };
11
+ /** 상단 고정 에러 배너 목록 (business-promotion `ErrorList` UI, MobX 없음). */
12
+ export declare function InlineErrorList({ errors, onDismiss, className }: InlineErrorListProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InlineErrorList = InlineErrorList;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /** 상단 고정 에러 배너 목록 (business-promotion `ErrorList` UI, MobX 없음). */
6
+ function InlineErrorList({ errors, onDismiss, className = '' }) {
7
+ if (!errors.length)
8
+ return null;
9
+ const listCls = ['xfc-inline-error-list', className].filter(Boolean).join(' ');
10
+ return ((0, jsx_runtime_1.jsx)("div", { className: listCls, "aria-live": "assertive", role: "alert", children: errors.map((e) => ((0, jsx_runtime_1.jsxs)("div", { className: "xfc-inline-error-item", children: [(0, jsx_runtime_1.jsx)("span", { children: e.message }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "xfc-inline-error-dismiss", onClick: () => onDismiss(e.id), "aria-label": "\uB2EB\uAE30", children: "\u00D7" })] }, e.id))) }));
11
+ }
@@ -0,0 +1,3 @@
1
+ import { type InputHTMLAttributes } from 'react';
2
+ export type InputProps = InputHTMLAttributes<HTMLInputElement>;
3
+ export declare const Input: import("react").ForwardRefExoticComponent<InputProps & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Input = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ exports.Input = (0, react_1.forwardRef)(function Input({ className = '', ...rest }, ref) {
7
+ const cls = ['xfc-input', className].filter(Boolean).join(' ');
8
+ return (0, jsx_runtime_1.jsx)("input", { ref: ref, className: cls, ...rest });
9
+ });
@@ -0,0 +1,8 @@
1
+ import type { ReactNode } from 'react';
2
+ export type LoadingOverlayProps = {
3
+ active: boolean;
4
+ message?: ReactNode;
5
+ className?: string;
6
+ };
7
+ /** 전역 로딩 오버레이 (business-promotion `GlobalIndicator` UI, 상태는 부모에서 주입). */
8
+ export declare function LoadingOverlay({ active, message, className }: LoadingOverlayProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoadingOverlay = LoadingOverlay;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /** 전역 로딩 오버레이 (business-promotion `GlobalIndicator` UI, 상태는 부모에서 주입). */
6
+ function LoadingOverlay({ active, message, className = '' }) {
7
+ if (!active)
8
+ return null;
9
+ const root = ['xfc-loading-overlay', className].filter(Boolean).join(' ');
10
+ return ((0, jsx_runtime_1.jsxs)("div", { className: root, role: "status", "aria-live": "polite", "aria-busy": "true", children: [(0, jsx_runtime_1.jsx)("span", { className: "xfc-loading-overlay-spinner", "aria-hidden": true }), message ? (0, jsx_runtime_1.jsx)("p", { className: "xfc-loading-overlay-message", children: message }) : null] }));
11
+ }
@@ -0,0 +1,8 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react';
2
+ export type StackProps = HTMLAttributes<HTMLDivElement> & {
3
+ direction?: 'row' | 'column';
4
+ gap?: 'none' | 'sm' | 'md' | 'lg';
5
+ align?: 'start' | 'center' | 'stretch';
6
+ children?: ReactNode;
7
+ };
8
+ export declare function Stack({ direction, gap, align, className, children, ...rest }: StackProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Stack = Stack;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ function Stack({ direction = 'column', gap = 'md', align = 'start', className = '', children, ...rest }) {
6
+ const cls = [
7
+ 'xfc-stack',
8
+ direction === 'column' ? 'xfc-stack--column' : 'xfc-stack--row',
9
+ `xfc-stack--gap-${gap}`,
10
+ `xfc-stack--align-${align}`,
11
+ className,
12
+ ]
13
+ .filter(Boolean)
14
+ .join(' ');
15
+ return ((0, jsx_runtime_1.jsx)("div", { className: cls, ...rest, children: children }));
16
+ }
@@ -0,0 +1,22 @@
1
+ import { type ElementType, type HTMLAttributes, type ReactNode } from 'react';
2
+ declare const variantClass: {
3
+ readonly title: "xfc-text xfc-text--title";
4
+ readonly appbar: "xfc-text xfc-text--appbar";
5
+ readonly section: "xfc-text xfc-text--section";
6
+ readonly subtitle: "xfc-text xfc-text--subtitle";
7
+ readonly body: "xfc-text xfc-text--body";
8
+ readonly muted: "xfc-text xfc-text--body xfc-text--muted";
9
+ readonly small: "xfc-text xfc-text--small";
10
+ readonly label: "xfc-text xfc-text--small xfc-text--muted";
11
+ readonly labelBlock: "xfc-text xfc-text--label-block";
12
+ readonly accent: "xfc-text xfc-text--body xfc-text--accent";
13
+ };
14
+ export type TextVariant = keyof typeof variantClass;
15
+ export type TextProps = {
16
+ as?: ElementType;
17
+ variant?: TextVariant;
18
+ children?: ReactNode;
19
+ className?: string;
20
+ } & HTMLAttributes<HTMLElement>;
21
+ export declare function Text({ as, variant, className, children, ...rest }: TextProps): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
22
+ export {};
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Text = Text;
4
+ const react_1 = require("react");
5
+ const variantClass = {
6
+ title: 'xfc-text xfc-text--title',
7
+ appbar: 'xfc-text xfc-text--appbar',
8
+ section: 'xfc-text xfc-text--section',
9
+ subtitle: 'xfc-text xfc-text--subtitle',
10
+ body: 'xfc-text xfc-text--body',
11
+ muted: 'xfc-text xfc-text--body xfc-text--muted',
12
+ small: 'xfc-text xfc-text--small',
13
+ label: 'xfc-text xfc-text--small xfc-text--muted',
14
+ labelBlock: 'xfc-text xfc-text--label-block',
15
+ accent: 'xfc-text xfc-text--body xfc-text--accent',
16
+ };
17
+ function Text({ as = 'p', variant = 'body', className = '', children, ...rest }) {
18
+ const cls = [variantClass[variant], className].filter(Boolean).join(' ');
19
+ return (0, react_1.createElement)(as, { className: cls, ...rest }, children);
20
+ }
@@ -0,0 +1,25 @@
1
+ import type { ReactNode } from 'react';
2
+ export type ToastSeverity = 'info' | 'success' | 'warn' | 'error';
3
+ export declare function ToastSeverityIcon({ severity }: {
4
+ severity: ToastSeverity;
5
+ }): import("react/jsx-runtime").JSX.Element;
6
+ export type ToastProps = {
7
+ severity: ToastSeverity;
8
+ message: ReactNode;
9
+ onDismiss?: () => void;
10
+ className?: string;
11
+ };
12
+ /** 단일 토스트 행 (목록·커스텀 레이아웃용). */
13
+ export declare function Toast({ severity, message, onDismiss, className }: ToastProps): import("react/jsx-runtime").JSX.Element;
14
+ export type ToastEntry = {
15
+ id: string;
16
+ severity: ToastSeverity;
17
+ message: ReactNode;
18
+ };
19
+ export type ToastListProps = {
20
+ toasts: ToastEntry[];
21
+ onDismiss: (id: string) => void;
22
+ className?: string;
23
+ };
24
+ /** 하단 고정 토스트 스택 (business-promotion `ToastList` UI, 상태는 부모에서 주입). */
25
+ export declare function ToastList({ toasts, onDismiss, className }: ToastListProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToastSeverityIcon = ToastSeverityIcon;
4
+ exports.Toast = Toast;
5
+ exports.ToastList = ToastList;
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const iconSvgProps = {
8
+ width: 20,
9
+ height: 20,
10
+ viewBox: '0 0 20 20',
11
+ fill: 'none',
12
+ xmlns: 'http://www.w3.org/2000/svg',
13
+ 'aria-hidden': true,
14
+ };
15
+ function ToastSeverityIcon({ severity }) {
16
+ switch (severity) {
17
+ case 'success':
18
+ return ((0, jsx_runtime_1.jsxs)("svg", { ...iconSvgProps, children: [(0, jsx_runtime_1.jsx)("path", { d: "M10 18.5a8.5 8.5 0 100-17 8.5 8.5 0 000 17z", stroke: "currentColor", strokeWidth: "1.33" }), (0, jsx_runtime_1.jsx)("path", { d: "M6.2 10.1l2.4 2.4 5.2-5.2", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round", strokeLinejoin: "round" })] }));
19
+ case 'error':
20
+ return ((0, jsx_runtime_1.jsxs)("svg", { ...iconSvgProps, children: [(0, jsx_runtime_1.jsx)("path", { d: "M10 18.5a8.5 8.5 0 100-17 8.5 8.5 0 000 17z", stroke: "currentColor", strokeWidth: "1.33" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 6.2v5.2M10 13.7v.1", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round" })] }));
21
+ case 'warn':
22
+ return ((0, jsx_runtime_1.jsxs)("svg", { ...iconSvgProps, children: [(0, jsx_runtime_1.jsx)("path", { d: "M10 3.2L17.3 16H2.7L10 3.2z", stroke: "currentColor", strokeWidth: "1.33", strokeLinejoin: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 8v3.2M10 13.5v.1", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round" })] }));
23
+ case 'info':
24
+ default:
25
+ return ((0, jsx_runtime_1.jsxs)("svg", { ...iconSvgProps, children: [(0, jsx_runtime_1.jsx)("path", { d: "M10 18.5a8.5 8.5 0 100-17 8.5 8.5 0 000 17z", stroke: "currentColor", strokeWidth: "1.33" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 8.8V14M10 5.8v.1", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round" })] }));
26
+ }
27
+ }
28
+ function ToastCloseIcon() {
29
+ return ((0, jsx_runtime_1.jsx)("svg", { width: 20, height: 20, viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M5 5l10 10M15 5L5 15", stroke: "currentColor", strokeWidth: "1.33", strokeLinecap: "round" }) }));
30
+ }
31
+ /** 단일 토스트 행 (목록·커스텀 레이아웃용). */
32
+ function Toast({ severity, message, onDismiss, className = '' }) {
33
+ const root = ['xfc-toast', `xfc-toast--${severity}`, className].filter(Boolean).join(' ');
34
+ return ((0, jsx_runtime_1.jsxs)("div", { className: root, role: "alert", children: [(0, jsx_runtime_1.jsx)("span", { className: "xfc-toast__icon", children: (0, jsx_runtime_1.jsx)(ToastSeverityIcon, { severity: severity }) }), (0, jsx_runtime_1.jsx)("div", { className: "xfc-toast__message", children: message }), onDismiss ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "xfc-toast-dismiss", onClick: onDismiss, "aria-label": "\uB2EB\uAE30", children: (0, jsx_runtime_1.jsx)(ToastCloseIcon, {}) })) : null] }));
35
+ }
36
+ /** 하단 고정 토스트 스택 (business-promotion `ToastList` UI, 상태는 부모에서 주입). */
37
+ function ToastList({ toasts, onDismiss, className = '' }) {
38
+ if (!toasts.length)
39
+ return null;
40
+ const listCls = ['xfc-toast-list', className].filter(Boolean).join(' ');
41
+ return ((0, jsx_runtime_1.jsx)("div", { className: listCls, "aria-live": "polite", children: toasts.map((t) => ((0, jsx_runtime_1.jsx)(Toast, { severity: t.severity, message: t.message, onDismiss: () => onDismiss(t.id) }, t.id))) }));
42
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Atomic UI — design tokens + base.css 의 `.xfc-*` 와 1:1.
3
+ * 패키지 루트는 `components/index.ts` → 여기서 동일 심볼을 재export.
4
+ */
5
+ export { Badge, type BadgeProps } from './Badge';
6
+ export { Box, type BoxProps } from './Box';
7
+ export { Button, type ButtonProps } from './Button';
8
+ export { Card, type CardProps } from './Card';
9
+ export { Input, type InputProps } from './Input';
10
+ export { InlineErrorList, type InlineErrorEntry, type InlineErrorListProps, } from './InlineErrorList';
11
+ export { LoadingOverlay, type LoadingOverlayProps } from './LoadingOverlay';
12
+ export { Stack, type StackProps } from './Stack';
13
+ export { Toast, ToastList, ToastSeverityIcon, type ToastEntry, type ToastListProps, type ToastProps, type ToastSeverity, } from './Toast';
14
+ export { Text, type TextProps, type TextVariant } from './Text';
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Text = exports.ToastSeverityIcon = exports.ToastList = exports.Toast = exports.Stack = exports.LoadingOverlay = exports.InlineErrorList = exports.Input = exports.Card = exports.Button = exports.Box = exports.Badge = void 0;
4
+ /**
5
+ * Atomic UI — design tokens + base.css 의 `.xfc-*` 와 1:1.
6
+ * 패키지 루트는 `components/index.ts` → 여기서 동일 심볼을 재export.
7
+ */
8
+ var Badge_1 = require("./Badge");
9
+ Object.defineProperty(exports, "Badge", { enumerable: true, get: function () { return Badge_1.Badge; } });
10
+ var Box_1 = require("./Box");
11
+ Object.defineProperty(exports, "Box", { enumerable: true, get: function () { return Box_1.Box; } });
12
+ var Button_1 = require("./Button");
13
+ Object.defineProperty(exports, "Button", { enumerable: true, get: function () { return Button_1.Button; } });
14
+ var Card_1 = require("./Card");
15
+ Object.defineProperty(exports, "Card", { enumerable: true, get: function () { return Card_1.Card; } });
16
+ var Input_1 = require("./Input");
17
+ Object.defineProperty(exports, "Input", { enumerable: true, get: function () { return Input_1.Input; } });
18
+ var InlineErrorList_1 = require("./InlineErrorList");
19
+ Object.defineProperty(exports, "InlineErrorList", { enumerable: true, get: function () { return InlineErrorList_1.InlineErrorList; } });
20
+ var LoadingOverlay_1 = require("./LoadingOverlay");
21
+ Object.defineProperty(exports, "LoadingOverlay", { enumerable: true, get: function () { return LoadingOverlay_1.LoadingOverlay; } });
22
+ var Stack_1 = require("./Stack");
23
+ Object.defineProperty(exports, "Stack", { enumerable: true, get: function () { return Stack_1.Stack; } });
24
+ var Toast_1 = require("./Toast");
25
+ Object.defineProperty(exports, "Toast", { enumerable: true, get: function () { return Toast_1.Toast; } });
26
+ Object.defineProperty(exports, "ToastList", { enumerable: true, get: function () { return Toast_1.ToastList; } });
27
+ Object.defineProperty(exports, "ToastSeverityIcon", { enumerable: true, get: function () { return Toast_1.ToastSeverityIcon; } });
28
+ var Text_1 = require("./Text");
29
+ Object.defineProperty(exports, "Text", { enumerable: true, get: function () { return Text_1.Text; } });
@@ -1,7 +1 @@
1
- export { Badge, type BadgeProps } from './Badge';
2
- export { Box, type BoxProps } from './Box';
3
- export { Button, type ButtonProps } from './Button';
4
- export { Card, type CardProps } from './Card';
5
- export { Input, type InputProps } from './Input';
6
- export { Stack, type StackProps } from './Stack';
7
- export { Text, type TextProps, type TextVariant } from './Text';
1
+ export * from './atoms';
@@ -1,17 +1,17 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Text = exports.Stack = exports.Input = exports.Card = exports.Button = exports.Box = exports.Badge = void 0;
4
- var Badge_1 = require("./Badge");
5
- Object.defineProperty(exports, "Badge", { enumerable: true, get: function () { return Badge_1.Badge; } });
6
- var Box_1 = require("./Box");
7
- Object.defineProperty(exports, "Box", { enumerable: true, get: function () { return Box_1.Box; } });
8
- var Button_1 = require("./Button");
9
- Object.defineProperty(exports, "Button", { enumerable: true, get: function () { return Button_1.Button; } });
10
- var Card_1 = require("./Card");
11
- Object.defineProperty(exports, "Card", { enumerable: true, get: function () { return Card_1.Card; } });
12
- var Input_1 = require("./Input");
13
- Object.defineProperty(exports, "Input", { enumerable: true, get: function () { return Input_1.Input; } });
14
- var Stack_1 = require("./Stack");
15
- Object.defineProperty(exports, "Stack", { enumerable: true, get: function () { return Stack_1.Stack; } });
16
- var Text_1 = require("./Text");
17
- Object.defineProperty(exports, "Text", { enumerable: true, get: function () { return Text_1.Text; } });
17
+ __exportStar(require("./atoms"), exports);
package/dist/index.d.ts CHANGED
@@ -1,11 +1,15 @@
1
1
  /**
2
2
  * @xfilecom/front-core — design tokens + atomic React components (browser-only).
3
3
  *
4
- * CSS ( 엔트리에서 순서대로):
4
+ * CSS (xframe 템플릿·web/shared 권장 순서):
5
5
  * import '@xfilecom/front-core/tokens.css';
6
+ * import '<shared>/styles/xfc-theme.css'; // 앱 토큰 덮어쓰기(선택)
6
7
  * import '@xfilecom/front-core/base.css';
8
+ * import '<shared>/styles/app.css'; // 레이아웃 + .xfc-* 오버라이드
9
+ *
10
+ * React atoms: 패키지 루트 또는 `@xfilecom/front-core/atoms`.
7
11
  */
8
- export declare const XFRAME_FRONT_CORE_VERSION = "0.2.1";
12
+ export declare const XFRAME_FRONT_CORE_VERSION = "0.2.4";
9
13
  /** CSS 커스텀 프로퍼티 이름 (-- 제외 시 var()와 함께 사용) */
10
14
  export declare const tokenVars: {
11
15
  readonly colorBg: "--xfc-bg";
@@ -34,5 +38,9 @@ export declare const tokenVars: {
34
38
  readonly textSection: "--xfc-text-section";
35
39
  readonly textBody: "--xfc-text-body";
36
40
  readonly textSmall: "--xfc-text-small";
41
+ readonly toastInfoBg: "--xfc-toast-info-bg";
42
+ readonly toastSuccessBg: "--xfc-toast-success-bg";
43
+ readonly toastWarnBg: "--xfc-toast-warn-bg";
44
+ readonly toastErrorBg: "--xfc-toast-error-bg";
37
45
  };
38
- export { Badge, Box, Button, Card, Input, Stack, Text, type BadgeProps, type BoxProps, type ButtonProps, type CardProps, type InputProps, type StackProps, type TextProps, type TextVariant, } from './components';
46
+ export { Badge, Box, Button, Card, InlineErrorList, Input, LoadingOverlay, Stack, Text, Toast, ToastList, ToastSeverityIcon, type BadgeProps, type BoxProps, type ButtonProps, type CardProps, type InlineErrorEntry, type InlineErrorListProps, type InputProps, type LoadingOverlayProps, type StackProps, type TextProps, type TextVariant, type ToastEntry, type ToastListProps, type ToastProps, type ToastSeverity, } from './components';
package/dist/index.js CHANGED
@@ -1,14 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Text = exports.Stack = exports.Input = exports.Card = exports.Button = exports.Box = exports.Badge = exports.tokenVars = exports.XFRAME_FRONT_CORE_VERSION = void 0;
3
+ exports.ToastSeverityIcon = exports.ToastList = exports.Toast = exports.Text = exports.Stack = exports.LoadingOverlay = exports.Input = exports.InlineErrorList = exports.Card = exports.Button = exports.Box = exports.Badge = exports.tokenVars = exports.XFRAME_FRONT_CORE_VERSION = void 0;
4
4
  /**
5
5
  * @xfilecom/front-core — design tokens + atomic React components (browser-only).
6
6
  *
7
- * CSS ( 엔트리에서 순서대로):
7
+ * CSS (xframe 템플릿·web/shared 권장 순서):
8
8
  * import '@xfilecom/front-core/tokens.css';
9
+ * import '<shared>/styles/xfc-theme.css'; // 앱 토큰 덮어쓰기(선택)
9
10
  * import '@xfilecom/front-core/base.css';
11
+ * import '<shared>/styles/app.css'; // 레이아웃 + .xfc-* 오버라이드
12
+ *
13
+ * React atoms: 패키지 루트 또는 `@xfilecom/front-core/atoms`.
10
14
  */
11
- exports.XFRAME_FRONT_CORE_VERSION = '0.2.1';
15
+ exports.XFRAME_FRONT_CORE_VERSION = '0.2.4';
12
16
  /** CSS 커스텀 프로퍼티 이름 (-- 제외 시 var()와 함께 사용) */
13
17
  exports.tokenVars = {
14
18
  colorBg: '--xfc-bg',
@@ -37,12 +41,21 @@ exports.tokenVars = {
37
41
  textSection: '--xfc-text-section',
38
42
  textBody: '--xfc-text-body',
39
43
  textSmall: '--xfc-text-small',
44
+ toastInfoBg: '--xfc-toast-info-bg',
45
+ toastSuccessBg: '--xfc-toast-success-bg',
46
+ toastWarnBg: '--xfc-toast-warn-bg',
47
+ toastErrorBg: '--xfc-toast-error-bg',
40
48
  };
41
49
  var components_1 = require("./components");
42
50
  Object.defineProperty(exports, "Badge", { enumerable: true, get: function () { return components_1.Badge; } });
43
51
  Object.defineProperty(exports, "Box", { enumerable: true, get: function () { return components_1.Box; } });
44
52
  Object.defineProperty(exports, "Button", { enumerable: true, get: function () { return components_1.Button; } });
45
53
  Object.defineProperty(exports, "Card", { enumerable: true, get: function () { return components_1.Card; } });
54
+ Object.defineProperty(exports, "InlineErrorList", { enumerable: true, get: function () { return components_1.InlineErrorList; } });
46
55
  Object.defineProperty(exports, "Input", { enumerable: true, get: function () { return components_1.Input; } });
56
+ Object.defineProperty(exports, "LoadingOverlay", { enumerable: true, get: function () { return components_1.LoadingOverlay; } });
47
57
  Object.defineProperty(exports, "Stack", { enumerable: true, get: function () { return components_1.Stack; } });
48
58
  Object.defineProperty(exports, "Text", { enumerable: true, get: function () { return components_1.Text; } });
59
+ Object.defineProperty(exports, "Toast", { enumerable: true, get: function () { return components_1.Toast; } });
60
+ Object.defineProperty(exports, "ToastList", { enumerable: true, get: function () { return components_1.ToastList; } });
61
+ Object.defineProperty(exports, "ToastSeverityIcon", { enumerable: true, get: function () { return components_1.ToastSeverityIcon; } });
package/dist/tokens.css CHANGED
@@ -34,6 +34,14 @@
34
34
  --xfc-warning: #d97706;
35
35
  --xfc-warning-bg: #fef3c7;
36
36
 
37
+ /* Toasts (business-promotion client index.css 와 동일 톤) */
38
+ --xfc-toast-info-bg: #1c252f;
39
+ --xfc-toast-success-bg: #19af66;
40
+ --xfc-toast-warn-bg: #e8a317;
41
+ --xfc-toast-error-bg: #f43b3c;
42
+ --xfc-toast-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
43
+ --xfc-toast-radius: 6px;
44
+
37
45
  /* Effects */
38
46
  --xfc-input-shadow: 0 7px 64px rgba(0, 0, 0, 0.07);
39
47
  --xfc-card-shadow: 0 1px 2px rgba(28, 37, 47, 0.06);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfilecom/front-core",
3
- "version": "0.2.2",
3
+ "version": "0.2.5",
4
4
  "description": "Shared design tokens, base CSS, and atomic React components (browser-only; no Nest dependency)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,7 +10,11 @@
10
10
  "default": "./dist/index.js"
11
11
  },
12
12
  "./tokens.css": "./dist/tokens.css",
13
- "./base.css": "./dist/base.css"
13
+ "./base.css": "./dist/base.css",
14
+ "./atoms": {
15
+ "types": "./dist/components/atoms/index.d.ts",
16
+ "default": "./dist/components/atoms/index.js"
17
+ }
14
18
  },
15
19
  "files": [
16
20
  "dist"