@mk-kit/ui 0.54.0 → 0.55.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.
- package/README.md +21 -0
- package/fesm2022/mk-kit-ui-core.mjs +2 -0
- package/fesm2022/mk-kit-ui-core.mjs.map +1 -1
- package/fesm2022/mk-kit-ui-dnd.mjs +339 -27
- package/fesm2022/mk-kit-ui-dnd.mjs.map +1 -1
- package/fesm2022/mk-kit-ui-locales-de.mjs +2 -0
- package/fesm2022/mk-kit-ui-locales-de.mjs.map +1 -1
- package/fesm2022/mk-kit-ui-locales-es.mjs +2 -0
- package/fesm2022/mk-kit-ui-locales-es.mjs.map +1 -1
- package/fesm2022/mk-kit-ui-locales-fr.mjs +2 -0
- package/fesm2022/mk-kit-ui-locales-fr.mjs.map +1 -1
- package/fesm2022/mk-kit-ui-locales-pl.mjs +2 -0
- package/fesm2022/mk-kit-ui-locales-pl.mjs.map +1 -1
- package/fesm2022/mk-kit-ui-locales-uk.mjs +2 -0
- package/fesm2022/mk-kit-ui-locales-uk.mjs.map +1 -1
- package/fesm2022/mk-kit-ui-translate-server.mjs +55 -0
- package/fesm2022/mk-kit-ui-translate-server.mjs.map +1 -0
- package/fesm2022/mk-kit-ui-translate.mjs +504 -0
- package/fesm2022/mk-kit-ui-translate.mjs.map +1 -0
- package/fesm2022/mk-kit-ui.mjs +1 -0
- package/fesm2022/mk-kit-ui.mjs.map +1 -1
- package/package.json +13 -1
- package/styles/presets/momentum.css +272 -0
- package/types/mk-kit-ui-core.d.ts +4 -0
- package/types/mk-kit-ui-dnd.d.ts +178 -6
- package/types/mk-kit-ui-translate-server.d.ts +39 -0
- package/types/mk-kit-ui-translate.d.ts +275 -0
- package/types/mk-kit-ui.d.ts +1 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/* =========================================================================
|
|
2
|
+
* Momentum — a warm, high-energy preset
|
|
3
|
+
* -------------------------------------------------------------------------
|
|
4
|
+
* The look of the Momentum task app: Manrope set heavy and tight, soft
|
|
5
|
+
* violet-grey surfaces, generous radii, feather-light card shadows and an
|
|
6
|
+
* indigo accent that is meant to be swapped at runtime (see below).
|
|
7
|
+
*
|
|
8
|
+
* import '@mk-kit/ui/styles.css';
|
|
9
|
+
* import '@mk-kit/ui/presets/momentum.css';
|
|
10
|
+
* <html data-mk-preset="momentum">
|
|
11
|
+
*
|
|
12
|
+
* Works on <html> for the whole app or on any subtree — these are plain
|
|
13
|
+
* custom properties, they inherit. Light and dark resolve with the same
|
|
14
|
+
* precedence as the base theme (`data-mk-theme`, else the OS). The preset
|
|
15
|
+
* steps aside for `data-mk-contrast="high"`: the high-contrast values are
|
|
16
|
+
* tuned for legibility and the preset never overrides them.
|
|
17
|
+
*
|
|
18
|
+
* The preset sets the font family but does not load it. Load Manrope
|
|
19
|
+
* yourself (Google Fonts, weights 500–800) or the stack falls back to the
|
|
20
|
+
* system sans without complaint.
|
|
21
|
+
*
|
|
22
|
+
* Accent swapping — the app changes its accent at runtime by writing
|
|
23
|
+
* `--mk-primary`, `--mk-primary-hover`, `--mk-primary-active`,
|
|
24
|
+
* `--mk-primary-subtle`, `--mk-primary-subtle-hover`,
|
|
25
|
+
* `--mk-primary-subtle-text`, `--mk-focus-ring`, `--mk-selected-bg` and
|
|
26
|
+
* `--mk-selected-text` on the same element. Everything else stays.
|
|
27
|
+
*
|
|
28
|
+
* Every text/surface pair the base theme holds to WCAG AA is held to AA here
|
|
29
|
+
* too (`contrast-smoke.spec.ts` reads this file as well).
|
|
30
|
+
* ========================================================================= */
|
|
31
|
+
/* Theme-independent: type, geometry, elevation shape, motion. */
|
|
32
|
+
/* Light (default) + the theme-independent tokens. */
|
|
33
|
+
[data-mk-preset=momentum]:not([data-mk-contrast=high]) {
|
|
34
|
+
color-scheme: light;
|
|
35
|
+
--mk-font-sans: 'Manrope', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
36
|
+
--mk-font-weight-normal: 500;
|
|
37
|
+
--mk-font-weight-medium: 600;
|
|
38
|
+
--mk-font-weight-semibold: 700;
|
|
39
|
+
--mk-font-weight-bold: 800;
|
|
40
|
+
--mk-line-height-tight: 1.18;
|
|
41
|
+
--mk-line-height-snug: 1.28;
|
|
42
|
+
--mk-line-height-normal: 1.5;
|
|
43
|
+
--mk-letter-spacing-tight: -0.02em;
|
|
44
|
+
--mk-letter-spacing-wide: 0.12em;
|
|
45
|
+
--mk-radius-xs: 5px;
|
|
46
|
+
--mk-radius-sm: 8px;
|
|
47
|
+
--mk-radius-md: 11px;
|
|
48
|
+
--mk-radius-lg: 13px;
|
|
49
|
+
--mk-radius-xl: 16px;
|
|
50
|
+
--mk-radius-2xl: 20px;
|
|
51
|
+
--mk-duration-fast: 150ms;
|
|
52
|
+
--mk-duration-normal: 220ms;
|
|
53
|
+
--mk-duration-slow: 360ms;
|
|
54
|
+
--mk-ease-emphasized: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
55
|
+
--mk-bg: #f4f4f8;
|
|
56
|
+
--mk-surface: #ffffff;
|
|
57
|
+
--mk-surface-2: #fbfbfe;
|
|
58
|
+
--mk-surface-3: #f4f4f9;
|
|
59
|
+
--mk-surface-inverse: #16161f;
|
|
60
|
+
--mk-overlay-scrim: rgba(22, 22, 31, 0.45);
|
|
61
|
+
--mk-text: #16161f;
|
|
62
|
+
--mk-text-muted: #42424f;
|
|
63
|
+
--mk-text-subtle: #6e6e82;
|
|
64
|
+
--mk-text-inverse: #ffffff;
|
|
65
|
+
--mk-text-disabled: #a9a9ba;
|
|
66
|
+
--mk-border: #ececf2;
|
|
67
|
+
--mk-border-strong: #d6d6e0;
|
|
68
|
+
--mk-border-subtle: #f1f1f6;
|
|
69
|
+
--mk-hover-overlay: rgba(22, 22, 31, 0.04);
|
|
70
|
+
--mk-active-overlay: rgba(22, 22, 31, 0.08);
|
|
71
|
+
--mk-selected-bg: #ebeafb;
|
|
72
|
+
--mk-selected-text: #4a3fc9;
|
|
73
|
+
--mk-primary: #5b4fe0;
|
|
74
|
+
--mk-primary-hover: #4f43d1;
|
|
75
|
+
--mk-primary-active: #4338be;
|
|
76
|
+
--mk-primary-contrast: #ffffff;
|
|
77
|
+
--mk-primary-subtle: #ebeafb;
|
|
78
|
+
--mk-primary-subtle-hover: #dedcf8;
|
|
79
|
+
--mk-primary-subtle-text: #4a3fc9;
|
|
80
|
+
--mk-success: #168553;
|
|
81
|
+
--mk-success-hover: #137548;
|
|
82
|
+
--mk-success-contrast: #ffffff;
|
|
83
|
+
--mk-success-subtle: #e4f6ee;
|
|
84
|
+
--mk-success-subtle-text: #136e47;
|
|
85
|
+
--mk-warning: #a8660e;
|
|
86
|
+
--mk-warning-hover: #93590c;
|
|
87
|
+
--mk-warning-contrast: #ffffff;
|
|
88
|
+
--mk-warning-subtle: #fbf1e1;
|
|
89
|
+
--mk-warning-subtle-text: #7f4e0b;
|
|
90
|
+
--mk-danger: #d4433a;
|
|
91
|
+
--mk-danger-hover: #bf3a32;
|
|
92
|
+
--mk-danger-contrast: #ffffff;
|
|
93
|
+
--mk-danger-text: #c43d33;
|
|
94
|
+
--mk-danger-subtle: #fce9e7;
|
|
95
|
+
--mk-danger-subtle-text: #a8322a;
|
|
96
|
+
--mk-info: #2568d6;
|
|
97
|
+
--mk-info-hover: #1f58b8;
|
|
98
|
+
--mk-info-contrast: #ffffff;
|
|
99
|
+
--mk-info-subtle: #e6effd;
|
|
100
|
+
--mk-info-subtle-text: #1b4e9e;
|
|
101
|
+
--mk-neutral-subtle: #f4f4f9;
|
|
102
|
+
--mk-neutral-subtle-hover: #eaeaf1;
|
|
103
|
+
--mk-neutral-subtle-text: #42424f;
|
|
104
|
+
--mk-focus-ring: #5b4fe0;
|
|
105
|
+
--mk-shadow-xs: 0 1px 2px rgba(22, 22, 31, 0.05);
|
|
106
|
+
--mk-shadow-sm: 0 2px 6px rgba(22, 22, 31, 0.05);
|
|
107
|
+
--mk-shadow-md: 0 8px 18px rgba(22, 22, 31, 0.12);
|
|
108
|
+
--mk-shadow-lg: 0 22px 50px rgba(22, 22, 31, 0.22);
|
|
109
|
+
--mk-shadow-xl: 0 32px 70px rgba(22, 22, 31, 0.4);
|
|
110
|
+
--mk-skeleton-base: #ececf2;
|
|
111
|
+
--mk-skeleton-shine: #f7f7fb;
|
|
112
|
+
--mk-scrollbar-thumb: #ececf2;
|
|
113
|
+
--mk-scrollbar-thumb-hover: #d6d6e0;
|
|
114
|
+
--mk-code-bg: #f4f4f9;
|
|
115
|
+
--mk-chart-1: #5b4fe0;
|
|
116
|
+
--mk-chart-2: #1faa6e;
|
|
117
|
+
--mk-chart-3: #ff6b5c;
|
|
118
|
+
--mk-chart-4: #e0982e;
|
|
119
|
+
--mk-chart-5: #a85cd6;
|
|
120
|
+
--mk-chart-6: #3aafa9;
|
|
121
|
+
--mk-chart-7: #d85c8a;
|
|
122
|
+
--mk-chart-8: #6e8bff;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Auto (OS) dark, unless explicitly overridden to light. */
|
|
126
|
+
@media (prefers-color-scheme: dark) {
|
|
127
|
+
:root:not([data-mk-theme=light]) [data-mk-preset=momentum]:not([data-mk-contrast=high]),
|
|
128
|
+
:root:not([data-mk-theme=light])[data-mk-preset=momentum]:not([data-mk-contrast=high]) {
|
|
129
|
+
color-scheme: dark;
|
|
130
|
+
--mk-bg: #0d0d13;
|
|
131
|
+
--mk-surface: #1b1b25;
|
|
132
|
+
--mk-surface-2: #14141c;
|
|
133
|
+
--mk-surface-3: #23232f;
|
|
134
|
+
--mk-surface-inverse: #f3f3f8;
|
|
135
|
+
--mk-overlay-scrim: rgba(0, 0, 0, 0.6);
|
|
136
|
+
--mk-text: #f3f3f8;
|
|
137
|
+
--mk-text-muted: #c3c3cf;
|
|
138
|
+
--mk-text-subtle: #8e8ea2;
|
|
139
|
+
--mk-text-inverse: #14141c;
|
|
140
|
+
--mk-text-disabled: #5c5c70;
|
|
141
|
+
--mk-border: #2a2a38;
|
|
142
|
+
--mk-border-strong: #3a3a4c;
|
|
143
|
+
--mk-border-subtle: #22222e;
|
|
144
|
+
--mk-hover-overlay: rgba(255, 255, 255, 0.05);
|
|
145
|
+
--mk-active-overlay: rgba(255, 255, 255, 0.09);
|
|
146
|
+
--mk-selected-bg: #26244a;
|
|
147
|
+
--mk-selected-text: #c9c3fa;
|
|
148
|
+
--mk-primary: #6d62ec;
|
|
149
|
+
--mk-primary-hover: #7f75f0;
|
|
150
|
+
--mk-primary-active: #918af4;
|
|
151
|
+
--mk-primary-contrast: #ffffff;
|
|
152
|
+
--mk-primary-subtle: #26244a;
|
|
153
|
+
--mk-primary-subtle-hover: #2f2c5c;
|
|
154
|
+
--mk-primary-subtle-text: #c9c3fa;
|
|
155
|
+
--mk-success: #2bc282;
|
|
156
|
+
--mk-success-hover: #4ed39a;
|
|
157
|
+
--mk-success-contrast: #06281a;
|
|
158
|
+
--mk-success-subtle: #123326;
|
|
159
|
+
--mk-success-subtle-text: #7ee2b3;
|
|
160
|
+
--mk-warning: #f0a93a;
|
|
161
|
+
--mk-warning-hover: #f5bb5c;
|
|
162
|
+
--mk-warning-contrast: #2a1a02;
|
|
163
|
+
--mk-warning-subtle: #33240f;
|
|
164
|
+
--mk-warning-subtle-text: #fbcf7a;
|
|
165
|
+
--mk-danger: #f06c62;
|
|
166
|
+
--mk-danger-hover: #f58a82;
|
|
167
|
+
--mk-danger-contrast: #2a0b09;
|
|
168
|
+
--mk-danger-text: #f58a82;
|
|
169
|
+
--mk-danger-subtle: #3a1a1a;
|
|
170
|
+
--mk-danger-subtle-text: #fca9a2;
|
|
171
|
+
--mk-info: #5b9cf9;
|
|
172
|
+
--mk-info-hover: #7cb1fb;
|
|
173
|
+
--mk-info-contrast: #04182e;
|
|
174
|
+
--mk-info-subtle: #12243c;
|
|
175
|
+
--mk-info-subtle-text: #a8ccfd;
|
|
176
|
+
--mk-neutral-subtle: #23232f;
|
|
177
|
+
--mk-neutral-subtle-hover: #2c2c3a;
|
|
178
|
+
--mk-neutral-subtle-text: #c3c3cf;
|
|
179
|
+
--mk-focus-ring: #8478f2;
|
|
180
|
+
--mk-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
181
|
+
--mk-shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.4);
|
|
182
|
+
--mk-shadow-md: 0 8px 18px rgba(0, 0, 0, 0.5);
|
|
183
|
+
--mk-shadow-lg: 0 22px 50px rgba(0, 0, 0, 0.55);
|
|
184
|
+
--mk-shadow-xl: 0 32px 70px rgba(0, 0, 0, 0.65);
|
|
185
|
+
--mk-skeleton-base: #23232f;
|
|
186
|
+
--mk-skeleton-shine: #2e2e3c;
|
|
187
|
+
--mk-scrollbar-thumb: #2a2a38;
|
|
188
|
+
--mk-scrollbar-thumb-hover: #3a3a4c;
|
|
189
|
+
--mk-code-bg: #23232f;
|
|
190
|
+
--mk-chart-1: #8478f2;
|
|
191
|
+
--mk-chart-2: #2fc07f;
|
|
192
|
+
--mk-chart-3: #ff7d70;
|
|
193
|
+
--mk-chart-4: #f0a93a;
|
|
194
|
+
--mk-chart-5: #bb7de3;
|
|
195
|
+
--mk-chart-6: #4dc2bc;
|
|
196
|
+
--mk-chart-7: #e5709c;
|
|
197
|
+
--mk-chart-8: #86a0ff;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/* Explicit dark. */
|
|
201
|
+
[data-mk-theme=dark] [data-mk-preset=momentum]:not([data-mk-contrast=high]),
|
|
202
|
+
[data-mk-preset=momentum]:not([data-mk-contrast=high])[data-mk-theme=dark] {
|
|
203
|
+
color-scheme: dark;
|
|
204
|
+
--mk-bg: #0d0d13;
|
|
205
|
+
--mk-surface: #1b1b25;
|
|
206
|
+
--mk-surface-2: #14141c;
|
|
207
|
+
--mk-surface-3: #23232f;
|
|
208
|
+
--mk-surface-inverse: #f3f3f8;
|
|
209
|
+
--mk-overlay-scrim: rgba(0, 0, 0, 0.6);
|
|
210
|
+
--mk-text: #f3f3f8;
|
|
211
|
+
--mk-text-muted: #c3c3cf;
|
|
212
|
+
--mk-text-subtle: #8e8ea2;
|
|
213
|
+
--mk-text-inverse: #14141c;
|
|
214
|
+
--mk-text-disabled: #5c5c70;
|
|
215
|
+
--mk-border: #2a2a38;
|
|
216
|
+
--mk-border-strong: #3a3a4c;
|
|
217
|
+
--mk-border-subtle: #22222e;
|
|
218
|
+
--mk-hover-overlay: rgba(255, 255, 255, 0.05);
|
|
219
|
+
--mk-active-overlay: rgba(255, 255, 255, 0.09);
|
|
220
|
+
--mk-selected-bg: #26244a;
|
|
221
|
+
--mk-selected-text: #c9c3fa;
|
|
222
|
+
--mk-primary: #6d62ec;
|
|
223
|
+
--mk-primary-hover: #7f75f0;
|
|
224
|
+
--mk-primary-active: #918af4;
|
|
225
|
+
--mk-primary-contrast: #ffffff;
|
|
226
|
+
--mk-primary-subtle: #26244a;
|
|
227
|
+
--mk-primary-subtle-hover: #2f2c5c;
|
|
228
|
+
--mk-primary-subtle-text: #c9c3fa;
|
|
229
|
+
--mk-success: #2bc282;
|
|
230
|
+
--mk-success-hover: #4ed39a;
|
|
231
|
+
--mk-success-contrast: #06281a;
|
|
232
|
+
--mk-success-subtle: #123326;
|
|
233
|
+
--mk-success-subtle-text: #7ee2b3;
|
|
234
|
+
--mk-warning: #f0a93a;
|
|
235
|
+
--mk-warning-hover: #f5bb5c;
|
|
236
|
+
--mk-warning-contrast: #2a1a02;
|
|
237
|
+
--mk-warning-subtle: #33240f;
|
|
238
|
+
--mk-warning-subtle-text: #fbcf7a;
|
|
239
|
+
--mk-danger: #f06c62;
|
|
240
|
+
--mk-danger-hover: #f58a82;
|
|
241
|
+
--mk-danger-contrast: #2a0b09;
|
|
242
|
+
--mk-danger-text: #f58a82;
|
|
243
|
+
--mk-danger-subtle: #3a1a1a;
|
|
244
|
+
--mk-danger-subtle-text: #fca9a2;
|
|
245
|
+
--mk-info: #5b9cf9;
|
|
246
|
+
--mk-info-hover: #7cb1fb;
|
|
247
|
+
--mk-info-contrast: #04182e;
|
|
248
|
+
--mk-info-subtle: #12243c;
|
|
249
|
+
--mk-info-subtle-text: #a8ccfd;
|
|
250
|
+
--mk-neutral-subtle: #23232f;
|
|
251
|
+
--mk-neutral-subtle-hover: #2c2c3a;
|
|
252
|
+
--mk-neutral-subtle-text: #c3c3cf;
|
|
253
|
+
--mk-focus-ring: #8478f2;
|
|
254
|
+
--mk-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
255
|
+
--mk-shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.4);
|
|
256
|
+
--mk-shadow-md: 0 8px 18px rgba(0, 0, 0, 0.5);
|
|
257
|
+
--mk-shadow-lg: 0 22px 50px rgba(0, 0, 0, 0.55);
|
|
258
|
+
--mk-shadow-xl: 0 32px 70px rgba(0, 0, 0, 0.65);
|
|
259
|
+
--mk-skeleton-base: #23232f;
|
|
260
|
+
--mk-skeleton-shine: #2e2e3c;
|
|
261
|
+
--mk-scrollbar-thumb: #2a2a38;
|
|
262
|
+
--mk-scrollbar-thumb-hover: #3a3a4c;
|
|
263
|
+
--mk-code-bg: #23232f;
|
|
264
|
+
--mk-chart-1: #8478f2;
|
|
265
|
+
--mk-chart-2: #2fc07f;
|
|
266
|
+
--mk-chart-3: #ff7d70;
|
|
267
|
+
--mk-chart-4: #f0a93a;
|
|
268
|
+
--mk-chart-5: #bb7de3;
|
|
269
|
+
--mk-chart-6: #4dc2bc;
|
|
270
|
+
--mk-chart-7: #e5709c;
|
|
271
|
+
--mk-chart-8: #86a0ff;
|
|
272
|
+
}
|
|
@@ -1130,6 +1130,10 @@ interface MkI18nStrings {
|
|
|
1130
1130
|
dndMovedToList: (list: string, position: number, total: number) => string;
|
|
1131
1131
|
/** Announced when the item is dropped. */
|
|
1132
1132
|
dndDropped: (position: number) => string;
|
|
1133
|
+
/** Announced as a lifted item reaches a drop zone (a target that is not a list). */
|
|
1134
|
+
dndMovedToZone: (zone: string) => string;
|
|
1135
|
+
/** Announced when the item is dropped on a zone. */
|
|
1136
|
+
dndDroppedInZone: (zone: string) => string;
|
|
1133
1137
|
/** Announced when the drag is cancelled. */
|
|
1134
1138
|
dndCancelled: string;
|
|
1135
1139
|
/** Repeater add-row button caption (default when no `addLabel` is given). */
|
package/types/mk-kit-ui-dnd.d.ts
CHANGED
|
@@ -70,6 +70,12 @@ declare class MkDragHandle {
|
|
|
70
70
|
* it up, **Arrow** keys to move it (crossing into connected lists at the ends /
|
|
71
71
|
* across the perpendicular axis), **Space/Enter** to drop, **Escape** to cancel.
|
|
72
72
|
*
|
|
73
|
+
* Besides lists, an item can be released on a connected `[mkDropZone]` — a
|
|
74
|
+
* target that reports *where* it was dropped instead of an index (a timeline,
|
|
75
|
+
* a priority band, a "focus on this" pane). Zones sit in the same keyboard
|
|
76
|
+
* travel group as lists, in document order; while an item hovers a zone no
|
|
77
|
+
* placeholder is shown and the zone streams `mkDropZoneMoved` events.
|
|
78
|
+
*
|
|
73
79
|
* Touch: a swipe scrolls the page as usual — the drag only arms after a
|
|
74
80
|
* long-press ({@link mkDragTouchDelay}, default 300 ms). While armed the item
|
|
75
81
|
* gets the `mk-drag--armed` class so consumers can style the lift moment.
|
|
@@ -145,6 +151,8 @@ declare class MkDrag<T = unknown> {
|
|
|
145
151
|
private targetIndex;
|
|
146
152
|
private homeIndex;
|
|
147
153
|
private placeholder;
|
|
154
|
+
/** The zone the item hovers (pointer) or sits on (keyboard); `null` while a list is the target. */
|
|
155
|
+
private targetZone;
|
|
148
156
|
private pointerId;
|
|
149
157
|
private started;
|
|
150
158
|
private startX;
|
|
@@ -182,6 +190,12 @@ declare class MkDrag<T = unknown> {
|
|
|
182
190
|
private cachedGroup;
|
|
183
191
|
/** List bounds snapshotted at lift / after invalidation. */
|
|
184
192
|
private readonly listRects;
|
|
193
|
+
/** Connected zones resolved once at lift, and their bounds. */
|
|
194
|
+
private cachedZones;
|
|
195
|
+
private readonly zoneRects;
|
|
196
|
+
/** Last pointer position a frame applied — the drop position on a zone. */
|
|
197
|
+
private lastX;
|
|
198
|
+
private lastY;
|
|
185
199
|
/** Item bounds per list, aligned with `itemElementsExcept(this)`. */
|
|
186
200
|
private readonly itemRects;
|
|
187
201
|
/** Lists whose snapshots a placeholder move invalidated (re-measured next frame). */
|
|
@@ -216,13 +230,31 @@ declare class MkDrag<T = unknown> {
|
|
|
216
230
|
* all style/DOM writes — no read ever follows a write within the frame.
|
|
217
231
|
*/
|
|
218
232
|
private applyPendingMove;
|
|
233
|
+
/** Pointer entered / moved over `zone`: no placeholder, the zone gets the position. */
|
|
234
|
+
private hoverZone;
|
|
235
|
+
/** Leave the current zone, if any (the zone is told, so it can clear its preview). */
|
|
236
|
+
private leaveZone;
|
|
237
|
+
/**
|
|
238
|
+
* Take the placeholder out of the lists while the item is over a zone. The
|
|
239
|
+
* next `syncPlaceholder` re-inserts it (the idempotence guard is reset), and
|
|
240
|
+
* the list it left is re-measured because its layout just changed.
|
|
241
|
+
*/
|
|
242
|
+
private detachPlaceholder;
|
|
243
|
+
/** Position of the item over `zone` — cached bounds on the pointer path, live otherwise. */
|
|
244
|
+
private zoneHover;
|
|
245
|
+
private zoneEvent;
|
|
219
246
|
private finishPointer;
|
|
220
247
|
private commitPointer;
|
|
221
248
|
protected onKeyDown(event: Event): void;
|
|
222
249
|
protected onFocusOut(event: Event): void;
|
|
223
250
|
private pickUp;
|
|
224
251
|
private stepPrimary;
|
|
225
|
-
|
|
252
|
+
/**
|
|
253
|
+
* Cross to the previous / next target on the perpendicular axis: connected
|
|
254
|
+
* lists **and** zones, in document order (see `MkDragDropRegistry.travelGroup`).
|
|
255
|
+
*/
|
|
256
|
+
private stepTarget;
|
|
257
|
+
private moveToZone;
|
|
226
258
|
private moveToList;
|
|
227
259
|
private dropKeyboard;
|
|
228
260
|
private cancelKeyboard;
|
|
@@ -232,6 +264,8 @@ declare class MkDrag<T = unknown> {
|
|
|
232
264
|
private announceMove;
|
|
233
265
|
/** Confirmation after a successful drop (pointer: polite; keyboard: assertive). */
|
|
234
266
|
private announceDropped;
|
|
267
|
+
/** Confirmation after a drop on a zone. */
|
|
268
|
+
private announceDroppedInZone;
|
|
235
269
|
/** The drag was cancelled and the item snapped back. */
|
|
236
270
|
private announceCancelled;
|
|
237
271
|
/** Highest valid target index for `list` given the item is being removed. */
|
|
@@ -242,10 +276,10 @@ declare class MkDrag<T = unknown> {
|
|
|
242
276
|
/** (Re)measure one list's bounds and item bounds into the cache. */
|
|
243
277
|
private measureList;
|
|
244
278
|
/**
|
|
245
|
-
* Which connected list (if any) the pointer is currently over.
|
|
246
|
-
* only — reads the rects snapshotted at lift, not live layout.
|
|
279
|
+
* Which connected list or zone (if any) the pointer is currently over.
|
|
280
|
+
* Pointer path only — reads the rects snapshotted at lift, not live layout.
|
|
247
281
|
*/
|
|
248
|
-
private
|
|
282
|
+
private targetUnderPoint;
|
|
249
283
|
/**
|
|
250
284
|
* Insertion index for the pointer position within `list`. Pointer path only
|
|
251
285
|
* — reads the cached item rects (live measurement is the fallback for a
|
|
@@ -381,6 +415,90 @@ declare class MkDropList<T = unknown> {
|
|
|
381
415
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MkDropList<any>, "[mkDropList]", ["mkDropList"], { "mkDropListData": { "alias": "mkDropListData"; "required": false; "isSignal": true; }; "mkDropListId": { "alias": "mkDropListId"; "required": false; "isSignal": true; }; "mkDropListConnectedTo": { "alias": "mkDropListConnectedTo"; "required": false; "isSignal": true; }; "mkDropListLabel": { "alias": "mkDropListLabel"; "required": false; "isSignal": true; }; "mkDropListLabelledBy": { "alias": "mkDropListLabelledBy"; "required": false; "isSignal": true; }; "mkDropListOrientation": { "alias": "mkDropListOrientation"; "required": false; "isSignal": true; }; "mkDropListDisabled": { "alias": "mkDropListDisabled"; "required": false; "isSignal": true; }; }, { "mkDropListDropped": "mkDropListDropped"; }, ["drags"], ["*"], true, never>;
|
|
382
416
|
}
|
|
383
417
|
|
|
418
|
+
/**
|
|
419
|
+
* A drop **target** that is not a list: an item dragged out of a connected
|
|
420
|
+
* `[mkDropList]` can be released anywhere on it, and the zone reports *where*
|
|
421
|
+
* — client coordinates, the offset inside the zone and the 0–1 fraction along
|
|
422
|
+
* each axis — so the consumer can turn a position into meaning: a time on a
|
|
423
|
+
* timeline, a priority band, a "focus on this" pane, a trash can.
|
|
424
|
+
*
|
|
425
|
+
* Nothing reorders and no placeholder is shown while an item hovers a zone;
|
|
426
|
+
* the zone gets the `mk-drop-zone--receiving` class and a stream of
|
|
427
|
+
* {@link mkDropZoneMoved} events instead. Zones and lists can overlap — the
|
|
428
|
+
* innermost target under the pointer wins, so a column can hold three
|
|
429
|
+
* priority bands and still accept plain drops between the bands.
|
|
430
|
+
*
|
|
431
|
+
* Wire a zone exactly like another list: give it an id and name that id in
|
|
432
|
+
* the source list's `mkDropListConnectedTo`.
|
|
433
|
+
*
|
|
434
|
+
* Keyboard: a lifted item reaches zones with the arrow keys that cross lists
|
|
435
|
+
* (Left/Right in a vertical list, Up/Down in a horizontal one) — zones sit in
|
|
436
|
+
* the same DOM-ordered travel group as connected lists; Space/Enter drops at
|
|
437
|
+
* the zone's centre. Every step is announced.
|
|
438
|
+
*
|
|
439
|
+
* ```html
|
|
440
|
+
* <ul mkDropList mkDropListId="backlog" [mkDropListConnectedTo]="['now', 'rail']" …>
|
|
441
|
+
* <section mkDropZone mkDropZoneId="now" mkDropZoneLabel="Focus now"
|
|
442
|
+
* (mkDropZoneDropped)="focus($event.item.mkDragData())">
|
|
443
|
+
* <div mkDropZone mkDropZoneId="rail" mkDropZoneLabel="Today"
|
|
444
|
+
* (mkDropZoneMoved)="preview($event.fractionY)"
|
|
445
|
+
* (mkDropZoneDropped)="schedule($event.item.mkDragData(), $event.fractionY)">
|
|
446
|
+
* ```
|
|
447
|
+
*
|
|
448
|
+
* @typeParam Z the zone's own payload type (`mkDropZoneData`).
|
|
449
|
+
* @typeParam T the dragged item's data type. A zone cannot infer it from a
|
|
450
|
+
* binding the way a list does from `mkDropListData`, so it defaults to
|
|
451
|
+
* `any` — a handler typed `(e: MkDropZoneEvent<Task>) => …` binds directly.
|
|
452
|
+
*/
|
|
453
|
+
declare class MkDropZone<Z = unknown, T = any> {
|
|
454
|
+
private readonly registry;
|
|
455
|
+
/** The zone's host element (drop target bounds). */
|
|
456
|
+
readonly element: HTMLElement;
|
|
457
|
+
/** Stable id source lists name in `mkDropListConnectedTo`. Auto-generated when omitted. */
|
|
458
|
+
readonly mkDropZoneId: _angular_core.InputSignal<string | undefined>;
|
|
459
|
+
/**
|
|
460
|
+
* Human-readable name, used in screen-reader announcements when a lifted
|
|
461
|
+
* item reaches the zone ("Moved to Focus now") and as the zone's accessible
|
|
462
|
+
* name. Set it: the fallback is the id, which may be generated gibberish.
|
|
463
|
+
*/
|
|
464
|
+
readonly mkDropZoneLabel: _angular_core.InputSignal<string>;
|
|
465
|
+
/** Id of a visible element that names the zone (`aria-labelledby`); wins over the label as the accessible name. */
|
|
466
|
+
readonly mkDropZoneLabelledBy: _angular_core.InputSignal<string>;
|
|
467
|
+
/** Arbitrary payload handed back on every hover and drop event. */
|
|
468
|
+
readonly mkDropZoneData: _angular_core.InputSignal<Z | undefined>;
|
|
469
|
+
/** Disable dropping onto this zone (it leaves the travel group too). */
|
|
470
|
+
readonly mkDropZoneDisabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
471
|
+
/** An item entered the zone (pointer or keyboard). */
|
|
472
|
+
readonly mkDropZoneEntered: _angular_core.OutputEmitterRef<MkDropZoneHover<T, Z>>;
|
|
473
|
+
/** The pointer moved while over the zone (one per frame, pointer only). */
|
|
474
|
+
readonly mkDropZoneMoved: _angular_core.OutputEmitterRef<MkDropZoneHover<T, Z>>;
|
|
475
|
+
/** The item left the zone without dropping (moved on, or the drag was cancelled). */
|
|
476
|
+
readonly mkDropZoneLeft: _angular_core.OutputEmitterRef<MkDrag<T>>;
|
|
477
|
+
/** The item was released on the zone. */
|
|
478
|
+
readonly mkDropZoneDropped: _angular_core.OutputEmitterRef<MkDropZoneEvent<T, Z>>;
|
|
479
|
+
/** Resolved id (input or generated). */
|
|
480
|
+
readonly id: _angular_core.Signal<string>;
|
|
481
|
+
private readonly autoId;
|
|
482
|
+
/** Announceable name: the label when set, otherwise the resolved id. */
|
|
483
|
+
readonly label: _angular_core.Signal<string>;
|
|
484
|
+
/** A `role` written in the template is kept; a zone is otherwise a named `group`. */
|
|
485
|
+
protected readonly role: string;
|
|
486
|
+
private readonly staticAriaLabel;
|
|
487
|
+
protected readonly ariaLabel: _angular_core.Signal<string | null>;
|
|
488
|
+
/** Highlight while a drag is hovering (or a keyboard-lifted item sits on) the zone. */
|
|
489
|
+
protected readonly _receiving: _angular_core.WritableSignal<boolean>;
|
|
490
|
+
constructor();
|
|
491
|
+
/** Toggle the "receiving" highlight (called by the active drag). */
|
|
492
|
+
setReceiving(value: boolean): void;
|
|
493
|
+
/** Called by the active `MkDrag` — not part of the consumer API. */
|
|
494
|
+
emitEntered(event: MkDropZoneHover<T, Z>): void;
|
|
495
|
+
emitMoved(event: MkDropZoneHover<T, Z>): void;
|
|
496
|
+
emitLeft(item: MkDrag<T>): void;
|
|
497
|
+
emitDrop(event: MkDropZoneEvent<T, Z>): void;
|
|
498
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MkDropZone<any, any>, never>;
|
|
499
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MkDropZone<any, any>, "[mkDropZone]", ["mkDropZone"], { "mkDropZoneId": { "alias": "mkDropZoneId"; "required": false; "isSignal": true; }; "mkDropZoneLabel": { "alias": "mkDropZoneLabel"; "required": false; "isSignal": true; }; "mkDropZoneLabelledBy": { "alias": "mkDropZoneLabelledBy"; "required": false; "isSignal": true; }; "mkDropZoneData": { "alias": "mkDropZoneData"; "required": false; "isSignal": true; }; "mkDropZoneDisabled": { "alias": "mkDropZoneDisabled"; "required": false; "isSignal": true; }; }, { "mkDropZoneEntered": "mkDropZoneEntered"; "mkDropZoneMoved": "mkDropZoneMoved"; "mkDropZoneLeft": "mkDropZoneLeft"; "mkDropZoneDropped": "mkDropZoneDropped"; }, never, ["*"], true, never>;
|
|
500
|
+
}
|
|
501
|
+
|
|
384
502
|
/** Layout axis a drop list lays its items along. */
|
|
385
503
|
type MkDropListOrientation = 'vertical' | 'horizontal';
|
|
386
504
|
/**
|
|
@@ -420,6 +538,43 @@ interface MkDropEvent<T = unknown> {
|
|
|
420
538
|
/** `true` for pointer (mouse/touch/pen) drops, `false` for keyboard drops. */
|
|
421
539
|
isPointerEvent: boolean;
|
|
422
540
|
}
|
|
541
|
+
/**
|
|
542
|
+
* Where an item is over a `[mkDropZone]`, emitted on enter and on every
|
|
543
|
+
* pointer frame (`mkDropZoneEntered` / `mkDropZoneMoved`). Keyboard entries
|
|
544
|
+
* report the zone's centre.
|
|
545
|
+
*
|
|
546
|
+
* @typeParam T item data type.
|
|
547
|
+
* @typeParam Z zone data type (`mkDropZoneData`).
|
|
548
|
+
*/
|
|
549
|
+
interface MkDropZoneHover<T = unknown, Z = unknown> {
|
|
550
|
+
/** The `MkDrag` directive instance being dragged. */
|
|
551
|
+
item: MkDrag<T>;
|
|
552
|
+
/** The zone under the pointer. */
|
|
553
|
+
zone: MkDropZone<Z>;
|
|
554
|
+
/** Pointer position in client (viewport) coordinates. */
|
|
555
|
+
x: number;
|
|
556
|
+
y: number;
|
|
557
|
+
/** Pointer position relative to the zone's top-left corner, in CSS pixels. */
|
|
558
|
+
offsetX: number;
|
|
559
|
+
offsetY: number;
|
|
560
|
+
/** Pointer position as a 0–1 fraction of the zone's width / height (clamped). */
|
|
561
|
+
fractionX: number;
|
|
562
|
+
fractionY: number;
|
|
563
|
+
/** `true` for pointer (mouse/touch/pen) hovers, `false` for keyboard steps. */
|
|
564
|
+
isPointerEvent: boolean;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Emitted by `[mkDropZone]` (`mkDropZoneDropped`) when an item is released on
|
|
568
|
+
* it. Carries the same position fields as {@link MkDropZoneHover} plus where
|
|
569
|
+
* the item came from — the consumer removes it from that list (or not: a
|
|
570
|
+
* "focus on this" zone may leave the card where it is).
|
|
571
|
+
*/
|
|
572
|
+
interface MkDropZoneEvent<T = unknown, Z = unknown> extends MkDropZoneHover<T, Z> {
|
|
573
|
+
/** The list the item came from. */
|
|
574
|
+
previousContainer: MkDropList<T>;
|
|
575
|
+
/** Index of the item within `previousContainer`'s data. */
|
|
576
|
+
previousIndex: number;
|
|
577
|
+
}
|
|
423
578
|
|
|
424
579
|
/**
|
|
425
580
|
* Pure array helpers for applying an {@link MkDropEvent}. They mutate the passed
|
|
@@ -446,6 +601,8 @@ declare function mkMoveItemInArray<T>(array: T[], fromIndex: number, toIndex: nu
|
|
|
446
601
|
*/
|
|
447
602
|
declare function mkTransferArrayItem<T>(from: T[], to: T[], fromIndex: number, toIndex: number): T[];
|
|
448
603
|
|
|
604
|
+
/** A keyboard-reachable drop target: a connected list or a connected zone. */
|
|
605
|
+
type MkDropTarget = MkDropList<any> | MkDropZone<any>;
|
|
449
606
|
/**
|
|
450
607
|
* Central registry of every live `[mkDropList]` on the page, keyed by id.
|
|
451
608
|
*
|
|
@@ -458,6 +615,7 @@ declare function mkTransferArrayItem<T>(from: T[], to: T[], fromIndex: number, t
|
|
|
458
615
|
*/
|
|
459
616
|
declare class MkDragDropRegistry {
|
|
460
617
|
private readonly lists;
|
|
618
|
+
private readonly zones;
|
|
461
619
|
/** Register (or replace) the list published under `id`. */
|
|
462
620
|
register(id: string, list: MkDropList<any>): void;
|
|
463
621
|
/** Remove `list` from the registry if it is still the holder of `id`. */
|
|
@@ -473,6 +631,20 @@ declare class MkDragDropRegistry {
|
|
|
473
631
|
* hit-test the pointer against candidate targets.
|
|
474
632
|
*/
|
|
475
633
|
connectedGroup(list: MkDropList<any>): MkDropList<any>[];
|
|
634
|
+
/** Register (or replace) the zone published under `id`. */
|
|
635
|
+
registerZone(id: string, zone: MkDropZone<any>): void;
|
|
636
|
+
/** Remove `zone` from the registry if it is still the holder of `id`. */
|
|
637
|
+
unregisterZone(id: string, zone: MkDropZone<any>): void;
|
|
638
|
+
/** Look up a zone by its `mkDropZoneId`. */
|
|
639
|
+
getZone(id: string): MkDropZone<any> | undefined;
|
|
640
|
+
/** Every enabled zone named in `list`'s `mkDropListConnectedTo`, in registration order. */
|
|
641
|
+
connectedZones(list: MkDropList<any>): MkDropZone<any>[];
|
|
642
|
+
/**
|
|
643
|
+
* The keyboard travel group for `list`: its connected lists **and** zones,
|
|
644
|
+
* in document order, so arrow keys walk targets the way they appear on
|
|
645
|
+
* screen regardless of when each registered.
|
|
646
|
+
*/
|
|
647
|
+
travelGroup(list: MkDropList<any>): MkDropTarget[];
|
|
476
648
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MkDragDropRegistry, never>;
|
|
477
649
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<MkDragDropRegistry>;
|
|
478
650
|
}
|
|
@@ -531,5 +703,5 @@ declare class MkSortableList<T = unknown> {
|
|
|
531
703
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MkSortableList<any>, "mk-sortable-list", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "labelledBy": { "alias": "labelledBy"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "trackBy": { "alias": "trackBy"; "required": false; "isSignal": true; }; }, { "items": "itemsChange"; "sorted": "sorted"; }, ["itemTemplate"], never, true, never>;
|
|
532
704
|
}
|
|
533
705
|
|
|
534
|
-
export { MkDrag, MkDragDropRegistry, MkDragHandle, MkDropList, MkSortableList, mkMoveItemInArray, mkTransferArrayItem };
|
|
535
|
-
export type { MkDropEvent, MkDropListOrientation };
|
|
706
|
+
export { MkDrag, MkDragDropRegistry, MkDragHandle, MkDropList, MkDropZone, MkSortableList, mkMoveItemInArray, mkTransferArrayItem };
|
|
707
|
+
export type { MkDropEvent, MkDropListOrientation, MkDropTarget, MkDropZoneEvent, MkDropZoneHover };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { MkTranslateLoaderFactory } from '@mk-kit/ui/translate';
|
|
2
|
+
|
|
3
|
+
/** Options for {@link mkFsTranslateLoader}. */
|
|
4
|
+
interface MkFsTranslateLoaderOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Directories searched in order for `<lang><suffix>`; the first readable
|
|
7
|
+
* file wins. Typical: the built browser assets next to the server bundle,
|
|
8
|
+
* then the source tree for `ng serve`.
|
|
9
|
+
*/
|
|
10
|
+
dirs: string[];
|
|
11
|
+
/** File suffix after the language code. Default `.json`. */
|
|
12
|
+
suffix?: string;
|
|
13
|
+
/**
|
|
14
|
+
* When no directory has the file: return `{}` (default) so the app boots
|
|
15
|
+
* with keys as text, or throw so the failure surfaces at once.
|
|
16
|
+
*/
|
|
17
|
+
onNotFound?: 'empty' | 'throw';
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Server-side loader that reads the translation JSON from disk instead of
|
|
21
|
+
* fetching the app's own HTTP endpoint during SSR — no self-request, no
|
|
22
|
+
* proxy hop, no interceptor ordering to get right. Register it in the
|
|
23
|
+
* server config only (`app.config.server.ts`); the browser keeps
|
|
24
|
+
* `mkHttpTranslateLoader`. Files are parsed once per process.
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* // app.config.server.ts
|
|
28
|
+
* provideMkTranslate({
|
|
29
|
+
* ...browserTranslateConfig,
|
|
30
|
+
* loader: mkFsTranslateLoader({
|
|
31
|
+
* dirs: [join(import.meta.dirname, '../browser/assets/i18n'), join(process.cwd(), 'src/assets/i18n')],
|
|
32
|
+
* }),
|
|
33
|
+
* })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
declare function mkFsTranslateLoader(options: MkFsTranslateLoaderOptions): MkTranslateLoaderFactory;
|
|
37
|
+
|
|
38
|
+
export { mkFsTranslateLoader };
|
|
39
|
+
export type { MkFsTranslateLoaderOptions };
|