@krizaka/ui 3.46.0 → 3.49.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 (230) hide show
  1. package/dist/account-menu.d.ts +2 -111
  2. package/dist/account-menu.js +39 -118
  3. package/dist/account-menu.js.map +1 -1
  4. package/dist/account-settings.d.ts +163 -0
  5. package/dist/account-settings.js +354 -0
  6. package/dist/account-settings.js.map +1 -0
  7. package/dist/agenda.d.ts +136 -0
  8. package/dist/agenda.js +90 -0
  9. package/dist/agenda.js.map +1 -0
  10. package/dist/avatar-iajODANU.d.ts +114 -0
  11. package/dist/chunk-3D2YI63L.js +27 -0
  12. package/dist/chunk-3D2YI63L.js.map +1 -0
  13. package/dist/chunk-3RVFD3UX.js +85 -0
  14. package/dist/chunk-3RVFD3UX.js.map +1 -0
  15. package/dist/{chunk-P4TTKYC4.js → chunk-4LYKBSOG.js} +4 -1
  16. package/dist/chunk-4LYKBSOG.js.map +1 -0
  17. package/dist/chunk-S6NYGOJT.js +22 -0
  18. package/dist/chunk-S6NYGOJT.js.map +1 -0
  19. package/dist/docs-layout.js +13 -32
  20. package/dist/docs-layout.js.map +1 -1
  21. package/dist/docs-nav.js +1 -1
  22. package/dist/drop-overlay.d.ts +31 -0
  23. package/dist/drop-overlay.js +86 -0
  24. package/dist/drop-overlay.js.map +1 -0
  25. package/dist/motion.css +27 -0
  26. package/dist/nav-bar.d.ts +1 -1
  27. package/dist/nav-bar.js +1 -1
  28. package/dist/settings-layout.d.ts +112 -8
  29. package/dist/settings-layout.js +274 -28
  30. package/dist/settings-layout.js.map +1 -1
  31. package/dist/site-footer.d.ts +1 -1
  32. package/dist/site-footer.js +1 -1
  33. package/dist/{sites-inztN_Bv.d.ts → sites-DlR8jicc.d.ts} +1 -1
  34. package/dist/sites.d.ts +1 -1
  35. package/dist/sites.js +3 -0
  36. package/dist/sites.js.map +1 -1
  37. package/dist/upload-queue.d.ts +67 -0
  38. package/dist/upload-queue.js +76 -0
  39. package/dist/upload-queue.js.map +1 -0
  40. package/package.json +33 -7
  41. package/registry/account-menu.json +2 -2
  42. package/registry/account-settings.json +721 -0
  43. package/registry/achievement.json +1 -1
  44. package/registry/action-bar.json +1 -1
  45. package/registry/activity-feed.json +1 -1
  46. package/registry/agenda.json +293 -0
  47. package/registry/alert.json +1 -1
  48. package/registry/anatomy-plate.json +1 -1
  49. package/registry/app-header.json +1 -1
  50. package/registry/app-shell.json +1 -1
  51. package/registry/argument-card.json +1 -1
  52. package/registry/audio-player.json +1 -1
  53. package/registry/auth-layout.json +1 -1
  54. package/registry/avatar.json +1 -1
  55. package/registry/badge.json +1 -1
  56. package/registry/bird-plate.json +1 -1
  57. package/registry/button.json +1 -1
  58. package/registry/captcha.json +1 -1
  59. package/registry/card-grid.json +1 -1
  60. package/registry/card.json +1 -1
  61. package/registry/catalogue-page.json +1 -1
  62. package/registry/changelog-page.json +1 -1
  63. package/registry/chat.json +3 -3
  64. package/registry/checkbox.json +1 -1
  65. package/registry/chip-link.json +1 -1
  66. package/registry/chip-row.json +1 -1
  67. package/registry/chip.json +1 -1
  68. package/registry/choice-grid.json +1 -1
  69. package/registry/code-block.json +1 -1
  70. package/registry/combobox.json +1 -1
  71. package/registry/command.json +1 -1
  72. package/registry/comparison-table.json +1 -1
  73. package/registry/component-page.json +1 -1
  74. package/registry/confirm-button.json +1 -1
  75. package/registry/contact-page.json +1 -1
  76. package/registry/continue-prompt.json +1 -1
  77. package/registry/countdown.json +1 -1
  78. package/registry/cover-hero.json +1 -1
  79. package/registry/cta-panel.json +1 -1
  80. package/registry/dashboard-layout.json +1 -1
  81. package/registry/data-table.json +3 -3
  82. package/registry/date-picker.json +1 -1
  83. package/registry/decision-list.json +1 -1
  84. package/registry/description-list.json +1 -1
  85. package/registry/detail-layout.json +1 -1
  86. package/registry/dialog.json +1 -1
  87. package/registry/docs-article-page.json +1 -1
  88. package/registry/docs-hub-page.json +1 -1
  89. package/registry/docs-layout.json +1 -1
  90. package/registry/docs-nav.json +1 -1
  91. package/registry/document-viewer.json +1 -1
  92. package/registry/drop-overlay.json +182 -0
  93. package/registry/dropdown-menu.json +1 -1
  94. package/registry/elephant.json +2 -2
  95. package/registry/empty-state.json +1 -1
  96. package/registry/engine-flow.json +1 -1
  97. package/registry/error-page.json +1 -1
  98. package/registry/examples/account-settings/avatar-picker.d.ts +4 -0
  99. package/registry/examples/account-settings/avatar-picker.js +15 -0
  100. package/registry/examples/account-settings/avatar-picker.tsx +15 -0
  101. package/registry/examples/account-settings/choice-cards.d.ts +4 -0
  102. package/registry/examples/account-settings/choice-cards.js +24 -0
  103. package/registry/examples/account-settings/choice-cards.tsx +20 -0
  104. package/registry/examples/account-settings/language-picker.d.ts +4 -0
  105. package/registry/examples/account-settings/language-picker.js +25 -0
  106. package/registry/examples/account-settings/language-picker.tsx +21 -0
  107. package/registry/examples/account-settings/patterns.d.ts +4 -0
  108. package/registry/examples/account-settings/patterns.js +29 -0
  109. package/registry/examples/account-settings/patterns.tsx +39 -0
  110. package/registry/examples/account-settings/profile.d.ts +4 -0
  111. package/registry/examples/account-settings/profile.js +70 -0
  112. package/registry/examples/account-settings/profile.tsx +80 -0
  113. package/registry/examples/agenda/day.d.ts +4 -0
  114. package/registry/examples/agenda/day.js +43 -0
  115. package/registry/examples/agenda/day.tsx +35 -0
  116. package/registry/examples/drop-overlay/default.d.ts +4 -0
  117. package/registry/examples/drop-overlay/default.js +20 -0
  118. package/registry/examples/drop-overlay/default.tsx +18 -0
  119. package/registry/examples/settings-layout/grouped.d.ts +4 -0
  120. package/registry/examples/settings-layout/grouped.js +64 -0
  121. package/registry/examples/settings-layout/grouped.tsx +66 -0
  122. package/registry/examples/upload-queue/default.d.ts +4 -0
  123. package/registry/examples/upload-queue/default.js +22 -0
  124. package/registry/examples/upload-queue/default.tsx +20 -0
  125. package/registry/examples/upload-queue/tray.d.ts +4 -0
  126. package/registry/examples/upload-queue/tray.js +21 -0
  127. package/registry/examples/upload-queue/tray.tsx +19 -0
  128. package/registry/field.json +1 -1
  129. package/registry/file-upload.json +1 -1
  130. package/registry/filter-bar.json +1 -1
  131. package/registry/flock.json +1 -1
  132. package/registry/footnote.json +1 -1
  133. package/registry/force-update-screen.json +1 -1
  134. package/registry/form.json +3 -3
  135. package/registry/gallery-page.json +1 -1
  136. package/registry/genui.json +1 -1
  137. package/registry/glow-card.json +1 -1
  138. package/registry/goal-gauge.json +1 -1
  139. package/registry/how-it-works-page.json +1 -1
  140. package/registry/image-cropper.json +1 -1
  141. package/registry/index.json +159 -10
  142. package/registry/iso.json +1 -1
  143. package/registry/kanban.json +1 -1
  144. package/registry/kbd.json +1 -1
  145. package/registry/landing-page.json +1 -1
  146. package/registry/landscape.json +1 -1
  147. package/registry/language-switch.json +1 -1
  148. package/registry/legal-page.json +1 -1
  149. package/registry/link-card.json +1 -1
  150. package/registry/list.json +3 -3
  151. package/registry/loader.json +1 -1
  152. package/registry/longform-page.json +1 -1
  153. package/registry/maintenance-screen.json +1 -1
  154. package/registry/map.json +2 -2
  155. package/registry/markdown.json +1 -1
  156. package/registry/marketing-layout.json +1 -1
  157. package/registry/marquee.json +1 -1
  158. package/registry/mascot-quote.json +3 -3
  159. package/registry/mascot-state.json +3 -3
  160. package/registry/mascots.json +3 -3
  161. package/registry/match-dialog.json +1 -1
  162. package/registry/media-capture.json +1 -1
  163. package/registry/media-gallery.json +1 -1
  164. package/registry/media-grid.json +1 -1
  165. package/registry/meta-row.json +1 -1
  166. package/registry/meter.json +1 -1
  167. package/registry/nav-bar.json +2 -2
  168. package/registry/number-ticker.json +1 -1
  169. package/registry/opening-hours.json +1 -1
  170. package/registry/page-header.json +1 -1
  171. package/registry/page-hero.json +1 -1
  172. package/registry/page-index.json +1 -1
  173. package/registry/page.json +1 -1
  174. package/registry/pagination.json +1 -1
  175. package/registry/photo-grid.json +1 -1
  176. package/registry/pointer-light.json +1 -1
  177. package/registry/popover.json +1 -1
  178. package/registry/pricing-page.json +1 -1
  179. package/registry/product-page.json +1 -1
  180. package/registry/profile-card.json +1 -1
  181. package/registry/progress.json +1 -1
  182. package/registry/promise-card.json +1 -1
  183. package/registry/radio-group.json +93 -5
  184. package/registry/rail-nav.json +2 -2
  185. package/registry/recipes.json +1 -1
  186. package/registry/router.json +1 -1
  187. package/registry/scroll-stage.json +1 -1
  188. package/registry/search-field.json +1 -1
  189. package/registry/section-backdrop.json +1 -1
  190. package/registry/separator.json +1 -1
  191. package/registry/service-card.json +1 -1
  192. package/registry/settings-layout.json +79 -13
  193. package/registry/showcase.json +1 -1
  194. package/registry/site-footer.json +2 -2
  195. package/registry/sites.json +2 -2
  196. package/registry/skeleton.json +1 -1
  197. package/registry/skip-link.json +1 -1
  198. package/registry/slider.json +1 -1
  199. package/registry/slot-picker.json +1 -1
  200. package/registry/slot.json +1 -1
  201. package/registry/specimen-tag.json +1 -1
  202. package/registry/spinner.json +1 -1
  203. package/registry/split-view.json +1 -1
  204. package/registry/stage-banner.json +1 -1
  205. package/registry/stat.json +1 -1
  206. package/registry/status-page.json +1 -1
  207. package/registry/step-progress.json +1 -1
  208. package/registry/step-showcase.json +1 -1
  209. package/registry/stepper.json +1 -1
  210. package/registry/sticky-action.json +1 -1
  211. package/registry/swipe-deck.json +1 -1
  212. package/registry/switch.json +1 -1
  213. package/registry/tabs.json +1 -1
  214. package/registry/tag-input.json +3 -3
  215. package/registry/tag-selector.json +1 -1
  216. package/registry/terminal-replay.json +1 -1
  217. package/registry/theme.json +1 -1
  218. package/registry/toast.json +1 -1
  219. package/registry/toc.json +1 -1
  220. package/registry/tooltip.json +1 -1
  221. package/registry/tree-view.json +1 -1
  222. package/registry/update-prompt.json +1 -1
  223. package/registry/upload-queue.json +243 -0
  224. package/registry/verified-badge.json +1 -1
  225. package/registry/vertical-video.json +1 -1
  226. package/registry/video-player.json +1 -1
  227. package/registry/video-trimmer.json +1 -1
  228. package/registry/virtual.json +1 -1
  229. package/registry/waveform.json +1 -1
  230. package/dist/chunk-P4TTKYC4.js.map +0 -1
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+
3
+ /** True while the drag carries files (not text or a link): the only drag that should raise the overlay. */
4
+ declare function dragHasFiles(transfer: {
5
+ types?: readonly string[] | DOMStringList;
6
+ } | null | undefined): boolean;
7
+ /** One accepted kind: a MIME type (`application/pdf`), a family (`image/*`) or an extension (`.pdf`). */
8
+ type AcceptRule = string;
9
+ interface DropSplit<F> {
10
+ accepted: F[];
11
+ rejected: F[];
12
+ }
13
+ /** Splits dropped files by `accept` (no rule: everything is accepted). */
14
+ declare function splitDropped<F extends Pick<File, "name" | "type">>(files: readonly F[], accept?: readonly AcceptRule[]): DropSplit<F>;
15
+
16
+ type DropOverlayProps = Omit<React.ComponentProps<"div">, "children" | "onDrop"> & {
17
+ /** What the overlay says (“Drop to check”) — passed translated. */
18
+ label: string;
19
+ /** One line under it (“PDF or text”). */
20
+ hint?: string;
21
+ /** The files dropped: the accepted ones, then the ones `accept` refused. */
22
+ onFiles: (accepted: File[], rejected: File[]) => void;
23
+ /** What is accepted: MIME types, families (`image/*`) or extensions (`.pdf`). */
24
+ accept?: readonly AcceptRule[];
25
+ /** Turns the window back into a plain page (while a modal is open, signed out). */
26
+ disabled?: boolean;
27
+ };
28
+ /** Drag a file anywhere on the page: a full-window overlay accepts it. */
29
+ declare function DropOverlay({ label, hint, onFiles, accept, disabled, className, ...props }: DropOverlayProps): React.JSX.Element | null;
30
+
31
+ export { type AcceptRule, DropOverlay, type DropOverlayProps, type DropSplit, dragHasFiles, splitDropped };
@@ -0,0 +1,86 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-S6NYGOJT.js";
4
+
5
+ // src/drop-overlay/drop-overlay.tsx
6
+ import * as React from "react";
7
+
8
+ // src/drop-overlay/files.ts
9
+ function dragHasFiles(transfer) {
10
+ return Array.from(transfer?.types ?? []).includes("Files");
11
+ }
12
+ function matches(file, rule) {
13
+ const wanted = rule.trim().toLowerCase();
14
+ if (wanted.startsWith(".")) return file.name.toLowerCase().endsWith(wanted);
15
+ if (wanted.endsWith("/*")) return file.type.toLowerCase().startsWith(wanted.slice(0, -1));
16
+ return file.type.toLowerCase() === wanted;
17
+ }
18
+ function splitDropped(files, accept) {
19
+ if (!accept || accept.length === 0) return { accepted: [...files], rejected: [] };
20
+ const accepted = [];
21
+ const rejected = [];
22
+ for (const file of files) (accept.some((rule) => matches(file, rule)) ? accepted : rejected).push(file);
23
+ return { accepted, rejected };
24
+ }
25
+
26
+ // src/drop-overlay/drop-overlay.tsx
27
+ import { jsx, jsxs } from "react/jsx-runtime";
28
+ function DropOverlay({ label, hint, onFiles, accept, disabled, className, ...props }) {
29
+ const [active, setActive] = React.useState(false);
30
+ const depth = React.useRef(0);
31
+ const latest = React.useRef({ onFiles, accept });
32
+ React.useEffect(() => {
33
+ latest.current = { onFiles, accept };
34
+ });
35
+ React.useEffect(() => {
36
+ if (disabled) return;
37
+ const reset = () => {
38
+ depth.current = 0;
39
+ setActive(false);
40
+ };
41
+ const carrying = (event) => dragHasFiles(event.dataTransfer);
42
+ const enter = (event) => {
43
+ if (!carrying(event)) return;
44
+ depth.current += 1;
45
+ setActive(true);
46
+ };
47
+ const over = (event) => {
48
+ if (carrying(event)) event.preventDefault();
49
+ };
50
+ const leave = (event) => {
51
+ if (!carrying(event)) return;
52
+ depth.current = Math.max(0, depth.current - 1);
53
+ if (depth.current === 0) setActive(false);
54
+ };
55
+ const drop = (event) => {
56
+ if (!carrying(event)) return;
57
+ event.preventDefault();
58
+ const files = Array.from(event.dataTransfer?.files ?? []);
59
+ reset();
60
+ const { accepted, rejected } = splitDropped(files, latest.current.accept);
61
+ latest.current.onFiles(accepted, rejected);
62
+ };
63
+ window.addEventListener("dragenter", enter);
64
+ window.addEventListener("dragover", over);
65
+ window.addEventListener("dragleave", leave);
66
+ window.addEventListener("drop", drop);
67
+ return () => {
68
+ window.removeEventListener("dragenter", enter);
69
+ window.removeEventListener("dragover", over);
70
+ window.removeEventListener("dragleave", leave);
71
+ window.removeEventListener("drop", drop);
72
+ reset();
73
+ };
74
+ }, [disabled]);
75
+ if (!active) return null;
76
+ return /* @__PURE__ */ jsx("div", { role: "status", "data-state": "open", className: cn("kz-drop-overlay", className), ...props, children: /* @__PURE__ */ jsxs("div", { className: "kz-drop-overlay-card", children: [
77
+ /* @__PURE__ */ jsx("span", { className: "text-lg font-semibold text-fg", children: label }),
78
+ hint ? /* @__PURE__ */ jsx("span", { className: "text-sm text-fg-secondary", children: hint }) : null
79
+ ] }) });
80
+ }
81
+ export {
82
+ DropOverlay,
83
+ dragHasFiles,
84
+ splitDropped
85
+ };
86
+ //# sourceMappingURL=drop-overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/drop-overlay/drop-overlay.tsx","../src/drop-overlay/files.ts"],"sourcesContent":["// Client (window listeners). The whole window is the drop target: while files are dragged over the page a full-window overlay\n// says so, and the dropped files go to `onFiles` (accepted, rejected). No dashed box in the page; the product keeps a real\n// file input behind its primary action for the keyboard and for phones. Motion: motion.css (« DROP OVERLAY »).\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { type AcceptRule, dragHasFiles, splitDropped } from \"./files\";\n\nexport type DropOverlayProps = Omit<React.ComponentProps<\"div\">, \"children\" | \"onDrop\"> & {\n /** What the overlay says (“Drop to check”) — passed translated. */\n label: string;\n /** One line under it (“PDF or text”). */\n hint?: string;\n /** The files dropped: the accepted ones, then the ones `accept` refused. */\n onFiles: (accepted: File[], rejected: File[]) => void;\n /** What is accepted: MIME types, families (`image/*`) or extensions (`.pdf`). */\n accept?: readonly AcceptRule[];\n /** Turns the window back into a plain page (while a modal is open, signed out). */\n disabled?: boolean;\n};\n\n/** Drag a file anywhere on the page: a full-window overlay accepts it. */\nexport function DropOverlay({ label, hint, onFiles, accept, disabled, className, ...props }: DropOverlayProps) {\n const [active, setActive] = React.useState(false);\n const depth = React.useRef(0);\n const latest = React.useRef({ onFiles, accept });\n React.useEffect(() => {\n latest.current = { onFiles, accept };\n });\n\n React.useEffect(() => {\n if (disabled) return;\n const reset = () => {\n depth.current = 0;\n setActive(false);\n };\n const carrying = (event: Event) => dragHasFiles((event as DragEvent).dataTransfer);\n const enter = (event: Event) => {\n if (!carrying(event)) return;\n depth.current += 1;\n setActive(true);\n };\n const over = (event: Event) => {\n if (carrying(event)) event.preventDefault();\n };\n const leave = (event: Event) => {\n if (!carrying(event)) return;\n depth.current = Math.max(0, depth.current - 1);\n if (depth.current === 0) setActive(false);\n };\n const drop = (event: Event) => {\n if (!carrying(event)) return;\n event.preventDefault();\n const files = Array.from((event as DragEvent).dataTransfer?.files ?? []);\n reset();\n const { accepted, rejected } = splitDropped(files, latest.current.accept);\n latest.current.onFiles(accepted, rejected);\n };\n window.addEventListener(\"dragenter\", enter);\n window.addEventListener(\"dragover\", over);\n window.addEventListener(\"dragleave\", leave);\n window.addEventListener(\"drop\", drop);\n return () => {\n window.removeEventListener(\"dragenter\", enter);\n window.removeEventListener(\"dragover\", over);\n window.removeEventListener(\"dragleave\", leave);\n window.removeEventListener(\"drop\", drop);\n reset();\n };\n }, [disabled]);\n\n if (!active) return null;\n return (\n <div role=\"status\" data-state=\"open\" className={cn(\"kz-drop-overlay\", className)} {...props}>\n <div className=\"kz-drop-overlay-card\">\n <span className=\"text-lg font-semibold text-fg\">{label}</span>\n {hint ? <span className=\"text-sm text-fg-secondary\">{hint}</span> : null}\n </div>\n </div>\n );\n}\n","// Headless: what a drag carries and which of the dropped files a product accepts.\n\n/** True while the drag carries files (not text or a link): the only drag that should raise the overlay. */\nexport function dragHasFiles(transfer: { types?: readonly string[] | DOMStringList } | null | undefined): boolean {\n return Array.from(transfer?.types ?? []).includes(\"Files\");\n}\n\n/** One accepted kind: a MIME type (`application/pdf`), a family (`image/*`) or an extension (`.pdf`). */\nexport type AcceptRule = string;\n\nfunction matches(file: Pick<File, \"name\" | \"type\">, rule: AcceptRule): boolean {\n const wanted = rule.trim().toLowerCase();\n if (wanted.startsWith(\".\")) return file.name.toLowerCase().endsWith(wanted);\n if (wanted.endsWith(\"/*\")) return file.type.toLowerCase().startsWith(wanted.slice(0, -1));\n return file.type.toLowerCase() === wanted;\n}\n\nexport interface DropSplit<F> {\n accepted: F[];\n rejected: F[];\n}\n\n/** Splits dropped files by `accept` (no rule: everything is accepted). */\nexport function splitDropped<F extends Pick<File, \"name\" | \"type\">>(files: readonly F[], accept?: readonly AcceptRule[]): DropSplit<F> {\n if (!accept || accept.length === 0) return { accepted: [...files], rejected: [] };\n const accepted: F[] = [];\n const rejected: F[] = [];\n for (const file of files) (accept.some((rule) => matches(file, rule)) ? accepted : rejected).push(file);\n return { accepted, rejected };\n}\n"],"mappings":"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","names":[]}
package/dist/motion.css CHANGED
@@ -768,3 +768,30 @@ svg[data-kz-icon="ExternalIcon"] {
768
768
  @media (prefers-reduced-motion: reduce) {
769
769
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
770
770
  }
771
+
772
+ /* ── DROP OVERLAY ───────────────────────────────────────────────────────────────────────────────────────────────────
773
+ <DropOverlay> (@krizaka/ui/drop-overlay): while files are dragged over the window, a full-window veil and one centred
774
+ card arrive over the motion tokens. It never takes the pointer (the window keeps receiving the drop). Reduced motion:
775
+ it appears at once. */
776
+ .kz-drop-overlay {
777
+ position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center; pointer-events: none;
778
+ background: color-mix(in srgb, var(--kz-surface-0) 78%, transparent); backdrop-filter: blur(6px);
779
+ animation: kz-drop-in var(--kz-motion-duration-base) var(--kz-motion-ease-out) both;
780
+ }
781
+ .kz-drop-overlay-card {
782
+ display: flex; flex-direction: column; align-items: center; gap: 0.25rem; padding: 2rem 2.5rem; text-align: center;
783
+ border: 2px solid var(--kz-accent); border-radius: 1rem; background: var(--kz-surface-1);
784
+ animation: kz-drop-card var(--kz-motion-duration-base) var(--kz-motion-ease-out) both;
785
+ }
786
+ @keyframes kz-drop-in { from { opacity: 0; } to { opacity: 1; } }
787
+ @keyframes kz-drop-card { from { opacity: 0; transform: translateY(8px) scale(0.98); } to { opacity: 1; transform: none; } }
788
+ @media (prefers-reduced-motion: reduce) { .kz-drop-overlay, .kz-drop-overlay-card { animation: none; } }
789
+
790
+ /* ── WORKING (upload queue, task tray) ──────────────────────────────────────────────────────────────────────────────
791
+ What is working moves, nothing else (.kz-working): a row's progress fill shimmers (text never animates: contrast stays AA). The tray rises in.
792
+ Reduced motion: no shimmer, no rise. */
793
+ .kz-working { background-image: linear-gradient(100deg, transparent 30%, color-mix(in srgb, var(--kz-fg) 22%, transparent) 50%, transparent 70%); background-size: 200% 100%; background-repeat: no-repeat; animation: kz-shimmer 1.6s linear infinite; }
794
+ @keyframes kz-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
795
+ .kz-tray { animation: kz-tray-in var(--kz-motion-duration-base) var(--kz-motion-ease-out) both; }
796
+ @keyframes kz-tray-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
797
+ @media (prefers-reduced-motion: reduce) { .kz-working, .kz-tray { animation: none; background-image: none; } }
package/dist/nav-bar.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as tailwind_variants from 'tailwind-variants';
2
2
  import { NavigationMenu } from 'radix-ui';
3
3
  import * as React from 'react';
4
4
  import { LanguageSwitchProps } from './language-switch.js';
5
- import { S as SiteId, F as FamilyLabels } from './sites-inztN_Bv.js';
5
+ import { S as SiteId, F as FamilyLabels } from './sites-DlR8jicc.js';
6
6
 
7
7
  declare const navBar: tailwind_variants.TVReturnType<{
8
8
  floating: {
package/dist/nav-bar.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  GitHubGlyph,
8
8
  familyLabels,
9
9
  sitesByGroup
10
- } from "./chunk-P4TTKYC4.js";
10
+ } from "./chunk-4LYKBSOG.js";
11
11
  import {
12
12
  useSlidingIndicator
13
13
  } from "./chunk-4QN5YJ3D.js";
@@ -1,6 +1,28 @@
1
1
  import * as tailwind_variants from 'tailwind-variants';
2
2
  import * as React from 'react';
3
3
 
4
+ /** Where an inline save is: nothing to say, in flight, done (for a moment), or failed. */
5
+ declare const SaveStatus: {
6
+ readonly Idle: "idle";
7
+ readonly Saving: "saving";
8
+ readonly Saved: "saved";
9
+ readonly Error: "error";
10
+ };
11
+ type SaveStatus = (typeof SaveStatus)[keyof typeof SaveStatus];
12
+ /** How long « Saved » stays before the section goes quiet again. */
13
+ declare const SAVED_VISIBLE_MS = 4000;
14
+ interface SaveTracker {
15
+ status: SaveStatus;
16
+ /** The failure of the last try, for the message beside the button. */
17
+ error: unknown;
18
+ /** Runs a save: `saving`, then `saved` (back to `idle` after a moment) or `error`. Never rejects. */
19
+ track: (save: () => Promise<unknown>) => Promise<boolean>;
20
+ /** Clears the status (the form was edited again, or the save was undone). */
21
+ reset: () => void;
22
+ }
23
+ /** The status of one section's save. Feed it to `SettingsSection`'s `save.status`. */
24
+ declare function useSaveStatus(): SaveTracker;
25
+
4
26
  declare const settingsLayout: tailwind_variants.TVReturnType<{
5
27
  variant: {
6
28
  card: {};
@@ -21,6 +43,18 @@ declare const settingsLayout: tailwind_variants.TVReturnType<{
21
43
  nav: string;
22
44
  navList: string;
23
45
  navLink: string;
46
+ sidebar: string;
47
+ sidebarList: string;
48
+ group: string;
49
+ groupLabel: string;
50
+ groupLink: string;
51
+ groupItems: string;
52
+ menu: string;
53
+ menuSummary: string;
54
+ menuChevron: string;
55
+ menuPanel: string;
56
+ navBadge: string;
57
+ header: string;
24
58
  content: string;
25
59
  section: string;
26
60
  sectionHead: string;
@@ -54,6 +88,18 @@ declare const settingsLayout: tailwind_variants.TVReturnType<{
54
88
  nav: string;
55
89
  navList: string;
56
90
  navLink: string;
91
+ sidebar: string;
92
+ sidebarList: string;
93
+ group: string;
94
+ groupLabel: string;
95
+ groupLink: string;
96
+ groupItems: string;
97
+ menu: string;
98
+ menuSummary: string;
99
+ menuChevron: string;
100
+ menuPanel: string;
101
+ navBadge: string;
102
+ header: string;
57
103
  content: string;
58
104
  section: string;
59
105
  sectionHead: string;
@@ -87,6 +133,18 @@ declare const settingsLayout: tailwind_variants.TVReturnType<{
87
133
  nav: string;
88
134
  navList: string;
89
135
  navLink: string;
136
+ sidebar: string;
137
+ sidebarList: string;
138
+ group: string;
139
+ groupLabel: string;
140
+ groupLink: string;
141
+ groupItems: string;
142
+ menu: string;
143
+ menuSummary: string;
144
+ menuChevron: string;
145
+ menuPanel: string;
146
+ navBadge: string;
147
+ header: string;
90
148
  content: string;
91
149
  section: string;
92
150
  sectionHead: string;
@@ -112,14 +170,27 @@ interface SettingsNavItem {
112
170
  icon?: React.ReactNode;
113
171
  /** The section shown now: `aria-current`. */
114
172
  current?: boolean;
173
+ /** A small count or status after the label (`3`, `New`). */
174
+ badge?: React.ReactNode;
175
+ }
176
+ interface SettingsNavGroup {
177
+ /** Its id. */
178
+ id: string;
179
+ /** The group's title (`Library`, `Money`). */
180
+ label: string;
181
+ items: readonly SettingsNavItem[];
115
182
  }
183
+ /** Past this many sections a phone gets one menu instead of a strip of chips (« never more than about 5 items in a horizontal tab bar »). */
184
+ declare const SETTINGS_CHIPS_MAX = 5;
116
185
  type SettingsLayoutProps = Omit<React.ComponentProps<"div">, "title"> & {
117
186
  /** The screen's title (`Settings`). */
118
187
  title?: React.ReactNode;
119
188
  /** One sentence under it. */
120
189
  description?: React.ReactNode;
121
- /** The sections. */
122
- nav: readonly SettingsNavItem[];
190
+ /** What the screen is about, above the sections: who the account is, with their actions. Replaces `title` and `description`. */
191
+ header?: React.ReactNode;
192
+ /** The sections, alone or in titled groups. */
193
+ nav: readonly SettingsNavItem[] | readonly SettingsNavGroup[];
123
194
  /** The navigation's accessible name (`Settings sections`). */
124
195
  navLabel: string;
125
196
  /** The app's link component for the sections (Next's `Link`); an `<a>` otherwise. */
@@ -132,9 +203,42 @@ type SettingsLayoutProps = Omit<React.ComponentProps<"div">, "title"> & {
132
203
  /** The current section's forms (`SettingsSection`). */
133
204
  children: React.ReactNode;
134
205
  };
135
- /** A settings screen: sections on the left (chips on a phone), forms on the right. */
136
- declare function SettingsLayout({ title, description, nav, navLabel, linkAs: Link, variant, className, children, ...props }: SettingsLayoutProps): React.JSX.Element;
206
+ /** A settings screen: sections on the left (chips on a phone, one menu past five), forms on the right. */
207
+ declare function SettingsLayout({ title, description, header, nav, navLabel, linkAs: Link, variant, className, children, ...props }: SettingsLayoutProps): React.JSX.Element;
208
+ interface SectionSaveLabels {
209
+ /** “Save”. */
210
+ save: string;
211
+ /** “Saving…”. */
212
+ saving: string;
213
+ /** “Saved”. */
214
+ saved: string;
215
+ /** What failed, one sentence (“Could not save. Try again.”). */
216
+ error: string;
217
+ /** “Undo” — only shown after a save, when `onUndo` is given. */
218
+ undo: string;
219
+ /** “Discard changes” — only shown while dirty, when `onDiscard` is given. */
220
+ discard: string;
221
+ }
222
+ /** The one save of a section: its dirty state, its status, its words. */
223
+ interface SectionSave {
224
+ /** Whether a field differs from what is saved: the save is enabled only then. */
225
+ dirty: boolean;
226
+ /** Where the save is (`useSaveStatus().status`). */
227
+ status: SaveStatus;
228
+ /** Saves the section (the form's submit, Enter included). */
229
+ onSave: () => void;
230
+ /** Puts the previous values back after a save, optimistic update included. */
231
+ onUndo?: () => void;
232
+ /** Throws the edits away while dirty. */
233
+ onDiscard?: () => void;
234
+ labels: SectionSaveLabels;
235
+ }
137
236
  type SettingsSectionProps = Omit<React.ComponentProps<"section">, "title"> & {
237
+ /**
238
+ * One save for the whole section: the section becomes a form, the foot shows the Save (enabled while dirty), the
239
+ * result in a live region (saved, or the error as an alert) and an undo after a save. Replaces `footer`.
240
+ */
241
+ save?: SectionSave;
138
242
  /** The section's title: it names the region (and is its anchor's target when `id` is set). */
139
243
  title: React.ReactNode;
140
244
  /** What these settings change, in one sentence. */
@@ -146,11 +250,11 @@ type SettingsSectionProps = Omit<React.ComponentProps<"section">, "title"> & {
146
250
  * @default "card"
147
251
  */
148
252
  variant?: "card" | "flat";
149
- /** The fields (or, flat, the `SettingsRow`s). */
150
- children: React.ReactNode;
253
+ /** The fields (or, flat, the `SettingsRow`s). A section of a title, a sentence and a foot action has none. */
254
+ children?: React.ReactNode;
151
255
  };
152
256
  /** A group of settings: a titled card with its fields and its own save, or flat rows under a title. */
153
- declare function SettingsSection({ title, description, footer, variant, id, className, children, ...props }: SettingsSectionProps): React.JSX.Element;
257
+ declare function SettingsSection({ title, description, footer, save, variant, id, className, children, ...props }: SettingsSectionProps): React.JSX.Element;
154
258
  type SettingsRowProps = Omit<React.ComponentProps<"div">, "title"> & {
155
259
  /** What the setting is (`Username`). */
156
260
  label: React.ReactNode;
@@ -164,4 +268,4 @@ type SettingsRowProps = Omit<React.ComponentProps<"div">, "title"> & {
164
268
  /** One setting: its label and help on the left, its control or value on the right. Put rows in a flat `SettingsSection`. */
165
269
  declare function SettingsRow({ label, description, htmlFor, className, children, ...props }: SettingsRowProps): React.JSX.Element;
166
270
 
167
- export { SettingsLayout, type SettingsLayoutProps, type SettingsNavItem, SettingsRow, type SettingsRowProps, SettingsSection, type SettingsSectionProps, settingsLayout };
271
+ export { SAVED_VISIBLE_MS, SETTINGS_CHIPS_MAX, SaveStatus, type SaveTracker, SettingsLayout, type SettingsLayoutProps, type SettingsNavGroup, type SettingsNavItem, SettingsRow, type SettingsRowProps, SettingsSection, type SettingsSectionProps, settingsLayout, useSaveStatus };