@monetizekit/react 0.3.0 → 0.4.0

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.d.ts CHANGED
@@ -183,7 +183,10 @@ interface PricingTableProps {
183
183
  plans?: Plan[];
184
184
  /** Plan name to highlight as "Most Popular". */
185
185
  highlightPlan?: string;
186
+ /** Active billing cycle (controlled). With `showBillingToggle`, also the initial value. */
186
187
  billingCycle?: "monthly" | "annually";
188
+ /** Render an interactive Monthly/Yearly toggle above the cards. */
189
+ showBillingToggle?: boolean;
187
190
  locale?: string;
188
191
  onSelectPlan?: (planId: string) => void;
189
192
  /** Where the Contact Sales CTA links (defaults to no-op). */
@@ -196,7 +199,47 @@ interface PricingTableProps {
196
199
  /** Override the sample-data disclaimer copy. */
197
200
  disclaimer?: ReactNode;
198
201
  }
199
- declare function PricingTable({ plans: plansProp, highlightPlan, locale, onSelectPlan, onContactSales, sampleWhenEmpty, disclaimer, }: PricingTableProps): react.JSX.Element;
202
+ declare function PricingTable({ plans: plansProp, highlightPlan, billingCycle, showBillingToggle, locale, onSelectPlan, onContactSales, sampleWhenEmpty, disclaimer, }: PricingTableProps): react.JSX.Element;
203
+
204
+ /** A labelled group of feature keys to compare across plans. */
205
+ interface ComparisonFeatureGroup {
206
+ title: string;
207
+ features: {
208
+ key: string;
209
+ label: string;
210
+ }[];
211
+ }
212
+ interface PricingComparisonProps {
213
+ /** Plans to compare; if omitted, fetched live from the publishable-key API. */
214
+ plans?: Plan[];
215
+ /**
216
+ * Feature groups (rows) to show. When omitted, a single "Features" group is
217
+ * derived from the union of the plans' entitlements.
218
+ */
219
+ groups?: ComparisonFeatureGroup[];
220
+ highlightPlan?: string;
221
+ billingCycle?: "monthly" | "annually";
222
+ locale?: string;
223
+ sampleWhenEmpty?: boolean;
224
+ disclaimer?: ReactNode;
225
+ }
226
+ /**
227
+ * A feature-comparison table across plans (à la a "Compare plans" section).
228
+ * Reads live plans via the publishable key when `plans` is omitted, and falls
229
+ * back to illustrative sample plans (behind a disclaimer) when empty.
230
+ */
231
+ declare function PricingComparison({ plans: plansProp, groups, highlightPlan, billingCycle, locale, sampleWhenEmpty, disclaimer, }: PricingComparisonProps): react.JSX.Element;
232
+
233
+ interface BillingCycleToggleProps {
234
+ value: "monthly" | "annually";
235
+ onChange: (value: "monthly" | "annually") => void;
236
+ /** When > 0, shows a "Save N%" hint on the Yearly option. */
237
+ savingsPercent?: number;
238
+ monthlyLabel?: string;
239
+ annuallyLabel?: string;
240
+ }
241
+ /** Monthly/Yearly billing switch used above pricing cards. */
242
+ declare function BillingCycleToggle({ value, onChange, savingsPercent, monthlyLabel, annuallyLabel, }: BillingCycleToggleProps): react.JSX.Element;
200
243
 
201
244
  interface PaywallProps {
202
245
  /** Feature key gating the content. */
@@ -207,9 +250,11 @@ interface PaywallProps {
207
250
  description?: string;
208
251
  ctaLabel?: string;
209
252
  onUpgrade?: () => void;
253
+ /** Always render the locked upgrade prompt (for previews, no live customer). */
254
+ sample?: boolean;
210
255
  }
211
256
  /** Gate content behind an entitlement, showing an upgrade prompt when locked. */
212
- declare function Paywall({ feature, children, title, description, ctaLabel, onUpgrade, }: PaywallProps): react.JSX.Element;
257
+ declare function Paywall({ feature, children, title, description, ctaLabel, onUpgrade, sample, }: PaywallProps): react.JSX.Element;
213
258
 
214
259
  interface UsageBannerProps {
215
260
  /** Meter to display usage for. */
@@ -222,6 +267,28 @@ interface UsageBannerProps {
222
267
  /** Show current usage vs allotment for a capacity meter, with overage hint. */
223
268
  declare function UsageBanner({ meterId, label, locale, warnAt, }: UsageBannerProps): react.JSX.Element;
224
269
 
270
+ type AlertBannerVariant = "info" | "warning" | "danger" | "neutral";
271
+ interface BannerAction {
272
+ label: string;
273
+ onClick?: () => void;
274
+ variant?: "primary" | "ghost";
275
+ }
276
+ interface AlertBannerProps {
277
+ variant?: AlertBannerVariant;
278
+ title: string;
279
+ description?: ReactNode;
280
+ /** Optional progress fraction (0–1) rendered as a colored bar. */
281
+ progress?: number;
282
+ actions?: BannerAction[];
283
+ /** Optional leading icon/emoji. */
284
+ icon?: ReactNode;
285
+ }
286
+ /**
287
+ * A flexible in-app notification banner (usage warnings, budget reached, low
288
+ * credits, trial ending, …). Presentational + fully themeable via tokens.
289
+ */
290
+ declare function AlertBanner({ variant, title, description, progress, actions, icon, }: AlertBannerProps): react.JSX.Element;
291
+
225
292
  interface CustomerPortalProps {
226
293
  /** Current plan name to display. */
227
294
  planName?: string;
@@ -317,8 +384,8 @@ interface PriceDisplay {
317
384
  * when the plan is tagged `contact_sales` or has no public price; renders a
318
385
  * "from $base + usage" headline when metered usage terms are present.
319
386
  */
320
- declare function describePlanPrice(plan: Plan, locale?: string): PriceDisplay;
387
+ declare function describePlanPrice(plan: Plan, locale?: string, billingCycle?: "monthly" | "annually"): PriceDisplay;
321
388
  /** Human-readable description of a usage term's metered tiers. */
322
389
  declare function describeUsageTerm(term: PricingTerm, locale?: string): string;
323
390
 
324
- export { type Appearance, type CreditBalance, CustomerPortal, type CustomerPortalProps, EntitlementGate, type EntitlementGateProps, type EntitlementResult, type Invoice, MonetizeKitClient, type MonetizeKitClientConfig, type MonetizeKitContextValue, MonetizeKitProvider, type MonetizeKitProviderProps, Paywall, type PaywallProps, type Plan, type PlanEntitlement, type PriceDisplay, PricingTable, type PricingTableProps, type PricingTerm, type PricingTier, SAMPLE_CREDITS, SAMPLE_INVOICES, SAMPLE_NOTICE_TEXT, SAMPLE_PLANS, SAMPLE_PORTAL, SAMPLE_TEAM, SAMPLE_USAGE, SampleNotice, type SampleNoticeProps, THEME_PRESETS, THEME_PRESET_NAMES, type TeamMember, type ThemePresetName, type ThemeTokens, UsageBanner, type UsageBannerProps, type UsageResult, describePlanPrice, describeUsageTerm, formatMoney, formatUnits, resolveTokens, tokensToStyle, useCredits, useEntitlement, useMonetizeKit, useUsage };
391
+ export { AlertBanner, type AlertBannerProps, type AlertBannerVariant, type Appearance, type BannerAction, BillingCycleToggle, type BillingCycleToggleProps, type ComparisonFeatureGroup, type CreditBalance, CustomerPortal, type CustomerPortalProps, EntitlementGate, type EntitlementGateProps, type EntitlementResult, type Invoice, MonetizeKitClient, type MonetizeKitClientConfig, type MonetizeKitContextValue, MonetizeKitProvider, type MonetizeKitProviderProps, Paywall, type PaywallProps, type Plan, type PlanEntitlement, type PriceDisplay, PricingComparison, type PricingComparisonProps, PricingTable, type PricingTableProps, type PricingTerm, type PricingTier, SAMPLE_CREDITS, SAMPLE_INVOICES, SAMPLE_NOTICE_TEXT, SAMPLE_PLANS, SAMPLE_PORTAL, SAMPLE_TEAM, SAMPLE_USAGE, SampleNotice, type SampleNoticeProps, THEME_PRESETS, THEME_PRESET_NAMES, type TeamMember, type ThemePresetName, type ThemeTokens, UsageBanner, type UsageBannerProps, type UsageResult, describePlanPrice, describeUsageTerm, formatMoney, formatUnits, resolveTokens, tokensToStyle, useCredits, useEntitlement, useMonetizeKit, useUsage };
package/dist/index.js CHANGED
@@ -357,13 +357,14 @@ var INTERVAL_SUFFIX = {
357
357
  annually: "/yr",
358
358
  one_time: ""
359
359
  };
360
- function describePlanPrice(plan, locale) {
360
+ function describePlanPrice(plan, locale, billingCycle = "monthly") {
361
361
  const pricing = plan.pricing ?? [];
362
362
  const contactSales = (plan.tags ?? []).includes("contact_sales") || pricing.length === 0;
363
363
  if (contactSales) {
364
364
  return { headline: null, contactSales: true };
365
365
  }
366
- const base = pricing.find((t) => t.type === "flat");
366
+ const flats = pricing.filter((t) => t.type === "flat");
367
+ const base = flats.find((t) => t.interval === billingCycle) ?? flats.find((t) => t.interval === "monthly") ?? flats[0];
367
368
  const hasUsage = pricing.some((t) => t.type === "usage");
368
369
  const currency = base?.currency ?? pricing[0]?.currency ?? "USD";
369
370
  const interval = base?.interval ?? pricing[0]?.interval ?? "monthly";
@@ -375,6 +376,14 @@ function describePlanPrice(plan, locale) {
375
376
  contactSales: false
376
377
  };
377
378
  }
379
+ function annualSavingsPercent(plan) {
380
+ const flats = (plan.pricing ?? []).filter((t) => t.type === "flat");
381
+ const monthly = flats.find((t) => t.interval === "monthly");
382
+ const annual = flats.find((t) => t.interval === "annually");
383
+ if (!monthly || !annual || monthly.amount <= 0) return null;
384
+ const pct = Math.round((1 - annual.amount / (monthly.amount * 12)) * 100);
385
+ return pct > 0 ? pct : null;
386
+ }
378
387
  function describeUsageTerm(term, locale) {
379
388
  const parts = [];
380
389
  if (term.includedUnits && term.includedUnits > 0) {
@@ -496,6 +505,78 @@ function SampleNotice({ children }) {
496
505
  /* @__PURE__ */ jsx("span", { children: children ?? SAMPLE_NOTICE_TEXT })
497
506
  ] });
498
507
  }
508
+ var trackStyle = {
509
+ display: "inline-flex",
510
+ alignSelf: "center",
511
+ gap: "0.125rem",
512
+ padding: "0.25rem",
513
+ borderRadius: "var(--mk-radius)",
514
+ background: "color-mix(in srgb, var(--mk-fg) 6%, transparent)",
515
+ fontFamily: "var(--mk-font)"
516
+ };
517
+ function optionStyle(active) {
518
+ return {
519
+ border: "none",
520
+ cursor: "pointer",
521
+ borderRadius: "var(--mk-radius)",
522
+ padding: "0.375rem 0.875rem",
523
+ fontSize: "0.8125rem",
524
+ fontWeight: 600,
525
+ display: "inline-flex",
526
+ alignItems: "center",
527
+ gap: "0.375rem",
528
+ background: active ? "var(--mk-card)" : "transparent",
529
+ color: active ? "var(--mk-card-fg)" : "var(--mk-muted)",
530
+ boxShadow: active ? "var(--mk-shadow)" : "none"
531
+ };
532
+ }
533
+ function BillingCycleToggle({
534
+ value,
535
+ onChange,
536
+ savingsPercent = 0,
537
+ monthlyLabel = "Monthly",
538
+ annuallyLabel = "Yearly"
539
+ }) {
540
+ return /* @__PURE__ */ jsxs("div", { style: trackStyle, role: "group", "aria-label": "Billing cycle", "data-mk-component": "billing-toggle", children: [
541
+ /* @__PURE__ */ jsx(
542
+ "button",
543
+ {
544
+ type: "button",
545
+ style: optionStyle(value === "monthly"),
546
+ "aria-pressed": value === "monthly",
547
+ onClick: () => onChange("monthly"),
548
+ children: monthlyLabel
549
+ }
550
+ ),
551
+ /* @__PURE__ */ jsxs(
552
+ "button",
553
+ {
554
+ type: "button",
555
+ style: optionStyle(value === "annually"),
556
+ "aria-pressed": value === "annually",
557
+ onClick: () => onChange("annually"),
558
+ children: [
559
+ annuallyLabel,
560
+ savingsPercent > 0 ? /* @__PURE__ */ jsxs(
561
+ "span",
562
+ {
563
+ style: {
564
+ fontSize: "0.6875rem",
565
+ fontWeight: 700,
566
+ color: "var(--mk-success)"
567
+ },
568
+ children: [
569
+ "Save ",
570
+ savingsPercent,
571
+ "%"
572
+ ]
573
+ }
574
+ ) : null
575
+ ]
576
+ }
577
+ )
578
+ ] });
579
+ }
499
580
  var wrapperStyle = {
500
581
  display: "grid",
501
582
  gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))",
@@ -515,6 +596,8 @@ var cardBase = {
515
596
  function PricingTable({
516
597
  plans: plansProp,
517
598
  highlightPlan,
599
+ billingCycle,
600
+ showBillingToggle = false,
518
601
  locale,
519
602
  onSelectPlan,
520
603
  onContactSales,
@@ -524,6 +607,10 @@ function PricingTable({
524
607
  const { client, tokens } = useMonetizeKit();
525
608
  const [plans, setPlans] = useState(plansProp ?? null);
526
609
  const [error, setError] = useState(null);
610
+ const [cycle, setCycle] = useState(billingCycle ?? "monthly");
611
+ useEffect(() => {
612
+ if (billingCycle) setCycle(billingCycle);
613
+ }, [billingCycle]);
527
614
  useEffect(() => {
528
615
  if (plansProp) {
529
616
  setPlans(plansProp);
@@ -558,8 +645,19 @@ function PricingTable({
558
645
  "data-mk-sample": isSample ? "true" : void 0,
559
646
  children: [
560
647
  isSample ? /* @__PURE__ */ jsx(SampleNotice, { children: disclaimer }) : null,
648
+ showBillingToggle ? /* @__PURE__ */ jsx(
649
+ BillingCycleToggle,
650
+ {
651
+ value: cycle,
652
+ onChange: setCycle,
653
+ savingsPercent: Math.max(
654
+ 0,
655
+ ...effectivePlans.map((p) => annualSavingsPercent(p) ?? 0)
656
+ )
657
+ }
658
+ ) : null,
561
659
  /* @__PURE__ */ jsx("div", { style: wrapperStyle, children: effectivePlans.map((plan) => {
562
- const price = describePlanPrice(plan, locale);
660
+ const price = describePlanPrice(plan, locale, cycle);
563
661
  const highlighted = highlightPlan != null && plan.name.toLowerCase() === highlightPlan.toLowerCase();
564
662
  return /* @__PURE__ */ jsxs(
565
663
  "div",
@@ -624,6 +722,169 @@ function PricingTable({
624
722
  }
625
723
  );
626
724
  }
725
+ var UNLIMITED_THRESHOLD = 9999;
726
+ function entitlementCell(ent, locale) {
727
+ if (!ent) return /* @__PURE__ */ jsx("span", { style: { color: "var(--mk-muted)" }, children: "\u2014" });
728
+ switch (ent.type) {
729
+ case "boolean":
730
+ return ent.value ? /* @__PURE__ */ jsx("span", { "aria-label": "Included", style: { color: "var(--mk-success)", fontWeight: 700 }, children: "\u2713" }) : /* @__PURE__ */ jsx("span", { "aria-label": "Not included", style: { color: "var(--mk-muted)" }, children: "\u2014" });
731
+ case "limit": {
732
+ const n = Number(ent.value);
733
+ return /* @__PURE__ */ jsx("span", { children: n >= UNLIMITED_THRESHOLD ? "Unlimited" : formatUnits(n, locale) });
734
+ }
735
+ default:
736
+ return /* @__PURE__ */ jsx("span", { children: String(ent.value) });
737
+ }
738
+ }
739
+ function deriveGroups(plans) {
740
+ const seen = /* @__PURE__ */ new Map();
741
+ for (const plan of plans) {
742
+ for (const ent of plan.entitlements ?? []) {
743
+ if (!seen.has(ent.featureKey)) seen.set(ent.featureKey, ent.featureDisplayName);
744
+ }
745
+ }
746
+ return [
747
+ {
748
+ title: "Features",
749
+ features: Array.from(seen, ([key, label]) => ({ key, label }))
750
+ }
751
+ ];
752
+ }
753
+ var cellStyle = {
754
+ padding: "0.75rem 1rem",
755
+ textAlign: "center",
756
+ fontSize: "0.875rem",
757
+ borderTop: "1px solid var(--mk-border)"
758
+ };
759
+ function PricingComparison({
760
+ plans: plansProp,
761
+ groups,
762
+ highlightPlan,
763
+ billingCycle = "monthly",
764
+ locale,
765
+ sampleWhenEmpty = true,
766
+ disclaimer
767
+ }) {
768
+ const { client, tokens } = useMonetizeKit();
769
+ const [plans, setPlans] = useState(plansProp ?? null);
770
+ const [error, setError] = useState(null);
771
+ useEffect(() => {
772
+ if (plansProp) {
773
+ setPlans(plansProp);
774
+ return;
775
+ }
776
+ let active = true;
777
+ client.listPlans().then((res) => {
778
+ if (active) setPlans(res.data ?? []);
779
+ }).catch((e) => {
780
+ if (active) setError(e instanceof Error ? e : new Error(String(e)));
781
+ });
782
+ return () => {
783
+ active = false;
784
+ };
785
+ }, [client, plansProp]);
786
+ if (error) {
787
+ return /* @__PURE__ */ jsx("div", { role: "alert", style: { color: "var(--mk-muted)" }, children: "Unable to load plan comparison." });
788
+ }
789
+ if (!plans) {
790
+ return /* @__PURE__ */ jsx("div", { "aria-busy": "true", style: { color: "var(--mk-muted)" }, children: "Loading comparison\u2026" });
791
+ }
792
+ const isSample = plans.length === 0 && sampleWhenEmpty;
793
+ const effectivePlans = isSample ? SAMPLE_PLANS : plans;
794
+ if (effectivePlans.length === 0) {
795
+ return /* @__PURE__ */ jsx("div", { style: { color: "var(--mk-muted)" }, children: "No plans to compare." });
796
+ }
797
+ const effectiveGroups = groups ?? deriveGroups(effectivePlans);
798
+ const entByPlan = effectivePlans.map(
799
+ (plan) => new Map((plan.entitlements ?? []).map((e) => [e.featureKey, e]))
800
+ );
801
+ return /* @__PURE__ */ jsxs(
802
+ "div",
803
+ {
804
+ style: { ...tokensToStyle(tokens), display: "flex", flexDirection: "column", gap: "1rem" },
805
+ "data-mk-component": "pricing-comparison",
806
+ "data-mk-sample": isSample ? "true" : void 0,
807
+ children: [
808
+ isSample ? /* @__PURE__ */ jsx(SampleNotice, { children: disclaimer }) : null,
809
+ /* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs(
810
+ "table",
811
+ {
812
+ style: {
813
+ width: "100%",
814
+ borderCollapse: "collapse",
815
+ background: "var(--mk-bg)",
816
+ color: "var(--mk-fg)",
817
+ fontFamily: "var(--mk-font)"
818
+ },
819
+ children: [
820
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
821
+ /* @__PURE__ */ jsx("th", { style: { ...cellStyle, textAlign: "left", borderTop: "none" }, children: "Features" }),
822
+ effectivePlans.map((plan) => {
823
+ const highlighted = highlightPlan != null && plan.name.toLowerCase() === highlightPlan.toLowerCase();
824
+ const price = describePlanPrice(plan, locale, billingCycle);
825
+ return /* @__PURE__ */ jsxs(
826
+ "th",
827
+ {
828
+ style: {
829
+ ...cellStyle,
830
+ borderTop: "none",
831
+ color: highlighted ? "var(--mk-primary)" : "var(--mk-fg)"
832
+ },
833
+ "data-mk-plan": plan.name,
834
+ "data-mk-highlighted": highlighted ? "true" : void 0,
835
+ children: [
836
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 700 }, children: plan.name }),
837
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "0.75rem", color: "var(--mk-muted)", fontWeight: 400 }, children: price.contactSales ? "Custom" : price.headline })
838
+ ]
839
+ },
840
+ plan.id
841
+ );
842
+ })
843
+ ] }) }),
844
+ /* @__PURE__ */ jsx("tbody", { children: effectiveGroups.map((group) => /* @__PURE__ */ jsx(
845
+ FeatureGroupRows,
846
+ {
847
+ group,
848
+ planCount: effectivePlans.length,
849
+ entByPlan,
850
+ locale
851
+ },
852
+ group.title
853
+ )) })
854
+ ]
855
+ }
856
+ ) })
857
+ ]
858
+ }
859
+ );
860
+ }
861
+ function FeatureGroupRows({
862
+ group,
863
+ planCount,
864
+ entByPlan,
865
+ locale
866
+ }) {
867
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
868
+ /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
869
+ "td",
870
+ {
871
+ colSpan: planCount + 1,
872
+ style: {
873
+ padding: "0.625rem 1rem",
874
+ fontSize: "0.8125rem",
875
+ fontWeight: 700,
876
+ background: "color-mix(in srgb, var(--mk-fg) 5%, transparent)",
877
+ borderTop: "1px solid var(--mk-border)"
878
+ },
879
+ children: group.title
880
+ }
881
+ ) }),
882
+ group.features.map((feature) => /* @__PURE__ */ jsxs("tr", { children: [
883
+ /* @__PURE__ */ jsx("td", { style: { ...cellStyle, textAlign: "left", color: "var(--mk-fg)" }, children: feature.label }),
884
+ entByPlan.map((map, i) => /* @__PURE__ */ jsx("td", { style: cellStyle, children: entitlementCell(map.get(feature.key), locale) }, i))
885
+ ] }, feature.key))
886
+ ] });
887
+ }
627
888
  var overlayStyle = {
628
889
  border: "1px solid var(--mk-border)",
629
890
  borderRadius: "var(--mk-radius)",
@@ -643,14 +904,15 @@ function Paywall({
643
904
  title = "Upgrade to unlock this feature",
644
905
  description = "This feature isn't included in your current plan.",
645
906
  ctaLabel = "Upgrade",
646
- onUpgrade
907
+ onUpgrade,
908
+ sample = false
647
909
  }) {
648
910
  const { allowed, loading } = useEntitlement(feature);
649
911
  const { tokens } = useMonetizeKit();
650
- if (loading) {
912
+ if (!sample && loading) {
651
913
  return /* @__PURE__ */ jsx("div", { "aria-busy": "true", style: { color: "var(--mk-muted)" }, children: "Checking access\u2026" });
652
914
  }
653
- if (allowed) {
915
+ if (!sample && allowed) {
654
916
  return /* @__PURE__ */ jsx(Fragment, { children });
655
917
  }
656
918
  return /* @__PURE__ */ jsxs("div", { style: { ...tokensToStyle(tokens), ...overlayStyle }, "data-mk-component": "paywall", children: [
@@ -729,6 +991,94 @@ function UsageBanner({
729
991
  over ? /* @__PURE__ */ jsx("span", { style: { color: "var(--mk-danger)", fontSize: "0.75rem" }, children: "Over included allotment \u2014 overage billed per usage pricing." }) : null
730
992
  ] });
731
993
  }
994
+ var VARIANT_COLOR = {
995
+ info: "var(--mk-accent)",
996
+ warning: "var(--mk-warning)",
997
+ danger: "var(--mk-danger)",
998
+ neutral: "var(--mk-muted)"
999
+ };
1000
+ function actionStyle(variant, accent) {
1001
+ if (variant === "ghost") {
1002
+ return {
1003
+ background: "transparent",
1004
+ color: "var(--mk-muted)",
1005
+ border: "none",
1006
+ cursor: "pointer",
1007
+ fontSize: "0.8125rem",
1008
+ fontWeight: 600,
1009
+ padding: "0.375rem 0.5rem"
1010
+ };
1011
+ }
1012
+ return {
1013
+ background: accent,
1014
+ color: "var(--mk-card)",
1015
+ border: "none",
1016
+ borderRadius: "var(--mk-radius)",
1017
+ cursor: "pointer",
1018
+ fontSize: "0.8125rem",
1019
+ fontWeight: 600,
1020
+ padding: "0.375rem 0.75rem"
1021
+ };
1022
+ }
1023
+ function AlertBanner({
1024
+ variant = "info",
1025
+ title,
1026
+ description,
1027
+ progress,
1028
+ actions = [],
1029
+ icon
1030
+ }) {
1031
+ const { tokens } = useMonetizeKit();
1032
+ const accent = VARIANT_COLOR[variant];
1033
+ return /* @__PURE__ */ jsxs(
1034
+ "div",
1035
+ {
1036
+ role: "status",
1037
+ "data-mk-component": "alert-banner",
1038
+ "data-mk-variant": variant,
1039
+ style: {
1040
+ ...tokensToStyle(tokens),
1041
+ display: "flex",
1042
+ gap: "0.75rem",
1043
+ alignItems: "flex-start",
1044
+ border: `1px solid color-mix(in srgb, ${accent} 35%, var(--mk-border))`,
1045
+ background: `color-mix(in srgb, ${accent} 8%, var(--mk-card))`,
1046
+ color: "var(--mk-card-fg)",
1047
+ borderRadius: "var(--mk-radius)",
1048
+ padding: "0.875rem 1rem",
1049
+ fontFamily: "var(--mk-font)"
1050
+ },
1051
+ children: [
1052
+ icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { color: accent, fontSize: "1.1rem", lineHeight: 1 }, children: icon }) : null,
1053
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
1054
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, fontSize: "0.875rem" }, children: title }),
1055
+ description ? /* @__PURE__ */ jsx("div", { style: { fontSize: "0.8125rem", color: "var(--mk-muted)" }, children: description }) : null,
1056
+ typeof progress === "number" ? /* @__PURE__ */ jsx(
1057
+ "div",
1058
+ {
1059
+ style: { height: 6, borderRadius: 999, background: "var(--mk-border)", overflow: "hidden" },
1060
+ role: "progressbar",
1061
+ "aria-valuenow": Math.round(Math.min(1, Math.max(0, progress)) * 100),
1062
+ "aria-valuemin": 0,
1063
+ "aria-valuemax": 100,
1064
+ children: /* @__PURE__ */ jsx("div", { style: { width: `${Math.min(1, Math.max(0, progress)) * 100}%`, height: "100%", background: accent } })
1065
+ }
1066
+ ) : null,
1067
+ actions.length > 0 ? /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: actions.map((action) => /* @__PURE__ */ jsx(
1068
+ "button",
1069
+ {
1070
+ type: "button",
1071
+ onClick: action.onClick,
1072
+ style: actionStyle(action.variant, accent),
1073
+ children: action.label
1074
+ },
1075
+ action.label
1076
+ )) }) : null
1077
+ ] })
1078
+ ]
1079
+ }
1080
+ );
1081
+ }
732
1082
  var containerStyle = {
733
1083
  border: "1px solid var(--mk-border)",
734
1084
  borderRadius: "var(--mk-radius)",
@@ -961,6 +1311,6 @@ function EntitlementGate({
961
1311
  return /* @__PURE__ */ jsx(Fragment, { children: allowed ? children : fallback });
962
1312
  }
963
1313
 
964
- export { CustomerPortal, EntitlementGate, MonetizeKitClient, MonetizeKitProvider, Paywall, PricingTable, SAMPLE_CREDITS, SAMPLE_INVOICES, SAMPLE_NOTICE_TEXT, SAMPLE_PLANS, SAMPLE_PORTAL, SAMPLE_TEAM, SAMPLE_USAGE, SampleNotice, THEME_PRESETS, THEME_PRESET_NAMES, UsageBanner, describePlanPrice, describeUsageTerm, formatMoney, formatUnits, resolveTokens, tokensToStyle, useCredits, useEntitlement, useMonetizeKit, useUsage };
1314
+ export { AlertBanner, BillingCycleToggle, CustomerPortal, EntitlementGate, MonetizeKitClient, MonetizeKitProvider, Paywall, PricingComparison, PricingTable, SAMPLE_CREDITS, SAMPLE_INVOICES, SAMPLE_NOTICE_TEXT, SAMPLE_PLANS, SAMPLE_PORTAL, SAMPLE_TEAM, SAMPLE_USAGE, SampleNotice, THEME_PRESETS, THEME_PRESET_NAMES, UsageBanner, describePlanPrice, describeUsageTerm, formatMoney, formatUnits, resolveTokens, tokensToStyle, useCredits, useEntitlement, useMonetizeKit, useUsage };
965
1315
  //# sourceMappingURL=index.js.map
966
1316
  //# sourceMappingURL=index.js.map