@duskmoon-dev/core 1.1.1 → 1.3.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 (33) hide show
  1. package/dist/components/checkbox.css +231 -0
  2. package/dist/components/collapse.css +208 -8
  3. package/dist/components/datepicker.css +404 -10
  4. package/dist/components/form-group.css +308 -0
  5. package/dist/components/index.css +4598 -816
  6. package/dist/components/multi-select.css +491 -0
  7. package/dist/components/navigation.css +346 -2
  8. package/dist/components/otp-input.css +195 -0
  9. package/dist/components/pin-input.css +184 -0
  10. package/dist/components/radio.css +183 -0
  11. package/dist/components/segment-control.css +186 -0
  12. package/dist/components/select.css +205 -0
  13. package/dist/components/switch.css +150 -193
  14. package/dist/components/textarea.css +202 -0
  15. package/dist/components/time-input.css +252 -0
  16. package/dist/components/tree-select.css +439 -0
  17. package/dist/esm/components/checkbox.js +238 -0
  18. package/dist/esm/components/collapse.js +208 -8
  19. package/dist/esm/components/datepicker.js +404 -10
  20. package/dist/esm/components/form-group.js +315 -0
  21. package/dist/esm/components/multi-select.js +498 -0
  22. package/dist/esm/components/navigation.js +346 -2
  23. package/dist/esm/components/otp-input.js +202 -0
  24. package/dist/esm/components/pin-input.js +191 -0
  25. package/dist/esm/components/radio.js +190 -0
  26. package/dist/esm/components/segment-control.js +193 -0
  27. package/dist/esm/components/select.js +212 -0
  28. package/dist/esm/components/switch.js +150 -193
  29. package/dist/esm/components/textarea.js +209 -0
  30. package/dist/esm/components/time-input.js +259 -0
  31. package/dist/esm/components/tree-select.js +446 -0
  32. package/dist/index.css +4402 -620
  33. package/package.json +56 -1
