@designbasekorea/figma-ui 0.7.0 → 0.7.1

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,16 @@ const FIGMA_UI_TRANSLATIONS = {
52
52
  'form.submit': '제출',
53
53
  'form.verifying': '확인 중...',
54
54
  'license.youtube_membership': 'YouTube 멤버십',
55
+ 'license.current_plan': '현재 플랜',
56
+ 'license.pro_plan': '프로 플랜',
57
+ 'license.membership': '멤버십',
55
58
  'license.pro_account': '프로 계정',
56
59
  'license.upgrade_to_pro': '프로로 업그레이드',
57
60
  'license.all_features_available': '모든 기능을 사용할 수 있습니다.',
58
61
  'license.youtube_membership_description': 'YouTube 멤버십에 가입하면 Designbase 플러그인을 무제한으로 사용할 수 있습니다.',
59
62
  'license.purchase_for_unlimited': '디자인베이스 멤버십 또는 라이선스로 무제한 이용이 가능합니다.',
60
63
  'license.usage_unlimited': '사용 횟수 제한 없음',
64
+ 'license.active_until_expiry': '만료일까지 모든 기능을 제한 없이 사용할 수 있습니다.',
61
65
  'license.usage_daily': '오늘 남은 횟수 {{remaining}}/{{limit}}',
62
66
  'license.usage_weekly': '이번 주 남은 횟수 {{remaining}}/{{limit}}',
63
67
  'license.usage_monthly': '이번 달 남은 횟수 {{remaining}}/{{limit}}',
@@ -67,6 +71,7 @@ const FIGMA_UI_TRANSLATIONS = {
67
71
  'license.spots_remaining': '자리 남음',
68
72
  'license.deactivating': '비활성화 중...',
69
73
  'license.deactivate': '라이선스 비활성화',
74
+ 'license.deactivate_hint': '이 기기에서 라이선스 연결을 해제합니다.',
70
75
  'license.designbase_account': '디자인베이스 계정',
71
76
  'license.designbase_account_hint': 'WordPress 계정으로 로그인하거나 멤버십을 구매하면 플러그인이 자동으로 활성화됩니다.',
72
77
  'license.authenticating': '인증 중...',
@@ -185,12 +190,16 @@ const FIGMA_UI_TRANSLATIONS = {
185
190
  'form.submit': 'Activate',
186
191
  'form.verifying': 'Verifying...',
187
192
  'license.youtube_membership': 'YouTube Membership',
193
+ 'license.current_plan': 'Current plan',
194
+ 'license.pro_plan': 'Pro plan',
195
+ 'license.membership': 'Membership',
188
196
  'license.pro_account': 'Pro account',
189
197
  'license.upgrade_to_pro': 'Upgrade to Pro',
190
198
  'license.all_features_available': 'All features are available.',
191
199
  'license.youtube_membership_description': 'Join YouTube Membership to use Designbase plugins without limits.',
192
200
  'license.purchase_for_unlimited': 'Get unlimited access with a Designbase membership or license.',
193
201
  'license.usage_unlimited': 'Unlimited usage',
202
+ 'license.active_until_expiry': 'All features remain available without limits until expiration.',
194
203
  'license.usage_daily': '{{remaining}}/{{limit}} remaining today',
195
204
  'license.usage_weekly': '{{remaining}}/{{limit}} remaining this week',
196
205
  'license.usage_monthly': '{{remaining}}/{{limit}} remaining this month',
@@ -200,6 +209,7 @@ const FIGMA_UI_TRANSLATIONS = {
200
209
  'license.spots_remaining': 'spots remaining',
201
210
  'license.deactivating': 'Deactivating...',
202
211
  'license.deactivate': 'Deactivate license',
212
+ 'license.deactivate_hint': 'Disconnects this license from the current device.',
203
213
  'license.designbase_account': 'Designbase account',
204
214
  'license.designbase_account_hint': 'Sign in with your WordPress account or purchase a membership to activate the plugin automatically.',
205
215
  'license.authenticating': 'Authenticating...',
@@ -318,12 +328,16 @@ const FIGMA_UI_TRANSLATIONS = {
318
328
  'form.submit': '有効化',
319
329
  'form.verifying': '確認中...',
320
330
  'license.youtube_membership': 'YouTubeメンバーシップ',
331
+ 'license.current_plan': '現在のプラン',
332
+ 'license.pro_plan': 'Proプラン',
333
+ 'license.membership': 'メンバーシップ',
321
334
  'license.pro_account': 'Proアカウント',
322
335
  'license.upgrade_to_pro': 'Proにアップグレード',
323
336
  'license.all_features_available': 'すべての機能を使用できます。',
324
337
  'license.youtube_membership_description': 'YouTubeメンバーシップに参加すると、Designbaseプラグインを無制限で使用できます。',
325
338
  'license.purchase_for_unlimited': 'Designbaseのメンバーシップまたはライセンスで無制限に利用できます。',
326
339
  'license.usage_unlimited': '使用回数の制限なし',
340
+ 'license.active_until_expiry': '有効期限まで、すべての機能を制限なく使用できます。',
327
341
  'license.usage_daily': '今日の残り {{remaining}}/{{limit}}回',
328
342
  'license.usage_weekly': '今週の残り {{remaining}}/{{limit}}回',
329
343
  'license.usage_monthly': '今月の残り {{remaining}}/{{limit}}回',
@@ -333,6 +347,7 @@ const FIGMA_UI_TRANSLATIONS = {
333
347
  'license.spots_remaining': '枠残り',
334
348
  'license.deactivating': '無効化中...',
335
349
  'license.deactivate': 'ライセンスを無効化',
350
+ 'license.deactivate_hint': 'このデバイスからライセンスの接続を解除します。',
336
351
  'license.designbase_account': 'Designbaseアカウント',
337
352
  'license.designbase_account_hint': 'WordPressアカウントでサインインするか、メンバーシップを購入するとプラグインが自動的に有効化されます。',
338
353
  'license.authenticating': '認証中...',
@@ -981,7 +996,7 @@ const fallbackText = (t, key, fallback) => {
981
996
  const translated = t?.(key);
982
997
  return translated && translated !== key ? translated : fallback;
983
998
  };
984
- const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, maxDailyUsage = 20, showUsage = true, showPlan = true, isLoading = false, onLicensePageClick, t, locale, className, }) => {
999
+ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, maxDailyUsage = 20, showUsage = true, showPlan = true, isLoading = false, onLicensePageClick, licenseSource, accessScope, expiresAt, lastVerifiedAt, t, locale, className, }) => {
985
1000
  const { t: translate } = useFigmaUiI18n(locale, t);
986
1001
  const [isOpen, setIsOpen] = React.useState(false);
987
1002
  const rootRef = React.useRef(null);
@@ -1004,9 +1019,12 @@ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, max
1004
1019
  : paymentStatus === 'TRIAL'
1005
1020
  ? fallbackText(translate, 'trialPlan', '체험판')
1006
1021
  : fallbackText(translate, 'free', '무료');
1007
- const planTitle = isBeta
1022
+ const planSuffix = fallbackText(translate, 'planSuffix', '플랜');
1023
+ const normalizedPlanLabel = planLabel.toLocaleLowerCase();
1024
+ const normalizedPlanSuffix = planSuffix.toLocaleLowerCase();
1025
+ const planTitle = isBeta || normalizedPlanLabel.includes(normalizedPlanSuffix)
1008
1026
  ? planLabel
1009
- : `${planLabel} ${fallbackText(translate, 'planSuffix', '플랜')}`;
1027
+ : `${planLabel} ${planSuffix}`;
1010
1028
  const triggerLabel = isPaid
1011
1029
  ? `${planLabel}, ${fallbackText(translate, 'unlimitedUsage', '무제한 사용 가능')}`
1012
1030
  : isBeta
@@ -1017,6 +1035,41 @@ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, max
1017
1035
  const upgradeLabel = isPaid
1018
1036
  ? fallbackText(translate, 'managePlan', '플랜 관리')
1019
1037
  : fallbackText(translate, 'upgradePlan', '플랜 업그레이드');
1038
+ const resolvedLocale = locale || 'ko';
1039
+ const formatDate = (value) => {
1040
+ if (!value)
1041
+ return undefined;
1042
+ const date = new Date(value);
1043
+ if (Number.isNaN(date.getTime()))
1044
+ return value;
1045
+ return new Intl.DateTimeFormat(resolvedLocale, { dateStyle: 'medium' }).format(date);
1046
+ };
1047
+ const formattedSource = licenseSource === 'youtube_membership' || licenseSource === 'membership'
1048
+ ? fallbackText(translate, 'license.source_youtube_membership', 'YouTube 멤버십')
1049
+ : licenseSource === 'lemonsqueezy'
1050
+ ? fallbackText(translate, 'license.source_purchase', '구매 라이선스')
1051
+ : licenseSource;
1052
+ const formattedScope = accessScope === 'all-products' || accessScope === 'all_products'
1053
+ ? fallbackText(translate, 'license.all_plugins', '모든 플러그인')
1054
+ : accessScope;
1055
+ const paidMetadata = [
1056
+ formattedSource && {
1057
+ label: fallbackText(translate, 'license.membership', '멤버십'),
1058
+ value: formattedSource,
1059
+ },
1060
+ expiresAt && {
1061
+ label: fallbackText(translate, 'license.expires', '만료일'),
1062
+ value: formatDate(expiresAt),
1063
+ },
1064
+ formattedScope && {
1065
+ label: fallbackText(translate, 'license.access', '접근 범위'),
1066
+ value: formattedScope,
1067
+ },
1068
+ lastVerifiedAt && {
1069
+ label: fallbackText(translate, 'license.last_checked', '최근 확인'),
1070
+ value: formatDate(lastVerifiedAt),
1071
+ },
1072
+ ].filter(Boolean);
1020
1073
  React.useEffect(() => {
1021
1074
  if (!isOpen)
1022
1075
  return undefined;
@@ -1051,7 +1104,10 @@ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, max
1051
1104
  'designbase-figma-usage-status--loading': isLoading,
1052
1105
  }, className) },
1053
1106
  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,
1107
+ 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,
1108
+ React.createElement("span", { className: "designbase-figma-usage-status__mini-progress", "aria-hidden": "true" },
1109
+ React.createElement("span", { style: { width: '100%' } })),
1110
+ React.createElement("span", { className: "designbase-figma-usage-status__unlimited-mark", "aria-hidden": "true" }, "\u221E"))) : hasDailyLimit ? (React.createElement(React.Fragment, null,
1055
1111
  React.createElement("span", { className: "designbase-figma-usage-status__mini-progress", "aria-hidden": "true" },
1056
1112
  React.createElement("span", { style: { width: `${remainingPercent}%` } })),
1057
1113
  React.createElement("span", { className: "designbase-figma-usage-status__usage-value" },
@@ -1062,11 +1118,19 @@ const UsageStatusPopover = ({ paymentStatus, usageCount = 0, remainingUsage, max
1062
1118
  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
1119
  isOpen && (React.createElement("div", { id: popoverId, className: "designbase-figma-usage-status__popover", role: "dialog", "aria-label": fallbackText(translate, 'usageDetails', '사용량 상세') },
1064
1120
  React.createElement("div", { className: "designbase-figma-usage-status__popover-header" },
1065
- React.createElement("span", { className: "designbase-figma-usage-status__plan-title" }, planTitle),
1121
+ React.createElement("span", { className: "designbase-figma-usage-status__plan-heading" },
1122
+ React.createElement("span", null, fallbackText(translate, 'license.current_plan', '현재 플랜')),
1123
+ React.createElement("strong", null, planTitle)),
1066
1124
  !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" },
1125
+ isPaid ? (React.createElement(React.Fragment, null,
1126
+ React.createElement("div", { className: "designbase-figma-usage-status__unlimited-copy" },
1127
+ React.createElement("span", { className: "designbase-figma-usage-status__unlimited-mark", "aria-hidden": "true" }, "\u221E"),
1128
+ React.createElement("span", null,
1129
+ React.createElement("strong", null, fallbackText(translate, 'unlimitedUsage', '무제한 사용')),
1130
+ React.createElement("small", null, fallbackText(translate, 'unlimitedUsageTooltip', '모든 기능을 제한 없이 사용할 수 있습니다')))),
1131
+ paidMetadata.length > 0 && (React.createElement("dl", { className: "designbase-figma-usage-status__license-meta" }, paidMetadata.map((item) => (React.createElement("div", { key: item.label },
1132
+ React.createElement("dt", null, item.label),
1133
+ 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
1134
  React.createElement("div", { className: "designbase-figma-usage-status__usage-summary" },
1071
1135
  React.createElement("strong", { className: "designbase-figma-usage-status__usage-count" },
1072
1136
  remaining,
@@ -1168,7 +1232,7 @@ FigmaToastProvider.displayName = 'FigmaToastProvider';
1168
1232
  FigmaToast.displayName = 'FigmaToast';
1169
1233
 
1170
1234
  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, }) => {
1235
+ 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
1236
  const { t: translate } = useFigmaUiI18n(currentLanguage, t);
1173
1237
  const { showToast, toastComponent } = useFigmaToast();
1174
1238
  const [liveUsage, setLiveUsage] = React.useState({});
@@ -1178,12 +1242,17 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
1178
1242
  const effectiveUsageCount = liveUsage.usageCount ?? usageCount;
1179
1243
  const effectiveRemainingUsage = liveUsage.remainingUsage ?? remainingUsage;
1180
1244
  const effectiveMaxDailyUsage = liveUsage.maxDailyUsage ?? maxDailyUsage;
1245
+ const effectiveLicenseSource = liveUsage.licenseSource ?? licenseSource;
1246
+ const effectiveAccessScope = liveUsage.accessScope ?? accessScope;
1247
+ const effectiveExpiresAt = liveUsage.expiresAt ?? expiresAt;
1248
+ const effectiveLastVerifiedAt = liveUsage.lastVerifiedAt ?? lastVerifiedAt;
1181
1249
  const limit = Math.max(1, Math.round(effectiveMaxDailyUsage));
1182
1250
  const resolvedRemaining = typeof effectiveRemainingUsage === 'number' && Number.isFinite(effectiveRemainingUsage)
1183
1251
  ? Math.min(limit, Math.max(0, Math.round(effectiveRemainingUsage)))
1184
1252
  : Math.max(0, limit - Math.min(limit, Math.max(0, Math.round(effectiveUsageCount))));
1185
1253
  const remainingPercent = Math.round((resolvedRemaining / limit) * 100);
1186
- const resolvedShowUsageInfo = showPaymentStatus && (showUsageInfo || effectivePaymentStatus === 'FREE');
1254
+ const resolvedShowUsageInfo = showPaymentStatus
1255
+ && (showUsageInfo || effectivePaymentStatus === 'FREE' || effectivePaymentStatus === 'PAID');
1187
1256
  const resolvedShowPaymentBadge = showPaymentStatus && showPaymentBadge;
1188
1257
  const resolvedLicensePageClick = effectivePaymentStatus === 'BETA' ? undefined : onLicensePageClick;
1189
1258
  const hasChildren = React.Children.count(children) > 0;
@@ -1209,10 +1278,31 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
1209
1278
  : message.paymentStatus === 'FREE' || message.paymentStatus === 'UNPAID'
1210
1279
  ? 'FREE'
1211
1280
  : undefined;
1281
+ const nextLicenseSource = typeof message.licenseSource === 'string' ? message.licenseSource : undefined;
1282
+ const nextAccessScope = typeof message.accessScope === 'string' ? message.accessScope : undefined;
1283
+ const nextExpiresAt = typeof message.expiresAt === 'string' ? message.expiresAt : undefined;
1284
+ const rawLastVerifiedAt = message.lastVerifiedAt;
1285
+ const numericLastVerifiedAt = typeof rawLastVerifiedAt === 'number' && Number.isFinite(rawLastVerifiedAt)
1286
+ ? rawLastVerifiedAt < 1000000000000
1287
+ ? rawLastVerifiedAt * 1000
1288
+ : rawLastVerifiedAt
1289
+ : undefined;
1290
+ const parsedLastVerifiedAt = numericLastVerifiedAt === undefined
1291
+ ? undefined
1292
+ : new Date(numericLastVerifiedAt);
1293
+ const nextLastVerifiedAt = typeof rawLastVerifiedAt === 'string'
1294
+ ? rawLastVerifiedAt
1295
+ : parsedLastVerifiedAt && !Number.isNaN(parsedLastVerifiedAt.getTime())
1296
+ ? parsedLastVerifiedAt.toISOString()
1297
+ : undefined;
1212
1298
  if (nextPaymentStatus === undefined
1213
1299
  && nextLimit === undefined
1214
1300
  && nextUsed === undefined
1215
- && nextRemaining === undefined) {
1301
+ && nextRemaining === undefined
1302
+ && nextLicenseSource === undefined
1303
+ && nextAccessScope === undefined
1304
+ && nextExpiresAt === undefined
1305
+ && nextLastVerifiedAt === undefined) {
1216
1306
  return;
1217
1307
  }
1218
1308
  setLiveUsage((previous) => ({
@@ -1221,6 +1311,10 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
1221
1311
  ...(typeof nextLimit === 'number' ? { maxDailyUsage: nextLimit } : {}),
1222
1312
  ...(typeof nextUsed === 'number' ? { usageCount: nextUsed } : {}),
1223
1313
  ...(typeof nextRemaining === 'number' ? { remainingUsage: nextRemaining } : {}),
1314
+ ...(nextLicenseSource ? { licenseSource: nextLicenseSource } : {}),
1315
+ ...(nextAccessScope ? { accessScope: nextAccessScope } : {}),
1316
+ ...(nextExpiresAt ? { expiresAt: nextExpiresAt } : {}),
1317
+ ...(nextLastVerifiedAt ? { lastVerifiedAt: nextLastVerifiedAt } : {}),
1224
1318
  }));
1225
1319
  };
1226
1320
  window.addEventListener('message', handleUsageMessage);
@@ -1279,7 +1373,7 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
1279
1373
  React.createElement("div", { className: "designbase-figma-footer__left" },
1280
1374
  React.createElement(LogoDropdown, { logoSrc: logoSrc, logoAlt: logoAlt, logoType: logoType, logoSize: logoSize, links: logoLinks, languages: languages, currentLanguage: currentLanguage, showLanguageSelector: showLanguageSelector, onLanguageChange: onLanguageChange, t: translate })),
1281
1375
  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 })),
1376
+ (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
1377
  showDonation && (React.createElement(DonationBadge, { donationUrl: donationUrl, text: donationText, iconType: "heart", size: "s", iconOnly: true, showPrompt: false, t: translate })))),
1284
1378
  children,
1285
1379
  toastComponent));
@@ -1292,9 +1386,15 @@ const FormWithSubmit = ({ onLicenseSubmit, disabled = false, isSubmitting = fals
1292
1386
  React.useEffect(() => {
1293
1387
  setInputValue(value);
1294
1388
  }, [value]);
1389
+ const submitLicense = async () => {
1390
+ const normalizedValue = inputValue.trim();
1391
+ if (!normalizedValue || disabled || isSubmitting)
1392
+ return;
1393
+ await onLicenseSubmit(normalizedValue);
1394
+ };
1295
1395
  const handleSubmit = async (e) => {
1296
1396
  e.preventDefault();
1297
- await onLicenseSubmit(inputValue);
1397
+ await submitLicense();
1298
1398
  };
1299
1399
  const handleChange = (value) => {
1300
1400
  setInputValue(value);
@@ -1314,7 +1414,9 @@ const FormWithSubmit = ({ onLicenseSubmit, disabled = false, isSubmitting = fals
1314
1414
  handleChange(value);
1315
1415
  }
1316
1416
  }, 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)));
1417
+ React.createElement(react.Button, { type: "button", variant: "primary", size: "m", loading: isSubmitting, disabled: !inputValue.trim() || isSubmitting || disabled, fullWidth: true, onPress: () => {
1418
+ void submitLicense();
1419
+ } }, isSubmitting ? displaySubmittingText : displaySubmitText)));
1318
1420
  };
1319
1421
  FormWithSubmit.displayName = 'FormWithSubmit';
1320
1422
 
@@ -1437,7 +1539,7 @@ function formatSource(value, t) {
1437
1539
  }
1438
1540
  return value;
1439
1541
  }
1440
- const LicenseStatusCard = ({ status, licenseKey = '', licenseStatus, licenseSource, accessScope, expiresAt, lastVerifiedAt, validationMessage, allowRevealKey = false, t, locale, className, }) => {
1542
+ const LicenseStatusCard = ({ status, licenseKey = '', licenseStatus, licenseSource, accessScope, expiresAt, lastVerifiedAt, validationMessage, showHeader = true, allowRevealKey = false, t, locale, className, }) => {
1441
1543
  const { locale: resolvedLocale, t: translate } = useFigmaUiI18n(locale, t);
1442
1544
  const [isKeyRevealed, setIsKeyRevealed] = React.useState(false);
1443
1545
  const normalizedLicenseStatus = licenseStatus?.toLowerCase();
@@ -1448,13 +1550,15 @@ const LicenseStatusCard = ({ status, licenseKey = '', licenseStatus, licenseSour
1448
1550
  : resolveText(translate, { key: 'license.status_inactive' }, 'License check failed');
1449
1551
  const statusClass = isActive ? 'active' : 'inactive';
1450
1552
  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" },
1553
+ showHeader && (React.createElement("div", { className: "designbase-figma-license-status-card__header" },
1452
1554
  React.createElement("div", null,
1453
1555
  React.createElement("div", { className: "designbase-figma-license-status-card__eyebrow" }, isActive
1454
1556
  ? resolveText(translate, { key: 'license.activated' }, '라이선스 활성화됨')
1455
1557
  : resolveText(translate, { key: 'license.status_label' }, '라이선스 상태')),
1456
1558
  React.createElement("h3", null, statusText)),
1457
- React.createElement("span", { className: "designbase-figma-license-status-card__badge" }, licenseStatus || (isActive ? 'active' : 'inactive'))),
1559
+ React.createElement("span", { className: "designbase-figma-license-status-card__badge" }, isActive
1560
+ ? resolveText(translate, { key: 'license.status_active' }, '활성')
1561
+ : resolveText(translate, { key: 'license.status_inactive' }, '비활성')))),
1458
1562
  validationMessage && !isActive && (React.createElement("p", { className: "designbase-figma-license-status-card__message" }, validationMessage)),
1459
1563
  licenseKey && (React.createElement("div", { className: "designbase-figma-license-status-card__key-row" },
1460
1564
  React.createElement("span", null, resolveText(translate, { key: 'license.key_label' }, '라이선스 키')),
@@ -1849,7 +1953,7 @@ function formatUsageLabel(state, t) {
1849
1953
  }
1850
1954
  return resolveText(t, { key: 'license.usage_generic', values: { remaining, limit } }, `남은 횟수 ${remaining}/${limit}`) ?? `남은 횟수 ${remaining}/${limit}`;
1851
1955
  }
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, }) => {
1956
+ 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
1957
  const { t: translate } = useFigmaUiI18n(locale, t);
1854
1958
  const links = React.useMemo(() => ({
1855
1959
  purchaseUrl: wordpressLinks?.purchaseUrl ?? paymentPageUrl,
@@ -1862,13 +1966,21 @@ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicens
1862
1966
  initialState: {
1863
1967
  paymentStatus: initialStatus,
1864
1968
  licenseKey: initialLicenseKey,
1969
+ hasLicenseKey: Boolean(initialLicenseKey),
1970
+ isLicenseRegistered: initialStatus === 'PAID',
1971
+ planTier: initialStatus === 'PAID' ? 'PRO' : 'FREE',
1972
+ usageLimit: initialStatus === 'PAID' ? 'unlimited' : 0,
1973
+ licenseStatus: initialLicenseStatus,
1974
+ licenseSource: initialLicenseSource,
1975
+ accessScope: initialAccessScope,
1976
+ expiresAt: initialExpiresAt,
1977
+ lastVerifiedAt: initialLastVerifiedAt,
1865
1978
  usageCount: initialUsageCount,
1866
1979
  },
1867
1980
  onStateChange,
1868
1981
  onPaymentStatusChange: setPaymentStatus,
1869
1982
  onUsageCountChange: setUsageCount,
1870
1983
  });
1871
- const [showDetails, setShowDetails] = React.useState(false);
1872
1984
  const [licenseKeyDraft, setLicenseKeyDraft] = React.useState(initialLicenseKey);
1873
1985
  const isPaid = state.isLicenseRegistered && state.paymentStatus === 'PAID';
1874
1986
  const isMembershipMode = mode === 'youtube-membership';
@@ -1893,7 +2005,7 @@ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicens
1893
2005
  : isPaid
1894
2006
  ? resolveText(translate, { key: 'license.pro_account' }, '프로 계정')
1895
2007
  : resolveText(translate, { key: 'license.upgrade_to_pro' }, '프로로 업그레이드')),
1896
- state.planTier && state.planTier !== 'FREE' && (React.createElement("span", { className: "designbase-figma-page-license__tier" }, state.planTier))),
2008
+ isPaid && (React.createElement("span", { className: "designbase-figma-page-license__tier" }, resolveText(translate, { key: 'license.pro_plan' }, '프로 플랜')))),
1897
2009
  React.createElement("p", { className: "designbase-figma-page-license__description" }, isPaid
1898
2010
  ? resolveText(translate, { key: 'license.all_features_available' }, '모든 기능을 사용할 수 있습니다.')
1899
2011
  : isMembershipMode
@@ -1901,16 +2013,16 @@ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicens
1901
2013
  : resolveText(translate, { key: 'license.purchase_for_unlimited' }, '디자인베이스 멤버십 또는 라이선스로 무제한 이용이 가능합니다.')),
1902
2014
  !isPaid && !isMembershipMode && (React.createElement("p", { className: "designbase-figma-page-license__usage" }, usageLabel))),
1903
2015
  !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" },
2016
+ state.lastMessage && state.lastErrorCode && !state.deactivateMessage && (React.createElement("p", { className: `designbase-figma-page-license__feedback ${state.lastErrorCode ? 'designbase-figma-page-license__feedback--error' : ''}`, "aria-live": "polite" }, state.lastMessage)),
2017
+ isPaid && (React.createElement("div", { className: "designbase-figma-page-license__paid-summary" },
2018
+ React.createElement("div", { className: "designbase-figma-page-license__paid-hero" },
2019
+ React.createElement("span", { "aria-hidden": "true" }, "\u221E"),
2020
+ React.createElement("div", null,
2021
+ React.createElement("strong", null, resolveText(translate, { key: 'license.usage_unlimited' }, '무제한 사용')),
2022
+ React.createElement("p", null, resolveText(translate, { key: 'license.active_until_expiry' }, '만료일까지 모든 기능을 제한 없이 사용할 수 있습니다.')))),
2023
+ 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 }),
2024
+ React.createElement("div", { className: "designbase-figma-page-license__paid-actions" },
2025
+ state.activationLimit > 0 && (React.createElement("div", { className: "designbase-figma-page-license__activation-info" },
1914
2026
  React.createElement("div", { className: "designbase-figma-page-license__remaining" },
1915
2027
  Math.max(0, state.activationLimit - state.activationUsage),
1916
2028
  ' ',
@@ -1920,12 +2032,12 @@ const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicens
1920
2032
  React.createElement("div", { className: "designbase-figma-page-license__usage-count" },
1921
2033
  state.activationUsage,
1922
2034
  "/",
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))))))),
2035
+ state.activationLimit))),
2036
+ React.createElement(react.Button, { onPress: deactivateLicense, variant: "secondary", size: "m", fullWidth: true, disabled: isDeactivating }, isDeactivating
2037
+ ? resolveText(translate, { key: 'license.deactivating' }, '비활성화 중...')
2038
+ : resolveText(translate, { key: 'license.deactivate' }, '라이선스 비활성화')),
2039
+ 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)),
2040
+ React.createElement("p", { className: "designbase-figma-page-license__deactivate-hint" }, resolveText(translate, { key: 'license.deactivate_hint' }, '이 기기에서 라이선스 연결을 해제합니다.'))))),
1929
2041
  !isPaid && (React.createElement(React.Fragment, null,
1930
2042
  isMembershipMode && (React.createElement(LicenseOffer, { joinUrl: links.membershipUrl || links.purchaseUrl, guideUrl: links.helpUrl || links.purchaseUrl, t: translate })),
1931
2043
  !isMembershipMode && (enableAccountAuth || links.purchaseUrl || links.accountUrl) && (React.createElement("div", { className: "designbase-figma-page-license__section" },