@astra-kit/ui 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/LICENSE.md +21 -0
- package/README.md +330 -2
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/assets/fonts/geist-LICENSE.txt +93 -0
- package/assets/fonts/geist-latin-variable.woff2 +0 -0
- package/assets/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
- package/assets/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
- package/assets/fonts/ibmplexmono-LICENSE.txt +93 -0
- package/assets/fonts/inter-LICENSE.txt +93 -0
- package/assets/fonts/inter-latin-variable.woff2 +0 -0
- package/dist/adapters/unpic-image.d.ts +3 -0
- package/dist/adapters/unpic-image.js +98 -0
- package/dist/components/account-menu.d.ts +67 -0
- package/dist/components/account-menu.js +440 -0
- package/dist/components/action-button.d.ts +25 -0
- package/dist/components/action-button.js +264 -0
- package/dist/components/alert.d.ts +31 -0
- package/dist/components/alert.js +503 -0
- package/dist/components/animated-collapse.d.ts +19 -0
- package/dist/components/animated-collapse.js +170 -0
- package/dist/components/animated-count.d.ts +13 -0
- package/dist/components/animated-count.js +105 -0
- package/dist/components/animated-list-item.d.ts +25 -0
- package/dist/components/animated-list-item.js +134 -0
- package/dist/components/animated-theme-toggler.d.ts +12 -0
- package/dist/components/animated-theme-toggler.js +200 -0
- package/dist/components/avatar.d.ts +65 -0
- package/dist/components/avatar.js +463 -0
- package/dist/components/badge.d.ts +21 -0
- package/dist/components/badge.js +297 -0
- package/dist/components/button-interaction.d.ts +23 -0
- package/dist/components/button-interaction.js +22 -0
- package/dist/components/button-label.d.ts +8 -0
- package/dist/components/button-label.js +203 -0
- package/dist/components/button.d.ts +23 -0
- package/dist/components/button.js +145 -0
- package/dist/components/calendar.d.ts +47 -0
- package/dist/components/calendar.js +155 -0
- package/dist/components/card.d.ts +38 -0
- package/dist/components/card.js +904 -0
- package/dist/components/carousel.d.ts +71 -0
- package/dist/components/carousel.js +585 -0
- package/dist/components/checkbox.d.ts +15 -0
- package/dist/components/checkbox.js +324 -0
- package/dist/components/control-button.d.ts +16 -0
- package/dist/components/control-button.js +215 -0
- package/dist/components/data-table.d.ts +118 -0
- package/dist/components/data-table.js +895 -0
- package/dist/components/dialog-surface.d.ts +49 -0
- package/dist/components/dialog-surface.js +220 -0
- package/dist/components/dialog.d.ts +92 -0
- package/dist/components/dialog.js +320 -0
- package/dist/components/dropdown-menu.d.ts +58 -0
- package/dist/components/dropdown-menu.js +135 -0
- package/dist/components/field.d.ts +53 -0
- package/dist/components/field.js +710 -0
- package/dist/components/file-upload.d.ts +88 -0
- package/dist/components/file-upload.js +776 -0
- package/dist/components/filter-presets-bar.d.ts +73 -0
- package/dist/components/filter-presets-bar.js +510 -0
- package/dist/components/filter-query-bar.d.ts +21 -0
- package/dist/components/filter-query-bar.js +881 -0
- package/dist/components/filter-query-grammar.d.ts +188 -0
- package/dist/components/filter-query-grammar.js +875 -0
- package/dist/components/form.d.ts +29 -0
- package/dist/components/form.js +330 -0
- package/dist/components/highlighter.d.ts +15 -0
- package/dist/components/highlighter.js +152 -0
- package/dist/components/hover-card.d.ts +50 -0
- package/dist/components/hover-card.js +80 -0
- package/dist/components/input-group.d.ts +16 -0
- package/dist/components/input-group.js +277 -0
- package/dist/components/input.d.ts +17 -0
- package/dist/components/input.js +120 -0
- package/dist/components/label.d.ts +4 -0
- package/dist/components/label.js +43 -0
- package/dist/components/link.d.ts +9 -0
- package/dist/components/link.js +43 -0
- package/dist/components/morph-text.d.ts +14 -0
- package/dist/components/morph-text.js +210 -0
- package/dist/components/pagination.d.ts +59 -0
- package/dist/components/pagination.js +190 -0
- package/dist/components/popover.d.ts +17 -0
- package/dist/components/popover.js +40 -0
- package/dist/components/presence-swap.d.ts +22 -0
- package/dist/components/presence-swap.js +209 -0
- package/dist/components/primitives/alert-dialog.d.ts +68 -0
- package/dist/components/primitives/alert-dialog.js +629 -0
- package/dist/components/primitives/avatar.d.ts +46 -0
- package/dist/components/primitives/avatar.js +265 -0
- package/dist/components/primitives/calendar.d.ts +37 -0
- package/dist/components/primitives/calendar.js +1250 -0
- package/dist/components/primitives/carousel.d.ts +106 -0
- package/dist/components/primitives/carousel.js +928 -0
- package/dist/components/primitives/dialog.d.ts +62 -0
- package/dist/components/primitives/dialog.js +490 -0
- package/dist/components/primitives/dropdown-menu-items.d.ts +59 -0
- package/dist/components/primitives/dropdown-menu-items.js +265 -0
- package/dist/components/primitives/dropdown-menu.d.ts +64 -0
- package/dist/components/primitives/dropdown-menu.js +560 -0
- package/dist/components/primitives/hover-card.d.ts +50 -0
- package/dist/components/primitives/hover-card.js +507 -0
- package/dist/components/primitives/pagination.d.ts +65 -0
- package/dist/components/primitives/pagination.js +373 -0
- package/dist/components/primitives/popover.d.ts +22 -0
- package/dist/components/primitives/popover.js +213 -0
- package/dist/components/primitives/select.d.ts +37 -0
- package/dist/components/primitives/select.js +428 -0
- package/dist/components/primitives/tooltip.d.ts +30 -0
- package/dist/components/primitives/tooltip.js +277 -0
- package/dist/components/progress-ring.d.ts +20 -0
- package/dist/components/progress-ring.js +53 -0
- package/dist/components/radio-group.d.ts +34 -0
- package/dist/components/radio-group.js +392 -0
- package/dist/components/reaction-button.d.ts +30 -0
- package/dist/components/reaction-button.js +189 -0
- package/dist/components/rich-link-editor.d.ts +25 -0
- package/dist/components/rich-link-editor.js +320 -0
- package/dist/components/rich-markdown-content.d.ts +10 -0
- package/dist/components/rich-markdown-content.js +56 -0
- package/dist/components/rich-text-content.d.ts +19 -0
- package/dist/components/rich-text-content.js +26 -0
- package/dist/components/select.d.ts +55 -0
- package/dist/components/select.js +188 -0
- package/dist/components/separator.d.ts +3 -0
- package/dist/components/separator.js +48 -0
- package/dist/components/sheet.d.ts +19 -0
- package/dist/components/sheet.js +420 -0
- package/dist/components/sidebar-panel-context.d.ts +17 -0
- package/dist/components/sidebar-panel-context.js +14 -0
- package/dist/components/sidebar.d.ts +195 -0
- package/dist/components/sidebar.js +2041 -0
- package/dist/components/skeleton.d.ts +23 -0
- package/dist/components/skeleton.js +334 -0
- package/dist/components/split-button.d.ts +36 -0
- package/dist/components/split-button.js +306 -0
- package/dist/components/svgs/whatsappIcon.d.ts +3 -0
- package/dist/components/svgs/whatsappIcon.js +14 -0
- package/dist/components/switch.d.ts +13 -0
- package/dist/components/switch.js +444 -0
- package/dist/components/table.d.ts +10 -0
- package/dist/components/table.js +298 -0
- package/dist/components/tabs.d.ts +36 -0
- package/dist/components/tabs.js +636 -0
- package/dist/components/textarea.d.ts +16 -0
- package/dist/components/textarea.js +111 -0
- package/dist/components/themed-toaster.d.ts +7 -0
- package/dist/components/themed-toaster.js +86 -0
- package/dist/components/toaster.d.ts +12 -0
- package/dist/components/toaster.js +62 -0
- package/dist/components/tooltip.d.ts +43 -0
- package/dist/components/tooltip.js +65 -0
- package/dist/components/typing-animation.d.ts +34 -0
- package/dist/components/typing-animation.js +389 -0
- package/dist/constants/action-button.d.ts +20 -0
- package/dist/constants/action-button.js +17 -0
- package/dist/constants/alert.d.ts +16 -0
- package/dist/constants/alert.js +13 -0
- package/dist/constants/avatar.d.ts +38 -0
- package/dist/constants/avatar.js +32 -0
- package/dist/constants/badge.d.ts +6 -0
- package/dist/constants/badge.js +6 -0
- package/dist/constants/button.d.ts +16 -0
- package/dist/constants/button.js +16 -0
- package/dist/constants/calendar.d.ts +36 -0
- package/dist/constants/calendar.js +34 -0
- package/dist/constants/card.d.ts +23 -0
- package/dist/constants/card.js +20 -0
- package/dist/constants/carousel.d.ts +55 -0
- package/dist/constants/carousel.js +74 -0
- package/dist/constants/checkbox.d.ts +17 -0
- package/dist/constants/checkbox.js +17 -0
- package/dist/constants/dialog.d.ts +11 -0
- package/dist/constants/dialog.js +10 -0
- package/dist/constants/dropdown-menu.d.ts +17 -0
- package/dist/constants/dropdown-menu.js +48 -0
- package/dist/constants/field.d.ts +24 -0
- package/dist/constants/field.js +24 -0
- package/dist/constants/hover-card.d.ts +37 -0
- package/dist/constants/hover-card.js +85 -0
- package/dist/constants/morph-text.d.ts +13 -0
- package/dist/constants/morph-text.js +13 -0
- package/dist/constants/motion.d.ts +12 -0
- package/dist/constants/motion.js +12 -0
- package/dist/constants/pagination.d.ts +20 -0
- package/dist/constants/pagination.js +20 -0
- package/dist/constants/popover.d.ts +7 -0
- package/dist/constants/popover.js +33 -0
- package/dist/constants/radio-group.d.ts +10 -0
- package/dist/constants/radio-group.js +10 -0
- package/dist/constants/select.d.ts +7 -0
- package/dist/constants/select.js +34 -0
- package/dist/constants/sidebar.d.ts +9 -0
- package/dist/constants/sidebar.js +17 -0
- package/dist/constants/skeleton.d.ts +17 -0
- package/dist/constants/skeleton.js +17 -0
- package/dist/constants/split-button.d.ts +7 -0
- package/dist/constants/split-button.js +5 -0
- package/dist/constants/switch.d.ts +33 -0
- package/dist/constants/switch.js +41 -0
- package/dist/constants/tabs.d.ts +17 -0
- package/dist/constants/tabs.js +17 -0
- package/dist/constants/toast.d.ts +3 -0
- package/dist/constants/toast.js +3 -0
- package/dist/constants/tooltip.d.ts +13 -0
- package/dist/constants/tooltip.js +52 -0
- package/dist/hooks/use-horizontal-swipe.d.ts +23 -0
- package/dist/hooks/use-horizontal-swipe.js +80 -0
- package/dist/hooks/use-is-hydrated.d.ts +6 -0
- package/dist/hooks/use-is-hydrated.js +20 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-mobile.js +19 -0
- package/dist/hooks/use-prefers-reduced-motion.d.ts +2 -0
- package/dist/hooks/use-prefers-reduced-motion.js +27 -0
- package/dist/hooks/use-rich-link-editor.d.ts +55 -0
- package/dist/hooks/use-rich-link-editor.js +515 -0
- package/dist/hooks/use-sidebar-persistence.d.ts +6 -0
- package/dist/hooks/use-sidebar-persistence.js +52 -0
- package/dist/hooks/use-today.d.ts +7 -0
- package/dist/hooks/use-today.js +50 -0
- package/dist/hooks/use-viewer-time-zone.d.ts +6 -0
- package/dist/hooks/use-viewer-time-zone.js +20 -0
- package/dist/hooks.d.ts +11 -0
- package/dist/hooks.js +11 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +69 -0
- package/dist/lib/browser-clipboard.d.ts +13 -0
- package/dist/lib/browser-clipboard.js +48 -0
- package/dist/lib/column-filter-value.d.ts +12 -0
- package/dist/lib/column-filter-value.js +52 -0
- package/dist/lib/file-acceptance.d.ts +43 -0
- package/dist/lib/file-acceptance.js +107 -0
- package/dist/lib/format-file-size.d.ts +16 -0
- package/dist/lib/format-file-size.js +34 -0
- package/dist/lib/fuzzy-search.d.ts +17 -0
- package/dist/lib/fuzzy-search.js +183 -0
- package/dist/lib/horizontal-swipe.d.ts +23 -0
- package/dist/lib/horizontal-swipe.js +29 -0
- package/dist/lib/image-dimensions.d.ts +2 -0
- package/dist/lib/image-dimensions.js +7 -0
- package/dist/lib/name-initials.d.ts +7 -0
- package/dist/lib/name-initials.js +11 -0
- package/dist/lib/rich-text/link-markdown-constants.d.ts +147 -0
- package/dist/lib/rich-text/link-markdown-constants.js +458 -0
- package/dist/lib/rich-text/link-markdown-types.d.ts +53 -0
- package/dist/lib/rich-text/link-markdown-types.js +1 -0
- package/dist/lib/rich-text/link-markdown.d.ts +193 -0
- package/dist/lib/rich-text/link-markdown.js +592 -0
- package/dist/lib/rich-text/rich-markdown.d.ts +41 -0
- package/dist/lib/rich-text/rich-markdown.js +105 -0
- package/dist/lib/rich-text/rich-text-editor-dom.d.ts +26 -0
- package/dist/lib/rich-text/rich-text-editor-dom.js +79 -0
- package/dist/lib/toast-layer.d.ts +24 -0
- package/dist/lib/toast-layer.js +76 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +2 -0
- package/dist/lib/year-month-filter.d.ts +16 -0
- package/dist/lib/year-month-filter.js +46 -0
- package/dist/motion/arc-floating-slot.d.ts +40 -0
- package/dist/motion/arc-floating-slot.js +177 -0
- package/dist/motion/arc-press.d.ts +6 -0
- package/dist/motion/arc-press.js +59 -0
- package/dist/motion/arc-swap.d.ts +22 -0
- package/dist/motion/arc-swap.js +49 -0
- package/dist/motion/arc-tokens.d.ts +53 -0
- package/dist/motion/arc-tokens.js +73 -0
- package/dist/motion/glide-indicator.d.ts +69 -0
- package/dist/motion/glide-indicator.js +309 -0
- package/dist/motion/glide-slot.d.ts +9 -0
- package/dist/motion/glide-slot.js +71 -0
- package/dist/motion/motion-slot.d.ts +12 -0
- package/dist/motion/motion-slot.js +376 -0
- package/dist/motion/overlay-warmth.d.ts +24 -0
- package/dist/motion/overlay-warmth.js +70 -0
- package/dist/motion/presence.d.ts +40 -0
- package/dist/motion/presence.js +101 -0
- package/dist/motion/surface-keyframes.d.ts +24 -0
- package/dist/motion/surface-keyframes.js +141 -0
- package/dist/motion/tokens.d.ts +81 -0
- package/dist/motion/tokens.js +67 -0
- package/dist/motion/use-attached-element.d.ts +7 -0
- package/dist/motion/use-attached-element.js +22 -0
- package/dist/motion/use-morph-width.d.ts +13 -0
- package/dist/motion/use-morph-width.js +59 -0
- package/dist/next.d.ts +14 -0
- package/dist/next.js +79 -0
- package/dist/providers/astra-ui-provider.d.ts +27 -0
- package/dist/providers/astra-ui-provider.js +100 -0
- package/dist/providers/native-provider.d.ts +4 -0
- package/dist/providers/native-provider.js +45 -0
- package/dist/sonner.d.ts +7 -0
- package/dist/sonner.js +8 -0
- package/dist/styles.css +2 -0
- package/dist/tanstack.d.ts +11 -0
- package/dist/tanstack.js +50 -0
- package/dist/theme.d.ts +3 -0
- package/dist/theme.js +1 -0
- package/dist/types/data-table.d.ts +27 -0
- package/dist/types/data-table.js +1 -0
- package/fonts.css +5 -0
- package/package.json +450 -4
- package/styles.css +4 -0
- package/theme.css +248 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** Exposes shared UI without promoting server-safe exports into a client boundary. */
|
|
2
|
+
export { useTheme } from "next-themes";
|
|
3
|
+
export { Link, type LinkProps } from "./components/link.js";
|
|
4
|
+
export { AstraUIProvider, type AstraUIProviderProps } from "./providers/native-provider.js";
|
|
5
|
+
export type { AstraUIComponents, AstraImageProps, AstraLinkProps } from "./providers/astra-ui-provider.js";
|
|
6
|
+
export * from "./components/action-button.js";
|
|
7
|
+
export * from "./components/avatar.js";
|
|
8
|
+
export * from "./components/badge.js";
|
|
9
|
+
export * from "./components/button.js";
|
|
10
|
+
export * from "./components/card.js";
|
|
11
|
+
export * from "./components/carousel.js";
|
|
12
|
+
export * from "./components/checkbox.js";
|
|
13
|
+
export * from "./components/dialog.js";
|
|
14
|
+
export * from "./components/dropdown-menu.js";
|
|
15
|
+
export * from "./components/hover-card.js";
|
|
16
|
+
export * from "./components/input.js";
|
|
17
|
+
export * from "./components/pagination.js";
|
|
18
|
+
export * from "./components/popover.js";
|
|
19
|
+
export * from "./components/select.js";
|
|
20
|
+
export * from "./components/separator.js";
|
|
21
|
+
export * from "./components/sheet.js";
|
|
22
|
+
export * from "./components/sidebar.js";
|
|
23
|
+
export * from "./components/skeleton.js";
|
|
24
|
+
export * from "./components/split-button.js";
|
|
25
|
+
export * from "./components/switch.js";
|
|
26
|
+
export * from "./components/table.js";
|
|
27
|
+
export * from "./components/tabs.js";
|
|
28
|
+
export * from "./components/textarea.js";
|
|
29
|
+
export * from "./components/tooltip.js";
|
|
30
|
+
export * from "./components/svgs/whatsappIcon.js";
|
|
31
|
+
export * from "./lib/utils.js";
|
|
32
|
+
export * from "./hooks/use-mobile.js";
|
|
33
|
+
export * from "./constants/sidebar.js";
|
|
34
|
+
export * from "./sonner.js";
|
|
35
|
+
export * from "./components/alert.js";
|
|
36
|
+
export * from "./components/animated-theme-toggler.js";
|
|
37
|
+
export * from "./components/calendar.js";
|
|
38
|
+
export * from "./components/data-table.js";
|
|
39
|
+
export * from "./components/filter-query-bar.js";
|
|
40
|
+
export * from "./components/filter-query-grammar.js";
|
|
41
|
+
export * from "./components/form.js";
|
|
42
|
+
export * from "./components/highlighter.js";
|
|
43
|
+
export * from "./components/input-group.js";
|
|
44
|
+
export * from "./components/label.js";
|
|
45
|
+
export * from "./components/radio-group.js";
|
|
46
|
+
export * from "./components/typing-animation.js";
|
|
47
|
+
export * from "./components/themed-toaster.js";
|
|
48
|
+
export * from "./theme.js";
|
|
49
|
+
export * from "./lib/year-month-filter.js";
|
|
50
|
+
export * from "./motion/tokens.js";
|
|
51
|
+
export * from "./components/animated-collapse.js";
|
|
52
|
+
export * from "./components/animated-count.js";
|
|
53
|
+
export * from "./components/animated-list-item.js";
|
|
54
|
+
export * from "./components/presence-swap.js";
|
|
55
|
+
export * from "./components/progress-ring.js";
|
|
56
|
+
export * from "./components/account-menu.js";
|
|
57
|
+
export * from "./components/rich-text-content.js";
|
|
58
|
+
export * from "./components/rich-markdown-content.js";
|
|
59
|
+
export * from "./components/rich-link-editor.js";
|
|
60
|
+
export * from "./components/reaction-button.js";
|
|
61
|
+
export * from "./components/file-upload.js";
|
|
62
|
+
export * from "./hooks/use-rich-link-editor.js";
|
|
63
|
+
export * from "./lib/browser-clipboard.js";
|
|
64
|
+
export * from "./lib/file-acceptance.js";
|
|
65
|
+
export * from "./lib/format-file-size.js";
|
|
66
|
+
export * from "./lib/fuzzy-search.js";
|
|
67
|
+
export { parseRichTextSegments, normalizeMarkdownUrl, normalizeAutolinkUrl } from "./lib/rich-text/link-markdown.js";
|
|
68
|
+
export { RICH_TEXT_SEGMENT_TYPE, RICH_LINK_KIND } from "./lib/rich-text/link-markdown-constants.js";
|
|
69
|
+
export type { RichTextSegment, RichLink } from "./lib/rich-text/link-markdown-types.js";
|
|
70
|
+
export * from "./lib/rich-text/rich-markdown.js";
|
|
71
|
+
export * from "./components/filter-presets-bar.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** Exposes shared UI without promoting server-safe exports into a client boundary. */
|
|
2
|
+
export { useTheme } from "next-themes";
|
|
3
|
+
export { Link } from "./components/link.js";
|
|
4
|
+
export { AstraUIProvider } from "./providers/native-provider.js";
|
|
5
|
+
export * from "./components/action-button.js";
|
|
6
|
+
export * from "./components/avatar.js";
|
|
7
|
+
export * from "./components/badge.js";
|
|
8
|
+
export * from "./components/button.js";
|
|
9
|
+
export * from "./components/card.js";
|
|
10
|
+
export * from "./components/carousel.js";
|
|
11
|
+
export * from "./components/checkbox.js";
|
|
12
|
+
export * from "./components/dialog.js";
|
|
13
|
+
export * from "./components/dropdown-menu.js";
|
|
14
|
+
export * from "./components/hover-card.js";
|
|
15
|
+
export * from "./components/input.js";
|
|
16
|
+
export * from "./components/pagination.js";
|
|
17
|
+
export * from "./components/popover.js";
|
|
18
|
+
export * from "./components/select.js";
|
|
19
|
+
export * from "./components/separator.js";
|
|
20
|
+
export * from "./components/sheet.js";
|
|
21
|
+
export * from "./components/sidebar.js";
|
|
22
|
+
export * from "./components/skeleton.js";
|
|
23
|
+
export * from "./components/split-button.js";
|
|
24
|
+
export * from "./components/switch.js";
|
|
25
|
+
export * from "./components/table.js";
|
|
26
|
+
export * from "./components/tabs.js";
|
|
27
|
+
export * from "./components/textarea.js";
|
|
28
|
+
export * from "./components/tooltip.js";
|
|
29
|
+
export * from "./components/svgs/whatsappIcon.js";
|
|
30
|
+
export * from "./lib/utils.js";
|
|
31
|
+
export * from "./hooks/use-mobile.js";
|
|
32
|
+
export * from "./constants/sidebar.js";
|
|
33
|
+
export * from "./sonner.js";
|
|
34
|
+
export * from "./components/alert.js";
|
|
35
|
+
export * from "./components/animated-theme-toggler.js";
|
|
36
|
+
export * from "./components/calendar.js";
|
|
37
|
+
export * from "./components/data-table.js";
|
|
38
|
+
export * from "./components/filter-query-bar.js";
|
|
39
|
+
export * from "./components/filter-query-grammar.js";
|
|
40
|
+
export * from "./components/form.js";
|
|
41
|
+
export * from "./components/highlighter.js";
|
|
42
|
+
export * from "./components/input-group.js";
|
|
43
|
+
export * from "./components/label.js";
|
|
44
|
+
export * from "./components/radio-group.js";
|
|
45
|
+
export * from "./components/typing-animation.js";
|
|
46
|
+
export * from "./components/themed-toaster.js";
|
|
47
|
+
export * from "./theme.js";
|
|
48
|
+
export * from "./lib/year-month-filter.js";
|
|
49
|
+
export * from "./motion/tokens.js";
|
|
50
|
+
export * from "./components/animated-collapse.js";
|
|
51
|
+
export * from "./components/animated-count.js";
|
|
52
|
+
export * from "./components/animated-list-item.js";
|
|
53
|
+
export * from "./components/presence-swap.js";
|
|
54
|
+
export * from "./components/progress-ring.js";
|
|
55
|
+
export * from "./components/account-menu.js";
|
|
56
|
+
export * from "./components/rich-text-content.js";
|
|
57
|
+
export * from "./components/rich-markdown-content.js";
|
|
58
|
+
export * from "./components/rich-link-editor.js";
|
|
59
|
+
export * from "./components/reaction-button.js";
|
|
60
|
+
export * from "./components/file-upload.js";
|
|
61
|
+
export * from "./hooks/use-rich-link-editor.js";
|
|
62
|
+
export * from "./lib/browser-clipboard.js";
|
|
63
|
+
export * from "./lib/file-acceptance.js";
|
|
64
|
+
export * from "./lib/format-file-size.js";
|
|
65
|
+
export * from "./lib/fuzzy-search.js";
|
|
66
|
+
export { parseRichTextSegments, normalizeMarkdownUrl, normalizeAutolinkUrl } from "./lib/rich-text/link-markdown.js";
|
|
67
|
+
export { RICH_TEXT_SEGMENT_TYPE, RICH_LINK_KIND } from "./lib/rich-text/link-markdown-constants.js";
|
|
68
|
+
export * from "./lib/rich-text/rich-markdown.js";
|
|
69
|
+
export * from "./components/filter-presets-bar.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser clipboard adapter with feature detection. The async Clipboard API
|
|
3
|
+
* is preferred; when it is missing (older WebKit, insecure context) or
|
|
4
|
+
* rejects, a hidden textarea plus `document.execCommand("copy")` is tried,
|
|
5
|
+
* which WebKit still honours inside a user gesture.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Copies text to the clipboard.
|
|
9
|
+
*
|
|
10
|
+
* @param text - Text to copy.
|
|
11
|
+
* @returns True when the text reached the clipboard.
|
|
12
|
+
*/
|
|
13
|
+
export declare function copyTextToClipboard(text: string): Promise<boolean>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser clipboard adapter with feature detection. The async Clipboard API
|
|
3
|
+
* is preferred; when it is missing (older WebKit, insecure context) or
|
|
4
|
+
* rejects, a hidden textarea plus `document.execCommand("copy")` is tried,
|
|
5
|
+
* which WebKit still honours inside a user gesture.
|
|
6
|
+
*/
|
|
7
|
+
const FALLBACK_COPY_COMMAND = "copy";
|
|
8
|
+
const FALLBACK_TEXTAREA_TAG = "textarea";
|
|
9
|
+
const FALLBACK_READONLY_ATTRIBUTE = "readonly";
|
|
10
|
+
const OFFSCREEN_POSITION = "fixed";
|
|
11
|
+
const OFFSCREEN_OFFSET = "-9999px";
|
|
12
|
+
function copyWithSelectionFallback(text) {
|
|
13
|
+
if (typeof document.execCommand !== "function") {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const textarea = document.createElement(FALLBACK_TEXTAREA_TAG);
|
|
17
|
+
textarea.value = text;
|
|
18
|
+
textarea.setAttribute(FALLBACK_READONLY_ATTRIBUTE, "");
|
|
19
|
+
textarea.style.position = OFFSCREEN_POSITION;
|
|
20
|
+
textarea.style.top = OFFSCREEN_OFFSET;
|
|
21
|
+
document.body.appendChild(textarea);
|
|
22
|
+
textarea.select();
|
|
23
|
+
// iOS Safari needs an explicit range for read-only fields.
|
|
24
|
+
textarea.setSelectionRange(0, text.length);
|
|
25
|
+
try {
|
|
26
|
+
return document.execCommand(FALLBACK_COPY_COMMAND);
|
|
27
|
+
} catch {
|
|
28
|
+
// The legacy command can throw when copying is blocked; report failure.
|
|
29
|
+
return false;
|
|
30
|
+
} finally {
|
|
31
|
+
textarea.remove();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Copies text to the clipboard.
|
|
36
|
+
*
|
|
37
|
+
* @param text - Text to copy.
|
|
38
|
+
* @returns True when the text reached the clipboard.
|
|
39
|
+
*/
|
|
40
|
+
export async function copyTextToClipboard(text) {
|
|
41
|
+
if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
|
|
42
|
+
try {
|
|
43
|
+
await navigator.clipboard.writeText(text);
|
|
44
|
+
return true;
|
|
45
|
+
} catch {}
|
|
46
|
+
}
|
|
47
|
+
return copyWithSelectionFallback(text);
|
|
48
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Normalizes text for accent- and case-insensitive comparisons. */
|
|
2
|
+
export declare function normalizeFilterToken(value: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Evalúa el valor de una celda contra un filtro de columna de la barra de filtros.
|
|
5
|
+
* Entiende los valores estructurados (`numberRange`, `enum`, `presence`, `yearMonthRange`)
|
|
6
|
+
* y, para texto plano, busca coincidencias parciales sin distinguir acentos ni mayúsculas.
|
|
7
|
+
* Una celda sin valor comparable no cumple los rangos; un filtro vacío deja pasar la fila.
|
|
8
|
+
* @param cellValue - Valor de la celda tal como lo devuelve el accessor de la columna.
|
|
9
|
+
* @param filterValue - Valor activo del filtro de esa columna.
|
|
10
|
+
* @returns `true` cuando la fila debe mostrarse.
|
|
11
|
+
*/
|
|
12
|
+
export declare function matchesColumnFilterValue(cellValue: unknown, filterValue: unknown): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { matchesAdvancedYearMonthRangeFilter } from "./year-month-filter.js";
|
|
2
|
+
const DIACRITICS_PATTERN = /[̀-ͯ]/g;
|
|
3
|
+
/** Normalizes text for accent- and case-insensitive comparisons. */
|
|
4
|
+
export function normalizeFilterToken(value) {
|
|
5
|
+
return value.normalize("NFD").replace(DIACRITICS_PATTERN, "").toLocaleLowerCase().trim();
|
|
6
|
+
}
|
|
7
|
+
/** Distinguishes the grammar's structured values from plain text written by the search input. */
|
|
8
|
+
function isColumnFilterValue(value) {
|
|
9
|
+
return typeof value === "object" && value !== null && typeof value.kind === "string";
|
|
10
|
+
}
|
|
11
|
+
/** Reads numbers and numeric strings; anything else has no comparable value. */
|
|
12
|
+
function toFiniteNumber(value) {
|
|
13
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
14
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
15
|
+
const parsed = Number(value);
|
|
16
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
/** Treats `null`, `undefined`, blank strings and empty lists as a missing value. */
|
|
21
|
+
function isMissingValue(value) {
|
|
22
|
+
if (value == null) return true;
|
|
23
|
+
if (typeof value === "string") return value.trim() === "";
|
|
24
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Evalúa el valor de una celda contra un filtro de columna de la barra de filtros.
|
|
29
|
+
* Entiende los valores estructurados (`numberRange`, `enum`, `presence`, `yearMonthRange`)
|
|
30
|
+
* y, para texto plano, busca coincidencias parciales sin distinguir acentos ni mayúsculas.
|
|
31
|
+
* Una celda sin valor comparable no cumple los rangos; un filtro vacío deja pasar la fila.
|
|
32
|
+
* @param cellValue - Valor de la celda tal como lo devuelve el accessor de la columna.
|
|
33
|
+
* @param filterValue - Valor activo del filtro de esa columna.
|
|
34
|
+
* @returns `true` cuando la fila debe mostrarse.
|
|
35
|
+
*/
|
|
36
|
+
export function matchesColumnFilterValue(cellValue, filterValue) {
|
|
37
|
+
if (!isColumnFilterValue(filterValue)) {
|
|
38
|
+
const query = normalizeFilterToken(String(filterValue ?? ""));
|
|
39
|
+
return query === "" || normalizeFilterToken(String(cellValue ?? "")).includes(query);
|
|
40
|
+
}
|
|
41
|
+
switch (filterValue.kind) {
|
|
42
|
+
case "numberRange": {
|
|
43
|
+
const value = toFiniteNumber(cellValue);
|
|
44
|
+
if (value == null) return false;
|
|
45
|
+
if (filterValue.min != null && value < filterValue.min) return false;
|
|
46
|
+
return filterValue.max == null || value <= filterValue.max;
|
|
47
|
+
}
|
|
48
|
+
case "enum": return Array.isArray(cellValue) ? cellValue.some((item) => String(item) === filterValue.value) : String(cellValue ?? "") === filterValue.value;
|
|
49
|
+
case "presence": return filterValue.value === "hasValue" ? !isMissingValue(cellValue) : isMissingValue(cellValue);
|
|
50
|
+
case "yearMonthRange": return matchesAdvancedYearMonthRangeFilter(filterValue, toFiniteNumber(cellValue));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates picked or dropped files against an `accept` list and a size limit, mirroring the
|
|
3
|
+
* native `<input accept>` syntax. Files without a MIME type (common on some Android pickers and
|
|
4
|
+
* drag sources) fall back to their extension.
|
|
5
|
+
*/
|
|
6
|
+
/** File metadata the checks need; a `File` satisfies it. */
|
|
7
|
+
export interface AcceptableFile {
|
|
8
|
+
name: string;
|
|
9
|
+
type: string;
|
|
10
|
+
size: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Extracts the lowercase extension from a file name.
|
|
14
|
+
* @param fileName - The file name.
|
|
15
|
+
* @returns The extension with its leading dot, or null when there is none.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getFileExtension(fileName: string): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Tells whether a file matches an `accept` list such as `"image/*,.pdf"`.
|
|
20
|
+
* @param file - File to check.
|
|
21
|
+
* @param accept - Comma-separated extensions, exact MIME types or `type/*` wildcards; empty accepts all.
|
|
22
|
+
* @returns Whether the file is accepted.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isFileTypeAccepted(file: AcceptableFile, accept?: string): boolean;
|
|
25
|
+
export interface ClassifyFilesOptions {
|
|
26
|
+
accept?: string;
|
|
27
|
+
/** Maximum size in bytes; checked before the type. */
|
|
28
|
+
maxSize?: number;
|
|
29
|
+
/** When false, only the first file is considered. */
|
|
30
|
+
allowsMultiple?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface ClassifiedFiles<TFile extends AcceptableFile> {
|
|
33
|
+
accepted: TFile[];
|
|
34
|
+
unaccepted: TFile[];
|
|
35
|
+
oversized: TFile[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Splits files into accepted, wrong-type and oversized groups.
|
|
39
|
+
* @param files - Picked or dropped files.
|
|
40
|
+
* @param options - Accept list, size limit and multiplicity.
|
|
41
|
+
* @returns The three groups, preserving input order.
|
|
42
|
+
*/
|
|
43
|
+
export declare function classifyFiles<TFile extends AcceptableFile>(files: readonly TFile[], { accept, maxSize, allowsMultiple }?: ClassifyFilesOptions): ClassifiedFiles<TFile>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates picked or dropped files against an `accept` list and a size limit, mirroring the
|
|
3
|
+
* native `<input accept>` syntax. Files without a MIME type (common on some Android pickers and
|
|
4
|
+
* drag sources) fall back to their extension.
|
|
5
|
+
*/
|
|
6
|
+
const MIME_TYPE_EXTENSION_FALLBACKS = {
|
|
7
|
+
"application/pdf": [".pdf"],
|
|
8
|
+
"audio/mpeg": [".mp3"],
|
|
9
|
+
"image/gif": [".gif"],
|
|
10
|
+
"image/heic": [".heic"],
|
|
11
|
+
"image/heif": [".heif"],
|
|
12
|
+
"image/jpeg": [".jpg", ".jpeg"],
|
|
13
|
+
"image/png": [".png"],
|
|
14
|
+
"image/webp": [".webp"],
|
|
15
|
+
"text/plain": [".txt"],
|
|
16
|
+
"video/mp4": [".mp4"]
|
|
17
|
+
};
|
|
18
|
+
const WILDCARD_MIME_PREFIX_EXTENSION_FALLBACKS = {
|
|
19
|
+
audio: [
|
|
20
|
+
".aac",
|
|
21
|
+
".flac",
|
|
22
|
+
".m4a",
|
|
23
|
+
".mp3",
|
|
24
|
+
".ogg",
|
|
25
|
+
".wav"
|
|
26
|
+
],
|
|
27
|
+
image: [
|
|
28
|
+
".avif",
|
|
29
|
+
".bmp",
|
|
30
|
+
".gif",
|
|
31
|
+
".heic",
|
|
32
|
+
".heif",
|
|
33
|
+
".jpeg",
|
|
34
|
+
".jpg",
|
|
35
|
+
".png",
|
|
36
|
+
".svg",
|
|
37
|
+
".webp"
|
|
38
|
+
],
|
|
39
|
+
text: [
|
|
40
|
+
".csv",
|
|
41
|
+
".md",
|
|
42
|
+
".txt"
|
|
43
|
+
],
|
|
44
|
+
video: [
|
|
45
|
+
".avi",
|
|
46
|
+
".m4v",
|
|
47
|
+
".mov",
|
|
48
|
+
".mp4",
|
|
49
|
+
".mkv",
|
|
50
|
+
".webm"
|
|
51
|
+
]
|
|
52
|
+
};
|
|
53
|
+
const ACCEPT_LIST_SEPARATOR = ",";
|
|
54
|
+
const EXTENSION_PREFIX = ".";
|
|
55
|
+
const MIME_WILDCARD_SUFFIX = "/*";
|
|
56
|
+
const MIME_TYPE_SEPARATOR = "/";
|
|
57
|
+
/**
|
|
58
|
+
* Extracts the lowercase extension from a file name.
|
|
59
|
+
* @param fileName - The file name.
|
|
60
|
+
* @returns The extension with its leading dot, or null when there is none.
|
|
61
|
+
*/
|
|
62
|
+
export function getFileExtension(fileName) {
|
|
63
|
+
const fileNameParts = fileName.split(EXTENSION_PREFIX);
|
|
64
|
+
const extension = fileNameParts.length > 1 ? fileNameParts.pop() : null;
|
|
65
|
+
return extension ? `${EXTENSION_PREFIX}${extension.toLowerCase()}` : null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Tells whether a file matches an `accept` list such as `"image/*,.pdf"`.
|
|
69
|
+
* @param file - File to check.
|
|
70
|
+
* @param accept - Comma-separated extensions, exact MIME types or `type/*` wildcards; empty accepts all.
|
|
71
|
+
* @returns Whether the file is accepted.
|
|
72
|
+
*/
|
|
73
|
+
export function isFileTypeAccepted(file, accept) {
|
|
74
|
+
if (!accept) return true;
|
|
75
|
+
const fileExtension = getFileExtension(file.name);
|
|
76
|
+
const normalizedFileType = file.type.toLowerCase();
|
|
77
|
+
const hasMimeType = normalizedFileType.length > 0;
|
|
78
|
+
const extensionMatches = (candidateExtensions) => Boolean(fileExtension && candidateExtensions?.includes(fileExtension));
|
|
79
|
+
return accept.split(ACCEPT_LIST_SEPARATOR).map((acceptedType) => acceptedType.trim().toLowerCase()).filter(Boolean).some((acceptedType) => {
|
|
80
|
+
if (acceptedType.startsWith(EXTENSION_PREFIX)) return fileExtension === acceptedType;
|
|
81
|
+
if (acceptedType.endsWith(MIME_WILDCARD_SUFFIX)) {
|
|
82
|
+
const typePrefix = acceptedType.split(MIME_TYPE_SEPARATOR)[0];
|
|
83
|
+
return hasMimeType ? normalizedFileType.startsWith(`${typePrefix}${MIME_TYPE_SEPARATOR}`) : extensionMatches(WILDCARD_MIME_PREFIX_EXTENSION_FALLBACKS[typePrefix]);
|
|
84
|
+
}
|
|
85
|
+
return hasMimeType && normalizedFileType === acceptedType || extensionMatches(MIME_TYPE_EXTENSION_FALLBACKS[acceptedType]);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Splits files into accepted, wrong-type and oversized groups.
|
|
90
|
+
* @param files - Picked or dropped files.
|
|
91
|
+
* @param options - Accept list, size limit and multiplicity.
|
|
92
|
+
* @returns The three groups, preserving input order.
|
|
93
|
+
*/
|
|
94
|
+
export function classifyFiles(files, { accept, maxSize, allowsMultiple = true } = {}) {
|
|
95
|
+
const classifiedFiles = {
|
|
96
|
+
accepted: [],
|
|
97
|
+
unaccepted: [],
|
|
98
|
+
oversized: []
|
|
99
|
+
};
|
|
100
|
+
const filesToProcess = allowsMultiple ? files : files.slice(0, 1);
|
|
101
|
+
for (const file of filesToProcess) {
|
|
102
|
+
if (maxSize !== undefined && file.size > maxSize) classifiedFiles.oversized.push(file);
|
|
103
|
+
else if (isFileTypeAccepted(file, accept)) classifiedFiles.accepted.push(file);
|
|
104
|
+
else classifiedFiles.unaccepted.push(file);
|
|
105
|
+
}
|
|
106
|
+
return classifiedFiles;
|
|
107
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure file-size formatting helper shared by attachment and upload UIs. Framework-safe:
|
|
3
|
+
* no React, no platform APIs beyond `Intl`, so it runs on the server and the client alike.
|
|
4
|
+
*/
|
|
5
|
+
export interface FormatFileSizeOptions {
|
|
6
|
+
/** BCP 47 locale used for the decimal separator. Defaults to `es-AR`. */
|
|
7
|
+
locale?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Formats a byte count as a short human-readable size, e.g. `12,3 MB`, `850 KB`, `25 MB`.
|
|
11
|
+
*
|
|
12
|
+
* @param bytes - Raw size in bytes. Non-finite or negative values render as `0 B`.
|
|
13
|
+
* @param options - Optional locale for the number format.
|
|
14
|
+
* @returns The formatted size with its unit, separated by a space.
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatFileSize(bytes: number, { locale }?: FormatFileSizeOptions): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure file-size formatting helper shared by attachment and upload UIs. Framework-safe:
|
|
3
|
+
* no React, no platform APIs beyond `Intl`, so it runs on the server and the client alike.
|
|
4
|
+
*/
|
|
5
|
+
const BYTES_PER_UNIT_STEP = 1024;
|
|
6
|
+
const FILE_SIZE_UNIT_LABELS = [
|
|
7
|
+
"B",
|
|
8
|
+
"KB",
|
|
9
|
+
"MB",
|
|
10
|
+
"GB",
|
|
11
|
+
"TB"
|
|
12
|
+
];
|
|
13
|
+
/** Spanish (Argentina) keeps the comma decimal separator of the original product copy. */
|
|
14
|
+
const DEFAULT_FILE_SIZE_LOCALE = "es-AR";
|
|
15
|
+
const SUB_UNIT_FRACTION_DIGITS = 0;
|
|
16
|
+
const SCALED_UNIT_FRACTION_DIGITS = 1;
|
|
17
|
+
/**
|
|
18
|
+
* Formats a byte count as a short human-readable size, e.g. `12,3 MB`, `850 KB`, `25 MB`.
|
|
19
|
+
*
|
|
20
|
+
* @param bytes - Raw size in bytes. Non-finite or negative values render as `0 B`.
|
|
21
|
+
* @param options - Optional locale for the number format.
|
|
22
|
+
* @returns The formatted size with its unit, separated by a space.
|
|
23
|
+
*/
|
|
24
|
+
export function formatFileSize(bytes, { locale = DEFAULT_FILE_SIZE_LOCALE } = {}) {
|
|
25
|
+
const safeBytes = Number.isFinite(bytes) && bytes > 0 ? bytes : 0;
|
|
26
|
+
let scaledValue = safeBytes;
|
|
27
|
+
let unitIndex = 0;
|
|
28
|
+
while (scaledValue >= BYTES_PER_UNIT_STEP && unitIndex < FILE_SIZE_UNIT_LABELS.length - 1) {
|
|
29
|
+
scaledValue /= BYTES_PER_UNIT_STEP;
|
|
30
|
+
unitIndex += 1;
|
|
31
|
+
}
|
|
32
|
+
const formattedValue = new Intl.NumberFormat(locale, { maximumFractionDigits: unitIndex === 0 ? SUB_UNIT_FRACTION_DIGITS : SCALED_UNIT_FRACTION_DIGITS }).format(scaledValue);
|
|
33
|
+
return `${formattedValue} ${FILE_SIZE_UNIT_LABELS[unitIndex]}`;
|
|
34
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Ranks and highlights fuzzy text matches, ignoring case and diacritics, for pickers and search lists. */
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
export interface FuzzyMatchRank {
|
|
4
|
+
contiguousPairCount: number;
|
|
5
|
+
gapCount: number;
|
|
6
|
+
longestRun: number;
|
|
7
|
+
matchedChars: number;
|
|
8
|
+
maxGap: number;
|
|
9
|
+
span: number;
|
|
10
|
+
startIndex: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function compareFuzzyMatchRank(leftRank: FuzzyMatchRank, rightRank: FuzzyMatchRank): number;
|
|
13
|
+
export declare function normalizeSearchValue(value: string): string;
|
|
14
|
+
export declare function getExactMatchIndices(value: string, query: string): number[] | null;
|
|
15
|
+
export declare function getFuzzyMatchIndices(value: string, query: string): number[] | null;
|
|
16
|
+
export declare function getFuzzyMatchRank(value: string, query: string): FuzzyMatchRank | null;
|
|
17
|
+
export declare function renderHighlightedText(value: string, matchedIndices: number[], highlightClassName: string, keyPrefix: string): ReactNode;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
const DIACRITICS_PATTERN = /[\u0300-\u036f]/g;
|
|
3
|
+
export function compareFuzzyMatchRank(leftRank, rightRank) {
|
|
4
|
+
if (leftRank.longestRun !== rightRank.longestRun) {
|
|
5
|
+
return rightRank.longestRun - leftRank.longestRun;
|
|
6
|
+
}
|
|
7
|
+
if (leftRank.contiguousPairCount !== rightRank.contiguousPairCount) {
|
|
8
|
+
return rightRank.contiguousPairCount - leftRank.contiguousPairCount;
|
|
9
|
+
}
|
|
10
|
+
if (leftRank.gapCount !== rightRank.gapCount) {
|
|
11
|
+
return leftRank.gapCount - rightRank.gapCount;
|
|
12
|
+
}
|
|
13
|
+
if (leftRank.maxGap !== rightRank.maxGap) {
|
|
14
|
+
return leftRank.maxGap - rightRank.maxGap;
|
|
15
|
+
}
|
|
16
|
+
if (leftRank.span !== rightRank.span) {
|
|
17
|
+
return leftRank.span - rightRank.span;
|
|
18
|
+
}
|
|
19
|
+
if (leftRank.startIndex !== rightRank.startIndex) {
|
|
20
|
+
return leftRank.startIndex - rightRank.startIndex;
|
|
21
|
+
}
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
export function normalizeSearchValue(value) {
|
|
25
|
+
return value.normalize("NFD").replace(DIACRITICS_PATTERN, "").toLocaleLowerCase();
|
|
26
|
+
}
|
|
27
|
+
function getSearchCharsWithSourceIndices(value) {
|
|
28
|
+
const chars = [];
|
|
29
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
30
|
+
const normalizedChar = normalizeSearchValue(value[index]);
|
|
31
|
+
if (!normalizedChar) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
for (const char of normalizedChar) {
|
|
35
|
+
chars.push({
|
|
36
|
+
char,
|
|
37
|
+
sourceIndex: index
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return chars;
|
|
42
|
+
}
|
|
43
|
+
export function getExactMatchIndices(value, query) {
|
|
44
|
+
const normalizedQuery = normalizeSearchValue(query).trim();
|
|
45
|
+
if (!normalizedQuery) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const valueChars = getSearchCharsWithSourceIndices(value);
|
|
49
|
+
const queryChars = Array.from(normalizedQuery);
|
|
50
|
+
if (queryChars.length > valueChars.length) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
for (let valueIndex = 0; valueIndex <= valueChars.length - queryChars.length; valueIndex += 1) {
|
|
54
|
+
let isExactMatch = true;
|
|
55
|
+
for (let queryIndex = 0; queryIndex < queryChars.length; queryIndex += 1) {
|
|
56
|
+
if (valueChars[valueIndex + queryIndex].char !== queryChars[queryIndex]) {
|
|
57
|
+
isExactMatch = false;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!isExactMatch) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const matchStartSourceIndex = valueChars[valueIndex].sourceIndex;
|
|
65
|
+
const matchEndSourceIndex = valueChars[valueIndex + queryChars.length - 1].sourceIndex;
|
|
66
|
+
return Array.from({ length: matchEndSourceIndex - matchStartSourceIndex + 1 }, (_, index) => matchStartSourceIndex + index);
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
export function getFuzzyMatchIndices(value, query) {
|
|
71
|
+
const normalizedQuery = normalizeSearchValue(query).trim();
|
|
72
|
+
if (!normalizedQuery) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
const valueChars = getSearchCharsWithSourceIndices(value);
|
|
76
|
+
const queryChars = Array.from(normalizedQuery);
|
|
77
|
+
const matchedIndices = [];
|
|
78
|
+
let valueCursor = 0;
|
|
79
|
+
for (const queryChar of queryChars) {
|
|
80
|
+
let foundAt = -1;
|
|
81
|
+
for (let index = valueCursor; index < valueChars.length; index += 1) {
|
|
82
|
+
if (valueChars[index].char === queryChar) {
|
|
83
|
+
foundAt = index;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (foundAt === -1) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
matchedIndices.push(valueChars[foundAt].sourceIndex);
|
|
91
|
+
valueCursor = foundAt + 1;
|
|
92
|
+
}
|
|
93
|
+
return Array.from(new Set(matchedIndices));
|
|
94
|
+
}
|
|
95
|
+
export function getFuzzyMatchRank(value, query) {
|
|
96
|
+
const normalizedQuery = normalizeSearchValue(query).trim();
|
|
97
|
+
if (!normalizedQuery) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const valueChars = getSearchCharsWithSourceIndices(value);
|
|
101
|
+
const queryChars = Array.from(normalizedQuery);
|
|
102
|
+
const matchedSourceIndices = [];
|
|
103
|
+
let valueCursor = 0;
|
|
104
|
+
for (const queryChar of queryChars) {
|
|
105
|
+
let foundAt = -1;
|
|
106
|
+
for (let index = valueCursor; index < valueChars.length; index += 1) {
|
|
107
|
+
if (valueChars[index].char === queryChar) {
|
|
108
|
+
foundAt = index;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (foundAt === -1) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
matchedSourceIndices.push(valueChars[foundAt].sourceIndex);
|
|
116
|
+
valueCursor = foundAt + 1;
|
|
117
|
+
}
|
|
118
|
+
const startIndex = matchedSourceIndices[0] ?? 0;
|
|
119
|
+
const endIndex = matchedSourceIndices[matchedSourceIndices.length - 1] ?? startIndex;
|
|
120
|
+
let contiguousPairCount = 0;
|
|
121
|
+
let gapCount = 0;
|
|
122
|
+
let longestRun = matchedSourceIndices.length > 0 ? 1 : 0;
|
|
123
|
+
let maxGap = 0;
|
|
124
|
+
let currentRun = matchedSourceIndices.length > 0 ? 1 : 0;
|
|
125
|
+
for (let index = 1; index < matchedSourceIndices.length; index += 1) {
|
|
126
|
+
if (matchedSourceIndices[index] === matchedSourceIndices[index - 1] + 1) {
|
|
127
|
+
contiguousPairCount += 1;
|
|
128
|
+
currentRun += 1;
|
|
129
|
+
} else {
|
|
130
|
+
currentRun = 1;
|
|
131
|
+
}
|
|
132
|
+
if (currentRun > longestRun) {
|
|
133
|
+
longestRun = currentRun;
|
|
134
|
+
}
|
|
135
|
+
const gap = Math.max(matchedSourceIndices[index] - matchedSourceIndices[index - 1] - 1, 0);
|
|
136
|
+
gapCount += gap;
|
|
137
|
+
if (gap > maxGap) {
|
|
138
|
+
maxGap = gap;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
contiguousPairCount,
|
|
143
|
+
gapCount,
|
|
144
|
+
longestRun,
|
|
145
|
+
matchedChars: queryChars.length,
|
|
146
|
+
maxGap,
|
|
147
|
+
span: Math.max(endIndex - startIndex, 0),
|
|
148
|
+
startIndex
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
export function renderHighlightedText(value, matchedIndices, highlightClassName, keyPrefix) {
|
|
152
|
+
if (matchedIndices.length === 0) {
|
|
153
|
+
return value;
|
|
154
|
+
}
|
|
155
|
+
const matchedIndexSet = new Set(matchedIndices);
|
|
156
|
+
const highlightedParts = [];
|
|
157
|
+
let currentStart = 0;
|
|
158
|
+
let partIndex = 0;
|
|
159
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
160
|
+
if (!matchedIndexSet.has(index)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (currentStart < index) {
|
|
164
|
+
highlightedParts.push(/* @__PURE__ */ _jsx("span", { children: value.slice(currentStart, index) }, `${keyPrefix}-text-${partIndex}`));
|
|
165
|
+
partIndex += 1;
|
|
166
|
+
}
|
|
167
|
+
let matchEnd = index + 1;
|
|
168
|
+
while (matchEnd < value.length && matchedIndexSet.has(matchEnd)) {
|
|
169
|
+
matchEnd += 1;
|
|
170
|
+
}
|
|
171
|
+
highlightedParts.push(/* @__PURE__ */ _jsx("mark", {
|
|
172
|
+
className: highlightClassName,
|
|
173
|
+
children: value.slice(index, matchEnd)
|
|
174
|
+
}, `${keyPrefix}-match-${partIndex}`));
|
|
175
|
+
partIndex += 1;
|
|
176
|
+
currentStart = matchEnd;
|
|
177
|
+
index = matchEnd - 1;
|
|
178
|
+
}
|
|
179
|
+
if (currentStart < value.length) {
|
|
180
|
+
highlightedParts.push(/* @__PURE__ */ _jsx("span", { children: value.slice(currentStart) }, `${keyPrefix}-text-${partIndex}`));
|
|
181
|
+
}
|
|
182
|
+
return /* @__PURE__ */ _jsx("span", { children: highlightedParts }, `${keyPrefix}-highlighted`);
|
|
183
|
+
}
|