css-zero 2.1.1 → 3.0.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/css-zero/reset.css +10 -10
  3. data/app/assets/stylesheets/css-zero/utilities.css +7 -9
  4. data/lib/css_zero/version.rb +1 -1
  5. data/lib/generators/css_zero/add/USAGE +1 -1
  6. data/lib/generators/css_zero/add/resources.yml +7 -2
  7. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/alert.css +1 -1
  8. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/badge.css +1 -1
  9. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/breadcrumb.css +1 -1
  10. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/button.css +2 -2
  11. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/card.css +0 -25
  12. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/combobox.css +1 -1
  13. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/command.css +10 -12
  14. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/datepicker.css +2 -2
  15. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/dropzone.css +1 -1
  16. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/flash.css +1 -1
  17. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/group.css +14 -26
  18. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/icons.css +11 -10
  19. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/input.css +2 -2
  20. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/input_otp.css +8 -0
  21. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/item.css +34 -0
  22. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/layouts.css +4 -4
  23. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/lightbox.css +2 -2
  24. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/progress.css +4 -4
  25. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/prose.css +1 -1
  26. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/separator.css +13 -0
  27. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/sheet.css +1 -1
  28. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/sidebar_menu.css +5 -3
  29. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/skeleton.css +1 -1
  30. data/lib/generators/css_zero/add/templates/app/assets/stylesheets/trix.css +6 -6
  31. data/lib/generators/css_zero/add/templates/app/javascript/controllers/autosave_controller.js +11 -8
  32. data/lib/generators/css_zero/add/templates/app/javascript/controllers/command_controller.js +4 -30
  33. data/lib/generators/css_zero/add/templates/app/javascript/controllers/form_controller.js +23 -2
  34. data/lib/generators/css_zero/add/templates/app/javascript/controllers/hotkey_controller.js +9 -1
  35. data/lib/generators/css_zero/add/templates/app/javascript/controllers/local_time_controller.js +62 -6
  36. data/lib/generators/css_zero/add/templates/app/javascript/controllers/popover_controller.js +2 -2
  37. metadata +4 -2
  38. data/lib/generators/css_zero/add/templates/app/javascript/controllers/web_otp_controller.js +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7830cbe9a3552842bf3e03618a696cbb286865a104881ef20c9392723bca1f3f
4
- data.tar.gz: 714d059191eaaa5aeb9e9c560b210a9e6149baf6ff544bf9c865f62fb1a909ff
3
+ metadata.gz: e08482091de7f5e6d07b6be39b26d0d4c90dfa38b5d0d2c4841690ac583c485c
4
+ data.tar.gz: 8cf44b3e21996398c4b49f2996b5c722b24389668c58f0f24d6adefca8b0dded
5
5
  SHA512:
6
- metadata.gz: 177c1259d2365fd172acba93af3dd1081820e64d36260948d4e249a1a5143d6fdcfbbb3e27c9e0391fc5a686ec5a65493464215645450f8ca6fbdae638cd094f
7
- data.tar.gz: 8294f56c6c1bb808930b46caf3e3acf4a510d76f6178799790648df7a1b21c94953d2762945a8f3ecb1b7963feed5ee32b308356e53fcfd09a7d29b5998b0dcc
6
+ metadata.gz: c7a2cc91ac8f3e9b826f6d565981bf5d258ca40c02ac76b25eb9be69e86d6c3df2a68f95b15978a85a158b84786ef23d9a680b7b766add0d3d3a7d2537bb4168
7
+ data.tar.gz: eefa20599577dcf8b66b6830f3fe785d3d2279aa40af8af8c34f079b9bf4abce3ce1704967fad42f49c6f9a12fd079fe7a9038a2a6689c9fa5bed488dd9f3753
@@ -372,35 +372,35 @@ input:where([type='button'], [type='reset'], [type='submit']),
372
372
  }
373
373
 
374
374
  /*
375
- Make elements with the HTML contents attribute become pseudo-box by default.
375
+ Make elements with the HTML contents attribute stay pseudo-box by default.
376
376
  */
377
377
 
378
378
  [contents] {
379
- display: contents !important;
379
+ display: contents;
380
380
  }
381
381
 
382
382
  /*
383
- Make turbo frame become pseudo-box by default.
383
+ Make elements with the HTML feedback attribute stay hidden by default.
384
384
  */
385
385
 
