@designbasekorea/figma-ui 0.6.3 → 0.6.6

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.esm.js CHANGED
@@ -1,7 +1,8 @@
1
- import React, { useRef, useState, useLayoutEffect, useEffect, createContext, useContext, useCallback } from 'react';
2
- import { HeartFilledIcon, CoffeeFilledIcon, ChevronLeftIcon, MoreHorizontalIcon, ChevronDownIcon, AppWindowIcon, YoutubeIcon, InstagramIcon, FigmaIcon, MailIcon, ExternalLinkIcon, CloseIcon, CircleCheckFilledIcon, ResizableIcon, GripVerticalIcon, ChevronRightIcon } from '@designbasekorea/icons';
3
- import { Button, Dropdown, Badge, Toggle, Spinner, SegmentControl, Logo, ToastContainer, Toast, Input, Modal, Progressbar, RandomGradient } from '@designbasekorea/ui';
4
- export * from '@designbasekorea/ui';
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
+ export { Accordion, ActivityHeatmap, AdBanner, AiChat, AiChatList, Alert, AnimationBackground, AnimationText, AppBadge, AudioPlayer, Avatar, Backdrop, Badge, Banner, BottomNavigation, BottomSheet, Breadcrumbs, Button, Calendar, Card, Carousel, ChatComposer, ChatList, ChatMessage, ChatOrb, ChatRoom, ChatSuggestions, ChatTyping, ChatWelcome, ChatWidget, Checkbox, Chip, CodeBlock, ColorPicker, ColorSwatch, Confirm, Container, ContextMenu, CookieBanner, Countdown, CursorFollower, DatePicker, Divider, DownloadProgress, Drawer, Dropdown, Dropzone, EmailVerify, EmptyState, FileUploader, FloatingActionButton, Footer, Form, Gantt, Gradient, Grid, GridBackground, GridItem, Image, ImageList, ImagePlaceholder, Indicator, Input, Kanban, Label, Lightbox, List, Logo, MarkdownEditor, Marquee, Masonry, MenuItem, Modal, ModalBody, ModalFooter, ModalHeader, Navbar, OnboardingModal, OtpInput, PageHeader, Pagination, PhoneVerify, Popover, Progress, ProgressStep, Progressbar, Radio, RandomGradient, RangeSlider, Rating, Reorder, ResizablePanels, ScrollArea, SearchBar, Section, SectionAppDownload, SectionContact, SectionCta, SectionFaq, SectionFeature, SectionFeatureGrid, SectionHero, SectionLogoCloud, SectionPricing, SectionStats, SectionTestimonials, SegmentControl, Select, Share, Sidebar, Signature, Skeleton, Spinner, SplitView, Stack, Stat, Stepper, Table, Tabs, Testimonial, Textarea, TimePicker, Timeline, Toast, Toggle, Toolbar, Tooltip, TopBanner, Tutorial, TwoFactor, VideoPlayer, YouTubePlayer, useContextMenu } from '@designbasekorea/ui-wc/react';
5
+ import { ChevronDownIcon, AppWindowIcon, YoutubeIcon, InstagramIcon, FigmaIcon, MailIcon, ExternalLinkIcon, MoreHorizontalIcon, CloseIcon, CircleCheckFilledIcon, ResizableIcon, GripVerticalIcon, ChevronRightIcon } from '@designbasekorea/icons';
5
6
 
6
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}
7
8
 
@@ -11,10 +12,20 @@ function resolveText(t, input, fallback) {
11
12
  if (typeof input === 'string') {
12
13
  return input;
13
14
  }
14
- 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;
15
22
  }
16
23
 
17
- 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 }) => {
18
29
  const handleClick = () => {
19
30
  if (onClick) {
20
31
  onClick();
@@ -23,15 +34,12 @@ const DonationBadge = ({ donationUrl = 'https://buymeacoffee.com/designbase', te
23
34
  window.open(donationUrl, '_blank', 'noopener,noreferrer');
24
35
  }
25
36
  };
26
- const Icon = iconType === 'heart' ? HeartFilledIcon : CoffeeFilledIcon;
27
37
  const displayText = resolveText(t, text, 'Buy me a coffee');
28
38
  const displayPromptText = resolveText(t, promptText, '도움이 되었다면 커피 한 잔 사주세요!');
29
39
  const buttonSize = size;
30
40
  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: Icon, className: clsx('designbase-figma-donation-badge', `designbase-figma-donation-badge--${iconType}`), "aria-label": displayText, style: {
33
- '--designbase-figma-donation-badge-icon-color': 'var(--db-brand-primary)'
34
- } }, displayText)));
41
+ showPrompt && !iconOnly && (React.createElement("div", { className: "designbase-figma-donation-badge__prompt" }, displayPromptText)),
42
+ 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
43
  };
36
44
  DonationBadge.displayName = 'DonationBadge';
37
45
 
@@ -69,10 +77,11 @@ const FigmaHeader = ({ children, actions = [], searchBar, sticky = true, classNa
69
77
  'designbase-figma-header--with-search': !!searchBar,
70
78
  'designbase-figma-header--with-actions': actions.length > 0,
71
79
  }, className);
80
+ const hasToolbar = !!children || actions.length > 0;
72
81
  return (React.createElement("header", { className: classes },
73
- React.createElement("div", { className: "designbase-figma-header__container" },
82
+ hasToolbar && (React.createElement("div", { className: "designbase-figma-header__container" },
74
83
  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, 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(Button, { key: `${action.startIcon}-${index}`, variant: "tertiary", size: "s", iconOnly: true, startIcon: action.startIcon, "aria-label": action.ariaLabel, onPress: action.onPress }))))))),
76
85
  searchBar && (React.createElement("div", { className: "designbase-figma-header__search-container" }, searchBar))));
77
86
  };
78
87
  FigmaHeader.displayName = 'FigmaHeader';
