@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/README.md +6 -0
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +102 -2
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.css.map +1 -1
- package/dist/index.esm.js +268 -34
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +271 -31
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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 = '
|
|
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
|
|
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(
|
|
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(
|
|
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("
|
|
82
|
-
"\uB77C\uC774\
|
|
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("
|
|
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("
|
|
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(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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("
|
|
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("
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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" },
|
|
244
|
-
|
|
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(
|
|
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.
|
|
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, {
|