@designbasekorea/figma-ui 0.7.0 → 0.7.2

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
@@ -52,12 +52,30 @@ const FIGMA_UI_TRANSLATIONS = {
52
52
  'form.submit': '제출',
53
53
  'form.verifying': '확인 중...',
54
54
  'license.youtube_membership': 'YouTube 멤버십',
55
+ 'license.unlock_unlimited': '무제한 사용 활성화',
56
+ 'license.unlock_unlimited_description': '라이선스 키를 등록하면 모든 Designbase 플러그인의 프로 기능과 무제한 사용을 이용할 수 있습니다.',
57
+ 'license.get_key_title': '라이선스 키 받기',
58
+ 'license.get_key_description': '멤버십 회원에게 매월 새 라이선스 키가 제공됩니다.',
59
+ 'license.get_key_step_1_title': '멤버십 가입',
60
+ 'license.get_key_step_1_description': 'Designbase YouTube 채널에서 멤버십에 가입합니다.',
61
+ 'license.get_key_step_2_title': '이번 달 키 복사',
62
+ 'license.get_key_step_2_description': '멤버 전용 커뮤니티 게시글에서 키를 확인합니다.',
63
+ 'license.get_key_step_3_title': '키 등록',
64
+ 'license.get_key_step_3_description': '아래 입력창에 붙여 넣으면 프로 기능이 열립니다.',
65
+ 'license.get_key_cta': '멤버십 가입하고 키 받기',
66
+ 'license.activate_key_title': '라이선스 키 등록',
67
+ 'license.activate_key_description': '이미 키가 있다면 아래에 붙여 넣어 프로 기능을 활성화하세요.',
68
+ 'license.unlock_pro_features': '프로 기능 활성화',
69
+ 'license.current_plan': '현재 플랜',
70
+ 'license.pro_plan': '프로 플랜',
71
+ 'license.membership': '멤버십',
55
72
  'license.pro_account': '프로 계정',
56
73
  'license.upgrade_to_pro': '프로로 업그레이드',
57
74
  'license.all_features_available': '모든 기능을 사용할 수 있습니다.',
58
75
  'license.youtube_membership_description': 'YouTube 멤버십에 가입하면 Designbase 플러그인을 무제한으로 사용할 수 있습니다.',
59
76
  'license.purchase_for_unlimited': '디자인베이스 멤버십 또는 라이선스로 무제한 이용이 가능합니다.',
60
77
  'license.usage_unlimited': '사용 횟수 제한 없음',
78
+ 'license.active_until_expiry': '만료일까지 모든 기능을 제한 없이 사용할 수 있습니다.',
61
79
  'license.usage_daily': '오늘 남은 횟수 {{remaining}}/{{limit}}',
62
80
  'license.usage_weekly': '이번 주 남은 횟수 {{remaining}}/{{limit}}',
63
81
  'license.usage_monthly': '이번 달 남은 횟수 {{remaining}}/{{limit}}',
@@ -67,6 +85,7 @@ const FIGMA_UI_TRANSLATIONS = {
67
85
  'license.spots_remaining': '자리 남음',
68
86
  'license.deactivating': '비활성화 중...',
69
87
  'license.deactivate': '라이선스 비활성화',
88
+ 'license.deactivate_hint': '이 기기에서 라이선스 연결을 해제합니다.',
70
89
  'license.designbase_account': '디자인베이스 계정',
71
90
  'license.designbase_account_hint': 'WordPress 계정으로 로그인하거나 멤버십을 구매하면 플러그인이 자동으로 활성화됩니다.',
72
91
  'license.authenticating': '인증 중...',
@@ -78,7 +97,7 @@ const FIGMA_UI_TRANSLATIONS = {
78
97
  'license.submit': '활성화',
79
98
  'license.verifying': '확인 중...',
80
99
  'license.enter_from_email': '이메일로 받은 라이선스 키를 입력하세요.',
81
- 'license.enter_from_youtube': '멤버 전용 커뮤니티에서 받은 키를 입력하세요.',
100
+ 'license.enter_from_youtube': '멤버 전용 게시글에서 복사한 이번 달 키를 입력하세요.',
82
101
  'license.help_link': '라이선스·결제 도움말',
83
102
  'license.youtube_membership_howto': '이용 방법',
84
103
  'license.youtube_membership_step_1': 'Designbase YouTube 채널 멤버십에 가입합니다.',
@@ -185,12 +204,30 @@ const FIGMA_UI_TRANSLATIONS = {
185
204
  'form.submit': 'Activate',
186
205
  'form.verifying': 'Verifying...',
187
206
  'license.youtube_membership': 'YouTube Membership',
207
+ 'license.unlock_unlimited': 'Unlock Unlimited Access',
208
+ 'license.unlock_unlimited_description': 'Add a license key to unlock Pro features and unlimited use across Designbase plugins.',
209
+ 'license.get_key_title': 'Get a license key',
210
+ 'license.get_key_description': 'Members receive a new license key every month.',
211
+ 'license.get_key_step_1_title': 'Join the membership',
212
+ 'license.get_key_step_1_description': 'Join the Designbase YouTube channel membership.',
213
+ 'license.get_key_step_2_title': 'Copy this month’s key',
214
+ 'license.get_key_step_2_description': 'Find the key in the members-only community post.',
215
+ 'license.get_key_step_3_title': 'Activate the key',
216
+ 'license.get_key_step_3_description': 'Paste it below to unlock Pro features.',
217
+ 'license.get_key_cta': 'Join and get a license key',
218
+ 'license.activate_key_title': 'Activate your license key',
219
+ 'license.activate_key_description': 'Already have a key? Paste it below to unlock Pro features.',
220
+ 'license.unlock_pro_features': 'Unlock Pro features',
221
+ 'license.current_plan': 'Current plan',
222
+ 'license.pro_plan': 'Pro plan',
223
+ 'license.membership': 'Membership',
188
224
  'license.pro_account': 'Pro account',
189
225
  'license.upgrade_to_pro': 'Upgrade to Pro',
190
226
  'license.all_features_available': 'All features are available.',
191
227
  'license.youtube_membership_description': 'Join YouTube Membership to use Designbase plugins without limits.',
192
228
  'license.purchase_for_unlimited': 'Get unlimited access with a Designbase membership or license.',
193
229
  'license.usage_unlimited': 'Unlimited usage',
230
+ 'license.active_until_expiry': 'All features remain available without limits until expiration.',
194
231
  'license.usage_daily': '{{remaining}}/{{limit}} remaining today',
195
232
  'license.usage_weekly': '{{remaining}}/{{limit}} remaining this week',
196
233
  'license.usage_monthly': '{{remaining}}/{{limit}} remaining this month',
@@ -200,6 +237,7 @@ const FIGMA_UI_TRANSLATIONS = {
200
237
  'license.spots_remaining': 'spots remaining',
201
238
  'license.deactivating': 'Deactivating...',
202
239
  'license.deactivate': 'Deactivate license',
240
+ 'license.deactivate_hint': 'Disconnects this license from the current device.',
203
241
  'license.designbase_account': 'Designbase account',
204
242
  'license.designbase_account_hint': 'Sign in with your WordPress account or purchase a membership to activate the plugin automatically.',
205
243
  'license.authenticating': 'Authenticating...',
@@ -211,7 +249,7 @@ const FIGMA_UI_TRANSLATIONS = {
211
249
  'license.submit': 'Activate',
212
250
  'license.verifying': 'Verifying...',
213
251
  'license.enter_from_email': 'Enter the license key you received by email.',
214
- 'license.enter_from_youtube': 'Enter the key from the members-only community.',
252
+ 'license.enter_from_youtube': 'Enter this month’s key copied from the members-only post.',
215
253
  'license.help_link': 'License · payment help',
216
254
  'license.youtube_membership_howto': 'How to use',
217
255
  'license.youtube_membership_step_1': 'Join the Designbase YouTube channel membership.',
@@ -318,12 +356,30 @@ const FIGMA_UI_TRANSLATIONS = {
318
356
  'form.submit': '有効化',
319
357
  'form.verifying': '確認中...',
320
358
  'license.youtube_membership': 'YouTubeメンバーシップ',
359
+ 'license.unlock_unlimited': '無制限アクセスを有効化',
360
+ 'license.unlock_unlimited_description': 'ライセンスキーを登録すると、DesignbaseプラグインのPro機能を無制限で利用できます。',
361
+ 'license.get_key_title': 'ライセンスキーを取得',
362
+ 'license.get_key_description': 'メンバーには毎月新しいライセンスキーが提供されます。',
363
+ 'license.get_key_step_1_title': 'メンバーシップに参加',
364
+ 'license.get_key_step_1_description': 'Designbase YouTubeチャンネルのメンバーシップに参加します。',
365
+ 'license.get_key_step_2_title': '今月のキーをコピー',
366
+ 'license.get_key_step_2_description': 'メンバー限定コミュニティの投稿でキーを確認します。',
367
+ 'license.get_key_step_3_title': 'キーを登録',
368
+ 'license.get_key_step_3_description': '下の入力欄に貼り付けるとPro機能が利用できます。',
369
+ 'license.get_key_cta': '参加してライセンスキーを取得',
370
+ 'license.activate_key_title': 'ライセンスキーを登録',
371
+ 'license.activate_key_description': 'キーをお持ちの場合は、下に貼り付けてPro機能を有効化してください。',
372
+ 'license.unlock_pro_features': 'Pro機能を有効化',
373
+ 'license.current_plan': '現在のプラン',
374
+ 'license.pro_plan': 'Proプラン',
375
+ 'license.membership': 'メンバーシップ',
321
376
  'license.pro_account': 'Proアカウント',
322
377
  'license.upgrade_to_pro': 'Proにアップグレード',
323
378
  'license.all_features_available': 'すべての機能を使用できます。',
324
379
  'license.youtube_membership_description': 'YouTubeメンバーシップに参加すると、Designbaseプラグインを無制限で使用できます。',
325
380
  'license.purchase_for_unlimited': 'Designbaseのメンバーシップまたはライセンスで無制限に利用できます。',
326
381
  'license.usage_unlimited': '使用回数の制限なし',
382
+ 'license.active_until_expiry': '有効期限まで、すべての機能を制限なく使用できます。',
327
383
  'license.usage_daily': '今日の残り {{remaining}}/{{limit}}回',
328
384
  'license.usage_weekly': '今週の残り {{remaining}}/{{limit}}回',
329
385
  'license.usage_monthly': '今月の残り {{remaining}}/{{limit}}回',
@@ -333,6 +389,7 @@ const FIGMA_UI_TRANSLATIONS = {
333
389
  'license.spots_remaining': '枠残り',
334
390
  'license.deactivating': '無効化中...',
335
391
  'license.deactivate': 'ライセンスを無効化',
392
+ 'license.deactivate_hint': 'このデバイスからライセンスの接続を解除します。',
336
393
  'license.designbase_account': 'Designbaseアカウント',
337
394
  'license.designbase_account_hint': 'WordPressアカウントでサインインするか、メンバーシップを購入するとプラグインが自動的に有効化されます。',
338
395
  'license.authenticating': '認証中...',
@@ -344,7 +401,7 @@ const FIGMA_UI_TRANSLATIONS = {
344
401
  'license.submit': '有効化',
345
402
  'license.verifying': '確認中...',
346
403
  'license.enter_from_email': 'メールで受け取ったライセンスキーを入力してください。',
347
- 'license.enter_from_youtube': 'メンバー限定コミュニティのキーを入力してください。',
404
+ 'license.enter_from_youtube': 'メンバー限定投稿からコピーした今月のキーを入力してください。',
348
405
  'license.help_link': 'ライセンス・支払いヘルプ',
349
406
  'license.youtube_membership_howto': '利用方法',
350
407
  'license.youtube_membership_step_1': 'Designbase YouTubeチャンネルのメンバーシップに参加します。',
@@ -981,7 +1038,7 @@ const fallbackText = (t, key, fallback) => {
981
1038
  const translated = t?.(key);
982
1039
  return translated && translated !== key ? translated : fallback;
983
1040
  };
984
- const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, maxDailyUsage = 20, showUsage = true, showPlan = true, isLoading = false, onLicensePageClick, t, locale, className, }) => {
1041
+ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, maxDailyUsage = 20, showUsage = true, showPlan = true, isLoading = false, onLicensePageClick, licenseSource, accessScope, expiresAt, lastVerifiedAt, t, locale, className, }) => {
985
1042
  const { t: translate } = useFigmaUiI18n(locale, t);
986
1043
  const [isOpen, setIsOpen] = React.useState(false);
987
1044
  const rootRef = React.useRef(null);
@@ -1004,9 +1061,12 @@ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, max
1004
1061
  : paymentStatus === 'TRIAL'
1005
1062
  ? fallbackText(translate, 'trialPlan', '체험판')
1006
1063
  : fallbackText(translate, 'free', '무료');
1007
- const planTitle = isBeta
1064
+ const planSuffix = fallbackText(translate, 'planSuffix', '플랜');
1065
+ const normalizedPlanLabel = planLabel.toLocaleLowerCase();
1066
+ const normalizedPlanSuffix = planSuffix.toLocaleLowerCase();
1067
+ const planTitle = isBeta || normalizedPlanLabel.includes(normalizedPlanSuffix)
1008
1068
  ? planLabel
1009
- : `${planLabel} ${fallbackText(translate, 'planSuffix', '플랜')}`;
1069
+ : `${planLabel} ${planSuffix}`;
1010
1070
  const triggerLabel = isPaid
1011
1071
  ? `${planLabel}, ${fallbackText(translate, 'unlimitedUsage', '무제한 사용 가능')}`
1012
1072
  : isBeta
@@ -1017,6 +1077,41 @@ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, max
1017
1077
  const upgradeLabel = isPaid
1018
1078
  ? fallbackText(translate, 'managePlan', '플랜 관리')
1019
1079
  : fallbackText(translate, 'upgradePlan', '플랜 업그레이드');
1080
+ const resolvedLocale = locale || 'ko';
1081
+ const formatDate = (value) => {
1082
+ if (!value)
1083
+ return undefined;
1084
+ const date = new Date(value);
1085
+ if (Number.isNaN(date.getTime()))
1086
+ return value;
1087
+ return new Intl.DateTimeFormat(resolvedLocale, { dateStyle: 'medium' }).format(date);
1088
+ };
1089
+ const formattedSource = licenseSource === 'youtube_membership' || licenseSource === 'membership'
1090
+ ? fallbackText(translate, 'license.source_youtube_membership', 'YouTube 멤버십')
1091
+ : licenseSource === 'lemonsqueezy'
1092
+ ? fallbackText(translate, 'license.source_purchase', '구매 라이선스')
1093
+ : licenseSource;
1094
+ const formattedScope = accessScope === 'all-products' || accessScope === 'all_products'
1095
+ ? fallbackText(translate, 'license.all_plugins', '모든 플러그인')
1096
+ : accessScope;
1097
+ const paidMetadata = [
1098
+ formattedSource && {
1099
+ label: fallbackText(translate, 'license.membership', '멤버십'),
1100
+ value: formattedSource,
1101
+ },
1102
+ expiresAt && {
1103
+ label: fallbackText(translate, 'license.expires', '만료일'),
1104
+ value: formatDate(expiresAt),
1105
+ },
1106
+ formattedScope && {
1107
+ label: fallbackText(translate, 'license.access', '접근 범위'),
1108
+ value: formattedScope,
1109
+ },
1110
+ lastVerifiedAt && {
1111
+ label: fallbackText(translate, 'license.last_checked', '최근 확인'),
1112
+ value: formatDate(lastVerifiedAt),
1113
+ },
1114
+ ].filter(Boolean);
1020
1115
  React.useEffect(() => {
1021
1116
  if (!isOpen)
1022
1117
  return undefined;
@@ -1051,7 +1146,10 @@ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, max
1051
1146
  'designbase-figma-usage-status--loading': isLoading,
1052
1147
  }, className) },
1053
1148
  React.createElement("div", { className: "designbase-figma-usage-status__control" },
1054
- showUsage && (React.createElement("button", { ref: triggerRef, type: "button", className: "designbase-figma-usage-status__trigger", "aria-expanded": isOpen, "aria-controls": popoverId, "aria-haspopup": "dialog", "aria-label": isLoading ? fallbackText(translate, 'loading', '불러오는 중') : triggerLabel, disabled: isLoading, onClick: togglePopover }, isLoading ? (React.createElement("span", { className: "designbase-figma-usage-status__skeleton", "aria-hidden": "true" })) : isPaid ? (React.createElement("span", { className: "designbase-figma-usage-status__unlimited-mark", "aria-hidden": "true" }, "\u221E")) : hasDailyLimit ? (React.createElement(React.Fragment, null,
1149
+ showUsage && (React.createElement("button", { ref: triggerRef, type: "button", className: "designbase-figma-usage-status__trigger", "aria-expanded": isOpen, "aria-controls": popoverId, "aria-haspopup": "dialog", "aria-label": isLoading ? fallbackText(translate, 'loading', '불러오는 중') : triggerLabel, disabled: isLoading, onClick: togglePopover }, isLoading ? (React.createElement("span", { className: "designbase-figma-usage-status__skeleton", "aria-hidden": "true" })) : isPaid ? (React.createElement(React.Fragment, null,
1150
+ React.createElement("span", { className: "designbase-figma-usage-status__mini-progress", "aria-hidden": "true" },
1151
+ React.createElement("span", { style: { width: '100%' } })),
1152
+ React.createElement("span", { className: "designbase-figma-usage-status__unlimited-mark", "aria-hidden": "true" }, "\u221E"))) : hasDailyLimit ? (React.createElement(React.Fragment, null,
1055
1153
  React.createElement("span", { className: "designbase-figma-usage-status__mini-progress", "aria-hidden": "true" },
1056
1154
  React.createElement("span", { style: { width: `${remainingPercent}%` } })),
1057
1155
  React.createElement("span", { className: "designbase-figma-usage-status__usage-value" },
@@ -1062,11 +1160,19 @@ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, max
1062
1160
  showPlan && !isLoading && (React.createElement("button", { type: "button", className: "designbase-figma-usage-status__plan-badge", "aria-expanded": isOpen, "aria-controls": popoverId, "aria-haspopup": "dialog", "aria-label": planTitle, onClick: togglePopover }, planLabel))),
1063
1161
  isOpen && (React.createElement("div", { id: popoverId, className: "designbase-figma-usage-status__popover", role: "dialog", "aria-label": fallbackText(translate, 'usageDetails', '사용량 상세') },
1064
1162
  React.createElement("div", { className: "designbase-figma-usage-status__popover-header" },
1065
- React.createElement("span", { className: "designbase-figma-usage-status__plan-title" }, planTitle),
1163
+ React.createElement("span", { className: "designbase-figma-usage-status__plan-heading" },
1164
+ React.createElement("span", null, fallbackText(translate, 'license.current_plan', '현재 플랜')),
1165
+ React.createElement("strong", null, planTitle)),
1066
1166
  !isBeta && (React.createElement(react.Button, { className: "designbase-figma-usage-status__upgrade", variant: isPaid ? 'secondary' : 'primary', size: "s", endIcon: "chevron-right", onPress: handleManageClick }, upgradeLabel))),
1067
- isPaid ? (React.createElement("div", { className: "designbase-figma-usage-status__unlimited-copy" },
1068
- React.createElement("span", { className: "designbase-figma-usage-status__unlimited-mark", "aria-hidden": "true" }, "\u221E"),
1069
- React.createElement("span", null, fallbackText(translate, 'unlimitedUsageTooltip', '모든 기능을 제한 없이 사용할 수 있습니다')))) : isBeta ? (React.createElement("p", { className: "designbase-figma-usage-status__note" }, fallbackText(translate, 'betaUsageDescription', '베타 기간에는 사용량 제한이 적용되지 않습니다'))) : hasDailyLimit ? (React.createElement("div", { className: "designbase-figma-usage-status__usage-detail" },
1167
+ isPaid ? (React.createElement(React.Fragment, null,
1168
+ React.createElement("div", { className: "designbase-figma-usage-status__unlimited-copy" },
1169
+ React.createElement("span", { className: "designbase-figma-usage-status__unlimited-mark", "aria-hidden": "true" }, "\u221E"),
1170
+ React.createElement("span", null,
1171
+ React.createElement("strong", null, fallbackText(translate, 'unlimitedUsage', '무제한 사용')),
1172
+ React.createElement("small", null, fallbackText(translate, 'unlimitedUsageTooltip', '모든 기능을 제한 없이 사용할 수 있습니다')))),
1173
+ paidMetadata.length > 0 && (React.createElement("dl", { className: "designbase-figma-usage-status__license-meta" }, paidMetadata.map((item) => (React.createElement("div", { key: item.label },
1174
+ React.createElement("dt", null, item.label),
1175
+ React.createElement("dd", null, item.value)))))))) : isBeta ? (React.createElement("p", { className: "designbase-figma-usage-status__note" }, fallbackText(translate, 'betaUsageDescription', '베타 기간에는 사용량 제한이 적용되지 않습니다'))) : hasDailyLimit ? (React.createElement("div", { className: "designbase-figma-usage-status__usage-detail" },
1070
1176
  React.createElement("div", { className: "designbase-figma-usage-status__usage-summary" },
1071
1177
  React.createElement("strong", { className: "designbase-figma-usage-status__usage-count" },
1072
1178
  remaining,
@@ -1168,7 +1274,7 @@ FigmaToastProvider.displayName = 'FigmaToastProvider';
1168
1274
  FigmaToast.displayName = 'FigmaToast';
1169
1275
 
1170
1276
  const DEFAULT_LOW_USAGE_WARNING = { key: 'lowUsageWarning' };
1171
- const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount = 0, remainingUsage, listenForUsageMessages = true, isLoading = false, showPaymentStatus = true, showUsageInfo = true, maxDailyUsage = 20, showLowUsageWarning = true, lowUsageThresholdPercent = 10, lowUsageWarningText = DEFAULT_LOW_USAGE_WARNING, onLowUsageWarning, showPaymentBadge = true, showDonation = true, donationUrl = 'https://buymeacoffee.com/designbase', donationText = { key: 'donation.buy_me_a_coffee' }, showDonationText = true, donationPromptText, showLanguageSelector = true, currentLanguage = 'ko', languages, onLanguageChange, logoSrc, logoAlt = 'DesignBase', logoType = 'designbase', logoSize = 'xs', logoLinks, className, t, children, }) => {
1277
+ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount = 0, remainingUsage, listenForUsageMessages = true, isLoading = false, showPaymentStatus = true, showUsageInfo = true, maxDailyUsage = 20, licenseSource, accessScope, expiresAt, lastVerifiedAt, showLowUsageWarning = true, lowUsageThresholdPercent = 10, lowUsageWarningText = DEFAULT_LOW_USAGE_WARNING, onLowUsageWarning, showPaymentBadge = true, showDonation = true, donationUrl = 'https://buymeacoffee.com/designbase', donationText = { key: 'donation.buy_me_a_coffee' }, showDonationText = true, donationPromptText, showLanguageSelector = true, currentLanguage = 'ko', languages, onLanguageChange, logoSrc, logoAlt = 'DesignBase', logoType = 'designbase', logoSize = 'xs', logoLinks, className, t, children, }) => {
1172
1278
  const { t: translate } = useFigmaUiI18n(currentLanguage, t);
1173
1279
  const { showToast, toastComponent } = useFigmaToast();
1174
1280
  const [liveUsage, setLiveUsage] = React.useState({});
@@ -1178,12 +1284,17 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
1178
1284
  const effectiveUsageCount = liveUsage.usageCount ?? usageCount;
1179
1285
  const effectiveRemainingUsage = liveUsage.remainingUsage ?? remainingUsage;
1180
1286
  const effectiveMaxDailyUsage = liveUsage.maxDailyUsage ?? maxDailyUsage;
1287
+ const effectiveLicenseSource = liveUsage.licenseSource ?? licenseSource;
1288
+ const effectiveAccessScope = liveUsage.accessScope ?? accessScope;
1289
+ const effectiveExpiresAt = liveUsage.expiresAt ?? expiresAt;
1290
+ const effectiveLastVerifiedAt = liveUsage.lastVerifiedAt ?? lastVerifiedAt;
1181
1291
  const limit = Math.max(1, Math.round(effectiveMaxDailyUsage));
1182
1292
  const resolvedRemaining = typeof effectiveRemainingUsage === 'number' && Number.isFinite(effectiveRemainingUsage)
1183
1293
  ? Math.min(limit, Math.max(0, Math.round(effectiveRemainingUsage)))
1184
1294
  : Math.max(0, limit - Math.min(limit, Math.max(0, Math.round(effectiveUsageCount))));
1185
1295
  const remainingPercent = Math.round((resolvedRemaining / limit) * 100);
1186
- const resolvedShowUsageInfo = showPaymentStatus && (showUsageInfo || effectivePaymentStatus === 'FREE');
1296
+ const resolvedShowUsageInfo = showPaymentStatus
1297
+ && (showUsageInfo || effectivePaymentStatus === 'FREE' || effectivePaymentStatus === 'PAID');
1187
1298
  const resolvedShowPaymentBadge = showPaymentStatus && showPaymentBadge;
1188
1299
  const resolvedLicensePageClick = effectivePaymentStatus === 'BETA' ? undefined : onLicensePageClick;
1189
1300
  const hasChildren = React.Children.count(children) > 0;
@@ -1209,10 +1320,31 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
1209
1320
  : message.paymentStatus === 'FREE' || message.paymentStatus === 'UNPAID'
1210
1321
  ? 'FREE'
1211
1322
  : undefined;
1323
+ const nextLicenseSource = typeof message.licenseSource === 'string' ? message.licenseSource : undefined;
1324
+ const nextAccessScope = typeof message.accessScope === 'string' ? message.accessScope : undefined;
1325
+ const nextExpiresAt = typeof message.expiresAt === 'string' ? message.expiresAt : undefined;
1326
+ const rawLastVerifiedAt = message.lastVerifiedAt;
1327
+ const numericLastVerifiedAt = typeof rawLastVerifiedAt === 'number' && Number.isFinite(rawLastVerifiedAt)
1328
+ ? rawLastVerifiedAt < 1000000000000
1329
+ ? rawLastVerifiedAt * 1000
1330
+ : rawLastVerifiedAt
1331
+ : undefined;
1332
+ const parsedLastVerifiedAt = numericLastVerifiedAt === undefined
1333
+ ? undefined
1334
+ : new Date(numericLastVerifiedAt);
1335
+ const nextLastVerifiedAt = typeof rawLastVerifiedAt === 'string'
1336
+ ? rawLastVerifiedAt
1337
+ : parsedLastVerifiedAt && !Number.isNaN(parsedLastVerifiedAt.getTime())
1338
+ ? parsedLastVerifiedAt.toISOString()
1339
+ : undefined;
1212
1340
  if (nextPaymentStatus === undefined
1213
1341
  && nextLimit === undefined
1214
1342
  && nextUsed === undefined
1215
- && nextRemaining === undefined) {
1343
+ && nextRemaining === undefined
1344
+ && nextLicenseSource === undefined
1345
+ && nextAccessScope === undefined
1346
+ && nextExpiresAt === undefined
1347
+ && nextLastVerifiedAt === undefined) {
1216
1348
  return;
1217
1349
  }
1218
1350
  setLiveUsage((previous) => ({
@@ -1221,6 +1353,10 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
1221
1353
  ...(typeof nextLimit === 'number' ? { maxDailyUsage: nextLimit } : {}),
1222
1354
  ...(typeof nextUsed === 'number' ? { usageCount: nextUsed } : {}),
1223
1355
  ...(typeof nextRemaining === 'number' ? { remainingUsage: nextRemaining } : {}),
1356
+ ...(nextLicenseSource ? { licenseSource: nextLicenseSource } : {}),
1357
+ ...(nextAccessScope ? { accessScope: nextAccessScope } : {}),
1358
+ ...(nextExpiresAt ? { expiresAt: nextExpiresAt } : {}),
1359
+ ...(nextLastVerifiedAt ? { lastVerifiedAt: nextLastVerifiedAt } : {}),
1224
1360
  }));
1225
1361
  };
1226
1362
  window.addEventListener('message', handleUsageMessage);
@@ -1279,7 +1415,7 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
1279
1415
  React.createElement("div", { className: "designbase-figma-footer__left" },
1280
1416
  React.createElement(LogoDropdown, { logoSrc: logoSrc, logoAlt: logoAlt, logoType: logoType, logoSize: logoSize, links: logoLinks, languages: languages, currentLanguage: currentLanguage, showLanguageSelector: showLanguageSelector, onLanguageChange: onLanguageChange, t: translate })),
1281
1417
  React.createElement("div", { className: "designbase-figma-footer__right" },
1282
- (resolvedShowUsageInfo || resolvedShowPaymentBadge) && (React.createElement(UsageStatusPopover, { paymentStatus: effectivePaymentStatus, usageCount: effectiveUsageCount, remainingUsage: effectiveRemainingUsage, maxDailyUsage: effectiveMaxDailyUsage, showUsage: resolvedShowUsageInfo, showPlan: resolvedShowPaymentBadge, isLoading: isLoading, onLicensePageClick: resolvedLicensePageClick, t: translate })),
1418
+ (resolvedShowUsageInfo || resolvedShowPaymentBadge) && (React.createElement(UsageStatusPopover, { paymentStatus: effectivePaymentStatus, usageCount: effectiveUsageCount, remainingUsage: effectiveRemainingUsage, maxDailyUsage: effectiveMaxDailyUsage, showUsage: resolvedShowUsageInfo, showPlan: resolvedShowPaymentBadge, isLoading: isLoading, onLicensePageClick: resolvedLicensePageClick, licenseSource: effectiveLicenseSource, accessScope: effectiveAccessScope, expiresAt: effectiveExpiresAt, lastVerifiedAt: effectiveLastVerifiedAt, locale: currentLanguage, t: translate })),
1283
1419
  showDonation && (React.createElement(DonationBadge, { donationUrl: donationUrl, text: donationText, iconType: "heart", size: "s", iconOnly: true, showPrompt: false, t: translate })))),
1284
1420
  children,
1285
1421
  toastComponent));
@@ -1292,9 +1428,15 @@ const FormWithSubmit = ({ onLicenseSubmit, disabled = false, isSubmitting = fals
1292
1428
  React.useEffect(() => {
1293
1429
  setInputValue(value);
1294
1430
  }, [value]);
1431
+ const submitLicense = async () => {
1432
+ const normalizedValue = inputValue.trim();
1433
+ if (!normalizedValue || disabled || isSubmitting)
1434
+ return;
1435
+ await onLicenseSubmit(normalizedValue);
1436
+ };
1295
1437
  const handleSubmit = async (e) => {
1296
1438
  e.preventDefault();
1297
- await onLicenseSubmit(inputValue);
1439
+ await submitLicense();
1298
1440
  };
1299
1441
  const handleChange = (value) => {
1300
1442
  setInputValue(value);
@@ -1314,7 +1456,9 @@ const FormWithSubmit = ({ onLicenseSubmit, disabled = false, isSubmitting = fals
1314
1456
  handleChange(value);
1315
1457
  }
1316
1458
  }, placeholder: displayPlaceholder, helperText: displayHelperText, disabled: disabled || isSubmitting, size: "m" })),
1317
- React.createElement(react.Button, { type: "submit", variant: "primary", size: "m", loading: isSubmitting, disabled: !inputValue.trim() || isSubmitting || disabled, fullWidth: true }, isSubmitting ? displaySubmittingText : displaySubmitText)));
1459
+ React.createElement(react.Button, { type: "button", variant: "primary", size: "m", loading: isSubmitting, disabled: !inputValue.trim() || isSubmitting || disabled, fullWidth: true, onPress: () => {
1460
+ void submitLicense();
1461
+ } }, isSubmitting ? displaySubmittingText : displaySubmitText)));
1318
1462
  };
1319
1463
  FormWithSubmit.displayName = 'FormWithSubmit';
1320
1464
 
@@ -1386,19 +1530,34 @@ const LicenseOffer = ({ joinUrl, guideUrl, membershipUrl, t, locale, className,
1386
1530
  const titleId = `designbase-license-offer-title-${React.useId().replace(/:/g, '')}`;
1387
1531
  const resolvedJoinUrl = joinUrl || membershipUrl;
1388
1532
  const steps = [
1389
- resolveText(translate, { key: 'license.youtube_membership_step_1' }, 'Designbase YouTube 채널 멤버십에 가입합니다.'),
1390
- resolveText(translate, { key: 'license.youtube_membership_step_2' }, '멤버 전용 커뮤니티에서 이번 달 키를 복사합니다.'),
1391
- resolveText(translate, { key: 'license.youtube_membership_step_3' }, '아래 입력창에 키를 붙여 넣고 활성화합니다.'),
1533
+ {
1534
+ title: resolveText(translate, { key: 'license.get_key_step_1_title' }, '멤버십 가입'),
1535
+ description: resolveText(translate, { key: 'license.get_key_step_1_description' }, 'Designbase YouTube 채널에서 멤버십에 가입합니다.'),
1536
+ },
1537
+ {
1538
+ title: resolveText(translate, { key: 'license.get_key_step_2_title' }, '이번 달 키 복사'),
1539
+ description: resolveText(translate, { key: 'license.get_key_step_2_description' }, '멤버 전용 커뮤니티 게시글에서 키를 확인합니다.'),
1540
+ },
1541
+ {
1542
+ title: resolveText(translate, { key: 'license.get_key_step_3_title' }, '키 등록'),
1543
+ description: resolveText(translate, { key: 'license.get_key_step_3_description' }, '아래 입력창에 붙여 넣으면 프로 기능이 열립니다.'),
1544
+ },
1392
1545
  ];
1393
1546
  return (React.createElement("section", { className: `designbase-figma-license-offer ${className || ''}`, "aria-labelledby": titleId },
1394
- React.createElement("h3", { id: titleId, className: "designbase-figma-license-offer__title" }, resolveText(translate, { key: 'license.youtube_membership_howto' }, '이용 방법')),
1547
+ React.createElement("header", { className: "designbase-figma-license-offer__header" },
1548
+ React.createElement("span", { className: "designbase-figma-license-offer__section-index", "aria-hidden": "true" }, "1"),
1549
+ React.createElement("div", null,
1550
+ React.createElement("h3", { id: titleId, className: "designbase-figma-license-offer__title" }, resolveText(translate, { key: 'license.get_key_title' }, '라이선스 키 받기')),
1551
+ React.createElement("p", { className: "designbase-figma-license-offer__description" }, resolveText(translate, { key: 'license.get_key_description' }, '멤버십 회원에게 매월 새 라이선스 키가 제공됩니다.')))),
1395
1552
  React.createElement("ol", { className: "designbase-figma-license-offer__steps" }, steps.map((step, index) => (React.createElement("li", { key: index },
1396
- React.createElement("span", { className: "designbase-figma-license-offer__step-index", "aria-hidden": "true" },
1397
- index + 1,
1398
- "."),
1399
- React.createElement("span", null, step))))),
1553
+ React.createElement("span", { className: "designbase-figma-license-offer__step-index", "aria-hidden": "true" }, index + 1),
1554
+ React.createElement("span", { className: "designbase-figma-license-offer__step-copy" },
1555
+ React.createElement("strong", null, step.title),
1556
+ React.createElement("span", null, step.description)))))),
1400
1557
  (resolvedJoinUrl || guideUrl) && (React.createElement("div", { className: "designbase-figma-license-offer__actions" },
1401
- resolvedJoinUrl && (React.createElement(react.Button, { onPress: () => openExternalUrl(resolvedJoinUrl), variant: "primary", size: "m", fullWidth: true }, resolveText(translate, { key: 'license.youtube_membership_join' }, '멤버십 가입'))),
1558
+ resolvedJoinUrl && (React.createElement(react.Button, { onPress: () => openExternalUrl(resolvedJoinUrl), variant: "primary", size: "m", fullWidth: true },
1559
+ React.createElement("span", null, resolveText(translate, { key: 'license.get_key_cta' }, '멤버십 가입하고 키 받기')),
1560
+ React.createElement(icons.ExternalLinkIcon, { size: 16, "aria-hidden": "true" }))),
1402
1561
  guideUrl && (React.createElement(react.Button, { onPress: () => openExternalUrl(guideUrl), variant: "secondary", size: "m", fullWidth: true },
1403
1562
  React.createElement("span", null, resolveText(translate, { key: 'license.youtube_membership_guide' }, '안내보기')),
1404
1563
  React.createElement(icons.ExternalLinkIcon, { size: 16, "aria-hidden": "true" })))))));
@@ -1437,7 +1596,7 @@ function formatSource(value, t) {
1437
1596
  }
1438
1597
  return value;
1439
1598
  }
1440
- const LicenseStatusCard = ({ status, licenseKey = '', licenseStatus, licenseSource, accessScope, expiresAt, lastVerifiedAt, validationMessage, allowRevealKey = false, t, locale, className, }) => {
1599
+ const LicenseStatusCard = ({ status, licenseKey = '', licenseStatus, licenseSource, accessScope, expiresAt, lastVerifiedAt, validationMessage, showHeader = true, allowRevealKey = false, t, locale, className, }) => {
1441
1600
  const { locale: resolvedLocale, t: translate } = useFigmaUiI18n(locale, t);
1442
1601
  const [isKeyRevealed, setIsKeyRevealed] = React.useState(false);
1443
1602
  const normalizedLicenseStatus = licenseStatus?.toLowerCase();
@@ -1448,13 +1607,15 @@ const LicenseStatusCard = ({ status, licenseKey = '', licenseStatus, licenseSour
1448
1607
  : resolveText(translate, { key: 'license.status_inactive' }, 'License check failed');
1449
1608
  const statusClass = isActive ? 'active' : 'inactive';
1450
1609
  return (React.createElement("section", { className: `designbase-figma-license-status-card designbase-figma-license-status-card--${statusClass} ${className || ''}`, "aria-label": statusText },
1451
- React.createElement("div", { className: "designbase-figma-license-status-card__header" },
1610
+ showHeader && (React.createElement("div", { className: "designbase-figma-license-status-card__header" },
1452
1611
  React.createElement("div", null,
1453
1612
  React.createElement("div", { className: "designbase-figma-license-status-card__eyebrow" }, isActive
1454
1613
  ? resolveText(translate, { key: 'license.activated' }, '라이선스 활성화됨')
1455
1614
  : resolveText(translate, { key: 'license.status_label' }, '라이선스 상태')),
1456
1615
  React.createElement("h3", null, statusText)),
1457
- React.createElement("span", { className: "designbase-figma-license-status-card__badge" }, licenseStatus || (isActive ? 'active' : 'inactive'))),
1616
+ React.createElement("span", { className: "designbase-figma-license-status-card__badge" }, isActive
1617
+ ? resolveText(translate, { key: 'license.status_active' }, '활성')
1618
+ : resolveText(translate, { key: 'license.status_inactive' }, '비활성')))),
1458
1619
  validationMessage && !isActive && (React.createElement("p", { className: "designbase-figma-license-status-card__message" }, validationMessage)),
1459
1620
  licenseKey && (React.createElement("div", { className: "designbase-figma-license-status-card__key-row" },
1460
1621
  React.createElement("span", null, resolveText(translate, { key: 'license.key_label' }, '라이선스 키')),
@@ -1828,7 +1989,7 @@ function useFigmaLicenseBridge(options = {}) {
1828
1989
  function formatUsageLabel(state, t) {
1829
1990
  const { remainingUsage, usageUsed, usageLimit, usageReset } = state;
1830
1991
  if (usageLimit === 'unlimited') {
1831
- return resolveText(t, { key: 'license.usage_unlimited' }, '사용 횟수 제한 없음') ?? '사용 횟수 제한 없음';
1992
+ return (resolveText(t, { key: 'license.usage_unlimited' }, '사용 횟수 제한 없음') ?? '사용 횟수 제한 없음');
1832
1993
  }
1833
1994
  const limit = typeof usageLimit === 'number' ? usageLimit : remainingUsage + usageUsed;
1834
1995
  const remaining = remainingUsage ?? Math.max(0, limit - usageUsed);
@@ -1847,9 +2008,9 @@ function formatUsageLabel(state, t) {
1847
2008
  const translated = resolveText(t, { key: 'license.usage_weekly', values: { remaining, limit } }, fallback) ?? fallback;
1848
2009
  return translated.includes(String(remaining)) ? translated : fallback;
1849
2010
  }
1850
- return resolveText(t, { key: 'license.usage_generic', values: { remaining, limit } }, `남은 횟수 ${remaining}/${limit}`) ?? `남은 횟수 ${remaining}/${limit}`;
2011
+ return (resolveText(t, { key: 'license.usage_generic', values: { remaining, limit } }, `남은 횟수 ${remaining}/${limit}`) ?? `남은 횟수 ${remaining}/${limit}`);
1851
2012
  }
1852
- 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, locale, className, }) => {
2013
+ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicenseKey = '', licenseStatus: initialLicenseStatus, licenseSource: initialLicenseSource, accessScope: initialAccessScope, expiresAt: initialExpiresAt, lastVerifiedAt: initialLastVerifiedAt, wordpressLinks, paymentPageUrl, mode = 'pricing', membershipUrl, enableAccountAuth = true, showLicenseKeyInput = true, pricingFeatures, pricing, paymentType = 'subscription', messageTypes, onStateChange, setPaymentStatus, setUsageCount, onLicenseSubmit, usageCount: initialUsageCount = 0, t, locale, className, }) => {
1853
2014
  const { t: translate } = useFigmaUiI18n(locale, t);
1854
2015
  const links = React.useMemo(() => ({
1855
2016
  purchaseUrl: wordpressLinks?.purchaseUrl ?? paymentPageUrl,
@@ -1862,13 +2023,21 @@ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicens
1862
2023
  initialState: {
1863
2024
  paymentStatus: initialStatus,
1864
2025
  licenseKey: initialLicenseKey,
2026
+ hasLicenseKey: Boolean(initialLicenseKey),
2027
+ isLicenseRegistered: initialStatus === 'PAID',
2028
+ planTier: initialStatus === 'PAID' ? 'PRO' : 'FREE',
2029
+ usageLimit: initialStatus === 'PAID' ? 'unlimited' : 0,
2030
+ licenseStatus: initialLicenseStatus,
2031
+ licenseSource: initialLicenseSource,
2032
+ accessScope: initialAccessScope,
2033
+ expiresAt: initialExpiresAt,
2034
+ lastVerifiedAt: initialLastVerifiedAt,
1865
2035
  usageCount: initialUsageCount,
1866
2036
  },
1867
2037
  onStateChange,
1868
2038
  onPaymentStatusChange: setPaymentStatus,
1869
2039
  onUsageCountChange: setUsageCount,
1870
2040
  });
1871
- const [showDetails, setShowDetails] = React.useState(false);
1872
2041
  const [licenseKeyDraft, setLicenseKeyDraft] = React.useState(initialLicenseKey);
1873
2042
  const isPaid = state.isLicenseRegistered && state.paymentStatus === 'PAID';
1874
2043
  const isMembershipMode = mode === 'youtube-membership';
@@ -1888,29 +2057,31 @@ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicens
1888
2057
  React.createElement("div", { className: "designbase-figma-page-license__content" },
1889
2058
  React.createElement("div", { className: "designbase-figma-page-license__header" },
1890
2059
  React.createElement("div", { className: "designbase-figma-page-license__title" },
1891
- React.createElement("h2", null, isMembershipMode
1892
- ? resolveText(translate, { key: 'license.youtube_membership' }, 'YouTube 멤버십')
1893
- : isPaid
1894
- ? resolveText(translate, { key: 'license.pro_account' }, '프로 계정')
2060
+ React.createElement("h2", null, isPaid
2061
+ ? resolveText(translate, { key: 'license.pro_account' }, '프로 계정')
2062
+ : isMembershipMode
2063
+ ? resolveText(translate, { key: 'license.unlock_unlimited' }, '무제한 사용 활성화')
1895
2064
  : resolveText(translate, { key: 'license.upgrade_to_pro' }, '프로로 업그레이드')),
1896
- state.planTier && state.planTier !== 'FREE' && (React.createElement("span", { className: "designbase-figma-page-license__tier" }, state.planTier))),
2065
+ isPaid && (React.createElement("span", { className: "designbase-figma-page-license__tier" }, resolveText(translate, { key: 'license.pro_plan' }, '프로 플랜')))),
1897
2066
  React.createElement("p", { className: "designbase-figma-page-license__description" }, isPaid
1898
2067
  ? resolveText(translate, { key: 'license.all_features_available' }, '모든 기능을 사용할 수 있습니다.')
1899
2068
  : isMembershipMode
1900
- ? resolveText(translate, { key: 'license.youtube_membership_description' }, 'YouTube 멤버십에 가입하면 Designbase 플러그인을 무제한으로 사용할 수 있습니다.')
2069
+ ? resolveText(translate, { key: 'license.unlock_unlimited_description' }, '라이선스 키를 등록하면 모든 Designbase 플러그인의 프로 기능과 무제한 사용을 이용할 수 있습니다.')
1901
2070
  : resolveText(translate, { key: 'license.purchase_for_unlimited' }, '디자인베이스 멤버십 또는 라이선스로 무제한 이용이 가능합니다.')),
1902
2071
  !isPaid && !isMembershipMode && (React.createElement("p", { className: "designbase-figma-page-license__usage" }, usageLabel))),
1903
2072
  !isMembershipMode && (React.createElement(PricingComparison, { features: pricingFeatures, pricing: pricing, paymentType: paymentType, t: translate })),
1904
- state.lastMessage && !state.deactivateMessage && (React.createElement("p", { className: `designbase-figma-page-license__feedback ${state.lastErrorCode ? 'designbase-figma-page-license__feedback--error' : ''}`, "aria-live": "polite" }, state.lastMessage)),
1905
- isPaid && (React.createElement("div", { className: "designbase-figma-page-license__section" },
1906
- React.createElement("div", { className: "designbase-figma-page-license__section-header" },
1907
- React.createElement("h3", null, resolveText(translate, { key: 'license.activated' }, '라이선스 활성화됨')),
1908
- React.createElement(react.Button, { onPress: () => setShowDetails(!showDetails), variant: "tertiary", size: "s", iconOnly: true },
1909
- React.createElement(icons.MoreHorizontalIcon, { size: 16 }))),
1910
- 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, allowRevealKey: false, t: translate }),
1911
- React.createElement("p", { className: "designbase-figma-page-license__usage" }, usageLabel),
1912
- showDetails && (React.createElement("div", { className: "designbase-figma-page-license__details" },
1913
- React.createElement("div", { className: "designbase-figma-page-license__activation-info" },
2073
+ state.lastMessage &&
2074
+ state.lastErrorCode &&
2075
+ !state.deactivateMessage && (React.createElement("p", { className: `designbase-figma-page-license__feedback ${state.lastErrorCode ? 'designbase-figma-page-license__feedback--error' : ''}`, "aria-live": "polite" }, state.lastMessage)),
2076
+ isPaid && (React.createElement("div", { className: "designbase-figma-page-license__paid-summary" },
2077
+ React.createElement("div", { className: "designbase-figma-page-license__paid-hero" },
2078
+ React.createElement("span", { "aria-hidden": "true" }, "\u221E"),
2079
+ React.createElement("div", null,
2080
+ React.createElement("strong", null, resolveText(translate, { key: 'license.usage_unlimited' }, '무제한 사용')),
2081
+ React.createElement("p", null, resolveText(translate, { key: 'license.active_until_expiry' }, '만료일까지 모든 기능을 제한 없이 사용할 수 있습니다.')))),
2082
+ 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, allowRevealKey: false, showHeader: false, t: translate }),
2083
+ React.createElement("div", { className: "designbase-figma-page-license__paid-actions" },
2084
+ state.activationLimit > 0 && (React.createElement("div", { className: "designbase-figma-page-license__activation-info" },
1914
2085
  React.createElement("div", { className: "designbase-figma-page-license__remaining" },
1915
2086
  Math.max(0, state.activationLimit - state.activationUsage),
1916
2087
  ' ',
@@ -1920,15 +2091,16 @@ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicens
1920
2091
  React.createElement("div", { className: "designbase-figma-page-license__usage-count" },
1921
2092
  state.activationUsage,
1922
2093
  "/",
1923
- state.activationLimit)),
1924
- React.createElement("div", { className: "designbase-figma-page-license__action" },
1925
- React.createElement(react.Button, { onPress: deactivateLicense, variant: "secondary", size: "s", fullWidth: true, disabled: isDeactivating }, isDeactivating
1926
- ? resolveText(translate, { key: 'license.deactivating' }, '비활성화 중...')
1927
- : resolveText(translate, { key: 'license.deactivate' }, '라이선스 비활성화')),
1928
- state.deactivateMessage && (React.createElement("p", { className: `designbase-figma-page-license__action-feedback designbase-figma-page-license__action-feedback--${resolvePaymentFeedbackVariant(state.deactivateErrorCode)}`, role: state.deactivateErrorCode ? 'alert' : 'status', "aria-live": "polite" }, state.deactivateMessage))))))),
2094
+ state.activationLimit))),
2095
+ React.createElement(react.Button, { onPress: deactivateLicense, variant: "secondary", size: "m", fullWidth: true, disabled: isDeactivating }, isDeactivating
2096
+ ? resolveText(translate, { key: 'license.deactivating' }, '비활성화 중...')
2097
+ : resolveText(translate, { key: 'license.deactivate' }, '라이선스 비활성화')),
2098
+ state.deactivateMessage && state.deactivateErrorCode && (React.createElement("p", { className: `designbase-figma-page-license__action-feedback designbase-figma-page-license__action-feedback--${resolvePaymentFeedbackVariant(state.deactivateErrorCode)}`, role: "alert", "aria-live": "polite" }, state.deactivateMessage)),
2099
+ React.createElement("p", { className: "designbase-figma-page-license__deactivate-hint" }, resolveText(translate, { key: 'license.deactivate_hint' }, '이 기기에서 라이선스 연결을 해제합니다.'))))),
1929
2100
  !isPaid && (React.createElement(React.Fragment, null,
1930
2101
  isMembershipMode && (React.createElement(LicenseOffer, { joinUrl: links.membershipUrl || links.purchaseUrl, guideUrl: links.helpUrl || links.purchaseUrl, t: translate })),
1931
- !isMembershipMode && (enableAccountAuth || links.purchaseUrl || links.accountUrl) && (React.createElement("div", { className: "designbase-figma-page-license__section" },
2102
+ !isMembershipMode &&
2103
+ (enableAccountAuth || links.purchaseUrl || links.accountUrl) && (React.createElement("div", { className: "designbase-figma-page-license__section" },
1932
2104
  React.createElement("div", { className: "designbase-figma-page-license__section-header" },
1933
2105
  React.createElement("h3", null, resolveText(translate, { key: 'license.designbase_account' }, '디자인베이스 계정'))),
1934
2106
  React.createElement("p", { className: "designbase-figma-page-license__hint" }, resolveText(translate, { key: 'license.designbase_account_hint' }, 'WordPress 계정으로 로그인하거나 멤버십을 구매하면 플러그인이 자동으로 활성화됩니다.')),
@@ -1946,8 +2118,20 @@ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicens
1946
2118
  ? 'designbase-figma-page-license__key-form'
1947
2119
  : 'designbase-figma-page-license__section' },
1948
2120
  React.createElement("div", { className: "designbase-figma-page-license__section-header" },
1949
- React.createElement("h3", null, resolveText(translate, { key: 'license.enter_key' }, '라이선스 키 입력'))),
1950
- 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: isMembershipMode ? 'license.enter_from_youtube' : 'license.enter_from_email' }, t: translate }))))),
2121
+ isMembershipMode && (React.createElement("span", { className: "designbase-figma-page-license__section-index", "aria-hidden": "true" }, "2")),
2122
+ React.createElement("h3", null, isMembershipMode
2123
+ ? resolveText(translate, { key: 'license.activate_key_title' }, '라이선스 키 등록')
2124
+ : resolveText(translate, { key: 'license.enter_key' }, '라이선스 키 입력'))),
2125
+ isMembershipMode && (React.createElement("p", { className: "designbase-figma-page-license__hint" }, resolveText(translate, { key: 'license.activate_key_description' }, '이미 키가 있다면 아래에 붙여 넣어 프로 기능을 활성화하세요.'))),
2126
+ React.createElement(FormWithSubmit, { onLicenseSubmit: handleLicenseSubmit, disabled: false, isSubmitting: isVerifying, value: licenseKeyDraft, onValueChange: handleLicenseKeyChange, label: { key: 'license.key' }, submitText: {
2127
+ key: isMembershipMode
2128
+ ? 'license.unlock_pro_features'
2129
+ : 'license.submit',
2130
+ }, submittingText: { key: 'license.verifying' }, helperText: {
2131
+ key: isMembershipMode
2132
+ ? 'license.enter_from_youtube'
2133
+ : 'license.enter_from_email',
2134
+ }, t: translate }))))),
1951
2135
  links.helpUrl && !isMembershipMode && (React.createElement("p", { className: "designbase-figma-page-license__disclaimer" },
1952
2136
  React.createElement("button", { type: "button", className: "designbase-figma-page-license__link", onClick: () => openExternalUrl(links.helpUrl) }, resolveText(translate, { key: 'license.help_link' }, '라이선스·결제 도움말'))))),
1953
2137
  React.createElement(react.Button, { className: "designbase-figma-page-license__close", onPress: onClose, variant: "tertiary", size: "s", iconOnly: true, "aria-label": translate('close') },