@livenetworks/ashlar 1.5.1 → 1.6.1

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 (217) 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 +165 -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 +82 -42
  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 +92 -2
  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 -56
  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 -25
  173. package/scss/components/_form.scss +7 -0
  174. package/scss/components/_ln-table.scss +13 -3
  175. package/scss/components/_sort.scss +10 -0
  176. package/scss/components/_table.scss +36 -23
  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 +11 -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 +3 -5
  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 +2 -0
  198. package/scss/config/mixins/_ln-table.scss +41 -2
  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 +85 -60
  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 +27 -9
  209. package/scss/ln-ashlar.scss +7 -1
  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 -1087
  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 -156
@@ -2,11 +2,15 @@
2
2
  @use 'borders' as *;
3
3
  @use 'motion' as *;
4
4
  @use 'card' as *;
5
+ @use 'form' as *;
6
+ @use 'focus' as *;
5
7
 
6
8
  @mixin popover {
7
9
  @include floating-panel;
8
10
  display: none;
9
11
  position: fixed;
12
+ inset: auto;
13
+ margin: 0;
10
14
  min-width: 14rem;
11
15
  max-width: 24rem;
12
16
  padding: var(--padding-y) var(--padding-x);
@@ -22,4 +26,39 @@
22
26
  &:focus {
23
27
  outline: none;
24
28
  }
29
+
30
+ // Filter popover content: optional search + checkbox option list
31
+ > input[type="search"] {
32
+ width: 100%;
33
+ margin-bottom: var(--size-xs);
34
+ box-sizing: border-box;
35
+ }
36
+
37
+ > ul {
38
+ list-style: none;
39
+ padding: 0;
40
+ margin: 0;
41
+ max-height: var(--filter-options-max-height, 15rem);
42
+ overflow-y: auto;
43
+
44
+ // Nav-link treatment for filter options (accent-tint wash on checked).
45
+ // Visually-hidden input (below) keeps the checkbox keyboard-focusable.
46
+ @include check-list-nav;
47
+
48
+ > li > label > input {
49
+ // Override pill's display:none — keep in focus order for keyboard nav
50
+ display: revert;
51
+ position: absolute;
52
+ width: 1px;
53
+ height: 1px;
54
+ overflow: hidden;
55
+ clip-path: inset(50%);
56
+ white-space: nowrap;
57
+ }
58
+
59
+ // Focus ring on label when the hidden input receives keyboard focus
60
+ > li > label:has(> input:focus-visible) {
61
+ @include focus-ring;
62
+ }
63
+ }
25
64
  }
@@ -75,7 +75,7 @@
75
75
 
76
76
  // Search field drops to a full-width second row below the
77
77
  // brand triad (enabled by `flex-wrap` above).
78
- > [data-ln-search] {
78
+ > .sidebar-search {
79
79
  @include w-full;
80
80
  --margin-block: var(--size-xs);
81
81
  @include mt(var(--margin-block));
@@ -0,0 +1,42 @@
1
+ @use 'display' as *;
2
+ @use 'table' as *;
3
+
4
+ // ─── Sort control — 3-trigger cycle (none → asc → desc → none) ─────────
5
+ // Only one <button data-ln-sort-dir> is visible at a time; the circular
6
+ // order lives HERE in CSS, not in JS (js/ln-sort/README.md "No cycle
7
+ // logic in JS"). [data-ln-sort-state] on the root decides which trigger
8
+ // shows — the visible button is always the NEXT action, but the icon it
9
+ // carries reports the CURRENT state, not that action (icon-per-button
10
+ // mapping: js/ln-sort/README.md "Icon convention").
11
+
12
+ @mixin sort {
13
+ @include inline-flex;
14
+ list-style: none !important;
15
+ list-style-type: none !important;
16
+ margin: 0;
17
+ padding: 0;
18
+ vertical-align: middle;
19
+
20
+ li {
21
+ list-style: none !important;
22
+ list-style-type: none !important;
23
+ }
24
+
25
+ button {
26
+ @include table-header-btn-base;
27
+ display: none;
28
+ }
29
+
30
+ &[data-ln-sort-state="none"] [data-ln-sort-dir="asc"],
31
+ &[data-ln-sort-state="asc"] [data-ln-sort-dir="desc"],
32
+ &[data-ln-sort-state="desc"] [data-ln-sort-dir="none"] {
33
+ display: inline-flex;
34
+ }
35
+ }
36
+
37
+ @mixin sort-active {
38
+ [data-ln-sort-dir] {
39
+ opacity: 1;
40
+ color: var(--color-accent);
41
+ }
42
+ }
@@ -36,13 +36,9 @@
36
36
  }
37
37
  font-variant-numeric: tabular-nums;
38
38
 
39
- // Row hover transition color. Sticky/enhanced tables use a relative lightness calculation
40
- // to make the hovered row visually distinct from --bg-sunken chrome headers/footers.
41
- $bg-hover: var(--bg-sunken);
42
- @if $sticky {
43
- $bg-hover: hsl(from var(--bg-base) h s calc(l - 4));
44
- }
45
- --bg-row-hover: #{$bg-hover};
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));
46
42
 
