@openrails/contentkit-ui 0.0.0-stage → 0.68.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.
- package/README.md +425 -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 +51 -0
- package/dist/client/client.js +35 -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 +93 -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 +148 -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 +91 -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 +79 -0
- package/dist/client/http.js +74 -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 +52 -0
- package/dist/client/media/rules.js +139 -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 +45 -0
- package/dist/components/media-folder-editor.js +564 -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 +213 -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 +88 -0
- package/dist/react/canonical.js.map +1 -0
- package/dist/react/comments.d.ts +82 -0
- package/dist/react/comments.js +147 -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 +48 -0
- package/dist/react/context.js +37 -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 +83 -0
- package/dist/react/folder.js +183 -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 +23 -0
- package/dist/react/provider.js +35 -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 +143 -0
- package/dist/react/read.js.map +1 -0
- package/dist/react/resources.d.ts +70 -0
- package/dist/react/resources.js +247 -0
- package/dist/react/resources.js.map +1 -0
- package/dist/react/slot.d.ts +102 -0
- package/dist/react/slot.js +181 -0
- package/dist/react/slot.js.map +1 -0
- package/dist/react/store.d.ts +51 -0
- package/dist/react/store.js +164 -0
- package/dist/react/store.js.map +1 -0
- package/dist/react/upload.d.ts +85 -0
- package/dist/react/upload.js +150 -0
- package/dist/react/upload.js.map +1 -0
- package/dist/react/use-resource.d.ts +43 -0
- package/dist/react/use-resource.js +66 -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 +118 -3
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ContentKitClient } from '../../client/client.js';
|
|
3
|
+
import { Poll as PollData } from '../../client/generated/wire.js';
|
|
4
|
+
import { ContentKitUiAppearance } from '../../appearance.js';
|
|
5
|
+
import { ContentKitErrorHandler } from '../../react/context.js';
|
|
6
|
+
export interface PollProps {
|
|
7
|
+
/** A poll id, or the poll the host already has; none shows the newest live poll (in language). */
|
|
8
|
+
poll?: string | PollData;
|
|
9
|
+
language?: string;
|
|
10
|
+
/** When results show: once the visitor voted (default), or always. A closed poll always shows them. */
|
|
11
|
+
results?: "voted" | "always";
|
|
12
|
+
/** Asks a signed-out visitor to sign in where the server takes no anonymous votes (default the provider's). */
|
|
13
|
+
onSignIn?: () => void;
|
|
14
|
+
/** Shown when there is no live poll; default nothing. */
|
|
15
|
+
empty?: ReactNode;
|
|
16
|
+
/** Longest free-text answer. Default 280. */
|
|
17
|
+
maxLength?: number;
|
|
18
|
+
client?: ContentKitClient;
|
|
19
|
+
onError?: ContentKitErrorHandler;
|
|
20
|
+
className?: string;
|
|
21
|
+
appearance?: ContentKitUiAppearance;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A poll: vote (at once, final) and results scaled to the leading option, or a
|
|
25
|
+
* free-text answer and its groups. Question and option images, the closing
|
|
26
|
+
* date and the closed state come from the poll. Signed out, visitors vote
|
|
27
|
+
* where the server allows it (`Config.anonymous.votes`) and are asked to sign
|
|
28
|
+
* in elsewhere; free-text answers always need a signed-in visitor.
|
|
29
|
+
*/
|
|
30
|
+
export declare function Poll(p: PollProps): import('react').JSX.Element | null;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { toContentKitError as e } from "../../client/errors.js";
|
|
2
|
+
import { useMessages as t } from "../../i18n/context.js";
|
|
3
|
+
import { ContentKitUiRoot as n } from "../../scope.js";
|
|
4
|
+
import { ContentKitContext as r, useErrorReporter as i } from "../../react/context.js";
|
|
5
|
+
import { Button as a } from "../../ui/button.js";
|
|
6
|
+
import { useContentConfig as o } from "../../react/config.js";
|
|
7
|
+
import { Skeleton as s } from "../../ui/skeleton.js";
|
|
8
|
+
import { Textarea as c } from "../../ui/textarea.js";
|
|
9
|
+
import { ErrorLine as l, formatDate as u } from "./parts.js";
|
|
10
|
+
import { usePoll as d } from "../../react/polls.js";
|
|
11
|
+
import { useContext as f, useId as p, useState as m } from "react";
|
|
12
|
+
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
13
|
+
import { cn as v } from "cn";
|
|
14
|
+
import { Tick02Icon as y } from "@hugeicons/core-free-icons";
|
|
15
|
+
import { HugeiconsIcon as b } from "@hugeicons/react";
|
|
16
|
+
//#region src/components/social/poll.tsx
|
|
17
|
+
function x(c) {
|
|
18
|
+
let p = t(), { t: y } = p, b = f(r), x = typeof c.poll == "string" ? c.poll : c.poll?.id, w = d(x ?? null, {
|
|
19
|
+
initial: typeof c.poll == "object" ? c.poll : void 0,
|
|
20
|
+
language: c.language,
|
|
21
|
+
client: c.client
|
|
22
|
+
}), T = i(c.onError), [E, D] = m(null), { config: O } = o({ client: c.client }), k = c.onSignIn ?? b?.onSignIn, A = b?.viewer === null && O?.anonymous.votes === !1, j = (e) => /* @__PURE__ */ g(n, {
|
|
23
|
+
appearance: c.appearance,
|
|
24
|
+
className: v("grid gap-3 rounded-xl border border-border bg-card p-4 text-sm text-card-foreground", c.className),
|
|
25
|
+
"data-ckui": "poll",
|
|
26
|
+
children: e
|
|
27
|
+
});
|
|
28
|
+
if (w.loading && !w.poll) return j(/* @__PURE__ */ _("div", {
|
|
29
|
+
className: "grid gap-2",
|
|
30
|
+
"aria-busy": !0,
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ g(s, { className: "h-5 w-2/3" }),
|
|
33
|
+
/* @__PURE__ */ g(s, { className: "h-9 w-full" }),
|
|
34
|
+
/* @__PURE__ */ g(s, { className: "h-9 w-full" })
|
|
35
|
+
]
|
|
36
|
+
}));
|
|
37
|
+
if (w.error && !w.poll) return j(/* @__PURE__ */ _("div", {
|
|
38
|
+
className: "grid justify-items-start gap-2",
|
|
39
|
+
children: [/* @__PURE__ */ g(l, { children: y("poll.loadFailed") }), /* @__PURE__ */ g(a, {
|
|
40
|
+
size: "sm",
|
|
41
|
+
variant: "outline",
|
|
42
|
+
onClick: w.reload,
|
|
43
|
+
children: y("common.retry")
|
|
44
|
+
})]
|
|
45
|
+
}));
|
|
46
|
+
let M = w.poll;
|
|
47
|
+
if (!M) return c.empty ? /* @__PURE__ */ g(h, { children: c.empty }) : null;
|
|
48
|
+
let N = (t, n) => {
|
|
49
|
+
let r = e(t);
|
|
50
|
+
if (r.code === "unauthorized" && k) return k();
|
|
51
|
+
D(r), T(r, n);
|
|
52
|
+
}, P = (e) => {
|
|
53
|
+
if (A) return k?.();
|
|
54
|
+
D(null), w.vote(e).catch((e) => N(e, "poll.vote"));
|
|
55
|
+
}, F = /* @__PURE__ */ _(h, { children: [
|
|
56
|
+
M.image_url && /* @__PURE__ */ g("img", {
|
|
57
|
+
src: M.image_url,
|
|
58
|
+
alt: "",
|
|
59
|
+
className: "aspect-video w-full rounded-lg object-cover",
|
|
60
|
+
loading: "lazy"
|
|
61
|
+
}),
|
|
62
|
+
/* @__PURE__ */ g("h3", {
|
|
63
|
+
className: "text-base font-semibold",
|
|
64
|
+
id: `poll-${M.id}`,
|
|
65
|
+
children: M.question
|
|
66
|
+
}),
|
|
67
|
+
M.closed ? /* @__PURE__ */ g("p", {
|
|
68
|
+
className: "text-muted-foreground",
|
|
69
|
+
children: y("poll.closed")
|
|
70
|
+
}) : M.closes_at && /* @__PURE__ */ g("p", {
|
|
71
|
+
className: "text-muted-foreground",
|
|
72
|
+
children: y("poll.closes", { date: u(p, M.closes_at) })
|
|
73
|
+
})
|
|
74
|
+
] });
|
|
75
|
+
return j(/* @__PURE__ */ _(h, { children: [
|
|
76
|
+
F,
|
|
77
|
+
M.kind === "free_text" ? /* @__PURE__ */ g(C, {
|
|
78
|
+
poll: M,
|
|
79
|
+
pending: w.pending,
|
|
80
|
+
maxLength: c.maxLength ?? 280,
|
|
81
|
+
results: c.results,
|
|
82
|
+
onAnswer: (e) => w.answer(e).then(() => !0, (e) => (N(e, "poll.answer"), !1))
|
|
83
|
+
}) : /* @__PURE__ */ g(S, {
|
|
84
|
+
poll: M,
|
|
85
|
+
results: c.results === "always" || M.voted || M.closed,
|
|
86
|
+
canVote: !M.voted && !M.closed && !w.pending && (!A || !!k),
|
|
87
|
+
onVote: P
|
|
88
|
+
}),
|
|
89
|
+
/* @__PURE__ */ g(l, { error: E }),
|
|
90
|
+
!M.voted && !M.closed && A && M.kind !== "free_text" && /* @__PURE__ */ g("p", {
|
|
91
|
+
className: "text-xs text-muted-foreground",
|
|
92
|
+
children: y("poll.signIn")
|
|
93
|
+
})
|
|
94
|
+
] }));
|
|
95
|
+
}
|
|
96
|
+
function S({ poll: e, results: n, canVote: r, onVote: i }) {
|
|
97
|
+
let o = t(), { t: s } = o, c = [...e.options].sort((e, t) => e.position - t.position), l = c.some((e) => e.image_url), u = e.total_votes || c.reduce((e, t) => e + t.vote_count, 0), d = Math.max(1, ...c.map((e) => e.vote_count));
|
|
98
|
+
return /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("ul", {
|
|
99
|
+
className: v("grid gap-2", l && "grid-cols-2"),
|
|
100
|
+
"aria-labelledby": `poll-${e.id}`,
|
|
101
|
+
children: c.map((t) => {
|
|
102
|
+
let c = e.my_option === t.id, l = u ? Math.round(t.vote_count / u * 100) : 0, f = /* @__PURE__ */ _(h, { children: [
|
|
103
|
+
t.image_url && /* @__PURE__ */ g("img", {
|
|
104
|
+
src: t.image_url,
|
|
105
|
+
alt: "",
|
|
106
|
+
className: "aspect-[4/3] w-full rounded-md bg-muted object-contain",
|
|
107
|
+
loading: "lazy"
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ _("span", {
|
|
110
|
+
className: "relative flex w-full items-center gap-2",
|
|
111
|
+
children: [n && /* @__PURE__ */ g("span", {
|
|
112
|
+
"aria-hidden": !0,
|
|
113
|
+
className: v("absolute inset-y-0 start-0 rounded-md transition-[width] duration-500 motion-reduce:transition-none", c ? "bg-primary/25" : "bg-muted"),
|
|
114
|
+
style: { width: `${t.vote_count / d * 100}%` }
|
|
115
|
+
}), /* @__PURE__ */ _("span", {
|
|
116
|
+
className: "relative flex min-w-0 flex-1 items-center gap-2 px-2 py-1.5",
|
|
117
|
+
children: [
|
|
118
|
+
c && /* @__PURE__ */ g(b, {
|
|
119
|
+
icon: y,
|
|
120
|
+
strokeWidth: 2.5,
|
|
121
|
+
className: "size-4 shrink-0 text-primary",
|
|
122
|
+
"aria-label": s("poll.yourVote")
|
|
123
|
+
}),
|
|
124
|
+
/* @__PURE__ */ g("span", {
|
|
125
|
+
className: "min-w-0 flex-1 break-words text-start",
|
|
126
|
+
children: t.label
|
|
127
|
+
}),
|
|
128
|
+
n && /* @__PURE__ */ _("span", {
|
|
129
|
+
className: "shrink-0 tabular-nums font-medium",
|
|
130
|
+
children: [l, "%"]
|
|
131
|
+
})
|
|
132
|
+
]
|
|
133
|
+
})]
|
|
134
|
+
}),
|
|
135
|
+
n && /* @__PURE__ */ g("span", {
|
|
136
|
+
className: "sr-only",
|
|
137
|
+
children: o.plural("poll.votes", t.vote_count)
|
|
138
|
+
})
|
|
139
|
+
] });
|
|
140
|
+
return /* @__PURE__ */ g("li", {
|
|
141
|
+
"data-option": t.id,
|
|
142
|
+
"data-mine": c || void 0,
|
|
143
|
+
children: r ? /* @__PURE__ */ g(a, {
|
|
144
|
+
variant: "outline",
|
|
145
|
+
className: "h-auto w-full flex-col items-stretch gap-1.5 p-1 whitespace-normal",
|
|
146
|
+
onClick: () => i(t.id),
|
|
147
|
+
children: f
|
|
148
|
+
}) : /* @__PURE__ */ g("div", {
|
|
149
|
+
className: "grid gap-1.5 rounded-md border border-border p-1",
|
|
150
|
+
role: "meter",
|
|
151
|
+
"aria-valuemin": 0,
|
|
152
|
+
"aria-valuemax": 100,
|
|
153
|
+
"aria-valuenow": l,
|
|
154
|
+
"aria-label": t.label,
|
|
155
|
+
children: f
|
|
156
|
+
})
|
|
157
|
+
}, t.id);
|
|
158
|
+
})
|
|
159
|
+
}), n && /* @__PURE__ */ g("p", {
|
|
160
|
+
className: "text-xs text-muted-foreground",
|
|
161
|
+
children: o.plural("poll.votes", u)
|
|
162
|
+
})] });
|
|
163
|
+
}
|
|
164
|
+
function C({ poll: e, pending: n, maxLength: r, results: i, onAnswer: o }) {
|
|
165
|
+
let s = t(), { t: l } = s, u = p(), d = e.my_answer, [f, v] = m(!1), [y, b] = m(d?.text ?? ""), x = !e.closed, S = [...e.groups ?? []].sort((e, t) => t.count - e.count), C = Math.max(1, ...S.map((e) => e.count)), w = S.length > 0 && (!!d || e.closed || i === "always");
|
|
166
|
+
return /* @__PURE__ */ _(h, { children: [x && (!d || f) ? /* @__PURE__ */ _("form", {
|
|
167
|
+
className: "grid gap-2",
|
|
168
|
+
onSubmit: (e) => {
|
|
169
|
+
e.preventDefault(), y.trim() && o(y.trim()).then((e) => e && v(!1));
|
|
170
|
+
},
|
|
171
|
+
children: [
|
|
172
|
+
/* @__PURE__ */ g("label", {
|
|
173
|
+
htmlFor: `${u}-answer`,
|
|
174
|
+
className: "sr-only",
|
|
175
|
+
children: l("poll.answerPlaceholder")
|
|
176
|
+
}),
|
|
177
|
+
/* @__PURE__ */ g(c, {
|
|
178
|
+
id: `${u}-answer`,
|
|
179
|
+
rows: 2,
|
|
180
|
+
maxLength: r,
|
|
181
|
+
placeholder: l("poll.answerPlaceholder"),
|
|
182
|
+
value: y,
|
|
183
|
+
disabled: n,
|
|
184
|
+
onChange: (e) => b(e.target.value)
|
|
185
|
+
}),
|
|
186
|
+
/* @__PURE__ */ _("div", {
|
|
187
|
+
className: "flex justify-end gap-2",
|
|
188
|
+
children: [f && /* @__PURE__ */ g(a, {
|
|
189
|
+
type: "button",
|
|
190
|
+
variant: "ghost",
|
|
191
|
+
size: "sm",
|
|
192
|
+
onClick: () => v(!1),
|
|
193
|
+
children: l("common.cancel")
|
|
194
|
+
}), /* @__PURE__ */ g(a, {
|
|
195
|
+
type: "submit",
|
|
196
|
+
size: "sm",
|
|
197
|
+
disabled: n || !y.trim(),
|
|
198
|
+
children: l(d ? "poll.updateAnswer" : "poll.answer")
|
|
199
|
+
})]
|
|
200
|
+
})
|
|
201
|
+
]
|
|
202
|
+
}) : d && /* @__PURE__ */ _("div", {
|
|
203
|
+
className: "grid gap-1 rounded-md bg-muted p-3",
|
|
204
|
+
children: [
|
|
205
|
+
/* @__PURE__ */ g("p", {
|
|
206
|
+
className: "text-xs text-muted-foreground",
|
|
207
|
+
children: l("poll.yourAnswer")
|
|
208
|
+
}),
|
|
209
|
+
/* @__PURE__ */ g("p", {
|
|
210
|
+
className: "break-words whitespace-pre-wrap",
|
|
211
|
+
children: d.text
|
|
212
|
+
}),
|
|
213
|
+
x && /* @__PURE__ */ g(a, {
|
|
214
|
+
variant: "link",
|
|
215
|
+
size: "xs",
|
|
216
|
+
className: "justify-self-start px-0",
|
|
217
|
+
onClick: () => {
|
|
218
|
+
b(d.text), v(!0);
|
|
219
|
+
},
|
|
220
|
+
children: l("poll.editAnswer")
|
|
221
|
+
})
|
|
222
|
+
]
|
|
223
|
+
}), w && /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("ul", {
|
|
224
|
+
className: "grid gap-2",
|
|
225
|
+
"aria-labelledby": `poll-${e.id}`,
|
|
226
|
+
children: S.map((e) => /* @__PURE__ */ _("li", {
|
|
227
|
+
className: "relative flex items-center gap-2 rounded-md px-2 py-1.5",
|
|
228
|
+
children: [
|
|
229
|
+
/* @__PURE__ */ g("span", {
|
|
230
|
+
"aria-hidden": !0,
|
|
231
|
+
className: "absolute inset-y-0 start-0 rounded-md bg-muted",
|
|
232
|
+
style: { width: `${e.count / C * 100}%` }
|
|
233
|
+
}),
|
|
234
|
+
/* @__PURE__ */ g("span", {
|
|
235
|
+
className: "relative min-w-0 flex-1 break-words",
|
|
236
|
+
children: e.label
|
|
237
|
+
}),
|
|
238
|
+
/* @__PURE__ */ g("span", {
|
|
239
|
+
className: "relative tabular-nums text-muted-foreground",
|
|
240
|
+
children: s.plural("poll.answers", e.count)
|
|
241
|
+
})
|
|
242
|
+
]
|
|
243
|
+
}, e.id))
|
|
244
|
+
}), e.answer_count !== void 0 && /* @__PURE__ */ g("p", {
|
|
245
|
+
className: "text-xs text-muted-foreground",
|
|
246
|
+
children: s.plural("poll.answers", e.answer_count)
|
|
247
|
+
})] })] });
|
|
248
|
+
}
|
|
249
|
+
//#endregion
|
|
250
|
+
export { x as Poll };
|
|
251
|
+
|
|
252
|
+
//# sourceMappingURL=poll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poll.js","names":[],"sources":["../../../src/components/social/poll.tsx"],"sourcesContent":["import { Tick02Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useContext, useId, useState, type ReactNode } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { Poll as PollData } from \"../../client/generated/wire.js\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext, useErrorReporter, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useContentConfig } from \"../../react/config.js\";\nimport { usePoll } from \"../../react/polls.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { Textarea } from \"#ckui/ui/textarea\";\nimport { ErrorLine, formatDate } from \"./parts.js\";\n\nexport interface PollProps {\n /** A poll id, or the poll the host already has; none shows the newest live poll (in language). */\n poll?: string | PollData;\n language?: string;\n /** When results show: once the visitor voted (default), or always. A closed poll always shows them. */\n results?: \"voted\" | \"always\";\n /** Asks a signed-out visitor to sign in where the server takes no anonymous votes (default the provider's). */\n onSignIn?: () => void;\n /** Shown when there is no live poll; default nothing. */\n empty?: ReactNode;\n /** Longest free-text answer. Default 280. */\n maxLength?: number;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * A poll: vote (at once, final) and results scaled to the leading option, or a\n * free-text answer and its groups. Question and option images, the closing\n * date and the closed state come from the poll. Signed out, visitors vote\n * where the server allows it (`Config.anonymous.votes`) and are asked to sign\n * in elsewhere; free-text answers always need a signed-in visitor.\n */\nexport function Poll(p: PollProps) {\n const m = useMessages();\n const { t } = m;\n const ctx = useContext(ContentKitContext);\n const id = typeof p.poll === \"string\" ? p.poll : p.poll?.id;\n const r = usePoll(id ?? null, { initial: typeof p.poll === \"object\" ? p.poll : undefined, language: p.language, client: p.client });\n const report = useErrorReporter(p.onError);\n const [error, setError] = useState<ContentKitError | null>(null);\n const { config } = useContentConfig({ client: p.client });\n const signIn = p.onSignIn ?? ctx?.onSignIn;\n const signedOut = ctx?.viewer === null;\n // Signed out where the server takes no anonymous votes.\n const mustSignIn = signedOut && config?.anonymous.votes === false;\n const root = (children: ReactNode) => (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-3 rounded-xl border border-border bg-card p-4 text-sm text-card-foreground\", p.className)} data-ckui=\"poll\">\n {children}\n </ContentKitUiRoot>\n );\n if (r.loading && !r.poll) {\n return root(\n <div className=\"grid gap-2\" aria-busy>\n <Skeleton className=\"h-5 w-2/3\" />\n <Skeleton className=\"h-9 w-full\" />\n <Skeleton className=\"h-9 w-full\" />\n </div>,\n );\n }\n if (r.error && !r.poll) {\n return root(\n <div className=\"grid justify-items-start gap-2\">\n <ErrorLine>{t(\"poll.loadFailed\")}</ErrorLine>\n <Button size=\"sm\" variant=\"outline\" onClick={r.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>,\n );\n }\n const poll = r.poll;\n if (!poll) return p.empty ? <>{p.empty}</> : null;\n\n const fail = (e: unknown, op: \"poll.vote\" | \"poll.answer\") => {\n const err = toContentKitError(e);\n if (err.code === \"unauthorized\" && signIn) return signIn();\n setError(err);\n report(err, op);\n };\n const vote = (option: string) => {\n if (mustSignIn) return signIn?.();\n setError(null);\n r.vote(option).catch((e) => fail(e, \"poll.vote\"));\n };\n const header = (\n <>\n {poll.image_url && <img src={poll.image_url} alt=\"\" className=\"aspect-video w-full rounded-lg object-cover\" loading=\"lazy\" />}\n <h3 className=\"text-base font-semibold\" id={`poll-${poll.id}`}>\n {poll.question}\n </h3>\n {poll.closed ? (\n <p className=\"text-muted-foreground\">{t(\"poll.closed\")}</p>\n ) : (\n poll.closes_at && <p className=\"text-muted-foreground\">{t(\"poll.closes\", { date: formatDate(m, poll.closes_at) })}</p>\n )}\n </>\n );\n return root(\n <>\n {header}\n {poll.kind === \"free_text\" ? (\n <FreeText poll={poll} pending={r.pending} maxLength={p.maxLength ?? 280} results={p.results} onAnswer={(text) =>\n r.answer(text).then(\n () => true,\n (e) => (fail(e, \"poll.answer\"), false),\n )\n }\n />\n ) : (\n <Choices poll={poll} results={p.results === \"always\" || poll.voted || poll.closed} canVote={!poll.voted && !poll.closed && !r.pending && (!mustSignIn || !!signIn)} onVote={vote} />\n )}\n <ErrorLine error={error} />\n {!poll.voted && !poll.closed && mustSignIn && poll.kind !== \"free_text\" && <p className=\"text-xs text-muted-foreground\">{t(\"poll.signIn\")}</p>}\n </>,\n );\n}\n\nfunction Choices({ poll, results, canVote, onVote }: { poll: PollData; results: boolean; canVote: boolean; onVote: (option: string) => void }) {\n const m = useMessages();\n const { t } = m;\n const options = [...poll.options].sort((a, b) => a.position - b.position);\n const images = options.some((o) => o.image_url);\n const total = poll.total_votes || options.reduce((n, o) => n + o.vote_count, 0);\n const lead = Math.max(1, ...options.map((o) => o.vote_count));\n return (\n <>\n <ul className={cn(\"grid gap-2\", images && \"grid-cols-2\")} aria-labelledby={`poll-${poll.id}`}>\n {options.map((o) => {\n const mine = poll.my_option === o.id;\n const percent = total ? Math.round((o.vote_count / total) * 100) : 0;\n const body = (\n <>\n {o.image_url && <img src={o.image_url} alt=\"\" className=\"aspect-[4/3] w-full rounded-md bg-muted object-contain\" loading=\"lazy\" />}\n <span className=\"relative flex w-full items-center gap-2\">\n {results && (\n <span\n aria-hidden\n className={cn(\"absolute inset-y-0 start-0 rounded-md transition-[width] duration-500 motion-reduce:transition-none\", mine ? \"bg-primary/25\" : \"bg-muted\")}\n style={{ width: `${(o.vote_count / lead) * 100}%` }}\n />\n )}\n <span className=\"relative flex min-w-0 flex-1 items-center gap-2 px-2 py-1.5\">\n {mine && <HugeiconsIcon icon={Tick02Icon} strokeWidth={2.5} className=\"size-4 shrink-0 text-primary\" aria-label={t(\"poll.yourVote\")} />}\n <span className=\"min-w-0 flex-1 break-words text-start\">{o.label}</span>\n {results && <span className=\"shrink-0 tabular-nums font-medium\">{percent}%</span>}\n </span>\n </span>\n {results && <span className=\"sr-only\">{m.plural(\"poll.votes\", o.vote_count)}</span>}\n </>\n );\n return (\n <li key={o.id} data-option={o.id} data-mine={mine || undefined}>\n {canVote ? (\n <Button variant=\"outline\" className=\"h-auto w-full flex-col items-stretch gap-1.5 p-1 whitespace-normal\" onClick={() => onVote(o.id)}>\n {body}\n </Button>\n ) : (\n <div\n className=\"grid gap-1.5 rounded-md border border-border p-1\"\n role=\"meter\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={percent}\n aria-label={o.label}\n >\n {body}\n </div>\n )}\n </li>\n );\n })}\n </ul>\n {results && <p className=\"text-xs text-muted-foreground\">{m.plural(\"poll.votes\", total)}</p>}\n </>\n );\n}\n\nfunction FreeText({ poll, pending, maxLength, results, onAnswer }: { poll: PollData; pending: boolean; maxLength: number; results?: \"voted\" | \"always\"; onAnswer: (text: string) => Promise<boolean> }) {\n const m = useMessages();\n const { t } = m;\n const ids = useId();\n const mine = poll.my_answer;\n const [editing, setEditing] = useState(false);\n const [text, setText] = useState(mine?.text ?? \"\");\n const open = !poll.closed;\n const groups = [...(poll.groups ?? [])].sort((a, b) => b.count - a.count);\n const lead = Math.max(1, ...groups.map((g) => g.count));\n const showGroups = groups.length > 0 && (!!mine || poll.closed || results === \"always\");\n return (\n <>\n {open && (!mine || editing) ? (\n <form\n className=\"grid gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n if (!text.trim()) return;\n void onAnswer(text.trim()).then((ok) => ok && setEditing(false));\n }}\n >\n <label htmlFor={`${ids}-answer`} className=\"sr-only\">\n {t(\"poll.answerPlaceholder\")}\n </label>\n <Textarea id={`${ids}-answer`} rows={2} maxLength={maxLength} placeholder={t(\"poll.answerPlaceholder\")} value={text} disabled={pending} onChange={(e) => setText(e.target.value)} />\n <div className=\"flex justify-end gap-2\">\n {editing && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => setEditing(false)}>\n {t(\"common.cancel\")}\n </Button>\n )}\n <Button type=\"submit\" size=\"sm\" disabled={pending || !text.trim()}>\n {t(mine ? \"poll.updateAnswer\" : \"poll.answer\")}\n </Button>\n </div>\n </form>\n ) : (\n mine && (\n <div className=\"grid gap-1 rounded-md bg-muted p-3\">\n <p className=\"text-xs text-muted-foreground\">{t(\"poll.yourAnswer\")}</p>\n <p className=\"break-words whitespace-pre-wrap\">{mine.text}</p>\n {open && (\n <Button\n variant=\"link\"\n size=\"xs\"\n className=\"justify-self-start px-0\"\n onClick={() => {\n setText(mine.text);\n setEditing(true);\n }}\n >\n {t(\"poll.editAnswer\")}\n </Button>\n )}\n </div>\n )\n )}\n {showGroups && (\n <>\n <ul className=\"grid gap-2\" aria-labelledby={`poll-${poll.id}`}>\n {groups.map((g) => (\n <li key={g.id} className=\"relative flex items-center gap-2 rounded-md px-2 py-1.5\">\n <span aria-hidden className=\"absolute inset-y-0 start-0 rounded-md bg-muted\" style={{ width: `${(g.count / lead) * 100}%` }} />\n <span className=\"relative min-w-0 flex-1 break-words\">{g.label}</span>\n <span className=\"relative tabular-nums text-muted-foreground\">{m.plural(\"poll.answers\", g.count)}</span>\n </li>\n ))}\n </ul>\n {poll.answer_count !== undefined && <p className=\"text-xs text-muted-foreground\">{m.plural(\"poll.answers\", poll.answer_count)}</p>}\n </>\n )}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { ContentKitUiAppearance } from '../appearance.js';
|
|
3
|
+
export interface SortableListProps<T> {
|
|
4
|
+
items: readonly T[];
|
|
5
|
+
/** A stable key per item. */
|
|
6
|
+
id: (item: T) => string;
|
|
7
|
+
/** The item's spoken name in announcements and the handle's label. */
|
|
8
|
+
name: (item: T) => string;
|
|
9
|
+
/** Called once per drop with the old and new index. */
|
|
10
|
+
onMove: (from: number, to: number) => void;
|
|
11
|
+
/** Rows (default) or a wrapping grid of tiles. */
|
|
12
|
+
layout?: "list" | "grid";
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Attributes of an item's `<li>`. */
|
|
15
|
+
row?: (item: T) => HTMLAttributes<HTMLLIElement> & Record<`data-${string}`, unknown>;
|
|
16
|
+
/** An item's content; place `handle` (its drag handle) where it belongs. */
|
|
17
|
+
children: (item: T, handle: ReactNode, index: number) => ReactNode;
|
|
18
|
+
className?: string;
|
|
19
|
+
/** Accessible name of the list. */
|
|
20
|
+
label?: string;
|
|
21
|
+
appearance?: ContentKitUiAppearance;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A reorderable list or grid (dnd-kit): drag an item by its handle with a
|
|
25
|
+
* mouse, a finger or the keyboard (Space or Enter lifts, arrows move, Space
|
|
26
|
+
* or Enter drops, Escape cancels), with localized screen reader
|
|
27
|
+
* announcements. onMove gets the old and new index once, on drop.
|
|
28
|
+
*/
|
|
29
|
+
export declare function SortableList<T>({ items, id, name, onMove, layout, disabled, row, children, className, label, appearance }: SortableListProps<T>): import('react').JSX.Element;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { useMessages as e } from "../i18n/context.js";
|
|
2
|
+
import { ContentKitUiRoot as t } from "../scope.js";
|
|
3
|
+
import { useMemo as n, useState as r } from "react";
|
|
4
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
|
+
import { cn as o } from "cn";
|
|
6
|
+
import { DragDropVerticalIcon as s } from "@hugeicons/core-free-icons";
|
|
7
|
+
import { HugeiconsIcon as c } from "@hugeicons/react";
|
|
8
|
+
import { DndContext as l, DragOverlay as u, KeyboardSensor as d, PointerSensor as f, closestCenter as p, useSensor as m, useSensors as h } from "@dnd-kit/core";
|
|
9
|
+
import { SortableContext as g, sortableKeyboardCoordinates as _, useSortable as v } from "@dnd-kit/sortable";
|
|
10
|
+
//#region src/components/sortable-list.tsx
|
|
11
|
+
var y = () => null, b = "inline-flex size-8 shrink-0 cursor-grab touch-none items-center justify-center rounded-md text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring active:cursor-grabbing disabled:cursor-default disabled:opacity-50";
|
|
12
|
+
function x({ items: v, id: x, name: C, onMove: w, layout: T = "list", disabled: E, row: D, children: O, className: k, label: A, appearance: j }) {
|
|
13
|
+
let { t: M } = e(), N = h(m(f, { activationConstraint: { distance: 4 } }), m(d, { coordinateGetter: _ })), P = n(() => v.map(x), [v, x]), [F, I] = r(null), [L, R] = r(null), z = (e) => P.indexOf(String(e)), B = (e) => {
|
|
14
|
+
let t = z(e);
|
|
15
|
+
return t < 0 ? "" : C(v[t]);
|
|
16
|
+
}, V = P.length, H = {
|
|
17
|
+
onDragStart: ({ active: e }) => M("sortable.pickedUp", {
|
|
18
|
+
name: B(e.id),
|
|
19
|
+
position: z(e.id) + 1,
|
|
20
|
+
total: V
|
|
21
|
+
}),
|
|
22
|
+
onDragOver: ({ active: e, over: t }) => t ? M("sortable.over", {
|
|
23
|
+
name: B(e.id),
|
|
24
|
+
position: z(t.id) + 1,
|
|
25
|
+
total: V
|
|
26
|
+
}) : void 0,
|
|
27
|
+
onDragEnd: ({ active: e, over: t }) => t ? M("sortable.dropped", {
|
|
28
|
+
name: B(e.id),
|
|
29
|
+
position: z(t.id) + 1,
|
|
30
|
+
total: V
|
|
31
|
+
}) : M("sortable.droppedAway", { name: B(e.id) }),
|
|
32
|
+
onDragCancel: ({ active: e }) => M("sortable.canceled", { name: B(e.id) })
|
|
33
|
+
}, U = { draggable: M("sortable.instructions") }, W = F ? z(F) : -1, G = L ? z(L) : -1, K = W >= 0 ? v[W] : void 0, q = T === "grid", J = (e, t) => /* @__PURE__ */ i("ol", {
|
|
34
|
+
className: o(q ? "grid grid-cols-[repeat(auto-fill,minmax(8rem,1fr))] gap-2" : "grid gap-1", k),
|
|
35
|
+
"aria-label": t ? void 0 : A,
|
|
36
|
+
"data-ckui": "sortable-list",
|
|
37
|
+
"data-layout": T,
|
|
38
|
+
"data-overlay": t ? "" : void 0,
|
|
39
|
+
children: e
|
|
40
|
+
});
|
|
41
|
+
return /* @__PURE__ */ i(t, {
|
|
42
|
+
appearance: j,
|
|
43
|
+
className: "contents",
|
|
44
|
+
children: /* @__PURE__ */ a(l, {
|
|
45
|
+
sensors: N,
|
|
46
|
+
collisionDetection: p,
|
|
47
|
+
accessibility: {
|
|
48
|
+
announcements: H,
|
|
49
|
+
screenReaderInstructions: U
|
|
50
|
+
},
|
|
51
|
+
onDragStart: (e) => I(String(e.active.id)),
|
|
52
|
+
onDragOver: (e) => R(e.over ? String(e.over.id) : null),
|
|
53
|
+
onDragCancel: () => {
|
|
54
|
+
I(null), R(null);
|
|
55
|
+
},
|
|
56
|
+
onDragEnd: (e) => {
|
|
57
|
+
I(null), R(null);
|
|
58
|
+
let t = z(e.active.id), n = e.over ? z(e.over.id) : -1;
|
|
59
|
+
t >= 0 && n >= 0 && t !== n && w(t, n);
|
|
60
|
+
},
|
|
61
|
+
children: [/* @__PURE__ */ i(g, {
|
|
62
|
+
items: P,
|
|
63
|
+
strategy: y,
|
|
64
|
+
disabled: E,
|
|
65
|
+
children: J(v.map((e, t) => /* @__PURE__ */ i(S, {
|
|
66
|
+
id: P[t],
|
|
67
|
+
label: M("sortable.handle", { name: C(e) }),
|
|
68
|
+
attrs: D?.(e),
|
|
69
|
+
disabled: E,
|
|
70
|
+
grid: q,
|
|
71
|
+
dragging: t === W,
|
|
72
|
+
drop: W >= 0 && t === G && G !== W ? G > W ? "after" : "before" : void 0,
|
|
73
|
+
render: (n) => O(e, n, t)
|
|
74
|
+
}, P[t])))
|
|
75
|
+
}), /* @__PURE__ */ i(u, {
|
|
76
|
+
dropAnimation: null,
|
|
77
|
+
children: K === void 0 ? null : J(/* @__PURE__ */ i("li", {
|
|
78
|
+
...D?.(K),
|
|
79
|
+
className: o(D?.(K).className, "cursor-grabbing rounded-md bg-background shadow-lg ring-1 ring-border"),
|
|
80
|
+
children: O(K, /* @__PURE__ */ i("span", {
|
|
81
|
+
className: b,
|
|
82
|
+
children: /* @__PURE__ */ i(c, {
|
|
83
|
+
icon: s,
|
|
84
|
+
strokeWidth: 2,
|
|
85
|
+
className: "size-4.5"
|
|
86
|
+
})
|
|
87
|
+
}), W)
|
|
88
|
+
}), !0)
|
|
89
|
+
})]
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function S({ id: e, label: t, attrs: n, disabled: r, grid: a, dragging: l, drop: u, render: d }) {
|
|
94
|
+
let { attributes: f, listeners: p, setNodeRef: m, setActivatorNodeRef: h } = v({ id: e }), g = /* @__PURE__ */ i("button", {
|
|
95
|
+
type: "button",
|
|
96
|
+
ref: h,
|
|
97
|
+
className: b,
|
|
98
|
+
"aria-label": t,
|
|
99
|
+
disabled: r,
|
|
100
|
+
"data-ckui": "sort-handle",
|
|
101
|
+
...f,
|
|
102
|
+
...p,
|
|
103
|
+
children: /* @__PURE__ */ i(c, {
|
|
104
|
+
icon: s,
|
|
105
|
+
strokeWidth: 2,
|
|
106
|
+
className: "size-4.5"
|
|
107
|
+
})
|
|
108
|
+
});
|
|
109
|
+
return /* @__PURE__ */ i("li", {
|
|
110
|
+
...n,
|
|
111
|
+
ref: m,
|
|
112
|
+
className: o(n?.className, "relative data-dragging:opacity-40 before:pointer-events-none before:absolute before:rounded-full before:bg-primary before:opacity-0", a ? "before:inset-y-0 before:w-0.5 data-[drop=before]:before:-left-[5px] data-[drop=before]:before:opacity-100 data-[drop=after]:before:-right-[5px] data-[drop=after]:before:opacity-100" : "before:inset-x-0 before:h-0.5 data-[drop=before]:before:-top-[3px] data-[drop=before]:before:opacity-100 data-[drop=after]:before:-bottom-[3px] data-[drop=after]:before:opacity-100"),
|
|
113
|
+
"data-drop": u,
|
|
114
|
+
"data-dragging": l || void 0,
|
|
115
|
+
children: d(g)
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
export { x as SortableList };
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=sortable-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sortable-list.js","names":[],"sources":["../../src/components/sortable-list.tsx"],"sourcesContent":["import {\n DndContext,\n DragOverlay,\n KeyboardSensor,\n PointerSensor,\n closestCenter,\n useSensor,\n useSensors,\n type Announcements,\n type ScreenReaderInstructions,\n} from \"@dnd-kit/core\";\nimport { SortableContext, sortableKeyboardCoordinates, useSortable } from \"@dnd-kit/sortable\";\nimport { DragDropVerticalIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useMemo, useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\n\nexport interface SortableListProps<T> {\n items: readonly T[];\n /** A stable key per item. */\n id: (item: T) => string;\n /** The item's spoken name in announcements and the handle's label. */\n name: (item: T) => string;\n /** Called once per drop with the old and new index. */\n onMove: (from: number, to: number) => void;\n /** Rows (default) or a wrapping grid of tiles. */\n layout?: \"list\" | \"grid\";\n disabled?: boolean;\n /** Attributes of an item's `<li>`. */\n row?: (item: T) => HTMLAttributes<HTMLLIElement> & Record<`data-${string}`, unknown>;\n /** An item's content; place `handle` (its drag handle) where it belongs. */\n children: (item: T, handle: ReactNode, index: number) => ReactNode;\n className?: string;\n /** Accessible name of the list. */\n label?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n// Items stay put while dragging; a bar marks where the item will land.\nconst noShift = () => null;\nconst handleClass =\n \"inline-flex size-8 shrink-0 cursor-grab touch-none items-center justify-center rounded-md text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring active:cursor-grabbing disabled:cursor-default disabled:opacity-50\";\n\n/**\n * A reorderable list or grid (dnd-kit): drag an item by its handle with a\n * mouse, a finger or the keyboard (Space or Enter lifts, arrows move, Space\n * or Enter drops, Escape cancels), with localized screen reader\n * announcements. onMove gets the old and new index once, on drop.\n */\nexport function SortableList<T>({ items, id, name, onMove, layout = \"list\", disabled, row, children, className, label, appearance }: SortableListProps<T>) {\n const { t } = useMessages();\n const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));\n const ids = useMemo(() => items.map(id), [items, id]);\n const [active, setActive] = useState<string | null>(null);\n const [over, setOver] = useState<string | null>(null);\n const at = (key: unknown) => ids.indexOf(String(key));\n const spoken = (key: unknown) => {\n const i = at(key);\n return i < 0 ? \"\" : name(items[i]!);\n };\n const total = ids.length;\n const announcements: Announcements = {\n onDragStart: ({ active }) => t(\"sortable.pickedUp\", { name: spoken(active.id), position: at(active.id) + 1, total }),\n onDragOver: ({ active, over }) => (over ? t(\"sortable.over\", { name: spoken(active.id), position: at(over.id) + 1, total }) : undefined),\n onDragEnd: ({ active, over }) =>\n over ? t(\"sortable.dropped\", { name: spoken(active.id), position: at(over.id) + 1, total }) : t(\"sortable.droppedAway\", { name: spoken(active.id) }),\n onDragCancel: ({ active }) => t(\"sortable.canceled\", { name: spoken(active.id) }),\n };\n const instructions: ScreenReaderInstructions = { draggable: t(\"sortable.instructions\") };\n const from = active ? at(active) : -1;\n const to = over ? at(over) : -1;\n const dragged = from >= 0 ? items[from] : undefined;\n const grid = layout === \"grid\";\n const list = (inner: ReactNode, overlay?: boolean) => (\n <ol\n className={cn(grid ? \"grid grid-cols-[repeat(auto-fill,minmax(8rem,1fr))] gap-2\" : \"grid gap-1\", className)}\n aria-label={overlay ? undefined : label}\n data-ckui=\"sortable-list\"\n data-layout={layout}\n data-overlay={overlay ? \"\" : undefined}\n >\n {inner}\n </ol>\n );\n return (\n <ContentKitUiRoot appearance={appearance} className=\"contents\">\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n accessibility={{ announcements, screenReaderInstructions: instructions }}\n onDragStart={(e) => setActive(String(e.active.id))}\n onDragOver={(e) => setOver(e.over ? String(e.over.id) : null)}\n onDragCancel={() => {\n setActive(null);\n setOver(null);\n }}\n onDragEnd={(e) => {\n setActive(null);\n setOver(null);\n const a = at(e.active.id);\n const b = e.over ? at(e.over.id) : -1;\n if (a >= 0 && b >= 0 && a !== b) onMove(a, b);\n }}\n >\n <SortableContext items={ids} strategy={noShift} disabled={disabled}>\n {list(\n items.map((item, i) => (\n <Item\n key={ids[i]}\n id={ids[i]!}\n label={t(\"sortable.handle\", { name: name(item) })}\n attrs={row?.(item)}\n disabled={disabled}\n grid={grid}\n dragging={i === from}\n drop={from >= 0 && i === to && to !== from ? (to > from ? \"after\" : \"before\") : undefined}\n render={(handle) => children(item, handle, i)}\n />\n )),\n )}\n </SortableContext>\n <DragOverlay dropAnimation={null}>\n {dragged !== undefined\n ? list(\n <li {...row?.(dragged)} className={cn(row?.(dragged).className, \"cursor-grabbing rounded-md bg-background shadow-lg ring-1 ring-border\")}>\n {children(\n dragged,\n <span className={handleClass}>\n <HugeiconsIcon icon={DragDropVerticalIcon} strokeWidth={2} className=\"size-4.5\" />\n </span>,\n from,\n )}\n </li>,\n true,\n )\n : null}\n </DragOverlay>\n </DndContext>\n </ContentKitUiRoot>\n );\n}\n\nfunction Item({\n id,\n label,\n attrs,\n disabled,\n grid,\n dragging,\n drop,\n render,\n}: {\n id: string;\n label: string;\n attrs?: HTMLAttributes<HTMLLIElement>;\n disabled?: boolean;\n grid: boolean;\n dragging: boolean;\n drop?: \"before\" | \"after\";\n render: (handle: ReactNode) => ReactNode;\n}) {\n const { attributes, listeners, setNodeRef, setActivatorNodeRef } = useSortable({ id });\n const handle = (\n <button type=\"button\" ref={setActivatorNodeRef} className={handleClass} aria-label={label} disabled={disabled} data-ckui=\"sort-handle\" {...attributes} {...listeners}>\n <HugeiconsIcon icon={DragDropVerticalIcon} strokeWidth={2} className=\"size-4.5\" />\n </button>\n );\n return (\n <li\n {...attrs}\n ref={setNodeRef}\n className={cn(\n attrs?.className,\n \"relative data-dragging:opacity-40 before:pointer-events-none before:absolute before:rounded-full before:bg-primary before:opacity-0\",\n grid\n ? \"before:inset-y-0 before:w-0.5 data-[drop=before]:before:-left-[5px] data-[drop=before]:before:opacity-100 data-[drop=after]:before:-right-[5px] data-[drop=after]:before:opacity-100\"\n : \"before:inset-x-0 before:h-0.5 data-[drop=before]:before:-top-[3px] data-[drop=before]:before:opacity-100 data-[drop=after]:before:-bottom-[3px] data-[drop=after]:before:opacity-100\",\n )}\n data-drop={drop}\n data-dragging={dragging || undefined}\n >\n {render(handle)}\n </li>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
import { ContentKitUiAppearance } from '../appearance.js';
|
|
3
|
+
import { HlsPlayerOptions } from '../react/gallery.js';
|
|
4
|
+
import { PlaybackProgress } from '../react/player.js';
|
|
5
|
+
import { PlayerHandoff } from './video-player.js';
|
|
6
|
+
export interface VideoMiniPlayerProps extends Omit<HlsPlayerOptions, "src" | "startAt" | "autoPlay" | "audioLanguage" | "subtitleLanguage" | "active"> {
|
|
7
|
+
/** What VideoPlayer's onMiniPlayer handed over. */
|
|
8
|
+
handoff: PlayerHandoff;
|
|
9
|
+
/** Back to the full player, where this one is. */
|
|
10
|
+
onExpand: (state: {
|
|
11
|
+
time: number;
|
|
12
|
+
playing: boolean;
|
|
13
|
+
}) => void;
|
|
14
|
+
onClose: (state: {
|
|
15
|
+
time: number;
|
|
16
|
+
}) => void;
|
|
17
|
+
onProgress?: (progress: PlaybackProgress) => void;
|
|
18
|
+
/** Milliseconds. Default 10000. */
|
|
19
|
+
progressInterval?: number;
|
|
20
|
+
/** K, J, L and M page-wide (default), every shortcut while focus is in it, or none. */
|
|
21
|
+
keyboard?: "global" | "focus" | false;
|
|
22
|
+
/** The video's title. */
|
|
23
|
+
label?: string;
|
|
24
|
+
position?: "bottom-right" | "bottom-left";
|
|
25
|
+
crossOrigin?: "anonymous" | "use-credentials";
|
|
26
|
+
className?: string;
|
|
27
|
+
style?: CSSProperties;
|
|
28
|
+
appearance?: ContentKitUiAppearance;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The video docked in a corner while the viewer browses: play, ±10 s, mute,
|
|
32
|
+
* a seek line, expand back to the full player and close. It starts where
|
|
33
|
+
* the handoff stopped, playing if it was.
|
|
34
|
+
*/
|
|
35
|
+
export declare function VideoMiniPlayer({ handoff, onExpand, onClose, onProgress, progressInterval, keyboard, label, position, crossOrigin, className, style, appearance, ...options }: VideoMiniPlayerProps): import('react').JSX.Element;
|