@marianmeres/stuic 3.131.0 → 3.133.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.
@@ -61,6 +61,13 @@ export interface Props extends InputWrapClassProps, Record<string, any> {
61
61
  withOnProgress?: boolean;
62
62
  classControls?: string;
63
63
  isLoading?: boolean;
64
+ /**
65
+ * Opt-in: when true, each asset tile in the grid gets "Move earlier" / "Move later"
66
+ * controls (shown on hover/focus) so the user can manually reorder the assets. The
67
+ * chosen order is serialized to `value`. Buttons only, no drag (the field's drag is
68
+ * reserved for file drops); full keyboard + aria-live announcements. Default `false`.
69
+ */
70
+ ordered?: boolean;
64
71
  classWrap?: string;
65
72
  }
66
73
  declare const FieldAssets: import("svelte").Component<Props, {
@@ -86,7 +86,7 @@
86
86
  /**
87
87
  * Opt-in: when true (and multi-select), exposes a dedicated "Arrange" screen in the
88
88
  * modal that lets the user manually reorder the current selection (buttons only, no
89
- * drag), plus "Sort A–Z" / "Reverse" shortcuts. The chosen order is what gets
89
+ * drag), plus "Sort A–Z" / "Reverse" / "Shuffle" shortcuts. The chosen order is what gets
90
90
  * serialized to `value` on submit. No-op for single-select. Default `false`.
91
91
  */
92
92
  ordered?: boolean;
@@ -130,6 +130,7 @@
130
130
  arrange_help: "Reorder the selected items. Use the buttons to move them.",
131
131
  sort_az: "Sort A–Z",
132
132
  reverse: "Reverse",
133
+ shuffle: "Shuffle",
133
134
  move_up: "Move up",
134
135
  move_down: "Move down",
135
136
  move_to_top: "Move to top",
@@ -140,6 +141,7 @@
140
141
  removed_item: "Removed {{value}}",
141
142
  sorted_az: "Sorted A to Z",
142
143
  reversed: "Order reversed",
144
+ shuffled: "Order shuffled",
143
145
  };
144
146
  let out = m[k] ?? fallback ?? k;
145
147
 
@@ -528,6 +530,17 @@
528
530
  liveAnnouncement = t("reversed") as string;
529
531
  }
530
532
 
