@livenetworks/ashlar 1.4.1 → 1.6.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 (219) hide show
  1. package/README.md +189 -177
  2. package/js/COMPONENTS.md +55 -49
  3. package/js/index.js +22 -5
  4. package/js/ln-accordion/README.md +186 -137
  5. package/js/ln-accordion/ln-accordion.js +1 -1
  6. package/js/ln-ajax/README.md +73 -4
  7. package/js/ln-ajax/ln-ajax.js +1 -1
  8. package/js/ln-ajax/src/ln-ajax.js +13 -13
  9. package/js/ln-api-connector/README.md +261 -150
  10. package/js/ln-api-connector/ln-api-connector.js +1 -1
  11. package/js/ln-api-connector/src/ln-api-connector.js +368 -265
  12. package/js/ln-api-queue/README.md +219 -0
  13. package/js/ln-api-queue/ln-api-queue.js +1 -0
  14. package/js/ln-api-queue/src/ln-api-queue.js +320 -0
  15. package/js/ln-api-queue/src/queue-storage.js +455 -0
  16. package/js/ln-autoresize/README.md +47 -0
  17. package/js/ln-autoresize/ln-autoresize.js +1 -1
  18. package/js/ln-autosave/README.md +33 -1
  19. package/js/ln-autosave/ln-autosave.js +1 -1
  20. package/js/ln-autosave/src/ln-autosave.js +4 -4
  21. package/js/ln-circular-progress/README.md +27 -13
  22. package/js/ln-circular-progress/ln-circular-progress.js +1 -1
  23. package/js/ln-circular-progress/src/ln-circular-progress.js +18 -5
  24. package/js/ln-confirm/README.md +162 -86
  25. package/js/ln-confirm/_ln-confirm.scss +11 -0
  26. package/js/ln-confirm/ln-confirm.js +1 -1
  27. package/js/ln-confirm/src/ln-confirm.js +77 -41
  28. package/js/ln-core/README.md +896 -0
  29. package/js/ln-core/hash.js +92 -0
  30. package/js/ln-core/helpers.js +337 -8
  31. package/js/ln-core/index.js +4 -2
  32. package/js/ln-core/persist.js +29 -3
  33. package/js/ln-core/positioning.js +1 -35
  34. package/js/ln-core/window-cache.js +213 -0
  35. package/js/ln-couchdb-connector/README.md +177 -156
  36. package/js/ln-couchdb-connector/ln-couchdb-connector.js +1 -1
  37. package/js/ln-couchdb-connector/src/ln-couchdb-connector.js +398 -348
  38. package/js/ln-data-coordinator/README.md +536 -165
  39. package/js/ln-data-coordinator/ln-data-coordinator.js +1 -1
  40. package/js/ln-data-coordinator/src/data-read-policy.js +18 -0
  41. package/js/ln-data-coordinator/src/ln-data-coordinator.js +1042 -249
  42. package/js/ln-data-coordinator/src/mutation-receipts.js +46 -0
  43. package/js/ln-data-store/README.md +241 -94
  44. package/js/ln-data-store/ln-data-store.js +1 -1
  45. package/js/ln-data-store/src/ln-data-store.js +694 -699
  46. package/js/ln-date/README.md +39 -1
  47. package/js/ln-date/ln-date-dev.scss +14 -0
  48. package/js/ln-date/ln-date.js +1 -1
  49. package/js/ln-date/src/ln-date.js +236 -178
  50. package/js/ln-debug/README.md +58 -0
  51. package/js/ln-debug/ln-debug.js +1 -0
  52. package/js/ln-debug/src/ln-debug.js +19 -0
  53. package/js/ln-dropdown/README.md +31 -8
  54. package/js/ln-dropdown/ln-dropdown.js +1 -1
  55. package/js/ln-dropdown/src/ln-dropdown.js +30 -13
  56. package/js/ln-editor/README.md +274 -0
  57. package/js/ln-editor/ln-editor.js +1 -0
  58. package/js/ln-editor/ln-editor.scss +43 -0
  59. package/js/ln-editor/src/ln-editor.js +619 -0
  60. package/js/ln-external-links/README.md +44 -5
  61. package/js/ln-external-links/ln-external-links.js +1 -1
  62. package/js/ln-fill/README.md +199 -0
  63. package/js/ln-fill/ln-fill.js +1 -0
  64. package/js/ln-fill/src/ln-fill.js +87 -0
  65. package/js/ln-filter/README.md +189 -99
  66. package/js/ln-filter/ln-filter-dev.scss +8 -0
  67. package/js/ln-filter/ln-filter.js +1 -1
  68. package/js/ln-filter/src/ln-filter.js +22 -7
  69. package/js/ln-form/README.md +212 -49
  70. package/js/ln-form/ln-form.js +1 -1
  71. package/js/ln-form/src/ln-form.js +99 -199
  72. package/js/ln-http/README.md +125 -89
  73. package/js/ln-http/ln-http.js +1 -1
  74. package/js/ln-http/src/ln-http.js +32 -13
  75. package/js/ln-icon/README.md +130 -0
  76. package/js/ln-icon/ln-icon.js +1 -0
  77. package/js/{ln-icons/src/ln-icons.js → ln-icon/src/ln-icon.js} +20 -15
  78. package/js/ln-link/README.md +47 -9
  79. package/js/ln-link/ln-link.js +1 -1
  80. package/js/ln-link/src/ln-link.js +22 -6
  81. package/js/ln-list/README.md +129 -0
  82. package/js/ln-list/ln-list.js +1 -0
  83. package/js/ln-list/ln-list.scss +28 -0
  84. package/js/ln-list/src/ln-list.js +1216 -0
  85. package/js/ln-modal/README.md +185 -154
  86. package/js/ln-modal/ln-modal-dev.scss +13 -0
  87. package/js/ln-modal/ln-modal.js +1 -1
  88. package/js/ln-modal/ln-modal.scss +28 -4
  89. package/js/ln-modal/src/ln-modal.js +137 -201
  90. package/js/ln-modal-coordinator/README.md +99 -0
  91. package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +8 -0
  92. package/js/ln-modal-coordinator/ln-modal-coordinator.js +1 -0
  93. package/js/ln-modal-coordinator/src/ln-modal-coordinator.js +345 -0
  94. package/js/ln-nav/README.md +46 -3
  95. package/js/ln-nav/ln-nav.js +1 -1
  96. package/js/ln-nav/src/ln-nav.js +92 -127
  97. package/js/ln-number/README.md +28 -1
  98. package/js/ln-number/ln-number-dev.scss +13 -0
  99. package/js/ln-number/ln-number.js +1 -1
  100. package/js/ln-number/src/ln-number.js +443 -350
  101. package/js/ln-options/README.md +66 -0
  102. package/js/ln-options/ln-options.js +1 -0
  103. package/js/ln-options/src/ln-options.js +74 -0
  104. package/js/ln-popover/README.md +40 -5
  105. package/js/ln-popover/ln-popover.js +1 -1
  106. package/js/ln-popover/src/ln-popover.js +38 -11
  107. package/js/ln-progress/README.md +413 -442
  108. package/js/ln-progress/ln-progress.js +1 -1
  109. package/js/ln-progress/src/ln-progress.js +98 -150
  110. package/js/ln-router/README.md +432 -0
  111. package/js/ln-router/ln-router.js +1 -0
  112. package/js/ln-router/src/ln-router.js +539 -0
  113. package/js/ln-search/README.md +158 -83
  114. package/js/ln-search/ln-search-dev.scss +8 -0
  115. package/js/ln-search/ln-search.js +1 -1
  116. package/js/ln-search/src/ln-search.js +12 -9
  117. package/js/ln-slug/README.md +110 -0
  118. package/js/ln-slug/ln-slug.js +1 -0
  119. package/js/ln-slug/src/ln-slug.js +74 -0
  120. package/js/ln-sort/README.md +170 -0
  121. package/js/ln-sort/ln-sort-dev.scss +8 -0
  122. package/js/ln-sort/ln-sort.js +1 -0
  123. package/js/ln-sort/src/ln-sort.js +178 -0
  124. package/js/ln-sortable/README.md +133 -95
  125. package/js/ln-sortable/ln-sortable.js +1 -1
  126. package/js/ln-stat/README.md +55 -0
  127. package/js/ln-stat/ln-stat.js +1 -0
  128. package/js/ln-stat/src/ln-stat.js +55 -0
  129. package/js/ln-table/README.md +285 -101
  130. package/js/ln-table/ln-table-dev.scss +17 -0
  131. package/js/ln-table/ln-table.js +1 -1
  132. package/js/ln-table/ln-table.scss +1 -1
  133. package/js/ln-table/src/ln-table.js +1493 -473
  134. package/js/ln-table-coordinator/README.md +73 -0
  135. package/js/ln-table-coordinator/ln-table-coordinator.js +1 -0
  136. package/js/ln-table-coordinator/src/ln-table-coordinator.js +160 -0
  137. package/js/ln-tabs/README.md +221 -137
  138. package/js/ln-tabs/ln-tabs-dev.scss +18 -0
  139. package/js/ln-tabs/ln-tabs.js +1 -1
  140. package/js/ln-tabs/src/ln-tabs.js +41 -24
  141. package/js/ln-time/README.md +14 -0
  142. package/js/ln-time/ln-time.js +1 -1
  143. package/js/ln-time/src/ln-time.js +223 -192
  144. package/js/ln-toast/README.md +178 -122
  145. package/js/ln-toast/ln-toast.js +1 -15
  146. package/js/ln-toast/src/ln-toast.js +232 -210
  147. package/js/ln-toast/template.html +16 -12
  148. package/js/ln-toggle/README.md +61 -2
  149. package/js/ln-toggle/ln-toggle-dev.scss +13 -0
  150. package/js/ln-toggle/ln-toggle.js +1 -1
  151. package/js/ln-toggle/src/ln-toggle.js +56 -43
  152. package/js/ln-tooltip/README.md +95 -58
  153. package/js/ln-tooltip/ln-tooltip-dev.scss +9 -0
  154. package/js/ln-tooltip/ln-tooltip.js +1 -1
  155. package/js/ln-tooltip/src/ln-tooltip.js +45 -6
  156. package/js/ln-translations/README.md +118 -96
  157. package/js/ln-translations/ln-translations.js +1 -1
  158. package/js/ln-translations/src/ln-translations.js +10 -5
  159. package/js/ln-upload/README.md +85 -10
  160. package/js/ln-upload/ln-upload.js +1 -1
  161. package/js/ln-upload/src/ln-upload.js +26 -10
  162. package/js/ln-validate/README.md +72 -0
  163. package/js/ln-validate/ln-validate-dev.scss +15 -0
  164. package/js/ln-validate/ln-validate.js +1 -1
  165. package/js/ln-validate/src/ln-validate.js +64 -0
  166. package/package.json +61 -55
  167. package/scss/base/_global.scss +2 -2
  168. package/scss/base/_typography.scss +1 -2
  169. package/scss/components/_date.scss +1 -0
  170. package/scss/components/_dropdown.scss +0 -5
  171. package/scss/components/_editor.scss +5 -0
  172. package/scss/components/_filter.scss +26 -0
  173. package/scss/components/_form.scss +7 -0
  174. package/scss/components/_ln-table.scss +14 -5
  175. package/scss/components/_sort.scss +10 -0
  176. package/scss/components/_table.scss +68 -1
  177. package/scss/components/_toast.scss +68 -41
  178. package/scss/components/_toggle.scss +16 -0
  179. package/scss/config/_density.scss +205 -117
  180. package/scss/config/_icons.scss +10 -9
  181. package/scss/config/_tokens.scss +69 -47
  182. package/scss/config/mixins/_accordion.scss +2 -7
  183. package/scss/config/mixins/_alert.scss +4 -4
  184. package/scss/config/mixins/_breadcrumbs.scss +2 -2
  185. package/scss/config/mixins/_btn.scss +1 -1
  186. package/scss/config/mixins/_card.scss +89 -14
  187. package/scss/config/mixins/_collapsible.scss +3 -0
  188. package/scss/config/mixins/_colors.scss +1 -1
  189. package/scss/config/mixins/_diagnostics.scss +48 -0
  190. package/scss/config/mixins/_display.scss +1 -0
  191. package/scss/config/mixins/_dropdown.scss +3 -5
  192. package/scss/config/mixins/_editor.scss +124 -0
  193. package/scss/config/mixins/_empty-state.scss +7 -0
  194. package/scss/config/mixins/_filter.scss +47 -0
  195. package/scss/config/mixins/_footer.scss +1 -2
  196. package/scss/config/mixins/_form.scss +207 -21
  197. package/scss/config/mixins/_index.scss +4 -1
  198. package/scss/config/mixins/_ln-table.scss +51 -93
  199. package/scss/config/mixins/_modal.scss +149 -66
  200. package/scss/config/mixins/_nav.scss +3 -4
  201. package/scss/config/mixins/_popover.scss +39 -0
  202. package/scss/config/mixins/_sidebar.scss +1 -1
  203. package/scss/config/mixins/_sort.scss +42 -0
  204. package/scss/config/mixins/_table.scss +232 -38
  205. package/scss/config/mixins/_toast.scss +179 -152
  206. package/scss/config/mixins/_tooltip.scss +17 -7
  207. package/scss/config/mixins/_typography.scss +4 -2
  208. package/scss/ln-ashlar-dev.scss +39 -0
  209. package/scss/ln-ashlar.scss +8 -2
  210. package/js/ln-data-table/README.md +0 -110
  211. package/js/ln-data-table/ln-data-table.js +0 -1
  212. package/js/ln-data-table/ln-data-table.scss +0 -10
  213. package/js/ln-data-table/src/ln-data-table.js +0 -1103
  214. package/js/ln-icons/README.md +0 -88
  215. package/js/ln-icons/ln-icons.js +0 -1
  216. package/js/ln-table/ln-table-sort.js +0 -1
  217. package/js/ln-table/src/ln-table-sort.js +0 -168
  218. package/scss/components/_data-table.scss +0 -83
  219. package/scss/config/mixins/_data-table.scss +0 -346
