myoperator-ui 0.0.189 → 0.0.190-beta.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 +322 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8391,17 +8391,26 @@ export const BankDetails = React.forwardRef<HTMLDivElement, BankDetailsProps>(
|
|
|
8391
8391
|
icon,
|
|
8392
8392
|
items,
|
|
8393
8393
|
defaultOpen = true,
|
|
8394
|
+
open,
|
|
8395
|
+
onOpenChange,
|
|
8394
8396
|
onCopy,
|
|
8395
8397
|
className,
|
|
8396
8398
|
},
|
|
8397
8399
|
ref
|
|
8398
8400
|
) => {
|
|
8401
|
+
const isControlled = open !== undefined;
|
|
8402
|
+
|
|
8399
8403
|
return (
|
|
8400
8404
|
<div ref={ref} className={cn("w-full", className)}>
|
|
8401
8405
|
<Accordion
|
|
8402
8406
|
type="single"
|
|
8403
8407
|
variant="bordered"
|
|
8404
|
-
|
|
8408
|
+
{...(isControlled
|
|
8409
|
+
? {
|
|
8410
|
+
value: open ? ["bank-details"] : [],
|
|
8411
|
+
onValueChange: (val) => onOpenChange?.(val.length > 0),
|
|
8412
|
+
}
|
|
8413
|
+
: { defaultValue: defaultOpen ? ["bank-details"] : [] })}
|
|
8405
8414
|
>
|
|
8406
8415
|
<AccordionItem value="bank-details">
|
|
8407
8416
|
<AccordionTrigger className="px-4 py-4">
|
|
@@ -8535,6 +8544,10 @@ export interface BankDetailsProps {
|
|
|
8535
8544
|
// Accordion
|
|
8536
8545
|
/** Whether the accordion is open by default */
|
|
8537
8546
|
defaultOpen?: boolean;
|
|
8547
|
+
/** Controlled open state \u2014 use with onOpenChange for exclusive accordion behavior */
|
|
8548
|
+
open?: boolean;
|
|
8549
|
+
/** Callback fired when the panel is toggled \u2014 receives new open state */
|
|
8550
|
+
onOpenChange?: (open: boolean) => void;
|
|
8538
8551
|
|
|
8539
8552
|
// Callbacks
|
|
8540
8553
|
/** Callback fired when a value is copied to clipboard */
|
|
@@ -11017,10 +11030,14 @@ export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
|
|
|
11017
11030
|
loading = false,
|
|
11018
11031
|
disabled = false,
|
|
11019
11032
|
defaultOpen = true,
|
|
11033
|
+
open,
|
|
11034
|
+
onOpenChange,
|
|
11020
11035
|
className,
|
|
11021
11036
|
},
|
|
11022
11037
|
ref
|
|
11023
11038
|
) => {
|
|
11039
|
+
const isOpenControlled = open !== undefined;
|
|
11040
|
+
|
|
11024
11041
|
// Controlled/uncontrolled amount selection
|
|
11025
11042
|
const isControlled = controlledAmount !== undefined;
|
|
11026
11043
|
const [internalAmount, setInternalAmount] = React.useState<number | null>(
|
|
@@ -11189,7 +11206,12 @@ export const WalletTopup = React.forwardRef<HTMLDivElement, WalletTopupProps>(
|
|
|
11189
11206
|
<Accordion
|
|
11190
11207
|
type="single"
|
|
11191
11208
|
variant="bordered"
|
|
11192
|
-
|
|
11209
|
+
{...(isOpenControlled
|
|
11210
|
+
? {
|
|
11211
|
+
value: open ? ["wallet-topup"] : [],
|
|
11212
|
+
onValueChange: (val) => onOpenChange?.(val.length > 0),
|
|
11213
|
+
}
|
|
11214
|
+
: { defaultValue: defaultOpen ? ["wallet-topup"] : [] })}
|
|
11193
11215
|
>
|
|
11194
11216
|
<AccordionItem value="wallet-topup">
|
|
11195
11217
|
<AccordionTrigger className="px-4 py-4">
|
|
@@ -11537,6 +11559,10 @@ export interface WalletTopupProps {
|
|
|
11537
11559
|
// Accordion
|
|
11538
11560
|
/** Whether the accordion is open by default */
|
|
11539
11561
|
defaultOpen?: boolean;
|
|
11562
|
+
/** Controlled open state \u2014 use with onOpenChange for exclusive accordion behavior */
|
|
11563
|
+
open?: boolean;
|
|
11564
|
+
/** Callback fired when the panel is toggled \u2014 receives new open state */
|
|
11565
|
+
onOpenChange?: (open: boolean) => void;
|
|
11540
11566
|
|
|
11541
11567
|
// Styling
|
|
11542
11568
|
/** Additional className for the root element */
|
|
@@ -11548,6 +11574,300 @@ export interface WalletTopupProps {
|
|
|
11548
11574
|
name: "index.ts",
|
|
11549
11575
|
content: prefixTailwindClasses(`export { WalletTopup } from "./wallet-topup";
|
|
11550
11576
|
export type { WalletTopupProps, AmountOption } from "./types";
|
|
11577
|
+
`, prefix)
|
|
11578
|
+
}
|
|
11579
|
+
]
|
|
11580
|
+
},
|
|
11581
|
+
"contact-form-modal": {
|
|
11582
|
+
name: "contact-form-modal",
|
|
11583
|
+
description: "A modal dialog for adding a new contact with phone number, country code, channel selector, and Start Conversation CTA",
|
|
11584
|
+
category: "custom",
|
|
11585
|
+
dependencies: [
|
|
11586
|
+
"clsx",
|
|
11587
|
+
"tailwind-merge",
|
|
11588
|
+
"lucide-react"
|
|
11589
|
+
],
|
|
11590
|
+
internalDependencies: [
|
|
11591
|
+
"dialog",
|
|
11592
|
+
"select",
|
|
11593
|
+
"input",
|
|
11594
|
+
"button"
|
|
11595
|
+
],
|
|
11596
|
+
isMultiFile: true,
|
|
11597
|
+
directory: "contact-form-modal",
|
|
11598
|
+
mainFile: "contact-form-modal.tsx",
|
|
11599
|
+
files: [
|
|
11600
|
+
{
|
|
11601
|
+
name: "contact-form-modal.tsx",
|
|
11602
|
+
content: prefixTailwindClasses(`import * as React from "react";
|
|
11603
|
+
import { cn } from "../../../lib/utils";
|
|
11604
|
+
import {
|
|
11605
|
+
Dialog,
|
|
11606
|
+
DialogContent,
|
|
11607
|
+
DialogHeader,
|
|
11608
|
+
DialogTitle,
|
|
11609
|
+
} from "../dialog";
|
|
11610
|
+
import {
|
|
11611
|
+
Select,
|
|
11612
|
+
SelectContent,
|
|
11613
|
+
SelectItem,
|
|
11614
|
+
SelectTrigger,
|
|
11615
|
+
SelectValue,
|
|
11616
|
+
} from "../select";
|
|
11617
|
+
import { Input } from "../input";
|
|
11618
|
+
import { Button } from "../button";
|
|
11619
|
+
import type { ContactFormModalProps, CountryCodeOption } from "./types";
|
|
11620
|
+
|
|
11621
|
+
/** Default country code options for the phone prefix selector */
|
|
11622
|
+
export const DEFAULT_COUNTRY_CODE_OPTIONS: CountryCodeOption[] = [
|
|
11623
|
+
{ value: "+91", label: "+91", flag: "\u{1F1EE}\u{1F1F3}" },
|
|
11624
|
+
{ value: "+1", label: "+1", flag: "\u{1F1FA}\u{1F1F8}" },
|
|
11625
|
+
{ value: "+44", label: "+44", flag: "\u{1F1EC}\u{1F1E7}" },
|
|
11626
|
+
{ value: "+61", label: "+61", flag: "\u{1F1E6}\u{1F1FA}" },
|
|
11627
|
+
{ value: "+971", label: "+971", flag: "\u{1F1E6}\u{1F1EA}" },
|
|
11628
|
+
{ value: "+65", label: "+65", flag: "\u{1F1F8}\u{1F1EC}" },
|
|
11629
|
+
];
|
|
11630
|
+
|
|
11631
|
+
/**
|
|
11632
|
+
* ContactFormModal renders a dialog for adding a new contact. It provides
|
|
11633
|
+
* fields for phone number (with country-code prefix), contact name, an
|
|
11634
|
+
* optional channel selector, and a Start Conversation CTA.
|
|
11635
|
+
*
|
|
11636
|
+
* Install via CLI:
|
|
11637
|
+
* \`\`\`bash
|
|
11638
|
+
* npx myoperator-ui add contact-form-modal
|
|
11639
|
+
* \`\`\`
|
|
11640
|
+
*
|
|
11641
|
+
* @example
|
|
11642
|
+
* \`\`\`tsx
|
|
11643
|
+
* <ContactFormModal
|
|
11644
|
+
* open={open}
|
|
11645
|
+
* onOpenChange={setOpen}
|
|
11646
|
+
* onStartConversation={() => console.log("start")}
|
|
11647
|
+
* />
|
|
11648
|
+
* \`\`\`
|
|
11649
|
+
*/
|
|
11650
|
+
export const ContactFormModal = React.forwardRef<
|
|
11651
|
+
HTMLDivElement,
|
|
11652
|
+
ContactFormModalProps
|
|
11653
|
+
>(
|
|
11654
|
+
(
|
|
11655
|
+
{
|
|
11656
|
+
open,
|
|
11657
|
+
onOpenChange,
|
|
11658
|
+
phoneNumber: phoneNumberProp,
|
|
11659
|
+
onPhoneNumberChange,
|
|
11660
|
+
contactName: contactNameProp,
|
|
11661
|
+
onContactNameChange,
|
|
11662
|
+
countryCodeOptions = DEFAULT_COUNTRY_CODE_OPTIONS,
|
|
11663
|
+
selectedCountryCode,
|
|
11664
|
+
onCountryCodeChange,
|
|
11665
|
+
channelOptions = [],
|
|
11666
|
+
selectedChannel,
|
|
11667
|
+
onChannelChange,
|
|
11668
|
+
startConversationDisabled,
|
|
11669
|
+
onStartConversation,
|
|
11670
|
+
className,
|
|
11671
|
+
},
|
|
11672
|
+
ref
|
|
11673
|
+
) => {
|
|
11674
|
+
const [internalPhone, setInternalPhone] = React.useState("");
|
|
11675
|
+
const [internalName, setInternalName] = React.useState("");
|
|
11676
|
+
const [internalCountryCode, setInternalCountryCode] = React.useState(
|
|
11677
|
+
countryCodeOptions[0]?.value ?? "+91"
|
|
11678
|
+
);
|
|
11679
|
+
|
|
11680
|
+
const phoneNumber =
|
|
11681
|
+
phoneNumberProp !== undefined ? phoneNumberProp : internalPhone;
|
|
11682
|
+
const contactName =
|
|
11683
|
+
contactNameProp !== undefined ? contactNameProp : internalName;
|
|
11684
|
+
const countryCode =
|
|
11685
|
+
selectedCountryCode !== undefined
|
|
11686
|
+
? selectedCountryCode
|
|
11687
|
+
: internalCountryCode;
|
|
11688
|
+
|
|
11689
|
+
const handlePhoneChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
11690
|
+
const val = e.target.value;
|
|
11691
|
+
if (phoneNumberProp === undefined) setInternalPhone(val);
|
|
11692
|
+
onPhoneNumberChange?.(val);
|
|
11693
|
+
};
|
|
11694
|
+
|
|
11695
|
+
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
11696
|
+
const val = e.target.value;
|
|
11697
|
+
if (contactNameProp === undefined) setInternalName(val);
|
|
11698
|
+
onContactNameChange?.(val);
|
|
11699
|
+
};
|
|
11700
|
+
|
|
11701
|
+
const handleCountryCodeChange = (val: string) => {
|
|
11702
|
+
if (selectedCountryCode === undefined) setInternalCountryCode(val);
|
|
11703
|
+
onCountryCodeChange?.(val);
|
|
11704
|
+
};
|
|
11705
|
+
|
|
11706
|
+
const isStartDisabled =
|
|
11707
|
+
startConversationDisabled !== undefined
|
|
11708
|
+
? startConversationDisabled
|
|
11709
|
+
: phoneNumber.trim() === "";
|
|
11710
|
+
|
|
11711
|
+
return (
|
|
11712
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
11713
|
+
<DialogContent
|
|
11714
|
+
ref={ref}
|
|
11715
|
+
className={cn("sm:max-w-[480px]", className)}
|
|
11716
|
+
>
|
|
11717
|
+
<DialogHeader>
|
|
11718
|
+
<DialogTitle>Add New Contact</DialogTitle>
|
|
11719
|
+
</DialogHeader>
|
|
11720
|
+
|
|
11721
|
+
<div className="flex flex-col gap-4 py-2">
|
|
11722
|
+
{/* Phone number */}
|
|
11723
|
+
<div className="flex flex-col gap-1.5">
|
|
11724
|
+
<label className="text-sm font-medium text-semantic-text-primary">
|
|
11725
|
+
Phone <span>*</span>
|
|
11726
|
+
</label>
|
|
11727
|
+
<div className="flex gap-2">
|
|
11728
|
+
{countryCodeOptions.length > 0 && (
|
|
11729
|
+
<Select
|
|
11730
|
+
value={countryCode}
|
|
11731
|
+
onValueChange={handleCountryCodeChange}
|
|
11732
|
+
>
|
|
11733
|
+
<SelectTrigger className="w-24 shrink-0">
|
|
11734
|
+
<SelectValue />
|
|
11735
|
+
</SelectTrigger>
|
|
11736
|
+
<SelectContent>
|
|
11737
|
+
{countryCodeOptions.map((opt) => (
|
|
11738
|
+
<SelectItem key={opt.value} value={opt.value}>
|
|
11739
|
+
{opt.flag ? \`\${opt.flag} \${opt.label}\` : opt.label}
|
|
11740
|
+
</SelectItem>
|
|
11741
|
+
))}
|
|
11742
|
+
</SelectContent>
|
|
11743
|
+
</Select>
|
|
11744
|
+
)}
|
|
11745
|
+
<Input
|
|
11746
|
+
type="tel"
|
|
11747
|
+
placeholder="Enter phone number"
|
|
11748
|
+
value={phoneNumber}
|
|
11749
|
+
onChange={handlePhoneChange}
|
|
11750
|
+
className="flex-1"
|
|
11751
|
+
/>
|
|
11752
|
+
</div>
|
|
11753
|
+
</div>
|
|
11754
|
+
|
|
11755
|
+
{/* Contact name */}
|
|
11756
|
+
<div className="flex flex-col gap-1.5">
|
|
11757
|
+
<label className="text-sm font-medium text-semantic-text-primary">
|
|
11758
|
+
Save contact as
|
|
11759
|
+
</label>
|
|
11760
|
+
<Input
|
|
11761
|
+
type="text"
|
|
11762
|
+
placeholder="Enter name"
|
|
11763
|
+
value={contactName}
|
|
11764
|
+
onChange={handleNameChange}
|
|
11765
|
+
/>
|
|
11766
|
+
</div>
|
|
11767
|
+
|
|
11768
|
+
{/* Channel selector (optional) */}
|
|
11769
|
+
{channelOptions.length > 0 && (
|
|
11770
|
+
<div className="flex flex-col gap-1.5">
|
|
11771
|
+
<label className="text-sm font-medium text-semantic-text-primary">
|
|
11772
|
+
Channel
|
|
11773
|
+
</label>
|
|
11774
|
+
<Select
|
|
11775
|
+
value={selectedChannel}
|
|
11776
|
+
onValueChange={onChannelChange}
|
|
11777
|
+
>
|
|
11778
|
+
<SelectTrigger>
|
|
11779
|
+
<SelectValue placeholder="Select channel" />
|
|
11780
|
+
</SelectTrigger>
|
|
11781
|
+
<SelectContent>
|
|
11782
|
+
{channelOptions.map((opt) => (
|
|
11783
|
+
<SelectItem key={opt.value} value={opt.value}>
|
|
11784
|
+
{opt.label}
|
|
11785
|
+
</SelectItem>
|
|
11786
|
+
))}
|
|
11787
|
+
</SelectContent>
|
|
11788
|
+
</Select>
|
|
11789
|
+
</div>
|
|
11790
|
+
)}
|
|
11791
|
+
</div>
|
|
11792
|
+
|
|
11793
|
+
{/* CTA */}
|
|
11794
|
+
<div className="flex justify-end pt-2">
|
|
11795
|
+
<Button
|
|
11796
|
+
onClick={onStartConversation}
|
|
11797
|
+
disabled={isStartDisabled}
|
|
11798
|
+
>
|
|
11799
|
+
Start Conversation
|
|
11800
|
+
</Button>
|
|
11801
|
+
</div>
|
|
11802
|
+
</DialogContent>
|
|
11803
|
+
</Dialog>
|
|
11804
|
+
);
|
|
11805
|
+
}
|
|
11806
|
+
);
|
|
11807
|
+
|
|
11808
|
+
ContactFormModal.displayName = "ContactFormModal";
|
|
11809
|
+
`, prefix)
|
|
11810
|
+
},
|
|
11811
|
+
{
|
|
11812
|
+
name: "types.ts",
|
|
11813
|
+
content: prefixTailwindClasses(`/** An option in the channel selector */
|
|
11814
|
+
export interface ChannelOption {
|
|
11815
|
+
value: string;
|
|
11816
|
+
label: string;
|
|
11817
|
+
}
|
|
11818
|
+
|
|
11819
|
+
/** A country code prefix option for the phone number field */
|
|
11820
|
+
export interface CountryCodeOption {
|
|
11821
|
+
value: string;
|
|
11822
|
+
label: string;
|
|
11823
|
+
flag?: string;
|
|
11824
|
+
}
|
|
11825
|
+
|
|
11826
|
+
/** Props for the ContactFormModal component */
|
|
11827
|
+
export interface ContactFormModalProps {
|
|
11828
|
+
/** Whether the modal is open */
|
|
11829
|
+
open: boolean;
|
|
11830
|
+
/** Callback when modal open state changes */
|
|
11831
|
+
onOpenChange: (open: boolean) => void;
|
|
11832
|
+
|
|
11833
|
+
/** Controlled phone number value */
|
|
11834
|
+
phoneNumber?: string;
|
|
11835
|
+
/** Callback when phone number changes */
|
|
11836
|
+
onPhoneNumberChange?: (value: string) => void;
|
|
11837
|
+
|
|
11838
|
+
/** Controlled contact name value */
|
|
11839
|
+
contactName?: string;
|
|
11840
|
+
/** Callback when contact name changes */
|
|
11841
|
+
onContactNameChange?: (value: string) => void;
|
|
11842
|
+
|
|
11843
|
+
/** Country code options for the phone prefix selector */
|
|
11844
|
+
countryCodeOptions?: CountryCodeOption[];
|
|
11845
|
+
/** Currently selected country code value */
|
|
11846
|
+
selectedCountryCode?: string;
|
|
11847
|
+
/** Callback when country code changes */
|
|
11848
|
+
onCountryCodeChange?: (value: string) => void;
|
|
11849
|
+
|
|
11850
|
+
/** Channel options for the channel selector (hidden when empty) */
|
|
11851
|
+
channelOptions?: ChannelOption[];
|
|
11852
|
+
/** Currently selected channel value */
|
|
11853
|
+
selectedChannel?: string;
|
|
11854
|
+
/** Callback when channel changes */
|
|
11855
|
+
onChannelChange?: (value: string) => void;
|
|
11856
|
+
|
|
11857
|
+
/** Override to explicitly disable the Start Conversation button */
|
|
11858
|
+
startConversationDisabled?: boolean;
|
|
11859
|
+
/** Callback when Start Conversation is clicked */
|
|
11860
|
+
onStartConversation?: () => void;
|
|
11861
|
+
|
|
11862
|
+
/** Additional className for the dialog content */
|
|
11863
|
+
className?: string;
|
|
11864
|
+
}
|
|
11865
|
+
`, prefix)
|
|
11866
|
+
},
|
|
11867
|
+
{
|
|
11868
|
+
name: "index.ts",
|
|
11869
|
+
content: prefixTailwindClasses(`export { ContactFormModal, DEFAULT_COUNTRY_CODE_OPTIONS } from "./contact-form-modal";
|
|
11870
|
+
export type { ContactFormModalProps, ChannelOption, CountryCodeOption } from "./types";
|
|
11551
11871
|
`, prefix)
|
|
11552
11872
|
}
|
|
11553
11873
|
]
|