odt-ui-rails 2.2.8 → 2.2.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec66ce1401b2367f67b2895e51e993f3a25066c996bfd4134d724d9103ad55c9
4
- data.tar.gz: 5255d9461830b286c5eb04086151b3b9a6209c8316875e53711b8b00a26b4373
3
+ metadata.gz: 96dede14c0cb2d23cc6c98786bc2ec498554da2444159c6384f174b877ff7fd0
4
+ data.tar.gz: 7a10098064d3a9b9fc0805b353df96f87469963a208cb1dadbb64504ad1943c6
5
5
  SHA512:
6
- metadata.gz: 749c6a4fb7c52247cf79baabf9c92d6994094c56c2481333092677732347807128d3e8a6050dbbb7addeb1abd4c17e2921942a95d3b471a464965461f5f07f8c
7
- data.tar.gz: 8b03e7c0568bfe461069052fb37e3d64256ec52925d642257e9a1fae6721c58d148296340a36da7724c948dbdf67fa9b8d75e810453809dfa603986f23763770
6
+ metadata.gz: 587b164eba1277283ca586a09d5293357012963e8e38424fd58a21bfd39382ea689086baf8b2517cb1f0cbe02391527073c2806da57ee4a8ae8f4392c83d86ec
7
+ data.tar.gz: 73aaec1ab91838903c9d88fbf703c2ab55e7179e0deb3acef8f3a8db0ac68b85707b2775e1cf4648e92322491351eec18a2ee30dcc4de8fe2880bd4758e1a4f0
data/README.md CHANGED
@@ -58,7 +58,7 @@
58
58
  Add the gem to your application's `Gemfile`:
59
59
 
60
60
  ```ruby
61
- gem "odt-ui-rails", "~> 2.2.7"
61
+ gem "odt-ui-rails", "~> 2.2.9"
62
62
  ```
63
63
 
64
64
  Install dependencies:
@@ -330,6 +330,16 @@ Accessible form components complete with labels, helper text, error validations,
330
330
  color: :primary
331
331
  ) %>
332
332
 
333
+ <%# Switch Toggle %>
334
+ <%= odt_switch(
335
+ label: "Enable Notifications",
336
+ description: "Receive instant updates in real-time",
337
+ name: "user[notifications]",
338
+ checked: true,
339
+ color: :primary,
340
+ size: :md
341
+ ) %>
342
+
333
343
  <%# Radio Group %>
334
344
  <%= odt_radio label: "Monthly Billing", name: "plan", value: "monthly", checked: true %>
335
345
  <%= odt_radio label: "Annual Billing (Save 20%)", name: "plan", value: "annual" %>
@@ -1471,7 +1471,7 @@
1471
1471
  .odt-select--md {
1472
1472
  height: 2.625rem;
1473
1473
  padding: 0 var(--spacing-4, 1rem);
1474
- font-size: var(--font-size-sm, 0.875rem);
1474
+ font-size: var(--font-size-base, 1rem);
1475
1475
  border-radius: var(--radius-xl, 0.75rem);
1476
1476
  }
1477
1477
 
@@ -1479,7 +1479,7 @@
1479
1479
  .odt-select--lg {
1480
1480
  height: 3.125rem;
1481
1481
  padding: 0 var(--spacing-5, 1.25rem);
1482
- font-size: var(--font-size-base, 1rem);
1482
+ font-size: var(--font-size-lg, 1.125rem);
1483
1483
  border-radius: var(--radius-2xl, 1rem);
1484
1484
  }
1485
1485
 
@@ -1498,14 +1498,14 @@
1498
1498
 
1499
1499
  .odt-textarea--md {
1500
1500
  padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);
1501
- font-size: var(--font-size-sm, 0.875rem);
1501
+ font-size: var(--font-size-base, 1rem);
1502
1502
  min-height: 5rem;
1503
1503
  border-radius: var(--radius-xl, 0.75rem);
1504
1504
  }
1505
1505
 
1506
1506
  .odt-textarea--lg {
1507
1507
  padding: var(--spacing-4, 1rem) var(--spacing-5, 1.25rem);
1508
- font-size: var(--font-size-base, 1rem);
1508
+ font-size: var(--font-size-lg, 1.125rem);
1509
1509
  min-height: 6.5rem;
1510
1510
  border-radius: var(--radius-2xl, 1rem);
1511
1511
  }
@@ -1899,6 +1899,196 @@
1899
1899
  line-height: 1rem;
1900
1900
  }
1901
1901
 
