@licklist/design 0.78.28 → 0.78.29

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 (125) hide show
  1. package/dist/assets/Trend-Down.svg.js +16 -0
  2. package/dist/assets/Trend-Up.svg.js +16 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +10 -0
  6. package/dist/v2/components/Button/Button.d.ts +8 -4
  7. package/dist/v2/components/Button/Button.d.ts.map +1 -1
  8. package/dist/v2/components/Button/index.d.ts +2 -2
  9. package/dist/v2/components/Button/index.d.ts.map +1 -1
  10. package/dist/v2/components/Checkbox/Checkbox.d.ts +9 -0
  11. package/dist/v2/components/Checkbox/Checkbox.d.ts.map +1 -0
  12. package/dist/v2/components/Checkbox/index.d.ts +3 -0
  13. package/dist/v2/components/Checkbox/index.d.ts.map +1 -0
  14. package/dist/v2/components/FormField/FormField.d.ts +10 -0
  15. package/dist/v2/components/FormField/FormField.d.ts.map +1 -0
  16. package/dist/v2/components/FormField/index.d.ts +3 -0
  17. package/dist/v2/components/FormField/index.d.ts.map +1 -0
  18. package/dist/v2/components/NewInput/NewInput.d.ts +20 -0
  19. package/dist/v2/components/NewInput/NewInput.d.ts.map +1 -0
  20. package/dist/v2/components/NewInput/index.d.ts +2 -0
  21. package/dist/v2/components/NewInput/index.d.ts.map +1 -0
  22. package/dist/v2/components/NewPageHeader/NewPageHeader.d.ts +10 -0
  23. package/dist/v2/components/NewPageHeader/NewPageHeader.d.ts.map +1 -0
  24. package/dist/v2/components/NewPageHeader/index.d.ts +2 -0
  25. package/dist/v2/components/NewPageHeader/index.d.ts.map +1 -0
  26. package/dist/v2/components/SectionHeader/SectionHeader.d.ts +8 -0
  27. package/dist/v2/components/SectionHeader/SectionHeader.d.ts.map +1 -0
  28. package/dist/v2/components/SectionHeader/index.d.ts +3 -0
  29. package/dist/v2/components/SectionHeader/index.d.ts.map +1 -0
  30. package/dist/v2/components/Select/Select.js +128 -0
  31. package/dist/v2/components/Select/Select.scss.js +6 -0
  32. package/dist/v2/components/WYSIWYGEditor/Icons.d.ts +16 -0
  33. package/dist/v2/components/WYSIWYGEditor/Icons.d.ts.map +1 -0
  34. package/dist/v2/components/WYSIWYGEditor/WYSIWYGEditor.d.ts +14 -0
  35. package/dist/v2/components/WYSIWYGEditor/WYSIWYGEditor.d.ts.map +1 -0
  36. package/dist/v2/components/WYSIWYGEditor/index.d.ts +3 -0
  37. package/dist/v2/components/WYSIWYGEditor/index.d.ts.map +1 -0
  38. package/dist/v2/components/index.d.ts +22 -0
  39. package/dist/v2/components/index.d.ts.map +1 -0
  40. package/dist/v2/dashboard-analytics/blog-posts/Blog.js +103 -0
  41. package/dist/v2/dashboard-analytics/blog-posts/Blog.scss.js +6 -0
  42. package/dist/v2/dashboard-analytics/chart/Chart.js +733 -0
  43. package/dist/v2/dashboard-analytics/chart/Chart.scss.js +6 -0
  44. package/dist/v2/dashboard-analytics/dashboard/Dashboard.js +270 -0
  45. package/dist/v2/dashboard-analytics/dashboard/Dashboard.scss.js +6 -0
  46. package/dist/v2/dashboard-analytics/metric-card/MetricCard.js +65 -0
  47. package/dist/v2/dashboard-analytics/metric-card/MetricCard.scss.js +6 -0
  48. package/dist/v2/dashboard-analytics/venue-card/VenueCard.js +50 -0
  49. package/dist/v2/dashboard-analytics/venue-card/VenueCard.scss.js +6 -0
  50. package/dist/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.js +48 -0
  51. package/dist/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.scss.js +6 -0
  52. package/dist/v2/icons/index.js +61 -1
  53. package/dist/v2/index.d.ts +3 -1
  54. package/dist/v2/index.d.ts.map +1 -1
  55. package/dist/v2/navigation/DashboardLayout/TopNavigation.scss.js +1 -1
  56. package/dist/v2/pages/Settings/SettingsPage.d.ts +13 -0
  57. package/dist/v2/pages/Settings/SettingsPage.d.ts.map +1 -0
  58. package/dist/v2/pages/Settings/SettingsPage.js +88 -0
  59. package/dist/v2/pages/Settings/SettingsPage.scss.js +6 -0
  60. package/dist/v2/pages/Settings/SettingsTabs.d.ts +14 -0
  61. package/dist/v2/pages/Settings/SettingsTabs.d.ts.map +1 -0
  62. package/dist/v2/pages/Settings/SettingsTabs.js +29 -0
  63. package/dist/v2/pages/Settings/SettingsTabs.scss.js +6 -0
  64. package/dist/v2/pages/Settings/components/SidebarCustomisation.js +283 -0
  65. package/dist/v2/pages/Settings/components/SidebarCustomisation.scss.js +6 -0
  66. package/dist/v2/pages/Settings/components/SidebarNavItem.d.ts +19 -0
  67. package/dist/v2/pages/Settings/components/SidebarNavItem.d.ts.map +1 -0
  68. package/dist/v2/pages/Settings/components/SidebarNavItem.js +41 -0
  69. package/dist/v2/pages/Settings/components/SidebarNavItem.scss.js +6 -0
  70. package/dist/v2/pages/Settings/components/index.d.ts +5 -0
  71. package/dist/v2/pages/Settings/components/index.d.ts.map +1 -0
  72. package/dist/v2/pages/Settings/index.d.ts +7 -0
  73. package/dist/v2/pages/Settings/index.d.ts.map +1 -0
  74. package/package.json +3 -3
  75. package/src/index.ts +3 -1
  76. package/src/v2/components/Alert/Alert.scss +3 -3
  77. package/src/v2/components/Button/Button.tsx +34 -12
  78. package/src/v2/components/Button/index.ts +2 -2
  79. package/src/v2/components/Checkbox/Checkbox.scss +211 -0
  80. package/src/v2/components/Checkbox/Checkbox.stories.tsx +316 -0
  81. package/src/v2/components/Checkbox/Checkbox.tsx +106 -0
  82. package/src/v2/components/Checkbox/index.ts +3 -0
  83. package/src/v2/components/FormField/FormField.scss +87 -0
  84. package/src/v2/components/FormField/FormField.stories.tsx +71 -0
  85. package/src/v2/components/FormField/FormField.tsx +37 -0
  86. package/src/v2/components/FormField/index.ts +3 -0
  87. package/src/v2/components/NewInput/NewInput.stories.tsx +433 -0
  88. package/src/v2/components/NewInput/NewInput.tsx +96 -0
  89. package/src/v2/components/NewInput/index.ts +1 -0
  90. package/src/v2/components/NewPageHeader/NewPageHeader.scss +47 -0
  91. package/src/v2/components/NewPageHeader/NewPageHeader.stories.tsx +44 -0
  92. package/src/v2/components/NewPageHeader/NewPageHeader.tsx +35 -0
  93. package/src/v2/components/NewPageHeader/index.ts +1 -0
  94. package/src/v2/components/SectionHeader/SectionHeader.scss +11 -0
  95. package/src/v2/components/SectionHeader/SectionHeader.tsx +15 -0
  96. package/src/v2/components/SectionHeader/index.ts +2 -0
  97. package/src/v2/components/Select/Select.scss +5 -5
  98. package/src/v2/components/WYSIWYGEditor/Icons.tsx +93 -0
  99. package/src/v2/components/WYSIWYGEditor/WYSIWYGEditor.scss +310 -0
  100. package/src/v2/components/WYSIWYGEditor/WYSIWYGEditor.stories.tsx +252 -0
  101. package/src/v2/components/WYSIWYGEditor/WYSIWYGEditor.tsx +393 -0
  102. package/src/v2/components/WYSIWYGEditor/index.ts +3 -0
  103. package/src/v2/components/index.ts +37 -0
  104. package/src/v2/index.ts +10 -2
  105. package/src/v2/navigation/DashboardLayout/TopNavigation.scss +1 -0
  106. package/src/v2/pages/Settings/SettingsContentPlaceholder.scss +24 -0
  107. package/src/v2/pages/Settings/SettingsPage.scss +52 -0
  108. package/src/v2/pages/Settings/SettingsPage.tsx +46 -0
  109. package/src/v2/pages/Settings/SettingsTabs.scss +44 -0
  110. package/src/v2/pages/Settings/SettingsTabs.tsx +36 -0
  111. package/src/v2/pages/Settings/components/SidebarCustomisation.stories.tsx +48 -0
  112. package/src/v2/pages/Settings/components/SidebarNavItem.scss +76 -0
  113. package/src/v2/pages/Settings/components/SidebarNavItem.stories.tsx +50 -0
  114. package/src/v2/pages/Settings/components/SidebarNavItem.tsx +52 -0
  115. package/src/v2/pages/Settings/components/index.ts +5 -0
  116. package/src/v2/pages/Settings/index.ts +8 -0
  117. package/src/v2/styles/components/Button.scss +51 -53
  118. package/src/v2/styles/form/Layout.scss +15 -0
  119. package/src/v2/styles/form/NewInput.scss +83 -53
  120. package/src/v2/styles/index.scss +1 -0
  121. package/src/v2/styles/tokens/_colors.scss +6 -6
  122. package/src/v2/styles/tokens/_typography.scss +2 -2
  123. package/dist/v2/navigation/icons/index.d.ts +0 -12
  124. package/dist/v2/navigation/icons/index.d.ts.map +0 -1
  125. package/src/v2/navigation/icons/index.tsx +0 -72
