omnira-ui 0.1.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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +145 -0
  3. package/cli/omnira-init.mjs +260 -0
  4. package/cli/presets.mjs +386 -0
  5. package/components/ui/AppStoreButton/AppStoreButton.module.css +87 -0
  6. package/components/ui/AppStoreButton/AppStoreButton.tsx +114 -0
  7. package/components/ui/AppStoreButton/index.ts +2 -0
  8. package/components/ui/Avatar/Avatar.module.css +76 -0
  9. package/components/ui/Avatar/Avatar.tsx +102 -0
  10. package/components/ui/Avatar/index.ts +2 -0
  11. package/components/ui/Badge/Badge.module.css +120 -0
  12. package/components/ui/Badge/Badge.tsx +25 -0
  13. package/components/ui/Badge/index.ts +2 -0
  14. package/components/ui/BadgeGroup/BadgeGroup.module.css +214 -0
  15. package/components/ui/BadgeGroup/BadgeGroup.tsx +88 -0
  16. package/components/ui/BadgeGroup/index.ts +2 -0
  17. package/components/ui/Browser/Browser.module.css +105 -0
  18. package/components/ui/Browser/Browser.tsx +54 -0
  19. package/components/ui/Browser/index.ts +2 -0
  20. package/components/ui/Button/Button.module.css +188 -0
  21. package/components/ui/Button/Button.tsx +74 -0
  22. package/components/ui/Button/index.ts +2 -0
  23. package/components/ui/ButtonUtility/ButtonUtility.module.css +154 -0
  24. package/components/ui/ButtonUtility/ButtonUtility.tsx +65 -0
  25. package/components/ui/ButtonUtility/index.ts +2 -0
  26. package/components/ui/Card/Card.module.css +80 -0
  27. package/components/ui/Card/Card.tsx +39 -0
  28. package/components/ui/Card/index.ts +2 -0
  29. package/components/ui/Checkbox/Checkbox.module.css +92 -0
  30. package/components/ui/Checkbox/Checkbox.tsx +95 -0
  31. package/components/ui/Checkbox/index.ts +2 -0
  32. package/components/ui/Collapse/Collapse.module.css +60 -0
  33. package/components/ui/Collapse/Collapse.tsx +100 -0
  34. package/components/ui/Collapse/index.ts +2 -0
  35. package/components/ui/CreditCard/CreditCard.module.css +117 -0
  36. package/components/ui/CreditCard/CreditCard.tsx +86 -0
  37. package/components/ui/CreditCard/index.ts +2 -0
  38. package/components/ui/Dropdown/Dropdown.module.css +269 -0
  39. package/components/ui/Dropdown/Dropdown.tsx +419 -0
  40. package/components/ui/Dropdown/index.ts +31 -0
  41. package/components/ui/GridLines/GridLines.module.css +95 -0
  42. package/components/ui/GridLines/GridLines.tsx +10 -0
  43. package/components/ui/GridLines/index.ts +1 -0
  44. package/components/ui/Illustration/Illustration.module.css +10 -0
  45. package/components/ui/Illustration/Illustration.tsx +96 -0
  46. package/components/ui/Illustration/index.ts +2 -0
  47. package/components/ui/Input/Input.module.css +217 -0
  48. package/components/ui/Input/Input.tsx +93 -0
  49. package/components/ui/Input/index.ts +2 -0
  50. package/components/ui/Phone/Phone.module.css +104 -0
  51. package/components/ui/Phone/Phone.tsx +54 -0
  52. package/components/ui/Phone/index.ts +2 -0
  53. package/components/ui/PinInput/PinInput.module.css +104 -0
  54. package/components/ui/PinInput/PinInput.tsx +210 -0
  55. package/components/ui/PinInput/index.ts +1 -0
  56. package/components/ui/ProgressBar/ProgressBar.module.css +180 -0
  57. package/components/ui/ProgressBar/ProgressBar.tsx +206 -0
  58. package/components/ui/ProgressBar/index.ts +2 -0
  59. package/components/ui/QRCode/QRCode.module.css +13 -0
  60. package/components/ui/QRCode/QRCode.tsx +128 -0
  61. package/components/ui/QRCode/index.ts +2 -0
  62. package/components/ui/RadioButton/RadioButton.module.css +92 -0
  63. package/components/ui/RadioButton/RadioButton.tsx +134 -0
  64. package/components/ui/RadioButton/index.ts +2 -0
  65. package/components/ui/RadioGroup/RadioGroup.module.css +382 -0
  66. package/components/ui/RadioGroup/RadioGroup.tsx +292 -0
  67. package/components/ui/RadioGroup/index.ts +1 -0
  68. package/components/ui/Rating/Rating.module.css +99 -0
  69. package/components/ui/Rating/Rating.tsx +123 -0
  70. package/components/ui/Rating/index.ts +2 -0
  71. package/components/ui/Select/Select.module.css +371 -0
  72. package/components/ui/Select/Select.tsx +507 -0
  73. package/components/ui/Select/index.ts +2 -0
  74. package/components/ui/SidebarNavigation/SidebarDual.tsx +71 -0
  75. package/components/ui/SidebarNavigation/SidebarFeatureCard.module.css +351 -0
  76. package/components/ui/SidebarNavigation/SidebarFeatureCard.tsx +388 -0
  77. package/components/ui/SidebarNavigation/SidebarNavigation.module.css +610 -0
  78. package/components/ui/SidebarNavigation/SidebarParts.tsx +215 -0
  79. package/components/ui/SidebarNavigation/SidebarSectionDividers.tsx +46 -0
  80. package/components/ui/SidebarNavigation/SidebarSectionHeadings.tsx +52 -0
  81. package/components/ui/SidebarNavigation/SidebarSimple.tsx +46 -0
  82. package/components/ui/SidebarNavigation/SidebarSlim.tsx +48 -0
  83. package/components/ui/SidebarNavigation/index.ts +29 -0
  84. package/components/ui/SidebarNavigation/types.ts +27 -0
  85. package/components/ui/Slider/Slider.module.css +93 -0
  86. package/components/ui/Slider/Slider.tsx +118 -0
  87. package/components/ui/Slider/index.ts +2 -0
  88. package/components/ui/SocialButton/SocialButton.module.css +223 -0
  89. package/components/ui/SocialButton/SocialButton.tsx +185 -0
  90. package/components/ui/SocialButton/index.ts +2 -0
  91. package/components/ui/Tag/Tag.module.css +203 -0
  92. package/components/ui/Tag/Tag.tsx +161 -0
  93. package/components/ui/Tag/index.ts +2 -0
  94. package/components/ui/TextEditor/TextEditor.module.css +182 -0
  95. package/components/ui/TextEditor/TextEditor.tsx +323 -0
  96. package/components/ui/TextEditor/index.ts +1 -0
  97. package/components/ui/Textarea/Textarea.module.css +75 -0
  98. package/components/ui/Textarea/Textarea.tsx +59 -0
  99. package/components/ui/Textarea/index.ts +2 -0
  100. package/components/ui/Toggle/Toggle.module.css +118 -0
  101. package/components/ui/Toggle/Toggle.tsx +77 -0
  102. package/components/ui/Toggle/index.ts +2 -0
  103. package/components/ui/Tooltip/Tooltip.module.css +95 -0
  104. package/components/ui/Tooltip/Tooltip.tsx +55 -0
  105. package/components/ui/Tooltip/index.ts +2 -0
  106. package/components/ui/VideoPlayer/VideoPlayer.module.css +120 -0
  107. package/components/ui/VideoPlayer/VideoPlayer.tsx +229 -0
  108. package/components/ui/VideoPlayer/index.ts +2 -0
  109. package/lib/cn.ts +3 -0
  110. package/lib/copy-to-clipboard.ts +21 -0
  111. package/package.json +61 -0
