@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.js CHANGED
@@ -4,6 +4,7 @@ var jsxRuntime = require('react/jsx-runtime');
4
4
  var React = require('react');
5
5
  var icons = require('@designbasekorea/icons');
6
6
  var $4AOtR$reactdom = require('react-dom');
7
+ var theme = require('@designbasekorea/theme');
7
8
 
8
9
  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}
9
10
 
@@ -2995,44 +2996,71 @@ const drawStars = (ctx, width, height, starsRef, options) => {
2995
2996
  };
2996
2997
  const drawWaves = (ctx, width, height, options) => {
2997
2998
  const { colors, offset, speedFactor } = options;
2998
- offset.current += 0.02 * speedFactor;
2999
+ offset.current += 0.005 * speedFactor; // Slower, smoother movement
2999
3000
  colors.forEach((color, i) => {
3001
+ const rgb = hexToRgb$1(color);
3002
+ const gradient = ctx.createLinearGradient(0, 0, 0, height);
3003
+ // Gradient from color to transparent for depth
3004
+ gradient.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);
3005
+ gradient.addColorStop(0.5, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.5)`);
3006
+ gradient.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.8)`);
3007
+ ctx.fillStyle = gradient;
3000
3008
  ctx.beginPath();
3001
3009
  ctx.moveTo(0, height);
3002
- const freq = 0.003 + i * 0.001;
3003
- const amp = 30 + i * 20;
3004
- const phase = offset.current + i * 2;
3005
- for (let x = 0; x <= width; x += 10) {
3006
- const y = height / 2 +
3007
- Math.sin(x * freq + phase) * amp +
3008
- Math.sin(x * 0.001 + phase * 0.5) * 50;
3010
+ // Organic wave generation
3011
+ for (let x = 0; x <= width; x += 5) {
3012
+ const freq1 = 0.002 + i * 0.0005;
3013
+ const freq2 = 0.005 + i * 0.001;
3014
+ const phase = offset.current + i * 1.5;
3015
+ // Combine two sine waves for more natural look
3016
+ const y1 = Math.sin(x * freq1 + phase) * (40 + i * 15);
3017
+ const y2 = Math.sin(x * freq2 + phase * 1.2) * (20 + i * 5);
3018
+ const y = height / 1.5 + y1 + y2 + (i * 30); // Base height + waves + layering offset
3009
3019
  ctx.lineTo(x, y);
3010
3020
  }
3011
3021
  ctx.lineTo(width, height);
3012
3022
  ctx.lineTo(0, height);
3013
3023
  ctx.closePath();
3014
- ctx.fillStyle = color;
3024
+ // Add subtle blur for "dreamy" effect
3025
+ // Note: filter can be expensive, use sparingly.
3026
+ // If performance is an issue, remove this toggle or reduce canvas size.
3027
+ // ctx.filter = 'blur(4px)';
3028
+ ctx.globalAlpha = 0.6; // Base transparency
3015
3029
  ctx.fill();
3030
+ ctx.globalAlpha = 1.0;
3031
+ // ctx.filter = 'none';
3016
3032
  });
3017
3033
  };
