myoperator-ui 0.0.166 → 0.0.167-beta.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.
Files changed (2) hide show
  1. package/dist/index.js +1239 -17
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8566,7 +8566,13 @@ import {
8566
8566
  DialogTitle,
8567
8567
  } from "../dialog";
8568
8568
  import { PaymentOptionCard } from "./payment-option-card";
8569
- import type { PaymentOptionCardModalProps } from "./types";
8569
+ import type { PaymentOptionCardProps } from "./types";
8570
+
8571
+ interface PaymentOptionCardModalProps
8572
+ extends Omit<PaymentOptionCardProps, "onClose"> {
8573
+ open: boolean;
8574
+ onOpenChange: (open: boolean) => void;
8575
+ }
8570
8576
 
8571
8577
  /**
8572
8578
  * PaymentOptionCardModal wraps the PaymentOptionCard in a centered Dialog overlay.
@@ -8694,30 +8700,1246 @@ export interface PaymentOptionCardProps {
8694
8700
  /** Additional className for the root element */
8695
8701
  className?: string;
8696
8702
  }
8703
+ `, prefix)
8704
+ },
8705
+ {
8706
+ name: "index.ts",
8707
+ content: prefixTailwindClasses(`export { PaymentOptionCard } from "./payment-option-card";
8708
+ export { PaymentOptionCardModal } from "./payment-option-card-modal";
8709
+ export type { PaymentOptionCardProps, PaymentOption } from "./types";
8710
+ `, prefix)
8711
+ }
8712
+ ]
8713
+ },
8714
+ "let-us-drive-card": {
8715
+ name: "let-us-drive-card",
8716
+ description: "A managed service card with pricing, billing badge, 'Show details' link, and CTA for the full-service management section",
8717
+ category: "custom",
8718
+ dependencies: [
8719
+ "clsx",
8720
+ "tailwind-merge"
8721
+ ],
8722
+ internalDependencies: [
8723
+ "button",
8724
+ "badge"
8725
+ ],
8726
+ isMultiFile: true,
8727
+ directory: "let-us-drive-card",
8728
+ mainFile: "let-us-drive-card.tsx",
8729
+ files: [
8730
+ {
8731
+ name: "let-us-drive-card.tsx",
8732
+ content: prefixTailwindClasses(`import * as React from "react";
8733
+ import { cn } from "../../../lib/utils";
8734
+ import { Button } from "../button";
8735
+ import { Badge } from "../badge";
8736
+ import type { LetUsDriveCardProps } from "./types";
8697
8737
 
8698
8738
  /**
8699
- * Props for the PaymentOptionCardModal component.
8700
- * Extends the card props with Dialog open/close control, omitting \`onClose\`
8701
- * which is handled internally by the modal.
8739
+ * LetUsDriveCard displays a managed service offering with pricing, billing
8740
+ * frequency badge, and a CTA. Used in the "Let us drive \u2014 Full-service
8741
+ * management" section of the pricing page.
8742
+ *
8743
+ * Supports a "free/discount" state where the original price is shown with
8744
+ * strikethrough and a green label (e.g., "FREE") replaces it.
8745
+ *
8746
+ * @example
8747
+ * \`\`\`tsx
8748
+ * <LetUsDriveCard
8749
+ * title="Account Manager"
8750
+ * price="15,000"
8751
+ * period="/month"
8752
+ * billingBadge="Annually"
8753
+ * description="One expert who knows your business. And moves it forward."
8754
+ * onShowDetails={() => console.log("details")}
8755
+ * onCtaClick={() => console.log("talk")}
8756
+ * />
8757
+ * \`\`\`
8702
8758
  */