1902
+ /* ==========================================================================
1903
+ * Switch Component (.odt-switch)
1904
+ * ========================================================================== */
1905
+ .odt-switch-wrapper {
1906
+ display: inline-flex;
1907
+ flex-direction: column;
1908
+ gap: 0.25rem;
1909
+ }
1910
+
1911
+ .odt-switch-container {
1912
+ display: inline-flex;
1913
+ align-items: center;
1914
+ gap: var(--spacing-3, 0.75rem);
1915
+ cursor: pointer;
1916
+ user-select: none;
1917
+ }
1918
+
1919
+ .odt-switch {
1920
+ appearance: none;
1921
+ -webkit-appearance: none;
1922
+ position: relative;
1923
+ display: inline-flex;
1924
+ align-items: center;
1925
+ flex-shrink: 0;
1926
+ width: 2.75rem;
1927
+ height: 1.5rem;
1928
+ border-radius: var(--radius-full, 9999px);
1929
+ background-color: var(--color-neutral-300);
1930
+ border: none;
1931
+ cursor: pointer;
1932
+ padding: 0;
1933
+ margin: 0;
1934
+ outline: none;
1935
+ box-sizing: border-box;
1936
+ transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
1937
+ }
1938
+
1939
+ .odt-switch::after {
1940
+ content: "";
1941
+ pointer-events: none;
1942
+ display: block;
1943
+ width: 1rem;
1944
+ height: 1rem;
1945
+ border-radius: var(--radius-full, 9999px);
1946
+ background-color: var(--color-switch-thumb, #ffffff);
1947
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
1948
+ transform: translateX(0.25rem);
1949
+ transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
1950
+ }
1951
+
1952
+ .odt-switch:checked::after {
1953
+ transform: translateX(1.5rem);
1954
+ }
1955
+
1956
+ /* Switch Sizes */
1957
+ .odt-switch--sm {
1958
+ width: 2rem;
1959
+ height: 1.125rem;
1960
+ }
1961
+
1962
+ .odt-switch--sm::after {
1963
+ width: 0.75rem;
1964
+ height: 0.75rem;
1965
+ transform: translateX(0.1875rem);
1966
+ }
1967
+
1968
+ .odt-switch--sm:checked::after {
1969
+ transform: translateX(1.0625rem);
1970
+ }
1971
+
1972
+ .odt-switch--md {
1973
+ width: 2.75rem;
1974
+ height: 1.5rem;
1975
+ }
1976
+
1977
+ .odt-switch--md::after {
1978
+ width: 1rem;
1979
+ height: 1rem;
1980
+ transform: translateX(0.25rem);
1981
+ }
1982
+
1983
+ .odt-switch--md:checked::after {
1984
+ transform: translateX(1.5rem);
1985
+ }
1986
+
1987
+ .odt-switch--lg {
1988
+ width: 3.5rem;
1989
+ height: 2rem;
1990
+ }
1991
+
1992
+ .odt-switch--lg::after {
1993
+ width: 1.5rem;
1994
+ height: 1.5rem;
1995
+ transform: translateX(0.25rem);
1996
+ }
1997
+
1998
+ .odt-switch--lg:checked::after {
1999
+ transform: translateX(1.75rem);
2000
+ }
2001
+
2002
+ /* Switch Colors */
2003
+ .odt-switch--primary:checked {
2004
+ background-color: var(--color-primary-500);
2005
+ }
2006
+
2007
+ .odt-switch--primary:focus-visible {
2008
+ box-shadow: 0 0 0 3px hsl(from var(--color-primary-500) h s l / 0.35);
2009
+ }
2010
+
2011
+ .odt-switch--secondary:checked {
2012
+ background-color: var(--color-secondary-500);
2013
+ }
2014
+
2015
+ .odt-switch--secondary:focus-visible {
2016
+ box-shadow: 0 0 0 3px hsl(from var(--color-secondary-500) h s l / 0.35);
2017
+ }
2018
+
2019
+ .odt-switch--success:checked {
2020
+ background-color: var(--color-success);
2021
+ }
2022
+
2023
+ .odt-switch--success:focus-visible {
2024
+ box-shadow: 0 0 0 3px hsl(from var(--color-success) h s l / 0.35);
2025
+ }
2026
+
2027
+ .odt-switch--warning:checked {
2028
+ background-color: var(--color-warning);
2029
+ }
2030
+
2031
+ .odt-switch--warning:focus-visible {
2032
+ box-shadow: 0 0 0 3px hsl(from var(--color-warning) h s l / 0.35);
2033
+ }
2034
+
2035
+ .odt-switch--danger:checked {
2036
+ background-color: var(--color-danger);
2037
+ }
2038
+
2039
+ .odt-switch--danger:focus-visible {
2040
+ box-shadow: 0 0 0 3px hsl(from var(--color-danger) h s l / 0.35);
2041
+ }
2042
+
2043
+ .odt-switch--info:checked {
2044
+ background-color: var(--color-info);
2045
+ }
2046
+
2047
+ .odt-switch--info:focus-visible {
2048
+ box-shadow: 0 0 0 3px hsl(from var(--color-info) h s l / 0.35);
2049
+ }
2050
+
2051
+ .odt-switch--dark:checked,
2052
+ .odt-switch--neutral:checked {
2053
+ background-color: var(--color-neutral-900);
2054
+ }
2055
+
2056
+ .odt-switch--dark:focus-visible,
2057
+ .odt-switch--neutral:focus-visible {
2058
+ box-shadow: 0 0 0 3px hsl(from var(--color-neutral-900) h s l / 0.35);
2059
+ }
2060
+
2061
+ /* Switch States */
2062
+ .odt-switch:disabled,
2063
+ .odt-switch-container--disabled {
2064
+ opacity: 0.45;
2065
+ cursor: not-allowed;
2066
+ pointer-events: none;
2067
+ }
2068
+
2069
+ .odt-switch--error:not(:checked) {
2070
+ box-shadow: 0 0 0 2px var(--color-danger);
2071
+ }
2072
+
2073
+ .odt-switch__label-content {
2074
+ display: flex;
2075
+ flex-direction: column;
2076
+ gap: 0.125rem;
2077
+ }
2078
+
2079
+ .odt-switch__label {
2080
+ font-size: var(--font-size-sm, 0.875rem);
2081
+ color: var(--color-fg);
2082
+ font-weight: 500;
2083
+ line-height: 1.25rem;
2084
+ }
2085
+
2086
+ .odt-switch__description {
2087
+ font-size: var(--font-size-xs, 0.75rem);
2088
+ color: var(--color-fg-muted);
2089
+ line-height: 1rem;
2090
+ }
2091
+
1902
2092
  /* ==========================================================================
1903
2093
  * 10. Toast & Toaster Component (.odt-toaster, .odt-toast)
1904
2094
  * ========================================================================== */
@@ -2450,13 +2640,13 @@
2450
2640
  .odt-dropdown__trigger--md {
2451
2641
  height: 2.625rem;
2452
2642
  padding: 0 var(--spacing-4, 1rem);
2453
- font-size: var(--font-size-sm, 0.875rem);
2643
+ font-size: var(--font-size-base, 1rem);
2454
2644
  }
2455
2645
 
2456
2646
  .odt-dropdown__trigger--lg {
2457
2647
  height: 3.125rem;
2458
2648
  padding: 0 var(--spacing-5, 1.25rem);
2459
- font-size: var(--font-size-base, 1rem);
2649
+ font-size: var(--font-size-lg, 1.125rem);
2460
2650
  }
2461
2651
 
2462
2652
  .odt-dropdown__trigger-text {
@@ -284,32 +284,32 @@
284
284
  /* ==========================================================================
285
285
  * Primary Brand Colors (Dark Scale)
286
286
  * ========================================================================== */
287
- --color-primary-0: hsl(240 78% 10%);
288
- --color-primary-50: hsla(225.1, 58.6%, 58.4%, 0.18);
289
- --color-primary-100: hsla(225.1, 58.6%, 58.4%, 0.28);
290
- --color-primary-200: hsl(240 78% 34%);
291
- --color-primary-300: hsl(234.2 73.9% 37.4%);
292
- --color-primary-400: hsl(229.7 65% 43%);
293
- --color-primary-500: hsl(226.9 53.8% 50.1%);
294
- --color-primary-600: hsl(225.1 58.6% 58.4%);
295
- --color-primary-700: hsl(224 63.5% 67.6%);
296
- --color-primary-800: hsl(223.3 68.7% 76.7%);
297
- --color-primary-900: hsl(222.5 100% 96.2%);
287
+ --color-primary-0: hsla(225.1, 58.6%, 58.4%, 0.05);
288
+ --color-primary-50: hsla(225.1, 58.6%, 58.4%, 0.12);
289
+ --color-primary-100: hsla(225.1, 58.6%, 58.4%, 0.20);
290
+ --color-primary-200: hsla(225.1, 58.6%, 58.4%, 0.32);
291
+ --color-primary-300: hsla(225.1, 58.6%, 58.4%, 0.48);
292
+ --color-primary-400: hsl(224 63.5% 67.6%);
293
+ --color-primary-500: hsl(225.1 58.6% 58.4%);
294
+ --color-primary-600: hsl(226.9 53.8% 50.1%);
295
+ --color-primary-700: hsl(229.7 65% 43%);
296
+ --color-primary-800: hsl(234.2 73.9% 37.4%);
297
+ --color-primary-900: hsl(240 78% 34%);
298
298
 
299
299
  /* ==========================================================================
300
300
  * Secondary Brand Colors (Dark Scale)
301
301
  * ========================================================================== */
302
- --color-secondary-0: hsl(47 100% 10%);
303
- --color-secondary-50: hsla(47, 100%, 68.6%, 0.16);
304
- --color-secondary-100: hsla(47, 100%, 68.6%, 0.25);
305
- --color-secondary-200: hsl(47 100% 50%);
306
- --color-secondary-300: hsl(47 100% 52.9%);
307
- --color-secondary-400: hsl(47 100% 57.3%);
308
- --color-secondary-500: hsl(47 100% 62.6%);
309
- --color-secondary-600: hsl(47 100% 68.6%);
310
- --color-secondary-700: hsl(47 100% 75.2%);
311
- --color-secondary-800: hsl(47 100% 81.6%);
312
- --color-secondary-900: hsl(47 100% 95.6%);
302
+ --color-secondary-0: hsla(47, 100%, 68.6%, 0.05);
303
+ --color-secondary-50: hsla(47, 100%, 68.6%, 0.12);
304
+ --color-secondary-100: hsla(47, 100%, 68.6%, 0.20);
305
+ --color-secondary-200: hsla(47, 100%, 68.6%, 0.32);
306
+ --color-secondary-300: hsla(47, 100%, 68.6%, 0.48);
307
+ --color-secondary-400: hsl(47 100% 75.2%);
308
+ --color-secondary-500: hsl(47 100% 68.6%);
309
+ --color-secondary-600: hsl(47 100% 62.6%);
310
+ --color-secondary-700: hsl(47 100% 57.3%);
311
+ --color-secondary-800: hsl(47 100% 52.9%);
312
+ --color-secondary-900: hsl(47 100% 50%);
313
313
 
314
314
  /* ==========================================================================
315
315
  * Neutral Palette (Dark Scale)
@@ -369,8 +369,8 @@
369
369
  --color-fg-inverse-disabled: var(--color-neutral-400);
370
370
 
371
371
  /* Brand Foreground */
372
- --color-fg-primary: var(--color-primary-600);
373
- --color-fg-secondary: var(--color-secondary-600);
372
+ --color-fg-primary: var(--color-primary-500);
373
+ --color-fg-secondary: var(--color-secondary-500);
374
374
 
375
375
  /* Semantic Foreground */
376
376
  --color-fg-success: var(--color-success);
@@ -406,7 +406,7 @@
406
406
  /* ==========================================================================
407
407
  * Gradients
408
408
  * ========================================================================== */
409
- --gradient-subtle: linear-gradient(to top right, var(--color-primary-50), var(--color-primary-0) 60%, var(--color-secondary-50));
409
+ --gradient-subtle: linear-gradient(to top right, var(--color-primary-50), var(--color-neutral-0) 60%, var(--color-secondary-50));
410
410
  --gradient-hero-primary: var(--gradient-subtle);
411
411
 
412
412
  /* Vibrant accent gradient */
@@ -414,7 +414,7 @@
414
414
  --gradient-hero-vibrant: var(--gradient-vibrant);
415
415
 
416
416
  /* Card surface gradients */
417
- --gradient-card: linear-gradient(to bottom, hsla(225.1, 58.6%, 58.4%, 0.25), var(--color-neutral-50));
417
+ --gradient-card: linear-gradient(to bottom, var(--color-primary-50), var(--color-neutral-50));
418
418
  --gradient-primary-to-white: linear-gradient(to bottom, var(--color-primary-50), var(--color-surface));
419
419
  --gradient-secondary-to-white: linear-gradient(to bottom, var(--color-secondary-50), var(--color-surface));
420
420
  --gradient-primary-h: linear-gradient(to right, var(--color-primary-50), var(--color-surface));
@@ -442,4 +442,3 @@
442
442
  --frosted-gradient-primary: linear-gradient(to bottom right, hsla(240, 78.3%, 65%, 0.18), hsl(224 25% 6% / 0.60));
443
443
  --frosted-gradient-secondary: linear-gradient(to bottom right, hsla(47, 100%, 60%, 0.16), hsl(224 25% 6% / 0.60));
444
444
  }
445
-
@@ -209,22 +209,14 @@
209
209
  /* ==========================================================================
210
210
  * Border Radius Scale
211
211
  * ========================================================================== */
212
- --radius-xs: 0.125rem;
213
- /* 2px */
214
- --radius-sm: 0.25rem;
215
- /* 4px */
216
- --radius-md: 0.375rem;
217
- /* 6px */
218
- --radius-lg: 0.5rem;
219
- /* 8px */
220
- --radius-xl: 0.75rem;
221
- /* 12px */
222
- --radius-2xl: 1rem;
223
- /* 16px */
224
- --radius-3xl: 1.5rem;
225
- /* 24px */
226
- --radius-4xl: 2rem;
227
- /* 32px */
212
+ --radius-xs: 0.125rem; /* 2px */
213
+ --radius-sm: 0.25rem; /* 4px */
214
+ --radius-md: 0.375rem; /* 6px */
215
+ --radius-lg: 0.5rem; /* 8px */
216
+ --radius-xl: 0.75rem; /* 12px */
217
+ --radius-2xl: 1rem; /* 16px */
218
+ --radius-3xl: 1.5rem; /* 24px */
219
+ --radius-4xl: 2rem; /* 32px */
228
220
  --radius-full: 9999px;
229
221
  }