3018
3034
  const drawPulse = (ctx, width, height, options) => {
3019
3035
  const { colors, time, intensity } = options;
3020
3036
  const centerX = width / 2;
3021
3037
  const centerY = height / 2;
3022
- const maxRadius = Math.max(width, height) * 0.8;
3023
- const intensityMap = { subtle: 0.5, medium: 1, vivid: 1.5 };
3038
+ const maxRadius = Math.max(width, height) * 0.6; // Slightly reduced max radius to keep it contained
3039
+ const intensityMap = { subtle: 0.8, medium: 1.2, vivid: 1.8 }; // Increased base intensity
3024
3040
  const factor = intensityMap[intensity];
3025
3041
  colors.forEach((color, i) => {
3026
- const t = time * 0.02 * factor + (i * (Math.PI * 2)) / colors.length;
3027
- const radius = (Math.sin(t) * 0.2 + 0.5) * maxRadius;
3028
- const alpha = (Math.sin(t + Math.PI) * 0.2 + 0.3) * factor;
3042
+ // Offset time for each color layer
3043
+ const t = time * 0.002 * factor + (i * (Math.PI / 1.5));
3044
+ // Breathing effect for radius
3045
+ const radius = (Math.sin(t) * 0.15 + 0.6) * maxRadius;
3046
+ // Breathing effect for opacity
3047
+ const alpha = (Math.sin(t + Math.PI / 2) * 0.3 + 0.5) * factor; // Higher base alpha (0.2->0.8 range)
3048
+ // Clamp alpha max to 1
3049
+ const safeAlpha = Math.min(Math.max(alpha, 0), 1);
3050
+ if (safeAlpha <= 0.01)
3051
+ return;
3029
3052
  const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius);
3030
3053
  const rgb = hexToRgb$1(color);
3054
+ // Harder center, softer edge
3031
3055
  gradient.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);
3032
- gradient.addColorStop(0.5, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha * 0.5})`);
3056
+ gradient.addColorStop(0.2, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${safeAlpha * 0.2})`);
3057
+ gradient.addColorStop(0.6, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${safeAlpha * 0.6})`);
3033
3058
  gradient.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);
3034
3059
  ctx.fillStyle = gradient;
3060
+ // Use globalCompositeOperation to blend nicely
3061
+ ctx.globalCompositeOperation = 'screen';
3035
3062
  ctx.fillRect(0, 0, width, height);
3063
+ ctx.globalCompositeOperation = 'source-over';
3036
3064
  });
3037
3065
  };
3038
3066
 
@@ -3324,63 +3352,132 @@ const AnimationBackground = ({ type = 'gradient', theme = 'dark', intensity = 's
3324
3352
  }, 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 }))] }));
3325
3353
  };
3326
3354
 
3327
- 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, }) => {
3355
+ 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, }) => {
3328
3356
  const [isVisible, setIsVisible] = React.useState(false);
3329
- const [currentIndex, setCurrentIndex] = React.useState(0);
3330
3357
  const [isAnimating, setIsAnimating] = React.useState(false);
3358
+ // Initialize with full text unless it's a mount trigger for typing/decode
3359
+ const [displayText, setDisplayText] = React.useState((type === 'decode' || type === 'typing') && trigger === 'mount' ? '' : children);
3360
+ const [currentRepeat, setCurrentRepeat] = React.useState(0);
3331
3361
  const textRef = React.useRef(null);
3332
- React.useRef(null);
3333
- // 타이핑 애니메이션을 위한 상태
3334
- const [displayText, setDisplayText] = React.useState('');
3362
+ const observerRef = React.useRef(null);
3363
+ // Initial trigger logic
3335
3364
  React.useEffect(() => {
3336
- if (delay > 0) {
3365
+ if (trigger === 'mount') {
3337
3366
  const timer = setTimeout(() => {
3338
3367
  setIsVisible(true);
3368
+ startAnimation();
3339
3369
  }, delay);
3340
3370
  return () => clearTimeout(timer);
3341
3371
  }
3342
- else {
3343
- setIsVisible(true);
3372
+ else if (trigger === 'in-view' && textRef.current) {
3373
+ observerRef.current = new IntersectionObserver((entries) => {
3374
+ if (entries[0].isIntersecting) {
3375
+ setTimeout(() => {
3376
+ setIsVisible(true);
3377
+ startAnimation();
3378
+ }, delay);
3379
+ observerRef.current?.disconnect();
3380
+ }
3381
+ });
3382
+ observerRef.current.observe(textRef.current);
3383
+ return () => observerRef.current?.disconnect();
3344
3384
  }
3345
- }, [delay]);
3346
- // 타이핑 애니메이션
3385
+ }, [trigger, delay]);
3386
+ // Update initial text visibility when props change
3347
3387
  React.useEffect(() => {
3348
- if (type === 'typing' && isVisible) {
3349
- setDisplayText('');
3350
- setCurrentIndex(0);
3351
- const typeInterval = setInterval(() => {
3352
- setCurrentIndex(prev => {
3353
- if (prev >= children.length) {
3354
- clearInterval(typeInterval);
3355
- return prev;
3356
- }
3357
- setDisplayText(children.slice(0, prev + 1));
3358
- return prev + 1;
3359
- });
3360
- }, speed / children.length);
3361
- return () => clearInterval(typeInterval);
3388
+ if ((type === 'typing' || type === 'decode') && trigger === 'mount') ;
3389
+ else {
3390
+ // For hover/click, ensure text is visible when not animating
3391
+ if (!isAnimating) {
3392
+ setDisplayText(children);
3393
+ }
3362
3394
  }
3363
- }, [type, isVisible, children, speed]);
3364
- // 반복 애니메이션
3365
- React.useEffect(() => {
3366
- if (repeat > 0 && type !== 'typing') {
3367
- let repeatCount = 0;
3368
- const repeatAnimation = () => {
3369
- setIsAnimating(true);
3370
- setTimeout(() => {
3395
+ }, [children, type, trigger]);
3396
+ const startAnimation = () => {
3397
+ setIsAnimating(true);
3398
+ setCurrentRepeat(0);
3399
+ if (type === 'typing') {
3400
+ startTyping(0);
3401
+ }
3402
+ else if (type === 'decode') {
3403
+ startDecoding(0);
3404
+ }
3405
+ };
3406
+ const startTyping = (iteration) => {
3407
+ setDisplayText('');
3408
+ let currentIndex = 0;
3409
+ const interval = setInterval(() => {
3410
+ if (currentIndex >= children.length) {
3411
+ clearInterval(interval);
3412
+ // Repetition logic
3413
+ if (repeat === 0 || iteration < repeat - 1) {
3414
+ setTimeout(() => {
3415
+ startTyping(iteration + 1);
3416
+ }, 500);
3417
+ }
3418
+ else {
3371
3419
  setIsAnimating(false);
3372
- repeatCount++;
3373
- if (repeatCount < repeat) {
3374
- setTimeout(repeatAnimation, speed);
3375
- }
3376
- }, speed);
3377
- };
3378
- if (isVisible) {
3379
- setTimeout(repeatAnimation, speed);
3420
+ }
3421
+ return;
3380
3422
  }
3423
+ setDisplayText(children.slice(0, currentIndex + 1));
3424
+ currentIndex++;
3425
+ }, speed / children.length);
3426
+ };
3427
+ const startDecoding = (iteration) => {
3428
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+';
3429
+ let iterations = 0;
3430
+ const interval = setInterval(() => {
3431
+ setDisplayText(children.split('').map((char, index) => {
3432
+ if (index < iterations) {
3433
+ return children[index];
3434
+ }
3435
+ return characters[Math.floor(Math.random() * characters.length)];
3436
+ }).join(''));
3437
+ if (iterations >= children.length) {
3438
+ clearInterval(interval);
3439
+ setDisplayText(children);
3440
+ // Repetition logic
3441
+ if (repeat === 0 || iteration < repeat - 1) {
3442
+ setTimeout(() => {
3443
+ startDecoding(iteration + 1);
3444
+ }, 500);
3445
+ }
3446
+ else {
3447
+ setIsAnimating(false);
3448
+ }
3449
+ }
3450
+ iterations += 1 / 3;
3451
+ }, 30);
3452
+ };
3453
+ const handleMouseEnter = () => {
3454
+ if (trigger === 'hover') {
3455
+ setIsVisible(true);
3456
+ startAnimation();
3381
3457
  }
3382
- }, [repeat, type, speed, isVisible]);
3458
+ };
3459
+ const handleMouseLeave = () => {
3460
+ if (trigger === 'hover') {
3461
+ setIsVisible(false);
3462
+ setIsAnimating(false);
3463
+ if (type === 'typing' || type === 'decode') {
3464
+ setDisplayText(children);
3465
+ }
3466
+ }
3467
+ };
3383
3468
  const handleClick = () => {
3469
+ if (trigger === 'click') {
3470
+ setIsVisible(!isVisible);
3471
+ if (isVisible) {
3472
+ setIsAnimating(false);
3473
+ if (type === 'typing' || type === 'decode') {
3474
+ setDisplayText(children);
3475
+ }
3476
+ }
3477
+ else {
3478
+ startAnimation();
3479
+ }
3480
+ }
3384
3481
  if (clickable && !disabled && onClick) {
3385
3482
  onClick();
3386
3483
  }
@@ -3397,14 +3494,6 @@ const AnimationText = ({ children, type = 'fade', speed = 1000, repeat = 0, dela
3397
3494
  }
3398
3495
  return {};
3399
3496
  };
3400
- const getWaveStyle = () => {
3401
- if (type === 'wave') {
3402
- return {
3403
- '--wave-colors': waveColors.join(', '),
3404
- };
3405
- }
3406
- return {};
3407
- };
3408
3497
  const getGlowStyle = () => {
3409
3498
  if (type === 'glow') {
3410
3499
  return {
@@ -3413,26 +3502,52 @@ const AnimationText = ({ children, type = 'fade', speed = 1000, repeat = 0, dela
3413
3502
  }
3414
3503
  return {};
3415
3504
  };
3416
- 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}`, {
3505
+ // For typing, the class should be applied to the inner element to handle caret correctly with ghost element
3506
+ const containerClasses = classNames('designbase-animation-text',
3507
+ // Exclude typing logic from outer container to prevent caret on full-width ghost container
3508
+ 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}`, {
3417
3509
  'designbase-animation-text--visible': isVisible,
3418
3510
  'designbase-animation-text--animating': isAnimating,
3419
- 'designbase-animation-text--clickable': clickable,
3511
+ 'designbase-animation-text--clickable': clickable || trigger === 'click',
3420
3512
  'designbase-animation-text--disabled': disabled,
3421
3513
  }, className);
3422
3514
  const style = {
3423
3515
  ...getGradientStyle(),
3424
- ...getWaveStyle(),
3425
3516
  ...getGlowStyle(),
3426
3517
  '--db-animation-speed': `${speed}ms`,
3427
3518
  '--db-text-custom': customColor,
3519
+ '--db-wave-colors': waveColors.join(', '),
3520
+ '--db-animation-iteration-count': repeat === 0 ? 'infinite' : repeat,
3428
3521
  };
3429
- const renderText = () => {
3430
- if (type === 'typing') {
3431
- return displayText;
3432
- }
3433
- return children;
3434
- };
3435
- return (jsxRuntime.jsx("div", { ref: textRef, className: classes, style: style, onClick: handleClick, children: renderText() }));
3522
+ const renderContent = () => {
3523
+ if (type === 'wave' || type === 'shake') {
3524
+ if (!isVisible && !isAnimating)
3525
+ return children;
3526
+ return children.split('').map((char, index) => (jsxRuntime.jsx("span", { style: {
3527
+ animationDelay: `${index * 0.05}s`,
3528
+ display: 'inline-block'
3529
+ }, children: char === ' ' ? '\u00A0' : char }, index)));
3530
+ }
3531
+ return displayText;
3532
+ };
3533
+ return (jsxRuntime.jsxs("div", { ref: textRef, className: containerClasses, style: style, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [jsxRuntime.jsx("span", { "aria-hidden": "true", style: {
3534
+ visibility: 'hidden',
3535
+ pointerEvents: 'none',
3536
+ userSelect: 'none',
3537
+ whiteSpace: type === 'typing' ? 'pre-wrap' : undefined
3538
+ }, children: children }), jsxRuntime.jsx("span", { className: classNames({
3539
+ 'designbase-animation-text--typing': type === 'typing',
3540
+ 'designbase-animation-text--animating': isAnimating && type === 'typing' // Ensure animating class is passed for typing caret
3541
+ }), style: {
3542
+ position: 'absolute',
3543
+ top: 0,
3544
+ left: 0,
3545
+ // For typing, we want width to be auto so caret follows text
3546
+ // For others, width 100% matches ghost element
3547
+ width: type === 'typing' ? 'auto' : '100%',
3548
+ height: '100%',
3549
+ whiteSpace: type === 'typing' ? 'pre-wrap' : undefined // Ensure pre-wrap behavior matches
3550
+ }, children: renderContent() })] }));
3436
3551
  };
3437
3552
 
3438
3553
  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, }) => {
@@ -4194,6 +4309,7 @@ SegmentControl.displayName = 'SegmentControl';
4194
4309
 
4195
4310
  const Modal = ({ isOpen, onClose, title, size = 'm', closeOnOutsideClick = true, closeOnEscape = true, children, className, overlayClassName, }) => {
4196
4311
  const modalRef = React.useRef(null);
4312
+ const titleId = React.useId();
4197
4313
  // 아이콘 크기 계산 (m이 기본값)
4198
4314
  const iconSize = size === 's' ? 16 : size === 'l' ? 20 : size === 'xl' ? 24 : 18;
4199
4315
  // Prevent scrolling while modal is open
@@ -4225,11 +4341,12 @@ const Modal = ({ isOpen, onClose, title, size = 'm', closeOnOutsideClick = true,
4225
4341
  return null;
4226
4342
  const modalClasses = clsx('designbase-modal', `designbase-modal--${size}`, className);
4227
4343
  const overlayClasses = clsx('designbase-modal__overlay', overlayClassName);
4228
- 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 })] }) }));
4344
+ 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 })] }) }));
4229
4345
  };
4230
- const ModalHeader = ({ title, showCloseButton = true, onClose, iconSize = 20, className, children, }) => {
4346
+ const ModalHeader = ({ title, titleId, showCloseButton = true, onClose, iconSize = 20, className, children, }) => {
4347
+ const fallbackTitleId = React.useId();
4231
4348
  const classes = clsx('designbase-modal__header', className);
4232
- 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" }) }))] }));
4349
+ 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" }) }))] }));
4233
4350
  };
4234
4351
  const ModalBody = ({ className, children, }) => {
4235
4352
  const classes = clsx('designbase-modal__body', className);
@@ -4492,6 +4609,11 @@ const Select = ({ value, defaultValue, options, label, placeholder = '선택하
4492
4609
  const [selectedValue, setSelectedValue] = React.useState(value ?? defaultValue ?? (multiple ? [] : ''));
4493
4610
  const [searchTerm, setSearchTerm] = React.useState('');
4494
4611
  const [focusedIndex, setFocusedIndex] = React.useState(-1);
4612
+ const selectId = React.useId();
4613
+ const labelId = `${selectId}-label`;
4614
+ const listboxId = `${selectId}-listbox`;
4615
+ const helperTextId = `${selectId}-helper-text`;
4616
+ const errorTextId = `${selectId}-error-text`;
4495
4617
  const containerRef = React.useRef(null);
4496
4618
  const inputRef = React.useRef(null);
4497
4619
  const dropdownRef = React.useRef(null);
@@ -4651,23 +4773,29 @@ const Select = ({ value, defaultValue, options, label, placeholder = '선택하
4651
4773
  const filteredOptions = getFilteredOptions();
4652
4774
  const selectedLabels = getSelectedLabels();
4653
4775
  const hasValue = multiple ? selectedValue.length > 0 : selectedValue !== '';
4654
- 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) => {
4776
+ const activeDescendantId = focusedIndex >= 0 ? `${selectId}-option-${focusedIndex}` : undefined;
4777
+ const describedBy = error && errorMessage
4778
+ ? errorTextId
4779
+ : helperText
4780
+ ? helperTextId
4781
+ : undefined;
4782
+ 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) => {
4655
4783
  const option = options.find(opt => opt.value === value);
4656
4784
  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) => {
4657
4785
  e.stopPropagation();
4658
4786
  handleRemoveValue(value);
4659
4787
  }, children: jsxRuntime.jsx(icons.CloseIcon, { size: 12 }) })] }, value));
4660
- }) })) : (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) => {
4788
+ }) })) : (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) => {
4661
4789
  const isSelected = multiple
4662
4790
  ? selectedValue.includes(option.value)
4663
4791
  : selectedValue === option.value;
4664
4792
  const isFocused = index === focusedIndex;
4665
- return (jsxRuntime.jsxs("div", { className: clsx('designbase-select__option', {
4793
+ return (jsxRuntime.jsxs("div", { id: `${selectId}-option-${index}`, className: clsx('designbase-select__option', {
4666
4794
  'designbase-select__option--selected': isSelected,
4667
4795
  'designbase-select__option--focused': isFocused,
4668
4796
  'designbase-select__option--disabled': option.disabled,
4669
4797
  }), 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));
4670
- })) })] }), helperText && !error && (jsxRuntime.jsx("p", { className: "designbase-select__helper-text", children: helperText })), error && errorMessage && (jsxRuntime.jsx("p", { className: "designbase-select__error-message", children: errorMessage }))] }));
4798
+ })) })] }), 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 }))] }));
4671
4799
  };
4672
4800
  Select.displayName = 'Select';
4673
4801
 
@@ -5271,7 +5399,7 @@ const Card = React.forwardRef(function Card({ title, subtitle, description, chil
5271
5399
  return null;
5272
5400
  return (jsxRuntime.jsx("div", { className: "designbase-card__actions", children: actions.map((action, index) => {
5273
5401
  const ActionIcon = action.icon;
5274
- 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));
5402
+ 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));
5275
5403
  }) }));
5276
5404
  };
5277
5405
  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()] }));
@@ -10899,7 +11027,7 @@ const Share = ({ url, title, description = '', imageUrl, hashtags = [], variant
10899
11027
  }
10900
11028
  };
10901
11029
 
10902
- 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 }) => {
11030
+ 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 }) => {
10903
11031
  const [expandedItems, setExpandedItems] = React.useState([]);
10904
11032
  const handleToggle = () => {
10905
11033
  if (onToggle) {
@@ -10940,24 +11068,24 @@ const Sidebar = ({ size = 'm', variant = 'default', position = 'left', logo, onL
10940
11068
  const hasChildren = item.children && item.children.length > 0;
10941
11069
  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));
10942
11070
  };
10943
- 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) => {
11071
+ 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) => {
10944
11072
  if (onLogoClick && (e.key === 'Enter' || e.key === ' ')) {
10945
11073
  e.preventDefault();
10946
11074
  onLogoClick();
10947
11075
  }
10948
11076
  }, 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', {
10949
11077
  'designbase-sidebar__toggle-icon--collapsed': collapsed,
10950
- }) }) }))] }), 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) => {
11078
+ }) }) }))] })), 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) => {
10951
11079
  if (e.key === 'Enter' || e.key === ' ') {
10952
11080
  e.preventDefault();
10953
11081
  onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
10954
11082
  }
10955
- }, 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) => {
11083
+ }, 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) => {
10956
11084
  if (e.key === 'Enter' || e.key === ' ') {
10957
11085
  e.preventDefault();
10958
11086
  onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
10959
11087
  }
10960
- }, 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() })) }))] }) }));
11088
+ }, style: { cursor: 'pointer' }, children: jsxRuntime.jsx(Avatar, { src: userProfile.avatar, initials: userProfile.name, alt: userProfile.name, size: "s", className: "designbase-sidebar__user-avatar-collapsed" }) }))] }) }));
10961
11089
  };
10962
11090
  Sidebar.displayName = 'Sidebar';
10963
11091
 
@@ -12392,25 +12520,18 @@ const YouTubePlayer = ({ videoId, title, description, size = 'm', variant = 'def
12392
12520
  };
12393
12521
  YouTubePlayer.displayName = 'YouTubePlayer';
12394
12522
 
12395
- /**
12396
- * Designbase UI 컴포넌트 라이브러리 메인 엔트리 포인트
12397
- *
12398
- * 목적: 모든 UI 컴포넌트와 타입을 내보냄
12399
- * 기능: Tree-shaking 가능한 개별 컴포넌트 내보내기
12400
- * 사용법: import { Button, Input } from '@designbasekorea/ui'
12401
- */
12402
- // 테마 CSS 자동 로드 (로컬 복사본 사용)
12403
- // 테마 관련 유틸리티 재내보내기
12404
- const setTheme = (theme) => {
12405
- console.log('setTheme called with:', theme);
12406
- };
12407
- const getTheme = () => {
12408
- return 'light';
12409
- };
12410
- const toggleTheme = () => {
12411
- console.log('toggleTheme called');
12412
- };
12413
-
12523
+ Object.defineProperty(exports, 'getTheme', {
12524
+ enumerable: true,
12525
+ get: function () { return theme.getTheme; }
12526
+ });
12527
+ Object.defineProperty(exports, 'setTheme', {
12528
+ enumerable: true,
12529
+ get: function () { return theme.setTheme; }
12530
+ });
12531
+ Object.defineProperty(exports, 'toggleTheme', {
12532
+ enumerable: true,
12533
+ get: function () { return theme.toggleTheme; }
12534
+ });
12414
12535
  exports.Accordion = Accordion;
12415
12536
  exports.AdBanner = AdBanner;
12416
12537
  exports.Alert = Alert;
@@ -12503,8 +12624,5 @@ exports.Tooltip = Tooltip;
12503
12624
  exports.Tutorial = Tutorial;
12504
12625
  exports.VideoPlayer = VideoPlayer;
12505
12626
  exports.YouTubePlayer = YouTubePlayer;
12506
- exports.getTheme = getTheme;
12507
- exports.setTheme = setTheme;
12508
- exports.toggleTheme = toggleTheme;
12509
12627
  exports.useToast = useToast;
12510
12628
  //# sourceMappingURL=index.js.map