@@ -6,41 +6,114 @@
6
6
  @use 'borders' as *;
7
7
  @use 'transitions' as *;
8
8
  @use 'position' as *;
9
+ @use 'motion' as *;
10
+ @use 'interaction' as *;
11
+ @use 'form' as *;
12
+ @use 'btn' as *;
13
+ @use 'card' as *;
14
+ @use 'ln-table';
9
15
 
10
16
  // ─── Base table ─────────────────────────────────────────────────
11
17
 
12
- @mixin table-base {
18
+ @mixin table-base($sticky: false) {
13
19
  @include w-full;
14
20
  background: var(--color-bg);
15
21
  --radius: var(--radius-lg);
16
22
  border-radius: var(--radius);
17
23
  // `overflow: clip` not `overflow: hidden` — clips at rounded corners
18
24
  // without establishing a scroll container, so sticky descendants
19
- // (e.g. `@mixin data-table` thead/tfoot) bind to the outer
20
- // `.app-main > section` scroll surface instead of being trapped
21
- // inside the <table> element. Same rationale as `@mixin section-card`
22
- // and `@mixin ln-table`.
25
+ // bind to the outer scroll surface instead of being trapped inside.
23
26
  overflow: clip;
24
27
  --shadow: var(--shadow-resting);
25
28
  box-shadow: var(--shadow);
26
- border-collapse: collapse;
29
+
30
+ @if $sticky {
31
+ @include relative;
32
+ border-collapse: separate;
33
+ border-spacing: 0;
34
+ } @else {
35
+ border-collapse: collapse;
36
+ }
27
37
  font-variant-numeric: tabular-nums;
28
38
 
39
+ // Row hover transition color. Default to a discrete tint of the primary color
40
+ // mixed with transparent to create a harmonious background shift across themes.
41
+ --bg-row-hover: var(--color-row-hover, color-mix(in srgb, var(--color-primary) 6%, transparent));
42
+
29
43
  thead {
30
44
  --color-bg: var(--bg-sunken);
31
45
  background: var(--color-bg);
32
46
  border-block-end: var(--border-block-end, var(--border-width-strong) solid var(--color-border));
47
+
48
+ @if $sticky {
49
+ @include sticky-top;
50
+ }
51
+ }
52
+
53
+ // Support for in-thead toolbar inside sticky tables
54
+ @if $sticky {
55
+ thead > tr:first-child:has(> th[colspan]) > th {
56
+ @include ln-table.ln-table-thead-toolbar;
57
+ }
33
58
  }
34
59
 
35
60
  th {
36
61
  @include text-left;
37
- padding: var(--padding-y) var(--padding-x);
62
+ padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
38
63
  @include font-semibold;
39
- font-size: var(--text-label-sm);
40
- line-height: var(--line-height);
41
- letter-spacing: 0.4px;
64
+ @include typography(label-sm);
65
+ letter-spacing: 0.06em;
42
66
  @include uppercase;
43
67
  color: var(--color-fg);
68
+ position: relative;
69
+ top: auto;
70
+ z-index: auto;
71
+
72
+ // Shared header-button stack — keyed off the unprefixed structural filter button
73
+ // class and the [data-ln-sort] JS-component selector, so table / ln-table /
74
+ // ln-data-table all share one positioning rule.
75
+ &:has([data-ln-sort]):has(.table-filter) {
76
+ padding-inline-end: calc(var(--padding-x, var(--size-md)) + 3.75rem);
77
+
78
+ .table-filter {
79
+ position: absolute;
80
+ top: 50%;
81
+ transform: translateY(-50%);
82
+ right: var(--padding-x, var(--size-md));
83
+ margin: 0;
84
+ }
85
+ [data-ln-sort] {
86
+ position: absolute;
87
+ top: 50%;
88
+ transform: translateY(-50%);
89
+ right: calc(var(--padding-x, var(--size-md)) + 1.75rem);
90
+ margin: 0;
91
+ }
92
+ }
93
+
94
+ &:has([data-ln-sort]):not(:has(.table-filter)) {
95
+ padding-inline-end: calc(var(--padding-x, var(--size-md)) + 2rem);
96
+
97
+ [data-ln-sort] {
98
+ position: absolute;
99
+ top: 50%;
100
+ transform: translateY(-50%);
101
+ right: var(--padding-x, var(--size-md));
102
+ margin: 0;
103
+ }
104
+ }
105
+
106
+ &:has(.table-filter):not(:has([data-ln-sort])) {
107
+ padding-inline-end: calc(var(--padding-x, var(--size-md)) + 2rem);
108
+
109
+ .table-filter {
110
+ position: absolute;
111
+ top: 50%;
112
+ transform: translateY(-50%);
113
+ right: var(--padding-x, var(--size-md));
114
+ margin: 0;
115
+ }
116
+ }
44
117
  }
45
118
 
46
119
  tbody tr {
@@ -48,16 +121,13 @@
48
121
  min-height: var(--density-row-h);
49
122
 
50
123
  &:hover {
51
- // Default hover stays --bg-sunken for standalone tables. Data-table
52
- // re-binds --color-bg locally (see _data-table.scss) so its hover
53
- // disambiguates from chrome that also uses --bg-sunken.
54
- --color-bg: var(--bg-sunken);
124
+ --color-bg: var(--bg-row-hover);
55
125
  background: var(--color-bg);
56
126
  }
57
127
  }
58
128
 
59
129
  td {
60
- padding: var(--padding-y) var(--padding-x);
130
+ padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
61
131
  @include border-b;
62
132
  font-size: var(--font-size);
63
133
  line-height: var(--line-height);
@@ -83,6 +153,21 @@
83
153
  th.nowrap {
84
154
  @include whitespace-nowrap;
85
155
  }
156
+
157
+ // Sticky section footer inside sticky/enhanced tables
158
+ @if $sticky {
159
+ > footer {
160
+ padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
161
+ border-block-start: var(--border-block-start, var(--border-width) solid var(--color-border));
162
+ --color-bg: var(--bg-sunken);
163
+ background: var(--color-bg);
164
+ --color-fg: var(--fg-muted);
165
+ color: var(--color-fg);
166
+ @include typography(body-sm);
167
+ position: sticky;
168
+ z-index: var(--z-sticky);
169
+ }
170
+ }
86
171
  }
87
172
 
88
173
  // ─── Responsive (mobile stacked layout) ─────────────────────────
@@ -182,34 +267,143 @@
182
267
  }
183
268
  }
