create-template-html-css 2.0.4 → 2.2.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 (99) hide show
  1. package/CHANGELOG.md +436 -0
  2. package/CODE-SPLITTING-GUIDE.md +274 -0
  3. package/COMPONENTS-GALLERY.html +143 -8
  4. package/HTML-VS-REACT.md +289 -0
  5. package/QUICKSTART-REACT.md +293 -0
  6. package/REACT-SUPPORT-SUMMARY.md +235 -0
  7. package/README.md +261 -12
  8. package/bin/cli.js +100 -759
  9. package/bin/commands/create.js +288 -0
  10. package/bin/commands/gallery.js +42 -0
  11. package/bin/commands/insert.js +123 -0
  12. package/bin/commands/list.js +73 -0
  13. package/package.json +10 -3
  14. package/src/component-choices.js +7 -0
  15. package/src/components-registry.js +112 -0
  16. package/src/format-utils.js +49 -0
  17. package/src/generator.js +83 -594
  18. package/src/generators/color-schemes.js +78 -0
  19. package/src/generators/color-utils.js +108 -0
  20. package/src/generators/component-filters.js +151 -0
  21. package/src/generators/html-generators.js +180 -0
  22. package/src/generators/validation.js +43 -0
  23. package/src/index.js +2 -1
  24. package/src/inserter.js +55 -233
  25. package/src/inserters/backup-utils.js +20 -0
  26. package/src/inserters/component-loader.js +68 -0
  27. package/src/inserters/html-utils.js +31 -0
  28. package/src/inserters/indentation-utils.js +90 -0
  29. package/src/inserters/validation-utils.js +49 -0
  30. package/src/react-component-choices.js +97 -0
  31. package/src/react-component-templates.js +182 -0
  32. package/src/react-file-operations.js +172 -0
  33. package/src/react-generator.js +219 -0
  34. package/src/react-templates.js +418 -0
  35. package/src/templates/basic-components-templates.js +157 -0
  36. package/src/templates/form-components-templates.js +194 -0
  37. package/src/templates/interactive-components-templates.js +139 -0
  38. package/src/utils/file-utils.js +97 -0
  39. package/src/utils/path-utils.js +32 -0
  40. package/src/utils/string-utils.js +51 -0
  41. package/src/utils/template-loader.js +91 -0
  42. package/templates/_shared/PATTERNS.md +246 -0
  43. package/templates/_shared/README.md +74 -0
  44. package/templates/_shared/base.css +18 -0
  45. package/templates/blackjack/index.html +1 -1
  46. package/templates/breakout/index.html +1 -1
  47. package/templates/connect-four/index.html +1 -1
  48. package/templates/dice-game/index.html +1 -1
  49. package/templates/flappy-bird/index.html +1 -1
  50. package/templates/pong/index.html +1 -1
  51. package/templates/skeleton/index.html +4 -4
  52. package/templates/slot-machine/index.html +1 -1
  53. package/templates/tetris/index.html +1 -1
  54. package/templates-react/README.md +126 -0
  55. package/templates-react/alert/Alert.css +158 -0
  56. package/templates-react/alert/Alert.example.jsx +106 -0
  57. package/templates-react/alert/Alert.jsx +61 -0
  58. package/templates-react/badge/Badge.css +196 -0
  59. package/templates-react/badge/Badge.example.jsx +182 -0
  60. package/templates-react/badge/Badge.jsx +44 -0
  61. package/templates-react/button/Button.css +88 -0
  62. package/templates-react/button/Button.example.jsx +40 -0
  63. package/templates-react/button/Button.jsx +29 -0
  64. package/templates-react/card/Card.css +86 -0
  65. package/templates-react/card/Card.example.jsx +49 -0
  66. package/templates-react/card/Card.jsx +35 -0
  67. package/templates-react/checkbox/Checkbox.css +217 -0
  68. package/templates-react/checkbox/Checkbox.example.jsx +141 -0
  69. package/templates-react/checkbox/Checkbox.jsx +82 -0
  70. package/templates-react/counter/Counter.css +99 -0
  71. package/templates-react/counter/Counter.example.jsx +45 -0
  72. package/templates-react/counter/Counter.jsx +70 -0
  73. package/templates-react/dropdown/Dropdown.css +237 -0
  74. package/templates-react/dropdown/Dropdown.example.jsx +98 -0
  75. package/templates-react/dropdown/Dropdown.jsx +154 -0
  76. package/templates-react/form/Form.css +128 -0
  77. package/templates-react/form/Form.example.jsx +64 -0
  78. package/templates-react/form/Form.jsx +125 -0
  79. package/templates-react/input/Input.css +113 -0
  80. package/templates-react/input/Input.example.jsx +82 -0
  81. package/templates-react/input/Input.jsx +87 -0
  82. package/templates-react/modal/Modal.css +152 -0
  83. package/templates-react/modal/Modal.example.jsx +90 -0
  84. package/templates-react/modal/Modal.jsx +46 -0
  85. package/templates-react/navbar/Navbar.css +139 -0
  86. package/templates-react/navbar/Navbar.example.jsx +37 -0
  87. package/templates-react/navbar/Navbar.jsx +62 -0
  88. package/templates-react/progress/Progress.css +247 -0
  89. package/templates-react/progress/Progress.example.jsx +244 -0
  90. package/templates-react/progress/Progress.jsx +79 -0
  91. package/templates-react/switch/Switch.css +244 -0
  92. package/templates-react/switch/Switch.example.jsx +221 -0
  93. package/templates-react/switch/Switch.jsx +98 -0
  94. package/templates-react/todo-list/TodoList.css +236 -0
  95. package/templates-react/todo-list/TodoList.example.jsx +15 -0
  96. package/templates-react/todo-list/TodoList.jsx +84 -0
  97. package/templates-react/tooltip/Tooltip.css +165 -0
  98. package/templates-react/tooltip/Tooltip.example.jsx +166 -0
  99. package/templates-react/tooltip/Tooltip.jsx +176 -0