@@ -0,0 +1,184 @@
1
+ /**
2
+ * PIN Input Component Styles
3
+ * DuskMoonUI - Secure PIN/password entry input
4
+ */
5
+
6
+ @layer components {
7
+ /* Base PIN Container */
8
+ .pin-input {
9
+ display: inline-flex;
10
+ align-items: center;
11
+ gap: 0.5rem;
12
+ }
13
+
14
+ /* PIN Input Field */
15
+ .pin-input-field {
16
+ width: 3rem;
17
+ height: 3.5rem;
18
+ padding: 0;
19
+ font-size: 1.5rem;
20
+ font-weight: 600;
21
+ text-align: center;
22
+ color: var(--color-on-surface);
23
+ background-color: var(--color-surface);
24
+ border: 2px solid var(--color-outline);
25
+ border-radius: 0.5rem;
26
+ outline: none;
27
+ transition: border-color 150ms ease-in-out, box-shadow 150ms ease-in-out;
28
+ caret-color: var(--color-primary);
29
+ -webkit-text-security: disc;
30
+ }
31
+
32
+ .pin-input-field::placeholder {
33
+ color: var(--color-on-surface-variant);
34
+ opacity: 0.3;
35
+ }
36
+
37
+ .pin-input-field:hover:not(:disabled):not(:focus) {
38
+ border-color: var(--color-on-surface-variant);
39
+ }
40
+
41
+ .pin-input-field:focus {
42
+ border-color: var(--color-primary);
43
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-primary) 10%, transparent);
44
+ }
45
+
46
+ .pin-input-field:disabled {
47
+ opacity: 0.38;
48
+ cursor: not-allowed;
49
+ background-color: var(--color-surface-container);
50
+ }
51
+
52
+ /* Show PIN (toggle visibility) */
53
+ .pin-input-visible .pin-input-field {
54
+ -webkit-text-security: none;
55
+ }
56
+
57
+ /* Size Variants */
58
+ .pin-input-sm .pin-input-field {
59
+ width: 2.5rem;
60
+ height: 3rem;
61
+ font-size: 1.25rem;
62
+ border-radius: 0.375rem;
63
+ }
64
+
65
+ .pin-input-lg .pin-input-field {
66
+ width: 3.5rem;
67
+ height: 4rem;
68
+ font-size: 1.75rem;
69
+ border-radius: 0.625rem;
70
+ }
71
+
72
+ /* Compact Gap */
73
+ .pin-input-compact {
74
+ gap: 0.25rem;
75
+ }
76
+
77
+ /* Filled Variant */
78
+ .pin-input-filled .pin-input-field {
79
+ background-color: var(--color-surface-container);
80
+ border: none;
81
+ border-bottom: 2px solid var(--color-outline);
82
+ border-radius: 0.5rem 0.5rem 0 0;
83
+ }
84
+
85
+ .pin-input-filled .pin-input-field:focus {
86
+ border-bottom-color: var(--color-primary);
87
+ box-shadow: none;
88
+ }
89
+
90
+ /* Circle Variant */
91
+ .pin-input-circle .pin-input-field {
92
+ width: 3rem;
93
+ height: 3rem;
94
+ border-radius: 50%;
95
+ }
96
+
97
+ .pin-input-circle.pin-input-sm .pin-input-field {
98
+ width: 2.5rem;
99
+ height: 2.5rem;
100
+ }
101
+
102
+ .pin-input-circle.pin-input-lg .pin-input-field {
103
+ width: 3.5rem;
104
+ height: 3.5rem;
105
+ }
106
+
107
+ /* Dot Display (shows dots instead of numbers) */
108
+ .pin-input-dots .pin-input-field {
109
+ font-size: 2rem;
110
+ letter-spacing: -0.25rem;
111
+ }
112
+
113
+ /* Color Variants */
114
+ .pin-input-primary .pin-input-field:focus {
115
+ border-color: var(--color-primary);
116
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-primary) 10%, transparent);
117
+ }
118
+
119
+ .pin-input-secondary .pin-input-field:focus {
120
+ border-color: var(--color-secondary);
121
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-secondary) 10%, transparent);
122
+ }
123
+
124
+ .pin-input-tertiary .pin-input-field:focus {
125
+ border-color: var(--color-tertiary);
126
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-tertiary) 10%, transparent);
127
+ }
128
+
129
+ /* Error State */
130
+ .pin-input-error .pin-input-field {
131
+ border-color: var(--color-error);
132
+ animation: pin-shake 300ms ease-in-out;
133
+ }
134
+
135
+ .pin-input-error .pin-input-field:focus {
136
+ border-color: var(--color-error);
137
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-error) 10%, transparent);
138
+ }
139
+
140
+ @keyframes pin-shake {
141
+ 0%, 100% { transform: translateX(0); }
142
+ 20%, 60% { transform: translateX(-4px); }
143
+ 40%, 80% { transform: translateX(4px); }
144
+ }
145
+
146
+ /* Success State */
147
+ .pin-input-success .pin-input-field {
148
+ border-color: var(--color-success);
149
+ }
150
+
151
+ /* PIN Group with Label */
152
+ .pin-group {
153
+ display: flex;
154
+ flex-direction: column;
155
+ gap: 0.5rem;
156
+ }
157
+
158
+ .pin-label {
159
+ font-size: 0.875rem;
160
+ font-weight: 500;
161
+ color: var(--color-on-surface);
162
+ }
163
+
164
+ .pin-helper {
165
+ font-size: 0.75rem;
166
+ color: var(--color-on-surface-variant);
167
+ }
168
+
169
+ .pin-error-message {
170
+ font-size: 0.75rem;
171
+ color: var(--color-error);
172
+ }
173
+
174
+ /* Reduce Motion */
175
+ @media (prefers-reduced-motion: reduce) {
176
+ .pin-input-field {
177
+ transition: none;
178
+ }
179
+
180
+ .pin-input-error .pin-input-field {
181
+ animation: none;
182
+ }
183
+ }
184
+ }
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Radio Component Styles
3
+ * DuskMoonUI - Material Design 3 inspired radio button
4
+ *
5
+ * Usage: <input type="radio" name="group" class="radio" />
6
+ * With label: <label class="radio-label"><input type="radio" name="group" class="radio" /><span>Option</span></label>
7
+ */
8
+
9
+ @layer components {
10
+ /* Base Radio - applied directly to input[type="radio"] */
11
+ .radio {
12
+ --radio-size: 1.25rem;
13
+ --radio-color: var(--color-primary);
14
+ --radio-border-color: var(--color-on-surface-variant);
15
+
16
+ position: relative;
17
+ display: inline-grid;
18
+ place-content: center;
19
+ width: var(--radio-size);
20
+ height: var(--radio-size);
21
+ margin: 0;
22
+ cursor: pointer;
23
+ appearance: none;
24
+ background-color: transparent;
25
+ border: 2px solid var(--radio-border-color);
26
+ border-radius: 50%;
27
+ transition: border-color 150ms ease-in-out;
28
+ }
29
+
30
+ /* Inner dot using ::before pseudo-element */
31
+ .radio::before {
32
+ content: "";
33
+ width: 0.5em;
34
+ height: 0.5em;
35
+ border-radius: 50%;
36
+ background-color: var(--radio-color);
37
+ transform: scale(0);
38
+ transition: transform 150ms ease-in-out;
39
+ }
40
+
41
+ /* Checked State */
42
+ .radio:checked {
43
+ border-color: var(--radio-color);
44
+ }
45
+
46
+ .radio:checked::before {
47
+ transform: scale(1);
48
+ }
49
+
50
+ /* Hover State */
51
+ .radio:hover:not(:disabled):not(:checked) {
52
+ border-color: var(--color-on-surface);
53
+ }
54
+
55
+ .radio:checked:hover:not(:disabled) {
56
+ border-color: color-mix(in oklch, var(--radio-color), black 10%);
57
+ }
58
+
59
+ .radio:checked:hover:not(:disabled)::before {
60
+ background-color: color-mix(in oklch, var(--radio-color), black 10%);
61
+ }
62
+
63
+ /* Focus State */
64
+ .radio:focus-visible {
65
+ outline: 2px solid var(--radio-color);
66
+ outline-offset: 2px;
67
+ }
68
+
69
+ /* Disabled State */
70
+ .radio:disabled {
71
+ cursor: not-allowed;
72
+ opacity: 0.38;
73
+ }
74
+
75
+ /* ========================================
76
+ * Size Variants
77
+ * ======================================== */
78
+
79
+ .radio-xs {
80
+ --radio-size: 0.875rem;
81
+ }
82
+
83
+ .radio-sm {
84
+ --radio-size: 1rem;
85
+ }
86
+
87
+ .radio-md {
88
+ --radio-size: 1.25rem;
89
+ }
90
+
91
+ .radio-lg {
92
+ --radio-size: 1.5rem;
93
+ }
94
+
95
+ .radio-xl {
96
+ --radio-size: 1.75rem;
97
+ }
98
+
99
+ /* ========================================
100
+ * Color Variants
101
+ * ======================================== */
102
+
103
+ .radio-primary {
104
+ --radio-color: var(--color-primary);
105
+ }
106
+
107
+ .radio-secondary {
108
+ --radio-color: var(--color-secondary);
109
+ }
110
+
111
+ .radio-tertiary {
112
+ --radio-color: var(--color-tertiary);
113
+ }
114
+
115
+ .radio-success {
116
+ --radio-color: var(--color-success);
117
+ }
118
+
119
+ .radio-warning {
120
+ --radio-color: var(--color-warning);
121
+ }
122
+
123
+ .radio-error {
124
+ --radio-color: var(--color-error);
125
+ }
126
+
127
+ .radio-info {
128
+ --radio-color: var(--color-info);
129
+ }
130
+
131
+ /* ========================================
132
+ * Radio with Label (wrapper pattern)
133
+ * ======================================== */
134
+
135
+ .radio-label {
136
+ display: inline-flex;
137
+ align-items: center;
138
+ gap: 0.5rem;
139
+ cursor: pointer;
140
+ user-select: none;
141
+ font-size: 0.875rem;
142
+ color: var(--color-on-surface);
143
+ }
144
+
145
+ .radio-label:has(.radio:disabled) {
146
+ cursor: not-allowed;
147
+ opacity: 0.38;
148
+ }
149
+
150
+ /* ========================================
151
+ * Radio Group
152
+ * ======================================== */
153
+
154
+ .radio-group {
155
+ display: flex;
156
+ flex-direction: column;
157
+ gap: 0.75rem;
158
+ }
159
+
160
+ .radio-group-horizontal {
161
+ flex-direction: row;
162
+ flex-wrap: wrap;
163
+ gap: 1.5rem;
164
+ }
165
+
166
+ .radio-group-label {
167
+ font-size: 0.875rem;
168
+ font-weight: 500;
169
+ color: var(--color-on-surface);
170
+ margin-bottom: 0.5rem;
171
+ }
172
+
173
+ /* ========================================
174
+ * Reduce Motion
175
+ * ======================================== */
176
+
177
+ @media (prefers-reduced-motion: reduce) {
178
+ .radio,
179
+ .radio::before {
180
+ transition: none;
181
+ }
182
+ }
183
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Segment Control Component Styles
3
+ * DuskMoonUI - Material Design 3 inspired segmented button/toggle group
4
+ */
5
+
6
+ @layer components {
7
+ /* Base Segment Control */
8
+ .segment-control {
9
+ display: inline-flex;
10
+ align-items: stretch;
11
+ background-color: var(--color-surface-container);
12
+ border: 1px solid var(--color-outline);
13
+ border-radius: 1.25rem;
14
+ padding: 0.25rem;
15
+ gap: 0.25rem;
16
+ }
17
+
18
+ /* Segment Item */
19
+ .segment-item {
20
+ position: relative;
21
+ display: inline-flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ gap: 0.5rem;
25
+ padding: 0.5rem 1rem;
26
+ font-size: 0.875rem;
27
+ font-weight: 500;
28
+ line-height: 1.25rem;
29
+ color: var(--color-on-surface);
30
+ background-color: transparent;
31
+ border: none;
32
+ border-radius: 1rem;
33
+ cursor: pointer;
34
+ transition: background-color 150ms ease-in-out, color 150ms ease-in-out;
35
+ user-select: none;
36
+ white-space: nowrap;
37
+ }
38
+
39
+ .segment-item:hover:not(:disabled):not(.segment-item-active) {
40
+ background-color: var(--color-surface-container-high);
41
+ }
42
+
43
+ .segment-item:focus-visible {
44
+ outline: 2px solid var(--color-primary);
45
+ outline-offset: 2px;
46
+ }
47
+
48
+ .segment-item:disabled {
49
+ opacity: 0.38;
50
+ cursor: not-allowed;
51
+ }
52
+
53
+ /* Active State */
54
+ .segment-item-active {
55
+ background-color: var(--color-primary-container);
56
+ color: var(--color-on-primary-container);
57
+ }
58
+
59
+ .segment-item-active:hover:not(:disabled) {
60
+ background-color: color-mix(in oklch, var(--color-primary-container), black 5%);
61
+ }
62
+
63
+ /* Segment Icon */
64
+ .segment-icon {
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+ width: 1.125rem;
69
+ height: 1.125rem;
70
+ }
71
+
72
+ /* Size Variants */
73
+ .segment-control-sm {
74
+ padding: 0.125rem;
75
+ gap: 0.125rem;
76
+ border-radius: 1rem;
77
+ }
78
+
79
+ .segment-control-sm .segment-item {
80
+ padding: 0.375rem 0.75rem;
81
+ font-size: 0.75rem;
82
+ line-height: 1rem;
83
+ border-radius: 0.75rem;
84
+ }
85
+
86
+ .segment-control-lg {
87
+ padding: 0.375rem;
88
+ gap: 0.375rem;
89
+ border-radius: 1.5rem;
90
+ }
91
+
92
+ .segment-control-lg .segment-item {
93
+ padding: 0.75rem 1.5rem;
94
+ font-size: 1rem;
95
+ line-height: 1.5rem;
96
+ border-radius: 1.25rem;
97
+ }
98
+
99
+ /* Color Variants */
100
+ .segment-control-primary .segment-item-active {
101
+ background-color: var(--color-primary);
102
+ color: var(--color-primary-content);
103
+ }
104
+
105
+ .segment-control-secondary .segment-item-active {
106
+ background-color: var(--color-secondary-container);
107
+ color: var(--color-on-secondary-container);
108
+ }
109
+
110
+ .segment-control-tertiary .segment-item-active {
111
+ background-color: var(--color-tertiary-container);
112
+ color: var(--color-on-tertiary-container);
113
+ }
114
+
115
+ /* Full Width */
116
+ .segment-control-full {
117
+ display: flex;
118
+ width: 100%;
119
+ }
120
+
121
+ .segment-control-full .segment-item {
122
+ flex: 1;
123
+ }
124
+
125
+ /* Outlined Variant */
126
+ .segment-control-outlined {
127
+ background-color: transparent;
128
+ padding: 0;
129
+ gap: 0;
130
+ }
131
+
132
+ .segment-control-outlined .segment-item {
133
+ border: 1px solid var(--color-outline);
134
+ border-radius: 0;
135
+ margin-left: -1px;
136
+ }
137
+
138
+ .segment-control-outlined .segment-item:first-child {
139
+ margin-left: 0;
140
+ border-top-left-radius: 1.25rem;
141
+ border-bottom-left-radius: 1.25rem;
142
+ }
143
+
144
+ .segment-control-outlined .segment-item:last-child {
145
+ border-top-right-radius: 1.25rem;
146
+ border-bottom-right-radius: 1.25rem;
147
+ }
148
+
149
+ .segment-control-outlined .segment-item-active {
150
+ background-color: var(--color-primary-container);
151
+ border-color: var(--color-primary);
152
+ z-index: 1;
153
+ }
154
+
155
+ /* Ghost Variant */
156
+ .segment-control-ghost {
157
+ background-color: transparent;
158
+ border-color: transparent;
159
+ }
160
+
161
+ /* Icon Only */
162
+ .segment-control-icon-only .segment-item {
163
+ padding: 0.625rem;
164
+ }
165
+
166
+ .segment-control-icon-only.segment-control-sm .segment-item {
167
+ padding: 0.5rem;
168
+ }
169
+
170
+ .segment-control-icon-only.segment-control-lg .segment-item {
171
+ padding: 0.75rem;
172
+ }
173
+
174
+ /* Multiple Selection (Toggle Group) */
175
+ .segment-control-multi .segment-item-active {
176
+ background-color: var(--color-primary-container);
177
+ color: var(--color-on-primary-container);
178
+ }
179
+
180
+ /* Reduce Motion */
181
+ @media (prefers-reduced-motion: reduce) {
182
+ .segment-item {
183
+ transition: none;
184
+ }
185
+ }
186
+ }