@@ -81,22 +90,24 @@ const FigmaPageHead = ({ onBack, title, description, actions = [], moreActions =
81
90
  const classes = clsx('designbase-figma-page-head', className);
82
91
  const displayTitle = resolveText(t, title);
83
92
  const displayDescription = description ? resolveText(t, description) : undefined;
84
- const dropdownItems = moreActions.map(action => ({
93
+ const dropdownItems = moreActions.map((action) => ({
85
94
  id: action.id,
86
95
  label: resolveText(t, action.label),
87
- onClick: action.onClick
88
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
+ };
89
102
  return (React.createElement("div", { className: classes },
90
103
  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 })),
104
+ React.createElement(Button, { variant: "tertiary", size: "s", iconOnly: true, startIcon: "chevron-left", onPress: onBack, "aria-label": "\uB4A4\uB85C\uAC00\uAE30" }),
93
105
  React.createElement("div", { className: "designbase-figma-page-head__titles" },
94
106
  React.createElement("h2", null, displayTitle),
95
107
  displayDescription && React.createElement("p", null, displayDescription))),
96
108
  React.createElement("div", { className: "designbase-figma-page-head__actions" },
97
109
  actions.map((action, index) => (React.createElement(React.Fragment, { key: index }, action))),
98
- moreActions.length > 0 && (React.createElement(Dropdown, { trigger: React.createElement("button", { type: "button", className: "designbase-figma-page-head__more-button", "aria-label": "\uB354\uBCF4\uAE30" },
99
- React.createElement(MoreHorizontalIcon, { size: 16 })), items: dropdownItems, placement: "bottom-right", size: "s" })))));
110
+ moreActions.length > 0 && (React.createElement(Dropdown, { items: dropdownItems, triggerIcon: "more-horizontal", iconOnly: true, triggerVariant: "tertiary", placement: "bottom-right", size: "s", onChange: handleDropdownChange })))));
100
111
  };
101
112
  FigmaPageHead.displayName = 'FigmaPageHead';
102
113
 
@@ -413,10 +424,19 @@ const LanguageSelector = ({ currentLanguage, languages = DEFAULT_LANGUAGES, onLa
413
424
  const segmentOptions = languages.map((language) => ({
414
425
  value: language.code,
415
426
  label: resolveText(t, language.label),
416
- disabled: false
427
+ disabled: false,
417
428
  }));
418
429
  return (React.createElement("div", { className: `designbase-figma-language-selector ${className || ''}` },
419
- React.createElement(SegmentControl, { options: segmentOptions, value: activeLanguage, onChange: handleLanguageChange, size: size, className: "designbase-figma-language-selector__segment" })));
430
+ React.createElement(SegmentControl, { options: segmentOptions, value: activeLanguage, onChange: (event) => {
431
+ const detail = event.detail;
432
+ const value = typeof detail === 'object' && detail !== null && 'value' in detail &&
433
+ typeof detail.value === 'string'
434
+ ? detail.value
435
+ : undefined;
436
+ if (value) {
437
+ handleLanguageChange(value);
438
+ }
439
+ }, size: size, className: "designbase-figma-language-selector__segment" })));
420
440
  };
421
441
  LanguageSelector.displayName = 'LanguageSelector';
422
442
 
@@ -506,22 +526,29 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
506
526
  React.createElement("div", { className: "designbase-figma-footer__left" },
507
527
  React.createElement(LogoDropdown, { logoSrc: logoSrc, logoAlt: logoAlt, logoType: logoType, logoSize: logoSize, links: logoLinks, t: t }),
508
528
  showLanguageSelector && (React.createElement(LanguageSelector, { currentLanguage: currentLanguage, languages: languages, onLanguageChange: onLanguageChange, size: "s" }))),
509
- showPaymentStatus && (React.createElement("div", { className: "designbase-figma-footer__payment-states" },
510
- 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,
511
- React.createElement("span", { className: "designbase-figma-footer__usage-info designbase-figma-footer__usage-info--tooltip", title: t('resetsDaily') },
512
- React.createElement("span", { className: "designbase-figma-footer__usage-count" }, usageCount),
513
- React.createElement("span", { className: "designbase-figma-footer__max-daily-usage" },
514
- "/",
515
- maxDailyUsage,
516
- " ",
517
- t('perDay'))))))),
518
- resolvedShowPaymentBadge && (React.createElement(PaymentBadge, { isActive: isActive, onClick: isBeta ? undefined : onLicensePageClick, isLoading: isLoading, text: isBeta ? (t('betaStatus') || 'BETA') : undefined, t: t })))),
519
- showDonation && (React.createElement("div", { className: "designbase-figma-footer__donation" },
520
- React.createElement(DonationBadge, { donationUrl: donationUrl, text: donationText, iconType: "heart", size: "s", showPrompt: showDonationText && !isActive, promptText: donationPromptText, t: t })))),
529
+ React.createElement("div", { className: "designbase-figma-footer__right" },
530
+ 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') },
531
+ React.createElement("span", { className: "designbase-figma-footer__usage-count" }, usageCount),
532
+ React.createElement("span", { className: "designbase-figma-footer__max-daily-usage" },
533
+ "/",
534
+ maxDailyUsage,
535
+ " ",
536
+ t('perDay')))))),
537
+ showPaymentStatus && resolvedShowPaymentBadge && (React.createElement(PaymentBadge, { isActive: isActive, onClick: isBeta ? undefined : onLicensePageClick, isLoading: isLoading, text: isBeta ? (t('betaStatus') || 'BETA') : undefined, t: t })),
538
+ showDonation && (React.createElement(DonationBadge, { donationUrl: donationUrl, text: donationText, iconType: "heart", size: "s", iconOnly: true, showPrompt: false, t: t })))),
521
539
  children));
522
540
  };
523
541
  FigmaFooter.displayName = 'FigmaFooter';
524
542
 
543
+ const FigmaToastStack = ({ toasts, position, maxToasts, onRemoveToast, }) => {
544
+ const visibleToasts = [...toasts]
545
+ .sort((a, b) => b.createdAt - a.createdAt)
546
+ .slice(0, maxToasts);
547
+ if (visibleToasts.length === 0)
548
+ return null;
549
+ 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" },
550
+ 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) }))))));
551
+ };
525
552
  const ToastContext = createContext(null);