@@ -0,0 +1,141 @@
1
+ import { useState } from 'react';
2
+ import Checkbox from './Checkbox';
3
+
4
+ function CheckboxExample() {
5
+ const [basicChecked, setBasicChecked] = useState(false);
6
+ const [termsAccepted, setTermsAccepted] = useState(false);
7
+ const [notifications, setNotifications] = useState({
8
+ email: true,
9
+ sms: false,
10
+ push: true
11
+ });
12
+ const [selectedColors, setSelectedColors] = useState([]);
13
+
14
+ const handleNotificationChange = (key) => (checked) => {
15
+ setNotifications(prev => ({ ...prev, [key]: checked }));
16
+ };
17
+
18
+ const handleColorToggle = (color) => (checked) => {
19
+ setSelectedColors(prev =>
20
+ checked
21
+ ? [...prev, color]
22
+ : prev.filter(c => c !== color)
23
+ );
24
+ };
25
+
26
+ return (
27
+ <div style={{ padding: '2rem', maxWidth: '600px', margin: '0 auto' }}>
28
+ <h1>Checkbox Component Examples</h1>
29
+
30
+ <section style={{ marginBottom: '2rem' }}>
31
+ <h2>Basic Checkbox</h2>
32
+ <Checkbox
33
+ label="I agree to the terms and conditions"
34
+ checked={basicChecked}
35
+ onChange={setBasicChecked}
36
+ />
37
+ <p>Status: {basicChecked ? 'Checked' : 'Unchecked'}</p>
38
+ </section>
39
+
40
+ <section style={{ marginBottom: '2rem' }}>
41
+ <h2>Different Sizes</h2>
42
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
43
+ <Checkbox label="Small checkbox" size="small" />
44
+ <Checkbox label="Medium checkbox (default)" size="medium" />
45
+ <Checkbox label="Large checkbox" size="large" />
46
+ </div>
47
+ </section>
48
+
49
+ <section style={{ marginBottom: '2rem' }}>
50
+ <h2>Different Colors</h2>
51
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
52
+ <Checkbox label="Primary color" checked color="primary" />
53
+ <Checkbox label="Secondary color" checked color="secondary" />
54
+ <Checkbox label="Success color" checked color="success" />
55
+ <Checkbox label="Error color" checked color="error" />
56
+ </div>
57
+ </section>
58
+
59
+ <section style={{ marginBottom: '2rem' }}>
60
+ <h2>With Helper Text</h2>
61
+ <Checkbox
62
+ label="Subscribe to newsletter"
63
+ helperText="You can unsubscribe at any time"
64
+ />
65
+ </section>
66
+
67
+ <section style={{ marginBottom: '2rem' }}>
68
+ <h2>Required Field with Error</h2>
69
+ <Checkbox
70
+ label="Accept terms and conditions"
71
+ checked={termsAccepted}
72
+ onChange={setTermsAccepted}
73
+ error={!termsAccepted ? 'You must accept the terms to continue' : ''}
74
+ />
75
+ </section>
76
+
77
+ <section style={{ marginBottom: '2rem' }}>
78
+ <h2>Disabled State</h2>
79
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
80
+ <Checkbox label="Disabled unchecked" disabled />
81
+ <Checkbox label="Disabled checked" checked disabled />
82
+ </div>
83
+ </section>
84
+
85
+ <section style={{ marginBottom: '2rem' }}>
86
+ <h2>Indeterminate State</h2>
87
+ <Checkbox
88
+ label="Select all notifications"
89
+ indeterminate={
90
+ notifications.email !== notifications.sms ||
91
+ notifications.sms !== notifications.push
92
+ }
93
+ checked={notifications.email && notifications.sms && notifications.push}
94
+ />
95
+ </section>
96
+
97
+ <section style={{ marginBottom: '2rem' }}>
98
+ <h2>Checkbox Group</h2>
99
+ <div style={{ marginLeft: '1.5rem' }}>
100
+ <h3 style={{ fontSize: '1rem', marginBottom: '0.5rem' }}>Notification Preferences</h3>
101
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
102
+ <Checkbox
103
+ label="Email notifications"
104
+ checked={notifications.email}
105
+ onChange={handleNotificationChange('email')}
106
+ />
107
+ <Checkbox
108
+ label="SMS notifications"
109
+ checked={notifications.sms}
110
+ onChange={handleNotificationChange('sms')}
111
+ />
112
+ <Checkbox
113
+ label="Push notifications"
114
+ checked={notifications.push}
115
+ onChange={handleNotificationChange('push')}
116
+ />
117
+ </div>
118
+ </div>
119
+ </section>
120
+
121
+ <section style={{ marginBottom: '2rem' }}>
122
+ <h2>Multiple Selection</h2>
123
+ <h3 style={{ fontSize: '1rem', marginBottom: '0.5rem' }}>Choose your favorite colors:</h3>
124
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
125
+ {['Red', 'Blue', 'Green', 'Yellow'].map(color => (
126
+ <Checkbox
127
+ key={color}
128
+ label={color}
129
+ checked={selectedColors.includes(color)}
130
+ onChange={handleColorToggle(color)}
131
+ color={color === 'Red' ? 'error' : color === 'Green' ? 'success' : 'primary'}
132
+ />
133
+ ))}
134
+ </div>
135
+ <p>Selected: {selectedColors.join(', ') || 'None'}</p>
136
+ </section>
137
+ </div>
138
+ );
139
+ }
140
+
141
+ export default CheckboxExample;
@@ -0,0 +1,82 @@
1
+
2
+ import './Checkbox.css';
3
+ import { useState } from 'react';
4
+
5
+ function Checkbox({
6
+ label = '',
7
+ checked = false,
8
+ onChange,
9
+ disabled = false,
10
+ indeterminate = false,
11
+ name = '',
12
+ value = '',
13
+ error = '',
14
+ helperText = '',
15
+ size = 'medium',
16
+ color = 'primary'
17
+ }) {
18
+ const [isChecked, setIsChecked] = useState(checked);
19
+
20
+ const handleChange = (e) => {
21
+ const newValue = e.target.checked;
22
+ setIsChecked(newValue);
23
+ onChange?.(newValue, e);
24
+ };
25
+
26
+ const checkboxId = `checkbox-${name || Math.random().toString(36).substr(2, 9)}`;
27
+
28
+ return (
29
+ <div className={`checkbox-container ${error ? 'checkbox-error' : ''}`}>
30
+ <div className="checkbox-wrapper">
31
+ <div className={`checkbox-input-wrapper ${size}`}>
32
+ <input
33
+ id={checkboxId}
34
+ type="checkbox"
35
+ className={`checkbox-input ${color}`}
36
+ checked={isChecked}
37
+ onChange={handleChange}
38
+ disabled={disabled}
39
+ name={name}
40
+ value={value}
41
+ aria-invalid={!!error}
42
+ aria-describedby={error ? `${checkboxId}-error` : helperText ? `${checkboxId}-helper` : undefined}
43
+ />
44
+ <span
45
+ className={`checkbox-custom ${isChecked ? 'checked' : ''} ${indeterminate ? 'indeterminate' : ''}`}
46
+ aria-hidden="true"
47
+ >
48
+ {indeterminate && !isChecked ? (
49
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
50
+ <line x1="5" y1="12" x2="19" y2="12" strokeWidth="3" strokeLinecap="round"/>
51
+ </svg>
52
+ ) : isChecked ? (
53
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
54
+ <polyline points="20 6 9 17 4 12" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"/>
55
+ </svg>
56
+ ) : null}
57
+ </span>
58
+ </div>
59
+
60
+ {label && (
61
+ <label htmlFor={checkboxId} className="checkbox-label">
62
+ {label}
63
+ </label>
64
+ )}
65
+ </div>
66
+
67
+ {helperText && !error && (
68
+ <span id={`${checkboxId}-helper`} className="checkbox-helper-text">
69
+ {helperText}
70
+ </span>
71
+ )}
72
+
73
+ {error && (
74
+ <span id={`${checkboxId}-error`} className="checkbox-error-message">
75
+ {error}
76
+ </span>
77
+ )}
78
+ </div>
79
+ );
80
+ }
81
+
82
+ export default Checkbox;
@@ -0,0 +1,99 @@
1
+ /* Counter Styles */
2
+ .counter-container {
3
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
4
+ background: white;
5
+ padding: 40px;
6
+ border-radius: 20px;
7
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
8
+ max-width: 400px;
9
+ margin: 0 auto;
10
+ text-align: center;
11
+ }
12
+
13
+ .counter-title {
14
+ font-size: 32px;
15
+ font-weight: 700;
16
+ margin: 0 0 30px 0;
17
+ background: linear-gradient(135deg, {{primaryColor}} 0%, {{secondaryColor}} 100%);
18
+ -webkit-background-clip: text;
19
+ -webkit-text-fill-color: transparent;
20
+ background-clip: text;
21
+ }
22
+
23
+ .counter-display {
24
+ font-size: 96px;
25
+ font-weight: 800;
26
+ background: linear-gradient(135deg, {{primaryColor}} 0%, {{secondaryColor}} 100%);
27
+ -webkit-background-clip: text;
28
+ -webkit-text-fill-color: transparent;
29
+ background-clip: text;
30
+ margin: 40px 0;
31
+ user-select: none;
32
+ animation: pulse 2s ease-in-out infinite;
33
+ }
34
+
35
+ @keyframes pulse {
36
+ 0%, 100% {
37
+ opacity: 1;
38
+ }
39
+ 50% {
40
+ opacity: 0.8;
41
+ }
42
+ }
43
+
44
+ .counter-controls {
45
+ display: flex;
46
+ gap: 12px;
47
+ justify-content: center;
48
+ }
49
+
50
+ .counter-btn {
51
+ font-family: inherit;
52
+ font-size: 32px;
53
+ font-weight: 700;
54
+ width: 80px;
55
+ height: 80px;
56
+ border: none;
57
+ border-radius: 50%;
58
+ cursor: pointer;
59
+ transition: all 0.3s ease;
60
+ outline: none;
61
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
62
+ }
63
+
64
+ .counter-btn:hover:not(:disabled) {
65
+ transform: translateY(-3px);
66
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
67
+ }
68
+
69
+ .counter-btn:active:not(:disabled) {
70
+ transform: translateY(0);
71
+ }
72
+
73
+ .counter-btn:disabled {
74
+ opacity: 0.5;
75
+ cursor: not-allowed;
76
+ }
77
+
78
+ .counter-btn-increment {
79
+ background: linear-gradient(135deg, {{primaryColor}} 0%, {{secondaryColor}} 100%);
80
+ color: white;
81
+ }
82
+
83
+ .counter-btn-decrement {
84
+ background: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%);
85
+ color: white;
86
+ }
87
+
88
+ .counter-btn-reset {
89
+ background: linear-gradient(135deg, #868e96 0%, #495057 100%);
90
+ color: white;
91
+ font-size: 16px;
92
+ }
93
+
94
+ /* Dark Mode Support */
95
+ @media (prefers-color-scheme: dark) {
96
+ .counter-container {
97
+ background: #2d3748;
98
+ }
99
+ }
@@ -0,0 +1,45 @@
1
+
2
+ import Counter from './Counter';
3
+
4
+ /**
5
+ * Example usage of Counter component
6
+ */
7
+ const CounterExample = () => {
8
+ const handleChange = (value) => {
9
+ console.log('Counter value changed to:', value);
10
+ };
11
+
12
+ return (
13
+ <div style={{ padding: '40px' }}>
14
+ <h2 style={{ marginBottom: '40px', textAlign: 'center' }}>Counter Component Examples</h2>
15
+
16
+ <div style={{ display: 'grid', gap: '40px', gridTemplateColumns: 'repeat(auto-fit, minmax(400px, 1fr))' }}>
17
+ <div>
18
+ <h3 style={{ textAlign: 'center' }}>Basic Counter</h3>
19
+ <Counter onChange={handleChange} />
20
+ </div>
21
+
22
+ <div>
23
+ <h3 style={{ textAlign: 'center' }}>Counter with Limits</h3>
24
+ <Counter
25
+ initialValue={5}
26
+ min={0}
27
+ max={10}
28
+ onChange={handleChange}
29
+ />
30
+ </div>
31
+
32
+ <div>
33
+ <h3 style={{ textAlign: 'center' }}>Counter with Custom Step</h3>
34
+ <Counter
35
+ initialValue={0}
36
+ step={5}
37
+ onChange={handleChange}
38
+ />
39
+ </div>
40
+ </div>
41
+ </div>
42
+ );
43
+ };
44
+
45
+ export default CounterExample;
@@ -0,0 +1,70 @@
1
+ import { useState } from 'react';
2
+ import './Counter.css';
3
+
4
+ /**
5
+ * Counter Component
6
+ * A simple counter with increment and decrement functionality
7
+ */
8
+ const Counter = ({
9
+ initialValue = 0,
10
+ min,
11
+ max,
12
+ step = 1,
13
+ onChange
14
+ }) => {
15
+ const [count, setCount] = useState(initialValue);
16
+
17
+ const handleIncrement = () => {
18
+ const newValue = count + step;
19
+ if (max === undefined || newValue <= max) {
20
+ setCount(newValue);
21
+ onChange?.(newValue);
22
+ }
23
+ };
24
+
25
+ const handleDecrement = () => {
26
+ const newValue = count - step;
27
+ if (min === undefined || newValue >= min) {
28
+ setCount(newValue);
29
+ onChange?.(newValue);
30
+ }
31
+ };
32
+
33
+ const handleReset = () => {
34
+ setCount(initialValue);
35
+ onChange?.(initialValue);
36
+ };
37
+
38
+ return (
39
+ <div className="counter-container">
40
+ <h2 className="counter-title">Counter</h2>
41
+ <div className="counter-display">
42
+ {count}
43
+ </div>
44
+ <div className="counter-controls">
45
+ <button
46
+ className="counter-btn counter-btn-decrement"
47
+ onClick={handleDecrement}
48
+ disabled={min !== undefined && count <= min}
49
+ >
50
+ -
51
+ </button>
52
+ <button
53
+ className="counter-btn counter-btn-reset"
54
+ onClick={handleReset}
55
+ >
56
+ Reset
57
+ </button>
58
+ <button
59
+ className="counter-btn counter-btn-increment"
60
+ onClick={handleIncrement}
61
+ disabled={max !== undefined && count >= max}
62
+ >
63
+ +
64
+ </button>
65
+ </div>
66
+ </div>
67
+ );
68
+ };
69
+
70
+ export default Counter;
@@ -0,0 +1,237 @@
1
+ .dropdown-container {
2
+ position: relative;
3
+ width: 100%;
4
+ margin-bottom: 1rem;
5
+ }
6
+
7
+ .dropdown-label {
8
+ display: block;
9
+ margin-bottom: 0.5rem;
10
+ font-weight: 500;
11
+ color: #374151;
12
+ font-size: 0.875rem;
13
+ }
14
+
15
+ .dropdown {
16
+ position: relative;
17
+ width: 100%;
18
+ }
19
+
20
+ .dropdown-toggle {
21
+ width: 100%;
22
+ padding: 0.625rem 2.5rem 0.625rem 0.875rem;
23
+ background-color: white;
24
+ border: 2px solid #d1d5db;
25
+ border-radius: 0.5rem;
26
+ font-size: 1rem;
27
+ text-align: left;
28
+ cursor: pointer;
29
+ transition: all 0.2s ease;
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: space-between;
33
+ position: relative;
34
+ }
35
+
36
+ .dropdown-toggle:hover:not(:disabled) {
37
+ border-color: ##PRIMARY_COLOR##;
38
+ }
39
+
40
+ .dropdown-toggle:focus {
41
+ outline: none;
42
+ border-color: ##PRIMARY_COLOR##;
43
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
44
+ }
45
+
46
+ .dropdown-toggle:disabled {
47
+ background-color: #f3f4f6;
48
+ cursor: not-allowed;
49
+ opacity: 0.6;
50
+ }
51
+
52
+ .dropdown.open .dropdown-toggle {
53
+ border-color: ##PRIMARY_COLOR##;
54
+ border-bottom-left-radius: 0;
55
+ border-bottom-right-radius: 0;
56
+ }
57
+
58
+ .dropdown-value {
59
+ flex: 1;
60
+ overflow: hidden;
61
+ text-overflow: ellipsis;
62
+ white-space: nowrap;
63
+ color: #111827;
64
+ }
65
+
66
+ .dropdown-toggle:disabled .dropdown-value {
67
+ color: #9ca3af;
68
+ }
69
+
70
+ .dropdown-arrow {
71
+ position: absolute;
72
+ right: 0.875rem;
73
+ top: 50%;
74
+ transform: translateY(-50%);
75
+ transition: transform 0.2s ease;
76
+ color: #6b7280;
77
+ font-size: 0.75rem;
78
+ }
79
+
80
+ .dropdown-arrow.up {
81
+ transform: translateY(-50%) rotate(180deg);
82
+ }
83
+
84
+ .dropdown-menu {
85
+ position: absolute;
86
+ top: 100%;
87
+ left: 0;
88
+ right: 0;
89
+ background-color: white;
90
+ border: 2px solid ##PRIMARY_COLOR##;
91
+ border-top: none;
92
+ border-radius: 0 0 0.5rem 0.5rem;
93
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
94
+ z-index: 1000;
95
+ overflow: hidden;
96
+ animation: slideDown 0.2s ease;
97
+ }
98
+
99
+ @keyframes slideDown {
100
+ from {
101
+ opacity: 0;
102
+ transform: translateY(-10px);
103
+ }
104
+ to {
105
+ opacity: 1;
106
+ transform: translateY(0);
107
+ }
108
+ }
109
+
110
+ .dropdown-search {
111
+ padding: 0.5rem;
112
+ border-bottom: 1px solid #e5e7eb;
113
+ }
114
+
115
+ .dropdown-search-input {
116
+ width: 100%;
117
+ padding: 0.5rem;
118
+ border: 1px solid #d1d5db;
119
+ border-radius: 0.375rem;
120
+ font-size: 0.875rem;
121
+ outline: none;
122
+ }
123
+
124
+ .dropdown-search-input:focus {
125
+ border-color: ##PRIMARY_COLOR##;
126
+ }
127
+
128
+ .dropdown-options {
129
+ list-style: none;
130
+ margin: 0;
131
+ padding: 0;
132
+ max-height: inherit;
133
+ overflow-y: auto;
134
+ }
135
+
136
+ .dropdown-option {
137
+ padding: 0.75rem 0.875rem;
138
+ cursor: pointer;
139
+ transition: background-color 0.15s ease;
140
+ color: #374151;
141
+ display: flex;
142
+ align-items: center;
143
+ gap: 0.5rem;
144
+ }
145
+
146
+ .dropdown-option:hover:not(.disabled) {
147
+ background-color: #f3f4f6;
148
+ }
149
+
150
+ .dropdown-option.selected {
151
+ background-color: ##PRIMARY_COLOR##;
152
+ color: white;
153
+ font-weight: 500;
154
+ }
155
+
156
+ .dropdown-option.disabled {
157
+ cursor: not-allowed;
158
+ color: #9ca3af;
159
+ font-style: italic;
160
+ }
161
+
162
+ .dropdown-checkbox {
163
+ width: 1rem;
164
+ height: 1rem;
165
+ cursor: pointer;
166
+ }
167
+
168
+ .dropdown-error .dropdown-toggle {
169
+ border-color: #ef4444;
170
+ }
171
+
172
+ .dropdown-error .dropdown-toggle:focus {
173
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
174
+ }
175
+
176
+ .dropdown-error-message {
177
+ display: block;
178
+ margin-top: 0.375rem;
179
+ font-size: 0.875rem;
180
+ color: #ef4444;
181
+ }
182
+
183
+ /* Dark Mode Support */
184
+ @media (prefers-color-scheme: dark) {
185
+ .dropdown-label {
186
+ color: #e5e7eb;
187
+ }
188
+
189
+ .dropdown-toggle {
190
+ background-color: #1f2937;
191
+ border-color: #4b5563;
192
+ color: #e5e7eb;
193
+ }
194
+
195
+ .dropdown-toggle:hover:not(:disabled) {
196
+ border-color: ##SECONDARY_COLOR##;
197
+ }
198
+
199
+ .dropdown-toggle:disabled {
200
+ background-color: #111827;
201
+ }
202
+
203
+ .dropdown-value {
204
+ color: #e5e7eb;
205
+ }
206
+
207
+ .dropdown.open .dropdown-toggle {
208
+ border-color: ##SECONDARY_COLOR##;
209
+ }
210
+
211
+ .dropdown-menu {
212
+ background-color: #1f2937;
213
+ border-color: ##SECONDARY_COLOR##;
214
+ }
215
+
216
+ .dropdown-search {
217
+ border-bottom-color: #4b5563;
218
+ }
219
+
220
+ .dropdown-search-input {
221
+ background-color: #111827;
222
+ border-color: #4b5563;
223
+ color: #e5e7eb;
224
+ }
225
+
226
+ .dropdown-option {
227
+ color: #e5e7eb;
228
+ }
229
+
230
+ .dropdown-option:hover:not(.disabled) {
231
+ background-color: #374151;
232
+ }
233
+
234
+ .dropdown-option.selected {
235
+ background-color: ##SECONDARY_COLOR##;
236
+ }
237
+ }