@designbasekorea/figma-ui 0.1.2 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import React, { useState, useEffect, useRef } from 'react';
2
- import { ExternalLinkIcon, StarIcon, KeyIcon, SettingsIcon, CloseIcon, ArrowsExpandIcon } from '@designbasekorea/icons';
3
- import { Badge, Spinner, Input, Button, Toggle, useToast, Divider } from '@designbasekorea/ui';
2
+ import { ExternalLinkIcon, HeartFilledIcon, CoffeeFilledIcon, StarIcon, KeyIcon, MoreHorizontalIcon, CloseIcon, ExpandIcon, GripVerticalIcon, CircleCheckFilledIcon } from '@designbasekorea/icons';
3
+ import { Logo, Spinner, Badge, Input, Button, SegmentControl, Modal, Toggle, Progressbar } from '@designbasekorea/ui';
4
4
  export * from '@designbasekorea/ui';
5
5
 
6
6
  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
7
 
8
- const LogoDropdown = ({ logoSrc, logoAlt = 'Logo', links, position = 'bottom-left', className, t = (key) => key, }) => {
8
+ const LogoDropdown = ({ logoSrc, logoAlt = 'DesignBase', logoType = 'designbase', logoSize = 'xs', links, position = 'top-left', className, t = (key) => key, }) => {
9
9
  const [isOpen, setIsOpen] = useState(false);
10
10
  const toggleDropdown = () => setIsOpen(!isOpen);
11
11
  const handleLinkClick = (url) => {
@@ -17,8 +17,15 @@ const LogoDropdown = ({ logoSrc, logoAlt = 'Logo', links, position = 'bottom-lef
17
17
  const classes = clsx('designbase-figma-logo-dropdown', `designbase-figma-logo-dropdown--${position}`, {
18
18
  'designbase-figma-logo-dropdown--open': isOpen,
19
19
  }, className);
20
+ const renderLogo = () => {
21
+ if (logoSrc) {
22
+ return (React.createElement("img", { className: "designbase-figma-logo-dropdown__logo", src: logoSrc, alt: logoAlt, onClick: toggleDropdown }));
23
+ }
24
+ return (React.createElement("div", { className: "designbase-figma-logo-dropdown__logo", onClick: toggleDropdown },
25
+ React.createElement(Logo, { type: logoType, size: logoSize, variant: "default" })));
26
+ };
20
27
  return (React.createElement("div", { className: classes },
21
- React.createElement("img", { className: "designbase-figma-logo-dropdown__logo", src: logoSrc, alt: logoAlt, onClick: toggleDropdown }),
28
+ renderLogo(),
22
29
  isOpen && (React.createElement("ul", { className: "designbase-figma-logo-dropdown__menu" }, links.map((link, index) => (React.createElement("li", { key: index, className: "designbase-figma-logo-dropdown__item" },
23
30
  React.createElement("button", { type: "button", className: "designbase-figma-logo-dropdown__link", onClick: () => handleLinkClick(link.url) },
24
31
  link.icon && (React.createElement("span", { className: "designbase-figma-logo-dropdown__icon" }, link.icon)),
@@ -27,7 +34,56 @@ const LogoDropdown = ({ logoSrc, logoAlt = 'Logo', links, position = 'bottom-lef
27
34
  };
28
35
  LogoDropdown.displayName = 'LogoDropdown';
29
36
 
30
- const Footer = ({ logoSrc, logoAlt = 'Logo', logoLinks = [], onLicensePageClick, paymentStatus = 'FREE', usageCount = 0, isLoading = false, showPaymentStatus = true, maxDailyUsage = 20, className, t = (key) => key, children, }) => {
37
+ const PaymentBadge = ({ isActive, onClick, isLoading = false, text, t = (key) => key, className, }) => {
38
+ const getBadgeText = () => {
39
+ if (text)
40
+ return text;
41
+ return isActive
42
+ ? (t('proUser') || '프로 계정')
43
+ : (t('usingFree') || '무료 사용');
44
+ };
45
+ const getBadgeVariant = () => {
46
+ return isActive ? 'success' : 'secondary';
47
+ };
48
+ return (React.createElement("div", { className: `designbase-figma-payment-badge ${className || ''} ${isActive ? 'active' : 'free'}`, onClick: onClick, style: { cursor: onClick ? 'pointer' : 'default' } }, isLoading ? (React.createElement(Spinner, { size: "s" })) : (React.createElement(Badge, { variant: getBadgeVariant(), size: "s", className: "designbase-figma-payment-badge__badge" }, getBadgeText()))));
49
+ };
50
+ PaymentBadge.displayName = 'PaymentBadge';
51
+
52
+ const DonationBadge = ({ donationUrl = 'https://buymeacoffee.com/designbase', text = 'Buy me a coffee', iconType = 'heart', size = 'm', className, onClick, }) => {
53
+ const handleClick = () => {
54
+ if (onClick) {
55
+ onClick();
56
+ }
57
+ else {
58
+ window.open(donationUrl, '_blank', 'noopener,noreferrer');
59
+ }
60
+ };
61
+ const Icon = iconType === 'heart' ? HeartFilledIcon : CoffeeFilledIcon;
62
+ const classes = clsx('designbase-figma-donation-badge', `designbase-figma-donation-badge--${size}`, `designbase-figma-donation-badge--${iconType}`, className);
63
+ return (React.createElement("button", { type: "button", className: classes, onClick: handleClick, "aria-label": text },
64
+ React.createElement(Icon, { className: "designbase-figma-donation-badge__icon" }),
65
+ React.createElement("span", { className: "designbase-figma-donation-badge__text" }, text)));
66
+ };
67
+ DonationBadge.displayName = 'DonationBadge';
68
+
69
+ const DEFAULT_LANGUAGES = [
70
+ { code: 'ko', label: 'KO' },
71
+ { code: 'en', label: 'EN' },
72
+ ];
73
+ const LanguageSelector = ({ currentLanguage = 'ko', languages = DEFAULT_LANGUAGES, onLanguageChange, size = 's', className, }) => {
74
+ const handleLanguageChange = (languageCode) => {
75
+ if (onLanguageChange) {
76
+ onLanguageChange(languageCode);
77
+ }
78
+ };
79
+ const classes = clsx('designbase-figma-language-selector', `designbase-figma-language-selector--${size}`, className);
80
+ return (React.createElement("div", { className: classes }, languages.map((language) => (React.createElement("button", { key: language.code, type: "button", className: clsx('designbase-figma-language-selector__button', {
81
+ 'designbase-figma-language-selector__button--active': currentLanguage === language.code,
82
+ }), onClick: () => handleLanguageChange(language.code), "aria-label": `${language.label} 언어 선택`, "aria-pressed": currentLanguage === language.code }, language.label)))));
83
+ };
84
+ LanguageSelector.displayName = 'LanguageSelector';
85
+
86
+ const Footer = ({ logoSrc, logoAlt = 'DesignBase', logoType = 'designbase', logoSize = 'xs', logoLinks = [], onLicensePageClick, paymentStatus = 'FREE', usageCount = 0, isLoading = false, showPaymentStatus = true, maxDailyUsage = 20, showDonation = false, donationUrl = 'https://buymeacoffee.com/designbase', donationText = 'Buy me a coffee', showLanguageSelector = false, currentLanguage = 'ko', languages, onLanguageChange, className, t = (key) => key, children, }) => {
31
87
  const isActive = paymentStatus === 'PAID';
32
88
  const hasChildren = React.Children.count(children) > 0;
33
89
  const classes = clsx('designbase-figma-footer', {
@@ -35,7 +91,9 @@ const Footer = ({ logoSrc, logoAlt = 'Logo', logoLinks = [], onLicensePageClick,
35
91
  }, className);
36
92
  return (React.createElement("footer", { className: classes },
37
93
  React.createElement("div", { className: "designbase-figma-footer__wrap" },
38
- React.createElement(LogoDropdown, { logoSrc: logoSrc, logoAlt: logoAlt, links: logoLinks, position: "bottom-left", t: t }),
94
+ React.createElement("div", { className: "designbase-figma-footer__left" },
95
+ React.createElement(LogoDropdown, { logoSrc: logoSrc, logoAlt: logoAlt, logoType: logoType, logoSize: logoSize, links: logoLinks, position: "top-left", t: t }),
96
+ showLanguageSelector && (React.createElement(LanguageSelector, { currentLanguage: currentLanguage, languages: languages, onLanguageChange: onLanguageChange, size: "s" }))),
39
97
  showPaymentStatus && (React.createElement("div", { className: "designbase-figma-footer__payment-states" },
40
98
  !isLoading && (React.createElement("div", { className: "designbase-figma-footer__usage-info" }, isActive ? (React.createElement("span", { className: "designbase-figma-footer__unlimited-usage" }, t('unlimitedUsage'))) : (React.createElement(React.Fragment, null,
41
99
  React.createElement("span", { className: "designbase-figma-footer__usage-count" }, usageCount),
@@ -45,7 +103,9 @@ const Footer = ({ logoSrc, logoAlt = 'Logo', logoLinks = [], onLicensePageClick,
45
103
  " ",
46
104
  t('perDay')),
47
105
  React.createElement("span", { className: "designbase-figma-footer__reset-info" }, t('resetsDaily')))))),
48
- React.createElement(Badge, { variant: isActive ? 'success' : 'secondary', size: "s", onClick: onLicensePageClick, style: { cursor: 'pointer' } }, isLoading ? t('loading') : isActive ? t('premium') : t('free'))))),
106
+ React.createElement(PaymentBadge, { isActive: isActive, onClick: onLicensePageClick, isLoading: isLoading, t: t }))),
107
+ showDonation && (React.createElement("div", { className: "designbase-figma-footer__donation" },
108
+ React.createElement(DonationBadge, { donationUrl: donationUrl, text: donationText, iconType: "heart", size: "s" })))),
49
109
  children));
50
110
  };
51
111
  Footer.displayName = 'Footer';
@@ -65,33 +125,31 @@ const FormWithSubmit = ({ onLicenseSubmit, disabled = false, isSubmitting = fals
65
125
  onValueChange?.(newValue);
66
126
  };
67
127
  return (React.createElement("form", { className: `designbase-figma-form-with-submit ${className || ''}`, onSubmit: handleSubmit },
68
- isSubmitting && (React.createElement("div", { className: "designbase-figma-form-with-submit__spinner" },
69
- React.createElement(Spinner, { size: "s" }))),
70
128
  React.createElement("div", { className: "designbase-figma-form-with-submit__field" },
71
129
  React.createElement("label", { className: "designbase-figma-form-with-submit__label" }, label),
72
130
  React.createElement(Input, { value: inputValue, onChange: handleChange, placeholder: placeholder, disabled: disabled || isSubmitting, size: "m" })),
73
- React.createElement(Button, { type: "submit", variant: "primary", size: "m", disabled: !inputValue.trim() || isSubmitting || disabled, fullWidth: true }, isSubmitting ? submittingText : submitText)));
131
+ React.createElement(Button, { type: "submit", variant: "primary", size: "m", loading: isSubmitting, disabled: !inputValue.trim() || isSubmitting || disabled, fullWidth: true }, isSubmitting ? submittingText : submitText)));
74
132
  };
75
133
  FormWithSubmit.displayName = 'FormWithSubmit';
76
134
 
77
135
  const PaymentStatusSection = ({ status, usageCount, activationLimit, activationUsage, licenseKey, onDeactivate, isDeactivating = false, showDetails = false, className, }) => {
78
136
  const remainingActivations = activationLimit - activationUsage;
79
137
  return (React.createElement("div", { className: `designbase-figma-payment-status ${className || ''}` },
80
- React.createElement("p", { className: "designbase-figma-payment-status__license-key" },
81
- "\uB77C\uC774\uC13C\uC2A4 \uD0A4: ",
138
+ React.createElement("div", { className: "designbase-figma-payment-status__license-key" },
139
+ "\uB77C\uC774\uC120\uC2A4 \uD0A4: ",
82
140
  React.createElement("span", null, licenseKey)),
83
141
  showDetails && (React.createElement("div", { className: "designbase-figma-payment-status__details" },
84
142
  React.createElement("div", { className: "designbase-figma-payment-status__activation-info" },
85
- React.createElement("p", { className: "designbase-figma-payment-status__remaining" },
143
+ React.createElement("div", { className: "designbase-figma-payment-status__remaining" },
86
144
  remainingActivations,
87
145
  " ",
88
146
  remainingActivations === 1 ? '활성' : '활성',
89
147
  " \uC790\uB9AC \uB0A8\uC74C"),
90
- React.createElement("p", { className: "designbase-figma-payment-status__usage" },
148
+ React.createElement("div", { className: "designbase-figma-payment-status__usage" },
91
149
  activationUsage,
92
150
  "/",
93
151
  activationLimit)),
94
- React.createElement(Button, { onClick: onDeactivate, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating ? '비활성화중...' : '라이센스 비활성화')))));
152
+ React.createElement(Button, { onClick: onDeactivate, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating ? '비활성화중...' : '라이선스 비활성화')))));
95
153
  };
96
154
  PaymentStatusSection.displayName = 'PaymentStatusSection';
97
155
 
@@ -112,24 +170,40 @@ const PricingComparison = ({ features = defaultFeatures, pricing = defaultPricin
112
170
  const price = isYearly ? pricing.yearly : pricing.monthly;
113
171
  return `$${price.toLocaleString()} / ${isYearly ? t('perYear') : t('perMonth')}`;
114
172
  };
173
+ const getDiscountPercentage = () => {
174
+ const monthlyPrice = pricing.monthly * 12;
175
+ const yearlyPrice = pricing.yearly;
176
+ const discount = Math.round(((monthlyPrice - yearlyPrice) / monthlyPrice) * 100);
177
+ return discount;
178
+ };
115
179
  return (React.createElement("div", { className: `designbase-figma-pricing-comparison ${className || ''}` },
116
180
  React.createElement("div", { className: "designbase-figma-pricing-comparison__billing-toggle" },
117
- React.createElement("span", { className: !isYearly ? 'active' : '' }, t('monthlyBilling') || '월간 결제'),
118
- React.createElement(Toggle, { size: "s", checked: isYearly, onChange: (e) => setIsYearly(e.target.checked) }),
119
- React.createElement("span", { className: isYearly ? 'active' : '' }, t('yearlyBilling') || '연간 결제'),
120
- React.createElement("span", { className: "designbase-figma-pricing-comparison__discount-badge" }, t('save10Percent') || '10% 절약')),
181
+ React.createElement(SegmentControl, { value: isYearly ? 'yearly' : 'monthly', onChange: (value) => setIsYearly(value === 'yearly'), options: [
182
+ {
183
+ value: 'monthly',
184
+ label: t('monthlyBilling') || '월간 결제',
185
+ },
186
+ {
187
+ value: 'yearly',
188
+ label: (React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
189
+ t('yearlyBilling') || '연간 결제',
190
+ React.createElement("span", { className: "designbase-figma-pricing-comparison__discount-badge" },
191
+ getDiscountPercentage(),
192
+ "% \uC808\uC57D"))),
193
+ },
194
+ ], size: "s" })),
121
195
  React.createElement("table", { className: "designbase-figma-pricing-comparison__table" },
122
196
  React.createElement("thead", null,
123
197
  React.createElement("tr", null,
124
198
  React.createElement("th", null, t('feature') || '기능'),
125
199
  React.createElement("th", null,
126
200
  React.createElement("div", { className: "designbase-figma-pricing-comparison__plan-name" }, t('free') || 'Free'),
127
- React.createElement("p", null, t('freePrice') || '$0')),
201
+ React.createElement("div", null, t('freePrice') || '$0')),
128
202
  React.createElement("th", { className: "designbase-figma-pricing-comparison__recommended" },
129
203
  React.createElement("div", { className: "designbase-figma-pricing-comparison__plan-name" },
130
204
  t('pro') || 'Pro',
131
205
  React.createElement("span", { className: "designbase-figma-pricing-comparison__recommended-badge" }, t('recommended') || '추천')),
132
- React.createElement("p", null, getPrice())))),
206
+ React.createElement("div", null, getPrice())))),
133
207
  React.createElement("tbody", null, features.map((feature, index) => (React.createElement("tr", { key: index },
134
208
  React.createElement("td", null, feature.name),
135
209
  React.createElement("td", null, typeof feature.free === 'boolean'
@@ -141,13 +215,12 @@ const PricingComparison = ({ features = defaultFeatures, pricing = defaultPricin
141
215
  };
142
216
  PricingComparison.displayName = 'PricingComparison';
143
217
 
144
- const PageLicense = ({ status: initialStatus, onClose, usageCount: initialUsageCount = 0, onLicenseSubmit, licenseKey: initialLicenseKey = '', setPaymentStatus, setUsageCount, setShowLicensePage, paymentPageUrl = 'https://designbasekorea.lemonsqueezy.com/buy/fc202a67-6f1a-4a61-9242-c643b282e230', t = (key) => key, className, }) => {
218
+ const PageLicense = ({ status: initialStatus, onClose, usageCount: initialUsageCount = 0, onLicenseSubmit, licenseKey: initialLicenseKey = '', setPaymentStatus, setUsageCount, setShowLicensePage, paymentPageUrl, t = (key) => key, className, }) => {
145
219
  const [isSubmitting, setIsSubmitting] = useState(false);
146
220
  const [isDeactivating, setIsDeactivating] = useState(false);
147
221
  const [licenseKey, setLicenseKey] = useState(initialLicenseKey);
148
222
  const [status, setStatus] = useState(initialStatus);
149
223
  const [usageCount, setLocalUsageCount] = useState(initialUsageCount);
150
- const { showToast } = useToast();
151
224
  const [activationLimit, setActivationLimit] = useState(0);
152
225
  const [activationUsage, setActivationUsage] = useState(0);
153
226
  const [showDetails, setShowDetails] = useState(false);
@@ -173,7 +246,7 @@ const PageLicense = ({ status: initialStatus, onClose, usageCount: initialUsageC
173
246
  if (type === 'license-verification-result') {
174
247
  setIsSubmitting(false);
175
248
  if (message)
176
- showToast(message);
249
+ console.log('License verification:', message);
177
250
  if (success) {
178
251
  setStatus('PAID');
179
252
  setPaymentStatus('PAID');
@@ -182,7 +255,7 @@ const PageLicense = ({ status: initialStatus, onClose, usageCount: initialUsageC
182
255
  if (type === 'license-deactivation-result') {
183
256
  setIsDeactivating(false);
184
257
  if (message)
185
- showToast(message);
258
+ console.log('License deactivation:', message);
186
259
  if (success) {
187
260
  setStatus('UNPAID');
188
261
  setPaymentStatus('UNPAID');
@@ -198,7 +271,7 @@ const PageLicense = ({ status: initialStatus, onClose, usageCount: initialUsageC
198
271
  parent.postMessage({ pluginMessage: { type: 'initialize' } }, '*');
199
272
  }
200
273
  return () => window.removeEventListener('message', handleMessage);
201
- }, [setPaymentStatus, setUsageCount, showToast]);
274
+ }, [setPaymentStatus, setUsageCount]);
202
275
  const handleLicenseSubmit = async (submittedLicenseKey) => {
203
276
  setIsSubmitting(true);
204
277
  if (typeof parent !== 'undefined') {
@@ -227,24 +300,25 @@ const PageLicense = ({ status: initialStatus, onClose, usageCount: initialUsageC
227
300
  React.createElement("h2", null, isPaid ? t('proAccount') || '프로 계정' : t('upgradeToPro') || '프로로 업그레이드')),
228
301
  React.createElement("p", { className: "designbase-figma-page-license__description" }, isPaid
229
302
  ? t('allFeaturesAvailable') || '모든 기능을 사용할 수 있습니다.'
230
- : t('purchaseForUnlimited') || '라이센스 구매 후 무제한 접근이 가능합니다.')),
303
+ : t('purchaseForUnlimited') || '라이선스 구매 후 무제한 접근이 가능합니다.')),
231
304
  React.createElement(PricingComparison, { t: t }),
232
- React.createElement(Divider, null),
233
305
  isPaid && (React.createElement("div", { className: "designbase-figma-page-license__section" },
234
306
  React.createElement("div", { className: "designbase-figma-page-license__section-header" },
235
307
  React.createElement("h3", null, t('licenseActivated') || '라이선스 활성화됨'),
236
- React.createElement(Button, { onClick: () => setShowDetails(!showDetails), variant: "tertiary", size: "s" },
237
- React.createElement(SettingsIcon, { size: 16 }))),
308
+ React.createElement(Button, { onClick: () => setShowDetails(!showDetails), variant: "tertiary", size: "s", iconOnly: true },
309
+ React.createElement(MoreHorizontalIcon, { size: 16 }))),
238
310
  React.createElement(PaymentStatusSection, { status: status, usageCount: usageCount, activationLimit: activationLimit, activationUsage: activationUsage, licenseKey: licenseKey, onDeactivate: handleDeactivateLicense, isDeactivating: isDeactivating, showDetails: showDetails }))),
239
311
  React.createElement("div", { className: "designbase-figma-page-license__section" },
240
312
  React.createElement("div", { className: "designbase-figma-page-license__section-header" },
241
313
  React.createElement("h3", null, t('enterLicenseKey') || '라이선스 키 입력'),
242
- !isPaid && (React.createElement(Button, { onClick: () => window.open(paymentPageUrl, '_blank'), variant: "primary", size: "s" }, t('purchaseLicense') || '라이센스 구매'))),
243
- React.createElement(FormWithSubmit, { onLicenseSubmit: handleLicenseSubmit, disabled: isPaid, isSubmitting: isSubmitting, value: licenseKey, onValueChange: setLicenseKey, label: t('licenseKey') || 'License Key', submitText: t('submit') || 'Submit', submittingText: t('verifying') || 'Verifying...' }),
314
+ !isPaid && paymentPageUrl && (React.createElement(Button, { onClick: () => window.open(paymentPageUrl, '_blank'), variant: "primary", size: "s" },
315
+ React.createElement("span", null, t('purchaseLicense') || '라이선스 구매'),
316
+ React.createElement(ExternalLinkIcon, { size: 16 })))),
317
+ React.createElement(FormWithSubmit, { onLicenseSubmit: handleLicenseSubmit, disabled: false, isSubmitting: isSubmitting, value: licenseKey, onValueChange: setLicenseKey, label: t('licenseKey') || 'License Key', submitText: t('submit') || 'Submit', submittingText: t('verifying') || 'Verifying...' }),
244
318
  React.createElement("p", { className: "designbase-figma-page-license__disclaimer" }, isPaid
245
319
  ? t('licenseActivatedSuccess') || '라이선스가 성공적으로 활성화되었습니다.'
246
320
  : t('enterLicenseFromEmail') || '구독 후 이메일로 받은 라이선스 키를 입력하세요.'))),
247
- React.createElement("button", { className: "designbase-figma-page-license__close", onClick: onClose, "aria-label": "Close" },
321
+ React.createElement(Button, { className: "designbase-figma-page-license__close", onPress: onClose, variant: "tertiary", size: "s", "aria-label": "Close" },
248
322
  React.createElement(CloseIcon, { size: 20 }))));
249
323
  };
250
324
  PageLicense.displayName = 'PageLicense';
@@ -295,9 +369,176 @@ const ResizablePlugin = ({ children, minWidth = 360, maxWidth = 460, minHeight =
295
369
  React.createElement("div", { ref: resizeHandleRef, className: `designbase-figma-resizable-plugin__handle ${isResizing ? 'resizing' : ''}`, onMouseDown: (e) => {
296
370
  e.preventDefault();
297
371
  setIsResizing(true);
298
- }, role: "button", tabIndex: 0, "aria-label": "Resize plugin" }, icon || React.createElement(ArrowsExpandIcon, { size: 12 }))));
372
+ }, role: "button", tabIndex: 0, "aria-label": "Resize plugin" }, icon || React.createElement(ExpandIcon, { size: 12 }))));
299
373
  };
300
374
  ResizablePlugin.displayName = 'ResizablePlugin';
301
375
 
302
- export { Footer, FormWithSubmit, LogoDropdown, PageLicense, PaymentStatusSection, PricingComparison, ResizablePlugin, UpgradeBanner };
376
+ const InteractionFeedback = ({ status = 'default', message, statusMessage, leftContent, rightContent, visible = true, className, fixed = true, }) => {
377
+ const wrapperClasses = clsx('designbase-figma-interaction-wrapper', {
378
+ 'designbase-figma-interaction-wrapper--fixed': fixed,
379
+ });
380
+ const feedbackClasses = clsx('designbase-figma-interaction', `designbase-figma-interaction--${status}`, {
381
+ 'designbase-figma-interaction--visible': visible,
382
+ }, className);
383
+ if (!visible)
384
+ return null;
385
+ return (React.createElement("div", { className: wrapperClasses },
386
+ React.createElement("div", { className: feedbackClasses },
387
+ React.createElement("div", { className: "designbase-figma-interaction__content" },
388
+ React.createElement("div", { className: "designbase-figma-interaction__left" }, leftContent || (React.createElement("div", { className: "designbase-figma-interaction__message" },
389
+ message && (React.createElement("span", { className: "designbase-figma-interaction__text" }, message)),
390
+ statusMessage && (React.createElement("span", { className: "designbase-figma-interaction__status-text" }, statusMessage))))),
391
+ rightContent && (React.createElement("div", { className: "designbase-figma-interaction__right" }, rightContent))))));
392
+ };
393
+ InteractionFeedback.displayName = 'InteractionFeedback';
394
+
395
+ const SettingsModal = ({ isOpen, onClose, categories: initialCategories, categoryGroups, onSave, onReset, title = '목록 변경', description = '드래그하여 순서를 변경하거나, 토글하여 카테고리를 숨길 수 있습니다.', className, }) => {
396
+ const [tempCategories, setTempCategories] = useState(initialCategories);
397
+ const [draggedIndex, setDraggedIndex] = useState(null);
398
+ useEffect(() => {
399
+ setTempCategories(initialCategories);
400
+ }, [initialCategories]);
401
+ const handleDragStart = (e, index) => {
402
+ setDraggedIndex(index);
403
+ e.dataTransfer.effectAllowed = 'move';
404
+ e.dataTransfer.setData('text/plain', index.toString());
405
+ };
406
+ const handleDragOver = (e) => {
407
+ e.preventDefault();
408
+ e.dataTransfer.dropEffect = 'move';
409
+ };
410
+ const handleDrop = (e, dropIndex) => {
411
+ e.preventDefault();
412
+ const dragIndex = Number(e.dataTransfer.getData('text/plain'));
413
+ if (dragIndex === dropIndex) {
414
+ setDraggedIndex(null);
415
+ return;
416
+ }
417
+ const newCategories = [...tempCategories];
418
+ const [draggedItem] = newCategories.splice(dragIndex, 1);
419
+ const enabledCategories = newCategories.filter(cat => cat.enabled);
420
+ const disabledCategories = newCategories.filter(cat => !cat.enabled);
421
+ if (draggedItem.enabled) {
422
+ if (dropIndex <= enabledCategories.length) {
423
+ const adjustedDropIndex = dragIndex < dropIndex ? dropIndex - 1 : dropIndex;
424
+ enabledCategories.splice(adjustedDropIndex, 0, draggedItem);
425
+ }
426
+ else {
427
+ enabledCategories.push(draggedItem);
428
+ }
429
+ }
430
+ else {
431
+ if (dropIndex > enabledCategories.length) {
432
+ const disabledDropIndex = dropIndex - enabledCategories.length;
433
+ const adjustedDropIndex = dragIndex < dropIndex ? disabledDropIndex - 1 : disabledDropIndex;
434
+ disabledCategories.splice(adjustedDropIndex, 0, draggedItem);
435
+ }
436
+ else {
437
+ disabledCategories.unshift(draggedItem);
438
+ }
439
+ }
440
+ const reorderedCategories = [
441
+ ...enabledCategories.map((cat, idx) => ({ ...cat, order: idx })),
442
+ ...disabledCategories.map((cat, idx) => ({ ...cat, order: enabledCategories.length + idx }))
443
+ ];
444
+ setTempCategories(reorderedCategories);
445
+ setDraggedIndex(null);
446
+ };
447
+ const handleDragEnd = () => {
448
+ setDraggedIndex(null);
449
+ };
450
+ const handleToggle = (id) => {
451
+ setTempCategories(prev => {
452
+ const enabledCategories = prev.filter(cat => cat.id !== id && cat.enabled);
453
+ const disabledCategories = prev.filter(cat => cat.id !== id && !cat.enabled);
454
+ const targetCategory = prev.find(cat => cat.id === id);
455
+ if (!targetCategory)
456
+ return prev;
457
+ const newTargetCategory = { ...targetCategory, enabled: !targetCategory.enabled };
458
+ if (newTargetCategory.enabled) {
459
+ return [
460
+ ...enabledCategories,
461
+ newTargetCategory,
462
+ ...disabledCategories
463
+ ].map((cat, idx) => ({ ...cat, order: idx }));
464
+ }
465
+ else {
466
+ return [
467
+ ...enabledCategories,
468
+ ...disabledCategories,
469
+ newTargetCategory
470
+ ].map((cat, idx) => ({ ...cat, order: idx }));
471
+ }
472
+ });
473
+ };
474
+ const handleSave = () => {
475
+ onSave(tempCategories);
476
+ onClose();
477
+ };
478
+ const handleCancel = () => {
479
+ setTempCategories(initialCategories);
480
+ onClose();
481
+ };
482
+ const handleReset = () => {
483
+ if (onReset) {
484
+ onReset();
485
+ }
486
+ };
487
+ const modalClasses = clsx('designbase-figma-settings-modal', className);
488
+ return (React.createElement(Modal, { isOpen: isOpen, onClose: onClose, title: title, size: "m", className: modalClasses },
489
+ React.createElement("div", { className: "designbase-figma-settings-modal__content" },
490
+ description && (React.createElement("p", { className: "designbase-figma-settings-modal__description" }, description)),
491
+ React.createElement("ul", { className: "designbase-figma-settings-modal__list" }, tempCategories.map((category, index) => (React.createElement("li", { key: category.id, draggable: true, onDragStart: (e) => handleDragStart(e, index), onDragOver: handleDragOver, onDrop: (e) => handleDrop(e, index), onDragEnd: handleDragEnd, className: clsx('designbase-figma-settings-modal__item', {
492
+ 'designbase-figma-settings-modal__item--disabled': !category.enabled,
493
+ 'designbase-figma-settings-modal__item--dragging': draggedIndex === index,
494
+ }) },
495
+ React.createElement("div", { className: "designbase-figma-settings-modal__item-info" },
496
+ React.createElement("span", { className: "designbase-figma-settings-modal__drag-handle" },
497
+ React.createElement(GripVerticalIcon, { size: 16 })),
498
+ category.icon && (React.createElement("span", { className: "designbase-figma-settings-modal__category-icon" }, category.icon)),
499
+ React.createElement("span", { className: "designbase-figma-settings-modal__category-title" }, category.title)),
500
+ React.createElement(Toggle, { checked: category.enabled, onChange: () => handleToggle(category.id), size: "s" })))))),
501
+ React.createElement("div", { className: "designbase-figma-settings-modal__footer" },
502
+ onReset && (React.createElement(Button, { onPress: handleReset, variant: "tertiary", size: "s" }, "\uCD08\uAE30\uD654")),
503
+ React.createElement("div", { className: "designbase-figma-settings-modal__footer-right" },
504
+ React.createElement(Button, { onPress: handleCancel, variant: "tertiary", size: "s" }, "\uCDE8\uC18C"),
505
+ React.createElement(Button, { onPress: handleSave, variant: "primary", size: "s" }, "\uC800\uC7A5")))));
506
+ };
507
+ SettingsModal.displayName = 'SettingsModal';
508
+
509
+ const ProgressModal = ({ isOpen, onClose, progress, title = '작업 중', completedMessage = '완료되었습니다', processingMessage = '처리 중...', stopButtonText = '중지', confirmButtonText = '확인', helpText, onStop, onComplete, loadingIcon, completeIcon, className, }) => {
510
+ const [isCompleted, setIsCompleted] = useState(false);
511
+ const { processedNodes, totalNodes } = progress;
512
+ const progressPercentage = totalNodes > 0 ? (processedNodes / totalNodes) * 100 : 0;
513
+ useEffect(() => {
514
+ if (processedNodes === totalNodes && totalNodes > 0) {
515
+ setIsCompleted(true);
516
+ if (onComplete)
517
+ onComplete();
518
+ }
519
+ }, [processedNodes, totalNodes, onComplete]);
520
+ useEffect(() => {
521
+ if (isOpen)
522
+ setIsCompleted(false);
523
+ }, [isOpen]);
524
+ const handleStop = () => {
525
+ if (onStop)
526
+ onStop();
527
+ onClose();
528
+ };
529
+ const modalClasses = clsx('designbase-figma-progress-modal', className);
530
+ return (React.createElement(Modal, { isOpen: isOpen, onClose: isCompleted ? onClose : undefined, title: isCompleted ? completedMessage : title, size: "s", className: modalClasses, showCloseButton: false },
531
+ React.createElement("div", { className: "designbase-figma-progress-modal__content" },
532
+ React.createElement("div", { className: "designbase-figma-progress-modal__icon", "aria-hidden": "true" }, isCompleted ? (completeIcon || (React.createElement("div", { className: "designbase-figma-progress-modal__icon-success" },
533
+ React.createElement(CircleCheckFilledIcon, null)))) : (loadingIcon || (React.createElement("div", { className: "designbase-figma-progress-modal__icon-loading" },
534
+ React.createElement(Spinner, { size: "m" }))))),
535
+ React.createElement("p", { className: "designbase-figma-progress-modal__message" }, isCompleted ? completedMessage : processingMessage),
536
+ React.createElement("div", { className: "designbase-figma-progress-modal__status" }, `${processedNodes} / ${totalNodes} (${progressPercentage.toFixed(1)}%)`),
537
+ React.createElement(Progressbar, { value: progressPercentage, size: "m", variant: isCompleted ? 'success' : 'primary', style: "animated", fullWidth: true }),
538
+ helpText && !isCompleted && (React.createElement("p", { className: "designbase-figma-progress-modal__help-text" }, helpText)),
539
+ React.createElement("div", { className: "designbase-figma-progress-modal__actions" }, isCompleted ? (React.createElement(Button, { onPress: onClose, variant: "primary", size: "m", fullWidth: true }, confirmButtonText)) : (React.createElement(Button, { onPress: handleStop, variant: "secondary", size: "m", fullWidth: true }, stopButtonText))))));
540
+ };
541
+ ProgressModal.displayName = 'ProgressModal';
542
+
543
+ export { DonationBadge, Footer, FormWithSubmit, InteractionFeedback, LanguageSelector, LogoDropdown, PageLicense, PaymentBadge, PaymentStatusSection, PricingComparison, ProgressModal, ResizablePlugin, SettingsModal, UpgradeBanner };
303
544
  //# sourceMappingURL=index.esm.js.map