@@ -0,0 +1,211 @@
1
+ @import '../../styles/index.scss';
2
+
3
+ .checkbox {
4
+ display: flex;
5
+ max-width: 500px;
6
+ align-items: flex-start;
7
+ gap: 11px;
8
+ align-self: stretch;
9
+
10
+ @media (min-width: 992px) {
11
+ max-width: unset;
12
+ }
13
+
14
+ &__wrapper {
15
+ display: flex;
16
+ align-items: flex-start;
17
+ gap: 11px;
18
+ cursor: pointer;
19
+ user-select: none;
20
+ width: 100%;
21
+ }
22
+
23
+ &__input {
24
+ position: absolute;
25
+ opacity: 0;
26
+ cursor: pointer;
27
+ height: 0;
28
+ width: 0;
29
+
30
+ &:checked ~ .checkbox__toggle {
31
+ background: var(--fill-selected, #14215A);
32
+ border: 1px solid var(--border-primary, #E8E9EF);
33
+
34
+ .checkbox__xmark {
35
+ opacity: 0;
36
+ visibility: hidden;
37
+ }
38
+
39
+ .checkbox__checked-group {
40
+ opacity: 1;
41
+ visibility: visible;
42
+ }
43
+ }
44
+
45
+ &:focus ~ .checkbox__toggle {
46
+ box-shadow: 0 0 0 2px rgba(20, 33, 90, 0.2);
47
+ }
48
+
49
+ &:disabled ~ .checkbox__toggle {
50
+ background-color: var(--surface-status-disabled, #f8f8fa);
51
+ border-color: var(--border-primary, #e8e9ef);
52
+ cursor: not-allowed;
53
+ opacity: 0.6;
54
+ }
55
+ }
56
+
57
+ // Only show X mark when not pristine and not checked
58
+ &:not(&--pristine) &__input:not(:checked) ~ &__toggle {
59
+ .checkbox__xmark {
60
+ opacity: 1;
61
+ visibility: visible;
62
+ top: 50%;
63
+ position: absolute;
64
+ right: 4px;
65
+ transform: translateY(-50%);
66
+ display: flex;
67
+ align-items: center;
68
+ justify-content: center;
69
+ }
70
+
71
+ .checkbox__checked-group {
72
+ opacity: 0;
73
+ visibility: hidden;
74
+ }
75
+ }
76
+
77
+ &__toggle {
78
+ position: relative;
79
+ display: flex;
80
+ align-items: center;
81
+ justify-content: flex-end; // Positions X mark to the right
82
+ width: 58px;
83
+ height: 34px; // Set explicit height to help with vertical centering
84
+ min-width: 58px;
85
+ padding: 4px;
86
+ background: var(--surface-secondary, #F8F8FA);
87
+ border: 1px solid var(--border-primary, #E8E9EF);
88
+ border-radius: var(--padding-xl, 32px);
89
+ flex-shrink: 0;
90
+ }
91
+
92
+ &__xmark {
93
+ width: 24px;
94
+ height: 24px;
95
+ opacity: 0; // Hidden by default (blank state)
96
+ visibility: hidden;
97
+
98
+ svg {
99
+ width: 100%;
100
+ height: 100%;
101
+ }
102
+ }
103
+
104
+ &__checked-group {
105
+ position: absolute;
106
+ left: 4px;
107
+ top: 50%;
108
+ transform: translateY(-50%);
109
+ width: 24px;
110
+ height: 24px;
111
+ opacity: 0;
112
+ visibility: hidden;
113
+ display: flex;
114
+ align-items: center;
115
+ justify-content: center;
116
+ }
117
+
118
+ &__circle {
119
+ position: relative;
120
+ width: 24px;
121
+ height: 24px;
122
+ display: flex;
123
+ align-items: center;
124
+ justify-content: center;
125
+
126
+ svg {
127
+ width: 100%;
128
+ height: 100%;
129
+ }
130
+ }
131
+
132
+ &__checkmark {
133
+ position: absolute;
134
+ top: 50%;
135
+ left: 50%;
136
+ transform: translate(-50%, -50%);
137
+ width: 24px;
138
+ height: 24px;
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: center;
142
+
143
+ svg {
144
+ width: 100%;
145
+ height: 100%;
146
+ }
147
+ }
148
+
149
+ &__content {
150
+ display: flex;
151
+ flex-direction: column;
152
+ gap: 4px;
153
+ flex: 1;
154
+ }
155
+
156
+ &__label {
157
+ font-family: var(--font-family-sans, 'Geist', sans-serif), serif;
158
+ color: var(--label-primary);
159
+ font-size: 15px;
160
+ font-style: normal;
161
+ font-weight: 600;
162
+ line-height: 20px;
163
+ }
164
+
165
+ &__description {
166
+ color: var(--label-secondary);
167
+ font-family: var(--font-family-sans, 'Geist', sans-serif), serif;
168
+ font-size: var(--text-regular-size, 15px);
169
+ font-style: normal;
170
+ font-weight: 400;
171
+ line-height: var(--text-regular-line, 20px);
172
+ word-break: break-word;
173
+ overflow-wrap: break-word;
174
+ }
175
+
176
+ &__error-text {
177
+ font-family: var(--font-family-sans, 'Geist', sans-serif), serif;
178
+ font-size: var(--text-xs-size, 11px);
179
+ line-height: var(--text-xs-line, 14px);
180
+ color: var(--label-status-error, #ef4444);
181
+ margin-left: 69px;
182
+ }
183
+
184
+ &__wrapper:hover &__input:not(:disabled) ~ &__toggle {
185
+ border-color: var(--border-primary-hover, #d1d3de);
186
+ }
187
+
188
+ &--pristine {
189
+ .checkbox__toggle {
190
+ background: var(--surface-secondary, #F8F8FA);
191
+ }
192
+ .checkbox__xmark,
193
+ .checkbox__checked-group {
194
+ opacity: 0 !important;
195
+ visibility: hidden !important;
196
+ }
197
+ }
198
+ }
199
+
200
+ .checkbox-pristine-wrapper {
201
+ display: flex;
202
+ width: 58px;
203
+ padding: 4px;
204
+ justify-content: flex-end;
205
+ align-items: center;
206
+ gap: 8px;
207
+ border-radius: var(--padding-xl, 32px);
208
+ border: 1px solid var(--border-primary, #E8E9EF);
209
+ background: var(--surface-primary, #FFF);
210
+ }
211
+
@@ -0,0 +1,316 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { Checkbox } from './Checkbox'
3
+ import { useState } from 'react'
4
+
5
+ const meta: Meta<typeof Checkbox> = {
6
+ title: 'V2/Components/Checkbox',
7
+ component: Checkbox,
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ tags: ['autodocs'],
12
+ }
13
+
14
+ export default meta
15
+ type Story = StoryObj<typeof Checkbox>
16
+
17
+ export const Default: Story = {
18
+ args: {
19
+ label: 'Accept terms and conditions',
20
+ },
21
+ }
22
+
23
+ export const WithDescription: Story = {
24
+ args: {
25
+ label: 'Legal Guardian Consent',
26
+ description: 'If enabled, displays a checkbox asking if you are, or have permission to sign on behalf of the minor.',
27
+ },
28
+ }
29
+
30
+ export const Checked: Story = {
31
+ args: {
32
+ label: 'Pre-checked checkbox',
33
+ description: 'This checkbox starts in checked state',
34
+ checked: true,
35
+ },
36
+ }
37
+
38
+ export const Unchecked: Story = {
39
+ args: {
40
+ label: 'Pre-unchecked checkbox',
41
+ description: 'This checkbox starts in unchecked state (showing X mark)',
42
+ checked: false,
43
+ },
44
+ }
45
+
46
+ export const WithError: Story = {
47
+ args: {
48
+ label: 'Checkbox with error',
49
+ description: 'This checkbox has an error state',
50
+ error: 'This field is required',
51
+ },
52
+ }
53
+
54
+ export const Disabled: Story = {
55
+ args: {
56
+ label: 'Disabled checkbox',
57
+ description: 'This checkbox is disabled',
58
+ disabled: true,
59
+ },
60
+ }
61
+
62
+ export const DisabledChecked: Story = {
63
+ args: {
64
+ label: 'Disabled checked checkbox',
65
+ description: 'This checkbox is disabled and checked',
66
+ disabled: true,
67
+ checked: true,
68
+ },
69
+ }
70
+
71
+ // Controlled checkbox example
72
+ export const Controlled: Story = {
73
+ render: () => {
74
+ const ControlledExample = () => {
75
+ const [checked, setChecked] = useState(false)
76
+
77
+ return (
78
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
79
+ <Checkbox
80
+ label="Controlled checkbox"
81
+ description={`Current state: ${checked ? 'Checked ✓' : 'Unchecked ✗'}`}
82
+ checked={checked}
83
+ onChange={(e) => setChecked(e.target.checked)}
84
+ />
85
+ <button onClick={() => setChecked(!checked)}>
86
+ Toggle programmatically
87
+ </button>
88
+ </div>
89
+ )
90
+ }
91
+
92
+ return <ControlledExample />
93
+ },
94
+ }
95
+
96
+ // Pristine (blank) state - initial state before any interaction
97
+ export const Pristine: Story = {
98
+ args: {
99
+ label: 'Pristine checkbox',
100
+ description: 'This checkbox is in pristine state (completely blank/empty before any interaction)',
101
+ },
102
+ }
103
+
104
+ // Animation showcase - demonstrates the sliding animation
105
+ export const AnimationShowcase: Story = {
106
+ render: () => {
107
+ const [checked, setChecked] = useState(false)
108
+
109
+ return (
110
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '20px', padding: '20px' }}>
111
+ <h3>Click to see the animation</h3>
112
+ <Checkbox
113
+ label="Animated checkbox"
114
+ description="Watch the smooth slide animation when toggling"
115
+ checked={checked}
116
+ onChange={(e) => setChecked(e.target.checked)}
117
+ />
118
+ <p style={{ fontSize: '14px', color: '#666' }}>
119
+ {checked
120
+ ? '✅ Checkmark slides in from the left'
121
+ : '❌ X mark slides in from the right'}
122
+ </p>
123
+ </div>
124
+ )
125
+ },
126
+ }
127
+
128
+ // Multiple checkboxes with pre-set values (like form edit mode)
129
+ export const MultipleWithPresetValues: Story = {
130
+ render: () => {
131
+ const [values, setValues] = useState({
132
+ legalGuardian: true,
133
+ oneAdultPerWaiver: false,
134
+ sendEmail: true,
135
+ })
136
+
137
+ return (
138
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
139
+ <h3>Edit Waiver Template (Simulated)</h3>
140
+ <Checkbox
141
+ label="Legal Guardian Consent"
142
+ description="If enabled, displays a checkbox asking if you are, or have permission to sign on behalf of the minor."
143
+ checked={values.legalGuardian}
144
+ onChange={(e) => setValues({ ...values, legalGuardian: e.target.checked })}
145
+ />
146
+ <Checkbox
147
+ label="1 Adult per Waiver"
148
+ description="If enabled, each participant over 18 must sign their own waiver."
149
+ checked={values.oneAdultPerWaiver}
150
+ onChange={(e) => setValues({ ...values, oneAdultPerWaiver: e.target.checked })}
151
+ />
152
+ <Checkbox
153
+ label="Send confirmation email"
154
+ description="Automatically send email after waiver is signed."
155
+ checked={values.sendEmail}
156
+ onChange={(e) => setValues({ ...values, sendEmail: e.target.checked })}
157
+ />
158
+ <div style={{ marginTop: '20px', padding: '10px', background: '#f0f0f0', borderRadius: '4px' }}>
159
+ <strong>Current values:</strong>
160
+ <pre>{JSON.stringify(values, null, 2)}</pre>
161
+ </div>
162
+ </div>
163
+ )
164
+ },
165
+ }
166
+
167
+ // Real-world form example with pristine, checked, and unchecked states
168
+ export const RealWorldFormExample: Story = {
169
+ render: () => {
170
+ const [isActive, setIsActive] = useState<boolean>(true)
171
+ const [legalGuardian, setLegalGuardian] = useState<boolean>(false)
172
+ const [oneAdult, setOneAdult] = useState<boolean | undefined>(undefined)
173
+
174
+ return (
175
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '20px', maxWidth: '600px' }}>
176
+ <h3>Waiver Template Settings</h3>
177
+ <div style={{
178
+ background: '#f8f9fa',
179
+ padding: '16px',
180
+ borderRadius: '8px',
181
+ marginBottom: '10px'
182
+ }}>
183
+ <strong>Current State:</strong>
184
+ <ul style={{ marginTop: '8px', fontSize: '14px' }}>
185
+ <li>Active: {String(isActive)} (Checked)</li>
186
+ <li>Legal Guardian: {String(legalGuardian)} (Unchecked with X)</li>
187
+ <li>One Adult: {oneAdult === undefined ? 'undefined' : String(oneAdult)} (Pristine/Blank)</li>
188
+ </ul>
189
+ </div>
190
+
191
+ <Checkbox
192
+ label="Active"
193
+ description="Use this waiver when asking customers to fill in their details. Setting as active will disable any other waivers currently in use."
194
+ checked={isActive}
195
+ onChange={(e) => setIsActive(e.target.checked)}
196
+ />
197
+
198
+ <Checkbox
199
+ label="Legal Guardian Consent"
200
+ description="If enabled, displays a checkbox asking if you are, or have permission to sign on behalf of the minor."
201
+ checked={legalGuardian}
202
+ onChange={(e) => setLegalGuardian(e.target.checked)}
203
+ />
204
+
205
+ <Checkbox
206
+ label="1 Adult per Waiver"
207
+ description="If enabled, each participant over 18 must sign their own waiver."
208
+ checked={oneAdult}
209
+ onChange={(e) => setOneAdult(e.target.checked)}
210
+ />
211
+
212
+ <button
213
+ onClick={() => {
214
+ setIsActive(true)
215
+ setLegalGuardian(false)
216
+ setOneAdult(true)
217
+ }}
218
+ style={{
219
+ padding: '8px 16px',
220
+ background: '#269B36',
221
+ color: 'white',
222
+ border: 'none',
223
+ borderRadius: '4px',
224
+ cursor: 'pointer'
225
+ }}
226
+ >
227
+ Load Preset Values
228
+ </button>
229
+
230
+ <button
231
+ onClick={() => {
232
+ setIsActive(false)
233
+ setLegalGuardian(false)
234
+ setOneAdult(undefined)
235
+ }}
236
+ style={{
237
+ padding: '8px 16px',
238
+ background: '#6c757d',
239
+ color: 'white',
240
+ border: 'none',
241
+ borderRadius: '4px',
242
+ cursor: 'pointer'
243
+ }}
244
+ >
245
+ Reset Form (Show Pristine State)
246
+ </button>
247
+ </div>
248
+ )
249
+ },
250
+ }
251
+
252
+ // All states in one view for comparison
253
+ export const AllStates: Story = {
254
+ render: () => {
255
+ return (
256
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: '30px', padding: '20px' }}>
257
+ <div>
258
+ <h4 style={{ marginBottom: '10px' }}>Pristine (Blank)</h4>
259
+ <Checkbox
260
+ label="Pristine state"
261
+ description="No value set (undefined)"
262
+ />
263
+ </div>
264
+
265
+ <div>
266
+ <h4 style={{ marginBottom: '10px' }}>Checked</h4>
267
+ <Checkbox
268
+ label="Checked state"
269
+ description="Value is true"
270
+ checked={true}
271
+ onChange={() => {}}
272
+ />
273
+ </div>
274
+
275
+ <div>
276
+ <h4 style={{ marginBottom: '10px' }}>Unchecked</h4>
277
+ <Checkbox
278
+ label="Unchecked state"
279
+ description="Value is false (X mark visible)"
280
+ checked={false}
281
+ onChange={() => {}}
282
+ />
283
+ </div>
284
+
285
+ <div>
286
+ <h4 style={{ marginBottom: '10px' }}>Disabled</h4>
287
+ <Checkbox
288
+ label="Disabled state"
289
+ description="Cannot be interacted with"
290
+ disabled={true}
291
+ />
292
+ </div>
293
+
294
+ <div>
295
+ <h4 style={{ marginBottom: '10px' }}>Disabled Checked</h4>
296
+ <Checkbox
297
+ label="Disabled checked"
298
+ description="Disabled and checked"
299
+ disabled={true}
300
+ checked={true}
301
+ />
302
+ </div>
303
+
304
+ <div>
305
+ <h4 style={{ marginBottom: '10px' }}>With Error</h4>
306
+ <Checkbox
307
+ label="Error state"
308
+ description="Has validation error"
309
+ error="This field is required"
310
+ />
311
+ </div>
312
+ </div>
313
+ )
314
+ },
315
+ }
316
+
@@ -0,0 +1,106 @@
1
+ import React, { InputHTMLAttributes, forwardRef } from 'react'
2
+ import './Checkbox.scss'
3
+
4
+ export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
5
+ label?: string | React.ReactNode
6
+ description?: string
7
+ error?: string
8
+ }
9
+
10
+ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
11
+ ({ label, description, error, className = '', checked, onChange, ...props }, ref) => {
12
+ const [isPristine, setIsPristine] = React.useState(checked === undefined)
13
+ const hasInteractedRef = React.useRef(false)
14
+
15
+ // Update pristine state when checked prop changes (e.g., from form defaultValues)
16
+ React.useEffect(() => {
17
+ // If checked is defined (true or false) and user hasn't manually interacted, show the state
18
+ if (checked !== undefined && !hasInteractedRef.current) {
19
+ setIsPristine(false)
20
+ } else if (checked === undefined && !hasInteractedRef.current) {
21
+ // If checked becomes undefined again, restore pristine state (blank)
22
+ setIsPristine(true)
23
+ }
24
+ }, [checked])
25
+
26
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
27
+ hasInteractedRef.current = true
28
+ setIsPristine(false)
29
+ onChange?.(e)
30
+ }
31
+
32
+ return (
33
+ <div className={`checkbox ${isPristine ? 'checkbox--pristine' : ''} ${className}`}>
34
+ <label className="checkbox__wrapper">
35
+ <input
36
+ ref={ref}
37
+ type="checkbox"
38
+ className={`checkbox__input ${error ? 'checkbox__input--error' : ''}`}
39
+ checked={checked}
40
+ onChange={handleChange}
41
+ {...props}
42
+ />
43
+ <span className="checkbox__toggle">
44
+ {/* X mark - visible when unchecked, positioned to the right */}
45
+ <span className="checkbox__xmark">
46
+ <svg
47
+ xmlns="http://www.w3.org/2000/svg"
48
+ width="24"
49
+ height="24"
50
+ viewBox="0 0 24 24"
51
+ fill="none"
52
+ >
53
+ <path
54
+ d="M0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12Z"
55
+ fill="#14215A"
56
+ />
57
+ <path
58
+ d="M18.1426 8.59961L14.0762 12.375L18.1426 16.1504L16.1006 18.3496L11.8711 14.4219L7.64258 18.3496L5.60059 16.1504L9.66602 12.375L5.60059 8.59961L7.64258 6.40039L11.8711 10.3271L16.1006 6.40039L18.1426 8.59961Z"
59
+ fill="white"
60
+ />
61
+ </svg>
62
+ </span>
63
+
64
+ {/* White circle + Checkmark - visible when checked, positioned to the left */}
65
+ <span className="checkbox__checked-group">
66
+ <span className="checkbox__circle">
67
+ <svg
68
+ xmlns="http://www.w3.org/2000/svg"
69
+ width="24"
70
+ height="24"
71
+ viewBox="0 0 24 24"
72
+ fill="none"
73
+ >
74
+ <circle cx="12" cy="12" r="12" fill="white" />
75
+ </svg>
76
+ </span>
77
+ <span className="checkbox__checkmark">
78
+ <svg
79
+ xmlns="http://www.w3.org/2000/svg"
80
+ width="24"
81
+ height="24"
82
+ viewBox="0 0 24 24"
83
+ fill="none"
84
+ >
85
+ <path
86
+ d="M19.1272 8.67725L10.8545 18.1013L5.71509 13.2058L7.78491 11.0334L10.6611 13.7734L16.8728 6.69824L19.1272 8.67725Z"
87
+ fill="#14215A"
88
+ />
89
+ </svg>
90
+ </span>
91
+ </span>
92
+ </span>
93
+ {(label || description) && (
94
+ <div className="checkbox__content">
95
+ {label && <span className="checkbox__label">{label}</span>}
96
+ {description && <span className="checkbox__description">{description}</span>}
97
+ </div>
98
+ )}
99
+ </label>
100
+ {error && <span className="checkbox__error-text">{error}</span>}
101
+ </div>
102
+ )
103
+ }
104
+ )
105
+
106
+ Checkbox.displayName = 'Checkbox'
@@ -0,0 +1,3 @@
1
+ export { Checkbox } from './Checkbox'
2
+ export type { CheckboxProps } from './Checkbox'
3
+