184
269
 
185
- // ─── Column filter button ──────────────────────────────────────
186
- // Button inside <th> that triggers a filter popover/dropdown.
187
- // Convention: add class="filter" to the trigger button.
188
- // ln-table.js sets data-ln-filter-active on the <th> when active.
189
-
190
- @mixin table-filter-button {
191
- th .filter {
192
- @include inline-flex;
193
- @include items-center;
194
- float: right;
195
- --btn-padding-y: var(--size-2xs);
196
- --btn-padding-x: var(--size-2xs);
197
- @include rounded-sm;
198
- opacity: 0.5;
270
+ // ─── Column sort & filter buttons ──────────────────────────────
199
271
 
200
- &:hover {
201
- opacity: 1;
202
- --color-bg: var(--bg-sunken);
203
- background: var(--color-bg);
204
- }
272
+ @mixin table-header-btn-base {
273
+ width: 1.75rem;
274
+ height: 1.75rem;
275
+ display: inline-flex;
276
+ align-items: center;
277
+ justify-content: center;
278
+ padding: 0;
279
+ border-radius: 50%;
280
+ background: transparent;
281
+ border: none;
282
+ color: inherit;
283
+ cursor: pointer;
284
+ box-shadow: none;
285
+ opacity: 0.45;
286
+ transition: all 0.15s ease-in-out;
287
+
288
+ &:hover {
289
+ background-color: hsl(var(--color-primary) / 0.12);
290
+ color: hsl(var(--color-primary));
291
+ opacity: 1;
292
+ }
293
+ }
294
+
295
+ @mixin table-filter {
296
+ @include table-header-btn-base;
297
+ vertical-align: middle;
298
+ position: relative;
299
+ }
300
+
301
+ @mixin table-filter-active {
302
+ opacity: 1;
303
+ color: var(--color-accent);
304
+
305
+ &::after {
306
+ content: '';
307
+ @include absolute;
308
+ top: 0;
309
+ right: 0;
310
+ width: 0.375rem;
311
+ height: 0.375rem;
312
+ border-radius: var(--radius-full);
313
+ background: var(--color-accent);
205
314
  }
315
+ }
316
+
317
+
318
+
319
+
206
320
 
207
- th [data-ln-dropdown] {
208
- float: right;
321
+ @mixin table-row-action {
322
+ background: none;
323
+ border: none;
324
+ --shadow: none;
325
+ --btn-padding-y: var(--size-2xs);
326
+ --btn-padding-x: var(--size-2xs);
327
+ opacity: 0.5;
328
+ @include motion-safe {
329
+ transition: opacity 0.15s;
209
330
  }
210
331
 
211
- th[data-ln-filter-active] .filter {
332
+ &:hover:not(:disabled) {
333
+ background: none;
212
334
  opacity: 1;
213
- color: var(--color-accent);
214
335
  }
215
336
  }
337
+
338
+ @mixin table-row-action-delete {
339
+ --color-primary: var(--color-error);
340
+ color: hsl(var(--color-primary));
341
+ }
342
+
343
+ @mixin table-row {
344
+ cursor: pointer;
345
+
346
+ &:hover {
347
+ --color-bg: var(--bg-sunken);
348
+ background: var(--color-bg);
349
+ }
350
+ }
351
+
352
+ @mixin table-row-selected {
353
+ background: var(--color-accent-tint);
354
+ }
355
+
356
+ @mixin table-row-focused {
357
+ --color-accent-focus: hsl(from var(--color-accent) h s calc(l + 8));
358
+ outline: 2px solid var(--color-accent-focus);
359
+ outline-offset: -2px;
360
+ }
361
+
362
+ @mixin table-spacer-row {
363
+ td {
364
+ padding: 0 !important;
365
+ border: none !important;
366
+ }
367
+ }
368
+
369
+ @mixin table-row-actions {
370
+ display: flex;
371
+ align-items: center;
372
+ gap: var(--size-xs);
373
+ position: absolute;
374
+ right: var(--padding-x, 1rem);
375
+ top: 50%;
376
+ transform: translateY(-50%);
377
+ opacity: 0;
378
+ pointer-events: none;
379
+ visibility: hidden;
380
+ transition: opacity var(--transition-fast, 0.15s) ease-in-out, visibility var(--transition-fast, 0.15s);
381
+ background: var(--bg-row-hover, var(--color-bg));
382
+ padding-left: var(--size-md);
383
+ margin: 0;
384
+ list-style: none;
385
+ z-index: 2;
386
+
387
+ &::before {
388
+ content: '';
389
+ position: absolute;
390
+ top: 0;
391
+ bottom: 0;
392
+ left: -2rem;
393
+ width: 2rem;
394
+ background: linear-gradient(to right, transparent, var(--bg-row-hover, var(--color-bg)));
395
+ pointer-events: none;
396
+ }
397
+
398
+ li {
399
+ display: inline-flex;
400
+ align-items: center;
401
+ }
402
+
403
+ form {
404
+ display: inline-flex;
405
+ margin: 0;
406
+ }
407
+ }
408
+
409
+
@@ -1,152 +1,179 @@
1
- @use 'display' as *;
2
- @use 'spacing' as *;
3
- @use 'sizing' as *;
4
- @use 'typography' as *;
5
- @use 'colors' as *;
6
- @use 'borders' as *;
7
- @use 'shadows' as *;
8
- @use 'position' as *;
9
- @use 'transitions' as *;
10
- @use 'interaction' as *;
11
- @use 'motion' as *;
12
- @use 'btn' as *;
13
- @use 'card' as *;
14
-
15
- // Toast notification -- side-accent card with icon, title, body, close button.
16
- //
17
- // Usage:
18
- // [data-ln-toast] { @include toast-container; }
19
- // .ln-toast__card { @include toast-card; }
20
- //
21
- // Color: attach .success/.error/.warning/.info utility class on the card to cascade --color-accent.
22
-
23
- @mixin toast-container {
24
- @include fixed;
25
- @include z-toast;
26
- list-style: none;
27
- padding: 0;
28
- margin: 0;
29
- pointer-events: none;
30
- // Viewport-edge offsets — toast container distance from viewport,
31
- // not shell rhythm.
32
- right: var(--size-lg);
33
- bottom: var(--size-lg);
34
- display: flex;
35
- flex-direction: column-reverse;
36
- }
37
-
38
- @mixin toast-item {
39
- list-style: none;
40
- opacity: 0;
41
- pointer-events: auto;
42
- @include motion-safe {
43
- transform: translateX(30px);
44
- transition: all var(--transition-base) var(--easing-standard);
45
- }
46
-
47
- & + & {
48
- --margin-block: var(--size-md);
49
- margin-bottom: var(--margin-block);
50
- }
51
- }
52
-
53
- @mixin toast-item-in {
54
- opacity: 1;
55
- @include motion-safe {
56
- transform: translateX(0);
57
- }
58
- }
59
-
60
- @mixin toast-item-out {
61
- opacity: 0 !important;
62
- @include motion-safe {
63
- transform: scale(0.95) !important;
64
- transition: all var(--transition-fast) !important;
65
- }
66
- }
67
-
68
- @mixin toast-card {
69
- @include floating-panel;
70
- @include flex;
71
- min-width: 320px;
72
- max-width: 450px;
73
- @include overflow-hidden;
74
- }
75
-
76
- @mixin toast-side {
77
- --color-accent: hsl(var(--color-primary));
78
- --color-accent-fg: hsl(var(--color-white));
79
- flex: 0 0 44px;
80
- @include flex;
81
- align-items: flex-start;
82
- @include justify-center;
83
- --padding-y: var(--size-md);
84
- padding-top: var(--padding-y);
85
- background: var(--color-accent);
86
- color: var(--color-accent-fg);
87
-
88
- &::before {
89
- width: 2rem;
90
- height: 2rem;
91
- }
92
- }
93
-
94
- @mixin toast-content {
95
- @include flex-1;
96
- --padding-y: var(--size-md);
97
- --padding-x: var(--size-md);
98
- padding: var(--padding-y) var(--padding-x) var(--padding-y) var(--size-sm); // 4th arm: icon-side gutter, component-design intrinsic.
99
- @include relative;
100
-
101
- .ln-toast__close {
102
- --btn-padding-y: var(--size-2xs);
103
- --btn-padding-x: var(--size-2xs);
104
- @include absolute;
105
- // Geometric — close button positioned inside content padding.
106
- top: var(--size-sm);
107
- right: var(--size-sm);
108
- }
109
- }
110
-
111
- // ─── Header & close ────────────────────────────────────
112
-
113
- @mixin toast-head {
114
- @include flex;
115
- align-items: flex-start;
116
- @include justify-between;
117
- --gap: var(--size-md);
118
- gap: var(--gap);
119
- }
120
-
121
- @mixin toast-title {
122
- @include font-bold;
123
- @include text-base;
124
- color: var(--color-fg);
125
- line-height: 1.25;
126
- }
127
-
128
- // ─── Body ──────────────────────────────────────────────
129
-
130
- @mixin toast-body {
131
- --color-fg: var(--fg-muted);
132
- --margin-block: var(--size-sm);
133
- margin-top: var(--margin-block);
134
- font-size: var(--text-base);
135
- color: var(--color-fg);
136
- line-height: 1.5;
137
-
138
- p { @include m(0); }
139
-
140
- ul {
141
- --margin-block: var(--size-sm);
142
- margin: var(--margin-block) 0 0 0;
143
- --padding-x: var(--size-md-up);
144
- padding-left: var(--padding-x);
145
- @include text-sm;
146
- }
147
-
148
- li + li {
149
- --margin-block: var(--size-xs);
150
- margin-top: var(--margin-block);
151
- }
152
- }
1
+ @use 'display' as *;
2
+ @use 'spacing' as *;
3
+ @use 'sizing' as *;
4
+ @use 'typography' as *;
5
+ @use 'colors' as *;
6
+ @use 'borders' as *;
7
+ @use 'shadows' as *;
8
+ @use 'position' as *;
9
+ @use 'transitions' as *;
10
+ @use 'interaction' as *;
11
+ @use 'motion' as *;
12
+ @use 'btn' as *;
13
+ @use 'card' as *;
14
+ @use 'breakpoints' as *;
15
+
16
+ // Toast notification -- side-accent card with icon, title, body, close button.
17
+ // The <li> IS the card; the type IS its class (.success/.error/.warn/.info).
18
+ //
19
+ // Usage:
20
+ // [data-ln-toast] { @include toast-container; }
21
+ // [data-ln-toast] > li { @include toast-item; @include toast-card; }
22
+ //
23
+ // Tone: the type class on the <li> rebinds --color-primary/--color-accent via
24
+ // semantic-color() — see components/_toast.scss. SSR authors the class; the
25
+ // dynamic path fills it (data-ln-attr="class:type"). warn maps to the warning
26
+ // family in that binding.
27
+
28
+ @mixin toast-container {
29
+ @include fixed;
30
+ @include z-toast;
31
+ border: none;
32
+ background: transparent;
33
+ inset: auto;
34
+ right: var(--size-lg);
35
+ bottom: var(--size-lg);
36
+ list-style: none;
37
+ padding: 0;
38
+ margin: 0;
39
+ pointer-events: none;
40
+ display: flex;
41
+ flex-direction: column-reverse;
42
+ overflow: visible;
43
+
44
+ &:popover-open {
45
+ display: flex;
46
+ }
47
+
48
+ @include mq-down(md) {
49
+ right: 0;
50
+ bottom: 0;
51
+ left: 0;
52
+ }
53
+ }
54
+
55
+ // Base = final visible resting state, so SSR-authored <li> render with
56
+ // zero JS. .ln-enter (below) is a transient pre-mount override applied
57
+ // only to JS-created items — see ln-toast.js _buildItem/_append.
58
+ @mixin toast-item {
59
+ list-style: none;
60
+ pointer-events: auto;
61
+ opacity: 1;
62
+ @include motion-safe {
63
+ transform: translateX(0);
64
+ transition: all var(--transition-base) var(--easing-standard);
65
+ }
66
+
67
+ & + & {
68
+ --margin-block: var(--size-md);
69
+ margin-bottom: var(--margin-block);
70
+ }
71
+ }
72
+
73
+ @mixin toast-item-enter {
74
+ opacity: 0;
75
+ @include motion-safe {
76
+ transform: translateX(30px);
77
+ }
78
+ }
79
+
80
+ @mixin toast-item-out {
81
+ opacity: 0 !important;
82
+ @include motion-safe {
83
+ transform: scale(0.95) !important;
84
+ transition: all var(--transition-fast) !important;
85
+ }
86
+ }
87
+
88
+ @mixin toast-card {
89
+ @include floating-panel;
90
+ @include flex;
91
+ min-width: 320px;
92
+ max-width: 450px;
93
+ @include overflow-hidden;
94
+
95
+ @include mq-down(md) {
96
+ min-width: 0;
97
+ max-width: none;
98
+ width: 100%;
99
+ border-radius: 0;
100
+ border-inline: 0;
101
+ border-block-end: 0;
102
+ }
103
+ }
104
+
105
+ @mixin toast-icon {
106
+ --color-accent: hsl(var(--color-primary));
107
+ --color-accent-fg: hsl(var(--color-white));
108
+ flex: 0 0 44px;
109
+ @include flex;
110
+ align-items: flex-start;
111
+ @include justify-center;
112
+ --padding-y: var(--size-md);
113
+ padding-top: var(--padding-y);
114
+ background: var(--color-accent);
115
+ color: var(--color-accent-fg);
116
+
117
+ &::before {
118
+ width: 2rem;
119
+ height: 2rem;
120
+ }
121
+ }
122
+
123
+ // The icon variant list — 4 authored icons, CSS shows the one matching the
124
+ // card's type class (see components/_toast.scss for the when-toggle).
125
+ // display:contents dissolves the <ul> box so the visible <li> becomes a direct
126
+ // flex child of .icon (parity with the SSR path's direct <svg> child).
127
+ @mixin toast-icon-list {
128
+ display: contents;
129
+
130
+ > li { @include hidden; }
131
+ }
132
+
133
+ @mixin toast-content {
134
+ @include flex-1;
135
+ --padding-y: var(--size-md);
136
+ --padding-x: var(--size-md);
137
+ padding: var(--padding-y) var(--padding-x) var(--padding-y) var(--size-sm); // 4th arm: icon-side gutter, component-design intrinsic.
138
+ @include relative;
139
+
140
+ button[data-ln-toast-close] {
141
+ --btn-padding-y: var(--size-2xs);
142
+ --btn-padding-x: var(--size-2xs);
143
+ @include absolute;
144
+ // Geometric — close button positioned inside content padding.
145
+ top: var(--size-sm);
146
+ right: var(--size-sm);
147
+ }
148
+ }
149
+
150
+ @mixin toast-title {
151
+ @include font-bold;
152
+ @include text-base;
153
+ color: var(--color-fg);
154
+ line-height: 1.25;
155
+ }
156
+
157
+ @mixin toast-body {
158
+ --color-fg: var(--fg-muted);
159
+ --margin-block: var(--size-sm);
160
+ margin-top: var(--margin-block);
161
+ font-size: var(--text-base);
162
+ color: var(--color-fg);
163
+ line-height: 1.5;
164
+
165
+ p { @include m(0); }
166
+
167
+ ul {
168
+ --margin-block: var(--size-sm);
169
+ margin: var(--margin-block) 0 0 0;
170
+ --padding-x: var(--size-md-up);
171
+ padding-left: var(--padding-x);
172
+ @include text-sm;
173
+ }
174
+
175
+ li + li {
176
+ --margin-block: var(--size-xs);
177
+ margin-top: var(--margin-block);
178
+ }
179
+ }