230
222
 
@@ -233,38 +225,22 @@
233
225
  * Spacing Scale
234
226
  * ========================================================================== */
235
227
  --spacing-0: 0px;
236
- --spacing-0-5: 0.125rem;
237
- /* 2px */
238
- --spacing-1: 0.25rem;
239
- /* 4px */
240
- --spacing-1-5: 0.375rem;
241
- /* 6px */
242
- --spacing-2: 0.5rem;
243
- /* 8px */
244
- --spacing-2-5: 0.625rem;
245
- /* 10px */
246
- --spacing-3: 0.75rem;
247
- /* 12px */
248
- --spacing-3-5: 0.875rem;
249
- /* 14px */
250
- --spacing-4: 1rem;
251
- /* 16px */
252
- --spacing-5: 1.25rem;
253
- /* 20px */
254
- --spacing-6: 1.5rem;
255
- /* 24px */
256
- --spacing-8: 2rem;
257
- /* 32px */
258
- --spacing-10: 2.5rem;
259
- /* 40px */
260
- --spacing-12: 3rem;
261
- /* 48px */
262
- --spacing-16: 4rem;
263
- /* 64px */
264
- --spacing-20: 5rem;
265
- /* 80px */
266
- --spacing-24: 6rem;
267
- /* 96px */
228
+ --spacing-0-5: 0.125rem; /* 2px */
229
+ --spacing-1: 0.25rem; /* 4px */
230
+ --spacing-1-5: 0.375rem; /* 6px */
231
+ --spacing-2: 0.5rem; /* 8px */
232
+ --spacing-2-5: 0.625rem; /* 10px */
233
+ --spacing-3: 0.75rem; /* 12px */
234
+ --spacing-3-5: 0.875rem; /* 14px */
235
+ --spacing-4: 1rem; /* 16px */
236
+ --spacing-5: 1.25rem; /* 20px */
237
+ --spacing-6: 1.5rem; /* 24px */
238
+ --spacing-8: 2rem; /* 32px */
239
+ --spacing-10: 2.5rem; /* 40px */
240
+ --spacing-12: 3rem; /* 48px */
241
+ --spacing-16: 4rem; /* 64px */
242
+ --spacing-20: 5rem; /* 80px */
243
+ --spacing-24: 6rem; /* 96px */
268
244
  }
