@designbasekorea/ui 0.5.1 → 0.5.4

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/dist/index.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react/jsx-runtime'), require('react'), require('@designbasekorea/icons'), require('react-dom')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'react/jsx-runtime', 'react', '@designbasekorea/icons', 'react-dom'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.DesignbaseUI = {}, global.jsxRuntime, global.React, global.icons, global.ReactDOM));
5
- })(this, (function (exports, jsxRuntime, React, icons, $4AOtR$reactdom) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react/jsx-runtime'), require('react'), require('@designbasekorea/icons'), require('react-dom'), require('@designbasekorea/theme')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'react/jsx-runtime', 'react', '@designbasekorea/icons', 'react-dom', '@designbasekorea/theme'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.DesignbaseUI = {}, global.jsxRuntime, global.React, global.icons, global.ReactDOM, global.theme));
5
+ })(this, (function (exports, jsxRuntime, React, icons, $4AOtR$reactdom, theme) { 'use strict';
6
6
 
7
7
  function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
8
8
 
@@ -2994,44 +2994,71 @@
2994
2994
  };
2995
2995
  const drawWaves = (ctx, width, height, options) => {
2996
2996
  const { colors, offset, speedFactor } = options;
2997
- offset.current += 0.02 * speedFactor;
2997
+ offset.current += 0.005 * speedFactor; // Slower, smoother movement
2998
2998
  colors.forEach((color, i) => {
2999
+ const rgb = hexToRgb$1(color);
3000
+ const gradient = ctx.createLinearGradient(0, 0, 0, height);
3001
+ // Gradient from color to transparent for depth
3002
+ gradient.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);
3003
+ gradient.addColorStop(0.5, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.5)`);
3004
+ gradient.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.8)`);
3005
+ ctx.fillStyle = gradient;
2999
3006
  ctx.beginPath();
3000
3007
  ctx.moveTo(0, height);
3001
- const freq = 0.003 + i * 0.001;
3002
- const amp = 30 + i * 20;
3003
- const phase = offset.current + i * 2;
3004
- for (let x = 0; x <= width; x += 10) {
3005
- const y = height / 2 +
3006
- Math.sin(x * freq + phase) * amp +
3007
- Math.sin(x * 0.001 + phase * 0.5) * 50;
3008
+ // Organic wave generation
3009
+ for (let x = 0; x <= width; x += 5) {
3010
+ const freq1 = 0.002 + i * 0.0005;
3011
+ const freq2 = 0.005 + i * 0.001;
3012
+ const phase = offset.current + i * 1.5;
3013
+ // Combine two sine waves for more natural look
3014
+ const y1 = Math.sin(x * freq1 + phase) * (40 + i * 15);
3015
+ const y2 = Math.sin(x * freq2 + phase * 1.2) * (20 + i * 5);
3016
+ const y = height / 1.5 + y1 + y2 + (i * 30); // Base height + waves + layering offset
3008
3017
  ctx.lineTo(x, y);
3009
3018
  }
3010
3019
  ctx.lineTo(width, height);
3011
3020
  ctx.lineTo(0, height);
3012
3021
  ctx.closePath();
3013
- ctx.fillStyle = color;
3022
+ // Add subtle blur for "dreamy" effect
3023
+ // Note: filter can be expensive, use sparingly.
3024
+ // If performance is an issue, remove this toggle or reduce canvas size.
3025
+ // ctx.filter = 'blur(4px)';
3026
+ ctx.globalAlpha = 0.6; // Base transparency
3014
3027
  ctx.fill();
3028
+ ctx.globalAlpha = 1.0;
3029
+ // ctx.filter = 'none';
3015
3030
  });
3016
3031
  };
3017
3032
  const drawPulse = (ctx, width, height, options) => {
3018
3033
  const { colors, time, intensity } = options;
3019
3034
  const centerX = width / 2;
3020
3035
  const centerY = height / 2;
3021
- const maxRadius = Math.max(width, height) * 0.8;
3022
- const intensityMap = { subtle: 0.5, medium: 1, vivid: 1.5 };
3036
+ const maxRadius = Math.max(width, height) * 0.6; // Slightly reduced max radius to keep it contained
3037
+ const intensityMap = { subtle: 0.8, medium: 1.2, vivid: 1.8 }; // Increased base intensity
3023
3038
  const factor = intensityMap[intensity];
3024
3039
  colors.forEach((color, i) => {
3025
- const t = time * 0.02 * factor + (i * (Math.PI * 2)) / colors.length;
3026
- const radius = (Math.sin(t) * 0.2 + 0.5) * maxRadius;
3027
- const alpha = (Math.sin(t + Math.PI) * 0.2 + 0.3) * factor;
3040
+ // Offset time for each color layer
3041
+ const t = time * 0.002 * factor + (i * (Math.PI / 1.5));
3042
+ // Breathing effect for radius
3043
+ const radius = (Math.sin(t) * 0.15 + 0.6) * maxRadius;
3044
+ // Breathing effect for opacity
3045
+ const alpha = (Math.sin(t + Math.PI / 2) * 0.3 + 0.5) * factor; // Higher base alpha (0.2->0.8 range)
3046
+ // Clamp alpha max to 1
3047
+ const safeAlpha = Math.min(Math.max(alpha, 0), 1);
3048
+ if (safeAlpha <= 0.01)
3049
+ return;
3028
3050
  const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius);
3029
3051
  const rgb = hexToRgb$1(color);
3052
+ // Harder center, softer edge
3030
3053
  gradient.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);
3031
- gradient.addColorStop(0.5, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha * 0.5})`);
3054
+ gradient.addColorStop(0.2, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${safeAlpha * 0.2})`);
3055
+ gradient.addColorStop(0.6, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${safeAlpha * 0.6})`);
3032
3056
  gradient.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);
3033
3057
  ctx.fillStyle = gradient;
3058
+ // Use globalCompositeOperation to blend nicely
3059
+ ctx.globalCompositeOperation = 'screen';
3034
3060
  ctx.fillRect(0, 0, width, height);
3061
+ ctx.globalCompositeOperation = 'source-over';
3035
3062
  });
3036
3063
  };
3037
3064
 
@@ -3323,63 +3350,132 @@
3323
3350
  }, children: content }), showGrid && (jsxRuntime.jsx(GridOverlay, { size: gridSize, color: effectiveGridColor, opacity: gridOpacity })), children && (jsxRuntime.jsx("div", { className: "designbase-animation-background__content", style: { position: 'relative', zIndex: 10, width: '100%', height: '100%' }, children: children }))] }));
3324
3351
  };
3325
3352
 
3326
- const AnimationText = ({ children, type = 'fade', speed = 1000, repeat = 0, delay = 0, direction = 'left', size = 'm', color = 'primary', customColor, weight = 'normal', align = 'left', gradientColors = ['#667eea', '#764ba2'], waveColors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#feca57'], glowColor = '#667eea', clickable = false, disabled = false, className, onClick, }) => {
3353
+ const AnimationText = ({ children, trigger = 'mount', type = 'fade', speed = 1000, repeat = 1, delay = 0, direction = 'left', size = 'm', color = 'primary', customColor, weight = 'normal', align = 'left', gradientColors = ['#667eea', '#764ba2'], waveColors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#feca57'], glowColor = '#667eea', clickable = false, disabled = false, className, onClick, }) => {
3327
3354
  const [isVisible, setIsVisible] = React.useState(false);
3328
- const [currentIndex, setCurrentIndex] = React.useState(0);
3329
3355
  const [isAnimating, setIsAnimating] = React.useState(false);
3356
+ // Initialize with full text unless it's a mount trigger for typing/decode
3357
+ const [displayText, setDisplayText] = React.useState((type === 'decode' || type === 'typing') && trigger === 'mount' ? '' : children);
3358
+ const [currentRepeat, setCurrentRepeat] = React.useState(0);
3330
3359
  const textRef = React.useRef(null);
3331
- React.useRef(null);
3332
- // 타이핑 애니메이션을 위한 상태
3333
- const [displayText, setDisplayText] = React.useState('');
3360
+ const observerRef = React.useRef(null);
3361
+ // Initial trigger logic
3334
3362
  React.useEffect(() => {
3335
- if (delay > 0) {
3363
+ if (trigger === 'mount') {
3336
3364
  const timer = setTimeout(() => {
3337
3365
  setIsVisible(true);
3366
+ startAnimation();
3338
3367
  }, delay);
3339
3368
  return () => clearTimeout(timer);
3340
3369
  }
3341
- else {
3342
- setIsVisible(true);
3370
+ else if (trigger === 'in-view' && textRef.current) {
3371
+ observerRef.current = new IntersectionObserver((entries) => {
3372
+ if (entries[0].isIntersecting) {
3373
+ setTimeout(() => {
3374
+ setIsVisible(true);
3375
+ startAnimation();
3376
+ }, delay);
3377
+ observerRef.current?.disconnect();
3378
+ }
3379
+ });
3380
+ observerRef.current.observe(textRef.current);
3381
+ return () => observerRef.current?.disconnect();
3343
3382
  }
3344
- }, [delay]);
3345
- // 타이핑 애니메이션
3383
+ }, [trigger, delay]);
3384
+ // Update initial text visibility when props change
3346
3385
  React.useEffect(() => {
3347
- if (type === 'typing' && isVisible) {
3348
- setDisplayText('');
3349
- setCurrentIndex(0);
3350
- const typeInterval = setInterval(() => {
3351
- setCurrentIndex(prev => {
3352
- if (prev >= children.length) {
3353
- clearInterval(typeInterval);
3354
- return prev;
3355
- }
3356
- setDisplayText(children.slice(0, prev + 1));
3357
- return prev + 1;
3358
- });
3359
- }, speed / children.length);
3360
- return () => clearInterval(typeInterval);
3386
+ if ((type === 'typing' || type === 'decode') && trigger === 'mount') ;
3387
+ else {
3388
+ // For hover/click, ensure text is visible when not animating
3389
+ if (!isAnimating) {
3390
+ setDisplayText(children);
3391
+ }
3361
3392
  }
3362
- }, [type, isVisible, children, speed]);
3363
- // 반복 애니메이션
3364
- React.useEffect(() => {
3365
- if (repeat > 0 && type !== 'typing') {
3366
- let repeatCount = 0;
3367
- const repeatAnimation = () => {
3368
- setIsAnimating(true);
3369
- setTimeout(() => {
3393
+ }, [children, type, trigger]);
3394
+ const startAnimation = () => {
3395
+ setIsAnimating(true);
3396
+ setCurrentRepeat(0);
3397
+ if (type === 'typing') {
3398
+ startTyping(0);
3399
+ }
3400
+ else if (type === 'decode') {
3401
+ startDecoding(0);
3402
+ }
3403
+ };
3404
+ const startTyping = (iteration) => {
3405
+ setDisplayText('');
3406
+ let currentIndex = 0;
3407
+ const interval = setInterval(() => {
3408
+ if (currentIndex >= children.length) {
3409
+ clearInterval(interval);
3410
+ // Repetition logic
3411
+ if (repeat === 0 || iteration < repeat - 1) {
3412
+ setTimeout(() => {
3413
+ startTyping(iteration + 1);
3414
+ }, 500);
3415
+ }
3416
+ else {
3370
3417
  setIsAnimating(false);
3371
- repeatCount++;
3372
- if (repeatCount < repeat) {
3373
- setTimeout(repeatAnimation, speed);
3374
- }
3375
- }, speed);
3376
- };
3377
- if (isVisible) {
3378
- setTimeout(repeatAnimation, speed);
3418
+ }
3419
+ return;
3379
3420
  }
3421
+ setDisplayText(children.slice(0, currentIndex + 1));
3422
+ currentIndex++;
3423
+ }, speed / children.length);
3424
+ };
3425
+ const startDecoding = (iteration) => {
3426
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+';
3427
+ let iterations = 0;
3428
+ const interval = setInterval(() => {
3429
+ setDisplayText(children.split('').map((char, index) => {
3430
+ if (index < iterations) {
3431
+ return children[index];
3432
+ }
3433
+ return characters[Math.floor(Math.random() * characters.length)];
3434
+ }).join(''));
3435
+ if (iterations >= children.length) {
3436
+ clearInterval(interval);
3437
+ setDisplayText(children);
3438
+ // Repetition logic
3439
+ if (repeat === 0 || iteration < repeat - 1) {
3440
+ setTimeout(() => {
3441
+ startDecoding(iteration + 1);
3442
+ }, 500);
3443
+ }
3444
+ else {
3445
+ setIsAnimating(false);
3446
+ }
3447
+ }
3448
+ iterations += 1 / 3;
3449
+ }, 30);
3450
+ };
3451
+ const handleMouseEnter = () => {
3452
+ if (trigger === 'hover') {
3453
+ setIsVisible(true);
3454
+ startAnimation();
3380
3455
  }
3381
- }, [repeat, type, speed, isVisible]);
3456
+ };
3457
+ const handleMouseLeave = () => {
3458
+ if (trigger === 'hover') {
3459
+ setIsVisible(false);
3460
+ setIsAnimating(false);
3461
+ if (type === 'typing' || type === 'decode') {
3462
+ setDisplayText(children);
3463
+ }
3464
+ }
3465
+ };
3382
3466
  const handleClick = () => {
3467
+ if (trigger === 'click') {
3468
+ setIsVisible(!isVisible);
3469
+ if (isVisible) {
3470
+ setIsAnimating(false);
3471
+ if (type === 'typing' || type === 'decode') {
3472
+ setDisplayText(children);
3473
+ }
3474
+ }
3475
+ else {
3476
+ startAnimation();
3477
+ }
3478
+ }
3383
3479
  if (clickable && !disabled && onClick) {
3384
3480
  onClick();
3385
3481
  }
@@ -3396,14 +3492,6 @@
3396
3492
  }
3397
3493
  return {};
3398
3494
  };
3399
- const getWaveStyle = () => {
3400
- if (type === 'wave') {
3401
- return {
3402
- '--wave-colors': waveColors.join(', '),
3403
- };
3404
- }
3405
- return {};
3406
- };
3407
3495
  const getGlowStyle = () => {
3408
3496
  if (type === 'glow') {
3409
3497
  return {
@@ -3412,26 +3500,52 @@
3412
3500
  }
3413
3501
  return {};
3414
3502
  };
3415
- const classes = classNames('designbase-animation-text', `designbase-animation-text--${type}`, `designbase-animation-text--${size}`, `designbase-animation-text--${color}`, `designbase-animation-text--${weight}`, `designbase-animation-text--${align}`, `designbase-animation-text--${direction}`, {
3503
+ // For typing, the class should be applied to the inner element to handle caret correctly with ghost element
3504
+ const containerClasses = classNames('designbase-animation-text',
3505
+ // Exclude typing logic from outer container to prevent caret on full-width ghost container
3506
+ type !== 'typing' && `designbase-animation-text--${type}`, `designbase-animation-text--${size}`, `designbase-animation-text--${color}`, `designbase-animation-text--${weight}`, `designbase-animation-text--${align}`, `designbase-animation-text--${direction}`, {
3416
3507
  'designbase-animation-text--visible': isVisible,
3417
3508
  'designbase-animation-text--animating': isAnimating,
3418
- 'designbase-animation-text--clickable': clickable,
3509
+ 'designbase-animation-text--clickable': clickable || trigger === 'click',
3419
3510
  'designbase-animation-text--disabled': disabled,
3420
3511
  }, className);
3421
3512
  const style = {
3422
3513
  ...getGradientStyle(),
3423
- ...getWaveStyle(),
3424
3514
  ...getGlowStyle(),
3425
3515
  '--db-animation-speed': `${speed}ms`,
3426
3516
  '--db-text-custom': customColor,
3517
+ '--db-wave-colors': waveColors.join(', '),
3518
+ '--db-animation-iteration-count': repeat === 0 ? 'infinite' : repeat,
3427
3519
  };
3428
- const renderText = () => {
3429
- if (type === 'typing') {
3430
- return displayText;
3431
- }
3432
- return children;
3433
- };
3434
- return (jsxRuntime.jsx("div", { ref: textRef, className: classes, style: style, onClick: handleClick, children: renderText() }));
3520
+ const renderContent = () => {
3521
+ if (type === 'wave' || type === 'shake') {
3522
+ if (!isVisible && !isAnimating)
3523
+ return children;
3524
+ return children.split('').map((char, index) => (jsxRuntime.jsx("span", { style: {
3525
+ animationDelay: `${index * 0.05}s`,
3526
+ display: 'inline-block'
3527
+ }, children: char === ' ' ? '\u00A0' : char }, index)));
3528
+ }
3529
+ return displayText;
3530
+ };
3531
+ return (jsxRuntime.jsxs("div", { ref: textRef, className: containerClasses, style: style, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [jsxRuntime.jsx("span", { "aria-hidden": "true", style: {
3532
+ visibility: 'hidden',
3533
+ pointerEvents: 'none',
3534
+ userSelect: 'none',
3535
+ whiteSpace: type === 'typing' ? 'pre-wrap' : undefined
3536
+ }, children: children }), jsxRuntime.jsx("span", { className: classNames({
3537
+ 'designbase-animation-text--typing': type === 'typing',
3538
+ 'designbase-animation-text--animating': isAnimating && type === 'typing' // Ensure animating class is passed for typing caret
3539
+ }), style: {
3540
+ position: 'absolute',
3541
+ top: 0,
3542
+ left: 0,
3543
+ // For typing, we want width to be auto so caret follows text
3544
+ // For others, width 100% matches ghost element
3545
+ width: type === 'typing' ? 'auto' : '100%',
3546
+ height: '100%',
3547
+ whiteSpace: type === 'typing' ? 'pre-wrap' : undefined // Ensure pre-wrap behavior matches
3548
+ }, children: renderContent() })] }));
3435
3549
  };
3436
3550
 
3437
3551
  const AudioPlayer = ({ src, title, artist, album, albumArt, size = 'm', variant = 'default', theme = 'auto', autoPlay = false, loop = false, muted = false, showControls = true, enableKeyboard = true, showProgress = true, showTime = true, showVolume = true, showSettings = false, playlist = [], currentIndex = 0, autoPause = true, playbackRates = [0.5, 0.75, 1, 1.25, 1.5, 2], defaultPlaybackRate = 1, repeatMode = 'none', shuffle = false, onPlay, onPause, onEnded, onTimeUpdate, onVolumeChange, onPlaylistChange, onPlaybackRateChange, onRepeatModeChange, onShuffleChange, onError, className, }) => {
@@ -4193,6 +4307,7 @@
4193
4307
 
4194
4308
  const Modal = ({ isOpen, onClose, title, size = 'm', closeOnOutsideClick = true, closeOnEscape = true, children, className, overlayClassName, }) => {
4195
4309
  const modalRef = React.useRef(null);
4310
+ const titleId = React.useId();
4196
4311
  // 아이콘 크기 계산 (m이 기본값)
4197
4312
  const iconSize = size === 's' ? 16 : size === 'l' ? 20 : size === 'xl' ? 24 : 18;
4198
4313
  // Prevent scrolling while modal is open
@@ -4224,11 +4339,12 @@
4224
4339
  return null;
4225
4340
  const modalClasses = clsx('designbase-modal', `designbase-modal--${size}`, className);
4226
4341
  const overlayClasses = clsx('designbase-modal__overlay', overlayClassName);
4227
- return (jsxRuntime.jsx("div", { className: overlayClasses, onClick: closeOnOutsideClick ? onClose : undefined, children: jsxRuntime.jsxs("div", { ref: modalRef, className: modalClasses, onClick: (e) => e.stopPropagation(), role: "dialog", "aria-modal": "true", "aria-labelledby": title ? 'modal-title' : undefined, children: [title && (jsxRuntime.jsx(ModalHeader, { title: title, showCloseButton: true, onClose: onClose, iconSize: iconSize })), jsxRuntime.jsx("div", { className: "designbase-modal__content", children: children })] }) }));
4342
+ return (jsxRuntime.jsx("div", { className: overlayClasses, onClick: closeOnOutsideClick ? onClose : undefined, children: jsxRuntime.jsxs("div", { ref: modalRef, className: modalClasses, onClick: (e) => e.stopPropagation(), role: "dialog", "aria-modal": "true", "aria-labelledby": title ? titleId : undefined, children: [title && (jsxRuntime.jsx(ModalHeader, { title: title, titleId: titleId, showCloseButton: true, onClose: onClose, iconSize: iconSize })), jsxRuntime.jsx("div", { className: "designbase-modal__content", children: children })] }) }));
4228
4343
  };
4229
- const ModalHeader = ({ title, showCloseButton = true, onClose, iconSize = 20, className, children, }) => {
4344
+ const ModalHeader = ({ title, titleId, showCloseButton = true, onClose, iconSize = 20, className, children, }) => {
4345
+ const fallbackTitleId = React.useId();
4230
4346
  const classes = clsx('designbase-modal__header', className);
4231
- return (jsxRuntime.jsxs("div", { className: classes, children: [jsxRuntime.jsxs("div", { className: "designbase-modal__header-content", children: [title && (jsxRuntime.jsx("h2", { id: "modal-title", className: "designbase-modal__title", children: title })), children] }), showCloseButton && onClose && (jsxRuntime.jsx("button", { type: "button", onClick: onClose, "aria-label": "\uBAA8\uB2EC \uB2EB\uAE30", className: "designbase-modal__close-button", children: jsxRuntime.jsx(icons.CloseIcon, { size: iconSize, color: "currentColor" }) }))] }));
4347
+ return (jsxRuntime.jsxs("div", { className: classes, children: [jsxRuntime.jsxs("div", { className: "designbase-modal__header-content", children: [title && (jsxRuntime.jsx("h2", { id: titleId || fallbackTitleId, className: "designbase-modal__title", children: title })), children] }), showCloseButton && onClose && (jsxRuntime.jsx("button", { type: "button", onClick: onClose, "aria-label": "\uBAA8\uB2EC \uB2EB\uAE30", className: "designbase-modal__close-button", children: jsxRuntime.jsx(icons.CloseIcon, { size: iconSize, color: "currentColor" }) }))] }));
4232
4348
  };
4233
4349
  const ModalBody = ({ className, children, }) => {
4234
4350
  const classes = clsx('designbase-modal__body', className);
@@ -4491,6 +4607,11 @@
4491
4607
  const [selectedValue, setSelectedValue] = React.useState(value ?? defaultValue ?? (multiple ? [] : ''));
4492
4608
  const [searchTerm, setSearchTerm] = React.useState('');
4493
4609
  const [focusedIndex, setFocusedIndex] = React.useState(-1);
4610
+ const selectId = React.useId();
4611
+ const labelId = `${selectId}-label`;
4612
+ const listboxId = `${selectId}-listbox`;
4613
+ const helperTextId = `${selectId}-helper-text`;
4614
+ const errorTextId = `${selectId}-error-text`;
4494
4615
  const containerRef = React.useRef(null);
4495
4616
  const inputRef = React.useRef(null);
4496
4617
  const dropdownRef = React.useRef(null);
@@ -4650,23 +4771,29 @@
4650
4771
  const filteredOptions = getFilteredOptions();
4651
4772
  const selectedLabels = getSelectedLabels();
4652
4773
  const hasValue = multiple ? selectedValue.length > 0 : selectedValue !== '';
4653
- return (jsxRuntime.jsxs("div", { className: classes, ref: containerRef, children: [label && (jsxRuntime.jsxs("label", { className: "designbase-select__label", children: [label, required && jsxRuntime.jsx("span", { className: "designbase-select__required", children: "*" })] })), jsxRuntime.jsxs("div", { className: triggerClasses, onClick: handleToggle, onFocus: onFocus, onBlur: onBlur, tabIndex: disabled || readOnly ? -1 : 0, role: "combobox", "aria-expanded": isOpen, "aria-haspopup": "listbox", "aria-labelledby": label ? 'select-label' : undefined, ...props, children: [jsxRuntime.jsx("div", { className: "designbase-select__value", children: multiple ? (jsxRuntime.jsx("div", { className: "designbase-select__tags", ref: tagsContainerRef, children: selectedValue.map((value) => {
4774
+ const activeDescendantId = focusedIndex >= 0 ? `${selectId}-option-${focusedIndex}` : undefined;
4775
+ const describedBy = error && errorMessage
4776
+ ? errorTextId
4777
+ : helperText
4778
+ ? helperTextId
4779
+ : undefined;
4780
+ return (jsxRuntime.jsxs("div", { className: classes, ref: containerRef, children: [label && (jsxRuntime.jsxs("label", { id: labelId, className: "designbase-select__label", children: [label, required && jsxRuntime.jsx("span", { className: "designbase-select__required", children: "*" })] })), jsxRuntime.jsxs("div", { className: triggerClasses, onClick: handleToggle, onFocus: onFocus, onBlur: onBlur, tabIndex: disabled || readOnly ? -1 : 0, role: "combobox", "aria-expanded": isOpen, "aria-haspopup": "listbox", "aria-controls": listboxId, "aria-activedescendant": activeDescendantId, "aria-labelledby": label ? labelId : undefined, "aria-describedby": describedBy, "aria-invalid": error, ...props, children: [jsxRuntime.jsx("div", { className: "designbase-select__value", children: multiple ? (jsxRuntime.jsx("div", { className: "designbase-select__tags", ref: tagsContainerRef, children: selectedValue.map((value) => {
4654
4781
  const option = options.find(opt => opt.value === value);
4655
4782
  return (jsxRuntime.jsxs("span", { className: "designbase-select__tag", children: [jsxRuntime.jsx("span", { className: "designbase-select__tag-label", children: option?.label || value }), jsxRuntime.jsx("button", { type: "button", className: "designbase-select__tag-remove", onClick: (e) => {
4656
4783
  e.stopPropagation();
4657
4784
  handleRemoveValue(value);
4658
4785
  }, children: jsxRuntime.jsx(icons.CloseIcon, { size: 12 }) })] }, value));
4659
- }) })) : (jsxRuntime.jsx("span", { className: "designbase-select__single-value", children: selectedLabels || placeholder })) }), jsxRuntime.jsxs("div", { className: "designbase-select__indicators", children: [showClearButton && hasValue && !disabled && !readOnly && (jsxRuntime.jsx("button", { type: "button", className: "designbase-select__clear-button", onClick: handleClearAll, "aria-label": "\uBAA8\uB4E0 \uAC12 \uC9C0\uC6B0\uAE30", children: jsxRuntime.jsx(icons.CloseIcon, { size: 16 }) })), jsxRuntime.jsx("div", { className: "designbase-select__chevron", children: isOpen ? jsxRuntime.jsx(icons.ChevronUpIcon, { size: 16 }) : jsxRuntime.jsx(icons.ChevronDownIcon, { size: 16 }) })] })] }), jsxRuntime.jsxs("div", { className: dropdownClasses, ref: dropdownRef, children: [searchable && (jsxRuntime.jsx("div", { className: "designbase-select__search", onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), children: jsxRuntime.jsx(SearchBar, { value: searchTerm, onChange: (value) => setSearchTerm(value), onSearch: (val) => setSearchTerm(val), placeholder: "\uC635\uC158 \uAC80\uC0C9", size: size, variant: "outlined", fullWidth: true, onFocus: (e) => e.stopPropagation(), onBlur: (e) => e.stopPropagation() }) })), jsxRuntime.jsx("div", { className: "designbase-select__options", style: { maxHeight: `${maxHeight}px` }, role: "listbox", children: filteredOptions.length === 0 ? (jsxRuntime.jsx("div", { className: "designbase-select__no-options", children: searchTerm ? '검색 결과가 없습니다.' : '옵션이 없습니다.' })) : (filteredOptions.map((option, index) => {
4786
+ }) })) : (jsxRuntime.jsx("span", { className: "designbase-select__single-value", children: selectedLabels || placeholder })) }), jsxRuntime.jsxs("div", { className: "designbase-select__indicators", children: [showClearButton && hasValue && !disabled && !readOnly && (jsxRuntime.jsx("button", { type: "button", className: "designbase-select__clear-button", onClick: handleClearAll, "aria-label": "\uBAA8\uB4E0 \uAC12 \uC9C0\uC6B0\uAE30", children: jsxRuntime.jsx(icons.CloseIcon, { size: 16 }) })), jsxRuntime.jsx("div", { className: "designbase-select__chevron", children: isOpen ? jsxRuntime.jsx(icons.ChevronUpIcon, { size: 16 }) : jsxRuntime.jsx(icons.ChevronDownIcon, { size: 16 }) })] })] }), jsxRuntime.jsxs("div", { className: dropdownClasses, ref: dropdownRef, children: [searchable && (jsxRuntime.jsx("div", { className: "designbase-select__search", onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), children: jsxRuntime.jsx(SearchBar, { value: searchTerm, onChange: (value) => setSearchTerm(value), onSearch: (val) => setSearchTerm(val), placeholder: "\uC635\uC158 \uAC80\uC0C9", size: size, variant: "outlined", fullWidth: true, onFocus: (e) => e.stopPropagation(), onBlur: (e) => e.stopPropagation() }) })), jsxRuntime.jsx("div", { className: "designbase-select__options", style: { maxHeight: `${maxHeight}px` }, id: listboxId, role: "listbox", children: filteredOptions.length === 0 ? (jsxRuntime.jsx("div", { className: "designbase-select__no-options", children: searchTerm ? '검색 결과가 없습니다.' : '옵션이 없습니다.' })) : (filteredOptions.map((option, index) => {
4660
4787
  const isSelected = multiple
4661
4788
  ? selectedValue.includes(option.value)
4662
4789
  : selectedValue === option.value;
4663
4790
  const isFocused = index === focusedIndex;
4664
- return (jsxRuntime.jsxs("div", { className: clsx('designbase-select__option', {
4791
+ return (jsxRuntime.jsxs("div", { id: `${selectId}-option-${index}`, className: clsx('designbase-select__option', {
4665
4792
  'designbase-select__option--selected': isSelected,
4666
4793
  'designbase-select__option--focused': isFocused,
4667
4794
  'designbase-select__option--disabled': option.disabled,
4668
4795
  }), onClick: () => handleOptionSelect(option), role: "option", "aria-selected": isSelected, children: [multiple && (jsxRuntime.jsx("div", { className: "designbase-select__checkbox", children: jsxRuntime.jsx(Checkbox, { isSelected: isSelected, isDisabled: option.disabled, size: "s", hasLabel: false, onChange: () => handleOptionSelect(option) }) })), jsxRuntime.jsx("span", { className: "designbase-select__option-label", children: option.label })] }, option.value));
4669
- })) })] }), helperText && !error && (jsxRuntime.jsx("p", { className: "designbase-select__helper-text", children: helperText })), error && errorMessage && (jsxRuntime.jsx("p", { className: "designbase-select__error-message", children: errorMessage }))] }));
4796
+ })) })] }), helperText && !error && (jsxRuntime.jsx("p", { id: helperTextId, className: "designbase-select__helper-text", children: helperText })), error && errorMessage && (jsxRuntime.jsx("p", { id: errorTextId, className: "designbase-select__error-message", children: errorMessage }))] }));
4670
4797
  };
4671
4798
  Select.displayName = 'Select';
4672
4799
 
@@ -5270,7 +5397,7 @@
5270
5397
  return null;
5271
5398
  return (jsxRuntime.jsx("div", { className: "designbase-card__actions", children: actions.map((action, index) => {
5272
5399
  const ActionIcon = action.icon;
5273
- return (jsxRuntime.jsx(Button, { variant: action.variant || 'primary', size: action.size || 's', onClick: () => handleActionClick(action, index), disabled: action.disabled || disabled, loading: !!action.loading, icon: ActionIcon, children: action.label }, index));
5400
+ return (jsxRuntime.jsx(Button, { variant: action.variant || 'primary', size: action.size || 's', onClick: () => handleActionClick(action, index), disabled: action.disabled || disabled, loading: !!action.loading, startIcon: ActionIcon, children: action.label }, index));
5274
5401
  }) }));
5275
5402
  };
5276
5403
  const renderContent = () => (jsxRuntime.jsxs("div", { className: "designbase-card__content", children: [renderIcon(), (title || subtitle) && (jsxRuntime.jsxs("div", { className: "designbase-card__header", children: [title && jsxRuntime.jsx("h3", { className: "designbase-card__title", children: title }), subtitle && jsxRuntime.jsx("p", { className: "designbase-card__subtitle", children: subtitle })] })), description && jsxRuntime.jsx("p", { className: "designbase-card__description", children: description }), children && jsxRuntime.jsx("div", { className: "designbase-card__body", children: children }), renderTags(), renderMeta(), renderActions()] }));
@@ -10898,7 +11025,7 @@
10898
11025
  }
10899
11026
  };
10900
11027
 
10901
- const Sidebar = ({ size = 'm', variant = 'default', position = 'left', logo, onLogoClick, items = [], onItemClick, userProfile, userMenuItems = [], onUserMenuItemClick, collapsed = false, onToggle, collapsible = true, fixed = false, fullHeight = false, shadow = false, className, ...props }) => {
11028
+ const Sidebar = ({ size = 'm', variant = 'default', position = 'left', showLogo = false, logo, onLogoClick, items = [], onItemClick, userProfile, userMenuItems = [], onUserMenuItemClick, collapsed = false, onToggle, collapsible = true, fixed = false, fullHeight = false, shadow = false, className, ...props }) => {
10902
11029
  const [expandedItems, setExpandedItems] = React.useState([]);
10903
11030
  const handleToggle = () => {
10904
11031
  if (onToggle) {
@@ -10939,24 +11066,24 @@
10939
11066
  const hasChildren = item.children && item.children.length > 0;
10940
11067
  return (jsxRuntime.jsx("li", { className: "designbase-sidebar__item", children: jsxRuntime.jsx(MenuItem, { ...item, type: "block", style: "accordion", depth: level, expanded: isExpanded, expandable: hasChildren, onClick: () => handleItemClick(item), onChildClick: (child) => handleItemClick(child) }) }, item.id));
10941
11068
  };
10942
- return (jsxRuntime.jsx("aside", { className: classes, role: "complementary", "aria-label": "\uC0AC\uC774\uB4DC\uBC14 \uB124\uBE44\uAC8C\uC774\uC158", ...props, children: jsxRuntime.jsxs("div", { className: "designbase-sidebar__container", children: [jsxRuntime.jsxs("div", { className: "designbase-sidebar__header", children: [jsxRuntime.jsx("div", { className: "designbase-sidebar__logo", onClick: onLogoClick, role: onLogoClick ? 'button' : undefined, tabIndex: onLogoClick ? 0 : undefined, onKeyDown: (e) => {
11069
+ return (jsxRuntime.jsx("aside", { className: classes, role: "complementary", "aria-label": "\uC0AC\uC774\uB4DC\uBC14 \uB124\uBE44\uAC8C\uC774\uC158", ...props, children: jsxRuntime.jsxs("div", { className: "designbase-sidebar__container", children: [showLogo && (jsxRuntime.jsxs("div", { className: "designbase-sidebar__header", children: [jsxRuntime.jsx("div", { className: "designbase-sidebar__logo", onClick: onLogoClick, role: onLogoClick ? 'button' : undefined, tabIndex: onLogoClick ? 0 : undefined, onKeyDown: (e) => {
10943
11070
  if (onLogoClick && (e.key === 'Enter' || e.key === ' ')) {
10944
11071
  e.preventDefault();
10945
11072
  onLogoClick();
10946
11073
  }
10947
11074
  }, children: logo || jsxRuntime.jsx(Logo, { size: "s" }) }), collapsible && (jsxRuntime.jsx(Button, { variant: "ghost", size: "s", iconOnly: true, className: "designbase-sidebar__toggle", onPress: handleToggle, "aria-label": collapsed ? '사이드바 펼치기' : '사이드바 접기', children: jsxRuntime.jsx(icons.ChevronLeftIcon, { className: clsx('designbase-sidebar__toggle-icon', {
10948
11075
  'designbase-sidebar__toggle-icon--collapsed': collapsed,
10949
- }) }) }))] }), jsxRuntime.jsx("nav", { className: "designbase-sidebar__nav", children: jsxRuntime.jsx("ul", { className: "designbase-sidebar__nav-list", children: items.map((item) => renderSidebarItem(item)) }) }), userProfile && !collapsed && (jsxRuntime.jsxs("div", { className: "designbase-sidebar__user", children: [jsxRuntime.jsxs("div", { className: "designbase-sidebar__user-info", onClick: () => onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' }), role: "button", tabIndex: 0, onKeyDown: (e) => {
11076
+ }) }) }))] })), jsxRuntime.jsx("nav", { className: "designbase-sidebar__nav", children: jsxRuntime.jsx("ul", { className: "designbase-sidebar__nav-list", children: items.map((item) => renderSidebarItem(item)) }) }), userProfile && !collapsed && (jsxRuntime.jsxs("div", { className: "designbase-sidebar__user", children: [jsxRuntime.jsxs("div", { className: "designbase-sidebar__user-info", onClick: () => onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' }), role: "button", tabIndex: 0, onKeyDown: (e) => {
10950
11077
  if (e.key === 'Enter' || e.key === ' ') {
10951
11078
  e.preventDefault();
10952
11079
  onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
10953
11080
  }
10954
- }, style: { cursor: 'pointer' }, children: [userProfile.avatar ? (jsxRuntime.jsx("img", { src: userProfile.avatar, alt: userProfile.name, className: "designbase-sidebar__user-avatar" })) : (jsxRuntime.jsx("div", { className: "designbase-sidebar__user-avatar-placeholder", children: userProfile.name.charAt(0).toUpperCase() })), jsxRuntime.jsxs("div", { className: "designbase-sidebar__user-details", children: [jsxRuntime.jsx("div", { className: "designbase-sidebar__user-name", children: userProfile.name }), userProfile.email && (jsxRuntime.jsx("div", { className: "designbase-sidebar__user-email", children: userProfile.email })), userProfile.role && (jsxRuntime.jsx("div", { className: "designbase-sidebar__user-role", children: userProfile.role }))] })] }), userMenuItems.length > 0 && (jsxRuntime.jsx("ul", { className: "designbase-sidebar__user-menu", children: userMenuItems.map((item) => (jsxRuntime.jsx("li", { children: jsxRuntime.jsx(MenuItem, { id: item.id, label: item.label, href: item.href, icon: item.icon, disabled: item.disabled, type: "block", style: "accordion", onClick: () => handleUserMenuItemClick(item) }) }, item.id))) }))] })), userProfile && collapsed && (jsxRuntime.jsx("div", { className: "designbase-sidebar__user-collapsed", onClick: () => onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' }), role: "button", tabIndex: 0, onKeyDown: (e) => {
11081
+ }, style: { cursor: 'pointer' }, children: [jsxRuntime.jsx(Avatar, { src: userProfile.avatar, initials: userProfile.name, alt: userProfile.name, size: "s", className: "designbase-sidebar__user-avatar" }), jsxRuntime.jsxs("div", { className: "designbase-sidebar__user-details", children: [jsxRuntime.jsx("div", { className: "designbase-sidebar__user-name", children: userProfile.name }), userProfile.email && (jsxRuntime.jsx("div", { className: "designbase-sidebar__user-email", children: userProfile.email })), userProfile.role && (jsxRuntime.jsx("div", { className: "designbase-sidebar__user-role", children: userProfile.role }))] })] }), userMenuItems.length > 0 && (jsxRuntime.jsx("ul", { className: "designbase-sidebar__user-menu", children: userMenuItems.map((item) => (jsxRuntime.jsx("li", { children: jsxRuntime.jsx(MenuItem, { id: item.id, label: item.label, href: item.href, icon: item.icon, disabled: item.disabled, type: "block", style: "accordion", onClick: () => handleUserMenuItemClick(item) }) }, item.id))) }))] })), userProfile && collapsed && (jsxRuntime.jsx("div", { className: "designbase-sidebar__user-collapsed", onClick: () => onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' }), role: "button", tabIndex: 0, onKeyDown: (e) => {
10955
11082
  if (e.key === 'Enter' || e.key === ' ') {
10956
11083
  e.preventDefault();
10957
11084
  onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
10958
11085
  }
10959
- }, style: { cursor: 'pointer' }, children: userProfile.avatar ? (jsxRuntime.jsx("img", { src: userProfile.avatar, alt: userProfile.name, className: "designbase-sidebar__user-avatar-collapsed" })) : (jsxRuntime.jsx("div", { className: "designbase-sidebar__user-avatar-placeholder-collapsed", children: userProfile.name.charAt(0).toUpperCase() })) }))] }) }));
11086
+ }, style: { cursor: 'pointer' }, children: jsxRuntime.jsx(Avatar, { src: userProfile.avatar, initials: userProfile.name, alt: userProfile.name, size: "s", className: "designbase-sidebar__user-avatar-collapsed" }) }))] }) }));
10960
11087
  };
10961
11088
  Sidebar.displayName = 'Sidebar';
10962
11089
 
@@ -12391,25 +12518,18 @@
12391
12518
  };
12392
12519
  YouTubePlayer.displayName = 'YouTubePlayer';
12393
12520
 
12394
- /**
12395
- * Designbase UI 컴포넌트 라이브러리 메인 엔트리 포인트
12396
- *
12397
- * 목적: 모든 UI 컴포넌트와 타입을 내보냄
12398
- * 기능: Tree-shaking 가능한 개별 컴포넌트 내보내기
12399
- * 사용법: import { Button, Input } from '@designbasekorea/ui'
12400
- */
12401
- // 테마 CSS 자동 로드 (로컬 복사본 사용)
12402
- // 테마 관련 유틸리티 재내보내기
12403
- const setTheme = (theme) => {
12404
- console.log('setTheme called with:', theme);
12405
- };
12406
- const getTheme = () => {
12407
- return 'light';
12408
- };
12409
- const toggleTheme = () => {
12410
- console.log('toggleTheme called');
12411
- };
12412
-
12521
+ Object.defineProperty(exports, 'getTheme', {
12522
+ enumerable: true,
12523
+ get: function () { return theme.getTheme; }
12524
+ });
12525
+ Object.defineProperty(exports, 'setTheme', {
12526
+ enumerable: true,
12527
+ get: function () { return theme.setTheme; }
12528
+ });
12529
+ Object.defineProperty(exports, 'toggleTheme', {
12530
+ enumerable: true,
12531
+ get: function () { return theme.toggleTheme; }
12532
+ });
12413
12533
  exports.Accordion = Accordion;
12414
12534
  exports.AdBanner = AdBanner;
12415
12535
  exports.Alert = Alert;
@@ -12502,9 +12622,6 @@
12502
12622
  exports.Tutorial = Tutorial;
12503
12623
  exports.VideoPlayer = VideoPlayer;
12504
12624
  exports.YouTubePlayer = YouTubePlayer;
12505
- exports.getTheme = getTheme;
12506
- exports.setTheme = setTheme;
12507
- exports.toggleTheme = toggleTheme;
12508
12625
  exports.useToast = useToast;
12509
12626
 
12510
12627
  }));