526
553
  const useToast = () => {
527
554
  const context = useContext(ToastContext);
@@ -539,13 +566,13 @@ const FigmaToastProvider = ({ children, position = 'top-right', maxToasts = 5, }
539
566
  id,
540
567
  createdAt: Date.now(),
541
568
  };
542
- setToasts(prev => {
569
+ setToasts((prev) => {
543
570
  const updated = [newToast, ...prev];
544
571
  return updated.slice(0, maxToasts);
545
572
  });
546
573
  }, [maxToasts]);
547
574
  const removeToast = useCallback((id) => {
548
- setToasts(prev => prev.filter(toast => toast.id !== id));
575
+ setToasts((prev) => prev.filter((toast) => toast.id !== id));
549
576
  }, []);
550
577
  const showToast = useCallback((message, options = {}) => {
551
578
  addToast({
@@ -564,17 +591,17 @@ const FigmaToastProvider = ({ children, position = 'top-right', maxToasts = 5, }
564
591
  };
565
592
  return (React.createElement(ToastContext.Provider, { value: contextValue },
566
593
  children,
567
- React.createElement(ToastContainer, { toasts: toasts, onRemoveToast: removeToast, position: position, maxToasts: maxToasts })));
594
+ React.createElement(FigmaToastStack, { toasts: toasts, onRemoveToast: removeToast, position: position, maxToasts: maxToasts })));
568
595
  };
569
596
  const FigmaToast = ({ message, isVisible, onClose, type = 'info', duration = 3000, className, }) => {
570
597
  if (!isVisible)
571
598
  return null;
572
599
  return (React.createElement("div", { className: `figma-toast-fixed-wrap ${className || ''}` },
573
- React.createElement(Toast, { id: "figma-toast-simple", title: message, status: type, duration: duration, showProgress: false, showCloseButton: true, onClose: onClose, position: "top-right" })));
600
+ React.createElement(Toast, { toastId: "figma-toast-simple", title: message, status: type, duration: duration, showProgress: false, showClose: true, onClose: onClose })));
574
601
  };