386
- turbo-frame {
387
- display: contents;
386
+ [feedback] {
387
+ display: none;
388
388
  }
389
389
 
390
390
  /*
391
- Make field with errors become pseudo-box by default.
391
+ Make elements with turbo frames stay pseudo-box by default.
392
392
  */
393
393
 
394
- .field_with_errors {
394
+ turbo-frame {
395
395
  display: contents;
396
396
  }
397
397
 
398
398
  /*
399
- Make invalid-feedback become hidden by default.
399
+ Make Rails field_with_errors stay pseudo-box by default.
400
400
  */
401
401
 
402
- .invalid-feedback {
403
- display: none;
402
+ .field_with_errors {
403
+ display: contents;
404
404
  }
405
405
 
406
406
  /*
@@ -16,11 +16,9 @@
16
16
  .items-center { align-items: center; }
17
17
  .items-baseline { align-items: baseline; }
18
18
 
19
- .grow { flex-grow: 1; }
20
- .grow-0 { flex-grow: 0; }
21
-
22
- .shrink { flex-shrink: 1; }
23
- .shrink-0 { flex-shrink: 0; }
19
+ .flex-1 { flex: 1; }
20
+ .flex-item-grow { flex-grow: 1; }
21
+ .flex-item-no-shrink { flex-shrink: 0; }
24
22
 
25
23
  .self-start { align-self: start; }
26
24
  .self-end { align-self: end; }
@@ -28,6 +26,7 @@
28
26
 
29
27
  .gap { column-gap: var(--column-gap, 0.5rem); row-gap: var(--row-gap, 1rem); }
30
28
  .gap-half { column-gap: var(--column-gap, 0.25rem); row-gap: var(--row-gap, 0.5rem); }
29
+ .gap-none { --column-gap: 0; --row-gap: 0; gap: 0; }
31
30
 
32
31
  /****************************************************************
33
32
  * Text
@@ -39,7 +38,6 @@
39
38
 
40
39
  .uppercase { text-transform: uppercase; }
41
40
  .capitalize { text-transform: capitalize; }
42
- .normal-case { text-transform: none; }
43
41
 
44
42
  .whitespace-nowrap { white-space: nowrap; }
45
43
  .whitespace-normal { white-space: normal; }
@@ -138,7 +136,7 @@
138
136
  .inline-block { display: inline-block; }
139
137
 
140
138
  .relative { position: relative; }
141
- .sticky { position: sticky; }
139
+ .sticky { position: sticky; inset-block-start: 0; z-index: 1; }
142
140
 
143
141
  .min-i-0 { min-inline-size: 0; }
144
142
  .max-i-none { max-inline-size: none; }
@@ -148,6 +146,7 @@
148
146
  .i-full { inline-size: 100%; }
149
147
 
150
148
  .i-min { inline-size: min-content; }
149
+ .i-fit { inline-size: fit-content; }
151
150
 
152
151
  .overflow-x-auto { overflow-x: auto; scroll-snap-type: x mandatory; }
153
152
  .overflow-y-auto { overflow-y: auto; scroll-snap-type: y mandatory; }
@@ -316,7 +315,6 @@
316
315
  * Hiding/Showing
317
316
  *****************************************************************/
318
317
  .show\@sm, .show\@md, .show\@lg, .show\@xl { display: none; }
319
-
320
318
  .show\@sm { @media (width >= 40rem) { display: flex; } }
321
319
  .show\@md { @media (width >= 48rem) { display: flex; } }
322
320
  .show\@lg { @media (width >= 64rem) { display: flex; } }
@@ -329,8 +327,8 @@
329
327
 
330
328
  .hide\@pwa { @media (display-mode: standalone) { display: none; } }
331
329
  .hide\@browser { @media (display-mode: browser) { display: none; } }
332
-
333
330
  .hide\@print { @media print { display: none; } }
331
+ .hide\@touch { @media (any-hover: none) { display: none; } }
334
332
 
335
333
  /****************************************************************
336
334
  * Accessibility
@@ -1,3 +1,3 @@
1
1
  module CssZero
2
- VERSION = "2.1.1"
2
+ VERSION = "3.0.0"
3
3
  end
@@ -2,7 +2,7 @@ Description:
2
2
  This will add components into your project.
3
3
 
4
4
  Components:
5
- accordion alert autoanimate autosave autoselect avatar back_navigation badge breadcrumb button card carousel chart check_all collapsible color_scheme combobox command context_menu datepicker dialog dropdown dropzone dual_range flash form fullscreen group hotkey icons input input_clearable input_copyable input_revealable inputmask layouts lightbox local_time popover progress prose resizable sheet skeleton sortable switch table tabs timezone_cookie trix turbo_confirm upload_preview toggle web_otp web_share
5
+ accordion alert autoanimate autosave autoselect avatar back_navigation badge breadcrumb button card carousel chart check_all collapsible color_scheme combobox command context_menu datepicker dialog dropdown dropzone dual_range flash form fullscreen group hotkey icons input input_clearable input_copyable input_otp input_revealable inputmask layouts lightbox list local_time popover progress prose resizable separator sheet skeleton sortable switch table tabs timezone_cookie trix turbo_confirm upload_preview toggle web_share
6
6
 
7
7
  Example:
8
8
  bin/rails generate css_zero:add [components...]
@@ -106,6 +106,9 @@ input_clearable:
106
106
  input_copyable:
107
107
  - app/javascript/controllers/input_copyable_controller.js
108
108
  - app/assets/stylesheets/input_copyable.css
109
+ input_otp:
110
+ - app/javascript/controllers/form_controller.js
111
+ - app/assets/stylesheets/input_otp.css
109
112
  input_revealable:
110
113
  - app/javascript/controllers/input_revealable_controller.js
111
114
  - app/assets/stylesheets/input_revealable.css
@@ -119,6 +122,8 @@ lightbox:
119
122
  - app/assets/stylesheets/lightbox.css
120
123
  - app/javascript/controllers/lightbox_controller.js
121
124
  - app/javascript/controllers/web_share_controller.js
125
+ list:
126
+ - app/assets/stylesheets/list.css
122
127
  local_time:
123
128
  - app/javascript/controllers/local_time_controller.js
124
129
  popover:
@@ -133,6 +138,8 @@ resizable:
133
138
  - app/assets/stylesheets/resizable_controller.js
134
139
  - app/assets/images/grip-horizontal-zink-500.svg
135
140
  - app/assets/images/grip-vertical-zink-500.svg
141
+ separator:
142
+ - app/assets/stylesheets/separator.css
136
143
  sheet:
137
144
  - app/assets/stylesheets/sheet.css
138
145
  - app/javascript/controllers/dialog_controller.js
@@ -159,7 +166,5 @@ turbo_confirm:
159
166
  upload_preview:
160
167
  - app/javascript/controllers/upload_preview_controller.js
161
168
  - app/assets/images/avatar.svg
162
- web_otp:
163
- - app/javascript/controllers/web_otp_controller.js
164
169
  web_share:
165
170
  - app/javascript/controllers/web_share_controller.js
@@ -1,7 +1,7 @@
1
1
  .alert {
2
2
  background-color: var(--alert-background, var(--color-surface));
3
- border-radius: var(--rounded-lg);
4
3
  border: 1px solid var(--alert-border-color, var(--color-border));
4
+ border-radius: var(--rounded-lg);
5
5
  color: var(--alert-color, var(--color-text));
6
6
  font-size: var(--text-sm);
7
7
  inline-size: var(--size-full);
@@ -1,8 +1,8 @@
1
1
  .badge {
2
2
  align-items: center;
3
3
  background-color: var(--badge-background, var(--color-bg));
4
- border-radius: var(--badge-radius, var(--rounded-md));
5
4
  border: 1px solid var(--badge-border-color, var(--color-border));
5
+ border-radius: var(--badge-radius, var(--rounded-md));
6
6
  box-shadow: var(--badge-box-shadow, none);
7
7
  color: var(--badge-color, var(--color-text));
8
8
  column-gap: var(--size-1);
@@ -1,7 +1,7 @@
1
1
  :where(.breadcrumb) {
2
2
  align-items: center;
3
- color: var(--color-text-subtle);
4
3
  column-gap: var(--size-1);
4
+ color: var(--color-text-subtle);
5
5
  display: flex;
6
6
  flex-wrap: wrap;
7
7
  font-size: var(--text-sm);
@@ -2,8 +2,8 @@
2
2
  align-items: center;
3
3
  background-color: var(--btn-background, var(--color-surface));
4
4
  block-size: var(--btn-block-size, auto);
5
- border-radius: var(--btn-radius, var(--rounded-md));
6
5
  border: 1px solid var(--btn-border-color, var(--color-border));
6
+ border-radius: var(--btn-radius, var(--rounded-md));
7
7
  box-shadow: var(--btn-box-shadow, var(--shadow-xs));
8
8
  color: var(--btn-color, var(--color-text));
9
9
  column-gap: var(--size-2);
@@ -76,7 +76,7 @@
76
76
  --btn-padding: var(--size-2);
77
77
  }
78
78
 
79
- [aria-busy="true"] .btn--loading:disabled {
79
+ [aria-busy="true"] .btn--busy:disabled {
80
80
  > * {
81
81
  visibility: hidden;
82
82
  }
@@ -4,29 +4,4 @@
4
4
  border-width: var(--border);
5
5
  box-shadow: var(--shadow-sm);
6
6
  padding: var(--size-6);
7
- position: relative;
8
-
9
- &[aria-disabled="true"] {
10
- pointer-events: none;
11
- }
12
-
13
- &[aria-disabled="true"]::after {
14
- background-color: rgba(0, 0, 0, .3);
15
- border-radius: inherit;
16
- content: "";
17
- inset: 0;
18
- position: absolute;
19
- }
20
- }
21
-
22
- .card-check {
23
- background-color: var(--color-surface);
24
- border-radius: var(--rounded-xl);
25
- border-width: var(--border);
26
- padding: var(--size-3);
27
-
28
- &:has(:checked) {
29
- background-color: rgb(from var(--color-border-light) r g b / .5);
30
- border-color: var(--color-border-dark);
31
- }
32
7
  }
@@ -5,11 +5,11 @@
5
5
  background-color: var(--color-surface);
6
6
  border: 1px solid var(--color-border);
7
7
  border-radius: var(--rounded-md);
8
- min-block-size: var(--size-9);
9
8
  color: var(--color-text);
10
9
  display: inline-flex;
11
10
  font-size: var(--text-sm);
12
11
  line-height: inherit;
12
+ min-block-size: var(--size-9);
13
13
  padding: var(--size-1_5) var(--size-3);
14
14
 
15
15
  > input {
@@ -1,7 +1,7 @@
1
1
  .command {
2
2
  background-color: var(--color-surface);
3
- border-width: var(--border);
4
3
  border-radius: var(--rounded-lg);
4
+ border-width: var(--border);
5
5
  box-shadow: var(--shadow-xs);
6
6
  display: flex;
7
7
  flex-direction: column;
@@ -10,6 +10,7 @@
10
10
  .command__input {
11
11
  --input-background: transparent;
12
12
  --input-border-color: transparent;
13
+ --input-box-shadow: none;
13
14
  --input-outline-size: 0;
14
15
  --input-padding: var(--size-2_5);
15
16
  }
@@ -18,6 +19,10 @@
18
19
  border-block-start-width: var(--border);
19
20
  max-block-size: 300px;
20
21
  overflow-y: auto;
22
+
23
+ &:not(:has(.command__item:not([hidden]))) {
24
+ display: none;
25
+ }
21
26
  }
22
27
 
23
28
  .command__group:not(:first-child) {
@@ -29,6 +34,10 @@
29
34
  flex-direction: column;
30
35
  padding: var(--size-1);
31
36
  row-gap: 1px;
37
+
38
+ &:not(:has(.command__item:not([hidden]))) {
39
+ display: none;
40
+ }
32
41
  }
33
42
 
34
43
  .command__group-header {
@@ -62,14 +71,3 @@
62
71
  font-size: var(--text-xs);
63
72
  margin-inline-start: auto;
64
73
  }
65
-
66
- .command__list--filtering:not(:has(.selected)) {
67
- .command__empty { display: flex; }
68
- }
69
-
70
- .command__list--filtering {
71
- .command__group { display: none; }
72
- .command__group:has(.selected) { display: flex; }
73
- .command__item { display: none; }
74
- .command__item:is(.selected) { display: flex; }
75
- }
@@ -23,8 +23,8 @@
23
23
 
24
24
  .dayContainer {
25
25
  inline-size: var(--container-size);
26
- min-inline-size: var(--container-size);
27
26
  max-inline-size: var(--container-size);
27
+ min-inline-size: var(--container-size);
28
28
  }
29
29
 
30
30
  .dayContainer + .dayContainer {
@@ -130,8 +130,8 @@
130
130
  }
131
131
 
132
132
  .flatpickr-day {
133
- border-radius: var(--rounded-md);
134
133
  border-color: transparent !important;
134
+ border-radius: var(--rounded-md);
135
135
  box-shadow: none !important;
136
136
  color: var(--color-text);
137
137
  height: var(--day-size);
@@ -1,8 +1,8 @@
1
1
  @import url("https://esm.sh/dropzone@6.0.0-beta.2/dist/dropzone.css");
2
2
 
3
3
  .dropzone {
4
- border-radius: var(--rounded-xl);
5
4
  border: 2px dashed var(--color-border);
5
+ border-radius: var(--rounded-xl);
6
6
  padding: var(--size-2);
7
7
  }
8
8
 
@@ -36,8 +36,8 @@
36
36
  }
37
37
 
38
38
  .flash--extended {
39
- animation-name: appear-then-fade-extended;
40
39
  animation-duration: 12s;
40
+ animation-name: appear-then-fade-extended;
41
41
  }
42
42
 
43
43
  @keyframes appear-then-fade {
@@ -1,23 +1,17 @@
1
- .group-inline {
1
+ .group {
2
+ align-items: stretch;
2
3
  display: flex;
3
4
  flex-direction: row;
4
5
 
5
- > :first-child {
6
- border-end-end-radius: 0;
7
- border-start-end-radius: 0;
8
- }
9
-
10
- > :last-child {
11
- border-end-start-radius: 0;
12
- border-start-start-radius: 0;
13
- }
14
-
15
6
  > :not(:first-child) {
7
+ border-end-start-radius: 0;
16
8
  border-inline-start: 0;
9
+ border-start-start-radius: 0;
17
10
  }
18
11
 
19
- > :not(:first-child, :last-child) {
20
- border-radius: 0;
12
+ > :not(:last-child) {
13
+ border-end-end-radius: 0;
14
+ border-start-end-radius: 0;
21
15
  }
22
16
 
23
17
  > :focus-visible {
@@ -25,26 +19,20 @@
25
19
  }
26
20
  }
27
21
 
28
- .group-block {
22
+ .group-vertical {
23
+ align-items: stretch;
29
24
  display: flex;
30
25
  flex-direction: column;
31
26
 
32
- > :first-child {
33
- border-end-end-radius: 0;
34
- border-end-start-radius: 0;
35
- }
36
-
37
- > :last-child {
38
- border-start-end-radius: 0;
39
- border-start-start-radius: 0;
40
- }
41
-
42
27
  > :not(:first-child) {
43
28
  border-block-start: 0;
29
+ border-start-end-radius: 0;
30
+ border-start-start-radius: 0;
44
31
  }
45
32
 
46
- > :not(:first-child, :last-child) {
47
- border-radius: 0;
33
+ > :not(:last-child) {
34
+ border-end-end-radius: 0;
35
+ border-end-start-radius: 0;
48
36
  }
49
37
 
50
38
  > :focus-visible {
@@ -5,8 +5,9 @@
5
5
  flex-shrink: 0;
6
6
  inline-size: var(--icon-size, 1rem);
7
7
  mask-image: var(--svg);
8
+ mask-position: center;
8
9
  mask-repeat: no-repeat;
9
- mask-size: cover;
10
+ mask-size: var(--icon-size, 1em);
10
11
  pointer-events: none;
11
12
  user-select: none;
12
13
  }
@@ -25,19 +26,19 @@ img.icon {
25
26
  * Lucide (https://lucide.dev)
26
27
  * Open-source icon library with a consistent style
27
28
  *****************************************************************/
29
+ .icon--camera { --svg: url("camera.svg"); }
28
30
  .icon--chevron-left { --svg: url("chevron-left.svg"); }
29
31
  .icon--chevron-right { --svg: url("chevron-right.svg"); }
30
- .icon--ellipsis { --svg: url("ellipsis.svg"); }
31
32
  .icon--chevrons-up-down { --svg: url("chevrons-up-down.svg"); }
32
- .icon--menu { --svg: url("menu.svg"); }
33
- .icon--x { --svg: url("x.svg"); }
34
- .icon--search { --svg: url("search.svg"); }
33
+ .icon--circle-alert { --svg: url("circle-alert.svg"); }
34
+ .icon--circle-check { --svg: url("circle-check.svg"); }
35
35
  .icon--copy { --svg: url("copy.svg"); }
36
36
  .icon--download { --svg: url("download.svg"); }
37
- .icon--share { --svg: url("share.svg"); }
38
- .icon--camera { --svg: url("camera.svg"); }
37
+ .icon--ellipsis { --svg: url("ellipsis.svg"); }
38
+ .icon--menu { --svg: url("menu.svg"); }
39
39
  .icon--minus { --svg: url("minus.svg"); }
40
- .icon--sun { --svg: url("sun.svg"); }
41
40
  .icon--moon { --svg: url("moon.svg"); }
42
- .icon--circle-alert { --svg: url("circle-alert.svg"); }
43
- .icon--circle-check { --svg: url("circle-check.svg"); }
41
+ .icon--search { --svg: url("search.svg"); }
42
+ .icon--share { --svg: url("share.svg"); }
43
+ .icon--sun { --svg: url("sun.svg"); }
44
+ .icon--x { --svg: url("x.svg"); }
@@ -46,8 +46,8 @@
46
46
  border-color: var(--color-negative);
47
47
  }
48
48
 
49
- &:user-invalid + .invalid-feedback {
50
- display: block;
49
+ &:user-invalid + [feedback] {
50
+ display: unset;
51
51
  }
52
52
 
53
53
  &:focus-visible {
@@ -0,0 +1,8 @@
1
+ .input--otp {
2
+ font-family: ui-monospace, monospace;
3
+ font-weight: var(--font-black);
4
+ inline-size: var(--input-otp-size, auto);
5
+ letter-spacing: 1ch;
6
+ min-inline-size: var(--input-otp-size, auto);
7
+ text-align: center;
8
+ }
@@ -0,0 +1,34 @@
1
+ .list {
2
+ display: flex;
3
+ flex-direction: column;
4
+ row-gap: var(--size-4);
5
+ }
6
+
7
+ .list-row {
8
+ background-color: var(--item-background, transparent);
9
+ border: 1px solid var(--item-border-color, var(--color-border));
10
+ border-radius: var(--rounded-lg);
11
+ font-size: var(--text-sm);
12
+ padding: var(--size-4);
13
+ }
14
+
15
+ .list-row--muted {
16
+ --item-background: rgb(from var(--color-border-light) r g b / .5);
17
+ }
18
+
19
+ .list-row--borderless {
20
+ --item-border-color: transparent;
21
+ }
22
+
23
+ .list-row--link:hover {
24
+ --item-background: rgb(from var(--color-border-light) r g b / .5);
25
+ }
26
+
27
+ .list-row--link:focus-visible {
28
+ outline: 2px solid var(--color-selected-dark);
29
+ }
30
+
31
+ .list-row--check:has(:checked) {
32
+ --item-background: rgb(from var(--color-border-light) r g b / .5);
33
+ --item-border-color: var(--color-primary);
34
+ }
@@ -1,9 +1,9 @@
1
1
  .sidebar-layout {
2
+ block-size: 100dvh;
2
3
  display: grid;
3
4
  grid-template-areas: "header header" "sidebar main";
4
5
  grid-template-columns: var(--sidebar-width, 0) 1fr;
5
6
  grid-template-rows: auto 1fr;
6
- block-size: 100dvh;
7
7
 
8
8
  @media (width >= 48rem) {
9
9
  --sidebar-border-width: var(--border);
@@ -13,16 +13,16 @@
13
13
  }
14
14
 
15
15
  .header-layout {
16
+ block-size: 100dvh;
16
17
  display: grid;
17
18
  grid-template-areas: "header" "main";
18
19
  grid-template-rows: auto 1fr;
19
- block-size: 100dvh;
20
20
  }
21
21
 
22
22
  .centered-layout {
23
+ block-size: 100dvh;
23
24
  display: grid;
24
25
  place-items: center;
25
- block-size: 100dvh;
26
26
  }
27
27
 
28
28
  .container {
@@ -34,8 +34,8 @@
34
34
  #header {
35
35
  align-items: center;
36
36
  background-color: rgb(from var(--color-border-light) r g b / .5);
37
- border-block-end-width: var(--border);
38
37
  block-size: var(--size-16);
38
+ border-block-end-width: var(--border);
39
39
  column-gap: var(--size-4);
40
40
  display: flex;
41
41
  grid-area: header;
@@ -1,8 +1,8 @@
1
1
  .lightbox {
2
2
  background-color: rgba(0, 0, 0, .8);
3
3
  block-size: 100dvh;
4
- max-block-size: unset;
5
4
  inline-size: 100dvw;
5
+ max-block-size: unset;
6
6
  max-inline-size: unset;
7
7
  padding: var(--size-4);
8
8
 
@@ -32,6 +32,6 @@
32
32
 
33
33
  .lightbox__image {
34
34
  grid-area: 1/1;
35
- max-inline-size: calc(100dvw - (var(--size-4) * 2));
36
35
  max-block-size: calc(100dvh - (var(--size-4) * 2));
36
+ max-inline-size: calc(100dvw - (var(--size-4) * 2));
37
37
  }
@@ -1,18 +1,18 @@
1
1
  .progress {
2
- --track: rgb(from var(--color-primary) r g b / .2);
3
2
  --progress: var(--color-primary);
3
+ --track: rgb(from var(--color-primary) r g b / .2);
4
4
 
5
5
  background-color: var(--track);
6
- border-radius: var(--rounded-full);
7
6
  block-size: var(--size-2);
7
+ border-radius: var(--rounded-full);
8
8
  inline-size: var(--size-full);
9
9
  overflow: hidden;
10
10
 
11
11
  &:indeterminate {
12
+ animation: progress-loading 2s infinite;
12
13
  background: linear-gradient(to right, var(--track) 45%, var(--progress) 0%, var(--progress) 55%, var(--track) 0%);
13
- background-size: 225% 100%;
14
14
  background-position: right;
15
- animation: progress-loading 2s infinite;
15
+ background-size: 225% 100%;
16
16
  }
17
17
 
18
18
  /* Safari/Chromium */
@@ -134,7 +134,7 @@
134
134
  }
135
135
 
136
136
  mark {
137
- color: var(--color-text);
138
137
  background-color: var(--color-highlight);
138
+ color: var(--color-text);
139
139
  }
140
140
  }
@@ -0,0 +1,13 @@
1
+ .separator {
2
+ background-color: var(--color-border-dark);
3
+ block-size: 1px;
4
+ flex-shrink: 0;
5
+ inline-size: var(--size-full);
6
+ }
7
+
8
+ .separator-vertical {
9
+ background-color: var(--color-border-dark);
10
+ block-size: var(--size-full);
11
+ flex-shrink: 0;
12
+ inline-size: 1px;
13
+ }
@@ -1,8 +1,8 @@
1
1
  .sheet {
2
2
  background-color: var(--color-bg);
3
+ block-size: var(--size-full);
3
4
  border-inline-width: var(--sheet-border);
4
5
  box-shadow: var(--shadow-lg);
5
- block-size: var(--size-full);
6
6
  color: var(--color-text);
7
7
  inline-size: var(--sheet-size, var(--size-3-4));
8
8
  margin-inline: var(--sheet-margin);
@@ -1,8 +1,8 @@
1
1
  .sidebar-menu {
2
+ block-size: var(--size-full);
2
3
  display: flex;
3
4
  flex-direction: column;
4
5
  row-gap: var(--size-4);
5
- block-size: var(--size-full);
6
6
  }
7
7
 
8
8
  .sidebar-menu__button {
@@ -10,9 +10,9 @@
10
10
  --btn-border-color: transparent;
11
11
  --btn-box-shadow: none;
12
12
  --btn-font-weight: var(--font-normal);
13
+ --btn-inline-size: var(--size-full);
13
14
  --btn-justify-content: start;
14
15
  --btn-outline-size: 0;
15
- --btn-inline-size: var(--size-full);
16
16
  --btn-padding: var(--size-1) var(--size-2);
17
17
 
18
18
  &[aria-current="page"] {
@@ -48,9 +48,11 @@
48
48
 
49
49
  .sidebar-menu__content {
50
50
  display: flex;
51
+ flex: 1;
51
52
  flex-direction: column;
53
+ min-block-size: 0;
54
+ overflow-y: auto;
52
55
  row-gap: var(--size-4);
53
- overflow-y: scroll;
54
56
  }
55
57
 
56
58
  .sidebar-menu__group {
@@ -1,6 +1,6 @@
1
1
  .skeleton {
2
2
  animation: var(--animate-blink);
3
3
  animation-duration: 2s;
4
- border-radius: var(--rounded-md);
5
4
  background-color: var(--color-border);
5
+ border-radius: var(--rounded-md);
6
6
  }
@@ -24,8 +24,8 @@
24
24
  /* CSS Zero */
25
25
 
26
26
  trix-toolbar {
27
- inset-block-start: 0;
28
27
  inline-size: 100%;
28
+ inset-block-start: 0;
29
29
  position: sticky;
30
30
 
31
31
  .trix-button-row {
@@ -64,20 +64,20 @@ trix-toolbar {
64
64
  background-color: var(--color-bg);
65
65
  border: 1px solid var(--color-border);
66
66
  border-radius: var(--rounded-md);
67
- margin: var(--size-1);
68
67
  box-shadow: var(--shadow-md);
68
+ margin: var(--size-1);
69
69
  }
70
70
 
71
71
  .trix-input--dialog {
72
- border-color: var(--color-border);
73
72
  background-color: var(--color-surface);
73
+ border-color: var(--color-border);
74
74
  margin: 0;
75
75
  }
76
76
 
77
77
  .trix-button--dialog {
78
- margin-inline-start: var(--size-1_5);
79
78
  background-color: var(--color-primary);
80
79
  color: var(--color-text-reversed);
80
+ margin-inline-start: var(--size-1_5);
81
81
  }
82
82
 
83
83
  [data-trix-dialog] [data-trix-validate]:invalid {
@@ -136,8 +136,8 @@ trix-editor {
136
136
  border-inline-start: 2px solid var(--color-border);
137
137
  font-style: italic;
138
138
  margin: 0;
139
- padding-inline-start: var(--size-6);
140
139
  padding-inline-end: 0;
140
+ padding-inline-start: var(--size-6);
141
141
  }
142
142
 
143
143
  pre {
@@ -176,8 +176,8 @@ trix-editor {
176
176
  }
177
177
 
178
178
  .attachment--file {
179
- color: var(--color--text);
180
179
  border: 1px solid var(--color-border);
180
+ color: var(--color--text);
181
181
  }
182
182
 
183
183
  .attachment__progress {
@@ -4,17 +4,16 @@ import { FetchRequest } from "https://esm.sh/@rails/request.js@0.0.12?standalone
4
4
  const AUTOSAVE_INTERVAL = 3000
5
5
 
6
6
  export default class extends Controller {
7
- static targets = [ "submitter" ]
7
+ static targets = [ "submit" ]
8
8
 
9
- #timer = null
9
+ #timer
10
10
 
11
11
  disconnect() {
12
12
  this.#submit()
13
13
  }
14
14
 
15
15
  change() {
16
- !this.#dirty && this.#scheduleSave()
17
- !this.#dirty && this.#updateAppearance(false)
16
+ !this.#dirty && this.#scheduleSaveAndUpdateAppearance(false)
18
17
  }
19
18
 
20
19
  async #submit() {
@@ -32,16 +31,20 @@ export default class extends Controller {
32
31
  return await new FetchRequest(form.method, form.action, { body: new FormData(form) }).perform()
33
32
  }
34
33
 
35
- #updateAppearance(saving) {
36
- this.element.ariaBusy = saving
37
- this.submitterTarget.ariaDisabled = saving
38
- this.submitterTarget.disabled = saving
34
+ #scheduleSaveAndUpdateAppearance(saving) {
35
+ this.#scheduleSave()
36
+ this.#updateAppearance(false)
39
37
  }
40
38
 
41
39
  #scheduleSave() {
42
40
  this.#timer = setTimeout(() => this.#save(), AUTOSAVE_INTERVAL)
43
41
  }
44
42
 
43
+ #updateAppearance(saving) {
44
+ this.element.ariaBusy = saving
45
+ this.submitTarget.disabled = saving
46
+ }
47
+
45
48
  #resetTimer() {
46
49
  clearTimeout(this.#timer)
47
50
  this.#timer = null
@@ -3,8 +3,7 @@ import debounce from "https://esm.sh/just-debounce-it@3.2.0?standalone"
3
3
  import Combobox from "https://esm.sh/@github/combobox-nav@3.0.1?standalone"
4
4
 
5
5
  export default class extends Controller {
6
- static targets = [ "input", "list" ]
7
- static classes = [ "active", "selected" ]
6
+ static targets = [ "input", "list", "item" ]
8
7
 
9
8
  initialize() {
10
9
  this.filter = debounce(this.filter.bind(this), 300)
@@ -20,39 +19,14 @@ export default class extends Controller {
20
19
  }
21
20
 
22
21
  filter({ target }) {
23
- this.#reset()
24
-
25
- if (target.value != "") {
26
- this.#selectMatches(target.value)
27
- this.#activate()
28
- } else {
29
- this.#deactivate()
30
- }
22
+ this.itemTargets.forEach(it => { this.#matches(it.dataset.value, target.value) ? it.removeAttribute("hidden") : it.toggleAttribute("hidden", true) })
31
23
  }
32
24
 
33
25
  commit({ target }) {
34
26
  Turbo.visit(target.dataset.href, { action: "advance" })
35
27
  }
36
28
 
37
- #reset() {
38
- this.listTarget.querySelectorAll(`.${this.selectedClass}`).forEach(it => {
39
- it.classList.remove(this.selectedClass)
40
- })
41
- }
42
-
43
- #selectMatches(value) {
44
- this.listTarget.querySelectorAll(`[data-value*="${value.toLowerCase()}"]`).forEach(it => {
45
- it.classList.add(this.selectedClass)
46
- })
47
- }
48
-
49
- #activate() {
50
- this.listTarget.classList.add(this.activeClass)
51
- this.combobox.resetSelection()
52
- }
53
-
54
- #deactivate() {
55
- this.listTarget.classList.remove(this.activeClass)
56
- this.combobox.resetSelection()
29
+ #matches(text, potentialMatch) {
30
+ return text.toLowerCase().includes(potentialMatch.toLowerCase())
57
31
  }
58
32
  }
@@ -2,10 +2,10 @@ import { Controller } from "@hotwired/stimulus"
2
2
  import debounce from "https://esm.sh/just-debounce-it@3.2.0?standalone"
3
3
 
4
4
  export default class extends Controller {
5
- static targets = [ "cancel" ]
5
+ static targets = [ "cancel", "submit" ]
6
6
 
7
7
  initialize() {
8
- this.debouncedSubmit = debounce(this.submit.bind(this), 300)
8
+ this.debouncedSubmit = debounce(this.debouncedSubmit.bind(this), 300)
9
9
  }
10
10
 
11
11
  submit({ params: { submitter } }) {
@@ -16,6 +16,27 @@ export default class extends Controller {
16
16
  }
17
17
  }
18
18
 
19
+ debouncedSubmit(event) {
20
+ this.submit(event)
21
+ }
22
+
23
+ submitToTopTarget() {
24
+ this.element.setAttribute("data-turbo-frame", "_top")
25
+ this.submit()
26
+ }
27
+
28
+ disableSubmitWhenInvalid() {
29
+ if (this.element.checkValidity()) {
30
+ this.submitTarget.removeAttribute("disabled")
31
+ } else {
32
+ this.submitTarget.toggleAttribute("disabled", true)
33
+ }
34
+ }
35
+
36
+ reset() {
37
+ this.element.reset()
38
+ }
39
+
19
40
  cancel() {
20
41
  this.cancelTarget?.click()
21
42
  }
@@ -2,7 +2,15 @@ import { Controller } from "@hotwired/stimulus"
2
2
 
3
3
  export default class extends Controller {
4
4
  click(event) {
5
- this.#isClickable && !this.#shouldIgnore(event) && this.element.click()
5
+ if (this.#isClickable && !this.#shouldIgnore(event)) {
6
+ event.preventDefault(); this.element.click()
7
+ }
8
+ }
9
+
10
+ focus(event) {
11
+ if (this.#isClickable && !this.#shouldIgnore(event)) {
12
+ event.preventDefault(); this.element.focus()
13
+ }
6
14
  }
7
15
 
8
16
  #shouldIgnore(event) {
@@ -1,12 +1,24 @@
1
1
  import { Controller } from "@hotwired/stimulus"
2
2
 
3
3
  export default class extends Controller {
4
- static targets = [ "time", "date", "datetime" ]
4
+ static targets = [ "time", "date", "shortdate", "datetime", "ago" ]
5
+
6
+ #timer
5
7
 
6
8
  initialize() {
7
9
  this.timeFormatter = new Intl.DateTimeFormat(undefined, { timeStyle: "short" })
8
10
  this.dateFormatter = new Intl.DateTimeFormat(undefined, { dateStyle: "long" })
9
- this.dateTimeFormatter = new Intl.DateTimeFormat(undefined, { timeStyle: "short", dateStyle: "short" })
11
+ this.shortdateFormatter = new Intl.DateTimeFormat(undefined, { month: "short", day: "numeric" })
12
+ this.datetimeFormatter = new Intl.DateTimeFormat(undefined, { timeStyle: "short", dateStyle: "short" })
13
+ this.agoFormatter = new TimeAgoFormat(undefined, { numeric: "always" })
14
+ }
15
+
16
+ connect() {
17
+ this.#timer = setInterval(() => this.#refreshRelativeTimes(), 30_000)
18
+ }
19
+
20
+ disconnect() {
21
+ clearInterval(this.#timer)
10
22
  }
11
23
 
12
24
  timeTargetConnected(target) {
@@ -18,12 +30,56 @@ export default class extends Controller {
18
30
  }
19
31
 
20
32
  datetimeTargetConnected(target) {
21
- this.#formatTime(this.dateTimeFormatter, target)
33
+ this.#formatTime(this.datetimeFormatter, target)
34
+ }
35
+
36
+ shortdateTargetConnected(target) {
37
+ this.#formatTime(this.shortdateFormatter, target)
38
+ }
39
+
40
+ agoTargetConnected(target) {
41
+ this.#formatTime(this.agoFormatter, target)
42
+ }
43
+
44
+ #refreshRelativeTimes() {
45
+ this.agoTargets.forEach(it => this.#formatTime(this.agoFormatter, it))
22
46
  }
23
47
 
24
48
  #formatTime(formatter, target) {
25
- const dt = new Date(target.getAttribute("datetime"))
26
- target.textContent = formatter.format(dt)
27
- target.title = this.dateTimeFormatter.format(dt)
49
+ const date = new Date(target.getAttribute("datetime"))
50
+ target.textContent = formatter.format(date)
51
+ target.title = this.datetimeFormatter.format(date)
52
+ }
53
+ }
54
+
55
+ class TimeAgoFormat extends Intl.RelativeTimeFormat {
56
+ format(date) {
57
+ const seconds = (Date.now() - date) / 1000
58
+ const minutes = seconds / 60
59
+ const hours = minutes / 60
60
+ const days = hours / 24
61
+ const weeks = days / 7
62
+ const months = days / 30.4
63
+ const years = days / 365
64
+
65
+ if (years >= 1) {
66
+ return super.format(-Math.floor(years), "years")
67
+ } else if (months >= 1) {
68
+ return super.format(-Math.floor(months), "months")
69
+ } else if (weeks >= 1) {
70
+ return super.format(-Math.floor(weeks), "weeks")
71
+ } else if (days >= 1) {
72
+ return super.format(-Math.floor(days), "days")
73
+ } else if (hours >= 1) {
74
+ return super.format(-Math.floor(hours), "hours")
75
+ } else if (minutes >= 1) {
76
+ return super.format(-Math.floor(minutes), "minutes")
77
+ } else {
78
+ return this.#formatAsTime(date)
79
+ }
80
+ }
81
+
82
+ #formatAsTime(date) {
83
+ return new Intl.DateTimeFormat(undefined, { timeStyle: "short" }).format(date)
28
84
  }
29
85
  }
@@ -5,8 +5,8 @@ export default class extends Controller {
5
5
  static targets = [ "trigger", "content" ]
6
6
  static values = { placement: { type: String, default: "bottom" } }
7
7
 
8
- #showTimer = null
9
- #hideTimer = null
8
+ #showTimer
9
+ #hideTimer
10
10
 
11
11
  initialize() {
12
12
  this.orient = this.orient.bind(this)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: css-zero
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lázaro Nixon
@@ -80,7 +80,9 @@ files:
80
80
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/input.css
81
81
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/input_clearable.css
82
82
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/input_copyable.css
83
+ - lib/generators/css_zero/add/templates/app/assets/stylesheets/input_otp.css
83
84
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/input_revealable.css
85
+ - lib/generators/css_zero/add/templates/app/assets/stylesheets/item.css
84
86
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/layouts.css
85
87
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/lightbox.css
86
88
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/menu.css
@@ -88,6 +90,7 @@ files:
88
90
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/progress.css
89
91
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/prose.css
90
92
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/resizable.css
93
+ - lib/generators/css_zero/add/templates/app/assets/stylesheets/separator.css
91
94
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/sheet.css
92
95
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/sidebar_menu.css
93
96
  - lib/generators/css_zero/add/templates/app/assets/stylesheets/skeleton.css
@@ -129,7 +132,6 @@ files:
129
132
  - lib/generators/css_zero/add/templates/app/javascript/controllers/timezone_cookie_controller.js
130
133
  - lib/generators/css_zero/add/templates/app/javascript/controllers/turbo_confirm_controller.js
131
134
  - lib/generators/css_zero/add/templates/app/javascript/controllers/upload_preview_controller.js
132
- - lib/generators/css_zero/add/templates/app/javascript/controllers/web_otp_controller.js
133
135
  - lib/generators/css_zero/add/templates/app/javascript/controllers/web_share_controller.js
134
136
  - lib/generators/css_zero/authentication/authentication_generator.rb
135
137
  - lib/generators/css_zero/authentication/templates/app/views/passwords/edit.html.erb.tt
@@ -1,32 +0,0 @@
1
- import { Controller } from "@hotwired/stimulus"
2
-
3
- export default class extends Controller {
4
- static targets = [ "input" ]
5
-
6
- initialize() {
7
- this.abortController = new AbortController()
8
- }
9
-
10
- disconnect() {
11
- this.abortController.abort()
12
- }
13
-
14
- connect() {
15
- this.#supportsOTP && this.#requestOTP()
16
- }
17
-
18
- #requestOTP() {
19
- navigator.credentials.get(this.#options).then(credential => {
20
- this.inputTarget.value = credential.code
21
- this.element.requestSubmit()
22
- }).catch(error => {})
23
- }
24
-
25
- get #options() {
26
- return { otp: { transport: ["sms"] }, signal: this.abortController.signal }
27
- }
28
-
29
- get #supportsOTP() {
30
- return "OTPCredential" in window
31
- }
32
- }