@openrails/contentkit-ui 0.0.0-stage → 0.68.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 +470 -2
- package/dist/appearance.d.ts +38 -0
- package/dist/appearance.js +15 -0
- package/dist/appearance.js.map +1 -0
- package/dist/assets/hash.worker-BYfo-7MQ.js.map +1 -0
- package/dist/client/aspect.d.ts +6 -0
- package/dist/client/aspect.js +17 -0
- package/dist/client/aspect.js.map +1 -0
- package/dist/client/client.d.ts +53 -0
- package/dist/client/client.js +36 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/codes.d.ts +12 -0
- package/dist/client/codes.js +19 -0
- package/dist/client/codes.js.map +1 -0
- package/dist/client/content/bans.d.ts +15 -0
- package/dist/client/content/bans.js +40 -0
- package/dist/client/content/bans.js.map +1 -0
- package/dist/client/content/comments.d.ts +36 -0
- package/dist/client/content/comments.js +95 -0
- package/dist/client/content/comments.js.map +1 -0
- package/dist/client/content/favorites.d.ts +14 -0
- package/dist/client/content/favorites.js +42 -0
- package/dist/client/content/favorites.js.map +1 -0
- package/dist/client/content/moderation.d.ts +18 -0
- package/dist/client/content/moderation.js +37 -0
- package/dist/client/content/moderation.js.map +1 -0
- package/dist/client/content/polls.d.ts +47 -0
- package/dist/client/content/polls.js +151 -0
- package/dist/client/content/polls.js.map +1 -0
- package/dist/client/content/posts.d.ts +44 -0
- package/dist/client/content/posts.js +92 -0
- package/dist/client/content/posts.js.map +1 -0
- package/dist/client/content/reactions.d.ts +12 -0
- package/dist/client/content/reactions.js +36 -0
- package/dist/client/content/reactions.js.map +1 -0
- package/dist/client/content/types.d.ts +91 -0
- package/dist/client/content/types.js +8 -0
- package/dist/client/content/types.js.map +1 -0
- package/dist/client/crop.d.ts +32 -0
- package/dist/client/crop.js +103 -0
- package/dist/client/crop.js.map +1 -0
- package/dist/client/errors.d.ts +54 -0
- package/dist/client/errors.js +80 -0
- package/dist/client/errors.js.map +1 -0
- package/dist/client/gallery.d.ts +43 -0
- package/dist/client/gallery.js +86 -0
- package/dist/client/gallery.js.map +1 -0
- package/dist/client/generated/error-codes.d.ts +5 -0
- package/dist/client/generated/error-codes.js +131 -0
- package/dist/client/generated/error-codes.js.map +1 -0
- package/dist/client/generated/routes.d.ts +1086 -0
- package/dist/client/generated/routes.js +1400 -0
- package/dist/client/generated/routes.js.map +1 -0
- package/dist/client/generated/wire.d.ts +630 -0
- package/dist/client/generated/wire.js +6 -0
- package/dist/client/generated/wire.js.map +1 -0
- package/dist/client/http.d.ts +83 -0
- package/dist/client/http.js +82 -0
- package/dist/client/http.js.map +1 -0
- package/dist/client/image.d.ts +24 -0
- package/dist/client/image.js +65 -0
- package/dist/client/image.js.map +1 -0
- package/dist/client/index.d.ts +33 -0
- package/dist/client/media/api.d.ts +36 -0
- package/dist/client/media/api.js +61 -0
- package/dist/client/media/api.js.map +1 -0
- package/dist/client/media/client.d.ts +247 -0
- package/dist/client/media/client.js +407 -0
- package/dist/client/media/client.js.map +1 -0
- package/dist/client/media/encode.d.ts +3 -0
- package/dist/client/media/encode.js +8 -0
- package/dist/client/media/encode.js.map +1 -0
- package/dist/client/media/hash-stream.d.ts +6 -0
- package/dist/client/media/hash-stream.js +16 -0
- package/dist/client/media/hash-stream.js.map +1 -0
- package/dist/client/media/hash.d.ts +12 -0
- package/dist/client/media/hash.js +48 -0
- package/dist/client/media/hash.js.map +1 -0
- package/dist/client/media/hash.worker-inline.js +18 -0
- package/dist/client/media/hash.worker-inline.js.map +1 -0
- package/dist/client/media/pacer.d.ts +21 -0
- package/dist/client/media/pacer.js +25 -0
- package/dist/client/media/pacer.js.map +1 -0
- package/dist/client/media/queue.d.ts +112 -0
- package/dist/client/media/queue.js +274 -0
- package/dist/client/media/queue.js.map +1 -0
- package/dist/client/media/ref.d.ts +6 -0
- package/dist/client/media/ref.js +10 -0
- package/dist/client/media/ref.js.map +1 -0
- package/dist/client/media/rules.d.ts +54 -0
- package/dist/client/media/rules.js +143 -0
- package/dist/client/media/rules.js.map +1 -0
- package/dist/client/media/transport.d.ts +13 -0
- package/dist/client/media/transport.js +33 -0
- package/dist/client/media/transport.js.map +1 -0
- package/dist/client/media/windows.d.ts +15 -0
- package/dist/client/media/windows.js +39 -0
- package/dist/client/media/windows.js.map +1 -0
- package/dist/client/playback.d.ts +200 -0
- package/dist/client/playback.js +142 -0
- package/dist/client/playback.js.map +1 -0
- package/dist/client/player.d.ts +102 -0
- package/dist/client/player.js +155 -0
- package/dist/client/player.js.map +1 -0
- package/dist/client/public.d.ts +25 -0
- package/dist/client/public.js +18 -0
- package/dist/client/public.js.map +1 -0
- package/dist/client/rendition.d.ts +19 -0
- package/dist/client/rendition.js +16 -0
- package/dist/client/rendition.js.map +1 -0
- package/dist/client/route.d.ts +39 -0
- package/dist/client/route.js +31 -0
- package/dist/client/route.js.map +1 -0
- package/dist/client/taxonomy.d.ts +30 -0
- package/dist/client/taxonomy.js +77 -0
- package/dist/client/taxonomy.js.map +1 -0
- package/dist/client.js +33 -0
- package/dist/components/encode-progress.d.ts +15 -0
- package/dist/components/encode-progress.js +49 -0
- package/dist/components/encode-progress.js.map +1 -0
- package/dist/components/hover-preview.d.ts +29 -0
- package/dist/components/hover-preview.js +49 -0
- package/dist/components/hover-preview.js.map +1 -0
- package/dist/components/image-crop-dialog.d.ts +48 -0
- package/dist/components/image-crop-dialog.js +359 -0
- package/dist/components/image-crop-dialog.js.map +1 -0
- package/dist/components/lazy-mount.d.ts +10 -0
- package/dist/components/lazy-mount.js +22 -0
- package/dist/components/lazy-mount.js.map +1 -0
- package/dist/components/media-folder-editor.d.ts +59 -0
- package/dist/components/media-folder-editor.js +611 -0
- package/dist/components/media-folder-editor.js.map +1 -0
- package/dist/components/media-gallery.d.ts +54 -0
- package/dist/components/media-gallery.js +597 -0
- package/dist/components/media-gallery.js.map +1 -0
- package/dist/components/media-readiness-notice.d.ts +24 -0
- package/dist/components/media-readiness-notice.js +61 -0
- package/dist/components/media-readiness-notice.js.map +1 -0
- package/dist/components/player-controls.d.ts +71 -0
- package/dist/components/player-controls.js +264 -0
- package/dist/components/player-controls.js.map +1 -0
- package/dist/components/progress.d.ts +5 -0
- package/dist/components/progress.js +14 -0
- package/dist/components/progress.js.map +1 -0
- package/dist/components/rendition-img.d.ts +34 -0
- package/dist/components/rendition-img.js +78 -0
- package/dist/components/rendition-img.js.map +1 -0
- package/dist/components/slot-editor.d.ts +95 -0
- package/dist/components/slot-editor.js +182 -0
- package/dist/components/slot-editor.js.map +1 -0
- package/dist/components/slot-image.d.ts +23 -0
- package/dist/components/slot-image.js +48 -0
- package/dist/components/slot-image.js.map +1 -0
- package/dist/components/slot-upload.d.ts +41 -0
- package/dist/components/slot-upload.js +215 -0
- package/dist/components/slot-upload.js.map +1 -0
- package/dist/components/social/bans.d.ts +42 -0
- package/dist/components/social/bans.js +300 -0
- package/dist/components/social/bans.js.map +1 -0
- package/dist/components/social/comments.d.ts +42 -0
- package/dist/components/social/comments.js +517 -0
- package/dist/components/social/comments.js.map +1 -0
- package/dist/components/social/engagement.d.ts +45 -0
- package/dist/components/social/engagement.js +129 -0
- package/dist/components/social/engagement.js.map +1 -0
- package/dist/components/social/index.d.ts +6 -0
- package/dist/components/social/moderation.d.ts +32 -0
- package/dist/components/social/moderation.js +383 -0
- package/dist/components/social/moderation.js.map +1 -0
- package/dist/components/social/parts.d.ts +50 -0
- package/dist/components/social/parts.js +106 -0
- package/dist/components/social/parts.js.map +1 -0
- package/dist/components/social/poll-editor.d.ts +34 -0
- package/dist/components/social/poll-editor.js +567 -0
- package/dist/components/social/poll-editor.js.map +1 -0
- package/dist/components/social/poll.d.ts +30 -0
- package/dist/components/social/poll.js +252 -0
- package/dist/components/social/poll.js.map +1 -0
- package/dist/components/sortable-list.d.ts +29 -0
- package/dist/components/sortable-list.js +121 -0
- package/dist/components/sortable-list.js.map +1 -0
- package/dist/components/video-mini-player.d.ts +35 -0
- package/dist/components/video-mini-player.js +236 -0
- package/dist/components/video-mini-player.js.map +1 -0
- package/dist/components/video-player.d.ts +146 -0
- package/dist/components/video-player.js +630 -0
- package/dist/components/video-player.js.map +1 -0
- package/dist/components/video-poster-picker.d.ts +59 -0
- package/dist/components/video-poster-picker.js +335 -0
- package/dist/components/video-poster-picker.js.map +1 -0
- package/dist/components/video-poster.d.ts +24 -0
- package/dist/components/video-poster.js +46 -0
- package/dist/components/video-poster.js.map +1 -0
- package/dist/i18n/context.d.ts +4 -0
- package/dist/i18n/context.js +11 -0
- package/dist/i18n/context.js.map +1 -0
- package/dist/i18n/messages.d.ts +40 -0
- package/dist/i18n/messages.js +94 -0
- package/dist/i18n/messages.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +41 -0
- package/dist/locales/de.d.ts +2 -0
- package/dist/locales/de.js +271 -0
- package/dist/locales/de.js.map +1 -0
- package/dist/locales/en.d.ts +457 -0
- package/dist/locales/en.js +271 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/es.d.ts +2 -0
- package/dist/locales/es.js +271 -0
- package/dist/locales/es.js.map +1 -0
- package/dist/locales/ja.d.ts +2 -0
- package/dist/locales/ja.js +271 -0
- package/dist/locales/ja.js.map +1 -0
- package/dist/locales/ko.d.ts +2 -0
- package/dist/locales/ko.js +271 -0
- package/dist/locales/ko.js.map +1 -0
- package/dist/locales/social/de.d.ts +2 -0
- package/dist/locales/social/de.js +198 -0
- package/dist/locales/social/de.js.map +1 -0
- package/dist/locales/social/en.d.ts +195 -0
- package/dist/locales/social/en.js +198 -0
- package/dist/locales/social/en.js.map +1 -0
- package/dist/locales/social/es.d.ts +2 -0
- package/dist/locales/social/es.js +198 -0
- package/dist/locales/social/es.js.map +1 -0
- package/dist/locales/social/ja.d.ts +2 -0
- package/dist/locales/social/ja.js +198 -0
- package/dist/locales/social/ja.js.map +1 -0
- package/dist/locales/social/ko.d.ts +2 -0
- package/dist/locales/social/ko.js +198 -0
- package/dist/locales/social/ko.js.map +1 -0
- package/dist/locales/social/zh.d.ts +2 -0
- package/dist/locales/social/zh.js +198 -0
- package/dist/locales/social/zh.js.map +1 -0
- package/dist/locales/zh.d.ts +2 -0
- package/dist/locales/zh.js +271 -0
- package/dist/locales/zh.js.map +1 -0
- package/dist/provider.d.ts +22 -0
- package/dist/provider.js +59 -0
- package/dist/provider.js.map +1 -0
- package/dist/react/canonical.d.ts +33 -0
- package/dist/react/canonical.js +78 -0
- package/dist/react/canonical.js.map +1 -0
- package/dist/react/comments.d.ts +82 -0
- package/dist/react/comments.js +155 -0
- package/dist/react/comments.js.map +1 -0
- package/dist/react/config.d.ts +13 -0
- package/dist/react/config.js +14 -0
- package/dist/react/config.js.map +1 -0
- package/dist/react/context.d.ts +55 -0
- package/dist/react/context.js +42 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/crop.d.ts +49 -0
- package/dist/react/crop.js +107 -0
- package/dist/react/crop.js.map +1 -0
- package/dist/react/engagement.d.ts +38 -0
- package/dist/react/engagement.js +88 -0
- package/dist/react/engagement.js.map +1 -0
- package/dist/react/folder.d.ts +103 -0
- package/dist/react/folder.js +240 -0
- package/dist/react/folder.js.map +1 -0
- package/dist/react/gallery.d.ts +140 -0
- package/dist/react/gallery.js +477 -0
- package/dist/react/gallery.js.map +1 -0
- package/dist/react/index.d.ts +21 -0
- package/dist/react/inline-preview.d.ts +24 -0
- package/dist/react/inline-preview.js +76 -0
- package/dist/react/inline-preview.js.map +1 -0
- package/dist/react/player.d.ts +70 -0
- package/dist/react/player.js +214 -0
- package/dist/react/player.js.map +1 -0
- package/dist/react/polls.d.ts +74 -0
- package/dist/react/polls.js +176 -0
- package/dist/react/polls.js.map +1 -0
- package/dist/react/posts.d.ts +59 -0
- package/dist/react/posts.js +149 -0
- package/dist/react/posts.js.map +1 -0
- package/dist/react/provider.d.ts +27 -0
- package/dist/react/provider.js +49 -0
- package/dist/react/provider.js.map +1 -0
- package/dist/react/public.d.ts +39 -0
- package/dist/react/public.js +70 -0
- package/dist/react/public.js.map +1 -0
- package/dist/react/read.d.ts +52 -0
- package/dist/react/read.js +144 -0
- package/dist/react/read.js.map +1 -0
- package/dist/react/resources.d.ts +73 -0
- package/dist/react/resources.js +247 -0
- package/dist/react/resources.js.map +1 -0
- package/dist/react/slot.d.ts +104 -0
- package/dist/react/slot.js +185 -0
- package/dist/react/slot.js.map +1 -0
- package/dist/react/store.d.ts +51 -0
- package/dist/react/store.js +165 -0
- package/dist/react/store.js.map +1 -0
- package/dist/react/upload.d.ts +86 -0
- package/dist/react/upload.js +155 -0
- package/dist/react/upload.js.map +1 -0
- package/dist/react/use-resource.d.ts +44 -0
- package/dist/react/use-resource.js +74 -0
- package/dist/react/use-resource.js.map +1 -0
- package/dist/react/video.d.ts +118 -0
- package/dist/react/video.js +184 -0
- package/dist/react/video.js.map +1 -0
- package/dist/react/viewport.d.ts +19 -0
- package/dist/react/viewport.js +30 -0
- package/dist/react/viewport.js.map +1 -0
- package/dist/react.js +21 -0
- package/dist/scope.d.ts +14 -0
- package/dist/scope.js +30 -0
- package/dist/scope.js.map +1 -0
- package/dist/styles.css +3 -0
- package/dist/ui/alert-dialog.d.ts +18 -0
- package/dist/ui/alert-dialog.js +86 -0
- package/dist/ui/alert-dialog.js.map +1 -0
- package/dist/ui/alert.d.ts +10 -0
- package/dist/ui/alert.js +38 -0
- package/dist/ui/alert.js.map +1 -0
- package/dist/ui/avatar.d.ts +11 -0
- package/dist/ui/avatar.js +31 -0
- package/dist/ui/avatar.js.map +1 -0
- package/dist/ui/badge.d.ts +7 -0
- package/dist/ui/badge.js +31 -0
- package/dist/ui/badge.js.map +1 -0
- package/dist/ui/button.d.ts +8 -0
- package/dist/ui/button.js +46 -0
- package/dist/ui/button.js.map +1 -0
- package/dist/ui/dialog.d.ts +17 -0
- package/dist/ui/dialog.js +91 -0
- package/dist/ui/dialog.js.map +1 -0
- package/dist/ui/dropdown-menu.d.ts +15 -0
- package/dist/ui/dropdown-menu.js +105 -0
- package/dist/ui/dropdown-menu.js.map +1 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.js +17 -0
- package/dist/ui/input.js.map +1 -0
- package/dist/ui/label.d.ts +3 -0
- package/dist/ui/label.js +15 -0
- package/dist/ui/label.js.map +1 -0
- package/dist/ui/progress.d.ts +7 -0
- package/dist/ui/progress.js +31 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/select.d.ts +15 -0
- package/dist/ui/select.js +98 -0
- package/dist/ui/select.js.map +1 -0
- package/dist/ui/skeleton.d.ts +2 -0
- package/dist/ui/skeleton.js +14 -0
- package/dist/ui/skeleton.js.map +1 -0
- package/dist/ui/slider.d.ts +3 -0
- package/dist/ui/slider.js +35 -0
- package/dist/ui/slider.js.map +1 -0
- package/dist/ui/switch.d.ts +5 -0
- package/dist/ui/switch.js +20 -0
- package/dist/ui/switch.js.map +1 -0
- package/dist/ui/tabs.d.ts +10 -0
- package/dist/ui/tabs.js +47 -0
- package/dist/ui/tabs.js.map +1 -0
- package/dist/ui/textarea.d.ts +3 -0
- package/dist/ui/textarea.js +15 -0
- package/dist/ui/textarea.js.map +1 -0
- package/dist/ui/toggle-group.d.ts +5 -0
- package/dist/ui/toggle-group.js +23 -0
- package/dist/ui/toggle-group.js.map +1 -0
- package/dist/urls/index.d.ts +100 -0
- package/dist/urls.js +118 -0
- package/dist/urls.js.map +1 -0
- package/package.json +120 -3
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { aspectOf as e, ratio as t } from "../client/aspect.js";
|
|
2
|
+
import { useMessages as n } from "../i18n/context.js";
|
|
3
|
+
import { editedSize as r, rotation as i, toRotated as a } from "../client/crop.js";
|
|
4
|
+
import { useCrop as o } from "../react/upload.js";
|
|
5
|
+
import { Progress as s } from "../ui/progress.js";
|
|
6
|
+
import { editOutput as c } from "../react/slot.js";
|
|
7
|
+
import { Alert as l, AlertDescription as u } from "../ui/alert.js";
|
|
8
|
+
import { Button as d } from "../ui/button.js";
|
|
9
|
+
import { Dialog as f, DialogContent as p, DialogDescription as m, DialogFooter as h, DialogHeader as g, DialogTitle as _ } from "../ui/dialog.js";
|
|
10
|
+
import { Slider as ee } from "../ui/slider.js";
|
|
11
|
+
import { progressLabel as v, progressValue as y } from "./progress.js";
|
|
12
|
+
import { useEffect as b, useMemo as te, useRef as x, useState as S } from "react";
|
|
13
|
+
import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
14
|
+
import { cn as E } from "cn";
|
|
15
|
+
import { Alert02Icon as D, Image01Icon as O, RotateClockwiseIcon as k } from "@hugeicons/core-free-icons";
|
|
16
|
+
import { HugeiconsIcon as A } from "@hugeicons/react";
|
|
17
|
+
import ne from "react-easy-crop";
|
|
18
|
+
//#region src/components/image-crop-dialog.tsx
|
|
19
|
+
var re = 5, j = .25;
|
|
20
|
+
function M(e) {
|
|
21
|
+
let { t } = n(), r = !!e.busy;
|
|
22
|
+
return /* @__PURE__ */ w(f, {
|
|
23
|
+
open: e.open,
|
|
24
|
+
onOpenChange: (t) => !r && e.onOpenChange(t),
|
|
25
|
+
children: /* @__PURE__ */ T(p, {
|
|
26
|
+
className: E("gap-0 overflow-hidden p-0 sm:max-w-xl", e.className),
|
|
27
|
+
showCloseButton: !r,
|
|
28
|
+
"data-ckui": "crop-dialog",
|
|
29
|
+
children: [/* @__PURE__ */ T(g, {
|
|
30
|
+
className: "px-5 pt-5 pb-4 pr-12",
|
|
31
|
+
children: [/* @__PURE__ */ w(_, { children: e.title ?? t("crop.title") }), /* @__PURE__ */ w(m, { children: e.description ?? t("crop.description") })]
|
|
32
|
+
}), e.source && /* @__PURE__ */ w(N, {
|
|
33
|
+
...e,
|
|
34
|
+
source: e.source
|
|
35
|
+
}, e.source.url)]
|
|
36
|
+
})
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function N(e) {
|
|
40
|
+
let { t } = n(), r = e.aspects?.length ? e.aspects : null, i = r && !r.includes(e.aspect) ? r[0] : e.aspect, [a, o] = S(i), s = r && r.length > 1 && /* @__PURE__ */ T("div", {
|
|
41
|
+
className: "flex items-center gap-2 px-5 pb-3",
|
|
42
|
+
"data-ckui": "crop-shapes",
|
|
43
|
+
children: [/* @__PURE__ */ w("span", {
|
|
44
|
+
className: "text-xs text-muted-foreground",
|
|
45
|
+
children: t("crop.shape")
|
|
46
|
+
}), /* @__PURE__ */ w("div", {
|
|
47
|
+
className: "inline-flex flex-wrap gap-0.5 rounded-lg bg-muted p-0.5",
|
|
48
|
+
role: "group",
|
|
49
|
+
"aria-label": t("crop.shape"),
|
|
50
|
+
children: r.map((n) => /* @__PURE__ */ w("button", {
|
|
51
|
+
type: "button",
|
|
52
|
+
"aria-pressed": a === n,
|
|
53
|
+
disabled: !!e.busy,
|
|
54
|
+
onClick: () => o(n),
|
|
55
|
+
className: E("inline-flex h-7 items-center rounded-md px-2.5 text-xs font-medium text-muted-foreground tabular-nums transition-colors outline-none hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50 disabled:opacity-50", a === n && "bg-background text-foreground shadow-xs"),
|
|
56
|
+
children: n || t("crop.original")
|
|
57
|
+
}, n || "original"))
|
|
58
|
+
})]
|
|
59
|
+
});
|
|
60
|
+
return /* @__PURE__ */ T(C, { children: [s, /* @__PURE__ */ w(P, {
|
|
61
|
+
...e,
|
|
62
|
+
aspect: a,
|
|
63
|
+
initialEdit: a === i ? e.initialEdit : null,
|
|
64
|
+
onReset: a === i ? void 0 : () => o(i)
|
|
65
|
+
}, a)] });
|
|
66
|
+
}
|
|
67
|
+
function P(a) {
|
|
68
|
+
let { t: f } = n(), { source: p } = a, [m, g] = S(() => i(a.initialEdit?.rotate ?? 0)), _ = t(a.aspect) ? a.aspect : m % 180 ? e(p.height, p.width) : e(p.width, p.height), E = te(() => ({
|
|
69
|
+
width: p.width,
|
|
70
|
+
height: p.height
|
|
71
|
+
}), [p.width, p.height]), M = o({
|
|
72
|
+
source: E,
|
|
73
|
+
aspect: _,
|
|
74
|
+
initial: a.initialEdit
|
|
75
|
+
}), N = x(_), { setCrop: P } = M;
|
|
76
|
+
b(() => {
|
|
77
|
+
N.current !== _ && (N.current = _, P({
|
|
78
|
+
x: 0,
|
|
79
|
+
y: 0,
|
|
80
|
+
w: E.width,
|
|
81
|
+
h: E.height
|
|
82
|
+
}));
|
|
83
|
+
}, [
|
|
84
|
+
_,
|
|
85
|
+
E,
|
|
86
|
+
P
|
|
87
|
+
]);
|
|
88
|
+
let [I, z] = S({
|
|
89
|
+
x: 0,
|
|
90
|
+
y: 0
|
|
91
|
+
}), [B, V] = S(1), [H, U] = S(!1), [W, ie] = S(() => a.initialEdit?.crop ? R(M.crop, E, M.rotate) : void 0), G = x(a.onEditChange);
|
|
92
|
+
G.current = a.onEditChange;
|
|
93
|
+
let K = !!a.busy;
|
|
94
|
+
b(() => G.current?.(M.edit), [M.edit]);
|
|
95
|
+
let q = c(E, M.edit, _), J = a.minWidth ?? 0, Y = c(E, { rotate: M.rotate }, _).width, X = Y < J, Z = X ? 1 : Math.max(1, Math.min(re, Y / Math.max(1, J))), ae = q.width < J, oe = !X && !!(a.targetWidth && q.width < a.targetWidth);
|
|
96
|
+
b(() => {
|
|
97
|
+
B > Z && V(Z);
|
|
98
|
+
}, [B, Z]);
|
|
99
|
+
let se = (e) => {
|
|
100
|
+
if (!(e.width > 0 && e.height > 0) || !Number.isFinite(e.x + e.y)) return;
|
|
101
|
+
let t = r(E, M.rotate), n = (e, t) => e / 100 * t;
|
|
102
|
+
M.setFromDisplay({
|
|
103
|
+
x: n(e.x, t.width),
|
|
104
|
+
y: n(e.y, t.height),
|
|
105
|
+
w: n(e.width, t.width),
|
|
106
|
+
h: n(e.height, t.height)
|
|
107
|
+
}, t);
|
|
108
|
+
}, Q = () => {
|
|
109
|
+
ie(void 0), z({
|
|
110
|
+
x: 0,
|
|
111
|
+
y: 0
|
|
112
|
+
}), V(1);
|
|
113
|
+
}, $ = (e) => {
|
|
114
|
+
g((t) => i(t + e)), M.rotateBy(e), Q();
|
|
115
|
+
};
|
|
116
|
+
return /* @__PURE__ */ T(C, { children: [
|
|
117
|
+
/* @__PURE__ */ w("div", {
|
|
118
|
+
className: "relative h-72 w-full bg-zinc-950 sm:h-80 [&_.reactEasyCrop_CropArea]:border-white/70 [&_.reactEasyCrop_CropArea]:text-black/65",
|
|
119
|
+
onKeyDown: (e) => {
|
|
120
|
+
if (!K) {
|
|
121
|
+
if (e.key === "+" || e.key === "=") V((e) => Math.min(Z, e + j));
|
|
122
|
+
else if (e.key === "-" || e.key === "_") V((e) => Math.max(1, e - j));
|
|
123
|
+
else if (a.rotatable !== !1 && (e.key === "r" || e.key === "R")) $(e.shiftKey ? -90 : 90);
|
|
124
|
+
else return;
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"data-ckui": "crop-stage",
|
|
129
|
+
children: /* @__PURE__ */ w("div", {
|
|
130
|
+
className: "absolute inset-3 sm:inset-4",
|
|
131
|
+
children: /* @__PURE__ */ w(ne, {
|
|
132
|
+
image: p.url,
|
|
133
|
+
crop: I,
|
|
134
|
+
zoom: B,
|
|
135
|
+
rotation: M.rotate,
|
|
136
|
+
aspect: t(_),
|
|
137
|
+
minZoom: 1,
|
|
138
|
+
maxZoom: Z,
|
|
139
|
+
zoomSpeed: .5,
|
|
140
|
+
cropShape: a.round ? "round" : "rect",
|
|
141
|
+
showGrid: !a.round || H,
|
|
142
|
+
objectFit: "contain",
|
|
143
|
+
initialCroppedAreaPercentages: W,
|
|
144
|
+
onCropChange: K ? F : z,
|
|
145
|
+
onZoomChange: K ? F : V,
|
|
146
|
+
onCropComplete: se,
|
|
147
|
+
onInteractionStart: () => U(!0),
|
|
148
|
+
onInteractionEnd: () => U(!1),
|
|
149
|
+
keyboardStep: 8,
|
|
150
|
+
disableAutomaticStylesInjection: !0,
|
|
151
|
+
mediaProps: {
|
|
152
|
+
alt: "",
|
|
153
|
+
draggable: !1
|
|
154
|
+
},
|
|
155
|
+
cropperProps: {
|
|
156
|
+
"aria-label": f("crop.area"),
|
|
157
|
+
role: "application"
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
}),
|
|
162
|
+
/* @__PURE__ */ T("div", {
|
|
163
|
+
className: "grid gap-3 px-5 pt-4",
|
|
164
|
+
children: [
|
|
165
|
+
/* @__PURE__ */ T("div", {
|
|
166
|
+
className: "flex items-center gap-1.5",
|
|
167
|
+
children: [
|
|
168
|
+
/* @__PURE__ */ w(d, {
|
|
169
|
+
variant: "ghost",
|
|
170
|
+
size: "icon-sm",
|
|
171
|
+
"aria-label": f("crop.zoomOut"),
|
|
172
|
+
disabled: K || B <= 1,
|
|
173
|
+
onClick: () => V((e) => Math.max(1, e - j)),
|
|
174
|
+
children: /* @__PURE__ */ w(A, {
|
|
175
|
+
icon: O,
|
|
176
|
+
strokeWidth: 2,
|
|
177
|
+
className: "size-3.5"
|
|
178
|
+
})
|
|
179
|
+
}),
|
|
180
|
+
/* @__PURE__ */ w(ee, {
|
|
181
|
+
"aria-label": f("crop.zoom"),
|
|
182
|
+
className: "mx-1 flex-1",
|
|
183
|
+
min: 1,
|
|
184
|
+
max: Z,
|
|
185
|
+
step: .01,
|
|
186
|
+
value: B,
|
|
187
|
+
disabled: K,
|
|
188
|
+
onValueChange: (e) => V(Array.isArray(e) ? e[0] : e)
|
|
189
|
+
}),
|
|
190
|
+
/* @__PURE__ */ w(d, {
|
|
191
|
+
variant: "ghost",
|
|
192
|
+
size: "icon-sm",
|
|
193
|
+
"aria-label": f("crop.zoomIn"),
|
|
194
|
+
disabled: K || B >= Z,
|
|
195
|
+
onClick: () => V((e) => Math.min(Z, e + j)),
|
|
196
|
+
children: /* @__PURE__ */ w(A, {
|
|
197
|
+
icon: O,
|
|
198
|
+
strokeWidth: 2,
|
|
199
|
+
className: "size-5"
|
|
200
|
+
})
|
|
201
|
+
}),
|
|
202
|
+
a.rotatable !== !1 && /* @__PURE__ */ T(C, { children: [
|
|
203
|
+
/* @__PURE__ */ w("span", {
|
|
204
|
+
className: "mx-1 h-5 w-px bg-border",
|
|
205
|
+
"aria-hidden": !0
|
|
206
|
+
}),
|
|
207
|
+
/* @__PURE__ */ w(d, {
|
|
208
|
+
variant: "ghost",
|
|
209
|
+
size: "icon-sm",
|
|
210
|
+
"aria-label": f("crop.rotateLeft"),
|
|
211
|
+
disabled: K,
|
|
212
|
+
onClick: () => $(-90),
|
|
213
|
+
children: /* @__PURE__ */ w(A, {
|
|
214
|
+
icon: k,
|
|
215
|
+
strokeWidth: 2
|
|
216
|
+
})
|
|
217
|
+
}),
|
|
218
|
+
/* @__PURE__ */ w(d, {
|
|
219
|
+
variant: "ghost",
|
|
220
|
+
size: "icon-sm",
|
|
221
|
+
"aria-label": f("crop.rotateRight"),
|
|
222
|
+
disabled: K,
|
|
223
|
+
onClick: () => $(90),
|
|
224
|
+
children: /* @__PURE__ */ w(A, {
|
|
225
|
+
icon: k,
|
|
226
|
+
strokeWidth: 2,
|
|
227
|
+
className: "-scale-x-100"
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
] }),
|
|
231
|
+
/* @__PURE__ */ w(d, {
|
|
232
|
+
variant: "ghost",
|
|
233
|
+
size: "sm",
|
|
234
|
+
disabled: K,
|
|
235
|
+
onClick: () => {
|
|
236
|
+
if (a.onReset) return a.onReset();
|
|
237
|
+
g(0), M.reset(), Q();
|
|
238
|
+
},
|
|
239
|
+
className: "text-muted-foreground",
|
|
240
|
+
children: f("crop.reset")
|
|
241
|
+
})
|
|
242
|
+
]
|
|
243
|
+
}),
|
|
244
|
+
a.preview !== !1 && /* @__PURE__ */ w(L, {
|
|
245
|
+
source: p,
|
|
246
|
+
crop: M.crop,
|
|
247
|
+
rotate: M.rotate,
|
|
248
|
+
round: a.round,
|
|
249
|
+
size: q
|
|
250
|
+
}),
|
|
251
|
+
X && /* @__PURE__ */ T(l, {
|
|
252
|
+
variant: "destructive",
|
|
253
|
+
role: "alert",
|
|
254
|
+
"data-ckui": "too-small",
|
|
255
|
+
children: [/* @__PURE__ */ w(A, {
|
|
256
|
+
icon: D,
|
|
257
|
+
strokeWidth: 2
|
|
258
|
+
}), /* @__PURE__ */ w(u, { children: f("crop.tooSmall", {
|
|
259
|
+
width: Y,
|
|
260
|
+
min: J
|
|
261
|
+
}) })]
|
|
262
|
+
}),
|
|
263
|
+
oe && /* @__PURE__ */ T(l, {
|
|
264
|
+
className: "border-warning/30 bg-warning/10 text-warning",
|
|
265
|
+
"data-ckui": "undersized",
|
|
266
|
+
children: [/* @__PURE__ */ w(A, {
|
|
267
|
+
icon: D,
|
|
268
|
+
strokeWidth: 2
|
|
269
|
+
}), /* @__PURE__ */ w(u, {
|
|
270
|
+
className: "text-warning/90",
|
|
271
|
+
children: f("crop.undersized", {
|
|
272
|
+
width: q.width,
|
|
273
|
+
target: a.targetWidth
|
|
274
|
+
})
|
|
275
|
+
})]
|
|
276
|
+
}),
|
|
277
|
+
a.error && /* @__PURE__ */ T(l, {
|
|
278
|
+
variant: "destructive",
|
|
279
|
+
role: "alert",
|
|
280
|
+
children: [/* @__PURE__ */ w(A, {
|
|
281
|
+
icon: D,
|
|
282
|
+
strokeWidth: 2
|
|
283
|
+
}), /* @__PURE__ */ w(u, { children: a.error })]
|
|
284
|
+
}),
|
|
285
|
+
K && /* @__PURE__ */ w(s, {
|
|
286
|
+
value: y(a.progress, a.rendering),
|
|
287
|
+
className: "gap-2",
|
|
288
|
+
"aria-label": v(f, a.progress, a.rendering),
|
|
289
|
+
children: /* @__PURE__ */ w("span", {
|
|
290
|
+
className: "text-xs text-muted-foreground",
|
|
291
|
+
children: v(f, a.progress, a.rendering)
|
|
292
|
+
})
|
|
293
|
+
})
|
|
294
|
+
]
|
|
295
|
+
}),
|
|
296
|
+
/* @__PURE__ */ T(h, {
|
|
297
|
+
className: "px-5 pt-4 pb-5",
|
|
298
|
+
children: [/* @__PURE__ */ w(d, {
|
|
299
|
+
variant: "outline",
|
|
300
|
+
disabled: K,
|
|
301
|
+
onClick: () => a.onOpenChange(!1),
|
|
302
|
+
children: f("common.cancel")
|
|
303
|
+
}), /* @__PURE__ */ w(d, {
|
|
304
|
+
disabled: K || X || ae,
|
|
305
|
+
onClick: () => a.onConfirm(M.edit),
|
|
306
|
+
children: K ? f("common.saving") : a.confirmLabel ?? f("common.save")
|
|
307
|
+
})]
|
|
308
|
+
})
|
|
309
|
+
] });
|
|
310
|
+
}
|
|
311
|
+
function F() {}
|
|
312
|
+
var I = 72;
|
|
313
|
+
function L({ source: e, crop: t, rotate: r, round: i, size: a }) {
|
|
314
|
+
let { t: o } = n(), s = r % 180 != 0, c = I / Math.max(t.w, t.h);
|
|
315
|
+
return /* @__PURE__ */ T("div", {
|
|
316
|
+
className: "flex items-center gap-3",
|
|
317
|
+
"data-ckui": "crop-preview",
|
|
318
|
+
children: [/* @__PURE__ */ w("span", {
|
|
319
|
+
role: "img",
|
|
320
|
+
"aria-label": o("crop.preview"),
|
|
321
|
+
className: E("relative shrink-0 overflow-hidden bg-muted ring-1 ring-border", i ? "rounded-full" : "rounded-sm"),
|
|
322
|
+
style: {
|
|
323
|
+
width: (s ? t.h : t.w) * c,
|
|
324
|
+
height: (s ? t.w : t.h) * c
|
|
325
|
+
},
|
|
326
|
+
children: /* @__PURE__ */ w("span", {
|
|
327
|
+
className: "absolute top-1/2 left-1/2 bg-no-repeat",
|
|
328
|
+
style: {
|
|
329
|
+
width: t.w * c,
|
|
330
|
+
height: t.h * c,
|
|
331
|
+
backgroundImage: `url("${e.url}")`,
|
|
332
|
+
backgroundSize: `${e.width * c}px ${e.height * c}px`,
|
|
333
|
+
backgroundPosition: `${-t.x * c}px ${-t.y * c}px`,
|
|
334
|
+
transform: `translate(-50%, -50%) rotate(${r}deg)`
|
|
335
|
+
}
|
|
336
|
+
})
|
|
337
|
+
}), /* @__PURE__ */ w("span", {
|
|
338
|
+
className: "text-xs text-muted-foreground tabular-nums",
|
|
339
|
+
"data-ckui": "crop-size",
|
|
340
|
+
children: o("crop.size", {
|
|
341
|
+
width: a.width,
|
|
342
|
+
height: a.height
|
|
343
|
+
})
|
|
344
|
+
})]
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
function R(e, t, n) {
|
|
348
|
+
let i = a(e, t, n), o = r(t, n);
|
|
349
|
+
return {
|
|
350
|
+
x: i.x / o.width * 100,
|
|
351
|
+
y: i.y / o.height * 100,
|
|
352
|
+
width: i.w / o.width * 100,
|
|
353
|
+
height: i.h / o.height * 100
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
//#endregion
|
|
357
|
+
export { M as ImageCropDialog };
|
|
358
|
+
|
|
359
|
+
//# sourceMappingURL=image-crop-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-crop-dialog.js","names":[],"sources":["../../src/components/image-crop-dialog.tsx"],"sourcesContent":["import { aspectOf, ratio, type AspectRatio } from \"../client/aspect.js\";\nimport { Alert02Icon, Image01Icon, RotateClockwiseIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useEffect, useMemo, useRef, useState, type KeyboardEvent, type ReactNode } from \"react\";\nimport Cropper, { type Area, type Point } from \"react-easy-crop\";\nimport type { Progress as UploadProgress } from \"../client/media/client.js\";\nimport { editedSize, rotation, toRotated, type Rotation, type Size } from \"../client/crop.js\";\nimport type { CropSource } from \"../client/image.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { useCrop } from \"../react/upload.js\";\nimport { editOutput } from \"../react/slot.js\";\nimport type { Edit } from \"../client/generated/wire.js\";\nimport { Alert, AlertDescription } from \"#ckui/ui/alert\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from \"#ckui/ui/dialog\";\nimport { Progress } from \"#ckui/ui/progress\";\nimport { Slider } from \"#ckui/ui/slider\";\nimport { progressLabel, progressValue } from \"./progress.js\";\n\nconst MAX_ZOOM = 5;\nconst ZOOM_STEP = 0.25;\n\nexport interface ImageCropDialogProps {\n open: boolean;\n /** Closing (Esc, the close button, Cancel) reports false. */\n onOpenChange: (open: boolean) => void;\n /** The image and its EXIF-oriented original size; edits are in those pixels. */\n source: CropSource | null;\n /** The output's \"W:H\" (after rotation); \"\" keeps the image's own shape. */\n aspect: AspectRatio;\n /**\n * Shapes to choose from, \"\" being the original's (e.g. [\"\", \"1:1\", \"4:5\",\n * \"16:9\"]). The chooser starts at aspect when listed, else the first.\n */\n aspects?: readonly AspectRatio[];\n /** A small preview of the result beside the controls. Default true. */\n preview?: boolean;\n /** Circular mask (avatars); the saved crop is still the square around it. */\n round?: boolean;\n /** Offer 90° rotation. Default true. */\n rotatable?: boolean;\n /** Starting edit (re-crop); default centred at aspect, unrotated. */\n initialEdit?: Edit | null;\n /** Called with the edit on open and whenever its value changes (safe to pass a state setter). */\n onEditChange?: (edit: Edit | null) => void;\n /** The chosen edit; null is the full centred crop, unrotated. */\n onConfirm: (edit: Edit | null) => void;\n /** Warns when the output is narrower than this many source pixels. */\n targetWidth?: number;\n /** The narrowest edit the server accepts (the preset's Image.MinWidth): zoom stops there, and a smaller image cannot be confirmed. */\n minWidth?: number;\n title?: ReactNode;\n description?: ReactNode;\n confirmLabel?: ReactNode;\n /** A save is running: controls lock and progress shows. */\n busy?: boolean;\n progress?: UploadProgress;\n /** The worker is rendering the outputs (indeterminate progress). */\n rendering?: boolean;\n /** Shown above the footer, e.g. a mapped ContentKitError. */\n error?: ReactNode;\n className?: string;\n}\n\n/** Pan, zoom (slider, wheel, pinch, keyboard), rotate and confirm a fixed-aspect edit. */\nexport function ImageCropDialog(p: ImageCropDialogProps) {\n const { t } = useMessages();\n const busy = !!p.busy;\n return (\n <Dialog open={p.open} onOpenChange={(o) => !busy && p.onOpenChange(o)}>\n <DialogContent className={cn(\"gap-0 overflow-hidden p-0 sm:max-w-xl\", p.className)} showCloseButton={!busy} data-ckui=\"crop-dialog\">\n <DialogHeader className=\"px-5 pt-5 pb-4 pr-12\">\n <DialogTitle>{p.title ?? t(\"crop.title\")}</DialogTitle>\n <DialogDescription>{p.description ?? t(\"crop.description\")}</DialogDescription>\n </DialogHeader>\n {p.source && <CropShapes key={p.source.url} {...p} source={p.source} />}\n </DialogContent>\n </Dialog>\n );\n}\n\n// The shape chooser: each choice crops afresh; the initial edit belongs to the starting shape.\nfunction CropShapes(p: ImageCropDialogProps & { source: CropSource }) {\n const { t } = useMessages();\n const shapes = p.aspects?.length ? p.aspects : null;\n const start = shapes && !shapes.includes(p.aspect) ? shapes[0]! : p.aspect;\n const [shape, setShape] = useState(start);\n const chooser = shapes && shapes.length > 1 && (\n <div className=\"flex items-center gap-2 px-5 pb-3\" data-ckui=\"crop-shapes\">\n <span className=\"text-xs text-muted-foreground\">{t(\"crop.shape\")}</span>\n <div className=\"inline-flex flex-wrap gap-0.5 rounded-lg bg-muted p-0.5\" role=\"group\" aria-label={t(\"crop.shape\")}>\n {shapes.map((a) => (\n <button\n key={a || \"original\"}\n type=\"button\"\n aria-pressed={shape === a}\n disabled={!!p.busy}\n onClick={() => setShape(a)}\n className={cn(\n \"inline-flex h-7 items-center rounded-md px-2.5 text-xs font-medium text-muted-foreground tabular-nums transition-colors outline-none hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50 disabled:opacity-50\",\n shape === a && \"bg-background text-foreground shadow-xs\",\n )}\n >\n {a || t(\"crop.original\")}\n </button>\n ))}\n </div>\n </div>\n );\n return (\n <>\n {chooser}\n <CropBody key={shape} {...p} aspect={shape} initialEdit={shape === start ? p.initialEdit : null} onReset={shape === start ? undefined : () => setShape(start)} />\n </>\n );\n}\n\nfunction CropBody(p: ImageCropDialogProps & { source: CropSource; onReset?: () => void }) {\n const { t } = useMessages();\n const { source } = p;\n // A native aspect (\"\") crops at the image's own shape.\n // A native shape (\"\") is the image's own, turned with it: the whole image fits.\n const [turn, setTurn] = useState<Rotation>(() => rotation(p.initialEdit?.rotate ?? 0));\n const aspect = ratio(p.aspect) ? p.aspect : turn % 180 ? aspectOf(source.height, source.width) : aspectOf(source.width, source.height);\n const size: Size = useMemo(() => ({ width: source.width, height: source.height }), [source.width, source.height]);\n const c = useCrop({ source: size, aspect, initial: p.initialEdit });\n // A native shape turned with the image: crop the whole image again, as the cropper recenters.\n const shaped = useRef(aspect);\n const { setCrop } = c;\n useEffect(() => {\n if (shaped.current === aspect) return;\n shaped.current = aspect;\n setCrop({ x: 0, y: 0, w: size.width, h: size.height });\n }, [aspect, size, setCrop]);\n const [pos, setPos] = useState<Point>({ x: 0, y: 0 });\n const [zoom, setZoom] = useState(1);\n const [interacting, setInteracting] = useState(false);\n const [initial, setInitial] = useState<Area | undefined>(() => (p.initialEdit?.crop ? percentOf(c.crop, size, c.rotate) : undefined));\n const onEditChange = useRef(p.onEditChange);\n onEditChange.current = p.onEditChange;\n const busy = !!p.busy;\n\n useEffect(() => onEditChange.current?.(c.edit), [c.edit]);\n\n const out = editOutput(size, c.edit, aspect);\n const min = p.minWidth ?? 0;\n // Zoom z shows 1/z of the widest crop; stop where the crop would fall under min.\n const widest = editOutput(size, { rotate: c.rotate }, aspect).width;\n const tooSmall = widest < min;\n const maxZoom = tooSmall ? 1 : Math.max(1, Math.min(MAX_ZOOM, widest / Math.max(1, min)));\n const belowMin = out.width < min;\n const undersized = !tooSmall && !!(p.targetWidth && out.width < p.targetWidth);\n useEffect(() => {\n if (zoom > maxZoom) setZoom(maxZoom);\n }, [zoom, maxZoom]);\n\n const complete = (area: Area) => {\n // Before the media has a size the cropper reports NaN areas.\n if (!(area.width > 0 && area.height > 0) || !Number.isFinite(area.x + area.y)) return;\n const shown = editedSize(size, c.rotate);\n const k = (v: number, of: number) => (v / 100) * of;\n c.setFromDisplay(\n { x: k(area.x, shown.width), y: k(area.y, shown.height), w: k(area.width, shown.width), h: k(area.height, shown.height) },\n shown,\n );\n };\n\n const recenter = () => {\n setInitial(undefined);\n setPos({ x: 0, y: 0 });\n setZoom(1);\n };\n const rotate = (deg: number) => {\n setTurn((r) => rotation(r + deg));\n c.rotateBy(deg);\n recenter();\n };\n const reset = () => {\n if (p.onReset) return p.onReset();\n setTurn(0);\n c.reset();\n recenter();\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (busy) return;\n if (e.key === \"+\" || e.key === \"=\") setZoom((z) => Math.min(maxZoom, z + ZOOM_STEP));\n else if (e.key === \"-\" || e.key === \"_\") setZoom((z) => Math.max(1, z - ZOOM_STEP));\n else if (p.rotatable !== false && (e.key === \"r\" || e.key === \"R\")) rotate(e.shiftKey ? -90 : 90);\n else return;\n e.preventDefault();\n };\n\n return (\n <>\n <div\n className=\"relative h-72 w-full bg-zinc-950 sm:h-80 [&_.reactEasyCrop_CropArea]:border-white/70 [&_.reactEasyCrop_CropArea]:text-black/65\"\n onKeyDown={onKeyDown}\n data-ckui=\"crop-stage\"\n >\n <div className=\"absolute inset-3 sm:inset-4\">\n <Cropper\n image={source.url}\n crop={pos}\n zoom={zoom}\n rotation={c.rotate}\n aspect={ratio(aspect)}\n minZoom={1}\n maxZoom={maxZoom}\n zoomSpeed={0.5}\n cropShape={p.round ? \"round\" : \"rect\"}\n showGrid={!p.round || interacting}\n objectFit=\"contain\"\n initialCroppedAreaPercentages={initial}\n onCropChange={busy ? noop : setPos}\n onZoomChange={busy ? noop : setZoom}\n onCropComplete={complete}\n onInteractionStart={() => setInteracting(true)}\n onInteractionEnd={() => setInteracting(false)}\n keyboardStep={8}\n disableAutomaticStylesInjection\n mediaProps={{ alt: \"\", draggable: false }}\n cropperProps={{ \"aria-label\": t(\"crop.area\"), role: \"application\" } as never}\n />\n </div>\n </div>\n\n <div className=\"grid gap-3 px-5 pt-4\">\n <div className=\"flex items-center gap-1.5\">\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t(\"crop.zoomOut\")}\n disabled={busy || zoom <= 1}\n onClick={() => setZoom((z) => Math.max(1, z - ZOOM_STEP))}\n >\n <HugeiconsIcon icon={Image01Icon} strokeWidth={2} className=\"size-3.5\" />\n </Button>\n <Slider\n aria-label={t(\"crop.zoom\")}\n className=\"mx-1 flex-1\"\n min={1}\n max={maxZoom}\n step={0.01}\n value={zoom}\n disabled={busy}\n onValueChange={(v) => setZoom(Array.isArray(v) ? v[0]! : (v as number))}\n />\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t(\"crop.zoomIn\")}\n disabled={busy || zoom >= maxZoom}\n onClick={() => setZoom((z) => Math.min(maxZoom, z + ZOOM_STEP))}\n >\n <HugeiconsIcon icon={Image01Icon} strokeWidth={2} className=\"size-5\" />\n </Button>\n {p.rotatable !== false && (\n <>\n <span className=\"mx-1 h-5 w-px bg-border\" aria-hidden />\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"crop.rotateLeft\")} disabled={busy} onClick={() => rotate(-90)}>\n <HugeiconsIcon icon={RotateClockwiseIcon} strokeWidth={2} />\n </Button>\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"crop.rotateRight\")} disabled={busy} onClick={() => rotate(90)}>\n <HugeiconsIcon icon={RotateClockwiseIcon} strokeWidth={2} className=\"-scale-x-100\" />\n </Button>\n </>\n )}\n <Button variant=\"ghost\" size=\"sm\" disabled={busy} onClick={reset} className=\"text-muted-foreground\">\n {t(\"crop.reset\")}\n </Button>\n </div>\n\n {p.preview !== false && <ResultPreview source={source} crop={c.crop} rotate={c.rotate} round={p.round} size={out} />}\n {tooSmall && (\n <Alert variant=\"destructive\" role=\"alert\" data-ckui=\"too-small\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertDescription>{t(\"crop.tooSmall\", { width: widest, min })}</AlertDescription>\n </Alert>\n )}\n {undersized && (\n <Alert className=\"border-warning/30 bg-warning/10 text-warning\" data-ckui=\"undersized\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertDescription className=\"text-warning/90\">{t(\"crop.undersized\", { width: out.width, target: p.targetWidth! })}</AlertDescription>\n </Alert>\n )}\n {p.error && (\n <Alert variant=\"destructive\" role=\"alert\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertDescription>{p.error}</AlertDescription>\n </Alert>\n )}\n {busy && (\n <Progress value={progressValue(p.progress, p.rendering)} className=\"gap-2\" aria-label={progressLabel(t, p.progress, p.rendering)}>\n <span className=\"text-xs text-muted-foreground\">{progressLabel(t, p.progress, p.rendering)}</span>\n </Progress>\n )}\n </div>\n\n <DialogFooter className=\"px-5 pt-4 pb-5\">\n <Button variant=\"outline\" disabled={busy} onClick={() => p.onOpenChange(false)}>\n {t(\"common.cancel\")}\n </Button>\n <Button disabled={busy || tooSmall || belowMin} onClick={() => p.onConfirm(c.edit)}>\n {busy ? t(\"common.saving\") : (p.confirmLabel ?? t(\"common.save\"))}\n </Button>\n </DialogFooter>\n </>\n );\n}\n\nfunction noop() {}\n\nconst PREVIEW = 72;\n\n// The crop as it will render: the source drawn through the crop, turned.\nfunction ResultPreview({ source, crop, rotate, round, size }: { source: CropSource; crop: { x: number; y: number; w: number; h: number }; rotate: 0 | 90 | 180 | 270; round?: boolean; size: Size }) {\n const { t } = useMessages();\n const turned = rotate % 180 !== 0;\n const k = PREVIEW / Math.max(crop.w, crop.h);\n return (\n <div className=\"flex items-center gap-3\" data-ckui=\"crop-preview\">\n <span\n role=\"img\"\n aria-label={t(\"crop.preview\")}\n className={cn(\"relative shrink-0 overflow-hidden bg-muted ring-1 ring-border\", round ? \"rounded-full\" : \"rounded-sm\")}\n style={{ width: (turned ? crop.h : crop.w) * k, height: (turned ? crop.w : crop.h) * k }}\n >\n <span\n className=\"absolute top-1/2 left-1/2 bg-no-repeat\"\n style={{\n width: crop.w * k,\n height: crop.h * k,\n backgroundImage: `url(\"${source.url}\")`,\n backgroundSize: `${source.width * k}px ${source.height * k}px`,\n backgroundPosition: `${-crop.x * k}px ${-crop.y * k}px`,\n transform: `translate(-50%, -50%) rotate(${rotate}deg)`,\n }}\n />\n </span>\n <span className=\"text-xs text-muted-foreground tabular-nums\" data-ckui=\"crop-size\">\n {t(\"crop.size\", { width: size.width, height: size.height })}\n </span>\n </div>\n );\n}\n\n/** The crop as percentages of the rotated image, as the cropper takes it. */\nfunction percentOf(crop: { x: number; y: number; w: number; h: number }, source: Size, rot: 0 | 90 | 180 | 270): Area {\n const r = toRotated(crop, source, rot);\n const shown = editedSize(source, rot);\n return { x: (r.x / shown.width) * 100, y: (r.y / shown.height) * 100, width: (r.w / shown.width) * 100, height: (r.h / shown.height) * 100 };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
import { NearViewportOptions } from '../react/viewport.js';
|
|
3
|
+
export interface LazyMountProps extends NearViewportOptions, Omit<ComponentProps<"div">, "children"> {
|
|
4
|
+
/** Mounted once the box nears the viewport (and, with leaveMargin, unmounted far away). */
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
/** Rendered while not near, e.g. a box at the content's size so the page keeps its height. */
|
|
7
|
+
placeholder?: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/** A box whose children mount as it nears the viewport: feeds read and play media lazily. */
|
|
10
|
+
export declare function LazyMount({ margin, leaveMargin, eager, root, children, placeholder, ...div }: LazyMountProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useNearViewport as e } from "../react/viewport.js";
|
|
2
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/lazy-mount.tsx
|
|
4
|
+
function n({ margin: n, leaveMargin: r, eager: i, root: a, children: o, placeholder: s, ...c }) {
|
|
5
|
+
let [l, u] = e({
|
|
6
|
+
margin: n,
|
|
7
|
+
leaveMargin: r,
|
|
8
|
+
eager: i,
|
|
9
|
+
root: a
|
|
10
|
+
});
|
|
11
|
+
return /* @__PURE__ */ t("div", {
|
|
12
|
+
...c,
|
|
13
|
+
ref: l,
|
|
14
|
+
"data-ckui": "lazy-mount",
|
|
15
|
+
"data-near": u ? "" : void 0,
|
|
16
|
+
children: u ? o : s
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { n as LazyMount };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=lazy-mount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy-mount.js","names":[],"sources":["../../src/components/lazy-mount.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\nimport { useNearViewport, type NearViewportOptions } from \"../react/viewport.js\";\n\nexport interface LazyMountProps extends NearViewportOptions, Omit<ComponentProps<\"div\">, \"children\"> {\n /** Mounted once the box nears the viewport (and, with leaveMargin, unmounted far away). */\n children?: ReactNode;\n /** Rendered while not near, e.g. a box at the content's size so the page keeps its height. */\n placeholder?: ReactNode;\n}\n\n/** A box whose children mount as it nears the viewport: feeds read and play media lazily. */\nexport function LazyMount({ margin, leaveMargin, eager, root, children, placeholder, ...div }: LazyMountProps) {\n const [ref, near] = useNearViewport({ margin, leaveMargin, eager, root });\n return (\n <div {...div} ref={ref} data-ckui=\"lazy-mount\" data-near={near ? \"\" : undefined}>\n {near ? children : placeholder}\n </div>\n );\n}\n"],"mappings":";;;AAWA,SAAgB,EAAU,EAAE,WAAQ,gBAAa,UAAO,SAAM,aAAU,gBAAa,GAAG,KAAuB;CAC7G,IAAM,CAAC,GAAK,KAAQ,EAAgB;EAAE;EAAQ;EAAa;EAAO;CAAK,CAAC;CACxE,OACE,kBAAC,OAAD;EAAK,GAAI;EAAU;EAAK,aAAU;EAAa,aAAW,IAAO,KAAK,KAAA;EACnE,UAAA,IAAO,IAAW;CAChB,CAAA;AAET"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ReactNode, Ref } from 'react';
|
|
2
|
+
import { ContentKitUiAppearance } from '../appearance.js';
|
|
3
|
+
import { AspectRatio } from '../client/aspect.js';
|
|
4
|
+
import { FileInfo, RefBody, UploadRule } from '../client/generated/wire.js';
|
|
5
|
+
import { Translator } from '../i18n/messages.js';
|
|
6
|
+
import { MediaFolderOptions, UseMediaFolder } from '../react/folder.js';
|
|
7
|
+
export interface MediaFolderEditorHandle {
|
|
8
|
+
/** Stops every upload and empties the queue (before deleting a draft). */
|
|
9
|
+
discard: () => void;
|
|
10
|
+
/** Commits the uploaded files (commit="manual"). */
|
|
11
|
+
commit: () => Promise<FileInfo[]>;
|
|
12
|
+
/** The folder's state and updates. */
|
|
13
|
+
folder: UseMediaFolder;
|
|
14
|
+
}
|
|
15
|
+
export interface MediaFolderEditorViewProps {
|
|
16
|
+
ref?: Ref<MediaFolderEditorHandle>;
|
|
17
|
+
/** Heading; default "Media". */
|
|
18
|
+
label?: ReactNode;
|
|
19
|
+
/** Beside "Add files" in the header, e.g. a ZIP import. */
|
|
20
|
+
toolbar?: ReactNode;
|
|
21
|
+
/** Extra actions on each upload, beside crop, rename, replace and remove. */
|
|
22
|
+
rowActions?: (file: FileInfo) => ReactNode;
|
|
23
|
+
/** Below the lists, e.g. what readers without access see. */
|
|
24
|
+
footer?: ReactNode;
|
|
25
|
+
/** Shapes offered when cropping an image whose path has no preset shape; "" is the original's. */
|
|
26
|
+
aspects?: readonly AspectRatio[];
|
|
27
|
+
/** Asked before removing selected uploads; default the browser's confirm; false skips it. */
|
|
28
|
+
confirmRemove?: ((count: number) => boolean | Promise<boolean>) | false;
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
className?: string;
|
|
31
|
+
appearance?: ContentKitUiAppearance;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Either the item, and the editor opens its folder with the options; or a
|
|
35
|
+
* folder the host opened (`folder={useMediaFolder(ref, options)}`), whose
|
|
36
|
+
* state the host reads and renders with.
|
|
37
|
+
*/
|
|
38
|
+
export type MediaFolderEditorProps = MediaFolderEditorViewProps & (({
|
|
39
|
+
/** The item whose folder this edits. */
|
|
40
|
+
item: RefBody;
|
|
41
|
+
folder?: never;
|
|
42
|
+
} & MediaFolderOptions) | ({
|
|
43
|
+
/** The host's folder (useMediaFolder); its ref may be null until the item exists. */
|
|
44
|
+
folder: UseMediaFolder;
|
|
45
|
+
item?: never;
|
|
46
|
+
} & {
|
|
47
|
+
[K in keyof MediaFolderOptions]?: never;
|
|
48
|
+
}));
|
|
49
|
+
/** The rules as a sentence for the drop zone: sizes, caps and video shapes. */
|
|
50
|
+
export declare function describeRules(t: Translator["t"], rules: readonly UploadRule[]): string;
|
|
51
|
+
/**
|
|
52
|
+
* An item's folder for its editors: drop or pick files (screened against the
|
|
53
|
+
* kind's upload rules), a queue with progress, retry and remove, and each
|
|
54
|
+
* upload path's uploads as a sortable list with thumbnail, name, edited
|
|
55
|
+
* badge, encode progress and failures; crop, rename, replace and bulk
|
|
56
|
+
* remove. commit="manual" adds the queue with "Add N"; "auto" commits as
|
|
57
|
+
* files finish (a draft; discard() through the ref).
|
|
58
|
+
*/
|
|
59
|
+
export declare function MediaFolderEditor(p: MediaFolderEditorProps): import('react').JSX.Element;
|