@designbasekorea/figma-ui 0.6.0 → 0.6.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 +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +83 -14
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.css.map +1 -1
- package/dist/index.esm.js +374 -144
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +394 -161
- package/dist/index.js.map +1 -1
- package/package.json +14 -7
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React, { useRef, useState, useEffect, createContext, useContext, useCallback } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import React, { useRef, useState, useLayoutEffect, useEffect, createContext, useContext, useCallback, useMemo } from 'react';
|
|
2
|
+
import { Button, Dropdown, Badge, Toggle, Spinner, SegmentControl, Logo, Toast, Input, Modal, Progressbar, RandomGradient } from '@designbasekorea/ui-wc/react';
|
|
3
|
+
export * from '@designbasekorea/ui-wc/react';
|
|
4
|
+
import { ChevronDownIcon, AppWindowIcon, YoutubeIcon, InstagramIcon, FigmaIcon, MailIcon, ExternalLinkIcon, MoreHorizontalIcon, CloseIcon, CircleCheckFilledIcon, ResizableIcon, GripVerticalIcon, ChevronRightIcon } from '@designbasekorea/icons';
|
|
5
5
|
|
|
6
6
|
function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
|
|
7
7
|
|
|
@@ -11,10 +11,20 @@ function resolveText(t, input, fallback) {
|
|
|
11
11
|
if (typeof input === 'string') {
|
|
12
12
|
return input;
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
if (t) {
|
|
15
|
+
const translated = t(input.key, input.values);
|
|
16
|
+
if (translated && translated !== input.key) {
|
|
17
|
+
return translated;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return fallback ?? input.key;
|
|
15
21
|
}
|
|
16
22
|
|
|
17
|
-
const
|
|
23
|
+
const DONATION_ICON_NAMES = {
|
|
24
|
+
heart: 'star-filled',
|
|
25
|
+
coffee: 'cart',
|
|
26
|
+
};
|
|
27
|
+
const DonationBadge = ({ donationUrl = 'https://buymeacoffee.com/designbase', text = { key: 'donation.buy_me_a_coffee' }, iconType = 'heart', size = 's', variant = 'tertiary', fullWidth = false, iconOnly = false, disabled = false, showPrompt = false, promptText = { key: 'donation.prompt' }, className, onClick, t }) => {
|
|
18
28
|
const handleClick = () => {
|
|
19
29
|
if (onClick) {
|
|
20
30
|
onClick();
|
|
@@ -23,15 +33,12 @@ const DonationBadge = ({ donationUrl = 'https://buymeacoffee.com/designbase', te
|
|
|
23
33
|
window.open(donationUrl, '_blank', 'noopener,noreferrer');
|
|
24
34
|
}
|
|
25
35
|
};
|
|
26
|
-
const Icon = iconType === 'heart' ? HeartFilledIcon : CoffeeFilledIcon;
|
|
27
36
|
const displayText = resolveText(t, text, 'Buy me a coffee');
|
|
28
37
|
const displayPromptText = resolveText(t, promptText, '도움이 되었다면 커피 한 잔 사주세요!');
|
|
29
38
|
const buttonSize = size;
|
|
30
39
|
return (React.createElement("div", { className: clsx('designbase-figma-donation-badge-container', className) },
|
|
31
|
-
showPrompt && (React.createElement("div", { className: "designbase-figma-donation-badge__prompt" }, displayPromptText)),
|
|
32
|
-
React.createElement(Button, { variant: variant, size: buttonSize, fullWidth: fullWidth, disabled: disabled, onPress: handleClick, startIcon:
|
|
33
|
-
'--designbase-figma-donation-badge-icon-color': 'var(--db-brand-primary)'
|
|
34
|
-
} }, displayText)));
|
|
40
|
+
showPrompt && !iconOnly && (React.createElement("div", { className: "designbase-figma-donation-badge__prompt" }, displayPromptText)),
|
|
41
|
+
React.createElement(Button, { variant: variant, size: buttonSize, fullWidth: fullWidth, disabled: disabled, onPress: handleClick, iconOnly: iconOnly, startIcon: DONATION_ICON_NAMES[iconType], className: clsx('designbase-figma-donation-badge', `designbase-figma-donation-badge--${iconType}`), "aria-label": displayText }, iconOnly ? undefined : displayText)));
|
|
35
42
|
};
|
|
36
43
|
DonationBadge.displayName = 'DonationBadge';
|
|
37
44
|
|
|
@@ -69,10 +76,11 @@ const FigmaHeader = ({ children, actions = [], searchBar, sticky = true, classNa
|
|
|
69
76
|
'designbase-figma-header--with-search': !!searchBar,
|
|
70
77
|
'designbase-figma-header--with-actions': actions.length > 0,
|
|
71
78
|
}, className);
|
|
79
|
+
const hasToolbar = !!children || actions.length > 0;
|
|
72
80
|
return (React.createElement("header", { className: classes },
|
|
73
|
-
React.createElement("div", { className: "designbase-figma-header__container" },
|
|
81
|
+
hasToolbar && (React.createElement("div", { className: "designbase-figma-header__container" },
|
|
74
82
|
children && (React.createElement("div", { className: "designbase-figma-header__center" }, children)),
|
|
75
|
-
actions.length > 0 && (React.createElement("div", { className: "designbase-figma-header__right" }, actions.map((action, index) => (React.createElement(Button, { key: index
|
|
83
|
+
actions.length > 0 && (React.createElement("div", { className: "designbase-figma-header__right" }, actions.map((action, index) => (React.createElement(Button, { key: `${action.startIcon}-${index}`, variant: "tertiary", size: "s", iconOnly: true, startIcon: action.startIcon, "aria-label": action.ariaLabel, onPress: action.onPress }))))))),
|
|
76
84
|
searchBar && (React.createElement("div", { className: "designbase-figma-header__search-container" }, searchBar))));
|
|
77
85
|
};
|
|
78
86
|
FigmaHeader.displayName = 'FigmaHeader';
|
|
@@ -81,22 +89,24 @@ const FigmaPageHead = ({ onBack, title, description, actions = [], moreActions =
|
|
|
81
89
|
const classes = clsx('designbase-figma-page-head', className);
|
|
82
90
|
const displayTitle = resolveText(t, title);
|
|
83
91
|
const displayDescription = description ? resolveText(t, description) : undefined;
|
|
84
|
-
const dropdownItems = moreActions.map(action => ({
|
|
92
|
+
const dropdownItems = moreActions.map((action) => ({
|
|
85
93
|
id: action.id,
|
|
86
94
|
label: resolveText(t, action.label),
|
|
87
|
-
onClick: action.onClick
|
|
88
95
|
}));
|
|
96
|
+
const handleDropdownChange = (event) => {
|
|
97
|
+
const actionId = event.detail?.id ?? event.detail?.value;
|
|
98
|
+
const action = moreActions.find((item) => item.id === actionId);
|
|
99
|
+
action?.onClick();
|
|
100
|
+
};
|
|
89
101
|
return (React.createElement("div", { className: classes },
|
|
90
102
|
React.createElement("div", { className: "designbase-figma-page-head__left" },
|
|
91
|
-
React.createElement(Button, { variant: "tertiary", size: "s", iconOnly: true, onPress: onBack, "aria-label": "\uB4A4\uB85C\uAC00\uAE30" },
|
|
92
|
-
React.createElement(ChevronLeftIcon, { size: 14 })),
|
|
103
|
+
React.createElement(Button, { variant: "tertiary", size: "s", iconOnly: true, startIcon: "chevron-left", onPress: onBack, "aria-label": "\uB4A4\uB85C\uAC00\uAE30" }),
|
|
93
104
|
React.createElement("div", { className: "designbase-figma-page-head__titles" },
|
|
94
105
|
React.createElement("h2", null, displayTitle),
|
|
95
106
|
displayDescription && React.createElement("p", null, displayDescription))),
|
|
96
107
|
React.createElement("div", { className: "designbase-figma-page-head__actions" },
|
|
97
108
|
actions.map((action, index) => (React.createElement(React.Fragment, { key: index }, action))),
|
|
98
|
-
moreActions.length > 0 && (React.createElement(Dropdown, {
|
|
99
|
-
React.createElement(MoreHorizontalIcon, { size: 16 })), items: dropdownItems, placement: "bottom-right", size: "s" })))));
|
|
109
|
+
moreActions.length > 0 && (React.createElement(Dropdown, { items: dropdownItems, triggerIcon: "more-horizontal", iconOnly: true, triggerVariant: "tertiary", placement: "bottom-right", size: "s", onChange: handleDropdownChange })))));
|
|
100
110
|
};
|
|
101
111
|
FigmaPageHead.displayName = 'FigmaPageHead';
|
|
102
112
|
|
|
@@ -105,7 +115,9 @@ const FigmaSection = ({ title, dataCategory, iconButton, children, marginBottom,
|
|
|
105
115
|
const clipRef = useRef(null);
|
|
106
116
|
const innerRef = useRef(null);
|
|
107
117
|
const animatingRef = useRef(false);
|
|
118
|
+
const isInitialMountRef = useRef(true);
|
|
108
119
|
const [collapsed, setCollapsed] = useState(defaultCollapsed);
|
|
120
|
+
const [contentHidden, setContentHidden] = useState(defaultCollapsed);
|
|
109
121
|
const sectionStyle = marginBottom ? { marginBottom: `${marginBottom}px` } : undefined;
|
|
110
122
|
const classes = [
|
|
111
123
|
'designbase-figma-section',
|
|
@@ -118,38 +130,42 @@ const FigmaSection = ({ title, dataCategory, iconButton, children, marginBottom,
|
|
|
118
130
|
const toggle = () => {
|
|
119
131
|
if (!collapsible)
|
|
120
132
|
return;
|
|
121
|
-
setCollapsed(
|
|
122
|
-
const next = !
|
|
133
|
+
setCollapsed((prev) => {
|
|
134
|
+
const next = !prev;
|
|
123
135
|
onCollapseChange?.(next, dataCategory);
|
|
124
|
-
animate(next);
|
|
125
136
|
return next;
|
|
126
137
|
});
|
|
127
138
|
};
|
|
128
|
-
const animate = (toCollapsed) => {
|
|
139
|
+
const animate = (toCollapsed, onComplete) => {
|
|
129
140
|
const clip = clipRef.current;
|
|
130
141
|
const inner = innerRef.current;
|
|
131
142
|
if (!clip || !inner)
|
|
132
143
|
return;
|
|
133
144
|
const transitionMs = 250;
|
|
134
|
-
const setH = (h) => {
|
|
145
|
+
const setH = (h) => {
|
|
146
|
+
clip.style.height = h;
|
|
147
|
+
};
|
|
135
148
|
if (animatingRef.current) {
|
|
136
149
|
const current = `${clip.getBoundingClientRect().height}px`;
|
|
137
150
|
clip.style.transition = 'none';
|
|
138
151
|
setH(current);
|
|
139
|
-
clip.offsetHeight;
|
|
152
|
+
void clip.offsetHeight;
|
|
140
153
|
clip.style.transition = '';
|
|
141
154
|
}
|
|
142
155
|
animatingRef.current = true;
|
|
143
156
|
if (toCollapsed) {
|
|
157
|
+
inner.classList.remove('is-collapsed');
|
|
144
158
|
const start = `${inner.scrollHeight}px`;
|
|
145
159
|
setH(start);
|
|
146
|
-
clip.offsetHeight;
|
|
160
|
+
void clip.offsetHeight;
|
|
147
161
|
setH('0px');
|
|
148
162
|
}
|
|
149
163
|
else {
|
|
164
|
+
inner.classList.remove('is-collapsed');
|
|
165
|
+
const targetHeight = inner.scrollHeight;
|
|
150
166
|
setH('0px');
|
|
151
|
-
clip.offsetHeight;
|
|
152
|
-
setH(`${
|
|
167
|
+
void clip.offsetHeight;
|
|
168
|
+
setH(`${targetHeight}px`);
|
|
153
169
|
}
|
|
154
170
|
const onEnd = (e) => {
|
|
155
171
|
if (e.propertyName !== 'height')
|
|
@@ -159,6 +175,7 @@ const FigmaSection = ({ title, dataCategory, iconButton, children, marginBottom,
|
|
|
159
175
|
setH('auto');
|
|
160
176
|
}
|
|
161
177
|
animatingRef.current = false;
|
|
178
|
+
onComplete?.();
|
|
162
179
|
};
|
|
163
180
|
clip.addEventListener('transitionend', onEnd);
|
|
164
181
|
window.setTimeout(() => {
|
|
@@ -167,15 +184,29 @@ const FigmaSection = ({ title, dataCategory, iconButton, children, marginBottom,
|
|
|
167
184
|
if (!toCollapsed)
|
|
168
185
|
setH('auto');
|
|
169
186
|
animatingRef.current = false;
|
|
187
|
+
onComplete?.();
|
|
170
188
|
}, transitionMs + 50);
|
|
171
189
|
};
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const inner = innerRef.current;
|
|
175
|
-
if (!clip || !inner)
|
|
190
|
+
useLayoutEffect(() => {
|
|
191
|
+
if (!collapsible)
|
|
176
192
|
return;
|
|
177
|
-
|
|
178
|
-
|
|
193
|
+
if (isInitialMountRef.current) {
|
|
194
|
+
isInitialMountRef.current = false;
|
|
195
|
+
const clip = clipRef.current;
|
|
196
|
+
if (clip) {
|
|
197
|
+
clip.style.height = collapsed ? '0px' : 'auto';
|
|
198
|
+
}
|
|
199
|
+
setContentHidden(collapsed);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (collapsed) {
|
|
203
|
+
animate(true, () => setContentHidden(true));
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
setContentHidden(false);
|
|
207
|
+
animate(false);
|
|
208
|
+
}
|
|
209
|
+
}, [collapsed, collapsible]);
|
|
179
210
|
useEffect(() => {
|
|
180
211
|
if (collapsed)
|
|
181
212
|
return;
|
|
@@ -202,14 +233,14 @@ const FigmaSection = ({ title, dataCategory, iconButton, children, marginBottom,
|
|
|
202
233
|
? resolveText(t, title)
|
|
203
234
|
: title,
|
|
204
235
|
badge && (React.createElement(Badge, { variant: "secondary", size: "s" }, badge)))),
|
|
205
|
-
React.createElement("div", { className: "designbase-figma-section__controls" },
|
|
236
|
+
React.createElement("div", { className: "designbase-figma-section__controls", onClick: (e) => e.stopPropagation() },
|
|
206
237
|
iconButton,
|
|
207
238
|
collapsible && (React.createElement("span", { className: `designbase-figma-section__collapse-icon ${collapsed ? 'designbase-figma-section__collapse-icon--collapsed' : ''}` },
|
|
208
239
|
React.createElement(ChevronDownIcon, { size: 16 }))),
|
|
209
240
|
onToggle && (React.createElement(Toggle, { checked: isEnabled, onChange: () => onToggle(dataCategory), size: "s" }))))),
|
|
210
241
|
React.createElement("div", { className: `designbase-figma-section__content ${!isEnabled ? 'designbase-figma-section__content--hidden' : ''}` },
|
|
211
242
|
React.createElement("div", { ref: clipRef, className: "designbase-figma-section__content-clip" },
|
|
212
|
-
React.createElement("div", { ref: innerRef, className: `designbase-figma-section__content-inner ${collapsible &&
|
|
243
|
+
React.createElement("div", { ref: innerRef, className: `designbase-figma-section__content-inner ${collapsible && contentHidden ? 'is-collapsed' : ''}` }, children)))));
|
|
213
244
|
};
|
|
214
245
|
FigmaSection.displayName = 'FigmaSection';
|
|
215
246
|
const scrollToSection = (category, headerHeight = 94) => {
|
|
@@ -392,10 +423,15 @@ const LanguageSelector = ({ currentLanguage, languages = DEFAULT_LANGUAGES, onLa
|
|
|
392
423
|
const segmentOptions = languages.map((language) => ({
|
|
393
424
|
value: language.code,
|
|
394
425
|
label: resolveText(t, language.label),
|
|
395
|
-
disabled: false
|
|
426
|
+
disabled: false,
|
|
396
427
|
}));
|
|
397
428
|
return (React.createElement("div", { className: `designbase-figma-language-selector ${className || ''}` },
|
|
398
|
-
React.createElement(SegmentControl, { options: segmentOptions, value: activeLanguage, onChange:
|
|
429
|
+
React.createElement(SegmentControl, { options: segmentOptions, value: activeLanguage, onChange: (event) => {
|
|
430
|
+
const value = event.detail?.value;
|
|
431
|
+
if (value) {
|
|
432
|
+
handleLanguageChange(value);
|
|
433
|
+
}
|
|
434
|
+
}, size: size, className: "designbase-figma-language-selector__segment" })));
|
|
399
435
|
};
|
|
400
436
|
LanguageSelector.displayName = 'LanguageSelector';
|
|
401
437
|
|
|
@@ -485,22 +521,29 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
|
|
|
485
521
|
React.createElement("div", { className: "designbase-figma-footer__left" },
|
|
486
522
|
React.createElement(LogoDropdown, { logoSrc: logoSrc, logoAlt: logoAlt, logoType: logoType, logoSize: logoSize, links: logoLinks, t: t }),
|
|
487
523
|
showLanguageSelector && (React.createElement(LanguageSelector, { currentLanguage: currentLanguage, languages: languages, onLanguageChange: onLanguageChange, size: "s" }))),
|
|
488
|
-
|
|
489
|
-
resolvedShowUsageInfo && (React.createElement("div", { className: "designbase-figma-footer__usage-info" }, isActive ? (React.createElement("span", { className: "designbase-figma-footer__unlimited-usage designbase-figma-footer__unlimited-usage--tooltip", title: t('unlimitedUsageTooltip') }, t('unlimitedUsage'))) : (React.createElement(
|
|
490
|
-
React.createElement("span", { className: "designbase-figma-footer__usage-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
showDonation && (React.createElement("div", { className: "designbase-figma-footer__donation" },
|
|
499
|
-
React.createElement(DonationBadge, { donationUrl: donationUrl, text: donationText, iconType: "heart", size: "s", showPrompt: showDonationText && !isActive, promptText: donationPromptText, t: t })))),
|
|
524
|
+
React.createElement("div", { className: "designbase-figma-footer__right" },
|
|
525
|
+
showPaymentStatus && resolvedShowUsageInfo && (React.createElement("div", { className: "designbase-figma-footer__usage-info" }, isActive ? (React.createElement("span", { className: "designbase-figma-footer__unlimited-usage designbase-figma-footer__unlimited-usage--tooltip", title: t('unlimitedUsageTooltip') }, t('unlimitedUsage'))) : (React.createElement("span", { className: "designbase-figma-footer__usage-info designbase-figma-footer__usage-info--tooltip", title: t('resetsDaily') },
|
|
526
|
+
React.createElement("span", { className: "designbase-figma-footer__usage-count" }, usageCount),
|
|
527
|
+
React.createElement("span", { className: "designbase-figma-footer__max-daily-usage" },
|
|
528
|
+
"/",
|
|
529
|
+
maxDailyUsage,
|
|
530
|
+
" ",
|
|
531
|
+
t('perDay')))))),
|
|
532
|
+
showPaymentStatus && resolvedShowPaymentBadge && (React.createElement(PaymentBadge, { isActive: isActive, onClick: isBeta ? undefined : onLicensePageClick, isLoading: isLoading, text: isBeta ? (t('betaStatus') || 'BETA') : undefined, t: t })),
|
|
533
|
+
showDonation && (React.createElement(DonationBadge, { donationUrl: donationUrl, text: donationText, iconType: "heart", size: "s", iconOnly: true, showPrompt: false, t: t })))),
|
|
500
534
|
children));
|
|
501
535
|
};
|
|
502
536
|
FigmaFooter.displayName = 'FigmaFooter';
|
|
503
537
|
|
|
538
|
+
const FigmaToastStack = ({ toasts, position, maxToasts, onRemoveToast, }) => {
|
|
539
|
+
const visibleToasts = [...toasts]
|
|
540
|
+
.sort((a, b) => b.createdAt - a.createdAt)
|
|
541
|
+
.slice(0, maxToasts);
|
|
542
|
+
if (visibleToasts.length === 0)
|
|
543
|
+
return null;
|
|
544
|
+
return (React.createElement("div", { className: `figma-toast-container figma-toast-container--${position}` }, visibleToasts.map((toast) => (React.createElement("div", { key: toast.id, className: "figma-toast-container__item" },
|
|
545
|
+
React.createElement(Toast, { toastId: toast.id, title: toast.title, description: toast.description, status: toast.status, duration: toast.duration, showProgress: toast.showProgress, showClose: toast.showCloseButton, onClose: () => onRemoveToast(toast.id) }))))));
|
|
546
|
+
};
|
|
504
547
|
const ToastContext = createContext(null);
|
|
505
548
|
const useToast = () => {
|
|
506
549
|
const context = useContext(ToastContext);
|
|
@@ -518,13 +561,13 @@ const FigmaToastProvider = ({ children, position = 'top-right', maxToasts = 5, }
|
|
|
518
561
|
id,
|
|
519
562
|
createdAt: Date.now(),
|
|
520
563
|
};
|
|
521
|
-
setToasts(prev => {
|
|
564
|
+
setToasts((prev) => {
|
|
522
565
|
const updated = [newToast, ...prev];
|
|
523
566
|
return updated.slice(0, maxToasts);
|
|
524
567
|
});
|
|
525
568
|
}, [maxToasts]);
|
|
526
569
|
const removeToast = useCallback((id) => {
|
|
527
|
-
setToasts(prev => prev.filter(toast => toast.id !== id));
|
|
570
|
+
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
|
528
571
|
}, []);
|
|
529
572
|
const showToast = useCallback((message, options = {}) => {
|
|
530
573
|
addToast({
|
|
@@ -543,17 +586,17 @@ const FigmaToastProvider = ({ children, position = 'top-right', maxToasts = 5, }
|
|
|
543
586
|
};
|
|
544
587
|
return (React.createElement(ToastContext.Provider, { value: contextValue },
|
|
545
588
|
children,
|
|
546
|
-
React.createElement(
|
|
589
|
+
React.createElement(FigmaToastStack, { toasts: toasts, onRemoveToast: removeToast, position: position, maxToasts: maxToasts })));
|
|
547
590
|
};
|
|
548
591
|
const FigmaToast = ({ message, isVisible, onClose, type = 'info', duration = 3000, className, }) => {
|
|
549
592
|
if (!isVisible)
|
|
550
593
|
return null;
|
|
551
594
|
return (React.createElement("div", { className: `figma-toast-fixed-wrap ${className || ''}` },
|
|
552
|
-
React.createElement(Toast, {
|
|
595
|
+
React.createElement(Toast, { toastId: "figma-toast-simple", title: message, status: type, duration: duration, showProgress: false, showClose: true, onClose: onClose })));
|
|
553
596
|
};
|
|
554
597
|
const useFigmaToast = () => {
|
|
555
598
|
const [toast, setToast] = useState({ message: '', isVisible: false });
|
|
556
|
-
const showToast = useCallback((message,
|
|
599
|
+
const showToast = useCallback((message, _type = 'info') => {
|
|
557
600
|
setToast({ message, isVisible: true });
|
|
558
601
|
setTimeout(() => setToast({ message: '', isVisible: false }), 5000);
|
|
559
602
|
}, []);
|
|
@@ -584,7 +627,12 @@ const FormWithSubmit = ({ onLicenseSubmit, disabled = false, isSubmitting = fals
|
|
|
584
627
|
return (React.createElement("form", { className: `designbase-figma-form-with-submit ${className || ''}`, onSubmit: handleSubmit },
|
|
585
628
|
React.createElement("div", { className: "designbase-figma-form-with-submit__field" },
|
|
586
629
|
React.createElement("label", { className: "designbase-figma-form-with-submit__label" }, displayLabel),
|
|
587
|
-
React.createElement(Input, { value: inputValue, onChange:
|
|
630
|
+
React.createElement(Input, { value: inputValue, onChange: (event) => {
|
|
631
|
+
const value = event.detail?.value;
|
|
632
|
+
if (value !== undefined) {
|
|
633
|
+
handleChange(value);
|
|
634
|
+
}
|
|
635
|
+
}, placeholder: displayPlaceholder, helperText: displayHelperText, disabled: disabled || isSubmitting, size: "m" })),
|
|
588
636
|
React.createElement(Button, { type: "submit", variant: "primary", size: "m", loading: isSubmitting, disabled: !inputValue.trim() || isSubmitting || disabled, fullWidth: true }, isSubmitting ? displaySubmittingText : displaySubmitText)));
|
|
589
637
|
};
|
|
590
638
|
FormWithSubmit.displayName = 'FormWithSubmit';
|
|
@@ -637,18 +685,17 @@ const PricingComparison = ({ features = defaultFeatures, pricing = defaultPricin
|
|
|
637
685
|
};
|
|
638
686
|
return (React.createElement("div", { className: `designbase-figma-pricing-comparison ${className || ''}` },
|
|
639
687
|
paymentType === 'subscription' && (React.createElement("div", { className: "designbase-figma-pricing-comparison__billing-toggle" },
|
|
640
|
-
React.createElement(SegmentControl, { value: isYearly ? 'yearly' : 'monthly', onChange: (
|
|
688
|
+
React.createElement(SegmentControl, { value: isYearly ? 'yearly' : 'monthly', onChange: (event) => {
|
|
689
|
+
const value = event.detail?.value;
|
|
690
|
+
setIsYearly(value === 'yearly');
|
|
691
|
+
}, options: [
|
|
641
692
|
{
|
|
642
693
|
value: 'monthly',
|
|
643
694
|
label: t('monthlyBilling') || '월간 결제',
|
|
644
695
|
},
|
|
645
696
|
{
|
|
646
697
|
value: 'yearly',
|
|
647
|
-
label: (
|
|
648
|
-
t('yearlyBilling') || '연간 결제',
|
|
649
|
-
React.createElement("span", { className: "designbase-figma-pricing-comparison__discount-badge" },
|
|
650
|
-
getDiscountPercentage(),
|
|
651
|
-
"% \uC808\uC57D"))),
|
|
698
|
+
label: `${t('yearlyBilling') || '연간 결제'} (${getDiscountPercentage()}% 절약)`,
|
|
652
699
|
},
|
|
653
700
|
], size: "s" }))),
|
|
654
701
|
paymentType === 'lifetime' && (React.createElement("div", { className: "designbase-figma-pricing-comparison__lifetime-info" },
|
|
@@ -676,123 +723,306 @@ const PricingComparison = ({ features = defaultFeatures, pricing = defaultPricin
|
|
|
676
723
|
};
|
|
677
724
|
PricingComparison.displayName = 'PricingComparison';
|
|
678
725
|
|
|
679
|
-
|
|
680
|
-
|
|
726
|
+
function postPluginMessage(message) {
|
|
727
|
+
if (typeof parent === 'undefined') {
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
parent.postMessage({ pluginMessage: message }, '*');
|
|
731
|
+
}
|
|
732
|
+
function openExternalUrl(url) {
|
|
733
|
+
if (!url)
|
|
734
|
+
return;
|
|
735
|
+
postPluginMessage({ type: 'open-external-url', url });
|
|
736
|
+
if (typeof window !== 'undefined') {
|
|
737
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const DEFAULT_LICENSE_MESSAGE_TYPES = {
|
|
742
|
+
initialize: 'initialize',
|
|
743
|
+
verifyLicense: 'verify-license',
|
|
744
|
+
deactivateLicense: 'deactivate-license',
|
|
745
|
+
updateStatus: 'update-plugin-status',
|
|
746
|
+
verifyResult: 'license-verification-result',
|
|
747
|
+
deactivateResult: 'license-deactivation-result',
|
|
748
|
+
};
|
|
749
|
+
const START_DESIGNBASE_AUTH_MESSAGE = 'start-designbase-auth';
|
|
750
|
+
const INITIAL_LICENSE_PAGE_STATE = {
|
|
751
|
+
paymentStatus: 'FREE',
|
|
752
|
+
licenseKey: '',
|
|
753
|
+
planTier: 'FREE',
|
|
754
|
+
hasLicenseKey: false,
|
|
755
|
+
isLicenseRegistered: false,
|
|
756
|
+
activationLimit: 0,
|
|
757
|
+
activationUsage: 0,
|
|
758
|
+
usageCount: 0,
|
|
759
|
+
remainingUsage: 0,
|
|
760
|
+
usageUsed: 0,
|
|
761
|
+
usageLimit: 0,
|
|
762
|
+
usageReset: 'none',
|
|
763
|
+
canUseFeature: true,
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
function readString(data, keys) {
|
|
767
|
+
for (const key of keys) {
|
|
768
|
+
const value = data[key];
|
|
769
|
+
if (typeof value === 'string') {
|
|
770
|
+
return value;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return '';
|
|
774
|
+
}
|
|
775
|
+
function readNumber(data, keys) {
|
|
776
|
+
for (const key of keys) {
|
|
777
|
+
const value = data[key];
|
|
778
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
779
|
+
return value;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
return undefined;
|
|
783
|
+
}
|
|
784
|
+
function readBoolean(data, keys) {
|
|
785
|
+
for (const key of keys) {
|
|
786
|
+
const value = data[key];
|
|
787
|
+
if (typeof value === 'boolean') {
|
|
788
|
+
return value;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
return undefined;
|
|
792
|
+
}
|
|
793
|
+
function parseLicenseMessage(data) {
|
|
794
|
+
const paymentStatus = readString(data, ['paymentStatus', 'status']);
|
|
795
|
+
const usageLimitRaw = data.usageLimit;
|
|
796
|
+
return {
|
|
797
|
+
...(paymentStatus ? { paymentStatus } : {}),
|
|
798
|
+
licenseKey: readString(data, ['licenseKey']) || undefined,
|
|
799
|
+
planTier: readString(data, ['planTier']) || undefined,
|
|
800
|
+
hasLicenseKey: readBoolean(data, ['hasLicenseKey']),
|
|
801
|
+
isLicenseRegistered: readBoolean(data, ['isLicenseRegistered']),
|
|
802
|
+
activationLimit: readNumber(data, ['activationLimit']),
|
|
803
|
+
activationUsage: readNumber(data, ['activationUsage']),
|
|
804
|
+
usageCount: readNumber(data, ['usageCount']),
|
|
805
|
+
remainingUsage: readNumber(data, ['remainingUsage']),
|
|
806
|
+
usageUsed: readNumber(data, ['usageUsed']),
|
|
807
|
+
usageLimit: usageLimitRaw === 'unlimited' ? 'unlimited' : readNumber(data, ['usageLimit']),
|
|
808
|
+
usageReset: readString(data, ['usageReset']) || undefined,
|
|
809
|
+
canUseFeature: readBoolean(data, ['canUseFeature']),
|
|
810
|
+
usageReason: readString(data, ['usageReason']) || undefined,
|
|
811
|
+
lastMessage: readString(data, ['message']) || undefined,
|
|
812
|
+
lastErrorCode: readString(data, ['errorCode']) || undefined,
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
function useFigmaLicenseBridge(options = {}) {
|
|
816
|
+
const messageTypes = useMemo(() => ({ ...DEFAULT_LICENSE_MESSAGE_TYPES, ...options.messageTypes }), [options.messageTypes]);
|
|
817
|
+
const [state, setState] = useState({
|
|
818
|
+
...INITIAL_LICENSE_PAGE_STATE,
|
|
819
|
+
...options.initialState,
|
|
820
|
+
});
|
|
821
|
+
const [isVerifying, setIsVerifying] = useState(false);
|
|
681
822
|
const [isDeactivating, setIsDeactivating] = useState(false);
|
|
682
|
-
const [
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
|
|
823
|
+
const [isStartingAuth, setIsStartingAuth] = useState(false);
|
|
824
|
+
const optionsRef = useRef(options);
|
|
825
|
+
optionsRef.current = options;
|
|
826
|
+
const applyPatch = useCallback((patch) => {
|
|
827
|
+
setState((prev) => {
|
|
828
|
+
const next = {
|
|
829
|
+
...prev,
|
|
830
|
+
...Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined)),
|
|
831
|
+
};
|
|
832
|
+
optionsRef.current.onStateChange?.(next);
|
|
833
|
+
if (patch.paymentStatus) {
|
|
834
|
+
optionsRef.current.onPaymentStatusChange?.(patch.paymentStatus);
|
|
835
|
+
}
|
|
836
|
+
if (patch.usageCount !== undefined) {
|
|
837
|
+
optionsRef.current.onUsageCountChange?.(patch.usageCount);
|
|
838
|
+
}
|
|
839
|
+
return next;
|
|
840
|
+
});
|
|
841
|
+
}, []);
|
|
688
842
|
useEffect(() => {
|
|
689
843
|
const handleMessage = (event) => {
|
|
690
|
-
const
|
|
691
|
-
if (
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
setActivationLimit(activationLimit);
|
|
698
|
-
if (activationUsage !== undefined)
|
|
699
|
-
setActivationUsage(activationUsage);
|
|
700
|
-
if (paymentStatus)
|
|
701
|
-
setPaymentStatus(paymentStatus);
|
|
702
|
-
if (usageCount !== undefined) {
|
|
703
|
-
setLocalUsageCount(usageCount);
|
|
704
|
-
setUsageCount(usageCount);
|
|
705
|
-
}
|
|
844
|
+
const data = event.data?.pluginMessage;
|
|
845
|
+
if (!data || typeof data !== 'object')
|
|
846
|
+
return;
|
|
847
|
+
const payload = data;
|
|
848
|
+
const type = typeof payload.type === 'string' ? payload.type : '';
|
|
849
|
+
if (type === messageTypes.updateStatus) {
|
|
850
|
+
applyPatch(parseLicenseMessage(payload));
|
|
706
851
|
}
|
|
707
|
-
if (type ===
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
if (success) {
|
|
712
|
-
|
|
713
|
-
setPaymentStatus('PAID');
|
|
852
|
+
if (type === messageTypes.verifyResult) {
|
|
853
|
+
setIsVerifying(false);
|
|
854
|
+
setIsStartingAuth(false);
|
|
855
|
+
applyPatch(parseLicenseMessage(payload));
|
|
856
|
+
if (payload.success === true) {
|
|
857
|
+
applyPatch({ paymentStatus: 'PAID', isLicenseRegistered: true });
|
|
714
858
|
}
|
|
715
859
|
}
|
|
716
|
-
if (type ===
|
|
860
|
+
if (type === messageTypes.deactivateResult) {
|
|
717
861
|
setIsDeactivating(false);
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
862
|
+
applyPatch(parseLicenseMessage(payload));
|
|
863
|
+
if (payload.success === true) {
|
|
864
|
+
applyPatch({
|
|
865
|
+
paymentStatus: 'UNPAID',
|
|
866
|
+
licenseKey: '',
|
|
867
|
+
hasLicenseKey: false,
|
|
868
|
+
isLicenseRegistered: false,
|
|
869
|
+
activationLimit: 0,
|
|
870
|
+
activationUsage: 0,
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (type === 'designbase-auth-result') {
|
|
875
|
+
setIsStartingAuth(false);
|
|
876
|
+
if (payload.success === true) {
|
|
877
|
+
applyPatch(parseLicenseMessage(payload));
|
|
878
|
+
}
|
|
879
|
+
else if (typeof payload.message === 'string') {
|
|
880
|
+
applyPatch({ lastMessage: payload.message });
|
|
727
881
|
}
|
|
728
882
|
}
|
|
729
883
|
};
|
|
730
884
|
window.addEventListener('message', handleMessage);
|
|
731
|
-
|
|
732
|
-
parent.postMessage({ pluginMessage: { type: 'initialize' } }, '*');
|
|
733
|
-
}
|
|
885
|
+
postPluginMessage({ type: messageTypes.initialize });
|
|
734
886
|
return () => window.removeEventListener('message', handleMessage);
|
|
735
|
-
}, [
|
|
887
|
+
}, [applyPatch, messageTypes]);
|
|
888
|
+
const verifyLicense = useCallback((licenseKey) => {
|
|
889
|
+
setIsVerifying(true);
|
|
890
|
+
postPluginMessage({
|
|
891
|
+
type: messageTypes.verifyLicense,
|
|
892
|
+
licenseKey,
|
|
893
|
+
});
|
|
894
|
+
}, [messageTypes.verifyLicense]);
|
|
895
|
+
const deactivateLicense = useCallback(() => {
|
|
896
|
+
setIsDeactivating(true);
|
|
897
|
+
postPluginMessage({ type: messageTypes.deactivateLicense });
|
|
898
|
+
}, [messageTypes.deactivateLicense]);
|
|
899
|
+
const startDesignbaseAuth = useCallback(() => {
|
|
900
|
+
setIsStartingAuth(true);
|
|
901
|
+
postPluginMessage({ type: START_DESIGNBASE_AUTH_MESSAGE });
|
|
902
|
+
}, []);
|
|
903
|
+
return {
|
|
904
|
+
state,
|
|
905
|
+
isVerifying,
|
|
906
|
+
isDeactivating,
|
|
907
|
+
isStartingAuth,
|
|
908
|
+
verifyLicense,
|
|
909
|
+
deactivateLicense,
|
|
910
|
+
startDesignbaseAuth,
|
|
911
|
+
setLicenseKeyInput: (licenseKey) => applyPatch({ licenseKey }),
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function formatUsageLabel(state, t) {
|
|
916
|
+
const { remainingUsage, usageUsed, usageLimit, usageReset } = state;
|
|
917
|
+
if (usageLimit === 'unlimited') {
|
|
918
|
+
return resolveText(t, { key: 'license.usage_unlimited' }, '사용 횟수 제한 없음');
|
|
919
|
+
}
|
|
920
|
+
const limit = typeof usageLimit === 'number' ? usageLimit : remainingUsage + usageUsed;
|
|
921
|
+
const remaining = remainingUsage ?? Math.max(0, limit - usageUsed);
|
|
922
|
+
if (usageReset === 'daily') {
|
|
923
|
+
const fallback = `오늘 남은 횟수 ${remaining}/${limit}`;
|
|
924
|
+
const translated = resolveText(t, { key: 'license.usage_daily' }, fallback);
|
|
925
|
+
return translated.includes(String(remaining)) ? translated : fallback;
|
|
926
|
+
}
|
|
927
|
+
if (usageReset === 'monthly') {
|
|
928
|
+
const fallback = `이번 달 남은 횟수 ${remaining}/${limit}`;
|
|
929
|
+
const translated = resolveText(t, { key: 'license.usage_monthly' }, fallback);
|
|
930
|
+
return translated.includes(String(remaining)) ? translated : fallback;
|
|
931
|
+
}
|
|
932
|
+
return `남은 횟수 ${remaining}/${limit}`;
|
|
933
|
+
}
|
|
934
|
+
const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicenseKey = '', wordpressLinks, paymentPageUrl, enableAccountAuth = true, showLicenseKeyInput = true, pricingFeatures, pricing, paymentType = 'subscription', messageTypes, onStateChange, setPaymentStatus, setUsageCount, onLicenseSubmit, usageCount: initialUsageCount = 0, t, className, }) => {
|
|
935
|
+
const links = useMemo(() => ({
|
|
936
|
+
purchaseUrl: wordpressLinks?.purchaseUrl ?? paymentPageUrl,
|
|
937
|
+
accountUrl: wordpressLinks?.accountUrl,
|
|
938
|
+
helpUrl: wordpressLinks?.helpUrl,
|
|
939
|
+
}), [wordpressLinks, paymentPageUrl]);
|
|
940
|
+
const { state, isVerifying, isDeactivating, isStartingAuth, verifyLicense, deactivateLicense, startDesignbaseAuth, setLicenseKeyInput, } = useFigmaLicenseBridge({
|
|
941
|
+
messageTypes,
|
|
942
|
+
initialState: {
|
|
943
|
+
paymentStatus: initialStatus,
|
|
944
|
+
licenseKey: initialLicenseKey,
|
|
945
|
+
usageCount: initialUsageCount,
|
|
946
|
+
},
|
|
947
|
+
onStateChange,
|
|
948
|
+
onPaymentStatusChange: setPaymentStatus,
|
|
949
|
+
onUsageCountChange: setUsageCount,
|
|
950
|
+
});
|
|
951
|
+
const [showDetails, setShowDetails] = useState(false);
|
|
952
|
+
const [licenseKeyDraft, setLicenseKeyDraft] = useState(initialLicenseKey);
|
|
953
|
+
const isPaid = state.isLicenseRegistered || state.paymentStatus === 'PAID';
|
|
954
|
+
const usageLabel = formatUsageLabel(state, t);
|
|
736
955
|
const handleLicenseSubmit = async (submittedLicenseKey) => {
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
pluginMessage: {
|
|
741
|
-
type: 'verify-license',
|
|
742
|
-
licenseKey: submittedLicenseKey
|
|
743
|
-
}
|
|
744
|
-
}, '*');
|
|
956
|
+
if (onLicenseSubmit) {
|
|
957
|
+
await onLicenseSubmit(submittedLicenseKey);
|
|
958
|
+
return;
|
|
745
959
|
}
|
|
960
|
+
verifyLicense(submittedLicenseKey);
|
|
746
961
|
};
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
parent.postMessage({
|
|
751
|
-
pluginMessage: { type: 'deactivate-license' }
|
|
752
|
-
}, '*');
|
|
753
|
-
}
|
|
962
|
+
const handleLicenseKeyChange = (value) => {
|
|
963
|
+
setLicenseKeyDraft(value);
|
|
964
|
+
setLicenseKeyInput(value);
|
|
754
965
|
};
|
|
755
|
-
const isPaid = status === 'PAID';
|
|
756
966
|
return (React.createElement("div", { className: `designbase-figma-page-license ${className || ''}` },
|
|
757
967
|
React.createElement("div", { className: "designbase-figma-page-license__content" },
|
|
758
968
|
React.createElement("div", { className: "designbase-figma-page-license__header" },
|
|
759
969
|
React.createElement("div", { className: "designbase-figma-page-license__title" },
|
|
760
|
-
React.createElement("h2", null, isPaid
|
|
970
|
+
React.createElement("h2", null, isPaid
|
|
971
|
+
? resolveText(t, { key: 'license.pro_account' }, '프로 계정')
|
|
972
|
+
: resolveText(t, { key: 'license.upgrade_to_pro' }, '프로로 업그레이드')),
|
|
973
|
+
state.planTier && state.planTier !== 'FREE' && (React.createElement("span", { className: "designbase-figma-page-license__tier" }, state.planTier))),
|
|
761
974
|
React.createElement("p", { className: "designbase-figma-page-license__description" }, isPaid
|
|
762
975
|
? resolveText(t, { key: 'license.all_features_available' }, '모든 기능을 사용할 수 있습니다.')
|
|
763
|
-
: resolveText(t, { key: 'license.purchase_for_unlimited' }, '
|
|
976
|
+
: resolveText(t, { key: 'license.purchase_for_unlimited' }, '디자인베이스 멤버십 또는 라이선스로 무제한 이용이 가능합니다.')),
|
|
977
|
+
!isPaid && (React.createElement("p", { className: "designbase-figma-page-license__usage" }, usageLabel))),
|
|
764
978
|
React.createElement(PricingComparison, { features: pricingFeatures, pricing: pricing, paymentType: paymentType, t: t }),
|
|
979
|
+
state.lastMessage && (React.createElement("p", { className: `designbase-figma-page-license__feedback ${state.lastErrorCode ? 'designbase-figma-page-license__feedback--error' : ''}` }, state.lastMessage)),
|
|
765
980
|
isPaid && (React.createElement("div", { className: "designbase-figma-page-license__section" },
|
|
766
981
|
React.createElement("div", { className: "designbase-figma-page-license__section-header" },
|
|
767
982
|
React.createElement("h3", null, resolveText(t, { key: 'license.activated' }, '라이선스 활성화됨')),
|
|
768
983
|
React.createElement(Button, { onClick: () => setShowDetails(!showDetails), variant: "tertiary", size: "s", iconOnly: true },
|
|
769
984
|
React.createElement(MoreHorizontalIcon, { size: 16 }))),
|
|
770
|
-
React.createElement("div", { className: "designbase-figma-page-license__license-key" },
|
|
985
|
+
state.licenseKey && (React.createElement("div", { className: "designbase-figma-page-license__license-key" },
|
|
771
986
|
resolveText(t, { key: 'license.key_label' }, '라이선스 키'),
|
|
772
987
|
": ",
|
|
773
|
-
React.createElement("span", null, licenseKey)),
|
|
988
|
+
React.createElement("span", null, state.licenseKey))),
|
|
989
|
+
React.createElement("p", { className: "designbase-figma-page-license__usage" }, usageLabel),
|
|
774
990
|
showDetails && (React.createElement("div", { className: "designbase-figma-page-license__details" },
|
|
775
991
|
React.createElement("div", { className: "designbase-figma-page-license__activation-info" },
|
|
776
992
|
React.createElement("div", { className: "designbase-figma-page-license__remaining" },
|
|
777
|
-
activationLimit - activationUsage,
|
|
778
|
-
|
|
993
|
+
Math.max(0, state.activationLimit - state.activationUsage),
|
|
994
|
+
' ',
|
|
779
995
|
resolveText(t, { key: 'license.activations_remaining' }, '활성'),
|
|
780
|
-
|
|
996
|
+
' ',
|
|
781
997
|
resolveText(t, { key: 'license.spots_remaining' }, '자리 남음')),
|
|
782
|
-
React.createElement("div", { className: "designbase-figma-page-license__usage" },
|
|
783
|
-
activationUsage,
|
|
998
|
+
React.createElement("div", { className: "designbase-figma-page-license__usage-count" },
|
|
999
|
+
state.activationUsage,
|
|
784
1000
|
"/",
|
|
785
|
-
activationLimit)),
|
|
786
|
-
React.createElement(Button, { onClick:
|
|
787
|
-
? resolveText(t, { key: 'license.deactivating' }, '
|
|
1001
|
+
state.activationLimit)),
|
|
1002
|
+
React.createElement(Button, { onClick: deactivateLicense, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating
|
|
1003
|
+
? resolveText(t, { key: 'license.deactivating' }, '비활성화 중...')
|
|
788
1004
|
: resolveText(t, { key: 'license.deactivate' }, '라이선스 비활성화')))))),
|
|
789
|
-
!isPaid && (React.createElement(
|
|
790
|
-
React.createElement("div", { className: "designbase-figma-page-license__section
|
|
791
|
-
React.createElement("
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
1005
|
+
!isPaid && (React.createElement(React.Fragment, null,
|
|
1006
|
+
(enableAccountAuth || links.purchaseUrl || links.accountUrl) && (React.createElement("div", { className: "designbase-figma-page-license__section" },
|
|
1007
|
+
React.createElement("div", { className: "designbase-figma-page-license__section-header" },
|
|
1008
|
+
React.createElement("h3", null, resolveText(t, { key: 'license.designbase_account' }, '디자인베이스 계정'))),
|
|
1009
|
+
React.createElement("p", { className: "designbase-figma-page-license__hint" }, resolveText(t, { key: 'license.designbase_account_hint' }, 'WordPress 계정으로 로그인하거나 멤버십을 구매하면 플러그인이 자동으로 활성화됩니다.')),
|
|
1010
|
+
React.createElement("div", { className: "designbase-figma-page-license__actions" },
|
|
1011
|
+
enableAccountAuth && (React.createElement(Button, { onClick: startDesignbaseAuth, variant: "primary", size: "m", disabled: isStartingAuth || isVerifying, fullWidth: true }, isStartingAuth
|
|
1012
|
+
? resolveText(t, { key: 'license.authenticating' }, '인증 중...')
|
|
1013
|
+
: resolveText(t, { key: 'license.login_with_designbase' }, '디자인베이스로 로그인'))),
|
|
1014
|
+
links.purchaseUrl && (React.createElement(Button, { onClick: () => openExternalUrl(links.purchaseUrl), variant: "secondary", size: "m", fullWidth: true },
|
|
1015
|
+
React.createElement("span", null, resolveText(t, { key: 'license.purchase_membership' }, '멤버십 구매')),
|
|
1016
|
+
React.createElement(ExternalLinkIcon, { size: 16 }))),
|
|
1017
|
+
links.accountUrl && (React.createElement(Button, { onClick: () => openExternalUrl(links.accountUrl), variant: "tertiary", size: "s", fullWidth: true },
|
|
1018
|
+
React.createElement("span", null, resolveText(t, { key: 'license.manage_account' }, '계정·멤버십 관리')),
|
|
1019
|
+
React.createElement(ExternalLinkIcon, { size: 16 })))))),
|
|
1020
|
+
showLicenseKeyInput && (React.createElement("div", { className: "designbase-figma-page-license__section" },
|
|
1021
|
+
React.createElement("div", { className: "designbase-figma-page-license__section-header" },
|
|
1022
|
+
React.createElement("h3", null, resolveText(t, { key: 'license.enter_key' }, '라이선스 키 입력'))),
|
|
1023
|
+
React.createElement(FormWithSubmit, { onLicenseSubmit: handleLicenseSubmit, disabled: false, isSubmitting: isVerifying, value: licenseKeyDraft, onValueChange: handleLicenseKeyChange, label: { key: 'license.key' }, submitText: { key: 'license.submit' }, submittingText: { key: 'license.verifying' }, helperText: { key: 'license.enter_from_email' }, t: t }))))),
|
|
1024
|
+
links.helpUrl && (React.createElement("p", { className: "designbase-figma-page-license__disclaimer" },
|
|
1025
|
+
React.createElement("button", { type: "button", className: "designbase-figma-page-license__link", onClick: () => openExternalUrl(links.helpUrl) }, resolveText(t, { key: 'license.help_link' }, '라이선스·결제 도움말'))))),
|
|
796
1026
|
React.createElement(Button, { className: "designbase-figma-page-license__close", onPress: onClose, variant: "tertiary", size: "s", "aria-label": "Close" },
|
|
797
1027
|
React.createElement(CloseIcon, { size: 20 }))));
|
|
798
1028
|
};
|
|
@@ -1066,11 +1296,11 @@ const UpgradeBanner = ({ onClick, variant = 'button', isLoading = false, title =
|
|
|
1066
1296
|
React.createElement("div", { className: "designbase-figma-upgrade-banner__text-wrap" },
|
|
1067
1297
|
React.createElement("h3", { className: "designbase-figma-upgrade-banner__title" }, displayTitle),
|
|
1068
1298
|
React.createElement("p", { className: "designbase-figma-upgrade-banner__text" }, displayDescription)),
|
|
1069
|
-
variant === 'button' ? (React.createElement(Button, {
|
|
1299
|
+
variant === 'button' ? (React.createElement(Button, { onPress: onClick, variant: "primary", size: "m", disabled: isLoading }, displayButtonText)) : (React.createElement("div", { className: "designbase-figma-upgrade-banner__icon" },
|
|
1070
1300
|
React.createElement(ChevronRightIcon, { size: 20 })))));
|
|
1071
1301
|
return (React.createElement("div", { className: `designbase-figma-upgrade-banner designbase-figma-upgrade-banner--${variant} ${className || ''}` }, useGradient ? (React.createElement(RandomGradient, { scheme: gradientScheme, tone: gradientTone, animated: gradientAnimated, height: "100%", width: "100%", className: "designbase-figma-upgrade-banner__gradient-bg" }, bannerContent)) : (bannerContent)));
|
|
1072
1302
|
};
|
|
1073
1303
|
UpgradeBanner.displayName = 'UpgradeBanner';
|
|
1074
1304
|
|
|
1075
|
-
export { DonationBadge, FigmaContainer, FigmaFooter, FigmaHeader, FigmaPageHead, FigmaSection, FigmaSidebar, FigmaToast, FigmaToastProvider, FormWithSubmit, InteractionFeedback, LanguageSelector, LogoDropdown, PageLicense, PaymentBadge, PaymentStatusSection, PricingComparison, ProgressModal, ResizablePlugin, SettingsModal, TitleDescription, UpgradeBanner, getActiveSection, resolveText, scrollToSection, useFigmaToast, useToast };
|
|
1305
|
+
export { DEFAULT_LICENSE_MESSAGE_TYPES, DonationBadge, FigmaContainer, FigmaFooter, FigmaHeader, FigmaPageHead, FigmaSection, FigmaSidebar, FigmaToast, FigmaToastProvider, FormWithSubmit, InteractionFeedback, LanguageSelector, LogoDropdown, PageLicense, PaymentBadge, PaymentStatusSection, PricingComparison, ProgressModal, ResizablePlugin, START_DESIGNBASE_AUTH_MESSAGE, SettingsModal, TitleDescription, UpgradeBanner, getActiveSection, resolveText, scrollToSection, useFigmaLicenseBridge, useFigmaToast, useToast };
|
|
1076
1306
|
//# sourceMappingURL=index.esm.js.map
|