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