@licklist/design 0.78.28 → 0.78.30
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/assets/Trend-Down.svg.js +16 -0
- package/dist/assets/Trend-Up.svg.js +16 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -0
- package/dist/v2/components/Alert/Alert.js +87 -0
- package/dist/v2/components/Alert/Alert.scss.js +6 -0
- package/dist/v2/components/Button/Button.d.ts +8 -4
- package/dist/v2/components/Button/Button.d.ts.map +1 -1
- package/dist/v2/components/Button/Button.js +121 -0
- package/dist/v2/components/Button/Button.scss.js +6 -0
- package/dist/v2/components/Button/index.d.ts +2 -2
- package/dist/v2/components/Button/index.d.ts.map +1 -1
- package/dist/v2/components/Checkbox/Checkbox.d.ts +9 -0
- package/dist/v2/components/Checkbox/Checkbox.d.ts.map +1 -0
- package/dist/v2/components/Checkbox/Checkbox.js +231 -0
- package/dist/v2/components/Checkbox/Checkbox.scss.js +6 -0
- package/dist/v2/components/Checkbox/index.d.ts +3 -0
- package/dist/v2/components/Checkbox/index.d.ts.map +1 -0
- package/dist/v2/components/FormField/FormField.d.ts +10 -0
- package/dist/v2/components/FormField/FormField.d.ts.map +1 -0
- package/dist/v2/components/FormField/FormField.js +98 -0
- package/dist/v2/components/FormField/FormField.scss.js +6 -0
- package/dist/v2/components/FormField/index.d.ts +3 -0
- package/dist/v2/components/FormField/index.d.ts.map +1 -0
- package/dist/v2/components/NPSScore/NPSScore.js +546 -0
- package/dist/v2/components/NPSScore/NPSScore.scss.js +6 -0
- package/dist/v2/components/NewInput/NewInput.d.ts +20 -0
- package/dist/v2/components/NewInput/NewInput.d.ts.map +1 -0
- package/dist/v2/components/NewInput/NewInput.js +134 -0
- package/dist/v2/components/NewInput/index.d.ts +2 -0
- package/dist/v2/components/NewInput/index.d.ts.map +1 -0
- package/dist/v2/components/NewPageHeader/NewPageHeader.d.ts +10 -0
- package/dist/v2/components/NewPageHeader/NewPageHeader.d.ts.map +1 -0
- package/dist/v2/components/NewPageHeader/NewPageHeader.js +36 -0
- package/dist/v2/components/NewPageHeader/NewPageHeader.scss.js +6 -0
- package/dist/v2/components/NewPageHeader/index.d.ts +2 -0
- package/dist/v2/components/NewPageHeader/index.d.ts.map +1 -0
- package/dist/v2/components/SectionHeader/SectionHeader.d.ts +8 -0
- package/dist/v2/components/SectionHeader/SectionHeader.d.ts.map +1 -0
- package/dist/v2/components/SectionHeader/SectionHeader.js +13 -0
- package/dist/v2/components/SectionHeader/SectionHeader.scss.js +6 -0
- package/dist/v2/components/SectionHeader/index.d.ts +3 -0
- package/dist/v2/components/SectionHeader/index.d.ts.map +1 -0
- package/dist/v2/components/Select/Select.js +128 -0
- package/dist/v2/components/Select/Select.scss.js +6 -0
- package/dist/v2/components/WYSIWYGEditor/Icons.d.ts +16 -0
- package/dist/v2/components/WYSIWYGEditor/Icons.d.ts.map +1 -0
- package/dist/v2/components/WYSIWYGEditor/Icons.js +221 -0
- package/dist/v2/components/WYSIWYGEditor/WYSIWYGEditor.d.ts +14 -0
- package/dist/v2/components/WYSIWYGEditor/WYSIWYGEditor.d.ts.map +1 -0
- package/dist/v2/components/WYSIWYGEditor/WYSIWYGEditor.js +358 -0
- package/dist/v2/components/WYSIWYGEditor/WYSIWYGEditor.scss.js +6 -0
- package/dist/v2/components/WYSIWYGEditor/index.d.ts +3 -0
- package/dist/v2/components/WYSIWYGEditor/index.d.ts.map +1 -0
- package/dist/v2/components/index.d.ts +22 -0
- package/dist/v2/components/index.d.ts.map +1 -0
- package/dist/v2/dashboard-analytics/blog-posts/Blog.js +103 -0
- package/dist/v2/dashboard-analytics/blog-posts/Blog.scss.js +6 -0
- package/dist/v2/dashboard-analytics/chart/Chart.js +733 -0
- package/dist/v2/dashboard-analytics/chart/Chart.scss.js +6 -0
- package/dist/v2/dashboard-analytics/dashboard/Dashboard.js +270 -0
- package/dist/v2/dashboard-analytics/dashboard/Dashboard.scss.js +6 -0
- package/dist/v2/dashboard-analytics/metric-card/MetricCard.js +65 -0
- package/dist/v2/dashboard-analytics/metric-card/MetricCard.scss.js +6 -0
- package/dist/v2/dashboard-analytics/venue-card/VenueCard.js +50 -0
- package/dist/v2/dashboard-analytics/venue-card/VenueCard.scss.js +6 -0
- package/dist/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.js +48 -0
- package/dist/v2/dashboard-analytics/venue-closed-card/VenueClosedCard.scss.js +6 -0
- package/dist/v2/icons/index.js +61 -1
- package/dist/v2/index.d.ts +3 -1
- package/dist/v2/index.d.ts.map +1 -1
- package/dist/v2/navigation/DashboardLayout/TopNavigation.scss.js +1 -1
- package/dist/v2/pages/Settings/SettingsPage.d.ts +13 -0
- package/dist/v2/pages/Settings/SettingsPage.d.ts.map +1 -0
- package/dist/v2/pages/Settings/SettingsPage.js +88 -0
- package/dist/v2/pages/Settings/SettingsPage.scss.js +6 -0
- package/dist/v2/pages/Settings/SettingsTabs.d.ts +14 -0
- package/dist/v2/pages/Settings/SettingsTabs.d.ts.map +1 -0
- package/dist/v2/pages/Settings/SettingsTabs.js +29 -0
- package/dist/v2/pages/Settings/SettingsTabs.scss.js +6 -0
- package/dist/v2/pages/Settings/components/SidebarCustomisation.js +283 -0
- package/dist/v2/pages/Settings/components/SidebarCustomisation.scss.js +6 -0
- package/dist/v2/pages/Settings/components/SidebarNavItem.d.ts +19 -0
- package/dist/v2/pages/Settings/components/SidebarNavItem.d.ts.map +1 -0
- package/dist/v2/pages/Settings/components/SidebarNavItem.js +41 -0
- package/dist/v2/pages/Settings/components/SidebarNavItem.scss.js +6 -0
- package/dist/v2/pages/Settings/components/index.d.ts +5 -0
- package/dist/v2/pages/Settings/components/index.d.ts.map +1 -0
- package/dist/v2/pages/Settings/index.d.ts +7 -0
- package/dist/v2/pages/Settings/index.d.ts.map +1 -0
- package/dist/v2/styles/form/NewInput.scss.js +6 -0
- package/package.json +3 -3
- package/src/index.ts +4 -1
- package/src/v2/components/Alert/Alert.scss +3 -3
- package/src/v2/components/Button/Button.tsx +34 -12
- package/src/v2/components/Button/index.ts +2 -2
- package/src/v2/components/Checkbox/Checkbox.scss +211 -0
- package/src/v2/components/Checkbox/Checkbox.stories.tsx +316 -0
- package/src/v2/components/Checkbox/Checkbox.tsx +106 -0
- package/src/v2/components/Checkbox/index.ts +3 -0
- package/src/v2/components/FormField/FormField.scss +87 -0
- package/src/v2/components/FormField/FormField.stories.tsx +71 -0
- package/src/v2/components/FormField/FormField.tsx +37 -0
- package/src/v2/components/FormField/index.ts +3 -0
- package/src/v2/components/NewInput/NewInput.stories.tsx +433 -0
- package/src/v2/components/NewInput/NewInput.tsx +96 -0
- package/src/v2/components/NewInput/index.ts +1 -0
- package/src/v2/components/NewPageHeader/NewPageHeader.scss +47 -0
- package/src/v2/components/NewPageHeader/NewPageHeader.stories.tsx +44 -0
- package/src/v2/components/NewPageHeader/NewPageHeader.tsx +35 -0
- package/src/v2/components/NewPageHeader/index.ts +1 -0
- package/src/v2/components/SectionHeader/SectionHeader.scss +11 -0
- package/src/v2/components/SectionHeader/SectionHeader.tsx +15 -0
- package/src/v2/components/SectionHeader/index.ts +2 -0
- package/src/v2/components/Select/Select.scss +5 -5
- package/src/v2/components/WYSIWYGEditor/Icons.tsx +93 -0
- package/src/v2/components/WYSIWYGEditor/WYSIWYGEditor.scss +310 -0
- package/src/v2/components/WYSIWYGEditor/WYSIWYGEditor.stories.tsx +252 -0
- package/src/v2/components/WYSIWYGEditor/WYSIWYGEditor.tsx +393 -0
- package/src/v2/components/WYSIWYGEditor/index.ts +3 -0
- package/src/v2/components/index.ts +37 -0
- package/src/v2/index.ts +10 -2
- package/src/v2/navigation/DashboardLayout/TopNavigation.scss +1 -0
- package/src/v2/pages/Settings/SettingsContentPlaceholder.scss +24 -0
- package/src/v2/pages/Settings/SettingsPage.scss +52 -0
- package/src/v2/pages/Settings/SettingsPage.tsx +46 -0
- package/src/v2/pages/Settings/SettingsTabs.scss +44 -0
- package/src/v2/pages/Settings/SettingsTabs.tsx +36 -0
- package/src/v2/pages/Settings/components/SidebarCustomisation.stories.tsx +48 -0
- package/src/v2/pages/Settings/components/SidebarNavItem.scss +76 -0
- package/src/v2/pages/Settings/components/SidebarNavItem.stories.tsx +50 -0
- package/src/v2/pages/Settings/components/SidebarNavItem.tsx +52 -0
- package/src/v2/pages/Settings/components/index.ts +5 -0
- package/src/v2/pages/Settings/index.ts +8 -0
- package/src/v2/styles/components/Button.scss +51 -53
- package/src/v2/styles/form/Layout.scss +15 -0
- package/src/v2/styles/form/NewInput.scss +83 -53
- package/src/v2/styles/index.scss +1 -0
- package/src/v2/styles/tokens/_colors.scss +6 -6
- package/src/v2/styles/tokens/_typography.scss +2 -2
- package/dist/v2/navigation/icons/index.d.ts +0 -12
- package/dist/v2/navigation/icons/index.d.ts.map +0 -1
- 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'
|