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