47
43
  thead {
48
44
  --color-bg: var(--bg-sunken);
@@ -63,58 +59,58 @@
63
59
 
64
60
  th {
65
61
  @include text-left;
66
- padding: var(--padding-y) var(--padding-x);
62
+ padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
67
63
  @include font-semibold;
68
- font-size: var(--text-label-sm);
69
- line-height: var(--line-height);
70
- letter-spacing: 0.4px;
64
+ @include typography(label-sm);
65
+ letter-spacing: 0.06em;
71
66
  @include uppercase;
72
67
  color: var(--color-fg);
73
68
  position: relative;
74
69
  top: auto;
75
70
  z-index: auto;
76
71
 
77
- // Shared header-button stack — keyed off the unprefixed structural button classes,
78
- // so table / ln-table / ln-data-table all share one positioning rule.
79
- &:has(.table-sort):has(.table-filter) {
80
- padding-inline-end: calc(var(--padding-x) + 2.5rem);
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);
81
77
 
82
78
  .table-filter {
83
79
  position: absolute;
84
80
  top: 50%;
85
81
  transform: translateY(-50%);
86
- right: var(--padding-x);
82
+ right: var(--padding-x, var(--size-md));
87
83
  margin: 0;
88
84
  }
89
- .table-sort {
85
+ [data-ln-sort] {
90
86
  position: absolute;
91
87
  top: 50%;
92
88
  transform: translateY(-50%);
93
- right: calc(var(--padding-x) + 1.25rem);
89
+ right: calc(var(--padding-x, var(--size-md)) + 1.75rem);
94
90
  margin: 0;
95
91
  }
96
92
  }
97
93
 
98
- &:has(.table-sort):not(:has(.table-filter)) {
99
- padding-inline-end: calc(var(--padding-x) + 1.25rem);
94
+ &:has([data-ln-sort]):not(:has(.table-filter)) {
95
+ padding-inline-end: calc(var(--padding-x, var(--size-md)) + 2rem);
100
96
 
101
- .table-sort {
97
+ [data-ln-sort] {
102
98
  position: absolute;
103
99
  top: 50%;
104
100
  transform: translateY(-50%);
105
- right: var(--padding-x);
101
+ right: var(--padding-x, var(--size-md));
106
102
  margin: 0;
107
103
  }
108
104
  }
109
105
 
110
- &:has(.table-filter):not(:has(.table-sort)) {
111
- padding-inline-end: calc(var(--padding-x) + 1.25rem);
106
+ &:has(.table-filter):not(:has([data-ln-sort])) {
107
+ padding-inline-end: calc(var(--padding-x, var(--size-md)) + 2rem);
112
108
 
113
109
  .table-filter {
114
110
  position: absolute;
115
111
  top: 50%;
116
112
  transform: translateY(-50%);
117
- right: var(--padding-x);
113
+ right: var(--padding-x, var(--size-md));
118
114
  margin: 0;
119
115
  }
120
116
  }
@@ -131,7 +127,7 @@
131
127
  }
132
128
 
133
129
  td {
134
- padding: var(--padding-y) var(--padding-x);
130
+ padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
135
131
  @include border-b;
136
132
  font-size: var(--font-size);
137
133
  line-height: var(--line-height);
@@ -161,13 +157,13 @@
161
157
  // Sticky section footer inside sticky/enhanced tables
162
158
  @if $sticky {
163
159
  > footer {
164
- padding: var(--padding-y) var(--padding-x);
160
+ padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
165
161
  border-block-start: var(--border-block-start, var(--border-width) solid var(--color-border));
166
162
  --color-bg: var(--bg-sunken);
167
163
  background: var(--color-bg);
168
164
  --color-fg: var(--fg-muted);
169
165
  color: var(--color-fg);
170
- font-size: var(--text-body-sm);
166
+ @include typography(body-sm);
171
167
  position: sticky;
172
168
  z-index: var(--z-sticky);
173
169
  }
@@ -273,45 +269,33 @@
273
269
 
274
270
  // ─── Column sort & filter buttons ──────────────────────────────
275
271
 
276
- @mixin table-sort {
277
- opacity: 0.4;
278
- @include motion-safe {
279
- transition: opacity 0.15s;
280
- }
281
- @include cursor-pointer;
282
- background: none;
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;
283
281
  border: none;
284
- --btn-padding-y: var(--size-2xs);
285
- --btn-padding-x: var(--size-2xs);
286
- --margin-inline: var(--size-xs);
287
- margin-inline-start: var(--margin-inline);
288
- vertical-align: middle;
282
+ color: inherit;
283
+ cursor: pointer;
284
+ box-shadow: none;
285
+ opacity: 0.45;
286
+ transition: all 0.15s ease-in-out;
289
287
 
290
- [data-ln-sort-icon="asc"],
291
- [data-ln-sort-icon="desc"] {
292
- display: none;
288
+ &:hover {
289
+ background-color: hsl(var(--color-primary) / 0.12);
290
+ color: hsl(var(--color-primary));
291
+ opacity: 1;
293
292
  }
294
293
  }
295
294
 
296
- @mixin table-sort-active {
297
- opacity: 1;
298
- color: var(--color-accent);
299
- }
300
-
301
295
  @mixin table-filter {
302
- opacity: 0.4;
303
- @include motion-safe {
304
- transition: opacity 0.15s;
305
- }
306
- @include cursor-pointer;
307
- background: none;
308
- border: none;
309
- --btn-padding-y: var(--size-2xs);
310
- --btn-padding-x: var(--size-2xs);
311
- --margin-inline: var(--size-2xs);
312
- margin-inline-start: var(--margin-inline);
296
+ @include table-header-btn-base;
313
297
  vertical-align: middle;
314
- @include relative;
298
+ position: relative;
315
299
  }
316
300
 
317
301
  @mixin table-filter-active {
@@ -382,3 +366,44 @@
382
366
  }
383
367
  }
384
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
+ }