533
+ // random reorder (Fisher–Yates); same snapshot/clear/re-add dance as reverse()
534
+ function shuffle() {
535
+ const arr = [...selected.items];
536
+ for (let i = arr.length - 1; i > 0; i--) {
537
+ const j = Math.floor(Math.random() * (i + 1));
538
+ [arr[i], arr[j]] = [arr[j], arr[i]];
539
+ }
540
+ _selectedColl.clear(false).addMany(arr);
541
+ liveAnnouncement = t("shuffled") as string;
542
+ }
543
+
531
544
  function enterArrange() {
532
545
  if (!selected.items.length) return;
533
546
  arrangeMode = true;
@@ -908,6 +921,15 @@
908
921
  >
909
922
  {@html t("reverse")}
910
923
  </button>
924
+ <button
925
+ type="button"
926
+ onclick={shuffle}
927
+ disabled={selected.items.length < 2}
928
+ class="control flex items-center p-1 m-1 text-sm underline rounded stuic-field-options-control"
929
+ tabindex={6}
930
+ >
931
+ {@html t("shuffle")}
932
+ </button>
911
933
  <span
912
934
  class="flex-1 block justify-end text-right text-xs p-1 pr-2 stuic-field-options-muted"
913
935
  >
@@ -58,7 +58,7 @@ export interface Props extends InputWrapClassProps, Record<string, any> {
58
58
  /**
59
59
  * Opt-in: when true (and multi-select), exposes a dedicated "Arrange" screen in the
60
60
  * modal that lets the user manually reorder the current selection (buttons only, no
61
- * drag), plus "Sort A–Z" / "Reverse" shortcuts. The chosen order is what gets
61
+ * drag), plus "Sort A–Z" / "Reverse" / "Shuffle" shortcuts. The chosen order is what gets
62
62
  * serialized to `value` on submit. No-op for single-select. Default `false`.
63
63
  */
64
64
  ordered?: boolean;
@@ -472,6 +472,33 @@ on submit (and round-trips on reopen). Single-select fields ignore the prop.
472
472
 
473
473
  ---
474
474
 
475
+ ## FieldAssets
476
+
477
+ Asset/image upload field with an inline thumbnail grid and a built-in lightbox preview
478
+ (`AssetsPreview`). Files are added via the picker button or by dragging them onto the
479
+ field; each shows as a thumbnail with its filename (and an upload progress indicator while
480
+ processing).
481
+
482
+ ### Ordering the assets (`ordered`)
483
+
484
+ By default assets keep their upload order. Opt in with `ordered` to let users reorder them
485
+ manually: each thumbnail gains **Move earlier** / **Move later** controls (revealed on
486
+ hover/focus) that shift the asset one position in the sequence. Buttons only, no drag — the
487
+ field's drag gesture is reserved for file drops — with full keyboard support and aria-live
488
+ announcements. The chosen order is serialized to `value`.
489
+
490
+ ```svelte
491
+ <FieldAssets
492
+ label="Gallery (ordered)"
493
+ name="gallery"
494
+ bind:value
495
+ {processAssets}
496
+ ordered
497
+ />
498
+ ```
499
+
500
+ ---
501
+
475
502
  ## Honeypot & TimeTrap (anti-bot primitives)
476
503
 
477
504
  Two small, **client-side, server-less** primitives for cheap spam mitigation. They produce **signals** — they do not block anything. Read the signal, then enforce on your server (the only place enforcement is trustworthy). Both are reusable on any form; [`ContactUsForm`](../ContactUsForm/README.md) composes them by default.
package/dist/index.css CHANGED
@@ -71,6 +71,7 @@ In practice:
71
71
  @import "./components/LoginOrRegisterForm/index.css";
72
72
  @import "./components/Checkout/index.css";
73
73
  @import "./components/CommandMenu/index.css";
74
+ @import "./components/CommentInput/index.css";
74
75
  @import "./components/ContactUsForm/index.css";
75
76
  @import "./components/CronInput/index.css";
76
77
  @import "./components/DataTable/index.css";
package/dist/index.d.ts CHANGED
@@ -38,6 +38,7 @@ export * from "./components/Checkout/index.js";
38
38
  export * from "./components/Collapsible/index.js";
39
39
  export * from "./components/ColorScheme/index.js";
40
40
  export * from "./components/CommandMenu/index.js";
41
+ export * from "./components/CommentInput/index.js";
41
42
  export * from "./components/ContactUsForm/index.js";
42
43
  export * from "./components/CronInput/index.js";
43
44
  export * from "./components/DataTable/index.js";
package/dist/index.js CHANGED
@@ -39,6 +39,7 @@ export * from "./components/Checkout/index.js";
39
39
  export * from "./components/Collapsible/index.js";
40
40
  export * from "./components/ColorScheme/index.js";
41
41
  export * from "./components/CommandMenu/index.js";
42
+ export * from "./components/CommentInput/index.js";
42
43
  export * from "./components/ContactUsForm/index.js";
43
44
  export * from "./components/CronInput/index.js";
44
45
  export * from "./components/DataTable/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "3.131.0",
3
+ "version": "3.133.0",
4
4
  "packageManager": "pnpm@11.5.0",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -72,6 +72,8 @@
72
72
  "@milkdown/prose": "^7.0.0",
73
73
  "@milkdown/transformer": "^7.0.0",
74
74
  "@milkdown/utils": "^7.0.0",
75
+ "dompurify": "^3.0.0",
76
+ "marked": "^18.0.0",
75
77
  "svelte": "^5.0.0"
76
78
  },
77
79
  "peerDependenciesMeta": {
@@ -119,15 +121,21 @@
119
121
  },
120
122
  "@milkdown/utils": {
121
123
  "optional": true
124
+ },
125
+ "dompurify": {
126
+ "optional": true
127
+ },
128
+ "marked": {
129
+ "optional": true
122
130
  }
123
131
  },
124
132
  "devDependencies": {
125
133
  "@codemirror/commands": "^6.10.4",
126
134
  "@codemirror/lang-markdown": "^6.5.0",
127
- "@codemirror/language": "^6.12.3",
135
+ "@codemirror/language": "^6.12.4",
128
136
  "@codemirror/language-data": "^6.5.2",
129
137
  "@codemirror/state": "^6.7.0",
130
- "@codemirror/view": "^6.43.2",
138
+ "@codemirror/view": "^6.43.4",
131
139
  "@eslint/js": "^9.39.4",
132
140
  "@marianmeres/random-human-readable": "^1.10.2",
133
141
  "@milkdown/core": "^7.21.2",
@@ -149,11 +157,13 @@
149
157
  "@tailwindcss/vite": "^4.3.1",
150
158
  "@types/node": "^25.9.4",
151
159
  "@vitest/browser-playwright": "^4.1.9",
160
+ "dompurify": "^3.4.11",
152
161
  "dotenv": "^16.6.1",
153
162
  "eslint": "^9.39.4",
154
163
  "globals": "^16.5.0",
164
+ "marked": "^18.0.5",
155
165
  "playwright": "^1.61.1",
156
- "prettier": "^3.8.4",
166
+ "prettier": "^3.9.0",
157
167
  "prettier-plugin-svelte": "^3.5.2",
158
168
  "publint": "^0.3.21",
159
169
  "svelte": "^5.56.4",
@@ -170,7 +180,7 @@
170
180
  "@marianmeres/clog": "^3.21.0",
171
181
  "@marianmeres/countries": "^1.0.1",
172
182
  "@marianmeres/cron": "^2.0.1",
173
- "@marianmeres/design-tokens": "^1.9.0",
183
+ "@marianmeres/design-tokens": "^1.12.0",
174
184
  "@marianmeres/icons-fns": "^5.0.0",
175
185
  "@marianmeres/item-collection": "^1.4.2",
176
186
  "@marianmeres/paging-store": "^2.1.1",