575
602
  const useFigmaToast = () => {
576
603
  const [toast, setToast] = useState({ message: '', isVisible: false });
577
- const showToast = useCallback((message, type = 'info') => {
604
+ const showToast = useCallback((message, _type = 'info') => {
578
605
  setToast({ message, isVisible: true });
579
606
  setTimeout(() => setToast({ message: '', isVisible: false }), 5000);
580
607
  }, []);
@@ -605,7 +632,12 @@ const FormWithSubmit = ({ onLicenseSubmit, disabled = false, isSubmitting = fals
605
632
  return (React.createElement("form", { className: `designbase-figma-form-with-submit ${className || ''}`, onSubmit: handleSubmit },
606
633
  React.createElement("div", { className: "designbase-figma-form-with-submit__field" },
607
634
  React.createElement("label", { className: "designbase-figma-form-with-submit__label" }, displayLabel),
608
- React.createElement(Input, { value: inputValue, onChange: handleChange, placeholder: displayPlaceholder, helperText: displayHelperText, disabled: disabled || isSubmitting, size: "m" })),
635
+ React.createElement(Input, { value: inputValue, onChange: (event) => {
636
+ const value = event.detail?.value;
637
+ if (value !== undefined) {
638
+ handleChange(value);
639
+ }
640
+ }, placeholder: displayPlaceholder, helperText: displayHelperText, disabled: disabled || isSubmitting, size: "m" })),
609
641
  React.createElement(Button, { type: "submit", variant: "primary", size: "m", loading: isSubmitting, disabled: !inputValue.trim() || isSubmitting || disabled, fullWidth: true }, isSubmitting ? displaySubmittingText : displaySubmitText)));
610
642
  };
611
643
  FormWithSubmit.displayName = 'FormWithSubmit';
@@ -626,6 +658,88 @@ const InteractionFeedback = ({ status = 'default', message, statusMessage, leftC
626
658
  };
627
659
  InteractionFeedback.displayName = 'InteractionFeedback';
628
660
 
661
+ function postPluginMessage(message) {
662
+ if (typeof parent === 'undefined') {
663
+ return;
664
+ }
665
+ parent.postMessage({ pluginMessage: message }, '*');
666
+ }
667
+ function openExternalUrl(url) {
668
+ if (!url)
669
+ return;
670
+ postPluginMessage({ type: 'open-external-url', url });
671
+ if (typeof window !== 'undefined') {
672
+ window.open(url, '_blank', 'noopener,noreferrer');
673
+ }
674
+ }
675
+
676
+ const LicenseOffer = ({ membershipUrl, t, className }) => (React.createElement("section", { className: `designbase-figma-license-offer ${className || ''}`, "aria-labelledby": "designbase-license-offer-title" },
677
+ React.createElement("div", { className: "designbase-figma-license-offer__eyebrow" }, "YouTube Membership"),
678
+ React.createElement("h3", { id: "designbase-license-offer-title" }, resolveText(t, { key: 'license.youtube_membership_title' }, 'YouTube 멤버십으로 전체 플러그인 이용')),
679
+ React.createElement("p", null, resolveText(t, { key: 'license.youtube_membership_description' }, 'YouTube 멤버십에 가입하면 Designbase 플러그인을 무제한으로 사용할 수 있습니다.')),
680
+ React.createElement("ol", null,
681
+ React.createElement("li", null, "Designbase YouTube \uCC44\uB110\uC758 \uBA64\uBC84\uC2ED\uC5D0 \uAC00\uC785\uD569\uB2C8\uB2E4."),
682
+ React.createElement("li", null, "\uBA64\uBC84 \uC804\uC6A9 \uCEE4\uBBA4\uB2C8\uD2F0 \uAC8C\uC2DC\uAE00\uC5D0\uC11C \uC774\uBC88 \uB2EC \uB77C\uC774\uC120\uC2A4 \uD0A4\uB97C \uD655\uC778\uD569\uB2C8\uB2E4."),
683
+ React.createElement("li", null, "\uC544\uB798 \uC785\uB825\uCC3D\uC5D0 \uD0A4\uB97C \uBD99\uC5EC \uB123\uACE0 \uD65C\uC131\uD654\uD569\uB2C8\uB2E4.")),
684
+ membershipUrl && (React.createElement(Button, { onPress: () => openExternalUrl(membershipUrl), variant: "secondary", size: "m", fullWidth: true },
685
+ React.createElement("span", null, resolveText(t, { key: 'license.youtube_membership_cta' }, '멤버십 안내 보기')),
686
+ React.createElement(ExternalLinkIcon, { size: 16 })))));
687
+ LicenseOffer.displayName = 'LicenseOffer';
688
+
689
+ function maskLicenseKey(value) {
690
+ if (value.length <= 8)
691
+ return '••••••••';
692
+ return `${value.slice(0, 4)}••••${value.slice(-4)}`;
693
+ }
694
+ function formatDate(value) {
695
+ if (!value)
696
+ return undefined;
697
+ const date = new Date(value);
698
+ if (Number.isNaN(date.getTime()))
699
+ return value;
700
+ return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(date);
701
+ }
702
+ function formatScope(value) {
703
+ if (!value)
704
+ return undefined;
705
+ if (value === 'all-products' || value === 'all_products')
706
+ return '전체 제품';
707
+ return value;
708
+ }
709
+ const LicenseStatusCard = ({ status, licenseKey = '', licenseStatus, licenseSource, accessScope, expiresAt, lastVerifiedAt, validationMessage, allowRevealKey = true, t, className, }) => {
710
+ const [isKeyRevealed, setIsKeyRevealed] = useState(false);
711
+ const isActive = status === 'PAID';
712
+ const statusText = isActive
713
+ ? resolveText(t, { key: 'license.status_active' }, 'Active')
714
+ : resolveText(t, { key: 'license.status_inactive' }, 'License check failed');
715
+ const statusClass = isActive ? 'active' : 'inactive';
716
+ return (React.createElement("section", { className: `designbase-figma-license-status-card designbase-figma-license-status-card--${statusClass} ${className || ''}`, "aria-label": statusText },
717
+ React.createElement("div", { className: "designbase-figma-license-status-card__header" },
718
+ React.createElement("div", null,
719
+ React.createElement("div", { className: "designbase-figma-license-status-card__eyebrow" }, isActive ? 'License Activated' : 'License Status'),
720
+ React.createElement("h3", null, statusText)),
721
+ React.createElement("span", { className: "designbase-figma-license-status-card__badge" }, licenseStatus || (isActive ? 'active' : 'inactive'))),
722
+ validationMessage && !isActive && (React.createElement("p", { className: "designbase-figma-license-status-card__message" }, validationMessage)),
723
+ licenseKey && (React.createElement("div", { className: "designbase-figma-license-status-card__key-row" },
724
+ React.createElement("span", null, resolveText(t, { key: 'license.key_label' }, '라이선스 키')),
725
+ React.createElement("code", null, allowRevealKey && isKeyRevealed ? licenseKey : maskLicenseKey(licenseKey)),
726
+ allowRevealKey && (React.createElement(Button, { type: "button", onPress: () => setIsKeyRevealed((value) => !value), variant: "tertiary", size: "s" }, isKeyRevealed ? '숨기기' : '보기')))),
727
+ (licenseSource || accessScope || expiresAt || lastVerifiedAt) && (React.createElement("dl", { className: "designbase-figma-license-status-card__meta" },
728
+ licenseSource && React.createElement(React.Fragment, null,
729
+ React.createElement("dt", null, "Source"),
730
+ React.createElement("dd", null, licenseSource)),
731
+ formatScope(accessScope) && React.createElement(React.Fragment, null,
732
+ React.createElement("dt", null, "Access"),
733
+ React.createElement("dd", null, formatScope(accessScope))),
734
+ expiresAt && React.createElement(React.Fragment, null,
735
+ React.createElement("dt", null, "Expires"),
736
+ React.createElement("dd", null, formatDate(expiresAt) || expiresAt)),
737
+ lastVerifiedAt && React.createElement(React.Fragment, null,
738
+ React.createElement("dt", null, "Last checked"),
739
+ React.createElement("dd", null, formatDate(lastVerifiedAt) || lastVerifiedAt))))));
740
+ };
741
+ LicenseStatusCard.displayName = 'LicenseStatusCard';
742
+
629
743
  const defaultFeatures = [
630
744
  { name: '사용 제한', free: '일일 제한', pro: '무제한' },
631
745
  { name: '모든 주제 사용', free: false, pro: true },
@@ -658,18 +772,21 @@ const PricingComparison = ({ features = defaultFeatures, pricing = defaultPricin
658
772
  };
659
773
  return (React.createElement("div", { className: `designbase-figma-pricing-comparison ${className || ''}` },
660
774
  paymentType === 'subscription' && (React.createElement("div", { className: "designbase-figma-pricing-comparison__billing-toggle" },
661
- React.createElement(SegmentControl, { value: isYearly ? 'yearly' : 'monthly', onChange: (value) => setIsYearly(value === 'yearly'), options: [
775
+ React.createElement(SegmentControl, { value: isYearly ? 'yearly' : 'monthly', onChange: (event) => {
776
+ const detail = event.detail;
777
+ const value = typeof detail === 'object' && detail !== null && 'value' in detail &&
778
+ typeof detail.value === 'string'
779
+ ? detail.value
780
+ : undefined;
781
+ setIsYearly(value === 'yearly');
782
+ }, options: [
662
783
  {
663
784
  value: 'monthly',
664
785
  label: t('monthlyBilling') || '월간 결제',
665
786
  },
666
787
  {
667
788
  value: 'yearly',
668
- label: (React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
669
- t('yearlyBilling') || '연간 결제',
670
- React.createElement("span", { className: "designbase-figma-pricing-comparison__discount-badge" },
671
- getDiscountPercentage(),
672
- "% \uC808\uC57D"))),
789
+ label: `${t('yearlyBilling') || '연간 결제'} (${getDiscountPercentage()}% 절약)`,
673
790
  },
674
791
  ], size: "s" }))),
675
792
  paymentType === 'lifetime' && (React.createElement("div", { className: "designbase-figma-pricing-comparison__lifetime-info" },
@@ -697,123 +814,301 @@ const PricingComparison = ({ features = defaultFeatures, pricing = defaultPricin
697
814
  };
698
815
  PricingComparison.displayName = 'PricingComparison';
699
816
 
700
- const PageLicense = ({ status: initialStatus, onClose, usageCount: initialUsageCount = 0, onLicenseSubmit, licenseKey: initialLicenseKey = '', setPaymentStatus, setUsageCount, setShowLicensePage, paymentPageUrl, pricingFeatures, pricing, paymentType = 'subscription', t, className, }) => {
701
- const [isSubmitting, setIsSubmitting] = useState(false);
817
+ const DEFAULT_LICENSE_MESSAGE_TYPES = {
818
+ initialize: 'initialize',
819
+ verifyLicense: 'verify-license',
820
+ deactivateLicense: 'deactivate-license',
821
+ updateStatus: 'update-plugin-status',
822
+ verifyResult: 'license-verification-result',
823
+ deactivateResult: 'license-deactivation-result',
824
+ };
825
+ const START_DESIGNBASE_AUTH_MESSAGE = 'start-designbase-auth';
826
+ const INITIAL_LICENSE_PAGE_STATE = {
827
+ paymentStatus: 'FREE',
828
+ licenseKey: '',
829
+ planTier: 'FREE',
830
+ hasLicenseKey: false,
831
+ isLicenseRegistered: false,
832
+ activationLimit: 0,
833
+ activationUsage: 0,
834
+ usageCount: 0,
835
+ remainingUsage: 0,
836
+ usageUsed: 0,
837
+ usageLimit: 0,
838
+ usageReset: 'none',
839
+ canUseFeature: true,
840
+ };
841
+
842
+ function readString(data, keys) {
843
+ for (const key of keys) {
844
+ const value = data[key];
845
+ if (typeof value === 'string') {
846
+ return value;
847
+ }
848
+ }
849
+ return '';
850
+ }
851
+ function readNumber(data, keys) {
852
+ for (const key of keys) {
853
+ const value = data[key];
854
+ if (typeof value === 'number' && Number.isFinite(value)) {
855
+ return value;
856
+ }
857
+ }
858
+ return undefined;
859
+ }
860
+ function readBoolean(data, keys) {
861
+ for (const key of keys) {
862
+ const value = data[key];
863
+ if (typeof value === 'boolean') {
864
+ return value;
865
+ }
866
+ }
867
+ return undefined;
868
+ }
869
+ function parseLicenseMessage(data) {
870
+ const paymentStatus = readString(data, ['paymentStatus', 'status']);
871
+ const usageLimitRaw = data.usageLimit;
872
+ return {
873
+ ...(paymentStatus ? { paymentStatus } : {}),
874
+ licenseKey: readString(data, ['licenseKey']) || undefined,
875
+ planTier: readString(data, ['planTier']) || undefined,
876
+ hasLicenseKey: readBoolean(data, ['hasLicenseKey']),
877
+ isLicenseRegistered: readBoolean(data, ['isLicenseRegistered']),
878
+ activationLimit: readNumber(data, ['activationLimit']),
879
+ activationUsage: readNumber(data, ['activationUsage']),
880
+ usageCount: readNumber(data, ['usageCount']),
881
+ remainingUsage: readNumber(data, ['remainingUsage']),
882
+ usageUsed: readNumber(data, ['usageUsed']),
883
+ usageLimit: usageLimitRaw === 'unlimited' ? 'unlimited' : readNumber(data, ['usageLimit']),
884
+ usageReset: readString(data, ['usageReset']) || undefined,
885
+ canUseFeature: readBoolean(data, ['canUseFeature']),
886
+ usageReason: readString(data, ['usageReason']) || undefined,
887
+ lastMessage: readString(data, ['message']) || undefined,
888
+ lastErrorCode: readString(data, ['errorCode']) || undefined,
889
+ licenseStatus: readString(data, ['licenseStatus', 'license_status']) || undefined,
890
+ licenseSource: readString(data, ['licenseSource', 'license_source', 'source']) || undefined,
891
+ accessScope: readString(data, ['accessScope', 'access_scope', 'scope']) || undefined,
892
+ expiresAt: readString(data, ['expiresAt', 'expires_at']) || undefined,
893
+ lastVerifiedAt: readString(data, ['lastVerifiedAt', 'last_verified_at']) || undefined,
894
+ validationMessage: readString(data, ['validationMessage', 'validation_message']) || undefined,
895
+ };
896
+ }
897
+ function useFigmaLicenseBridge(options = {}) {
898
+ const messageTypes = useMemo(() => ({ ...DEFAULT_LICENSE_MESSAGE_TYPES, ...options.messageTypes }), [options.messageTypes]);
899
+ const [state, setState] = useState({
900
+ ...INITIAL_LICENSE_PAGE_STATE,
901
+ ...options.initialState,
902
+ });
903
+ const [isVerifying, setIsVerifying] = useState(false);
702
904
  const [isDeactivating, setIsDeactivating] = useState(false);
703
- const [licenseKey, setLicenseKey] = useState(initialLicenseKey);
704
- const [status, setStatus] = useState(initialStatus);
705
- const [usageCount, setLocalUsageCount] = useState(initialUsageCount);
706
- const [activationLimit, setActivationLimit] = useState(0);
707
- const [activationUsage, setActivationUsage] = useState(0);
708
- const [showDetails, setShowDetails] = useState(false);
905
+ const [isStartingAuth, setIsStartingAuth] = useState(false);
906
+ const optionsRef = useRef(options);
907
+ optionsRef.current = options;
908
+ const applyPatch = useCallback((patch) => {
909
+ setState((prev) => {
910
+ const next = {
911
+ ...prev,
912
+ ...Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined)),
913
+ };
914
+ optionsRef.current.onStateChange?.(next);
915
+ if (patch.paymentStatus) {
916
+ optionsRef.current.onPaymentStatusChange?.(patch.paymentStatus);
917
+ }
918
+ if (patch.usageCount !== undefined) {
919
+ optionsRef.current.onUsageCountChange?.(patch.usageCount);
920
+ }
921
+ return next;
922
+ });
923
+ }, []);
709
924
  useEffect(() => {
710
925
  const handleMessage = (event) => {
711
- const { type, paymentStatus, licenseKey, activationLimit, activationUsage, success, message, usageCount } = event.data.pluginMessage || {};
712
- if (type === 'update-plugin-status' || type === 'license-verification-result') {
713
- if (paymentStatus)
714
- setStatus(paymentStatus);
715
- if (licenseKey)
716
- setLicenseKey(licenseKey);
717
- if (activationLimit !== undefined)
718
- setActivationLimit(activationLimit);
719
- if (activationUsage !== undefined)
720
- setActivationUsage(activationUsage);
721
- if (paymentStatus)
722
- setPaymentStatus(paymentStatus);
723
- if (usageCount !== undefined) {
724
- setLocalUsageCount(usageCount);
725
- setUsageCount(usageCount);
726
- }
926
+ const data = event.data?.pluginMessage;
927
+ if (!data || typeof data !== 'object')
928
+ return;
929
+ const payload = data;
930
+ const type = typeof payload.type === 'string' ? payload.type : '';
931
+ if (type === messageTypes.updateStatus) {
932
+ applyPatch(parseLicenseMessage(payload));
727
933
  }
728
- if (type === 'license-verification-result') {
729
- setIsSubmitting(false);
730
- if (message)
731
- console.log('License verification:', message);
732
- if (success) {
733
- setStatus('PAID');
734
- setPaymentStatus('PAID');
934
+ if (type === messageTypes.verifyResult) {
935
+ setIsVerifying(false);
936
+ setIsStartingAuth(false);
937
+ applyPatch(parseLicenseMessage(payload));
938
+ if (payload.success === true) {
939
+ applyPatch({ paymentStatus: 'PAID', isLicenseRegistered: true });
735
940
  }
736
941
  }
737
- if (type === 'license-deactivation-result') {
942
+ if (type === messageTypes.deactivateResult) {
738
943
  setIsDeactivating(false);
739
- if (message)
740
- console.log('License deactivation:', message);
741
- if (success) {
742
- setStatus('UNPAID');
743
- setPaymentStatus('UNPAID');
744
- setLicenseKey('');
745
- setLocalUsageCount(20);
746
- setActivationLimit(0);
747
- setActivationUsage(0);
944
+ applyPatch(parseLicenseMessage(payload));
945
+ if (payload.success === true) {
946
+ applyPatch({
947
+ paymentStatus: 'UNPAID',
948
+ licenseKey: '',
949
+ hasLicenseKey: false,
950
+ isLicenseRegistered: false,
951
+ activationLimit: 0,
952
+ activationUsage: 0,
953
+ });
954
+ }
955
+ }
956
+ if (type === 'designbase-auth-result') {
957
+ setIsStartingAuth(false);
958
+ if (payload.success === true) {
959
+ applyPatch(parseLicenseMessage(payload));
960
+ }
961
+ else if (typeof payload.message === 'string') {
962
+ applyPatch({ lastMessage: payload.message });
748
963
  }
749
964
  }
750
965
  };
751
966
  window.addEventListener('message', handleMessage);
752
- if (typeof parent !== 'undefined') {
753
- parent.postMessage({ pluginMessage: { type: 'initialize' } }, '*');
754
- }
967
+ postPluginMessage({ type: messageTypes.initialize });
755
968
  return () => window.removeEventListener('message', handleMessage);
756
- }, [setPaymentStatus, setUsageCount]);
969
+ }, [applyPatch, messageTypes]);
970
+ const verifyLicense = useCallback((licenseKey) => {
971
+ setIsVerifying(true);
972
+ postPluginMessage({
973
+ type: messageTypes.verifyLicense,
974
+ licenseKey,
975
+ });
976
+ }, [messageTypes.verifyLicense]);
977
+ const deactivateLicense = useCallback(() => {
978
+ setIsDeactivating(true);
979
+ postPluginMessage({ type: messageTypes.deactivateLicense });
980
+ }, [messageTypes.deactivateLicense]);
981
+ const startDesignbaseAuth = useCallback(() => {
982
+ setIsStartingAuth(true);
983
+ postPluginMessage({ type: START_DESIGNBASE_AUTH_MESSAGE });
984
+ }, []);
985
+ return {
986
+ state,
987
+ isVerifying,
988
+ isDeactivating,
989
+ isStartingAuth,
990
+ verifyLicense,
991
+ deactivateLicense,
992
+ startDesignbaseAuth,
993
+ setLicenseKeyInput: (licenseKey) => applyPatch({ licenseKey }),
994
+ };
995
+ }
996
+
997
+ function formatUsageLabel(state, t) {
998
+ const { remainingUsage, usageUsed, usageLimit, usageReset } = state;
999
+ if (usageLimit === 'unlimited') {
1000
+ return resolveText(t, { key: 'license.usage_unlimited' }, '사용 횟수 제한 없음') ?? '사용 횟수 제한 없음';
1001
+ }
1002
+ const limit = typeof usageLimit === 'number' ? usageLimit : remainingUsage + usageUsed;
1003
+ const remaining = remainingUsage ?? Math.max(0, limit - usageUsed);
1004
+ if (usageReset === 'daily') {
1005
+ const fallback = `오늘 남은 횟수 ${remaining}/${limit}`;
1006
+ const translated = resolveText(t, { key: 'license.usage_daily' }, fallback) ?? fallback;
1007
+ return translated.includes(String(remaining)) ? translated : fallback;
1008
+ }
1009
+ if (usageReset === 'monthly') {
1010
+ const fallback = `이번 달 남은 횟수 ${remaining}/${limit}`;
1011
+ const translated = resolveText(t, { key: 'license.usage_monthly' }, fallback) ?? fallback;
1012
+ return translated.includes(String(remaining)) ? translated : fallback;
1013
+ }
1014
+ return `남은 횟수 ${remaining}/${limit}`;
1015
+ }
1016
+ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicenseKey = '', wordpressLinks, paymentPageUrl, mode = 'pricing', membershipUrl, enableAccountAuth = true, showLicenseKeyInput = true, pricingFeatures, pricing, paymentType = 'subscription', messageTypes, onStateChange, setPaymentStatus, setUsageCount, onLicenseSubmit, usageCount: initialUsageCount = 0, t, className, }) => {
1017
+ const links = useMemo(() => ({
1018
+ purchaseUrl: wordpressLinks?.purchaseUrl ?? paymentPageUrl,
1019
+ membershipUrl: membershipUrl ?? wordpressLinks?.membershipUrl,
1020
+ accountUrl: wordpressLinks?.accountUrl,
1021
+ helpUrl: wordpressLinks?.helpUrl,
1022
+ }), [wordpressLinks, paymentPageUrl, membershipUrl]);
1023
+ const { state, isVerifying, isDeactivating, isStartingAuth, verifyLicense, deactivateLicense, startDesignbaseAuth, setLicenseKeyInput, } = useFigmaLicenseBridge({
1024
+ messageTypes,
1025
+ initialState: {
1026
+ paymentStatus: initialStatus,
1027
+ licenseKey: initialLicenseKey,
1028
+ usageCount: initialUsageCount,
1029
+ },
1030
+ onStateChange,
1031
+ onPaymentStatusChange: setPaymentStatus,
1032
+ onUsageCountChange: setUsageCount,
1033
+ });
1034
+ const [showDetails, setShowDetails] = useState(false);
1035
+ const [licenseKeyDraft, setLicenseKeyDraft] = useState(initialLicenseKey);
1036
+ const isPaid = state.isLicenseRegistered && state.paymentStatus === 'PAID';
1037
+ const isMembershipMode = mode === 'youtube-membership';
1038
+ const usageLabel = formatUsageLabel(state, t);
757
1039
  const handleLicenseSubmit = async (submittedLicenseKey) => {
758
- setIsSubmitting(true);
759
- if (typeof parent !== 'undefined') {
760
- parent.postMessage({
761
- pluginMessage: {
762
- type: 'verify-license',
763
- licenseKey: submittedLicenseKey
764
- }
765
- }, '*');
1040
+ if (onLicenseSubmit) {
1041
+ await onLicenseSubmit(submittedLicenseKey);
1042
+ return;
766
1043
  }
1044
+ verifyLicense(submittedLicenseKey);
767
1045
  };
768
- const handleDeactivateLicense = () => {
769
- setIsDeactivating(true);
770
- if (typeof parent !== 'undefined') {
771
- parent.postMessage({
772
- pluginMessage: { type: 'deactivate-license' }
773
- }, '*');
774
- }
1046
+ const handleLicenseKeyChange = (value) => {
1047
+ setLicenseKeyDraft(value);
1048
+ setLicenseKeyInput(value);
775
1049
  };
776
- const isPaid = status === 'PAID';
777
1050
  return (React.createElement("div", { className: `designbase-figma-page-license ${className || ''}` },
778
1051
  React.createElement("div", { className: "designbase-figma-page-license__content" },
779
1052
  React.createElement("div", { className: "designbase-figma-page-license__header" },
780
1053
  React.createElement("div", { className: "designbase-figma-page-license__title" },
781
- React.createElement("h2", null, isPaid ? resolveText(t, { key: 'license.pro_account' }, '프로 계정') : resolveText(t, { key: 'license.upgrade_to_pro' }, '프로로 업그레이드'))),
1054
+ React.createElement("h2", null, isMembershipMode
1055
+ ? resolveText(t, { key: 'license.youtube_membership' }, 'YouTube 멤버십')
1056
+ : isPaid
1057
+ ? resolveText(t, { key: 'license.pro_account' }, '프로 계정')
1058
+ : resolveText(t, { key: 'license.upgrade_to_pro' }, '프로로 업그레이드')),
1059
+ state.planTier && state.planTier !== 'FREE' && (React.createElement("span", { className: "designbase-figma-page-license__tier" }, state.planTier))),
782
1060
  React.createElement("p", { className: "designbase-figma-page-license__description" }, isPaid
783
1061
  ? resolveText(t, { key: 'license.all_features_available' }, '모든 기능을 사용할 수 있습니다.')
784
- : resolveText(t, { key: 'license.purchase_for_unlimited' }, '라이선스 구매 후 무제한 접근이 가능합니다.'))),
785
- React.createElement(PricingComparison, { features: pricingFeatures, pricing: pricing, paymentType: paymentType, t: t }),
1062
+ : isMembershipMode
1063
+ ? resolveText(t, { key: 'license.youtube_membership_description' }, 'YouTube 멤버십에 가입하면 Designbase 플러그인을 무제한으로 사용할 수 있습니다.')
1064
+ : resolveText(t, { key: 'license.purchase_for_unlimited' }, '디자인베이스 멤버십 또는 라이선스로 무제한 이용이 가능합니다.')),
1065
+ !isPaid && (React.createElement("p", { className: "designbase-figma-page-license__usage" }, usageLabel))),
1066
+ !isMembershipMode && (React.createElement(PricingComparison, { features: pricingFeatures, pricing: pricing, paymentType: paymentType, t: t })),
1067
+ state.lastMessage && (React.createElement("p", { className: `designbase-figma-page-license__feedback ${state.lastErrorCode ? 'designbase-figma-page-license__feedback--error' : ''}` }, state.lastMessage)),
786
1068
  isPaid && (React.createElement("div", { className: "designbase-figma-page-license__section" },
787
1069
  React.createElement("div", { className: "designbase-figma-page-license__section-header" },
788
1070
  React.createElement("h3", null, resolveText(t, { key: 'license.activated' }, '라이선스 활성화됨')),
789
- React.createElement(Button, { onClick: () => setShowDetails(!showDetails), variant: "tertiary", size: "s", iconOnly: true },
1071
+ React.createElement(Button, { onPress: () => setShowDetails(!showDetails), variant: "tertiary", size: "s", iconOnly: true },
790
1072
  React.createElement(MoreHorizontalIcon, { size: 16 }))),
791
- React.createElement("div", { className: "designbase-figma-page-license__license-key" },
792
- resolveText(t, { key: 'license.key_label' }, '라이선스 키'),
793
- ": ",
794
- React.createElement("span", null, licenseKey)),
1073
+ React.createElement(LicenseStatusCard, { status: state.paymentStatus, licenseKey: state.licenseKey, licenseStatus: state.licenseStatus, licenseSource: state.licenseSource, accessScope: state.accessScope, expiresAt: state.expiresAt, lastVerifiedAt: state.lastVerifiedAt, validationMessage: state.validationMessage, t: t }),
1074
+ React.createElement("p", { className: "designbase-figma-page-license__usage" }, usageLabel),
795
1075
  showDetails && (React.createElement("div", { className: "designbase-figma-page-license__details" },
796
1076
  React.createElement("div", { className: "designbase-figma-page-license__activation-info" },
797
1077
  React.createElement("div", { className: "designbase-figma-page-license__remaining" },
798
- activationLimit - activationUsage,
799
- " ",
1078
+ Math.max(0, state.activationLimit - state.activationUsage),
1079
+ ' ',
800
1080
  resolveText(t, { key: 'license.activations_remaining' }, '활성'),
801
- " ",
1081
+ ' ',
802
1082
  resolveText(t, { key: 'license.spots_remaining' }, '자리 남음')),
803
- React.createElement("div", { className: "designbase-figma-page-license__usage" },
804
- activationUsage,
1083
+ React.createElement("div", { className: "designbase-figma-page-license__usage-count" },
1084
+ state.activationUsage,
805
1085
  "/",
806
- activationLimit)),
807
- React.createElement(Button, { onClick: handleDeactivateLicense, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating
808
- ? resolveText(t, { key: 'license.deactivating' }, '비활성화중...')
1086
+ state.activationLimit)),
1087
+ React.createElement(Button, { onPress: deactivateLicense, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating
1088
+ ? resolveText(t, { key: 'license.deactivating' }, '비활성화 중...')
809
1089
  : resolveText(t, { key: 'license.deactivate' }, '라이선스 비활성화')))))),
810
- !isPaid && (React.createElement("div", { className: "designbase-figma-page-license__section" },
811
- React.createElement("div", { className: "designbase-figma-page-license__section-header" },
812
- React.createElement("h3", null, resolveText(t, { key: 'license.enter_key' }, '라이선스 키 입력')),
813
- paymentPageUrl && (React.createElement(Button, { onClick: () => window.open(paymentPageUrl, '_blank'), variant: "primary", size: "s" },
814
- React.createElement("span", null, resolveText(t, { key: 'license.purchase' }, '라이선스 구매')),
815
- React.createElement(ExternalLinkIcon, { size: 16 })))),
816
- 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 })))),
1090
+ !isPaid && (React.createElement(React.Fragment, null,
1091
+ isMembershipMode && (React.createElement(LicenseOffer, { membershipUrl: links.membershipUrl || links.purchaseUrl, t: t })),
1092
+ !isMembershipMode && (enableAccountAuth || links.purchaseUrl || links.accountUrl) && (React.createElement("div", { className: "designbase-figma-page-license__section" },
1093
+ React.createElement("div", { className: "designbase-figma-page-license__section-header" },
1094
+ React.createElement("h3", null, resolveText(t, { key: 'license.designbase_account' }, '디자인베이스 계정'))),
1095
+ React.createElement("p", { className: "designbase-figma-page-license__hint" }, resolveText(t, { key: 'license.designbase_account_hint' }, 'WordPress 계정으로 로그인하거나 멤버십을 구매하면 플러그인이 자동으로 활성화됩니다.')),
1096
+ React.createElement("div", { className: "designbase-figma-page-license__actions" },
1097
+ enableAccountAuth && (React.createElement(Button, { onPress: startDesignbaseAuth, variant: "primary", size: "m", disabled: isStartingAuth || isVerifying, fullWidth: true }, isStartingAuth
1098
+ ? resolveText(t, { key: 'license.authenticating' }, '인증 중...')
1099
+ : resolveText(t, { key: 'license.login_with_designbase' }, '디자인베이스로 로그인'))),
1100
+ links.purchaseUrl && (React.createElement(Button, { onPress: () => openExternalUrl(links.purchaseUrl), variant: "secondary", size: "m", fullWidth: true },
1101
+ React.createElement("span", null, resolveText(t, { key: 'license.purchase_membership' }, '멤버십 안내')),
1102
+ React.createElement(ExternalLinkIcon, { size: 16 }))),
1103
+ links.accountUrl && (React.createElement(Button, { onPress: () => openExternalUrl(links.accountUrl), variant: "tertiary", size: "s", fullWidth: true },
1104
+ React.createElement("span", null, resolveText(t, { key: 'license.manage_account' }, '계정·멤버십 관리')),
1105
+ React.createElement(ExternalLinkIcon, { size: 16 })))))),
1106
+ showLicenseKeyInput && (React.createElement("div", { className: "designbase-figma-page-license__section" },
1107
+ React.createElement("div", { className: "designbase-figma-page-license__section-header" },
1108
+ React.createElement("h3", null, resolveText(t, { key: 'license.enter_key' }, '라이선스 키 입력'))),
1109
+ 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 }))))),
1110
+ links.helpUrl && (React.createElement("p", { className: "designbase-figma-page-license__disclaimer" },
1111
+ React.createElement("button", { type: "button", className: "designbase-figma-page-license__link", onClick: () => openExternalUrl(links.helpUrl) }, resolveText(t, { key: 'license.help_link' }, '라이선스·결제 도움말'))))),
817
1112
  React.createElement(Button, { className: "designbase-figma-page-license__close", onPress: onClose, variant: "tertiary", size: "s", "aria-label": "Close" },
818
1113
  React.createElement(CloseIcon, { size: 20 }))));
819
1114
  };
@@ -838,7 +1133,7 @@ const PaymentStatusSection = ({ status, usageCount, activationLimit, activationU
838
1133
  activationUsage,
839
1134
  "/",
840
1135
  activationLimit)),
841
- React.createElement(Button, { onClick: onDeactivate, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating
1136
+ React.createElement(Button, { onPress: onDeactivate, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating
842
1137
  ? resolveText(t, { key: 'payment.deactivating' }, '비활성화중...')
843
1138
  : resolveText(t, { key: 'payment.deactivate_license' }, '라이선스 비활성화'))))));
844
1139
  };
@@ -1087,11 +1382,11 @@ const UpgradeBanner = ({ onClick, variant = 'button', isLoading = false, title =
1087
1382
  React.createElement("div", { className: "designbase-figma-upgrade-banner__text-wrap" },
1088
1383
  React.createElement("h3", { className: "designbase-figma-upgrade-banner__title" }, displayTitle),
1089
1384
  React.createElement("p", { className: "designbase-figma-upgrade-banner__text" }, displayDescription)),
1090
- variant === 'button' ? (React.createElement(Button, { onClick: onClick, variant: "primary", size: "m", disabled: isLoading }, displayButtonText)) : (React.createElement("div", { className: "designbase-figma-upgrade-banner__icon" },
1385
+ variant === 'button' ? (React.createElement(Button, { onPress: onClick, variant: "primary", size: "m", disabled: isLoading }, displayButtonText)) : (React.createElement("div", { className: "designbase-figma-upgrade-banner__icon" },
1091
1386
  React.createElement(ChevronRightIcon, { size: 20 })))));
1092
1387
  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)));
1093
1388
  };
1094
1389
  UpgradeBanner.displayName = 'UpgradeBanner';
1095
1390
 
1096
- 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 };
1391
+ export { DEFAULT_LICENSE_MESSAGE_TYPES, DonationBadge, FigmaContainer, FigmaFooter, FigmaHeader, FigmaPageHead, FigmaSection, FigmaSidebar, FigmaToast, FigmaToastProvider, FormWithSubmit, InteractionFeedback, LanguageSelector, LicenseOffer, LicenseStatusCard, LogoDropdown, PageLicense, PaymentBadge, PaymentStatusSection, PricingComparison, ProgressModal, ResizablePlugin, START_DESIGNBASE_AUTH_MESSAGE, SettingsModal, TitleDescription, UpgradeBanner, getActiveSection, resolveText, scrollToSection, useFigmaLicenseBridge, useFigmaToast, useToast };
1097
1392
  //# sourceMappingURL=index.esm.js.map