@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 @@
|
|
|
1
|
+
{"version":3,"file":"highlight.d.ts","sourceRoot":"","sources":["../../src/lib/highlight.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAuBvC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,SAAS,CAa1F;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EACpC,MAAM,SAAM,GACX,SAAS,CAsBX"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as d } from "react/jsx-runtime";
|
|
2
|
+
function g(n, i = 1) {
|
|
3
|
+
const c = n.filter(([r, t]) => t - r >= i).sort((r, t) => r[0] - t[0]), o = [];
|
|
4
|
+
for (const [r, t] of c) {
|
|
5
|
+
const s = o[o.length - 1];
|
|
6
|
+
s && r <= s[1] ? s[1] = Math.max(s[1], t) : o.push([r, t]);
|
|
7
|
+
}
|
|
8
|
+
return o;
|
|
9
|
+
}
|
|
10
|
+
function m(n, i) {
|
|
11
|
+
return /* @__PURE__ */ d("mark", { className: "rounded-sm bg-primary/25 px-0.5 text-foreground", children: n }, i);
|
|
12
|
+
}
|
|
13
|
+
function b(n, i) {
|
|
14
|
+
const c = g(i.map(([s, e]) => [s, e + 1]), 2);
|
|
15
|
+
if (c.length === 0) return n;
|
|
16
|
+
const o = [];
|
|
17
|
+
let r = 0, t = 0;
|
|
18
|
+
for (const [s, e] of c)
|
|
19
|
+
s > r && o.push(n.slice(r, s)), o.push(m(n.slice(s, e), t++)), r = e;
|
|
20
|
+
return r < n.length && o.push(n.slice(r)), o;
|
|
21
|
+
}
|
|
22
|
+
function j(n, i, c = 260) {
|
|
23
|
+
var a;
|
|
24
|
+
const o = g(i.map(([f, l]) => [f, l + 1]), 2), r = ((a = o[0]) == null ? void 0 : a[0]) ?? 0, t = Math.max(0, r - 60), s = Math.min(n.length, t + c), e = [];
|
|
25
|
+
t > 0 && e.push("… ");
|
|
26
|
+
let h = t, k = 0;
|
|
27
|
+
for (const [f, l] of o) {
|
|
28
|
+
if (l <= t) continue;
|
|
29
|
+
if (f >= s) break;
|
|
30
|
+
const u = Math.max(f, t), p = Math.min(l, s);
|
|
31
|
+
u > h && e.push(n.slice(h, u)), e.push(m(n.slice(u, p), k++)), h = p;
|
|
32
|
+
}
|
|
33
|
+
return h < s && e.push(n.slice(h, s)), s < n.length && e.push(" …"), e;
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
b as highlightAll,
|
|
37
|
+
j as highlightSnippet
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=highlight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlight.js","sources":["../../src/lib/highlight.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\n/** Merge overlapping/adjacent [start,end) ranges, dropping any shorter than\n * `minLen` (so single fuzzy-char hits don't produce noisy highlights). */\nfunction mergeRanges(ranges: [number, number][], minLen = 1): [number, number][] {\n const kept = ranges.filter(([s, e]) => e - s >= minLen).sort((a, b) => a[0] - b[0]);\n const out: [number, number][] = [];\n for (const [s, e] of kept) {\n const last = out[out.length - 1];\n if (last && s <= last[1]) last[1] = Math.max(last[1], e);\n else out.push([s, e]);\n }\n return out;\n}\n\nfunction mark(text: string, key: number): ReactNode {\n return (\n <mark key={key} className=\"rounded-sm bg-primary/25 px-0.5 text-foreground\">\n {text}\n </mark>\n );\n}\n\n/**\n * Wrap the matched ranges of `text` in `<mark>`, highlighting the whole string\n * (no windowing). `indices` are Fuse.js match indices — inclusive `[start, end]`\n * pairs.\n */\nexport function highlightAll(text: string, indices: readonly [number, number][]): ReactNode {\n const ranges = mergeRanges(indices.map(([s, e]) => [s, e + 1] as [number, number]), 2);\n if (ranges.length === 0) return text;\n const parts: ReactNode[] = [];\n let cursor = 0;\n let k = 0;\n for (const [s, e] of ranges) {\n if (s > cursor) parts.push(text.slice(cursor, s));\n parts.push(mark(text.slice(s, e), k++));\n cursor = e;\n }\n if (cursor < text.length) parts.push(text.slice(cursor));\n return parts;\n}\n\n/**\n * Build a compact snippet of `text` centered on the first match, with the\n * matched ranges wrapped in `<mark>` and ellipses at any trimmed edge. Good for\n * long fields (message bodies, descriptions) where you only want the hit in\n * context. `indices` are Fuse.js match indices — inclusive `[start, end]` pairs.\n */\nexport function highlightSnippet(\n text: string,\n indices: readonly [number, number][],\n window = 260,\n): ReactNode {\n const ranges = mergeRanges(indices.map(([s, e]) => [s, e + 1] as [number, number]), 2);\n const first = ranges[0]?.[0] ?? 0;\n const start = Math.max(0, first - 60);\n const end = Math.min(text.length, start + window);\n\n const parts: ReactNode[] = [];\n if (start > 0) parts.push('… ');\n let cursor = start;\n let k = 0;\n for (const [rs, re] of ranges) {\n if (re <= start) continue;\n if (rs >= end) break;\n const s = Math.max(rs, start);\n const e = Math.min(re, end);\n if (s > cursor) parts.push(text.slice(cursor, s));\n parts.push(mark(text.slice(s, e), k++));\n cursor = e;\n }\n if (cursor < end) parts.push(text.slice(cursor, end));\n if (end < text.length) parts.push(' …');\n return parts;\n}\n"],"names":["mergeRanges","ranges","minLen","kept","s","e","a","b","out","last","mark","text","key","jsx","highlightAll","indices","parts","cursor","k","highlightSnippet","window","first","_a","start","end","rs","re"],"mappings":";AAIA,SAASA,EAAYC,GAA4BC,IAAS,GAAuB;AAC/E,QAAMC,IAAOF,EAAO,OAAO,CAAC,CAACG,GAAGC,CAAC,MAAMA,IAAID,KAAKF,CAAM,EAAE,KAAK,CAACI,GAAGC,MAAMD,EAAE,CAAC,IAAIC,EAAE,CAAC,CAAC,GAC5EC,IAA0B,CAAA;AAChC,aAAW,CAACJ,GAAGC,CAAC,KAAKF,GAAM;AACzB,UAAMM,IAAOD,EAAIA,EAAI,SAAS,CAAC;AAC/B,IAAIC,KAAQL,KAAKK,EAAK,CAAC,IAAGA,EAAK,CAAC,IAAI,KAAK,IAAIA,EAAK,CAAC,GAAGJ,CAAC,IAClDG,EAAI,KAAK,CAACJ,GAAGC,CAAC,CAAC;AAAA,EACtB;AACA,SAAOG;AACT;AAEA,SAASE,EAAKC,GAAcC,GAAwB;AAClD,SACE,gBAAAC,EAAC,QAAA,EAAe,WAAU,mDACvB,eADQD,CAEX;AAEJ;AAOO,SAASE,EAAaH,GAAcI,GAAiD;AAC1F,QAAMd,IAASD,EAAYe,EAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAqB,GAAG,CAAC;AACrF,MAAId,EAAO,WAAW,EAAG,QAAOU;AAChC,QAAMK,IAAqB,CAAA;AAC3B,MAAIC,IAAS,GACTC,IAAI;AACR,aAAW,CAAC,GAAG,CAAC,KAAKjB;AACnB,IAAI,IAAIgB,KAAQD,EAAM,KAAKL,EAAK,MAAMM,GAAQ,CAAC,CAAC,GAChDD,EAAM,KAAKN,EAAKC,EAAK,MAAM,GAAG,CAAC,GAAGO,GAAG,CAAC,GACtCD,IAAS;AAEX,SAAIA,IAASN,EAAK,UAAQK,EAAM,KAAKL,EAAK,MAAMM,CAAM,CAAC,GAChDD;AACT;AAQO,SAASG,EACdR,GACAI,GACAK,IAAS,KACE;;AACX,QAAMnB,IAASD,EAAYe,EAAQ,IAAI,CAAC,CAACX,GAAGC,CAAC,MAAM,CAACD,GAAGC,IAAI,CAAC,CAAqB,GAAG,CAAC,GAC/EgB,MAAQC,IAAArB,EAAO,CAAC,MAAR,gBAAAqB,EAAY,OAAM,GAC1BC,IAAQ,KAAK,IAAI,GAAGF,IAAQ,EAAE,GAC9BG,IAAM,KAAK,IAAIb,EAAK,QAAQY,IAAQH,CAAM,GAE1CJ,IAAqB,CAAA;AAC3B,EAAIO,IAAQ,KAAGP,EAAM,KAAK,IAAI;AAC9B,MAAIC,IAASM,GACT,IAAI;AACR,aAAW,CAACE,GAAIC,CAAE,KAAKzB,GAAQ;AAC7B,QAAIyB,KAAMH,EAAO;AACjB,QAAIE,KAAMD,EAAK;AACf,UAAMpB,IAAI,KAAK,IAAIqB,GAAIF,CAAK,GACtBlB,IAAI,KAAK,IAAIqB,GAAIF,CAAG;AAC1B,IAAIpB,IAAIa,KAAQD,EAAM,KAAKL,EAAK,MAAMM,GAAQb,CAAC,CAAC,GAChDY,EAAM,KAAKN,EAAKC,EAAK,MAAMP,GAAGC,CAAC,GAAG,GAAG,CAAC,GACtCY,IAASZ;AAAA,EACX;AACA,SAAIY,IAASO,KAAKR,EAAM,KAAKL,EAAK,MAAMM,GAAQO,CAAG,CAAC,GAChDA,IAAMb,EAAK,UAAQK,EAAM,KAAK,IAAI,GAC/BA;AACT;"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { default as Fuse, FuseOptionKey, FuseResultMatch } from 'fuse.js';
|
|
2
|
+
/** One row of {@link runSearch} output — mirrors a Fuse result, but the matches
|
|
3
|
+
* may be a mix of fuzzy hits (from Fuse) and exact-phrase hits (computed here). */
|
|
4
|
+
export interface SearchResult<T> {
|
|
5
|
+
item: T;
|
|
6
|
+
refIndex: number;
|
|
7
|
+
matches: readonly FuseResultMatch[];
|
|
8
|
+
}
|
|
9
|
+
interface ParsedQuery {
|
|
10
|
+
/** Double-quoted segments — matched as exact, case-insensitive substrings. */
|
|
11
|
+
phrases: string[];
|
|
12
|
+
/** Everything outside quotes — matched fuzzily by Fuse. */
|
|
13
|
+
rest: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Split a raw query into exact `"quoted"` phrases and the leftover fuzzy text:
|
|
17
|
+
* `foo "bar baz" qux` → `{ phrases: ['bar baz'], rest: 'foo qux' }`.
|
|
18
|
+
*
|
|
19
|
+
* An unterminated quote is treated as literal text (it stays in `rest`), so a
|
|
20
|
+
* query that is mid-typing (`foo "ba`) keeps fuzzy-searching instead of
|
|
21
|
+
* suddenly matching nothing.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseQuery(query: string): ParsedQuery;
|
|
24
|
+
/**
|
|
25
|
+
* Search `items` with quote-aware semantics:
|
|
26
|
+
*
|
|
27
|
+
* - A bare query is fuzzy-matched by Fuse (unchanged behaviour).
|
|
28
|
+
* - Any `"double-quoted"` segment must appear **exactly** (case-insensitive
|
|
29
|
+
* substring) in one of the searched keys — great for pinning down an exact
|
|
30
|
+
* name/id when the fuzzy ranking would otherwise bury it.
|
|
31
|
+
* - The two can mix: `parser "utils.ts"` fuzzy-matches `parser` and then keeps
|
|
32
|
+
* only items whose fields contain the literal `utils.ts`.
|
|
33
|
+
*
|
|
34
|
+
* Returns results in Fuse relevance order when there is fuzzy text, otherwise in
|
|
35
|
+
* input order. Exact-phrase and fuzzy match indices are merged so the caller's
|
|
36
|
+
* highlighter marks both.
|
|
37
|
+
*/
|
|
38
|
+
export declare function runSearch<T>(fuse: Fuse<T>, items: T[], keys: FuseOptionKey<T>[], rawQuery: string, limit?: number): SearchResult<T>[];
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/lib/search.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,EAAE,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAEzE;mFACmF;AACnF,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;CACrC;AAED,UAAU,WAAW;IACnB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAiBrD;AAkFD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACzB,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EACb,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,EACxB,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,GACb,YAAY,CAAC,CAAC,CAAC,EAAE,CAwCnB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import "fuse.js";
|
|
2
|
+
function g(t) {
|
|
3
|
+
const r = [];
|
|
4
|
+
let e = "", s = 0;
|
|
5
|
+
const o = /"([^"]*)"/g;
|
|
6
|
+
let c;
|
|
7
|
+
for (; (c = o.exec(t)) !== null; ) {
|
|
8
|
+
e += t.slice(s, c.index);
|
|
9
|
+
const u = c[1].trim();
|
|
10
|
+
u && r.push(u), s = o.lastIndex;
|
|
11
|
+
}
|
|
12
|
+
return e += t.slice(s), { phrases: r, rest: e.replace(/"/g, " ").replace(/\s+/g, " ").trim() };
|
|
13
|
+
}
|
|
14
|
+
function x(t) {
|
|
15
|
+
if (typeof t == "string") return t;
|
|
16
|
+
if (Array.isArray(t)) return t.join(".");
|
|
17
|
+
const r = t.name;
|
|
18
|
+
return Array.isArray(r) ? r.join(".") : r;
|
|
19
|
+
}
|
|
20
|
+
function d(t, r) {
|
|
21
|
+
let e = t;
|
|
22
|
+
for (const s of r.split(".")) {
|
|
23
|
+
if (e == null || typeof e != "object") return "";
|
|
24
|
+
e = e[s];
|
|
25
|
+
}
|
|
26
|
+
return e == null ? "" : String(e);
|
|
27
|
+
}
|
|
28
|
+
function y(t, r, e) {
|
|
29
|
+
const s = /* @__PURE__ */ new Map(), o = e.map(() => !1);
|
|
30
|
+
for (const a of r) {
|
|
31
|
+
const h = d(t, a);
|
|
32
|
+
if (!h) continue;
|
|
33
|
+
const m = h.toLowerCase();
|
|
34
|
+
e.forEach((l, n) => {
|
|
35
|
+
const i = l.toLowerCase();
|
|
36
|
+
let f = m.indexOf(i);
|
|
37
|
+
if (f === -1) return;
|
|
38
|
+
o[n] = !0;
|
|
39
|
+
const p = s.get(a) ?? [];
|
|
40
|
+
for (; f !== -1; )
|
|
41
|
+
p.push([f, f + i.length - 1]), f = m.indexOf(i, f + i.length);
|
|
42
|
+
s.set(a, p);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const c = o.every(Boolean), u = c ? [...s.entries()].map(
|
|
46
|
+
([a, h]) => ({ key: a, value: d(t, a), indices: h })
|
|
47
|
+
) : [];
|
|
48
|
+
return { ok: c, matches: u };
|
|
49
|
+
}
|
|
50
|
+
function v(t, r) {
|
|
51
|
+
const e = /* @__PURE__ */ new Map();
|
|
52
|
+
for (const s of [...t, ...r]) {
|
|
53
|
+
const o = s.key ?? "", c = e.get(o);
|
|
54
|
+
c ? e.set(o, {
|
|
55
|
+
...c,
|
|
56
|
+
indices: [...c.indices ?? [], ...s.indices ?? []]
|
|
57
|
+
}) : e.set(o, s);
|
|
58
|
+
}
|
|
59
|
+
return [...e.values()];
|
|
60
|
+
}
|
|
61
|
+
function w(t, r, e, s, o) {
|
|
62
|
+
const c = s.trim();
|
|
63
|
+
if (!c) return r.map((n, i) => ({ item: n, refIndex: i, matches: [] }));
|
|
64
|
+
const { phrases: u, rest: a } = g(c);
|
|
65
|
+
if (u.length === 0)
|
|
66
|
+
return t.search(a || c, o ? { limit: o } : void 0).map((n) => ({
|
|
67
|
+
item: n.item,
|
|
68
|
+
refIndex: n.refIndex,
|
|
69
|
+
matches: n.matches ?? []
|
|
70
|
+
}));
|
|
71
|
+
const h = e.map(x), m = a ? t.search(a).map((n) => ({
|
|
72
|
+
item: n.item,
|
|
73
|
+
refIndex: n.refIndex,
|
|
74
|
+
matches: [...n.matches ?? []]
|
|
75
|
+
})) : r.map((n, i) => ({ item: n, refIndex: i, matches: [] })), l = [];
|
|
76
|
+
for (const n of m) {
|
|
77
|
+
const { ok: i, matches: f } = y(n.item, h, u);
|
|
78
|
+
if (i && (l.push({
|
|
79
|
+
item: n.item,
|
|
80
|
+
refIndex: n.refIndex,
|
|
81
|
+
matches: v(n.matches, f)
|
|
82
|
+
}), o && l.length >= o))
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
return l;
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
g as parseQuery,
|
|
89
|
+
w as runSearch
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sources":["../../src/lib/search.ts"],"sourcesContent":["import Fuse, { type FuseOptionKey, type FuseResultMatch } from 'fuse.js';\n\n/** One row of {@link runSearch} output — mirrors a Fuse result, but the matches\n * may be a mix of fuzzy hits (from Fuse) and exact-phrase hits (computed here). */\nexport interface SearchResult<T> {\n item: T;\n refIndex: number;\n matches: readonly FuseResultMatch[];\n}\n\ninterface ParsedQuery {\n /** Double-quoted segments — matched as exact, case-insensitive substrings. */\n phrases: string[];\n /** Everything outside quotes — matched fuzzily by Fuse. */\n rest: string;\n}\n\n/**\n * Split a raw query into exact `\"quoted\"` phrases and the leftover fuzzy text:\n * `foo \"bar baz\" qux` → `{ phrases: ['bar baz'], rest: 'foo qux' }`.\n *\n * An unterminated quote is treated as literal text (it stays in `rest`), so a\n * query that is mid-typing (`foo \"ba`) keeps fuzzy-searching instead of\n * suddenly matching nothing.\n */\nexport function parseQuery(query: string): ParsedQuery {\n const phrases: string[] = [];\n let rest = '';\n let last = 0;\n const re = /\"([^\"]*)\"/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(query)) !== null) {\n rest += query.slice(last, m.index);\n const phrase = m[1].trim();\n if (phrase) phrases.push(phrase);\n last = re.lastIndex;\n }\n rest += query.slice(last);\n // Any `\"` left in `rest` is an unbalanced quote from a mid-typed query — drop\n // it so the leftover text still fuzzy-searches instead of the literal quote\n // poisoning the match.\n return { phrases, rest: rest.replace(/\"/g, ' ').replace(/\\s+/g, ' ').trim() };\n}\n\n/** Normalise a Fuse key (string, path array, or weighted object) to a dotted path. */\nfunction keyToPath<T>(key: FuseOptionKey<T>): string {\n if (typeof key === 'string') return key;\n if (Array.isArray(key)) return key.join('.');\n const name = (key as { name: string | string[] }).name;\n return Array.isArray(name) ? name.join('.') : name;\n}\n\n/** Read a dotted path off an object as a string — same coercion the highlighter\n * uses (arrays via `String`, i.e. comma-joined) so match indices line up. */\nfunction valueAt(obj: unknown, path: string): string {\n let cur: unknown = obj;\n for (const seg of path.split('.')) {\n if (cur == null || typeof cur !== 'object') return '';\n cur = (cur as Record<string, unknown>)[seg];\n }\n return cur == null ? '' : String(cur);\n}\n\n/** Test one item against every quoted phrase and, if all are present, collect\n * the `<mark>`-ready match indices per key. An item passes only when EVERY\n * phrase appears (case-insensitively) in at least one searched key. */\nfunction exactMatch<T>(\n item: T,\n keyPaths: string[],\n phrases: string[],\n): { ok: boolean; matches: FuseResultMatch[] } {\n const indicesByKey = new Map<string, [number, number][]>();\n const found = phrases.map(() => false);\n\n for (const path of keyPaths) {\n const value = valueAt(item, path);\n if (!value) continue;\n const hay = value.toLowerCase();\n phrases.forEach((phrase, pi) => {\n const needle = phrase.toLowerCase();\n let at = hay.indexOf(needle);\n if (at === -1) return;\n found[pi] = true;\n const arr = indicesByKey.get(path) ?? [];\n while (at !== -1) {\n arr.push([at, at + needle.length - 1]);\n at = hay.indexOf(needle, at + needle.length);\n }\n indicesByKey.set(path, arr);\n });\n }\n\n const ok = found.every(Boolean);\n const matches: FuseResultMatch[] = ok\n ? [...indicesByKey.entries()].map(\n ([key, indices]) =>\n ({ key, value: valueAt(item, key), indices } as unknown as FuseResultMatch),\n )\n : [];\n return { ok, matches };\n}\n\n/** Merge two match lists, consolidating by key so the highlighter (which looks\n * matches up by key) sees a single entry per field with all its ranges. */\nfunction mergeMatches(\n a: readonly FuseResultMatch[],\n b: readonly FuseResultMatch[],\n): FuseResultMatch[] {\n const byKey = new Map<string, FuseResultMatch>();\n for (const m of [...a, ...b]) {\n const key = m.key ?? '';\n const prev = byKey.get(key);\n if (prev) {\n byKey.set(key, {\n ...prev,\n indices: [...(prev.indices ?? []), ...(m.indices ?? [])],\n } as FuseResultMatch);\n } else {\n byKey.set(key, m);\n }\n }\n return [...byKey.values()];\n}\n\n/**\n * Search `items` with quote-aware semantics:\n *\n * - A bare query is fuzzy-matched by Fuse (unchanged behaviour).\n * - Any `\"double-quoted\"` segment must appear **exactly** (case-insensitive\n * substring) in one of the searched keys — great for pinning down an exact\n * name/id when the fuzzy ranking would otherwise bury it.\n * - The two can mix: `parser \"utils.ts\"` fuzzy-matches `parser` and then keeps\n * only items whose fields contain the literal `utils.ts`.\n *\n * Returns results in Fuse relevance order when there is fuzzy text, otherwise in\n * input order. Exact-phrase and fuzzy match indices are merged so the caller's\n * highlighter marks both.\n */\nexport function runSearch<T>(\n fuse: Fuse<T>,\n items: T[],\n keys: FuseOptionKey<T>[],\n rawQuery: string,\n limit?: number,\n): SearchResult<T>[] {\n const query = rawQuery.trim();\n if (!query) return items.map((item, refIndex) => ({ item, refIndex, matches: [] }));\n\n const { phrases, rest } = parseQuery(query);\n\n // No quoted phrase → plain fuzzy, exactly as before.\n if (phrases.length === 0) {\n return fuse.search(rest || query, limit ? { limit } : undefined).map((r) => ({\n item: r.item,\n refIndex: r.refIndex,\n matches: (r.matches ?? []) as readonly FuseResultMatch[],\n }));\n }\n\n const keyPaths = keys.map(keyToPath);\n\n // Candidate pool: when there's fuzzy text, rank/narrow by it first (no limit\n // yet — the exact filter still has to run); otherwise consider every item and\n // keep input order. `limit` is applied after the exact filter below.\n const pool: SearchResult<T>[] = rest\n ? fuse.search(rest).map((r) => ({\n item: r.item,\n refIndex: r.refIndex,\n matches: [...(r.matches ?? [])] as FuseResultMatch[],\n }))\n : items.map((item, refIndex) => ({ item, refIndex, matches: [] as FuseResultMatch[] }));\n\n const out: SearchResult<T>[] = [];\n for (const cand of pool) {\n const { ok, matches } = exactMatch(cand.item, keyPaths, phrases);\n if (!ok) continue;\n out.push({\n item: cand.item,\n refIndex: cand.refIndex,\n matches: mergeMatches(cand.matches, matches),\n });\n if (limit && out.length >= limit) break;\n }\n return out;\n}\n"],"names":["parseQuery","query","phrases","rest","last","re","m","phrase","keyToPath","key","name","valueAt","obj","path","cur","seg","exactMatch","item","keyPaths","indicesByKey","found","value","hay","pi","needle","at","arr","ok","matches","indices","mergeMatches","a","b","byKey","prev","runSearch","fuse","items","keys","rawQuery","limit","refIndex","r","pool","out","cand"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C,mEAAmE;AACnE,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../src/lib/utils.ts"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/** Merge Tailwind class names, resolving conflicts (last wins). */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"names":["cn","inputs","twMerge","clsx"],"mappings":";;AAIO,SAASA,KAAMC,GAAsB;AAC1C,SAAOC,EAAQC,EAAKF,CAAM,CAAC;AAC7B;"}
|
package/dist/overlay.css
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Motion for <Modal> and the toast stack.
|
|
3
|
+
*
|
|
4
|
+
* Plain CSS — no Tailwind directives — so the animations work whether or not
|
|
5
|
+
* the consumer's Tailwind config scans this package. Everything is under
|
|
6
|
+
* `prefers-reduced-motion`, so the overlays simply appear when motion is off.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
@keyframes ds-fade-in {
|
|
10
|
+
from {
|
|
11
|
+
opacity: 0;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@keyframes ds-scrim-in {
|
|
16
|
+
from {
|
|
17
|
+
opacity: 0;
|
|
18
|
+
backdrop-filter: blur(0);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@keyframes ds-panel-in {
|
|
23
|
+
from {
|
|
24
|
+
opacity: 0;
|
|
25
|
+
transform: translateY(12px) scale(0.97);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@keyframes ds-panel-in-sheet {
|
|
30
|
+
from {
|
|
31
|
+
transform: translateY(100%);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@keyframes ds-toast-in-bottom {
|
|
36
|
+
from {
|
|
37
|
+
opacity: 0;
|
|
38
|
+
transform: translateY(14px) scale(0.97);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@keyframes ds-toast-in-top {
|
|
43
|
+
from {
|
|
44
|
+
opacity: 0;
|
|
45
|
+
transform: translateY(-14px) scale(0.97);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.ds-modal-scrim {
|
|
50
|
+
animation: ds-scrim-in 160ms ease-out;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* On phones the modal is a bottom sheet, so it rises from the edge it sits on. */
|
|
54
|
+
.ds-modal-panel {
|
|
55
|
+
animation: ds-panel-in-sheet 260ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@media (min-width: 640px) {
|
|
59
|
+
.ds-modal-panel {
|
|
60
|
+
animation: ds-panel-in 180ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ds-toast--bottom {
|
|
65
|
+
animation: ds-toast-in-bottom 220ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.ds-toast--top {
|
|
69
|
+
animation: ds-toast-in-top 220ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@media (prefers-reduced-motion: reduce) {
|
|
73
|
+
.ds-modal-scrim,
|
|
74
|
+
.ds-modal-panel,
|
|
75
|
+
.ds-toast {
|
|
76
|
+
animation: ds-fade-in 1ms linear;
|
|
77
|
+
}
|
|
78
|
+
}
|
package/dist/styles.css
ADDED
package/dist/theme.css
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @gabvdl/ui design tokens.
|
|
3
|
+
*
|
|
4
|
+
* Import this into your Tailwind v4 entry, after `@import "tailwindcss"`, so the
|
|
5
|
+
* `@theme inline` block below wires the tokens into utilities (`bg-card`,
|
|
6
|
+
* `text-muted-foreground`, `border-border`, …). Light values live on :root; add
|
|
7
|
+
* the `.dark` class to any ancestor to switch. Override any custom property to
|
|
8
|
+
* retheme without touching component code.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
:root {
|
|
12
|
+
--background: #ffffff;
|
|
13
|
+
--foreground: #1c1917;
|
|
14
|
+
--card: #ffffff;
|
|
15
|
+
--card-foreground: #1c1917;
|
|
16
|
+
--popover: #ffffff;
|
|
17
|
+
--popover-foreground: #1c1917;
|
|
18
|
+
--primary: #1c1917;
|
|
19
|
+
--primary-foreground: #fafaf9;
|
|
20
|
+
--secondary: #f5f5f4;
|
|
21
|
+
--secondary-foreground: #1c1917;
|
|
22
|
+
--muted: #f5f5f4;
|
|
23
|
+
--muted-foreground: #78716c;
|
|
24
|
+
--accent: #f5f5f4;
|
|
25
|
+
--accent-foreground: #1c1917;
|
|
26
|
+
--destructive: #dc2626;
|
|
27
|
+
--destructive-foreground: #fafaf9;
|
|
28
|
+
--border: #e7e5e4;
|
|
29
|
+
--input: #e7e5e4;
|
|
30
|
+
--ring: #a8a29e;
|
|
31
|
+
--radius: 0.625rem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.dark {
|
|
35
|
+
--background: #0c0a09;
|
|
36
|
+
--foreground: #fafaf9;
|
|
37
|
+
--card: #1c1917;
|
|
38
|
+
--card-foreground: #fafaf9;
|
|
39
|
+
--popover: #1c1917;
|
|
40
|
+
--popover-foreground: #fafaf9;
|
|
41
|
+
--primary: #fafaf9;
|
|
42
|
+
--primary-foreground: #1c1917;
|
|
43
|
+
--secondary: #292524;
|
|
44
|
+
--secondary-foreground: #fafaf9;
|
|
45
|
+
--muted: #292524;
|
|
46
|
+
--muted-foreground: #a8a29e;
|
|
47
|
+
--accent: #292524;
|
|
48
|
+
--accent-foreground: #fafaf9;
|
|
49
|
+
--destructive: #ef4444;
|
|
50
|
+
--destructive-foreground: #fafaf9;
|
|
51
|
+
--border: #292524;
|
|
52
|
+
--input: #292524;
|
|
53
|
+
--ring: #57534e;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@theme inline {
|
|
57
|
+
--color-background: var(--background);
|
|
58
|
+
--color-foreground: var(--foreground);
|
|
59
|
+
--color-card: var(--card);
|
|
60
|
+
--color-card-foreground: var(--card-foreground);
|
|
61
|
+
--color-popover: var(--popover);
|
|
62
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
63
|
+
--color-primary: var(--primary);
|
|
64
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
65
|
+
--color-secondary: var(--secondary);
|
|
66
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
67
|
+
--color-muted: var(--muted);
|
|
68
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
69
|
+
--color-accent: var(--accent);
|
|
70
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
71
|
+
--color-destructive: var(--destructive);
|
|
72
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
73
|
+
--color-border: var(--border);
|
|
74
|
+
--color-input: var(--input);
|
|
75
|
+
--color-ring: var(--ring);
|
|
76
|
+
|
|
77
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
78
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
79
|
+
--radius-lg: var(--radius);
|
|
80
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
81
|
+
}
|
package/dist/tooltip.css
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Styling for the tooltip attached to <Button tooltip="…">.
|
|
3
|
+
*
|
|
4
|
+
* Plain CSS — no Tailwind directives — so the bubble is visible whether or not
|
|
5
|
+
* the consumer's Tailwind scans this package. Every value reads from a
|
|
6
|
+
* `--ds-tooltip-*` custom property, so it can be rethemed from the outside.
|
|
7
|
+
*
|
|
8
|
+
* The anchor is what gets positioned (fixed, at the trigger's edge, then pulled
|
|
9
|
+
* onto the right side with a transform); the bubble inside it is free to run its
|
|
10
|
+
* own entrance animation without fighting that transform.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
:root {
|
|
14
|
+
--ds-tooltip-bg: var(--popover, #1c1917);
|
|
15
|
+
--ds-tooltip-fg: var(--popover-foreground, #fafaf9);
|
|
16
|
+
--ds-tooltip-border: var(--border, rgba(255, 255, 255, 0.12));
|
|
17
|
+
--ds-tooltip-radius: 6px;
|
|
18
|
+
--ds-tooltip-z: 300;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.ds-tooltip-anchor {
|
|
22
|
+
position: fixed;
|
|
23
|
+
z-index: var(--ds-tooltip-z);
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.ds-tooltip {
|
|
28
|
+
display: block;
|
|
29
|
+
max-width: 16rem;
|
|
30
|
+
padding: 0.25rem 0.5rem;
|
|
31
|
+
border: 1px solid var(--ds-tooltip-border);
|
|
32
|
+
border-radius: var(--ds-tooltip-radius);
|
|
33
|
+
background: var(--ds-tooltip-bg);
|
|
34
|
+
color: var(--ds-tooltip-fg);
|
|
35
|
+
box-shadow: 0 6px 18px -6px rgba(0, 0, 0, 0.4);
|
|
36
|
+
font-size: 0.75rem;
|
|
37
|
+
line-height: 1.1rem;
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
animation: ds-tooltip-in 90ms ease-out;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@keyframes ds-tooltip-in {
|
|
43
|
+
from {
|
|
44
|
+
opacity: 0;
|
|
45
|
+
transform: scale(0.96);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@media (prefers-reduced-motion: reduce) {
|
|
50
|
+
.ds-tooltip {
|
|
51
|
+
animation: none;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Smooth-reorder animation for <VirtualList smooth>.
|
|
3
|
+
*
|
|
4
|
+
* Plain CSS — no Tailwind directives — so it works whether or not the consumer
|
|
5
|
+
* uses Tailwind. Each virtualized row is absolutely positioned and moved with a
|
|
6
|
+
* `transform: translateY(...)`; when the underlying list is re-sorted (e.g. an
|
|
7
|
+
* auto-sort by "updated" date whose value changed), a row's target offset
|
|
8
|
+
* changes and this transition glides it to its new slot instead of teleporting,
|
|
9
|
+
* so the reorder reads clearly instead of flashing.
|
|
10
|
+
*
|
|
11
|
+
* The component only adds `--smooth` while the list is idle (not actively being
|
|
12
|
+
* scrolled), so scroll and lazy height-measurement never animate — only genuine
|
|
13
|
+
* reorders do. Honors `prefers-reduced-motion`.
|
|
14
|
+
*/
|
|
15
|
+
.ds-virtual-row {
|
|
16
|
+
/* base marker class — no styling on its own */
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.ds-virtual-row--smooth {
|
|
20
|
+
transition: transform var(--ds-virtual-row-duration, 320ms)
|
|
21
|
+
var(--ds-virtual-row-ease, cubic-bezier(0.22, 1, 0.36, 1));
|
|
22
|
+
will-change: transform;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@media (prefers-reduced-motion: reduce) {
|
|
26
|
+
.ds-virtual-row--smooth {
|
|
27
|
+
transition: none;
|
|
28
|
+
}
|
|
29
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gabvdl/ui",
|
|
3
|
+
"version": "0.0.14",
|
|
4
|
+
"description": "Gabriel Vidal's personal design system — tree-shakeable React components built on shadcn primitives. Flagship: a full-screen image viewer with zoom, pan and swipe.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/GabrielVidal1/design-system.git",
|
|
10
|
+
"directory": "packages/ui"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://ui.gabvdl.xyz",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/GabrielVidal1/design-system/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react",
|
|
18
|
+
"components",
|
|
19
|
+
"design-system",
|
|
20
|
+
"shadcn",
|
|
21
|
+
"tailwind",
|
|
22
|
+
"image-viewer"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": [
|
|
25
|
+
"**/*.css"
|
|
26
|
+
],
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"main": "./dist/index.js",
|
|
35
|
+
"module": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"import": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./styles.css": "./dist/styles.css",
|
|
43
|
+
"./theme.css": "./dist/theme.css",
|
|
44
|
+
"./image-viewer.css": "./dist/image-viewer.css",
|
|
45
|
+
"./virtual-list.css": "./dist/virtual-list.css",
|
|
46
|
+
"./overlay.css": "./dist/overlay.css",
|
|
47
|
+
"./tooltip.css": "./dist/tooltip.css",
|
|
48
|
+
"./package.json": "./package.json"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "vite build && node scripts/copy-css.mjs",
|
|
52
|
+
"dev": "vite build --watch",
|
|
53
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"react": ">=18",
|
|
57
|
+
"react-dom": ">=18"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@tanstack/react-virtual": "^3.14.5",
|
|
61
|
+
"clsx": "^2.1.1",
|
|
62
|
+
"fuse.js": "^7.1.0",
|
|
63
|
+
"lucide-react": "^0.469.0",
|
|
64
|
+
"react-resizable-panels": "^2.1.9",
|
|
65
|
+
"tailwind-merge": "^3.6.0"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@types/react": "^19.1.2",
|
|
69
|
+
"@types/react-dom": "^19.1.2",
|
|
70
|
+
"@vitejs/plugin-react": "^4.4.1",
|
|
71
|
+
"react": "^19.1.0",
|
|
72
|
+
"react-dom": "^19.1.0",
|
|
73
|
+
"typescript": "~5.8.3",
|
|
74
|
+
"vite": "^6.3.1",
|
|
75
|
+
"vite-plugin-dts": "^4.5.0"
|
|
76
|
+
}
|
|
77
|
+
}
|