@designbasekorea/figma-ui 0.1.0 → 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,13 +97,457 @@ 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';
53
106
 
107
+ const FormWithSubmit = ({ onLicenseSubmit, disabled = false, isSubmitting = false, value = '', onValueChange, label = 'License Key', placeholder = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', submitText = 'Submit', submittingText = 'Verifying...', className, }) => {
108
+ const [inputValue, setInputValue] = React.useState(value);
109
+ React.useEffect(() => {
110
+ setInputValue(value);
111
+ }, [value]);
112
+ const handleSubmit = async (e) => {
113
+ e.preventDefault();
114
+ await onLicenseSubmit(inputValue);
115
+ };
116
+ const handleChange = (e) => {
117
+ const newValue = e.target.value;
118
+ setInputValue(newValue);
119
+ onValueChange?.(newValue);
120
+ };
121
+ return (React.createElement("form", { className: `designbase-figma-form-with-submit ${className || ''}`, onSubmit: handleSubmit },
122
+ React.createElement("div", { className: "designbase-figma-form-with-submit__field" },
123
+ React.createElement("label", { className: "designbase-figma-form-with-submit__label" }, label),
124
+ React.createElement(ui.Input, { value: inputValue, onChange: handleChange, placeholder: placeholder, disabled: disabled || isSubmitting, size: "m" })),
125
+ React.createElement(ui.Button, { type: "submit", variant: "primary", size: "m", loading: isSubmitting, disabled: !inputValue.trim() || isSubmitting || disabled, fullWidth: true }, isSubmitting ? submittingText : submitText)));
126
+ };
127
+ FormWithSubmit.displayName = 'FormWithSubmit';
128
+
129
+ const PaymentStatusSection = ({ status, usageCount, activationLimit, activationUsage, licenseKey, onDeactivate, isDeactivating = false, showDetails = false, className, }) => {
130
+ const remainingActivations = activationLimit - activationUsage;
131
+ return (React.createElement("div", { className: `designbase-figma-payment-status ${className || ''}` },
132
+ React.createElement("div", { className: "designbase-figma-payment-status__license-key" },
133
+ "\uB77C\uC774\uC120\uC2A4 \uD0A4: ",
134
+ React.createElement("span", null, licenseKey)),
135
+ showDetails && (React.createElement("div", { className: "designbase-figma-payment-status__details" },
136
+ React.createElement("div", { className: "designbase-figma-payment-status__activation-info" },
137
+ React.createElement("div", { className: "designbase-figma-payment-status__remaining" },
138
+ remainingActivations,
139
+ " ",
140
+ remainingActivations === 1 ? '활성' : '활성',
141
+ " \uC790\uB9AC \uB0A8\uC74C"),
142
+ React.createElement("div", { className: "designbase-figma-payment-status__usage" },
143
+ activationUsage,
144
+ "/",
145
+ activationLimit)),
146
+ React.createElement(ui.Button, { onClick: onDeactivate, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating ? '비활성화중...' : '라이선스 비활성화')))));
147
+ };
148
+ PaymentStatusSection.displayName = 'PaymentStatusSection';
149
+
150
+ const defaultFeatures = [
151
+ { name: '사용 제한', free: '일일 제한', pro: '무제한' },
152
+ { name: '모든 주제 사용', free: false, pro: true },
153
+ { name: '최대 선택 제한', free: '최대 5개', pro: '최대 30개' },
154
+ { name: '더미 개수', free: '1,400개', pro: '4,400개 +' },
155
+ { name: '커스텀 숫자 사용', free: false, pro: true },
156
+ ];
157
+ const defaultPricing = {
158
+ monthly: 2,
159
+ yearly: 21.6,
160
+ };
161
+ const PricingComparison = ({ features = defaultFeatures, pricing = defaultPricing, t = (key) => key, className, }) => {
162
+ const [isYearly, setIsYearly] = React.useState(false);
163
+ const getPrice = () => {
164
+ const price = isYearly ? pricing.yearly : pricing.monthly;
165
+ return `$${price.toLocaleString()} / ${isYearly ? t('perYear') : t('perMonth')}`;
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
+ };
173
+ return (React.createElement("div", { className: `designbase-figma-pricing-comparison ${className || ''}` },
174
+ React.createElement("div", { className: "designbase-figma-pricing-comparison__billing-toggle" },
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" })),
189
+ React.createElement("table", { className: "designbase-figma-pricing-comparison__table" },
190
+ React.createElement("thead", null,
191
+ React.createElement("tr", null,
192
+ React.createElement("th", null, t('feature') || '기능'),
193
+ React.createElement("th", null,
194
+ React.createElement("div", { className: "designbase-figma-pricing-comparison__plan-name" }, t('free') || 'Free'),
195
+ React.createElement("div", null, t('freePrice') || '$0')),
196
+ React.createElement("th", { className: "designbase-figma-pricing-comparison__recommended" },
197
+ React.createElement("div", { className: "designbase-figma-pricing-comparison__plan-name" },
198
+ t('pro') || 'Pro',
199
+ React.createElement("span", { className: "designbase-figma-pricing-comparison__recommended-badge" }, t('recommended') || '추천')),
200
+ React.createElement("div", null, getPrice())))),
201
+ React.createElement("tbody", null, features.map((feature, index) => (React.createElement("tr", { key: index },
202
+ React.createElement("td", null, feature.name),
203
+ React.createElement("td", null, typeof feature.free === 'boolean'
204
+ ? (feature.free ? '✓' : '✗')
205
+ : feature.free),
206
+ React.createElement("td", null, typeof feature.pro === 'boolean'
207
+ ? (feature.pro ? '✓' : '✗')
208
+ : feature.pro))))))));
209
+ };
210
+ PricingComparison.displayName = 'PricingComparison';
211
+
212
+ const PageLicense = ({ status: initialStatus, onClose, usageCount: initialUsageCount = 0, onLicenseSubmit, licenseKey: initialLicenseKey = '', setPaymentStatus, setUsageCount, setShowLicensePage, paymentPageUrl, t = (key) => key, className, }) => {
213
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
214
+ const [isDeactivating, setIsDeactivating] = React.useState(false);
215
+ const [licenseKey, setLicenseKey] = React.useState(initialLicenseKey);
216
+ const [status, setStatus] = React.useState(initialStatus);
217
+ const [usageCount, setLocalUsageCount] = React.useState(initialUsageCount);
218
+ const [activationLimit, setActivationLimit] = React.useState(0);
219
+ const [activationUsage, setActivationUsage] = React.useState(0);
220
+ const [showDetails, setShowDetails] = React.useState(false);
221
+ React.useEffect(() => {
222
+ const handleMessage = (event) => {
223
+ const { type, paymentStatus, licenseKey, activationLimit, activationUsage, success, message, usageCount } = event.data.pluginMessage || {};
224
+ if (type === 'update-plugin-status' || type === 'license-verification-result') {
225
+ if (paymentStatus)
226
+ setStatus(paymentStatus);
227
+ if (licenseKey)
228
+ setLicenseKey(licenseKey);
229
+ if (activationLimit !== undefined)
230
+ setActivationLimit(activationLimit);
231
+ if (activationUsage !== undefined)
232
+ setActivationUsage(activationUsage);
233
+ if (paymentStatus)
234
+ setPaymentStatus(paymentStatus);
235
+ if (usageCount !== undefined) {
236
+ setLocalUsageCount(usageCount);
237
+ setUsageCount(usageCount);
238
+ }
239
+ }
240
+ if (type === 'license-verification-result') {
241
+ setIsSubmitting(false);
242
+ if (message)
243
+ console.log('License verification:', message);
244
+ if (success) {
245
+ setStatus('PAID');
246
+ setPaymentStatus('PAID');
247
+ }
248
+ }
249
+ if (type === 'license-deactivation-result') {
250
+ setIsDeactivating(false);
251
+ if (message)
252
+ console.log('License deactivation:', message);
253
+ if (success) {
254
+ setStatus('UNPAID');
255
+ setPaymentStatus('UNPAID');
256
+ setLicenseKey('');
257
+ setLocalUsageCount(20);
258
+ setActivationLimit(0);
259
+ setActivationUsage(0);
260
+ }
261
+ }
262
+ };
263
+ window.addEventListener('message', handleMessage);
264
+ if (typeof parent !== 'undefined') {
265
+ parent.postMessage({ pluginMessage: { type: 'initialize' } }, '*');
266
+ }
267
+ return () => window.removeEventListener('message', handleMessage);
268
+ }, [setPaymentStatus, setUsageCount]);
269
+ const handleLicenseSubmit = async (submittedLicenseKey) => {
270
+ setIsSubmitting(true);
271
+ if (typeof parent !== 'undefined') {
272
+ parent.postMessage({
273
+ pluginMessage: {
274
+ type: 'verify-license',
275
+ licenseKey: submittedLicenseKey
276
+ }
277
+ }, '*');
278
+ }
279
+ };
280
+ const handleDeactivateLicense = () => {
281
+ setIsDeactivating(true);
282
+ if (typeof parent !== 'undefined') {
283
+ parent.postMessage({
284
+ pluginMessage: { type: 'deactivate-license' }
285
+ }, '*');
286
+ }
287
+ };
288
+ const isPaid = status === 'PAID';
289
+ return (React.createElement("div", { className: `designbase-figma-page-license ${className || ''}` },
290
+ React.createElement("div", { className: "designbase-figma-page-license__content" },
291
+ React.createElement("div", { className: "designbase-figma-page-license__header" },
292
+ React.createElement("div", { className: "designbase-figma-page-license__title" },
293
+ isPaid ? React.createElement(icons.StarIcon, { size: 24 }) : React.createElement(icons.KeyIcon, { size: 24 }),
294
+ React.createElement("h2", null, isPaid ? t('proAccount') || '프로 계정' : t('upgradeToPro') || '프로로 업그레이드')),
295
+ React.createElement("p", { className: "designbase-figma-page-license__description" }, isPaid
296
+ ? t('allFeaturesAvailable') || '모든 기능을 사용할 수 있습니다.'
297
+ : t('purchaseForUnlimited') || '라이선스 구매 후 무제한 접근이 가능합니다.')),
298
+ React.createElement(PricingComparison, { t: t }),
299
+ isPaid && (React.createElement("div", { className: "designbase-figma-page-license__section" },
300
+ React.createElement("div", { className: "designbase-figma-page-license__section-header" },
301
+ React.createElement("h3", null, t('licenseActivated') || '라이선스 활성화됨'),
302
+ React.createElement(ui.Button, { onClick: () => setShowDetails(!showDetails), variant: "tertiary", size: "s", iconOnly: true },
303
+ React.createElement(icons.MoreHorizontalIcon, { size: 16 }))),
304
+ React.createElement(PaymentStatusSection, { status: status, usageCount: usageCount, activationLimit: activationLimit, activationUsage: activationUsage, licenseKey: licenseKey, onDeactivate: handleDeactivateLicense, isDeactivating: isDeactivating, showDetails: showDetails }))),
305
+ React.createElement("div", { className: "designbase-figma-page-license__section" },
306
+ React.createElement("div", { className: "designbase-figma-page-license__section-header" },
307
+ React.createElement("h3", null, t('enterLicenseKey') || '라이선스 키 입력'),
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...' }),
312
+ React.createElement("p", { className: "designbase-figma-page-license__disclaimer" }, isPaid
313
+ ? t('licenseActivatedSuccess') || '라이선스가 성공적으로 활성화되었습니다.'
314
+ : t('enterLicenseFromEmail') || '구독 후 이메일로 받은 라이선스 키를 입력하세요.'))),
315
+ React.createElement(ui.Button, { className: "designbase-figma-page-license__close", onPress: onClose, variant: "tertiary", size: "s", "aria-label": "Close" },
316
+ React.createElement(icons.CloseIcon, { size: 20 }))));
317
+ };
318
+ PageLicense.displayName = 'PageLicense';
319
+
320
+ const UpgradeBanner = ({ onClick, isLoading = false, title, description, buttonText, t = (key) => key, className, }) => {
321
+ return (React.createElement("div", { className: `designbase-figma-upgrade-banner ${className || ''}` },
322
+ React.createElement("div", { className: "designbase-figma-upgrade-banner__content" },
323
+ React.createElement("div", { className: "designbase-figma-upgrade-banner__text-wrap" },
324
+ React.createElement("h3", { className: "designbase-figma-upgrade-banner__title" }, title || t('bannerTitle') || '프로로 업그레이드하세요'),
325
+ React.createElement("p", { className: "designbase-figma-upgrade-banner__text" }, description || t('bannerText') || '무제한 기능을 사용하고 더 많은 혜택을 누리세요.')),
326
+ React.createElement(ui.Button, { onClick: onClick, variant: "primary", size: "m", disabled: isLoading }, buttonText || t('upgradeNow') || '지금 업그레이드'))));
327
+ };
328
+ UpgradeBanner.displayName = 'UpgradeBanner';
329
+
330
+ const ResizablePlugin = ({ children, minWidth = 360, maxWidth = 460, minHeight = 440, maxHeight = 700, icon, className, }) => {
331
+ const [isResizing, setIsResizing] = React.useState(false);
332
+ const resizeHandleRef = React.useRef(null);
333
+ React.useEffect(() => {
334
+ const handleMouseMove = (e) => {
335
+ if (!isResizing)
336
+ return;
337
+ const newWidth = Math.max(minWidth, Math.min(maxWidth, e.clientX + 10));
338
+ const newHeight = Math.max(minHeight, Math.min(maxHeight, e.clientY + 10));
339
+ if (typeof parent !== 'undefined') {
340
+ parent.postMessage({
341
+ pluginMessage: {
342
+ type: 'resize',
343
+ width: newWidth,
344
+ height: newHeight
345
+ }
346
+ }, '*');
347
+ }
348
+ };
349
+ const handleMouseUp = () => {
350
+ setIsResizing(false);
351
+ };
352
+ if (isResizing) {
353
+ window.addEventListener('mousemove', handleMouseMove);
354
+ window.addEventListener('mouseup', handleMouseUp);
355
+ }
356
+ return () => {
357
+ window.removeEventListener('mousemove', handleMouseMove);
358
+ window.removeEventListener('mouseup', handleMouseUp);
359
+ };
360
+ }, [isResizing, minWidth, maxWidth, minHeight, maxHeight]);
361
+ return (React.createElement("div", { className: `designbase-figma-resizable-plugin ${className || ''}` },
362
+ children,
363
+ React.createElement("div", { ref: resizeHandleRef, className: `designbase-figma-resizable-plugin__handle ${isResizing ? 'resizing' : ''}`, onMouseDown: (e) => {
364
+ e.preventDefault();
365
+ setIsResizing(true);
366
+ }, role: "button", tabIndex: 0, "aria-label": "Resize plugin" }, icon || React.createElement(icons.ExpandIcon, { size: 12 }))));
367
+ };
368
+ ResizablePlugin.displayName = 'ResizablePlugin';
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;
54
538
  exports.Footer = Footer;
539
+ exports.FormWithSubmit = FormWithSubmit;
540
+ exports.InteractionFeedback = InteractionFeedback;
541
+ exports.LanguageSelector = LanguageSelector;
55
542
  exports.LogoDropdown = LogoDropdown;
543
+ exports.PageLicense = PageLicense;
544
+ exports.PaymentBadge = PaymentBadge;
545
+ exports.PaymentStatusSection = PaymentStatusSection;
546
+ exports.PricingComparison = PricingComparison;
547
+ exports.ProgressModal = ProgressModal;
548
+ exports.ResizablePlugin = ResizablePlugin;
549
+ exports.SettingsModal = SettingsModal;
550
+ exports.UpgradeBanner = UpgradeBanner;
56
551
  Object.keys(ui).forEach(function (k) {
57
552
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
58
553
  enumerable: true,