@@ -0,0 +1,92 @@
1
+ /* ── Wrapper ── */
2
+ .wrapper {
3
+ display: flex;
4
+ align-items: flex-start;
5
+ gap: 10px;
6
+ cursor: pointer;
7
+ }
8
+
9
+ .wrapperDisabled {
10
+ opacity: 0.5;
11
+ cursor: not-allowed;
12
+ pointer-events: none;
13
+ }
14
+
15
+ /* ── Hidden native input ── */
16
+ .hiddenInput {
17
+ position: absolute;
18
+ width: 1px;
19
+ height: 1px;
20
+ overflow: hidden;
21
+ clip: rect(0, 0, 0, 0);
22
+ white-space: nowrap;
23
+ border: 0;
24
+ }
25
+
26
+ /* ── Box ── */
27
+ .box {
28
+ flex-shrink: 0;
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: center;
32
+ border-radius: var(--radius-sm);
33
+ background: var(--color-bg-input);
34
+ border: 1px solid var(--color-border-standard);
35
+ cursor: pointer;
36
+ transition: all 0.2s;
37
+ padding: 0;
38
+ color: var(--color-bg-primary);
39
+ }
40
+
41
+ .box:hover {
42
+ border-color: var(--color-border-lime-strong);
43
+ }
44
+
45
+ .boxChecked {
46
+ background: var(--color-lime);
47
+ border-color: var(--color-lime);
48
+ }
49
+
50
+ /* Box sizes */
51
+ .box_sm {
52
+ width: 18px;
53
+ height: 18px;
54
+ }
55
+
56
+ .box_md {
57
+ width: 22px;
58
+ height: 22px;
59
+ }
60
+
61
+ .box_lg {
62
+ width: 26px;
63
+ height: 26px;
64
+ }
65
+
66
+ /* ── Check icon ── */
67
+ .checkIcon {
68
+ width: 70%;
69
+ height: 70%;
70
+ }
71
+
72
+ /* ── Text ── */
73
+ .textWrap {
74
+ display: flex;
75
+ flex-direction: column;
76
+ gap: 2px;
77
+ cursor: pointer;
78
+ padding-top: 0px;
79
+ }
80
+
81
+ .label {
82
+ font-size: 14px;
83
+ font-weight: 500;
84
+ color: var(--color-text-primary);
85
+ line-height: 1.3;
86
+ }
87
+
88
+ .hint {
89
+ font-size: 12px;
90
+ color: var(--color-text-tertiary);
91
+ line-height: 1.4;
92
+ }
@@ -0,0 +1,95 @@
1
+ "use client";
2
+
3
+ import { forwardRef, useState, useCallback, useId } from "react";
4
+ import { cn } from "@/lib/cn";
5
+ import styles from "./Checkbox.module.css";
6
+
7
+ export interface CheckboxProps {
8
+ label?: string;
9
+ hint?: string;
10
+ size?: "sm" | "md" | "lg";
11
+ disabled?: boolean;
12
+ checked?: boolean;
13
+ defaultChecked?: boolean;
14
+ onChange?: (checked: boolean) => void;
15
+ className?: string;
16
+ }
17
+
18
+ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
19
+ (
20
+ {
21
+ label,
22
+ hint,
23
+ size = "sm",
24
+ disabled = false,
25
+ checked: controlledChecked,
26
+ defaultChecked = false,
27
+ onChange,
28
+ className,
29
+ },
30
+ ref,
31
+ ) => {
32
+ const id = useId();
33
+ const [internalChecked, setInternalChecked] = useState(defaultChecked);
34
+ const isControlled = controlledChecked !== undefined;
35
+ const checked = isControlled ? controlledChecked : internalChecked;
36
+
37
+ const handleChange = useCallback(() => {
38
+ if (disabled) return;
39
+ const next = !checked;
40
+ if (!isControlled) setInternalChecked(next);
41
+ onChange?.(next);
42
+ }, [checked, disabled, isControlled, onChange]);
43
+
44
+ return (
45
+ <div className={cn(styles.wrapper, disabled && styles.wrapperDisabled, className)}>
46
+ <input
47
+ ref={ref}
48
+ id={id}
49
+ type="checkbox"
50
+ checked={checked}
51
+ onChange={handleChange}
52
+ disabled={disabled}
53
+ className={styles.hiddenInput}
54
+ aria-checked={checked}
55
+ />
56
+ <button
57
+ type="button"
58
+ role="checkbox"
59
+ aria-checked={checked}
60
+ disabled={disabled}
61
+ onClick={handleChange}
62
+ className={cn(
63
+ styles.box,
64
+ styles[`box_${size}`],
65
+ checked && styles.boxChecked,
66
+ )}
67
+ >
68
+ {checked && (
69
+ <svg
70
+ viewBox="0 0 12 12"
71
+ fill="none"
72
+ className={styles.checkIcon}
73
+ >
74
+ <path
75
+ d="M2.5 6L5 8.5L9.5 3.5"
76
+ stroke="currentColor"
77
+ strokeWidth="1.8"
78
+ strokeLinecap="round"
79
+ strokeLinejoin="round"
80
+ />
81
+ </svg>
82
+ )}
83
+ </button>
84
+ {(label || hint) && (
85
+ <label htmlFor={id} className={styles.textWrap}>
86
+ {label && <span className={styles.label}>{label}</span>}
87
+ {hint && <span className={styles.hint}>{hint}</span>}
88
+ </label>
89
+ )}
90
+ </div>
91
+ );
92
+ },
93
+ );
94
+
95
+ Checkbox.displayName = "Checkbox";
@@ -0,0 +1,2 @@
1
+ export { Checkbox } from "./Checkbox";
2
+ export type { CheckboxProps } from "./Checkbox";
@@ -0,0 +1,60 @@
1
+ .group {
2
+ display: flex;
3
+ flex-direction: column;
4
+ width: 100%;
5
+ }
6
+
7
+ /* ── Item ── */
8
+ .item {
9
+ border-bottom: 1px solid var(--color-border-subtle);
10
+ }
11
+
12
+ .item:first-child {
13
+ border-top: 1px solid var(--color-border-subtle);
14
+ }
15
+
16
+ .itemHeader {
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: space-between;
20
+ width: 100%;
21
+ padding: 18px 4px;
22
+ background: none;
23
+ border: none;
24
+ cursor: pointer;
25
+ transition: color 0.2s;
26
+ }
27
+
28
+ .itemHeader:hover {
29
+ color: var(--color-text-primary);
30
+ }
31
+
32
+ .itemTitle {
33
+ font-family: var(--font-display);
34
+ font-size: 17px;
35
+ font-weight: 600;
36
+ color: var(--color-text-primary);
37
+ letter-spacing: -0.01em;
38
+ text-align: left;
39
+ }
40
+
41
+ .itemChevron {
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ color: var(--color-text-tertiary);
46
+ transition: transform 0.25s ease;
47
+ flex-shrink: 0;
48
+ }
49
+
50
+ .itemChevronOpen {
51
+ transform: rotate(180deg);
52
+ }
53
+
54
+ /* ── Content ── */
55
+ .itemContent {
56
+ padding: 0 4px 20px;
57
+ font-size: 15px;
58
+ line-height: 1.65;
59
+ color: var(--color-text-secondary);
60
+ }
@@ -0,0 +1,100 @@
1
+ "use client";
2
+
3
+ import { useState, useCallback, createContext, useContext, forwardRef } from "react";
4
+ import { cn } from "@/lib/cn";
5
+ import styles from "./Collapse.module.css";
6
+
7
+ /* ══════════════════════════════════════
8
+ Collapse Group (accordion wrapper)
9
+ ══════════════════════════════════════ */
10
+ interface CollapseContextValue {
11
+ openItems: Set<string>;
12
+ toggle: (id: string) => void;
13
+ }
14
+
15
+ const CollapseContext = createContext<CollapseContextValue | null>(null);
16
+
17
+ export interface CollapseGroupProps {
18
+ children: React.ReactNode;
19
+ multiple?: boolean;
20
+ defaultOpen?: string[];
21
+ className?: string;
22
+ }
23
+
24
+ export const CollapseGroup = forwardRef<HTMLDivElement, CollapseGroupProps>(
25
+ ({ children, multiple = false, defaultOpen = [], className }, ref) => {
26
+ const [openItems, setOpenItems] = useState<Set<string>>(new Set(defaultOpen));
27
+
28
+ const toggle = useCallback(
29
+ (id: string) => {
30
+ setOpenItems((prev) => {
31
+ const next = new Set(prev);
32
+ if (next.has(id)) {
33
+ next.delete(id);
34
+ } else {
35
+ if (!multiple) next.clear();
36
+ next.add(id);
37
+ }
38
+ return next;
39
+ });
40
+ },
41
+ [multiple],
42
+ );
43
+
44
+ return (
45
+ <CollapseContext.Provider value={{ openItems, toggle }}>
46
+ <div ref={ref} className={cn(styles.group, className)}>
47
+ {children}
48
+ </div>
49
+ </CollapseContext.Provider>
50
+ );
51
+ },
52
+ );
53
+
54
+ CollapseGroup.displayName = "CollapseGroup";
55
+
56
+ /* ══════════════════════════════════════
57
+ Collapse Item
58
+ ══════════════════════════════════════ */
59
+ export interface CollapseItemProps {
60
+ id: string;
61
+ title: string;
62
+ children: React.ReactNode;
63
+ defaultOpen?: boolean;
64
+ className?: string;
65
+ }
66
+
67
+ export const CollapseItem = forwardRef<HTMLDivElement, CollapseItemProps>(
68
+ ({ id, title, children, defaultOpen = false, className }, ref) => {
69
+ const ctx = useContext(CollapseContext);
70
+
71
+ // Standalone mode (no group)
72
+ const [standaloneOpen, setStandaloneOpen] = useState(defaultOpen);
73
+ const isOpen = ctx ? ctx.openItems.has(id) : standaloneOpen;
74
+ const handleToggle = ctx ? () => ctx.toggle(id) : () => setStandaloneOpen((p) => !p);
75
+
76
+ return (
77
+ <div ref={ref} className={cn(styles.item, className)}>
78
+ <button
79
+ className={styles.itemHeader}
80
+ onClick={handleToggle}
81
+ aria-expanded={isOpen}
82
+ >
83
+ <span className={styles.itemTitle}>{title}</span>
84
+ <span className={cn(styles.itemChevron, isOpen && styles.itemChevronOpen)}>
85
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
86
+ <path d="M4 6L8 10L12 6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
87
+ </svg>
88
+ </span>
89
+ </button>
90
+ {isOpen && (
91
+ <div className={styles.itemContent}>
92
+ {children}
93
+ </div>
94
+ )}
95
+ </div>
96
+ );
97
+ },
98
+ );
99
+
100
+ CollapseItem.displayName = "CollapseItem";
@@ -0,0 +1,2 @@
1
+ export { CollapseGroup, CollapseItem } from "./Collapse";
2
+ export type { CollapseGroupProps, CollapseItemProps } from "./Collapse";
@@ -0,0 +1,117 @@
1
+ .card {
2
+ position: relative;
3
+ width: 380px;
4
+ height: 240px;
5
+ border-radius: var(--radius-xl);
6
+ padding: 28px;
7
+ display: flex;
8
+ flex-direction: column;
9
+ justify-content: space-between;
10
+ overflow: hidden;
11
+ font-family: var(--font-display);
12
+ user-select: none;
13
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
14
+ }
15
+
16
+ .pattern {
17
+ position: absolute;
18
+ inset: 0;
19
+ opacity: 0.06;
20
+ background-image: radial-gradient(circle at 20% 80%, rgba(255,255,255,0.8) 0%, transparent 50%),
21
+ radial-gradient(circle at 80% 20%, rgba(255,255,255,0.6) 0%, transparent 50%);
22
+ pointer-events: none;
23
+ }
24
+
25
+ /* ── Variants ── */
26
+ .card_brand-dark {
27
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
28
+ color: #fff;
29
+ }
30
+
31
+ .card_brand-light {
32
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 50%, #dee2e6 100%);
33
+ color: #1a1a2e;
34
+ }
35
+
36
+ .card_gradient {
37
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
38
+ color: #fff;
39
+ }
40
+
41
+ .card_minimal {
42
+ background: var(--color-bg-card);
43
+ border: 1px solid var(--color-border-standard);
44
+ color: var(--color-text-primary);
45
+ box-shadow: var(--shadow-card);
46
+ backdrop-filter: var(--blur-standard);
47
+ }
48
+
49
+ /* ── Top row ── */
50
+ .top {
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: space-between;
54
+ position: relative;
55
+ z-index: 1;
56
+ }
57
+
58
+ .company {
59
+ font-size: 20px;
60
+ font-weight: 700;
61
+ letter-spacing: -0.02em;
62
+ }
63
+
64
+ .chip {
65
+ flex-shrink: 0;
66
+ }
67
+
68
+ /* ── Number ── */
69
+ .number {
70
+ font-size: 20px;
71
+ font-weight: 600;
72
+ letter-spacing: 0.12em;
73
+ position: relative;
74
+ z-index: 1;
75
+ }
76
+
77
+ /* ── Bottom row ── */
78
+ .bottom {
79
+ display: flex;
80
+ align-items: flex-end;
81
+ gap: 24px;
82
+ position: relative;
83
+ z-index: 1;
84
+ }
85
+
86
+ .field {
87
+ display: flex;
88
+ flex-direction: column;
89
+ gap: 2px;
90
+ }
91
+
92
+ .fieldLabel {
93
+ font-size: 9px;
94
+ font-weight: 500;
95
+ text-transform: uppercase;
96
+ letter-spacing: 0.08em;
97
+ opacity: 0.6;
98
+ }
99
+
100
+ .fieldValue {
101
+ font-size: 13px;
102
+ font-weight: 600;
103
+ letter-spacing: 0.04em;
104
+ }
105
+
106
+ .network {
107
+ margin-left: auto;
108
+ }
109
+
110
+ /* ── Light variant overrides ── */
111
+ .card_brand-light .pattern {
112
+ opacity: 0.03;
113
+ }
114
+
115
+ .card_brand-light .fieldLabel {
116
+ opacity: 0.5;
117
+ }
@@ -0,0 +1,86 @@
1
+ "use client";
2
+
3
+ import { forwardRef } from "react";
4
+ import { cn } from "@/lib/cn";
5
+ import styles from "./CreditCard.module.css";
6
+
7
+ export interface CreditCardProps {
8
+ type?: "brand-dark" | "brand-light" | "gradient" | "minimal";
9
+ company?: string;
10
+ cardNumber?: string;
11
+ cardHolder?: string;
12
+ cardExpiration?: string;
13
+ className?: string;
14
+ }
15
+
16
+ export const CreditCard = forwardRef<HTMLDivElement, CreditCardProps>(
17
+ (
18
+ {
19
+ type = "brand-dark",
20
+ company = "Omnira.",
21
+ cardNumber = "1234 1234 1234 1234",
22
+ cardHolder = "CARD HOLDER",
23
+ cardExpiration = "00/00",
24
+ className,
25
+ },
26
+ ref,
27
+ ) => {
28
+ const last4 = cardNumber.replace(/\s/g, "").slice(-4);
29
+ const masked = `**** **** **** ${last4}`;
30
+
31
+ return (
32
+ <div ref={ref} className={cn(styles.card, styles[`card_${type}`], className)}>
33
+ {/* Background pattern */}
34
+ <div className={styles.pattern} />
35
+
36
+ {/* Top row: company + chip */}
37
+ <div className={styles.top}>
38
+ <span className={styles.company}>{company}</span>
39
+ <ChipIcon />
40
+ </div>
41
+
42
+ {/* Card number */}
43
+ <div className={styles.number}>{masked}</div>
44
+
45
+ {/* Bottom row: holder + expiry + network */}
46
+ <div className={styles.bottom}>
47
+ <div className={styles.field}>
48
+ <span className={styles.fieldLabel}>Card Holder</span>
49
+ <span className={styles.fieldValue}>{cardHolder}</span>
50
+ </div>
51
+ <div className={styles.field}>
52
+ <span className={styles.fieldLabel}>Expires</span>
53
+ <span className={styles.fieldValue}>{cardExpiration}</span>
54
+ </div>
55
+ <div className={styles.network}>
56
+ <CardNetworkIcon />
57
+ </div>
58
+ </div>
59
+ </div>
60
+ );
61
+ },
62
+ );
63
+
64
+ CreditCard.displayName = "CreditCard";
65
+
66
+ /* ── Inline SVG Icons ── */
67
+ function ChipIcon() {
68
+ return (
69
+ <svg width="36" height="28" viewBox="0 0 36 28" fill="none" className={styles.chip}>
70
+ <rect x="0.5" y="0.5" width="35" height="27" rx="4" fill="rgba(255,215,0,0.25)" stroke="rgba(255,215,0,0.4)" />
71
+ <line x1="0" y1="10" x2="36" y2="10" stroke="rgba(255,215,0,0.3)" strokeWidth="0.5" />
72
+ <line x1="0" y1="18" x2="36" y2="18" stroke="rgba(255,215,0,0.3)" strokeWidth="0.5" />
73
+ <line x1="12" y1="0" x2="12" y2="28" stroke="rgba(255,215,0,0.3)" strokeWidth="0.5" />
74
+ <line x1="24" y1="0" x2="24" y2="28" stroke="rgba(255,215,0,0.3)" strokeWidth="0.5" />
75
+ </svg>
76
+ );
77
+ }
78
+
79
+ function CardNetworkIcon() {
80
+ return (
81
+ <svg width="40" height="26" viewBox="0 0 40 26" fill="none">
82
+ <circle cx="15" cy="13" r="12" fill="rgba(255,255,255,0.25)" />
83
+ <circle cx="25" cy="13" r="12" fill="rgba(255,255,255,0.2)" />
84
+ </svg>
85
+ );
86
+ }
@@ -0,0 +1,2 @@
1
+ export { CreditCard } from "./CreditCard";
2
+ export type { CreditCardProps } from "./CreditCard";