@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/README.md +100 -59
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +10 -7
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.css.map +1 -1
- package/dist/index.esm.js +216 -107
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +227 -109
- package/dist/index.js.map +1 -1
- package/dist/index.umd.css +1 -1
- package/dist/index.umd.css.map +1 -1
- package/dist/index.umd.js +230 -113
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -3
package/dist/index.esm.js
CHANGED
|
@@ -2,6 +2,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
2
2
|
import React, { useState, useCallback, useEffect, useRef, useMemo, useContext, useLayoutEffect, forwardRef, useId, createContext } from 'react';
|
|
3
3
|
import { ChevronDownIcon, StarIcon, TrendingUpIcon, StarFilledIcon, CartIcon, CloseIcon, ArrowRightIcon, InfoFilledIcon, ErrorFilledIcon, WarningFilledIcon, CircleCheckFilledIcon, RefreshIcon, ChevronLeftIcon, PauseIcon, PlayIcon, ChevronRightIcon, RepeatIcon, MuteFilledIcon, VolumeUpIcon, SettingsIcon, UserIcon, HideIcon, ShowIcon, SearchIcon, ChevronUpIcon, GalleryIcon, HeartIcon, BookmarkIcon, ShareAltIcon, DownloadIcon, ArrowLeftIcon, ShrinkIcon, ExpandIcon, DoneIcon as DoneIcon$1, CopyIcon, EyedropperIcon, BulbIcon, CloudCloseIcon, BellActiveIcon, AwardIcon, CalendarIcon, PlusIcon, ErrorIcon, FileBlankIcon, ClockIcon, MinusIcon as MinusIcon$1, VideoIcon, CodeIcon, WriteIcon, UploadIcon, ArrowBarLeftIcon, ArrowBarRightIcon, StarHalfIcon, MoveIcon, MoreVerticalIcon, ArrowDownIcon, ArrowUpLeftIcon, ArrowUpRightIcon, ArrowDownLeftIcon, ArrowDownRightIcon, FacebookIcon, XIcon, InstagramIcon, LinkedinIcon, PinterestIcon, WhatsappIcon, TelegramIcon, MailIcon, LinkIcon, ScanQrcodeIcon, CaretUpdownFilledIcon, WarningIcon, InfoIcon } from '@designbasekorea/icons';
|
|
4
4
|
import { flushSync, createPortal } from 'react-dom';
|
|
5
|
+
export { getTheme, setTheme, toggleTheme } from '@designbasekorea/theme';
|
|
5
6
|
|
|
6
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}
|
|
7
8
|
|
|
@@ -2993,44 +2994,71 @@ const drawStars = (ctx, width, height, starsRef, options) => {
|
|
|
2993
2994
|
};
|
|
2994
2995
|
const drawWaves = (ctx, width, height, options) => {
|
|
2995
2996
|
const { colors, offset, speedFactor } = options;
|
|
2996
|
-
offset.current += 0.
|
|
2997
|
+
offset.current += 0.005 * speedFactor; // Slower, smoother movement
|
|
2997
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;
|
|
2998
3006
|
ctx.beginPath();
|
|
2999
3007
|
ctx.moveTo(0, height);
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
const
|
|
3005
|
-
|
|
3006
|
-
|
|
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
|
|
3007
3017
|
ctx.lineTo(x, y);
|
|
3008
3018
|
}
|
|
3009
3019
|
ctx.lineTo(width, height);
|
|
3010
3020
|
ctx.lineTo(0, height);
|
|
3011
3021
|
ctx.closePath();
|
|
3012
|
-
|
|
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
|
|
3013
3027
|
ctx.fill();
|
|
3028
|
+
ctx.globalAlpha = 1.0;
|
|
3029
|
+
// ctx.filter = 'none';
|
|
3014
3030
|
});
|
|
3015
3031
|
};
|
|
3016
3032
|
const drawPulse = (ctx, width, height, options) => {
|
|
3017
3033
|
const { colors, time, intensity } = options;
|
|
3018
3034
|
const centerX = width / 2;
|
|
3019
3035
|
const centerY = height / 2;
|
|
3020
|
-
const maxRadius = Math.max(width, height) * 0.
|
|
3021
|
-
const intensityMap = { subtle: 0.
|
|
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
|
|
3022
3038
|
const factor = intensityMap[intensity];
|
|
3023
3039
|
colors.forEach((color, i) => {
|
|
3024
|
-
|
|
3025
|
-
const
|
|
3026
|
-
|
|
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;
|
|
3027
3050
|
const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius);
|
|
3028
3051
|
const rgb = hexToRgb$1(color);
|
|
3052
|
+
// Harder center, softer edge
|
|
3029
3053
|
gradient.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);
|
|
3030
|
-
gradient.addColorStop(0.
|
|
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})`);
|
|
3031
3056
|
gradient.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);
|
|
3032
3057
|
ctx.fillStyle = gradient;
|
|
3058
|
+
// Use globalCompositeOperation to blend nicely
|
|
3059
|
+
ctx.globalCompositeOperation = 'screen';
|
|
3033
3060
|
ctx.fillRect(0, 0, width, height);
|
|
3061
|
+
ctx.globalCompositeOperation = 'source-over';
|
|
3034
3062
|
});
|
|
3035
3063
|
};
|
|
3036
3064
|
|
|
@@ -3322,63 +3350,132 @@ const AnimationBackground = ({ type = 'gradient', theme = 'dark', intensity = 's
|
|
|
3322
3350
|
}, children: content }), showGrid && (jsx(GridOverlay, { size: gridSize, color: effectiveGridColor, opacity: gridOpacity })), children && (jsx("div", { className: "designbase-animation-background__content", style: { position: 'relative', zIndex: 10, width: '100%', height: '100%' }, children: children }))] }));
|
|
3323
3351
|
};
|
|
3324
3352
|
|
|
3325
|
-
const AnimationText = ({ children, type = 'fade', speed = 1000, repeat =
|
|
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, }) => {
|
|
3326
3354
|
const [isVisible, setIsVisible] = useState(false);
|
|
3327
|
-
const [currentIndex, setCurrentIndex] = useState(0);
|
|
3328
3355
|
const [isAnimating, setIsAnimating] = useState(false);
|
|
3356
|
+
// Initialize with full text unless it's a mount trigger for typing/decode
|
|
3357
|
+
const [displayText, setDisplayText] = useState((type === 'decode' || type === 'typing') && trigger === 'mount' ? '' : children);
|
|
3358
|
+
const [currentRepeat, setCurrentRepeat] = useState(0);
|
|
3329
3359
|
const textRef = useRef(null);
|
|
3330
|
-
useRef(null);
|
|
3331
|
-
//
|
|
3332
|
-
const [displayText, setDisplayText] = useState('');
|
|
3360
|
+
const observerRef = useRef(null);
|
|
3361
|
+
// Initial trigger logic
|
|
3333
3362
|
useEffect(() => {
|
|
3334
|
-
if (
|
|
3363
|
+
if (trigger === 'mount') {
|
|
3335
3364
|
const timer = setTimeout(() => {
|
|
3336
3365
|
setIsVisible(true);
|
|
3366
|
+
startAnimation();
|
|
3337
3367
|
}, delay);
|
|
3338
3368
|
return () => clearTimeout(timer);
|
|
3339
3369
|
}
|
|
3340
|
-
else {
|
|
3341
|
-
|
|
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();
|
|
3342
3382
|
}
|
|
3343
|
-
}, [delay]);
|
|
3344
|
-
//
|
|
3383
|
+
}, [trigger, delay]);
|
|
3384
|
+
// Update initial text visibility when props change
|
|
3345
3385
|
useEffect(() => {
|
|
3346
|
-
if (type === 'typing' &&
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
clearInterval(typeInterval);
|
|
3353
|
-
return prev;
|
|
3354
|
-
}
|
|
3355
|
-
setDisplayText(children.slice(0, prev + 1));
|
|
3356
|
-
return prev + 1;
|
|
3357
|
-
});
|
|
3358
|
-
}, speed / children.length);
|
|
3359
|
-
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
|
+
}
|
|
3360
3392
|
}
|
|
3361
|
-
}, [
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
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 {
|
|
3369
3417
|
setIsAnimating(false);
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3418
|
+
}
|
|
3419
|
+
return;
|
|
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
|
+
}
|
|
3378
3447
|
}
|
|
3448
|
+
iterations += 1 / 3;
|
|
3449
|
+
}, 30);
|
|
3450
|
+
};
|
|
3451
|
+
const handleMouseEnter = () => {
|
|
3452
|
+
if (trigger === 'hover') {
|
|
3453
|
+
setIsVisible(true);
|
|
3454
|
+
startAnimation();
|
|
3379
3455
|
}
|
|
3380
|
-
}
|
|
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
|
+
};
|
|
3381
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
|
+
}
|
|
3382
3479
|
if (clickable && !disabled && onClick) {
|
|
3383
3480
|
onClick();
|
|
3384
3481
|
}
|
|
@@ -3395,14 +3492,6 @@ const AnimationText = ({ children, type = 'fade', speed = 1000, repeat = 0, dela
|
|
|
3395
3492
|
}
|
|
3396
3493
|
return {};
|
|
3397
3494
|
};
|
|
3398
|
-
const getWaveStyle = () => {
|
|
3399
|
-
if (type === 'wave') {
|
|
3400
|
-
return {
|
|
3401
|
-
'--wave-colors': waveColors.join(', '),
|
|
3402
|
-
};
|
|
3403
|
-
}
|
|
3404
|
-
return {};
|
|
3405
|
-
};
|
|
3406
3495
|
const getGlowStyle = () => {
|
|
3407
3496
|
if (type === 'glow') {
|
|
3408
3497
|
return {
|
|
@@ -3411,26 +3500,52 @@ const AnimationText = ({ children, type = 'fade', speed = 1000, repeat = 0, dela
|
|
|
3411
3500
|
}
|
|
3412
3501
|
return {};
|
|
3413
3502
|
};
|
|
3414
|
-
|
|
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}`, {
|
|
3415
3507
|
'designbase-animation-text--visible': isVisible,
|
|
3416
3508
|
'designbase-animation-text--animating': isAnimating,
|
|
3417
|
-
'designbase-animation-text--clickable': clickable,
|
|
3509
|
+
'designbase-animation-text--clickable': clickable || trigger === 'click',
|
|
3418
3510
|
'designbase-animation-text--disabled': disabled,
|
|
3419
3511
|
}, className);
|
|
3420
3512
|
const style = {
|
|
3421
3513
|
...getGradientStyle(),
|
|
3422
|
-
...getWaveStyle(),
|
|
3423
3514
|
...getGlowStyle(),
|
|
3424
3515
|
'--db-animation-speed': `${speed}ms`,
|
|
3425
3516
|
'--db-text-custom': customColor,
|
|
3517
|
+
'--db-wave-colors': waveColors.join(', '),
|
|
3518
|
+
'--db-animation-iteration-count': repeat === 0 ? 'infinite' : repeat,
|
|
3426
3519
|
};
|
|
3427
|
-
const
|
|
3428
|
-
if (type === '
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3520
|
+
const renderContent = () => {
|
|
3521
|
+
if (type === 'wave' || type === 'shake') {
|
|
3522
|
+
if (!isVisible && !isAnimating)
|
|
3523
|
+
return children;
|
|
3524
|
+
return children.split('').map((char, index) => (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 (jsxs("div", { ref: textRef, className: containerClasses, style: style, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [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 }), 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() })] }));
|
|
3434
3549
|
};
|
|
3435
3550
|
|
|
3436
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, }) => {
|
|
@@ -4192,6 +4307,7 @@ SegmentControl.displayName = 'SegmentControl';
|
|
|
4192
4307
|
|
|
4193
4308
|
const Modal = ({ isOpen, onClose, title, size = 'm', closeOnOutsideClick = true, closeOnEscape = true, children, className, overlayClassName, }) => {
|
|
4194
4309
|
const modalRef = useRef(null);
|
|
4310
|
+
const titleId = useId();
|
|
4195
4311
|
// 아이콘 크기 계산 (m이 기본값)
|
|
4196
4312
|
const iconSize = size === 's' ? 16 : size === 'l' ? 20 : size === 'xl' ? 24 : 18;
|
|
4197
4313
|
// Prevent scrolling while modal is open
|
|
@@ -4223,11 +4339,12 @@ const Modal = ({ isOpen, onClose, title, size = 'm', closeOnOutsideClick = true,
|
|
|
4223
4339
|
return null;
|
|
4224
4340
|
const modalClasses = clsx('designbase-modal', `designbase-modal--${size}`, className);
|
|
4225
4341
|
const overlayClasses = clsx('designbase-modal__overlay', overlayClassName);
|
|
4226
|
-
return (jsx("div", { className: overlayClasses, onClick: closeOnOutsideClick ? onClose : undefined, children: jsxs("div", { ref: modalRef, className: modalClasses, onClick: (e) => e.stopPropagation(), role: "dialog", "aria-modal": "true", "aria-labelledby": title ?
|
|
4342
|
+
return (jsx("div", { className: overlayClasses, onClick: closeOnOutsideClick ? onClose : undefined, children: jsxs("div", { ref: modalRef, className: modalClasses, onClick: (e) => e.stopPropagation(), role: "dialog", "aria-modal": "true", "aria-labelledby": title ? titleId : undefined, children: [title && (jsx(ModalHeader, { title: title, titleId: titleId, showCloseButton: true, onClose: onClose, iconSize: iconSize })), jsx("div", { className: "designbase-modal__content", children: children })] }) }));
|
|
4227
4343
|
};
|
|
4228
|
-
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 = useId();
|
|
4229
4346
|
const classes = clsx('designbase-modal__header', className);
|
|
4230
|
-
return (jsxs("div", { className: classes, children: [jsxs("div", { className: "designbase-modal__header-content", children: [title && (jsx("h2", { id:
|
|
4347
|
+
return (jsxs("div", { className: classes, children: [jsxs("div", { className: "designbase-modal__header-content", children: [title && (jsx("h2", { id: titleId || fallbackTitleId, className: "designbase-modal__title", children: title })), children] }), showCloseButton && onClose && (jsx("button", { type: "button", onClick: onClose, "aria-label": "\uBAA8\uB2EC \uB2EB\uAE30", className: "designbase-modal__close-button", children: jsx(CloseIcon, { size: iconSize, color: "currentColor" }) }))] }));
|
|
4231
4348
|
};
|
|
4232
4349
|
const ModalBody = ({ className, children, }) => {
|
|
4233
4350
|
const classes = clsx('designbase-modal__body', className);
|
|
@@ -4490,6 +4607,11 @@ const Select = ({ value, defaultValue, options, label, placeholder = '선택하
|
|
|
4490
4607
|
const [selectedValue, setSelectedValue] = useState(value ?? defaultValue ?? (multiple ? [] : ''));
|
|
4491
4608
|
const [searchTerm, setSearchTerm] = useState('');
|
|
4492
4609
|
const [focusedIndex, setFocusedIndex] = useState(-1);
|
|
4610
|
+
const selectId = useId();
|
|
4611
|
+
const labelId = `${selectId}-label`;
|
|
4612
|
+
const listboxId = `${selectId}-listbox`;
|
|
4613
|
+
const helperTextId = `${selectId}-helper-text`;
|
|
4614
|
+
const errorTextId = `${selectId}-error-text`;
|
|
4493
4615
|
const containerRef = useRef(null);
|
|
4494
4616
|
const inputRef = useRef(null);
|
|
4495
4617
|
const dropdownRef = useRef(null);
|
|
@@ -4649,23 +4771,29 @@ const Select = ({ value, defaultValue, options, label, placeholder = '선택하
|
|
|
4649
4771
|
const filteredOptions = getFilteredOptions();
|
|
4650
4772
|
const selectedLabels = getSelectedLabels();
|
|
4651
4773
|
const hasValue = multiple ? selectedValue.length > 0 : selectedValue !== '';
|
|
4652
|
-
|
|
4774
|
+
const activeDescendantId = focusedIndex >= 0 ? `${selectId}-option-${focusedIndex}` : undefined;
|
|
4775
|
+
const describedBy = error && errorMessage
|
|
4776
|
+
? errorTextId
|
|
4777
|
+
: helperText
|
|
4778
|
+
? helperTextId
|
|
4779
|
+
: undefined;
|
|
4780
|
+
return (jsxs("div", { className: classes, ref: containerRef, children: [label && (jsxs("label", { id: labelId, className: "designbase-select__label", children: [label, required && jsx("span", { className: "designbase-select__required", children: "*" })] })), 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: [jsx("div", { className: "designbase-select__value", children: multiple ? (jsx("div", { className: "designbase-select__tags", ref: tagsContainerRef, children: selectedValue.map((value) => {
|
|
4653
4781
|
const option = options.find(opt => opt.value === value);
|
|
4654
4782
|
return (jsxs("span", { className: "designbase-select__tag", children: [jsx("span", { className: "designbase-select__tag-label", children: option?.label || value }), jsx("button", { type: "button", className: "designbase-select__tag-remove", onClick: (e) => {
|
|
4655
4783
|
e.stopPropagation();
|
|
4656
4784
|
handleRemoveValue(value);
|
|
4657
4785
|
}, children: jsx(CloseIcon, { size: 12 }) })] }, value));
|
|
4658
|
-
}) })) : (jsx("span", { className: "designbase-select__single-value", children: selectedLabels || placeholder })) }), jsxs("div", { className: "designbase-select__indicators", children: [showClearButton && hasValue && !disabled && !readOnly && (jsx("button", { type: "button", className: "designbase-select__clear-button", onClick: handleClearAll, "aria-label": "\uBAA8\uB4E0 \uAC12 \uC9C0\uC6B0\uAE30", children: jsx(CloseIcon, { size: 16 }) })), jsx("div", { className: "designbase-select__chevron", children: isOpen ? jsx(ChevronUpIcon, { size: 16 }) : jsx(ChevronDownIcon, { size: 16 }) })] })] }), jsxs("div", { className: dropdownClasses, ref: dropdownRef, children: [searchable && (jsx("div", { className: "designbase-select__search", onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), children: 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() }) })), jsx("div", { className: "designbase-select__options", style: { maxHeight: `${maxHeight}px` }, role: "listbox", children: filteredOptions.length === 0 ? (jsx("div", { className: "designbase-select__no-options", children: searchTerm ? '검색 결과가 없습니다.' : '옵션이 없습니다.' })) : (filteredOptions.map((option, index) => {
|
|
4786
|
+
}) })) : (jsx("span", { className: "designbase-select__single-value", children: selectedLabels || placeholder })) }), jsxs("div", { className: "designbase-select__indicators", children: [showClearButton && hasValue && !disabled && !readOnly && (jsx("button", { type: "button", className: "designbase-select__clear-button", onClick: handleClearAll, "aria-label": "\uBAA8\uB4E0 \uAC12 \uC9C0\uC6B0\uAE30", children: jsx(CloseIcon, { size: 16 }) })), jsx("div", { className: "designbase-select__chevron", children: isOpen ? jsx(ChevronUpIcon, { size: 16 }) : jsx(ChevronDownIcon, { size: 16 }) })] })] }), jsxs("div", { className: dropdownClasses, ref: dropdownRef, children: [searchable && (jsx("div", { className: "designbase-select__search", onMouseDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), children: 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() }) })), jsx("div", { className: "designbase-select__options", style: { maxHeight: `${maxHeight}px` }, id: listboxId, role: "listbox", children: filteredOptions.length === 0 ? (jsx("div", { className: "designbase-select__no-options", children: searchTerm ? '검색 결과가 없습니다.' : '옵션이 없습니다.' })) : (filteredOptions.map((option, index) => {
|
|
4659
4787
|
const isSelected = multiple
|
|
4660
4788
|
? selectedValue.includes(option.value)
|
|
4661
4789
|
: selectedValue === option.value;
|
|
4662
4790
|
const isFocused = index === focusedIndex;
|
|
4663
|
-
return (jsxs("div", { className: clsx('designbase-select__option', {
|
|
4791
|
+
return (jsxs("div", { id: `${selectId}-option-${index}`, className: clsx('designbase-select__option', {
|
|
4664
4792
|
'designbase-select__option--selected': isSelected,
|
|
4665
4793
|
'designbase-select__option--focused': isFocused,
|
|
4666
4794
|
'designbase-select__option--disabled': option.disabled,
|
|
4667
4795
|
}), onClick: () => handleOptionSelect(option), role: "option", "aria-selected": isSelected, children: [multiple && (jsx("div", { className: "designbase-select__checkbox", children: jsx(Checkbox, { isSelected: isSelected, isDisabled: option.disabled, size: "s", hasLabel: false, onChange: () => handleOptionSelect(option) }) })), jsx("span", { className: "designbase-select__option-label", children: option.label })] }, option.value));
|
|
4668
|
-
})) })] }), helperText && !error && (jsx("p", { className: "designbase-select__helper-text", children: helperText })), error && errorMessage && (jsx("p", { className: "designbase-select__error-message", children: errorMessage }))] }));
|
|
4796
|
+
})) })] }), helperText && !error && (jsx("p", { id: helperTextId, className: "designbase-select__helper-text", children: helperText })), error && errorMessage && (jsx("p", { id: errorTextId, className: "designbase-select__error-message", children: errorMessage }))] }));
|
|
4669
4797
|
};
|
|
4670
4798
|
Select.displayName = 'Select';
|
|
4671
4799
|
|
|
@@ -5269,7 +5397,7 @@ const Card = forwardRef(function Card({ title, subtitle, description, children,
|
|
|
5269
5397
|
return null;
|
|
5270
5398
|
return (jsx("div", { className: "designbase-card__actions", children: actions.map((action, index) => {
|
|
5271
5399
|
const ActionIcon = action.icon;
|
|
5272
|
-
return (jsx(Button, { variant: action.variant || 'primary', size: action.size || 's', onClick: () => handleActionClick(action, index), disabled: action.disabled || disabled, loading: !!action.loading,
|
|
5400
|
+
return (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));
|
|
5273
5401
|
}) }));
|
|
5274
5402
|
};
|
|
5275
5403
|
const renderContent = () => (jsxs("div", { className: "designbase-card__content", children: [renderIcon(), (title || subtitle) && (jsxs("div", { className: "designbase-card__header", children: [title && jsx("h3", { className: "designbase-card__title", children: title }), subtitle && jsx("p", { className: "designbase-card__subtitle", children: subtitle })] })), description && jsx("p", { className: "designbase-card__description", children: description }), children && jsx("div", { className: "designbase-card__body", children: children }), renderTags(), renderMeta(), renderActions()] }));
|
|
@@ -10897,7 +11025,7 @@ const Share = ({ url, title, description = '', imageUrl, hashtags = [], variant
|
|
|
10897
11025
|
}
|
|
10898
11026
|
};
|
|
10899
11027
|
|
|
10900
|
-
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 }) => {
|
|
10901
11029
|
const [expandedItems, setExpandedItems] = useState([]);
|
|
10902
11030
|
const handleToggle = () => {
|
|
10903
11031
|
if (onToggle) {
|
|
@@ -10938,24 +11066,24 @@ const Sidebar = ({ size = 'm', variant = 'default', position = 'left', logo, onL
|
|
|
10938
11066
|
const hasChildren = item.children && item.children.length > 0;
|
|
10939
11067
|
return (jsx("li", { className: "designbase-sidebar__item", children: jsx(MenuItem, { ...item, type: "block", style: "accordion", depth: level, expanded: isExpanded, expandable: hasChildren, onClick: () => handleItemClick(item), onChildClick: (child) => handleItemClick(child) }) }, item.id));
|
|
10940
11068
|
};
|
|
10941
|
-
return (jsx("aside", { className: classes, role: "complementary", "aria-label": "\uC0AC\uC774\uB4DC\uBC14 \uB124\uBE44\uAC8C\uC774\uC158", ...props, children: jsxs("div", { className: "designbase-sidebar__container", children: [jsxs("div", { className: "designbase-sidebar__header", children: [jsx("div", { className: "designbase-sidebar__logo", onClick: onLogoClick, role: onLogoClick ? 'button' : undefined, tabIndex: onLogoClick ? 0 : undefined, onKeyDown: (e) => {
|
|
11069
|
+
return (jsx("aside", { className: classes, role: "complementary", "aria-label": "\uC0AC\uC774\uB4DC\uBC14 \uB124\uBE44\uAC8C\uC774\uC158", ...props, children: jsxs("div", { className: "designbase-sidebar__container", children: [showLogo && (jsxs("div", { className: "designbase-sidebar__header", children: [jsx("div", { className: "designbase-sidebar__logo", onClick: onLogoClick, role: onLogoClick ? 'button' : undefined, tabIndex: onLogoClick ? 0 : undefined, onKeyDown: (e) => {
|
|
10942
11070
|
if (onLogoClick && (e.key === 'Enter' || e.key === ' ')) {
|
|
10943
11071
|
e.preventDefault();
|
|
10944
11072
|
onLogoClick();
|
|
10945
11073
|
}
|
|
10946
11074
|
}, children: logo || jsx(Logo, { size: "s" }) }), collapsible && (jsx(Button, { variant: "ghost", size: "s", iconOnly: true, className: "designbase-sidebar__toggle", onPress: handleToggle, "aria-label": collapsed ? '사이드바 펼치기' : '사이드바 접기', children: jsx(ChevronLeftIcon, { className: clsx('designbase-sidebar__toggle-icon', {
|
|
10947
11075
|
'designbase-sidebar__toggle-icon--collapsed': collapsed,
|
|
10948
|
-
}) }) }))] }), jsx("nav", { className: "designbase-sidebar__nav", children: jsx("ul", { className: "designbase-sidebar__nav-list", children: items.map((item) => renderSidebarItem(item)) }) }), userProfile && !collapsed && (jsxs("div", { className: "designbase-sidebar__user", children: [jsxs("div", { className: "designbase-sidebar__user-info", onClick: () => onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' }), role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
11076
|
+
}) }) }))] })), jsx("nav", { className: "designbase-sidebar__nav", children: jsx("ul", { className: "designbase-sidebar__nav-list", children: items.map((item) => renderSidebarItem(item)) }) }), userProfile && !collapsed && (jsxs("div", { className: "designbase-sidebar__user", children: [jsxs("div", { className: "designbase-sidebar__user-info", onClick: () => onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' }), role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
10949
11077
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
10950
11078
|
e.preventDefault();
|
|
10951
11079
|
onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
|
|
10952
11080
|
}
|
|
10953
|
-
}, style: { cursor: 'pointer' }, children: [
|
|
11081
|
+
}, style: { cursor: 'pointer' }, children: [jsx(Avatar, { src: userProfile.avatar, initials: userProfile.name, alt: userProfile.name, size: "s", className: "designbase-sidebar__user-avatar" }), jsxs("div", { className: "designbase-sidebar__user-details", children: [jsx("div", { className: "designbase-sidebar__user-name", children: userProfile.name }), userProfile.email && (jsx("div", { className: "designbase-sidebar__user-email", children: userProfile.email })), userProfile.role && (jsx("div", { className: "designbase-sidebar__user-role", children: userProfile.role }))] })] }), userMenuItems.length > 0 && (jsx("ul", { className: "designbase-sidebar__user-menu", children: userMenuItems.map((item) => (jsx("li", { children: 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 && (jsx("div", { className: "designbase-sidebar__user-collapsed", onClick: () => onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' }), role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
10954
11082
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
10955
11083
|
e.preventDefault();
|
|
10956
11084
|
onUserMenuItemClick?.({ id: 'profile', label: '프로필', href: '#' });
|
|
10957
11085
|
}
|
|
10958
|
-
}, style: { cursor: 'pointer' }, children:
|
|
11086
|
+
}, style: { cursor: 'pointer' }, children: jsx(Avatar, { src: userProfile.avatar, initials: userProfile.name, alt: userProfile.name, size: "s", className: "designbase-sidebar__user-avatar-collapsed" }) }))] }) }));
|
|
10959
11087
|
};
|
|
10960
11088
|
Sidebar.displayName = 'Sidebar';
|
|
10961
11089
|
|
|
@@ -12390,24 +12518,5 @@ const YouTubePlayer = ({ videoId, title, description, size = 'm', variant = 'def
|
|
|
12390
12518
|
};
|
|
12391
12519
|
YouTubePlayer.displayName = 'YouTubePlayer';
|
|
12392
12520
|
|
|
12393
|
-
|
|
12394
|
-
* Designbase UI 컴포넌트 라이브러리 메인 엔트리 포인트
|
|
12395
|
-
*
|
|
12396
|
-
* 목적: 모든 UI 컴포넌트와 타입을 내보냄
|
|
12397
|
-
* 기능: Tree-shaking 가능한 개별 컴포넌트 내보내기
|
|
12398
|
-
* 사용법: import { Button, Input } from '@designbasekorea/ui'
|
|
12399
|
-
*/
|
|
12400
|
-
// 테마 CSS 자동 로드 (로컬 복사본 사용)
|
|
12401
|
-
// 테마 관련 유틸리티 재내보내기
|
|
12402
|
-
const setTheme = (theme) => {
|
|
12403
|
-
console.log('setTheme called with:', theme);
|
|
12404
|
-
};
|
|
12405
|
-
const getTheme = () => {
|
|
12406
|
-
return 'light';
|
|
12407
|
-
};
|
|
12408
|
-
const toggleTheme = () => {
|
|
12409
|
-
console.log('toggleTheme called');
|
|
12410
|
-
};
|
|
12411
|
-
|
|
12412
|
-
export { Accordion, AdBanner, Alert, AnimationBackground, AnimationText, AudioPlayer, Avatar, Backdrop, Badge, Banner, BottomNavigation, BottomSheet, Breadcrumbs, Button, Calendar, Card, Carousel, Checkbox, Chip, ColorPicker, Confirm, Container, ContextMenu, Countdown, DatePicker, Divider, Drawer, Dropdown, Dropzone, EmptyState, FileUploader, FloatingActionButton, Form, Gradient, Grid, HeroFeature, Image$1 as Image, ImageList, Indicator, Input, Label, Lightbox, List, Logo, MarkdownEditor, Masonry, MenuItem, Modal, ModalBody, ModalFooter, ModalHeader, Navbar, OnboardingModal, Pagination, Popover, Progress, ProgressStep, Progressbar, Radio, RandomGradient, RangeSlider, Rating, Reorder, ResizablePanels, ScrollArea, SearchBar, Section, SegmentControl, Select, Share, Sidebar, Skeleton, Spinner, SplitView, Stack, Stat, Stepper, Table, Tabs, Testimonial, Textarea, TimePicker, Timeline, Toast, ToastContainer, ToastProvider, Toggle, Toolbar, Tooltip, Tutorial, VideoPlayer, YouTubePlayer, getTheme, setTheme, toggleTheme, useToast };
|
|
12521
|
+
export { Accordion, AdBanner, Alert, AnimationBackground, AnimationText, AudioPlayer, Avatar, Backdrop, Badge, Banner, BottomNavigation, BottomSheet, Breadcrumbs, Button, Calendar, Card, Carousel, Checkbox, Chip, ColorPicker, Confirm, Container, ContextMenu, Countdown, DatePicker, Divider, Drawer, Dropdown, Dropzone, EmptyState, FileUploader, FloatingActionButton, Form, Gradient, Grid, HeroFeature, Image$1 as Image, ImageList, Indicator, Input, Label, Lightbox, List, Logo, MarkdownEditor, Masonry, MenuItem, Modal, ModalBody, ModalFooter, ModalHeader, Navbar, OnboardingModal, Pagination, Popover, Progress, ProgressStep, Progressbar, Radio, RandomGradient, RangeSlider, Rating, Reorder, ResizablePanels, ScrollArea, SearchBar, Section, SegmentControl, Select, Share, Sidebar, Skeleton, Spinner, SplitView, Stack, Stat, Stepper, Table, Tabs, Testimonial, Textarea, TimePicker, Timeline, Toast, ToastContainer, ToastProvider, Toggle, Toolbar, Tooltip, Tutorial, VideoPlayer, YouTubePlayer, useToast };
|
|
12413
12522
|
//# sourceMappingURL=index.esm.js.map
|