activeadmin-tom_select 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.actrc +20 -0
- data/.claude/commands/fix-tests.md +203 -0
- data/.github/workflows/ci.yml +174 -0
- data/.github/workflows/npm-publish.yml +50 -0
- data/.gitignore +35 -0
- data/.npmignore +58 -0
- data/.rspec +1 -0
- data/.rubocop.yml +75 -0
- data/.yardopts +2 -0
- data/AGENTS.md +39 -0
- data/Appraisals +9 -0
- data/CHANGELOG.md +64 -0
- data/CLAUDE.md +157 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +368 -0
- data/LICENSE.txt +25 -0
- data/README.md +483 -0
- data/Rakefile +4 -0
- data/activeadmin-tom_select.gemspec +43 -0
- data/bin/rspec +17 -0
- data/config/database.yml +16 -0
- data/docs/activeadmin-4-detailed-reference.md +932 -0
- data/docs/activeadmin-4-gem-migration-guide.md +313 -0
- data/docs/combustion.md +213 -0
- data/docs/fail.png +0 -0
- data/docs/guide-update-your-app.md +283 -0
- data/docs/normal.png +0 -0
- data/docs/propshaft-readme.md +320 -0
- data/docs/propshaft-upgrade.md +484 -0
- data/docs/setup-activeadmin-app.md +552 -0
- data/docs/setup-activeadmin-gem.md +535 -0
- data/docs/tailwind/blog-page.md +341 -0
- data/docs/tailwind/upgrade-guide-enhanced.md +438 -0
- data/docs/tailwind/upgrade-guide.md +416 -0
- data/docs/tailwind-4/active_admin.rake +38 -0
- data/docs/tailwind-4/active_admin.tailwind.css +415 -0
- data/docs/tailwind-4/tailwind-active_admin.config.js +18 -0
- data/docs/test-app-change.md +154 -0
- data/docs/test-environment-fixes.md +58 -0
- data/docs/update-tom-select.md +184 -0
- data/docs/upload-system.md +225 -0
- data/gemfiles/rails_7.x_active_admin_4.x.gemfile +10 -0
- data/gemfiles/rails_7.x_active_admin_4.x.gemfile.lock +377 -0
- data/gemfiles/rails_8.x_active_admin_4.x.gemfile +10 -0
- data/gemfiles/rails_8.x_active_admin_4.x.gemfile.lock +372 -0
- data/lefthook.yml +17 -0
- data/lib/activeadmin/inputs/filters/searchable_select_input.rb +19 -0
- data/lib/activeadmin/inputs/searchable_select_input.rb +16 -0
- data/lib/activeadmin/tom_select/engine.rb +17 -0
- data/lib/activeadmin/tom_select/option_collection.rb +128 -0
- data/lib/activeadmin/tom_select/resource_dsl_extension.rb +56 -0
- data/lib/activeadmin/tom_select/resource_extension.rb +10 -0
- data/lib/activeadmin/tom_select/select_input_extension.rb +168 -0
- data/lib/activeadmin/tom_select/version.rb +5 -0
- data/lib/activeadmin/tom_select.rb +20 -0
- data/lib/activeadmin-tom_select.rb +5 -0
- data/lib/generators/active_admin/tom_select/install/install_generator.rb +180 -0
- data/npm-package/package-lock.json +51 -0
- data/npm-package/package.json +43 -0
- data/npm-package/src/index.js +153 -0
- data/npm-package/src/tom-select-tailwind.css +392 -0
- data/sonar-project.properties +25 -0
- data/spec/features/ajax_params_spec.rb +31 -0
- data/spec/features/asset_pipeline_diagnostic_spec.rb +155 -0
- data/spec/features/end_to_end_spec.rb +273 -0
- data/spec/features/filter_input_spec.rb +144 -0
- data/spec/features/form_input_spec.rb +122 -0
- data/spec/features/inline_ajax_setting_spec.rb +26 -0
- data/spec/features/input_errors_spec.rb +76 -0
- data/spec/features/input_html_options_spec.rb +30 -0
- data/spec/features/options_dsl_spec.rb +230 -0
- data/spec/features/production_build_spec.rb +108 -0
- data/spec/internal/.node-version +1 -0
- data/spec/internal/Gemfile +43 -0
- data/spec/internal/Gemfile.lock +333 -0
- data/spec/internal/Procfile.dev +3 -0
- data/spec/internal/README.md +24 -0
- data/spec/internal/Rakefile +6 -0
- data/spec/internal/app/admin/categories.rb +26 -0
- data/spec/internal/app/admin/dashboard.rb +29 -0
- data/spec/internal/app/admin/option_types.rb +19 -0
- data/spec/internal/app/admin/option_values.rb +30 -0
- data/spec/internal/app/admin/posts.rb +27 -0
- data/spec/internal/app/admin/products.rb +22 -0
- data/spec/internal/app/admin/rgb_colors.rb +25 -0
- data/spec/internal/app/admin/tag_names.rb +21 -0
- data/spec/internal/app/admin/test_ajax_params_category.rb +10 -0
- data/spec/internal/app/admin/test_ajax_params_post.rb +20 -0
- data/spec/internal/app/admin/test_form_post_class.rb +7 -0
- data/spec/internal/app/admin/test_form_post_custom.rb +11 -0
- data/spec/internal/app/admin/test_form_post_resource.rb +11 -0
- data/spec/internal/app/admin/test_form_post_resource_custom.rb +12 -0
- data/spec/internal/app/admin/test_inline_ajax_post.rb +9 -0
- data/spec/internal/app/admin/test_input_html_post.rb +11 -0
- data/spec/internal/app/admin/test_posts_display_text.rb +9 -0
- data/spec/internal/app/admin/test_posts_filter.rb +9 -0
- data/spec/internal/app/admin/test_posts_named.rb +9 -0
- data/spec/internal/app/admin/test_posts_pagination.rb +9 -0
- data/spec/internal/app/admin/test_posts_payload_lambda.rb +11 -0
- data/spec/internal/app/admin/test_posts_payload_proc.rb +9 -0
- data/spec/internal/app/admin/test_posts_scope_lambda.rb +8 -0
- data/spec/internal/app/admin/test_posts_scope_params.rb +8 -0
- data/spec/internal/app/admin/test_posts_scope_user.rb +8 -0
- data/spec/internal/app/admin/test_posts_text_attr.rb +5 -0
- data/spec/internal/app/admin/users.rb +23 -0
- data/spec/internal/app/admin/variants.rb +31 -0
- data/spec/internal/app/assets/config/manifest.js +2 -0
- data/spec/internal/app/assets/images/.keep +0 -0
- data/spec/internal/app/assets/stylesheets/active_admin.tailwind.css +16 -0
- data/spec/internal/app/assets/stylesheets/application.tailwind.css +15 -0
- data/spec/internal/app/controllers/application_controller.rb +9 -0
- data/spec/internal/app/controllers/concerns/.keep +0 -0
- data/spec/internal/app/helpers/application_helper.rb +2 -0
- data/spec/internal/app/javascript/active_admin.js +19 -0
- data/spec/internal/app/javascript/application.js +2 -0
- data/spec/internal/app/jobs/application_job.rb +7 -0
- data/spec/internal/app/mailers/application_mailer.rb +4 -0
- data/spec/internal/app/models/admin_user.rb +9 -0
- data/spec/internal/app/models/application_record.rb +3 -0
- data/spec/internal/app/models/article.rb +12 -0
- data/spec/internal/app/models/category.rb +12 -0
- data/spec/internal/app/models/color.rb +9 -0
- data/spec/internal/app/models/concerns/.keep +0 -0
- data/spec/internal/app/models/internal/tag_name.rb +14 -0
- data/spec/internal/app/models/internal_tag_name.rb +11 -0
- data/spec/internal/app/models/option_type.rb +12 -0
- data/spec/internal/app/models/option_value.rb +4 -0
- data/spec/internal/app/models/post.rb +15 -0
- data/spec/internal/app/models/product.rb +12 -0
- data/spec/internal/app/models/rgb_color.rb +16 -0
- data/spec/internal/app/models/tag.rb +12 -0
- data/spec/internal/app/models/tagging.rb +12 -0
- data/spec/internal/app/models/user.rb +12 -0
- data/spec/internal/app/models/variant.rb +12 -0
- data/spec/internal/app/views/layouts/application.html.erb +28 -0
- data/spec/internal/app/views/layouts/mailer.html.erb +13 -0
- data/spec/internal/app/views/layouts/mailer.text.erb +1 -0
- data/spec/internal/app/views/pwa/manifest.json.erb +22 -0
- data/spec/internal/app/views/pwa/service-worker.js +26 -0
- data/spec/internal/bin/bundle +117 -0
- data/spec/internal/bin/dev +11 -0
- data/spec/internal/bin/rackup +27 -0
- data/spec/internal/bin/rails +4 -0
- data/spec/internal/bin/rake +4 -0
- data/spec/internal/bin/setup +37 -0
- data/spec/internal/config/application.rb +50 -0
- data/spec/internal/config/boot.rb +3 -0
- data/spec/internal/config/credentials.yml.enc +1 -0
- data/spec/internal/config/database.yml +32 -0
- data/spec/internal/config/environment.rb +5 -0
- data/spec/internal/config/environments/development.rb +63 -0
- data/spec/internal/config/environments/production.rb +86 -0
- data/spec/internal/config/environments/test.rb +50 -0
- data/spec/internal/config/initializers/active_admin.rb +54 -0
- data/spec/internal/config/initializers/assets.rb +8 -0
- data/spec/internal/config/initializers/content_security_policy.rb +25 -0
- data/spec/internal/config/initializers/devise.rb +315 -0
- data/spec/internal/config/initializers/filter_parameter_logging.rb +8 -0
- data/spec/internal/config/initializers/inflections.rb +16 -0
- data/spec/internal/config/initializers/searchable_select.rb +6 -0
- data/spec/internal/config/locales/devise.en.yml +65 -0
- data/spec/internal/config/locales/en.yml +31 -0
- data/spec/internal/config/master.key +1 -0
- data/spec/internal/config/puma.rb +38 -0
- data/spec/internal/config/routes.rb +17 -0
- data/spec/internal/config.ru +6 -0
- data/spec/internal/db/schema.rb +174 -0
- data/spec/internal/db/seeds.rb +167 -0
- data/spec/internal/esbuild.config.js +34 -0
- data/spec/internal/lib/tasks/.keep +0 -0
- data/spec/internal/lib/tasks/active_admin.rake +55 -0
- data/spec/internal/log/.keep +0 -0
- data/spec/internal/package-lock.json +1954 -0
- data/spec/internal/package.json +21 -0
- data/spec/internal/public/400.html +114 -0
- data/spec/internal/public/404.html +114 -0
- data/spec/internal/public/406-unsupported-browser.html +114 -0
- data/spec/internal/public/422.html +114 -0
- data/spec/internal/public/500.html +114 -0
- data/spec/internal/public/icon.png +0 -0
- data/spec/internal/public/icon.svg +3 -0
- data/spec/internal/public/robots.txt +1 -0
- data/spec/internal/script/.keep +0 -0
- data/spec/internal/storage/.keep +0 -0
- data/spec/internal/tailwind.config.js +23 -0
- data/spec/internal/vendor/.keep +0 -0
- data/spec/internal/yarn.lock +824 -0
- data/spec/rails_helper.rb +62 -0
- data/spec/spec_helper.rb +138 -0
- data/spec/support/active_admin_helpers.rb +17 -0
- data/spec/support/capybara.rb +8 -0
- data/spec/support/models.rb +11 -0
- data/spec/support/pluck_polyfill.rb +12 -0
- data/spec/support/reset_settings.rb +5 -0
- metadata +497 -0
@@ -0,0 +1,438 @@
|
|
1
|
+
# Tailwind CSS v3 to v4 Upgrade Guide - Enhanced Edition
|
2
|
+
|
3
|
+
This enhanced guide focuses on migrating from Tailwind CSS v3 to v4, with special attention to form controls, select elements, and component styling.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
1. [Quick Start](#quick-start)
|
7
|
+
2. [Core Breaking Changes](#core-breaking-changes)
|
8
|
+
3. [Form and Input Styling Changes](#form-and-input-styling-changes)
|
9
|
+
4. [Select Element Changes](#select-element-changes)
|
10
|
+
5. [Component Migration Guide](#component-migration-guide)
|
11
|
+
6. [Tom Select & Custom Selects](#tom-select--custom-selects)
|
12
|
+
7. [Migration Checklist](#migration-checklist)
|
13
|
+
|
14
|
+
## Quick Start
|
15
|
+
|
16
|
+
### Automated Upgrade
|
17
|
+
```bash
|
18
|
+
# Use the official upgrade tool (requires Node.js 20+)
|
19
|
+
$ npx @tailwindcss/upgrade
|
20
|
+
```
|
21
|
+
|
22
|
+
### Manual Installation
|
23
|
+
|
24
|
+
#### PostCSS Setup
|
25
|
+
```js
|
26
|
+
// postcss.config.mjs
|
27
|
+
export default {
|
28
|
+
plugins: {
|
29
|
+
// Remove these v3 plugins
|
30
|
+
// "postcss-import": {},
|
31
|
+
// tailwindcss: {},
|
32
|
+
// autoprefixer: {},
|
33
|
+
|
34
|
+
// Add v4 plugin
|
35
|
+
"@tailwindcss/postcss": {},
|
36
|
+
},
|
37
|
+
};
|
38
|
+
```
|
39
|
+
|
40
|
+
#### Vite Setup (Recommended)
|
41
|
+
```ts
|
42
|
+
// vite.config.ts
|
43
|
+
import { defineConfig } from "vite";
|
44
|
+
import tailwindcss from "@tailwindcss/vite";
|
45
|
+
|
46
|
+
export default defineConfig({
|
47
|
+
plugins: [tailwindcss()],
|
48
|
+
});
|
49
|
+
```
|
50
|
+
|
51
|
+
#### CSS Import Change
|
52
|
+
```css
|
53
|
+
/* v3 */
|
54
|
+
@tailwind base;
|
55
|
+
@tailwind components;
|
56
|
+
@tailwind utilities;
|
57
|
+
|
58
|
+
/* v4 */
|
59
|
+
@import "tailwindcss";
|
60
|
+
```
|
61
|
+
|
62
|
+
## Core Breaking Changes
|
63
|
+
|
64
|
+
### Browser Requirements
|
65
|
+
- **Minimum versions**: Safari 16.4+, Chrome 111+, Firefox 128+
|
66
|
+
- Uses modern CSS features: `@property`, `color-mix()`, cascade layers
|
67
|
+
- No fallback for older browsers
|
68
|
+
|
69
|
+
### Configuration Migration
|
70
|
+
|
71
|
+
#### v3: JavaScript Config
|
72
|
+
```js
|
73
|
+
// tailwind.config.js (v3)
|
74
|
+
module.exports = {
|
75
|
+
content: ['./src/**/*.{html,js}'],
|
76
|
+
theme: {
|
77
|
+
extend: {
|
78
|
+
colors: {
|
79
|
+
brand: '#1a73e8',
|
80
|
+
},
|
81
|
+
},
|
82
|
+
},
|
83
|
+
plugins: [require('@tailwindcss/forms')],
|
84
|
+
}
|
85
|
+
```
|
86
|
+
|
87
|
+
#### v4: CSS-First Config
|
88
|
+
```css
|
89
|
+
/* app.css (v4) */
|
90
|
+
@import "tailwindcss";
|
91
|
+
|
92
|
+
@theme {
|
93
|
+
--color-brand: #1a73e8;
|
94
|
+
--font-display: "Inter", "sans-serif";
|
95
|
+
--breakpoint-3xl: 120rem;
|
96
|
+
}
|
97
|
+
|
98
|
+
/* Automatic content detection - no config needed! */
|
99
|
+
```
|
100
|
+
|
101
|
+
### Renamed Utilities
|
102
|
+
|
103
|
+
| v3 | v4 | Notes |
|
104
|
+
|---|---|-------|
|
105
|
+
| `shadow-sm` | `shadow-xs` | |
|
106
|
+
| `shadow` | `shadow-sm` | |
|
107
|
+
| `rounded-sm` | `rounded-xs` | |
|
108
|
+
| `rounded` | `rounded-sm` | |
|
109
|
+
| `outline-none` | `outline-hidden` | Invisible outline for a11y |
|
110
|
+
| `ring` | `ring-3` | Default width changed |
|
111
|
+
|
112
|
+
## Form and Input Styling Changes
|
113
|
+
|
114
|
+
### Default Border Colors
|
115
|
+
```css
|
116
|
+
/* v3: gray-200 by default */
|
117
|
+
.border { border-color: rgb(229 231 235); }
|
118
|
+
|
119
|
+
/* v4: currentColor by default */
|
120
|
+
.border { border-color: currentColor; }
|
121
|
+
|
122
|
+
/* Fix: Always specify border color */
|
123
|
+
<input class="border border-gray-200" />
|
124
|
+
|
125
|
+
/* Or add global override */
|
126
|
+
@layer base {
|
127
|
+
*,
|
128
|
+
::after,
|
129
|
+
::before,
|
130
|
+
::backdrop,
|
131
|
+
::file-selector-button {
|
132
|
+
border-color: var(--color-gray-200, currentColor);
|
133
|
+
}
|
134
|
+
}
|
135
|
+
```
|
136
|
+
|
137
|
+
### Placeholder Colors
|
138
|
+
```css
|
139
|
+
/* v3: gray-400 by default */
|
140
|
+
input::placeholder { color: rgb(156 163 175); }
|
141
|
+
|
142
|
+
/* v4: 50% opacity of text color */
|
143
|
+
input::placeholder { color: color-mix(in srgb, currentColor 50%, transparent); }
|
144
|
+
|
145
|
+
/* Restore v3 behavior if needed */
|
146
|
+
@layer base {
|
147
|
+
input::placeholder,
|
148
|
+
textarea::placeholder {
|
149
|
+
color: var(--color-gray-400);
|
150
|
+
}
|
151
|
+
}
|
152
|
+
```
|
153
|
+
|
154
|
+
### Button Cursor Changes
|
155
|
+
```css
|
156
|
+
/* v3: pointer cursor */
|
157
|
+
button { cursor: pointer; }
|
158
|
+
|
159
|
+
/* v4: default cursor (browser default) */
|
160
|
+
button { cursor: default; }
|
161
|
+
|
162
|
+
/* Restore pointer cursor */
|
163
|
+
@layer base {
|
164
|
+
button:not(:disabled),
|
165
|
+
[role="button"]:not(:disabled) {
|
166
|
+
cursor: pointer;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
```
|
170
|
+
|
171
|
+
### New Form Utilities in v4
|
172
|
+
|
173
|
+
#### Field Sizing
|
174
|
+
```html
|
175
|
+
<!-- Auto-resize textareas without JavaScript -->
|
176
|
+
<textarea class="field-sizing-content">
|
177
|
+
Content grows with text
|
178
|
+
</textarea>
|
179
|
+
|
180
|
+
<!-- Fixed size (default behavior) -->
|
181
|
+
<textarea class="field-sizing-fixed w-full">
|
182
|
+
Fixed width textarea
|
183
|
+
</textarea>
|
184
|
+
```
|
185
|
+
|
186
|
+
#### Accent Color
|
187
|
+
```html
|
188
|
+
<!-- Custom checkbox/radio colors -->
|
189
|
+
<input type="checkbox" class="accent-blue-500" />
|
190
|
+
<input type="radio" class="accent-purple-500" />
|
191
|
+
|
192
|
+
<!-- With opacity modifier -->
|
193
|
+
<input type="checkbox" class="accent-green-500/75" />
|
194
|
+
```
|
195
|
+
|
196
|
+
## Select Element Changes
|
197
|
+
|
198
|
+
### Native Select Styling
|
199
|
+
|
200
|
+
#### v3 Approach
|
201
|
+
```html
|
202
|
+
<!-- v3: Required forms plugin or custom styles -->
|
203
|
+
<select class="form-select rounded-md border-gray-300">
|
204
|
+
<option>Option 1</option>
|
205
|
+
</select>
|
206
|
+
```
|
207
|
+
|
208
|
+
#### v4 Approach
|
209
|
+
```html
|
210
|
+
<!-- v4: Style with utilities directly -->
|
211
|
+
<select class="rounded-sm border border-gray-300 bg-white px-3 py-2">
|
212
|
+
<option>Option 1</option>
|
213
|
+
</select>
|
214
|
+
|
215
|
+
<!-- Remove default appearance for custom styling -->
|
216
|
+
<div class="relative">
|
217
|
+
<select class="appearance-none rounded-sm border border-gray-300 bg-white pl-3 pr-10 py-2">
|
218
|
+
<option>Option 1</option>
|
219
|
+
</select>
|
220
|
+
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
221
|
+
<svg class="h-5 w-5 text-gray-400"><!-- chevron icon --></svg>
|
222
|
+
</div>
|
223
|
+
</div>
|
224
|
+
```
|
225
|
+
|
226
|
+
### Forms Plugin Changes
|
227
|
+
|
228
|
+
The `@tailwindcss/forms` plugin approach has changed in v4:
|
229
|
+
|
230
|
+
```css
|
231
|
+
/* v3: Auto-applied with plugin */
|
232
|
+
/* @tailwindcss/forms would style all inputs automatically */
|
233
|
+
|
234
|
+
/* v4: Explicit utility classes */
|
235
|
+
/* More control, less magic */
|
236
|
+
```
|
237
|
+
|
238
|
+
## Component Migration Guide
|
239
|
+
|
240
|
+
### Card/Panel Component
|
241
|
+
|
242
|
+
#### v3
|
243
|
+
```html
|
244
|
+
<div class="shadow rounded bg-white p-4">
|
245
|
+
<h3 class="text-lg font-semibold">Card Title</h3>
|
246
|
+
<p class="text-gray-600">Card content</p>
|
247
|
+
</div>
|
248
|
+
```
|
249
|
+
|
250
|
+
#### v4
|
251
|
+
```html
|
252
|
+
<div class="shadow-sm rounded-sm bg-white p-4">
|
253
|
+
<h3 class="text-lg font-semibold">Card Title</h3>
|
254
|
+
<p class="text-gray-600">Card content</p>
|
255
|
+
</div>
|
256
|
+
```
|
257
|
+
|
258
|
+
### Form Component
|
259
|
+
|
260
|
+
#### v3
|
261
|
+
```html
|
262
|
+
<form class="space-y-4">
|
263
|
+
<div>
|
264
|
+
<label class="block text-sm font-medium text-gray-700">
|
265
|
+
Name
|
266
|
+
</label>
|
267
|
+
<input type="text"
|
268
|
+
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
269
|
+
</div>
|
270
|
+
<button class="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
|
271
|
+
Submit
|
272
|
+
</button>
|
273
|
+
</form>
|
274
|
+
```
|
275
|
+
|
276
|
+
#### v4
|
277
|
+
```html
|
278
|
+
<form class="flex flex-col gap-4">
|
279
|
+
<div>
|
280
|
+
<label class="block text-sm font-medium text-gray-700">
|
281
|
+
Name
|
282
|
+
</label>
|
283
|
+
<input type="text"
|
284
|
+
class="mt-1 block w-full rounded-sm border border-gray-300 shadow-xs focus:border-indigo-500 focus:ring-3 focus:ring-indigo-500">
|
285
|
+
</div>
|
286
|
+
<button class="rounded-sm bg-blue-500 px-4 py-2 text-white hover:bg-blue-600 cursor-pointer">
|
287
|
+
Submit
|
288
|
+
</button>
|
289
|
+
</form>
|
290
|
+
```
|
291
|
+
|
292
|
+
## Tom Select & Custom Selects
|
293
|
+
|
294
|
+
### Tom Select with Tailwind v4
|
295
|
+
|
296
|
+
```css
|
297
|
+
/* tom-select-tailwind.css for v4 */
|
298
|
+
@layer components {
|
299
|
+
.ts-wrapper {
|
300
|
+
@apply relative;
|
301
|
+
}
|
302
|
+
|
303
|
+
.ts-control {
|
304
|
+
@apply flex flex-wrap items-center rounded-sm border border-gray-300 bg-white px-3 py-2;
|
305
|
+
@apply focus-within:border-blue-500 focus-within:ring-3 focus-within:ring-blue-500;
|
306
|
+
}
|
307
|
+
|
308
|
+
.ts-control input {
|
309
|
+
@apply flex-1 border-0 bg-transparent p-0 outline-hidden;
|
310
|
+
}
|
311
|
+
|
312
|
+
.ts-dropdown {
|
313
|
+
@apply absolute z-50 mt-1 w-full rounded-sm border border-gray-200 bg-white shadow-sm;
|
314
|
+
}
|
315
|
+
|
316
|
+
.ts-dropdown .option {
|
317
|
+
@apply cursor-pointer px-3 py-2 hover:bg-gray-100;
|
318
|
+
}
|
319
|
+
|
320
|
+
.ts-dropdown .option.active {
|
321
|
+
@apply bg-blue-50 text-blue-700;
|
322
|
+
}
|
323
|
+
}
|
324
|
+
```
|
325
|
+
|
326
|
+
### Select2 to Tom Select Migration
|
327
|
+
|
328
|
+
| Select2 Class | Tom Select Class | Purpose |
|
329
|
+
|--------------|------------------|---------|
|
330
|
+
| `.select2-container` | `.ts-wrapper` | Main container |
|
331
|
+
| `.select2-selection` | `.ts-control` | Selected items display |
|
332
|
+
| `.select2-dropdown` | `.ts-dropdown` | Dropdown container |
|
333
|
+
| `.select2-results__option` | `.ts-dropdown .option` | Dropdown options |
|
334
|
+
| `.select2-search__field` | `.ts-control input` | Search input |
|
335
|
+
|
336
|
+
## Migration Checklist
|
337
|
+
|
338
|
+
### Pre-Migration
|
339
|
+
- [ ] Verify Node.js 20+ is installed
|
340
|
+
- [ ] Check browser support requirements
|
341
|
+
- [ ] Backup current configuration
|
342
|
+
- [ ] Review custom components for breaking changes
|
343
|
+
|
344
|
+
### Core Changes
|
345
|
+
- [ ] Run upgrade tool or manually update dependencies
|
346
|
+
- [ ] Convert `@tailwind` directives to `@import "tailwindcss"`
|
347
|
+
- [ ] Migrate JavaScript config to CSS `@theme` block
|
348
|
+
- [ ] Update PostCSS or switch to Vite plugin
|
349
|
+
|
350
|
+
### Utility Updates
|
351
|
+
- [ ] Replace `shadow` → `shadow-sm`, `shadow-sm` → `shadow-xs`
|
352
|
+
- [ ] Replace `rounded` → `rounded-sm`, `rounded-sm` → `rounded-xs`
|
353
|
+
- [ ] Replace `outline-none` → `outline-hidden`
|
354
|
+
- [ ] Replace `ring` → `ring-3`
|
355
|
+
- [ ] Update `space-y-*` to `flex flex-col gap-*` where needed
|
356
|
+
|
357
|
+
### Form Styling
|
358
|
+
- [ ] Add explicit border colors to all border utilities
|
359
|
+
- [ ] Review placeholder text colors
|
360
|
+
- [ ] Add `cursor-pointer` to buttons if needed
|
361
|
+
- [ ] Update select elements with explicit styles
|
362
|
+
- [ ] Test form components with new utilities
|
363
|
+
|
364
|
+
### Component Libraries
|
365
|
+
- [ ] Update Tom Select styles for v4 utilities
|
366
|
+
- [ ] Migrate Select2 to Tom Select if applicable
|
367
|
+
- [ ] Test all custom dropdowns and selects
|
368
|
+
- [ ] Verify third-party component compatibility
|
369
|
+
|
370
|
+
### Testing
|
371
|
+
- [ ] Test in all target browsers
|
372
|
+
- [ ] Verify responsive designs work correctly
|
373
|
+
- [ ] Check dark mode if implemented
|
374
|
+
- [ ] Validate accessibility features
|
375
|
+
- [ ] Run visual regression tests
|
376
|
+
|
377
|
+
### Post-Migration
|
378
|
+
- [ ] Update documentation
|
379
|
+
- [ ] Train team on new v4 patterns
|
380
|
+
- [ ] Monitor for issues in production
|
381
|
+
- [ ] Document any custom workarounds
|
382
|
+
|
383
|
+
## Additional Resources
|
384
|
+
|
385
|
+
- [Official Tailwind CSS v4.0 Blog Post](https://tailwindcss.com/blog/tailwindcss-v4)
|
386
|
+
- [Official Upgrade Guide](https://tailwindcss.com/docs/upgrade-guide)
|
387
|
+
- [v4.0 Release Notes](https://github.com/tailwindlabs/tailwindcss/releases/tag/v4.0.0)
|
388
|
+
- [Tom Select Documentation](https://tom-select.js.org/)
|
389
|
+
- [Modern CSS Features Used in v4](https://developer.mozilla.org/en-US/docs/Web/CSS)
|
390
|
+
|
391
|
+
## Common Gotchas
|
392
|
+
|
393
|
+
1. **CSS Variables in Media Queries**: The `theme()` function now uses CSS variable names
|
394
|
+
```css
|
395
|
+
/* v3 */
|
396
|
+
@media (min-width: theme(screens.lg)) { }
|
397
|
+
|
398
|
+
/* v4 */
|
399
|
+
@media (min-width: theme(--breakpoint-lg)) { }
|
400
|
+
```
|
401
|
+
|
402
|
+
2. **Gradient Preservation**: Gradients now preserve all stops when overridden
|
403
|
+
```html
|
404
|
+
<!-- v3: to-yellow-400 becomes transparent in dark mode -->
|
405
|
+
<div class="bg-gradient-to-r from-red-500 to-yellow-400 dark:from-blue-500"></div>
|
406
|
+
|
407
|
+
<!-- v4: Explicitly reset with via-none -->
|
408
|
+
<div class="bg-linear-to-r from-red-500 via-orange-400 to-yellow-400 dark:via-none dark:from-blue-500 dark:to-teal-400"></div>
|
409
|
+
```
|
410
|
+
|
411
|
+
3. **Hover on Touch Devices**: `hover:` now only applies when device supports hover
|
412
|
+
```css
|
413
|
+
/* v4: Add custom variant for old behavior */
|
414
|
+
@custom-variant hover (&:hover);
|
415
|
+
```
|
416
|
+
|
417
|
+
4. **Dynamic Values**: Many utilities now accept any value without configuration
|
418
|
+
```html
|
419
|
+
<!-- v3: Required extending config -->
|
420
|
+
<div class="grid-cols-[arbitrary]">
|
421
|
+
|
422
|
+
<!-- v4: Works out of the box -->
|
423
|
+
<div class="grid-cols-15">
|
424
|
+
<div class="mt-17">
|
425
|
+
<div class="w-29">
|
426
|
+
```
|
427
|
+
|
428
|
+
## Summary
|
429
|
+
|
430
|
+
Tailwind CSS v4 brings significant improvements in performance, developer experience, and modern CSS support. While there are breaking changes, the upgrade tool handles most migrations automatically. The key changes for forms and selects are:
|
431
|
+
|
432
|
+
1. More explicit styling requirements (no magic defaults)
|
433
|
+
2. Better performance with native CSS features
|
434
|
+
3. Improved customization through CSS variables
|
435
|
+
4. Enhanced form utilities like `field-sizing` and `accent-color`
|
436
|
+
5. Simpler configuration without JavaScript
|
437
|
+
|
438
|
+
The migration effort is worth it for the performance gains (5x faster builds, 100x faster incremental builds) and the improved developer experience with automatic content detection and CSS-first configuration.
|