269
245
 
270
246
  :root {
@@ -275,24 +251,15 @@
275
251
  --font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
276
252
 
277
253
  /* Font Sizes */
278
- --font-size-xs: 0.75rem;
279
- /* 12px */
280
- --font-size-sm: 0.875rem;
281
- /* 14px */
282
- --font-size-base: 1rem;
283
- /* 16px */
284
- --font-size-lg: 1.125rem;
285
- /* 18px */
286
- --font-size-xl: 1.25rem;
287
- /* 20px */
288
- --font-size-2xl: 1.5rem;
289
- /* 24px */
290
- --font-size-3xl: 1.875rem;
291
- /* 30px */
292
- --font-size-4xl: 2.25rem;
293
- /* 36px */
294
- --font-size-5xl: 3rem;
295
- /* 48px */
254
+ --font-size-xs: 0.75rem; /* 12px */
255
+ --font-size-sm: 0.875rem; /* 14px */
256
+ --font-size-base: 1rem; /* 16px */
257
+ --font-size-lg: 1.125rem; /* 18px */
258
+ --font-size-xl: 1.25rem; /* 20px */
259
+ --font-size-2xl: 1.5rem; /* 24px */
260
+ --font-size-3xl: 1.875rem; /* 30px */
261
+ --font-size-4xl: 2.25rem; /* 36px */
262
+ --font-size-5xl: 3rem; /* 48px */
296
263
 
297
264
  /* Line Heights */
298
265
  --line-height-none: 1;
@@ -322,32 +289,32 @@
322
289
  /* ==========================================================================
323
290
  * Primary Brand Colors (Dark Scale)
324
291
  * ========================================================================== */
325
- --color-primary-0: hsl(240 78% 10%);
326
- --color-primary-50: hsla(225.1, 58.6%, 58.4%, 0.18);
327
- --color-primary-100: hsla(225.1, 58.6%, 58.4%, 0.28);
328
- --color-primary-200: hsl(240 78% 34%);
329
- --color-primary-300: hsl(234.2 73.9% 37.4%);
330
- --color-primary-400: hsl(229.7 65% 43%);
331
- --color-primary-500: hsl(226.9 53.8% 50.1%);
332
- --color-primary-600: hsl(225.1 58.6% 58.4%);
333
- --color-primary-700: hsl(224 63.5% 67.6%);
334
- --color-primary-800: hsl(223.3 68.7% 76.7%);
335
- --color-primary-900: hsl(222.5 100% 96.2%);
292
+ --color-primary-0: hsla(225.1, 58.6%, 58.4%, 0.05);
293
+ --color-primary-50: hsla(225.1, 58.6%, 58.4%, 0.12);
294
+ --color-primary-100: hsla(225.1, 58.6%, 58.4%, 0.20);
295
+ --color-primary-200: hsla(225.1, 58.6%, 58.4%, 0.32);
296
+ --color-primary-300: hsla(225.1, 58.6%, 58.4%, 0.48);
297
+ --color-primary-400: hsl(224 63.5% 67.6%);
298
+ --color-primary-500: hsl(225.1 58.6% 58.4%);
299
+ --color-primary-600: hsl(226.9 53.8% 50.1%);
300
+ --color-primary-700: hsl(229.7 65% 43%);
301
+ --color-primary-800: hsl(234.2 73.9% 37.4%);
302
+ --color-primary-900: hsl(240 78% 34%);
336
303
 
337
304
  /* ==========================================================================
338
305
  * Secondary Brand Colors (Dark Scale)
339
306
  * ========================================================================== */
340
- --color-secondary-0: hsl(47 100% 10%);
341
- --color-secondary-50: hsla(47, 100%, 68.6%, 0.16);
342
- --color-secondary-100: hsla(47, 100%, 68.6%, 0.25);
343
- --color-secondary-200: hsl(47 100% 50%);
344
- --color-secondary-300: hsl(47 100% 52.9%);
345
- --color-secondary-400: hsl(47 100% 57.3%);
346
- --color-secondary-500: hsl(47 100% 62.6%);
347
- --color-secondary-600: hsl(47 100% 68.6%);
348
- --color-secondary-700: hsl(47 100% 75.2%);
349
- --color-secondary-800: hsl(47 100% 81.6%);
350
- --color-secondary-900: hsl(47 100% 95.6%);
307
+ --color-secondary-0: hsla(47, 100%, 68.6%, 0.05);
308
+ --color-secondary-50: hsla(47, 100%, 68.6%, 0.12);
309
+ --color-secondary-100: hsla(47, 100%, 68.6%, 0.20);
310
+ --color-secondary-200: hsla(47, 100%, 68.6%, 0.32);
311
+ --color-secondary-300: hsla(47, 100%, 68.6%, 0.48);
312
+ --color-secondary-400: hsl(47 100% 75.2%);
313
+ --color-secondary-500: hsl(47 100% 68.6%);
314
+ --color-secondary-600: hsl(47 100% 62.6%);
315
+ --color-secondary-700: hsl(47 100% 57.3%);
316
+ --color-secondary-800: hsl(47 100% 52.9%);
317
+ --color-secondary-900: hsl(47 100% 50%);
351
318
 
352
319
  /* ==========================================================================
353
320
  * Neutral Palette (Dark Scale)
@@ -407,8 +374,8 @@
407
374
  --color-fg-inverse-disabled: var(--color-neutral-400);
408
375
 
409
376
  /* Brand Foreground */
410
- --color-fg-primary: var(--color-primary-600);
411
- --color-fg-secondary: var(--color-secondary-600);
377
+ --color-fg-primary: var(--color-primary-500);
378
+ --color-fg-secondary: var(--color-secondary-500);
412
379
 
413
380
  /* Semantic Foreground */
414
381
  --color-fg-success: var(--color-success);
@@ -444,7 +411,7 @@
444
411
  /* ==========================================================================
445
412
  * Gradients
446
413
  * ========================================================================== */
447
- --gradient-subtle: linear-gradient(to top right, var(--color-primary-50), var(--color-primary-0) 60%, var(--color-secondary-50));
414
+ --gradient-subtle: linear-gradient(to top right, var(--color-primary-50), var(--color-neutral-0) 60%, var(--color-secondary-50));
448
415
  --gradient-hero-primary: var(--gradient-subtle);
449
416
 
450
417
  /* Vibrant accent gradient */
@@ -452,7 +419,7 @@
452
419
  --gradient-hero-vibrant: var(--gradient-vibrant);
453
420
 
454
421
  /* Card surface gradients */
455
- --gradient-card: linear-gradient(to bottom, hsla(225.1, 58.6%, 58.4%, 0.25), var(--color-neutral-50));
422
+ --gradient-card: linear-gradient(to bottom, var(--color-primary-50), var(--color-neutral-50));
456
423
  --gradient-primary-to-white: linear-gradient(to bottom, var(--color-primary-50), var(--color-surface));
457
424
  --gradient-secondary-to-white: linear-gradient(to bottom, var(--color-secondary-50), var(--color-surface));
458
425
  --gradient-primary-h: linear-gradient(to right, var(--color-primary-50), var(--color-surface));
@@ -482,7 +449,6 @@
482
449
  }
