@gabvdl/ui 0.0.14
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 +95 -0
- package/dist/components/button/button.d.ts +39 -0
- package/dist/components/button/button.d.ts.map +1 -0
- package/dist/components/button/button.js +72 -0
- package/dist/components/button/button.js.map +1 -0
- package/dist/components/button/index.d.ts +5 -0
- package/dist/components/button/index.d.ts.map +1 -0
- package/dist/components/button/tooltip.d.ts +31 -0
- package/dist/components/button/tooltip.d.ts.map +1 -0
- package/dist/components/button/tooltip.js +83 -0
- package/dist/components/button/tooltip.js.map +1 -0
- package/dist/components/changelog/changelog.d.ts +52 -0
- package/dist/components/changelog/changelog.d.ts.map +1 -0
- package/dist/components/changelog/changelog.js +164 -0
- package/dist/components/changelog/changelog.js.map +1 -0
- package/dist/components/changelog/index.d.ts +3 -0
- package/dist/components/changelog/index.d.ts.map +1 -0
- package/dist/components/copy-button/copy-button.d.ts +16 -0
- package/dist/components/copy-button/copy-button.d.ts.map +1 -0
- package/dist/components/copy-button/copy-button.js +40 -0
- package/dist/components/copy-button/copy-button.js.map +1 -0
- package/dist/components/copy-button/index.d.ts +3 -0
- package/dist/components/copy-button/index.d.ts.map +1 -0
- package/dist/components/drop-zone/drop-zone.d.ts +20 -0
- package/dist/components/drop-zone/drop-zone.d.ts.map +1 -0
- package/dist/components/drop-zone/drop-zone.js +54 -0
- package/dist/components/drop-zone/drop-zone.js.map +1 -0
- package/dist/components/drop-zone/index.d.ts +5 -0
- package/dist/components/drop-zone/index.d.ts.map +1 -0
- package/dist/components/drop-zone/use-file-drop.d.ts +45 -0
- package/dist/components/drop-zone/use-file-drop.d.ts.map +1 -0
- package/dist/components/drop-zone/use-file-drop.js +97 -0
- package/dist/components/drop-zone/use-file-drop.js.map +1 -0
- package/dist/components/element-picker/element-picker-field.d.ts +30 -0
- package/dist/components/element-picker/element-picker-field.d.ts.map +1 -0
- package/dist/components/element-picker/element-picker-field.js +273 -0
- package/dist/components/element-picker/element-picker-field.js.map +1 -0
- package/dist/components/element-picker/element-picker.d.ts +45 -0
- package/dist/components/element-picker/element-picker.d.ts.map +1 -0
- package/dist/components/element-picker/element-picker.js +179 -0
- package/dist/components/element-picker/element-picker.js.map +1 -0
- package/dist/components/element-picker/element-preview.d.ts +23 -0
- package/dist/components/element-picker/element-preview.d.ts.map +1 -0
- package/dist/components/element-picker/element-preview.js +72 -0
- package/dist/components/element-picker/element-preview.js.map +1 -0
- package/dist/components/element-picker/index.d.ts +12 -0
- package/dist/components/element-picker/index.d.ts.map +1 -0
- package/dist/components/element-picker/parse.d.ts +32 -0
- package/dist/components/element-picker/parse.d.ts.map +1 -0
- package/dist/components/element-picker/parse.js +230 -0
- package/dist/components/element-picker/parse.js.map +1 -0
- package/dist/components/element-picker/types.d.ts +72 -0
- package/dist/components/element-picker/types.d.ts.map +1 -0
- package/dist/components/element-picker/use-element-picker.d.ts +56 -0
- package/dist/components/element-picker/use-element-picker.d.ts.map +1 -0
- package/dist/components/element-picker/use-element-picker.js +201 -0
- package/dist/components/element-picker/use-element-picker.js.map +1 -0
- package/dist/components/empty-state/empty-state.d.ts +16 -0
- package/dist/components/empty-state/empty-state.d.ts.map +1 -0
- package/dist/components/empty-state/empty-state.js +41 -0
- package/dist/components/empty-state/empty-state.js.map +1 -0
- package/dist/components/empty-state/index.d.ts +3 -0
- package/dist/components/empty-state/index.d.ts.map +1 -0
- package/dist/components/floating-panel/dock-context.d.ts +66 -0
- package/dist/components/floating-panel/dock-context.d.ts.map +1 -0
- package/dist/components/floating-panel/dock-context.js +96 -0
- package/dist/components/floating-panel/dock-context.js.map +1 -0
- package/dist/components/floating-panel/dock.d.ts +26 -0
- package/dist/components/floating-panel/dock.d.ts.map +1 -0
- package/dist/components/floating-panel/dock.js +46 -0
- package/dist/components/floating-panel/dock.js.map +1 -0
- package/dist/components/floating-panel/floating-panel.d.ts +69 -0
- package/dist/components/floating-panel/floating-panel.d.ts.map +1 -0
- package/dist/components/floating-panel/floating-panel.js +285 -0
- package/dist/components/floating-panel/floating-panel.js.map +1 -0
- package/dist/components/floating-panel/index.d.ts +7 -0
- package/dist/components/floating-panel/index.d.ts.map +1 -0
- package/dist/components/fuzzy-list/fuzzy-list.d.ts +96 -0
- package/dist/components/fuzzy-list/fuzzy-list.d.ts.map +1 -0
- package/dist/components/fuzzy-list/fuzzy-list.js +127 -0
- package/dist/components/fuzzy-list/fuzzy-list.js.map +1 -0
- package/dist/components/fuzzy-list/index.d.ts +4 -0
- package/dist/components/fuzzy-list/index.d.ts.map +1 -0
- package/dist/components/global-search/global-search.d.ts +78 -0
- package/dist/components/global-search/global-search.d.ts.map +1 -0
- package/dist/components/global-search/global-search.js +181 -0
- package/dist/components/global-search/global-search.js.map +1 -0
- package/dist/components/global-search/hotkey.d.ts +23 -0
- package/dist/components/global-search/hotkey.d.ts.map +1 -0
- package/dist/components/global-search/hotkey.js +41 -0
- package/dist/components/global-search/hotkey.js.map +1 -0
- package/dist/components/global-search/index.d.ts +5 -0
- package/dist/components/global-search/index.d.ts.map +1 -0
- package/dist/components/iframe-preview/iframe-preview.d.ts +64 -0
- package/dist/components/iframe-preview/iframe-preview.d.ts.map +1 -0
- package/dist/components/iframe-preview/iframe-preview.js +257 -0
- package/dist/components/iframe-preview/iframe-preview.js.map +1 -0
- package/dist/components/iframe-preview/index.d.ts +3 -0
- package/dist/components/iframe-preview/index.d.ts.map +1 -0
- package/dist/components/image-viewer/image-viewer.d.ts +30 -0
- package/dist/components/image-viewer/image-viewer.d.ts.map +1 -0
- package/dist/components/image-viewer/image-viewer.js +226 -0
- package/dist/components/image-viewer/image-viewer.js.map +1 -0
- package/dist/components/image-viewer/index.d.ts +4 -0
- package/dist/components/image-viewer/index.d.ts.map +1 -0
- package/dist/components/image-viewer/progressive-image.d.ts +20 -0
- package/dist/components/image-viewer/progressive-image.d.ts.map +1 -0
- package/dist/components/image-viewer/progressive-image.js +62 -0
- package/dist/components/image-viewer/progressive-image.js.map +1 -0
- package/dist/components/image-viewer/viewable-image.d.ts +17 -0
- package/dist/components/image-viewer/viewable-image.d.ts.map +1 -0
- package/dist/components/image-viewer/viewable-image.js +38 -0
- package/dist/components/image-viewer/viewable-image.js.map +1 -0
- package/dist/components/input/index.d.ts +3 -0
- package/dist/components/input/index.d.ts.map +1 -0
- package/dist/components/input/input.d.ts +15 -0
- package/dist/components/input/input.d.ts.map +1 -0
- package/dist/components/input/input.js +56 -0
- package/dist/components/input/input.js.map +1 -0
- package/dist/components/modal/index.d.ts +5 -0
- package/dist/components/modal/index.d.ts.map +1 -0
- package/dist/components/modal/modal-context.d.ts +37 -0
- package/dist/components/modal/modal-context.d.ts.map +1 -0
- package/dist/components/modal/modal-context.js +81 -0
- package/dist/components/modal/modal-context.js.map +1 -0
- package/dist/components/modal/modal.d.ts +28 -0
- package/dist/components/modal/modal.d.ts.map +1 -0
- package/dist/components/modal/modal.js +94 -0
- package/dist/components/modal/modal.js.map +1 -0
- package/dist/components/nav-2d/index.d.ts +3 -0
- package/dist/components/nav-2d/index.d.ts.map +1 -0
- package/dist/components/nav-2d/nav-2d.d.ts +59 -0
- package/dist/components/nav-2d/nav-2d.d.ts.map +1 -0
- package/dist/components/nav-2d/nav-2d.js +290 -0
- package/dist/components/nav-2d/nav-2d.js.map +1 -0
- package/dist/components/phone-preview/index.d.ts +3 -0
- package/dist/components/phone-preview/index.d.ts.map +1 -0
- package/dist/components/phone-preview/phone-preview.d.ts +45 -0
- package/dist/components/phone-preview/phone-preview.d.ts.map +1 -0
- package/dist/components/phone-preview/phone-preview.js +117 -0
- package/dist/components/phone-preview/phone-preview.js.map +1 -0
- package/dist/components/progressive-bash/index.d.ts +7 -0
- package/dist/components/progressive-bash/index.d.ts.map +1 -0
- package/dist/components/progressive-bash/parse.d.ts +88 -0
- package/dist/components/progressive-bash/parse.d.ts.map +1 -0
- package/dist/components/progressive-bash/parse.js +120 -0
- package/dist/components/progressive-bash/parse.js.map +1 -0
- package/dist/components/progressive-bash/playback.d.ts +50 -0
- package/dist/components/progressive-bash/playback.d.ts.map +1 -0
- package/dist/components/progressive-bash/playback.js +19 -0
- package/dist/components/progressive-bash/playback.js.map +1 -0
- package/dist/components/progressive-bash/progressive-bash.d.ts +97 -0
- package/dist/components/progressive-bash/progressive-bash.d.ts.map +1 -0
- package/dist/components/progressive-bash/progressive-bash.js +377 -0
- package/dist/components/progressive-bash/progressive-bash.js.map +1 -0
- package/dist/components/progressive-list/index.d.ts +3 -0
- package/dist/components/progressive-list/index.d.ts.map +1 -0
- package/dist/components/progressive-list/progressive-list.d.ts +55 -0
- package/dist/components/progressive-list/progressive-list.d.ts.map +1 -0
- package/dist/components/progressive-list/progressive-list.js +83 -0
- package/dist/components/progressive-list/progressive-list.js.map +1 -0
- package/dist/components/progressive-table/index.d.ts +3 -0
- package/dist/components/progressive-table/index.d.ts.map +1 -0
- package/dist/components/progressive-table/progressive-table.d.ts +58 -0
- package/dist/components/progressive-table/progressive-table.d.ts.map +1 -0
- package/dist/components/progressive-table/progressive-table.js +86 -0
- package/dist/components/progressive-table/progressive-table.js.map +1 -0
- package/dist/components/progressive-text/index.d.ts +3 -0
- package/dist/components/progressive-text/index.d.ts.map +1 -0
- package/dist/components/progressive-text/progressive-text.d.ts +54 -0
- package/dist/components/progressive-text/progressive-text.d.ts.map +1 -0
- package/dist/components/progressive-text/progressive-text.js +97 -0
- package/dist/components/progressive-text/progressive-text.js.map +1 -0
- package/dist/components/progressive-timeline/index.d.ts +3 -0
- package/dist/components/progressive-timeline/index.d.ts.map +1 -0
- package/dist/components/progressive-timeline/progressive-timeline.d.ts +46 -0
- package/dist/components/progressive-timeline/progressive-timeline.d.ts.map +1 -0
- package/dist/components/progressive-timeline/progressive-timeline.js +62 -0
- package/dist/components/progressive-timeline/progressive-timeline.js.map +1 -0
- package/dist/components/relative-time/index.d.ts +3 -0
- package/dist/components/relative-time/index.d.ts.map +1 -0
- package/dist/components/relative-time/relative-time.d.ts +14 -0
- package/dist/components/relative-time/relative-time.d.ts.map +1 -0
- package/dist/components/relative-time/relative-time.js +15 -0
- package/dist/components/relative-time/relative-time.js.map +1 -0
- package/dist/components/resizable-layout/index.d.ts +3 -0
- package/dist/components/resizable-layout/index.d.ts.map +1 -0
- package/dist/components/resizable-layout/resizable-layout.d.ts +113 -0
- package/dist/components/resizable-layout/resizable-layout.d.ts.map +1 -0
- package/dist/components/resizable-layout/resizable-layout.js +398 -0
- package/dist/components/resizable-layout/resizable-layout.js.map +1 -0
- package/dist/components/rich-input/compose.d.ts +13 -0
- package/dist/components/rich-input/compose.d.ts.map +1 -0
- package/dist/components/rich-input/compose.js +28 -0
- package/dist/components/rich-input/compose.js.map +1 -0
- package/dist/components/rich-input/index.d.ts +5 -0
- package/dist/components/rich-input/index.d.ts.map +1 -0
- package/dist/components/rich-input/parts.d.ts +53 -0
- package/dist/components/rich-input/parts.d.ts.map +1 -0
- package/dist/components/rich-input/parts.js +285 -0
- package/dist/components/rich-input/parts.js.map +1 -0
- package/dist/components/rich-input/rich-input.d.ts +64 -0
- package/dist/components/rich-input/rich-input.d.ts.map +1 -0
- package/dist/components/rich-input/rich-input.js +351 -0
- package/dist/components/rich-input/rich-input.js.map +1 -0
- package/dist/components/rich-input/types.d.ts +92 -0
- package/dist/components/rich-input/types.d.ts.map +1 -0
- package/dist/components/rich-input/use-draft.d.ts +9 -0
- package/dist/components/rich-input/use-draft.d.ts.map +1 -0
- package/dist/components/rich-input/use-draft.js +47 -0
- package/dist/components/rich-input/use-draft.js.map +1 -0
- package/dist/components/rich-input/use-file-upload.d.ts +18 -0
- package/dist/components/rich-input/use-file-upload.d.ts.map +1 -0
- package/dist/components/rich-input/use-file-upload.js +88 -0
- package/dist/components/rich-input/use-file-upload.js.map +1 -0
- package/dist/components/rich-input/use-guidelines.d.ts +16 -0
- package/dist/components/rich-input/use-guidelines.d.ts.map +1 -0
- package/dist/components/rich-input/use-guidelines.js +85 -0
- package/dist/components/rich-input/use-guidelines.js.map +1 -0
- package/dist/components/rich-input/use-input-history.d.ts +22 -0
- package/dist/components/rich-input/use-input-history.d.ts.map +1 -0
- package/dist/components/rich-input/use-input-history.js +61 -0
- package/dist/components/rich-input/use-input-history.js.map +1 -0
- package/dist/components/rich-input/use-mention.d.ts +24 -0
- package/dist/components/rich-input/use-mention.d.ts.map +1 -0
- package/dist/components/rich-input/use-mention.js +54 -0
- package/dist/components/rich-input/use-mention.js.map +1 -0
- package/dist/components/search-input/index.d.ts +3 -0
- package/dist/components/search-input/index.d.ts.map +1 -0
- package/dist/components/search-input/search-input.d.ts +14 -0
- package/dist/components/search-input/search-input.d.ts.map +1 -0
- package/dist/components/search-input/search-input.js +63 -0
- package/dist/components/search-input/search-input.js.map +1 -0
- package/dist/components/skeleton/index.d.ts +3 -0
- package/dist/components/skeleton/index.d.ts.map +1 -0
- package/dist/components/skeleton/skeleton.d.ts +19 -0
- package/dist/components/skeleton/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton/skeleton.js +29 -0
- package/dist/components/skeleton/skeleton.js.map +1 -0
- package/dist/components/spinner/index.d.ts +3 -0
- package/dist/components/spinner/index.d.ts.map +1 -0
- package/dist/components/spinner/spinner.d.ts +11 -0
- package/dist/components/spinner/spinner.d.ts.map +1 -0
- package/dist/components/spinner/spinner.js +32 -0
- package/dist/components/spinner/spinner.js.map +1 -0
- package/dist/components/status-badge/index.d.ts +3 -0
- package/dist/components/status-badge/index.d.ts.map +1 -0
- package/dist/components/status-badge/status-badge.d.ts +31 -0
- package/dist/components/status-badge/status-badge.d.ts.map +1 -0
- package/dist/components/status-badge/status-badge.js +53 -0
- package/dist/components/status-badge/status-badge.js.map +1 -0
- package/dist/components/theme/index.d.ts +5 -0
- package/dist/components/theme/index.d.ts.map +1 -0
- package/dist/components/theme/theme-toggle.d.ts +11 -0
- package/dist/components/theme/theme-toggle.d.ts.map +1 -0
- package/dist/components/theme/theme-toggle.js +57 -0
- package/dist/components/theme/theme-toggle.js.map +1 -0
- package/dist/components/theme/theme.d.ts +29 -0
- package/dist/components/theme/theme.d.ts.map +1 -0
- package/dist/components/theme/theme.js +70 -0
- package/dist/components/theme/theme.js.map +1 -0
- package/dist/components/toast/index.d.ts +3 -0
- package/dist/components/toast/index.d.ts.map +1 -0
- package/dist/components/toast/toast.d.ts +64 -0
- package/dist/components/toast/toast.d.ts.map +1 -0
- package/dist/components/toast/toast.js +155 -0
- package/dist/components/toast/toast.js.map +1 -0
- package/dist/components/virtual-list/index.d.ts +3 -0
- package/dist/components/virtual-list/index.d.ts.map +1 -0
- package/dist/components/virtual-list/virtual-list.d.ts +71 -0
- package/dist/components/virtual-list/virtual-list.d.ts.map +1 -0
- package/dist/components/virtual-list/virtual-list.js +65 -0
- package/dist/components/virtual-list/virtual-list.js.map +1 -0
- package/dist/hooks/index.d.ts +12 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/use-copy-to-clipboard.d.ts +26 -0
- package/dist/hooks/use-copy-to-clipboard.d.ts.map +1 -0
- package/dist/hooks/use-copy-to-clipboard.js +36 -0
- package/dist/hooks/use-copy-to-clipboard.js.map +1 -0
- package/dist/hooks/use-debounced-value.d.ts +23 -0
- package/dist/hooks/use-debounced-value.d.ts.map +1 -0
- package/dist/hooks/use-debounced-value.js +19 -0
- package/dist/hooks/use-debounced-value.js.map +1 -0
- package/dist/hooks/use-intersection.d.ts +25 -0
- package/dist/hooks/use-intersection.d.ts.map +1 -0
- package/dist/hooks/use-intersection.js +38 -0
- package/dist/hooks/use-intersection.js.map +1 -0
- package/dist/hooks/use-local-storage.d.ts +12 -0
- package/dist/hooks/use-local-storage.d.ts.map +1 -0
- package/dist/hooks/use-local-storage.js +43 -0
- package/dist/hooks/use-local-storage.js.map +1 -0
- package/dist/hooks/use-long-press.d.ts +37 -0
- package/dist/hooks/use-long-press.d.ts.map +1 -0
- package/dist/hooks/use-long-press.js +39 -0
- package/dist/hooks/use-long-press.js.map +1 -0
- package/dist/hooks/use-media-query.d.ts +17 -0
- package/dist/hooks/use-media-query.d.ts.map +1 -0
- package/dist/hooks/use-media-query.js +37 -0
- package/dist/hooks/use-media-query.js.map +1 -0
- package/dist/hooks/use-overlay.d.ts +20 -0
- package/dist/hooks/use-overlay.d.ts.map +1 -0
- package/dist/hooks/use-overlay.js +42 -0
- package/dist/hooks/use-overlay.js.map +1 -0
- package/dist/image-viewer.css +152 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +161 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/format.d.ts +19 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/format.js +62 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/highlight.d.ts +15 -0
- package/dist/lib/highlight.d.ts.map +1 -0
- package/dist/lib/highlight.js +39 -0
- package/dist/lib/highlight.js.map +1 -0
- package/dist/lib/search.d.ts +40 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/search.js +91 -0
- package/dist/lib/search.js.map +1 -0
- package/dist/lib/utils.d.ts +4 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/overlay.css +78 -0
- package/dist/styles.css +6 -0
- package/dist/theme.css +81 -0
- package/dist/tooltip.css +53 -0
- package/dist/virtual-list.css +29 -0
- package/package.json +77 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { useState as h, useCallback as p } from "react";
|
|
2
|
+
function R(t, a) {
|
|
3
|
+
const o = typeof URL < "u" && t.type.startsWith("image/") ? URL.createObjectURL(t) : void 0;
|
|
4
|
+
return {
|
|
5
|
+
id: `${t.name}:${t.size}:${t.lastModified}:${a}`,
|
|
6
|
+
name: t.name,
|
|
7
|
+
size: t.size,
|
|
8
|
+
contentType: t.type || "application/octet-stream",
|
|
9
|
+
url: o,
|
|
10
|
+
meta: t
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function W(t, a) {
|
|
14
|
+
if (!t) return !0;
|
|
15
|
+
const o = t.split(",").map((n) => n.trim().toLowerCase()).filter(Boolean);
|
|
16
|
+
if (o.length === 0) return !0;
|
|
17
|
+
const u = a.name.toLowerCase(), l = a.type.toLowerCase();
|
|
18
|
+
return o.some((n) => n.startsWith(".") ? u.endsWith(n) : n.endsWith("/*") ? l.startsWith(n.slice(0, -1)) : l === n);
|
|
19
|
+
}
|
|
20
|
+
function j({
|
|
21
|
+
upload: t,
|
|
22
|
+
accept: a,
|
|
23
|
+
maxFiles: o,
|
|
24
|
+
filter: u
|
|
25
|
+
}) {
|
|
26
|
+
const [l, n] = h([]), [y, g] = h(!1), [$, s] = h(null), L = p(
|
|
27
|
+
async (f) => {
|
|
28
|
+
const i = Array.from(f ?? []);
|
|
29
|
+
if (i.length === 0) return;
|
|
30
|
+
s(null);
|
|
31
|
+
const r = [];
|
|
32
|
+
for (const e of i) {
|
|
33
|
+
if (!W(a, e)) {
|
|
34
|
+
s(`${e.name}: type not accepted`);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const m = u == null ? void 0 : u(e);
|
|
38
|
+
if (m === !1) {
|
|
39
|
+
s(`${e.name}: rejected`);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (typeof m == "string") {
|
|
43
|
+
s(`${e.name}: ${m}`);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
r.push(e);
|
|
47
|
+
}
|
|
48
|
+
if (r.length === 0) return;
|
|
49
|
+
const d = o == null ? r.length : Math.max(0, o - l.length);
|
|
50
|
+
if (d <= 0) {
|
|
51
|
+
s(`At most ${o} file${o === 1 ? "" : "s"}`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const c = r.slice(0, d);
|
|
55
|
+
if (c.length < r.length && s(`At most ${o} files`), !t) {
|
|
56
|
+
n((e) => [...e, ...c.map(R)]);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
g(!0);
|
|
60
|
+
try {
|
|
61
|
+
const e = await t(c);
|
|
62
|
+
n((m) => [...m, ...e]);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
s(e instanceof Error ? e.message : String(e));
|
|
65
|
+
} finally {
|
|
66
|
+
g(!1);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
[a, o, u, t, l.length]
|
|
70
|
+
), U = p((f) => {
|
|
71
|
+
n((i) => {
|
|
72
|
+
var d;
|
|
73
|
+
const r = i.find((c) => c.id === f);
|
|
74
|
+
return (d = r == null ? void 0 : r.url) != null && d.startsWith("blob:") && URL.revokeObjectURL(r.url), i.filter((c) => c.id !== f);
|
|
75
|
+
});
|
|
76
|
+
}, []), b = p(() => {
|
|
77
|
+
n((f) => {
|
|
78
|
+
var i;
|
|
79
|
+
for (const r of f) (i = r.url) != null && i.startsWith("blob:") && URL.revokeObjectURL(r.url);
|
|
80
|
+
return [];
|
|
81
|
+
}), s(null);
|
|
82
|
+
}, []);
|
|
83
|
+
return { files: l, uploading: y, error: $, add: L, remove: U, reset: b, setFiles: n };
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
j as useFileUpload
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=use-file-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-file-upload.js","sources":["../../../src/components/rich-input/use-file-upload.ts"],"sourcesContent":["import { useCallback, useState } from 'react';\n\nimport type { RichFile } from './types';\n\n/** Turn a browser File into a local RichFile (used when no uploader is given). */\nfunction localFile(file: File, i: number): RichFile {\n const url =\n typeof URL !== 'undefined' && file.type.startsWith('image/') ? URL.createObjectURL(file) : undefined;\n return {\n id: `${file.name}:${file.size}:${file.lastModified}:${i}`,\n name: file.name,\n size: file.size,\n contentType: file.type || 'application/octet-stream',\n url,\n meta: file,\n };\n}\n\n/** Does `accept` (an <input accept> string) admit this file? */\nfunction acceptsFile(accept: string | undefined, file: File): boolean {\n if (!accept) return true;\n const parts = accept.split(',').map((p) => p.trim().toLowerCase()).filter(Boolean);\n if (parts.length === 0) return true;\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return parts.some((p) => {\n if (p.startsWith('.')) return name.endsWith(p);\n if (p.endsWith('/*')) return type.startsWith(p.slice(0, -1));\n return type === p;\n });\n}\n\nexport interface FileUpload {\n files: RichFile[];\n uploading: boolean;\n error: string | null;\n add: (list: FileList | File[] | null) => Promise<void>;\n remove: (id: string) => void;\n reset: () => void;\n setFiles: (files: RichFile[]) => void;\n}\n\nexport function useFileUpload({\n upload,\n accept,\n maxFiles,\n filter,\n}: {\n upload?: (files: File[]) => Promise<RichFile[]>;\n accept?: string;\n maxFiles?: number;\n /** Return `true` to keep, `false`/reason-string to reject a file. */\n filter?: (file: File) => boolean | string;\n}): FileUpload {\n const [files, setFilesState] = useState<RichFile[]>([]);\n const [uploading, setUploading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const add = useCallback(\n async (list: FileList | File[] | null) => {\n const picked = Array.from(list ?? []);\n if (picked.length === 0) return;\n setError(null);\n\n const kept: File[] = [];\n for (const f of picked) {\n if (!acceptsFile(accept, f)) {\n setError(`${f.name}: type not accepted`);\n continue;\n }\n const verdict = filter?.(f);\n if (verdict === false) {\n setError(`${f.name}: rejected`);\n continue;\n }\n if (typeof verdict === 'string') {\n setError(`${f.name}: ${verdict}`);\n continue;\n }\n kept.push(f);\n }\n if (kept.length === 0) return;\n\n const room = maxFiles == null ? kept.length : Math.max(0, maxFiles - files.length);\n if (room <= 0) {\n setError(`At most ${maxFiles} file${maxFiles === 1 ? '' : 's'}`);\n return;\n }\n const admitted = kept.slice(0, room);\n if (admitted.length < kept.length) setError(`At most ${maxFiles} files`);\n\n if (!upload) {\n setFilesState((prev) => [...prev, ...admitted.map(localFile)]);\n return;\n }\n\n setUploading(true);\n try {\n const stored = await upload(admitted);\n setFilesState((prev) => [...prev, ...stored]);\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setUploading(false);\n }\n },\n [accept, maxFiles, filter, upload, files.length],\n );\n\n const remove = useCallback((id: string) => {\n setFilesState((prev) => {\n const gone = prev.find((f) => f.id === id);\n if (gone?.url?.startsWith('blob:')) URL.revokeObjectURL(gone.url);\n return prev.filter((f) => f.id !== id);\n });\n }, []);\n\n const reset = useCallback(() => {\n setFilesState((prev) => {\n for (const f of prev) if (f.url?.startsWith('blob:')) URL.revokeObjectURL(f.url);\n return [];\n });\n setError(null);\n }, []);\n\n return { files, uploading, error, add, remove, reset, setFiles: setFilesState };\n}\n"],"names":["localFile","file","i","url","acceptsFile","accept","parts","p","name","type","useFileUpload","upload","maxFiles","filter","files","setFilesState","useState","uploading","setUploading","error","setError","add","useCallback","list","picked","kept","f","verdict","room","admitted","prev","stored","remove","id","gone","_a","reset"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { GuidelineTag } from './types';
|
|
2
|
+
export interface Guidelines {
|
|
3
|
+
/** Ids of tags currently on. */
|
|
4
|
+
selected: Set<string>;
|
|
5
|
+
toggle: (id: string) => void;
|
|
6
|
+
setOn: (id: string, on: boolean) => void;
|
|
7
|
+
clear: () => void;
|
|
8
|
+
/** Tags that are active (toggle-on, or mention-picked). */
|
|
9
|
+
active: GuidelineTag[];
|
|
10
|
+
/** Injected guideline lines for the current selection. */
|
|
11
|
+
lines: string[];
|
|
12
|
+
/** Toggle tags (the chip row); mention-only tags are excluded. */
|
|
13
|
+
toggles: GuidelineTag[];
|
|
14
|
+
}
|
|
15
|
+
export declare function useGuidelines(tags: GuidelineTag[]): Guidelines;
|
|
16
|
+
//# sourceMappingURL=use-guidelines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-guidelines.d.ts","sourceRoot":"","sources":["../../../src/components/rich-input/use-guidelines.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,WAAW,UAAU;IACzB,gCAAgC;IAChC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,2DAA2D;IAC3D,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kEAAkE;IAClE,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAiBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,UAAU,CA8F9D"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useState as O, useCallback as u, useRef as g, useEffect as y, useMemo as a } from "react";
|
|
2
|
+
import { tagGuideline as z } from "./compose.js";
|
|
3
|
+
function h(o) {
|
|
4
|
+
const l = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set();
|
|
5
|
+
for (const c of o)
|
|
6
|
+
if (!((c.kind ?? "toggle") !== "toggle" || !c.defaultOn)) {
|
|
7
|
+
if (c.exclusive) {
|
|
8
|
+
if (r.has(c.exclusive)) continue;
|
|
9
|
+
r.add(c.exclusive);
|
|
10
|
+
}
|
|
11
|
+
l.add(c.id);
|
|
12
|
+
}
|
|
13
|
+
return l;
|
|
14
|
+
}
|
|
15
|
+
function j(o) {
|
|
16
|
+
const [l, r] = O(() => h(o)), c = u(
|
|
17
|
+
(e) => {
|
|
18
|
+
var t;
|
|
19
|
+
const s = (t = o.find((i) => i.id === e)) == null ? void 0 : t.exclusive;
|
|
20
|
+
return s ? o.filter((i) => i.exclusive === s && i.id !== e).map((i) => i.id) : [];
|
|
21
|
+
},
|
|
22
|
+
[o]
|
|
23
|
+
), m = g(new Set(o.map((e) => e.id))), x = o.map((e) => e.id).join(",");
|
|
24
|
+
y(() => {
|
|
25
|
+
r((e) => {
|
|
26
|
+
const s = new Set(o.map((n) => n.id)), t = new Set([...e].filter((n) => s.has(n))), i = new Set(
|
|
27
|
+
o.filter((n) => n.exclusive && t.has(n.id)).map((n) => n.exclusive)
|
|
28
|
+
);
|
|
29
|
+
for (const n of o)
|
|
30
|
+
if (!((n.kind ?? "toggle") !== "toggle" || !n.defaultOn || m.current.has(n.id))) {
|
|
31
|
+
if (n.exclusive) {
|
|
32
|
+
if (i.has(n.exclusive)) continue;
|
|
33
|
+
i.add(n.exclusive);
|
|
34
|
+
}
|
|
35
|
+
t.add(n.id);
|
|
36
|
+
}
|
|
37
|
+
return m.current = s, t.size === e.size && [...t].every((n) => e.has(n)) ? e : t;
|
|
38
|
+
});
|
|
39
|
+
}, [x]);
|
|
40
|
+
const p = u(
|
|
41
|
+
(e) => {
|
|
42
|
+
r((s) => {
|
|
43
|
+
const t = new Set(s);
|
|
44
|
+
if (t.has(e))
|
|
45
|
+
t.delete(e);
|
|
46
|
+
else {
|
|
47
|
+
for (const i of c(e)) t.delete(i);
|
|
48
|
+
t.add(e);
|
|
49
|
+
}
|
|
50
|
+
return t;
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
[c]
|
|
54
|
+
), S = u(
|
|
55
|
+
(e, s) => {
|
|
56
|
+
r((t) => {
|
|
57
|
+
const i = s ? c(e) : [];
|
|
58
|
+
if (t.has(e) === s && !i.some((d) => t.has(d))) return t;
|
|
59
|
+
const n = new Set(t);
|
|
60
|
+
if (s) {
|
|
61
|
+
for (const d of i) n.delete(d);
|
|
62
|
+
n.add(e);
|
|
63
|
+
} else
|
|
64
|
+
n.delete(e);
|
|
65
|
+
return n;
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
[c]
|
|
69
|
+
), w = u(() => r(h(o)), [o]), f = a(() => o.filter((e) => (e.kind ?? "toggle") === "toggle"), [o]), k = a(() => o.filter((e) => l.has(e.id)), [o, l]), v = a(() => {
|
|
70
|
+
var s;
|
|
71
|
+
const e = [];
|
|
72
|
+
for (const t of f) {
|
|
73
|
+
const i = z(t, l.has(t.id));
|
|
74
|
+
i && e.push(i);
|
|
75
|
+
}
|
|
76
|
+
for (const t of o)
|
|
77
|
+
(t.kind ?? "toggle") === "mention" && l.has(t.id) && ((s = t.prompt) != null && s.trim()) && e.push(t.prompt);
|
|
78
|
+
return e;
|
|
79
|
+
}, [f, o, l]);
|
|
80
|
+
return { selected: l, toggle: p, setOn: S, clear: w, active: k, lines: v, toggles: f };
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
j as useGuidelines
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=use-guidelines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-guidelines.js","sources":["../../../src/components/rich-input/use-guidelines.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { tagGuideline } from './compose';\nimport type { GuidelineTag } from './types';\n\nexport interface Guidelines {\n /** Ids of tags currently on. */\n selected: Set<string>;\n toggle: (id: string) => void;\n setOn: (id: string, on: boolean) => void;\n clear: () => void;\n /** Tags that are active (toggle-on, or mention-picked). */\n active: GuidelineTag[];\n /** Injected guideline lines for the current selection. */\n lines: string[];\n /** Toggle tags (the chip row); mention-only tags are excluded. */\n toggles: GuidelineTag[];\n}\n\nfunction initialSelection(tags: GuidelineTag[]): Set<string> {\n const out = new Set<string>();\n const claimed = new Set<string>();\n for (const t of tags) {\n if ((t.kind ?? 'toggle') !== 'toggle' || !t.defaultOn) continue;\n // At most one default-on tag per exclusive key — the first wins.\n if (t.exclusive) {\n if (claimed.has(t.exclusive)) continue;\n claimed.add(t.exclusive);\n }\n out.add(t.id);\n }\n return out;\n}\n\nexport function useGuidelines(tags: GuidelineTag[]): Guidelines {\n const [selected, setSelected] = useState<Set<string>>(() => initialSelection(tags));\n\n // Ids to drop when `id` is turned on: the rest of its exclusive key.\n const peersOf = useCallback(\n (id: string): string[] => {\n const key = tags.find((t) => t.id === id)?.exclusive;\n if (!key) return [];\n return tags.filter((t) => t.exclusive === key && t.id !== id).map((t) => t.id);\n },\n [tags],\n );\n\n // Keep selection in sync as the tag set changes: drop ids that no longer\n // exist, seed newly-appeared default-on toggles.\n const knownIds = useRef<Set<string>>(new Set(tags.map((t) => t.id)));\n const idKey = tags.map((t) => t.id).join(',');\n useEffect(() => {\n setSelected((prev) => {\n const ids = new Set(tags.map((t) => t.id));\n const next = new Set([...prev].filter((id) => ids.has(id)));\n const taken = new Set(\n tags.filter((t) => t.exclusive && next.has(t.id)).map((t) => t.exclusive as string),\n );\n for (const t of tags) {\n if ((t.kind ?? 'toggle') !== 'toggle' || !t.defaultOn || knownIds.current.has(t.id)) continue;\n // A default-on newcomer can't claim an exclusive key that's already taken.\n if (t.exclusive) {\n if (taken.has(t.exclusive)) continue;\n taken.add(t.exclusive);\n }\n next.add(t.id);\n }\n knownIds.current = ids;\n return next.size === prev.size && [...next].every((id) => prev.has(id)) ? prev : next;\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [idKey]);\n\n const toggle = useCallback(\n (id: string) => {\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n for (const peer of peersOf(id)) next.delete(peer);\n next.add(id);\n }\n return next;\n });\n },\n [peersOf],\n );\n\n const setOn = useCallback(\n (id: string, on: boolean) => {\n setSelected((prev) => {\n const peers = on ? peersOf(id) : [];\n if (prev.has(id) === on && !peers.some((p) => prev.has(p))) return prev;\n const next = new Set(prev);\n if (on) {\n for (const peer of peers) next.delete(peer);\n next.add(id);\n } else {\n next.delete(id);\n }\n return next;\n });\n },\n [peersOf],\n );\n\n const clear = useCallback(() => setSelected(initialSelection(tags)), [tags]);\n\n const toggles = useMemo(() => tags.filter((t) => (t.kind ?? 'toggle') === 'toggle'), [tags]);\n\n const active = useMemo(() => tags.filter((t) => selected.has(t.id)), [tags, selected]);\n\n const lines = useMemo(() => {\n const out: string[] = [];\n for (const t of toggles) {\n const line = tagGuideline(t, selected.has(t.id));\n if (line) out.push(line);\n }\n for (const t of tags) {\n if ((t.kind ?? 'toggle') === 'mention' && selected.has(t.id) && t.prompt?.trim()) {\n out.push(t.prompt);\n }\n }\n return out;\n }, [toggles, tags, selected]);\n\n return { selected, toggle, setOn, clear, active, lines, toggles };\n}\n"],"names":["initialSelection","tags","out","claimed","t","useGuidelines","selected","setSelected","useState","peersOf","useCallback","id","key","_a","knownIds","useRef","idKey","useEffect","prev","ids","next","taken","toggle","peer","setOn","on","peers","p","clear","toggles","useMemo","active","lines","line","tagGuideline"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface InputHistory {
|
|
2
|
+
/** Newest-last list of past submissions. */
|
|
3
|
+
entries: string[];
|
|
4
|
+
/** Record a value (skips blanks and consecutive duplicates). */
|
|
5
|
+
push: (value: string) => void;
|
|
6
|
+
/** Move to an older entry. `draft` is stashed the first time. */
|
|
7
|
+
prev: (draft: string) => string | null;
|
|
8
|
+
/** Move to a newer entry, or back to the stashed draft at the end. */
|
|
9
|
+
next: () => string | null;
|
|
10
|
+
/** Whether the cursor is currently browsing history (not on the draft). */
|
|
11
|
+
browsing: boolean;
|
|
12
|
+
/** Drop the cursor back to the draft (call when the user edits manually). */
|
|
13
|
+
resetCursor: () => void;
|
|
14
|
+
/** Newest-first match for a reverse (Ctrl+R) search; `bump` cycles matches. */
|
|
15
|
+
reverseSearch: (query: string, bump?: boolean) => string | null;
|
|
16
|
+
/** Reset the reverse-search cursor. */
|
|
17
|
+
resetSearch: () => void;
|
|
18
|
+
clear: () => void;
|
|
19
|
+
}
|
|
20
|
+
/** A shell-style command history for the composer. */
|
|
21
|
+
export declare function useInputHistory(cacheKey: string | null | undefined, max?: number): InputHistory;
|
|
22
|
+
//# sourceMappingURL=use-input-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-input-history.d.ts","sourceRoot":"","sources":["../../../src/components/rich-input/use-input-history.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gEAAgE;IAChE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,iEAAiE;IACjE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACvC,sEAAsE;IACtE,IAAI,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC1B,2EAA2E;IAC3E,QAAQ,EAAE,OAAO,CAAC;IAClB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,+EAA+E;IAC/E,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;IAChE,uCAAuC;IACvC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,SAAc,GAAG,YAAY,CA4FpG"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useState as x, useRef as g, useCallback as l, useMemo as F } from "react";
|
|
2
|
+
const J = "rich-input:history:", M = 100;
|
|
3
|
+
function L(u) {
|
|
4
|
+
if (!u || typeof window > "u") return [];
|
|
5
|
+
try {
|
|
6
|
+
const s = window.localStorage.getItem(u), e = s ? JSON.parse(s) : [];
|
|
7
|
+
return Array.isArray(e) ? e.filter((t) => typeof t == "string") : [];
|
|
8
|
+
} catch {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function b(u, s) {
|
|
13
|
+
if (!(!u || typeof window > "u"))
|
|
14
|
+
try {
|
|
15
|
+
window.localStorage.setItem(u, JSON.stringify(s));
|
|
16
|
+
} catch {
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function O(u, s = M) {
|
|
20
|
+
const e = u ? J + u : null, [t, a] = x(() => L(e)), w = g(e);
|
|
21
|
+
w.current !== e && (w.current = e, a(L(e)));
|
|
22
|
+
const r = g(t.length), d = g(""), o = g(-1), p = l(
|
|
23
|
+
(h) => {
|
|
24
|
+
const i = h.trim();
|
|
25
|
+
r.current = t.length, i && a((c) => {
|
|
26
|
+
if (c[c.length - 1] === i)
|
|
27
|
+
return r.current = c.length, c;
|
|
28
|
+
const n = [...c.filter((f) => f !== i), i].slice(-s);
|
|
29
|
+
return r.current = n.length, b(e, n), n;
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
[t.length, s, e]
|
|
33
|
+
), y = l(
|
|
34
|
+
(h) => t.length === 0 ? null : (r.current >= t.length ? (d.current = h, r.current = t.length - 1) : r.current > 0 && (r.current -= 1), t[r.current] ?? null),
|
|
35
|
+
[t]
|
|
36
|
+
), m = l(() => r.current >= t.length ? null : (r.current += 1, r.current >= t.length ? d.current : t[r.current] ?? null), [t]), S = l(() => {
|
|
37
|
+
r.current = t.length;
|
|
38
|
+
}, [t.length]), A = l(
|
|
39
|
+
(h, i = !1) => {
|
|
40
|
+
const c = h.trim().toLowerCase();
|
|
41
|
+
if (!c) return null;
|
|
42
|
+
const n = [];
|
|
43
|
+
for (let f = t.length - 1; f >= 0; f--)
|
|
44
|
+
t[f].toLowerCase().includes(c) && n.push(t[f]);
|
|
45
|
+
return n.length === 0 ? null : (i ? o.current = (o.current + 1) % n.length : (o.current < 0 || o.current >= n.length) && (o.current = 0), n[o.current]);
|
|
46
|
+
},
|
|
47
|
+
[t]
|
|
48
|
+
), C = l(() => {
|
|
49
|
+
o.current = -1;
|
|
50
|
+
}, []), I = l(() => {
|
|
51
|
+
a([]), r.current = 0, b(e, []);
|
|
52
|
+
}, [e]), E = r.current < t.length;
|
|
53
|
+
return F(
|
|
54
|
+
() => ({ entries: t, push: p, prev: y, next: m, browsing: E, resetCursor: S, reverseSearch: A, resetSearch: C, clear: I }),
|
|
55
|
+
[t, p, y, m, E, S, A, C, I]
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
O as useInputHistory
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=use-input-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-input-history.js","sources":["../../../src/components/rich-input/use-input-history.ts"],"sourcesContent":["import { useCallback, useMemo, useRef, useState } from 'react';\n\nconst PREFIX = 'rich-input:history:';\nconst DEFAULT_MAX = 100;\n\nfunction load(key: string | null): string[] {\n if (!key || typeof window === 'undefined') return [];\n try {\n const raw = window.localStorage.getItem(key);\n const parsed = raw ? (JSON.parse(raw) as unknown) : [];\n return Array.isArray(parsed) ? parsed.filter((x): x is string => typeof x === 'string') : [];\n } catch {\n return [];\n }\n}\n\nfunction save(key: string | null, entries: string[]) {\n if (!key || typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(key, JSON.stringify(entries));\n } catch {\n /* best-effort */\n }\n}\n\nexport interface InputHistory {\n /** Newest-last list of past submissions. */\n entries: string[];\n /** Record a value (skips blanks and consecutive duplicates). */\n push: (value: string) => void;\n /** Move to an older entry. `draft` is stashed the first time. */\n prev: (draft: string) => string | null;\n /** Move to a newer entry, or back to the stashed draft at the end. */\n next: () => string | null;\n /** Whether the cursor is currently browsing history (not on the draft). */\n browsing: boolean;\n /** Drop the cursor back to the draft (call when the user edits manually). */\n resetCursor: () => void;\n /** Newest-first match for a reverse (Ctrl+R) search; `bump` cycles matches. */\n reverseSearch: (query: string, bump?: boolean) => string | null;\n /** Reset the reverse-search cursor. */\n resetSearch: () => void;\n clear: () => void;\n}\n\n/** A shell-style command history for the composer. */\nexport function useInputHistory(cacheKey: string | null | undefined, max = DEFAULT_MAX): InputHistory {\n const storageKey = cacheKey ? PREFIX + cacheKey : null;\n const [entries, setEntries] = useState<string[]>(() => load(storageKey));\n\n // Reload if the key changed.\n const prevKey = useRef(storageKey);\n if (prevKey.current !== storageKey) {\n prevKey.current = storageKey;\n setEntries(load(storageKey));\n }\n\n const cursor = useRef<number>(entries.length); // === length → on the draft\n const stash = useRef<string>('');\n const search = useRef<number>(-1); // match index for reverse search\n\n const push = useCallback(\n (value: string) => {\n const v = value.trim();\n cursor.current = entries.length; // logical reset; recomputed below on set\n if (!v) return;\n setEntries((prev) => {\n if (prev[prev.length - 1] === v) {\n cursor.current = prev.length;\n return prev;\n }\n const next = [...prev.filter((e) => e !== v), v].slice(-max);\n cursor.current = next.length;\n save(storageKey, next);\n return next;\n });\n },\n [entries.length, max, storageKey],\n );\n\n const prev = useCallback(\n (draft: string): string | null => {\n if (entries.length === 0) return null;\n if (cursor.current >= entries.length) {\n stash.current = draft; // leaving the draft\n cursor.current = entries.length - 1;\n } else if (cursor.current > 0) {\n cursor.current -= 1;\n }\n return entries[cursor.current] ?? null;\n },\n [entries],\n );\n\n const next = useCallback((): string | null => {\n if (cursor.current >= entries.length) return null; // already on the draft\n cursor.current += 1;\n if (cursor.current >= entries.length) return stash.current;\n return entries[cursor.current] ?? null;\n }, [entries]);\n\n const resetCursor = useCallback(() => {\n cursor.current = entries.length;\n }, [entries.length]);\n\n const reverseSearch = useCallback(\n (query: string, bump = false): string | null => {\n const q = query.trim().toLowerCase();\n if (!q) return null;\n // Newest-first list of matches.\n const matches: string[] = [];\n for (let i = entries.length - 1; i >= 0; i--) {\n if (entries[i].toLowerCase().includes(q)) matches.push(entries[i]);\n }\n if (matches.length === 0) return null;\n if (bump) search.current = (search.current + 1) % matches.length;\n else if (search.current < 0 || search.current >= matches.length) search.current = 0;\n return matches[search.current];\n },\n [entries],\n );\n\n const resetSearch = useCallback(() => {\n search.current = -1;\n }, []);\n\n const clear = useCallback(() => {\n setEntries([]);\n cursor.current = 0;\n save(storageKey, []);\n }, [storageKey]);\n\n const browsing = cursor.current < entries.length;\n\n return useMemo(\n () => ({ entries, push, prev, next, browsing, resetCursor, reverseSearch, resetSearch, clear }),\n [entries, push, prev, next, browsing, resetCursor, reverseSearch, resetSearch, clear],\n );\n}\n"],"names":["PREFIX","DEFAULT_MAX","load","key","raw","parsed","x","save","entries","useInputHistory","cacheKey","max","storageKey","setEntries","useState","prevKey","useRef","cursor","stash","search","push","useCallback","value","v","prev","next","e","draft","resetCursor","reverseSearch","query","bump","q","matches","i","resetSearch","clear","browsing","useMemo"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { KeyboardEvent, RefObject } from 'react';
|
|
2
|
+
import { GuidelineTag } from './types';
|
|
3
|
+
export declare function tagSlug(tag: GuidelineTag): string;
|
|
4
|
+
export interface MentionApi {
|
|
5
|
+
open: boolean;
|
|
6
|
+
matches: GuidelineTag[];
|
|
7
|
+
active: number;
|
|
8
|
+
query: string | null;
|
|
9
|
+
setActive: (i: number) => void;
|
|
10
|
+
pick: (tag: GuidelineTag) => void;
|
|
11
|
+
/** Handle a key while the menu is open; returns true if it consumed the key. */
|
|
12
|
+
onKeyDown: (e: KeyboardEvent<HTMLTextAreaElement>) => boolean;
|
|
13
|
+
/** Keep the caret position in sync (call from onSelect / onChange). */
|
|
14
|
+
syncCaret: () => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function useMention({ tags, value, setValue, taRef, prefix, onPick, }: {
|
|
17
|
+
tags: GuidelineTag[];
|
|
18
|
+
value: string;
|
|
19
|
+
setValue: (v: string) => void;
|
|
20
|
+
taRef: RefObject<HTMLTextAreaElement | null>;
|
|
21
|
+
prefix: string;
|
|
22
|
+
onPick: (tag: GuidelineTag) => void;
|
|
23
|
+
}): MentionApi;
|
|
24
|
+
//# sourceMappingURL=use-mention.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-mention.d.ts","sourceRoot":"","sources":["../../../src/components/rich-input/use-mention.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEnG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAK5C,wBAAgB,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAEjD;AAWD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,IAAI,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IAClC,gFAAgF;IAChF,SAAS,EAAE,CAAC,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,KAAK,OAAO,CAAC;IAC9D,uEAAuE;IACvE,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,KAAK,EACL,MAAM,EACN,MAAM,GACP,EAAE;IACD,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,KAAK,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;CACrC,GAAG,UAAU,CAuEb"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useState as M, useRef as E, useMemo as $, useCallback as k } from "react";
|
|
2
|
+
const b = 8, v = /[\w.-]/;
|
|
3
|
+
function d(n) {
|
|
4
|
+
return n.slug ?? n.id;
|
|
5
|
+
}
|
|
6
|
+
function L(n, s, l) {
|
|
7
|
+
let e = s - 1;
|
|
8
|
+
for (; e >= 0 && v.test(n[e]); ) e--;
|
|
9
|
+
return e < 0 || n[e] !== l || e > 0 && !/\s/.test(n[e - 1]) ? null : { start: e, query: n.slice(e + 1, s) };
|
|
10
|
+
}
|
|
11
|
+
function H({
|
|
12
|
+
tags: n,
|
|
13
|
+
value: s,
|
|
14
|
+
setValue: l,
|
|
15
|
+
taRef: e,
|
|
16
|
+
prefix: i,
|
|
17
|
+
onPick: m
|
|
18
|
+
}) {
|
|
19
|
+
const [f, p] = M(0), [w, y] = M(0), g = E(null), u = L(s, f, i), r = (u == null ? void 0 : u.query) ?? null, o = $(() => {
|
|
20
|
+
if (r === null) return [];
|
|
21
|
+
const t = r.toLowerCase();
|
|
22
|
+
return n.filter((c) => d(c).toLowerCase().startsWith(t) || c.label.toLowerCase().includes(t)).slice(0, b);
|
|
23
|
+
}, [n, r]), h = r !== null && g.current !== r && o.length > 0, q = k(() => {
|
|
24
|
+
const t = e.current;
|
|
25
|
+
t && p(t.selectionStart ?? 0);
|
|
26
|
+
}, [e]), A = k(
|
|
27
|
+
(t) => {
|
|
28
|
+
if (!u) return;
|
|
29
|
+
const c = d(t), a = `${s.slice(0, u.start)}${i}${c} ${s.slice(f)}`, C = u.start + c.length + i.length + 1;
|
|
30
|
+
l(a), m(t), y(0), g.current = null, requestAnimationFrame(() => {
|
|
31
|
+
const D = e.current;
|
|
32
|
+
D && (D.setSelectionRange(C, C), p(C));
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
[u, s, f, i, l, m, e]
|
|
36
|
+
), S = k(
|
|
37
|
+
(t) => {
|
|
38
|
+
if (!h) return !1;
|
|
39
|
+
if (t.key === "ArrowDown" || t.key === "ArrowUp") {
|
|
40
|
+
t.preventDefault();
|
|
41
|
+
const c = t.key === "ArrowDown" ? 1 : -1;
|
|
42
|
+
return y((a) => (a + c + o.length) % o.length), !0;
|
|
43
|
+
}
|
|
44
|
+
return t.key === "Enter" || t.key === "Tab" ? (t.preventDefault(), A(o[Math.min(w, o.length - 1)]), !0) : t.key === "Escape" ? (t.preventDefault(), g.current = r, !0) : !1;
|
|
45
|
+
},
|
|
46
|
+
[h, o, w, A, r]
|
|
47
|
+
);
|
|
48
|
+
return { open: h, matches: o, active: w, query: r, setActive: y, pick: A, onKeyDown: S, syncCaret: q };
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
d as tagSlug,
|
|
52
|
+
H as useMention
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=use-mention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-mention.js","sources":["../../../src/components/rich-input/use-mention.ts"],"sourcesContent":["import { useCallback, useMemo, useRef, useState, type KeyboardEvent, type RefObject } from 'react';\n\nimport type { GuidelineTag } from './types';\n\nconst MAX_MATCHES = 8;\nconst TOKEN_CHAR = /[\\w.-]/;\n\nexport function tagSlug(tag: GuidelineTag): string {\n return tag.slug ?? tag.id;\n}\n\n/** Detect a `<prefix><token>` under the caret, at a word boundary. */\nfunction activeMention(text: string, caret: number, prefix: string): { start: number; query: string } | null {\n let i = caret - 1;\n while (i >= 0 && TOKEN_CHAR.test(text[i])) i--;\n if (i < 0 || text[i] !== prefix) return null;\n if (i > 0 && !/\\s/.test(text[i - 1])) return null; // must follow whitespace / line start\n return { start: i, query: text.slice(i + 1, caret) };\n}\n\nexport interface MentionApi {\n open: boolean;\n matches: GuidelineTag[];\n active: number;\n query: string | null;\n setActive: (i: number) => void;\n pick: (tag: GuidelineTag) => void;\n /** Handle a key while the menu is open; returns true if it consumed the key. */\n onKeyDown: (e: KeyboardEvent<HTMLTextAreaElement>) => boolean;\n /** Keep the caret position in sync (call from onSelect / onChange). */\n syncCaret: () => void;\n}\n\nexport function useMention({\n tags,\n value,\n setValue,\n taRef,\n prefix,\n onPick,\n}: {\n tags: GuidelineTag[];\n value: string;\n setValue: (v: string) => void;\n taRef: RefObject<HTMLTextAreaElement | null>;\n prefix: string;\n onPick: (tag: GuidelineTag) => void;\n}): MentionApi {\n const [caret, setCaret] = useState(0);\n const [active, setActive] = useState(0);\n const dismissed = useRef<string | null>(null);\n\n const mention = activeMention(value, caret, prefix);\n const query = mention?.query ?? null;\n\n const matches = useMemo(() => {\n if (query === null) return [];\n const q = query.toLowerCase();\n return tags\n .filter((t) => {\n const slug = tagSlug(t).toLowerCase();\n return slug.startsWith(q) || t.label.toLowerCase().includes(q);\n })\n .slice(0, MAX_MATCHES);\n }, [tags, query]);\n\n const open = query !== null && dismissed.current !== query && matches.length > 0;\n\n const syncCaret = useCallback(() => {\n const el = taRef.current;\n if (el) setCaret(el.selectionStart ?? 0);\n }, [taRef]);\n\n const pick = useCallback(\n (tag: GuidelineTag) => {\n if (!mention) return;\n const slug = tagSlug(tag);\n const next = `${value.slice(0, mention.start)}${prefix}${slug} ${value.slice(caret)}`;\n const pos = mention.start + slug.length + prefix.length + 1;\n setValue(next);\n onPick(tag);\n setActive(0);\n dismissed.current = null;\n requestAnimationFrame(() => {\n const el = taRef.current;\n if (!el) return;\n el.setSelectionRange(pos, pos);\n setCaret(pos);\n });\n },\n [mention, value, caret, prefix, setValue, onPick, taRef],\n );\n\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>): boolean => {\n if (!open) return false;\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n e.preventDefault();\n const d = e.key === 'ArrowDown' ? 1 : -1;\n setActive((i) => (i + d + matches.length) % matches.length);\n return true;\n }\n if (e.key === 'Enter' || e.key === 'Tab') {\n e.preventDefault();\n pick(matches[Math.min(active, matches.length - 1)]);\n return true;\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n dismissed.current = query;\n return true;\n }\n return false;\n },\n [open, matches, active, pick, query],\n );\n\n return { open, matches, active, query, setActive, pick, onKeyDown, syncCaret };\n}\n"],"names":["MAX_MATCHES","TOKEN_CHAR","tagSlug","tag","activeMention","text","caret","prefix","i","useMention","tags","value","setValue","taRef","onPick","setCaret","useState","active","setActive","dismissed","useRef","mention","query","matches","useMemo","q","t","open","syncCaret","useCallback","el","pick","slug","next","pos","onKeyDown","e","d"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/search-input/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface SearchInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'type'> {
|
|
3
|
+
value: string;
|
|
4
|
+
onValueChange: (value: string) => void;
|
|
5
|
+
/** Focus on `⌘K` / `Ctrl-K` (and `/`), and show the hint key. */
|
|
6
|
+
shortcut?: boolean;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A search field with the leading icon, a clear button, and Escape-to-clear —
|
|
11
|
+
* the input every list in the lab puts above itself. Pairs with `FuzzyList`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function SearchInput({ value, onValueChange, shortcut, className, placeholder, ...props }: SearchInputProps): React.JSX.Element;
|
|
14
|
+
//# sourceMappingURL=search-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-input.d.ts","sourceRoot":"","sources":["../../../src/components/search-input/search-input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;IACxF,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,iEAAiE;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,aAAa,EACb,QAAgB,EAChB,SAAS,EACT,WAAuB,EACvB,GAAG,KAAK,EACT,EAAE,gBAAgB,qBA6DlB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsxs as g, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import * as l from "react";
|
|
3
|
+
import { Search as y, X as h } from "lucide-react";
|
|
4
|
+
import { cn as u } from "../../lib/utils.js";
|
|
5
|
+
function N({
|
|
6
|
+
value: n,
|
|
7
|
+
onValueChange: i,
|
|
8
|
+
shortcut: o = !1,
|
|
9
|
+
className: f,
|
|
10
|
+
placeholder: m = "Search…",
|
|
11
|
+
...p
|
|
12
|
+
}) {
|
|
13
|
+
const s = l.useRef(null);
|
|
14
|
+
return l.useEffect(() => {
|
|
15
|
+
if (!o) return;
|
|
16
|
+
const e = (r) => {
|
|
17
|
+
var a, d, c;
|
|
18
|
+
const b = /^(INPUT|TEXTAREA)$/.test(((a = r.target) == null ? void 0 : a.tagName) ?? "");
|
|
19
|
+
(r.key === "k" && (r.metaKey || r.ctrlKey) || r.key === "/" && !b) && (r.preventDefault(), (d = s.current) == null || d.focus(), (c = s.current) == null || c.select());
|
|
20
|
+
};
|
|
21
|
+
return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
|
|
22
|
+
}, [o]), /* @__PURE__ */ g("div", { className: u("relative flex items-center", f), children: [
|
|
23
|
+
/* @__PURE__ */ t(y, { className: "pointer-events-none absolute left-3 size-4 text-muted-foreground" }),
|
|
24
|
+
/* @__PURE__ */ t(
|
|
25
|
+
"input",
|
|
26
|
+
{
|
|
27
|
+
ref: s,
|
|
28
|
+
type: "search",
|
|
29
|
+
value: n,
|
|
30
|
+
placeholder: m,
|
|
31
|
+
onChange: (e) => i(e.target.value),
|
|
32
|
+
onKeyDown: (e) => {
|
|
33
|
+
e.key === "Escape" && n && (e.preventDefault(), i(""));
|
|
34
|
+
},
|
|
35
|
+
className: u(
|
|
36
|
+
"h-9 w-full rounded-lg border border-border bg-transparent pl-9 text-sm outline-none transition-colors",
|
|
37
|
+
"placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40",
|
|
38
|
+
"[&::-webkit-search-cancel-button]:hidden",
|
|
39
|
+
// we ship our own clear button
|
|
40
|
+
n ? "pr-9" : o ? "pr-12" : "pr-3"
|
|
41
|
+
),
|
|
42
|
+
...p
|
|
43
|
+
}
|
|
44
|
+
),
|
|
45
|
+
n ? /* @__PURE__ */ t(
|
|
46
|
+
"button",
|
|
47
|
+
{
|
|
48
|
+
type: "button",
|
|
49
|
+
onClick: () => {
|
|
50
|
+
var e;
|
|
51
|
+
i(""), (e = s.current) == null || e.focus();
|
|
52
|
+
},
|
|
53
|
+
"aria-label": "Clear search",
|
|
54
|
+
className: "absolute right-2 rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
55
|
+
children: /* @__PURE__ */ t(h, { className: "size-3.5" })
|
|
56
|
+
}
|
|
57
|
+
) : o && /* @__PURE__ */ t("kbd", { className: "pointer-events-none absolute right-2.5 rounded border border-border px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground", children: "⌘K" })
|
|
58
|
+
] });
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
N as SearchInput
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=search-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-input.js","sources":["../../../src/components/search-input/search-input.tsx"],"sourcesContent":["import * as React from 'react';\nimport { Search, X } from 'lucide-react';\n\nimport { cn } from '../../lib/utils';\n\nexport interface SearchInputProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'type'> {\n value: string;\n onValueChange: (value: string) => void;\n /** Focus on `⌘K` / `Ctrl-K` (and `/`), and show the hint key. */\n shortcut?: boolean;\n className?: string;\n}\n\n/**\n * A search field with the leading icon, a clear button, and Escape-to-clear —\n * the input every list in the lab puts above itself. Pairs with `FuzzyList`.\n */\nexport function SearchInput({\n value,\n onValueChange,\n shortcut = false,\n className,\n placeholder = 'Search…',\n ...props\n}: SearchInputProps) {\n const ref = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n if (!shortcut) return;\n const onKey = (e: KeyboardEvent) => {\n const typing = /^(INPUT|TEXTAREA)$/.test((e.target as HTMLElement)?.tagName ?? '');\n const hotkey = (e.key === 'k' && (e.metaKey || e.ctrlKey)) || (e.key === '/' && !typing);\n if (!hotkey) return;\n e.preventDefault();\n ref.current?.focus();\n ref.current?.select();\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [shortcut]);\n\n return (\n <div className={cn('relative flex items-center', className)}>\n <Search className=\"pointer-events-none absolute left-3 size-4 text-muted-foreground\" />\n <input\n ref={ref}\n type=\"search\"\n value={value}\n placeholder={placeholder}\n onChange={(e) => onValueChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Escape' && value) {\n e.preventDefault(); // don't let it bubble up and close the dialog too\n onValueChange('');\n }\n }}\n className={cn(\n 'h-9 w-full rounded-lg border border-border bg-transparent pl-9 text-sm outline-none transition-colors',\n 'placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40',\n '[&::-webkit-search-cancel-button]:hidden', // we ship our own clear button\n value ? 'pr-9' : shortcut ? 'pr-12' : 'pr-3',\n )}\n {...props}\n />\n {value ? (\n <button\n type=\"button\"\n onClick={() => {\n onValueChange('');\n ref.current?.focus();\n }}\n aria-label=\"Clear search\"\n className=\"absolute right-2 rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <X className=\"size-3.5\" />\n </button>\n ) : (\n shortcut && (\n <kbd className=\"pointer-events-none absolute right-2.5 rounded border border-border px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground\">\n ⌘K\n </kbd>\n )\n )}\n </div>\n );\n}\n"],"names":["SearchInput","value","onValueChange","shortcut","className","placeholder","props","ref","React","onKey","e","typing","_a","_b","_c","cn","jsx","Search","X"],"mappings":";;;;AAkBO,SAASA,EAAY;AAAA,EAC1B,OAAAC;AAAA,EACA,eAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,WAAAC;AAAA,EACA,aAAAC,IAAc;AAAA,EACd,GAAGC;AACL,GAAqB;AACnB,QAAMC,IAAMC,EAAM,OAAyB,IAAI;AAE/C,SAAAA,EAAM,UAAU,MAAM;AACpB,QAAI,CAACL,EAAU;AACf,UAAMM,IAAQ,CAACC,MAAqB;;AAClC,YAAMC,IAAS,qBAAqB,OAAMC,IAAAF,EAAE,WAAF,gBAAAE,EAA0B,YAAW,EAAE;AAEjF,OADgBF,EAAE,QAAQ,QAAQA,EAAE,WAAWA,EAAE,YAAcA,EAAE,QAAQ,OAAO,CAACC,OAEjFD,EAAE,eAAA,IACFG,IAAAN,EAAI,YAAJ,QAAAM,EAAa,UACbC,IAAAP,EAAI,YAAJ,QAAAO,EAAa;AAAA,IACf;AACA,kBAAO,iBAAiB,WAAWL,CAAK,GACjC,MAAM,OAAO,oBAAoB,WAAWA,CAAK;AAAA,EAC1D,GAAG,CAACN,CAAQ,CAAC,qBAGV,OAAA,EAAI,WAAWY,EAAG,8BAA8BX,CAAS,GACxD,UAAA;AAAA,IAAA,gBAAAY,EAACC,GAAA,EAAO,WAAU,mEAAA,CAAmE;AAAA,IACrF,gBAAAD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAAT;AAAA,QACA,MAAK;AAAA,QACL,OAAAN;AAAA,QACA,aAAAI;AAAA,QACA,UAAU,CAAC,MAAMH,EAAc,EAAE,OAAO,KAAK;AAAA,QAC7C,WAAW,CAAC,MAAM;AAChB,UAAI,EAAE,QAAQ,YAAYD,MACxB,EAAE,eAAA,GACFC,EAAc,EAAE;AAAA,QAEpB;AAAA,QACA,WAAWa;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA;AAAA,UACAd,IAAQ,SAASE,IAAW,UAAU;AAAA,QAAA;AAAA,QAEvC,GAAGG;AAAA,MAAA;AAAA,IAAA;AAAA,IAELL,IACC,gBAAAe;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM;;AACb,UAAAd,EAAc,EAAE,IAChBU,IAAAL,EAAI,YAAJ,QAAAK,EAAa;AAAA,QACf;AAAA,QACA,cAAW;AAAA,QACX,WAAU;AAAA,QAEV,UAAA,gBAAAI,EAACE,GAAA,EAAE,WAAU,WAAA,CAAW;AAAA,MAAA;AAAA,IAAA,IAG1Bf,KACE,gBAAAa,EAAC,OAAA,EAAI,WAAU,mIAAkI,UAAA,KAAA,CAEjJ;AAAA,EAAA,GAGN;AAEJ;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/skeleton/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAClE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/** A pulsing placeholder block. Give it a size with `className`. */
|
|
3
|
+
export declare function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): React.JSX.Element;
|
|
4
|
+
export interface SkeletonTextProps {
|
|
5
|
+
/** Number of lines. The last one is short, like real ragged text. */
|
|
6
|
+
lines?: number;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
/** A paragraph of skeleton lines — the shape text actually loads into. */
|
|
10
|
+
export declare function SkeletonText({ lines, className }: SkeletonTextProps): React.JSX.Element;
|
|
11
|
+
export interface SkeletonGridProps {
|
|
12
|
+
count?: number;
|
|
13
|
+
/** Tailwind aspect class for each tile. */
|
|
14
|
+
aspect?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
/** A grid of tiles — the gallery/card placeholder. */
|
|
18
|
+
export declare function SkeletonGrid({ count, aspect, className, }: SkeletonGridProps): React.JSX.Element;
|
|
19
|
+
//# sourceMappingURL=skeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/skeleton/skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,qBAQrF;AAED,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,EAAE,KAAS,EAAE,SAAS,EAAE,EAAE,iBAAiB,qBAQvE;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,EAC3B,KAAS,EACT,MAAwB,EACxB,SAAS,GACV,EAAE,iBAAiB,qBAQnB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as a } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { cn as n } from "../../lib/utils.js";
|
|
4
|
+
function o({ className: e, ...r }) {
|
|
5
|
+
return /* @__PURE__ */ a(
|
|
6
|
+
"div",
|
|
7
|
+
{
|
|
8
|
+
"aria-hidden": !0,
|
|
9
|
+
className: n("animate-pulse rounded-md bg-muted", e),
|
|
10
|
+
...r
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
function c({ lines: e = 3, className: r }) {
|
|
15
|
+
return /* @__PURE__ */ a("div", { className: n("space-y-2", r), children: Array.from({ length: e }, (l, t) => /* @__PURE__ */ a(o, { className: n("h-3.5", t === e - 1 ? "w-2/5" : "w-full") }, t)) });
|
|
16
|
+
}
|
|
17
|
+
function u({
|
|
18
|
+
count: e = 6,
|
|
19
|
+
aspect: r = "aspect-square",
|
|
20
|
+
className: l
|
|
21
|
+
}) {
|
|
22
|
+
return /* @__PURE__ */ a("div", { className: n("grid grid-cols-2 gap-3 sm:grid-cols-3", l), children: Array.from({ length: e }, (t, d) => /* @__PURE__ */ a(o, { className: n("w-full rounded-xl", r) }, d)) });
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
o as Skeleton,
|
|
26
|
+
u as SkeletonGrid,
|
|
27
|
+
c as SkeletonText
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=skeleton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton.js","sources":["../../../src/components/skeleton/skeleton.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../../lib/utils';\n\n/** A pulsing placeholder block. Give it a size with `className`. */\nexport function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n aria-hidden\n className={cn('animate-pulse rounded-md bg-muted', className)}\n {...props}\n />\n );\n}\n\nexport interface SkeletonTextProps {\n /** Number of lines. The last one is short, like real ragged text. */\n lines?: number;\n className?: string;\n}\n\n/** A paragraph of skeleton lines — the shape text actually loads into. */\nexport function SkeletonText({ lines = 3, className }: SkeletonTextProps) {\n return (\n <div className={cn('space-y-2', className)}>\n {Array.from({ length: lines }, (_, i) => (\n <Skeleton key={i} className={cn('h-3.5', i === lines - 1 ? 'w-2/5' : 'w-full')} />\n ))}\n </div>\n );\n}\n\nexport interface SkeletonGridProps {\n count?: number;\n /** Tailwind aspect class for each tile. */\n aspect?: string;\n className?: string;\n}\n\n/** A grid of tiles — the gallery/card placeholder. */\nexport function SkeletonGrid({\n count = 6,\n aspect = 'aspect-square',\n className,\n}: SkeletonGridProps) {\n return (\n <div className={cn('grid grid-cols-2 gap-3 sm:grid-cols-3', className)}>\n {Array.from({ length: count }, (_, i) => (\n <Skeleton key={i} className={cn('w-full rounded-xl', aspect)} />\n ))}\n </div>\n );\n}\n"],"names":["Skeleton","className","props","jsx","cn","SkeletonText","lines","_","i","SkeletonGrid","count","aspect"],"mappings":";;;AAKO,SAASA,EAAS,EAAE,WAAAC,GAAW,GAAGC,KAA+C;AACtF,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,eAAW;AAAA,MACX,WAAWC,EAAG,qCAAqCH,CAAS;AAAA,MAC3D,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AASO,SAASG,EAAa,EAAE,OAAAC,IAAQ,GAAG,WAAAL,KAAgC;AACxE,SACE,gBAAAE,EAAC,OAAA,EAAI,WAAWC,EAAG,aAAaH,CAAS,GACtC,UAAA,MAAM,KAAK,EAAE,QAAQK,EAAA,GAAS,CAACC,GAAGC,MACjC,gBAAAL,EAACH,GAAA,EAAiB,WAAWI,EAAG,SAASI,MAAMF,IAAQ,IAAI,UAAU,QAAQ,EAAA,GAA9DE,CAAiE,CACjF,EAAA,CACH;AAEJ;AAUO,SAASC,EAAa;AAAA,EAC3B,OAAAC,IAAQ;AAAA,EACR,QAAAC,IAAS;AAAA,EACT,WAAAV;AACF,GAAsB;AACpB,SACE,gBAAAE,EAAC,OAAA,EAAI,WAAWC,EAAG,yCAAyCH,CAAS,GAClE,UAAA,MAAM,KAAK,EAAE,QAAQS,KAAS,CAACH,GAAGC,MACjC,gBAAAL,EAACH,GAAA,EAAiB,WAAWI,EAAG,qBAAqBO,CAAM,EAAA,GAA5CH,CAA+C,CAC/D,EAAA,CACH;AAEJ;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/spinner/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
|