8703
- export interface PaymentOptionCardModalProps
8704
- extends Omit<PaymentOptionCardProps, "onClose"> {
8705
- /** Whether the modal is open */
8706
- open: boolean;
8707
- /** Callback when modal should open or close */
8708
- onOpenChange: (open: boolean) => void;
8759
+ const LetUsDriveCard = React.forwardRef<HTMLDivElement, LetUsDriveCardProps>(
8760
+ (
8761
+ {
8762
+ title,
8763
+ price,
8764
+ period,
8765
+ startsAt = false,
8766
+ billingBadge,
8767
+ description,
8768
+ freeLabel,
8769
+ showDetailsLabel = "Show details",
8770
+ ctaLabel = "Talk to us",
8771
+ onShowDetails,
8772
+ onCtaClick,
8773
+ className,
8774
+ ...props
8775
+ },
8776
+ ref
8777
+ ) => {
8778
+ return (
8779
+ <div
8780
+ ref={ref}
8781
+ className={cn(
8782
+ "flex flex-col gap-6 rounded-[14px] border border-semantic-border-layout bg-card p-5",
8783
+ className
8784
+ )}
8785
+ {...props}
8786
+ >
8787
+ {/* Header: title + optional billing badge */}
8788
+ <div className="flex items-center justify-between">
8789
+ <h3 className="text-base font-semibold text-semantic-text-primary m-0">
8790
+ {title}
8791
+ </h3>
8792
+ {billingBadge && (
8793
+ <Badge
8794
+ size="sm"
8795
+ className="bg-semantic-info-surface text-semantic-info-primary font-normal"
8796
+ >
8797
+ {billingBadge}
8798
+ </Badge>
8799
+ )}
8800
+ </div>
8801
+
8802
+ {/* Price section */}
8803
+ <div className="flex flex-col gap-2.5">
8804
+ {startsAt && (
8805
+ <span className="text-xs text-semantic-text-muted tracking-[0.048px]">
8806
+ Starts at
8807
+ </span>
8808
+ )}
8809
+ <div className="flex gap-1 items-end">
8810
+ {freeLabel ? (
8811
+ <span className="text-[28px] font-semibold leading-[36px]">
8812
+ <span className="line-through text-semantic-text-muted">
8813
+ \u20B9{price}
8814
+ </span>{" "}
8815
+ <span className="text-semantic-success-primary">
8816
+ {freeLabel}
8817
+ </span>
8818
+ </span>
8819
+ ) : (
8820
+ <span className="text-[28px] font-semibold leading-[36px] text-semantic-text-primary">
8821
+ \u20B9{price}
8822
+ </span>
8823
+ )}
8824
+ {period && (
8825
+ <span className="text-sm text-semantic-text-muted tracking-[0.035px]">
8826
+ {period}
8827
+ </span>
8828
+ )}
8829
+ </div>
8830
+
8831
+ {/* Description */}
8832
+ <p className="text-sm text-semantic-text-secondary tracking-[0.035px] m-0">
8833
+ {description}
8834
+ </p>
8835
+ </div>
8836
+
8837
+ {/* Actions: Show details link + CTA button */}
8838
+ <div className="flex flex-col gap-3 w-full">
8839
+ {onShowDetails && (
8840
+ <Button
8841
+ variant="link"
8842
+ className="text-semantic-text-link p-0 h-auto min-w-0 justify-start"
8843
+ onClick={onShowDetails}
8844
+ >
8845
+ {showDetailsLabel}
8846
+ </Button>
8847
+ )}
8848
+ <Button variant="outline" className="w-full" onClick={onCtaClick}>
8849
+ {ctaLabel}
8850
+ </Button>
8851
+ </div>
8852
+ </div>
8853
+ );
8854
+ }
8855
+ );
8856
+
8857
+ LetUsDriveCard.displayName = "LetUsDriveCard";
8858
+
8859
+ export { LetUsDriveCard };
8860
+ `, prefix)
8861
+ },
8862
+ {
8863
+ name: "types.ts",
8864
+ content: prefixTailwindClasses(`import * as React from "react";
8865
+
8866
+ /**
8867
+ * Props for the LetUsDriveCard component.
8868
+ */
8869
+ export interface LetUsDriveCardProps
8870
+ extends React.HTMLAttributes<HTMLDivElement> {
8871
+ /** Service title (e.g., "Dedicated Onboarding", "Account Manager") */
8872
+ title: string;
8873
+ /** Price amount as formatted string (e.g., "20,000", "15,000") */
8874
+ price: string;
8875
+ /** Billing period label (e.g., "/one-time fee", "/month") */
8876
+ period?: string;
8877
+ /** Show "Starts at" prefix above the price */
8878
+ startsAt?: boolean;
8879
+ /** Billing frequency badge text (e.g., "Annually", "Quarterly") */
8880
+ billingBadge?: string;
8881
+ /** Service description text */
8882
+ description: string;
8883
+ /** When provided, price is shown with strikethrough and this label (e.g., "FREE") is displayed in green */
8884
+ freeLabel?: string;
8885
+ /** Text for the details link (default: "Show details") */
8886
+ showDetailsLabel?: string;
8887
+ /** CTA button text (default: "Talk to us") */
8888
+ ctaLabel?: string;
8889
+ /** Callback when "Show details" link is clicked */
8890
+ onShowDetails?: () => void;
8891
+ /** Callback when CTA button is clicked */
8892
+ onCtaClick?: () => void;
8709
8893
  }
8710
8894
  `, prefix)
8711
8895
  },
8712
8896
  {
8713
8897
  name: "index.ts",
8714
- content: prefixTailwindClasses(`export { PaymentOptionCard } from "./payment-option-card";
8715
- export { PaymentOptionCardModal } from "./payment-option-card-modal";
8716
- export type {
8717
- PaymentOptionCardProps,
8718
- PaymentOptionCardModalProps,
8719
- PaymentOption,
8720
- } from "./types";
8898
+ content: prefixTailwindClasses(`export { LetUsDriveCard } from "./let-us-drive-card";
8899
+ export type { LetUsDriveCardProps } from "./types";
8900
+ `, prefix)
8901
+ }
8902
+ ]
8903
+ },
8904
+ "power-up-card": {
8905
+ name: "power-up-card",
8906
+ description: "An add-on service card with icon, title, pricing, description, and CTA button for the power-ups section",
8907
+ category: "custom",
8908
+ dependencies: [
8909
+ "clsx",
8910
+ "tailwind-merge"
8911
+ ],
8912
+ internalDependencies: [
8913
+ "button"
8914
+ ],
8915
+ isMultiFile: true,
8916
+ directory: "power-up-card",
8917
+ mainFile: "power-up-card.tsx",
8918
+ files: [
8919
+ {
8920
+ name: "power-up-card.tsx",
8921
+ content: prefixTailwindClasses(`import * as React from "react";
8922
+ import { cn } from "../../../lib/utils";
8923
+ import { Button } from "../button";
8924
+ import type { PowerUpCardProps } from "./types";
8925
+
8926
+ /**
8927
+ * PowerUpCard displays an add-on service with icon, pricing, description,
8928
+ * and a CTA button. Used in the "Power-ups and charges" section of
8929
+ * the pricing page.
8930
+ *
8931
+ * @example
8932
+ * \`\`\`tsx
8933
+ * <PowerUpCard
8934
+ * icon={<PhoneCall className="size-6" />}
8935
+ * title="Auto-Dialer"
8936
+ * price="Starts @ \u20B9700/user/month"
8937
+ * description="Available for SUV & Enterprise plans as an add-on per user."
8938
+ * onCtaClick={() => console.log("clicked")}
8939
+ * />
8940
+ * \`\`\`
8941
+ */
8942
+ const PowerUpCard = React.forwardRef<HTMLDivElement, PowerUpCardProps>(
8943
+ (
8944
+ {
8945
+ icon,
8946
+ title,
8947
+ price,
8948
+ description,
8949
+ ctaLabel = "Talk to us",
8950
+ onCtaClick,
8951
+ className,
8952
+ ...props
8953
+ },
8954
+ ref
8955
+ ) => {
8956
+ return (
8957
+ <div
8958
+ ref={ref}
8959
+ className={cn(
8960
+ "flex flex-col justify-between gap-8 rounded-md border border-semantic-border-layout bg-card p-5",
8961
+ className
8962
+ )}
8963
+ {...props}
8964
+ >
8965
+ {/* Content */}
8966
+ <div className="flex flex-col gap-4">
8967
+ {/* Icon + title/price row */}
8968
+ <div className="flex gap-4 items-start">
8969
+ {icon && (
8970
+ <div className="flex items-center justify-center size-[47px] rounded bg-[var(--color-info-25)] shrink-0">
8971
+ {icon}
8972
+ </div>
8973
+ )}
8974
+ <div className="flex flex-col gap-2 min-w-0">
8975
+ <h3 className="text-base font-semibold text-semantic-text-primary m-0 leading-normal">
8976
+ {title}
8977
+ </h3>
8978
+ <p className="text-sm text-semantic-text-primary tracking-[0.035px] m-0 leading-normal">
8979
+ {price}
8980
+ </p>
8981
+ </div>
8982
+ </div>
8983
+
8984
+ {/* Description */}
8985
+ <p className="text-sm text-semantic-text-secondary tracking-[0.035px] m-0 leading-normal">
8986
+ {description}
8987
+ </p>
8988
+ </div>
8989
+
8990
+ {/* CTA */}
8991
+ <Button variant="outline" className="w-full" onClick={onCtaClick}>
8992
+ {ctaLabel}
8993
+ </Button>
8994
+ </div>
8995
+ );
8996
+ }
8997
+ );
8998
+
8999
+ PowerUpCard.displayName = "PowerUpCard";
9000
+
9001
+ export { PowerUpCard };
9002
+ `, prefix)
9003
+ },
9004
+ {
9005
+ name: "types.ts",
9006
+ content: prefixTailwindClasses(`import * as React from "react";
9007
+
9008
+ /**
9009
+ * Props for the PowerUpCard component.
9010
+ */
9011
+ export interface PowerUpCardProps
9012
+ extends React.HTMLAttributes<HTMLDivElement> {
9013
+ /** Icon or illustration displayed in the tinted container */
9014
+ icon?: React.ReactNode;
9015
+ /** Service title (e.g., "Truecaller business") */
9016
+ title: string;
9017
+ /** Pricing text (e.g., "Starts @ \u20B930,000/month") */
9018
+ price: string;
9019
+ /** Description explaining the service value */
9020
+ description: string;
9021
+ /** CTA button label (default: "Talk to us") */
9022
+ ctaLabel?: string;
9023
+ /** Callback when CTA button is clicked */
9024
+ onCtaClick?: () => void;
9025
+ }
9026
+ `, prefix)
9027
+ },
9028
+ {
9029
+ name: "index.ts",
9030
+ content: prefixTailwindClasses(`export { PowerUpCard } from "./power-up-card";
9031
+ export type { PowerUpCardProps } from "./types";
9032
+ `, prefix)
9033
+ }
9034
+ ]
9035
+ },
9036
+ "pricing-card": {
9037
+ name: "pricing-card",
9038
+ description: "A pricing tier card with plan name, pricing, feature checklist, CTA button, and optional popularity badge and addon footer",
9039
+ category: "custom",
9040
+ dependencies: [
9041
+ "clsx",
9042
+ "tailwind-merge",
9043
+ "lucide-react"
9044
+ ],
9045
+ internalDependencies: [
9046
+ "button",
9047
+ "badge"
9048
+ ],
9049
+ isMultiFile: true,
9050
+ directory: "pricing-card",
9051
+ mainFile: "pricing-card.tsx",
9052
+ files: [
9053
+ {
9054
+ name: "pricing-card.tsx",
9055
+ content: prefixTailwindClasses(`import * as React from "react";
9056
+ import { cn } from "../../../lib/utils";
9057
+ import { Button } from "../button";
9058
+ import { Badge } from "../badge";
9059
+ import { CircleCheck } from "lucide-react";
9060
+ import type { PricingCardProps } from "./types";
9061
+
9062
+ /**
9063
+ * PricingCard displays a plan tier with pricing, features, and a CTA button.
9064
+ * Supports current-plan state (outlined button), popularity badge, and an
9065
+ * optional add-on footer.
9066
+ *
9067
+ * @example
9068
+ * \`\`\`tsx
9069
+ * <PricingCard
9070
+ * planName="Compact"
9071
+ * price="2,5000"
9072
+ * planDetails="3 Users | 12 Month plan"
9073
+ * description="For small teams that need a WhatsApp-first plan"
9074
+ * headerBgColor="#d7eae9"
9075
+ * features={["WhatsApp Campaigns", "Missed Call Tracking"]}
9076
+ * onCtaClick={() => console.log("selected")}
9077
+ * onFeatureDetails={() => console.log("details")}
9078
+ * />
9079
+ * \`\`\`
9080
+ */
9081
+ const PricingCard = React.forwardRef<HTMLDivElement, PricingCardProps>(
9082
+ (
9083
+ {
9084
+ planName,
9085
+ price,
9086
+ period = "/Month",
9087
+ planDetails,
9088
+ planIcon,
9089
+ description,
9090
+ headerBgColor,
9091
+ features = [],
9092
+ isCurrentPlan = false,
9093
+ showPopularBadge = false,
9094
+ badgeText = "MOST POPULAR",
9095
+ ctaText,
9096
+ onCtaClick,
9097
+ onFeatureDetails,
9098
+ addon,
9099
+ usageDetails,
9100
+ className,
9101
+ ...props
9102
+ },
9103
+ ref
9104
+ ) => {
9105
+ const buttonText =
9106
+ ctaText || (isCurrentPlan ? "Current plan" : "Select plan");
9107
+
9108
+ return (
9109
+ <div
9110
+ ref={ref}
9111
+ className={cn(
9112
+ "flex flex-col gap-6 rounded-t-xl rounded-b-lg border border-semantic-border-layout p-4",
9113
+ className
9114
+ )}
9115
+ {...props}
9116
+ >
9117
+ {/* Header */}
9118
+ <div
9119
+ className="flex flex-col gap-4 rounded-t-xl rounded-b-lg p-4"
9120
+ style={
9121
+ headerBgColor ? { backgroundColor: headerBgColor } : undefined
9122
+ }
9123
+ >
9124
+ {/* Plan name + badge */}
9125
+ <div className="flex items-center gap-4">
9126
+ <h3 className="text-xl font-semibold text-semantic-text-primary m-0">
9127
+ {planName}
9128
+ </h3>
9129
+ {showPopularBadge && (
9130
+ <Badge
9131
+ size="sm"
9132
+ className="bg-[#e3fdfe] text-[#119ba8] uppercase tracking-wider font-semibold"
9133
+ >
9134
+ {badgeText}
9135
+ </Badge>
9136
+ )}
9137
+ </div>
9138
+
9139
+ {/* Price */}
9140
+ <div className="flex flex-col gap-2.5">
9141
+ <div className="flex items-end gap-1">
9142
+ <span className="text-4xl leading-[44px] text-semantic-text-primary">
9143
+ \u20B9{price}
9144
+ </span>
9145
+ <span className="text-sm text-semantic-text-muted tracking-[0.035px]">
9146
+ {period}
9147
+ </span>
9148
+ </div>
9149
+ {planDetails && (
9150
+ <p className="text-sm tracking-[0.035px] text-semantic-text-primary m-0">
9151
+ {planDetails}
9152
+ </p>
9153
+ )}
9154
+ </div>
9155
+
9156
+ {/* Plan icon */}
9157
+ {planIcon && <div className="size-[30px]">{planIcon}</div>}
9158
+
9159
+ {/* Description */}
9160
+ {description && (
9161
+ <p className="text-sm text-semantic-text-secondary tracking-[0.035px] m-0">
9162
+ {description}
9163
+ </p>
9164
+ )}
9165
+
9166
+ {/* Feature details link + CTA */}
9167
+ <div className="flex flex-col gap-3.5 w-full">
9168
+ {onFeatureDetails && (
9169
+ <div className="flex justify-center">
9170
+ <Button
9171
+ variant="link"
9172
+ className="text-semantic-text-link p-0 h-auto min-w-0"
9173
+ onClick={onFeatureDetails}
9174
+ >
9175
+ Feature details
9176
+ </Button>
9177
+ </div>
9178
+ )}
9179
+ <Button
9180
+ variant={isCurrentPlan ? "outline" : "default"}
9181
+ className="w-full"
9182
+ onClick={onCtaClick}
9183
+ >
9184
+ {buttonText}
9185
+ </Button>
9186
+ </div>
9187
+ </div>
9188
+
9189
+ {/* Features */}
9190
+ {features.length > 0 && (
9191
+ <div className="flex flex-col gap-4">
9192
+ <p className="text-sm font-semibold text-semantic-text-primary tracking-[0.014px] uppercase m-0">
9193
+ Includes
9194
+ </p>
9195
+ <div className="flex flex-col gap-4">
9196
+ {features.map((feature, index) => {
9197
+ const text =
9198
+ typeof feature === "string" ? feature : feature.text;
9199
+ const isBold =
9200
+ typeof feature !== "string" && feature.bold;
9201
+ return (
9202
+ <div key={index} className="flex items-start gap-2">
9203
+ <CircleCheck className="size-[18px] text-semantic-text-secondary shrink-0 mt-0.5" />
9204
+ <span
9205
+ className={cn(
9206
+ "text-sm text-semantic-text-secondary tracking-[0.035px]",
9207
+ isBold && "font-semibold"
9208
+ )}
9209
+ >
9210
+ {text}
9211
+ </span>
9212
+ </div>
9213
+ );
9214
+ })}
9215
+ </div>
9216
+ </div>
9217
+ )}
9218
+
9219
+ {/* Addon */}
9220
+ {addon && (
9221
+ <div className="flex items-center gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] pl-4 py-2.5">
9222
+ {addon.icon && (
9223
+ <div className="size-5 shrink-0">{addon.icon}</div>
9224
+ )}
9225
+ <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
9226
+ {addon.text}
9227
+ </span>
9228
+ </div>
9229
+ )}
9230
+
9231
+ {/* Usage Details */}
9232
+ {usageDetails && usageDetails.length > 0 && (
9233
+ <div className="flex flex-col gap-2.5 rounded-md bg-[var(--color-info-25)] border border-[#f3f5f6] px-4 py-2.5">
9234
+ {usageDetails.map((detail, index) => (
9235
+ <div key={index} className="flex items-start gap-2">
9236
+ <span className="size-1.5 rounded-full bg-semantic-primary shrink-0 mt-[7px]" />
9237
+ <span className="text-sm text-semantic-text-primary tracking-[0.035px]">
9238
+ <strong>{detail.label}:</strong> {detail.value}
9239
+ </span>
9240
+ </div>
9241
+ ))}
9242
+ </div>
9243
+ )}
9244
+ </div>
9245
+ );
9246
+ }
9247
+ );
9248
+
9249
+ PricingCard.displayName = "PricingCard";
9250
+
9251
+ export { PricingCard };
9252
+ `, prefix)
9253
+ },
9254
+ {
9255
+ name: "plan-icons.tsx",
9256
+ content: prefixTailwindClasses(`import * as React from "react";
9257
+
9258
+ interface PlanIconProps extends React.SVGAttributes<SVGElement> {
9259
+ className?: string;
9260
+ }
9261
+
9262
+ const CompactCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
9263
+ ({ className, ...props }, ref) => (
9264
+ <svg
9265
+ ref={ref}
9266
+ className={className}
9267
+ viewBox="0 0 30 19"
9268
+ fill="none"
9269
+ xmlns="http://www.w3.org/2000/svg"
9270
+ {...props}
9271
+ >
9272
+ <ellipse cx="25.2" cy="14.72" rx="3.33" ry="3.03" fill="white" />
9273
+ <path
9274
+ d="M25.12 11.21c-1.95 0-3.5 1.56-3.5 3.5 0 1.95 1.55 3.5 3.5 3.5 1.94 0 3.5-1.55 3.5-3.5 0-1.94-1.56-3.5-3.5-3.5zm0 5.45c-1.09 0-2.02-.93-2.02-2.02s.93-2.02 2.02-2.02 2.02.93 2.02 2.02-.93 2.02-2.02 2.02z"
9275
+ stroke="#2BBAC8"
9276
+ strokeLinejoin="round"
9277
+ />
9278
+ <ellipse cx="4.09" cy="14.72" rx="3.33" ry="3.03" fill="white" />
9279
+ <path
9280
+ d="M4.26 11.21c-1.95 0-3.5 1.56-3.5 3.5 0 1.95 1.55 3.5 3.5 3.5 1.94 0 3.5-1.55 3.5-3.5 0-1.94-1.56-3.5-3.5-3.5zm0 5.45c-1.09 0-2.02-.93-2.02-2.02s.93-2.02 2.02-2.02 2.02.93 2.02 2.02-.93 2.02-2.02 2.02z"
9281
+ stroke="#2BBAC8"
9282
+ strokeLinejoin="round"
9283
+ />
9284
+ <path
9285
+ d="M28.85 12.38c-.08-.16-.31-.31-.39-.47-.16-.39-.16-1.09-.23-1.48-.31-1.17-1.17-2.02-2.02-2.72-1.64-1.25-3.66-2.57-5.45-3.74C18 2.11 15.85.78 12.35.63c-1.79-.08-4.51 0-6.23.23-.15 0-1.4.31-1.24.62 1.25.23.55.93.24 1.63-.31.62-1.09 2.49-1.64 2.8-.15 0-.23.08-.31 0-.23-.31.16-1.4.31-1.71.16-.47.86-1.4.93-1.79 0-.31 0-.7-.39-.62L2.62 4.75c-.62 1.17-.62 2.18-.78 3.42-.15 1.56-1.09 2.88-1.24 4.36 0 .16 0 .39 0 .54.08.31.23.31.47.08.54-1.17 1.71-2.02 3.11-2.02 1.4 0 3.5 1.56 3.5 3.5s-.08 1.86-.23 2.25l.85-.08h11.75c.78-.08 1.4-.47 1.56-1.24 0-1.79 1.56-3.35 3.5-3.35 1.95 0 3.5 1.56 3.5 3.5 0 1.95-.16.93 0 1.09 1.09-.54.86-2.57.23-3.35v-.08z"
9286
+ fill="white"
9287
+ stroke="currentColor"
9288
+ strokeWidth="1.2"
9289
+ strokeLinejoin="round"
9290
+ />
9291
+ <path
9292
+ d="M10.02 1.41c3.81-.23 8.56 1.4 11.44 3.89 2.88 2.49 1.79 1.64.16 1.79-3.58-.31-7.16-.62-10.74-.93-.86 0-2.65 0-3.27-.47-.62-.47-.54-1.87-.23-2.72.54-1.25 1.4-1.48 2.64-1.56z"
9293
+ stroke="currentColor"
9294
+ strokeWidth="1.2"
9295
+ strokeLinejoin="round"
9296
+ />
9297
+ </svg>
9298
+ )
9299
+ );
9300
+ CompactCarIcon.displayName = "CompactCarIcon";
9301
+
9302
+ const SedanCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
9303
+ ({ className, ...props }, ref) => (
9304
+ <svg
9305
+ ref={ref}
9306
+ className={className}
9307
+ viewBox="0 0 31 13"
9308
+ fill="none"
9309
+ xmlns="http://www.w3.org/2000/svg"
9310
+ {...props}
9311
+ >
9312
+ <ellipse cx="24.98" cy="9.51" rx="2.19" ry="2.56" fill="white" />
9313
+ <path
9314
+ d="M24.8 7.16c-1.33 0-2.38 1.09-2.38 2.45 0 1.37 1.05 2.46 2.38 2.46 1.33 0 2.38-1.09 2.38-2.46 0-1.36-1.05-2.45-2.38-2.45zm0 3.82c-.74 0-1.38-.66-1.38-1.42 0-.76.64-1.42 1.38-1.42.74 0 1.38.66 1.38 1.42 0 .76-.64 1.42-1.38 1.42z"
9315
+ stroke="#2BBAC8"
9316
+ strokeLinejoin="round"
9317
+ />
9318
+ <ellipse cx="6.33" cy="9.51" rx="2.19" ry="2.56" fill="white" />
9319
+ <path
9320
+ d="M6.32 7.16c-1.32 0-2.38 1.09-2.38 2.45 0 1.37 1.06 2.46 2.38 2.46 1.33 0 2.39-1.09 2.39-2.46 0-1.36-1.06-2.45-2.39-2.45zm0 3.82c-.74 0-1.38-.66-1.38-1.42 0-.76.64-1.42 1.38-1.42.74 0 1.38.66 1.38 1.42 0 .76-.64 1.42-1.38 1.42z"
9321
+ stroke="#2BBAC8"
9322
+ strokeLinejoin="round"
9323
+ />
9324
+ <path
9325
+ d="M29.7 7.79l-.24.81c0 .08-.16.4-.23.49-.24.16-1.97.57-2.05.49.24-1.22-.47-2.6-1.57-3 -2.05-.81-4.09 1.05-3.54 3.24H8.99v-.81c0-.32-.39-1.05-.55-1.3C7.03 5.6 4.27 6.33 3.8 8.6c-.47 2.27 0 .49 0 .49l-2.28-.41C.81 8.27.49 7.14.73 6.33c.23-.81.39-.57.39-.73.08-.49-.16-1.62.16-2.03.31-.4 1.97-.4 2.44-.57 1.42-.4 2.76-1.22 4.17-1.62 2.91-.89 6.61-1.05 9.53 0 2.91 1.05 3.7 1.95 5.51 2.51 1.81.57 4.09.65 5.83 1.62 1.73.97.62 1.05.93 1.78v.57z"
9326
+ fill="white"
9327
+ stroke="currentColor"
9328
+ strokeWidth="1.3"
9329
+ strokeLinejoin="round"
9330
+ />
9331
+ <path
9332
+ d="M13.48 1.38l.63 2.6 4.8.16c0-.32 0-.64.32-.89-1.58-1.38-3.78-1.78-5.83-1.87h.08z"
9333
+ stroke="currentColor"
9334
+ strokeWidth="1.3"
9335
+ strokeLinejoin="round"
9336
+ />
9337
+ <path
9338
+ d="M8.99 1.87s-.63.97-.63 1.05c0 .16.16.65.24.81l4.41.16-.39-2.51c-.87 0-1.81 0-2.68.16-.87.16-.87.16-.95.24v.09z"
9339
+ stroke="currentColor"
9340
+ strokeWidth="1.3"
9341
+ strokeLinejoin="round"
9342
+ />
9343
+ <path
9344
+ d="M6.08 3.81h1.18l1.26-1.78c-.47.32-2.2.81-2.36 1.3-.16.49 0 .32 0 .49h-.08z"
9345
+ stroke="currentColor"
9346
+ strokeWidth="1.3"
9347
+ strokeLinejoin="round"
9348
+ />
9349
+ </svg>
9350
+ )
9351
+ );
9352
+ SedanCarIcon.displayName = "SedanCarIcon";
9353
+
9354
+ const SuvCarIcon = React.forwardRef<SVGSVGElement, PlanIconProps>(
9355
+ ({ className, ...props }, ref) => (
9356
+ <svg
9357
+ ref={ref}
9358
+ className={className}
9359
+ viewBox="0 0 32 15"
9360
+ fill="none"
9361
+ xmlns="http://www.w3.org/2000/svg"
9362
+ {...props}
9363
+ >
9364
+ <ellipse cx="25.57" cy="11.14" rx="2.65" ry="2.78" fill="white" />
9365
+ <ellipse cx="9.12" cy="11.14" rx="2.89" ry="2.78" fill="white" />
9366
+ <path
9367
+ d="M25.32 8.18c-1.61 0-2.9 1.3-2.9 2.94 0 1.63 1.29 2.93 2.9 2.93 1.62 0 2.9-1.3 2.9-2.93 0-1.64-1.28-2.94-2.9-2.94zm0 4.57c-.9 0-1.68-.78-1.68-1.7 0-.91.78-1.69 1.68-1.69.9 0 1.68.78 1.68 1.7 0 .91-.78 1.69-1.68 1.69z"
9368
+ stroke="#2BBAC8"
9369
+ strokeWidth="1.2"
9370
+ strokeLinejoin="round"
9371
+ />
9372
+ <ellipse cx="9.14" cy="11.09" rx="1.4" ry="1.37" fill="white" />
9373
+ <path
9374
+ d="M8.96 8.18c-1.61 0-2.9 1.3-2.9 2.94 0 1.63 1.29 2.93 2.9 2.93 1.61 0 2.9-1.3 2.9-2.93 0-1.64-1.29-2.94-2.9-2.94zm0 4.57c-.9 0-1.68-.78-1.68-1.7 0-.91.78-1.69 1.68-1.69.9 0 1.68.78 1.68 1.7 0 .91-.78 1.69-1.68 1.69z"
9375
+ stroke="#2BBAC8"
9376
+ strokeWidth="1.2"
9377
+ strokeLinejoin="round"
9378
+ />
9379
+ <path
9380
+ d="M30.6 10.78l-.26.99c-.3 1-.36.56-1.09.64.48-3.15-2.66-5.79-5.13-3.7-.43.37-1.18 1.52-1.18 2.1v1.5H12.06c.33-2.62-1.84-5.01-4.24-4.06-1.53.61-2.13 2.39-1.98 4.06-1.61-.14-3.18.68-3.39-1.7-.05-.6.07-1.21-.04-1.8-.65-.34-1.63.37-1.75-.77C.57 7.13.59 4.97.67 4.03c.03-.33.06-.79.43-.87.28-.06 1.83-.08 1.83.26v1.49l.29-.06c.67-1.75.59-3.97 2.76-4.15 3.76-.3 7.87.23 11.67.02 1.75.22 4.02 3.02 5.39 4.18 1.24.15 2.5.24 3.73.44.5.09 1.95.3 2.31.56.7.49.57 2.79.67 2.91.02.03.37.04.56.26.19.23.12.47.28.67v1.03z"
9381
+ fill="white"
9382
+ stroke="currentColor"
9383
+ strokeWidth="1.2"
9384
+ strokeLinejoin="round"
9385
+ />
9386
+ <path
9387
+ d="M14.32 1.53c.25 1.41.16 2.98.61 4.32h6.22l.1-.21c-.48-1.34-1.41-2.72-2.51-3.53-.15-.11-.86-.59-.98-.59h-3.44z"
9388
+ stroke="currentColor"
9389
+ strokeWidth="1.2"
9390
+ strokeLinejoin="round"
9391
+ />
9392
+ <path
9393
+ d="M9.71 1.53l-.19 4.32h4.33c-.17-1.3-.17-2.78-.38-4.06-.02-.12-.04-.2-.14-.26H9.71z"
9394
+ stroke="currentColor"
9395
+ strokeWidth="1.2"
9396
+ strokeLinejoin="round"
9397
+ />
9398
+ <path
9399
+ d="M8.58 5.84l.29-4.07-.09-.31c-1.1.07-2.89-.32-3.46.95-.23.51-.74 2.67-.74 3.2 0 .12.01.13.1.21h3.91v-.01z"
9400
+ stroke="currentColor"
9401
+ strokeWidth="1.2"
9402
+ strokeLinejoin="round"
9403
+ />
9404
+ </svg>
9405
+ )
9406
+ );
9407
+ SuvCarIcon.displayName = "SuvCarIcon";
9408
+
9409
+ export { CompactCarIcon, SedanCarIcon, SuvCarIcon };
9410
+ `, prefix)
9411
+ },
9412
+ {
9413
+ name: "types.ts",
9414
+ content: prefixTailwindClasses(`import * as React from "react";
9415
+
9416
+ /**
9417
+ * Add-on info displayed at the bottom of the pricing card.
9418
+ */
9419
+ export interface PricingCardAddon {
9420
+ /** Icon rendered in the addon section */
9421
+ icon?: React.ReactNode;
9422
+ /** Addon description text */
9423
+ text: string;
9424
+ }
9425
+
9426
+ /**
9427
+ * A single usage detail item (e.g., "Usage: Includes 2,000 AI conversations/month").
9428
+ */
9429
+ export interface UsageDetail {
9430
+ /** Bold label (e.g., "Usage") */
9431
+ label: string;
9432
+ /** Value text (e.g., "Includes 2,000 AI conversations/month") */
9433
+ value: string;
9434
+ }
9435
+
9436
+ /**
9437
+ * A feature can be a plain string or an object with bold styling.
9438
+ */
9439
+ export type PricingCardFeature = string | { text: string; bold?: boolean };
9440
+
9441
+ /**
9442
+ * Props for the PricingCard component.
9443
+ */
9444
+ export interface PricingCardProps
9445
+ extends React.HTMLAttributes<HTMLDivElement> {
9446
+ /** Plan name displayed in the header (e.g., "Compact", "Sedan", "SUV") */
9447
+ planName: string;
9448
+ /** Price amount as formatted string (e.g., "2,5000") */
9449
+ price: string;
9450
+ /** Billing period label (default: "/Month") */
9451
+ period?: string;
9452
+ /** Plan detail line (e.g., "3 Users | 12 Month plan") */
9453
+ planDetails?: React.ReactNode;
9454
+ /** Plan icon or illustration */
9455
+ planIcon?: React.ReactNode;
9456
+ /** Plan description text */
9457
+ description?: string;
9458
+ /** Background color for the header section */
9459
+ headerBgColor?: string;
9460
+ /** List of included features shown with checkmarks. Supports bold items via object form. */
9461
+ features?: PricingCardFeature[];
9462
+ /** Whether this is the currently active plan (shows outlined button) */
9463
+ isCurrentPlan?: boolean;
9464
+ /** Show a popularity badge next to the plan name */
9465
+ showPopularBadge?: boolean;
9466
+ /** Custom badge text (defaults to "MOST POPULAR") */
9467
+ badgeText?: string;
9468
+ /** Custom CTA button text (overrides default "Select plan" / "Current plan") */
9469
+ ctaText?: string;
9470
+ /** Callback when CTA button is clicked */
9471
+ onCtaClick?: () => void;
9472
+ /** Callback when "Feature details" link is clicked */
9473
+ onFeatureDetails?: () => void;
9474
+ /** Add-on info displayed at the bottom of the card */
9475
+ addon?: PricingCardAddon;
9476
+ /** Usage details displayed in a bulleted list at the bottom (e.g., AIO plan) */
9477
+ usageDetails?: UsageDetail[];
9478
+ }
9479
+ `, prefix)
9480
+ },
9481
+ {
9482
+ name: "index.ts",
9483
+ content: prefixTailwindClasses(`export { PricingCard } from "./pricing-card";
9484
+ export { CompactCarIcon, SedanCarIcon, SuvCarIcon } from "./plan-icons";
9485
+ export type {
9486
+ PricingCardProps,
9487
+ PricingCardAddon,
9488
+ PricingCardFeature,
9489
+ UsageDetail,
9490
+ } from "./types";
9491
+ `, prefix)
9492
+ }
9493
+ ]
9494
+ },
9495
+ "pricing-page": {
9496
+ name: "pricing-page",
9497
+ description: "A full pricing page layout composing plan-type tabs, billing toggle, pricing cards grid, power-ups section, and let-us-drive managed services section",
9498
+ category: "custom",
9499
+ dependencies: [
9500
+ "clsx",
9501
+ "tailwind-merge",
9502
+ "lucide-react"
9503
+ ],
9504
+ internalDependencies: [
9505
+ "button",
9506
+ "page-header",
9507
+ "pricing-toggle",
9508
+ "pricing-card",
9509
+ "power-up-card",
9510
+ "let-us-drive-card"
9511
+ ],
9512
+ isMultiFile: true,
9513
+ directory: "pricing-page",
9514
+ mainFile: "pricing-page.tsx",
9515
+ files: [
9516
+ {
9517
+ name: "pricing-page.tsx",
9518
+ content: prefixTailwindClasses(`import * as React from "react";
9519
+ import { cn } from "../../../lib/utils";
9520
+ import { PageHeader } from "../page-header";
9521
+ import { Button } from "../button";
9522
+ import { PricingToggle } from "../pricing-toggle/pricing-toggle";
9523
+ import { PricingCard } from "../pricing-card/pricing-card";
9524
+ import { PowerUpCard } from "../power-up-card/power-up-card";
9525
+ import { LetUsDriveCard } from "../let-us-drive-card/let-us-drive-card";
9526
+ import { ExternalLink } from "lucide-react";
9527
+ import type { PricingPageProps } from "./types";
9528
+
9529
+ /**
9530
+ * PricingPage composes all plan-selection sub-components into a full
9531
+ * page layout: header, plan-type tabs with billing toggle, pricing
9532
+ * cards grid, power-ups section, and let-us-drive section.
9533
+ *
9534
+ * Supports controlled or uncontrolled tab / billing state.
9535
+ *
9536
+ * @example
9537
+ * \`\`\`tsx
9538
+ * <PricingPage
9539
+ * tabs={[
9540
+ * { label: "Team-Led Plans", value: "team" },
9541
+ * { label: "Go-AI First", value: "ai" },
9542
+ * ]}
9543
+ * planCards={compactCard, sedanCard, suvCard}
9544
+ * powerUpCards={[truecaller, tollFree, autoDialer]}
9545
+ * letUsDriveCards={[onboarding, accountMgr, managed]}
9546
+ * />
9547
+ * \`\`\`
9548
+ */
9549
+ const PricingPage = React.forwardRef<HTMLDivElement, PricingPageProps>(
9550
+ (
9551
+ {
9552
+ title = "Select business plan",
9553
+ headerActions,
9554
+ tabs = [],
9555
+ activeTab: controlledTab,
9556
+ onTabChange,
9557
+ showBillingToggle = false,
9558
+ billingPeriod: controlledBilling,
9559
+ onBillingPeriodChange,
9560
+ planCards = [],
9561
+ powerUpCards = [],
9562
+ powerUpsTitle = "Power-ups and charges",
9563
+ featureComparisonText = "See full feature comparison",
9564
+ onFeatureComparisonClick,
9565
+ letUsDriveCards = [],
9566
+ letUsDriveTitle = "Let us drive \u2014 Full-service management",
9567
+ className,
9568
+ ...props
9569
+ },
9570
+ ref
9571
+ ) => {
9572
+ // Internal state for uncontrolled mode
9573
+ const [internalTab, setInternalTab] = React.useState(
9574
+ tabs[0]?.value ?? ""
9575
+ );
9576
+ const [internalBilling, setInternalBilling] = React.useState<
9577
+ "monthly" | "yearly"
9578
+ >("monthly");
9579
+
9580
+ const currentTab = controlledTab ?? internalTab;
9581
+ const currentBilling = controlledBilling ?? internalBilling;
9582
+
9583
+ const handleTabChange = (value: string) => {
9584
+ if (!controlledTab) setInternalTab(value);
9585
+ onTabChange?.(value);
9586
+ };
9587
+
9588
+ const handleBillingChange = (period: "monthly" | "yearly") => {
9589
+ if (!controlledBilling) setInternalBilling(period);
9590
+ onBillingPeriodChange?.(period);
9591
+ };
9592
+
9593
+ const hasPowerUps = powerUpCards.length > 0;
9594
+ const hasLetUsDrive = letUsDriveCards.length > 0;
9595
+
9596
+ return (
9597
+ <div
9598
+ ref={ref}
9599
+ className={cn("flex flex-col bg-card", className)}
9600
+ {...props}
9601
+ >
9602
+ {/* \u2500\u2500\u2500\u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500 */}
9603
+ <PageHeader
9604
+ title={title}
9605
+ actions={headerActions}
9606
+ layout="horizontal"
9607
+ />
9608
+
9609
+ {/* \u2500\u2500\u2500\u2500\u2500 Plan Selection Area \u2500\u2500\u2500\u2500\u2500 */}
9610
+ <div className="flex flex-col gap-6 px-6 py-6">
9611
+ {/* Tabs + billing toggle */}
9612
+ {tabs.length > 0 && (
9613
+ <PricingToggle
9614
+ tabs={tabs}
9615
+ activeTab={currentTab}
9616
+ onTabChange={handleTabChange}
9617
+ showBillingToggle={showBillingToggle}
9618
+ billingPeriod={currentBilling}
9619
+ onBillingPeriodChange={handleBillingChange}
9620
+ />
9621
+ )}
9622
+
9623
+ {/* Plan cards grid */}
9624
+ {planCards.length > 0 && (
9625
+ <div
9626
+ className={cn(
9627
+ "grid gap-6 justify-center",
9628
+ planCards.length <= 2
9629
+ ? "grid-cols-1 md:grid-cols-2 max-w-[960px] mx-auto"
9630
+ : "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
9631
+ )}
9632
+ >
9633
+ {planCards.map((cardProps, index) => (
9634
+ <PricingCard key={index} {...cardProps} />
9635
+ ))}
9636
+ </div>
9637
+ )}
9638
+ </div>
9639
+
9640
+ {/* \u2500\u2500\u2500\u2500\u2500 Power-ups Section \u2500\u2500\u2500\u2500\u2500 */}
9641
+ {hasPowerUps && (
9642
+ <div className="bg-semantic-bg-ui px-6 py-[60px]">
9643
+ <div className="flex flex-col gap-4">
9644
+ {/* Section header */}
9645
+ <div className="flex items-center justify-between">
9646
+ <h2 className="text-lg font-semibold text-semantic-text-primary m-0">
9647
+ {powerUpsTitle}
9648
+ </h2>
9649
+ {onFeatureComparisonClick && (
9650
+ <Button
9651
+ variant="link"
9652
+ className="text-semantic-text-link p-0 h-auto min-w-0 gap-1"
9653
+ onClick={onFeatureComparisonClick}
9654
+ >
9655
+ {featureComparisonText}
9656
+ <ExternalLink className="size-3.5" />
9657
+ </Button>
9658
+ )}
9659
+ </div>
9660
+
9661
+ {/* Power-up cards */}
9662
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
9663
+ {powerUpCards.map((cardProps, index) => (
9664
+ <PowerUpCard key={index} {...cardProps} />
9665
+ ))}
9666
+ </div>
9667
+ </div>
9668
+ </div>
9669
+ )}
9670
+
9671
+ {/* \u2500\u2500\u2500\u2500\u2500 Let Us Drive Section \u2500\u2500\u2500\u2500\u2500 */}
9672
+ {hasLetUsDrive && (
9673
+ <div className="bg-card px-6 py-[60px]">
9674
+ <div className="flex flex-col gap-4">
9675
+ {/* Section header */}
9676
+ <h2 className="text-lg font-semibold text-semantic-text-primary m-0">
9677
+ {letUsDriveTitle}
9678
+ </h2>
9679
+
9680
+ {/* Service cards */}
9681
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
9682
+ {letUsDriveCards.map((cardProps, index) => (
9683
+ <LetUsDriveCard key={index} {...cardProps} />
9684
+ ))}
9685
+ </div>
9686
+ </div>
9687
+ </div>
9688
+ )}
9689
+ </div>
9690
+ );
9691
+ }
9692
+ );
9693
+
9694
+ PricingPage.displayName = "PricingPage";
9695
+
9696
+ export { PricingPage };
9697
+ `, prefix)
9698
+ },
9699
+ {
9700
+ name: "types.ts",
9701
+ content: prefixTailwindClasses(`import * as React from "react";
9702
+ import type { PricingCardProps } from "../pricing-card/types";
9703
+ import type { PowerUpCardProps } from "../power-up-card/types";
9704
+ import type { LetUsDriveCardProps } from "../let-us-drive-card/types";
9705
+ import type { PricingToggleTab } from "../pricing-toggle/types";
9706
+
9707
+ export type { PricingToggleTab };
9708
+
9709
+ /**
9710
+ * Props for the PricingPage component.
9711
+ *
9712
+ * PricingPage is a layout compositor that orchestrates PricingToggle,
9713
+ * PricingCard, PowerUpCard, LetUsDriveCard, and PageHeader into
9714
+ * the full plan selection page.
9715
+ */
9716
+ export interface PricingPageProps
9717
+ extends React.HTMLAttributes<HTMLDivElement> {
9718
+ /* \u2500\u2500\u2500\u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500 */
9719
+
9720
+ /** Page title (default: "Select business plan") */
9721
+ title?: string;
9722
+ /** Actions rendered on the right side of the header (e.g., number-type dropdown) */
9723
+ headerActions?: React.ReactNode;
9724
+
9725
+ /* \u2500\u2500\u2500\u2500\u2500 Tabs & Billing \u2500\u2500\u2500\u2500\u2500 */
9726
+
9727
+ /** Plan type tabs shown in the pill selector */
9728
+ tabs?: PricingToggleTab[];
9729
+ /** Currently active tab value (controlled). Falls back to first tab when unset. */
9730
+ activeTab?: string;
9731
+ /** Callback when the active tab changes */
9732
+ onTabChange?: (value: string) => void;
9733
+ /** Whether to show the monthly/yearly billing toggle */
9734
+ showBillingToggle?: boolean;
9735
+ /** Current billing period (controlled) */
9736
+ billingPeriod?: "monthly" | "yearly";
9737
+ /** Callback when the billing period changes */
9738
+ onBillingPeriodChange?: (period: "monthly" | "yearly") => void;
9739
+
9740
+ /* \u2500\u2500\u2500\u2500\u2500 Plan Cards \u2500\u2500\u2500\u2500\u2500 */
9741
+
9742
+ /** Array of plan card props to render in the main pricing grid */
9743
+ planCards?: PricingCardProps[];
9744
+
9745
+ /* \u2500\u2500\u2500\u2500\u2500 Power-ups Section \u2500\u2500\u2500\u2500\u2500 */
9746
+
9747
+ /** Array of power-up card props */
9748
+ powerUpCards?: PowerUpCardProps[];
9749
+ /** Power-ups section heading (default: "Power-ups and charges") */
9750
+ powerUpsTitle?: string;
9751
+ /** Feature comparison link text (default: "See full feature comparison") */
9752
+ featureComparisonText?: string;
9753
+ /** Callback when the feature comparison link is clicked */
9754
+ onFeatureComparisonClick?: () => void;
9755
+
9756
+ /* \u2500\u2500\u2500\u2500\u2500 Let Us Drive Section \u2500\u2500\u2500\u2500\u2500 */
9757
+
9758
+ /** Array of let-us-drive card props */
9759
+ letUsDriveCards?: LetUsDriveCardProps[];
9760
+ /** Let-us-drive section heading (default: "Let us drive \u2014 Full-service management") */
9761
+ letUsDriveTitle?: string;
9762
+ }
9763
+ `, prefix)
9764
+ },
9765
+ {
9766
+ name: "index.ts",
9767
+ content: prefixTailwindClasses(`export { PricingPage } from "./pricing-page";
9768
+ export type { PricingPageProps, PricingToggleTab } from "./types";
9769
+ `, prefix)
9770
+ }
9771
+ ]
9772
+ },
9773
+ "pricing-toggle": {
9774
+ name: "pricing-toggle",
9775
+ description: "A plan type tab selector with billing period toggle for pricing pages. Pill-shaped tabs switch plan categories, and an optional switch toggles between monthly/yearly billing.",
9776
+ category: "custom",
9777
+ dependencies: [
9778
+ "clsx",
9779
+ "tailwind-merge",
9780
+ "@radix-ui/react-switch@^1.2.6"
9781
+ ],
9782
+ internalDependencies: [
9783
+ "switch"
9784
+ ],
9785
+ isMultiFile: true,
9786
+ directory: "pricing-toggle",
9787
+ mainFile: "pricing-toggle.tsx",
9788
+ files: [
9789
+ {
9790
+ name: "pricing-toggle.tsx",
9791
+ content: prefixTailwindClasses(`import * as React from "react";
9792
+ import { cn } from "../../../lib/utils";
9793
+ import { Switch } from "../switch";
9794
+ import type { PricingToggleProps } from "./types";
9795
+
9796
+ /**
9797
+ * PricingToggle provides a plan type tab selector with an optional
9798
+ * billing period toggle. The pill-shaped tabs switch between plan
9799
+ * categories (e.g. "Team-Led Plans" vs "Go-AI First"), and the
9800
+ * billing toggle switches between monthly/yearly pricing.
9801
+ *
9802
+ * @example
9803
+ * \`\`\`tsx
9804
+ * <PricingToggle
9805
+ * tabs={[
9806
+ * { label: "Team-Led Plans", value: "team" },
9807
+ * { label: "Go-AI First", value: "ai" },
9808
+ * ]}
9809
+ * activeTab="team"
9810
+ * onTabChange={(value) => setActiveTab(value)}
9811
+ * showBillingToggle
9812
+ * billingPeriod="monthly"
9813
+ * onBillingPeriodChange={(period) => setBillingPeriod(period)}
9814
+ * />
9815
+ * \`\`\`
9816
+ */
9817
+ const PricingToggle = React.forwardRef<HTMLDivElement, PricingToggleProps>(
9818
+ (
9819
+ {
9820
+ tabs,
9821
+ activeTab,
9822
+ onTabChange,
9823
+ showBillingToggle = false,
9824
+ billingPeriod = "monthly",
9825
+ onBillingPeriodChange,
9826
+ monthlyLabel = "Monthly",
9827
+ yearlyLabel = "Yearly (Save 20%)",
9828
+ className,
9829
+ ...props
9830
+ },
9831
+ ref
9832
+ ) => {
9833
+ const isYearly = billingPeriod === "yearly";
9834
+
9835
+ return (
9836
+ <div
9837
+ ref={ref}
9838
+ className={cn("flex flex-col items-center gap-4", className)}
9839
+ {...props}
9840
+ >
9841
+ {/* Plan type tabs */}
9842
+ <div className="inline-flex items-start gap-1 rounded-full bg-semantic-bg-ui p-1">
9843
+ {tabs.map((tab) => {
9844
+ const isActive = tab.value === activeTab;
9845
+ return (
9846
+ <button
9847
+ key={tab.value}
9848
+ type="button"
9849
+ role="tab"
9850
+ aria-selected={isActive}
9851
+ className={cn(
9852
+ "h-10 shrink-0 rounded-full px-4 py-1 text-base transition-colors",
9853
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-semantic-brand focus-visible:ring-offset-2",
9854
+ isActive
9855
+ ? "bg-semantic-brand font-semibold text-white shadow-sm"
9856
+ : "font-normal text-semantic-text-primary"
9857
+ )}
9858
+ onClick={() => onTabChange(tab.value)}
9859
+ >
9860
+ {tab.label}
9861
+ </button>
9862
+ );
9863
+ })}
9864
+ </div>
9865
+
9866
+ {/* Billing period toggle */}
9867
+ {showBillingToggle && (
9868
+ <div className="flex items-center gap-4">
9869
+ <span
9870
+ className={cn(
9871
+ "text-sm font-semibold tracking-[0.014px]",
9872
+ !isYearly
9873
+ ? "text-semantic-text-secondary"
9874
+ : "text-semantic-text-muted"
9875
+ )}
9876
+ >
9877
+ {monthlyLabel}
9878
+ </span>
9879
+ <Switch
9880
+ size="sm"
9881
+ checked={isYearly}
9882
+ onCheckedChange={(checked) =>
9883
+ onBillingPeriodChange?.(checked ? "yearly" : "monthly")
9884
+ }
9885
+ />
9886
+ <span
9887
+ className={cn(
9888
+ "text-sm font-semibold tracking-[0.014px]",
9889
+ isYearly
9890
+ ? "text-semantic-text-secondary"
9891
+ : "text-semantic-text-muted"
9892
+ )}
9893
+ >
9894
+ {yearlyLabel}
9895
+ </span>
9896
+ </div>
9897
+ )}
9898
+ </div>
9899
+ );
9900
+ }
9901
+ );
9902
+
9903
+ PricingToggle.displayName = "PricingToggle";
9904
+
9905
+ export { PricingToggle };
9906
+ `, prefix)
9907
+ },
9908
+ {
9909
+ name: "types.ts",
9910
+ content: prefixTailwindClasses(`/** A single tab option in the plan tab selector */
9911
+ export interface PricingToggleTab {
9912
+ /** Display label for the tab */
9913
+ label: string;
9914
+ /** Unique value identifier for the tab */
9915
+ value: string;
9916
+ }
9917
+
9918
+ export interface PricingToggleProps
9919
+ extends React.HTMLAttributes<HTMLDivElement> {
9920
+ /** Array of tab options for the plan type selector */
9921
+ tabs: PricingToggleTab[];
9922
+ /** Currently active tab value (controlled) */
9923
+ activeTab: string;
9924
+ /** Callback when the active tab changes */
9925
+ onTabChange: (value: string) => void;
9926
+ /** Whether to show the billing period toggle below the tabs */
9927
+ showBillingToggle?: boolean;
9928
+ /** Current billing period \u2014 "monthly" or "yearly" (controlled) */
9929
+ billingPeriod?: "monthly" | "yearly";
9930
+ /** Callback when the billing period changes */
9931
+ onBillingPeriodChange?: (period: "monthly" | "yearly") => void;
9932
+ /** Left label for the billing toggle (default: "Monthly") */
9933
+ monthlyLabel?: string;
9934
+ /** Right label for the billing toggle (default: "Yearly (Save 20%)") */
9935
+ yearlyLabel?: string;
9936
+ }
9937
+ `, prefix)
9938
+ },
9939
+ {
9940
+ name: "index.ts",
9941
+ content: prefixTailwindClasses(`export { PricingToggle } from "./pricing-toggle";
9942
+ export type { PricingToggleProps, PricingToggleTab } from "./types";
8721
9943
  `, prefix)
8722
9944
  }
8723
9945
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-ui",
3
- "version": "0.0.166",
3
+ "version": "0.0.167-beta.0",
4
4
  "description": "CLI for adding myOperator UI components to your project",
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",