483
450
 
484
451
 
485
-
486
452
  /* Component Styles */
487
453
  /* ==========================================================================
488
454
  * ODT Lightweight UI - Standalone Component Styles (Rails)
@@ -1957,7 +1923,7 @@
1957
1923
  .odt-select--md {
1958
1924
  height: 2.625rem;
1959
1925
  padding: 0 var(--spacing-4, 1rem);
1960
- font-size: var(--font-size-sm, 0.875rem);
1926
+ font-size: var(--font-size-base, 1rem);
1961
1927
  border-radius: var(--radius-xl, 0.75rem);
1962
1928
  }
1963
1929
 
@@ -1965,7 +1931,7 @@
1965
1931
  .odt-select--lg {
1966
1932
  height: 3.125rem;
1967
1933
  padding: 0 var(--spacing-5, 1.25rem);
1968
- font-size: var(--font-size-base, 1rem);
1934
+ font-size: var(--font-size-lg, 1.125rem);
1969
1935
  border-radius: var(--radius-2xl, 1rem);
1970
1936
  }
1971
1937
 
@@ -1984,14 +1950,14 @@
1984
1950
 
1985
1951
  .odt-textarea--md {
1986
1952
  padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);
1987
- font-size: var(--font-size-sm, 0.875rem);
1953
+ font-size: var(--font-size-base, 1rem);
1988
1954
  min-height: 5rem;
1989
1955
  border-radius: var(--radius-xl, 0.75rem);
1990
1956
  }
1991
1957
 
1992
1958
  .odt-textarea--lg {
1993
1959
  padding: var(--spacing-4, 1rem) var(--spacing-5, 1.25rem);
1994
- font-size: var(--font-size-base, 1rem);
1960
+ font-size: var(--font-size-lg, 1.125rem);
1995
1961
  min-height: 6.5rem;
1996
1962
  border-radius: var(--radius-2xl, 1rem);
1997
1963
  }
@@ -2385,6 +2351,196 @@
2385
2351
  line-height: 1rem;
2386
2352
  }
2387
2353
 
2354
+ /* ==========================================================================
2355
+ * Switch Component (.odt-switch)
2356
+ * ========================================================================== */
2357
+ .odt-switch-wrapper {
2358
+ display: inline-flex;
2359
+ flex-direction: column;
2360
+ gap: 0.25rem;
2361
+ }
2362
+
2363
+ .odt-switch-container {
2364
+ display: inline-flex;
2365
+ align-items: center;
2366
+ gap: var(--spacing-3, 0.75rem);
2367
+ cursor: pointer;
2368
+ user-select: none;
2369
+ }
2370
+
2371
+ .odt-switch {
2372
+ appearance: none;
2373
+ -webkit-appearance: none;
2374
+ position: relative;
2375
+ display: inline-flex;
2376
+ align-items: center;
2377
+ flex-shrink: 0;
2378
+ width: 2.75rem;
2379
+ height: 1.5rem;
2380
+ border-radius: var(--radius-full, 9999px);
2381
+ background-color: var(--color-neutral-300);
2382
+ border: none;
2383
+ cursor: pointer;
2384
+ padding: 0;
2385
+ margin: 0;
2386
+ outline: none;
2387
+ box-sizing: border-box;
2388
+ transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
2389
+ }
2390
+
2391
+ .odt-switch::after {
2392
+ content: "";
2393
+ pointer-events: none;
2394
+ display: block;
2395
+ width: 1rem;
2396
+ height: 1rem;
2397
+ border-radius: var(--radius-full, 9999px);
2398
+ background-color: var(--color-switch-thumb, #ffffff);
2399
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
2400
+ transform: translateX(0.25rem);
2401
+ transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
2402
+ }
2403
+
2404
+ .odt-switch:checked::after {
2405
+ transform: translateX(1.5rem);
2406
+ }
2407
+
2408
+ /* Switch Sizes */
2409
+ .odt-switch--sm {
2410
+ width: 2rem;
2411
+ height: 1.125rem;
2412
+ }
2413
+
2414
+ .odt-switch--sm::after {
2415
+ width: 0.75rem;
2416
+ height: 0.75rem;
2417
+ transform: translateX(0.1875rem);
2418
+ }
2419
+
2420
+ .odt-switch--sm:checked::after {
2421
+ transform: translateX(1.0625rem);
2422
+ }
2423
+
2424
+ .odt-switch--md {
2425
+ width: 2.75rem;
2426
+ height: 1.5rem;
2427
+ }
2428
+
2429
+ .odt-switch--md::after {
2430
+ width: 1rem;
2431
+ height: 1rem;
2432
+ transform: translateX(0.25rem);
2433
+ }
2434
+
2435
+ .odt-switch--md:checked::after {
2436
+ transform: translateX(1.5rem);
2437
+ }
2438
+
2439
+ .odt-switch--lg {
2440
+ width: 3.5rem;
2441
+ height: 2rem;
2442
+ }
2443
+
2444
+ .odt-switch--lg::after {
2445
+ width: 1.5rem;
2446
+ height: 1.5rem;
2447
+ transform: translateX(0.25rem);
2448
+ }
2449
+
2450
+ .odt-switch--lg:checked::after {
2451
+ transform: translateX(1.75rem);
2452
+ }
2453
+
2454
+ /* Switch Colors */
2455
+ .odt-switch--primary:checked {
2456
+ background-color: var(--color-primary-500);
2457
+ }
2458
+
2459
+ .odt-switch--primary:focus-visible {
2460
+ box-shadow: 0 0 0 3px hsl(from var(--color-primary-500) h s l / 0.35);
2461
+ }
2462
+
2463
+ .odt-switch--secondary:checked {
2464
+ background-color: var(--color-secondary-500);
2465
+ }
2466
+
2467
+ .odt-switch--secondary:focus-visible {
2468
+ box-shadow: 0 0 0 3px hsl(from var(--color-secondary-500) h s l / 0.35);
2469
+ }
2470
+
2471
+ .odt-switch--success:checked {
2472
+ background-color: var(--color-success);
2473
+ }
2474
+
2475
+ .odt-switch--success:focus-visible {
2476
+ box-shadow: 0 0 0 3px hsl(from var(--color-success) h s l / 0.35);
2477
+ }
2478
+
2479
+ .odt-switch--warning:checked {
2480
+ background-color: var(--color-warning);
2481
+ }
2482
+
2483
+ .odt-switch--warning:focus-visible {
2484
+ box-shadow: 0 0 0 3px hsl(from var(--color-warning) h s l / 0.35);
2485
+ }
2486
+
2487
+ .odt-switch--danger:checked {
2488
+ background-color: var(--color-danger);
2489
+ }
2490
+
2491
+ .odt-switch--danger:focus-visible {
2492
+ box-shadow: 0 0 0 3px hsl(from var(--color-danger) h s l / 0.35);
2493
+ }
2494
+
2495
+ .odt-switch--info:checked {
2496
+ background-color: var(--color-info);
2497
+ }
2498
+
2499
+ .odt-switch--info:focus-visible {
2500
+ box-shadow: 0 0 0 3px hsl(from var(--color-info) h s l / 0.35);
2501
+ }
2502
+
2503
+ .odt-switch--dark:checked,
2504
+ .odt-switch--neutral:checked {
2505
+ background-color: var(--color-neutral-900);
2506
+ }
2507
+
2508
+ .odt-switch--dark:focus-visible,
2509
+ .odt-switch--neutral:focus-visible {
2510
+ box-shadow: 0 0 0 3px hsl(from var(--color-neutral-900) h s l / 0.35);
2511
+ }
2512
+
2513
+ /* Switch States */
2514
+ .odt-switch:disabled,
2515
+ .odt-switch-container--disabled {
2516
+ opacity: 0.45;
2517
+ cursor: not-allowed;
2518
+ pointer-events: none;
2519
+ }
2520
+
2521
+ .odt-switch--error:not(:checked) {
2522
+ box-shadow: 0 0 0 2px var(--color-danger);
2523
+ }
2524
+
2525
+ .odt-switch__label-content {
2526
+ display: flex;
2527
+ flex-direction: column;
2528
+ gap: 0.125rem;
2529
+ }
2530
+
2531
+ .odt-switch__label {
2532
+ font-size: var(--font-size-sm, 0.875rem);
2533
+ color: var(--color-fg);
2534
+ font-weight: 500;
2535
+ line-height: 1.25rem;
2536
+ }
2537
+
2538
+ .odt-switch__description {
2539
+ font-size: var(--font-size-xs, 0.75rem);
2540
+ color: var(--color-fg-muted);
2541
+ line-height: 1rem;
2542
+ }
2543
+
2388
2544
  /* ==========================================================================
2389
2545
  * 10. Toast & Toaster Component (.odt-toaster, .odt-toast)
2390
2546
  * ========================================================================== */
@@ -2936,13 +3092,13 @@
2936
3092
  .odt-dropdown__trigger--md {
2937
3093
  height: 2.625rem;
2938
3094
  padding: 0 var(--spacing-4, 1rem);
2939
- font-size: var(--font-size-sm, 0.875rem);
3095
+ font-size: var(--font-size-base, 1rem);
2940
3096
  }
2941
3097
 
2942
3098
  .odt-dropdown__trigger--lg {
2943
3099
  height: 3.125rem;
2944
3100
  padding: 0 var(--spacing-5, 1.25rem);
2945
- font-size: var(--font-size-base, 1rem);
3101
+ font-size: var(--font-size-lg, 1.125rem);
2946
3102
  }
2947
3103
 
2948
3104
  .odt-dropdown__trigger-text {
@@ -41,6 +41,9 @@ module OdtUi
41
41
  type radio_size = :sm | :md | :lg
42
42
  type radio_orientation = :horizontal | :vertical
43
43
 
44
+ type switch_color = :primary | :secondary | :success | :warning | :danger | :info | :dark
45
+ type switch_size = :sm | :md | :lg
46
+
44
47
  def odt_button: (
45
48
  ?String? text,
46
49
  ?variant: button_variant,
@@ -199,6 +202,17 @@ module OdtUi
199
202
  **untyped
200
203
  ) -> untyped
201
204
 
205
+ def odt_switch: (
206
+ ?label: String?,
207
+ ?description: String?,
208
+ ?checked: bool,
209
+ ?color: switch_color,
210
+ ?size: switch_size,
211
+ ?disabled: bool,
212
+ ?error: String?,
213
+ **untyped
214
+ ) ?{ () -> untyped } -> untyped
215
+
202
216
  def odt_form_group: (
203
217
  ?label: String?,
204
218
  ?error: String?,
data/lib/odt_ui/helper.rb CHANGED
@@ -457,6 +457,61 @@ module OdtUi
457
457
  end
458
458
  end
459
459
 
460
+ def odt_switch(label: nil, description: nil, checked: false, color: :primary, size: :md, disabled: false, error: nil, **html_options, &block)
461
+ color_key = color.to_sym == :dark ? "neutral" : color.to_s.tr("_", "-")
462
+ size_key = size.to_s.tr("_", "-")
463
+ has_error = error.present?
464
+
465
+ classes = [
466
+ "odt-switch",
467
+ "odt-switch--#{color_key}",
468
+ "odt-switch--#{size_key}"
469
+ ]
470
+ classes << "odt-switch--error" if has_error
471
+ classes << html_options.delete(:class)
472
+
473
+ opts = html_options.merge(
474
+ type: "checkbox",
475
+ role: "switch",
476
+ class: classes.compact.reject(&:blank?).join(" "),
477
+ disabled: disabled
478
+ )
479
+ opts[:checked] = "checked" if checked
480
+ opts["aria-checked"] = checked ? "true" : "false"
481
+
482
+ switch_input = tag.input(**opts)
483
+
484
+ resolved_label = block_given? ? capture(&block) : label
485
+
486
+ if resolved_label.blank? && description.blank? && !has_error
487
+ return switch_input
488
+ end
489
+
490
+ container_classes = ["odt-switch-container"]
491
+ container_classes << "odt-switch-container--disabled" if disabled
492
+
493
+ tag.div(class: "odt-switch-wrapper") do
494
+ parts = []
495
+ parts << tag.label(class: container_classes.join(" ")) do
496
+ label_parts = [switch_input]
497
+
498
+ if resolved_label.present? || description.present?
499
+ label_parts << tag.div(class: "odt-switch__label-content") do
500
+ d_parts = []
501
+ d_parts << tag.span(resolved_label, class: "odt-switch__label") if resolved_label.present?
502
+ d_parts << tag.span(description, class: "odt-switch__description") if description.present?
503
+ safe_join(d_parts)
504
+ end
505
+ end
506
+
507
+ safe_join(label_parts)
508
+ end
509
+
510
+ parts << tag.p(error, class: "odt-error-text", role: "alert") if has_error
511
+ safe_join(parts)
512
+ end
513
+ end
514
+
460
515
  def odt_form_group(label: nil, error: nil, helper: nil, helper_text: nil, success: nil, required: false, **html_options, &block)
461
516
  resolved_helper = helper.presence || helper_text.presence
462
517
  has_error = error.present?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OdtUi
4
- VERSION = "2.2.8"
4
+ VERSION = "2.2.9"
5
5
  end
data/sig/odt_ui.rbs CHANGED
@@ -41,6 +41,9 @@ module OdtUi
41
41
  type radio_size = :sm | :md | :lg
42
42
  type radio_orientation = :horizontal | :vertical
43
43
 
44
+ type switch_color = :primary | :secondary | :success | :warning | :danger | :info | :dark
45
+ type switch_size = :sm | :md | :lg
46
+
44
47
  def odt_button: (
45
48
  ?String? text,
46
49
  ?variant: button_variant,
@@ -199,6 +202,17 @@ module OdtUi
199
202
  **untyped
200
203
  ) -> untyped
201
204
 
205
+ def odt_switch: (
206
+ ?label: String?,
207
+ ?description: String?,
208
+ ?checked: bool,
209
+ ?color: switch_color,
210
+ ?size: switch_size,
211
+ ?disabled: bool,
212
+ ?error: String?,
213
+ **untyped
214
+ ) ?{ () -> untyped } -> untyped
215
+
202
216
  def odt_form_group: (
203
217
  ?label: String?,
204
218
  ?error: String?,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: odt-ui-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.8
4
+ version: 2.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pixel